summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2021-08-20 10:31:40 +0200
committerEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2021-08-23 07:37:04 +0200
commitd8f815db7f5eb2bdfb911dbf6d28da17c0a47025 (patch)
tree61c296bd8e694ef8e6d238d93fb9835ff5bea939
parentd07742f333df89dc399fc5d9cabf2bdef0b346c5 (diff)
Update Harfbuzz to version 2.9.0
[ChangeLog][Text] Updated bundled Harfbuzz to version 2.9.0. Pick-to: 6.2 Change-Id: Ib8fed753b99a127d5a4cc793c5c1d55a0090f902 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com>
-rw-r--r--src/3rdparty/harfbuzz-ng/CMakeLists.txt4
-rw-r--r--src/3rdparty/harfbuzz-ng/COPYING4
-rw-r--r--src/3rdparty/harfbuzz-ng/NEWS45
-rw-r--r--src/3rdparty/harfbuzz-ng/README.md4
-rw-r--r--src/3rdparty/harfbuzz-ng/qt_attribution.json2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/harfbuzz.cc1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-ankr-table.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh11
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-feat-table.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-just-table.hh16
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh14
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh21
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-opbd-table.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-trak-table.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc13
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-ltag-table.hh4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-algs.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-array.hh51
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-bimap.hh5
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-blob.cc123
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-blob.h10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-blob.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer.cc77
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer.hh17
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cache.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cff-interp-common.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-common.cc22
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-config.hh9
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-coretext.cc50
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-debug.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc264
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-draw.cc2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-face.cc102
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-font.cc79
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ft.cc24
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-gdi.cc6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-gobject-structs.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc13
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-iter.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-machinery.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-map.cc2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-map.hh24
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-meta.hh31
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ms-feature-ranges.cc177
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ms-feature-ranges.hh96
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-mutex.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-null.hh20
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-object.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-open-file.hh68
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-open-type.hh146
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh7
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh186
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-color-cbdt-table.hh14
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-color-colr-table.hh890
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-color-colrv1-closure.hh101
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-color-cpal-table.hh120
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-color-sbix-table.hh10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-color-svg-table.hh4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-gasp-table.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-glyf-table.hh140
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh36
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh641
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh42
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh622
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh322
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh608
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh32
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc184
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh3
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc11
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh44
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-maxp-table.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-meta-table.hh4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-name-table.hh17
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh25
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-post-table-v2subset.hh114
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh36
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic-fallback.hh12
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-hangul.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc14
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-khmer.cc7
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc3
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-syllabic.cc5
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-syllabic.hh3
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-machine.hh4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use.cc9
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-fallback.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc71
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape.hh1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh9
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh14
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh42
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-vorg-table.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-pool.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh151
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-repacker.hh769
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-sanitize.hh4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-serialize.hh131
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-set.cc37
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-set.h3
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-set.hh168
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc16
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-shape-plan.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-shape.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-shaper.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-static.cc1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc12
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh13
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc14
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc453
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-input.hh10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc349
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh25
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset.cc235
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset.h126
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-unicode-emoji-table.hh64
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-unicode.cc2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-unicode.hh11
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc237
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-vector.hh11
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-version.h4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb.hh19
-rw-r--r--src/3rdparty/harfbuzz-ng/src/main.cc12
-rw-r--r--src/3rdparty/harfbuzz-ng/src/test-buffer-serialize.cc5
-rw-r--r--src/3rdparty/harfbuzz-ng/src/test-gpos-size-params.cc5
-rw-r--r--src/3rdparty/harfbuzz-ng/src/test-gsub-would-substitute.cc5
-rw-r--r--src/3rdparty/harfbuzz-ng/src/test-ot-glyphname.cc5
-rw-r--r--src/3rdparty/harfbuzz-ng/src/test-ot-meta.cc5
-rw-r--r--src/3rdparty/harfbuzz-ng/src/test-ot-name.cc5
-rw-r--r--src/3rdparty/harfbuzz-ng/src/test-priority-queue.cc89
-rw-r--r--src/3rdparty/harfbuzz-ng/src/test-repacker.cc485
-rw-r--r--src/3rdparty/harfbuzz-ng/src/test.cc5
144 files changed, 7313 insertions, 2295 deletions
diff --git a/src/3rdparty/harfbuzz-ng/CMakeLists.txt b/src/3rdparty/harfbuzz-ng/CMakeLists.txt
index 966cc09d36..45eeb89f6b 100644
--- a/src/3rdparty/harfbuzz-ng/CMakeLists.txt
+++ b/src/3rdparty/harfbuzz-ng/CMakeLists.txt
@@ -34,6 +34,8 @@ qt_internal_add_3rdparty_library(BundledHarfbuzz
src/hb-object.hh
src/hb-open-file.hh
src/hb-open-type.hh
+ src/hb-priority-queue.hh
+ src/hb-repacker.hh
src/hb-set.cc src/hb-set.h src/hb-set.hh
src/hb-set-digest.hh
src/hb-shape.cc src/hb-shape.h
@@ -105,6 +107,7 @@ qt_internal_extend_target(BundledHarfbuzz CONDITION TRUE # special case
src/hb-ot-cmap-table.hh
src/hb-ot-color.cc
src/hb-ot-color-cbdt-table.hh
+ src/hb-ot-color-colrv1-closure.hh
src/hb-ot-face.cc
src/hb-ot-font.cc src/hb-ot-font.h
src/hb-ot-glyf-table.hh
@@ -128,6 +131,7 @@ qt_internal_extend_target(BundledHarfbuzz CONDITION TRUE # special case
src/hb-ot-os2-table.hh
src/hb-ot-post-macroman.hh
src/hb-ot-post-table.hh
+ src/hb-ot-post-table-v2subset.hh
src/hb-ot-shape.cc src/hb-ot-shape.h src/hb-ot-shape.hh
src/hb-ot-shape-complex-arabic.cc src/hb-ot-shape-complex-arabic.hh
src/hb-ot-shape-complex-arabic-fallback.hh
diff --git a/src/3rdparty/harfbuzz-ng/COPYING b/src/3rdparty/harfbuzz-ng/COPYING
index 57343164f2..48d1b30f90 100644
--- a/src/3rdparty/harfbuzz-ng/COPYING
+++ b/src/3rdparty/harfbuzz-ng/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
diff --git a/src/3rdparty/harfbuzz-ng/NEWS b/src/3rdparty/harfbuzz-ng/NEWS
index 321c550188..2d3e6a6e3f 100644
--- a/src/3rdparty/harfbuzz-ng/NEWS
+++ b/src/3rdparty/harfbuzz-ng/NEWS
@@ -1,3 +1,48 @@
+Overview of changes leading to 2.9.0
+Wednesday, August 18, 2021
+History Repeats Itself (Afghanistan)
+====================================
+- Subsetter API is being stabilized, with the first stable API to happen in
+ 3.0.0 release (https://github.com/harfbuzz/harfbuzz/issues/3078).
+- Support multiple variation axes with same tag, aka HOI.
+- The “coretext” testing shaper now passes font variations to CoreText.
+- hb-shape/hb-view does not break line at new lines unless text is read from
+ file.
+- hb-view and hb-subset has a --batch now, similar to hb-shape.
+- The --batch mode now uses ; as argument separator instead of : used previously.
+- The --batch in hb-shape does not expect 0th argument anymore. That is, the
+ lines read are interpreted as argv[1:], instead of argv[0:].
+- The --batch option has been undocumented. We are ready to document it; send
+ feedback if you find it useful.
+- hb-subset got arguments revamps. Added much-requested --gids-file, --glyphs,
+ --glyphs-file, --unicodes-file, supporting ranges in --unicodes.
+- Various bug fixes.
+
+Overview of changes leading to 2.8.2
+Tuesday, July 8, 2021
+====================================
+- Shaping LTR digits for RTL scripts now makes the native direction of the
+ digits LTR, applying shaping and positioning rules on the same glyph order as
+ Uniscribe. (Jonathan Kew, Khaled Hosny).
+- Subsetting COLR v1 and CPAL tables is now supported. (Garret Rieger, Qunxin Liu)
+- Various fixes and improvements to the subsetter. (Garret Rieger, Qunxin Liu, Behdad)
+- When applying morx table, mark glyph widths should not be zeroed. (Jonathan Kew)
+- GPOS is preferred over kerx, if GSUB was applied. (Behdad)
+- Regional_Indicator pairs are grouped together when clustering. (Behdad)
+- New API:
++hb_blob_create_or_fail()
++hb_blob_create_from_file_or_fail()
++hb_set_copy()
+
+Overview of changes leading to 2.8.1
+Tuesday, May 4, 2021
+====================================
+- Subsetter now fully supports GSUB/GPOS/GDEF tables (including variations); as
+ such, layout tables are retained by subsetter by default. (Garret Rieger, Qunxin Liu)
+- Build scripts no longer check for FontConfig as HarfBuzz does not use it.
+- hb-view supports iTerm2 and kitty inline image protocols (Khaled Hosny),
+ it can also use Chafa for terminal graphics if available (Hans Petter Jansson).
+
Overview of changes leading to 2.8.0
Tuesday, March 16, 2021
====================================
diff --git a/src/3rdparty/harfbuzz-ng/README.md b/src/3rdparty/harfbuzz-ng/README.md
index 0df556de37..9deb32c1e8 100644
--- a/src/3rdparty/harfbuzz-ng/README.md
+++ b/src/3rdparty/harfbuzz-ng/README.md
@@ -1,9 +1,9 @@
[![Linux CI Status](https://github.com/harfbuzz/harfbuzz/workflows/linux-ci/badge.svg)](https://github.com/harfbuzz/harfbuzz/workflows/linux-ci/badge.svg)
-[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master)
+[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main)
[![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html)
[![Coverity Code Health](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/behdad-harfbuzz)
[![Codacy Code Health](https://api.codacy.com/project/badge/Grade/f17f1708783c447488bc8dd317150eaa)](https://app.codacy.com/app/behdad/harfbuzz)
-[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/master/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
+[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/main/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
[![Coverals Code Coverage](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz)
[![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions)
[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
diff --git a/src/3rdparty/harfbuzz-ng/qt_attribution.json b/src/3rdparty/harfbuzz-ng/qt_attribution.json
index 96808bf35d..a8d24696c0 100644
--- a/src/3rdparty/harfbuzz-ng/qt_attribution.json
+++ b/src/3rdparty/harfbuzz-ng/qt_attribution.json
@@ -6,7 +6,7 @@
"Description": "HarfBuzz is an OpenType text shaping engine.",
"Homepage": "http://harfbuzz.org",
- "Version": "2.8.0",
+ "Version": "2.9.0",
"License": "MIT License",
"LicenseId": "MIT",
diff --git a/src/3rdparty/harfbuzz-ng/src/harfbuzz.cc b/src/3rdparty/harfbuzz-ng/src/harfbuzz.cc
index fe00100974..14ee6f5e8a 100644
--- a/src/3rdparty/harfbuzz-ng/src/harfbuzz.cc
+++ b/src/3rdparty/harfbuzz-ng/src/harfbuzz.cc
@@ -9,6 +9,7 @@
#include "hb-fallback-shape.cc"
#include "hb-font.cc"
#include "hb-map.cc"
+#include "hb-ms-feature-ranges.cc"
#include "hb-number.cc"
#include "hb-ot-cff1-table.cc"
#include "hb-ot-cff2-table.cc"
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-ankr-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-ankr-table.hh
index f2785a6f58..63fac84524 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-ankr-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh
index 98ed20d8eb..e70ce97174 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh
+++ b/src/3rdparty/harfbuzz-ng/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;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-feat-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-feat-table.hh
index 359e859cfc..573f0cf9f6 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-feat-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-just-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-just-table.hh
index 49506e9f5a..556d4ad75b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-just-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh
index 1cd412164e..d0eacf0e61 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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);
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh
index e3bc268d26..a807bdcfc5 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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;
}
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-opbd-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-opbd-table.hh
index 8c04a6482f..b1a1512821 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-opbd-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-trak-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-trak-table.hh
index baa1c72020..68bcb2396f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-trak-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc
index 0e9f2b4954..e2d4de2ccd 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc
+++ b/src/3rdparty/harfbuzz-ng/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");
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-ltag-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-ltag-table.hh
index 711f9aa6c1..6d771e1513 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-ltag-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-algs.hh b/src/3rdparty/harfbuzz-ng/src/hb-algs.hh
index bc170b0546..57b87b05ca 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-algs.hh
+++ b/src/3rdparty/harfbuzz-ng/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)
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-array.hh b/src/3rdparty/harfbuzz-ng/src/hb-array.hh
index 02bd8d81c2..ab0dd6ebe3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-array.hh
+++ b/src/3rdparty/harfbuzz-ng/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;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bimap.hh b/src/3rdparty/harfbuzz-ng/src/hb-bimap.hh
index e9f3a6a52d..d409880751 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-bimap.hh
+++ b/src/3rdparty/harfbuzz-ng/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); }
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-blob.cc b/src/3rdparty/harfbuzz-ng/src/hb-blob.cc
index 71b1b1fc4f..f120002d17 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-blob.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-blob.cc
@@ -72,14 +72,52 @@ hb_blob_create (const char *data,
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 */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-blob.h b/src/3rdparty/harfbuzz-ng/src/hb-blob.h
index 86f12788d2..203f9e19dd 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-blob.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-blob.h
@@ -91,8 +91,18 @@ hb_blob_create (const char *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
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-blob.hh b/src/3rdparty/harfbuzz-ng/src/hb-blob.hh
index b03dfc1380..a3683a681e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-blob.hh
+++ b/src/3rdparty/harfbuzz-ng/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;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc b/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
index 8cad6ab8e6..13fe11f181 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
+++ b/src/3rdparty/harfbuzz-ng/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))
@@ -282,21 +283,12 @@ 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;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh b/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh
index 8b432b5f96..8635ebd35f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh
+++ b/src/3rdparty/harfbuzz-ng/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
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cache.hh b/src/3rdparty/harfbuzz-ng/src/hb-cache.hh
index bf26d96be4..e617b75de9 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cache.hh
+++ b/src/3rdparty/harfbuzz-ng/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
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-common.hh
index 91a9b7d0d1..c251e2d0ed 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-common.hh
+++ b/src/3rdparty/harfbuzz-ng/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>
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh b/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh
index 332ece31cd..d961566447 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh
+++ b/src/3rdparty/harfbuzz-ng/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;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-common.cc b/src/3rdparty/harfbuzz-ng/src/hb-common.cc
index 7bb878b217..cbba1a7942 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-common.cc
+++ b/src/3rdparty/harfbuzz-ng/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,11 +272,11 @@ 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;
@@ -294,7 +292,7 @@ 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;
}
}
@@ -311,21 +309,21 @@ 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;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-config.hh b/src/3rdparty/harfbuzz-ng/src/hb-config.hh
index fc8d424bfb..ad800f0f74 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-config.hh
+++ b/src/3rdparty/harfbuzz-ng/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 */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc b/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc
index 461bd20e65..4b6c67c1ee 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc
+++ b/src/3rdparty/harfbuzz-ng/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++;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-debug.hh b/src/3rdparty/harfbuzz-ng/src/hb-debug.hh
index ec3a1ff211..f80c8980ba 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-debug.hh
+++ b/src/3rdparty/harfbuzz-ng/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 + \
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc b/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc
index a07302159c..8f6d73b639 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc
+++ b/src/3rdparty/harfbuzz-ng/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;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-draw.cc b/src/3rdparty/harfbuzz-ng/src/hb-draw.cc
index 1a5f9c8c6b..c0af6ce013 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-draw.cc
+++ b/src/3rdparty/harfbuzz-ng/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);
}
/**
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-face.cc b/src/3rdparty/harfbuzz-ng/src/hb-face.cc
index 61bd4af7b1..2c0087370c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-face.cc
+++ b/src/3rdparty/harfbuzz-ng/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;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-font.cc b/src/3rdparty/harfbuzz-ng/src/hb-font.cc
index 37a0e7fe85..fa8da96395 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-font.cc
+++ b/src/3rdparty/harfbuzz-ng/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;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ft.cc b/src/3rdparty/harfbuzz-ng/src/hb-ft.cc
index b82c1a67bd..a6beb9f0fe 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ft.cc
+++ b/src/3rdparty/harfbuzz-ng/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);
}
/**
@@ -642,20 +642,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 +846,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 +866,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
@@ -1020,13 +1020,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
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-gdi.cc b/src/3rdparty/harfbuzz-ng/src/hb-gdi.cc
index dc4659c7f6..8e7589beac 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-gdi.cc
+++ b/src/3rdparty/harfbuzz-ng/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:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-gobject-structs.cc b/src/3rdparty/harfbuzz-ng/src/hb-gobject-structs.cc
index 7c46e26400..540b11f911 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-gobject-structs.cc
+++ b/src/3rdparty/harfbuzz-ng/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)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc b/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc
index 9dafe654c8..209207f1e5 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc
+++ b/src/3rdparty/harfbuzz-ng/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);
}
/**
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-iter.hh b/src/3rdparty/harfbuzz-ng/src/hb-iter.hh
index f7018150e4..b8c4472636 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-iter.hh
+++ b/src/3rdparty/harfbuzz-ng/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
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh b/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh
index 3bd5a979b0..010c2570d7 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh
+++ b/src/3rdparty/harfbuzz-ng/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:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-map.cc b/src/3rdparty/harfbuzz-ng/src/hb-map.cc
index f115da2bb8..6757535b79 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-map.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-map.cc
@@ -109,7 +109,7 @@ hb_map_destroy (hb_map_t *map)
map->fini_shallow ();
- free (map);
+ hb_free (map);
}
/**
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-map.hh b/src/3rdparty/harfbuzz-ng/src/hb-map.hh
index 84fe1d549b..751cab6844 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-map.hh
+++ b/src/3rdparty/harfbuzz-ng/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
@@ -211,20 +211,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 +235,8 @@ struct hb_hashmap_t
occupancy++;
if (!items[i].is_tombstone ())
population++;
+
+ return true;
}
unsigned int bucket_for (K key) const
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-meta.hh b/src/3rdparty/harfbuzz-ng/src/hb-meta.hh
index e40d9fd178..a714bc2bf0 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-meta.hh
+++ b/src/3rdparty/harfbuzz-ng/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> {};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ms-feature-ranges.cc b/src/3rdparty/harfbuzz-ng/src/hb-ms-feature-ranges.cc
new file mode 100644
index 0000000000..6d09b252d8
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/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;
+ }
+}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ms-feature-ranges.hh b/src/3rdparty/harfbuzz-ng/src/hb-ms-feature-ranges.hh
new file mode 100644
index 0000000000..401d1e1d97
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/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 */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-mutex.hh b/src/3rdparty/harfbuzz-ng/src/hb-mutex.hh
index 2fc8d7ee58..a9227a741d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-mutex.hh
+++ b/src/3rdparty/harfbuzz-ng/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;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-null.hh b/src/3rdparty/harfbuzz-ng/src/hb-null.hh
index d09f858cde..db38a4dfd2 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-null.hh
+++ b/src/3rdparty/harfbuzz-ng/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()
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-object.hh b/src/3rdparty/harfbuzz-ng/src/hb-object.hh
index f3048b1c3e..64abb0ce13 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-object.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-object.hh
@@ -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;
@@ -284,7 +284,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;
}
}
@@ -303,14 +303,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;
}
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-open-file.hh b/src/3rdparty/harfbuzz-ng/src/hb-open-file.hh
index 54c07ff13c..6eee5827c1 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-open-file.hh
+++ b/src/3rdparty/harfbuzz-ng/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));
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh b/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh
index dc0ae1d989..49653ce97e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh
+++ b/src/3rdparty/harfbuzz-ng/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
*/
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh
index 864a27f458..eaaf5e12ec 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh
+++ b/src/3rdparty/harfbuzz-ng/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))))
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh
index 7228f77727..5dd183e3a0 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh
index 878e02ff17..7593bf5858 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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++)
@@ -253,7 +259,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 +282,9 @@ 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;
+ if (unlikely (!c->check_assign(this->length,
+ c->length () - table_initpos,
+ 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 +293,11 @@ struct CmapSubtableFormat4
: 0;
}
+ unsigned get_language () const
+ {
+ return language;
+ }
+
struct accelerator_t
{
accelerator_t () {}
@@ -547,6 +560,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 +625,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 +694,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 +715,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 +808,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 +874,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 +902,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 +1065,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 +1082,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 +1099,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 +1135,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 +1205,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 +1260,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 +1377,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);
@@ -1364,44 +1403,77 @@ struct cmap
for (const EncodingRecord& _ : encodingrec_iter)
{
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 (format == 4) c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx);
+ else if (format == 12)
{
- 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);
+ 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);
}
- /* when --gids option is not used, we iterate input unicodes instead of
- * all codepoints in each subtable, which is more efficient */
- else
- {
- hb_set_t unicodes_set;
- (base+_.subtable).collect_unicodes (&unicodes_set);
+ 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);
+ }
+
+ 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;
+ }
- 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);
+ 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,
@@ -1697,7 +1769,7 @@ struct cmap
protected:
HBUINT16 version; /* Table version number (0). */
- SortedArrayOf<EncodingRecord>
+ SortedArray16Of<EncodingRecord>
encodingRecord; /* Encoding tables. */
public:
DEFINE_SIZE_ARRAY (4, encodingRecord);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-color-cbdt-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-color-cbdt-table.hh
index e285acec3d..6c31d1b53e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-color-cbdt-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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);
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-color-colr-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-color-colr-table.hh
index e2a1ff4662..007ff3f47b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-color-colr-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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 */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-color-colrv1-closure.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-color-colrv1-closure.hh
new file mode 100644
index 0000000000..4124efe0b1
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/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 */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-color-cpal-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-color-cpal-table.hh
index fa7d3207be..9ee4bafb2a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-color-cpal-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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,39 @@ 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.serialize_copy (c, paletteFlagsZ, base, 0, hb_serialize_context_t::Head, palette_count);
+ 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 +119,15 @@ struct CPALV1Tail
}
protected:
- LNNOffsetTo<UnsizedArrayOf<HBUINT32>>
+ 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 +189,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 +283,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>
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-color-sbix-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-color-sbix-table.hh
index 09da11597d..d2911f19e6 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-color-sbix-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-color-svg-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-color-svg-table.hh
index 1cc40ae53f..e022ef43b7 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-color-svg-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh
index 367e143fdf..ffbbb1bc53 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh
+++ b/src/3rdparty/harfbuzz-ng/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. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-gasp-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-gasp-table.hh
index 4f291924af..f2a9cad464 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-gasp-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-glyf-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-glyf-table.hh
index 5352156f02..ff7b9b2d25 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-glyf-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh
index c9c391bad5..dea2b7e29a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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 ());
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh
index d06c0fa4a4..4038329938 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh
index 4df0d942ce..492947751e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh
index 0ba7e3c061..65f499a00d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh
@@ -88,12 +88,66 @@ static inline void ClassDef_serialize (hb_serialize_context_t *c,
Iterator it);
static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
- const hb_set_t &glyphset,
const hb_map_t &gid_klass_map,
hb_sorted_vector_t<HBGlyphID> &glyphs,
const hb_set_t &klasses,
+ bool use_class_zero,
hb_map_t *klass_map /*INOUT*/);
+
+struct hb_prune_langsys_context_t
+{
+ hb_prune_langsys_context_t (const void *table_,
+ hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *script_langsys_map_,
+ const hb_map_t *duplicate_feature_map_,
+ hb_set_t *new_collected_feature_indexes_)
+ :table (table_),
+ script_langsys_map (script_langsys_map_),
+ duplicate_feature_map (duplicate_feature_map_),
+ new_feature_indexes (new_collected_feature_indexes_),
+ script_count (0),langsys_count (0) {}
+
+ bool visitedScript (const void *s)
+ {
+ if (script_count++ > HB_MAX_SCRIPTS)
+ return true;
+
+ return visited (s, visited_script);
+ }
+
+ bool visitedLangsys (const void *l)
+ {
+ if (langsys_count++ > HB_MAX_LANGSYS)
+ return true;
+
+ return visited (l, visited_langsys);
+ }
+
+ private:
+ template <typename T>
+ bool visited (const T *p, hb_set_t &visited_set)
+ {
+ hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) p - (uintptr_t) table);
+ if (visited_set.has (delta))
+ return true;
+
+ visited_set.add (delta);
+ return false;
+ }
+
+ public:
+ const void *table;
+ hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *script_langsys_map;
+ const hb_map_t *duplicate_feature_map;
+ hb_set_t *new_feature_indexes;
+
+ private:
+ hb_set_t visited_script;
+ hb_set_t visited_langsys;
+ unsigned script_count;
+ unsigned langsys_count;
+};
+
struct hb_subset_layout_context_t :
hb_dispatch_context_t<hb_subset_layout_context_t, hb_empty_t, HB_DEBUG_SUBSET>
{
@@ -125,16 +179,21 @@ struct hb_subset_layout_context_t :
hb_subset_context_t *subset_context;
const hb_tag_t table_tag;
const hb_map_t *lookup_index_map;
+ const hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *script_langsys_map;
const hb_map_t *feature_index_map;
+ unsigned cur_script_index;
hb_subset_layout_context_t (hb_subset_context_t *c_,
hb_tag_t tag_,
hb_map_t *lookup_map_,
- hb_map_t *feature_map_) :
+ hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *script_langsys_map_,
+ hb_map_t *feature_index_map_) :
subset_context (c_),
table_tag (tag_),
lookup_index_map (lookup_map_),
- feature_index_map (feature_map_),
+ script_langsys_map (script_langsys_map_),
+ feature_index_map (feature_index_map_),
+ cur_script_index (0xFFFFu),
script_count (0),
langsys_count (0),
feature_index_count (0),
@@ -325,7 +384,7 @@ struct Record
}
Tag tag; /* 4-byte Tag identifier */
- OffsetTo<Type>
+ Offset16To<Type>
offset; /* Offset from beginning of object holding
* the Record */
public:
@@ -333,11 +392,11 @@ struct Record
};
template <typename Type>
-struct RecordArrayOf : SortedArrayOf<Record<Type>>
+struct RecordArrayOf : SortedArray16Of<Record<Type>>
{
- const OffsetTo<Type>& get_offset (unsigned int i) const
+ const Offset16To<Type>& get_offset (unsigned int i) const
{ return (*this)[i].offset; }
- OffsetTo<Type>& get_offset (unsigned int i)
+ Offset16To<Type>& get_offset (unsigned int i)
{ return (*this)[i].offset; }
const Tag& get_tag (unsigned int i) const
{ return (*this)[i].tag; }
@@ -356,7 +415,7 @@ struct RecordArrayOf : SortedArrayOf<Record<Type>>
}
bool find_index (hb_tag_t tag, unsigned int *index) const
{
- return this->bfind (tag, index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
+ return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
}
};
@@ -407,6 +466,30 @@ struct RecordListOfFeature : RecordListOf<Feature>
}
};
+struct Script;
+struct RecordListOfScript : RecordListOf<Script>
+{
+ bool subset (hb_subset_context_t *c,
+ hb_subset_layout_context_t *l) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ unsigned count = this->len;
+ for (auto _ : + hb_zip (*this, hb_range (count)))
+ {
+ auto snap = c->serializer->snapshot ();
+ l->cur_script_index = _.second;
+ bool ret = _.first.subset (l, this);
+ if (!ret) c->serializer->revert (snap);
+ else out->len++;
+ }
+
+ return_trace (true);
+ }
+};
+
struct RangeRecord
{
int cmp (hb_codepoint_t g) const
@@ -434,7 +517,7 @@ struct RangeRecord
DECLARE_NULL_NAMESPACE_BYTES (OT, RangeRecord);
-struct IndexArray : ArrayOf<Index>
+struct IndexArray : Array16Of<Index>
{
bool intersects (const hb_map_t *indexes) const
{ return hb_any (*this, indexes); }
@@ -474,7 +557,7 @@ struct IndexArray : ArrayOf<Index>
void add_indexes_to (hb_set_t* output /* OUT */) const
{
- output->add_array (arrayZ, len);
+ output->add_array (as_array ());
}
};
@@ -506,18 +589,46 @@ struct LangSys
return_trace (c->embed (*this));
}
- bool operator == (const LangSys& o) const
+ bool compare (const LangSys& o, const hb_map_t *feature_index_map) const
{
- if (featureIndex.len != o.featureIndex.len ||
- reqFeatureIndex != o.reqFeatureIndex)
+ if (reqFeatureIndex != o.reqFeatureIndex)
+ return false;
+
+ auto iter =
+ + hb_iter (featureIndex)
+ | hb_filter (feature_index_map)
+ | hb_map (feature_index_map)
+ ;
+
+ auto o_iter =
+ + hb_iter (o.featureIndex)
+ | hb_filter (feature_index_map)
+ | hb_map (feature_index_map)
+ ;
+
+ if (iter.len () != o_iter.len ())
return false;
- for (const auto _ : + hb_zip (featureIndex, o.featureIndex))
+ for (const auto _ : + hb_zip (iter, o_iter))
if (_.first != _.second) return false;
return true;
}
+ void collect_features (hb_prune_langsys_context_t *c) const
+ {
+ if (!has_required_feature () && !get_feature_count ()) return;
+ if (c->visitedLangsys (this)) return;
+ if (has_required_feature () &&
+ c->duplicate_feature_map->has (reqFeatureIndex))
+ c->new_feature_indexes->add (get_required_feature_index ());
+
+ + hb_iter (featureIndex)
+ | hb_filter (c->duplicate_feature_map)
+ | hb_sink (c->new_feature_indexes)
+ ;
+ }
+
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l,
const Tag *tag = nullptr) const
@@ -581,6 +692,49 @@ struct Script
bool has_default_lang_sys () const { return defaultLangSys != 0; }
const LangSys& get_default_lang_sys () const { return this+defaultLangSys; }
+ void prune_langsys (hb_prune_langsys_context_t *c,
+ unsigned script_index) const
+ {
+ if (!has_default_lang_sys () && !get_lang_sys_count ()) return;
+ if (c->visitedScript (this)) return;
+
+ if (!c->script_langsys_map->has (script_index))
+ {
+ hb_set_t* empty_set = hb_set_create ();
+ if (unlikely (!c->script_langsys_map->set (script_index, empty_set)))
+ {
+ hb_set_destroy (empty_set);
+ return;
+ }
+ }
+
+ unsigned langsys_count = get_lang_sys_count ();
+ if (has_default_lang_sys ())
+ {
+ //only collect features from non-redundant langsys
+ const LangSys& d = get_default_lang_sys ();
+ d.collect_features (c);
+
+ for (auto _ : + hb_zip (langSys, hb_range (langsys_count)))
+ {
+ const LangSys& l = this+_.first.offset;
+ if (l.compare (d, c->duplicate_feature_map)) continue;
+
+ l.collect_features (c);
+ c->script_langsys_map->get (script_index)->add (_.second);
+ }
+ }
+ else
+ {
+ for (auto _ : + hb_zip (langSys, hb_range (langsys_count)))
+ {
+ const LangSys& l = this+_.first.offset;
+ l.collect_features (c);
+ c->script_langsys_map->get (script_index)->add (_.second);
+ }
+ }
+ }
+
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l,
const Tag *tag) const
@@ -609,16 +763,17 @@ struct Script
}
}
- + langSys.iter ()
- | hb_filter ([=] (const Record<LangSys>& record) {return l->visitLangSys (); })
- | hb_filter ([&] (const Record<LangSys>& record)
- {
- const LangSys& d = this+defaultLangSys;
- const LangSys& l = this+record.offset;
- return !(l == d);
- })
- | hb_apply (subset_record_array (l, &(out->langSys), this))
- ;
+ const hb_set_t *active_langsys = l->script_langsys_map->get (l->cur_script_index);
+ if (active_langsys)
+ {
+ unsigned count = langSys.len;
+ + hb_zip (langSys, hb_range (count))
+ | hb_filter (active_langsys, hb_second)
+ | hb_map (hb_first)
+ | hb_filter ([=] (const Record<LangSys>& record) {return l->visitLangSys (); })
+ | hb_apply (subset_record_array (l, &(out->langSys), this))
+ ;
+ }
return_trace (bool (out->langSys.len) || defaultLang || l->table_tag == HB_OT_TAG_GSUB);
}
@@ -631,7 +786,7 @@ struct Script
}
protected:
- OffsetTo<LangSys>
+ Offset16To<LangSys>
defaultLangSys; /* Offset to DefaultLangSys table--from
* beginning of Script table--may be Null */
RecordArrayOf<LangSys>
@@ -641,7 +796,7 @@ struct Script
DEFINE_SIZE_ARRAY_SIZED (4, langSys);
};
-typedef RecordListOf<Script> ScriptList;
+typedef RecordListOfScript ScriptList;
/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
@@ -856,7 +1011,7 @@ struct FeatureParamsCharacterVariants
* user-interface labels for the
* feature parameters. (Must be zero
* if numParameters is zero.) */
- ArrayOf<HBUINT24>
+ Array16Of<HBUINT24>
characters; /* Array of the Unicode Scalar Value
* of the characters for which this
* feature provides glyph variants.
@@ -953,7 +1108,7 @@ struct Feature
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
- bool subset_featureParams = out->featureParams.serialize_subset (c, featureParams, this, tag);
+ out->featureParams.serialize_subset (c, featureParams, this, tag);
auto it =
+ hb_iter (lookupIndex)
@@ -962,8 +1117,9 @@ struct Feature
;
out->lookupIndex.serialize (c->serializer, l, it);
- return_trace (bool (it) || subset_featureParams
- || (tag && *tag == HB_TAG ('p', 'r', 'e', 'f')));
+ // The decision to keep or drop this feature is already made before we get here
+ // so always retain it.
+ return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c,
@@ -998,7 +1154,7 @@ struct Feature
unsigned int new_offset_int = orig_offset -
(((char *) this) - ((char *) closure->list_base));
- OffsetTo<FeatureParams> new_offset;
+ Offset16To<FeatureParams> new_offset;
/* Check that it would not overflow. */
new_offset = new_offset_int;
if (new_offset == new_offset_int &&
@@ -1010,7 +1166,7 @@ struct Feature
return_trace (true);
}
- OffsetTo<FeatureParams>
+ Offset16To<FeatureParams>
featureParams; /* Offset to Feature Parameters table (if one
* has been defined for the feature), relative
* to the beginning of the Feature Table; = Null
@@ -1049,11 +1205,11 @@ struct Lookup
unsigned int get_subtable_count () const { return subTable.len; }
template <typename TSubTable>
- const OffsetArrayOf<TSubTable>& get_subtables () const
- { return reinterpret_cast<const OffsetArrayOf<TSubTable> &> (subTable); }
+ const Array16OfOffset16To<TSubTable>& get_subtables () const
+ { return reinterpret_cast<const Array16OfOffset16To<TSubTable> &> (subTable); }
template <typename TSubTable>
- OffsetArrayOf<TSubTable>& get_subtables ()
- { return reinterpret_cast<OffsetArrayOf<TSubTable> &> (subTable); }
+ Array16OfOffset16To<TSubTable>& get_subtables ()
+ { return reinterpret_cast<Array16OfOffset16To<TSubTable> &> (subTable); }
template <typename TSubTable>
const TSubTable& get_subtable (unsigned int i) const
@@ -1106,13 +1262,13 @@ struct Lookup
unsigned int num_subtables)
{
TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (*this))) return_trace (false);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
lookupType = lookup_type;
lookupFlag = lookup_props & 0xFFFFu;
if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
if (lookupFlag & LookupFlag::UseMarkFilteringSet)
{
- if (unlikely (!c->extend (*this))) return_trace (false);
+ if (unlikely (!c->extend (this))) return_trace (false);
HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
markFilteringSet = lookup_props >> 16;
}
@@ -1131,10 +1287,18 @@ struct Lookup
const hb_set_t *glyphset = c->plan->glyphset_gsub ();
unsigned int lookup_type = get_type ();
+ hb_iter (get_subtables <TSubTable> ())
- | hb_filter ([this, glyphset, lookup_type] (const OffsetTo<TSubTable> &_) { return (this+_).intersects (glyphset, lookup_type); })
+ | hb_filter ([this, glyphset, lookup_type] (const Offset16To<TSubTable> &_) { return (this+_).intersects (glyphset, lookup_type); })
| hb_apply (subset_offset_array (c, out->get_subtables<TSubTable> (), this, lookup_type))
;
+ if (lookupFlag & LookupFlag::UseMarkFilteringSet)
+ {
+ if (unlikely (!c->serializer->extend (out))) return_trace (false);
+ const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
+ HBUINT16 &outMarkFilteringSet = StructAfter<HBUINT16> (out->subTable);
+ outMarkFilteringSet = markFilteringSet;
+ }
+
return_trace (true);
}
@@ -1179,7 +1343,7 @@ struct Lookup
private:
HBUINT16 lookupType; /* Different enumerations for GSUB and GPOS */
HBUINT16 lookupFlag; /* Lookup qualifiers */
- ArrayOf<Offset16>
+ Array16Of<Offset16>
subTable; /* Array of SubTables */
/*HBUINT16 markFilteringSetX[HB_VAR_ARRAY];*//* Index (base 0) into GDEF mark glyph sets
* structure. This field is only present if bit
@@ -1188,10 +1352,10 @@ struct Lookup
DEFINE_SIZE_ARRAY (6, subTable);
};
-typedef OffsetListOf<Lookup> LookupList;
+typedef List16OfOffset16To<Lookup> LookupList;
template <typename TLookup>
-struct LookupOffsetList : OffsetListOf<TLookup>
+struct LookupOffsetList : List16OfOffset16To<TLookup>
{
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l) const
@@ -1212,7 +1376,7 @@ struct LookupOffsetList : OffsetListOf<TLookup>
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (OffsetListOf<TLookup>::sanitize (c, this));
+ return_trace (List16OfOffset16To<TLookup>::sanitize (c, this));
}
};
@@ -1229,7 +1393,7 @@ struct CoverageFormat1
unsigned int get_coverage (hb_codepoint_t glyph_id) const
{
unsigned int i;
- glyphArray.bfind (glyph_id, &i, HB_BFIND_NOT_FOUND_STORE, NOT_COVERED);
+ glyphArray.bfind (glyph_id, &i, HB_NOT_FOUND_STORE, NOT_COVERED);
return i;
}
@@ -1250,19 +1414,25 @@ struct CoverageFormat1
bool intersects (const hb_set_t *glyphs) const
{
/* TODO Speed up, using hb_set_next() and bsearch()? */
- unsigned int count = glyphArray.len;
- const HBGlyphID *arr = glyphArray.arrayZ;
- for (unsigned int i = 0; i < count; i++)
- if (glyphs->has (arr[i]))
+ for (const auto& g : glyphArray.as_array ())
+ if (glyphs->has (g))
return true;
return false;
}
bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
{ return glyphs->has (glyphArray[index]); }
+ void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *intersect_glyphs) const
+ {
+ unsigned count = glyphArray.len;
+ for (unsigned i = 0; i < count; i++)
+ if (glyphs->has (glyphArray[i]))
+ intersect_glyphs->add (glyphArray[i]);
+ }
+
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
- { return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len); }
+ { return glyphs->add_sorted_array (glyphArray.as_array ()); }
public:
/* Older compilers need this to be public. */
@@ -1284,7 +1454,7 @@ struct CoverageFormat1
protected:
HBUINT16 coverageFormat; /* Format identifier--format = 1 */
- SortedArrayOf<HBGlyphID>
+ SortedArray16Of<HBGlyphID>
glyphArray; /* Array of GlyphIDs--in numerical order */
public:
DEFINE_SIZE_ARRAY (4, glyphArray);
@@ -1308,7 +1478,7 @@ struct CoverageFormat2
bool serialize (hb_serialize_context_t *c, Iterator glyphs)
{
TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (*this))) return_trace (false);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!glyphs))
{
@@ -1358,20 +1528,16 @@ struct CoverageFormat2
{
/* TODO Speed up, using hb_set_next() and bsearch()? */
/* TODO(iter) Rewrite as dagger. */
- unsigned count = rangeRecord.len;
- const RangeRecord *arr = rangeRecord.arrayZ;
- for (unsigned i = 0; i < count; i++)
- if (arr[i].intersects (glyphs))
+ for (const auto& range : rangeRecord.as_array ())
+ if (range.intersects (glyphs))
return true;
return false;
}
bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
{
/* TODO(iter) Rewrite as dagger. */
- unsigned count = rangeRecord.len;
- const RangeRecord *arr = rangeRecord.arrayZ;
- for (unsigned i = 0; i < count; i++) {
- const RangeRecord &range = arr[i];
+ for (const auto& range : rangeRecord.as_array ())
+ {
if (range.value <= index &&
index < (unsigned int) range.value + (range.last - range.first) &&
range.intersects (glyphs))
@@ -1382,6 +1548,16 @@ struct CoverageFormat2
return false;
}
+ void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *intersect_glyphs) const
+ {
+ for (const auto& range : rangeRecord.as_array ())
+ {
+ if (!range.intersects (glyphs)) continue;
+ for (hb_codepoint_t g = range.first; g <= range.last; g++)
+ if (glyphs->has (g)) intersect_glyphs->add (g);
+ }
+ }
+
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{
@@ -1448,7 +1624,7 @@ struct CoverageFormat2
protected:
HBUINT16 coverageFormat; /* Format identifier--format = 2 */
- SortedArrayOf<RangeRecord>
+ SortedArray16Of<RangeRecord>
rangeRecord; /* Array of glyph ranges--ordered by
* Start GlyphID. rangeCount entries
* long */
@@ -1481,7 +1657,7 @@ struct Coverage
bool serialize (hb_serialize_context_t *c, Iterator glyphs)
{
TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (*this))) return_trace (false);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
unsigned count = 0;
unsigned num_ranges = 0;
@@ -1564,6 +1740,16 @@ struct Coverage
}
}
+ void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *intersect_glyphs) const
+ {
+ switch (u.format)
+ {
+ case 1: return u.format1.intersected_coverage_glyphs (glyphs, intersect_glyphs);
+ case 2: return u.format2.intersected_coverage_glyphs (glyphs, intersect_glyphs);
+ default:return ;
+ }
+ }
+
struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
{
static constexpr bool is_sorted_iterator = true;
@@ -1645,10 +1831,10 @@ Coverage_serialize (hb_serialize_context_t *c,
{ c->start_embed<Coverage> ()->serialize (c, it); }
static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
- const hb_set_t &glyphset,
const hb_map_t &gid_klass_map,
hb_sorted_vector_t<HBGlyphID> &glyphs,
const hb_set_t &klasses,
+ bool use_class_zero,
hb_map_t *klass_map /*INOUT*/)
{
if (!klass_map)
@@ -1660,7 +1846,7 @@ static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
/* any glyph not assigned a class value falls into Class zero (0),
* if any glyph assigned to class 0, remapping must start with 0->0*/
- if (glyphset.get_population () > gid_klass_map.get_population ())
+ if (!use_class_zero)
klass_map->set (0, 0);
unsigned idx = klass_map->has (0) ? 1 : 0;
@@ -1704,10 +1890,11 @@ struct ClassDefFormat1
Iterator it)
{
TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (*this))) return_trace (false);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!it))
{
+ classFormat = 1;
startGlyph = 0;
classValue.len = 0;
return_trace (true);
@@ -1730,7 +1917,10 @@ struct ClassDefFormat1
}
bool subset (hb_subset_context_t *c,
- hb_map_t *klass_map = nullptr /*OUT*/) const
+ hb_map_t *klass_map = nullptr /*OUT*/,
+ bool keep_empty_table = true,
+ bool use_class_zero = true,
+ const Coverage* glyph_filter = nullptr) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
@@ -1742,9 +1932,12 @@ struct ClassDefFormat1
hb_codepoint_t start = startGlyph;
hb_codepoint_t end = start + classValue.len;
+
for (const hb_codepoint_t gid : + hb_range (start, end)
- | hb_filter (glyphset))
+ | hb_filter (glyphset))
{
+ if (glyph_filter && !glyph_filter->has(gid)) continue;
+
unsigned klass = classValue[gid - start];
if (!klass) continue;
@@ -1753,9 +1946,13 @@ struct ClassDefFormat1
orig_klasses.add (klass);
}
- ClassDef_remap_and_serialize (c->serializer, glyphset, gid_org_klass_map,
- glyphs, orig_klasses, klass_map);
- return_trace ((bool) glyphs);
+ unsigned glyph_count = glyph_filter
+ ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter))
+ : glyphset.get_population ();
+ use_class_zero = use_class_zero && glyph_count <= gid_org_klass_map.get_population ();
+ ClassDef_remap_and_serialize (c->serializer, gid_org_klass_map,
+ glyphs, orig_klasses, use_class_zero, klass_map);
+ return_trace (keep_empty_table || (bool) glyphs);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -1829,10 +2026,28 @@ struct ClassDefFormat1
return false;
}
+ void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const
+ {
+ unsigned count = classValue.len;
+ if (klass == 0)
+ {
+ hb_codepoint_t endGlyph = startGlyph + count -1;
+ for (hb_codepoint_t g : glyphs->iter ())
+ if (g < startGlyph || g > endGlyph)
+ intersect_glyphs->add (g);
+
+ return;
+ }
+
+ for (unsigned i = 0; i < count; i++)
+ if (classValue[i] == klass && glyphs->has (startGlyph + i))
+ intersect_glyphs->add (startGlyph + i);
+ }
+
protected:
HBUINT16 classFormat; /* Format identifier--format = 1 */
HBGlyphID startGlyph; /* First GlyphID of the classValueArray */
- ArrayOf<HBUINT16>
+ Array16Of<HBUINT16>
classValue; /* Array of Class Values--one per GlyphID */
public:
DEFINE_SIZE_ARRAY (6, classValue);
@@ -1854,10 +2069,11 @@ struct ClassDefFormat2
Iterator it)
{
TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (*this))) return_trace (false);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!it))
{
+ classFormat = 2;
rangeRecord.len = 0;
return_trace (true);
}
@@ -1903,7 +2119,10 @@ struct ClassDefFormat2
}
bool subset (hb_subset_context_t *c,
- hb_map_t *klass_map = nullptr /*OUT*/) const
+ hb_map_t *klass_map = nullptr /*OUT*/,
+ bool keep_empty_table = true,
+ bool use_class_zero = true,
+ const Coverage* glyph_filter = nullptr) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
@@ -1923,15 +2142,20 @@ struct ClassDefFormat2
for (hb_codepoint_t g = start; g < end; g++)
{
if (!glyphset.has (g)) continue;
+ if (glyph_filter && !glyph_filter->has (g)) continue;
glyphs.push (glyph_map[g]);
gid_org_klass_map.set (glyph_map[g], klass);
orig_klasses.add (klass);
}
}
- ClassDef_remap_and_serialize (c->serializer, glyphset, gid_org_klass_map,
- glyphs, orig_klasses, klass_map);
- return_trace ((bool) glyphs);
+ unsigned glyph_count = glyph_filter
+ ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter))
+ : glyphset.get_population ();
+ use_class_zero = use_class_zero && glyph_count <= gid_org_klass_map.get_population ();
+ ClassDef_remap_and_serialize (c->serializer, gid_org_klass_map,
+ glyphs, orig_klasses, use_class_zero, klass_map);
+ return_trace (keep_empty_table || (bool) glyphs);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -2005,9 +2229,57 @@ struct ClassDefFormat2
return false;
}
+ void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const
+ {
+ unsigned count = rangeRecord.len;
+ if (klass == 0)
+ {
+ hb_codepoint_t g = HB_SET_VALUE_INVALID;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (!hb_set_next (glyphs, &g))
+ break;
+ while (g != HB_SET_VALUE_INVALID && g < rangeRecord[i].first)
+ {
+ intersect_glyphs->add (g);
+ hb_set_next (glyphs, &g);
+ }
+ g = rangeRecord[i].last;
+ }
+ while (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
+ intersect_glyphs->add (g);
+
+ return;
+ }
+
+ hb_codepoint_t g = HB_SET_VALUE_INVALID;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (rangeRecord[i].value != klass) continue;
+
+ if (g != HB_SET_VALUE_INVALID)
+ {
+ if (g >= rangeRecord[i].first &&
+ g <= rangeRecord[i].last)
+ intersect_glyphs->add (g);
+ if (g > rangeRecord[i].last)
+ continue;
+ }
+
+ g = rangeRecord[i].first - 1;
+ while (hb_set_next (glyphs, &g))
+ {
+ if (g >= rangeRecord[i].first && g <= rangeRecord[i].last)
+ intersect_glyphs->add (g);
+ else if (g > rangeRecord[i].last)
+ break;
+ }
+ }
+ }
+
protected:
HBUINT16 classFormat; /* Format identifier--format = 2 */
- SortedArrayOf<RangeRecord>
+ SortedArray16Of<RangeRecord>
rangeRecord; /* Array of glyph ranges--ordered by
* Start GlyphID */
public:
@@ -2036,19 +2308,20 @@ struct ClassDef
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
- bool serialize (hb_serialize_context_t *c, Iterator it)
+ bool serialize (hb_serialize_context_t *c, Iterator it_with_class_zero)
{
TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (*this))) return_trace (false);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
+
+ auto it = + it_with_class_zero | hb_filter (hb_second);
unsigned format = 2;
if (likely (it))
{
hb_codepoint_t glyph_min = (*it).first;
- hb_codepoint_t glyph_max = + it
- | hb_map (hb_first)
- | hb_reduce (hb_max, 0u);
+ hb_codepoint_t glyph_max = glyph_min;
+ unsigned num_glyphs = 0;
unsigned num_ranges = 1;
hb_codepoint_t prev_gid = glyph_min;
unsigned prev_klass = (*it).second;
@@ -2057,7 +2330,9 @@ struct ClassDef
{
hb_codepoint_t cur_gid = gid_klass_pair.first;
unsigned cur_klass = gid_klass_pair.second;
- if (cur_gid == glyph_min || !cur_klass) continue;
+ num_glyphs++;
+ if (cur_gid == glyph_min) continue;
+ if (cur_gid > glyph_max) glyph_max = cur_gid;
if (cur_gid != prev_gid + 1 ||
cur_klass != prev_klass)
num_ranges++;
@@ -2066,7 +2341,7 @@ struct ClassDef
prev_klass = cur_klass;
}
- if (1 + (glyph_max - glyph_min + 1) <= num_ranges * 3)
+ if (num_glyphs && 1 + (glyph_max - glyph_min + 1) <= num_ranges * 3)
format = 1;
}
u.format = format;
@@ -2080,12 +2355,15 @@ struct ClassDef
}
bool subset (hb_subset_context_t *c,
- hb_map_t *klass_map = nullptr /*OUT*/) const
+ hb_map_t *klass_map = nullptr /*OUT*/,
+ bool keep_empty_table = true,
+ bool use_class_zero = true,
+ const Coverage* glyph_filter = nullptr) const
{
TRACE_SUBSET (this);
switch (u.format) {
- case 1: return_trace (u.format1.subset (c, klass_map));
- case 2: return_trace (u.format2.subset (c, klass_map));
+ case 1: return_trace (u.format1.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
+ case 2: return_trace (u.format2.subset (c, klass_map, keep_empty_table, use_class_zero, glyph_filter));
default:return_trace (false);
}
}
@@ -2142,6 +2420,15 @@ struct ClassDef
}
}
+ void intersected_class_glyphs (const hb_set_t *glyphs, unsigned klass, hb_set_t *intersect_glyphs) const
+ {
+ switch (u.format) {
+ case 1: return u.format1.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
+ case 2: return u.format2.intersected_class_glyphs (glyphs, klass, intersect_glyphs);
+ default:return;
+ }
+ }
+
protected:
union {
HBUINT16 format; /* Format identifier */
@@ -2229,19 +2516,19 @@ struct VarRegionList
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) &&
- axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount));
+ return_trace (c->check_struct (this) && axesZ.sanitize (c, axisCount * regionCount));
}
bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_bimap_t &region_map)
{
TRACE_SERIALIZE (this);
- VarRegionList *out = c->allocate_min<VarRegionList> ();
- if (unlikely (!out)) return_trace (false);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
axisCount = src->axisCount;
regionCount = region_map.get_population ();
- if (unlikely (!c->allocate_size<VarRegionList> (get_size () - min_size))) return_trace (false);
- unsigned int region_count = src->get_region_count ();
+ if (unlikely (hb_unsigned_mul_overflows (axisCount * regionCount,
+ VarRegionAxis::static_size))) return_trace (false);
+ if (unlikely (!c->extend (this))) return_trace (false);
+ unsigned int region_count = src->regionCount;
for (unsigned int r = 0; r < regionCount; r++)
{
unsigned int backward = region_map.backward (r);
@@ -2253,11 +2540,11 @@ struct VarRegionList
}
unsigned int get_size () const { return min_size + VarRegionAxis::static_size * axisCount * regionCount; }
- unsigned int get_region_count () const { return regionCount; }
- protected:
+ public:
HBUINT16 axisCount;
HBUINT16 regionCount;
+ protected:
UnsizedArrayOf<VarRegionAxis>
axesZ;
public:
@@ -2273,7 +2560,10 @@ struct VarData
{ return shortCount + regionIndices.len; }
unsigned int get_size () const
- { return itemCount * get_row_size (); }
+ { return min_size
+ - regionIndices.min_size + regionIndices.get_size ()
+ + itemCount * get_row_size ();
+ }
float get_delta (unsigned int inner,
const int *coords, unsigned int coord_count,
@@ -2307,10 +2597,10 @@ struct VarData
return delta;
}
- void get_scalars (const int *coords, unsigned int coord_count,
- const VarRegionList &regions,
- float *scalars /*OUT */,
- unsigned int num_scalars) const
+ void get_region_scalars (const int *coords, unsigned int coord_count,
+ const VarRegionList &regions,
+ float *scalars /*OUT */,
+ unsigned int num_scalars) const
{
unsigned count = hb_min (num_scalars, regionIndices.len);
for (unsigned int i = 0; i < count; i++)
@@ -2336,7 +2626,7 @@ struct VarData
const hb_bimap_t &region_map)
{
TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (*this))) return_trace (false);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
itemCount = inner_map.get_next_value ();
/* Optimize short count */
@@ -2378,9 +2668,7 @@ struct VarData
shortCount = new_short_count;
regionIndices.len = new_ri_count;
- unsigned int size = regionIndices.get_size () - HBUINT16::static_size/*regionIndices.len*/ + (get_row_size () * itemCount);
- if (unlikely (!c->allocate_size<HBUINT8> (size)))
- return_trace (false);
+ if (unlikely (!c->extend (this))) return_trace (false);
for (r = 0; r < ri_count; r++)
if (delta_sz[r]) regionIndices[ri_map[r]] = region_map[src->regionIndices[r]];
@@ -2395,16 +2683,16 @@ struct VarData
return_trace (true);
}
- void collect_region_refs (hb_inc_bimap_t &region_map, const hb_inc_bimap_t &inner_map) const
+ void collect_region_refs (hb_set_t &region_indices, const hb_inc_bimap_t &inner_map) const
{
for (unsigned int r = 0; r < regionIndices.len; r++)
{
unsigned int region = regionIndices[r];
- if (region_map.has (region)) continue;
+ if (region_indices.has (region)) continue;
for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
if (get_item_delta (inner_map.backward (i), r) != 0)
{
- region_map.add (region);
+ region_indices.add (region);
break;
}
}
@@ -2439,7 +2727,7 @@ struct VarData
protected:
HBUINT16 itemCount;
HBUINT16 shortCount;
- ArrayOf<HBUINT16> regionIndices;
+ Array16Of<HBUINT16> regionIndices;
/*UnsizedArrayOf<HBUINT8>bytesX;*/
public:
DEFINE_SIZE_ARRAY (6, regionIndices);
@@ -2447,6 +2735,7 @@ struct VarData
struct VariationStore
{
+ private:
float get_delta (unsigned int outer, unsigned int inner,
const int *coords, unsigned int coord_count) const
{
@@ -2462,6 +2751,7 @@ struct VariationStore
this+regions);
}
+ public:
float get_delta (unsigned int index,
const int *coords, unsigned int coord_count) const
{
@@ -2488,32 +2778,48 @@ struct VariationStore
const hb_array_t <hb_inc_bimap_t> &inner_maps)
{
TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
+
unsigned int set_count = 0;
for (unsigned int i = 0; i < inner_maps.length; i++)
- if (inner_maps[i].get_population () > 0) set_count++;
+ if (inner_maps[i].get_population ())
+ set_count++;
- unsigned int size = min_size + HBUINT32::static_size * set_count;
- if (unlikely (!c->allocate_size<HBUINT32> (size))) return_trace (false);
format = 1;
- hb_inc_bimap_t region_map;
+ const auto &src_regions = src+src->regions;
+
+ hb_set_t region_indices;
for (unsigned int i = 0; i < inner_maps.length; i++)
- (src+src->dataSets[i]).collect_region_refs (region_map, inner_maps[i]);
- region_map.sort ();
+ (src+src->dataSets[i]).collect_region_refs (region_indices, inner_maps[i]);
- if (unlikely (!regions.serialize (c, this)
- .serialize (c, &(src+src->regions), region_map))) return_trace (false);
+ if (region_indices.in_error ())
+ return_trace (false);
+
+ region_indices.del_range ((src_regions).regionCount, hb_set_t::INVALID);
+
+ /* TODO use constructor when our data-structures support that. */
+ hb_inc_bimap_t region_map;
+ + hb_iter (region_indices)
+ | hb_apply ([&region_map] (unsigned _) { region_map.add(_); })
+ ;
+ if (region_map.in_error())
+ return_trace (false);
+
+ if (unlikely (!regions.serialize_serialize (c, &src_regions, region_map)))
+ return_trace (false);
- /* TODO: The following code could be simplified when
- * OffsetListOf::subset () can take a custom param to be passed to VarData::serialize ()
- */
dataSets.len = set_count;
+ if (unlikely (!c->extend (dataSets))) return_trace (false);
+
+ /* TODO: The following code could be simplified when
+ * List16OfOffset16To::subset () can take a custom param to be passed to VarData::serialize () */
unsigned int set_index = 0;
for (unsigned int i = 0; i < inner_maps.length; i++)
{
- if (inner_maps[i].get_population () == 0) continue;
- if (unlikely (!dataSets[set_index++].serialize (c, this)
- .serialize (c, &(src+src->dataSets[i]), inner_maps[i], region_map)))
+ if (!inner_maps[i].get_population ()) continue;
+ if (unlikely (!dataSets[set_index++]
+ .serialize_serialize (c, &(src+src->dataSets[i]), inner_maps[i], region_map)))
return_trace (false);
}
@@ -2558,13 +2864,13 @@ struct VariationStore
&& varstore_prime->dataSets);
}
- unsigned int get_region_index_count (unsigned int ivs) const
- { return (this+dataSets[ivs]).get_region_index_count (); }
+ unsigned int get_region_index_count (unsigned int major) const
+ { return (this+dataSets[major]).get_region_index_count (); }
- void get_scalars (unsigned int ivs,
- const int *coords, unsigned int coord_count,
- float *scalars /*OUT*/,
- unsigned int num_scalars) const
+ void get_region_scalars (unsigned int major,
+ const int *coords, unsigned int coord_count,
+ float *scalars /*OUT*/,
+ unsigned int num_scalars) const
{
#ifdef HB_NO_VAR
for (unsigned i = 0; i < num_scalars; i++)
@@ -2572,18 +2878,19 @@ struct VariationStore
return;
#endif
- (this+dataSets[ivs]).get_scalars (coords, coord_count, this+regions,
- &scalars[0], num_scalars);
+ (this+dataSets[major]).get_region_scalars (coords, coord_count,
+ this+regions,
+ &scalars[0], num_scalars);
}
unsigned int get_sub_table_count () const { return dataSets.len; }
protected:
HBUINT16 format;
- LOffsetTo<VarRegionList> regions;
- LOffsetArrayOf<VarData> dataSets;
+ Offset32To<VarRegionList> regions;
+ Array16OfOffset32To<VarData> dataSets;
public:
- DEFINE_SIZE_ARRAY (8, dataSets);
+ DEFINE_SIZE_ARRAY_SIZED (8, dataSets);
};
/*
@@ -2684,7 +2991,8 @@ struct ConditionSet
+ conditions.iter ()
| hb_apply (subset_offset_array (c, out->conditions, this))
;
- return_trace (true);
+
+ return_trace (bool (out->conditions));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -2694,7 +3002,7 @@ struct ConditionSet
}
protected:
- LOffsetArrayOf<Condition> conditions;
+ Array16OfOffset32To<Condition> conditions;
public:
DEFINE_SIZE_ARRAY (2, conditions);
};
@@ -2719,6 +3027,12 @@ struct FeatureTableSubstitutionRecord
bool subset (hb_subset_layout_context_t *c, const void *base) const
{
TRACE_SUBSET (this);
+ if (!c->feature_index_map->has (featureIndex)) {
+ // Feature that is being substituted is not being retained, so we don't
+ // need this.
+ return_trace (false);
+ }
+
auto *out = c->subset_context->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
@@ -2735,7 +3049,7 @@ struct FeatureTableSubstitutionRecord
protected:
HBUINT16 featureIndex;
- LOffsetTo<Feature> feature;
+ Offset32To<Feature> feature;
public:
DEFINE_SIZE_STATIC (6);
};
@@ -2771,6 +3085,15 @@ struct FeatureTableSubstitution
record.closure_features (this, lookup_indexes, feature_indexes);
}
+ bool intersects_features (const hb_map_t *feature_index_map) const
+ {
+ for (const FeatureTableSubstitutionRecord& record : substitutions)
+ {
+ if (feature_index_map->has (record.featureIndex)) return true;
+ }
+ return false;
+ }
+
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l) const
{
@@ -2784,7 +3107,8 @@ struct FeatureTableSubstitution
+ substitutions.iter ()
| hb_apply (subset_record_array (l, &(out->substitutions), this))
;
- return_trace (true);
+
+ return_trace (bool (out->substitutions));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -2797,7 +3121,7 @@ struct FeatureTableSubstitution
protected:
FixedVersion<> version; /* Version--0x00010000u */
- ArrayOf<FeatureTableSubstitutionRecord>
+ Array16Of<FeatureTableSubstitutionRecord>
substitutions;
public:
DEFINE_SIZE_ARRAY (6, substitutions);
@@ -2821,6 +3145,11 @@ struct FeatureVariationRecord
(base+substitutions).closure_features (lookup_indexes, feature_indexes);
}
+ bool intersects_features (const void *base, const hb_map_t *feature_index_map) const
+ {
+ return (base+substitutions).intersects_features (feature_index_map);
+ }
+
bool subset (hb_subset_layout_context_t *c, const void *base) const
{
TRACE_SUBSET (this);
@@ -2841,9 +3170,9 @@ struct FeatureVariationRecord
}
protected:
- LOffsetTo<ConditionSet>
+ Offset32To<ConditionSet>
conditions;
- LOffsetTo<FeatureTableSubstitution>
+ Offset32To<FeatureTableSubstitution>
substitutions;
public:
DEFINE_SIZE_STATIC (8);
@@ -2907,9 +3236,18 @@ struct FeatureVariations
out->version.major = version.major;
out->version.minor = version.minor;
- + varRecords.iter ()
- | hb_apply (subset_record_array (l, &(out->varRecords), this))
- ;
+ int keep_up_to = -1;
+ for (int i = varRecords.len - 1; i >= 0; i--) {
+ if (varRecords[i].intersects_features (this, l->feature_index_map)) {
+ keep_up_to = i;
+ break;
+ }
+ }
+
+ unsigned count = (unsigned) (keep_up_to + 1);
+ for (unsigned i = 0; i < count; i++) {
+ subset_record_array (l, &(out->varRecords), this) (varRecords[i]);
+ }
return_trace (bool (out->varRecords));
}
@@ -2923,7 +3261,7 @@ struct FeatureVariations
protected:
FixedVersion<> version; /* Version--0x00010000u */
- LArrayOf<FeatureVariationRecord>
+ Array32Of<FeatureVariationRecord>
varRecords;
public:
DEFINE_SIZE_ARRAY_SIZED (8, varRecords);
@@ -3036,22 +3374,20 @@ struct VariationDevice
if (unlikely (!out)) return_trace (nullptr);
if (!layout_variation_idx_map || layout_variation_idx_map->is_empty ()) return_trace (out);
- unsigned org_idx = (outerIndex << 16) + innerIndex;
- if (!layout_variation_idx_map->has (org_idx))
+ /* TODO Just get() and bail if NO_VARIATION. Needs to setup the map to return that. */
+ if (!layout_variation_idx_map->has (varIdx))
{
c->revert (snap);
return_trace (nullptr);
}
- unsigned new_idx = layout_variation_idx_map->get (org_idx);
- out->outerIndex = new_idx >> 16;
- out->innerIndex = new_idx & 0xFFFF;
+ unsigned new_idx = layout_variation_idx_map->get (varIdx);
+ out->varIdx = new_idx;
return_trace (out);
}
void record_variation_index (hb_set_t *layout_variation_indices) const
{
- unsigned var_idx = (outerIndex << 16) + innerIndex;
- layout_variation_indices->add (var_idx);
+ layout_variation_indices->add (varIdx);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -3064,12 +3400,11 @@ struct VariationDevice
float get_delta (hb_font_t *font, const VariationStore &store) const
{
- return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
+ return store.get_delta (varIdx, font->coords, font->num_coords);
}
protected:
- HBUINT16 outerIndex;
- HBUINT16 innerIndex;
+ VarIdx varIdx;
HBUINT16 deltaFormat; /* Format identifier for this table: 0x0x8000 */
public:
DEFINE_SIZE_STATIC (6);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh
index 437e760f64..31a4a3e84c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh
index f523e35c00..1e305518f5 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh
@@ -89,20 +89,22 @@ struct ValueFormat : HBUINT16
HBINT16 yAdvance; /* Vertical adjustment for advance--in
* design units (only used for vertical
* writing) */
- OffsetTo<Device> xPlaDevice; /* Offset to Device table for
+ Offset16To<Device> xPlaDevice; /* Offset to Device table for
* horizontal placement--measured from
* beginning of PosTable (may be NULL) */
- OffsetTo<Device> yPlaDevice; /* Offset to Device table for vertical
+ Offset16To<Device> yPlaDevice; /* Offset to Device table for vertical
* placement--measured from beginning
* of PosTable (may be NULL) */
- OffsetTo<Device> xAdvDevice; /* Offset to Device table for
+ Offset16To<Device> xAdvDevice; /* Offset to Device table for
* horizontal advance--measured from
* beginning of PosTable (may be NULL) */
- OffsetTo<Device> yAdvDevice; /* Offset to Device table for vertical
+ Offset16To<Device> yAdvDevice; /* Offset to Device table for vertical
* advance--measured from beginning of
* PosTable (may be NULL) */
#endif
+ IntType& operator = (uint16_t i) { v = i; return *this; }
+
unsigned int get_len () const { return hb_popcount ((unsigned int) *this); }
unsigned int get_size () const { return get_len () * Value::static_size; }
@@ -160,16 +162,40 @@ struct ValueFormat : HBUINT16
return ret;
}
- void serialize_copy (hb_serialize_context_t *c, const void *base,
- const Value *values, const hb_map_t *layout_variation_idx_map) const
+ unsigned int get_effective_format (const Value *values) const
+ {
+ unsigned int format = *this;
+ for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
+ if (format & flag) should_drop (*values++, (Flags) flag, &format);
+ }
+
+ return format;
+ }
+
+ template<typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ unsigned int get_effective_format (Iterator it) const {
+ unsigned int new_format = 0;
+
+ for (const hb_array_t<const Value>& values : it)
+ new_format = new_format | get_effective_format (&values);
+
+ return new_format;
+ }
+
+ void copy_values (hb_serialize_context_t *c,
+ unsigned int new_format,
+ const void *base,
+ const Value *values,
+ const hb_map_t *layout_variation_idx_map) const
{
unsigned int format = *this;
if (!format) return;
- if (format & xPlacement) c->copy (*values++);
- if (format & yPlacement) c->copy (*values++);
- if (format & xAdvance) c->copy (*values++);
- if (format & yAdvance) c->copy (*values++);
+ if (format & xPlacement) copy_value (c, new_format, xPlacement, *values++);
+ if (format & yPlacement) copy_value (c, new_format, yPlacement, *values++);
+ if (format & xAdvance) copy_value (c, new_format, xAdvance, *values++);
+ if (format & yAdvance) copy_value (c, new_format, yAdvance, *values++);
if (format & xPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
if (format & yPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
@@ -177,6 +203,16 @@ struct ValueFormat : HBUINT16
if (format & yAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
}
+ void copy_value (hb_serialize_context_t *c,
+ unsigned int new_format,
+ Flags flag,
+ Value value) const
+ {
+ // Filter by new format.
+ if (!(new_format & flag)) return;
+ c->copy (value);
+ }
+
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
const void *base,
const hb_array_t<const Value>& values) const
@@ -232,14 +268,14 @@ struct ValueFormat : HBUINT16
return true;
}
- static inline OffsetTo<Device>& get_device (Value* value)
+ static inline Offset16To<Device>& get_device (Value* value)
{
- return *static_cast<OffsetTo<Device> *> (value);
+ return *static_cast<Offset16To<Device> *> (value);
}
- static inline const OffsetTo<Device>& get_device (const Value* value, bool *worked=nullptr)
+ static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr)
{
if (worked) *worked |= bool (*value);
- return *static_cast<const OffsetTo<Device> *> (value);
+ return *static_cast<const Offset16To<Device> *> (value);
}
bool copy_device (hb_serialize_context_t *c, const void *base,
@@ -317,13 +353,21 @@ struct ValueFormat : HBUINT16
return_trace (true);
}
+
+ private:
+
+ void should_drop (Value value, Flags flag, unsigned int* format) const
+ {
+ if (value) return;
+ *format = *format & ~flag;
+ }
+
};
-template<typename Iterator>
+template<typename Iterator, typename SrcLookup>
static void SinglePos_serialize (hb_serialize_context_t *c,
- const void *src,
+ const SrcLookup *src,
Iterator it,
- ValueFormat valFormat,
const hb_map_t *layout_variation_idx_map);
@@ -346,7 +390,10 @@ struct AnchorFormat1
AnchorFormat1* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
- return_trace (c->embed<AnchorFormat1> (this));
+ AnchorFormat1* out = c->embed<AnchorFormat1> (this);
+ if (!out) return_trace (out);
+ out->format = 1;
+ return_trace (out);
}
protected:
@@ -447,11 +494,11 @@ struct AnchorFormat3
HBUINT16 format; /* Format identifier--format = 3 */
FWORD xCoordinate; /* Horizontal value--in design units */
FWORD yCoordinate; /* Vertical value--in design units */
- OffsetTo<Device>
+ Offset16To<Device>
xDeviceTable; /* Offset to Device table for X
* coordinate-- from beginning of
* Anchor table (may be NULL) */
- OffsetTo<Device>
+ Offset16To<Device>
yDeviceTable; /* Offset to Device table for Y
* coordinate-- from beginning of
* Anchor table (may be NULL) */
@@ -485,14 +532,22 @@ struct Anchor
}
}
- Anchor* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map) const
+ bool subset (hb_subset_context_t *c) const
{
- TRACE_SERIALIZE (this);
+ TRACE_SUBSET (this);
switch (u.format) {
- case 1: return_trace (reinterpret_cast<Anchor *> (u.format1.copy (c)));
- case 2: return_trace (reinterpret_cast<Anchor *> (u.format2.copy (c)));
- case 3: return_trace (reinterpret_cast<Anchor *> (u.format3.copy (c, layout_variation_idx_map)));
- default:return_trace (nullptr);
+ case 1: return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
+ case 2:
+ if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+ {
+ // AnchorFormat 2 just containins extra hinting information, so
+ // if hints are being dropped convert to format 1.
+ return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
+ }
+ return_trace (bool (reinterpret_cast<Anchor *> (u.format2.copy (c->serializer))));
+ case 3: return_trace (bool (reinterpret_cast<Anchor *> (u.format3.copy (c->serializer,
+ c->plan->layout_variation_idx_map))));
+ default:return_trace (false);
}
}
@@ -541,51 +596,29 @@ struct AnchorMatrix
}
template <typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
- bool serialize (hb_serialize_context_t *c,
- unsigned num_rows,
- AnchorMatrix const *offset_matrix,
- const hb_map_t *layout_variation_idx_map,
- Iterator index_iter)
+ hb_requires (hb_is_iterator (Iterator))>
+ bool subset (hb_subset_context_t *c,
+ unsigned num_rows,
+ Iterator index_iter) const
{
- TRACE_SERIALIZE (this);
+ TRACE_SUBSET (this);
+
+ auto *out = c->serializer->start_embed (this);
+
if (!index_iter) return_trace (false);
- if (unlikely (!c->extend_min ((*this)))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
- this->rows = num_rows;
+ out->rows = num_rows;
for (const unsigned i : index_iter)
{
- auto *offset = c->embed (offset_matrix->matrixZ[i]);
+ auto *offset = c->serializer->embed (matrixZ[i]);
if (!offset) return_trace (false);
- offset->serialize_copy (c, offset_matrix->matrixZ[i],
- offset_matrix, c->to_bias (this),
- hb_serialize_context_t::Head,
- layout_variation_idx_map);
+ offset->serialize_subset (c, matrixZ[i], this);
}
return_trace (true);
}
- bool subset (hb_subset_context_t *c,
- unsigned cols,
- const hb_map_t *klass_mapping) const
- {
- TRACE_SUBSET (this);
- auto *out = c->serializer->start_embed (*this);
-
- auto indexes =
- + hb_range (rows * cols)
- | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % cols); })
- ;
-
- out->serialize (c->serializer,
- (unsigned) rows,
- this,
- c->plan->layout_variation_idx_map,
- indexes);
- return_trace (true);
- }
-
bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
{
TRACE_SANITIZE (this);
@@ -599,7 +632,7 @@ struct AnchorMatrix
}
HBUINT16 rows; /* Number of rows */
- UnsizedArrayOf<OffsetTo<Anchor>>
+ UnsizedArrayOf<Offset16To<Anchor>>
matrixZ; /* Matrix of offsets to Anchor tables--
* from beginning of AnchorMatrix table */
public:
@@ -618,18 +651,16 @@ struct MarkRecord
return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
}
- MarkRecord *copy (hb_serialize_context_t *c,
- const void *src_base,
- unsigned dst_bias,
- const hb_map_t *klass_mapping,
- const hb_map_t *layout_variation_idx_map) const
+ MarkRecord *subset (hb_subset_context_t *c,
+ const void *src_base,
+ const hb_map_t *klass_mapping) const
{
- TRACE_SERIALIZE (this);
- auto *out = c->embed (this);
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (nullptr);
out->klass = klass_mapping->get (klass);
- out->markAnchor.serialize_copy (c, markAnchor, src_base, dst_bias, hb_serialize_context_t::Head, layout_variation_idx_map);
+ out->markAnchor.serialize_subset (c, markAnchor, src_base);
return_trace (out);
}
@@ -641,14 +672,14 @@ struct MarkRecord
protected:
HBUINT16 klass; /* Class defined for this mark */
- OffsetTo<Anchor>
+ Offset16To<Anchor>
markAnchor; /* Offset to Anchor table--from
* beginning of MarkArray table */
public:
DEFINE_SIZE_STATIC (4);
};
-struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */
+struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Coverage order */
{
bool apply (hb_ot_apply_context_t *c,
unsigned int mark_index, unsigned int glyph_index,
@@ -657,7 +688,7 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
- const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
+ const MarkRecord &record = Array16Of<MarkRecord>::operator[](mark_index);
unsigned int mark_class = record.klass;
const Anchor& mark_anchor = this + record.markAnchor;
@@ -684,25 +715,42 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde
return_trace (true);
}
- template<typename Iterator,
- hb_requires (hb_is_source_of (Iterator, MarkRecord))>
- bool serialize (hb_serialize_context_t *c,
- const hb_map_t *klass_mapping,
- const hb_map_t *layout_variation_idx_map,
- const void *base,
- Iterator it)
+ template <typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ bool subset (hb_subset_context_t *c,
+ Iterator coverage,
+ const hb_map_t *klass_mapping) const
{
- TRACE_SERIALIZE (this);
- if (unlikely (!c->extend_min (*this))) return_trace (false);
- if (unlikely (!c->check_assign (len, it.len ()))) return_trace (false);
- c->copy_all (it, base, c->to_bias (this), klass_mapping, layout_variation_idx_map);
+ TRACE_SUBSET (this);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+
+ auto* out = c->serializer->start_embed (this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+ auto mark_iter =
+ + hb_zip (coverage, this->iter ())
+ | hb_filter (glyphset, hb_first)
+ | hb_map (hb_second)
+ ;
+
+ unsigned new_length = 0;
+ for (const auto& mark_record : mark_iter) {
+ if (unlikely (!mark_record.subset (c, this, klass_mapping)))
+ return_trace (false);
+ new_length++;
+ }
+
+ if (unlikely (!c->serializer->check_assign (out->len, new_length,
+ HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)))
+ return_trace (false);
+
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (ArrayOf<MarkRecord>::sanitize (c, this));
+ return_trace (Array16Of<MarkRecord>::sanitize (c, this));
}
};
@@ -733,6 +781,8 @@ struct SinglePosFormat1
const Coverage &get_coverage () const { return this+coverage; }
+ ValueFormat get_value_format () const { return valueFormat; }
+
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
@@ -747,29 +797,33 @@ struct SinglePosFormat1
}
template<typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
+ typename SrcLookup,
+ hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
- const void *src,
+ const SrcLookup *src,
Iterator it,
- ValueFormat valFormat,
+ ValueFormat newFormat,
const hb_map_t *layout_variation_idx_map)
{
- auto out = c->extend_min (*this);
- if (unlikely (!out)) return;
- if (unlikely (!c->check_assign (valueFormat, valFormat))) return;
+ if (unlikely (!c->extend_min (this))) return;
+ if (unlikely (!c->check_assign (valueFormat,
+ newFormat,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
- + it
- | hb_map (hb_second)
- | hb_apply ([&] (hb_array_t<const Value> _)
- { valFormat.serialize_copy (c, src, &_, layout_variation_idx_map); })
- ;
+ for (const hb_array_t<const Value>& _ : + it | hb_map (hb_second))
+ {
+ src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map);
+ // Only serialize the first entry in the iterator, the rest are assumed to
+ // be the same.
+ break;
+ }
auto glyphs =
+ it
| hb_map_retains_sorting (hb_first)
;
- coverage.serialize (c, this).serialize (c, glyphs);
+ coverage.serialize_serialize (c, glyphs);
}
bool subset (hb_subset_context_t *c) const
@@ -786,7 +840,7 @@ struct SinglePosFormat1
;
bool ret = bool (it);
- SinglePos_serialize (c->serializer, this, it, valueFormat, c->plan->layout_variation_idx_map);
+ SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
return_trace (ret);
}
@@ -800,7 +854,7 @@ struct SinglePosFormat1
protected:
HBUINT16 format; /* Format identifier--format = 1 */
- OffsetTo<Coverage>
+ Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
ValueFormat valueFormat; /* Defines the types of data in the
@@ -843,6 +897,8 @@ struct SinglePosFormat2
const Coverage &get_coverage () const { return this+coverage; }
+ ValueFormat get_value_format () const { return valueFormat; }
+
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
@@ -861,22 +917,23 @@ struct SinglePosFormat2
}
template<typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
+ typename SrcLookup,
+ hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
- const void *src,
+ const SrcLookup *src,
Iterator it,
- ValueFormat valFormat,
+ ValueFormat newFormat,
const hb_map_t *layout_variation_idx_map)
{
- auto out = c->extend_min (*this);
+ auto out = c->extend_min (this);
if (unlikely (!out)) return;
- if (unlikely (!c->check_assign (valueFormat, valFormat))) return;
- if (unlikely (!c->check_assign (valueCount, it.len ()))) return;
+ if (unlikely (!c->check_assign (valueFormat, newFormat, HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
+ if (unlikely (!c->check_assign (valueCount, it.len (), HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) return;
+ it
| hb_map (hb_second)
| hb_apply ([&] (hb_array_t<const Value> _)
- { valFormat.serialize_copy (c, src, &_, layout_variation_idx_map); })
+ { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); })
;
auto glyphs =
@@ -884,7 +941,7 @@ struct SinglePosFormat2
| hb_map_retains_sorting (hb_first)
;
- coverage.serialize (c, this).serialize (c, glyphs);
+ coverage.serialize_serialize (c, glyphs);
}
bool subset (hb_subset_context_t *c) const
@@ -908,7 +965,7 @@ struct SinglePosFormat2
;
bool ret = bool (it);
- SinglePos_serialize (c->serializer, this, it, valueFormat, c->plan->layout_variation_idx_map);
+ SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
return_trace (ret);
}
@@ -922,7 +979,7 @@ struct SinglePosFormat2
protected:
HBUINT16 format; /* Format identifier--format = 2 */
- OffsetTo<Coverage>
+ Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
ValueFormat valueFormat; /* Defines the types of data in the
@@ -952,24 +1009,37 @@ struct SinglePos
template<typename Iterator,
- hb_requires (hb_is_iterator (Iterator))>
+ typename SrcLookup,
+ hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
- const void *src,
+ const SrcLookup* src,
Iterator glyph_val_iter_pairs,
- ValueFormat valFormat,
const hb_map_t *layout_variation_idx_map)
{
if (unlikely (!c->extend_min (u.format))) return;
unsigned format = 2;
+ ValueFormat new_format = src->get_value_format ();
- if (glyph_val_iter_pairs) format = get_format (glyph_val_iter_pairs);
+ if (glyph_val_iter_pairs)
+ {
+ format = get_format (glyph_val_iter_pairs);
+ new_format = src->get_value_format ().get_effective_format (+ glyph_val_iter_pairs | hb_map (hb_second));
+ }
u.format = format;
switch (u.format) {
- case 1: u.format1.serialize (c, src, glyph_val_iter_pairs, valFormat, layout_variation_idx_map);
- return;
- case 2: u.format2.serialize (c, src, glyph_val_iter_pairs, valFormat, layout_variation_idx_map);
- return;
+ case 1: u.format1.serialize (c,
+ src,
+ glyph_val_iter_pairs,
+ new_format,
+ layout_variation_idx_map);
+ return;
+ case 2: u.format2.serialize (c,
+ src,
+ glyph_val_iter_pairs,
+ new_format,
+ layout_variation_idx_map);
+ return;
default:return;
}
}
@@ -994,14 +1064,13 @@ struct SinglePos
} u;
};
-template<typename Iterator>
+template<typename Iterator, typename SrcLookup>
static void
SinglePos_serialize (hb_serialize_context_t *c,
- const void *src,
+ const SrcLookup *src,
Iterator it,
- ValueFormat valFormat,
const hb_map_t *layout_variation_idx_map)
-{ c->start_embed<SinglePos> ()->serialize (c, src, it, valFormat, layout_variation_idx_map); }
+{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_map); }
struct PairValueRecord
@@ -1011,26 +1080,35 @@ struct PairValueRecord
int cmp (hb_codepoint_t k) const
{ return secondGlyph.cmp (k); }
- struct serialize_closure_t
+ struct context_t
{
const void *base;
const ValueFormat *valueFormats;
+ const ValueFormat *newFormats;
unsigned len1; /* valueFormats[0].get_len() */
const hb_map_t *glyph_map;
const hb_map_t *layout_variation_idx_map;
};
- bool serialize (hb_serialize_context_t *c,
- serialize_closure_t *closure) const
+ bool subset (hb_subset_context_t *c,
+ context_t *closure) const
{
TRACE_SERIALIZE (this);
- auto *out = c->start_embed (*this);
- if (unlikely (!c->extend_min (out))) return_trace (false);
+ auto *s = c->serializer;
+ auto *out = s->start_embed (*this);
+ if (unlikely (!s->extend_min (out))) return_trace (false);
out->secondGlyph = (*closure->glyph_map)[secondGlyph];
- closure->valueFormats[0].serialize_copy (c, closure->base, &values[0], closure->layout_variation_idx_map);
- closure->valueFormats[1].serialize_copy (c, closure->base, &values[closure->len1], closure->layout_variation_idx_map);
+ closure->valueFormats[0].copy_values (s,
+ closure->newFormats[0],
+ closure->base, &values[0],
+ closure->layout_variation_idx_map);
+ closure->valueFormats[1].copy_values (s,
+ closure->newFormats[1],
+ closure->base,
+ &values[closure->len1],
+ closure->layout_variation_idx_map);
return_trace (true);
}
@@ -1050,6 +1128,21 @@ struct PairValueRecord
valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len));
}
+ bool intersects (const hb_set_t& glyphset) const
+ {
+ return glyphset.has(secondGlyph);
+ }
+
+ const Value* get_values_1 () const
+ {
+ return &values[0];
+ }
+
+ const Value* get_values_2 (ValueFormat format1) const
+ {
+ return &values[format1.get_len ()];
+ }
+
protected:
HBGlyphID secondGlyph; /* GlyphID of second glyph in the
* pair--first glyph is listed in the
@@ -1140,7 +1233,8 @@ struct PairSet
}
bool subset (hb_subset_context_t *c,
- const ValueFormat valueFormats[2]) const
+ const ValueFormat valueFormats[2],
+ const ValueFormat newFormats[2]) const
{
TRACE_SUBSET (this);
auto snap = c->serializer->snapshot ();
@@ -1156,10 +1250,11 @@ struct PairSet
unsigned len2 = valueFormats[1].get_len ();
unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
- PairValueRecord::serialize_closure_t closure =
+ PairValueRecord::context_t context =
{
this,
valueFormats,
+ newFormats,
len1,
&glyph_map,
c->plan->layout_variation_idx_map
@@ -1170,7 +1265,7 @@ struct PairSet
for (unsigned i = 0; i < count; i++)
{
if (glyphset.has (record->secondGlyph)
- && record->serialize (c->serializer, &closure)) num++;
+ && record->subset (c, &context)) num++;
record = &StructAtOffset<const PairValueRecord> (record, record_size);
}
@@ -1218,7 +1313,7 @@ struct PairPosFormat1
+ hb_zip (this+coverage, pairSet)
| hb_filter (*glyphs, hb_first)
| hb_map (hb_second)
- | hb_map ([glyphs, this] (const OffsetTo<PairSet> &_)
+ | hb_map ([glyphs, this] (const Offset16To<PairSet> &_)
{ return (this+_).intersects (glyphs, valueFormat); })
| hb_any
;
@@ -1278,17 +1373,23 @@ struct PairPosFormat1
out->format = format;
out->valueFormat[0] = valueFormat[0];
out->valueFormat[1] = valueFormat[1];
+ if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+ {
+ hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
+ out->valueFormat[0] = newFormats.first;
+ out->valueFormat[1] = newFormats.second;
+ }
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ hb_zip (this+coverage, pairSet)
| hb_filter (glyphset, hb_first)
- | hb_filter ([this, c, out] (const OffsetTo<PairSet>& _)
+ | hb_filter ([this, c, out] (const Offset16To<PairSet>& _)
{
auto *o = out->pairSet.serialize_append (c->serializer);
if (unlikely (!o)) return false;
auto snap = c->serializer->snapshot ();
- bool ret = o->serialize_subset (c, _, this, valueFormat);
+ bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat);
if (!ret)
{
out->pairSet.pop ();
@@ -1302,12 +1403,41 @@ struct PairPosFormat1
| 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));
}
+
+ hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
+ {
+ unsigned len1 = valueFormat[0].get_len ();
+ unsigned len2 = valueFormat[1].get_len ();
+ unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
+
+ unsigned format1 = 0;
+ unsigned format2 = 0;
+ for (const Offset16To<PairSet>& _ :
+ + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) | hb_map (hb_second))
+ {
+ const PairSet& set = (this + _);
+ const PairValueRecord *record = &set.firstPairValueRecord;
+
+ for (unsigned i = 0; i < set.len; i++)
+ {
+ if (record->intersects (glyphset))
+ {
+ format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ());
+ format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]));
+ }
+ record = &StructAtOffset<const PairValueRecord> (record, record_size);
+ }
+ }
+
+ return hb_pair (format1, format2);
+ }
+
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -1328,7 +1458,7 @@ struct PairPosFormat1
protected:
HBUINT16 format; /* Format identifier--format = 1 */
- OffsetTo<Coverage>
+ Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
ValueFormat valueFormat[2]; /* [0] Defines the types of data in
@@ -1337,7 +1467,7 @@ struct PairPosFormat1
/* [1] Defines the types of data in
* ValueRecord2--for the second glyph
* in the pair--may be zero (0) */
- OffsetArrayOf<PairSet>
+ Array16OfOffset16To<PairSet>
pairSet; /* Array of PairSet tables
* ordered by Coverage Index */
public:
@@ -1355,18 +1485,35 @@ struct PairPosFormat2
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
+ if (!intersects (c->glyph_set)) return;
if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return;
+ hb_set_t klass1_glyphs, klass2_glyphs;
+ if (!(this+classDef1).collect_coverage (&klass1_glyphs)) return;
+ if (!(this+classDef2).collect_coverage (&klass2_glyphs)) return;
+
hb_set_t class1_set, class2_set;
- for (const unsigned cp : c->glyph_set->iter ())
+ for (const unsigned cp : + c->glyph_set->iter () | hb_filter (this + coverage))
+ {
+ if (!klass1_glyphs.has (cp)) class1_set.add (0);
+ else
+ {
+ unsigned klass1 = (this+classDef1).get (cp);
+ class1_set.add (klass1);
+ }
+ }
+
+ class2_set.add (0);
+ for (const unsigned cp : + c->glyph_set->iter () | hb_filter (klass2_glyphs))
{
- unsigned klass1 = (this+classDef1).get (cp);
unsigned klass2 = (this+classDef2).get (cp);
- class1_set.add (klass1);
class2_set.add (klass2);
}
- if (class1_set.is_empty () || class2_set.is_empty ()) return;
+ if (class1_set.is_empty ()
+ || class2_set.is_empty ()
+ || (class2_set.get_population() == 1 && class2_set.has(0)))
+ return;
unsigned len1 = valueFormat1.get_len ();
unsigned len2 = valueFormat2.get_len ();
@@ -1431,35 +1578,34 @@ struct PairPosFormat2
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
- out->valueFormat1 = valueFormat1;
- out->valueFormat2 = valueFormat2;
hb_map_t klass1_map;
- out->classDef1.serialize_subset (c, classDef1, this, &klass1_map);
+ out->classDef1.serialize_subset (c, classDef1, this, &klass1_map, true, true, &(this + coverage));
out->class1Count = klass1_map.get_population ();
hb_map_t klass2_map;
- out->classDef2.serialize_subset (c, classDef2, this, &klass2_map);
+ out->classDef2.serialize_subset (c, classDef2, this, &klass2_map, true, false);
out->class2Count = klass2_map.get_population ();
unsigned len1 = valueFormat1.get_len ();
unsigned len2 = valueFormat2.get_len ();
- + hb_range ((unsigned) class1Count)
- | hb_filter (klass1_map)
- | hb_apply ([&] (const unsigned class1_idx)
- {
- + hb_range ((unsigned) class2Count)
- | hb_filter (klass2_map)
- | hb_apply ([&] (const unsigned class2_idx)
- {
- unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
- valueFormat1.serialize_copy (c->serializer, this, &values[idx], c->plan->layout_variation_idx_map);
- valueFormat2.serialize_copy (c->serializer, this, &values[idx + len1], c->plan->layout_variation_idx_map);
- })
- ;
- })
- ;
+ hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
+ if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+ newFormats = compute_effective_value_formats (klass1_map, klass2_map);
+
+ out->valueFormat1 = newFormats.first;
+ out->valueFormat2 = newFormats.second;
+
+ for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
+ {
+ for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
+ {
+ unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+ valueFormat1.copy_values (c->serializer, newFormats.first, this, &values[idx], c->plan->layout_variation_idx_map);
+ valueFormat2.copy_values (c->serializer, newFormats.second, this, &values[idx + len1], c->plan->layout_variation_idx_map);
+ }
+ }
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
@@ -1470,10 +1616,34 @@ struct PairPosFormat2
| hb_map_retains_sorting (glyph_map)
;
- out->coverage.serialize (c->serializer, out).serialize (c->serializer, it);
+ out->coverage.serialize_serialize (c->serializer, it);
return_trace (out->class1Count && out->class2Count && bool (it));
}
+
+ hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map,
+ const hb_map_t& klass2_map) const
+ {
+ unsigned len1 = valueFormat1.get_len ();
+ unsigned len2 = valueFormat2.get_len ();
+
+ unsigned format1 = 0;
+ unsigned format2 = 0;
+
+ for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
+ {
+ for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
+ {
+ unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+ format1 = format1 | valueFormat1.get_effective_format (&values[idx]);
+ format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]);
+ }
+ }
+
+ return hb_pair (format1, format2);
+ }
+
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -1496,7 +1666,7 @@ struct PairPosFormat2
protected:
HBUINT16 format; /* Format identifier--format = 2 */
- OffsetTo<Coverage>
+ Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
ValueFormat valueFormat1; /* ValueRecord definition--for the
@@ -1505,11 +1675,11 @@ struct PairPosFormat2
ValueFormat valueFormat2; /* ValueRecord definition--for the
* second glyph of the pair--may be
* zero (0) */
- OffsetTo<ClassDef>
+ Offset16To<ClassDef>
classDef1; /* Offset to ClassDef table--from
* beginning of PairPos subtable--for
* the first glyph of the pair */
- OffsetTo<ClassDef>
+ Offset16To<ClassDef>
classDef2; /* Offset to ClassDef table--from
* beginning of PairPos subtable--for
* the second glyph of the pair */
@@ -1564,26 +1734,24 @@ struct EntryExitRecord
(src_base+exitAnchor).collect_variation_indices (c);
}
- EntryExitRecord* copy (hb_serialize_context_t *c,
- const void *src_base,
- const void *dst_base,
- const hb_map_t *layout_variation_idx_map) const
+ EntryExitRecord* subset (hb_subset_context_t *c,
+ const void *src_base) const
{
TRACE_SERIALIZE (this);
- auto *out = c->embed (this);
+ auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (nullptr);
- out->entryAnchor.serialize_copy (c, entryAnchor, src_base, c->to_bias (dst_base), hb_serialize_context_t::Head, layout_variation_idx_map);
- out->exitAnchor.serialize_copy (c, exitAnchor, src_base, c->to_bias (dst_base), hb_serialize_context_t::Head, layout_variation_idx_map);
+ out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
+ out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
return_trace (out);
}
protected:
- OffsetTo<Anchor>
+ Offset16To<Anchor>
entryAnchor; /* Offset to EntryAnchor table--from
* beginning of CursivePos
* subtable--may be NULL */
- OffsetTo<Anchor>
+ Offset16To<Anchor>
exitAnchor; /* Offset to ExitAnchor table--from
* beginning of CursivePos
* subtable--may be NULL */
@@ -1712,7 +1880,7 @@ struct CursivePosFormat1
else
pos[child].x_offset = x_offset;
- /* If parent was attached to child, break them free.
+ /* If parent was attached to child, separate them.
* https://github.com/harfbuzz/harfbuzz/issues/2469
*/
if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain()))
@@ -1724,25 +1892,24 @@ struct CursivePosFormat1
template <typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
- void serialize (hb_serialize_context_t *c,
+ void serialize (hb_subset_context_t *c,
Iterator it,
- const void *src_base,
- const hb_map_t *layout_variation_idx_map)
+ const void *src_base)
{
- if (unlikely (!c->extend_min ((*this)))) return;
+ if (unlikely (!c->serializer->extend_min ((*this)))) return;
this->format = 1;
this->entryExitRecord.len = it.len ();
for (const EntryExitRecord& entry_record : + it
| hb_map (hb_second))
- c->copy (entry_record, src_base, this, layout_variation_idx_map);
+ entry_record.subset (c, src_base);
auto glyphs =
+ it
| hb_map_retains_sorting (hb_first)
;
- coverage.serialize (c, this).serialize (c, glyphs);
+ coverage.serialize_serialize (c->serializer, glyphs);
}
bool subset (hb_subset_context_t *c) const
@@ -1762,7 +1929,7 @@ struct CursivePosFormat1
;
bool ret = bool (it);
- out->serialize (c->serializer, it, this, c->plan->layout_variation_idx_map);
+ out->serialize (c, it, this);
return_trace (ret);
}
@@ -1774,10 +1941,10 @@ struct CursivePosFormat1
protected:
HBUINT16 format; /* Format identifier--format = 1 */
- OffsetTo<Coverage>
+ Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
- ArrayOf<EntryExitRecord>
+ Array16Of<EntryExitRecord>
entryExitRecord; /* Array of EntryExit records--in
* Coverage Index order */
public:
@@ -1949,13 +2116,12 @@ struct MarkBasePosFormat1
| hb_sink (new_coverage)
;
- if (!out->markCoverage.serialize (c->serializer, out)
- .serialize (c->serializer, new_coverage.iter ()))
+ if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
- out->markArray.serialize (c->serializer, out)
- .serialize (c->serializer, &klass_mapping, c->plan->layout_variation_idx_map, &(this+markArray), + mark_iter
- | hb_map (hb_second));
+ out->markArray.serialize_subset (c, markArray, this,
+ (this+markCoverage).iter (),
+ &klass_mapping);
unsigned basecount = (this+baseArray).rows;
auto base_iter =
@@ -1970,8 +2136,7 @@ struct MarkBasePosFormat1
| hb_sink (new_coverage)
;
- if (!out->baseCoverage.serialize (c->serializer, out)
- .serialize (c->serializer, new_coverage.iter ()))
+ if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
hb_sorted_vector_t<unsigned> base_indexes;
@@ -1984,8 +2149,10 @@ struct MarkBasePosFormat1
| hb_sink (base_indexes)
;
}
- out->baseArray.serialize (c->serializer, out)
- .serialize (c->serializer, base_iter.len (), &(this+baseArray), c->plan->layout_variation_idx_map, base_indexes.iter ());
+
+ out->baseArray.serialize_subset (c, baseArray, this,
+ base_iter.len (),
+ base_indexes.iter ());
return_trace (true);
}
@@ -2002,17 +2169,17 @@ struct MarkBasePosFormat1
protected:
HBUINT16 format; /* Format identifier--format = 1 */
- OffsetTo<Coverage>
+ Offset16To<Coverage>
markCoverage; /* Offset to MarkCoverage table--from
* beginning of MarkBasePos subtable */
- OffsetTo<Coverage>
+ Offset16To<Coverage>
baseCoverage; /* Offset to BaseCoverage table--from
* beginning of MarkBasePos subtable */
HBUINT16 classCount; /* Number of classes defined for marks */
- OffsetTo<MarkArray>
+ Offset16To<MarkArray>
markArray; /* Offset to MarkArray table--from
* beginning of MarkBasePos subtable */
- OffsetTo<BaseArray>
+ Offset16To<BaseArray>
baseArray; /* Offset to BaseArray table--from
* beginning of MarkBasePos subtable */
public:
@@ -2046,12 +2213,12 @@ typedef AnchorMatrix LigatureAttach; /* component-major--
* ordered by class--zero-based. */
/* Array of LigatureAttach tables ordered by LigatureCoverage Index */
-struct LigatureArray : OffsetListOf<LigatureAttach>
+struct LigatureArray : List16OfOffset16To<LigatureAttach>
{
template <typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool subset (hb_subset_context_t *c,
- Iterator coverage,
+ Iterator coverage,
unsigned class_count,
const hb_map_t *klass_mapping) const
{
@@ -2067,11 +2234,16 @@ struct LigatureArray : OffsetListOf<LigatureAttach>
auto *matrix = out->serialize_append (c->serializer);
if (unlikely (!matrix)) return_trace (false);
+ const LigatureAttach& src = (this + _.second);
+ auto indexes =
+ + hb_range (src.rows * class_count)
+ | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
+ ;
matrix->serialize_subset (c,
_.second,
this,
- class_count,
- klass_mapping);
+ src.rows,
+ indexes);
}
return_trace (this->len);
}
@@ -2201,17 +2373,12 @@ struct MarkLigPosFormat1
| hb_map_retains_sorting (glyph_map)
;
- if (!out->markCoverage.serialize (c->serializer, out)
- .serialize (c->serializer, new_mark_coverage))
+ if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
return_trace (false);
- out->markArray.serialize (c->serializer, out)
- .serialize (c->serializer,
- &klass_mapping,
- c->plan->layout_variation_idx_map,
- &(this+markArray),
- + mark_iter
- | hb_map (hb_second));
+ out->markArray.serialize_subset (c, markArray, this,
+ (this+markCoverage).iter (),
+ &klass_mapping);
auto new_ligature_coverage =
+ hb_iter (this + ligatureCoverage)
@@ -2219,8 +2386,7 @@ struct MarkLigPosFormat1
| hb_map_retains_sorting (glyph_map)
;
- if (!out->ligatureCoverage.serialize (c->serializer, out)
- .serialize (c->serializer, new_ligature_coverage))
+ if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
return_trace (false);
out->ligatureArray.serialize_subset (c, ligatureArray, this,
@@ -2241,18 +2407,18 @@ struct MarkLigPosFormat1
protected:
HBUINT16 format; /* Format identifier--format = 1 */
- OffsetTo<Coverage>
+ Offset16To<Coverage>
markCoverage; /* Offset to Mark Coverage table--from
* beginning of MarkLigPos subtable */
- OffsetTo<Coverage>
+ Offset16To<Coverage>
ligatureCoverage; /* Offset to Ligature Coverage
* table--from beginning of MarkLigPos
* subtable */
HBUINT16 classCount; /* Number of defined mark classes */
- OffsetTo<MarkArray>
+ Offset16To<MarkArray>
markArray; /* Offset to MarkArray table--from
* beginning of MarkLigPos subtable */
- OffsetTo<LigatureArray>
+ Offset16To<LigatureArray>
ligatureArray; /* Offset to LigatureArray table--from
* beginning of MarkLigPos subtable */
public:
@@ -2409,13 +2575,12 @@ struct MarkMarkPosFormat1
| hb_sink (new_coverage)
;
- if (!out->mark1Coverage.serialize (c->serializer, out)
- .serialize (c->serializer, new_coverage.iter ()))
+ if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
- out->mark1Array.serialize (c->serializer, out)
- .serialize (c->serializer, &klass_mapping, c->plan->layout_variation_idx_map, &(this+mark1Array), + mark1_iter
- | hb_map (hb_second));
+ out->mark1Array.serialize_subset (c, mark1Array, this,
+ (this+mark1Coverage).iter (),
+ &klass_mapping);
unsigned mark2count = (this+mark2Array).rows;
auto mark2_iter =
@@ -2430,8 +2595,7 @@ struct MarkMarkPosFormat1
| hb_sink (new_coverage)
;
- if (!out->mark2Coverage.serialize (c->serializer, out)
- .serialize (c->serializer, new_coverage.iter ()))
+ if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
hb_sorted_vector_t<unsigned> mark2_indexes;
@@ -2444,8 +2608,8 @@ struct MarkMarkPosFormat1
| hb_sink (mark2_indexes)
;
}
- out->mark2Array.serialize (c->serializer, out)
- .serialize (c->serializer, mark2_iter.len (), &(this+mark2Array), c->plan->layout_variation_idx_map, mark2_indexes.iter ());
+
+ out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ());
return_trace (true);
}
@@ -2462,19 +2626,19 @@ struct MarkMarkPosFormat1
protected:
HBUINT16 format; /* Format identifier--format = 1 */
- OffsetTo<Coverage>
+ Offset16To<Coverage>
mark1Coverage; /* Offset to Combining Mark1 Coverage
* table--from beginning of MarkMarkPos
* subtable */
- OffsetTo<Coverage>
+ Offset16To<Coverage>
mark2Coverage; /* Offset to Combining Mark2 Coverage
* table--from beginning of MarkMarkPos
* subtable */
HBUINT16 classCount; /* Number of defined mark classes */
- OffsetTo<MarkArray>
+ Offset16To<MarkArray>
mark1Array; /* Offset to Mark1Array table--from
* beginning of MarkMarkPos subtable */
- OffsetTo<Mark2Array>
+ Offset16To<Mark2Array>
mark2Array; /* Offset to Mark2Array table--from
* beginning of MarkMarkPos subtable */
public:
@@ -2663,7 +2827,7 @@ struct GPOS : GSUBGPOS
bool subset (hb_subset_context_t *c) const
{
- hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_features);
+ hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features);
return GSUBGPOS::subset<PosLookup> (&l);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh
index 5f10ecb7ee..393ada1351 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh
index 36a95ead15..f1c111a4a5 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh
@@ -52,23 +52,32 @@ struct hb_intersects_context_t :
const hb_set_t *glyphs;
hb_intersects_context_t (const hb_set_t *glyphs_) :
- glyphs (glyphs_) {}
+ glyphs (glyphs_) {}
+};
+
+struct hb_have_non_1to1_context_t :
+ hb_dispatch_context_t<hb_have_non_1to1_context_t, bool>
+{
+ template <typename T>
+ return_t dispatch (const T &obj) { return obj.may_have_non_1to1 (); }
+ static return_t default_return_value () { return false; }
+ bool stop_sublookup_iteration (return_t r) const { return r; }
};
struct hb_closure_context_t :
hb_dispatch_context_t<hb_closure_context_t>
{
- typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
+ typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indicies, unsigned seq_index, unsigned end_index);
template <typename T>
return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); }
static return_t default_return_value () { return hb_empty_t (); }
- void recurse (unsigned int lookup_index)
+ void recurse (unsigned lookup_index, hb_set_t *covered_seq_indicies, unsigned seq_index, unsigned end_index)
{
if (unlikely (nesting_level_left == 0 || !recurse_func))
return;
nesting_level_left--;
- recurse_func (this, lookup_index);
+ recurse_func (this, lookup_index, covered_seq_indicies, seq_index, end_index);
nesting_level_left++;
}
@@ -83,36 +92,90 @@ struct hb_closure_context_t :
if (is_lookup_done (lookup_index))
return false;
- done_lookups->set (lookup_index, glyphs->get_population ());
return true;
}
bool is_lookup_done (unsigned int lookup_index)
{
- if (unlikely (done_lookups->in_error ()))
+ if (done_lookups_glyph_count->in_error () ||
+ done_lookups_glyph_set->in_error ())
return true;
/* Have we visited this lookup with the current set of glyphs? */
- return done_lookups->get (lookup_index) == glyphs->get_population ();
+ if (done_lookups_glyph_count->get (lookup_index) != glyphs->get_population ())
+ {
+ done_lookups_glyph_count->set (lookup_index, glyphs->get_population ());
+
+ if (!done_lookups_glyph_set->get (lookup_index))
+ {
+ hb_set_t* empty_set = hb_set_create ();
+ if (unlikely (!done_lookups_glyph_set->set (lookup_index, empty_set)))
+ {
+ hb_set_destroy (empty_set);
+ return true;
+ }
+ }
+
+ hb_set_clear (done_lookups_glyph_set->get (lookup_index));
+ }
+
+ hb_set_t *covered_glyph_set = done_lookups_glyph_set->get (lookup_index);
+ if (unlikely (covered_glyph_set->in_error ()))
+ return true;
+ if (parent_active_glyphs ()->is_subset (*covered_glyph_set))
+ return true;
+
+ hb_set_union (covered_glyph_set, parent_active_glyphs ());
+ return false;
+ }
+
+ hb_set_t* parent_active_glyphs ()
+ {
+ if (active_glyphs_stack.length < 1)
+ return glyphs;
+
+ return active_glyphs_stack.tail ();
+ }
+
+ void push_cur_active_glyphs (hb_set_t* cur_active_glyph_set)
+ {
+ active_glyphs_stack.push (cur_active_glyph_set);
+ }
+
+ bool pop_cur_done_glyphs ()
+ {
+ if (active_glyphs_stack.length < 1)
+ return false;
+
+ active_glyphs_stack.pop ();
+ return true;
}
hb_face_t *face;
hb_set_t *glyphs;
+ hb_set_t *cur_intersected_glyphs;
hb_set_t output[1];
+ hb_vector_t<hb_set_t *> active_glyphs_stack;
recurse_func_t recurse_func;
unsigned int nesting_level_left;
hb_closure_context_t (hb_face_t *face_,
hb_set_t *glyphs_,
- hb_map_t *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_,
unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
face (face_),
glyphs (glyphs_),
+ cur_intersected_glyphs (cur_intersected_glyphs_),
recurse_func (nullptr),
nesting_level_left (nesting_level_left_),
- done_lookups (done_lookups_),
+ done_lookups_glyph_count (done_lookups_glyph_count_),
+ done_lookups_glyph_set (done_lookups_glyph_set_),
lookup_count (0)
- {}
+ {
+ push_cur_active_glyphs (glyphs_);
+ }
~hb_closure_context_t () { flush (); }
@@ -120,16 +183,21 @@ struct hb_closure_context_t :
void flush ()
{
- hb_set_del_range (output, face->get_num_glyphs (), hb_set_get_max (output)); /* Remove invalid glyphs. */
+ hb_set_del_range (output, face->get_num_glyphs (), HB_SET_VALUE_INVALID); /* Remove invalid glyphs. */
hb_set_union (glyphs, output);
hb_set_clear (output);
+ active_glyphs_stack.pop ();
+ active_glyphs_stack.fini ();
}
private:
- hb_map_t *done_lookups;
+ hb_map_t *done_lookups_glyph_count;
+ hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *done_lookups_glyph_set;
unsigned int lookup_count;
};
+
+
struct hb_closure_lookups_context_t :
hb_dispatch_context_t<hb_closure_lookups_context_t>
{
@@ -737,12 +805,14 @@ struct hb_get_subtables_context_t :
typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
+typedef void (*intersected_glyphs_func_t) (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs);
typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
struct ContextClosureFuncs
{
intersects_func_t intersects;
+ intersected_glyphs_func_t intersected_glyphs;
};
struct ContextCollectGlyphsFuncs
{
@@ -765,10 +835,29 @@ static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &val
}
static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
{
- const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
+ const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
return (data+coverage).intersects (glyphs);
}
+
+static inline void intersected_glyph (const hb_set_t *glyphs HB_UNUSED, const void *data, unsigned value, hb_set_t *intersected_glyphs)
+{
+ unsigned g = reinterpret_cast<const HBUINT16 *>(data)[value];
+ intersected_glyphs->add (g);
+}
+static inline void intersected_class_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs)
+{
+ const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+ class_def.intersected_class_glyphs (glyphs, value, intersected_glyphs);
+}
+static inline void intersected_coverage_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs)
+{
+ Offset16To<Coverage> coverage;
+ coverage = value;
+ (data+coverage).intersected_coverage_glyphs (glyphs, intersected_glyphs);
+}
+
+
static inline bool array_is_subset_of (const hb_set_t *glyphs,
unsigned int count,
const HBUINT16 values[],
@@ -792,7 +881,7 @@ static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const
}
static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
{
- const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
+ const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
(data+coverage).collect_coverage (glyphs);
}
static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
@@ -820,7 +909,7 @@ static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value,
}
static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
{
- const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
+ const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
}
@@ -1146,10 +1235,79 @@ struct LookupRecord
DEFINE_SIZE_STATIC (4);
};
+enum ContextFormat { SimpleContext = 1, ClassBasedContext = 2, CoverageBasedContext = 3 };
+
+static void context_closure_recurse_lookups (hb_closure_context_t *c,
+ unsigned inputCount, const HBUINT16 input[],
+ unsigned lookupCount,
+ const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */,
+ unsigned value,
+ ContextFormat context_format,
+ const void *data,
+ intersected_glyphs_func_t intersected_glyphs_func)
+{
+ hb_set_t *covered_seq_indicies = hb_set_create ();
+ for (unsigned int i = 0; i < lookupCount; i++)
+ {
+ unsigned seqIndex = lookupRecord[i].sequenceIndex;
+ if (seqIndex >= inputCount) continue;
+
+ hb_set_t *pos_glyphs = nullptr;
+
+ if (hb_set_is_empty (covered_seq_indicies) || !hb_set_has (covered_seq_indicies, seqIndex))
+ {
+ pos_glyphs = hb_set_create ();
+ if (seqIndex == 0)
+ {
+ switch (context_format) {
+ case ContextFormat::SimpleContext:
+ pos_glyphs->add (value);
+ break;
+ case ContextFormat::ClassBasedContext:
+ intersected_glyphs_func (c->cur_intersected_glyphs, data, value, pos_glyphs);
+ break;
+ case ContextFormat::CoverageBasedContext:
+ hb_set_set (pos_glyphs, c->cur_intersected_glyphs);
+ break;
+ }
+ }
+ else
+ {
+ const void *input_data = input;
+ unsigned input_value = seqIndex - 1;
+ if (context_format != ContextFormat::SimpleContext)
+ {
+ input_data = data;
+ input_value = input[seqIndex - 1];
+ }
+
+ intersected_glyphs_func (c->glyphs, input_data, input_value, pos_glyphs);
+ }
+ }
+
+ hb_set_add (covered_seq_indicies, seqIndex);
+ if (pos_glyphs)
+ c->push_cur_active_glyphs (pos_glyphs);
+
+ unsigned endIndex = inputCount;
+ if (context_format == ContextFormat::CoverageBasedContext)
+ endIndex += 1;
+
+ c->recurse (lookupRecord[i].lookupListIndex, covered_seq_indicies, seqIndex, endIndex);
+
+ if (pos_glyphs) {
+ c->pop_cur_done_glyphs ();
+ hb_set_destroy (pos_glyphs);
+ }
+ }
+
+ hb_set_destroy (covered_seq_indicies);
+}
+
template <typename context_t>
static inline void recurse_lookups (context_t *c,
- unsigned int lookupCount,
- const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
+ unsigned int lookupCount,
+ const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
{
for (unsigned int i = 0; i < lookupCount; i++)
c->recurse (lookupRecord[i].lookupListIndex);
@@ -1284,6 +1442,7 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c,
struct ContextClosureLookupContext
{
ContextClosureFuncs funcs;
+ ContextFormat context_format;
const void *intersects_data;
};
@@ -1314,13 +1473,19 @@ static inline void context_closure_lookup (hb_closure_context_t *c,
const HBUINT16 input[], /* Array of input values--start with second glyph */
unsigned int lookupCount,
const LookupRecord lookupRecord[],
+ unsigned value, /* Index of first glyph in Coverage or Class value in ClassDef table */
ContextClosureLookupContext &lookup_context)
{
if (context_intersects (c->glyphs,
inputCount, input,
lookup_context))
- recurse_lookups (c,
- lookupCount, lookupRecord);
+ context_closure_recurse_lookups (c,
+ inputCount, input,
+ lookupCount, lookupRecord,
+ value,
+ lookup_context.context_format,
+ lookup_context.intersects_data,
+ lookup_context.funcs.intersected_glyphs);
}
static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
@@ -1377,7 +1542,7 @@ struct Rule
lookup_context);
}
- void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
+ void closure (hb_closure_context_t *c, unsigned value, ContextClosureLookupContext &lookup_context) const
{
if (unlikely (c->lookup_limit_exceeded ())) return;
@@ -1386,7 +1551,7 @@ struct Rule
context_closure_lookup (c,
inputCount, inputZ.arrayZ,
lookupCount, lookupRecord.arrayZ,
- lookup_context);
+ value, lookup_context);
}
void closure_lookups (hb_closure_lookups_context_t *c,
@@ -1511,7 +1676,7 @@ struct RuleSet
;
}
- void closure (hb_closure_context_t *c,
+ void closure (hb_closure_context_t *c, unsigned value,
ContextClosureLookupContext &lookup_context) const
{
if (unlikely (c->lookup_limit_exceeded ())) return;
@@ -1519,7 +1684,7 @@ struct RuleSet
return
+ hb_iter (rule)
| hb_map (hb_add (this))
- | hb_apply ([&] (const Rule &_) { _.closure (c, lookup_context); })
+ | hb_apply ([&] (const Rule &_) { _.closure (c, value, lookup_context); })
;
}
@@ -1577,7 +1742,7 @@ struct RuleSet
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
- for (const OffsetTo<Rule>& _ : rule)
+ for (const Offset16To<Rule>& _ : rule)
{
if (!_) continue;
auto *o = out->rule.serialize_append (c->serializer);
@@ -1604,7 +1769,7 @@ struct RuleSet
}
protected:
- OffsetArrayOf<Rule>
+ Array16OfOffset16To<Rule>
rule; /* Array of Rule tables
* ordered by preference */
public:
@@ -1617,7 +1782,8 @@ struct ContextFormat1
bool intersects (const hb_set_t *glyphs) const
{
struct ContextClosureLookupContext lookup_context = {
- {intersects_glyph},
+ {intersects_glyph, intersected_glyph},
+ ContextFormat::SimpleContext,
nullptr
};
@@ -1631,25 +1797,32 @@ struct ContextFormat1
;
}
+ bool may_have_non_1to1 () const
+ { return true; }
+
void closure (hb_closure_context_t *c) const
{
+ c->cur_intersected_glyphs->clear ();
+ get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+
struct ContextClosureLookupContext lookup_context = {
- {intersects_glyph},
+ {intersects_glyph, intersected_glyph},
+ ContextFormat::SimpleContext,
nullptr
};
- + hb_zip (this+coverage, ruleSet)
- | hb_filter (*c->glyphs, hb_first)
- | hb_map (hb_second)
- | hb_map (hb_add (this))
- | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
+ + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
+ | hb_filter (c->parent_active_glyphs (), hb_first)
+ | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const RuleSet&> (_.first, this+ruleSet[_.second]); })
+ | hb_apply ([&] (const hb_pair_t<unsigned, const RuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const
{
struct ContextClosureLookupContext lookup_context = {
- {intersects_glyph},
+ {intersects_glyph, intersected_glyph},
+ ContextFormat::SimpleContext,
nullptr
};
@@ -1725,8 +1898,7 @@ struct ContextFormat1
| 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));
}
@@ -1738,10 +1910,10 @@ struct ContextFormat1
protected:
HBUINT16 format; /* Format identifier--format = 1 */
- OffsetTo<Coverage>
+ Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of table */
- OffsetArrayOf<RuleSet>
+ Array16OfOffset16To<RuleSet>
ruleSet; /* Array of RuleSet tables
* ordered by Coverage Index */
public:
@@ -1759,7 +1931,8 @@ struct ContextFormat2
const ClassDef &class_def = this+classDef;
struct ContextClosureLookupContext lookup_context = {
- {intersects_class},
+ {intersects_class, intersected_class_glyphs},
+ ContextFormat::ClassBasedContext,
&class_def
};
@@ -1774,26 +1947,35 @@ struct ContextFormat2
;
}
+ bool may_have_non_1to1 () const
+ { return true; }
+
void closure (hb_closure_context_t *c) const
{
if (!(this+coverage).intersects (c->glyphs))
return;
+ c->cur_intersected_glyphs->clear ();
+ get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+
const ClassDef &class_def = this+classDef;
struct ContextClosureLookupContext lookup_context = {
- {intersects_class},
+ {intersects_class, intersected_class_glyphs},
+ ContextFormat::ClassBasedContext,
&class_def
};
return
+ hb_enumerate (ruleSet)
| hb_filter ([&] (unsigned _)
- { return class_def.intersects_class (c->glyphs, _); },
+ { return class_def.intersects_class (c->cur_intersected_glyphs, _); },
hb_first)
- | hb_map (hb_second)
- | hb_map (hb_add (this))
- | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
+ | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<RuleSet>&> _)
+ {
+ const RuleSet& rule_set = this+_.second;
+ rule_set.closure (c, _.first, lookup_context);
+ })
;
}
@@ -1805,7 +1987,8 @@ struct ContextFormat2
const ClassDef &class_def = this+classDef;
struct ContextClosureLookupContext lookup_context = {
- {intersects_class},
+ {intersects_class, intersected_class_glyphs},
+ ContextFormat::ClassBasedContext,
&class_def
};
@@ -1919,13 +2102,13 @@ struct ContextFormat2
protected:
HBUINT16 format; /* Format identifier--format = 2 */
- OffsetTo<Coverage>
+ Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of table */
- OffsetTo<ClassDef>
+ Offset16To<ClassDef>
classDef; /* Offset to glyph ClassDef table--from
* beginning of table */
- OffsetArrayOf<RuleSet>
+ Array16OfOffset16To<RuleSet>
ruleSet; /* Array of RuleSet tables
* ordered by class */
public:
@@ -1941,7 +2124,8 @@ struct ContextFormat3
return false;
struct ContextClosureLookupContext lookup_context = {
- {intersects_coverage},
+ {intersects_coverage, intersected_coverage_glyphs},
+ ContextFormat::CoverageBasedContext,
this
};
return context_intersects (glyphs,
@@ -1949,20 +2133,27 @@ struct ContextFormat3
lookup_context);
}
+ bool may_have_non_1to1 () const
+ { return true; }
+
void closure (hb_closure_context_t *c) const
{
if (!(this+coverageZ[0]).intersects (c->glyphs))
return;
+ c->cur_intersected_glyphs->clear ();
+ get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
struct ContextClosureLookupContext lookup_context = {
- {intersects_coverage},
+ {intersects_coverage, intersected_coverage_glyphs},
+ ContextFormat::CoverageBasedContext,
this
};
context_closure_lookup (c,
glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
lookupCount, lookupRecord,
- lookup_context);
+ 0, lookup_context);
}
void closure_lookups (hb_closure_lookups_context_t *c) const
@@ -2032,10 +2223,10 @@ struct ContextFormat3
auto coverages = coverageZ.as_array (glyphCount);
- for (const OffsetTo<Coverage>& offset : coverages)
+ for (const Offset16To<Coverage>& offset : coverages)
{
/* TODO(subset) This looks like should not be necessary to write this way. */
- auto *o = c->serializer->allocate_size<OffsetTo<Coverage>> (OffsetTo<Coverage>::static_size);
+ auto *o = c->serializer->allocate_size<Offset16To<Coverage>> (Offset16To<Coverage>::static_size);
if (unlikely (!o)) return_trace (false);
if (!o->serialize_subset (c, offset, this)) return_trace (false);
}
@@ -2066,7 +2257,7 @@ struct ContextFormat3
HBUINT16 glyphCount; /* Number of glyphs in the input glyph
* sequence */
HBUINT16 lookupCount; /* Number of LookupRecords */
- UnsizedArrayOf<OffsetTo<Coverage>>
+ UnsizedArrayOf<Offset16To<Coverage>>
coverageZ; /* Array of offsets to Coverage
* table in glyph sequence order */
/*UnsizedArrayOf<LookupRecord>
@@ -2106,6 +2297,7 @@ struct Context
struct ChainContextClosureLookupContext
{
ContextClosureFuncs funcs;
+ ContextFormat context_format;
const void *intersects_data[3];
};
@@ -2150,6 +2342,7 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
const HBUINT16 lookahead[],
unsigned int lookupCount,
const LookupRecord lookupRecord[],
+ unsigned value,
ChainContextClosureLookupContext &lookup_context)
{
if (chain_context_intersects (c->glyphs,
@@ -2157,8 +2350,13 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
inputCount, input,
lookaheadCount, lookahead,
lookup_context))
- recurse_lookups (c,
- lookupCount, lookupRecord);
+ context_closure_recurse_lookups (c,
+ inputCount, input,
+ lookupCount, lookupRecord,
+ value,
+ lookup_context.context_format,
+ lookup_context.intersects_data[1],
+ lookup_context.funcs.intersected_glyphs);
}
static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
@@ -2239,7 +2437,7 @@ struct ChainRule
bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
{
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
- const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+ const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
return chain_context_intersects (glyphs,
backtrack.len, backtrack.arrayZ,
input.lenP1, input.arrayZ,
@@ -2247,19 +2445,20 @@ struct ChainRule
lookup_context);
}
- void closure (hb_closure_context_t *c,
+ void closure (hb_closure_context_t *c, unsigned value,
ChainContextClosureLookupContext &lookup_context) const
{
if (unlikely (c->lookup_limit_exceeded ())) return;
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
- const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
- const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+ const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
chain_context_closure_lookup (c,
backtrack.len, backtrack.arrayZ,
input.lenP1, input.arrayZ,
lookahead.len, lookahead.arrayZ,
lookup.len, lookup.arrayZ,
+ value,
lookup_context);
}
@@ -2270,8 +2469,8 @@ struct ChainRule
if (!intersects (c->glyphs, lookup_context)) return;
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
- const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
- const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+ const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
recurse_lookups (c, lookup.len, lookup.arrayZ);
}
@@ -2279,8 +2478,8 @@ struct ChainRule
ChainContextCollectGlyphsLookupContext &lookup_context) const
{
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
- const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
- const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+ const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
chain_context_collect_glyphs_lookup (c,
backtrack.len, backtrack.arrayZ,
input.lenP1, input.arrayZ,
@@ -2293,8 +2492,8 @@ struct ChainRule
ChainContextApplyLookupContext &lookup_context) const
{
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
- const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
- const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+ const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
return chain_context_would_apply_lookup (c,
backtrack.len, backtrack.arrayZ,
input.lenP1, input.arrayZ,
@@ -2306,8 +2505,8 @@ struct ChainRule
{
TRACE_APPLY (this);
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
- const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
- const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+ const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
return_trace (chain_context_apply_lookup (c,
backtrack.len, backtrack.arrayZ,
input.lenP1, input.arrayZ,
@@ -2345,12 +2544,12 @@ struct ChainRule
serialize_array (c, input.lenP1, + input.iter ()
| hb_map (mapping));
- const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+ const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
if (lookahead_map) mapping = lookahead_map;
serialize_array (c, lookahead.len, + lookahead.iter ()
| hb_map (mapping));
- const ArrayOf<LookupRecord> &lookupRecord = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ const Array16Of<LookupRecord> &lookupRecord = StructAfter<Array16Of<LookupRecord>> (lookahead);
HBUINT16* lookupCount = c->embed (&(lookupRecord.len));
if (!lookupCount) return_trace (nullptr);
@@ -2377,7 +2576,7 @@ struct ChainRule
TRACE_SUBSET (this);
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
- const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+ const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
if (!backtrack_map)
{
@@ -2408,24 +2607,24 @@ struct ChainRule
if (!backtrack.sanitize (c)) return_trace (false);
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
if (!input.sanitize (c)) return_trace (false);
- const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+ const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
if (!lookahead.sanitize (c)) return_trace (false);
- const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
return_trace (lookup.sanitize (c));
}
protected:
- ArrayOf<HBUINT16>
+ Array16Of<HBUINT16>
backtrack; /* Array of backtracking values
* (to be matched before the input
* sequence) */
HeadlessArrayOf<HBUINT16>
inputX; /* Array of input values (start with
* second glyph) */
- ArrayOf<HBUINT16>
+ Array16Of<HBUINT16>
lookaheadX; /* Array of lookahead values's (to be
* matched after the input sequence) */
- ArrayOf<LookupRecord>
+ Array16Of<LookupRecord>
lookupX; /* Array of LookupRecords--in
* design order) */
public:
@@ -2443,14 +2642,14 @@ struct ChainRuleSet
| hb_any
;
}
- void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
+ void closure (hb_closure_context_t *c, unsigned value, ChainContextClosureLookupContext &lookup_context) const
{
if (unlikely (c->lookup_limit_exceeded ())) return;
return
+ hb_iter (rule)
| hb_map (hb_add (this))
- | hb_apply ([&] (const ChainRule &_) { _.closure (c, lookup_context); })
+ | hb_apply ([&] (const ChainRule &_) { _.closure (c, value, lookup_context); })
;
}
@@ -2508,7 +2707,7 @@ struct ChainRuleSet
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
- for (const OffsetTo<ChainRule>& _ : rule)
+ for (const Offset16To<ChainRule>& _ : rule)
{
if (!_) continue;
auto *o = out->rule.serialize_append (c->serializer);
@@ -2539,7 +2738,7 @@ struct ChainRuleSet
}
protected:
- OffsetArrayOf<ChainRule>
+ Array16OfOffset16To<ChainRule>
rule; /* Array of ChainRule tables
* ordered by preference */
public:
@@ -2551,7 +2750,8 @@ struct ChainContextFormat1
bool intersects (const hb_set_t *glyphs) const
{
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_glyph},
+ {intersects_glyph, intersected_glyph},
+ ContextFormat::SimpleContext,
{nullptr, nullptr, nullptr}
};
@@ -2565,25 +2765,32 @@ struct ChainContextFormat1
;
}
+ bool may_have_non_1to1 () const
+ { return true; }
+
void closure (hb_closure_context_t *c) const
{
+ c->cur_intersected_glyphs->clear ();
+ get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_glyph},
+ {intersects_glyph, intersected_glyph},
+ ContextFormat::SimpleContext,
{nullptr, nullptr, nullptr}
};
- + hb_zip (this+coverage, ruleSet)
- | hb_filter (*c->glyphs, hb_first)
- | hb_map (hb_second)
- | hb_map (hb_add (this))
- | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
+ + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
+ | hb_filter (c->parent_active_glyphs (), hb_first)
+ | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const ChainRuleSet&> (_.first, this+ruleSet[_.second]); })
+ | hb_apply ([&] (const hb_pair_t<unsigned, const ChainRuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const
{
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_glyph},
+ {intersects_glyph, intersected_glyph},
+ ContextFormat::SimpleContext,
{nullptr, nullptr, nullptr}
};
@@ -2658,8 +2865,7 @@ struct ChainContextFormat1
| 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));
}
@@ -2671,10 +2877,10 @@ struct ChainContextFormat1
protected:
HBUINT16 format; /* Format identifier--format = 1 */
- OffsetTo<Coverage>
+ Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of table */
- OffsetArrayOf<ChainRuleSet>
+ Array16OfOffset16To<ChainRuleSet>
ruleSet; /* Array of ChainRuleSet tables
* ordered by Coverage Index */
public:
@@ -2693,7 +2899,8 @@ struct ChainContextFormat2
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_class},
+ {intersects_class, intersected_class_glyphs},
+ ContextFormat::ClassBasedContext,
{&backtrack_class_def,
&input_class_def,
&lookahead_class_def}
@@ -2709,17 +2916,25 @@ struct ChainContextFormat2
| hb_any
;
}
+
+ bool may_have_non_1to1 () const
+ { return true; }
+
void closure (hb_closure_context_t *c) const
{
if (!(this+coverage).intersects (c->glyphs))
return;
+ c->cur_intersected_glyphs->clear ();
+ get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+
const ClassDef &backtrack_class_def = this+backtrackClassDef;
const ClassDef &input_class_def = this+inputClassDef;
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_class},
+ {intersects_class, intersected_class_glyphs},
+ ContextFormat::ClassBasedContext,
{&backtrack_class_def,
&input_class_def,
&lookahead_class_def}
@@ -2728,11 +2943,13 @@ struct ChainContextFormat2
return
+ hb_enumerate (ruleSet)
| hb_filter ([&] (unsigned _)
- { return input_class_def.intersects_class (c->glyphs, _); },
+ { return input_class_def.intersects_class (c->cur_intersected_glyphs, _); },
hb_first)
- | hb_map (hb_second)
- | hb_map (hb_add (this))
- | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
+ | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<ChainRuleSet>&> _)
+ {
+ const ChainRuleSet& chainrule_set = this+_.second;
+ chainrule_set.closure (c, _.first, lookup_context);
+ })
;
}
@@ -2746,7 +2963,8 @@ struct ChainContextFormat2
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_class},
+ {intersects_class, intersected_class_glyphs},
+ ContextFormat::ClassBasedContext,
{&backtrack_class_def,
&input_class_def,
&lookahead_class_def}
@@ -2852,7 +3070,7 @@ struct ChainContextFormat2
bool ret = true;
const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
auto last_non_zero = c->serializer->snapshot ();
- for (const OffsetTo<ChainRuleSet>& _ : + hb_enumerate (ruleSet)
+ for (const Offset16To<ChainRuleSet>& _ : + hb_enumerate (ruleSet)
| hb_filter (input_klass_map, hb_first)
| hb_map (hb_second))
{
@@ -2898,22 +3116,22 @@ struct ChainContextFormat2
protected:
HBUINT16 format; /* Format identifier--format = 2 */
- OffsetTo<Coverage>
+ Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of table */
- OffsetTo<ClassDef>
+ Offset16To<ClassDef>
backtrackClassDef; /* Offset to glyph ClassDef table
* containing backtrack sequence
* data--from beginning of table */
- OffsetTo<ClassDef>
+ Offset16To<ClassDef>
inputClassDef; /* Offset to glyph ClassDef
* table containing input sequence
* data--from beginning of table */
- OffsetTo<ClassDef>
+ Offset16To<ClassDef>
lookaheadClassDef; /* Offset to glyph ClassDef table
* containing lookahead sequence
* data--from beginning of table */
- OffsetArrayOf<ChainRuleSet>
+ Array16OfOffset16To<ChainRuleSet>
ruleSet; /* Array of ChainRuleSet tables
* ordered by class */
public:
@@ -2924,14 +3142,15 @@ struct ChainContextFormat3
{
bool intersects (const hb_set_t *glyphs) const
{
- const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+ const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
if (!(this+input[0]).intersects (glyphs))
return false;
- const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+ const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_coverage},
+ {intersects_coverage, intersected_coverage_glyphs},
+ ContextFormat::CoverageBasedContext,
{this, this, this}
};
return chain_context_intersects (glyphs,
@@ -2941,17 +3160,24 @@ struct ChainContextFormat3
lookup_context);
}
+ bool may_have_non_1to1 () const
+ { return true; }
+
void closure (hb_closure_context_t *c) const
{
- const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+ const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
if (!(this+input[0]).intersects (c->glyphs))
return;
- const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
- const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ c->cur_intersected_glyphs->clear ();
+ get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs);
+
+ const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+ const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_coverage},
+ {intersects_coverage, intersected_coverage_glyphs},
+ ContextFormat::CoverageBasedContext,
{this, this, this}
};
chain_context_closure_lookup (c,
@@ -2959,7 +3185,7 @@ struct ChainContextFormat3
input.len, (const HBUINT16 *) input.arrayZ + 1,
lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
lookup.len, lookup.arrayZ,
- lookup_context);
+ 0, lookup_context);
}
void closure_lookups (hb_closure_lookups_context_t *c) const
@@ -2967,9 +3193,9 @@ struct ChainContextFormat3
if (!intersects (c->glyphs))
return;
- const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
- const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
- const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+ const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+ const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
recurse_lookups (c, lookup.len, lookup.arrayZ);
}
@@ -2977,12 +3203,12 @@ struct ChainContextFormat3
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
- const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+ const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
(this+input[0]).collect_coverage (c->input);
- const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
- const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+ const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
struct ChainContextCollectGlyphsLookupContext lookup_context = {
{collect_coverage},
{this, this, this}
@@ -2997,9 +3223,9 @@ struct ChainContextFormat3
bool would_apply (hb_would_apply_context_t *c) const
{
- const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
- const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
- const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+ const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+ const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
struct ChainContextApplyLookupContext lookup_context = {
{match_coverage},
{this, this, this}
@@ -3013,20 +3239,20 @@ struct ChainContextFormat3
const Coverage &get_coverage () const
{
- const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+ const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
return this+input[0];
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
- const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+ const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
- const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
- const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+ const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
struct ChainContextApplyLookupContext lookup_context = {
{match_coverage},
{this, this, this}
@@ -3043,7 +3269,7 @@ struct ChainContextFormat3
bool serialize_coverage_offsets (hb_subset_context_t *c, Iterator it, const void* base) const
{
TRACE_SERIALIZE (this);
- auto *out = c->serializer->start_embed<OffsetArrayOf<Coverage>> ();
+ auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
return_trace (false);
@@ -3068,15 +3294,15 @@ struct ChainContextFormat3
if (!serialize_coverage_offsets (c, backtrack.iter (), this))
return_trace (false);
- const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+ const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
if (!serialize_coverage_offsets (c, input.iter (), this))
return_trace (false);
- const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+ const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
if (!serialize_coverage_offsets (c, lookahead.iter (), this))
return_trace (false);
- const ArrayOf<LookupRecord> &lookupRecord = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ const Array16Of<LookupRecord> &lookupRecord = StructAfter<Array16Of<LookupRecord>> (lookahead);
HBUINT16 lookupCount;
lookupCount = lookupRecord.len;
if (!c->serializer->copy (lookupCount)) return_trace (false);
@@ -3092,30 +3318,30 @@ struct ChainContextFormat3
{
TRACE_SANITIZE (this);
if (!backtrack.sanitize (c, this)) return_trace (false);
- const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+ const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
if (!input.sanitize (c, this)) return_trace (false);
if (!input.len) return_trace (false); /* To be consistent with Context. */
- const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+ const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
if (!lookahead.sanitize (c, this)) return_trace (false);
- const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+ const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
return_trace (lookup.sanitize (c));
}
protected:
HBUINT16 format; /* Format identifier--format = 3 */
- OffsetArrayOf<Coverage>
+ Array16OfOffset16To<Coverage>
backtrack; /* Array of coverage tables
* in backtracking sequence, in glyph
* sequence order */
- OffsetArrayOf<Coverage>
+ Array16OfOffset16To<Coverage>
inputX ; /* Array of coverage
* tables in input sequence, in glyph
* sequence order */
- OffsetArrayOf<Coverage>
+ Array16OfOffset16To<Coverage>
lookaheadX; /* Array of coverage tables
* in lookahead sequence, in glyph
* sequence order */
- ArrayOf<LookupRecord>
+ Array16Of<LookupRecord>
lookupX; /* Array of LookupRecords--in
* design order) */
public:
@@ -3154,7 +3380,7 @@ struct ExtensionFormat1
template <typename X>
const X& get_subtable () const
- { return this + reinterpret_cast<const LOffsetTo<typename T::SubTable> &> (extensionOffset); }
+ { return this + reinterpret_cast<const Offset32To<typename T::SubTable> &> (extensionOffset); }
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
@@ -3186,9 +3412,9 @@ struct ExtensionFormat1
out->extensionLookupType = extensionLookupType;
const auto& src_offset =
- reinterpret_cast<const LOffsetTo<typename T::SubTable> &> (extensionOffset);
+ reinterpret_cast<const Offset32To<typename T::SubTable> &> (extensionOffset);
auto& dest_offset =
- reinterpret_cast<LOffsetTo<typename T::SubTable> &> (out->extensionOffset);
+ reinterpret_cast<Offset32To<typename T::SubTable> &> (out->extensionOffset);
return_trace (dest_offset.serialize_subset (c, src_offset, this, get_type ()));
}
@@ -3372,6 +3598,20 @@ struct GSUBGPOS
hb_set_subtract (lookup_indexes, &inactive_lookups);
}
+ void prune_langsys (const hb_map_t *duplicate_feature_map,
+ hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *script_langsys_map,
+ hb_set_t *new_feature_indexes /* OUT */) const
+ {
+ hb_prune_langsys_context_t c (this, script_langsys_map, duplicate_feature_map, new_feature_indexes);
+
+ unsigned count = get_script_count ();
+ for (unsigned script_index = 0; script_index < count; script_index++)
+ {
+ const Script& s = get_script (script_index);
+ s.prune_langsys (&c, script_index);
+ }
+ }
+
template <typename TLookup>
bool subset (hb_subset_layout_context_t *c) const
{
@@ -3380,15 +3620,15 @@ struct GSUBGPOS
if (unlikely (!out)) return_trace (false);
typedef LookupOffsetList<TLookup> TLookupList;
- reinterpret_cast<OffsetTo<TLookupList> &> (out->lookupList)
+ reinterpret_cast<Offset16To<TLookupList> &> (out->lookupList)
.serialize_subset (c->subset_context,
- reinterpret_cast<const OffsetTo<TLookupList> &> (lookupList),
+ reinterpret_cast<const Offset16To<TLookupList> &> (lookupList),
this,
c);
- reinterpret_cast<OffsetTo<RecordListOfFeature> &> (out->featureList)
+ reinterpret_cast<Offset16To<RecordListOfFeature> &> (out->featureList)
.serialize_subset (c->subset_context,
- reinterpret_cast<const OffsetTo<RecordListOfFeature> &> (featureList),
+ reinterpret_cast<const Offset16To<RecordListOfFeature> &> (featureList),
this,
c);
@@ -3412,8 +3652,65 @@ struct GSUBGPOS
return_trace (true);
}
+ void find_duplicate_features (const hb_map_t *lookup_indices,
+ const hb_set_t *feature_indices,
+ hb_map_t *duplicate_feature_map /* OUT */) const
+ {
+ //find out duplicate features after subset
+ unsigned prev = 0xFFFFu;
+ for (unsigned i : feature_indices->iter ())
+ {
+ if (prev == 0xFFFFu)
+ {
+ duplicate_feature_map->set (i, i);
+ prev = i;
+ continue;
+ }
+
+ hb_tag_t t = get_feature_tag (i);
+ hb_tag_t prev_t = get_feature_tag (prev);
+ if (t != prev_t)
+ {
+ duplicate_feature_map->set (i, i);
+ prev = i;
+ continue;
+ }
+
+ const Feature& f = get_feature (i);
+ const Feature& prev_f = get_feature (prev);
+
+ auto f_iter =
+ + hb_iter (f.lookupIndex)
+ | hb_filter (lookup_indices)
+ ;
+
+ auto prev_iter =
+ + hb_iter (prev_f.lookupIndex)
+ | hb_filter (lookup_indices)
+ ;
+
+ if (f_iter.len () != prev_iter.len ())
+ {
+ duplicate_feature_map->set (i, i);
+ prev = i;
+ continue;
+ }
+
+ bool is_equal = true;
+ for (auto _ : + hb_zip (f_iter, prev_iter))
+ if (_.first != _.second) { is_equal = false; break; }
+
+ if (is_equal == true) duplicate_feature_map->set (i, prev);
+ else
+ {
+ duplicate_feature_map->set (i, i);
+ prev = i;
+ }
+ }
+ }
+
void prune_features (const hb_map_t *lookup_indices, /* IN */
- hb_set_t *feature_indices /* IN/OUT */) const
+ hb_set_t *feature_indices /* IN/OUT */) const
{
#ifndef HB_NO_VAR
// This is the set of feature indices which have alternate versions defined
@@ -3431,6 +3728,13 @@ struct GSUBGPOS
for (unsigned i : feature_indices->iter())
{
const Feature& f = get_feature (i);
+ hb_tag_t tag = get_feature_tag (i);
+ if (tag == HB_TAG ('p', 'r', 'e', 'f'))
+ // Note: Never ever drop feature 'pref', even if it's empty.
+ // HarfBuzz chooses shaper for Khmer based on presence of this
+ // feature. See thread at:
+ // http://lists.freedesktop.org/archives/harfbuzz/2012-November/002660.html
+ continue;
if (f.featureParams.is_null ()
&& !f.intersects_lookup_indexes (lookup_indices)
@@ -3452,12 +3756,12 @@ struct GSUBGPOS
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- typedef OffsetListOf<TLookup> TLookupList;
+ typedef List16OfOffset16To<TLookup> TLookupList;
if (unlikely (!(version.sanitize (c) &&
likely (version.major == 1) &&
scriptList.sanitize (c, this) &&
featureList.sanitize (c, this) &&
- reinterpret_cast<const OffsetTo<TLookupList> &> (lookupList).sanitize (c, this))))
+ reinterpret_cast<const Offset16To<TLookupList> &> (lookupList).sanitize (c, this))))
return_trace (false);
#ifndef HB_NO_VAR
@@ -3482,7 +3786,7 @@ struct GSUBGPOS
this->lookup_count = table->get_lookup_count ();
- this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
+ this->accels = (hb_ot_layout_lookup_accelerator_t *) hb_calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
if (unlikely (!this->accels))
{
this->lookup_count = 0;
@@ -3498,7 +3802,7 @@ struct GSUBGPOS
{
for (unsigned int i = 0; i < this->lookup_count; i++)
this->accels[i].fini ();
- free (this->accels);
+ hb_free (this->accels);
this->table.destroy ();
}
@@ -3510,13 +3814,13 @@ struct GSUBGPOS
protected:
FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
* to 0x00010000u */
- OffsetTo<ScriptList>
+ Offset16To<ScriptList>
scriptList; /* ScriptList table */
- OffsetTo<FeatureList>
+ Offset16To<FeatureList>
featureList; /* FeatureList table */
- OffsetTo<LookupList>
+ Offset16To<LookupList>
lookupList; /* LookupList table */
- LOffsetTo<FeatureVariations>
+ Offset32To<FeatureVariations>
featureVars; /* Offset to Feature Variations
table--from beginning of table
* (may be NULL). Introduced
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh
index ffd2bf4574..3b2293dff0 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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>
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
index 89df949b26..0454af2063 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
+++ b/src/3rdparty/harfbuzz-ng/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
**/
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh
index ac61bc70de..bcc014ee98 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh
+++ b/src/3rdparty/harfbuzz-ng/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)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc
index e4bb4b6366..b48faf522d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc
@@ -150,9 +150,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 +204,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 +220,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 +274,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 */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh
index 26aa080603..5916ad29f2 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-maxp-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-maxp-table.hh
index 929956d12b..3a019ef782 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-maxp-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-meta-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-meta-table.hh
index 1225e26ce1..e31447f8fc 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-meta-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-name-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-name-table.hh
index ece3c28466..c17bb4abb8 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-name-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh
index 8e98f87f4e..f0035e2f04 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table-v2subset.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table-v2subset.hh
new file mode 100644
index 0000000000..c8ea011269
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table-v2subset.hh
@@ -0,0 +1,114 @@
+/*
+ * 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;
+
+ 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
+ {
+ new_index = 258 + i;
+ old_new_index_map.set (old_index, new_index);
+ i++;
+ }
+ 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);
+ })
+ ;
+
+ post::accelerator_t _post;
+ _post.init (c->plan->source);
+ bool ret = serialize (c->serializer, index_iter, &_post);
+ _post.fini ();
+ return_trace (ret);
+}
+
+} /* namespace OT */
+#endif /* HB_OT_POST_TABLE_V2SUBSET_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh
index f22d6e244d..39de671707 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh
+++ b/src/3rdparty/harfbuzz-ng/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;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic-fallback.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic-fallback.hh
index 244e967b12..2b3b134ae3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/src/3rdparty/harfbuzz-ng/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
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc
index 1f244f940c..1f8c1410fc 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc
+++ b/src/3rdparty/harfbuzz-ng/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
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-hangul.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-hangul.cc
index dbedd6af0c..0d84a76b85 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-hangul.cc
+++ b/src/3rdparty/harfbuzz-ng/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. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc
index a4f2d9a847..0983a32848 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc
+++ b/src/3rdparty/harfbuzz-ng/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);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-khmer.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-khmer.cc
index dddba142a3..7787886857 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-khmer.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-khmer.cc
@@ -42,7 +42,8 @@ khmer_features[] =
{
/*
* Basic features.
- * These features are applied in order, one at a time, after reordering.
+ * These features are applied all at once, before reordering, constrained
+ * to the syllable.
*/
{HB_TAG('p','r','e','f'), F_MANUAL_JOINERS},
{HB_TAG('b','l','w','f'), F_MANUAL_JOINERS},
@@ -147,7 +148,7 @@ struct khmer_shape_plan_t
static void *
data_create_khmer (const hb_ot_shape_plan_t *plan)
{
- khmer_shape_plan_t *khmer_plan = (khmer_shape_plan_t *) calloc (1, sizeof (khmer_shape_plan_t));
+ khmer_shape_plan_t *khmer_plan = (khmer_shape_plan_t *) hb_calloc (1, sizeof (khmer_shape_plan_t));
if (unlikely (!khmer_plan))
return nullptr;
@@ -161,7 +162,7 @@ data_create_khmer (const hb_ot_shape_plan_t *plan)
static void
data_destroy_khmer (void *data)
{
- free (data);
+ hb_free (data);
}
static void
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc
index bc5dcb904c..6e92a9b0ae 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc
@@ -41,7 +41,8 @@ myanmar_basic_features[] =
{
/*
* Basic features.
- * These features are applied in order, one at a time, after reordering.
+ * These features are applied in order, one at a time, after reordering,
+ * constrained to the syllable.
*/
HB_TAG('r','p','h','f'),
HB_TAG('p','r','e','f'),
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-syllabic.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-syllabic.cc
index 46509abee2..5a08f878dc 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-syllabic.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-syllabic.cc
@@ -34,7 +34,8 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
hb_buffer_t *buffer,
unsigned int broken_syllable_type,
unsigned int dottedcircle_category,
- int repha_category)
+ int repha_category,
+ int dottedcircle_position)
{
if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
return;
@@ -61,6 +62,8 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
hb_glyph_info_t dottedcircle = {0};
dottedcircle.codepoint = 0x25CCu;
dottedcircle.complex_var_u8_category() = dottedcircle_category;
+ if (dottedcircle_position != -1)
+ dottedcircle.complex_var_u8_auxiliary() = dottedcircle_position;
dottedcircle.codepoint = dottedcircle_glyph;
buffer->clear_output ();
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-syllabic.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-syllabic.hh
index c80b8fee1d..b901a660d3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-syllabic.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-syllabic.hh
@@ -35,7 +35,8 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
hb_buffer_t *buffer,
unsigned int broken_syllable_type,
unsigned int dottedcircle_category,
- int repha_category = -1);
+ int repha_category = -1,
+ int dottedcircle_position = -1);
#endif /* HB_OT_SHAPE_COMPLEX_SYLLABIC_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-machine.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-machine.hh
index b4b2b75100..96bebcef0c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-machine.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-machine.hh
@@ -375,7 +375,9 @@ hb_iter_with_fallback_t<machine_index_t<Iter>,
typename Iter::item_t>
{
machine_index_t (const Iter& it) : it (it) {}
- machine_index_t (const machine_index_t& o) : it (o.it) {}
+ machine_index_t (const machine_index_t& o) :
+ hb_iter_with_fallback_t<machine_index_t<Iter>, typename Iter::item_t>(o),
+ it (o.it) {}
static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use.cc
index 0d0b7e771e..1e4804c4a2 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use.cc
@@ -47,7 +47,8 @@ use_basic_features[] =
{
/*
* Basic features.
- * These features are applied all at once, before reordering.
+ * These features are applied all at once, before reordering, constrained
+ * to the syllable.
*/
HB_TAG('r','k','r','f'),
HB_TAG('a','b','v','f'),
@@ -154,7 +155,7 @@ struct use_shape_plan_t
static void *
data_create_use (const hb_ot_shape_plan_t *plan)
{
- use_shape_plan_t *use_plan = (use_shape_plan_t *) calloc (1, sizeof (use_shape_plan_t));
+ use_shape_plan_t *use_plan = (use_shape_plan_t *) hb_calloc (1, sizeof (use_shape_plan_t));
if (unlikely (!use_plan))
return nullptr;
@@ -165,7 +166,7 @@ data_create_use (const hb_ot_shape_plan_t *plan)
use_plan->arabic_plan = (arabic_shape_plan_t *) data_create_arabic (plan);
if (unlikely (!use_plan->arabic_plan))
{
- free (use_plan);
+ hb_free (use_plan);
return nullptr;
}
}
@@ -181,7 +182,7 @@ data_destroy_use (void *data)
if (use_plan->arabic_plan)
data_destroy_arabic (use_plan->arabic_plan);
- free (data);
+ hb_free (data);
}
static void
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-fallback.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-fallback.cc
index 7d00a35ab9..eb1bc79768 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-fallback.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-fallback.cc
@@ -92,7 +92,7 @@ recategorize_combining_class (hb_codepoint_t u,
case HB_MODIFIED_COMBINING_CLASS_CCC15: /* tsere */
case HB_MODIFIED_COMBINING_CLASS_CCC16: /* segol */
case HB_MODIFIED_COMBINING_CLASS_CCC17: /* patah */
- case HB_MODIFIED_COMBINING_CLASS_CCC18: /* qamats */
+ case HB_MODIFIED_COMBINING_CLASS_CCC18: /* qamats & qamats qatan */
case HB_MODIFIED_COMBINING_CLASS_CCC20: /* qubuts */
case HB_MODIFIED_COMBINING_CLASS_CCC22: /* meteg */
return HB_UNICODE_COMBINING_CLASS_BELOW;
@@ -104,7 +104,7 @@ recategorize_combining_class (hb_codepoint_t u,
return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
case HB_MODIFIED_COMBINING_CLASS_CCC25: /* sin dot */
- case HB_MODIFIED_COMBINING_CLASS_CCC19: /* holam */
+ case HB_MODIFIED_COMBINING_CLASS_CCC19: /* holam & holam haser for vav */
return HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT;
case HB_MODIFIED_COMBINING_CLASS_CCC26: /* point varika */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
index 86ab0b4268..90d0d99a04 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
@@ -149,13 +149,15 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
* Decide who does positioning. GPOS, kerx, kern, or fallback.
*/
- if (0)
+ bool has_gsub = hb_ot_layout_has_substitution (face);
+ bool has_gpos = !disable_gpos && hb_ot_layout_has_positioning (face);
+ if (false)
;
#ifndef HB_NO_AAT_SHAPE
- else if (hb_aat_layout_has_positioning (face))
+ else if (hb_aat_layout_has_positioning (face) && !(has_gsub && has_gpos))
plan.apply_kerx = true;
#endif
- else if (!apply_morx && !disable_gpos && hb_ot_layout_has_positioning (face))
+ else if (!apply_morx && has_gpos)
plan.apply_gpos = true;
if (!plan.apply_kerx && (!has_gpos_kern || !plan.apply_gpos))
@@ -172,6 +174,8 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
#endif
}
+ plan.apply_fallback_kern = !(plan.apply_gpos || plan.apply_kerx || plan.apply_kern);
+
plan.zero_marks = script_zero_marks &&
!plan.apply_kerx &&
(!plan.apply_kern
@@ -193,6 +197,12 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
script_fallback_mark_positioning;
#ifndef HB_NO_AAT_SHAPE
+ /* If we're using morx shaping, we cancel mark position adjustment because
+ Apple Color Emoji assumes this will NOT be done when forming emoji sequences;
+ https://github.com/harfbuzz/harfbuzz/issues/2967. */
+ if (plan.apply_morx)
+ plan.adjust_mark_positioning_when_zeroing = false;
+
/* Currently we always apply trak. */
plan.apply_trak = plan.requested_tracking && hb_aat_layout_has_tracking (face);
#endif
@@ -266,11 +276,12 @@ hb_ot_shape_plan_t::position (hb_font_t *font,
else if (this->apply_kerx)
hb_aat_layout_position (this, font, buffer);
#endif
+
#ifndef HB_NO_OT_KERN
- else if (this->apply_kern)
+ if (this->apply_kern)
hb_ot_layout_kern (this, font, buffer);
#endif
- else
+ else if (this->apply_fallback_kern)
_hb_ot_shape_fallback_kern (this, font, buffer);
#ifndef HB_NO_AAT_SHAPE
@@ -363,6 +374,10 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
map->add_feature (horizontal_features[i]);
else
{
+ /* We only apply `vert` feature. See:
+ * https://github.com/harfbuzz/harfbuzz/commit/d71c0df2d17f4590d5611239577a6cb532c26528
+ * https://lists.freedesktop.org/archives/harfbuzz/2013-August/003490.html */
+
/* We really want to find a 'vert' feature if there's any in the font, no
* matter which script/langsys it is listed (or not) under.
* See various bugs referenced from:
@@ -478,6 +493,14 @@ hb_set_unicode_props (hb_buffer_t *buffer)
if (unlikely (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL &&
hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F3FBu, 0x1F3FFu)))
{
+ _hb_glyph_info_set_continuation (&info[i]);
+ }
+ /* Regional_Indicators are hairy as hell...
+ * https://github.com/harfbuzz/harfbuzz/issues/2265 */
+ else if (unlikely (i && hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F1E6u, 0x1F1FFu)))
+ {
+ if (hb_in_range<hb_codepoint_t> (info[i - 1].codepoint, 0x1F1E6u, 0x1F1FFu) &&
+ !_hb_glyph_info_is_continuation (&info[i - 1]))
_hb_glyph_info_set_continuation (&info[i]);
}
#ifndef HB_NO_EMOJI_SEQUENCES
@@ -535,6 +558,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
info.cluster = buffer->cur().cluster;
info.mask = buffer->cur().mask;
(void) buffer->output_info (info);
+
buffer->swap_buffers ();
}
@@ -558,6 +582,36 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
hb_direction_t direction = buffer->props.direction;
hb_direction_t horiz_dir = hb_script_get_horizontal_direction (buffer->props.script);
+ /* Numeric runs in natively-RTL scripts are actually native-LTR, so we reset
+ * the horiz_dir if the run contains at least one decimal-number char, and no
+ * letter chars (ideally we should be checking for chars with strong
+ * directionality but hb-unicode currently lacks bidi categories).
+ *
+ * This allows digit sequences in Arabic etc to be shaped in "native"
+ * direction, so that features like ligatures will work as intended.
+ *
+ * https://github.com/harfbuzz/harfbuzz/issues/501
+ */
+ if (unlikely (horiz_dir == HB_DIRECTION_RTL && direction == HB_DIRECTION_LTR))
+ {
+ bool found_number = false, found_letter = false;
+ const auto* info = buffer->info;
+ const auto count = buffer->len;
+ for (unsigned i = 0; i < count; i++)
+ {
+ auto gc = _hb_glyph_info_get_general_category (&info[i]);
+ if (gc == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
+ found_number = true;
+ else if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc))
+ {
+ found_letter = true;
+ break;
+ }
+ }
+ if (found_number && !found_letter)
+ horiz_dir = HB_DIRECTION_LTR;
+ }
+
/* TODO vertical:
* The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
* Ogham fonts are supposed to be implemented BTT or not. Need to research that
@@ -1111,8 +1165,6 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
_hb_buffer_allocate_unicode_vars (c->buffer);
- c->buffer->clear_output ();
-
hb_ot_shape_initialize_masks (c);
hb_set_unicode_props (c->buffer);
hb_insert_dotted_circle (c->buffer, c->font);
@@ -1122,7 +1174,8 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
hb_ensure_native_direction (c->buffer);
if (c->plan->shaper->preprocess_text &&
- c->buffer->message(c->font, "start preprocess-text")) {
+ c->buffer->message(c->font, "start preprocess-text"))
+ {
c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
(void) c->buffer->message(c->font, "end preprocess-text");
}
@@ -1164,7 +1217,7 @@ _hb_ot_shape (hb_shape_plan_t *shape_plan,
* @lookup_indexes: (out): The #hb_set_t set of lookups returned
*
* Computes the complete set of GSUB or GPOS lookups that are applicable
- * under a given @shape_plan.
+ * under a given @shape_plan.
*
* Since: 0.9.7
**/
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.hh
index acc98772a9..e8c81015c7 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.hh
@@ -112,6 +112,7 @@ struct hb_ot_shape_plan_t
#else
static constexpr bool apply_kern = false;
#endif
+ bool apply_fallback_kern : 1;
#ifndef HB_NO_AAT_SHAPE
bool apply_kerx : 1;
bool apply_morx : 1;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh
index 6aa4fa4492..41d1734b39 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh
@@ -297,7 +297,7 @@ struct STAT
unsigned int axis_index;
if (!get_design_axes ().lfind (tag, &axis_index)) return false;
- hb_array_t<const OffsetTo<AxisValue>> axis_values = get_axis_value_offsets ();
+ hb_array_t<const Offset16To<AxisValue>> axis_values = get_axis_value_offsets ();
for (unsigned int i = 0; i < axis_values.length; i++)
{
const AxisValue& axis_value = this+axis_values[i];
@@ -359,7 +359,7 @@ struct STAT
hb_array_t<const StatAxisRecord> const get_design_axes () const
{ return (this+designAxesOffset).as_array (designAxisCount); }
- hb_array_t<const OffsetTo<AxisValue>> const get_axis_value_offsets () const
+ hb_array_t<const Offset16To<AxisValue>> const get_axis_value_offsets () const
{ return (this+offsetToAxisValueOffsets).as_array (axisValueCount); }
@@ -373,7 +373,7 @@ struct STAT
* in the 'fvar' table. In all fonts, must
* be greater than zero if axisValueCount
* is greater than zero. */
- LNNOffsetTo<UnsizedArrayOf<StatAxisRecord>>
+ NNOffset32To<UnsizedArrayOf<StatAxisRecord>>
designAxesOffset;
/* Offset in bytes from the beginning of
* the STAT table to the start of the design
@@ -381,7 +381,7 @@ struct STAT
* set to zero; if designAxisCount is greater
* than zero, must be greater than zero. */
HBUINT16 axisValueCount; /* The number of axis value tables. */
- LNNOffsetTo<UnsizedArrayOf<OffsetTo<AxisValue>>>
+ NNOffset32To<UnsizedArrayOf<Offset16To<AxisValue>>>
offsetToAxisValueOffsets;
/* Offset in bytes from the beginning of
* the STAT table to the start of the design
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc
index fc145a41f7..1837063af8 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc
@@ -522,7 +522,7 @@ hb_ot_tags_to_script_and_language (hb_tag_t script_tag,
unsigned char *buf;
const char *lang_str = hb_language_to_string (*language);
size_t len = strlen (lang_str);
- buf = (unsigned char *) malloc (len + 16);
+ buf = (unsigned char *) hb_malloc (len + 16);
if (unlikely (!buf))
{
*language = nullptr;
@@ -544,7 +544,7 @@ hb_ot_tags_to_script_and_language (hb_tag_t script_tag,
for (shift = 28; shift >= 0; shift -= 4)
buf[len++] = TOHEX (script_tag >> shift);
*language = hb_language_from_string ((char *) buf, len);
- free (buf);
+ hb_free (buf);
}
}
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh
index 29219adb0a..65f26c1d22 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh
@@ -58,7 +58,7 @@ struct AxisValueMap
DEFINE_SIZE_STATIC (4);
};
-struct SegmentMaps : ArrayOf<AxisValueMap>
+struct SegmentMaps : Array16Of<AxisValueMap>
{
int map (int value, unsigned int from_offset = 0, unsigned int to_offset = 1) const
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh
index f9e933fb2b..05f289db26 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh
@@ -142,11 +142,13 @@ struct AxisRecord
max = hb_max (default_, maxValue / 65536.f);
}
- protected:
+ public:
Tag axisTag; /* Tag identifying the design variation for the axis. */
+ protected:
HBFixed minValue; /* The minimum coordinate value for the axis. */
HBFixed defaultValue; /* The default coordinate value for the axis. */
HBFixed maxValue; /* The maximum coordinate value for the axis. */
+ public:
HBUINT16 flags; /* Axis flags. */
NameID axisNameID; /* The name ID for entries in the 'name' table that
* provide a display name for this axis. */
@@ -214,7 +216,6 @@ struct fvar
return axes.lfind (tag, axis_index) && (axes[*axis_index].get_axis_deprecated (info), true);
}
#endif
-
bool
find_axis_info (hb_tag_t tag, hb_ot_var_axis_info_t *info) const
{
@@ -289,7 +290,7 @@ struct fvar
;
}
- protected:
+ public:
hb_array_t<const AxisRecord> get_axes () const
{ return hb_array (&(this+firstAxis), axisCount); }
@@ -303,7 +304,7 @@ struct fvar
protected:
FixedVersion<>version; /* Version of the fvar table
* initially set to 0x00010000u */
- OffsetTo<AxisRecord>
+ Offset16To<AxisRecord>
firstAxis; /* Offset in bytes from the beginning of the table
* to the start of the AxisRecord array. */
HBUINT16 reserved; /* This field is permanently reserved. Set to 2. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh
index 7e4eaaad95..49b5532d40 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh
@@ -374,7 +374,7 @@ struct GlyphVariationData
* low 12 bits are the number of tuple variation tables
* for this glyph. The number of tuple variation tables
* can be any number between 1 and 4095. */
- OffsetTo<HBUINT8>
+ Offset16To<HBUINT8>
data; /* Offset from the start of the GlyphVariationData table
* to the serialized data. */
/* TupleVariationHeader tupleVariationHeaders[] *//* Array of tuple variation headers. */
@@ -419,7 +419,9 @@ struct gvar
out->glyphCount = num_glyphs;
unsigned int subset_data_size = 0;
- for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
+ for (hb_codepoint_t gid = (c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE) ? 0 : 1;
+ gid < num_glyphs;
+ gid++)
{
hb_codepoint_t old_gid;
if (!c->plan->old_gid_for_new_gid (gid, &old_gid)) continue;
@@ -449,7 +451,9 @@ struct gvar
out->dataZ = subset_data - (char *) out;
unsigned int glyph_offset = 0;
- for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
+ for (hb_codepoint_t gid = (c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE) ? 0 : 1;
+ gid < num_glyphs;
+ gid++)
{
hb_codepoint_t old_gid;
hb_bytes_t var_data_bytes = c->plan->old_gid_for_new_gid (gid, &old_gid)
@@ -676,7 +680,7 @@ no_more_gaps:
* can be referenced within glyph variation data tables for
* multiple glyphs, as opposed to other tuple records stored
* directly within a glyph variation data table. */
- LNNOffsetTo<UnsizedArrayOf<F2DOT14>>
+ NNOffset32To<UnsizedArrayOf<F2DOT14>>
sharedTuples; /* Offset from the start of this table to the shared tuple records.
* Array of tuple records shared across all glyph variation data tables. */
HBUINT16 glyphCount; /* The number of glyphs in this font. This must match the number of
@@ -684,7 +688,7 @@ no_more_gaps:
HBUINT16 flags; /* Bit-field that gives the format of the offset array that follows.
* If bit 0 is clear, the offsets are uint16; if bit 0 is set, the
* offsets are uint32. */
- LOffsetTo<GlyphVariationData>
+ Offset32To<GlyphVariationData>
dataZ; /* Offset from the start of this table to the array of
* GlyphVariationData tables. */
UnsizedArrayOf<HBUINT8>
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh
index fdcc88d674..72217e7f29 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh
@@ -49,12 +49,12 @@ struct DeltaSetIndexMap
{
unsigned int width = plan.get_width ();
unsigned int inner_bit_count = plan.get_inner_bit_count ();
- const hb_array_t<const unsigned int> output_map = plan.get_output_map ();
+ const hb_array_t<const uint32_t> output_map = plan.get_output_map ();
TRACE_SERIALIZE (this);
if (unlikely (output_map.length && ((((inner_bit_count-1)&~0xF)!=0) || (((width-1)&~0x3)!=0))))
return_trace (false);
- if (unlikely (!c->extend_min (*this))) return_trace (false);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
format = ((width-1)<<4)|(inner_bit_count-1);
mapCount = output_map.length;
@@ -76,7 +76,7 @@ struct DeltaSetIndexMap
return_trace (true);
}
- unsigned int map (unsigned int v) const /* Returns 16.16 outer.inner. */
+ uint32_t map (unsigned int v) const /* Returns 16.16 outer.inner. */
{
/* If count is zero, pass value unchanged. This takes
* care of direct mapping for advance map. */
@@ -217,7 +217,7 @@ struct index_map_subset_plan_t
hb_codepoint_t old_gid;
if (plan->old_gid_for_new_gid (gid, &old_gid))
{
- unsigned int v = input_map->map (old_gid);
+ uint32_t v = input_map->map (old_gid);
unsigned int outer = v >> 16;
output_map[gid] = (outer_map[outer] << 16) | (inner_maps[outer][v & 0xFFFF]);
}
@@ -234,14 +234,14 @@ struct index_map_subset_plan_t
{ return (map_count? (DeltaSetIndexMap::min_size + get_width () * map_count): 0); }
bool is_identity () const { return get_output_map ().length == 0; }
- hb_array_t<const unsigned int> get_output_map () const { return output_map.as_array (); }
+ hb_array_t<const uint32_t> get_output_map () const { return output_map.as_array (); }
protected:
unsigned int map_count;
hb_vector_t<unsigned int> max_inners;
unsigned int outer_bit_count;
unsigned int inner_bit_count;
- hb_vector_t<unsigned int> output_map;
+ hb_vector_t<uint32_t> output_map;
};
struct hvarvvar_subset_plan_t
@@ -272,7 +272,7 @@ struct hvarvvar_subset_plan_t
index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan);
if (index_maps[0] == &Null (DeltaSetIndexMap))
{
- retain_adv_map = plan->retain_gids;
+ retain_adv_map = plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS;
outer_map.add (0);
for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++)
{
@@ -367,15 +367,15 @@ struct HVARVVAR
TRACE_SERIALIZE (this);
if (im_plans[index_map_subset_plan_t::ADV_INDEX].is_identity ())
advMap = 0;
- else if (unlikely (!advMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::ADV_INDEX])))
+ else if (unlikely (!advMap.serialize_serialize (c, im_plans[index_map_subset_plan_t::ADV_INDEX])))
return_trace (false);
if (im_plans[index_map_subset_plan_t::LSB_INDEX].is_identity ())
lsbMap = 0;
- else if (unlikely (!lsbMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::LSB_INDEX])))
+ else if (unlikely (!lsbMap.serialize_serialize (c, im_plans[index_map_subset_plan_t::LSB_INDEX])))
return_trace (false);
if (im_plans[index_map_subset_plan_t::RSB_INDEX].is_identity ())
rsbMap = 0;
- else if (unlikely (!rsbMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::RSB_INDEX])))
+ else if (unlikely (!rsbMap.serialize_serialize (c, im_plans[index_map_subset_plan_t::RSB_INDEX])))
return_trace (false);
return_trace (true);
@@ -398,8 +398,10 @@ struct HVARVVAR
out->version.major = 1;
out->version.minor = 0;
- if (unlikely (!out->varStore.serialize (c->serializer, out)
- .serialize (c->serializer, hvar_plan.var_store, hvar_plan.inner_maps.as_array ())))
+ if (unlikely (!out->varStore
+ .serialize_serialize (c->serializer,
+ hvar_plan.var_store,
+ hvar_plan.inner_maps.as_array ())))
return_trace (false);
return_trace (out->T::serialize_index_maps (c->serializer,
@@ -408,7 +410,7 @@ struct HVARVVAR
float get_advance_var (hb_codepoint_t glyph, hb_font_t *font) const
{
- unsigned int varidx = (this+advMap).map (glyph);
+ uint32_t varidx = (this+advMap).map (glyph);
return (this+varStore).get_delta (varidx, font->coords, font->num_coords);
}
@@ -416,7 +418,7 @@ struct HVARVVAR
const int *coords, unsigned int coord_count) const
{
if (!has_side_bearing_deltas ()) return 0.f;
- unsigned int varidx = (this+lsbMap).map (glyph);
+ uint32_t varidx = (this+lsbMap).map (glyph);
return (this+varStore).get_delta (varidx, coords, coord_count);
}
@@ -425,13 +427,13 @@ struct HVARVVAR
protected:
FixedVersion<>version; /* Version of the metrics variation table
* initially set to 0x00010000u */
- LOffsetTo<VariationStore>
+ Offset32To<VariationStore>
varStore; /* Offset to item variation store table. */
- LOffsetTo<DeltaSetIndexMap>
+ Offset32To<DeltaSetIndexMap>
advMap; /* Offset to advance var-idx mapping. */
- LOffsetTo<DeltaSetIndexMap>
+ Offset32To<DeltaSetIndexMap>
lsbMap; /* Offset to lsb/tsb var-idx mapping. */
- LOffsetTo<DeltaSetIndexMap>
+ Offset32To<DeltaSetIndexMap>
rsbMap; /* Offset to rsb/bsb var-idx mapping. */
public:
@@ -466,7 +468,7 @@ struct VVAR : HVARVVAR {
return_trace (false);
if (!im_plans[index_map_subset_plan_t::VORG_INDEX].get_map_count ())
vorgMap = 0;
- else if (unlikely (!vorgMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::VORG_INDEX])))
+ else if (unlikely (!vorgMap.serialize_serialize (c, im_plans[index_map_subset_plan_t::VORG_INDEX])))
return_trace (false);
return_trace (true);
@@ -475,7 +477,7 @@ struct VVAR : HVARVVAR {
bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset<VVAR> (c); }
protected:
- LOffsetTo<DeltaSetIndexMap>
+ Offset32To<DeltaSetIndexMap>
vorgMap; /* Offset to vertical-origin var-idx mapping. */
public:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh
index 1b7fad9cec..208db46741 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh
@@ -103,7 +103,7 @@ protected:
HBUINT16 valueRecordSize;/* The size in bytes of each value record —
* must be greater than zero. */
HBUINT16 valueRecordCount;/* The number of value records — may be zero. */
- OffsetTo<VariationStore>
+ Offset16To<VariationStore>
varStore; /* Offset to item variation store table. */
UnsizedArrayOf<HBUINT8>
valuesZ; /* Array of value records. The records must be
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-vorg-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-vorg-table.hh
index c6803200f9..efa7737d6f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-vorg-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-vorg-table.hh
@@ -125,7 +125,7 @@ struct VORG
FixedVersion<>version; /* Version of VORG table. Set to 0x00010000u. */
FWORD defaultVertOriginY;
/* The default vertical origin. */
- SortedArrayOf<VertOriginMetric>
+ SortedArray16Of<VertOriginMetric>
vertYOrigins; /* The array of vertical origins. */
public:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-pool.hh b/src/3rdparty/harfbuzz-ng/src/hb-pool.hh
index dcf0faf2a9..dcf8f6627d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-pool.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-pool.hh
@@ -41,7 +41,7 @@ struct hb_pool_t
{
next = nullptr;
- for (chunk_t *_ : chunks) ::free (_);
+ for (chunk_t *_ : chunks) hb_free (_);
chunks.fini ();
}
@@ -51,7 +51,7 @@ struct hb_pool_t
if (unlikely (!next))
{
if (unlikely (!chunks.alloc (chunks.length + 1))) return nullptr;
- chunk_t *chunk = (chunk_t *) calloc (1, sizeof (chunk_t));
+ chunk_t *chunk = (chunk_t *) hb_calloc (1, sizeof (chunk_t));
if (unlikely (!chunk)) return nullptr;
chunks.push (chunk);
next = chunk->thread ();
@@ -65,7 +65,7 @@ struct hb_pool_t
return obj;
}
- void free (T* obj)
+ void release (T* obj)
{
* (T**) obj = next;
next = obj;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh b/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh
new file mode 100644
index 0000000000..7d799ae906
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#ifndef HB_PRIORITY_QUEUE_HH
+#define HB_PRIORITY_QUEUE_HH
+
+#include "hb.hh"
+#include "hb-vector.hh"
+
+/*
+ * hb_priority_queue_t
+ *
+ * Priority queue implemented as a binary heap. Supports extract minimum
+ * and insert operations.
+ */
+struct hb_priority_queue_t
+{
+ HB_DELETE_COPY_ASSIGN (hb_priority_queue_t);
+ hb_priority_queue_t () { init (); }
+ ~hb_priority_queue_t () { fini (); }
+
+ private:
+ typedef hb_pair_t<int64_t, unsigned> item_t;
+ hb_vector_t<item_t> heap;
+
+ public:
+ void init () { heap.init (); }
+
+ void fini () { heap.fini (); }
+
+ void reset () { heap.resize (0); }
+
+ bool in_error () const { return heap.in_error (); }
+
+ void insert (int64_t priority, unsigned value)
+ {
+ heap.push (item_t (priority, value));
+ bubble_up (heap.length - 1);
+ }
+
+ item_t pop_minimum ()
+ {
+ item_t result = heap[0];
+
+ heap[0] = heap[heap.length - 1];
+ heap.shrink (heap.length - 1);
+ bubble_down (0);
+
+ return result;
+ }
+
+ const item_t& minimum ()
+ {
+ return heap[0];
+ }
+
+ bool is_empty () const { return heap.length == 0; }
+ explicit operator bool () const { return !is_empty (); }
+ unsigned int get_population () const { return heap.length; }
+
+ /* Sink interface. */
+ hb_priority_queue_t& operator << (item_t item)
+ { insert (item.first, item.second); return *this; }
+
+ private:
+
+ static constexpr unsigned parent (unsigned index)
+ {
+ return (index - 1) / 2;
+ }
+
+ static constexpr unsigned left_child (unsigned index)
+ {
+ return 2 * index + 1;
+ }
+
+ static constexpr unsigned right_child (unsigned index)
+ {
+ return 2 * index + 2;
+ }
+
+ void bubble_down (unsigned index)
+ {
+ unsigned left = left_child (index);
+ unsigned right = right_child (index);
+
+ bool has_left = left < heap.length;
+ if (!has_left)
+ // If there's no left, then there's also no right.
+ return;
+
+ bool has_right = right < heap.length;
+ if (heap[index].first <= heap[left].first
+ && (!has_right || heap[index].first <= heap[right].first))
+ return;
+
+ if (!has_right || heap[left].first < heap[right].first)
+ {
+ swap (index, left);
+ bubble_down (left);
+ return;
+ }
+
+ swap (index, right);
+ bubble_down (right);
+ }
+
+ void bubble_up (unsigned index)
+ {
+ if (index == 0) return;
+
+ unsigned parent_index = parent (index);
+ if (heap[parent_index].first <= heap[index].first)
+ return;
+
+ swap (index, parent_index);
+ bubble_up (parent_index);
+ }
+
+ void swap (unsigned a, unsigned b)
+ {
+ item_t temp = heap[a];
+ heap[a] = heap[b];
+ heap[b] = temp;
+ }
+};
+
+#endif /* HB_PRIORITY_QUEUE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh b/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh
new file mode 100644
index 0000000000..b02128b5c4
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh
@@ -0,0 +1,769 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#ifndef HB_REPACKER_HH
+#define HB_REPACKER_HH
+
+#include "hb-open-type.hh"
+#include "hb-map.hh"
+#include "hb-priority-queue.hh"
+#include "hb-serialize.hh"
+#include "hb-vector.hh"
+
+
+struct graph_t
+{
+ struct vertex_t
+ {
+ vertex_t () :
+ distance (0),
+ incoming_edges (0),
+ start (0),
+ end (0),
+ priority(0) {}
+
+ void fini () { obj.fini (); }
+
+ hb_serialize_context_t::object_t obj;
+ int64_t distance;
+ unsigned incoming_edges;
+ unsigned start;
+ unsigned end;
+ unsigned priority;
+
+ bool is_shared () const
+ {
+ return incoming_edges > 1;
+ }
+
+ bool is_leaf () const
+ {
+ return !obj.links.length;
+ }
+
+ void raise_priority ()
+ {
+ priority++;
+ }
+
+ int64_t modified_distance (unsigned order) const
+ {
+ // TODO(garretrieger): once priority is high enough, should try
+ // setting distance = 0 which will force to sort immediately after
+ // it's parent where possible.
+
+ int64_t modified_distance =
+ hb_min (hb_max(distance + distance_modifier (), 0), 0x7FFFFFFFFF);
+ return (modified_distance << 24) | (0x00FFFFFF & order);
+ }
+
+ int64_t distance_modifier () const
+ {
+ if (!priority) return 0;
+ int64_t table_size = obj.tail - obj.head;
+ return -(table_size - table_size / (1 << hb_min(priority, 16u)));
+ }
+ };
+
+ struct overflow_record_t
+ {
+ unsigned parent;
+ const hb_serialize_context_t::object_t::link_t* link;
+ };
+
+ struct clone_buffer_t
+ {
+ clone_buffer_t () : head (nullptr), tail (nullptr) {}
+
+ bool copy (const hb_serialize_context_t::object_t& object)
+ {
+ fini ();
+ unsigned size = object.tail - object.head;
+ head = (char*) hb_malloc (size);
+ if (!head) return false;
+
+ memcpy (head, object.head, size);
+ tail = head + size;
+ return true;
+ }
+
+ char* head;
+ char* tail;
+
+ void fini ()
+ {
+ if (!head) return;
+ hb_free (head);
+ head = nullptr;
+ }
+ };
+
+ /*
+ * A topological sorting of an object graph. Ordered
+ * in reverse serialization order (first object in the
+ * serialization is at the end of the list). This matches
+ * the 'packed' object stack used internally in the
+ * serializer
+ */
+ graph_t (const hb_vector_t<hb_serialize_context_t::object_t *>& objects)
+ : edge_count_invalid (true),
+ distance_invalid (true),
+ positions_invalid (true),
+ successful (true)
+ {
+ bool removed_nil = false;
+ for (unsigned i = 0; i < objects.length; i++)
+ {
+ // TODO(grieger): check all links point to valid objects.
+
+ // If this graph came from a serialization buffer object 0 is the
+ // nil object. We don't need it for our purposes here so drop it.
+ if (i == 0 && !objects[i])
+ {
+ removed_nil = true;
+ continue;
+ }
+
+ vertex_t* v = vertices_.push ();
+ if (check_success (!vertices_.in_error ()))
+ v->obj = *objects[i];
+ if (!removed_nil) continue;
+ for (unsigned i = 0; i < v->obj.links.length; i++)
+ // Fix indices to account for removed nil object.
+ v->obj.links[i].objidx--;
+ }
+ }
+
+ ~graph_t ()
+ {
+ vertices_.fini_deep ();
+ clone_buffers_.fini_deep ();
+ }
+
+ bool in_error () const
+ {
+ return !successful || vertices_.in_error () || clone_buffers_.in_error ();
+ }
+
+ const vertex_t& root () const
+ {
+ return vertices_[root_idx ()];
+ }
+
+ unsigned root_idx () const
+ {
+ // Object graphs are in reverse order, the first object is at the end
+ // of the vector. Since the graph is topologically sorted it's safe to
+ // assume the first object has no incoming edges.
+ return vertices_.length - 1;
+ }
+
+ const hb_serialize_context_t::object_t& object(unsigned i) const
+ {
+ return vertices_[i].obj;
+ }
+
+ /*
+ * serialize graph into the provided serialization buffer.
+ */
+ void serialize (hb_serialize_context_t* c) const
+ {
+ c->start_serialize<void> ();
+ for (unsigned i = 0; i < vertices_.length; i++) {
+ c->push ();
+
+ size_t size = vertices_[i].obj.tail - vertices_[i].obj.head;
+ char* start = c->allocate_size <char> (size);
+ if (!start) return;
+
+ memcpy (start, vertices_[i].obj.head, size);
+
+ for (const auto& link : vertices_[i].obj.links)
+ serialize_link (link, start, c);
+
+ // All duplications are already encoded in the graph, so don't
+ // enable sharing during packing.
+ c->pop_pack (false);
+ }
+ c->end_serialize ();
+ }
+
+ /*
+ * Generates a new topological sorting of graph using Kahn's
+ * algorithm: https://en.wikipedia.org/wiki/Topological_sorting#Algorithms
+ */
+ void sort_kahn ()
+ {
+ positions_invalid = true;
+
+ if (vertices_.length <= 1) {
+ // Graph of 1 or less doesn't need sorting.
+ return;
+ }
+
+ hb_vector_t<unsigned> queue;
+ hb_vector_t<vertex_t> sorted_graph;
+ hb_vector_t<unsigned> id_map;
+ if (unlikely (!check_success (id_map.resize (vertices_.length)))) return;
+
+ hb_vector_t<unsigned> removed_edges;
+ if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return;
+ update_incoming_edge_count ();
+
+ queue.push (root_idx ());
+ int new_id = vertices_.length - 1;
+
+ while (!queue.in_error () && queue.length)
+ {
+ unsigned next_id = queue[0];
+ queue.remove (0);
+
+ vertex_t& next = vertices_[next_id];
+ sorted_graph.push (next);
+ id_map[next_id] = new_id--;
+
+ for (const auto& link : next.obj.links) {
+ removed_edges[link.objidx]++;
+ if (!(vertices_[link.objidx].incoming_edges - removed_edges[link.objidx]))
+ queue.push (link.objidx);
+ }
+ }
+
+ check_success (!queue.in_error ());
+ check_success (!sorted_graph.in_error ());
+ if (!check_success (new_id == -1))
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected.");
+
+ remap_obj_indices (id_map, &sorted_graph);
+
+ sorted_graph.as_array ().reverse ();
+
+ vertices_.fini_deep ();
+ vertices_ = sorted_graph;
+ sorted_graph.fini_deep ();
+ }
+
+ /*
+ * Generates a new topological sorting of graph ordered by the shortest
+ * distance to each node.
+ */
+ void sort_shortest_distance ()
+ {
+ positions_invalid = true;
+
+ if (vertices_.length <= 1) {
+ // Graph of 1 or less doesn't need sorting.
+ return;
+ }
+
+ update_distances ();
+
+ hb_priority_queue_t queue;
+ hb_vector_t<vertex_t> sorted_graph;
+ hb_vector_t<unsigned> id_map;
+ if (unlikely (!check_success (id_map.resize (vertices_.length)))) return;
+
+ hb_vector_t<unsigned> removed_edges;
+ if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return;
+ update_incoming_edge_count ();
+
+ queue.insert (root ().modified_distance (0), root_idx ());
+ int new_id = root_idx ();
+ unsigned order = 1;
+ while (!queue.in_error () && !queue.is_empty ())
+ {
+ unsigned next_id = queue.pop_minimum().second;
+
+ vertex_t& next = vertices_[next_id];
+ sorted_graph.push (next);
+ id_map[next_id] = new_id--;
+
+ for (const auto& link : next.obj.links) {
+ removed_edges[link.objidx]++;
+ if (!(vertices_[link.objidx].incoming_edges - removed_edges[link.objidx]))
+ // Add the order that the links were encountered to the priority.
+ // This ensures that ties between priorities objects are broken in a consistent
+ // way. More specifically this is set up so that if a set of objects have the same
+ // distance they'll be added to the topological order in the order that they are
+ // referenced from the parent object.
+ queue.insert (vertices_[link.objidx].modified_distance (order++),
+ link.objidx);
+ }
+ }
+
+ check_success (!queue.in_error ());
+ check_success (!sorted_graph.in_error ());
+ if (!check_success (new_id == -1))
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected.");
+
+ remap_obj_indices (id_map, &sorted_graph);
+
+ sorted_graph.as_array ().reverse ();
+
+ vertices_.fini_deep ();
+ vertices_ = sorted_graph;
+ sorted_graph.fini_deep ();
+ }
+
+ /*
+ * Creates a copy of child and re-assigns the link from
+ * parent to the clone. The copy is a shallow copy, objects
+ * linked from child are not duplicated.
+ */
+ void duplicate (unsigned parent_idx, unsigned child_idx)
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d",
+ parent_idx, child_idx);
+
+ positions_invalid = true;
+
+ auto* clone = vertices_.push ();
+ auto& child = vertices_[child_idx];
+ clone_buffer_t* buffer = clone_buffers_.push ();
+ if (vertices_.in_error ()
+ || clone_buffers_.in_error ()
+ || !check_success (buffer->copy (child.obj))) {
+ return;
+ }
+
+ clone->obj.head = buffer->head;
+ clone->obj.tail = buffer->tail;
+ clone->distance = child.distance;
+
+ for (const auto& l : child.obj.links)
+ clone->obj.links.push (l);
+
+ check_success (!clone->obj.links.in_error ());
+
+ auto& parent = vertices_[parent_idx];
+ unsigned clone_idx = vertices_.length - 2;
+ for (unsigned i = 0; i < parent.obj.links.length; i++)
+ {
+ auto& l = parent.obj.links[i];
+ if (l.objidx == child_idx)
+ {
+ l.objidx = clone_idx;
+ clone->incoming_edges++;
+ child.incoming_edges--;
+ }
+ }
+
+ // The last object is the root of the graph, so swap back the root to the end.
+ // The root's obj idx does change, however since it's root nothing else refers to it.
+ // all other obj idx's will be unaffected.
+ vertex_t root = vertices_[vertices_.length - 2];
+ vertices_[vertices_.length - 2] = *clone;
+ vertices_[vertices_.length - 1] = root;
+ }
+
+ /*
+ * Raises the sorting priority of all children.
+ */
+ void raise_childrens_priority (unsigned parent_idx)
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %d",
+ parent_idx);
+ // This operation doesn't change ordering until a sort is run, so no need
+ // to invalidate positions. It does not change graph structure so no need
+ // to update distances or edge counts.
+ auto& parent = vertices_[parent_idx].obj;
+ for (unsigned i = 0; i < parent.links.length; i++)
+ vertices_[parent.links[i].objidx].raise_priority ();
+ }
+
+ /*
+ * Will any offsets overflow on graph when it's serialized?
+ */
+ bool will_overflow (hb_vector_t<overflow_record_t>* overflows = nullptr)
+ {
+ if (overflows) overflows->resize (0);
+ update_positions ();
+
+ for (int parent_idx = vertices_.length - 1; parent_idx >= 0; parent_idx--)
+ {
+ for (const auto& link : vertices_[parent_idx].obj.links)
+ {
+ int64_t offset = compute_offset (parent_idx, link);
+ if (is_valid_offset (offset, link))
+ continue;
+
+ if (!overflows) return true;
+
+ overflow_record_t r;
+ r.parent = parent_idx;
+ r.link = &link;
+ overflows->push (r);
+ }
+ }
+
+ if (!overflows) return false;
+ return overflows->length;
+ }
+
+ void print_overflows (const hb_vector_t<overflow_record_t>& overflows)
+ {
+ if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
+
+ update_incoming_edge_count ();
+ for (const auto& o : overflows)
+ {
+ const auto& child = vertices_[o.link->objidx];
+ DEBUG_MSG (SUBSET_REPACK, nullptr, " overflow from %d => %d (%d incoming , %d outgoing)",
+ o.parent,
+ o.link->objidx,
+ child.incoming_edges,
+ child.obj.links.length);
+ }
+ }
+
+ void err_other_error () { this->successful = false; }
+
+ private:
+
+ bool check_success (bool success)
+ { return this->successful && (success || (err_other_error (), false)); }
+
+ /*
+ * Creates a map from objid to # of incoming edges.
+ */
+ void update_incoming_edge_count ()
+ {
+ if (!edge_count_invalid) return;
+
+ for (unsigned i = 0; i < vertices_.length; i++)
+ vertices_[i].incoming_edges = 0;
+
+ for (const vertex_t& v : vertices_)
+ {
+ for (auto& l : v.obj.links)
+ {
+ vertices_[l.objidx].incoming_edges++;
+ }
+ }
+
+ edge_count_invalid = false;
+ }
+
+ /*
+ * compute the serialized start and end positions for each vertex.
+ */
+ void update_positions ()
+ {
+ if (!positions_invalid) return;
+
+ unsigned current_pos = 0;
+ for (int i = root_idx (); i >= 0; i--)
+ {
+ auto& v = vertices_[i];
+ v.start = current_pos;
+ current_pos += v.obj.tail - v.obj.head;
+ v.end = current_pos;
+ }
+
+ positions_invalid = false;
+ }
+
+ /*
+ * Finds the distance to each object in the graph
+ * from the initial node.
+ */
+ void update_distances ()
+ {
+ if (!distance_invalid) return;
+
+ // Uses Dijkstra's algorithm to find all of the shortest distances.
+ // https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
+ //
+ // Implementation Note:
+ // Since our priority queue doesn't support fast priority decreases
+ // we instead just add new entries into the queue when a priority changes.
+ // Redundant ones are filtered out later on by the visited set.
+ // According to https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf
+ // for practical performance this is faster then using a more advanced queue
+ // (such as a fibonaacci queue) with a fast decrease priority.
+ for (unsigned i = 0; i < vertices_.length; i++)
+ {
+ if (i == vertices_.length - 1)
+ vertices_[i].distance = 0;
+ else
+ vertices_[i].distance = hb_int_max (int64_t);
+ }
+
+ hb_priority_queue_t queue;
+ queue.insert (0, vertices_.length - 1);
+
+ hb_set_t visited;
+
+ while (!queue.in_error () && !queue.is_empty ())
+ {
+ unsigned next_idx = queue.pop_minimum ().second;
+ if (visited.has (next_idx)) continue;
+ const auto& next = vertices_[next_idx];
+ int64_t next_distance = vertices_[next_idx].distance;
+ visited.add (next_idx);
+
+ for (const auto& link : next.obj.links)
+ {
+ if (visited.has (link.objidx)) continue;
+
+ const auto& child = vertices_[link.objidx].obj;
+ int64_t child_weight = child.tail - child.head +
+ ((int64_t) 1 << (link.width * 8));
+ int64_t child_distance = next_distance + child_weight;
+
+ if (child_distance < vertices_[link.objidx].distance)
+ {
+ vertices_[link.objidx].distance = child_distance;
+ queue.insert (child_distance, link.objidx);
+ }
+ }
+ }
+
+ check_success (!queue.in_error ());
+ if (!check_success (queue.is_empty ()))
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected.");
+ return;
+ }
+
+ distance_invalid = false;
+ }
+
+ int64_t compute_offset (
+ unsigned parent_idx,
+ const hb_serialize_context_t::object_t::link_t& link) const
+ {
+ const auto& parent = vertices_[parent_idx];
+ const auto& child = vertices_[link.objidx];
+ int64_t offset = 0;
+ switch ((hb_serialize_context_t::whence_t) link.whence) {
+ case hb_serialize_context_t::whence_t::Head:
+ offset = child.start - parent.start; break;
+ case hb_serialize_context_t::whence_t::Tail:
+ offset = child.start - parent.end; break;
+ case hb_serialize_context_t::whence_t::Absolute:
+ offset = child.start; break;
+ }
+
+ assert (offset >= link.bias);
+ offset -= link.bias;
+ return offset;
+ }
+
+ bool is_valid_offset (int64_t offset,
+ const hb_serialize_context_t::object_t::link_t& link) const
+ {
+ if (link.is_signed)
+ {
+ if (link.width == 4)
+ return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31);
+ else
+ return offset >= -(1 << 15) && offset < (1 << 15);
+ }
+ else
+ {
+ if (link.width == 4)
+ return offset >= 0 && offset < ((int64_t) 1 << 32);
+ else if (link.width == 3)
+ return offset >= 0 && offset < ((int32_t) 1 << 24);
+ else
+ return offset >= 0 && offset < (1 << 16);
+ }
+ }
+
+ /*
+ * Updates all objidx's in all links using the provided mapping.
+ */
+ void remap_obj_indices (const hb_vector_t<unsigned>& id_map,
+ hb_vector_t<vertex_t>* sorted_graph) const
+ {
+ for (unsigned i = 0; i < sorted_graph->length; i++)
+ {
+ for (unsigned j = 0; j < (*sorted_graph)[i].obj.links.length; j++)
+ {
+ auto& link = (*sorted_graph)[i].obj.links[j];
+ link.objidx = id_map[link.objidx];
+ }
+ }
+ }
+
+ template <typename O> void
+ serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link,
+ char* head,
+ hb_serialize_context_t* c) const
+ {
+ OT::Offset<O>* offset = reinterpret_cast<OT::Offset<O>*> (head + link.position);
+ *offset = 0;
+ c->add_link (*offset,
+ // serializer has an extra nil object at the start of the
+ // object array. So all id's are +1 of what our id's are.
+ link.objidx + 1,
+ (hb_serialize_context_t::whence_t) link.whence,
+ link.bias);
+ }
+
+ void serialize_link (const hb_serialize_context_t::object_t::link_t& link,
+ char* head,
+ hb_serialize_context_t* c) const
+ {
+ switch (link.width)
+ {
+ case 4:
+ if (link.is_signed)
+ {
+ serialize_link_of_type<OT::HBINT32> (link, head, c);
+ } else {
+ serialize_link_of_type<OT::HBUINT32> (link, head, c);
+ }
+ return;
+ case 2:
+ if (link.is_signed)
+ {
+ serialize_link_of_type<OT::HBINT16> (link, head, c);
+ } else {
+ serialize_link_of_type<OT::HBUINT16> (link, head, c);
+ }
+ return;
+ case 3:
+ serialize_link_of_type<OT::HBUINT24> (link, head, c);
+ return;
+ default:
+ // Unexpected link width.
+ assert (0);
+ }
+ }
+
+ public:
+ // TODO(garretrieger): make private, will need to move most of offset overflow code into graph.
+ hb_vector_t<vertex_t> vertices_;
+ private:
+ hb_vector_t<clone_buffer_t> clone_buffers_;
+ bool edge_count_invalid;
+ bool distance_invalid;
+ bool positions_invalid;
+ bool successful;
+};
+
+
+/*
+ * Attempts to modify the topological sorting of the provided object graph to
+ * eliminate offset overflows in the links between objects of the graph. If a
+ * non-overflowing ordering is found the updated graph is serialized it into the
+ * provided serialization context.
+ *
+ * If necessary the structure of the graph may be modified in ways that do not
+ * affect the functionality of the graph. For example shared objects may be
+ * duplicated.
+ */
+inline void
+hb_resolve_overflows (const hb_vector_t<hb_serialize_context_t::object_t *>& packed,
+ hb_serialize_context_t* c) {
+ // Kahn sort is ~twice as fast as shortest distance sort and works for many fonts
+ // so try it first to save time.
+ graph_t sorted_graph (packed);
+ sorted_graph.sort_kahn ();
+ if (!sorted_graph.will_overflow ())
+ {
+ sorted_graph.serialize (c);
+ return;
+ }
+
+ sorted_graph.sort_shortest_distance ();
+
+ unsigned round = 0;
+ hb_vector_t<graph_t::overflow_record_t> overflows;
+ // TODO(garretrieger): select a good limit for max rounds.
+ while (!sorted_graph.in_error ()
+ && sorted_graph.will_overflow (&overflows)
+ && round++ < 10) {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "=== Over flow resolution round %d ===", round);
+ sorted_graph.print_overflows (overflows);
+
+ bool resolution_attempted = false;
+ hb_set_t priority_bumped_parents;
+ // Try resolving the furthest overflows first.
+ for (int i = overflows.length - 1; i >= 0; i--)
+ {
+ const graph_t::overflow_record_t& r = overflows[i];
+ const auto& child = sorted_graph.vertices_[r.link->objidx];
+ if (child.is_shared ())
+ {
+ // The child object is shared, we may be able to eliminate the overflow
+ // by duplicating it.
+ sorted_graph.duplicate (r.parent, r.link->objidx);
+ resolution_attempted = true;
+
+ // Stop processing overflows for this round so that object order can be
+ // updated to account for the newly added object.
+ break;
+ }
+
+ if (child.is_leaf () && !priority_bumped_parents.has (r.parent))
+ {
+ // This object is too far from it's parent, attempt to move it closer.
+ //
+ // TODO(garretrieger): initially limiting this to leaf's since they can be
+ // moved closer with fewer consequences. However, this can
+ // likely can be used for non-leafs as well.
+ // TODO(garretrieger): add a maximum priority, don't try to raise past this.
+ // TODO(garretrieger): also try lowering priority of the parent. Make it
+ // get placed further up in the ordering, closer to it's children.
+ // this is probably preferable if the total size of the parent object
+ // is < then the total size of the children (and the parent can be moved).
+ // Since in that case moving the parent will cause a smaller increase in
+ // the length of other offsets.
+ sorted_graph.raise_childrens_priority (r.parent);
+ priority_bumped_parents.add (r.parent);
+ resolution_attempted = true;
+ continue;
+ }
+
+ // TODO(garretrieger): add additional offset resolution strategies
+ // - Promotion to extension lookups.
+ // - Table splitting.
+ }
+
+ if (resolution_attempted)
+ {
+ sorted_graph.sort_shortest_distance ();
+ continue;
+ }
+
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "No resolution available :(");
+ c->err (HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
+ return;
+ }
+
+ if (sorted_graph.in_error ())
+ {
+ c->err (HB_SERIALIZE_ERROR_OTHER);
+ return;
+ }
+ sorted_graph.serialize (c);
+}
+
+
+#endif /* HB_REPACKER_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-sanitize.hh b/src/3rdparty/harfbuzz-ng/src/hb-sanitize.hh
index 1675e8448a..56c46015a6 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-sanitize.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-sanitize.hh
@@ -105,7 +105,7 @@
#define HB_SANITIZE_MAX_EDITS 32
#endif
#ifndef HB_SANITIZE_MAX_OPS_FACTOR
-#define HB_SANITIZE_MAX_OPS_FACTOR 8
+#define HB_SANITIZE_MAX_OPS_FACTOR 64
#endif
#ifndef HB_SANITIZE_MAX_OPS_MIN
#define HB_SANITIZE_MAX_OPS_MIN 16384
@@ -233,7 +233,7 @@ struct hb_sanitize_context_t :
(this->start <= p &&
p <= this->end &&
(unsigned int) (this->end - p) >= len &&
- this->max_ops-- > 0);
+ (this->max_ops -= len) > 0);
DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
"check_range [%p..%p]"
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh b/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh
index fe29bdf96e..5e07bb8238 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh
@@ -41,6 +41,16 @@
* Serialize
*/
+enum hb_serialize_error_t {
+ HB_SERIALIZE_ERROR_NONE = 0x00000000u,
+ HB_SERIALIZE_ERROR_OTHER = 0x00000001u,
+ HB_SERIALIZE_ERROR_OFFSET_OVERFLOW = 0x00000002u,
+ HB_SERIALIZE_ERROR_OUT_OF_ROOM = 0x00000004u,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW = 0x00000008u,
+ HB_SERIALIZE_ERROR_ARRAY_OVERFLOW = 0x00000010u
+};
+HB_MARK_AS_FLAG_T (hb_serialize_error_t);
+
struct hb_serialize_context_t
{
typedef unsigned objidx_t;
@@ -51,6 +61,8 @@ struct hb_serialize_context_t
Absolute /* Absolute: from the start of the serialize buffer. */
};
+
+
struct object_t
{
void fini () { links.fini (); }
@@ -70,7 +82,7 @@ struct hb_serialize_context_t
struct link_t
{
- bool is_wide: 1;
+ unsigned width: 3;
bool is_signed: 1;
unsigned whence: 2;
unsigned position: 28;
@@ -117,30 +129,54 @@ struct hb_serialize_context_t
object_pool.fini ();
}
- bool in_error () const { return !this->successful; }
+ bool in_error () const { return bool (errors); }
+
+ bool successful () const { return !bool (errors); }
+
+ HB_NODISCARD bool ran_out_of_room () const { return errors & HB_SERIALIZE_ERROR_OUT_OF_ROOM; }
+ HB_NODISCARD bool offset_overflow () const { return errors & HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
+ HB_NODISCARD bool only_offset_overflow () const { return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
+
+ void reset (void *start_, unsigned int size)
+ {
+ start = (char*) start_;
+ end = start + size;
+ reset ();
+ current = nullptr;
+ }
void reset ()
{
- this->successful = true;
- this->ran_out_of_room = false;
+ this->errors = HB_SERIALIZE_ERROR_NONE;
this->head = this->start;
this->tail = this->end;
this->debug_depth = 0;
fini ();
this->packed.push (nullptr);
+ this->packed_map.init ();
}
- bool check_success (bool success)
- { return this->successful && (success || (err_other_error (), false)); }
+ bool check_success (bool success,
+ hb_serialize_error_t err_type = HB_SERIALIZE_ERROR_OTHER)
+ {
+ return successful ()
+ && (success || err (err_type));
+ }
template <typename T1, typename T2>
- bool check_equal (T1 &&v1, T2 &&v2)
- { return check_success ((long long) v1 == (long long) v2); }
+ bool check_equal (T1 &&v1, T2 &&v2, hb_serialize_error_t err_type)
+ {
+ if ((long long) v1 != (long long) v2)
+ {
+ return err (err_type);
+ }
+ return true;
+ }
template <typename T1, typename T2>
- bool check_assign (T1 &v1, T2 &&v2)
- { return check_equal (v1 = v2, v2); }
+ bool check_assign (T1 &v1, T2 &&v2, hb_serialize_error_t err_type)
+ { return check_equal (v1 = v2, v2, err_type); }
template <typename T> bool propagate_error (T &&obj)
{ return check_success (!hb_deref (obj).in_error ()); }
@@ -167,12 +203,18 @@ struct hb_serialize_context_t
"end [%p..%p] serialized %u bytes; %s",
this->start, this->end,
(unsigned) (this->head - this->start),
- this->successful ? "successful" : "UNSUCCESSFUL");
+ successful () ? "successful" : "UNSUCCESSFUL");
propagate_error (packed, packed_map);
if (unlikely (!current)) return;
- if (unlikely (in_error())) return;
+ if (unlikely (in_error()))
+ {
+ // Offset overflows that occur before link resolution cannot be handled
+ // by repacking, so set a more general error.
+ if (offset_overflow ()) err (HB_SERIALIZE_ERROR_OTHER);
+ return;
+ }
assert (!current->next);
@@ -212,7 +254,7 @@ struct hb_serialize_context_t
current = current->next;
revert (obj->head, obj->tail);
obj->fini ();
- object_pool.free (obj);
+ object_pool.release (obj);
}
/* Set share to false when an object is unlikely sharable with others
@@ -312,7 +354,6 @@ struct hb_serialize_context_t
whence_t whence = Head,
unsigned bias = 0)
{
- static_assert (sizeof (T) == 2 || sizeof (T) == 4, "");
if (unlikely (in_error ())) return;
if (!objidx)
@@ -323,7 +364,7 @@ struct hb_serialize_context_t
auto& link = *current->links.push ();
- link.is_wide = sizeof (T) == 4;
+ link.width = sizeof (T);
link.is_signed = hb_is_signed (hb_unwrap_type (T));
link.whence = (unsigned) whence;
link.position = (const char *) &ofs - current->head;
@@ -351,7 +392,7 @@ struct hb_serialize_context_t
for (const object_t::link_t &link : parent->links)
{
const object_t* child = packed[link.objidx];
- if (unlikely (!child)) { err_other_error(); return; }
+ if (unlikely (!child)) { err (HB_SERIALIZE_ERROR_OTHER); return; }
unsigned offset = 0;
switch ((whence_t) link.whence) {
case Head: offset = child->head - parent->head; break;
@@ -363,15 +404,19 @@ struct hb_serialize_context_t
offset -= link.bias;
if (link.is_signed)
{
- if (link.is_wide)
+ assert (link.width == 2 || link.width == 4);
+ if (link.width == 4)
assign_offset<int32_t> (parent, link, offset);
else
assign_offset<int16_t> (parent, link, offset);
}
else
{
- if (link.is_wide)
+ assert (link.width == 2 || link.width == 3 || link.width == 4);
+ if (link.width == 4)
assign_offset<uint32_t> (parent, link, offset);
+ else if (link.width == 3)
+ assign_offset<uint32_t, 3> (parent, link, offset);
else
assign_offset<uint16_t> (parent, link, offset);
}
@@ -398,22 +443,22 @@ struct hb_serialize_context_t
Type *start_embed (const Type &obj) const
{ return start_embed (hb_addressof (obj)); }
- /* Following two functions exist to allow setting breakpoint on. */
- void err_ran_out_of_room () { this->ran_out_of_room = true; }
- void err_other_error () { this->successful = false; }
+ bool err (hb_serialize_error_t err_type)
+ {
+ return !bool ((errors = (errors | err_type)));
+ }
template <typename Type>
- Type *allocate_size (unsigned int size)
+ Type *allocate_size (size_t size)
{
- if (unlikely (!this->successful)) return nullptr;
+ if (unlikely (in_error ())) return nullptr;
- if (this->tail - this->head < ptrdiff_t (size))
+ if (unlikely (size > INT_MAX || this->tail - this->head < ptrdiff_t (size)))
{
- err_ran_out_of_room ();
- this->successful = false;
+ err (HB_SERIALIZE_ERROR_OUT_OF_ROOM);
return nullptr;
}
- memset (this->head, 0, size);
+ hb_memset (this->head, 0, size);
char *ret = this->head;
this->head += size;
return reinterpret_cast<Type *> (ret);
@@ -468,18 +513,19 @@ struct hb_serialize_context_t
hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; }
template <typename Type>
- Type *extend_size (Type *obj, unsigned int size)
+ Type *extend_size (Type *obj, size_t size)
{
if (unlikely (in_error ())) return nullptr;
assert (this->start <= (char *) obj);
assert ((char *) obj <= this->head);
- assert ((char *) obj + size >= this->head);
- if (unlikely (!this->allocate_size<Type> (((char *) obj) + size - this->head))) return nullptr;
+ assert ((size_t) (this->head - (char *) obj) <= size);
+ if (unlikely (((char *) obj + size < (char *) obj) ||
+ !this->allocate_size<Type> (((char *) obj) + size - this->head))) return nullptr;
return reinterpret_cast<Type *> (obj);
}
template <typename Type>
- Type *extend_size (Type &obj, unsigned int size)
+ Type *extend_size (Type &obj, size_t size)
{ return extend_size (hb_addressof (obj), size); }
template <typename Type>
@@ -497,12 +543,16 @@ struct hb_serialize_context_t
/* Output routines. */
hb_bytes_t copy_bytes () const
{
- assert (this->successful);
+ assert (successful ());
/* Copy both items from head side and tail side... */
unsigned int len = (this->head - this->start)
+ (this->end - this->tail);
- char *p = (char *) malloc (len);
+ // If len is zero don't hb_malloc as the memory won't get properly
+ // cleaned up later.
+ if (!len) return hb_bytes_t ();
+
+ char *p = (char *) hb_malloc (len);
if (unlikely (!p)) return hb_bytes_t ();
memcpy (p, this->start, this->head - this->start);
@@ -517,23 +567,25 @@ struct hb_serialize_context_t
hb_bytes_t b = copy_bytes ();
return hb_blob_create (b.arrayZ, b.length,
HB_MEMORY_MODE_WRITABLE,
- (char *) b.arrayZ, free);
+ (char *) b.arrayZ, hb_free);
}
+ const hb_vector_t<object_t *>& object_graph() const
+ { return packed; }
+
private:
- template <typename T>
+ template <typename T, unsigned Size = sizeof (T)>
void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset)
{
- auto &off = * ((BEInt<T> *) (parent->head + link.position));
+ auto &off = * ((BEInt<T, Size> *) (parent->head + link.position));
assert (0 == off);
- check_assign (off, offset);
+ check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
}
public: /* TODO Make private. */
char *start, *head, *tail, *end;
unsigned int debug_depth;
- bool successful;
- bool ran_out_of_room;
+ hb_serialize_error_t errors;
private:
@@ -550,5 +602,4 @@ struct hb_serialize_context_t
hb_hashmap_t<const object_t *, objidx_t, nullptr, 0> packed_map;
};
-
#endif /* HB_SERIALIZE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh b/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh
index b97526f775..1ef1ba5fb2 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh
@@ -87,6 +87,8 @@ struct hb_set_digest_lowest_bits_t
}
}
template <typename T>
+ void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
+ template <typename T>
bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
{
for (unsigned int i = 0; i < count; i++)
@@ -96,6 +98,8 @@ struct hb_set_digest_lowest_bits_t
}
return true;
}
+ template <typename T>
+ bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
bool may_have (hb_codepoint_t g) const
{ return !!(mask & mask_for (g)); }
@@ -135,12 +139,16 @@ struct hb_set_digest_combiner_t
tail.add_array (array, count, stride);
}
template <typename T>
+ void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
+ template <typename T>
bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
{
head.add_sorted_array (array, count, stride);
tail.add_sorted_array (array, count, stride);
return true;
}
+ template <typename T>
+ bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
bool may_have (hb_codepoint_t g) const
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set.cc b/src/3rdparty/harfbuzz-ng/src/hb-set.cc
index 86bf70034c..25f29c67bf 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-set.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-set.cc
@@ -109,7 +109,7 @@ hb_set_destroy (hb_set_t *set)
set->fini_shallow ();
- free (set);
+ hb_free (set);
}
/**
@@ -173,6 +173,24 @@ hb_set_allocation_successful (const hb_set_t *set)
}
/**
+ * hb_set_copy:
+ * @set: A set
+ *
+ * Allocate a copy of @set.
+ *
+ * Return value: Newly-allocated set.
+ *
+ * Since: 2.8.2
+ **/
+hb_set_t *
+hb_set_copy (const hb_set_t *set)
+{
+ hb_set_t *copy = hb_set_create ();
+ copy->set (*set);
+ return copy;
+}
+
+/**
* hb_set_clear:
* @set: A set
*
@@ -283,6 +301,9 @@ hb_set_del (hb_set_t *set,
* Removes all of the elements from @first to @last
* (inclusive) from @set.
*
+ * If @last is #HB_SET_VALUE_INVALID, then all values
+ * greater than or equal to @first are removed.
+ *
* Since: 0.9.7
**/
void
@@ -309,7 +330,7 @@ hb_bool_t
hb_set_is_equal (const hb_set_t *set,
const hb_set_t *other)
{
- return set->is_equal (other);
+ return set->is_equal (*other);
}
/**
@@ -327,7 +348,7 @@ hb_bool_t
hb_set_is_subset (const hb_set_t *set,
const hb_set_t *larger_set)
{
- return set->is_subset (larger_set);
+ return set->is_subset (*larger_set);
}
/**
@@ -343,7 +364,7 @@ void
hb_set_set (hb_set_t *set,
const hb_set_t *other)
{
- set->set (other);
+ set->set (*other);
}
/**
@@ -359,7 +380,7 @@ void
hb_set_union (hb_set_t *set,
const hb_set_t *other)
{
- set->union_ (other);
+ set->union_ (*other);
}
/**
@@ -375,7 +396,7 @@ void
hb_set_intersect (hb_set_t *set,
const hb_set_t *other)
{
- set->intersect (other);
+ set->intersect (*other);
}
/**
@@ -391,7 +412,7 @@ void
hb_set_subtract (hb_set_t *set,
const hb_set_t *other)
{
- set->subtract (other);
+ set->subtract (*other);
}
/**
@@ -408,7 +429,7 @@ void
hb_set_symmetric_difference (hb_set_t *set,
const hb_set_t *other)
{
- set->symmetric_difference (other);
+ set->symmetric_difference (*other);
}
#ifndef HB_DISABLE_DEPRECATED
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set.h b/src/3rdparty/harfbuzz-ng/src/hb-set.h
index 0ad27f4bbd..7f2112e69f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-set.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-set.h
@@ -85,6 +85,9 @@ hb_set_get_user_data (hb_set_t *set,
HB_EXTERN hb_bool_t
hb_set_allocation_successful (const hb_set_t *set);
+HB_EXTERN hb_set_t *
+hb_set_copy (const hb_set_t *set);
+
HB_EXTERN void
hb_set_clear (hb_set_t *set);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set.hh b/src/3rdparty/harfbuzz-ng/src/hb-set.hh
index ae8b5eb10f..8bb7f9f0b4 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-set.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-set.hh
@@ -35,18 +35,23 @@
* hb_set_t
*/
-/* TODO Keep a free-list so we can free pages that are completely zeroed. At that
+/* TODO Keep a freelist so we can release pages that are completely zeroed. At that
* point maybe also use a sentinel value for "all-1" pages? */
struct hb_set_t
{
- HB_DELETE_COPY_ASSIGN (hb_set_t);
hb_set_t () { init (); }
~hb_set_t () { fini (); }
+ hb_set_t (const hb_set_t& other) : hb_set_t () { set (other); }
+ void operator= (const hb_set_t& other) { set (other); }
+ // TODO Add move construtor/assign
+ // TODO Add constructor for Iterator; with specialization for (sorted) vector / array?
+
struct page_map_t
{
int cmp (const page_map_t &o) const { return (int) o.major - (int) major; }
+ int cmp (uint32_t o_major) const { return (int) o_major - (int) major; }
uint32_t major;
uint32_t index;
@@ -57,7 +62,7 @@ struct hb_set_t
void init0 () { v.clear (); }
void init1 () { v.clear (0xFF); }
- unsigned int len () const
+ constexpr unsigned len () const
{ return ARRAY_LENGTH_CONST (v); }
bool is_empty () const
@@ -106,9 +111,16 @@ struct hb_set_t
}
}
- bool is_equal (const page_t *other) const
+ bool is_equal (const page_t &other) const
+ {
+ return 0 == hb_memcmp (&v, &other.v, sizeof (v));
+ }
+ bool is_subset (const page_t &larger_page) const
{
- return 0 == hb_memcmp (&v, &other->v, sizeof (v));
+ for (unsigned i = 0; i < len (); i++)
+ if (~larger_page.v[i] & v[i])
+ return false;
+ return true;
}
unsigned int get_population () const
@@ -203,8 +215,8 @@ struct hb_set_t
static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
- elt_t const &elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
- elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & ELT_MASK); }
+ 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;
};
@@ -213,6 +225,7 @@ struct hb_set_t
hb_object_header_t header;
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;
@@ -220,6 +233,7 @@ struct hb_set_t
{
successful = true;
population = 0;
+ last_page_lookup = 0;
page_map.init ();
pages.init ();
}
@@ -231,6 +245,7 @@ struct hb_set_t
void fini_shallow ()
{
population = 0;
+ last_page_lookup = 0;
page_map.fini ();
pages.fini ();
}
@@ -337,6 +352,8 @@ struct hb_set_t
while (count && (g = *array, start <= g && g < end));
}
}
+ 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. */
@@ -368,6 +385,8 @@ struct hb_set_t
}
return true;
}
+ 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)
{
@@ -408,7 +427,7 @@ struct hb_set_t
{
/* TODO perform op even if !successful. */
if (unlikely (!successful)) return;
- if (unlikely (a > b || a == INVALID || b == INVALID)) return;
+ if (unlikely (a > b || a == INVALID)) return;
dirty ();
unsigned int ma = get_major (a);
unsigned int mb = get_major (b);
@@ -462,32 +481,33 @@ struct hb_set_t
hb_codepoint_t c = first - 1;
return next (&c) && c <= last;
}
- void set (const hb_set_t *other)
+ void set (const hb_set_t &other)
{
if (unlikely (!successful)) return;
- unsigned int count = other->pages.length;
+ unsigned int count = other.pages.length;
if (!resize (count))
return;
- population = other->population;
- memcpy ((void *) pages, (const void *) other->pages, count * pages.item_size);
- memcpy ((void *) page_map, (const void *) other->page_map, count * page_map.item_size);
+ population = other.population;
+
+ 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_set_t *other) const
+ bool is_equal (const hb_set_t &other) const
{
- if (get_population () != other->get_population ())
+ if (get_population () != other.get_population ())
return false;
unsigned int na = pages.length;
- unsigned int nb = other->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)))
+ 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++;
@@ -495,21 +515,40 @@ struct hb_set_t
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; }
+ if (!other.page_at (b).is_empty ()) { return false; }
return true;
}
- bool is_subset (const hb_set_t *larger_set) const
+ bool is_subset (const hb_set_t &larger_set) const
{
- if (get_population () > larger_set->get_population ())
- return false;
+ /* TODO: Merge this and is_equal() into something like process(). */
+ if (unlikely(larger_set.is_empty ()))
+ return is_empty ();
- /* TODO Optimize to use pages. */
- hb_codepoint_t c = INVALID;
- while (next (&c))
- if (!larger_set->has (c))
- 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;
}
@@ -560,7 +599,7 @@ struct hb_set_t
}
template <typename Op>
- void process (const Op& op, const hb_set_t *other)
+ void process (const Op& op, const hb_set_t &other)
{
const bool passthru_left = op (1, 0);
const bool passthru_right = op (0, 1);
@@ -570,7 +609,7 @@ struct hb_set_t
dirty ();
unsigned int na = pages.length;
- unsigned int nb = other->pages.length;
+ unsigned int nb = other.pages.length;
unsigned int next_page = na;
unsigned int count = 0, newCount = 0;
@@ -584,7 +623,7 @@ struct hb_set_t
for (; a < na && b < nb; )
{
- if (page_map[a].major == other->page_map[b].major)
+ if (page_map[a].major == other.page_map[b].major)
{
if (!passthru_left)
{
@@ -601,7 +640,7 @@ struct hb_set_t
a++;
b++;
}
- else if (page_map[a].major < other->page_map[b].major)
+ else if (page_map[a].major < other.page_map[b].major)
{
if (passthru_left)
count++;
@@ -636,15 +675,15 @@ struct hb_set_t
b = nb;
for (; a && b; )
{
- if (page_map[a - 1].major == other->page_map[b - 1].major)
+ 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);
+ 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)
+ else if (page_map[a - 1].major > other.page_map[b - 1].major)
{
a--;
if (passthru_left)
@@ -659,9 +698,9 @@ struct hb_set_t
if (passthru_right)
{
count--;
- page_map[count].major = other->page_map[b].major;
+ page_map[count].major = other.page_map[b].major;
page_map[count].index = next_page++;
- page_at (count).v = other->page_at (b).v;
+ page_at (count).v = other.page_at (b).v;
}
}
}
@@ -677,9 +716,9 @@ struct hb_set_t
{
b--;
count--;
- page_map[count].major = other->page_map[b].major;
+ page_map[count].major = other.page_map[b].major;
page_map[count].index = next_page++;
- page_at (count).v = other->page_at (b).v;
+ page_at (count).v = other.page_at (b).v;
}
assert (!count);
if (pages.length > newCount)
@@ -689,50 +728,69 @@ struct hb_set_t
resize (newCount);
}
- void union_ (const hb_set_t *other)
+ void union_ (const hb_set_t &other)
{
process (hb_bitwise_or, other);
}
- void intersect (const hb_set_t *other)
+ void intersect (const hb_set_t &other)
{
process (hb_bitwise_and, other);
}
- void subtract (const hb_set_t *other)
+ void subtract (const hb_set_t &other)
{
process (hb_bitwise_sub, other);
}
- void symmetric_difference (const hb_set_t *other)
+ void symmetric_difference (const hb_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;
}
- page_map_t map = {get_major (*codepoint), 0};
- unsigned int i;
- page_map.bfind (map, &i, HB_BFIND_NOT_FOUND_STORE_CLOSEST);
- if (i < page_map.length && page_map[i].major == map.major)
+ 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[page_map[i].index].next (codepoint))
+ if (pages_array[current.index].next (codepoint))
{
- *codepoint += page_map[i].major * page_t::PAGE_BITS;
- return true;
+ *codepoint += current.major * page_t::PAGE_BITS;
+ last_page_lookup = i;
+ return true;
}
i++;
}
+
for (; i < page_map.length; i++)
{
- hb_codepoint_t m = pages[page_map[i].index].get_min ();
+ const page_map_t &current = page_map.arrayZ[i];
+ hb_codepoint_t m = pages_array[current.index].get_min ();
if (m != INVALID)
{
- *codepoint = page_map[i].major * page_t::PAGE_BITS + m;
+ *codepoint = current.major * page_t::PAGE_BITS + m;
+ last_page_lookup = i;
return true;
}
}
+ last_page_lookup = 0;
*codepoint = INVALID;
return false;
}
@@ -745,7 +803,7 @@ struct hb_set_t
page_map_t map = {get_major (*codepoint), 0};
unsigned int i;
- page_map.bfind (map, &i, HB_BFIND_NOT_FOUND_STORE_CLOSEST);
+ 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))
@@ -828,7 +886,7 @@ struct hb_set_t
hb_codepoint_t get_max () const
{
unsigned int count = pages.length;
- for (int i = count - 1; i >= 0; i++)
+ for (int i = count - 1; i >= 0; i--)
if (!page_at (i).is_empty ())
return page_map[(unsigned) i].major * page_t::PAGE_BITS + page_at (i).get_max ();
return INVALID;
@@ -876,7 +934,7 @@ struct hb_set_t
{
page_map_t map = {get_major (g), pages.length};
unsigned int i;
- if (!page_map.bfind (map, &i, HB_BFIND_NOT_FOUND_STORE_CLOSEST))
+ if (!page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST))
{
if (!resize (pages.length + 1))
return nullptr;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc b/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc
index 0d9eaddaa6..aa7da2db3f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc
@@ -66,7 +66,7 @@ hb_shape_plan_key_t::init (bool copy,
const char * const *shaper_list)
{
hb_feature_t *features = nullptr;
- if (copy && num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
+ if (copy && num_user_features && !(features = (hb_feature_t *) hb_calloc (num_user_features, sizeof (hb_feature_t))))
goto bail;
this->props = *props;
@@ -130,7 +130,7 @@ hb_shape_plan_key_t::init (bool copy,
#undef HB_SHAPER_PLAN
bail:
- ::free (features);
+ ::hb_free (features);
return false;
}
@@ -264,9 +264,9 @@ hb_shape_plan_create2 (hb_face_t *face,
#ifndef HB_NO_OT_SHAPE
bail3:
#endif
- shape_plan->key.free ();
+ shape_plan->key.fini ();
bail2:
- free (shape_plan);
+ hb_free (shape_plan);
bail:
return hb_shape_plan_get_empty ();
}
@@ -320,8 +320,8 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
#ifndef HB_NO_OT_SHAPE
shape_plan->ot.fini ();
#endif
- shape_plan->key.free ();
- free (shape_plan);
+ shape_plan->key.fini ();
+ hb_free (shape_plan);
}
/**
@@ -560,7 +560,7 @@ retry:
if (unlikely (dont_cache))
return shape_plan;
- hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
+ hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) hb_calloc (1, sizeof (hb_face_t::plan_node_t));
if (unlikely (!node))
return shape_plan;
@@ -570,7 +570,7 @@ retry:
if (unlikely (!face->shape_plans.cmpexch (cached_plan_nodes, node)))
{
hb_shape_plan_destroy (shape_plan);
- free (node);
+ hb_free (node);
goto retry;
}
DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.hh b/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.hh
index 6da7edb2f8..8cb4ddb927 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.hh
@@ -55,7 +55,7 @@ struct hb_shape_plan_key_t
unsigned int num_coords,
const char * const *shaper_list);
- HB_INTERNAL void free () { ::free ((void *) user_features); }
+ HB_INTERNAL void fini () { hb_free ((void *) user_features); }
HB_INTERNAL bool user_features_match (const hb_shape_plan_key_t *other);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-shape.cc
index c442f4403b..f303a569fd 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-shape.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-shape.cc
@@ -59,7 +59,7 @@ static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *,
{
static const char ** create ()
{
- const char **shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
+ const char **shaper_list = (const char **) hb_calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
if (unlikely (!shaper_list))
return nullptr;
@@ -76,7 +76,7 @@ static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *,
return shaper_list;
}
static void destroy (const char **l)
- { free (l); }
+ { hb_free (l); }
static const char ** get_null ()
{ return nil_shaper_list; }
} static_shaper_list;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shaper.cc b/src/3rdparty/harfbuzz-ng/src/hb-shaper.cc
index 0ea68ad1f5..265df1084b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-shaper.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-shaper.cc
@@ -51,7 +51,7 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_
if (!env || !*env)
return nullptr;
- hb_shaper_entry_t *shapers = (hb_shaper_entry_t *) calloc (1, sizeof (all_shapers));
+ hb_shaper_entry_t *shapers = (hb_shaper_entry_t *) hb_calloc (1, sizeof (all_shapers));
if (unlikely (!shapers))
return nullptr;
@@ -89,7 +89,7 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_
return shapers;
}
- static void destroy (const hb_shaper_entry_t *p) { free ((void *) p); }
+ static void destroy (const hb_shaper_entry_t *p) { hb_free ((void *) p); }
static const hb_shaper_entry_t *get_null () { return all_shapers; }
} static_shapers;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-static.cc b/src/3rdparty/harfbuzz-ng/src/hb-static.cc
index f5b7fa50a0..ec4b241470 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-static.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-static.cc
@@ -43,6 +43,7 @@ uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof
/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
DEFINE_NULL_NAMESPACE_BYTES (OT, Index) = {0xFF,0xFF};
+DEFINE_NULL_NAMESPACE_BYTES (OT, VarIdx) = {0xFF,0xFF,0xFF,0xFF};
DEFINE_NULL_NAMESPACE_BYTES (OT, LangSys) = {0x00,0x00, 0xFF,0xFF, 0x00,0x00};
DEFINE_NULL_NAMESPACE_BYTES (OT, RangeRecord) = {0x00,0x01, 0x00,0x00, 0x00, 0x00};
DEFINE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup) = {0x00,0x00,0x00,0x01, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc
index 04e1db24ac..711b2236d6 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc
@@ -38,13 +38,12 @@
using namespace CFF;
-/**
- * hb_plan_subset_cff_fdselect
- * Determine an optimal FDSelect format according to a provided plan.
+
+/* Determine an optimal FDSelect format according to a provided plan.
*
* Return value: FDSelect format, size, and ranges for the most compact subset FDSelect
* along with a font index remapping table
- **/
+ */
bool
hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
@@ -169,10 +168,7 @@ serialize_fdselect_3_4 (hb_serialize_context_t *c,
return_trace (true);
}
-/**
- * hb_serialize_cff_fdselect
- * Serialize a subset FDSelect format planned above.
- **/
+/* Serialize a subset FDSelect format planned above. */
bool
hb_serialize_cff_fdselect (hb_serialize_context_t *c,
const unsigned int num_glyphs,
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh
index 422b20b8d0..7fd96ca86d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh
@@ -259,7 +259,10 @@ struct subr_flattener_t
return false;
cs_interpreter_t<ENV, OPSET, flatten_param_t> interp;
interp.env.init (str, acc, fd);
- flatten_param_t param = { flat_charstrings[i], plan->drop_hints };
+ flatten_param_t param = {
+ flat_charstrings[i],
+ (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+ };
if (unlikely (!interp.interpret (param)))
return false;
}
@@ -636,7 +639,7 @@ struct subr_subsetter_t
param.init (&parsed_charstrings[i],
&parsed_global_subrs, &parsed_local_subrs[fd],
closures.global_closure, closures.local_closures[fd],
- plan->drop_hints);
+ plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
if (unlikely (!interp.interpret (param)))
return false;
@@ -645,7 +648,7 @@ struct subr_subsetter_t
SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[i]);
}
- if (plan->drop_hints)
+ if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
{
/* mark hint ops and arguments for drop */
for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
@@ -660,7 +663,7 @@ struct subr_subsetter_t
param.init (&parsed_charstrings[i],
&parsed_global_subrs, &parsed_local_subrs[fd],
closures.global_closure, closures.local_closures[fd],
- plan->drop_hints);
+ plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
drop_hints_param_t drop;
if (drop_hints_in_str (parsed_charstrings[i], param, drop))
@@ -685,7 +688,7 @@ struct subr_subsetter_t
param.init (&parsed_charstrings[i],
&parsed_global_subrs, &parsed_local_subrs[fd],
closures.global_closure, closures.local_closures[fd],
- plan->drop_hints);
+ plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
collect_subr_refs_in_str (parsed_charstrings[i], param);
}
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc
index df322f8451..b4e24122c9 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc
@@ -402,7 +402,7 @@ struct cff_subset_plan {
void plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
{
const Encoding *encoding = acc.encoding;
- unsigned int size0, size1, supp_size;
+ unsigned int size0, size1;
hb_codepoint_t code, last_code = CFF_UNDEF_CODE;
hb_vector_t<hb_codepoint_t> supp_codes;
@@ -412,7 +412,6 @@ struct cff_subset_plan {
return;
}
- supp_size = 0;
supp_codes.init ();
subset_enc_num_codes = plan->num_output_glyphs () - 1;
@@ -448,7 +447,6 @@ struct cff_subset_plan {
code_pair_t pair = { supp_codes[i], sid };
subset_enc_supp_codes.push (pair);
}
- supp_size += SuppEncoding::static_size * supp_codes.length;
}
}
supp_codes.fini ();
@@ -545,8 +543,8 @@ struct cff_subset_plan {
num_glyphs = plan->num_output_glyphs ();
orig_fdcount = acc.fdCount;
- drop_hints = plan->drop_hints;
- desubroutinize = plan->desubroutinize;
+ drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING;
+ desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE;
/* check whether the subset renumbers any glyph IDs */
gid_renum = false;
@@ -919,12 +917,6 @@ _hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc,
return _serialize_cff1 (c->serializer, cff_plan, acc, c->plan->num_output_glyphs ());
}
-/**
- * hb_subset_cff1:
- * Subsets the CFF table according to a provided plan.
- *
- * Return value: subsetted cff table.
- **/
bool
hb_subset_cff1 (hb_subset_context_t *c)
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc
index 17ee040deb..896ae64016 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc
@@ -262,8 +262,8 @@ struct cff2_subset_plan {
{
orig_fdcount = acc.fdArray->count;
- drop_hints = plan->drop_hints;
- desubroutinize = plan->desubroutinize;
+ drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING;
+ desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE;
if (desubroutinize)
{
@@ -470,10 +470,6 @@ _hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc,
return _serialize_cff2 (c->serializer, cff2_plan, acc, c->plan->num_output_glyphs ());
}
-/**
- * hb_subset_cff2:
- * Subsets the CFF2 table according to a provided subset context.
- **/
bool
hb_subset_cff2 (hb_subset_context_t *c)
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc
index fe9be3ce02..e2e325f12b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc
@@ -30,12 +30,15 @@
/**
* hb_subset_input_create_or_fail:
*
- * Return value: New subset input.
+ * Creates a new subset input object.
+ *
+ * Return value: (transfer full): New subset input, or %NULL if failed. Destroy
+ * with hb_subset_input_destroy().
*
* Since: 1.8.0
**/
hb_subset_input_t *
-hb_subset_input_create_or_fail ()
+hb_subset_input_create_or_fail (void)
{
hb_subset_input_t *input = hb_object_create<hb_subset_input_t>();
@@ -48,17 +51,14 @@ hb_subset_input_create_or_fail ()
hb_set_add_range (input->name_ids, 0, 6);
input->name_languages = hb_set_create ();
hb_set_add (input->name_languages, 0x0409);
+ input->layout_features = hb_set_create ();
input->drop_tables = hb_set_create ();
- input->drop_hints = false;
- input->desubroutinize = false;
- input->retain_gids = false;
- input->name_legacy = false;
+ input->no_subset_tables = hb_set_create ();
+
+ input->flags = HB_SUBSET_FLAGS_DEFAULT;
hb_tag_t default_drop_tables[] = {
// Layout disabled by default
- HB_TAG ('G', 'S', 'U', 'B'),
- HB_TAG ('G', 'P', 'O', 'S'),
- HB_TAG ('G', 'D', 'E', 'F'),
HB_TAG ('m', 'o', 'r', 'x'),
HB_TAG ('m', 'o', 'r', 't'),
HB_TAG ('k', 'e', 'r', 'x'),
@@ -81,149 +81,478 @@ hb_subset_input_create_or_fail ()
HB_TAG ('S', 'i', 'l', 'f'),
HB_TAG ('S', 'i', 'l', 'l'),
};
-
input->drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables));
+ hb_tag_t default_no_subset_tables[] = {
+ HB_TAG ('a', 'v', 'a', 'r'),
+ HB_TAG ('f', 'v', 'a', 'r'),
+ HB_TAG ('g', 'a', 's', 'p'),
+ HB_TAG ('c', 'v', 't', ' '),
+ HB_TAG ('f', 'p', 'g', 'm'),
+ HB_TAG ('p', 'r', 'e', 'p'),
+ HB_TAG ('V', 'D', 'M', 'X'),
+ HB_TAG ('D', 'S', 'I', 'G'),
+ HB_TAG ('M', 'V', 'A', 'R'),
+ HB_TAG ('c', 'v', 'a', 'r'),
+ HB_TAG ('S', 'T', 'A', 'T'),
+ };
+ input->no_subset_tables->add_array (default_no_subset_tables,
+ ARRAY_LENGTH (default_no_subset_tables));
+
+ //copied from _layout_features_groups in fonttools
+ hb_tag_t default_layout_features[] = {
+ // default shaper
+ // common
+ HB_TAG ('r', 'v', 'r', 'n'),
+ HB_TAG ('c', 'c', 'm', 'p'),
+ HB_TAG ('l', 'i', 'g', 'a'),
+ HB_TAG ('l', 'o', 'c', 'l'),
+ HB_TAG ('m', 'a', 'r', 'k'),
+ HB_TAG ('m', 'k', 'm', 'k'),
+ HB_TAG ('r', 'l', 'i', 'g'),
+
+ //fractions
+ HB_TAG ('f', 'r', 'a', 'c'),
+ HB_TAG ('n', 'u', 'm', 'r'),
+ HB_TAG ('d', 'n', 'o', 'm'),
+
+ //horizontal
+ HB_TAG ('c', 'a', 'l', 't'),
+ HB_TAG ('c', 'l', 'i', 'g'),
+ HB_TAG ('c', 'u', 'r', 's'),
+ HB_TAG ('k', 'e', 'r', 'n'),
+ HB_TAG ('r', 'c', 'l', 't'),
+
+ //vertical
+ HB_TAG ('v', 'a', 'l', 't'),
+ HB_TAG ('v', 'e', 'r', 't'),
+ HB_TAG ('v', 'k', 'r', 'n'),
+ HB_TAG ('v', 'p', 'a', 'l'),
+ HB_TAG ('v', 'r', 't', '2'),
+
+ //ltr
+ HB_TAG ('l', 't', 'r', 'a'),
+ HB_TAG ('l', 't', 'r', 'm'),
+
+ //rtl
+ HB_TAG ('r', 't', 'l', 'a'),
+ HB_TAG ('r', 't', 'l', 'm'),
+
+ //Complex shapers
+ //arabic
+ HB_TAG ('i', 'n', 'i', 't'),
+ HB_TAG ('m', 'e', 'd', 'i'),
+ HB_TAG ('f', 'i', 'n', 'a'),
+ HB_TAG ('i', 's', 'o', 'l'),
+ HB_TAG ('m', 'e', 'd', '2'),
+ HB_TAG ('f', 'i', 'n', '2'),
+ HB_TAG ('f', 'i', 'n', '3'),
+ HB_TAG ('c', 's', 'w', 'h'),
+ HB_TAG ('m', 's', 'e', 't'),
+ HB_TAG ('s', 't', 'c', 'h'),
+
+ //hangul
+ HB_TAG ('l', 'j', 'm', 'o'),
+ HB_TAG ('v', 'j', 'm', 'o'),
+ HB_TAG ('t', 'j', 'm', 'o'),
+
+ //tibetan
+ HB_TAG ('a', 'b', 'v', 's'),
+ HB_TAG ('b', 'l', 'w', 's'),
+ HB_TAG ('a', 'b', 'v', 'm'),
+ HB_TAG ('b', 'l', 'w', 'm'),
+
+ //indic
+ HB_TAG ('n', 'u', 'k', 't'),
+ HB_TAG ('a', 'k', 'h', 'n'),
+ HB_TAG ('r', 'p', 'h', 'f'),
+ HB_TAG ('r', 'k', 'r', 'f'),
+ HB_TAG ('p', 'r', 'e', 'f'),
+ HB_TAG ('b', 'l', 'w', 'f'),
+ HB_TAG ('h', 'a', 'l', 'f'),
+ HB_TAG ('a', 'b', 'v', 'f'),
+ HB_TAG ('p', 's', 't', 'f'),
+ HB_TAG ('c', 'f', 'a', 'r'),
+ HB_TAG ('v', 'a', 't', 'u'),
+ HB_TAG ('c', 'j', 'c', 't'),
+ HB_TAG ('i', 'n', 'i', 't'),
+ HB_TAG ('p', 'r', 'e', 's'),
+ HB_TAG ('a', 'b', 'v', 's'),
+ HB_TAG ('b', 'l', 'w', 's'),
+ HB_TAG ('p', 's', 't', 's'),
+ HB_TAG ('h', 'a', 'l', 'n'),
+ HB_TAG ('d', 'i', 's', 't'),
+ HB_TAG ('a', 'b', 'v', 'm'),
+ HB_TAG ('b', 'l', 'w', 'm'),
+ };
+
+ input->layout_features->add_array (default_layout_features, ARRAY_LENGTH (default_layout_features));
return input;
}
/**
* hb_subset_input_reference: (skip)
- * @subset_input: a subset_input.
- *
+ * @input: a #hb_subset_input_t object.
*
+ * Increases the reference count on @input.
*
- * Return value:
+ * Return value: @input.
*
* Since: 1.8.0
**/
hb_subset_input_t *
-hb_subset_input_reference (hb_subset_input_t *subset_input)
+hb_subset_input_reference (hb_subset_input_t *input)
{
- return hb_object_reference (subset_input);
+ return hb_object_reference (input);
}
/**
* hb_subset_input_destroy:
- * @subset_input: a subset_input.
+ * @input: a #hb_subset_input_t object.
+ *
+ * Decreases the reference count on @input, and if it reaches zero, destroys
+ * @input, freeing all memory.
*
* Since: 1.8.0
**/
void
-hb_subset_input_destroy (hb_subset_input_t *subset_input)
+hb_subset_input_destroy (hb_subset_input_t *input)
{
- if (!hb_object_destroy (subset_input)) return;
+ if (!hb_object_destroy (input)) return;
- hb_set_destroy (subset_input->unicodes);
- hb_set_destroy (subset_input->glyphs);
- hb_set_destroy (subset_input->name_ids);
- hb_set_destroy (subset_input->name_languages);
- hb_set_destroy (subset_input->drop_tables);
+ hb_set_destroy (input->unicodes);
+ hb_set_destroy (input->glyphs);
+ hb_set_destroy (input->name_ids);
+ hb_set_destroy (input->name_languages);
+ hb_set_destroy (input->drop_tables);
+ hb_set_destroy (input->layout_features);
+ hb_set_destroy (input->no_subset_tables);
- free (subset_input);
+ hb_free (input);
}
/**
* hb_subset_input_unicode_set:
- * @subset_input: a subset_input.
+ * @input: a #hb_subset_input_t object.
+ *
+ * Gets the set of Unicode code points to retain, the caller should modify the
+ * set as needed.
+ *
+ * Return value: (transfer none): pointer to the #hb_set_t of Unicode code
+ * points.
*
* Since: 1.8.0
**/
HB_EXTERN hb_set_t *
-hb_subset_input_unicode_set (hb_subset_input_t *subset_input)
+hb_subset_input_unicode_set (hb_subset_input_t *input)
{
- return subset_input->unicodes;
+ return input->unicodes;
}
/**
* hb_subset_input_glyph_set:
- * @subset_input: a subset_input.
+ * @input: a #hb_subset_input_t object.
+ *
+ * Gets the set of glyph IDs to retain, the caller should modify the set as
+ * needed.
+ *
+ * Return value: (transfer none): pointer to the #hb_set_t of glyph IDs.
*
* Since: 1.8.0
**/
HB_EXTERN hb_set_t *
-hb_subset_input_glyph_set (hb_subset_input_t *subset_input)
+hb_subset_input_glyph_set (hb_subset_input_t *input)
{
- return subset_input->glyphs;
+ return input->glyphs;
}
+/**
+ * hb_subset_input_nameid_set:
+ * @input: a #hb_subset_input_t object.
+ *
+ * Gets the set of name table name IDs to retain, the caller should modify the
+ * set as needed.
+ *
+ * Return value: (transfer none): pointer to the #hb_set_t of name IDs.
+ *
+ * Since: 2.9.0
+ **/
HB_EXTERN hb_set_t *
-hb_subset_input_nameid_set (hb_subset_input_t *subset_input)
+hb_subset_input_nameid_set (hb_subset_input_t *input)
{
- return subset_input->name_ids;
+ return input->name_ids;
}
+/**
+ * hb_subset_input_namelangid_set:
+ * @input: a #hb_subset_input_t object.
+ *
+ * Gets the set of name table language IDs to retain, the caller should modify
+ * the set as needed.
+ *
+ * Return value: (transfer none): pointer to the #hb_set_t of language IDs.
+ *
+ * Since: 2.9.0
+ **/
HB_EXTERN hb_set_t *
-hb_subset_input_namelangid_set (hb_subset_input_t *subset_input)
+hb_subset_input_namelangid_set (hb_subset_input_t *input)
{
- return subset_input->name_languages;
+ return input->name_languages;
}
+
+/**
+ * hb_subset_input_layout_features_set:
+ * @input: a #hb_subset_input_t object.
+ *
+ * Gets the set of layout feature tags to retain, the caller should modify the
+ * set as needed.
+ *
+ * Return value: (transfer none): pointer to the #hb_set_t of feature tags.
+ *
+ * Since: 2.9.0
+ **/
HB_EXTERN hb_set_t *
-hb_subset_input_drop_tables_set (hb_subset_input_t *subset_input)
+hb_subset_input_layout_features_set (hb_subset_input_t *input)
{
- return subset_input->drop_tables;
+ return input->layout_features;
}
+/**
+ * hb_subset_input_drop_tables_set:
+ * @input: a #hb_subset_input_t object.
+ *
+ * Gets the set of table tags to drop, the caller should modify the set as
+ * needed.
+ *
+ * Return value: (transfer none): pointer to the #hb_set_t of table tags.
+ *
+ * Since: 2.9.0
+ **/
+HB_EXTERN hb_set_t *
+hb_subset_input_drop_tables_set (hb_subset_input_t *input)
+{
+ return input->drop_tables;
+}
+
+/**
+ * hb_subset_input_no_subset_tables_set:
+ * @input: a #hb_subset_input_t object.
+ *
+ * Gets the set of table tags which specifies tables that should not be
+ * subsetted, the caller should modify the set as needed.
+ *
+ * Return value: (transfer none): pointer to the #hb_set_t of table tags.
+ *
+ * Since: 2.9.0
+ **/
+HB_EXTERN hb_set_t *
+hb_subset_input_no_subset_tables_set (hb_subset_input_t *input)
+{
+ return input->no_subset_tables;
+}
+
+
+/**
+ * hb_subset_input_get_flags:
+ * @input: a #hb_subset_input_t object.
+ *
+ * Return value: the subsetting flags bit field.
+ *
+ * Since: 2.9.0
+ **/
+HB_EXTERN hb_subset_flags_t
+hb_subset_input_get_flags (hb_subset_input_t *input)
+{
+ return (hb_subset_flags_t) input->flags;
+}
+
+/**
+ * hb_subset_input_set_flags:
+ * @input: a #hb_subset_input_t object.
+ * @value: bit field of flags
+ *
+ * Set all of the flags in the input object to the values
+ * specified by the bit field.
+ *
+ * Since: 2.9.0
+ **/
HB_EXTERN void
+hb_subset_input_set_flags (hb_subset_input_t *input,
+ unsigned value)
+{
+ input->flags = (hb_subset_flags_t) value;
+}
+
+/**
+ * hb_subset_input_set_user_data: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @key: The user-data key to set
+ * @data: A pointer to the user data
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
+ * @replace: Whether to replace an existing data with the same key
+ *
+ * Attaches a user-data key/data pair to the given subset input object.
+ *
+ * Return value: %true if success, %false otherwise
+ *
+ * Since: 2.9.0
+ **/
+hb_bool_t
+hb_subset_input_set_user_data (hb_subset_input_t *input,
+ hb_user_data_key_t *key,
+ void * data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace)
+{
+ return hb_object_set_user_data (input, key, data, destroy, replace);
+}
+
+/**
+ * hb_subset_input_get_user_data: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @key: The user-data key to query
+ *
+ * Fetches the user data associated with the specified key,
+ * attached to the specified subset input object.
+ *
+ * Return value: (transfer none): A pointer to the user data
+ *
+ * Since: 2.9.0
+ **/
+void *
+hb_subset_input_get_user_data (const hb_subset_input_t *input,
+ hb_user_data_key_t *key)
+{
+ return hb_object_get_user_data (input, key);
+}
+
+
+static void set_flag_value (hb_subset_input_t *input, hb_subset_flags_t flag, hb_bool_t value)
+{
+ hb_subset_input_set_flags (input,
+ value
+ ? hb_subset_input_get_flags (input) | flag
+ : hb_subset_input_get_flags (input) & ~flag);
+}
+
+void
+hb_subset_input_set_retain_all_features (hb_subset_input_t *subset_input,
+ hb_bool_t value)
+{
+ return set_flag_value (subset_input,
+ HB_SUBSET_FLAGS_RETAIN_ALL_FEATURES,
+ value);
+}
+
+hb_bool_t
+hb_subset_input_get_retain_all_features (hb_subset_input_t *subset_input)
+{
+ return (bool) (hb_subset_input_get_flags (subset_input) & HB_SUBSET_FLAGS_RETAIN_ALL_FEATURES);
+}
+
+void
hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
hb_bool_t drop_hints)
{
- subset_input->drop_hints = drop_hints;
+ return set_flag_value (subset_input,
+ HB_SUBSET_FLAGS_NO_HINTING,
+ drop_hints);
}
-HB_EXTERN hb_bool_t
+hb_bool_t
hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input)
{
- return subset_input->drop_hints;
+ return (bool) (hb_subset_input_get_flags (subset_input) & HB_SUBSET_FLAGS_NO_HINTING);
}
-HB_EXTERN void
+void
hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input,
hb_bool_t desubroutinize)
{
- subset_input->desubroutinize = desubroutinize;
+ return set_flag_value (subset_input,
+ HB_SUBSET_FLAGS_DESUBROUTINIZE,
+ desubroutinize);
}
-HB_EXTERN hb_bool_t
+hb_bool_t
hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input)
{
- return subset_input->desubroutinize;
+ return (bool) (hb_subset_input_get_flags (subset_input) & HB_SUBSET_FLAGS_DESUBROUTINIZE);
}
-/**
- * hb_subset_input_set_retain_gids:
- * @subset_input: a subset_input.
- * @retain_gids: If true the subsetter will not renumber glyph ids.
- * Since: 2.4.0
- **/
-HB_EXTERN void
+void
hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input,
hb_bool_t retain_gids)
{
- subset_input->retain_gids = retain_gids;
+ return set_flag_value (subset_input,
+ HB_SUBSET_FLAGS_RETAIN_GIDS,
+ retain_gids);
}
-/**
- * hb_subset_input_get_retain_gids:
- * Returns: value of retain_gids.
- * Since: 2.4.0
- **/
-HB_EXTERN hb_bool_t
+hb_bool_t
hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input)
{
- return subset_input->retain_gids;
+ return (bool) (hb_subset_input_get_flags (subset_input) & HB_SUBSET_FLAGS_RETAIN_GIDS);
}
-HB_EXTERN void
+void
hb_subset_input_set_name_legacy (hb_subset_input_t *subset_input,
hb_bool_t name_legacy)
{
- subset_input->name_legacy = name_legacy;
+ return set_flag_value (subset_input,
+ HB_SUBSET_FLAGS_NAME_LEGACY,
+ name_legacy);
}
-HB_EXTERN hb_bool_t
+hb_bool_t
hb_subset_input_get_name_legacy (hb_subset_input_t *subset_input)
{
- return subset_input->name_legacy;
+ return (bool) (hb_subset_input_get_flags (subset_input) & HB_SUBSET_FLAGS_NAME_LEGACY);
+}
+
+void
+hb_subset_input_set_overlaps_flag (hb_subset_input_t *subset_input,
+ hb_bool_t overlaps_flag)
+{
+ return set_flag_value (subset_input,
+ HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG,
+ overlaps_flag);
+}
+
+hb_bool_t
+hb_subset_input_get_overlaps_flag (hb_subset_input_t *subset_input)
+{
+ return (bool) (hb_subset_input_get_flags (subset_input) & HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG);
+}
+
+void
+hb_subset_input_set_notdef_outline (hb_subset_input_t *subset_input,
+ hb_bool_t notdef_outline)
+{
+ return set_flag_value (subset_input,
+ HB_SUBSET_FLAGS_NOTDEF_OUTLINE,
+ notdef_outline);
+}
+
+hb_bool_t
+hb_subset_input_get_notdef_outline (hb_subset_input_t *subset_input)
+{
+ return (bool) (hb_subset_input_get_flags (subset_input) & HB_SUBSET_FLAGS_NOTDEF_OUTLINE);
+}
+
+void
+hb_subset_input_set_no_prune_unicode_ranges (hb_subset_input_t *subset_input,
+ hb_bool_t no_prune_unicode_ranges)
+{
+ return set_flag_value (subset_input,
+ HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES,
+ no_prune_unicode_ranges);
+}
+
+
+hb_bool_t
+hb_subset_input_get_no_prune_unicode_ranges (hb_subset_input_t *subset_input)
+{
+ return (bool) (hb_subset_input_get_flags (subset_input) & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.hh
index 0aeb96695b..99ce5284cb 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.hh
@@ -34,6 +34,8 @@
#include "hb-font.hh"
+HB_MARK_AS_FLAG_T (hb_subset_flags_t);
+
struct hb_subset_input_t
{
hb_object_header_t header;
@@ -42,12 +44,12 @@ struct hb_subset_input_t
hb_set_t *glyphs;
hb_set_t *name_ids;
hb_set_t *name_languages;
+ hb_set_t *no_subset_tables;
hb_set_t *drop_tables;
+ hb_set_t *layout_features;
+
+ unsigned flags;
- bool drop_hints;
- bool desubroutinize;
- bool retain_gids;
- bool name_legacy;
/* TODO
*
* features
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc
index d055783a4d..aab78c5f0f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc
@@ -35,10 +35,12 @@
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-cff1-table.hh"
#include "hb-ot-color-colr-table.hh"
+#include "hb-ot-color-colrv1-closure.hh"
#include "hb-ot-var-fvar-table.hh"
#include "hb-ot-stat-table.hh"
+typedef hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> script_langsys_map;
#ifndef HB_NO_SUBSET_CFF
static inline void
_add_cff_seac_components (const OT::cff1::accelerator_t &cff,
@@ -54,7 +56,23 @@ _add_cff_seac_components (const OT::cff1::accelerator_t &cff,
}
#endif
-#ifndef HB_NO_SUBSET_LAYOUT
+static void
+_remap_palette_indexes (const hb_set_t *palette_indexes,
+ hb_map_t *mapping /* OUT */)
+{
+ unsigned new_idx = 0;
+ for (unsigned palette_index : palette_indexes->iter ())
+ {
+ if (palette_index == 0xFFFF)
+ {
+ mapping->set (palette_index, palette_index);
+ continue;
+ }
+ mapping->set (palette_index, new_idx);
+ new_idx++;
+ }
+}
+
static void
_remap_indexes (const hb_set_t *indexes,
hb_map_t *mapping /* OUT */)
@@ -66,73 +84,97 @@ _remap_indexes (const hb_set_t *indexes,
}
-static inline void
-_gsub_closure_glyphs_lookups_features (hb_face_t *face,
- hb_set_t *gids_to_retain,
- hb_map_t *gsub_lookups,
- hb_map_t *gsub_features)
+#ifndef HB_NO_SUBSET_LAYOUT
+typedef void (*layout_collect_func_t) (hb_face_t *face, hb_tag_t table_tag, const hb_tag_t *scripts, const hb_tag_t *languages, const hb_tag_t *features, hb_set_t *lookup_indexes /* OUT */);
+
+static void _collect_subset_layout (hb_face_t *face,
+ hb_tag_t table_tag,
+ const hb_set_t *layout_features_to_retain,
+ bool retain_all_features,
+ layout_collect_func_t layout_collect_func,
+ hb_set_t *lookup_indices /* OUT */)
{
- hb_set_t lookup_indices;
- hb_ot_layout_collect_lookups (face,
- HB_OT_TAG_GSUB,
- nullptr,
- nullptr,
- nullptr,
- &lookup_indices);
- hb_ot_layout_lookups_substitute_closure (face,
- &lookup_indices,
- gids_to_retain);
- hb_blob_ptr_t<OT::GSUB> gsub = hb_sanitize_context_t ().reference_table<OT::GSUB> (face);
- gsub->closure_lookups (face,
- gids_to_retain,
- &lookup_indices);
- _remap_indexes (&lookup_indices, gsub_lookups);
+ if (retain_all_features)
+ {
+ layout_collect_func (face,
+ table_tag,
+ nullptr,
+ nullptr,
+ nullptr,
+ lookup_indices);
+ return;
+ }
- // Collect and prune features
- hb_set_t feature_indices;
- hb_ot_layout_collect_features (face,
- HB_OT_TAG_GSUB,
- nullptr,
- nullptr,
- nullptr,
- &feature_indices);
- gsub->prune_features (gsub_lookups, &feature_indices);
- _remap_indexes (&feature_indices, gsub_features);
-
- gsub.destroy ();
+ if (hb_set_is_empty (layout_features_to_retain)) return;
+ unsigned num = layout_features_to_retain->get_population () + 1;
+ hb_tag_t *features = (hb_tag_t *) hb_malloc (num * sizeof (hb_tag_t));
+ if (!features) return;
+
+ unsigned i = 0;
+ for (hb_tag_t f : layout_features_to_retain->iter ())
+ features[i++] = f;
+
+ features[i] = 0;
+
+ layout_collect_func (face,
+ table_tag,
+ nullptr,
+ nullptr,
+ features,
+ lookup_indices);
+
+ hb_free (features);
}
+template <typename T>
static inline void
-_gpos_closure_lookups_features (hb_face_t *face,
- const hb_set_t *gids_to_retain,
- hb_map_t *gpos_lookups,
- hb_map_t *gpos_features)
+_closure_glyphs_lookups_features (hb_face_t *face,
+ hb_set_t *gids_to_retain,
+ const hb_set_t *layout_features_to_retain,
+ bool retain_all_features,
+ hb_map_t *lookups,
+ hb_map_t *features,
+ script_langsys_map *langsys_map)
{
+ hb_blob_ptr_t<T> table = hb_sanitize_context_t ().reference_table<T> (face);
+ hb_tag_t table_tag = table->tableTag;
hb_set_t lookup_indices;
- hb_ot_layout_collect_lookups (face,
- HB_OT_TAG_GPOS,
- nullptr,
- nullptr,
- nullptr,
- &lookup_indices);
- hb_blob_ptr_t<OT::GPOS> gpos = hb_sanitize_context_t ().reference_table<OT::GPOS> (face);
- gpos->closure_lookups (face,
- gids_to_retain,
+ _collect_subset_layout (face,
+ table_tag,
+ layout_features_to_retain,
+ retain_all_features,
+ hb_ot_layout_collect_lookups,
+ &lookup_indices);
+
+ if (table_tag == HB_OT_TAG_GSUB)
+ hb_ot_layout_lookups_substitute_closure (face,
+ &lookup_indices,
+ gids_to_retain);
+ table->closure_lookups (face,
+ gids_to_retain,
&lookup_indices);
- _remap_indexes (&lookup_indices, gpos_lookups);
+ _remap_indexes (&lookup_indices, lookups);
// Collect and prune features
hb_set_t feature_indices;
- hb_ot_layout_collect_features (face,
- HB_OT_TAG_GPOS,
- nullptr,
- nullptr,
- nullptr,
- &feature_indices);
- gpos->prune_features (gpos_lookups, &feature_indices);
- _remap_indexes (&feature_indices, gpos_features);
- gpos.destroy ();
+ _collect_subset_layout (face,
+ table_tag,
+ layout_features_to_retain,
+ retain_all_features,
+ hb_ot_layout_collect_features,
+ &feature_indices);
+
+ table->prune_features (lookups, &feature_indices);
+ hb_map_t duplicate_feature_map;
+ table->find_duplicate_features (lookups, &feature_indices, &duplicate_feature_map);
+
+ feature_indices.clear ();
+ table->prune_langsys (&duplicate_feature_map, langsys_map, &feature_indices);
+ _remap_indexes (&feature_indices, features);
+
+ table.destroy ();
}
+
#endif
#ifndef HB_NO_VAR
@@ -166,9 +208,9 @@ static inline void
#endif
static inline void
-_cmap_closure (hb_face_t *face,
- const hb_set_t *unicodes,
- hb_set_t *glyphset)
+_cmap_closure (hb_face_t *face,
+ const hb_set_t *unicodes,
+ hb_set_t *glyphset)
{
OT::cmap::accelerator_t cmap;
cmap.init (face);
@@ -189,6 +231,45 @@ _remove_invalid_gids (hb_set_t *glyphs,
}
static void
+_populate_unicodes_to_retain (const hb_set_t *unicodes,
+ const hb_set_t *glyphs,
+ hb_subset_plan_t *plan)
+{
+ OT::cmap::accelerator_t cmap;
+ cmap.init (plan->source);
+
+ for (hb_codepoint_t cp : *unicodes)
+ {
+ hb_codepoint_t gid;
+ if (!cmap.get_nominal_glyph (cp, &gid))
+ {
+ DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
+ continue;
+ }
+ plan->unicodes->add (cp);
+ plan->codepoint_to_glyph->set (cp, gid);
+ plan->_glyphset_gsub->add (gid);
+ }
+
+ if (glyphs->is_empty ())
+ {
+ cmap.fini ();
+ return;
+ }
+
+ hb_map_t unicode_glyphid_map;
+ cmap.collect_mapping (hb_set_get_empty (), &unicode_glyphid_map);
+ cmap.fini ();
+
+ for (hb_pair_t<hb_codepoint_t, hb_codepoint_t> cp_gid :
+ + unicode_glyphid_map.iter () | hb_filter (glyphs, hb_second))
+ {
+ plan->unicodes->add (cp_gid.first);
+ plan->codepoint_to_glyph->set (cp_gid.first, cp_gid.second);
+ }
+}
+
+static void
_populate_gids_to_retain (hb_subset_plan_t* plan,
const hb_set_t *unicodes,
const hb_set_t *input_glyphs_to_retain,
@@ -196,13 +277,11 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
bool close_over_gpos,
bool close_over_gdef)
{
- OT::cmap::accelerator_t cmap;
OT::glyf::accelerator_t glyf;
#ifndef HB_NO_SUBSET_CFF
OT::cff1::accelerator_t cff;
#endif
OT::COLR::accelerator_t colr;
- cmap.init (plan->source);
glyf.init (plan->source);
#ifndef HB_NO_SUBSET_CFF
cff.init (plan->source);
@@ -212,71 +291,89 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
plan->_glyphset_gsub->add (0); // Not-def
hb_set_union (plan->_glyphset_gsub, input_glyphs_to_retain);
- hb_codepoint_t cp = HB_SET_VALUE_INVALID;
- while (unicodes->next (&cp))
- {
- hb_codepoint_t gid;
- if (!cmap.get_nominal_glyph (cp, &gid))
- {
- DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
- continue;
- }
- plan->unicodes->add (cp);
- plan->codepoint_to_glyph->set (cp, gid);
- plan->_glyphset_gsub->add (gid);
- }
-
_cmap_closure (plan->source, plan->unicodes, plan->_glyphset_gsub);
#ifndef HB_NO_SUBSET_LAYOUT
if (close_over_gsub)
// closure all glyphs/lookups/features needed for GSUB substitutions.
- _gsub_closure_glyphs_lookups_features (plan->source, plan->_glyphset_gsub, plan->gsub_lookups, plan->gsub_features);
+ _closure_glyphs_lookups_features<OT::GSUB> (
+ plan->source,
+ plan->_glyphset_gsub,
+ plan->layout_features,
+ plan->flags & HB_SUBSET_FLAGS_RETAIN_ALL_FEATURES,
+ plan->gsub_lookups,
+ plan->gsub_features,
+ plan->gsub_langsys);
if (close_over_gpos)
- _gpos_closure_lookups_features (plan->source, plan->_glyphset_gsub, plan->gpos_lookups, plan->gpos_features);
+ _closure_glyphs_lookups_features<OT::GPOS> (
+ plan->source,
+ plan->_glyphset_gsub,
+ plan->layout_features,
+ plan->flags & HB_SUBSET_FLAGS_RETAIN_ALL_FEATURES,
+ plan->gpos_lookups,
+ plan->gpos_features,
+ plan->gpos_langsys);
#endif
_remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ());
+ // Collect all glyphs referenced by COLRv0
+ hb_set_t* cur_glyphset = plan->_glyphset_gsub;
+ hb_set_t glyphset_colrv0;
+ if (colr.is_valid ())
+ {
+ glyphset_colrv0.union_ (*cur_glyphset);
+ for (hb_codepoint_t gid : cur_glyphset->iter ())
+ colr.closure_glyphs (gid, &glyphset_colrv0);
+ cur_glyphset = &glyphset_colrv0;
+ }
+
+ hb_set_t palette_indices;
+ colr.closure_V0palette_indices (cur_glyphset, &palette_indices);
+
+ hb_set_t layer_indices;
+ colr.closure_forV1 (cur_glyphset, &layer_indices, &palette_indices);
+ _remap_indexes (&layer_indices, plan->colrv1_layers);
+ _remap_palette_indexes (&palette_indices, plan->colr_palettes);
+ colr.fini ();
+ _remove_invalid_gids (cur_glyphset, plan->source->get_num_glyphs ());
+
// Populate a full set of glyphs to retain by adding all referenced
// composite glyphs.
- hb_codepoint_t gid = HB_SET_VALUE_INVALID;
- while (plan->_glyphset_gsub->next (&gid))
+ for (hb_codepoint_t gid : cur_glyphset->iter ())
{
glyf.add_gid_and_children (gid, plan->_glyphset);
#ifndef HB_NO_SUBSET_CFF
if (cff.is_valid ())
_add_cff_seac_components (cff, gid, plan->_glyphset);
#endif
- if (colr.is_valid ())
- colr.closure_glyphs (gid, plan->_glyphset);
}
_remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ());
+
#ifndef HB_NO_VAR
if (close_over_gdef)
_collect_layout_variation_indices (plan->source,
- plan->_glyphset_gsub,
- plan->gpos_lookups,
- plan->layout_variation_indices,
- plan->layout_variation_idx_map);
+ plan->_glyphset_gsub,
+ plan->gpos_lookups,
+ plan->layout_variation_indices,
+ plan->layout_variation_idx_map);
#endif
#ifndef HB_NO_SUBSET_CFF
cff.fini ();
#endif
glyf.fini ();
- cmap.fini ();
}
static void
_create_old_gid_to_new_gid_map (const hb_face_t *face,
- bool retain_gids,
- const hb_set_t *all_gids_to_retain,
- hb_map_t *glyph_map, /* OUT */
- hb_map_t *reverse_glyph_map, /* OUT */
- unsigned int *num_glyphs /* OUT */)
+ bool retain_gids,
+ const hb_set_t *all_gids_to_retain,
+ hb_map_t *glyph_map, /* OUT */
+ hb_map_t *reverse_glyph_map, /* OUT */
+ unsigned int *num_glyphs /* OUT */)
{
if (!retain_gids)
{
@@ -319,33 +416,36 @@ _nameid_closure (hb_face_t *face,
/**
* hb_subset_plan_create:
+ * @face: font face to create the plan for.
+ * @input: a #hb_subset_input_t input.
+ *
* Computes a plan for subsetting the supplied face according
* to a provided input. The plan describes
* which tables and glyphs should be retained.
*
- * Return value: New subset plan.
+ * Return value: (transfer full): New subset plan. Destroy with
+ * hb_subset_plan_destroy().
*
* Since: 1.7.5
**/
hb_subset_plan_t *
-hb_subset_plan_create (hb_face_t *face,
- hb_subset_input_t *input)
+hb_subset_plan_create (hb_face_t *face,
+ const hb_subset_input_t *input)
{
hb_subset_plan_t *plan;
if (unlikely (!(plan = hb_object_create<hb_subset_plan_t> ())))
return const_cast<hb_subset_plan_t *> (&Null (hb_subset_plan_t));
plan->successful = true;
- plan->drop_hints = input->drop_hints;
- plan->desubroutinize = input->desubroutinize;
- plan->retain_gids = input->retain_gids;
- plan->name_legacy = input->name_legacy;
+ plan->flags = input->flags;
plan->unicodes = hb_set_create ();
- plan->name_ids = hb_set_reference (input->name_ids);
+ plan->name_ids = hb_set_copy (input->name_ids);
_nameid_closure (face, plan->name_ids);
- plan->name_languages = hb_set_reference (input->name_languages);
- plan->glyphs_requested = hb_set_reference (input->glyphs);
- plan->drop_tables = hb_set_reference (input->drop_tables);
+ plan->name_languages = hb_set_copy (input->name_languages);
+ plan->layout_features = hb_set_copy (input->layout_features);
+ plan->glyphs_requested = hb_set_copy (input->glyphs);
+ plan->drop_tables = hb_set_copy (input->drop_tables);
+ plan->no_subset_tables = hb_set_copy (input->no_subset_tables);
plan->source = hb_face_reference (face);
plan->dest = hb_face_builder_create ();
@@ -356,11 +456,25 @@ hb_subset_plan_create (hb_face_t *face,
plan->reverse_glyph_map = hb_map_create ();
plan->gsub_lookups = hb_map_create ();
plan->gpos_lookups = hb_map_create ();
+
+ if (plan->check_success (plan->gsub_langsys = hb_object_create<script_langsys_map> ()))
+ plan->gsub_langsys->init_shallow ();
+ if (plan->check_success (plan->gpos_langsys = hb_object_create<script_langsys_map> ()))
+ plan->gpos_langsys->init_shallow ();
+
plan->gsub_features = hb_map_create ();
plan->gpos_features = hb_map_create ();
+ plan->colrv1_layers = hb_map_create ();
+ plan->colr_palettes = hb_map_create ();
plan->layout_variation_indices = hb_set_create ();
plan->layout_variation_idx_map = hb_map_create ();
+ if (plan->in_error ()) {
+ return plan;
+ }
+
+ _populate_unicodes_to_retain (input->unicodes, input->glyphs, plan);
+
_populate_gids_to_retain (plan,
input->unicodes,
input->glyphs,
@@ -369,7 +483,7 @@ hb_subset_plan_create (hb_face_t *face,
!input->drop_tables->has (HB_OT_TAG_GDEF));
_create_old_gid_to_new_gid_map (face,
- input->retain_gids,
+ input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,
plan->_glyphset,
plan->glyph_map,
plan->reverse_glyph_map,
@@ -380,6 +494,10 @@ hb_subset_plan_create (hb_face_t *face,
/**
* hb_subset_plan_destroy:
+ * @plan: a #hb_subset_plan_t
+ *
+ * Decreases the reference count on @plan, and if it reaches zero, destroys
+ * @plan, freeing all memory.
*
* Since: 1.7.5
**/
@@ -391,8 +509,10 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
hb_set_destroy (plan->unicodes);
hb_set_destroy (plan->name_ids);
hb_set_destroy (plan->name_languages);
+ hb_set_destroy (plan->layout_features);
hb_set_destroy (plan->glyphs_requested);
hb_set_destroy (plan->drop_tables);
+ hb_set_destroy (plan->no_subset_tables);
hb_face_destroy (plan->source);
hb_face_destroy (plan->dest);
hb_map_destroy (plan->codepoint_to_glyph);
@@ -404,9 +524,30 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
hb_map_destroy (plan->gpos_lookups);
hb_map_destroy (plan->gsub_features);
hb_map_destroy (plan->gpos_features);
+ hb_map_destroy (plan->colrv1_layers);
+ hb_map_destroy (plan->colr_palettes);
hb_set_destroy (plan->layout_variation_indices);
hb_map_destroy (plan->layout_variation_idx_map);
+ if (plan->gsub_langsys)
+ {
+ for (auto _ : plan->gsub_langsys->iter ())
+ hb_set_destroy (_.second);
+
+ hb_object_destroy (plan->gsub_langsys);
+ plan->gsub_langsys->fini_shallow ();
+ hb_free (plan->gsub_langsys);
+ }
+
+ if (plan->gpos_langsys)
+ {
+ for (auto _ : plan->gpos_langsys->iter ())
+ hb_set_destroy (_.second);
+
+ hb_object_destroy (plan->gpos_langsys);
+ plan->gpos_langsys->fini_shallow ();
+ hb_free (plan->gpos_langsys);
+ }
- free (plan);
+ hb_free (plan);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh
index cc9cb7a1a2..92a4e27ccc 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh
@@ -39,11 +39,8 @@ struct hb_subset_plan_t
{
hb_object_header_t header;
- bool successful : 1;
- bool drop_hints : 1;
- bool desubroutinize : 1;
- bool retain_gids : 1;
- bool name_legacy : 1;
+ bool successful;
+ unsigned flags;
// For each cp that we'd like to retain maps to the corresponding gid.
hb_set_t *unicodes;
@@ -54,9 +51,15 @@ struct hb_subset_plan_t
// name_languages we would like to retain
hb_set_t *name_languages;
+ //layout features which will be preserved
+ hb_set_t *layout_features;
+
//glyph ids requested to retain
hb_set_t *glyphs_requested;
+ // Tables which should not be processed, just pass them through.
+ hb_set_t *no_subset_tables;
+
// Tables which should be dropped.
hb_set_t *drop_tables;
@@ -79,10 +82,18 @@ struct hb_subset_plan_t
hb_map_t *gsub_lookups;
hb_map_t *gpos_lookups;
- //active features we'd like to retain
+ //active langsys we'd like to retain
+ hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *gsub_langsys;
+ hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *gpos_langsys;
+
+ //active features after removing redundant langsys and prune_features
hb_map_t *gsub_features;
hb_map_t *gpos_features;
+ //active layers/palettes we'd like to retain
+ hb_map_t *colrv1_layers;
+ hb_map_t *colr_palettes;
+
//The set of layout item variation store delta set indices to be retained
hb_set_t *layout_variation_indices;
//Old -> New layout item variation store delta set index mapping
@@ -189,7 +200,7 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
HB_INTERNAL hb_subset_plan_t *
hb_subset_plan_create (hb_face_t *face,
- hb_subset_input_t *input);
+ const hb_subset_input_t *input);
HB_INTERNAL void
hb_subset_plan_destroy (hb_subset_plan_t *plan);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset.cc
index 8b77ecd45a..9c4d64413f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset.cc
@@ -39,8 +39,10 @@
#include "hb-ot-maxp-table.hh"
#include "hb-ot-color-sbix-table.hh"
#include "hb-ot-color-colr-table.hh"
+#include "hb-ot-color-cpal-table.hh"
#include "hb-ot-os2-table.hh"
#include "hb-ot-post-table.hh"
+#include "hb-ot-post-table-v2subset.hh"
#include "hb-ot-cff1-table.hh"
#include "hb-ot-cff2-table.hh"
#include "hb-ot-vorg-table.hh"
@@ -50,7 +52,28 @@
#include "hb-ot-layout-gpos-table.hh"
#include "hb-ot-var-gvar-table.hh"
#include "hb-ot-var-hvar-table.hh"
+#include "hb-repacker.hh"
+/**
+ * SECTION:hb-subset
+ * @title: hb-subset
+ * @short_description: Subsets font files.
+ * @include: hb-subset.h
+ *
+ * Subsetting reduces the codepoint coverage of font files and removes all data
+ * that is no longer needed. A subset input describes the desired subset. The input is
+ * provided along with a font to the subsetting operation. Output is a new font file
+ * containing only the data specified in the input.
+ *
+ * Currently most outline and bitmap tables are supported: glyf, CFF, CFF2, sbix,
+ * COLR, and CBDT/CBLC. This also includes fonts with variable outlines via OpenType
+ * variations. Notably EBDT/EBLC and SVG are not supported. Layout subsetting is supported
+ * only for OpenType Layout tables (GSUB, GPOS, GDEF). Notably subsetting of graphite or AAT tables
+ * is not yet supported.
+ *
+ * Fonts with graphite or AAT tables may still be subsetted but will likely need to use the
+ * retain glyph ids option and configure the subset to pass through the layout tables untouched.
+ */
static unsigned
_plan_estimate_subset_table_size (hb_subset_plan_t *plan, unsigned table_len)
@@ -64,69 +87,133 @@ _plan_estimate_subset_table_size (hb_subset_plan_t *plan, unsigned table_len)
return 512 + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
}
+/*
+ * Repack the serialization buffer if any offset overflows exist.
+ */
+static hb_blob_t*
+_repack (hb_tag_t tag, const hb_serialize_context_t& c)
+{
+ if (tag != HB_OT_TAG_GPOS
+ && tag != HB_OT_TAG_GSUB)
+ {
+ // Check for overflow in a non-handled table.
+ return c.successful () ? c.copy_blob () : nullptr;
+ }
+
+ if (!c.offset_overflow ())
+ return c.copy_blob ();
+
+ hb_vector_t<char> buf;
+ int buf_size = c.end - c.start;
+ if (unlikely (!buf.alloc (buf_size)))
+ return nullptr;
+
+ hb_serialize_context_t repacked ((void *) buf, buf_size);
+ hb_resolve_overflows (c.object_graph (), &repacked);
+
+ if (unlikely (repacked.in_error ()))
+ // TODO(garretrieger): refactor so we can share the resize/retry logic with the subset
+ // portion.
+ return nullptr;
+
+ return repacked.copy_blob ();
+}
+
+template<typename TableType>
+static
+bool
+_try_subset (const TableType *table,
+ hb_vector_t<char>* buf,
+ unsigned buf_size,
+ hb_subset_context_t* c /* OUT */)
+{
+ c->serializer->start_serialize<TableType> ();
+ if (c->serializer->in_error ()) return false;
+
+ bool needed = table->subset (c);
+ if (!c->serializer->ran_out_of_room ())
+ {
+ c->serializer->end_serialize ();
+ return needed;
+ }
+
+ buf_size += (buf_size >> 1) + 32;
+ DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.",
+ HB_UNTAG (c->table_tag), buf_size);
+
+ if (unlikely (!buf->alloc (buf_size)))
+ {
+ DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.",
+ HB_UNTAG (c->table_tag), buf_size);
+ return needed;
+ }
+
+ c->serializer->reset (buf->arrayZ, buf_size);
+ return _try_subset (table, buf, buf_size, c);
+}
+
template<typename TableType>
static bool
_subset (hb_subset_plan_t *plan)
{
- bool result = false;
hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source);
const TableType *table = source_blob->as<TableType> ();
hb_tag_t tag = TableType::tableTag;
- if (source_blob->data)
+ if (!source_blob->data)
+ {
+ DEBUG_MSG (SUBSET, nullptr,
+ "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag));
+ hb_blob_destroy (source_blob);
+ return false;
+ }
+
+ hb_vector_t<char> buf;
+ /* TODO Not all tables are glyph-related. 'name' table size for example should not be
+ * affected by number of glyphs. Accommodate that. */
+ unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length);
+ DEBUG_MSG (SUBSET, nullptr,
+ "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size);
+ if (unlikely (!buf.alloc (buf_size)))
+ {
+ DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size);
+ hb_blob_destroy (source_blob);
+ return false;
+ }
+
+ bool needed = false;
+ hb_serialize_context_t serializer (buf.arrayZ, buf_size);
{
- hb_vector_t<char> buf;
- /* TODO Not all tables are glyph-related. 'name' table size for example should not be
- * affected by number of glyphs. Accommodate that. */
- unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length);
- DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size);
- if (unlikely (!buf.alloc (buf_size)))
- {
- DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size);
- hb_blob_destroy (source_blob);
- return false;
- }
- retry:
- hb_serialize_context_t serializer ((void *) buf, buf_size);
- serializer.start_serialize<TableType> ();
hb_subset_context_t c (source_blob, plan, &serializer, tag);
- bool needed = table->subset (&c);
- if (serializer.ran_out_of_room)
- {
- buf_size += (buf_size >> 1) + 32;
- DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (tag), buf_size);
- if (unlikely (!buf.alloc (buf_size)))
- {
- DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", HB_UNTAG (tag), buf_size);
- hb_blob_destroy (source_blob);
- return false;
- }
- goto retry;
- }
- serializer.end_serialize ();
+ needed = _try_subset (table, &buf, buf_size, &c);
+ }
+ hb_blob_destroy (source_blob);
- result = !serializer.in_error ();
+ if (serializer.in_error () && !serializer.only_offset_overflow ())
+ {
+ DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset FAILED!", HB_UNTAG (tag));
+ return false;
+ }
- if (result)
- {
- if (needed)
- {
- hb_blob_t *dest_blob = serializer.copy_blob ();
- DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length);
- result = c.plan->add_table (tag, dest_blob);
- hb_blob_destroy (dest_blob);
- }
- else
- {
- DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag));
- }
- }
+ if (!needed)
+ {
+ DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag));
+ return true;
}
- else
- DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag));
- hb_blob_destroy (source_blob);
- DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!");
+ bool result = false;
+ hb_blob_t *dest_blob = _repack (tag, serializer);
+ if (dest_blob)
+ {
+ DEBUG_MSG (SUBSET, nullptr,
+ "OT::%c%c%c%c final subset table size: %u bytes.",
+ HB_UNTAG (tag), dest_blob->length);
+ result = plan->add_table (tag, dest_blob);
+ hb_blob_destroy (dest_blob);
+ }
+
+ DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s",
+ HB_UNTAG (tag), result ? "success" : "FAILED!");
return result;
}
@@ -159,7 +246,7 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
case HB_TAG ('p','r','e','p'): /* hint table, fallthrough */
case HB_TAG ('h','d','m','x'): /* hint table, fallthrough */
case HB_TAG ('V','D','M','X'): /* hint table, fallthrough */
- return plan->drop_hints;
+ return plan->flags & HB_SUBSET_FLAGS_NO_HINTING;
#ifdef HB_NO_SUBSET_LAYOUT
// Drop Layout Tables if requested.
@@ -179,8 +266,21 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
}
static bool
+_passthrough (hb_subset_plan_t *plan, hb_tag_t tag)
+{
+ hb_blob_t *source_table = hb_face_reference_table (plan->source, tag);
+ bool result = plan->add_table (tag, source_table);
+ hb_blob_destroy (source_table);
+ return result;
+}
+
+static bool
_subset_table (hb_subset_plan_t *plan, hb_tag_t tag)
{
+ if (plan->no_subset_tables->has (tag)) {
+ return _passthrough (plan, tag);
+ }
+
DEBUG_MSG (SUBSET, nullptr, "subset %c%c%c%c", HB_UNTAG (tag));
switch (tag)
{
@@ -202,6 +302,7 @@ _subset_table (hb_subset_plan_t *plan, hb_tag_t tag)
case HB_OT_TAG_OS2 : return _subset<const OT::OS2 > (plan);
case HB_OT_TAG_post: return _subset<const OT::post> (plan);
case HB_OT_TAG_COLR: return _subset<const OT::COLR> (plan);
+ case HB_OT_TAG_CPAL: return _subset<const OT::CPAL> (plan);
case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan);
case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */
@@ -221,28 +322,42 @@ _subset_table (hb_subset_plan_t *plan, hb_tag_t tag)
#endif
default:
- hb_blob_t *source_table = hb_face_reference_table (plan->source, tag);
- bool result = plan->add_table (tag, source_table);
- hb_blob_destroy (source_table);
- return result;
+ if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED)
+ return _passthrough (plan, tag);
+
+ // Drop table
+ return true;
}
}
+hb_face_t *
+hb_subset (hb_face_t *source, hb_subset_input_t *input)
+{
+ hb_face_t* face = hb_subset_or_fail (source, input);
+ if (face) return face;
+ return hb_face_get_empty ();
+}
+
/**
- * hb_subset:
+ * hb_subset_or_fail:
* @source: font face data to be subset.
* @input: input to use for the subsetting.
*
- * Subsets a font according to provided input.
+ * Subsets a font according to provided input. Returns nullptr
+ * if the subset operation fails.
+ *
+ * Since: 2.9.0
**/
hb_face_t *
-hb_subset (hb_face_t *source, hb_subset_input_t *input)
+hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input)
{
if (unlikely (!input || !source)) return hb_face_get_empty ();
hb_subset_plan_t *plan = hb_subset_plan_create (source, input);
- if (unlikely (plan->in_error ()))
- return hb_face_get_empty ();
+ if (unlikely (plan->in_error ())) {
+ hb_subset_plan_destroy (plan);
+ return nullptr;
+ }
hb_set_t tags_set;
bool success = true;
@@ -262,7 +377,7 @@ hb_subset (hb_face_t *source, hb_subset_input_t *input)
}
end:
- hb_face_t *result = success ? hb_face_reference (plan->dest) : hb_face_get_empty ();
+ hb_face_t *result = success ? hb_face_reference (plan->dest) : nullptr;
hb_subset_plan_destroy (plan);
return result;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset.h b/src/3rdparty/harfbuzz-ng/src/hb-subset.h
index ddf4409734..164a6f9360 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset.h
@@ -31,37 +31,122 @@
HB_BEGIN_DECLS
-/*
- * hb_subset_input_t
+/**
+ * hb_subset_input_t:
*
* Things that change based on the input. Characters to keep, etc.
*/
typedef struct hb_subset_input_t hb_subset_input_t;
+/**
+ * hb_subset_flags_t:
+ * @HB_SUBSET_FLAGS_DEFAULT: all flags at their default value of false.
+ * @HB_SUBSET_FLAGS_NO_HINTING: If set hinting instructions will be dropped in
+ * the produced subset. Otherwise hinting instructions will be retained.
+ * @HB_SUBSET_FLAGS_RETAIN_GIDS: If set glyph indices will not be modified in
+ * the produced subset. If glyphs are dropped their indices will be retained
+ * as an empty glyph.
+ * @HB_SUBSET_FLAGS_DESUBROUTINIZE: If set and subsetting a CFF font the
+ * subsetter will attempt to remove subroutines from the CFF glyphs.
+ * @HB_SUBSET_FLAGS_NAME_LEGACY: If set non-unicode name records will be
+ * retained in the subset.
+ * @HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG: If set the subsetter will set the
+ * OVERLAP_SIMPLE flag on each simple glyph.
+ * @HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED: If set the subsetter will not
+ * drop unrecognized tables and instead pass them through untouched.
+ * @HB_SUBSET_FLAGS_NOTDEF_OUTLINE: If set the notdef glyph outline will be
+ * retained in the final subset.
+ * @HB_SUBSET_FLAGS_GLYPH_NAMES: If set the PS glyph names will be retained
+ * in the final subset.
+ * @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in
+ * OS/2 will not be recalculated.
+ * @HB_SUBSET_FLAGS_RETAIN_ALL_FEATURES: If set all layout features will be
+ * retained. If unset then the set accessed by
+ * hb_subset_input_layout_features_set() will be used to determine the features
+ * to be retained.
+ *
+ * List of boolean properties that can be configured on the subset input.
+ *
+ * Since: 2.9.0
+ **/
+typedef enum { /*< flags >*/
+ HB_SUBSET_FLAGS_DEFAULT = 0x00000000u,
+ HB_SUBSET_FLAGS_NO_HINTING = 0x00000001u,
+ HB_SUBSET_FLAGS_RETAIN_GIDS = 0x00000002u,
+ HB_SUBSET_FLAGS_DESUBROUTINIZE = 0x00000004u,
+ HB_SUBSET_FLAGS_NAME_LEGACY = 0x00000008u,
+ HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG = 0x00000010u,
+ HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED = 0x00000020u,
+ HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u,
+ HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u,
+ HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u,
+ HB_SUBSET_FLAGS_RETAIN_ALL_FEATURES = 0x00000200u,
+} hb_subset_flags_t;
+
HB_EXTERN hb_subset_input_t *
hb_subset_input_create_or_fail (void);
HB_EXTERN hb_subset_input_t *
-hb_subset_input_reference (hb_subset_input_t *subset_input);
+hb_subset_input_reference (hb_subset_input_t *input);
HB_EXTERN void
-hb_subset_input_destroy (hb_subset_input_t *subset_input);
+hb_subset_input_destroy (hb_subset_input_t *input);
+
+HB_EXTERN hb_bool_t
+hb_subset_input_set_user_data (hb_subset_input_t *input,
+ hb_user_data_key_t *key,
+ void * data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace);
+
+HB_EXTERN void *
+hb_subset_input_get_user_data (const hb_subset_input_t *input,
+ hb_user_data_key_t *key);
+
+HB_EXTERN hb_set_t *
+hb_subset_input_unicode_set (hb_subset_input_t *input);
HB_EXTERN hb_set_t *
-hb_subset_input_unicode_set (hb_subset_input_t *subset_input);
+hb_subset_input_glyph_set (hb_subset_input_t *input);
HB_EXTERN hb_set_t *
-hb_subset_input_glyph_set (hb_subset_input_t *subset_input);
+hb_subset_input_nameid_set (hb_subset_input_t *input);
HB_EXTERN hb_set_t *
-hb_subset_input_nameid_set (hb_subset_input_t *subset_input);
+hb_subset_input_namelangid_set (hb_subset_input_t *input);
HB_EXTERN hb_set_t *
-hb_subset_input_namelangid_set (hb_subset_input_t *subset_input);
+hb_subset_input_layout_features_set (hb_subset_input_t *input);
HB_EXTERN hb_set_t *
-hb_subset_input_drop_tables_set (hb_subset_input_t *subset_input);
+hb_subset_input_no_subset_tables_set (hb_subset_input_t *input);
+
+HB_EXTERN hb_set_t *
+hb_subset_input_drop_tables_set (hb_subset_input_t *input);
+
+HB_EXTERN hb_subset_flags_t
+hb_subset_input_get_flags (hb_subset_input_t *input);
+
+HB_EXTERN void
+hb_subset_input_set_flags (hb_subset_input_t *input,
+ unsigned value);
+
+HB_EXTERN hb_face_t *
+hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input);
+
+
+/*
+ * ### Legacy API ###
+ * The methods below are part of the legacy harfbuzz subsetting API and will be
+ * Removed as of version 3.0.0
+ */
+
+HB_EXTERN void
+hb_subset_input_set_retain_all_features (hb_subset_input_t *subset_input,
+ hb_bool_t value);
+HB_EXTERN hb_bool_t
+hb_subset_input_get_retain_all_features (hb_subset_input_t *subset_input);
HB_EXTERN void
hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
@@ -87,11 +172,30 @@ hb_subset_input_set_name_legacy (hb_subset_input_t *subset_input,
HB_EXTERN hb_bool_t
hb_subset_input_get_name_legacy (hb_subset_input_t *subset_input);
-/* hb_subset () */
+HB_EXTERN void
+hb_subset_input_set_overlaps_flag (hb_subset_input_t *subset_input,
+ hb_bool_t overlaps_flag);
+
+HB_EXTERN hb_bool_t
+hb_subset_input_get_overlaps_flag (hb_subset_input_t *subset_input);
+
+HB_EXTERN void
+hb_subset_input_set_notdef_outline (hb_subset_input_t *subset_input,
+ hb_bool_t notdef_outline);
+
+HB_EXTERN hb_bool_t
+hb_subset_input_get_notdef_outline (hb_subset_input_t *subset_input);
+
+HB_EXTERN void
+hb_subset_input_set_no_prune_unicode_ranges (hb_subset_input_t *subset_input,
+ hb_bool_t no_prune_unicode_ranges);
+
+HB_EXTERN hb_bool_t
+hb_subset_input_get_no_prune_unicode_ranges (hb_subset_input_t *subset_input);
+
HB_EXTERN hb_face_t *
hb_subset (hb_face_t *source, hb_subset_input_t *input);
-
HB_END_DECLS
#endif /* HB_SUBSET_H */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-unicode-emoji-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-unicode-emoji-table.hh
index eb7776eecb..41878697c9 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-unicode-emoji-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-unicode-emoji-table.hh
@@ -24,36 +24,42 @@
#include "hb-unicode.hh"
static const uint8_t
-_hb_emoji_u8[448] =
+_hb_emoji_u8[544] =
{
- 0, 0, 0, 0, 33, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 16, 17, 17, 17, 50, 20, 21, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,118,152,
+ 0, 0, 1, 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, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84,118,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 3,
- 0, 0, 0, 0, 0, 0, 4, 5, 6, 7, 8, 7, 9, 10, 11, 0,
- 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0,
- 7, 7, 7, 14, 15, 16, 17, 18, 19, 20, 7, 7, 7, 7, 7, 21,
- 7, 7, 7, 7, 22, 23, 7, 7, 7, 24, 7, 14, 0, 25, 0, 26,
- 27, 28, 29, 14, 30, 31, 7, 7, 7, 7, 7, 14, 0, 0, 0, 0,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 22,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,240, 1, 0, 2, 0, 0,
- 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,254, 7, 3,
- 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,
- 159,255,243,255,255,255,255,255,255,255,255,255,255,255,255,255,
- 31, 0,255,255,255,255,255,255, 31,255, 3, 0, 0, 0, 8, 0,
- 0, 0, 24, 0,120, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 16, 0, 96, 0, 0, 8, 0, 0, 0, 0,
- 255,255,255,255,255,255,255,127, 0, 96, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,240, 1, 64, 0, 0,254, 3, 0,224,255,255,
- 255,255,255,255, 31, 0, 0, 0,254,127, 0, 0, 0, 0,252,115,
- 0,254,255,255,255,255,255,255,255,255,255,255,255,255,255, 3,
- 255,255,255,255,255,255,255, 31,192,255,255,255,255,255,255,255,
- 255,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,240,127,
- 0, 0,224,255,255,255,255,127, 0,112, 0, 0, 0, 0, 0, 0,
- 0,127, 0,124, 0, 0, 0, 0, 0,127, 0, 0, 0,192,255,255,
- 0,240,255,255,255,255,255,243,159,255,255,255,255,255,255,255,
+ 2, 3, 0, 0, 4, 0, 5, 0, 0, 0, 0, 0, 6, 0, 7, 8,
+ 0, 0, 0, 9, 0, 0, 10, 11, 12, 13, 14, 13, 15, 16, 17, 0,
+ 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 19, 20, 0, 0,
+ 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0,
+ 13, 13, 13, 13, 23, 24, 25, 26, 27, 28, 13, 13, 13, 13, 13, 29,
+ 13, 13, 13, 13, 30, 31, 13, 13, 13, 32, 13, 13, 0, 33, 0, 34,
+ 35, 36, 37, 13, 38, 39, 13, 13, 13, 13, 13, 13, 0, 0, 0, 0,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 30,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 16, 0, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 4, 0, 0, 2, 0, 0,240, 3, 0, 6, 0, 0,
+ 0, 0, 0, 12, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0,128, 0, 0, 0,254, 15, 7, 4, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 12, 64, 0, 1, 0, 0, 0, 0, 0, 0,120,
+ 191,255,247,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 63, 0,255,255,255,255,255,255, 63,255, 87, 32, 2, 1, 24, 0,
+ 144, 80,184, 0,248, 0, 0, 0, 0, 0,224, 0, 2, 0, 1,128,
+ 0, 0, 0, 0, 0, 0, 48, 0,224, 0, 0, 24, 0, 0, 0, 0,
+ 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32,
+ 0, 0,128, 2, 0, 0, 0, 0, 0,224, 0, 0, 0,128, 0, 0,
+ 0, 0, 0, 0, 0,240, 3,192, 0, 64,254, 7, 0,224,255,255,
+ 255,255,255,255, 63, 0, 0, 0,254,255, 0, 4, 0,128,252,247,
+ 0,254,255,255,255,255,255,255,255,255,255,255,255,255,255, 7,
+ 255,255,255,255,255,255,255, 63,192,255,255,255,255,255,255,255,
+ 255,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,240,255,
+ 0, 0,224,255,255,255,255,255, 0,240, 0, 0, 0, 0, 0, 0,
+ 0,255, 0,252, 0, 0, 0, 0, 0,255, 0, 0, 0,192,255,255,
+ 0,240,255,255,255,255,255,247,191,255,255,255,255,255,255,255,
};
static inline unsigned
@@ -69,7 +75,7 @@ _hb_emoji_b1 (const uint8_t* a, unsigned i)
static inline uint_fast8_t
_hb_emoji_is_Extended_Pictographic (unsigned u)
{
- return u<131069u?_hb_emoji_b1(192+_hb_emoji_u8,((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>6>>4))<<4)+((u>>6)&15u))])<<6)+((u)&63u)):0;
+ return u<131070u?_hb_emoji_b1(224+_hb_emoji_u8,((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>6>>4))<<4)+((u>>6)&15u))])<<6)+((u)&63u)):0;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-unicode.cc b/src/3rdparty/harfbuzz-ng/src/hb-unicode.cc
index 7470bb1b6e..83ead6398b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-unicode.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-unicode.cc
@@ -268,7 +268,7 @@ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
hb_unicode_funcs_destroy (ufuncs->parent);
- free (ufuncs);
+ hb_free (ufuncs);
}
/**
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-unicode.hh b/src/3rdparty/harfbuzz-ng/src/hb-unicode.hh
index 34d66d7aa3..0a79944107 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-unicode.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-unicode.hh
@@ -289,8 +289,8 @@ DECLARE_NULL_INSTANCE (hb_unicode_funcs_t);
#define HB_MODIFIED_COMBINING_CLASS_CCC15 18 /* tsere */
#define HB_MODIFIED_COMBINING_CLASS_CCC16 19 /* segol */
#define HB_MODIFIED_COMBINING_CLASS_CCC17 20 /* patah */
-#define HB_MODIFIED_COMBINING_CLASS_CCC18 21 /* qamats */
-#define HB_MODIFIED_COMBINING_CLASS_CCC19 14 /* holam */
+#define HB_MODIFIED_COMBINING_CLASS_CCC18 21 /* qamats & qamats qatan */
+#define HB_MODIFIED_COMBINING_CLASS_CCC19 14 /* holam & holam haser for vav*/
#define HB_MODIFIED_COMBINING_CLASS_CCC20 24 /* qubuts */
#define HB_MODIFIED_COMBINING_CLASS_CCC21 12 /* dagesh */
#define HB_MODIFIED_COMBINING_CLASS_CCC22 25 /* meteg */
@@ -359,6 +359,13 @@ DECLARE_NULL_INSTANCE (hb_unicode_funcs_t);
FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
+#define HB_UNICODE_GENERAL_CATEGORY_IS_LETTER(gen_cat) \
+ (FLAG_UNSAFE (gen_cat) & \
+ (FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER)))
/*
* Ranges, used for bsearch tables.
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc b/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc
index 48a5dc50ad..2e14211cdf 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc
@@ -44,6 +44,7 @@
#include "hb-uniscribe.h"
+#include "hb-ms-feature-ranges.hh"
#include "hb-open-file.hh"
#include "hb-ot-name-table.hh"
#include "hb-ot-layout.h"
@@ -247,7 +248,7 @@ static struct hb_uniscribe_shaper_funcs_lazy_loader_t : hb_lazy_loader_t<hb_unis
{
static hb_uniscribe_shaper_funcs_t *create ()
{
- hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
+ hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) hb_calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
if (unlikely (!funcs))
return nullptr;
@@ -261,7 +262,7 @@ static struct hb_uniscribe_shaper_funcs_lazy_loader_t : hb_lazy_loader_t<hb_unis
}
static void destroy (hb_uniscribe_shaper_funcs_t *p)
{
- free ((void *) p);
+ hb_free ((void *) p);
}
static hb_uniscribe_shaper_funcs_t *get_null ()
{
@@ -284,44 +285,6 @@ hb_uniscribe_shaper_get_funcs ()
}
-struct active_feature_t {
- OPENTYPE_FEATURE_RECORD rec;
- unsigned int order;
-
- HB_INTERNAL static int cmp (const void *pa, const void *pb) {
- const active_feature_t *a = (const active_feature_t *) pa;
- const active_feature_t *b = (const active_feature_t *) pb;
- return a->rec.tagFeature < b->rec.tagFeature ? -1 : a->rec.tagFeature > b->rec.tagFeature ? 1 :
- a->order < b->order ? -1 : a->order > b->order ? 1 :
- a->rec.lParameter < b->rec.lParameter ? -1 : a->rec.lParameter > b->rec.lParameter ? 1 :
- 0;
- }
- bool operator== (const active_feature_t *f)
- { return cmp (this, f) == 0; }
-};
-
-struct feature_event_t {
- unsigned int index;
- bool start;
- active_feature_t feature;
-
- HB_INTERNAL static int cmp (const void *pa, const void *pb)
- {
- const feature_event_t *a = (const feature_event_t *) pa;
- const feature_event_t *b = (const feature_event_t *) pb;
- return a->index < b->index ? -1 : a->index > b->index ? 1 :
- a->start < b->start ? -1 : a->start > b->start ? 1 :
- active_feature_t::cmp (&a->feature, &b->feature);
- }
-};
-
-struct range_record_t {
- TEXTRANGE_PROPERTIES props;
- unsigned int index_first; /* == start */
- unsigned int index_last; /* == end - 1 */
-};
-
-
/*
* shaper face data
*/
@@ -391,7 +354,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
unsigned int name_table_offset = (length + 3) & ~3;
new_length = name_table_offset + padded_name_table_length;
- void *new_sfnt_data = calloc (1, new_length);
+ void *new_sfnt_data = hb_calloc (1, new_length);
if (!new_sfnt_data)
{
hb_blob_destroy (blob);
@@ -441,7 +404,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
}
else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
{
- free (new_sfnt_data);
+ hb_free (new_sfnt_data);
hb_blob_destroy (blob);
return nullptr;
}
@@ -453,20 +416,20 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
hb_blob_destroy (blob);
return hb_blob_create ((const char *) new_sfnt_data, new_length,
- HB_MEMORY_MODE_WRITABLE, new_sfnt_data, free);
+ HB_MEMORY_MODE_WRITABLE, new_sfnt_data, hb_free);
}
hb_uniscribe_face_data_t *
_hb_uniscribe_shaper_face_data_create (hb_face_t *face)
{
- hb_uniscribe_face_data_t *data = (hb_uniscribe_face_data_t *) calloc (1, sizeof (hb_uniscribe_face_data_t));
+ hb_uniscribe_face_data_t *data = (hb_uniscribe_face_data_t *) hb_calloc (1, sizeof (hb_uniscribe_face_data_t));
if (unlikely (!data))
return nullptr;
data->funcs = hb_uniscribe_shaper_get_funcs ();
if (unlikely (!data->funcs))
{
- free (data);
+ hb_free (data);
return nullptr;
}
@@ -477,7 +440,7 @@ _hb_uniscribe_shaper_face_data_create (hb_face_t *face)
blob = _hb_rename_font (blob, data->face_name);
if (unlikely (!blob))
{
- free (data);
+ hb_free (data);
return nullptr;
}
@@ -488,7 +451,7 @@ _hb_uniscribe_shaper_face_data_create (hb_face_t *face)
if (unlikely (!data->fh))
{
DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
- free (data);
+ hb_free (data);
return nullptr;
}
@@ -499,7 +462,7 @@ void
_hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_face_data_t *data)
{
RemoveFontMemResourceEx (data->fh);
- free (data);
+ hb_free (data);
}
@@ -533,7 +496,7 @@ populate_log_font (LOGFONTW *lf,
hb_uniscribe_font_data_t *
_hb_uniscribe_shaper_font_data_create (hb_font_t *font)
{
- hb_uniscribe_font_data_t *data = (hb_uniscribe_font_data_t *) calloc (1, sizeof (hb_uniscribe_font_data_t));
+ hb_uniscribe_font_data_t *data = (hb_uniscribe_font_data_t *) hb_calloc (1, sizeof (hb_uniscribe_font_data_t));
if (unlikely (!data))
return nullptr;
@@ -580,7 +543,7 @@ _hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_font_data_t *data)
DeleteObject (data->hfont);
if (data->script_cache)
ScriptFreeCache (&data->script_cache);
- free (data);
+ hb_free (data);
}
/**
@@ -635,109 +598,6 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan,
const hb_uniscribe_font_data_t *font_data = font->data.uniscribe;
hb_uniscribe_shaper_funcs_t *funcs = face_data->funcs;
- /*
- * Set up features.
- */
- hb_vector_t<OPENTYPE_FEATURE_RECORD> feature_records;
- hb_vector_t<range_record_t> range_records;
- if (num_features)
- {
- /* Sort features by start/end events. */
- hb_vector_t<feature_event_t> feature_events;
- for (unsigned int i = 0; i < num_features; i++)
- {
- active_feature_t feature;
- feature.rec.tagFeature = hb_uint32_swap (features[i].tag);
- feature.rec.lParameter = features[i].value;
- feature.order = i;
-
- 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. */
- {
- active_feature_t feature;
- feature.rec.tagFeature = 0;
- feature.rec.lParameter = 0;
- feature.order = num_features + 1;
-
- feature_event_t *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<active_feature_t> active_features;
- unsigned int last_index = 0;
- for (unsigned int i = 0; i < feature_events.length; i++)
- {
- feature_event_t *event = &feature_events[i];
-
- if (event->index != last_index)
- {
- /* Save a snapshot of active features and the range. */
- range_record_t *range = range_records.push ();
-
- unsigned int offset = feature_records.length;
-
- active_features.qsort ();
- for (unsigned int j = 0; j < active_features.length; j++)
- {
- if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.length - 1].tagFeature)
- {
- feature_records.push (active_features[j].rec);
- }
- else
- {
- /* Overrides value for existing feature. */
- feature_records[feature_records.length - 1].lParameter = active_features[j].rec.lParameter;
- }
- }
-
- /* Will convert to pointer after all is ready, since feature_records.array
- * may move as we grow it. */
- range->props.potfRecords = reinterpret_cast<OPENTYPE_FEATURE_RECORD *> (offset);
- range->props.cotfRecords = 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
- {
- active_feature_t *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++)
- {
- range_record_t *range = &range_records[i];
- range->props.potfRecords = (OPENTYPE_FEATURE_RECORD *) feature_records + reinterpret_cast<uintptr_t> (range->props.potfRecords);
- }
- }
-
#define FAIL(...) \
HB_STMT_START { \
DEBUG_MSG (UNISCRIBE, nullptr, __VA_ARGS__); \
@@ -856,8 +716,23 @@ retry:
nullptr, nullptr,
&lang_count, &lang_tag);
OPENTYPE_TAG language_tag = hb_uint32_swap (lang_count ? lang_tag : HB_TAG_NONE);
- hb_vector_t<TEXTRANGE_PROPERTIES*> range_properties;
- hb_vector_t<int> range_char_counts;
+
+ /*
+ * Set up features.
+ */
+ static_assert ((sizeof (TEXTRANGE_PROPERTIES) == sizeof (hb_ms_features_t)), "");
+ static_assert ((sizeof (OPENTYPE_FEATURE_RECORD) == sizeof (hb_ms_feature_t)), "");
+ hb_vector_t<hb_ms_feature_t> feature_records;
+ hb_vector_t<hb_ms_range_record_t> range_records;
+ bool has_features = false;
+ if (num_features)
+ has_features = hb_ms_setup_features (features,
+ num_features,
+ feature_records,
+ range_records);
+
+ hb_vector_t<hb_ms_features_t*> range_properties;
+ hb_vector_t<uint32_t> range_char_counts;
unsigned int glyphs_offset = 0;
unsigned int glyphs_len;
@@ -867,42 +742,14 @@ retry:
unsigned int chars_offset = items[i].iCharPos;
unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset;
- if (num_features)
- {
- range_properties.shrink (0);
- range_char_counts.shrink (0);
-
- range_record_t *last_range = &range_records[0];
-
- for (unsigned int k = chars_offset; k < chars_offset + item_chars_len; k++)
- {
- range_record_t *range = last_range;
- while (log_clusters[k] < range->index_first)
- range--;
- while (log_clusters[k] > range->index_last)
- range++;
- if (!range_properties.length ||
- &range->props != range_properties[range_properties.length - 1])
- {
- TEXTRANGE_PROPERTIES **props = range_properties.push ();
- int *c = range_char_counts.push ();
- if (unlikely (!props || !c))
- {
- range_properties.shrink (0);
- range_char_counts.shrink (0);
- break;
- }
- *props = &range->props;
- *c = 1;
- }
- else
- {
- range_char_counts[range_char_counts.length - 1]++;
- }
-
- last_range = range;
- }
- }
+ if (has_features)
+ hb_ms_make_feature_ranges (feature_records,
+ range_records,
+ item_chars_len,
+ chars_offset,
+ log_clusters,
+ range_properties,
+ range_char_counts);
/* Asking for glyphs in logical order circumvents at least
* one bug in Uniscribe. */
@@ -914,8 +761,8 @@ retry:
&items[i].a,
script_tags[i],
language_tag,
- range_char_counts.arrayZ,
- range_properties.arrayZ,
+ (int *) range_char_counts.arrayZ,
+ (TEXTRANGE_PROPERTIES**) range_properties.arrayZ,
range_properties.length,
pchars + chars_offset,
item_chars_len,
@@ -955,8 +802,8 @@ retry:
&items[i].a,
script_tags[i],
language_tag,
- range_char_counts.arrayZ,
- range_properties.arrayZ,
+ (int *) range_char_counts.arrayZ,
+ (TEXTRANGE_PROPERTIES**) range_properties.arrayZ,
range_properties.length,
pchars + chars_offset,
log_clusters + chars_offset,
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-vector.hh b/src/3rdparty/harfbuzz-ng/src/hb-vector.hh
index 13517a9c29..110d457caf 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-vector.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-vector.hh
@@ -69,7 +69,7 @@ struct hb_vector_t
void fini ()
{
- free (arrayZ);
+ hb_free (arrayZ);
init ();
}
void fini_deep ()
@@ -177,6 +177,11 @@ struct hb_vector_t
Type *push (T&& v)
{
Type *p = push ();
+ if (p == &Crap (Type))
+ // If push failed to allocate then don't copy v, since this may cause
+ // the created copy to leak memory since we won't have stored a
+ // reference to it.
+ return p;
*p = hb_forward<T> (v);
return p;
}
@@ -204,7 +209,7 @@ struct hb_vector_t
(new_allocated < (unsigned) allocated) ||
hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
if (likely (!overflows))
- new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
+ new_array = (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type));
if (unlikely (!new_array))
{
@@ -310,7 +315,7 @@ struct hb_sorted_vector_t : hb_vector_t<Type>
{ 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); }
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-version.h b/src/3rdparty/harfbuzz-ng/src/hb-version.h
index 6db58c3f7c..94bd707931 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-version.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-version.h
@@ -47,7 +47,7 @@ HB_BEGIN_DECLS
*
* The minor component of the library version available at compile-time.
*/
-#define HB_VERSION_MINOR 8
+#define HB_VERSION_MINOR 9
/**
* HB_VERSION_MICRO:
*
@@ -60,7 +60,7 @@ HB_BEGIN_DECLS
*
* A string literal containing the library version available at compile-time.
*/
-#define HB_VERSION_STRING "2.8.0"
+#define HB_VERSION_STRING "2.9.0"
/**
* HB_VERSION_ATLEAST:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb.hh b/src/3rdparty/harfbuzz-ng/src/hb.hh
index 18516581c7..052cabed9f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb.hh
@@ -117,6 +117,9 @@
#pragma GCC diagnostic ignored "-Wshadow" // TODO fix
#pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations" // TODO fix
#pragma GCC diagnostic ignored "-Wunused-parameter" // TODO fix
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic ignored "-Wunused-result" // TODO fix
+#endif
#endif
/* Ignored intentionally. */
@@ -220,10 +223,15 @@ extern "C" void* hb_malloc_impl(size_t size);
extern "C" void* hb_calloc_impl(size_t nmemb, size_t size);
extern "C" void* hb_realloc_impl(void *ptr, size_t size);
extern "C" void hb_free_impl(void *ptr);
-#define malloc hb_malloc_impl
-#define calloc hb_calloc_impl
-#define realloc hb_realloc_impl
-#define free hb_free_impl
+#define hb_malloc hb_malloc_impl
+#define hb_calloc hb_calloc_impl
+#define hb_realloc hb_realloc_impl
+#define hb_free hb_free_impl
+#else
+#define hb_malloc malloc
+#define hb_calloc calloc
+#define hb_realloc realloc
+#define hb_free free
#endif
@@ -335,7 +343,6 @@ extern "C" void hb_free_impl(void *ptr);
#else
# define HB_NODISCARD
#endif
-#define hb_success_t HB_NODISCARD bool
/* https://github.com/harfbuzz/harfbuzz/issues/1852 */
#if defined(__clang__) && !(defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__)))
@@ -376,7 +383,7 @@ extern "C" void hb_free_impl(void *ptr);
# define HB_NO_SETLOCALE
# define HB_NO_ERRNO
# endif
-# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+# elif !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
# ifndef HB_NO_GETENV
# define HB_NO_GETENV
# endif
diff --git a/src/3rdparty/harfbuzz-ng/src/main.cc b/src/3rdparty/harfbuzz-ng/src/main.cc
index e898e6e4b6..1ab013cd3a 100644
--- a/src/3rdparty/harfbuzz-ng/src/main.cc
+++ b/src/3rdparty/harfbuzz-ng/src/main.cc
@@ -33,12 +33,13 @@
#include "hb.h"
#include "hb-ot.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include <cassert>
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
#ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x) hb_blob_get_empty ()
+#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif
#if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW) && defined(HB_EXPERIMENTAL_API)
@@ -505,7 +506,8 @@ main (int argc, char **argv)
exit (1);
}
- hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+ hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+ assert (blob);
printf ("Opened font file %s: %d bytes long\n", argv[1], hb_blob_get_length (blob));
#ifndef MAIN_CC_NO_PRIVATE_API
print_layout_info_using_private_api (blob);
diff --git a/src/3rdparty/harfbuzz-ng/src/test-buffer-serialize.cc b/src/3rdparty/harfbuzz-ng/src/test-buffer-serialize.cc
index 4a3d4bc107..8d5a694275 100644
--- a/src/3rdparty/harfbuzz-ng/src/test-buffer-serialize.cc
+++ b/src/3rdparty/harfbuzz-ng/src/test-buffer-serialize.cc
@@ -33,7 +33,7 @@
#endif
#ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x) hb_blob_get_empty ()
+#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif
int
@@ -48,7 +48,8 @@ main (int argc, char **argv)
exit (1);
}
- hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+ hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+ assert (blob);
hb_face_t *face = hb_face_create (blob, 0 /* first face */);
hb_blob_destroy (blob);
blob = nullptr;
diff --git a/src/3rdparty/harfbuzz-ng/src/test-gpos-size-params.cc b/src/3rdparty/harfbuzz-ng/src/test-gpos-size-params.cc
index 549f5ae06a..b96381ddcb 100644
--- a/src/3rdparty/harfbuzz-ng/src/test-gpos-size-params.cc
+++ b/src/3rdparty/harfbuzz-ng/src/test-gpos-size-params.cc
@@ -30,7 +30,7 @@
#include "hb-ot.h"
#ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x) hb_blob_get_empty ()
+#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif
int
@@ -42,7 +42,8 @@ main (int argc, char **argv)
}
/* Create the face */
- hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+ hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+ assert (blob);
hb_face_t *face = hb_face_create (blob, 0 /* first face */);
hb_blob_destroy (blob);
blob = nullptr;
diff --git a/src/3rdparty/harfbuzz-ng/src/test-gsub-would-substitute.cc b/src/3rdparty/harfbuzz-ng/src/test-gsub-would-substitute.cc
index 508217dde9..87123030ed 100644
--- a/src/3rdparty/harfbuzz-ng/src/test-gsub-would-substitute.cc
+++ b/src/3rdparty/harfbuzz-ng/src/test-gsub-would-substitute.cc
@@ -34,7 +34,7 @@
#endif
#ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x) hb_blob_get_empty ()
+#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif
int
@@ -46,7 +46,8 @@ main (int argc, char **argv)
}
/* Create the face */
- hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+ hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+ assert (blob);
hb_face_t *face = hb_face_create (blob, 0 /* first face */);
hb_blob_destroy (blob);
blob = nullptr;
diff --git a/src/3rdparty/harfbuzz-ng/src/test-ot-glyphname.cc b/src/3rdparty/harfbuzz-ng/src/test-ot-glyphname.cc
index b2d4b3bcf0..50d023166f 100644
--- a/src/3rdparty/harfbuzz-ng/src/test-ot-glyphname.cc
+++ b/src/3rdparty/harfbuzz-ng/src/test-ot-glyphname.cc
@@ -28,7 +28,7 @@
#include "hb-ot.h"
#ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x) hb_blob_get_empty ()
+#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif
int
@@ -39,7 +39,8 @@ main (int argc, char **argv)
exit (1);
}
- hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+ hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+ assert (blob);
hb_face_t *face = hb_face_create (blob, 0 /* first face */);
hb_font_t *font = hb_font_create (face);
hb_blob_destroy (blob);
diff --git a/src/3rdparty/harfbuzz-ng/src/test-ot-meta.cc b/src/3rdparty/harfbuzz-ng/src/test-ot-meta.cc
index f7a755cd59..7cf69dbcc3 100644
--- a/src/3rdparty/harfbuzz-ng/src/test-ot-meta.cc
+++ b/src/3rdparty/harfbuzz-ng/src/test-ot-meta.cc
@@ -26,7 +26,7 @@
#include "hb-ot.h"
#ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x) hb_blob_get_empty ()
+#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif
int
@@ -37,7 +37,8 @@ main (int argc, char **argv)
exit (1);
}
- hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+ hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+ assert (blob);
hb_face_t *face = hb_face_create (blob, 0 /* first face */);
hb_blob_destroy (blob);
blob = nullptr;
diff --git a/src/3rdparty/harfbuzz-ng/src/test-ot-name.cc b/src/3rdparty/harfbuzz-ng/src/test-ot-name.cc
index f331161fa4..bfa654a7c1 100644
--- a/src/3rdparty/harfbuzz-ng/src/test-ot-name.cc
+++ b/src/3rdparty/harfbuzz-ng/src/test-ot-name.cc
@@ -28,7 +28,7 @@
#include "hb-ot.h"
#ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x) hb_blob_get_empty ()
+#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif
int
@@ -39,7 +39,8 @@ main (int argc, char **argv)
exit (1);
}
- hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+ hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+ assert (blob);
hb_face_t *face = hb_face_create (blob, 0 /* first face */);
hb_blob_destroy (blob);
blob = nullptr;
diff --git a/src/3rdparty/harfbuzz-ng/src/test-priority-queue.cc b/src/3rdparty/harfbuzz-ng/src/test-priority-queue.cc
new file mode 100644
index 0000000000..fab63acb63
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/test-priority-queue.cc
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "hb.hh"
+#include "hb-priority-queue.hh"
+
+static void
+test_insert ()
+{
+ hb_priority_queue_t queue;
+ assert (queue.is_empty ());
+
+ queue.insert (10, 0);
+ assert (!queue.is_empty ());
+ assert (queue.minimum () == hb_pair (10, 0));
+
+ queue.insert (20, 1);
+ assert (queue.minimum () == hb_pair (10, 0));
+
+ queue.insert (5, 2);
+ assert (queue.minimum () == hb_pair (5, 2));
+
+ queue.insert (15, 3);
+ assert (queue.minimum () == hb_pair (5, 2));
+
+ queue.insert (1, 4);
+ assert (queue.minimum () == hb_pair (1, 4));
+}
+
+static void
+test_extract ()
+{
+ hb_priority_queue_t queue;
+ queue.insert (0, 0);
+ queue.insert (60, 6);
+ queue.insert (30, 3);
+ queue.insert (40 ,4);
+ queue.insert (20, 2);
+ queue.insert (50, 5);
+ queue.insert (70, 7);
+ queue.insert (10, 1);
+
+ for (int i = 0; i < 8; i++)
+ {
+ assert (!queue.is_empty ());
+ assert (queue.minimum () == hb_pair (i * 10, i));
+ assert (queue.pop_minimum () == hb_pair (i * 10, i));
+ }
+
+ assert (queue.is_empty ());
+}
+
+static void
+test_extract_empty ()
+{
+ hb_priority_queue_t queue;
+ assert (queue.pop_minimum () == hb_pair (0, 0));
+}
+
+int
+main (int argc, char **argv)
+{
+ test_insert ();
+ test_extract ();
+ test_extract_empty ();
+}
diff --git a/src/3rdparty/harfbuzz-ng/src/test-repacker.cc b/src/3rdparty/harfbuzz-ng/src/test-repacker.cc
new file mode 100644
index 0000000000..6f46b04287
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/test-repacker.cc
@@ -0,0 +1,485 @@
+/*
+ * 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.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include <string>
+
+#include "hb-repacker.hh"
+#include "hb-open-type.hh"
+
+static void start_object(const char* tag,
+ unsigned len,
+ hb_serialize_context_t* c)
+{
+ c->push ();
+ char* obj = c->allocate_size<char> (len);
+ strncpy (obj, tag, len);
+}
+
+
+static unsigned add_object(const char* tag,
+ unsigned len,
+ hb_serialize_context_t* c)
+{
+ start_object (tag, len, c);
+ return c->pop_pack (false);
+}
+
+
+static void add_offset (unsigned id,
+ hb_serialize_context_t* c)
+{
+ OT::Offset16* offset = c->start_embed<OT::Offset16> ();
+ c->extend_min (offset);
+ c->add_link (*offset, id);
+}
+
+static void
+populate_serializer_simple (hb_serialize_context_t* c)
+{
+ c->start_serialize<char> ();
+
+ unsigned obj_1 = add_object ("ghi", 3, c);
+ unsigned obj_2 = add_object ("def", 3, c);
+
+ start_object ("abc", 3, c);
+ add_offset (obj_2, c);
+ add_offset (obj_1, c);
+ c->pop_pack ();
+
+ c->end_serialize();
+}
+
+static void
+populate_serializer_with_overflow (hb_serialize_context_t* c)
+{
+ std::string large_string(50000, 'a');
+ c->start_serialize<char> ();
+
+ unsigned obj_1 = add_object (large_string.c_str(), 10000, c);
+ unsigned obj_2 = add_object (large_string.c_str(), 20000, c);
+ unsigned obj_3 = add_object (large_string.c_str(), 50000, c);
+
+ start_object ("abc", 3, c);
+ add_offset (obj_3, c);
+ add_offset (obj_2, c);
+ add_offset (obj_1, c);
+ c->pop_pack ();
+
+ c->end_serialize();
+}
+
+static void
+populate_serializer_with_dedup_overflow (hb_serialize_context_t* c)
+{
+ std::string large_string(70000, 'a');
+ c->start_serialize<char> ();
+
+ unsigned obj_1 = add_object ("def", 3, c);
+
+ start_object (large_string.c_str(), 60000, c);
+ add_offset (obj_1, c);
+ unsigned obj_2 = c->pop_pack (false);
+
+ start_object (large_string.c_str(), 10000, c);
+ add_offset (obj_2, c);
+ add_offset (obj_1, c);
+ c->pop_pack (false);
+
+ c->end_serialize();
+}
+
+static void
+populate_serializer_complex_1 (hb_serialize_context_t* c)
+{
+ c->start_serialize<char> ();
+
+ unsigned obj_4 = add_object ("jkl", 3, c);
+ unsigned obj_3 = add_object ("ghi", 3, c);
+
+ start_object ("def", 3, c);
+ add_offset (obj_3, c);
+ unsigned obj_2 = c->pop_pack (false);
+
+ start_object ("abc", 3, c);
+ add_offset (obj_2, c);
+ add_offset (obj_4, c);
+ c->pop_pack ();
+
+ c->end_serialize();
+}
+
+static void
+populate_serializer_complex_2 (hb_serialize_context_t* c)
+{
+ c->start_serialize<char> ();
+
+ unsigned obj_5 = add_object ("mn", 2, c);
+
+ unsigned obj_4 = add_object ("jkl", 3, c);
+
+ start_object ("ghi", 3, c);
+ add_offset (obj_4, c);
+ unsigned obj_3 = c->pop_pack (false);
+
+ start_object ("def", 3, c);
+ add_offset (obj_3, c);
+ unsigned obj_2 = c->pop_pack (false);
+
+ start_object ("abc", 3, c);
+ add_offset (obj_2, c);
+ add_offset (obj_4, c);
+ add_offset (obj_5, c);
+ c->pop_pack ();
+
+ c->end_serialize();
+}
+
+static void
+populate_serializer_complex_3 (hb_serialize_context_t* c)
+{
+ c->start_serialize<char> ();
+
+ unsigned obj_6 = add_object ("opqrst", 6, c);
+
+ unsigned obj_5 = add_object ("mn", 2, c);
+
+ start_object ("jkl", 3, c);
+ add_offset (obj_6, c);
+ unsigned obj_4 = c->pop_pack (false);
+
+ start_object ("ghi", 3, c);
+ add_offset (obj_4, c);
+ unsigned obj_3 = c->pop_pack (false);
+
+ start_object ("def", 3, c);
+ add_offset (obj_3, c);
+ unsigned obj_2 = c->pop_pack (false);
+
+ start_object ("abc", 3, c);
+ add_offset (obj_2, c);
+ add_offset (obj_4, c);
+ add_offset (obj_5, c);
+ c->pop_pack ();
+
+ c->end_serialize();
+}
+
+static void test_sort_kahn_1 ()
+{
+ size_t buffer_size = 100;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_complex_1 (&c);
+
+ graph_t graph (c.object_graph ());
+ graph.sort_kahn ();
+
+ assert(strncmp (graph.object (3).head, "abc", 3) == 0);
+ assert(graph.object (3).links.length == 2);
+ assert(graph.object (3).links[0].objidx == 2);
+ assert(graph.object (3).links[1].objidx == 1);
+
+ assert(strncmp (graph.object (2).head, "def", 3) == 0);
+ assert(graph.object (2).links.length == 1);
+ assert(graph.object (2).links[0].objidx == 0);
+
+ assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
+ assert(graph.object (1).links.length == 0);
+
+ assert(strncmp (graph.object (0).head, "ghi", 3) == 0);
+ assert(graph.object (0).links.length == 0);
+
+ free (buffer);
+}
+
+static void test_sort_kahn_2 ()
+{
+ size_t buffer_size = 100;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_complex_2 (&c);
+
+ graph_t graph (c.object_graph ());
+ graph.sort_kahn ();
+
+
+ assert(strncmp (graph.object (4).head, "abc", 3) == 0);
+ assert(graph.object (4).links.length == 3);
+ assert(graph.object (4).links[0].objidx == 3);
+ assert(graph.object (4).links[1].objidx == 0);
+ assert(graph.object (4).links[2].objidx == 2);
+
+ assert(strncmp (graph.object (3).head, "def", 3) == 0);
+ assert(graph.object (3).links.length == 1);
+ assert(graph.object (3).links[0].objidx == 1);
+
+ assert(strncmp (graph.object (2).head, "mn", 2) == 0);
+ assert(graph.object (2).links.length == 0);
+
+ assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
+ assert(graph.object (1).links.length == 1);
+ assert(graph.object (1).links[0].objidx == 0);
+
+ assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
+ assert(graph.object (0).links.length == 0);
+
+ free (buffer);
+}
+
+static void test_sort_shortest ()
+{
+ size_t buffer_size = 100;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_complex_2 (&c);
+
+ graph_t graph (c.object_graph ());
+ graph.sort_shortest_distance ();
+
+ assert(strncmp (graph.object (4).head, "abc", 3) == 0);
+ assert(graph.object (4).links.length == 3);
+ assert(graph.object (4).links[0].objidx == 2);
+ assert(graph.object (4).links[1].objidx == 0);
+ assert(graph.object (4).links[2].objidx == 3);
+
+ assert(strncmp (graph.object (3).head, "mn", 2) == 0);
+ assert(graph.object (3).links.length == 0);
+
+ assert(strncmp (graph.object (2).head, "def", 3) == 0);
+ assert(graph.object (2).links.length == 1);
+ assert(graph.object (2).links[0].objidx == 1);
+
+ assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
+ assert(graph.object (1).links.length == 1);
+ assert(graph.object (1).links[0].objidx == 0);
+
+ assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
+ assert(graph.object (0).links.length == 0);
+
+ free (buffer);
+}
+
+static void test_duplicate_leaf ()
+{
+ size_t buffer_size = 100;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_complex_2 (&c);
+
+ graph_t graph (c.object_graph ());
+ graph.duplicate (4, 1);
+
+ assert(strncmp (graph.object (5).head, "abc", 3) == 0);
+ assert(graph.object (5).links.length == 3);
+ assert(graph.object (5).links[0].objidx == 3);
+ assert(graph.object (5).links[1].objidx == 4);
+ assert(graph.object (5).links[2].objidx == 0);
+
+ assert(strncmp (graph.object (4).head, "jkl", 3) == 0);
+ assert(graph.object (4).links.length == 0);
+
+ assert(strncmp (graph.object (3).head, "def", 3) == 0);
+ assert(graph.object (3).links.length == 1);
+ assert(graph.object (3).links[0].objidx == 2);
+
+ assert(strncmp (graph.object (2).head, "ghi", 3) == 0);
+ assert(graph.object (2).links.length == 1);
+ assert(graph.object (2).links[0].objidx == 1);
+
+ assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
+ assert(graph.object (1).links.length == 0);
+
+ assert(strncmp (graph.object (0).head, "mn", 2) == 0);
+ assert(graph.object (0).links.length == 0);
+
+ free (buffer);
+}
+
+static void test_duplicate_interior ()
+{
+ size_t buffer_size = 100;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_complex_3 (&c);
+
+ graph_t graph (c.object_graph ());
+ graph.duplicate (3, 2);
+
+ assert(strncmp (graph.object (6).head, "abc", 3) == 0);
+ assert(graph.object (6).links.length == 3);
+ assert(graph.object (6).links[0].objidx == 4);
+ assert(graph.object (6).links[1].objidx == 2);
+ assert(graph.object (6).links[2].objidx == 1);
+
+ assert(strncmp (graph.object (5).head, "jkl", 3) == 0);
+ assert(graph.object (5).links.length == 1);
+ assert(graph.object (5).links[0].objidx == 0);
+
+ assert(strncmp (graph.object (4).head, "def", 3) == 0);
+ assert(graph.object (4).links.length == 1);
+ assert(graph.object (4).links[0].objidx == 3);
+
+ assert(strncmp (graph.object (3).head, "ghi", 3) == 0);
+ assert(graph.object (3).links.length == 1);
+ assert(graph.object (3).links[0].objidx == 5);
+
+ assert(strncmp (graph.object (2).head, "jkl", 3) == 0);
+ assert(graph.object (2).links.length == 1);
+ assert(graph.object (2).links[0].objidx == 0);
+
+ assert(strncmp (graph.object (1).head, "mn", 2) == 0);
+ assert(graph.object (1).links.length == 0);
+
+ assert(strncmp (graph.object (0).head, "opqrst", 6) == 0);
+ assert(graph.object (0).links.length == 0);
+
+ free (buffer);
+}
+
+static void
+test_serialize ()
+{
+ size_t buffer_size = 100;
+ void* buffer_1 = malloc (buffer_size);
+ hb_serialize_context_t c1 (buffer_1, buffer_size);
+ populate_serializer_simple (&c1);
+ hb_bytes_t expected = c1.copy_bytes ();
+
+ void* buffer_2 = malloc (buffer_size);
+ hb_serialize_context_t c2 (buffer_2, buffer_size);
+
+ graph_t graph (c1.object_graph ());
+ graph.serialize (&c2);
+ hb_bytes_t actual = c2.copy_bytes ();
+
+ assert (actual == expected);
+
+ actual.fini ();
+ expected.fini ();
+ free (buffer_1);
+ free (buffer_2);
+}
+
+static void test_will_overflow_1 ()
+{
+ size_t buffer_size = 100;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_complex_2 (&c);
+ graph_t graph (c.object_graph ());
+
+ assert (!graph.will_overflow (nullptr));
+
+ free (buffer);
+}
+
+static void test_will_overflow_2 ()
+{
+ size_t buffer_size = 160000;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_overflow (&c);
+ graph_t graph (c.object_graph ());
+
+ assert (graph.will_overflow (nullptr));
+
+ free (buffer);
+}
+
+static void test_will_overflow_3 ()
+{
+ size_t buffer_size = 160000;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_dedup_overflow (&c);
+ graph_t graph (c.object_graph ());
+
+ assert (graph.will_overflow (nullptr));
+
+ free (buffer);
+}
+
+static void test_resolve_overflows_via_sort ()
+{
+ size_t buffer_size = 160000;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_overflow (&c);
+ graph_t graph (c.object_graph ());
+
+ void* out_buffer = malloc (buffer_size);
+ hb_serialize_context_t out (out_buffer, buffer_size);
+
+ hb_resolve_overflows (c.object_graph (), &out);
+ assert (!out.offset_overflow ());
+ hb_bytes_t result = out.copy_bytes ();
+ assert (result.length == (80000 + 3 + 3 * 2));
+
+ result.fini ();
+ free (buffer);
+ free (out_buffer);
+}
+
+static void test_resolve_overflows_via_duplication ()
+{
+ size_t buffer_size = 160000;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_dedup_overflow (&c);
+ graph_t graph (c.object_graph ());
+
+ void* out_buffer = malloc (buffer_size);
+ hb_serialize_context_t out (out_buffer, buffer_size);
+
+ hb_resolve_overflows (c.object_graph (), &out);
+ assert (!out.offset_overflow ());
+ hb_bytes_t result = out.copy_bytes ();
+ assert (result.length == (10000 + 2 * 2 + 60000 + 2 + 3 * 2));
+
+ result.fini ();
+ free (buffer);
+ free (out_buffer);
+}
+
+// TODO(garretrieger): update will_overflow tests to check the overflows array.
+// TODO(garretrieger): add a test(s) using a real font.
+// TODO(garretrieger): add tests for priority raising.
+
+int
+main (int argc, char **argv)
+{
+ test_serialize ();
+ test_sort_kahn_1 ();
+ test_sort_kahn_2 ();
+ test_sort_shortest ();
+ test_will_overflow_1 ();
+ test_will_overflow_2 ();
+ test_will_overflow_3 ();
+ test_resolve_overflows_via_sort ();
+ test_resolve_overflows_via_duplication ();
+ test_duplicate_leaf ();
+ test_duplicate_interior ();
+}
diff --git a/src/3rdparty/harfbuzz-ng/src/test.cc b/src/3rdparty/harfbuzz-ng/src/test.cc
index 347b71d38b..d848cf1062 100644
--- a/src/3rdparty/harfbuzz-ng/src/test.cc
+++ b/src/3rdparty/harfbuzz-ng/src/test.cc
@@ -31,7 +31,7 @@
#endif
#ifdef HB_NO_OPEN
-#define hb_blob_create_from_file(x) hb_blob_get_empty ()
+#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
#endif
int
@@ -42,7 +42,8 @@ main (int argc, char **argv)
exit (1);
}
- hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+ hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
+ assert (blob);
printf ("Opened font file %s: %u bytes long\n", argv[1], hb_blob_get_length (blob));
/* Create the face */