mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1726416 - Update HarfBuzz to 2.9.1. r=jfkthame
Differential Revision: https://phabricator.services.mozilla.com/D122989
This commit is contained in:
parent
a9b982bfec
commit
b35a31e2b9
@ -11,7 +11,7 @@ Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
|
|||||||
Copyright © 2009 Keith Stribley
|
Copyright © 2009 Keith Stribley
|
||||||
Copyright © 2009 Martin Hosken and SIL International
|
Copyright © 2009 Martin Hosken and SIL International
|
||||||
Copyright © 2007 Chris Wilson
|
Copyright © 2007 Chris Wilson
|
||||||
Copyright © 2006 Behdad Esfahbod
|
Copyright © 2005,2006,2020,2021 Behdad Esfahbod
|
||||||
Copyright © 2005 David Turner
|
Copyright © 2005 David Turner
|
||||||
Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc.
|
Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc.
|
||||||
Copyright © 1998-2004 David Turner and Werner Lemberg
|
Copyright © 1998-2004 David Turner and Werner Lemberg
|
||||||
|
@ -19,13 +19,11 @@ EXTRA_DIST = \
|
|||||||
replace-enum-strings.cmake \
|
replace-enum-strings.cmake \
|
||||||
meson.build \
|
meson.build \
|
||||||
meson_options.txt \
|
meson_options.txt \
|
||||||
subprojects/expat.wrap \
|
subprojects/cairo.wrap \
|
||||||
subprojects/freetype2.wrap \
|
subprojects/freetype2.wrap \
|
||||||
subprojects/glib.wrap \
|
subprojects/glib.wrap \
|
||||||
subprojects/libffi.wrap \
|
|
||||||
subprojects/proxy-libintl.wrap \
|
|
||||||
subprojects/zlib.wrap \
|
|
||||||
subprojects/google-benchmark.wrap \
|
subprojects/google-benchmark.wrap \
|
||||||
|
subprojects/ttf-parser.wrap \
|
||||||
perf/meson.build \
|
perf/meson.build \
|
||||||
perf/perf-draw.hh \
|
perf/perf-draw.hh \
|
||||||
perf/perf-extents.hh \
|
perf/perf-extents.hh \
|
||||||
|
@ -1,3 +1,57 @@
|
|||||||
|
Overview of changes leading to 2.9.1
|
||||||
|
Tuesday, September 7, 2021
|
||||||
|
====================================
|
||||||
|
- Final subset API is in place and if no issues are discovered, it will be the
|
||||||
|
stable subset API of HarfBuzz 3.0.0. Old API is kept to ease transition, but
|
||||||
|
will be removed in 3.0.0.
|
||||||
|
- Various fuzzer-found bug fixes.
|
||||||
|
- hb_buffer_append() now handles the pre- and post-context which previously
|
||||||
|
were left unchanged in the destination buffer.
|
||||||
|
- hb-view / hb-shape now accept following new arguments:
|
||||||
|
o --unicodes: takes a list of hex numbers that represent Unicode
|
||||||
|
codepoints.
|
||||||
|
- Undeprecated API:
|
||||||
|
hb_set_invert()
|
||||||
|
|
||||||
|
|
||||||
|
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
|
Overview of changes leading to 2.8.1
|
||||||
Tuesday, May 4, 2021
|
Tuesday, May 4, 2021
|
||||||
====================================
|
====================================
|
||||||
@ -29,6 +83,7 @@ Sunday, December 27, 2020
|
|||||||
tarball.
|
tarball.
|
||||||
- Documentation updates.
|
- Documentation updates.
|
||||||
|
|
||||||
|
|
||||||
Overview of changes leading to 2.7.3
|
Overview of changes leading to 2.7.3
|
||||||
Wednesday, December 23, 2020
|
Wednesday, December 23, 2020
|
||||||
====================================
|
====================================
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
This directory contains the HarfBuzz source from the upstream repo:
|
This directory contains the HarfBuzz source from the upstream repo:
|
||||||
https://github.com/harfbuzz/harfbuzz
|
https://github.com/harfbuzz/harfbuzz
|
||||||
|
|
||||||
Current version: 2.8.1 [commit b37f03f16b39d397a626f097858e9ae550234ca0]
|
Current version: 2.9.1 [commit 505df5abf8032f3a2295ded417dca9bfb14ea7b8]
|
||||||
|
|
||||||
!!!Please Note!!!
|
!!!Please Note!!!
|
||||||
Because LLVM added in D100581 support for -Wunused-but-set-parameter and -Wunused-but-set-variable
|
Because LLVM added in D100581 support for -Wunused-but-set-parameter and -Wunused-but-set-variable
|
||||||
|
@ -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)
|
[![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)
|
[![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)
|
[![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)
|
[![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)
|
[![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)
|
[![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/)
|
[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
AC_PREREQ([2.64])
|
AC_PREREQ([2.64])
|
||||||
AC_INIT([HarfBuzz],
|
AC_INIT([HarfBuzz],
|
||||||
[2.8.1],
|
[2.9.1],
|
||||||
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
||||||
[harfbuzz],
|
[harfbuzz],
|
||||||
[http://harfbuzz.org/])
|
[http://harfbuzz.org/])
|
||||||
@ -425,11 +425,11 @@ util/Makefile
|
|||||||
test/Makefile
|
test/Makefile
|
||||||
test/api/Makefile
|
test/api/Makefile
|
||||||
test/fuzzing/Makefile
|
test/fuzzing/Makefile
|
||||||
test/shaping/Makefile
|
test/shape/Makefile
|
||||||
test/shaping/data/Makefile
|
test/shape/data/Makefile
|
||||||
test/shaping/data/aots/Makefile
|
test/shape/data/aots/Makefile
|
||||||
test/shaping/data/in-house/Makefile
|
test/shape/data/in-house/Makefile
|
||||||
test/shaping/data/text-rendering-tests/Makefile
|
test/shape/data/text-rendering-tests/Makefile
|
||||||
test/subset/Makefile
|
test/subset/Makefile
|
||||||
test/subset/data/Makefile
|
test/subset/data/Makefile
|
||||||
test/subset/data/repack_tests/Makefile
|
test/subset/data/repack_tests/Makefile
|
||||||
|
@ -410,6 +410,10 @@ TESTS_ENVIRONMENT = \
|
|||||||
MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
|
MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
|
||||||
HBSOURCES="$(HBSOURCES)" \
|
HBSOURCES="$(HBSOURCES)" \
|
||||||
HBHEADERS="$(HBHEADERS)" \
|
HBHEADERS="$(HBHEADERS)" \
|
||||||
|
LDD="$(LDD)" \
|
||||||
|
NM="$(NM)" \
|
||||||
|
OBJDUMP="$(OBJDUMP)" \
|
||||||
|
OTOOL="$(OTOOL)" \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
if HAVE_INTROSPECTION
|
if HAVE_INTROSPECTION
|
||||||
|
@ -19,6 +19,9 @@ HB_BASE_sources = \
|
|||||||
hb-array.hh \
|
hb-array.hh \
|
||||||
hb-atomic.hh \
|
hb-atomic.hh \
|
||||||
hb-bimap.hh \
|
hb-bimap.hh \
|
||||||
|
hb-bit-page.hh \
|
||||||
|
hb-bit-set.hh \
|
||||||
|
hb-bit-set-invertible.hh \
|
||||||
hb-blob.cc \
|
hb-blob.cc \
|
||||||
hb-blob.hh \
|
hb-blob.hh \
|
||||||
hb-buffer-serialize.cc \
|
hb-buffer-serialize.cc \
|
||||||
@ -47,6 +50,8 @@ HB_BASE_sources = \
|
|||||||
hb-map.cc \
|
hb-map.cc \
|
||||||
hb-map.hh \
|
hb-map.hh \
|
||||||
hb-meta.hh \
|
hb-meta.hh \
|
||||||
|
hb-ms-feature-ranges.cc \
|
||||||
|
hb-ms-feature-ranges.hh \
|
||||||
hb-mutex.hh \
|
hb-mutex.hh \
|
||||||
hb-null.hh \
|
hb-null.hh \
|
||||||
hb-number.cc \
|
hb-number.cc \
|
||||||
@ -256,6 +261,8 @@ HB_SUBSET_sources = \
|
|||||||
hb-number.hh \
|
hb-number.hh \
|
||||||
hb-ot-cff1-table.cc \
|
hb-ot-cff1-table.cc \
|
||||||
hb-ot-cff2-table.cc \
|
hb-ot-cff2-table.cc \
|
||||||
|
hb-ot-color-colrv1-closure.hh \
|
||||||
|
hb-ot-post-table-v2subset.hh \
|
||||||
hb-static.cc \
|
hb-static.cc \
|
||||||
hb-subset-cff-common.cc \
|
hb-subset-cff-common.cc \
|
||||||
hb-subset-cff-common.hh \
|
hb-subset-cff-common.hh \
|
||||||
|
@ -6,13 +6,11 @@ os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
|
|||||||
|
|
||||||
libs = os.getenv ('libs', '.libs')
|
libs = os.getenv ('libs', '.libs')
|
||||||
|
|
||||||
ldd = shutil.which ('ldd')
|
ldd = os.getenv ('LDD', shutil.which ('ldd'))
|
||||||
if ldd:
|
if not ldd:
|
||||||
ldd = [ldd]
|
otool = os.getenv ('OTOOL', shutil.which ('otool'))
|
||||||
else:
|
if otool:
|
||||||
ldd = shutil.which ('otool')
|
ldd = otool + ' -L'
|
||||||
if ldd:
|
|
||||||
ldd = [ldd, '-L'] # otool -L
|
|
||||||
else:
|
else:
|
||||||
print ('check-libstdc++.py: \'ldd\' not found; skipping test')
|
print ('check-libstdc++.py: \'ldd\' not found; skipping test')
|
||||||
sys.exit (77)
|
sys.exit (77)
|
||||||
@ -27,7 +25,7 @@ for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-gobject']:
|
|||||||
if not os.path.exists (so): continue
|
if not os.path.exists (so): continue
|
||||||
|
|
||||||
print ('Checking that we are not linking to libstdc++ or libc++ in %s' % so)
|
print ('Checking that we are not linking to libstdc++ or libc++ in %s' % so)
|
||||||
ldd_result = subprocess.check_output (ldd + [so])
|
ldd_result = subprocess.check_output (ldd.split() + [so])
|
||||||
if (b'libstdc++' in ldd_result) or (b'libc++' in ldd_result):
|
if (b'libstdc++' in ldd_result) or (b'libc++' in ldd_result):
|
||||||
print ('Ouch, %s is linked to libstdc++ or libc++' % so)
|
print ('Ouch, %s is linked to libstdc++ or libc++' % so)
|
||||||
stat = 1
|
stat = 1
|
||||||
|
@ -5,7 +5,7 @@ import sys, os, shutil, subprocess, glob, re
|
|||||||
builddir = os.getenv ('builddir', os.path.dirname (__file__))
|
builddir = os.getenv ('builddir', os.path.dirname (__file__))
|
||||||
libs = os.getenv ('libs', '.libs')
|
libs = os.getenv ('libs', '.libs')
|
||||||
|
|
||||||
objdump = shutil.which ('objdump')
|
objdump = os.getenv ('OBJDUMP', shutil.which ('objdump'))
|
||||||
if not objdump:
|
if not objdump:
|
||||||
print ('check-static-inits.py: \'ldd\' not found; skipping test')
|
print ('check-static-inits.py: \'ldd\' not found; skipping test')
|
||||||
sys.exit (77)
|
sys.exit (77)
|
||||||
@ -20,9 +20,20 @@ if not OBJS:
|
|||||||
sys.exit (77)
|
sys.exit (77)
|
||||||
|
|
||||||
stat = 0
|
stat = 0
|
||||||
|
tested = 0
|
||||||
|
|
||||||
for obj in OBJS:
|
for obj in OBJS:
|
||||||
result = subprocess.check_output ([objdump, '-t', obj]).decode ('utf-8')
|
result = subprocess.run(objdump.split () + ['-t', obj], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
|
||||||
|
if result.returncode:
|
||||||
|
if result.stderr.find (b'not recognized') != -1:
|
||||||
|
# https://github.com/harfbuzz/harfbuzz/issues/3019
|
||||||
|
print ('objdump %s returned "not recognized", skipping' % obj)
|
||||||
|
continue
|
||||||
|
print ('objdump %s returned error:\n%s' % (obj, result.stderr.decode ('utf-8')))
|
||||||
|
stat = 2
|
||||||
|
|
||||||
|
result = result.stdout.decode ('utf-8')
|
||||||
|
|
||||||
# Checking that no object file has static initializers
|
# Checking that no object file has static initializers
|
||||||
for l in re.findall (r'^.*\.[cd]tors.*$', result, re.MULTILINE):
|
for l in re.findall (r'^.*\.[cd]tors.*$', result, re.MULTILINE):
|
||||||
@ -35,4 +46,6 @@ for obj in OBJS:
|
|||||||
print ('Ouch, %s has lazy static C++ constructors/destructors or other such stuff' % obj)
|
print ('Ouch, %s has lazy static C++ constructors/destructors or other such stuff' % obj)
|
||||||
stat = 1
|
stat = 1
|
||||||
|
|
||||||
sys.exit (stat)
|
tested += 1
|
||||||
|
|
||||||
|
sys.exit (stat if tested else 77)
|
||||||
|
@ -9,9 +9,10 @@ libs = os.getenv ('libs', '.libs')
|
|||||||
|
|
||||||
IGNORED_SYMBOLS = '|'.join(['_fini', '_init', '_fdata', '_ftext', '_fbss',
|
IGNORED_SYMBOLS = '|'.join(['_fini', '_init', '_fdata', '_ftext', '_fbss',
|
||||||
'__bss_start', '__bss_start__', '__bss_end__', '_edata', '_end', '_bss_end__',
|
'__bss_start', '__bss_start__', '__bss_end__', '_edata', '_end', '_bss_end__',
|
||||||
'__end__', '__gcov_.*', 'llvm_.*', 'flush_fn_list', 'writeout_fn_list', 'mangle_path'])
|
'__end__', '__gcov_.*', 'llvm_.*', 'flush_fn_list', 'writeout_fn_list', 'mangle_path',
|
||||||
|
'lprofDirMode', 'reset_fn_list'])
|
||||||
|
|
||||||
nm = shutil.which ('nm')
|
nm = os.getenv ('NM', shutil.which ('nm'))
|
||||||
if not nm:
|
if not nm:
|
||||||
print ('check-symbols.py: \'nm\' not found; skipping test')
|
print ('check-symbols.py: \'nm\' not found; skipping test')
|
||||||
sys.exit (77)
|
sys.exit (77)
|
||||||
@ -30,7 +31,7 @@ for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject'
|
|||||||
symprefix = '_' if suffix == 'dylib' else ''
|
symprefix = '_' if suffix == 'dylib' else ''
|
||||||
|
|
||||||
EXPORTED_SYMBOLS = [s.split ()[2]
|
EXPORTED_SYMBOLS = [s.split ()[2]
|
||||||
for s in re.findall (r'^.+ [BCDGIRST] .+$', subprocess.check_output ([nm, so]).decode ('utf-8'), re.MULTILINE)
|
for s in re.findall (r'^.+ [BCDGIRST] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE)
|
||||||
if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)]
|
if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)]
|
||||||
|
|
||||||
# run again c++flit also if is available
|
# run again c++flit also if is available
|
||||||
@ -67,7 +68,7 @@ for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject'
|
|||||||
tested = True
|
tested = True
|
||||||
|
|
||||||
if not tested:
|
if not tested:
|
||||||
print ('check-symbols.sh: no shared libraries found; skipping test')
|
print ('check-symbols.py: no shared libraries found; skipping test')
|
||||||
sys.exit (77)
|
sys.exit (77)
|
||||||
|
|
||||||
sys.exit (stat)
|
sys.exit (stat)
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
"""usage: ./gen-emoji-table.py emoji-data.txt
|
"""usage: ./gen-emoji-table.py emoji-data.txt emoji-test.txt
|
||||||
|
|
||||||
Input file:
|
Input file:
|
||||||
* https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt
|
* https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt
|
||||||
|
* https://www.unicode.org/Public/emoji/latest/emoji-test.txt
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import packTab
|
import packTab
|
||||||
|
|
||||||
if len (sys.argv) != 2:
|
if len (sys.argv) != 3:
|
||||||
sys.exit (__doc__)
|
sys.exit (__doc__)
|
||||||
|
|
||||||
f = open(sys.argv[1])
|
f = open(sys.argv[1])
|
||||||
@ -61,7 +62,7 @@ for typ, s in ranges.items():
|
|||||||
|
|
||||||
arr = dict()
|
arr = dict()
|
||||||
for start,end in s:
|
for start,end in s:
|
||||||
for i in range(start,end):
|
for i in range(start, end + 1):
|
||||||
arr[i] = 1
|
arr[i] = 1
|
||||||
|
|
||||||
sol = packTab.pack_table(arr, 0, compression=3)
|
sol = packTab.pack_table(arr, 0, compression=3)
|
||||||
@ -74,3 +75,24 @@ print ()
|
|||||||
print ("#endif /* HB_UNICODE_EMOJI_TABLE_HH */")
|
print ("#endif /* HB_UNICODE_EMOJI_TABLE_HH */")
|
||||||
print ()
|
print ()
|
||||||
print ("/* == End of generated table == */")
|
print ("/* == End of generated table == */")
|
||||||
|
|
||||||
|
|
||||||
|
# Generate test file.
|
||||||
|
sequences = []
|
||||||
|
with open(sys.argv[2]) as f:
|
||||||
|
for line in f.readlines():
|
||||||
|
if "#" in line:
|
||||||
|
line = line[:line.index("#")]
|
||||||
|
if ";" in line:
|
||||||
|
line = line[:line.index(";")]
|
||||||
|
line = line.strip()
|
||||||
|
line = line.split(" ")
|
||||||
|
if len(line) < 2:
|
||||||
|
continue
|
||||||
|
sequences.append(line)
|
||||||
|
|
||||||
|
with open("../test/shaping/data/in-house/tests/emoji-clusters.tests", "w") as f:
|
||||||
|
for sequence in sequences:
|
||||||
|
f.write("../fonts/AdobeBlank2.ttf:--no-glyph-names --no-positions --font-funcs=ot")
|
||||||
|
f.write(":" + ",".join(sequence))
|
||||||
|
f.write(":[" + "|".join("1=0" for c in sequence) + "]\n")
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
import os, os.path, sys, subprocess, shutil
|
import os, os.path, sys, subprocess, shutil
|
||||||
|
|
||||||
ragel = shutil.which ('ragel')
|
ragel = os.getenv ('RAGEL', shutil.which ('ragel'))
|
||||||
if not ragel:
|
if not ragel:
|
||||||
sys.exit ('You have to install ragel if you are going to develop HarfBuzz itself')
|
sys.exit ('You have to install ragel if you are going to develop HarfBuzz itself')
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ outdir = os.path.dirname (OUTPUT)
|
|||||||
shutil.copy (INPUT, outdir)
|
shutil.copy (INPUT, outdir)
|
||||||
rl = os.path.basename (INPUT)
|
rl = os.path.basename (INPUT)
|
||||||
hh = rl.replace ('.rl', '.hh')
|
hh = rl.replace ('.rl', '.hh')
|
||||||
subprocess.Popen ([ragel, '-e', '-F1', '-o', hh, rl], cwd=outdir).wait ()
|
subprocess.Popen (ragel.split() + ['-e', '-F1', '-o', hh, rl], cwd=outdir).wait ()
|
||||||
|
|
||||||
# copy it also to src/
|
# copy it also to src/
|
||||||
shutil.copyfile (os.path.join (outdir, hh), os.path.join (CURRENT_SOURCE_DIR, hh))
|
shutil.copyfile (os.path.join (outdir, hh), os.path.join (CURRENT_SOURCE_DIR, hh))
|
||||||
|
@ -18,7 +18,7 @@ import sys
|
|||||||
if len (sys.argv) != 8:
|
if len (sys.argv) != 8:
|
||||||
sys.exit (__doc__)
|
sys.exit (__doc__)
|
||||||
|
|
||||||
BLACKLISTED_BLOCKS = [
|
DISABLED_BLOCKS = [
|
||||||
'Samaritan',
|
'Samaritan',
|
||||||
'Thai',
|
'Thai',
|
||||||
'Lao',
|
'Lao',
|
||||||
@ -137,7 +137,7 @@ for i,d in enumerate (data):
|
|||||||
if not u in combined:
|
if not u in combined:
|
||||||
combined[u] = list (defaults)
|
combined[u] = list (defaults)
|
||||||
combined[u][i] = v
|
combined[u][i] = v
|
||||||
combined = {k:v for k,v in combined.items() if v[4] not in BLACKLISTED_BLOCKS}
|
combined = {k:v for k,v in combined.items() if v[4] not in DISABLED_BLOCKS}
|
||||||
data = combined
|
data = combined
|
||||||
del combined
|
del combined
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "hb-fallback-shape.cc"
|
#include "hb-fallback-shape.cc"
|
||||||
#include "hb-font.cc"
|
#include "hb-font.cc"
|
||||||
#include "hb-map.cc"
|
#include "hb-map.cc"
|
||||||
|
#include "hb-ms-feature-ranges.cc"
|
||||||
#include "hb-number.cc"
|
#include "hb-number.cc"
|
||||||
#include "hb-ot-cff1-table.cc"
|
#include "hb-ot-cff1-table.cc"
|
||||||
#include "hb-ot-cff2-table.cc"
|
#include "hb-ot-cff2-table.cc"
|
||||||
|
@ -249,7 +249,9 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
|
|||||||
if (morx.has_data ())
|
if (morx.has_data ())
|
||||||
{
|
{
|
||||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
|
AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
|
||||||
|
if (!buffer->message (font, "start table morx")) return;
|
||||||
morx.apply (&c);
|
morx.apply (&c);
|
||||||
|
(void) buffer->message (font, "end table morx");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,7 +260,9 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
|
|||||||
if (mort.has_data ())
|
if (mort.has_data ())
|
||||||
{
|
{
|
||||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob);
|
AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob);
|
||||||
|
if (!buffer->message (font, "start table mort")) return;
|
||||||
mort.apply (&c);
|
mort.apply (&c);
|
||||||
|
(void) buffer->message (font, "end table mort");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,8 +318,10 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
|
|||||||
const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> ();
|
const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> ();
|
||||||
|
|
||||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, kerx_blob);
|
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 ());
|
c.set_ankr_table (font->face->table.ankr.get ());
|
||||||
kerx.apply (&c);
|
kerx.apply (&c);
|
||||||
|
(void) buffer->message (font, "end table kerx");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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])))
|
#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
|
static inline int
|
||||||
hb_memcmp (const void *a, const void *b, unsigned int len)
|
hb_memcmp (const void *a, const void *b, unsigned int len)
|
||||||
{
|
{
|
||||||
@ -1151,30 +1159,48 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o
|
|||||||
|
|
||||||
/* Operators. */
|
/* Operators. */
|
||||||
|
|
||||||
struct hb_bitwise_and
|
struct
|
||||||
{ HB_PARTIALIZE(2);
|
{ HB_PARTIALIZE(2);
|
||||||
template <typename T> constexpr auto
|
template <typename T> constexpr auto
|
||||||
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b)
|
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b)
|
||||||
}
|
}
|
||||||
HB_FUNCOBJ (hb_bitwise_and);
|
HB_FUNCOBJ (hb_bitwise_and);
|
||||||
struct hb_bitwise_or
|
struct
|
||||||
{ HB_PARTIALIZE(2);
|
{ HB_PARTIALIZE(2);
|
||||||
template <typename T> constexpr auto
|
template <typename T> constexpr auto
|
||||||
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b)
|
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b)
|
||||||
}
|
}
|
||||||
HB_FUNCOBJ (hb_bitwise_or);
|
HB_FUNCOBJ (hb_bitwise_or);
|
||||||
struct hb_bitwise_xor
|
struct
|
||||||
{ HB_PARTIALIZE(2);
|
{ HB_PARTIALIZE(2);
|
||||||
template <typename T> constexpr auto
|
template <typename T> constexpr auto
|
||||||
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b)
|
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b)
|
||||||
}
|
}
|
||||||
HB_FUNCOBJ (hb_bitwise_xor);
|
HB_FUNCOBJ (hb_bitwise_xor);
|
||||||
struct hb_bitwise_sub
|
struct
|
||||||
|
{ HB_PARTIALIZE(2);
|
||||||
|
template <typename T> constexpr auto
|
||||||
|
operator () (const T &a, const T &b) const HB_AUTO_RETURN (~a & b)
|
||||||
|
}
|
||||||
|
HB_FUNCOBJ (hb_bitwise_lt);
|
||||||
|
struct
|
||||||
{ HB_PARTIALIZE(2);
|
{ HB_PARTIALIZE(2);
|
||||||
template <typename T> constexpr auto
|
template <typename T> constexpr auto
|
||||||
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b)
|
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b)
|
||||||
}
|
}
|
||||||
HB_FUNCOBJ (hb_bitwise_sub);
|
HB_FUNCOBJ (hb_bitwise_gt); // aka sub
|
||||||
|
struct
|
||||||
|
{ HB_PARTIALIZE(2);
|
||||||
|
template <typename T> constexpr auto
|
||||||
|
operator () (const T &a, const T &b) const HB_AUTO_RETURN (~a | b)
|
||||||
|
}
|
||||||
|
HB_FUNCOBJ (hb_bitwise_le);
|
||||||
|
struct
|
||||||
|
{ HB_PARTIALIZE(2);
|
||||||
|
template <typename T> constexpr auto
|
||||||
|
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | ~b)
|
||||||
|
}
|
||||||
|
HB_FUNCOBJ (hb_bitwise_ge);
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
template <typename T> constexpr auto
|
template <typename T> constexpr auto
|
||||||
@ -1195,6 +1221,12 @@ struct
|
|||||||
}
|
}
|
||||||
HB_FUNCOBJ (hb_sub);
|
HB_FUNCOBJ (hb_sub);
|
||||||
struct
|
struct
|
||||||
|
{ HB_PARTIALIZE(2);
|
||||||
|
template <typename T, typename T2> constexpr auto
|
||||||
|
operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (b - a)
|
||||||
|
}
|
||||||
|
HB_FUNCOBJ (hb_rsub);
|
||||||
|
struct
|
||||||
{ HB_PARTIALIZE(2);
|
{ HB_PARTIALIZE(2);
|
||||||
template <typename T, typename T2> constexpr auto
|
template <typename T, typename T2> constexpr auto
|
||||||
operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a * b)
|
operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a * b)
|
||||||
|
@ -36,6 +36,14 @@
|
|||||||
template <typename Type>
|
template <typename Type>
|
||||||
struct hb_sorted_array_t;
|
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>
|
template <typename Type>
|
||||||
struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, 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;
|
return lfind (x, &i) ? &this->arrayZ[i] : not_found;
|
||||||
}
|
}
|
||||||
template <typename T>
|
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)
|
for (unsigned i = 0; i < length; ++i)
|
||||||
if (hb_equal (x, this->arrayZ[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;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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;
|
&& (unsigned int) (arrayZ + length - (const char *) p) >= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only call if you allocated the underlying array using malloc() or similar. */
|
/* Only call if you allocated the underlying array using hb_malloc() or similar. */
|
||||||
void free ()
|
void fini ()
|
||||||
{ ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
|
{ hb_free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
|
||||||
|
|
||||||
template <typename hb_serialize_context_t>
|
template <typename hb_serialize_context_t>
|
||||||
hb_array_t copy (hb_serialize_context_t *c) const
|
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_])
|
hb_array (T (&array_)[length_])
|
||||||
{ return hb_array_t<T> (array_); }
|
{ 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>
|
template <typename Type>
|
||||||
struct hb_sorted_array_t :
|
struct hb_sorted_array_t :
|
||||||
hb_iter_t<hb_sorted_array_t<Type>, Type&>,
|
hb_iter_t<hb_sorted_array_t<Type>, Type&>,
|
||||||
@ -323,7 +342,7 @@ struct hb_sorted_array_t :
|
|||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool bfind (const T &x, unsigned int *i = nullptr,
|
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 int to_store = (unsigned int) -1) const
|
||||||
{
|
{
|
||||||
unsigned pos;
|
unsigned pos;
|
||||||
@ -339,14 +358,14 @@ struct hb_sorted_array_t :
|
|||||||
{
|
{
|
||||||
switch (not_found)
|
switch (not_found)
|
||||||
{
|
{
|
||||||
case HB_BFIND_NOT_FOUND_DONT_STORE:
|
case HB_NOT_FOUND_DONT_STORE:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HB_BFIND_NOT_FOUND_STORE:
|
case HB_NOT_FOUND_STORE:
|
||||||
*i = to_store;
|
*i = to_store;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
|
case HB_NOT_FOUND_STORE_CLOSEST:
|
||||||
*i = pos;
|
*i = pos;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -58,10 +58,15 @@ struct hb_bimap_t
|
|||||||
|
|
||||||
void set (hb_codepoint_t lhs, hb_codepoint_t rhs)
|
void set (hb_codepoint_t lhs, hb_codepoint_t rhs)
|
||||||
{
|
{
|
||||||
|
if (in_error ()) return;
|
||||||
if (unlikely (lhs == HB_MAP_VALUE_INVALID)) return;
|
if (unlikely (lhs == HB_MAP_VALUE_INVALID)) return;
|
||||||
if (unlikely (rhs == HB_MAP_VALUE_INVALID)) { del (lhs); return; }
|
if (unlikely (rhs == HB_MAP_VALUE_INVALID)) { del (lhs); return; }
|
||||||
|
|
||||||
forw_map.set (lhs, rhs);
|
forw_map.set (lhs, rhs);
|
||||||
|
if (in_error ()) return;
|
||||||
|
|
||||||
back_map.set (rhs, lhs);
|
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); }
|
hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }
|
||||||
|
203
gfx/harfbuzz/src/hb-bit-page.hh
Normal file
203
gfx/harfbuzz/src/hb-bit-page.hh
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2012,2017 Google, Inc.
|
||||||
|
* Copyright © 2021 Behdad Esfahbod
|
||||||
|
*
|
||||||
|
* This is part of HarfBuzz, a text shaping library.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, without written agreement and without
|
||||||
|
* license or royalty fees, to use, copy, modify, and distribute this
|
||||||
|
* software and its documentation for any purpose, provided that the
|
||||||
|
* above copyright notice and the following two paragraphs appear in
|
||||||
|
* all copies of this software.
|
||||||
|
*
|
||||||
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||||
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||||
|
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
* DAMAGE.
|
||||||
|
*
|
||||||
|
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||||
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||||
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
|
*
|
||||||
|
* Google Author(s): Behdad Esfahbod
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HB_BIT_PAGE_HH
|
||||||
|
#define HB_BIT_PAGE_HH
|
||||||
|
|
||||||
|
#include "hb.hh"
|
||||||
|
|
||||||
|
struct hb_bit_page_t
|
||||||
|
{
|
||||||
|
void init0 () { v.clear (); }
|
||||||
|
void init1 () { v.clear (0xFF); }
|
||||||
|
|
||||||
|
constexpr unsigned len () const
|
||||||
|
{ return ARRAY_LENGTH_CONST (v); }
|
||||||
|
|
||||||
|
bool is_empty () const
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < len (); i++)
|
||||||
|
if (v[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add (hb_codepoint_t g) { elt (g) |= mask (g); }
|
||||||
|
void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
|
||||||
|
void set (hb_codepoint_t g, bool v) { if (v) add (g); else del (g); }
|
||||||
|
bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
|
||||||
|
|
||||||
|
void add_range (hb_codepoint_t a, hb_codepoint_t b)
|
||||||
|
{
|
||||||
|
elt_t *la = &elt (a);
|
||||||
|
elt_t *lb = &elt (b);
|
||||||
|
if (la == lb)
|
||||||
|
*la |= (mask (b) << 1) - mask(a);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*la |= ~(mask (a) - 1);
|
||||||
|
la++;
|
||||||
|
|
||||||
|
memset (la, 0xff, (char *) lb - (char *) la);
|
||||||
|
|
||||||
|
*lb |= ((mask (b) << 1) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void del_range (hb_codepoint_t a, hb_codepoint_t b)
|
||||||
|
{
|
||||||
|
elt_t *la = &elt (a);
|
||||||
|
elt_t *lb = &elt (b);
|
||||||
|
if (la == lb)
|
||||||
|
*la &= ~((mask (b) << 1) - mask(a));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*la &= mask (a) - 1;
|
||||||
|
la++;
|
||||||
|
|
||||||
|
memset (la, 0, (char *) lb - (char *) la);
|
||||||
|
|
||||||
|
*lb &= ~((mask (b) << 1) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
|
||||||
|
{ if (v) add_range (a, b); else del_range (a, b); }
|
||||||
|
|
||||||
|
bool is_equal (const hb_bit_page_t &other) const
|
||||||
|
{
|
||||||
|
return 0 == hb_memcmp (&v, &other.v, sizeof (v));
|
||||||
|
}
|
||||||
|
bool is_subset (const hb_bit_page_t &larger_page) const
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < len (); i++)
|
||||||
|
if (~larger_page.v[i] & v[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int get_population () const
|
||||||
|
{
|
||||||
|
unsigned int pop = 0;
|
||||||
|
for (unsigned int i = 0; i < len (); i++)
|
||||||
|
pop += hb_popcount (v[i]);
|
||||||
|
return pop;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next (hb_codepoint_t *codepoint) const
|
||||||
|
{
|
||||||
|
unsigned int m = (*codepoint + 1) & MASK;
|
||||||
|
if (!m)
|
||||||
|
{
|
||||||
|
*codepoint = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
unsigned int i = m / ELT_BITS;
|
||||||
|
unsigned int j = m & ELT_MASK;
|
||||||
|
|
||||||
|
const elt_t vv = v[i] & ~((elt_t (1) << j) - 1);
|
||||||
|
for (const elt_t *p = &vv; i < len (); p = &v[++i])
|
||||||
|
if (*p)
|
||||||
|
{
|
||||||
|
*codepoint = i * ELT_BITS + elt_get_min (*p);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*codepoint = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool previous (hb_codepoint_t *codepoint) const
|
||||||
|
{
|
||||||
|
unsigned int m = (*codepoint - 1) & MASK;
|
||||||
|
if (m == MASK)
|
||||||
|
{
|
||||||
|
*codepoint = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
unsigned int i = m / ELT_BITS;
|
||||||
|
unsigned int j = m & ELT_MASK;
|
||||||
|
|
||||||
|
/* Fancy mask to avoid shifting by elt_t bitsize, which is undefined. */
|
||||||
|
const elt_t mask = j < 8 * sizeof (elt_t) - 1 ?
|
||||||
|
((elt_t (1) << (j + 1)) - 1) :
|
||||||
|
(elt_t) -1;
|
||||||
|
const elt_t vv = v[i] & mask;
|
||||||
|
const elt_t *p = &vv;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (*p)
|
||||||
|
{
|
||||||
|
*codepoint = i * ELT_BITS + elt_get_max (*p);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((int) i <= 0) break;
|
||||||
|
p = &v[--i];
|
||||||
|
}
|
||||||
|
|
||||||
|
*codepoint = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
hb_codepoint_t get_min () const
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < len (); i++)
|
||||||
|
if (v[i])
|
||||||
|
return i * ELT_BITS + elt_get_min (v[i]);
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
hb_codepoint_t get_max () const
|
||||||
|
{
|
||||||
|
for (int i = len () - 1; i >= 0; i--)
|
||||||
|
if (v[i])
|
||||||
|
return i * ELT_BITS + elt_get_max (v[i]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
|
||||||
|
|
||||||
|
typedef unsigned long long elt_t;
|
||||||
|
static constexpr unsigned PAGE_BITS = 512;
|
||||||
|
static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
|
||||||
|
|
||||||
|
static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
|
||||||
|
static unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; }
|
||||||
|
|
||||||
|
typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
|
||||||
|
|
||||||
|
static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
|
||||||
|
static constexpr unsigned ELT_MASK = ELT_BITS - 1;
|
||||||
|
static constexpr unsigned BITS = sizeof (vector_t) * 8;
|
||||||
|
static constexpr unsigned MASK = BITS - 1;
|
||||||
|
static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
|
||||||
|
|
||||||
|
elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
|
||||||
|
const elt_t& elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
|
||||||
|
static constexpr elt_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); }
|
||||||
|
|
||||||
|
vector_t v;
|
||||||
|
};
|
||||||
|
static_assert (hb_bit_page_t::PAGE_BITS == sizeof (hb_bit_page_t) * 8, "");
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* HB_BIT_PAGE_HH */
|
354
gfx/harfbuzz/src/hb-bit-set-invertible.hh
Normal file
354
gfx/harfbuzz/src/hb-bit-set-invertible.hh
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2012,2017 Google, Inc.
|
||||||
|
* Copyright © 2021 Behdad Esfahbod
|
||||||
|
*
|
||||||
|
* This is part of HarfBuzz, a text shaping library.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, without written agreement and without
|
||||||
|
* license or royalty fees, to use, copy, modify, and distribute this
|
||||||
|
* software and its documentation for any purpose, provided that the
|
||||||
|
* above copyright notice and the following two paragraphs appear in
|
||||||
|
* all copies of this software.
|
||||||
|
*
|
||||||
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||||
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||||
|
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
* DAMAGE.
|
||||||
|
*
|
||||||
|
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||||
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||||
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
|
*
|
||||||
|
* Google Author(s): Behdad Esfahbod
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HB_BIT_SET_INVERTIBLE_HH
|
||||||
|
#define HB_BIT_SET_INVERTIBLE_HH
|
||||||
|
|
||||||
|
#include "hb.hh"
|
||||||
|
#include "hb-bit-set.hh"
|
||||||
|
|
||||||
|
|
||||||
|
struct hb_bit_set_invertible_t
|
||||||
|
{
|
||||||
|
hb_bit_set_t s;
|
||||||
|
bool inverted;
|
||||||
|
|
||||||
|
hb_bit_set_invertible_t () { init (); }
|
||||||
|
~hb_bit_set_invertible_t () { fini (); }
|
||||||
|
|
||||||
|
void init () { s.init (); inverted = false; }
|
||||||
|
void fini () { s.fini (); }
|
||||||
|
void err () { s.err (); }
|
||||||
|
bool in_error () const { return s.in_error (); }
|
||||||
|
explicit operator bool () const { return !is_empty (); }
|
||||||
|
|
||||||
|
void reset ()
|
||||||
|
{
|
||||||
|
s.reset ();
|
||||||
|
inverted = false;
|
||||||
|
}
|
||||||
|
void clear ()
|
||||||
|
{
|
||||||
|
s.clear ();
|
||||||
|
if (likely (s.successful))
|
||||||
|
inverted = false;
|
||||||
|
}
|
||||||
|
void invert ()
|
||||||
|
{
|
||||||
|
if (likely (s.successful))
|
||||||
|
inverted = !inverted;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_empty () const
|
||||||
|
{
|
||||||
|
hb_codepoint_t v = INVALID;
|
||||||
|
next (&v);
|
||||||
|
return v == INVALID;
|
||||||
|
}
|
||||||
|
hb_codepoint_t get_min () const
|
||||||
|
{
|
||||||
|
hb_codepoint_t v = INVALID;
|
||||||
|
next (&v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
hb_codepoint_t get_max () const
|
||||||
|
{
|
||||||
|
hb_codepoint_t v = INVALID;
|
||||||
|
previous (&v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
unsigned int get_population () const
|
||||||
|
{ return inverted ? INVALID - s.get_population () : s.get_population (); }
|
||||||
|
|
||||||
|
|
||||||
|
void add (hb_codepoint_t g) { unlikely (inverted) ? s.del (g) : s.add (g); }
|
||||||
|
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
|
||||||
|
{ return unlikely (inverted) ? (s.del_range (a, b), true) : s.add_range (a, b); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
|
||||||
|
{ inverted ? s.del_array (array, count, stride) : s.add_array (array, count, stride); }
|
||||||
|
template <typename T>
|
||||||
|
void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
|
||||||
|
|
||||||
|
/* Might return false if array looks unsorted.
|
||||||
|
* Used for faster rejection of corrupt data. */
|
||||||
|
template <typename T>
|
||||||
|
bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
|
||||||
|
{ return inverted ? s.del_sorted_array (array, count, stride) : s.add_sorted_array (array, count, stride); }
|
||||||
|
template <typename T>
|
||||||
|
bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
|
||||||
|
|
||||||
|
void del (hb_codepoint_t g) { unlikely (inverted) ? s.add (g) : s.del (g); }
|
||||||
|
void del_range (hb_codepoint_t a, hb_codepoint_t b)
|
||||||
|
{ unlikely (inverted) ? (void) s.add_range (a, b) : s.del_range (a, b); }
|
||||||
|
|
||||||
|
bool get (hb_codepoint_t g) const { return s.get (g) ^ inverted; }
|
||||||
|
|
||||||
|
/* Has interface. */
|
||||||
|
static constexpr bool SENTINEL = false;
|
||||||
|
typedef bool value_t;
|
||||||
|
value_t operator [] (hb_codepoint_t k) const { return get (k); }
|
||||||
|
bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
|
||||||
|
/* Predicate. */
|
||||||
|
bool operator () (hb_codepoint_t k) const { return has (k); }
|
||||||
|
|
||||||
|
/* Sink interface. */
|
||||||
|
hb_bit_set_invertible_t& operator << (hb_codepoint_t v)
|
||||||
|
{ add (v); return *this; }
|
||||||
|
hb_bit_set_invertible_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
|
||||||
|
{ add_range (range.first, range.second); return *this; }
|
||||||
|
|
||||||
|
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
|
||||||
|
{
|
||||||
|
hb_codepoint_t c = first - 1;
|
||||||
|
return next (&c) && c <= last;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set (const hb_bit_set_invertible_t &other)
|
||||||
|
{
|
||||||
|
s.set (other.s);
|
||||||
|
if (likely (s.successful))
|
||||||
|
inverted = other.inverted;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_equal (const hb_bit_set_invertible_t &other) const
|
||||||
|
{
|
||||||
|
if (likely (inverted == other.inverted))
|
||||||
|
return s.is_equal (other.s);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* TODO Add iter_ranges() and use here. */
|
||||||
|
auto it1 = iter ();
|
||||||
|
auto it2 = other.iter ();
|
||||||
|
return hb_all (+ hb_zip (it1, it2)
|
||||||
|
| hb_map ([](hb_pair_t<hb_codepoint_t, hb_codepoint_t> _) { return _.first == _.second; }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_subset (const hb_bit_set_invertible_t &larger_set) const
|
||||||
|
{
|
||||||
|
if (unlikely (inverted != larger_set.inverted))
|
||||||
|
return hb_all (hb_iter (s) | hb_map (larger_set.s));
|
||||||
|
else
|
||||||
|
return unlikely (inverted) ? larger_set.s.is_subset (s) : s.is_subset (larger_set.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template <typename Op>
|
||||||
|
void process (const Op& op, const hb_bit_set_invertible_t &other)
|
||||||
|
{ s.process (op, other.s); }
|
||||||
|
public:
|
||||||
|
void union_ (const hb_bit_set_invertible_t &other)
|
||||||
|
{
|
||||||
|
if (likely (inverted == other.inverted))
|
||||||
|
{
|
||||||
|
if (unlikely (inverted))
|
||||||
|
process (hb_bitwise_and, other);
|
||||||
|
else
|
||||||
|
process (hb_bitwise_or, other); /* Main branch. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (unlikely (inverted))
|
||||||
|
process (hb_bitwise_gt, other);
|
||||||
|
else
|
||||||
|
process (hb_bitwise_lt, other);
|
||||||
|
}
|
||||||
|
if (likely (s.successful))
|
||||||
|
inverted = inverted || other.inverted;
|
||||||
|
}
|
||||||
|
void intersect (const hb_bit_set_invertible_t &other)
|
||||||
|
{
|
||||||
|
if (likely (inverted == other.inverted))
|
||||||
|
{
|
||||||
|
if (unlikely (inverted))
|
||||||
|
process (hb_bitwise_or, other);
|
||||||
|
else
|
||||||
|
process (hb_bitwise_and, other); /* Main branch. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (unlikely (inverted))
|
||||||
|
process (hb_bitwise_lt, other);
|
||||||
|
else
|
||||||
|
process (hb_bitwise_gt, other);
|
||||||
|
}
|
||||||
|
if (likely (s.successful))
|
||||||
|
inverted = inverted && other.inverted;
|
||||||
|
}
|
||||||
|
void subtract (const hb_bit_set_invertible_t &other)
|
||||||
|
{
|
||||||
|
if (likely (inverted == other.inverted))
|
||||||
|
{
|
||||||
|
if (unlikely (inverted))
|
||||||
|
process (hb_bitwise_lt, other);
|
||||||
|
else
|
||||||
|
process (hb_bitwise_gt, other); /* Main branch. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (unlikely (inverted))
|
||||||
|
process (hb_bitwise_or, other);
|
||||||
|
else
|
||||||
|
process (hb_bitwise_and, other);
|
||||||
|
}
|
||||||
|
if (likely (s.successful))
|
||||||
|
inverted = inverted && !other.inverted;
|
||||||
|
}
|
||||||
|
void symmetric_difference (const hb_bit_set_invertible_t &other)
|
||||||
|
{
|
||||||
|
process (hb_bitwise_xor, other);
|
||||||
|
if (likely (s.successful))
|
||||||
|
inverted = inverted ^ other.inverted;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next (hb_codepoint_t *codepoint) const
|
||||||
|
{
|
||||||
|
if (likely (!inverted))
|
||||||
|
return s.next (codepoint);
|
||||||
|
|
||||||
|
auto old = *codepoint;
|
||||||
|
if (unlikely (old + 1 == INVALID))
|
||||||
|
{
|
||||||
|
*codepoint = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto v = old;
|
||||||
|
s.next (&v);
|
||||||
|
if (old + 1 < v)
|
||||||
|
{
|
||||||
|
*codepoint = old + 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = old;
|
||||||
|
s.next_range (&old, &v);
|
||||||
|
|
||||||
|
*codepoint = v + 1;
|
||||||
|
return *codepoint != INVALID;
|
||||||
|
}
|
||||||
|
bool previous (hb_codepoint_t *codepoint) const
|
||||||
|
{
|
||||||
|
if (likely (!inverted))
|
||||||
|
return s.previous (codepoint);
|
||||||
|
|
||||||
|
auto old = *codepoint;
|
||||||
|
if (unlikely (old - 1 == INVALID))
|
||||||
|
{
|
||||||
|
*codepoint = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto v = old;
|
||||||
|
s.previous (&v);
|
||||||
|
|
||||||
|
if (old - 1 > v || v == INVALID)
|
||||||
|
{
|
||||||
|
*codepoint = old - 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = old;
|
||||||
|
s.previous_range (&v, &old);
|
||||||
|
|
||||||
|
*codepoint = v - 1;
|
||||||
|
return *codepoint != INVALID;
|
||||||
|
}
|
||||||
|
bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
|
||||||
|
{
|
||||||
|
if (likely (!inverted))
|
||||||
|
return s.next_range (first, last);
|
||||||
|
|
||||||
|
if (!next (last))
|
||||||
|
{
|
||||||
|
*last = *first = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*first = *last;
|
||||||
|
s.next (last);
|
||||||
|
--*last;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
|
||||||
|
{
|
||||||
|
if (likely (!inverted))
|
||||||
|
return s.previous_range (first, last);
|
||||||
|
|
||||||
|
if (!previous (first))
|
||||||
|
{
|
||||||
|
*last = *first = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*last = *first;
|
||||||
|
s.previous (first);
|
||||||
|
++*first;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr hb_codepoint_t INVALID = hb_bit_set_t::INVALID;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Iterator implementation.
|
||||||
|
*/
|
||||||
|
struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
|
||||||
|
{
|
||||||
|
static constexpr bool is_sorted_iterator = true;
|
||||||
|
iter_t (const hb_bit_set_invertible_t &s_ = Null (hb_bit_set_invertible_t),
|
||||||
|
bool init = true) : s (&s_), v (INVALID), l(0)
|
||||||
|
{
|
||||||
|
if (init)
|
||||||
|
{
|
||||||
|
l = s->get_population () + 1;
|
||||||
|
__next__ ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef hb_codepoint_t __item_t__;
|
||||||
|
hb_codepoint_t __item__ () const { return v; }
|
||||||
|
bool __more__ () const { return v != INVALID; }
|
||||||
|
void __next__ () { s->next (&v); if (l) l--; }
|
||||||
|
void __prev__ () { s->previous (&v); }
|
||||||
|
unsigned __len__ () const { return l; }
|
||||||
|
iter_t end () const { return iter_t (*s, false); }
|
||||||
|
bool operator != (const iter_t& o) const
|
||||||
|
{ return s != o.s || v != o.v; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const hb_bit_set_invertible_t *s;
|
||||||
|
hb_codepoint_t v;
|
||||||
|
unsigned l;
|
||||||
|
};
|
||||||
|
iter_t iter () const { return iter_t (*this); }
|
||||||
|
operator iter_t () const { return iter (); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* HB_BIT_SET_INVERTIBLE_HH */
|
808
gfx/harfbuzz/src/hb-bit-set.hh
Normal file
808
gfx/harfbuzz/src/hb-bit-set.hh
Normal file
@ -0,0 +1,808 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2012,2017 Google, Inc.
|
||||||
|
* Copyright © 2021 Behdad Esfahbod
|
||||||
|
*
|
||||||
|
* This is part of HarfBuzz, a text shaping library.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, without written agreement and without
|
||||||
|
* license or royalty fees, to use, copy, modify, and distribute this
|
||||||
|
* software and its documentation for any purpose, provided that the
|
||||||
|
* above copyright notice and the following two paragraphs appear in
|
||||||
|
* all copies of this software.
|
||||||
|
*
|
||||||
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||||
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||||
|
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
* DAMAGE.
|
||||||
|
*
|
||||||
|
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||||
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||||
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
|
*
|
||||||
|
* Google Author(s): Behdad Esfahbod
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HB_BIT_SET_HH
|
||||||
|
#define HB_BIT_SET_HH
|
||||||
|
|
||||||
|
#include "hb.hh"
|
||||||
|
#include "hb-bit-page.hh"
|
||||||
|
#include "hb-machinery.hh"
|
||||||
|
|
||||||
|
|
||||||
|
struct hb_bit_set_t
|
||||||
|
{
|
||||||
|
hb_bit_set_t () { init (); }
|
||||||
|
~hb_bit_set_t () { fini (); }
|
||||||
|
|
||||||
|
hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other); }
|
||||||
|
void operator= (const hb_bit_set_t& other) { set (other); }
|
||||||
|
// TODO Add move construtor/assign
|
||||||
|
// TODO Add constructor for Iterator; with specialization for (sorted) vector / array?
|
||||||
|
|
||||||
|
void init ()
|
||||||
|
{
|
||||||
|
successful = true;
|
||||||
|
population = 0;
|
||||||
|
last_page_lookup = 0;
|
||||||
|
page_map.init ();
|
||||||
|
pages.init ();
|
||||||
|
}
|
||||||
|
void fini ()
|
||||||
|
{
|
||||||
|
page_map.fini ();
|
||||||
|
pages.fini ();
|
||||||
|
}
|
||||||
|
|
||||||
|
using page_t = hb_bit_page_t;
|
||||||
|
struct page_map_t
|
||||||
|
{
|
||||||
|
int cmp (const page_map_t &o) const { return cmp (o.major); }
|
||||||
|
int cmp (uint32_t o_major) const { return (int) o_major - (int) major; }
|
||||||
|
|
||||||
|
uint32_t major;
|
||||||
|
uint32_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool successful; /* Allocations successful */
|
||||||
|
mutable unsigned int population;
|
||||||
|
mutable unsigned int last_page_lookup;
|
||||||
|
hb_sorted_vector_t<page_map_t> page_map;
|
||||||
|
hb_vector_t<page_t> pages;
|
||||||
|
|
||||||
|
void err () { if (successful) successful = false; } /* TODO Remove */
|
||||||
|
bool in_error () const { return !successful; }
|
||||||
|
|
||||||
|
bool resize (unsigned int count)
|
||||||
|
{
|
||||||
|
if (unlikely (!successful)) return false;
|
||||||
|
if (unlikely (!pages.resize (count) || !page_map.resize (count)))
|
||||||
|
{
|
||||||
|
pages.resize (page_map.length);
|
||||||
|
successful = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset ()
|
||||||
|
{
|
||||||
|
successful = true;
|
||||||
|
clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear ()
|
||||||
|
{
|
||||||
|
resize (0);
|
||||||
|
if (likely (successful))
|
||||||
|
population = 0;
|
||||||
|
}
|
||||||
|
bool is_empty () const
|
||||||
|
{
|
||||||
|
unsigned int count = pages.length;
|
||||||
|
for (unsigned int i = 0; i < count; i++)
|
||||||
|
if (!pages[i].is_empty ())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
explicit operator bool () const { return !is_empty (); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void dirty () { population = UINT_MAX; }
|
||||||
|
public:
|
||||||
|
|
||||||
|
void add (hb_codepoint_t g)
|
||||||
|
{
|
||||||
|
if (unlikely (!successful)) return;
|
||||||
|
if (unlikely (g == INVALID)) return;
|
||||||
|
dirty ();
|
||||||
|
page_t *page = page_for (g, true); if (unlikely (!page)) return;
|
||||||
|
page->add (g);
|
||||||
|
}
|
||||||
|
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
|
||||||
|
{
|
||||||
|
if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
|
||||||
|
if (unlikely (a > b || a == INVALID || b == INVALID)) return false;
|
||||||
|
dirty ();
|
||||||
|
unsigned int ma = get_major (a);
|
||||||
|
unsigned int mb = get_major (b);
|
||||||
|
if (ma == mb)
|
||||||
|
{
|
||||||
|
page_t *page = page_for (a, true); if (unlikely (!page)) return false;
|
||||||
|
page->add_range (a, b);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
page_t *page = page_for (a, true); if (unlikely (!page)) return false;
|
||||||
|
page->add_range (a, major_start (ma + 1) - 1);
|
||||||
|
|
||||||
|
for (unsigned int m = ma + 1; m < mb; m++)
|
||||||
|
{
|
||||||
|
page = page_for (major_start (m), true); if (unlikely (!page)) return false;
|
||||||
|
page->init1 ();
|
||||||
|
}
|
||||||
|
|
||||||
|
page = page_for (b, true); if (unlikely (!page)) return false;
|
||||||
|
page->add_range (major_start (mb), b);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void set_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
|
||||||
|
{
|
||||||
|
if (unlikely (!successful)) return;
|
||||||
|
if (!count) return;
|
||||||
|
dirty ();
|
||||||
|
hb_codepoint_t g = *array;
|
||||||
|
while (count)
|
||||||
|
{
|
||||||
|
unsigned int m = get_major (g);
|
||||||
|
page_t *page = page_for (g, v); if (unlikely (v && !page)) return;
|
||||||
|
unsigned int start = major_start (m);
|
||||||
|
unsigned int end = major_start (m + 1);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (v || page) /* The v check is to optimize out the page check if v is true. */
|
||||||
|
page->set (g, v);
|
||||||
|
|
||||||
|
array = &StructAtOffsetUnaligned<T> (array, stride);
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
while (count && (g = *array, start <= g && g < end));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
|
||||||
|
{ set_array (true, array, count, stride); }
|
||||||
|
template <typename T>
|
||||||
|
void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void del_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
|
||||||
|
{ set_array (false, array, count, stride); }
|
||||||
|
template <typename T>
|
||||||
|
void del_array (const hb_array_t<const T>& arr) { del_array (&arr, arr.len ()); }
|
||||||
|
|
||||||
|
/* Might return false if array looks unsorted.
|
||||||
|
* Used for faster rejection of corrupt data. */
|
||||||
|
template <typename T>
|
||||||
|
bool set_sorted_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
|
||||||
|
{
|
||||||
|
if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
|
||||||
|
if (!count) return true;
|
||||||
|
dirty ();
|
||||||
|
hb_codepoint_t g = *array;
|
||||||
|
hb_codepoint_t last_g = g;
|
||||||
|
while (count)
|
||||||
|
{
|
||||||
|
unsigned int m = get_major (g);
|
||||||
|
page_t *page = page_for (g, v); if (unlikely (v && !page)) return false;
|
||||||
|
unsigned int end = major_start (m + 1);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* If we try harder we can change the following comparison to <=;
|
||||||
|
* Not sure if it's worth it. */
|
||||||
|
if (g < last_g) return false;
|
||||||
|
last_g = g;
|
||||||
|
|
||||||
|
if (v || page) /* The v check is to optimize out the page check if v is true. */
|
||||||
|
page->add (g);
|
||||||
|
|
||||||
|
array = (const T *) ((const char *) array + stride);
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
while (count && (g = *array, g < end));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
|
||||||
|
{ return set_sorted_array (true, array, count, stride); }
|
||||||
|
template <typename T>
|
||||||
|
bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool del_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
|
||||||
|
{ return set_sorted_array (false, array, count, stride); }
|
||||||
|
template <typename T>
|
||||||
|
bool del_sorted_array (const hb_sorted_array_t<const T>& arr) { return del_sorted_array (&arr, arr.len ()); }
|
||||||
|
|
||||||
|
void del (hb_codepoint_t g)
|
||||||
|
{
|
||||||
|
if (unlikely (!successful)) return;
|
||||||
|
page_t *page = page_for (g);
|
||||||
|
if (!page)
|
||||||
|
return;
|
||||||
|
dirty ();
|
||||||
|
page->del (g);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void del_pages (int ds, int de)
|
||||||
|
{
|
||||||
|
if (ds <= de)
|
||||||
|
{
|
||||||
|
// Pre-allocate the workspace that compact() will need so we can bail on allocation failure
|
||||||
|
// before attempting to rewrite the page map.
|
||||||
|
hb_vector_t<unsigned> compact_workspace;
|
||||||
|
if (unlikely (!allocate_compact_workspace (compact_workspace))) return;
|
||||||
|
|
||||||
|
unsigned int write_index = 0;
|
||||||
|
for (unsigned int i = 0; i < page_map.length; i++)
|
||||||
|
{
|
||||||
|
int m = (int) page_map[i].major;
|
||||||
|
if (m < ds || de < m)
|
||||||
|
page_map[write_index++] = page_map[i];
|
||||||
|
}
|
||||||
|
compact (compact_workspace, write_index);
|
||||||
|
resize (write_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
void del_range (hb_codepoint_t a, hb_codepoint_t b)
|
||||||
|
{
|
||||||
|
if (unlikely (!successful)) return;
|
||||||
|
if (unlikely (a > b || a == INVALID)) return;
|
||||||
|
dirty ();
|
||||||
|
unsigned int ma = get_major (a);
|
||||||
|
unsigned int mb = get_major (b);
|
||||||
|
/* Delete pages from ds through de if ds <= de. */
|
||||||
|
int ds = (a == major_start (ma))? (int) ma: (int) (ma + 1);
|
||||||
|
int de = (b + 1 == major_start (mb + 1))? (int) mb: ((int) mb - 1);
|
||||||
|
if (ds > de || (int) ma < ds)
|
||||||
|
{
|
||||||
|
page_t *page = page_for (a);
|
||||||
|
if (page)
|
||||||
|
{
|
||||||
|
if (ma == mb)
|
||||||
|
page->del_range (a, b);
|
||||||
|
else
|
||||||
|
page->del_range (a, major_start (ma + 1) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (de < (int) mb && ma != mb)
|
||||||
|
{
|
||||||
|
page_t *page = page_for (b);
|
||||||
|
if (page)
|
||||||
|
page->del_range (major_start (mb), b);
|
||||||
|
}
|
||||||
|
del_pages (ds, de);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get (hb_codepoint_t g) const
|
||||||
|
{
|
||||||
|
const page_t *page = page_for (g);
|
||||||
|
if (!page)
|
||||||
|
return false;
|
||||||
|
return page->get (g);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Has interface. */
|
||||||
|
static constexpr bool SENTINEL = false;
|
||||||
|
typedef bool value_t;
|
||||||
|
value_t operator [] (hb_codepoint_t k) const { return get (k); }
|
||||||
|
bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
|
||||||
|
/* Predicate. */
|
||||||
|
bool operator () (hb_codepoint_t k) const { return has (k); }
|
||||||
|
|
||||||
|
/* Sink interface. */
|
||||||
|
hb_bit_set_t& operator << (hb_codepoint_t v)
|
||||||
|
{ add (v); return *this; }
|
||||||
|
hb_bit_set_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
|
||||||
|
{ add_range (range.first, range.second); return *this; }
|
||||||
|
|
||||||
|
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
|
||||||
|
{
|
||||||
|
hb_codepoint_t c = first - 1;
|
||||||
|
return next (&c) && c <= last;
|
||||||
|
}
|
||||||
|
void set (const hb_bit_set_t &other)
|
||||||
|
{
|
||||||
|
if (unlikely (!successful)) return;
|
||||||
|
unsigned int count = other.pages.length;
|
||||||
|
if (unlikely (!resize (count)))
|
||||||
|
return;
|
||||||
|
population = other.population;
|
||||||
|
|
||||||
|
/* TODO switch to vector operator =. */
|
||||||
|
hb_memcpy ((void *) pages, (const void *) other.pages, count * pages.item_size);
|
||||||
|
hb_memcpy ((void *) page_map, (const void *) other.page_map, count * page_map.item_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_equal (const hb_bit_set_t &other) const
|
||||||
|
{
|
||||||
|
if (has_population () && other.has_population () &&
|
||||||
|
get_population () != other.get_population ())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
unsigned int na = pages.length;
|
||||||
|
unsigned int nb = other.pages.length;
|
||||||
|
|
||||||
|
unsigned int a = 0, b = 0;
|
||||||
|
for (; a < na && b < nb; )
|
||||||
|
{
|
||||||
|
if (page_at (a).is_empty ()) { a++; continue; }
|
||||||
|
if (other.page_at (b).is_empty ()) { b++; continue; }
|
||||||
|
if (page_map[a].major != other.page_map[b].major ||
|
||||||
|
!page_at (a).is_equal (other.page_at (b)))
|
||||||
|
return false;
|
||||||
|
a++;
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
for (; a < na; a++)
|
||||||
|
if (!page_at (a).is_empty ()) { return false; }
|
||||||
|
for (; b < nb; b++)
|
||||||
|
if (!other.page_at (b).is_empty ()) { return false; }
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_subset (const hb_bit_set_t &larger_set) const
|
||||||
|
{
|
||||||
|
if (has_population () && larger_set.has_population () &&
|
||||||
|
get_population () != larger_set.get_population ())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32_t spi = 0;
|
||||||
|
for (uint32_t lpi = 0; spi < page_map.length && lpi < larger_set.page_map.length; lpi++)
|
||||||
|
{
|
||||||
|
uint32_t spm = page_map[spi].major;
|
||||||
|
uint32_t lpm = larger_set.page_map[lpi].major;
|
||||||
|
auto sp = page_at (spi);
|
||||||
|
auto lp = larger_set.page_at (lpi);
|
||||||
|
|
||||||
|
if (spm < lpm && !sp.is_empty ())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (lpm < spm)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!sp.is_subset (lp))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
spi++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (spi < page_map.length)
|
||||||
|
if (!page_at (spi++).is_empty ())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool allocate_compact_workspace (hb_vector_t<unsigned>& workspace)
|
||||||
|
{
|
||||||
|
if (unlikely (!workspace.resize (pages.length)))
|
||||||
|
{
|
||||||
|
successful = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* workspace should be a pre-sized vector allocated to hold at exactly pages.length
|
||||||
|
* elements.
|
||||||
|
*/
|
||||||
|
void compact (hb_vector_t<unsigned>& workspace,
|
||||||
|
unsigned int length)
|
||||||
|
{
|
||||||
|
assert(workspace.length == pages.length);
|
||||||
|
hb_vector_t<unsigned>& old_index_to_page_map_index = workspace;
|
||||||
|
|
||||||
|
hb_fill (old_index_to_page_map_index.writer(), 0xFFFFFFFF);
|
||||||
|
for (unsigned i = 0; i < length; i++)
|
||||||
|
old_index_to_page_map_index[page_map[i].index] = i;
|
||||||
|
|
||||||
|
compact_pages (old_index_to_page_map_index);
|
||||||
|
}
|
||||||
|
void compact_pages (const hb_vector_t<unsigned>& old_index_to_page_map_index)
|
||||||
|
{
|
||||||
|
unsigned int write_index = 0;
|
||||||
|
for (unsigned int i = 0; i < pages.length; i++)
|
||||||
|
{
|
||||||
|
if (old_index_to_page_map_index[i] == 0xFFFFFFFF) continue;
|
||||||
|
|
||||||
|
if (write_index < i)
|
||||||
|
pages[write_index] = pages[i];
|
||||||
|
|
||||||
|
page_map[old_index_to_page_map_index[i]].index = write_index;
|
||||||
|
write_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
|
||||||
|
template <typename Op>
|
||||||
|
void process (const Op& op, const hb_bit_set_t &other)
|
||||||
|
{
|
||||||
|
const bool passthru_left = op (1, 0);
|
||||||
|
const bool passthru_right = op (0, 1);
|
||||||
|
|
||||||
|
if (unlikely (!successful)) return;
|
||||||
|
|
||||||
|
dirty ();
|
||||||
|
|
||||||
|
unsigned int na = pages.length;
|
||||||
|
unsigned int nb = other.pages.length;
|
||||||
|
unsigned int next_page = na;
|
||||||
|
|
||||||
|
unsigned int count = 0, newCount = 0;
|
||||||
|
unsigned int a = 0, b = 0;
|
||||||
|
unsigned int write_index = 0;
|
||||||
|
|
||||||
|
// Pre-allocate the workspace that compact() will need so we can bail on allocation failure
|
||||||
|
// before attempting to rewrite the page map.
|
||||||
|
hb_vector_t<unsigned> compact_workspace;
|
||||||
|
if (!passthru_left && unlikely (!allocate_compact_workspace (compact_workspace))) return;
|
||||||
|
|
||||||
|
for (; a < na && b < nb; )
|
||||||
|
{
|
||||||
|
if (page_map[a].major == other.page_map[b].major)
|
||||||
|
{
|
||||||
|
if (!passthru_left)
|
||||||
|
{
|
||||||
|
// Move page_map entries that we're keeping from the left side set
|
||||||
|
// to the front of the page_map vector. This isn't necessary if
|
||||||
|
// passthru_left is set since no left side pages will be removed
|
||||||
|
// in that case.
|
||||||
|
if (write_index < a)
|
||||||
|
page_map[write_index] = page_map[a];
|
||||||
|
write_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
a++;
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
else if (page_map[a].major < other.page_map[b].major)
|
||||||
|
{
|
||||||
|
if (passthru_left)
|
||||||
|
count++;
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (passthru_right)
|
||||||
|
count++;
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (passthru_left)
|
||||||
|
count += na - a;
|
||||||
|
if (passthru_right)
|
||||||
|
count += nb - b;
|
||||||
|
|
||||||
|
if (!passthru_left)
|
||||||
|
{
|
||||||
|
na = write_index;
|
||||||
|
next_page = write_index;
|
||||||
|
compact (compact_workspace, write_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely (!resize (count)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
newCount = count;
|
||||||
|
|
||||||
|
/* Process in-place backward. */
|
||||||
|
a = na;
|
||||||
|
b = nb;
|
||||||
|
for (; a && b; )
|
||||||
|
{
|
||||||
|
if (page_map[a - 1].major == other.page_map[b - 1].major)
|
||||||
|
{
|
||||||
|
a--;
|
||||||
|
b--;
|
||||||
|
count--;
|
||||||
|
page_map[count] = page_map[a];
|
||||||
|
page_at (count).v = op (page_at (a).v, other.page_at (b).v);
|
||||||
|
}
|
||||||
|
else if (page_map[a - 1].major > other.page_map[b - 1].major)
|
||||||
|
{
|
||||||
|
a--;
|
||||||
|
if (passthru_left)
|
||||||
|
{
|
||||||
|
count--;
|
||||||
|
page_map[count] = page_map[a];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
b--;
|
||||||
|
if (passthru_right)
|
||||||
|
{
|
||||||
|
count--;
|
||||||
|
page_map[count].major = other.page_map[b].major;
|
||||||
|
page_map[count].index = next_page++;
|
||||||
|
page_at (count).v = other.page_at (b).v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (passthru_left)
|
||||||
|
while (a)
|
||||||
|
{
|
||||||
|
a--;
|
||||||
|
count--;
|
||||||
|
page_map[count] = page_map [a];
|
||||||
|
}
|
||||||
|
if (passthru_right)
|
||||||
|
while (b)
|
||||||
|
{
|
||||||
|
b--;
|
||||||
|
count--;
|
||||||
|
page_map[count].major = other.page_map[b].major;
|
||||||
|
page_map[count].index = next_page++;
|
||||||
|
page_at (count).v = other.page_at (b).v;
|
||||||
|
}
|
||||||
|
assert (!count);
|
||||||
|
resize (newCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void union_ (const hb_bit_set_t &other) { process (hb_bitwise_or, other); }
|
||||||
|
void intersect (const hb_bit_set_t &other) { process (hb_bitwise_and, other); }
|
||||||
|
void subtract (const hb_bit_set_t &other) { process (hb_bitwise_gt, other); }
|
||||||
|
void symmetric_difference (const hb_bit_set_t &other) { process (hb_bitwise_xor, other); }
|
||||||
|
|
||||||
|
bool next (hb_codepoint_t *codepoint) const
|
||||||
|
{
|
||||||
|
// TODO: this should be merged with prev() as both implementations
|
||||||
|
// are very similar.
|
||||||
|
if (unlikely (*codepoint == INVALID)) {
|
||||||
|
*codepoint = get_min ();
|
||||||
|
return *codepoint != INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* page_map_array = page_map.arrayZ;
|
||||||
|
unsigned int major = get_major (*codepoint);
|
||||||
|
unsigned int i = last_page_lookup;
|
||||||
|
|
||||||
|
if (unlikely (i >= page_map.length || page_map_array[i].major != major))
|
||||||
|
{
|
||||||
|
page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
|
||||||
|
if (i >= page_map.length) {
|
||||||
|
*codepoint = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* pages_array = pages.arrayZ;
|
||||||
|
const page_map_t ¤t = page_map_array[i];
|
||||||
|
if (likely (current.major == major))
|
||||||
|
{
|
||||||
|
if (pages_array[current.index].next (codepoint))
|
||||||
|
{
|
||||||
|
*codepoint += current.major * page_t::PAGE_BITS;
|
||||||
|
last_page_lookup = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < page_map.length; i++)
|
||||||
|
{
|
||||||
|
const page_map_t ¤t = page_map.arrayZ[i];
|
||||||
|
hb_codepoint_t m = pages_array[current.index].get_min ();
|
||||||
|
if (m != INVALID)
|
||||||
|
{
|
||||||
|
*codepoint = current.major * page_t::PAGE_BITS + m;
|
||||||
|
last_page_lookup = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_page_lookup = 0;
|
||||||
|
*codepoint = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool previous (hb_codepoint_t *codepoint) const
|
||||||
|
{
|
||||||
|
if (unlikely (*codepoint == INVALID)) {
|
||||||
|
*codepoint = get_max ();
|
||||||
|
return *codepoint != INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
page_map_t map = {get_major (*codepoint), 0};
|
||||||
|
unsigned int i;
|
||||||
|
page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST);
|
||||||
|
if (i < page_map.length && page_map[i].major == map.major)
|
||||||
|
{
|
||||||
|
if (pages[page_map[i].index].previous (codepoint))
|
||||||
|
{
|
||||||
|
*codepoint += page_map[i].major * page_t::PAGE_BITS;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i--;
|
||||||
|
for (; (int) i >= 0; i--)
|
||||||
|
{
|
||||||
|
hb_codepoint_t m = pages[page_map[i].index].get_max ();
|
||||||
|
if (m != INVALID)
|
||||||
|
{
|
||||||
|
*codepoint = page_map[i].major * page_t::PAGE_BITS + m;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*codepoint = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
|
||||||
|
{
|
||||||
|
hb_codepoint_t i;
|
||||||
|
|
||||||
|
i = *last;
|
||||||
|
if (!next (&i))
|
||||||
|
{
|
||||||
|
*last = *first = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO Speed up. */
|
||||||
|
*last = *first = i;
|
||||||
|
while (next (&i) && i == *last + 1)
|
||||||
|
(*last)++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
|
||||||
|
{
|
||||||
|
hb_codepoint_t i;
|
||||||
|
|
||||||
|
i = *first;
|
||||||
|
if (!previous (&i))
|
||||||
|
{
|
||||||
|
*last = *first = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO Speed up. */
|
||||||
|
*last = *first = i;
|
||||||
|
while (previous (&i) && i == *first - 1)
|
||||||
|
(*first)--;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_population () const { return population != UINT_MAX; }
|
||||||
|
unsigned int get_population () const
|
||||||
|
{
|
||||||
|
if (has_population ())
|
||||||
|
return population;
|
||||||
|
|
||||||
|
unsigned int pop = 0;
|
||||||
|
unsigned int count = pages.length;
|
||||||
|
for (unsigned int i = 0; i < count; i++)
|
||||||
|
pop += pages[i].get_population ();
|
||||||
|
|
||||||
|
population = pop;
|
||||||
|
return pop;
|
||||||
|
}
|
||||||
|
hb_codepoint_t get_min () const
|
||||||
|
{
|
||||||
|
unsigned count = pages.length;
|
||||||
|
for (unsigned i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
const auto& map = page_map[i];
|
||||||
|
const auto& page = pages[map.index];
|
||||||
|
|
||||||
|
if (!page.is_empty ())
|
||||||
|
return map.major * page_t::PAGE_BITS + page.get_min ();
|
||||||
|
}
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
hb_codepoint_t get_max () const
|
||||||
|
{
|
||||||
|
unsigned count = pages.length;
|
||||||
|
for (signed i = count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
const auto& map = page_map[(unsigned) i];
|
||||||
|
const auto& page = pages[map.index];
|
||||||
|
|
||||||
|
if (!page.is_empty ())
|
||||||
|
return map.major * page_t::PAGE_BITS + page.get_max ();
|
||||||
|
}
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr hb_codepoint_t INVALID = page_t::INVALID;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Iterator implementation.
|
||||||
|
*/
|
||||||
|
struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
|
||||||
|
{
|
||||||
|
static constexpr bool is_sorted_iterator = true;
|
||||||
|
iter_t (const hb_bit_set_t &s_ = Null (hb_bit_set_t),
|
||||||
|
bool init = true) : s (&s_), v (INVALID), l(0)
|
||||||
|
{
|
||||||
|
if (init)
|
||||||
|
{
|
||||||
|
l = s->get_population () + 1;
|
||||||
|
__next__ ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef hb_codepoint_t __item_t__;
|
||||||
|
hb_codepoint_t __item__ () const { return v; }
|
||||||
|
bool __more__ () const { return v != INVALID; }
|
||||||
|
void __next__ () { s->next (&v); if (l) l--; }
|
||||||
|
void __prev__ () { s->previous (&v); }
|
||||||
|
unsigned __len__ () const { return l; }
|
||||||
|
iter_t end () const { return iter_t (*s, false); }
|
||||||
|
bool operator != (const iter_t& o) const
|
||||||
|
{ return s != o.s || v != o.v; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const hb_bit_set_t *s;
|
||||||
|
hb_codepoint_t v;
|
||||||
|
unsigned l;
|
||||||
|
};
|
||||||
|
iter_t iter () const { return iter_t (*this); }
|
||||||
|
operator iter_t () const { return iter (); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
page_t *page_for (hb_codepoint_t g, bool insert = false)
|
||||||
|
{
|
||||||
|
page_map_t map = {get_major (g), pages.length};
|
||||||
|
unsigned int i;
|
||||||
|
if (!page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST))
|
||||||
|
{
|
||||||
|
if (!insert)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (unlikely (!resize (pages.length + 1)))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
pages[map.index].init0 ();
|
||||||
|
memmove (page_map + i + 1,
|
||||||
|
page_map + i,
|
||||||
|
(page_map.length - 1 - i) * page_map.item_size);
|
||||||
|
page_map[i] = map;
|
||||||
|
}
|
||||||
|
return &pages[page_map[i].index];
|
||||||
|
}
|
||||||
|
const page_t *page_for (hb_codepoint_t g) const
|
||||||
|
{
|
||||||
|
page_map_t key = {get_major (g)};
|
||||||
|
const page_map_t *found = page_map.bsearch (key);
|
||||||
|
if (found)
|
||||||
|
return &pages[found->index];
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
|
||||||
|
const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
|
||||||
|
unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
|
||||||
|
hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* HB_BIT_SET_HH */
|
@ -72,16 +72,54 @@ hb_blob_create (const char *data,
|
|||||||
void *user_data,
|
void *user_data,
|
||||||
hb_destroy_func_t destroy)
|
hb_destroy_func_t destroy)
|
||||||
{
|
{
|
||||||
hb_blob_t *blob;
|
if (!length)
|
||||||
|
{
|
||||||
if (!length ||
|
|
||||||
length >= 1u << 31 ||
|
|
||||||
!(blob = hb_object_create<hb_blob_t> ())) {
|
|
||||||
if (destroy)
|
if (destroy)
|
||||||
destroy (user_data);
|
destroy (user_data);
|
||||||
return hb_blob_get_empty ();
|
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 >= 1u << 31 ||
|
||||||
|
!(blob = hb_object_create<hb_blob_t> ()))
|
||||||
|
{
|
||||||
|
if (destroy)
|
||||||
|
destroy (user_data);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
blob->data = data;
|
blob->data = data;
|
||||||
blob->length = length;
|
blob->length = length;
|
||||||
blob->mode = mode;
|
blob->mode = mode;
|
||||||
@ -91,9 +129,10 @@ hb_blob_create (const char *data,
|
|||||||
|
|
||||||
if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
|
if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
|
||||||
blob->mode = HB_MEMORY_MODE_READONLY;
|
blob->mode = HB_MEMORY_MODE_READONLY;
|
||||||
if (!blob->try_make_writable ()) {
|
if (!blob->try_make_writable ())
|
||||||
|
{
|
||||||
hb_blob_destroy (blob);
|
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 ();
|
blob->fini_shallow ();
|
||||||
|
|
||||||
free (blob);
|
hb_free (blob);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -452,7 +491,7 @@ hb_blob_t::try_make_writable ()
|
|||||||
|
|
||||||
char *new_data;
|
char *new_data;
|
||||||
|
|
||||||
new_data = (char *) malloc (this->length);
|
new_data = (char *) hb_malloc (this->length);
|
||||||
if (unlikely (!new_data))
|
if (unlikely (!new_data))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -463,7 +502,7 @@ hb_blob_t::try_make_writable ()
|
|||||||
this->mode = HB_MEMORY_MODE_WRITABLE;
|
this->mode = HB_MEMORY_MODE_WRITABLE;
|
||||||
this->data = new_data;
|
this->data = new_data;
|
||||||
this->user_data = new_data;
|
this->user_data = new_data;
|
||||||
this->destroy = free;
|
this->destroy = hb_free;
|
||||||
|
|
||||||
return true;
|
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
|
assert (0); // If we don't have mmap we shouldn't reach here
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
free (file);
|
hb_free (file);
|
||||||
}
|
}
|
||||||
#endif
|
#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 name_len = strlen (file_name);
|
||||||
size_t len = name_len + sizeof (_PATH_RSRCFORKSPEC);
|
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;
|
if (unlikely (!rsrc_name)) return -1;
|
||||||
|
|
||||||
strncpy (rsrc_name, file_name, name_len);
|
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);
|
sizeof (_PATH_RSRCFORKSPEC) - 1);
|
||||||
|
|
||||||
int fd = open (rsrc_name, O_RDONLY | O_BINARY, 0);
|
int fd = open (rsrc_name, O_RDONLY | O_BINARY, 0);
|
||||||
free (rsrc_name);
|
hb_free (rsrc_name);
|
||||||
|
|
||||||
if (fd != -1)
|
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
|
* Creates a new blob containing the data from the
|
||||||
* specified binary font file.
|
* 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
|
* Since: 1.7.7
|
||||||
**/
|
**/
|
||||||
hb_blob_t *
|
hb_blob_t *
|
||||||
hb_blob_create_from_file (const char *file_name)
|
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
|
/* Adopted from glib's gmappedfile.c with Matthias Clasen and
|
||||||
Allison Lortie permission but changed a lot to suit our need. */
|
Allison Lortie permission but changed a lot to suit our need. */
|
||||||
#if defined(HAVE_MMAP) && !defined(HB_NO_MMAP)
|
#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 ();
|
if (unlikely (!file)) return hb_blob_get_empty ();
|
||||||
|
|
||||||
int fd = open (file_name, O_RDONLY | O_BINARY, 0);
|
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);
|
close (fd);
|
||||||
|
|
||||||
return hb_blob_create (file->contents, file->length,
|
return hb_blob_create_or_fail (file->contents, file->length,
|
||||||
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
|
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
|
||||||
(hb_destroy_func_t) _hb_mapped_file_destroy);
|
(hb_destroy_func_t) _hb_mapped_file_destroy);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
close (fd);
|
close (fd);
|
||||||
fail_without_close:
|
fail_without_close:
|
||||||
free (file);
|
hb_free (file);
|
||||||
|
|
||||||
#elif defined(_WIN32) && !defined(HB_NO_MMAP)
|
#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 ();
|
if (unlikely (!file)) return hb_blob_get_empty ();
|
||||||
|
|
||||||
HANDLE fd;
|
HANDLE fd;
|
||||||
unsigned int size = strlen (file_name) + 1;
|
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;
|
if (unlikely (!wchar_file_name)) goto fail_without_close;
|
||||||
mbstowcs (wchar_file_name, file_name, size);
|
mbstowcs (wchar_file_name, file_name, size);
|
||||||
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||||
@ -636,7 +695,7 @@ fail_without_close:
|
|||||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
|
||||||
nullptr);
|
nullptr);
|
||||||
#endif
|
#endif
|
||||||
free (wchar_file_name);
|
hb_free (wchar_file_name);
|
||||||
|
|
||||||
if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
|
if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
|
||||||
|
|
||||||
@ -661,22 +720,22 @@ fail_without_close:
|
|||||||
if (unlikely (!file->contents)) goto fail;
|
if (unlikely (!file->contents)) goto fail;
|
||||||
|
|
||||||
CloseHandle (fd);
|
CloseHandle (fd);
|
||||||
return hb_blob_create (file->contents, file->length,
|
return hb_blob_create_or_fail (file->contents, file->length,
|
||||||
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
|
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
|
||||||
(hb_destroy_func_t) _hb_mapped_file_destroy);
|
(hb_destroy_func_t) _hb_mapped_file_destroy);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
CloseHandle (fd);
|
CloseHandle (fd);
|
||||||
fail_without_close:
|
fail_without_close:
|
||||||
free (file);
|
hb_free (file);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* The following tries to read a file without knowing its size beforehand
|
/* 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 */
|
It's used as a fallback for systems without mmap or to read from pipes */
|
||||||
unsigned long len = 0, allocated = BUFSIZ * 16;
|
unsigned long len = 0, allocated = BUFSIZ * 16;
|
||||||
char *data = (char *) malloc (allocated);
|
char *data = (char *) hb_malloc (allocated);
|
||||||
if (unlikely (!data)) return hb_blob_get_empty ();
|
if (unlikely (!data)) return nullptr;
|
||||||
|
|
||||||
FILE *fp = fopen (file_name, "rb");
|
FILE *fp = fopen (file_name, "rb");
|
||||||
if (unlikely (!fp)) goto fread_fail_without_close;
|
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
|
/* Don't allocate and go more than ~536MB, our mmap reader still
|
||||||
can cover files like that but lets limit our fallback reader */
|
can cover files like that but lets limit our fallback reader */
|
||||||
if (unlikely (allocated > (2 << 28))) goto fread_fail;
|
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;
|
if (unlikely (!new_data)) goto fread_fail;
|
||||||
data = new_data;
|
data = new_data;
|
||||||
}
|
}
|
||||||
@ -706,13 +765,13 @@ fail_without_close:
|
|||||||
}
|
}
|
||||||
fclose (fp);
|
fclose (fp);
|
||||||
|
|
||||||
return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data,
|
return hb_blob_create_or_fail (data, len, HB_MEMORY_MODE_WRITABLE, data,
|
||||||
(hb_destroy_func_t) free);
|
(hb_destroy_func_t) hb_free);
|
||||||
|
|
||||||
fread_fail:
|
fread_fail:
|
||||||
fclose (fp);
|
fclose (fp);
|
||||||
fread_fail_without_close:
|
fread_fail_without_close:
|
||||||
free (data);
|
hb_free (data);
|
||||||
return hb_blob_get_empty ();
|
return nullptr;
|
||||||
}
|
}
|
||||||
#endif /* !HB_NO_OPEN */
|
#endif /* !HB_NO_OPEN */
|
||||||
|
@ -90,9 +90,19 @@ hb_blob_create (const char *data,
|
|||||||
void *user_data,
|
void *user_data,
|
||||||
hb_destroy_func_t destroy);
|
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_EXTERN hb_blob_t *
|
||||||
hb_blob_create_from_file (const char *file_name);
|
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.
|
/* Always creates with MEMORY_MODE_READONLY.
|
||||||
* Even if the parent blob is writable, we don't
|
* Even if the parent blob is writable, we don't
|
||||||
* want the user of the sub-blob to be able to
|
* want the user of the sub-blob to be able to
|
||||||
|
@ -88,7 +88,7 @@ struct hb_blob_ptr_t
|
|||||||
const T * get () const { return b->as<T> (); }
|
const T * get () const { return b->as<T> (); }
|
||||||
hb_blob_t * get_blob () const { return b.get_raw (); }
|
hb_blob_t * get_blob () const { return b.get_raw (); }
|
||||||
unsigned int get_length () const { return b.get ()->length; }
|
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:
|
private:
|
||||||
hb_nonnull_ptr_t<hb_blob_t> b;
|
hb_nonnull_ptr_t<hb_blob_t> b;
|
||||||
|
@ -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
|
* As an optimization, both info and out_info may point to the
|
||||||
* same piece of memory, which is owned by info. This remains 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.
|
* 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
|
* In that case, swap_buffers() is mostly no-op and the glyph operations
|
||||||
* mostly in-place.
|
* operate mostly in-place.
|
||||||
*
|
*
|
||||||
* As soon as out_info gets longer than info, out_info is moved over
|
* 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.
|
* current contents (out_len entries) are copied to the new place.
|
||||||
|
*
|
||||||
* This should all remain transparent to the user. swap_buffers() then
|
* 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]))))
|
if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]))))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
|
new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_allocated * sizeof (pos[0]));
|
||||||
new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
|
new_info = (hb_glyph_info_t *) hb_realloc (info, new_allocated * sizeof (info[0]));
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (unlikely (!new_pos || !new_info))
|
if (unlikely (!new_pos || !new_info))
|
||||||
@ -281,22 +282,13 @@ hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
hb_buffer_t::remove_output ()
|
|
||||||
{
|
|
||||||
have_output = false;
|
|
||||||
have_positions = false;
|
|
||||||
|
|
||||||
out_len = 0;
|
|
||||||
out_info = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
hb_buffer_t::clear_output ()
|
hb_buffer_t::clear_output ()
|
||||||
{
|
{
|
||||||
have_output = true;
|
have_output = true;
|
||||||
have_positions = false;
|
have_positions = false;
|
||||||
|
|
||||||
|
idx = 0;
|
||||||
out_len = 0;
|
out_len = 0;
|
||||||
out_info = info;
|
out_info = info;
|
||||||
}
|
}
|
||||||
@ -316,29 +308,23 @@ hb_buffer_t::clear_positions ()
|
|||||||
void
|
void
|
||||||
hb_buffer_t::swap_buffers ()
|
hb_buffer_t::swap_buffers ()
|
||||||
{
|
{
|
||||||
if (unlikely (!successful)) return;
|
assert (have_output);
|
||||||
|
|
||||||
assert (idx <= len);
|
assert (idx <= len);
|
||||||
if (unlikely (!next_glyphs (len - idx))) return;
|
|
||||||
|
|
||||||
assert (have_output);
|
if (unlikely (!successful || !next_glyphs (len - idx)))
|
||||||
have_output = false;
|
goto reset;
|
||||||
|
|
||||||
if (out_info != info)
|
if (out_info != info)
|
||||||
{
|
{
|
||||||
hb_glyph_info_t *tmp;
|
pos = (hb_glyph_position_t *) info;
|
||||||
tmp = info;
|
|
||||||
info = out_info;
|
info = out_info;
|
||||||
out_info = tmp;
|
|
||||||
|
|
||||||
pos = (hb_glyph_position_t *) out_info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int tmp;
|
|
||||||
tmp = len;
|
|
||||||
len = out_len;
|
len = out_len;
|
||||||
out_len = tmp;
|
|
||||||
|
|
||||||
|
reset:
|
||||||
|
have_output = false;
|
||||||
|
out_len = 0;
|
||||||
idx = 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
|
/* This will blow in our face if memory allocation fails later
|
||||||
* in this same lookup...
|
* 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
|
* But that would leave empty slots in the buffer in case of allocation
|
||||||
* failures. Setting to zero for now to avoid other problems (see
|
* failures. See comments in shift_forward(). This can cause O(N^2)
|
||||||
* comments in shift_forward(). This can cause O(N^2) behavior more
|
* behavior more severely than adding 32 empty slots can... */
|
||||||
* severely than adding 32 empty slots can... */
|
if (unlikely (idx < count && !shift_forward (count - idx))) return false;
|
||||||
if (unlikely (idx < count && !shift_forward (count + 0))) return false;
|
|
||||||
|
|
||||||
assert (idx >= count);
|
assert (idx >= count);
|
||||||
|
|
||||||
@ -630,7 +615,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
|
|||||||
HB_BUFFER_CONTENT_TYPE_INVALID,
|
HB_BUFFER_CONTENT_TYPE_INVALID,
|
||||||
HB_SEGMENT_PROPERTIES_DEFAULT,
|
HB_SEGMENT_PROPERTIES_DEFAULT,
|
||||||
false, /* successful */
|
false, /* successful */
|
||||||
true, /* have_output */
|
false, /* have_output */
|
||||||
true /* have_positions */
|
true /* have_positions */
|
||||||
|
|
||||||
/* Zero is good enough for everything else. */
|
/* Zero is good enough for everything else. */
|
||||||
@ -717,14 +702,14 @@ hb_buffer_destroy (hb_buffer_t *buffer)
|
|||||||
|
|
||||||
hb_unicode_funcs_destroy (buffer->unicode);
|
hb_unicode_funcs_destroy (buffer->unicode);
|
||||||
|
|
||||||
free (buffer->info);
|
hb_free (buffer->info);
|
||||||
free (buffer->pos);
|
hb_free (buffer->pos);
|
||||||
#ifndef HB_NO_BUFFER_MESSAGE
|
#ifndef HB_NO_BUFFER_MESSAGE
|
||||||
if (buffer->message_destroy)
|
if (buffer->message_destroy)
|
||||||
buffer->message_destroy (buffer->message_data);
|
buffer->message_destroy (buffer->message_data);
|
||||||
#endif
|
#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
|
* Returns @buffer glyph position array. Returned pointer
|
||||||
* is valid as long as @buffer contents are not modified.
|
* 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):
|
* Return value: (transfer none) (array length=length):
|
||||||
* The @buffer glyph position array.
|
* The @buffer glyph position array.
|
||||||
* The value valid as long as buffer has not been modified.
|
* 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,
|
hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
|
||||||
unsigned int *length)
|
unsigned int *length)
|
||||||
{
|
{
|
||||||
if (!buffer->have_positions)
|
|
||||||
buffer->clear_positions ();
|
|
||||||
|
|
||||||
if (length)
|
if (length)
|
||||||
*length = buffer->len;
|
*length = buffer->len;
|
||||||
|
|
||||||
|
if (!buffer->have_positions)
|
||||||
|
{
|
||||||
|
if (unlikely (buffer->message_depth))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
buffer->clear_positions ();
|
||||||
|
}
|
||||||
|
|
||||||
return (hb_glyph_position_t *) buffer->pos;
|
return (hb_glyph_position_t *) buffer->pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1760,6 +1755,28 @@ hb_buffer_append (hb_buffer_t *buffer,
|
|||||||
memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
|
memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
|
||||||
if (buffer->have_positions)
|
if (buffer->have_positions)
|
||||||
memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
|
memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
|
||||||
|
|
||||||
|
if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE)
|
||||||
|
{
|
||||||
|
/* See similar logic in add_utf. */
|
||||||
|
|
||||||
|
/* pre-context */
|
||||||
|
if (!orig_len && start + source->context_len[0] > 0)
|
||||||
|
{
|
||||||
|
buffer->clear_context (0);
|
||||||
|
while (start > 0 && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
|
||||||
|
buffer->context[0][buffer->context_len[0]++] = source->info[--start].codepoint;
|
||||||
|
for (auto i = 0u; i < source->context_len[0] && buffer->context_len[0] < buffer->CONTEXT_LENGTH; i++)
|
||||||
|
buffer->context[0][buffer->context_len[0]++] = source->context[0][i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* post-context */
|
||||||
|
buffer->clear_context (1);
|
||||||
|
while (end < source->len && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
|
||||||
|
buffer->context[1][buffer->context_len[1]++] = source->info[end++].codepoint;
|
||||||
|
for (auto i = 0u; i < source->context_len[1] && buffer->context_len[1] < buffer->CONTEXT_LENGTH; i++)
|
||||||
|
buffer->context[1][buffer->context_len[1]++] = source->context[1][i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ struct hb_buffer_t
|
|||||||
|
|
||||||
unsigned int idx; /* Cursor into ->info and ->pos arrays */
|
unsigned int idx; /* Cursor into ->info and ->pos arrays */
|
||||||
unsigned int len; /* Length of ->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 */
|
unsigned int allocated; /* Length of allocated arrays */
|
||||||
hb_glyph_info_t *info;
|
hb_glyph_info_t *info;
|
||||||
@ -128,6 +128,9 @@ struct hb_buffer_t
|
|||||||
hb_buffer_message_func_t message_func;
|
hb_buffer_message_func_t message_func;
|
||||||
void *message_data;
|
void *message_data;
|
||||||
hb_destroy_func_t message_destroy;
|
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
|
#endif
|
||||||
|
|
||||||
/* Internal debugging. */
|
/* 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 () { 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_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 reset ();
|
||||||
HB_INTERNAL void clear ();
|
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 lookahead_len () const { return len - idx; }
|
||||||
unsigned int next_serial () { return serial++; }
|
unsigned int next_serial () { return serial++; }
|
||||||
|
|
||||||
@ -206,7 +206,6 @@ struct hb_buffer_t
|
|||||||
HB_INTERNAL void guess_segment_properties ();
|
HB_INTERNAL void guess_segment_properties ();
|
||||||
|
|
||||||
HB_INTERNAL void swap_buffers ();
|
HB_INTERNAL void swap_buffers ();
|
||||||
HB_INTERNAL void remove_output ();
|
|
||||||
HB_INTERNAL void clear_output ();
|
HB_INTERNAL void clear_output ();
|
||||||
HB_INTERNAL void clear_positions ();
|
HB_INTERNAL void clear_positions ();
|
||||||
|
|
||||||
@ -400,10 +399,16 @@ struct hb_buffer_t
|
|||||||
#else
|
#else
|
||||||
if (!messaging ())
|
if (!messaging ())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
message_depth++;
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start (ap, fmt);
|
va_start (ap, fmt);
|
||||||
bool ret = message_impl (font, fmt, ap);
|
bool ret = message_impl (font, fmt, ap);
|
||||||
va_end (ap);
|
va_end (ap);
|
||||||
|
|
||||||
|
message_depth--;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
#include "hb.hh"
|
#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>
|
template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits>
|
||||||
struct hb_cache_t
|
struct hb_cache_t
|
||||||
|
@ -136,7 +136,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
|||||||
if (unlikely (!scalars.resize (region_count)))
|
if (unlikely (!scalars.resize (region_count)))
|
||||||
set_error ();
|
set_error ();
|
||||||
else
|
else
|
||||||
varStore->varStore.get_scalars (get_ivs (), coords, num_coords,
|
varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
|
||||||
&scalars[0], region_count);
|
&scalars[0], region_count);
|
||||||
}
|
}
|
||||||
seen_blend = true;
|
seen_blend = true;
|
||||||
|
@ -257,13 +257,11 @@ struct hb_language_item_t {
|
|||||||
bool operator == (const char *s) const
|
bool operator == (const char *s) const
|
||||||
{ return lang_equal (lang, s); }
|
{ return lang_equal (lang, s); }
|
||||||
|
|
||||||
hb_language_item_t & operator = (const char *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.
|
/* We can't call strdup(), because we allow custom allocators. */
|
||||||
Therefore don't call strdup(), implement its behavior.
|
|
||||||
*/
|
|
||||||
size_t len = strlen(s) + 1;
|
size_t len = strlen(s) + 1;
|
||||||
lang = (hb_language_t) malloc(len);
|
lang = (hb_language_t) hb_malloc(len);
|
||||||
if (likely (lang))
|
if (likely (lang))
|
||||||
{
|
{
|
||||||
memcpy((unsigned char *) lang, s, len);
|
memcpy((unsigned char *) lang, s, len);
|
||||||
@ -274,11 +272,11 @@ struct hb_language_item_t {
|
|||||||
return *this;
|
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;
|
static hb_atomic_ptr_t <hb_language_item_t> langs;
|
||||||
|
|
||||||
@ -294,7 +292,7 @@ retry:
|
|||||||
while (first_lang) {
|
while (first_lang) {
|
||||||
hb_language_item_t *next = first_lang->next;
|
hb_language_item_t *next = first_lang->next;
|
||||||
first_lang->fini ();
|
first_lang->fini ();
|
||||||
free (first_lang);
|
hb_free (first_lang);
|
||||||
first_lang = next;
|
first_lang = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,21 +309,21 @@ retry:
|
|||||||
return lang;
|
return lang;
|
||||||
|
|
||||||
/* Not found; allocate one. */
|
/* 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))
|
if (unlikely (!lang))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
lang->next = first_lang;
|
lang->next = first_lang;
|
||||||
*lang = key;
|
*lang = key;
|
||||||
if (unlikely (!lang->lang))
|
if (unlikely (!lang->lang))
|
||||||
{
|
{
|
||||||
free (lang);
|
hb_free (lang);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely (!langs.cmpexch (first_lang, lang)))
|
if (unlikely (!langs.cmpexch (first_lang, lang)))
|
||||||
{
|
{
|
||||||
lang->fini ();
|
lang->fini ();
|
||||||
free (lang);
|
hb_free (lang);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@
|
|||||||
#define HB_NO_CMAP_LEGACY_SUBTABLES
|
#define HB_NO_CMAP_LEGACY_SUBTABLES
|
||||||
#define HB_NO_FALLBACK_SHAPE
|
#define HB_NO_FALLBACK_SHAPE
|
||||||
#define HB_NO_OT_KERN
|
#define HB_NO_OT_KERN
|
||||||
#define HB_NO_OT_LAYOUT_BLACKLIST
|
#define HB_NO_OT_LAYOUT_BLOCKLIST
|
||||||
#define HB_NO_OT_SHAPE_FALLBACK
|
#define HB_NO_OT_SHAPE_FALLBACK
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -332,6 +332,44 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
|
|||||||
return nullptr;
|
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;
|
return (hb_coretext_font_data_t *) ct_font;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1061,7 +1099,7 @@ resize_and_retry:
|
|||||||
hb_glyph_info_t *info = run_info;
|
hb_glyph_info_t *info = run_info;
|
||||||
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
|
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++)
|
for (unsigned int j = 0; j < num_glyphs; j++)
|
||||||
{
|
{
|
||||||
CGFloat advance;
|
CGFloat advance;
|
||||||
@ -1069,15 +1107,15 @@ resize_and_retry:
|
|||||||
advance = positions[j + 1].x - positions[j].x;
|
advance = positions[j + 1].x - positions[j].x;
|
||||||
else /* last glyph */
|
else /* last glyph */
|
||||||
advance = run_advance - (positions[j].x - positions[0].x);
|
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->var1.i32 = x_offset;
|
||||||
info->var2.i32 = positions[j].y * y_mult;
|
info->var2.i32 = round (positions[j].y * y_mult);
|
||||||
info++;
|
info++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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++)
|
for (unsigned int j = 0; j < num_glyphs; j++)
|
||||||
{
|
{
|
||||||
CGFloat advance;
|
CGFloat advance;
|
||||||
@ -1085,8 +1123,8 @@ resize_and_retry:
|
|||||||
advance = positions[j + 1].y - positions[j].y;
|
advance = positions[j + 1].y - positions[j].y;
|
||||||
else /* last glyph */
|
else /* last glyph */
|
||||||
advance = run_advance - (positions[j].y - positions[0].y);
|
advance = run_advance - (positions[j].y - positions[0].y);
|
||||||
info->mask = advance * y_mult;
|
info->mask = round (advance * y_mult);
|
||||||
info->var1.i32 = positions[j].x * x_mult;
|
info->var1.i32 = round (positions[j].x * x_mult);
|
||||||
info->var2.i32 = y_offset;
|
info->var2.i32 = y_offset;
|
||||||
info++;
|
info++;
|
||||||
}
|
}
|
||||||
|
@ -307,7 +307,7 @@ struct hb_auto_trace_t
|
|||||||
|
|
||||||
_hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
|
_hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
|
||||||
"return %s (line %d)",
|
"return %s (line %d)",
|
||||||
hb_printer_t<decltype (v)>().print (v), line);
|
hb_printer_t<hb_decay<decltype (v)>>().print (v), line);
|
||||||
if (plevel) --*plevel;
|
if (plevel) --*plevel;
|
||||||
plevel = nullptr;
|
plevel = nullptr;
|
||||||
returned = true;
|
returned = true;
|
||||||
|
@ -107,9 +107,6 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
|
|||||||
hb_font_get_glyph_func_t func,
|
hb_font_get_glyph_func_t func,
|
||||||
void *user_data, hb_destroy_func_t destroy);
|
void *user_data, hb_destroy_func_t destroy);
|
||||||
|
|
||||||
HB_EXTERN HB_DEPRECATED void
|
|
||||||
hb_set_invert (hb_set_t *set);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hb_unicode_eastasian_width_func_t:
|
* hb_unicode_eastasian_width_func_t:
|
||||||
* @ufuncs: A Unicode-functions structure
|
* @ufuncs: A Unicode-functions structure
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include "hb-directwrite.h"
|
#include "hb-directwrite.h"
|
||||||
|
|
||||||
|
#include "hb-ms-feature-ranges.hh"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION:hb-directwrite
|
* SECTION:hb-directwrite
|
||||||
@ -42,24 +43,6 @@
|
|||||||
* Functions for using HarfBuzz with DirectWrite fonts.
|
* 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
|
* DirectWrite font stream helpers
|
||||||
*/
|
*/
|
||||||
@ -154,7 +137,6 @@ public:
|
|||||||
|
|
||||||
struct hb_directwrite_face_data_t
|
struct hb_directwrite_face_data_t
|
||||||
{
|
{
|
||||||
HMODULE dwrite_dll;
|
|
||||||
IDWriteFactory *dwriteFactory;
|
IDWriteFactory *dwriteFactory;
|
||||||
IDWriteFontFile *fontFile;
|
IDWriteFontFile *fontFile;
|
||||||
DWriteFontFileStream *fontFileStream;
|
DWriteFontFileStream *fontFileStream;
|
||||||
@ -176,32 +158,11 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
|
|||||||
return nullptr; \
|
return nullptr; \
|
||||||
} HB_STMT_END
|
} 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;
|
HRESULT hr;
|
||||||
|
|
||||||
// TODO: factory and fontFileLoader should be cached separately
|
// TODO: factory and fontFileLoader should be cached separately
|
||||||
IDWriteFactory* dwriteFactory;
|
IDWriteFactory* dwriteFactory;
|
||||||
hr = p_DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
|
hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
|
||||||
(IUnknown**) &dwriteFactory);
|
(IUnknown**) &dwriteFactory);
|
||||||
|
|
||||||
if (unlikely (hr != S_OK))
|
if (unlikely (hr != S_OK))
|
||||||
@ -266,8 +227,6 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
|
|||||||
delete data->fontFileStream;
|
delete data->fontFileStream;
|
||||||
if (data->faceBlob)
|
if (data->faceBlob)
|
||||||
hb_blob_destroy (data->faceBlob);
|
hb_blob_destroy (data->faceBlob);
|
||||||
if (data->dwrite_dll)
|
|
||||||
FreeLibrary (data->dwrite_dll);
|
|
||||||
if (data)
|
if (data)
|
||||||
delete data;
|
delete data;
|
||||||
}
|
}
|
||||||
@ -552,13 +511,12 @@ protected:
|
|||||||
* shaper
|
* shaper
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static hb_bool_t
|
hb_bool_t
|
||||||
_hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
|
_hb_directwrite_shape (hb_shape_plan_t *shape_plan,
|
||||||
hb_font_t *font,
|
hb_font_t *font,
|
||||||
hb_buffer_t *buffer,
|
hb_buffer_t *buffer,
|
||||||
const hb_feature_t *features,
|
const hb_feature_t *features,
|
||||||
unsigned int num_features,
|
unsigned int num_features)
|
||||||
float lineWidth)
|
|
||||||
{
|
{
|
||||||
hb_face_t *face = font->face;
|
hb_face_t *face = font->face;
|
||||||
const hb_directwrite_face_data_t *face_data = face->data.directwrite;
|
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. */
|
log_clusters[chars_len++] = cluster; /* Surrogates. */
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
|
|
||||||
|
|
||||||
DWRITE_READING_DIRECTION readingDirection;
|
DWRITE_READING_DIRECTION readingDirection;
|
||||||
readingDirection = buffer->props.direction ?
|
readingDirection = buffer->props.direction ?
|
||||||
DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
|
DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
|
||||||
@ -648,38 +604,54 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
|
|||||||
mbstowcs ((wchar_t*) localeName,
|
mbstowcs ((wchar_t*) localeName,
|
||||||
hb_language_to_string (buffer->props.language), 20);
|
hb_language_to_string (buffer->props.language), 20);
|
||||||
|
|
||||||
// TODO: it does work but doesn't care about ranges
|
/*
|
||||||
DWRITE_TYPOGRAPHIC_FEATURES typographic_features;
|
* Set up features.
|
||||||
typographic_features.featureCount = num_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)
|
if (num_features)
|
||||||
{
|
{
|
||||||
typographic_features.features = new DWRITE_FONT_FEATURE[num_features];
|
hb_vector_t<hb_ms_feature_t> feature_records;
|
||||||
for (unsigned int i = 0; i < num_features; ++i)
|
hb_vector_t<hb_ms_range_record_t> range_records;
|
||||||
{
|
if (hb_ms_setup_features (features, num_features, feature_records, range_records))
|
||||||
typographic_features.features[i].nameTag = (DWRITE_FONT_FEATURE_TAG)
|
hb_ms_make_feature_ranges (feature_records,
|
||||||
hb_uint32_swap (features[i].tag);
|
range_records,
|
||||||
typographic_features.features[i].parameter = features[i].value;
|
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;
|
uint16_t* clusterMap;
|
||||||
clusterMap = new uint16_t[textLength];
|
clusterMap = new uint16_t[textLength];
|
||||||
DWRITE_SHAPING_TEXT_PROPERTIES* textProperties;
|
DWRITE_SHAPING_TEXT_PROPERTIES* textProperties;
|
||||||
textProperties = new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
|
textProperties = new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
|
||||||
|
|
||||||
retry_getglyphs:
|
retry_getglyphs:
|
||||||
uint16_t* glyphIndices = new uint16_t[maxGlyphCount];
|
uint16_t* glyphIndices = new uint16_t[maxGlyphCount];
|
||||||
DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties;
|
DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties;
|
||||||
glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
|
glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
|
||||||
|
|
||||||
hr = analyzer->GetGlyphs (textString, textLength, fontFace, false,
|
hr = analyzer->GetGlyphs (textString,
|
||||||
isRightToLeft, &runHead->mScript, localeName,
|
chars_len,
|
||||||
nullptr, &dwFeatures, featureRangeLengths, 1,
|
fontFace,
|
||||||
maxGlyphCount, clusterMap, textProperties,
|
false,
|
||||||
glyphIndices, glyphProperties, &glyphCount);
|
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)))
|
if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
|
||||||
{
|
{
|
||||||
@ -715,101 +687,28 @@ retry_getglyphs:
|
|||||||
double x_mult = (double) font->x_scale / fontEmSize;
|
double x_mult = (double) font->x_scale / fontEmSize;
|
||||||
double y_mult = (double) font->y_scale / fontEmSize;
|
double y_mult = (double) font->y_scale / fontEmSize;
|
||||||
|
|
||||||
hr = analyzer->GetGlyphPlacements (textString, clusterMap, textProperties,
|
hr = analyzer->GetGlyphPlacements (textString,
|
||||||
textLength, glyphIndices, glyphProperties,
|
clusterMap,
|
||||||
glyphCount, fontFace, fontEmSize,
|
textProperties,
|
||||||
false, isRightToLeft, &runHead->mScript, localeName,
|
chars_len,
|
||||||
&dwFeatures, featureRangeLengths, 1,
|
glyphIndices,
|
||||||
glyphAdvances, glyphOffsets);
|
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))
|
if (FAILED (hr))
|
||||||
FAIL ("Analyzer failed to get glyph placements.");
|
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,
|
/* Ok, we've got everything we need, now compose output buffer,
|
||||||
* very, *very*, carefully! */
|
* very, *very*, carefully! */
|
||||||
|
|
||||||
@ -870,43 +769,10 @@ retry_getglyphs:
|
|||||||
delete [] glyphAdvances;
|
delete [] glyphAdvances;
|
||||||
delete [] glyphOffsets;
|
delete [] glyphOffsets;
|
||||||
|
|
||||||
if (num_features)
|
|
||||||
delete [] typographic_features.features;
|
|
||||||
|
|
||||||
/* Wow, done! */
|
/* Wow, done! */
|
||||||
return true;
|
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 {
|
struct _hb_directwrite_font_table_context {
|
||||||
IDWriteFontFace *face;
|
IDWriteFontFace *face;
|
||||||
void *table_context;
|
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;
|
_hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) data;
|
||||||
context->face->ReleaseFontTable (context->table_context);
|
context->face->ReleaseFontTable (context->table_context);
|
||||||
delete context;
|
hb_free (context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static hb_blob_t *
|
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;
|
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->face = dw_face;
|
||||||
context->table_context = table_context;
|
context->table_context = table_context;
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ hb_draw_funcs_destroy (hb_draw_funcs_t *funcs)
|
|||||||
{
|
{
|
||||||
if (!hb_object_destroy (funcs)) return;
|
if (!hb_object_destroy (funcs)) return;
|
||||||
|
|
||||||
free (funcs);
|
hb_free (funcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "hb-open-file.hh"
|
#include "hb-open-file.hh"
|
||||||
#include "hb-ot-face.hh"
|
#include "hb-ot-face.hh"
|
||||||
#include "hb-ot-cmap-table.hh"
|
#include "hb-ot-cmap-table.hh"
|
||||||
|
#include "hb-map.hh"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -150,7 +151,7 @@ _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
|
|||||||
{
|
{
|
||||||
hb_face_for_data_closure_t *closure;
|
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))
|
if (unlikely (!closure))
|
||||||
return nullptr;
|
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_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data;
|
||||||
|
|
||||||
hb_blob_destroy (closure->blob);
|
hb_blob_destroy (closure->blob);
|
||||||
free (closure);
|
hb_free (closure);
|
||||||
}
|
}
|
||||||
|
|
||||||
static hb_blob_t *
|
static hb_blob_t *
|
||||||
@ -281,7 +282,7 @@ hb_face_destroy (hb_face_t *face)
|
|||||||
{
|
{
|
||||||
hb_face_t::plan_node_t *next = node->next;
|
hb_face_t::plan_node_t *next = node->next;
|
||||||
hb_shape_plan_destroy (node->shape_plan);
|
hb_shape_plan_destroy (node->shape_plan);
|
||||||
free (node);
|
hb_free (node);
|
||||||
node = next;
|
node = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +292,7 @@ hb_face_destroy (hb_face_t *face)
|
|||||||
if (face->destroy)
|
if (face->destroy)
|
||||||
face->destroy (face->user_data);
|
face->destroy (face->user_data);
|
||||||
|
|
||||||
free (face);
|
hb_free (face);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -623,26 +624,26 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
|
|||||||
|
|
||||||
struct hb_face_builder_data_t
|
struct hb_face_builder_data_t
|
||||||
{
|
{
|
||||||
struct table_entry_t
|
hb_hashmap_t<hb_tag_t, hb_blob_t *> tables;
|
||||||
{
|
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 *
|
static hb_face_builder_data_t *
|
||||||
_hb_face_builder_data_create ()
|
_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))
|
if (unlikely (!data))
|
||||||
return nullptr;
|
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;
|
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < data->tables.length; i++)
|
for (hb_blob_t* b : data->tables.values())
|
||||||
hb_blob_destroy (data->tables[i].blob);
|
hb_blob_destroy (b);
|
||||||
|
|
||||||
data->tables.fini ();
|
data->tables.fini ();
|
||||||
|
|
||||||
free (data);
|
hb_free (data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static hb_blob_t *
|
static hb_blob_t *
|
||||||
_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
|
_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;
|
unsigned int face_length = table_count * 16 + 12;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < table_count; i++)
|
for (hb_blob_t* b : data->tables.values())
|
||||||
face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob));
|
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))
|
if (unlikely (!buf))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@ -682,20 +683,31 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
|
|||||||
c.propagate_error (data->tables);
|
c.propagate_error (data->tables);
|
||||||
OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
|
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;
|
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 ();
|
c.end_serialize ();
|
||||||
|
|
||||||
if (unlikely (!ret))
|
if (unlikely (!ret))
|
||||||
{
|
{
|
||||||
free (buf);
|
hb_free (buf);
|
||||||
return nullptr;
|
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 *
|
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)
|
if (!tag)
|
||||||
return _hb_face_builder_data_reference_blob (data);
|
return _hb_face_builder_data_reference_blob (data);
|
||||||
|
|
||||||
hb_face_builder_data_t::table_entry_t *entry = data->tables.lsearch (tag);
|
return hb_blob_reference (data->tables[tag]);
|
||||||
if (entry)
|
|
||||||
return hb_blob_reference (entry->blob);
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -750,17 +758,21 @@ hb_face_builder_create ()
|
|||||||
hb_bool_t
|
hb_bool_t
|
||||||
hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
|
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))
|
if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
|
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 ();
|
hb_blob_t* previous = data->tables.get (tag);
|
||||||
if (unlikely (data->tables.in_error()))
|
if (!data->tables.set (tag, hb_blob_reference (blob)))
|
||||||
|
{
|
||||||
|
hb_blob_destroy (blob);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
entry->tag = tag;
|
hb_blob_destroy (previous);
|
||||||
entry->blob = hb_blob_reference (blob);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -620,7 +620,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
|
|||||||
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
|
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
|
||||||
#undef HB_FONT_FUNC_IMPLEMENT
|
#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,
|
float *design_coords,
|
||||||
unsigned int coords_length)
|
unsigned int coords_length)
|
||||||
{
|
{
|
||||||
free (font->coords);
|
hb_free (font->coords);
|
||||||
free (font->design_coords);
|
hb_free (font->design_coords);
|
||||||
|
|
||||||
font->coords = coords;
|
font->coords = coords;
|
||||||
font->design_coords = design_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;
|
unsigned int num_coords = parent->num_coords;
|
||||||
if (num_coords)
|
if (num_coords)
|
||||||
{
|
{
|
||||||
int *coords = (int *) calloc (num_coords, sizeof (parent->coords[0]));
|
int *coords = (int *) hb_calloc (num_coords, sizeof (parent->coords[0]));
|
||||||
float *design_coords = (float *) calloc (num_coords, sizeof (parent->design_coords[0]));
|
float *design_coords = (float *) hb_calloc (num_coords, sizeof (parent->design_coords[0]));
|
||||||
if (likely (coords && design_coords))
|
if (likely (coords && design_coords))
|
||||||
{
|
{
|
||||||
memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0]));
|
memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0]));
|
||||||
@ -1596,8 +1596,8 @@ hb_font_create_sub_font (hb_font_t *parent)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
free (coords);
|
hb_free (coords);
|
||||||
free (design_coords);
|
hb_free (design_coords);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1659,10 +1659,10 @@ hb_font_destroy (hb_font_t *font)
|
|||||||
hb_face_destroy (font->face);
|
hb_face_destroy (font->face);
|
||||||
hb_font_funcs_destroy (font->klass);
|
hb_font_funcs_destroy (font->klass);
|
||||||
|
|
||||||
free (font->coords);
|
hb_free (font->coords);
|
||||||
free (font->design_coords);
|
hb_free (font->design_coords);
|
||||||
|
|
||||||
free (font);
|
hb_free (font);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2052,28 +2052,29 @@ hb_font_set_variations (hb_font_t *font,
|
|||||||
return;
|
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;
|
int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr;
|
||||||
float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
|
float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
|
||||||
|
|
||||||
if (unlikely (coords_length && !(normalized && design_coords)))
|
if (unlikely (coords_length && !(normalized && design_coords)))
|
||||||
{
|
{
|
||||||
free (normalized);
|
hb_free (normalized);
|
||||||
free (design_coords);
|
hb_free (design_coords);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const OT::fvar &fvar = *font->face->table.fvar;
|
|
||||||
for (unsigned int i = 0; i < variations_length; i++)
|
for (unsigned int i = 0; i < variations_length; i++)
|
||||||
{
|
{
|
||||||
hb_ot_var_axis_info_t info;
|
const auto tag = variations[i].tag;
|
||||||
if (hb_ot_var_find_axis_info (font->face, variations[i].tag, &info) &&
|
const auto v = variations[i].value;
|
||||||
info.axis_index < coords_length)
|
for (unsigned axis_index = 0; axis_index < coords_length; axis_index++)
|
||||||
|
if (axes[axis_index].axisTag == tag)
|
||||||
{
|
{
|
||||||
float v = variations[i].value;
|
design_coords[axis_index] = v;
|
||||||
design_coords[info.axis_index] = v;
|
normalized[axis_index] = fvar.normalize_axis_value (axis_index, v);
|
||||||
normalized[info.axis_index] = fvar.normalize_axis_value (info.axis_index, v);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
font->face->table.avar->map_coords (normalized, coords_length);
|
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))
|
if (hb_object_is_immutable (font))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
|
int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr;
|
||||||
float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
|
float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
|
||||||
|
|
||||||
if (unlikely (coords_length && !(normalized && design_coords)))
|
if (unlikely (coords_length && !(normalized && design_coords)))
|
||||||
{
|
{
|
||||||
free (normalized);
|
hb_free (normalized);
|
||||||
free (design_coords);
|
hb_free (design_coords);
|
||||||
return;
|
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);
|
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))
|
if (unlikely (coords_length && !coords))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hb_ot_var_named_instance_get_design_coords (font->face, instance_index, &coords_length, coords);
|
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);
|
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))
|
if (hb_object_is_immutable (font))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr;
|
int *copy = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr;
|
||||||
int *unmapped = coords_length ? (int *) 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 *) calloc (coords_length, sizeof (design_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)))
|
if (unlikely (coords_length && !(copy && unmapped && design_coords)))
|
||||||
{
|
{
|
||||||
free (copy);
|
hb_free (copy);
|
||||||
free (unmapped);
|
hb_free (unmapped);
|
||||||
free (design_coords);
|
hb_free (design_coords);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2187,7 +2188,7 @@ hb_font_set_var_coords_normalized (hb_font_t *font,
|
|||||||
font->face->table.avar->unmap_coords (unmapped, coords_length);
|
font->face->table.avar->unmap_coords (unmapped, coords_length);
|
||||||
for (unsigned int i = 0; i < coords_length; ++i)
|
for (unsigned int i = 0; i < coords_length; ++i)
|
||||||
design_coords[i] = font->face->table.fvar->unnormalize_axis_value (i, unmapped[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);
|
_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;
|
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))
|
if (unlikely (!trampoline))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -2296,7 +2297,7 @@ trampoline_destroy (void *user_data)
|
|||||||
|
|
||||||
if (closure->destroy)
|
if (closure->destroy)
|
||||||
closure->destroy (closure->user_data);
|
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;
|
typedef hb_trampoline_t<hb_font_get_glyph_func_t> hb_font_get_glyph_trampoline_t;
|
||||||
|
@ -91,7 +91,7 @@ struct hb_ft_font_t
|
|||||||
static hb_ft_font_t *
|
static hb_ft_font_t *
|
||||||
_hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
|
_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;
|
if (unlikely (!ft_font)) return nullptr;
|
||||||
|
|
||||||
ft_font->lock.init ();
|
ft_font->lock.init ();
|
||||||
@ -125,7 +125,7 @@ _hb_ft_font_destroy (void *data)
|
|||||||
|
|
||||||
ft_font->lock.fini ();
|
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)
|
if (error)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
buffer = (FT_Byte *) malloc (length);
|
buffer = (FT_Byte *) hb_malloc (length);
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
|
error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
free (buffer);
|
hb_free (buffer);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hb_blob_create ((const char *) buffer, length,
|
return hb_blob_create ((const char *) buffer, length,
|
||||||
HB_MEMORY_MODE_WRITABLE,
|
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;
|
FT_MM_Var *mm_var = nullptr;
|
||||||
if (!FT_Get_MM_Var (ft_face, &mm_var))
|
if (!FT_Get_MM_Var (ft_face, &mm_var))
|
||||||
{
|
{
|
||||||
FT_Fixed *ft_coords = (FT_Fixed *) calloc (mm_var->num_axis, sizeof (FT_Fixed));
|
FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (mm_var->num_axis, sizeof (FT_Fixed));
|
||||||
int *coords = (int *) calloc (mm_var->num_axis, sizeof (int));
|
int *coords = (int *) hb_calloc (mm_var->num_axis, sizeof (int));
|
||||||
if (coords && ft_coords)
|
if (coords && ft_coords)
|
||||||
{
|
{
|
||||||
if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, 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);
|
hb_font_set_var_coords_normalized (font, nullptr, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free (coords);
|
hb_free (coords);
|
||||||
free (ft_coords);
|
hb_free (ft_coords);
|
||||||
#ifdef HAVE_FT_DONE_MM_VAR
|
#ifdef HAVE_FT_DONE_MM_VAR
|
||||||
FT_Done_MM_Var (ft_face->glyph->library, mm_var);
|
FT_Done_MM_Var (ft_face->glyph->library, mm_var);
|
||||||
#else
|
#else
|
||||||
free (mm_var);
|
hb_free (mm_var);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#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);
|
const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
|
||||||
if (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)
|
if (ft_coords)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < num_coords; i++)
|
for (unsigned int i = 0; i < num_coords; i++)
|
||||||
ft_coords[i] = coords[i] * 4;
|
ft_coords[i] = coords[i] * 4;
|
||||||
FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
|
FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
|
||||||
free (ft_coords);
|
hb_free (ft_coords);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -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);
|
length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length);
|
||||||
if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc;
|
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;
|
if (unlikely (!buffer)) goto fail_with_releasedc;
|
||||||
length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length);
|
length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length);
|
||||||
if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc_and_free;
|
if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc_and_free;
|
||||||
ReleaseDC (nullptr, hdc);
|
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:
|
fail_with_releasedc_and_free:
|
||||||
free (buffer);
|
hb_free (buffer);
|
||||||
fail_with_releasedc:
|
fail_with_releasedc:
|
||||||
ReleaseDC (nullptr, hdc);
|
ReleaseDC (nullptr, hdc);
|
||||||
fail:
|
fail:
|
||||||
|
@ -80,12 +80,12 @@ hb_gobject_##name##_get_type () \
|
|||||||
#define HB_DEFINE_VALUE_TYPE(name) \
|
#define HB_DEFINE_VALUE_TYPE(name) \
|
||||||
static hb_##name##_t *_hb_##name##_reference (const hb_##name##_t *l) \
|
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; \
|
if (unlikely (!c)) return nullptr; \
|
||||||
*c = *l; \
|
*c = *l; \
|
||||||
return c; \
|
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_BOXED_TYPE (name, _hb_##name##_reference, _hb_##name##_destroy)
|
||||||
|
|
||||||
HB_DEFINE_OBJECT_TYPE (buffer)
|
HB_DEFINE_OBJECT_TYPE (buffer)
|
||||||
|
@ -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);
|
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)) {
|
if (unlikely (!p)) {
|
||||||
hb_blob_destroy (blob);
|
hb_blob_destroy (blob);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -123,15 +123,16 @@ _hb_graphite2_shaper_face_data_create (hb_face_t *face)
|
|||||||
}
|
}
|
||||||
hb_blob_destroy (silf_blob);
|
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))
|
if (unlikely (!data))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
data->face = face;
|
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)) {
|
if (unlikely (!data->grface)) {
|
||||||
free (data);
|
hb_free (data);
|
||||||
return nullptr;
|
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_graphite2_tablelist_t *old = tlist;
|
||||||
hb_blob_destroy (tlist->blob);
|
hb_blob_destroy (tlist->blob);
|
||||||
tlist = tlist->next;
|
tlist = tlist->next;
|
||||||
free (old);
|
hb_free (old);
|
||||||
}
|
}
|
||||||
|
|
||||||
gr_face_destroy (data->grface);
|
gr_face_destroy (data->grface);
|
||||||
|
|
||||||
free (data);
|
hb_free (data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
* TODO Document more.
|
* TODO Document more.
|
||||||
*
|
*
|
||||||
* If iterator implementation implements operator!=, then can be
|
* 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
|
* is random-access. Otherwise, the range-based for loop incurs
|
||||||
* one traversal to find end(), which can be avoided if written
|
* one traversal to find end(), which can be avoided if written
|
||||||
* as a while-style for loop, or if iterator implements a faster
|
* as a while-style for loop, or if iterator implements a faster
|
||||||
|
@ -242,14 +242,14 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
|
|||||||
static const Stored* get_null () { return &Null (Stored); }
|
static const Stored* get_null () { return &Null (Stored); }
|
||||||
static Stored *create (Data *data)
|
static Stored *create (Data *data)
|
||||||
{
|
{
|
||||||
Stored *p = (Stored *) calloc (1, sizeof (Stored));
|
Stored *p = (Stored *) hb_calloc (1, sizeof (Stored));
|
||||||
if (likely (p))
|
if (likely (p))
|
||||||
p->init (data);
|
p->init (data);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
static Stored *create ()
|
static Stored *create ()
|
||||||
{
|
{
|
||||||
Stored *p = (Stored *) calloc (1, sizeof (Stored));
|
Stored *p = (Stored *) hb_calloc (1, sizeof (Stored));
|
||||||
if (likely (p))
|
if (likely (p))
|
||||||
p->init ();
|
p->init ();
|
||||||
return p;
|
return p;
|
||||||
@ -257,7 +257,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
|
|||||||
static void destroy (Stored *p)
|
static void destroy (Stored *p)
|
||||||
{
|
{
|
||||||
p->fini ();
|
p->fini ();
|
||||||
free (p);
|
hb_free (p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// private:
|
// private:
|
||||||
|
@ -109,7 +109,7 @@ hb_map_destroy (hb_map_t *map)
|
|||||||
|
|
||||||
map->fini_shallow ();
|
map->fini_shallow ();
|
||||||
|
|
||||||
free (map);
|
hb_free (map);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -188,6 +188,7 @@ hb_map_set (hb_map_t *map,
|
|||||||
hb_codepoint_t key,
|
hb_codepoint_t key,
|
||||||
hb_codepoint_t value)
|
hb_codepoint_t value)
|
||||||
{
|
{
|
||||||
|
/* Immutable-safe. */
|
||||||
map->set (key, value);
|
map->set (key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,6 +221,7 @@ void
|
|||||||
hb_map_del (hb_map_t *map,
|
hb_map_del (hb_map_t *map,
|
||||||
hb_codepoint_t key)
|
hb_codepoint_t key)
|
||||||
{
|
{
|
||||||
|
/* Immutable-safe. */
|
||||||
map->del (key);
|
map->del (key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,9 +255,6 @@ hb_map_has (const hb_map_t *map,
|
|||||||
void
|
void
|
||||||
hb_map_clear (hb_map_t *map)
|
hb_map_clear (hb_map_t *map)
|
||||||
{
|
{
|
||||||
if (unlikely (hb_object_is_immutable (map)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
return map->clear ();
|
return map->clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ struct hb_hashmap_t
|
|||||||
}
|
}
|
||||||
void fini_shallow ()
|
void fini_shallow ()
|
||||||
{
|
{
|
||||||
free (items);
|
hb_free (items);
|
||||||
items = nullptr;
|
items = nullptr;
|
||||||
population = occupancy = 0;
|
population = occupancy = 0;
|
||||||
}
|
}
|
||||||
@ -109,7 +109,7 @@ struct hb_hashmap_t
|
|||||||
|
|
||||||
unsigned int power = hb_bit_storage (population * 2 + 8);
|
unsigned int power = hb_bit_storage (population * 2 + 8);
|
||||||
unsigned int new_size = 1u << power;
|
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))
|
if (unlikely (!new_items))
|
||||||
{
|
{
|
||||||
successful = false;
|
successful = false;
|
||||||
@ -135,7 +135,7 @@ struct hb_hashmap_t
|
|||||||
old_items[i].hash,
|
old_items[i].hash,
|
||||||
old_items[i].value);
|
old_items[i].value);
|
||||||
|
|
||||||
free (old_items);
|
hb_free (old_items);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -169,6 +169,8 @@ struct hb_hashmap_t
|
|||||||
|
|
||||||
void clear ()
|
void clear ()
|
||||||
{
|
{
|
||||||
|
if (unlikely (!successful)) return;
|
||||||
|
|
||||||
if (items)
|
if (items)
|
||||||
for (auto &_ : hb_iter (items, mask + 1))
|
for (auto &_ : hb_iter (items, mask + 1))
|
||||||
_.clear ();
|
_.clear ();
|
||||||
@ -224,7 +226,7 @@ struct hb_hashmap_t
|
|||||||
if (!items[i].is_unused ())
|
if (!items[i].is_unused ())
|
||||||
{
|
{
|
||||||
occupancy--;
|
occupancy--;
|
||||||
if (items[i].is_tombstone ())
|
if (!items[i].is_tombstone ())
|
||||||
population--;
|
population--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,14 +101,14 @@ HB_FUNCOBJ (hb_addressof);
|
|||||||
template <typename T> static inline T hb_declval ();
|
template <typename T> static inline T hb_declval ();
|
||||||
#define hb_declval(T) (hb_declval<T> ())
|
#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 : hb_type_identity_t<T>, hb_false_type {};
|
||||||
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<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_remove_const = typename hb_match_const<T>::type;
|
||||||
template <typename T> using hb_add_const = const T;
|
template <typename T> using hb_add_const = const T;
|
||||||
#define hb_is_const(T) hb_match_const<T>::value
|
#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 : hb_type_identity_t<T>, hb_false_type {};
|
||||||
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_true_type {};
|
||||||
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_true_type {};
|
||||||
template <typename T> using hb_remove_reference = typename hb_match_reference<T>::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<1>) -> hb_type_identity<T&>;
|
||||||
template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<0>) -> 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> 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));
|
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
|
#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 : hb_type_identity_t<T>, hb_false_type {};
|
||||||
template <typename T> struct hb_match_pointer<T *> : hb_type_identity_t<T>, hb_bool_constant<true> {};
|
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> 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<hb_remove_reference<T>*>;
|
||||||
template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<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
|
#define hb_is_arithmetic(T) hb_is_arithmetic<T>::value
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T, bool is_arithmetic> struct hb_is_signed_;
|
||||||
using hb_is_signed = hb_conditional<hb_is_arithmetic (T),
|
template <typename T> struct hb_is_signed_<T, false> : hb_false_type {};
|
||||||
hb_bool_constant<(T) -1 < (T) 0>,
|
template <typename T> struct hb_is_signed_<T, true> : hb_bool_constant<(T) -1 < (T) 0> {};
|
||||||
hb_false_type>;
|
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
|
#define hb_is_signed(T) hb_is_signed<T>::value
|
||||||
template <typename T>
|
template <typename T, bool is_arithmetic> struct hb_is_unsigned_;
|
||||||
using hb_is_unsigned = hb_conditional<hb_is_arithmetic (T),
|
template <typename T> struct hb_is_unsigned_<T, false> : hb_false_type {};
|
||||||
hb_bool_constant<(T) 0 < (T) -1>,
|
template <typename T> struct hb_is_unsigned_<T, true> : hb_bool_constant<(T) 0 < (T) -1> {};
|
||||||
hb_false_type>;
|
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
|
#define hb_is_unsigned(T) hb_is_unsigned<T>::value
|
||||||
|
|
||||||
template <typename T> struct hb_int_min;
|
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<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<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 <> 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
|
#define hb_int_min(T) hb_int_min<T>::value
|
||||||
template <typename T> struct hb_int_max;
|
template <typename T> struct hb_int_max;
|
||||||
template <> struct hb_int_max<char> : hb_integral_constant<char, CHAR_MAX> {};
|
template <> struct hb_int_max<char> : hb_integral_constant<char, CHAR_MAX> {};
|
||||||
|
177
gfx/harfbuzz/src/hb-ms-feature-ranges.cc
Normal file
177
gfx/harfbuzz/src/hb-ms-feature-ranges.cc
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2011,2012,2013 Google, Inc.
|
||||||
|
* Copyright © 2021 Khaled Hosny
|
||||||
|
*
|
||||||
|
* This is part of HarfBuzz, a text shaping library.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, without written agreement and without
|
||||||
|
* license or royalty fees, to use, copy, modify, and distribute this
|
||||||
|
* software and its documentation for any purpose, provided that the
|
||||||
|
* above copyright notice and the following two paragraphs appear in
|
||||||
|
* all copies of this software.
|
||||||
|
*
|
||||||
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||||
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||||
|
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
* DAMAGE.
|
||||||
|
*
|
||||||
|
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||||
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||||
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
|
*
|
||||||
|
* Google Author(s): Behdad Esfahbod
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hb-ms-feature-ranges.hh"
|
||||||
|
|
||||||
|
bool
|
||||||
|
hb_ms_setup_features (const hb_feature_t *features,
|
||||||
|
unsigned int num_features,
|
||||||
|
hb_vector_t<hb_ms_feature_t> &feature_records, /* OUT */
|
||||||
|
hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */)
|
||||||
|
{
|
||||||
|
feature_records.shrink(0);
|
||||||
|
range_records.shrink(0);
|
||||||
|
|
||||||
|
/* Sort features by start/end events. */
|
||||||
|
hb_vector_t<hb_ms_feature_event_t> feature_events;
|
||||||
|
for (unsigned int i = 0; i < num_features; i++)
|
||||||
|
{
|
||||||
|
hb_ms_active_feature_t feature;
|
||||||
|
feature.fea.tag_le = hb_uint32_swap (features[i].tag);
|
||||||
|
feature.fea.value = features[i].value;
|
||||||
|
feature.order = i;
|
||||||
|
|
||||||
|
hb_ms_feature_event_t *event;
|
||||||
|
|
||||||
|
event = feature_events.push ();
|
||||||
|
event->index = features[i].start;
|
||||||
|
event->start = true;
|
||||||
|
event->feature = feature;
|
||||||
|
|
||||||
|
event = feature_events.push ();
|
||||||
|
event->index = features[i].end;
|
||||||
|
event->start = false;
|
||||||
|
event->feature = feature;
|
||||||
|
}
|
||||||
|
feature_events.qsort ();
|
||||||
|
/* Add a strategic final event. */
|
||||||
|
{
|
||||||
|
hb_ms_active_feature_t feature;
|
||||||
|
feature.fea.tag_le = 0;
|
||||||
|
feature.fea.value = 0;
|
||||||
|
feature.order = num_features + 1;
|
||||||
|
|
||||||
|
auto *event = feature_events.push ();
|
||||||
|
event->index = 0; /* This value does magic. */
|
||||||
|
event->start = false;
|
||||||
|
event->feature = feature;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scan events and save features for each range. */
|
||||||
|
hb_vector_t<hb_ms_active_feature_t> active_features;
|
||||||
|
unsigned int last_index = 0;
|
||||||
|
for (unsigned int i = 0; i < feature_events.length; i++)
|
||||||
|
{
|
||||||
|
auto *event = &feature_events[i];
|
||||||
|
|
||||||
|
if (event->index != last_index)
|
||||||
|
{
|
||||||
|
/* Save a snapshot of active features and the range. */
|
||||||
|
auto *range = range_records.push ();
|
||||||
|
auto offset = feature_records.length;
|
||||||
|
|
||||||
|
active_features.qsort ();
|
||||||
|
for (unsigned int j = 0; j < active_features.length; j++)
|
||||||
|
{
|
||||||
|
if (!j || active_features[j].fea.tag_le != feature_records[feature_records.length - 1].tag_le)
|
||||||
|
{
|
||||||
|
feature_records.push (active_features[j].fea);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Overrides value for existing feature. */
|
||||||
|
feature_records[feature_records.length - 1].value = active_features[j].fea.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Will convert to pointer after all is ready, since feature_records.array
|
||||||
|
* may move as we grow it. */
|
||||||
|
range->features.features = reinterpret_cast<hb_ms_feature_t *> (offset);
|
||||||
|
range->features.num_features = feature_records.length - offset;
|
||||||
|
range->index_first = last_index;
|
||||||
|
range->index_last = event->index - 1;
|
||||||
|
|
||||||
|
last_index = event->index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->start)
|
||||||
|
{
|
||||||
|
active_features.push (event->feature);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto *feature = active_features.find (&event->feature);
|
||||||
|
if (feature)
|
||||||
|
active_features.remove (feature - active_features.arrayZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!range_records.length) /* No active feature found. */
|
||||||
|
num_features = 0;
|
||||||
|
|
||||||
|
/* Fixup the pointers. */
|
||||||
|
for (unsigned int i = 0; i < range_records.length; i++)
|
||||||
|
{
|
||||||
|
auto *range = &range_records[i];
|
||||||
|
range->features.features = (hb_ms_feature_t *) feature_records + reinterpret_cast<uintptr_t> (range->features.features);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!num_features;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hb_ms_make_feature_ranges (hb_vector_t<hb_ms_feature_t> &feature_records,
|
||||||
|
hb_vector_t<hb_ms_range_record_t> &range_records,
|
||||||
|
unsigned int chars_offset,
|
||||||
|
unsigned int chars_len,
|
||||||
|
uint16_t *log_clusters,
|
||||||
|
hb_vector_t<hb_ms_features_t*> &range_features, /* OUT */
|
||||||
|
hb_vector_t<uint32_t> &range_counts /* OUT */)
|
||||||
|
{
|
||||||
|
range_features.shrink (0);
|
||||||
|
range_counts.shrink (0);
|
||||||
|
|
||||||
|
auto *last_range = &range_records[0];
|
||||||
|
for (unsigned int i = chars_offset; i < chars_len; i++)
|
||||||
|
{
|
||||||
|
auto *range = last_range;
|
||||||
|
while (log_clusters[i] < range->index_first)
|
||||||
|
range--;
|
||||||
|
while (log_clusters[i] > range->index_last)
|
||||||
|
range++;
|
||||||
|
if (!range_features.length ||
|
||||||
|
&range->features != range_features[range_features.length - 1])
|
||||||
|
{
|
||||||
|
auto **features = range_features.push ();
|
||||||
|
auto *c = range_counts.push ();
|
||||||
|
if (unlikely (!features || !c))
|
||||||
|
{
|
||||||
|
range_features.shrink (0);
|
||||||
|
range_counts.shrink (0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*features = &range->features;
|
||||||
|
*c = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
range_counts[range_counts.length - 1]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_range = range;
|
||||||
|
}
|
||||||
|
}
|
96
gfx/harfbuzz/src/hb-ms-feature-ranges.hh
Normal file
96
gfx/harfbuzz/src/hb-ms-feature-ranges.hh
Normal file
@ -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 */
|
@ -39,8 +39,7 @@
|
|||||||
|
|
||||||
/* We need external help for these */
|
/* We need external help for these */
|
||||||
|
|
||||||
#if defined(HB_MUTEX_IMPL_INIT) \
|
#if defined(hb_mutex_impl_init) \
|
||||||
&& defined(hb_mutex_impl_init) \
|
|
||||||
&& defined(hb_mutex_impl_lock) \
|
&& defined(hb_mutex_impl_lock) \
|
||||||
&& defined(hb_mutex_impl_unlock) \
|
&& defined(hb_mutex_impl_unlock) \
|
||||||
&& defined(hb_mutex_impl_finish)
|
&& defined(hb_mutex_impl_finish)
|
||||||
@ -52,7 +51,6 @@
|
|||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
typedef pthread_mutex_t hb_mutex_impl_t;
|
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_init(M) pthread_mutex_init (M, nullptr)
|
||||||
#define hb_mutex_impl_lock(M) pthread_mutex_lock (M)
|
#define hb_mutex_impl_lock(M) pthread_mutex_lock (M)
|
||||||
#define hb_mutex_impl_unlock(M) pthread_mutex_unlock (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)
|
#elif !defined(HB_NO_MT) && defined(_WIN32)
|
||||||
|
|
||||||
typedef CRITICAL_SECTION hb_mutex_impl_t;
|
typedef CRITICAL_SECTION hb_mutex_impl_t;
|
||||||
#define HB_MUTEX_IMPL_INIT {0}
|
|
||||||
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||||
#define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0)
|
#define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0)
|
||||||
#else
|
#else
|
||||||
@ -76,7 +73,6 @@ typedef CRITICAL_SECTION hb_mutex_impl_t;
|
|||||||
#elif defined(HB_NO_MT)
|
#elif defined(HB_NO_MT)
|
||||||
|
|
||||||
typedef int hb_mutex_impl_t;
|
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_init(M) HB_STMT_START {} HB_STMT_END
|
||||||
#define hb_mutex_impl_lock(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
|
#define hb_mutex_impl_unlock(M) HB_STMT_START {} HB_STMT_END
|
||||||
@ -91,8 +87,6 @@ typedef int hb_mutex_impl_t;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define HB_MUTEX_INIT {HB_MUTEX_IMPL_INIT}
|
|
||||||
|
|
||||||
struct hb_mutex_t
|
struct hb_mutex_t
|
||||||
{
|
{
|
||||||
hb_mutex_impl_t m;
|
hb_mutex_impl_t m;
|
||||||
|
@ -140,8 +140,6 @@ struct hb_lockable_set_t
|
|||||||
* Reference-count.
|
* Reference-count.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define HB_REFERENCE_COUNT_INIT {0}
|
|
||||||
|
|
||||||
struct hb_reference_count_t
|
struct hb_reference_count_t
|
||||||
{
|
{
|
||||||
mutable hb_atomic_int_t ref_count;
|
mutable hb_atomic_int_t ref_count;
|
||||||
@ -197,6 +195,8 @@ struct hb_object_header_t
|
|||||||
hb_reference_count_t ref_count;
|
hb_reference_count_t ref_count;
|
||||||
mutable hb_atomic_int_t writable = 0;
|
mutable hb_atomic_int_t writable = 0;
|
||||||
hb_atomic_ptr_t<hb_user_data_array_t> user_data;
|
hb_atomic_ptr_t<hb_user_data_array_t> user_data;
|
||||||
|
|
||||||
|
bool is_inert () const { return !ref_count.get_relaxed (); }
|
||||||
};
|
};
|
||||||
#define HB_OBJECT_HEADER_STATIC {}
|
#define HB_OBJECT_HEADER_STATIC {}
|
||||||
|
|
||||||
@ -217,7 +217,7 @@ static inline void hb_object_trace (const Type *obj, const char *function)
|
|||||||
template <typename Type>
|
template <typename Type>
|
||||||
static inline Type *hb_object_create ()
|
static inline Type *hb_object_create ()
|
||||||
{
|
{
|
||||||
Type *obj = (Type *) calloc (1, sizeof (Type));
|
Type *obj = (Type *) hb_calloc (1, sizeof (Type));
|
||||||
|
|
||||||
if (unlikely (!obj))
|
if (unlikely (!obj))
|
||||||
return obj;
|
return obj;
|
||||||
@ -234,11 +234,6 @@ static inline void hb_object_init (Type *obj)
|
|||||||
obj->header.user_data.init ();
|
obj->header.user_data.init ();
|
||||||
}
|
}
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
static inline bool hb_object_is_inert (const Type *obj)
|
|
||||||
{
|
|
||||||
return unlikely (obj->header.ref_count.is_inert ());
|
|
||||||
}
|
|
||||||
template <typename Type>
|
|
||||||
static inline bool hb_object_is_valid (const Type *obj)
|
static inline bool hb_object_is_valid (const Type *obj)
|
||||||
{
|
{
|
||||||
return likely (obj->header.ref_count.is_valid ());
|
return likely (obj->header.ref_count.is_valid ());
|
||||||
@ -257,7 +252,7 @@ template <typename Type>
|
|||||||
static inline Type *hb_object_reference (Type *obj)
|
static inline Type *hb_object_reference (Type *obj)
|
||||||
{
|
{
|
||||||
hb_object_trace (obj, HB_FUNC);
|
hb_object_trace (obj, HB_FUNC);
|
||||||
if (unlikely (!obj || hb_object_is_inert (obj)))
|
if (unlikely (!obj || obj->header.is_inert ()))
|
||||||
return obj;
|
return obj;
|
||||||
assert (hb_object_is_valid (obj));
|
assert (hb_object_is_valid (obj));
|
||||||
obj->header.ref_count.inc ();
|
obj->header.ref_count.inc ();
|
||||||
@ -267,7 +262,7 @@ template <typename Type>
|
|||||||
static inline bool hb_object_destroy (Type *obj)
|
static inline bool hb_object_destroy (Type *obj)
|
||||||
{
|
{
|
||||||
hb_object_trace (obj, HB_FUNC);
|
hb_object_trace (obj, HB_FUNC);
|
||||||
if (unlikely (!obj || hb_object_is_inert (obj)))
|
if (unlikely (!obj || obj->header.is_inert ()))
|
||||||
return false;
|
return false;
|
||||||
assert (hb_object_is_valid (obj));
|
assert (hb_object_is_valid (obj));
|
||||||
if (obj->header.ref_count.dec () != 1)
|
if (obj->header.ref_count.dec () != 1)
|
||||||
@ -284,7 +279,7 @@ static inline void hb_object_fini (Type *obj)
|
|||||||
if (user_data)
|
if (user_data)
|
||||||
{
|
{
|
||||||
user_data->fini ();
|
user_data->fini ();
|
||||||
free (user_data);
|
hb_free (user_data);
|
||||||
user_data = nullptr;
|
user_data = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,7 +290,7 @@ static inline bool hb_object_set_user_data (Type *obj,
|
|||||||
hb_destroy_func_t destroy,
|
hb_destroy_func_t destroy,
|
||||||
hb_bool_t replace)
|
hb_bool_t replace)
|
||||||
{
|
{
|
||||||
if (unlikely (!obj || hb_object_is_inert (obj)))
|
if (unlikely (!obj || obj->header.is_inert ()))
|
||||||
return false;
|
return false;
|
||||||
assert (hb_object_is_valid (obj));
|
assert (hb_object_is_valid (obj));
|
||||||
|
|
||||||
@ -303,14 +298,14 @@ retry:
|
|||||||
hb_user_data_array_t *user_data = obj->header.user_data.get ();
|
hb_user_data_array_t *user_data = obj->header.user_data.get ();
|
||||||
if (unlikely (!user_data))
|
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))
|
if (unlikely (!user_data))
|
||||||
return false;
|
return false;
|
||||||
user_data->init ();
|
user_data->init ();
|
||||||
if (unlikely (!obj->header.user_data.cmpexch (nullptr, user_data)))
|
if (unlikely (!obj->header.user_data.cmpexch (nullptr, user_data)))
|
||||||
{
|
{
|
||||||
user_data->fini ();
|
user_data->fini ();
|
||||||
free (user_data);
|
hb_free (user_data);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,7 +317,7 @@ template <typename Type>
|
|||||||
static inline void *hb_object_get_user_data (Type *obj,
|
static inline void *hb_object_get_user_data (Type *obj,
|
||||||
hb_user_data_key_t *key)
|
hb_user_data_key_t *key)
|
||||||
{
|
{
|
||||||
if (unlikely (!obj || hb_object_is_inert (obj)))
|
if (unlikely (!obj || obj->header.is_inert ()))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
assert (hb_object_is_valid (obj));
|
assert (hb_object_is_valid (obj));
|
||||||
hb_user_data_array_t *user_data = obj->header.user_data.get ();
|
hb_user_data_array_t *user_data = obj->header.user_data.get ();
|
||||||
|
@ -35,7 +35,6 @@
|
|||||||
|
|
||||||
namespace OT {
|
namespace OT {
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* The OpenType Font File
|
* The OpenType Font File
|
||||||
@ -102,7 +101,13 @@ typedef struct OpenTypeOffsetTable
|
|||||||
{
|
{
|
||||||
Tag t;
|
Tag t;
|
||||||
t = tag;
|
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
|
const TableRecord& get_table_by_tag (hb_tag_t tag) const
|
||||||
{
|
{
|
||||||
@ -113,44 +118,53 @@ typedef struct OpenTypeOffsetTable
|
|||||||
|
|
||||||
public:
|
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,
|
bool serialize (hb_serialize_context_t *c,
|
||||||
hb_tag_t sfnt_tag,
|
hb_tag_t sfnt_tag,
|
||||||
hb_array_t<item_t> items)
|
Iterator it)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
/* Alloc 12 for the OTHeader. */
|
/* 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). */
|
/* Write sfntVersion (bytes 0..3). */
|
||||||
sfnt_version = sfnt_tag;
|
sfnt_version = sfnt_tag;
|
||||||
/* Take space for numTables, searchRange, entrySelector, RangeShift
|
/* Take space for numTables, searchRange, entrySelector, RangeShift
|
||||||
* and the TableRecords themselves. */
|
* 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;
|
const char *dir_end = (const char *) c->head;
|
||||||
HBUINT32 *checksum_adjustment = nullptr;
|
HBUINT32 *checksum_adjustment = nullptr;
|
||||||
|
|
||||||
/* Write OffsetTables, alloc for and write actual table blobs. */
|
/* 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 = entry.second;
|
||||||
hb_blob_t *blob = items[i].blob;
|
unsigned len = blob->length;
|
||||||
rec.tag = items[i].tag;
|
|
||||||
rec.length = blob->length;
|
|
||||||
rec.offset.serialize (c, this);
|
|
||||||
|
|
||||||
/* Allocate room for the table and copy it. */
|
/* 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 (unlikely (!start)) return false;
|
||||||
|
|
||||||
if (likely (rec.length))
|
TableRecord &rec = tables.arrayZ[i];
|
||||||
memcpy (start, blob->data, rec.length);
|
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. */
|
/* 4-byte alignment. */
|
||||||
c->align (4);
|
c->align (4);
|
||||||
const char *end = (const char *) c->head;
|
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)
|
(unsigned) (end - start) >= head::static_size)
|
||||||
{
|
{
|
||||||
head *h = (head *) start;
|
head *h = (head *) start;
|
||||||
@ -159,6 +173,7 @@ typedef struct OpenTypeOffsetTable
|
|||||||
}
|
}
|
||||||
|
|
||||||
rec.checkSum.set_for_data (start, end - start);
|
rec.checkSum.set_for_data (start, end - start);
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
tables.qsort ();
|
tables.qsort ();
|
||||||
@ -170,7 +185,7 @@ typedef struct OpenTypeOffsetTable
|
|||||||
/* The following line is a slower version of the following block. */
|
/* 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, (const char *) c->head - (const char *) this);
|
||||||
checksum.set_for_data (this, dir_end - (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];
|
TableRecord &rec = tables.arrayZ[i];
|
||||||
checksum = checksum + rec.checkSum;
|
checksum = checksum + rec.checkSum;
|
||||||
@ -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,
|
bool serialize_single (hb_serialize_context_t *c,
|
||||||
hb_tag_t sfnt_tag,
|
hb_tag_t sfnt_tag,
|
||||||
hb_array_t<item_t> items)
|
Iterator items)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
assert (sfnt_tag != TTCTag);
|
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));
|
return_trace (u.fontFace.serialize (c, sfnt_tag, items));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,15 +212,6 @@ struct Offset : Type
|
|||||||
|
|
||||||
bool is_null () const { return has_null && 0 == *this; }
|
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),
|
|
||||||
HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_STATIC (sizeof (Type));
|
DEFINE_SIZE_STATIC (sizeof (Type));
|
||||||
};
|
};
|
||||||
@ -328,10 +319,6 @@ struct OffsetTo : Offset<OffsetType, has_null>
|
|||||||
hb_enable_if (hb_is_convertible (Base, void *))>
|
hb_enable_if (hb_is_convertible (Base, void *))>
|
||||||
friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); }
|
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>
|
template <typename ...Ts>
|
||||||
bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src,
|
bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src,
|
||||||
@ -355,6 +342,23 @@ struct OffsetTo : Offset<OffsetType, has_null>
|
|||||||
return ret;
|
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(). */
|
/* TODO: Somehow merge this with previous function into a serialize_dispatch(). */
|
||||||
/* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029
|
/* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029
|
||||||
* Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&...
|
* Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&...
|
||||||
@ -464,8 +468,10 @@ struct UnsizedArrayOf
|
|||||||
const Type &lsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const
|
const Type &lsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const
|
||||||
{ return *as_array (len).lsearch (x, ¬_found); }
|
{ return *as_array (len).lsearch (x, ¬_found); }
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool lfind (unsigned int len, const T &x, unsigned *pos = nullptr) const
|
bool lfind (unsigned int len, const T &x, unsigned int *i = nullptr,
|
||||||
{ return as_array (len).lfind (x, pos); }
|
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)
|
void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
|
||||||
{ as_array (len).qsort (start, end); }
|
{ as_array (len).qsort (start, end); }
|
||||||
@ -473,7 +479,7 @@ struct UnsizedArrayOf
|
|||||||
bool serialize (hb_serialize_context_t *c, unsigned int items_len)
|
bool serialize (hb_serialize_context_t *c, unsigned int items_len)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
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);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
template <typename Iterator,
|
template <typename Iterator,
|
||||||
@ -573,7 +579,7 @@ struct SortedUnsizedArrayOf : UnsizedArrayOf<Type>
|
|||||||
{ return *as_array (len).bsearch (x, ¬_found); }
|
{ return *as_array (len).bsearch (x, ¬_found); }
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr,
|
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
|
unsigned int to_store = (unsigned int) -1) const
|
||||||
{ return as_array (len).bfind (x, i, not_found, to_store); }
|
{ return as_array (len).bfind (x, i, not_found, to_store); }
|
||||||
};
|
};
|
||||||
@ -635,8 +641,10 @@ struct ArrayOf
|
|||||||
const Type &lsearch (const T &x, const Type ¬_found = Null (Type)) const
|
const Type &lsearch (const T &x, const Type ¬_found = Null (Type)) const
|
||||||
{ return *as_array ().lsearch (x, ¬_found); }
|
{ return *as_array ().lsearch (x, ¬_found); }
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool lfind (const T &x, unsigned *pos = nullptr) const
|
bool lfind (const T &x, unsigned int *i = nullptr,
|
||||||
{ return as_array ().lfind (x, pos); }
|
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)
|
void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
|
||||||
{ as_array ().qsort (start, end); }
|
{ as_array ().qsort (start, end); }
|
||||||
@ -644,9 +652,9 @@ struct ArrayOf
|
|||||||
HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len)
|
HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
if (unlikely (!c->extend_min (this))) return_trace (false);
|
||||||
c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
|
c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
|
||||||
if (unlikely (!c->extend (*this))) return_trace (false);
|
if (unlikely (!c->extend (this))) return_trace (false);
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
template <typename Iterator,
|
template <typename Iterator,
|
||||||
@ -667,7 +675,7 @@ struct ArrayOf
|
|||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
len++;
|
len++;
|
||||||
if (unlikely (!len || !c->extend (*this)))
|
if (unlikely (!len || !c->extend (this)))
|
||||||
{
|
{
|
||||||
len--;
|
len--;
|
||||||
return_trace (nullptr);
|
return_trace (nullptr);
|
||||||
@ -794,9 +802,9 @@ struct HeadlessArrayOf
|
|||||||
bool serialize (hb_serialize_context_t *c, unsigned int items_len)
|
bool serialize (hb_serialize_context_t *c, unsigned int items_len)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (!c->extend_min (*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);
|
c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
|
||||||
if (unlikely (!c->extend (*this))) return_trace (false);
|
if (unlikely (!c->extend (this))) return_trace (false);
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
template <typename Iterator,
|
template <typename Iterator,
|
||||||
@ -937,7 +945,7 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
|
|||||||
{ return *as_array ().bsearch (x, ¬_found); }
|
{ return *as_array ().bsearch (x, ¬_found); }
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool bfind (const T &x, unsigned int *i = nullptr,
|
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 int to_store = (unsigned int) -1) const
|
||||||
{ return as_array ().bfind (x, i, not_found, to_store); }
|
{ return as_array ().bfind (x, i, not_found, to_store); }
|
||||||
};
|
};
|
||||||
|
@ -126,7 +126,7 @@ struct CFFIndex
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* serialize CFFIndex header */
|
/* 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->count = byteArray.length;
|
||||||
this->offSize = offSize_;
|
this->offSize = offSize_;
|
||||||
if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1))))
|
if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1))))
|
||||||
@ -214,7 +214,7 @@ struct CFFIndex
|
|||||||
unsigned off_size = calcOffSize (total);
|
unsigned off_size = calcOffSize (total);
|
||||||
|
|
||||||
/* serialize CFFIndex header */
|
/* 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->count = it.len ();
|
||||||
this->offSize = off_size;
|
this->offSize = off_size;
|
||||||
if (unlikely (!c->allocate_size<HBUINT8> (off_size * (it.len () + 1))))
|
if (unlikely (!c->allocate_size<HBUINT8> (off_size * (it.len () + 1))))
|
||||||
@ -335,7 +335,7 @@ struct CFFIndexOf : CFFIndex<COUNT>
|
|||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
/* serialize CFFIndex header */
|
/* 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->count = dataArrayLen;
|
||||||
this->offSize = offSize_;
|
this->offSize = offSize_;
|
||||||
if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
|
if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
|
||||||
|
@ -187,7 +187,7 @@ struct Encoding
|
|||||||
const hb_vector_t<code_pair_t>& supp_codes)
|
const hb_vector_t<code_pair_t>& supp_codes)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
Encoding *dest = c->extend_min (*this);
|
Encoding *dest = c->extend_min (this);
|
||||||
if (unlikely (!dest)) return_trace (false);
|
if (unlikely (!dest)) return_trace (false);
|
||||||
dest->format = format | ((supp_codes.length > 0) ? 0x80 : 0);
|
dest->format = format | ((supp_codes.length > 0) ? 0x80 : 0);
|
||||||
switch (format) {
|
switch (format) {
|
||||||
@ -457,7 +457,7 @@ struct Charset
|
|||||||
const hb_vector_t<code_pair_t>& sid_ranges)
|
const hb_vector_t<code_pair_t>& sid_ranges)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
Charset *dest = c->extend_min (*this);
|
Charset *dest = c->extend_min (this);
|
||||||
if (unlikely (!dest)) return_trace (false);
|
if (unlikely (!dest)) return_trace (false);
|
||||||
dest->format = format;
|
dest->format = format;
|
||||||
switch (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_Notice:
|
||||||
case OpCode_Copyright:
|
case OpCode_Copyright:
|
||||||
case OpCode_FullName:
|
case OpCode_FullName:
|
||||||
|
case OpCode_FontName:
|
||||||
case OpCode_FamilyName:
|
case OpCode_FamilyName:
|
||||||
case OpCode_Weight:
|
case OpCode_Weight:
|
||||||
case OpCode_PostScript:
|
case OpCode_PostScript:
|
||||||
|
@ -49,6 +49,12 @@ struct CmapSubtableFormat0
|
|||||||
*glyph = gid;
|
*glyph = gid;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned get_language () const
|
||||||
|
{
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
void collect_unicodes (hb_set_t *out) const
|
void collect_unicodes (hb_set_t *out) const
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < 256; i++)
|
for (unsigned int i = 0; i < 256; i++)
|
||||||
@ -212,29 +218,24 @@ struct CmapSubtableFormat4
|
|||||||
HBINT16 *idDelta,
|
HBINT16 *idDelta,
|
||||||
unsigned segcount)
|
unsigned segcount)
|
||||||
{
|
{
|
||||||
|
hb_hashmap_t<hb_codepoint_t, hb_codepoint_t> cp_to_gid;
|
||||||
|
+ it | hb_sink (cp_to_gid);
|
||||||
|
|
||||||
HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
|
HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
|
||||||
if (unlikely (!c->check_success (idRangeOffset))) return nullptr;
|
if (unlikely (!c->check_success (idRangeOffset))) return nullptr;
|
||||||
if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr;
|
if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr;
|
||||||
|
|
||||||
+ hb_range (segcount)
|
for (unsigned i : + hb_range (segcount)
|
||||||
| hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; })
|
| hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }))
|
||||||
| hb_apply ([&] (const unsigned i)
|
|
||||||
{
|
{
|
||||||
idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
|
idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
|
||||||
|
for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++)
|
||||||
+ it
|
|
||||||
| hb_filter ([&] (const hb_item_type<Iterator> _) { return _.first >= startCode[i] && _.first <= endCode[i]; })
|
|
||||||
| hb_apply ([&] (const hb_item_type<Iterator> _)
|
|
||||||
{
|
{
|
||||||
HBUINT16 glyID;
|
HBUINT16 gid;
|
||||||
glyID = _.second;
|
gid = cp_to_gid[cp];
|
||||||
c->copy<HBUINT16> (glyID);
|
c->copy<HBUINT16> (gid);
|
||||||
})
|
}
|
||||||
;
|
}
|
||||||
|
|
||||||
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
return idRangeOffset;
|
return idRangeOffset;
|
||||||
}
|
}
|
||||||
@ -253,7 +254,7 @@ struct CmapSubtableFormat4
|
|||||||
if (format4_iter.len () == 0) return;
|
if (format4_iter.len () == 0) return;
|
||||||
|
|
||||||
unsigned table_initpos = c->length ();
|
unsigned table_initpos = c->length ();
|
||||||
if (unlikely (!c->extend_min (*this))) return;
|
if (unlikely (!c->extend_min (this))) return;
|
||||||
this->format = 4;
|
this->format = 4;
|
||||||
|
|
||||||
//serialize endCode[]
|
//serialize endCode[]
|
||||||
@ -276,9 +277,17 @@ struct CmapSubtableFormat4
|
|||||||
HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount);
|
HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount);
|
||||||
if (unlikely (!c->check_success (idRangeOffset))) return;
|
if (unlikely (!c->check_success (idRangeOffset))) return;
|
||||||
|
|
||||||
if (unlikely (!c->check_assign(this->length,
|
this->length = c->length () - table_initpos;
|
||||||
c->length () - table_initpos,
|
if ((long long) this->length != (long long) c->length () - table_initpos)
|
||||||
HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
|
{
|
||||||
|
// Length overflowed. Discard the current object before setting the error condition, otherwise
|
||||||
|
// discard is a noop which prevents the higher level code from reverting the serializer to the
|
||||||
|
// pre-error state in cmap4 overflow handling code.
|
||||||
|
c->pop_discard ();
|
||||||
|
c->err (HB_SERIALIZE_ERROR_INT_OVERFLOW);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this->segCountX2 = segcount * 2;
|
this->segCountX2 = segcount * 2;
|
||||||
this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1;
|
this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1;
|
||||||
this->searchRange = 2 * (1u << this->entrySelector);
|
this->searchRange = 2 * (1u << this->entrySelector);
|
||||||
@ -287,6 +296,11 @@ struct CmapSubtableFormat4
|
|||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned get_language () const
|
||||||
|
{
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
struct accelerator_t
|
struct accelerator_t
|
||||||
{
|
{
|
||||||
accelerator_t () {}
|
accelerator_t () {}
|
||||||
@ -549,6 +563,12 @@ struct CmapSubtableTrimmed
|
|||||||
*glyph = gid;
|
*glyph = gid;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned get_language () const
|
||||||
|
{
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
void collect_unicodes (hb_set_t *out) const
|
void collect_unicodes (hb_set_t *out) const
|
||||||
{
|
{
|
||||||
hb_codepoint_t start = startCharCode;
|
hb_codepoint_t start = startCharCode;
|
||||||
@ -608,6 +628,11 @@ struct CmapSubtableLongSegmented
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned get_language () const
|
||||||
|
{
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
|
void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < this->groups.len; i++)
|
for (unsigned int i = 0; i < this->groups.len; i++)
|
||||||
@ -693,7 +718,7 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
|
|||||||
{
|
{
|
||||||
if (it.len () == 0) return;
|
if (it.len () == 0) return;
|
||||||
unsigned table_initpos = c->length ();
|
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 startCharCode = 0xFFFF, endCharCode = 0xFFFF;
|
||||||
hb_codepoint_t glyphID = 0;
|
hb_codepoint_t glyphID = 0;
|
||||||
@ -1077,7 +1102,7 @@ struct CmapSubtableFormat14
|
|||||||
unsigned table_initpos = c->length ();
|
unsigned table_initpos = c->length ();
|
||||||
const char* init_tail = c->tail;
|
const char* init_tail = c->tail;
|
||||||
|
|
||||||
if (unlikely (!c->extend_min (*this))) return;
|
if (unlikely (!c->extend_min (this))) return;
|
||||||
this->format = 14;
|
this->format = 14;
|
||||||
|
|
||||||
auto src_tbl = reinterpret_cast<const CmapSubtableFormat14*> (base);
|
auto src_tbl = reinterpret_cast<const CmapSubtableFormat14*> (base);
|
||||||
@ -1238,6 +1263,20 @@ struct CmapSubtable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned get_language () const
|
||||||
|
{
|
||||||
|
switch (u.format) {
|
||||||
|
case 0: return u.format0 .get_language ();
|
||||||
|
case 4: return u.format4 .get_language ();
|
||||||
|
case 6: return u.format6 .get_language ();
|
||||||
|
case 10: return u.format10.get_language ();
|
||||||
|
case 12: return u.format12.get_language ();
|
||||||
|
case 13: return u.format13.get_language ();
|
||||||
|
case 14:
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Iterator,
|
template<typename Iterator,
|
||||||
hb_requires (hb_is_iterator (Iterator))>
|
hb_requires (hb_is_iterator (Iterator))>
|
||||||
void serialize (hb_serialize_context_t *c,
|
void serialize (hb_serialize_context_t *c,
|
||||||
@ -1353,60 +1392,112 @@ struct cmap
|
|||||||
|
|
||||||
template<typename Iterator, typename EncodingRecIter,
|
template<typename Iterator, typename EncodingRecIter,
|
||||||
hb_requires (hb_is_iterator (EncodingRecIter))>
|
hb_requires (hb_is_iterator (EncodingRecIter))>
|
||||||
void serialize (hb_serialize_context_t *c,
|
bool serialize (hb_serialize_context_t *c,
|
||||||
Iterator it,
|
Iterator it,
|
||||||
EncodingRecIter encodingrec_iter,
|
EncodingRecIter encodingrec_iter,
|
||||||
const void *base,
|
const void *base,
|
||||||
const hb_subset_plan_t *plan)
|
const hb_subset_plan_t *plan,
|
||||||
|
bool drop_format_4 = false)
|
||||||
{
|
{
|
||||||
if (unlikely (!c->extend_min ((*this)))) return;
|
if (unlikely (!c->extend_min ((*this)))) return false;
|
||||||
this->version = 0;
|
this->version = 0;
|
||||||
|
|
||||||
unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
|
unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
|
||||||
|
auto snap = c->snapshot ();
|
||||||
|
|
||||||
for (const EncodingRecord& _ : encodingrec_iter)
|
for (const EncodingRecord& _ : encodingrec_iter)
|
||||||
{
|
{
|
||||||
|
if (c->in_error ())
|
||||||
|
return false;
|
||||||
|
|
||||||
unsigned format = (base+_.subtable).u.format;
|
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;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
/* 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;
|
hb_set_t unicodes_set;
|
||||||
(base+_.subtable).collect_unicodes (&unicodes_set);
|
(base+_.subtable).collect_unicodes (&unicodes_set);
|
||||||
|
|
||||||
if (format == 4) c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx);
|
if (!drop_format_4 && format == 4)
|
||||||
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);
|
c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx);
|
||||||
|
if (c->in_error () && c->only_overflow ())
|
||||||
|
{
|
||||||
|
// cmap4 overflowed, reset and retry serialization without format 4 subtables.
|
||||||
|
c->revert (snap);
|
||||||
|
return serialize (c, it,
|
||||||
|
encodingrec_iter,
|
||||||
|
base,
|
||||||
|
plan,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (format == 12)
|
||||||
|
{
|
||||||
|
if (_can_drop (_, unicodes_set, base, + it | hb_map (hb_first), encodingrec_iter)) continue;
|
||||||
|
c->copy (_, + it | hb_filter (unicodes_set, hb_first), 12u, base, plan, &format12objidx);
|
||||||
|
}
|
||||||
|
else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
|
||||||
|
}
|
||||||
c->check_assign(this->encodingRecord.len,
|
c->check_assign(this->encodingRecord.len,
|
||||||
(c->length () - cmap::min_size)/EncodingRecord::static_size,
|
(c->length () - cmap::min_size)/EncodingRecord::static_size,
|
||||||
HB_SERIALIZE_ERROR_INT_OVERFLOW);
|
HB_SERIALIZE_ERROR_INT_OVERFLOW);
|
||||||
|
|
||||||
|
// Fail if format 4 was dropped and there is no cmap12.
|
||||||
|
return !drop_format_4 || format12objidx;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Iterator, typename EncodingRecordIterator,
|
||||||
|
hb_requires (hb_is_iterator (Iterator)),
|
||||||
|
hb_requires (hb_is_iterator (EncodingRecordIterator))>
|
||||||
|
bool _can_drop (const EncodingRecord& cmap12,
|
||||||
|
const hb_set_t& cmap12_unicodes,
|
||||||
|
const void* base,
|
||||||
|
Iterator subset_unicodes,
|
||||||
|
EncodingRecordIterator encoding_records)
|
||||||
|
{
|
||||||
|
for (auto cp : + subset_unicodes | hb_filter (cmap12_unicodes))
|
||||||
|
{
|
||||||
|
if (cp >= 0x10000) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned target_platform;
|
||||||
|
unsigned target_encoding;
|
||||||
|
unsigned target_language = (base+cmap12.subtable).get_language ();
|
||||||
|
|
||||||
|
if (cmap12.platformID == 0 && cmap12.encodingID == 4)
|
||||||
|
{
|
||||||
|
target_platform = 0;
|
||||||
|
target_encoding = 3;
|
||||||
|
} else if (cmap12.platformID == 3 && cmap12.encodingID == 10) {
|
||||||
|
target_platform = 3;
|
||||||
|
target_encoding = 1;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& _ : encoding_records)
|
||||||
|
{
|
||||||
|
if (_.platformID != target_platform
|
||||||
|
|| _.encodingID != target_encoding
|
||||||
|
|| (base+_.subtable).get_language() != target_language)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
hb_set_t sibling_unicodes;
|
||||||
|
(base+_.subtable).collect_unicodes (&sibling_unicodes);
|
||||||
|
|
||||||
|
auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes);
|
||||||
|
auto sibling = + subset_unicodes | hb_filter (sibling_unicodes);
|
||||||
|
for (; cmap12 && sibling; cmap12++, sibling++)
|
||||||
|
{
|
||||||
|
unsigned a = *cmap12;
|
||||||
|
unsigned b = *sibling;
|
||||||
|
if (a != b) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !cmap12 && !sibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void closure_glyphs (const hb_set_t *unicodes,
|
void closure_glyphs (const hb_set_t *unicodes,
|
||||||
@ -1473,8 +1564,8 @@ struct cmap
|
|||||||
| hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
|
| hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
|
||||||
{ return (_.second != HB_MAP_VALUE_INVALID); })
|
{ return (_.second != HB_MAP_VALUE_INVALID); })
|
||||||
;
|
;
|
||||||
cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan);
|
|
||||||
return_trace (true);
|
return_trace (cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan));
|
||||||
}
|
}
|
||||||
|
|
||||||
const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
|
const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
|
||||||
|
@ -738,7 +738,7 @@ struct CBLC
|
|||||||
cbdt_prime->length,
|
cbdt_prime->length,
|
||||||
HB_MEMORY_MODE_WRITABLE,
|
HB_MEMORY_MODE_WRITABLE,
|
||||||
cbdt_prime->arrayZ,
|
cbdt_prime->arrayZ,
|
||||||
free);
|
hb_free);
|
||||||
cbdt_prime->init (); // Leak arrayZ to the blob.
|
cbdt_prime->init (); // Leak arrayZ to the blob.
|
||||||
bool ret = c->plan->add_table (HB_OT_TAG_CBDT, cbdt_prime_blob);
|
bool ret = c->plan->add_table (HB_OT_TAG_CBDT, cbdt_prime_blob);
|
||||||
hb_blob_destroy (cbdt_prime_blob);
|
hb_blob_destroy (cbdt_prime_blob);
|
||||||
|
@ -37,9 +37,79 @@
|
|||||||
*/
|
*/
|
||||||
#define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
|
#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 {
|
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
|
struct LayerRecord
|
||||||
{
|
{
|
||||||
operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; }
|
operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; }
|
||||||
@ -125,6 +195,15 @@ struct NoVariable
|
|||||||
template <template<typename> class Var>
|
template <template<typename> class Var>
|
||||||
struct ColorIndex
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -140,6 +219,13 @@ struct ColorIndex
|
|||||||
template <template<typename> class Var>
|
template <template<typename> class Var>
|
||||||
struct ColorStop
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -166,6 +252,23 @@ struct Extend : HBUINT8
|
|||||||
template <template<typename> class Var>
|
template <template<typename> class Var>
|
||||||
struct ColorLine
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -249,6 +352,19 @@ struct Affine2x3
|
|||||||
|
|
||||||
struct PaintColrLayers
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -265,6 +381,16 @@ struct PaintColrLayers
|
|||||||
template <template<typename> class Var>
|
template <template<typename> class Var>
|
||||||
struct PaintSolid
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -280,6 +406,21 @@ struct PaintSolid
|
|||||||
template <template<typename> class Var>
|
template <template<typename> class Var>
|
||||||
struct PaintLinearGradient
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -302,6 +443,21 @@ struct PaintLinearGradient
|
|||||||
template <template<typename> class Var>
|
template <template<typename> class Var>
|
||||||
struct PaintRadialGradient
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -324,6 +480,21 @@ struct PaintRadialGradient
|
|||||||
template <template<typename> class Var>
|
template <template<typename> class Var>
|
||||||
struct PaintSweepGradient
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -345,6 +516,21 @@ struct Paint;
|
|||||||
// Paint a non-COLR glyph, filled as indicated by paint.
|
// Paint a non-COLR glyph, filled as indicated by paint.
|
||||||
struct PaintGlyph
|
struct PaintGlyph
|
||||||
{
|
{
|
||||||
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -360,6 +546,18 @@ struct PaintGlyph
|
|||||||
|
|
||||||
struct PaintColrGlyph
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -375,6 +573,17 @@ struct PaintColrGlyph
|
|||||||
template <template<typename> class Var>
|
template <template<typename> class Var>
|
||||||
struct PaintTransform
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -391,6 +600,17 @@ struct PaintTransform
|
|||||||
template <template<typename> class Var>
|
template <template<typename> class Var>
|
||||||
struct PaintTranslate
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -408,6 +628,17 @@ struct PaintTranslate
|
|||||||
template <template<typename> class Var>
|
template <template<typename> class Var>
|
||||||
struct PaintRotate
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -426,6 +657,17 @@ struct PaintRotate
|
|||||||
template <template<typename> class Var>
|
template <template<typename> class Var>
|
||||||
struct PaintSkew
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -444,6 +686,18 @@ struct PaintSkew
|
|||||||
|
|
||||||
struct PaintComposite
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -523,27 +777,83 @@ struct BaseGlyphV1Record
|
|||||||
int cmp (hb_codepoint_t g) const
|
int cmp (hb_codepoint_t g) const
|
||||||
{ return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
|
{ return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
|
||||||
|
|
||||||
bool sanitize (hb_sanitize_context_t *c) const
|
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);
|
TRACE_SANITIZE (this);
|
||||||
return_trace (likely (c->check_struct (this) && paint.sanitize (c, this)));
|
return_trace (likely (c->check_struct (this) && paint.sanitize (c, base)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HBGlyphID glyphId; /* Glyph ID of reference glyph */
|
HBGlyphID glyphId; /* Glyph ID of reference glyph */
|
||||||
Offset32To<Paint> paint; /* Offset (from beginning of BaseGlyphV1Record) to Paint,
|
Offset32To<Paint> paint; /* Offset (from beginning of BaseGlyphV1Record array) to Paint,
|
||||||
* Typically PaintColrLayers */
|
* Typically PaintColrLayers */
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_STATIC (6);
|
DEFINE_SIZE_STATIC (6);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef SortedArray32Of<BaseGlyphV1Record> BaseGlyphV1List;
|
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>
|
struct LayerV1List : Array32OfOffset32To<Paint>
|
||||||
{
|
{
|
||||||
const Paint& get_paint (unsigned i) const
|
const Paint& get_paint (unsigned i) const
|
||||||
{ return this+(*this)[i]; }
|
{ 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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
@ -592,6 +902,15 @@ struct COLR
|
|||||||
hb_set_t *related_ids /* OUT */) const
|
hb_set_t *related_ids /* OUT */) const
|
||||||
{ colr->closure_glyphs (glyph, related_ids); }
|
{ 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:
|
private:
|
||||||
hb_blob_ptr_t<COLR> colr;
|
hb_blob_ptr_t<COLR> colr;
|
||||||
};
|
};
|
||||||
@ -608,13 +927,58 @@ struct COLR
|
|||||||
related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size);
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
return_trace (c->check_struct (this) &&
|
return_trace (c->check_struct (this) &&
|
||||||
(this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
|
(this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
|
||||||
(this+layersZ).sanitize (c, numLayers) &&
|
(this+layersZ).sanitize (c, numLayers) &&
|
||||||
(version == 0 || (version == 1 &&
|
(version == 0 ||
|
||||||
|
(COLRV1_ENABLE_SUBSETTING && version == 1 &&
|
||||||
baseGlyphsV1List.sanitize (c, this) &&
|
baseGlyphsV1List.sanitize (c, this) &&
|
||||||
layersV1.sanitize (c, this) &&
|
layersV1.sanitize (c, this) &&
|
||||||
varStore.sanitize (c, this))));
|
varStore.sanitize (c, this))));
|
||||||
@ -623,7 +987,7 @@ struct COLR
|
|||||||
template<typename BaseIterator, typename LayerIterator,
|
template<typename BaseIterator, typename LayerIterator,
|
||||||
hb_requires (hb_is_iterator (BaseIterator)),
|
hb_requires (hb_is_iterator (BaseIterator)),
|
||||||
hb_requires (hb_is_iterator (LayerIterator))>
|
hb_requires (hb_is_iterator (LayerIterator))>
|
||||||
bool serialize (hb_serialize_context_t *c,
|
bool serialize_V0 (hb_serialize_context_t *c,
|
||||||
unsigned version,
|
unsigned version,
|
||||||
BaseIterator base_it,
|
BaseIterator base_it,
|
||||||
LayerIterator layer_it)
|
LayerIterator layer_it)
|
||||||
@ -636,6 +1000,12 @@ struct COLR
|
|||||||
this->version = version;
|
this->version = version;
|
||||||
numLayers = 0;
|
numLayers = 0;
|
||||||
numBaseGlyphs = base_it.len ();
|
numBaseGlyphs = base_it.len ();
|
||||||
|
if (base_it.len () == 0)
|
||||||
|
{
|
||||||
|
baseGlyphsZ = 0;
|
||||||
|
layersZ = 0;
|
||||||
|
return_trace (true);
|
||||||
|
}
|
||||||
baseGlyphsZ = COLR::min_size;
|
baseGlyphsZ = COLR::min_size;
|
||||||
layersZ = COLR::min_size + numBaseGlyphs * BaseGlyphRecord::min_size;
|
layersZ = COLR::min_size + numBaseGlyphs * BaseGlyphRecord::min_size;
|
||||||
|
|
||||||
@ -663,6 +1033,14 @@ struct COLR
|
|||||||
return record;
|
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
|
bool subset (hb_subset_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SUBSET (this);
|
TRACE_SUBSET (this);
|
||||||
@ -710,6 +1088,7 @@ struct COLR
|
|||||||
if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
|
if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
|
||||||
return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
|
return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
|
||||||
out_layers[i].glyphId = new_gid;
|
out_layers[i].glyphId = new_gid;
|
||||||
|
out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
|
return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
|
||||||
@ -718,11 +1097,29 @@ struct COLR
|
|||||||
| hb_map_retains_sorting (hb_second)
|
| 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);
|
return_trace (false);
|
||||||
|
|
||||||
COLR *colr_prime = c->serializer->start_embed<COLR> ();
|
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:
|
protected:
|
||||||
|
101
gfx/harfbuzz/src/hb-ot-color-colrv1-closure.hh
Normal file
101
gfx/harfbuzz/src/hb-ot-color-colrv1-closure.hh
Normal file
@ -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 */
|
@ -39,7 +39,6 @@
|
|||||||
*/
|
*/
|
||||||
#define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
|
#define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
|
||||||
|
|
||||||
|
|
||||||
namespace OT {
|
namespace OT {
|
||||||
|
|
||||||
|
|
||||||
@ -74,6 +73,44 @@ struct CPALV1Tail
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
bool serialize (hb_serialize_context_t *c,
|
||||||
|
unsigned palette_count,
|
||||||
|
unsigned color_count,
|
||||||
|
const void *base,
|
||||||
|
const hb_map_t *color_index_map) const
|
||||||
|
{
|
||||||
|
TRACE_SERIALIZE (this);
|
||||||
|
auto *out = c->allocate_size<CPALV1Tail> (static_size);
|
||||||
|
if (unlikely (!out)) return_trace (false);
|
||||||
|
|
||||||
|
out->paletteFlagsZ = 0;
|
||||||
|
if (paletteFlagsZ)
|
||||||
|
out->paletteFlagsZ.serialize_copy (c, paletteFlagsZ, base, 0, hb_serialize_context_t::Head, palette_count);
|
||||||
|
|
||||||
|
out->paletteLabelsZ = 0;
|
||||||
|
if (paletteLabelsZ)
|
||||||
|
out->paletteLabelsZ.serialize_copy (c, paletteLabelsZ, base, 0, hb_serialize_context_t::Head, palette_count);
|
||||||
|
|
||||||
|
const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
|
||||||
|
if (colorLabelsZ)
|
||||||
|
{
|
||||||
|
c->push ();
|
||||||
|
for (const auto _ : colorLabels)
|
||||||
|
{
|
||||||
|
if (!color_index_map->has (_)) continue;
|
||||||
|
NameID new_color_idx;
|
||||||
|
new_color_idx = color_index_map->get (_);
|
||||||
|
if (!c->copy<NameID> (new_color_idx))
|
||||||
|
{
|
||||||
|
c->pop_discard ();
|
||||||
|
return_trace (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c->add_link (out->colorLabelsZ, c->pop_pack ());
|
||||||
|
}
|
||||||
|
return_trace (true);
|
||||||
|
}
|
||||||
|
|
||||||
bool sanitize (hb_sanitize_context_t *c,
|
bool sanitize (hb_sanitize_context_t *c,
|
||||||
const void *base,
|
const void *base,
|
||||||
unsigned int palette_count,
|
unsigned int palette_count,
|
||||||
@ -87,6 +124,8 @@ struct CPALV1Tail
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// TODO(garretrieger): these offsets can hold nulls so we should not be using non-null offsets
|
||||||
|
// here. Currently they are needed since UnsizedArrayOf doesn't define null_size
|
||||||
NNOffset32To<UnsizedArrayOf<HBUINT32>>
|
NNOffset32To<UnsizedArrayOf<HBUINT32>>
|
||||||
paletteFlagsZ; /* Offset from the beginning of CPAL table to
|
paletteFlagsZ; /* Offset from the beginning of CPAL table to
|
||||||
* the Palette Type Array. Set to 0 if no array
|
* the Palette Type Array. Set to 0 if no array
|
||||||
@ -157,6 +196,84 @@ struct CPAL
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
|
@ -145,7 +145,7 @@ struct SBIXStrike
|
|||||||
auto* out = c->serializer->start_embed<SBIXStrike> ();
|
auto* out = c->serializer->start_embed<SBIXStrike> ();
|
||||||
if (unlikely (!out)) return_trace (false);
|
if (unlikely (!out)) return_trace (false);
|
||||||
auto snap = c->serializer->snapshot ();
|
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->ppem = ppem;
|
||||||
out->resolution = resolution;
|
out->resolution = resolution;
|
||||||
HBUINT32 head;
|
HBUINT32 head;
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
/* This lists font tables that the hb_face_t will contain and lazily
|
/* 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
|
* 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. */
|
/* v--- Add new tables in the right place here. */
|
||||||
|
|
||||||
|
@ -45,6 +45,10 @@ namespace OT {
|
|||||||
*/
|
*/
|
||||||
#define HB_OT_TAG_loca HB_TAG('l','o','c','a')
|
#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
|
struct loca
|
||||||
{
|
{
|
||||||
@ -98,7 +102,7 @@ struct glyf
|
|||||||
unsigned num_offsets = padded_offsets.len () + 1;
|
unsigned num_offsets = padded_offsets.len () + 1;
|
||||||
bool use_short_loca = max_offset < 0x1FFFF;
|
bool use_short_loca = max_offset < 0x1FFFF;
|
||||||
unsigned entry_size = use_short_loca ? 2 : 4;
|
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;
|
if (unlikely (!loca_prime_data)) return false;
|
||||||
|
|
||||||
@ -115,7 +119,7 @@ struct glyf
|
|||||||
entry_size * num_offsets,
|
entry_size * num_offsets,
|
||||||
HB_MEMORY_MODE_WRITABLE,
|
HB_MEMORY_MODE_WRITABLE,
|
||||||
loca_prime_data,
|
loca_prime_data,
|
||||||
free);
|
hb_free);
|
||||||
|
|
||||||
bool result = plan->add_table (HB_OT_TAG_loca, loca_blob)
|
bool result = plan->add_table (HB_OT_TAG_loca, loca_blob)
|
||||||
&& _add_head_and_set_loca_version (plan, use_short_loca);
|
&& _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))
|
if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid))
|
||||||
return subset_glyph;
|
return subset_glyph;
|
||||||
|
|
||||||
|
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);
|
subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
|
||||||
if (plan->drop_hints) subset_glyph.drop_hints_bytes ();
|
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
|
||||||
else subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
|
subset_glyph.drop_hints_bytes ();
|
||||||
|
else
|
||||||
|
subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
|
||||||
return subset_glyph;
|
return subset_glyph;
|
||||||
})
|
})
|
||||||
| hb_sink (glyphs)
|
| hb_sink (glyphs)
|
||||||
@ -281,6 +290,11 @@ struct glyf
|
|||||||
hb_codepoint_t get_glyph_index () const { return glyphIndex; }
|
hb_codepoint_t get_glyph_index () const { return glyphIndex; }
|
||||||
|
|
||||||
void drop_instructions_flag () { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; }
|
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_instructions () const { return flags & WE_HAVE_INSTRUCTIONS; }
|
||||||
|
|
||||||
bool has_more () const { return flags & MORE_COMPONENTS; }
|
bool has_more () const { return flags & MORE_COMPONENTS; }
|
||||||
@ -383,9 +397,12 @@ struct glyf
|
|||||||
{
|
{
|
||||||
typedef const CompositeGlyphChain *__item_t__;
|
typedef const CompositeGlyphChain *__item_t__;
|
||||||
composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) :
|
composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) :
|
||||||
glyph (glyph_), current (current_)
|
glyph (glyph_), current (nullptr), current_size (0)
|
||||||
{ if (!check_range (current)) current = nullptr; }
|
{
|
||||||
composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr) {}
|
set_next (current_);
|
||||||
|
}
|
||||||
|
|
||||||
|
composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {}
|
||||||
|
|
||||||
const CompositeGlyphChain &__item__ () const { return *current; }
|
const CompositeGlyphChain &__item__ () const { return *current; }
|
||||||
bool __more__ () const { return current; }
|
bool __more__ () const { return current; }
|
||||||
@ -393,23 +410,36 @@ struct glyf
|
|||||||
{
|
{
|
||||||
if (!current->has_more ()) { current = nullptr; return; }
|
if (!current->has_more ()) { current = nullptr; return; }
|
||||||
|
|
||||||
const CompositeGlyphChain *possible = &StructAfter<CompositeGlyphChain,
|
set_next (&StructAtOffset<CompositeGlyphChain> (current, current_size));
|
||||||
CompositeGlyphChain> (*current);
|
|
||||||
if (!check_range (possible)) { current = nullptr; return; }
|
|
||||||
current = possible;
|
|
||||||
}
|
}
|
||||||
bool operator != (const composite_iter_t& o) const
|
bool operator != (const composite_iter_t& o) const
|
||||||
{ return glyph != o.glyph || current != o.current; }
|
{ 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)
|
if (!glyph.check_range (composite, CompositeGlyphChain::min_size))
|
||||||
&& glyph.check_range (composite, composite->get_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:
|
private:
|
||||||
hb_bytes_t glyph;
|
hb_bytes_t glyph;
|
||||||
__item_t__ current;
|
__item_t__ current;
|
||||||
|
unsigned current_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum phantom_point_index_t
|
enum phantom_point_index_t
|
||||||
@ -433,7 +463,7 @@ struct glyf
|
|||||||
FLAG_REPEAT = 0x08,
|
FLAG_REPEAT = 0x08,
|
||||||
FLAG_X_SAME = 0x10,
|
FLAG_X_SAME = 0x10,
|
||||||
FLAG_Y_SAME = 0x20,
|
FLAG_Y_SAME = 0x20,
|
||||||
FLAG_RESERVED1 = 0x40,
|
FLAG_OVERLAP_SIMPLE = 0x40,
|
||||||
FLAG_RESERVED2 = 0x80
|
FLAG_RESERVED2 = 0x80
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -495,8 +525,8 @@ struct glyf
|
|||||||
const Glyph trim_padding () const
|
const Glyph trim_padding () const
|
||||||
{
|
{
|
||||||
/* based on FontTools _g_l_y_f.py::trim */
|
/* based on FontTools _g_l_y_f.py::trim */
|
||||||
const char *glyph = bytes.arrayZ;
|
const uint8_t *glyph = (uint8_t*) bytes.arrayZ;
|
||||||
const char *glyph_end = glyph + bytes.length;
|
const uint8_t *glyph_end = glyph + bytes.length;
|
||||||
/* simple glyph w/contours, possibly trimmable */
|
/* simple glyph w/contours, possibly trimmable */
|
||||||
glyph += instruction_len_offset ();
|
glyph += instruction_len_offset ();
|
||||||
|
|
||||||
@ -553,6 +583,17 @@ struct glyf
|
|||||||
dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length);
|
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 */,
|
static bool read_points (const HBUINT8 *&p /* IN/OUT */,
|
||||||
contour_point_vector_t &points_ /* IN/OUT */,
|
contour_point_vector_t &points_ /* IN/OUT */,
|
||||||
const hb_bytes_t &bytes,
|
const hb_bytes_t &bytes,
|
||||||
@ -666,6 +707,12 @@ struct glyf
|
|||||||
/* Chop instructions off the end */
|
/* Chop instructions off the end */
|
||||||
void drop_hints_bytes (hb_bytes_t &dest_start) const
|
void drop_hints_bytes (hb_bytes_t &dest_start) const
|
||||||
{ dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); }
|
{ 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 };
|
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
|
void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -886,7 +942,7 @@ struct glyf
|
|||||||
{
|
{
|
||||||
if (gid >= num_glyphs) return false;
|
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
|
https://github.com/harfbuzz/harfbuzz/issues/2095
|
||||||
mostly because of gvar handling in VF fonts,
|
mostly because of gvar handling in VF fonts,
|
||||||
perhaps a separate path for non-VF fonts can be considered */
|
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;
|
return needs_padding_removal ? glyph.trim_padding () : glyph;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
unsigned
|
||||||
add_gid_and_children (hb_codepoint_t gid, hb_set_t *gids_to_retain,
|
add_gid_and_children (hb_codepoint_t gid,
|
||||||
unsigned int depth = 0) const
|
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 */
|
/* 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);
|
gids_to_retain->add (gid);
|
||||||
|
|
||||||
for (auto &item : glyph_for_gid (gid).get_composite_iterator ())
|
auto it = glyph_for_gid (gid).get_composite_iterator ();
|
||||||
add_gid_and_children (item.get_glyph_index (), gids_to_retain, depth);
|
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
|
#ifdef HB_EXPERIMENTAL_API
|
||||||
@ -1230,7 +1296,11 @@ struct glyf
|
|||||||
const_cast<CompositeGlyphChain &> (_).set_glyph_index (new_gid);
|
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);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ struct DeviceRecord
|
|||||||
|
|
||||||
unsigned length = it.len ();
|
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->pixelSize = pixelSize;
|
||||||
this->maxWidth =
|
this->maxWidth =
|
||||||
|
@ -415,7 +415,7 @@ struct RecordArrayOf : SortedArray16Of<Record<Type>>
|
|||||||
}
|
}
|
||||||
bool find_index (hb_tag_t tag, unsigned int *index) const
|
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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1262,13 +1262,13 @@ struct Lookup
|
|||||||
unsigned int num_subtables)
|
unsigned int num_subtables)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
if (unlikely (!c->extend_min (this))) return_trace (false);
|
||||||
lookupType = lookup_type;
|
lookupType = lookup_type;
|
||||||
lookupFlag = lookup_props & 0xFFFFu;
|
lookupFlag = lookup_props & 0xFFFFu;
|
||||||
if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
|
if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
|
||||||
if (lookupFlag & LookupFlag::UseMarkFilteringSet)
|
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);
|
HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
|
||||||
markFilteringSet = lookup_props >> 16;
|
markFilteringSet = lookup_props >> 16;
|
||||||
}
|
}
|
||||||
@ -1393,7 +1393,7 @@ struct CoverageFormat1
|
|||||||
unsigned int get_coverage (hb_codepoint_t glyph_id) const
|
unsigned int get_coverage (hb_codepoint_t glyph_id) const
|
||||||
{
|
{
|
||||||
unsigned int i;
|
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;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1478,7 +1478,7 @@ struct CoverageFormat2
|
|||||||
bool serialize (hb_serialize_context_t *c, Iterator glyphs)
|
bool serialize (hb_serialize_context_t *c, Iterator glyphs)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
if (unlikely (!c->extend_min (this))) return_trace (false);
|
||||||
|
|
||||||
if (unlikely (!glyphs))
|
if (unlikely (!glyphs))
|
||||||
{
|
{
|
||||||
@ -1657,7 +1657,7 @@ struct Coverage
|
|||||||
bool serialize (hb_serialize_context_t *c, Iterator glyphs)
|
bool serialize (hb_serialize_context_t *c, Iterator glyphs)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
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 count = 0;
|
||||||
unsigned num_ranges = 0;
|
unsigned num_ranges = 0;
|
||||||
@ -1890,7 +1890,7 @@ struct ClassDefFormat1
|
|||||||
Iterator it)
|
Iterator it)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
if (unlikely (!c->extend_min (this))) return_trace (false);
|
||||||
|
|
||||||
if (unlikely (!it))
|
if (unlikely (!it))
|
||||||
{
|
{
|
||||||
@ -2069,7 +2069,7 @@ struct ClassDefFormat2
|
|||||||
Iterator it)
|
Iterator it)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
if (unlikely (!c->extend_min (this))) return_trace (false);
|
||||||
|
|
||||||
if (unlikely (!it))
|
if (unlikely (!it))
|
||||||
{
|
{
|
||||||
@ -2311,7 +2311,7 @@ struct ClassDef
|
|||||||
bool serialize (hb_serialize_context_t *c, Iterator it_with_class_zero)
|
bool serialize (hb_serialize_context_t *c, Iterator it_with_class_zero)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
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);
|
auto it = + it_with_class_zero | hb_filter (hb_second);
|
||||||
|
|
||||||
@ -2516,19 +2516,19 @@ struct VarRegionList
|
|||||||
bool sanitize (hb_sanitize_context_t *c) const
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
return_trace (c->check_struct (this) &&
|
return_trace (c->check_struct (this) && axesZ.sanitize (c, axisCount * regionCount));
|
||||||
axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_bimap_t ®ion_map)
|
bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_bimap_t ®ion_map)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
VarRegionList *out = c->allocate_min<VarRegionList> ();
|
if (unlikely (!c->extend_min (this))) return_trace (false);
|
||||||
if (unlikely (!out)) return_trace (false);
|
|
||||||
axisCount = src->axisCount;
|
axisCount = src->axisCount;
|
||||||
regionCount = region_map.get_population ();
|
regionCount = region_map.get_population ();
|
||||||
if (unlikely (!c->allocate_size<VarRegionList> (get_size () - min_size))) return_trace (false);
|
if (unlikely (hb_unsigned_mul_overflows (axisCount * regionCount,
|
||||||
unsigned int region_count = src->get_region_count ();
|
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++)
|
for (unsigned int r = 0; r < regionCount; r++)
|
||||||
{
|
{
|
||||||
unsigned int backward = region_map.backward (r);
|
unsigned int backward = region_map.backward (r);
|
||||||
@ -2540,11 +2540,11 @@ struct VarRegionList
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned int get_size () const { return min_size + VarRegionAxis::static_size * axisCount * regionCount; }
|
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 axisCount;
|
||||||
HBUINT16 regionCount;
|
HBUINT16 regionCount;
|
||||||
|
protected:
|
||||||
UnsizedArrayOf<VarRegionAxis>
|
UnsizedArrayOf<VarRegionAxis>
|
||||||
axesZ;
|
axesZ;
|
||||||
public:
|
public:
|
||||||
@ -2560,7 +2560,10 @@ struct VarData
|
|||||||
{ return shortCount + regionIndices.len; }
|
{ return shortCount + regionIndices.len; }
|
||||||
|
|
||||||
unsigned int get_size () const
|
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,
|
float get_delta (unsigned int inner,
|
||||||
const int *coords, unsigned int coord_count,
|
const int *coords, unsigned int coord_count,
|
||||||
@ -2594,7 +2597,7 @@ struct VarData
|
|||||||
return delta;
|
return delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_scalars (const int *coords, unsigned int coord_count,
|
void get_region_scalars (const int *coords, unsigned int coord_count,
|
||||||
const VarRegionList ®ions,
|
const VarRegionList ®ions,
|
||||||
float *scalars /*OUT */,
|
float *scalars /*OUT */,
|
||||||
unsigned int num_scalars) const
|
unsigned int num_scalars) const
|
||||||
@ -2623,7 +2626,7 @@ struct VarData
|
|||||||
const hb_bimap_t ®ion_map)
|
const hb_bimap_t ®ion_map)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
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 ();
|
itemCount = inner_map.get_next_value ();
|
||||||
|
|
||||||
/* Optimize short count */
|
/* Optimize short count */
|
||||||
@ -2665,9 +2668,7 @@ struct VarData
|
|||||||
shortCount = new_short_count;
|
shortCount = new_short_count;
|
||||||
regionIndices.len = new_ri_count;
|
regionIndices.len = new_ri_count;
|
||||||
|
|
||||||
unsigned int size = regionIndices.get_size () - HBUINT16::static_size/*regionIndices.len*/ + (get_row_size () * itemCount);
|
if (unlikely (!c->extend (this))) return_trace (false);
|
||||||
if (unlikely (!c->allocate_size<HBUINT8> (size)))
|
|
||||||
return_trace (false);
|
|
||||||
|
|
||||||
for (r = 0; r < ri_count; r++)
|
for (r = 0; r < ri_count; r++)
|
||||||
if (delta_sz[r]) regionIndices[ri_map[r]] = region_map[src->regionIndices[r]];
|
if (delta_sz[r]) regionIndices[ri_map[r]] = region_map[src->regionIndices[r]];
|
||||||
@ -2682,16 +2683,16 @@ struct VarData
|
|||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void collect_region_refs (hb_inc_bimap_t ®ion_map, const hb_inc_bimap_t &inner_map) const
|
void collect_region_refs (hb_set_t ®ion_indices, const hb_inc_bimap_t &inner_map) const
|
||||||
{
|
{
|
||||||
for (unsigned int r = 0; r < regionIndices.len; r++)
|
for (unsigned int r = 0; r < regionIndices.len; r++)
|
||||||
{
|
{
|
||||||
unsigned int region = regionIndices[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++)
|
for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
|
||||||
if (get_item_delta (inner_map.backward (i), r) != 0)
|
if (get_item_delta (inner_map.backward (i), r) != 0)
|
||||||
{
|
{
|
||||||
region_map.add (region);
|
region_indices.add (region);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2777,32 +2778,48 @@ struct VariationStore
|
|||||||
const hb_array_t <hb_inc_bimap_t> &inner_maps)
|
const hb_array_t <hb_inc_bimap_t> &inner_maps)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
|
if (unlikely (!c->extend_min (this))) return_trace (false);
|
||||||
|
|
||||||
unsigned int set_count = 0;
|
unsigned int set_count = 0;
|
||||||
for (unsigned int i = 0; i < inner_maps.length; i++)
|
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;
|
format = 1;
|
||||||
|
|
||||||
hb_inc_bimap_t region_map;
|
const auto &src_regions = src+src->regions;
|
||||||
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 ();
|
|
||||||
|
|
||||||
if (unlikely (!regions.serialize (c, this)
|
hb_set_t region_indices;
|
||||||
.serialize (c, &(src+src->regions), region_map))) return_trace (false);
|
for (unsigned int i = 0; i < inner_maps.length; i++)
|
||||||
|
(src+src->dataSets[i]).collect_region_refs (region_indices, inner_maps[i]);
|
||||||
|
|
||||||
|
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 ([®ion_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);
|
||||||
|
|
||||||
|
dataSets.len = set_count;
|
||||||
|
if (unlikely (!c->extend (dataSets))) return_trace (false);
|
||||||
|
|
||||||
/* TODO: The following code could be simplified when
|
/* TODO: The following code could be simplified when
|
||||||
* List16OfOffset16To::subset () can take a custom param to be passed to VarData::serialize ()
|
* List16OfOffset16To::subset () can take a custom param to be passed to VarData::serialize () */
|
||||||
*/
|
|
||||||
dataSets.len = set_count;
|
|
||||||
unsigned int set_index = 0;
|
unsigned int set_index = 0;
|
||||||
for (unsigned int i = 0; i < inner_maps.length; i++)
|
for (unsigned int i = 0; i < inner_maps.length; i++)
|
||||||
{
|
{
|
||||||
if (inner_maps[i].get_population () == 0) continue;
|
if (!inner_maps[i].get_population ()) continue;
|
||||||
if (unlikely (!dataSets[set_index++].serialize (c, this)
|
if (unlikely (!dataSets[set_index++]
|
||||||
.serialize (c, &(src+src->dataSets[i]), inner_maps[i], region_map)))
|
.serialize_serialize (c, &(src+src->dataSets[i]), inner_maps[i], region_map)))
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2847,10 +2864,10 @@ struct VariationStore
|
|||||||
&& varstore_prime->dataSets);
|
&& varstore_prime->dataSets);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int get_region_index_count (unsigned int ivs) const
|
unsigned int get_region_index_count (unsigned int major) const
|
||||||
{ return (this+dataSets[ivs]).get_region_index_count (); }
|
{ return (this+dataSets[major]).get_region_index_count (); }
|
||||||
|
|
||||||
void get_scalars (unsigned int ivs,
|
void get_region_scalars (unsigned int major,
|
||||||
const int *coords, unsigned int coord_count,
|
const int *coords, unsigned int coord_count,
|
||||||
float *scalars /*OUT*/,
|
float *scalars /*OUT*/,
|
||||||
unsigned int num_scalars) const
|
unsigned int num_scalars) const
|
||||||
@ -2861,7 +2878,8 @@ struct VariationStore
|
|||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
(this+dataSets[ivs]).get_scalars (coords, coord_count, this+regions,
|
(this+dataSets[major]).get_region_scalars (coords, coord_count,
|
||||||
|
this+regions,
|
||||||
&scalars[0], num_scalars);
|
&scalars[0], num_scalars);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2872,7 +2890,7 @@ struct VariationStore
|
|||||||
Offset32To<VarRegionList> regions;
|
Offset32To<VarRegionList> regions;
|
||||||
Array16OfOffset32To<VarData> dataSets;
|
Array16OfOffset32To<VarData> dataSets;
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_ARRAY (8, dataSets);
|
DEFINE_SIZE_ARRAY_SIZED (8, dataSets);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -98,8 +98,7 @@ struct AttachList
|
|||||||
| hb_map (glyph_map)
|
| hb_map (glyph_map)
|
||||||
| hb_sink (new_coverage)
|
| hb_sink (new_coverage)
|
||||||
;
|
;
|
||||||
out->coverage.serialize (c->serializer, out)
|
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
|
||||||
.serialize (c->serializer, new_coverage.iter ());
|
|
||||||
return_trace (bool (new_coverage));
|
return_trace (bool (new_coverage));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,8 +385,7 @@ struct LigCaretList
|
|||||||
| hb_map (glyph_map)
|
| hb_map (glyph_map)
|
||||||
| hb_sink (new_coverage)
|
| hb_sink (new_coverage)
|
||||||
;
|
;
|
||||||
out->coverage.serialize (c->serializer, out)
|
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
|
||||||
.serialize (c->serializer, new_coverage.iter ());
|
|
||||||
return_trace (bool (new_coverage));
|
return_trace (bool (new_coverage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,7 +538,7 @@ struct Anchor
|
|||||||
switch (u.format) {
|
switch (u.format) {
|
||||||
case 1: return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
|
case 1: return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
|
||||||
case 2:
|
case 2:
|
||||||
if (c->plan->drop_hints)
|
if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
|
||||||
{
|
{
|
||||||
// AnchorFormat 2 just containins extra hinting information, so
|
// AnchorFormat 2 just containins extra hinting information, so
|
||||||
// if hints are being dropped convert to format 1.
|
// if hints are being dropped convert to format 1.
|
||||||
@ -805,7 +805,7 @@ struct SinglePosFormat1
|
|||||||
ValueFormat newFormat,
|
ValueFormat newFormat,
|
||||||
const hb_map_t *layout_variation_idx_map)
|
const hb_map_t *layout_variation_idx_map)
|
||||||
{
|
{
|
||||||
if (unlikely (!c->extend_min (*this))) return;
|
if (unlikely (!c->extend_min (this))) return;
|
||||||
if (unlikely (!c->check_assign (valueFormat,
|
if (unlikely (!c->check_assign (valueFormat,
|
||||||
newFormat,
|
newFormat,
|
||||||
HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
|
HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
|
||||||
@ -823,8 +823,7 @@ struct SinglePosFormat1
|
|||||||
| hb_map_retains_sorting (hb_first)
|
| hb_map_retains_sorting (hb_first)
|
||||||
;
|
;
|
||||||
|
|
||||||
// TODO(garretrieger): serialize_subset this.
|
coverage.serialize_serialize (c, glyphs);
|
||||||
coverage.serialize (c, this).serialize (c, glyphs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool subset (hb_subset_context_t *c) const
|
bool subset (hb_subset_context_t *c) const
|
||||||
@ -926,7 +925,7 @@ struct SinglePosFormat2
|
|||||||
ValueFormat newFormat,
|
ValueFormat newFormat,
|
||||||
const hb_map_t *layout_variation_idx_map)
|
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 (!out)) return;
|
||||||
if (unlikely (!c->check_assign (valueFormat, newFormat, HB_SERIALIZE_ERROR_INT_OVERFLOW))) 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;
|
if (unlikely (!c->check_assign (valueCount, it.len (), HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) return;
|
||||||
@ -942,7 +941,7 @@ struct SinglePosFormat2
|
|||||||
| hb_map_retains_sorting (hb_first)
|
| 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
|
bool subset (hb_subset_context_t *c) const
|
||||||
@ -1374,7 +1373,7 @@ struct PairPosFormat1
|
|||||||
out->format = format;
|
out->format = format;
|
||||||
out->valueFormat[0] = valueFormat[0];
|
out->valueFormat[0] = valueFormat[0];
|
||||||
out->valueFormat[1] = valueFormat[1];
|
out->valueFormat[1] = valueFormat[1];
|
||||||
if (c->plan->drop_hints)
|
if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
|
||||||
{
|
{
|
||||||
hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
|
hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
|
||||||
out->valueFormat[0] = newFormats.first;
|
out->valueFormat[0] = newFormats.first;
|
||||||
@ -1404,8 +1403,7 @@ struct PairPosFormat1
|
|||||||
| hb_sink (new_coverage)
|
| hb_sink (new_coverage)
|
||||||
;
|
;
|
||||||
|
|
||||||
out->coverage.serialize (c->serializer, out)
|
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
|
||||||
.serialize (c->serializer, new_coverage.iter ());
|
|
||||||
|
|
||||||
return_trace (bool (new_coverage));
|
return_trace (bool (new_coverage));
|
||||||
}
|
}
|
||||||
@ -1593,7 +1591,7 @@ struct PairPosFormat2
|
|||||||
unsigned len2 = valueFormat2.get_len ();
|
unsigned len2 = valueFormat2.get_len ();
|
||||||
|
|
||||||
hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
|
hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
|
||||||
if (c->plan->drop_hints)
|
if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
|
||||||
newFormats = compute_effective_value_formats (klass1_map, klass2_map);
|
newFormats = compute_effective_value_formats (klass1_map, klass2_map);
|
||||||
|
|
||||||
out->valueFormat1 = newFormats.first;
|
out->valueFormat1 = newFormats.first;
|
||||||
@ -1618,7 +1616,7 @@ struct PairPosFormat2
|
|||||||
| hb_map_retains_sorting (glyph_map)
|
| 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));
|
return_trace (out->class1Count && out->class2Count && bool (it));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1882,7 +1880,7 @@ struct CursivePosFormat1
|
|||||||
else
|
else
|
||||||
pos[child].x_offset = x_offset;
|
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
|
* https://github.com/harfbuzz/harfbuzz/issues/2469
|
||||||
*/
|
*/
|
||||||
if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain()))
|
if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain()))
|
||||||
@ -1911,7 +1909,7 @@ struct CursivePosFormat1
|
|||||||
| hb_map_retains_sorting (hb_first)
|
| hb_map_retains_sorting (hb_first)
|
||||||
;
|
;
|
||||||
|
|
||||||
coverage.serialize (c->serializer, this).serialize (c->serializer, glyphs);
|
coverage.serialize_serialize (c->serializer, glyphs);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool subset (hb_subset_context_t *c) const
|
bool subset (hb_subset_context_t *c) const
|
||||||
@ -2118,8 +2116,7 @@ struct MarkBasePosFormat1
|
|||||||
| hb_sink (new_coverage)
|
| hb_sink (new_coverage)
|
||||||
;
|
;
|
||||||
|
|
||||||
if (!out->markCoverage.serialize (c->serializer, out)
|
if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
|
||||||
.serialize (c->serializer, new_coverage.iter ()))
|
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
|
|
||||||
out->markArray.serialize_subset (c, markArray, this,
|
out->markArray.serialize_subset (c, markArray, this,
|
||||||
@ -2139,8 +2136,7 @@ struct MarkBasePosFormat1
|
|||||||
| hb_sink (new_coverage)
|
| hb_sink (new_coverage)
|
||||||
;
|
;
|
||||||
|
|
||||||
if (!out->baseCoverage.serialize (c->serializer, out)
|
if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
|
||||||
.serialize (c->serializer, new_coverage.iter ()))
|
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
|
|
||||||
hb_sorted_vector_t<unsigned> base_indexes;
|
hb_sorted_vector_t<unsigned> base_indexes;
|
||||||
@ -2377,8 +2373,7 @@ struct MarkLigPosFormat1
|
|||||||
| hb_map_retains_sorting (glyph_map)
|
| hb_map_retains_sorting (glyph_map)
|
||||||
;
|
;
|
||||||
|
|
||||||
if (!out->markCoverage.serialize (c->serializer, out)
|
if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
|
||||||
.serialize (c->serializer, new_mark_coverage))
|
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
|
|
||||||
out->markArray.serialize_subset (c, markArray, this,
|
out->markArray.serialize_subset (c, markArray, this,
|
||||||
@ -2391,8 +2386,7 @@ struct MarkLigPosFormat1
|
|||||||
| hb_map_retains_sorting (glyph_map)
|
| hb_map_retains_sorting (glyph_map)
|
||||||
;
|
;
|
||||||
|
|
||||||
if (!out->ligatureCoverage.serialize (c->serializer, out)
|
if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
|
||||||
.serialize (c->serializer, new_ligature_coverage))
|
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
|
|
||||||
out->ligatureArray.serialize_subset (c, ligatureArray, this,
|
out->ligatureArray.serialize_subset (c, ligatureArray, this,
|
||||||
@ -2581,8 +2575,7 @@ struct MarkMarkPosFormat1
|
|||||||
| hb_sink (new_coverage)
|
| hb_sink (new_coverage)
|
||||||
;
|
;
|
||||||
|
|
||||||
if (!out->mark1Coverage.serialize (c->serializer, out)
|
if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
|
||||||
.serialize (c->serializer, new_coverage.iter ()))
|
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
|
|
||||||
out->mark1Array.serialize_subset (c, mark1Array, this,
|
out->mark1Array.serialize_subset (c, mark1Array, this,
|
||||||
@ -2602,8 +2595,7 @@ struct MarkMarkPosFormat1
|
|||||||
| hb_sink (new_coverage)
|
| hb_sink (new_coverage)
|
||||||
;
|
;
|
||||||
|
|
||||||
if (!out->mark2Coverage.serialize (c->serializer, out)
|
if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
|
||||||
.serialize (c->serializer, new_coverage.iter ()))
|
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
|
|
||||||
hb_sorted_vector_t<unsigned> mark2_indexes;
|
hb_sorted_vector_t<unsigned> mark2_indexes;
|
||||||
|
@ -100,8 +100,8 @@ struct SingleSubstFormat1
|
|||||||
unsigned delta)
|
unsigned delta)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
if (unlikely (!c->extend_min (this))) 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);
|
||||||
c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW);
|
c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW);
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
@ -209,9 +209,9 @@ struct SingleSubstFormat2
|
|||||||
+ it
|
+ it
|
||||||
| hb_map_retains_sorting (hb_first)
|
| 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 (!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);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,8 +343,13 @@ struct Sequence
|
|||||||
|
|
||||||
unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
|
unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
|
||||||
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
|
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++) {
|
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);
|
_hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
|
||||||
c->output_glyph_for_component (substitute.arrayZ[i], klass);
|
c->output_glyph_for_component (substitute.arrayZ[i], klass);
|
||||||
}
|
}
|
||||||
@ -408,7 +413,6 @@ struct MultipleSubstFormat1
|
|||||||
| hb_map (hb_add (this))
|
| hb_map (hb_add (this))
|
||||||
| hb_apply ([c] (const Sequence &_) { _.closure (c); })
|
| hb_apply ([c] (const Sequence &_) { _.closure (c); })
|
||||||
;
|
;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void closure_lookups (hb_closure_lookups_context_t *c) const {}
|
void closure_lookups (hb_closure_lookups_context_t *c) const {}
|
||||||
@ -444,17 +448,17 @@ struct MultipleSubstFormat1
|
|||||||
hb_array_t<const HBGlyphID> substitute_glyphs_list)
|
hb_array_t<const HBGlyphID> substitute_glyphs_list)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
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);
|
if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
|
||||||
for (unsigned int i = 0; i < glyphs.length; i++)
|
for (unsigned int i = 0; i < glyphs.length; i++)
|
||||||
{
|
{
|
||||||
unsigned int substitute_len = substitute_len_list[i];
|
unsigned int substitute_len = substitute_len_list[i];
|
||||||
if (unlikely (!sequence[i].serialize (c, this)
|
if (unlikely (!sequence[i]
|
||||||
.serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
|
.serialize_serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
substitute_glyphs_list += substitute_len;
|
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
|
bool subset (hb_subset_context_t *c) const
|
||||||
@ -475,8 +479,7 @@ struct MultipleSubstFormat1
|
|||||||
| hb_map (glyph_map)
|
| hb_map (glyph_map)
|
||||||
| hb_sink (new_coverage)
|
| hb_sink (new_coverage)
|
||||||
;
|
;
|
||||||
out->coverage.serialize (c->serializer, out)
|
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
|
||||||
.serialize (c->serializer, new_coverage.iter ());
|
|
||||||
return_trace (bool (new_coverage));
|
return_trace (bool (new_coverage));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -560,7 +563,12 @@ struct AlternateSet
|
|||||||
|
|
||||||
/* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
|
/* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
|
||||||
if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
|
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;
|
alt_index = c->random_number () % count + 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
|
if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
|
||||||
|
|
||||||
@ -683,17 +691,17 @@ struct AlternateSubstFormat1
|
|||||||
hb_array_t<const HBGlyphID> alternate_glyphs_list)
|
hb_array_t<const HBGlyphID> alternate_glyphs_list)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
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);
|
if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
|
||||||
for (unsigned int i = 0; i < glyphs.length; i++)
|
for (unsigned int i = 0; i < glyphs.length; i++)
|
||||||
{
|
{
|
||||||
unsigned int alternate_len = alternate_len_list[i];
|
unsigned int alternate_len = alternate_len_list[i];
|
||||||
if (unlikely (!alternateSet[i].serialize (c, this)
|
if (unlikely (!alternateSet[i]
|
||||||
.serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
|
.serialize_serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
alternate_glyphs_list += alternate_len;
|
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
|
bool subset (hb_subset_context_t *c) const
|
||||||
@ -714,8 +722,7 @@ struct AlternateSubstFormat1
|
|||||||
| hb_map (glyph_map)
|
| hb_map (glyph_map)
|
||||||
| hb_sink (new_coverage)
|
| hb_sink (new_coverage)
|
||||||
;
|
;
|
||||||
out->coverage.serialize (c->serializer, out)
|
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
|
||||||
.serialize (c->serializer, new_coverage.iter ());
|
|
||||||
return_trace (bool (new_coverage));
|
return_trace (bool (new_coverage));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,7 +855,7 @@ struct Ligature
|
|||||||
Iterator components /* Starting from second */)
|
Iterator components /* Starting from second */)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
if (unlikely (!c->extend_min (this))) return_trace (false);
|
||||||
ligGlyph = ligature;
|
ligGlyph = ligature;
|
||||||
if (unlikely (!component.serialize (c, components))) return_trace (false);
|
if (unlikely (!component.serialize (c, components))) return_trace (false);
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
@ -947,13 +954,12 @@ struct LigatureSet
|
|||||||
hb_array_t<const HBGlyphID> &component_list /* Starting from second for each ligature */)
|
hb_array_t<const HBGlyphID> &component_list /* Starting from second for each ligature */)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
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);
|
if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
|
||||||
for (unsigned int i = 0; i < ligatures.length; i++)
|
for (unsigned int i = 0; i < ligatures.length; i++)
|
||||||
{
|
{
|
||||||
unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
|
unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
|
||||||
if (unlikely (!ligature[i].serialize (c, this)
|
if (unlikely (!ligature[i].serialize_serialize (c,
|
||||||
.serialize (c,
|
|
||||||
ligatures[i],
|
ligatures[i],
|
||||||
component_list.sub_array (0, component_count))))
|
component_list.sub_array (0, component_count))))
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
@ -1060,20 +1066,20 @@ struct LigatureSubstFormat1
|
|||||||
hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
|
hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
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);
|
if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
|
||||||
for (unsigned int i = 0; i < first_glyphs.length; i++)
|
for (unsigned int i = 0; i < first_glyphs.length; i++)
|
||||||
{
|
{
|
||||||
unsigned int ligature_count = ligature_per_first_glyph_count_list[i];
|
unsigned int ligature_count = ligature_per_first_glyph_count_list[i];
|
||||||
if (unlikely (!ligatureSet[i].serialize (c, this)
|
if (unlikely (!ligatureSet[i]
|
||||||
.serialize (c,
|
.serialize_serialize (c,
|
||||||
ligatures_list.sub_array (0, ligature_count),
|
ligatures_list.sub_array (0, ligature_count),
|
||||||
component_count_list.sub_array (0, ligature_count),
|
component_count_list.sub_array (0, ligature_count),
|
||||||
component_list))) return_trace (false);
|
component_list))) return_trace (false);
|
||||||
ligatures_list += ligature_count;
|
ligatures_list += ligature_count;
|
||||||
component_count_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
|
bool subset (hb_subset_context_t *c) const
|
||||||
@ -1094,8 +1100,7 @@ struct LigatureSubstFormat1
|
|||||||
| hb_map (glyph_map)
|
| hb_map (glyph_map)
|
||||||
| hb_sink (new_coverage)
|
| hb_sink (new_coverage)
|
||||||
;
|
;
|
||||||
out->coverage.serialize (c->serializer, out)
|
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
|
||||||
.serialize (c->serializer, new_coverage.iter ());
|
|
||||||
return_trace (bool (new_coverage));
|
return_trace (bool (new_coverage));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1325,7 +1330,7 @@ struct ReverseChainSingleSubstFormat1
|
|||||||
if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes))))
|
if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes))))
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
|
|
||||||
if (unlikely (!out->coverage.serialize (c->serializer, out).serialize (c->serializer, glyphs)))
|
if (unlikely (!out->coverage.serialize_serialize (c->serializer, glyphs)))
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
@ -1554,10 +1559,6 @@ struct SubstLookup : Lookup
|
|||||||
|
|
||||||
static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
|
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,
|
bool serialize_single (hb_serialize_context_t *c,
|
||||||
uint32_t lookup_props,
|
uint32_t lookup_props,
|
||||||
hb_sorted_array_t<const HBGlyphID> glyphs,
|
hb_sorted_array_t<const HBGlyphID> glyphs,
|
||||||
@ -1565,8 +1566,13 @@ struct SubstLookup : Lookup
|
|||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
|
if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
|
||||||
return_trace (serialize_subtable (c, 0).u.single.
|
if (c->push<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes)))
|
||||||
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,
|
bool serialize_multiple (hb_serialize_context_t *c,
|
||||||
@ -1577,11 +1583,17 @@ struct SubstLookup : Lookup
|
|||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
|
if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
|
||||||
return_trace (serialize_subtable (c, 0).u.multiple.
|
if (c->push<SubTable> ()->u.multiple.
|
||||||
serialize (c,
|
serialize (c,
|
||||||
glyphs,
|
glyphs,
|
||||||
substitute_len_list,
|
substitute_len_list,
|
||||||
substitute_glyphs_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,
|
bool serialize_alternate (hb_serialize_context_t *c,
|
||||||
@ -1592,11 +1604,18 @@ struct SubstLookup : Lookup
|
|||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
|
if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
|
||||||
return_trace (serialize_subtable (c, 0).u.alternate.
|
|
||||||
|
if (c->push<SubTable> ()->u.alternate.
|
||||||
serialize (c,
|
serialize (c,
|
||||||
glyphs,
|
glyphs,
|
||||||
alternate_len_list,
|
alternate_len_list,
|
||||||
alternate_glyphs_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,
|
bool serialize_ligature (hb_serialize_context_t *c,
|
||||||
@ -1609,13 +1628,19 @@ struct SubstLookup : Lookup
|
|||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
|
if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
|
||||||
return_trace (serialize_subtable (c, 0).u.ligature.
|
if (c->push<SubTable> ()->u.ligature.
|
||||||
serialize (c,
|
serialize (c,
|
||||||
first_glyphs,
|
first_glyphs,
|
||||||
ligature_per_first_glyph_count_list,
|
ligature_per_first_glyph_count_list,
|
||||||
ligatures_list,
|
ligatures_list,
|
||||||
component_count_list,
|
component_count_list,
|
||||||
component_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>
|
template <typename context_t>
|
||||||
|
@ -122,7 +122,7 @@ struct hb_closure_context_t :
|
|||||||
hb_set_t *covered_glyph_set = 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 ()))
|
if (unlikely (covered_glyph_set->in_error ()))
|
||||||
return true;
|
return true;
|
||||||
if (parent_active_glyphs ()->is_subset (covered_glyph_set))
|
if (parent_active_glyphs ()->is_subset (*covered_glyph_set))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
hb_set_union (covered_glyph_set, parent_active_glyphs ());
|
hb_set_union (covered_glyph_set, parent_active_glyphs ());
|
||||||
@ -183,7 +183,7 @@ struct hb_closure_context_t :
|
|||||||
|
|
||||||
void flush ()
|
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_union (glyphs, output);
|
||||||
hb_set_clear (output);
|
hb_set_clear (output);
|
||||||
active_glyphs_stack.pop ();
|
active_glyphs_stack.pop ();
|
||||||
@ -1898,8 +1898,7 @@ struct ContextFormat1
|
|||||||
| hb_sink (new_coverage)
|
| hb_sink (new_coverage)
|
||||||
;
|
;
|
||||||
|
|
||||||
out->coverage.serialize (c->serializer, out)
|
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
|
||||||
.serialize (c->serializer, new_coverage.iter ());
|
|
||||||
return_trace (bool (new_coverage));
|
return_trace (bool (new_coverage));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2866,8 +2865,7 @@ struct ChainContextFormat1
|
|||||||
| hb_sink (new_coverage)
|
| hb_sink (new_coverage)
|
||||||
;
|
;
|
||||||
|
|
||||||
out->coverage.serialize (c->serializer, out)
|
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
|
||||||
.serialize (c->serializer, new_coverage.iter ());
|
|
||||||
return_trace (bool (new_coverage));
|
return_trace (bool (new_coverage));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3721,8 +3719,9 @@ struct GSUBGPOS
|
|||||||
hb_set_t alternate_feature_indices;
|
hb_set_t alternate_feature_indices;
|
||||||
if (version.to_int () >= 0x00010001u)
|
if (version.to_int () >= 0x00010001u)
|
||||||
(this+featureVars).closure_features (lookup_indices, &alternate_feature_indices);
|
(this+featureVars).closure_features (lookup_indices, &alternate_feature_indices);
|
||||||
if (unlikely (alternate_feature_indices.in_error())) {
|
if (unlikely (alternate_feature_indices.in_error()))
|
||||||
feature_indices->successful = false;
|
{
|
||||||
|
feature_indices->err ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -3788,7 +3787,7 @@ struct GSUBGPOS
|
|||||||
|
|
||||||
this->lookup_count = table->get_lookup_count ();
|
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))
|
if (unlikely (!this->accels))
|
||||||
{
|
{
|
||||||
this->lookup_count = 0;
|
this->lookup_count = 0;
|
||||||
@ -3804,7 +3803,7 @@ struct GSUBGPOS
|
|||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < this->lookup_count; i++)
|
for (unsigned int i = 0; i < this->lookup_count; i++)
|
||||||
this->accels[i].fini ();
|
this->accels[i].fini ();
|
||||||
free (this->accels);
|
hb_free (this->accels);
|
||||||
this->table.destroy ();
|
this->table.destroy ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
|
||||||
|
|
||||||
|
if (!buffer->message (font, "start table kern")) return;
|
||||||
kern.apply (&c);
|
kern.apply (&c);
|
||||||
|
(void) buffer->message (font, "end table kern");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -144,7 +146,7 @@ bool
|
|||||||
OT::GDEF::is_blocklisted (hb_blob_t *blob,
|
OT::GDEF::is_blocklisted (hb_blob_t *blob,
|
||||||
hb_face_t *face) const
|
hb_face_t *face) const
|
||||||
{
|
{
|
||||||
#ifdef HB_NO_OT_LAYOUT_BLACKLIST
|
#ifdef HB_NO_OT_LAYOUT_BLOCKLIST
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
/* The ugly business of blocklisting individual fonts' tables happen here!
|
/* The ugly business of blocklisting individual fonts' tables happen here!
|
||||||
@ -383,7 +385,7 @@ bool
|
|||||||
OT::GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
|
OT::GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
|
||||||
hb_face_t *face) const
|
hb_face_t *face) const
|
||||||
{
|
{
|
||||||
#ifdef HB_NO_OT_LAYOUT_BLACKLIST
|
#ifdef HB_NO_OT_LAYOUT_BLOCKLIST
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
@ -393,7 +395,7 @@ bool
|
|||||||
OT::GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED,
|
OT::GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED,
|
||||||
hb_face_t *face HB_UNUSED) const
|
hb_face_t *face HB_UNUSED) const
|
||||||
{
|
{
|
||||||
#ifdef HB_NO_OT_LAYOUT_BLACKLIST
|
#ifdef HB_NO_OT_LAYOUT_BLOCKLIST
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
@ -991,10 +993,46 @@ struct hb_collect_features_context_t
|
|||||||
{
|
{
|
||||||
hb_collect_features_context_t (hb_face_t *face,
|
hb_collect_features_context_t (hb_face_t *face,
|
||||||
hb_tag_t table_tag,
|
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)),
|
: g (get_gsubgpos_table (face, table_tag)),
|
||||||
feature_indexes (feature_indexes_),
|
feature_indices (feature_indices_),
|
||||||
script_count (0),langsys_count (0), feature_index_count (0) {}
|
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)
|
bool visited (const OT::Script &s)
|
||||||
{
|
{
|
||||||
@ -1043,7 +1081,9 @@ struct hb_collect_features_context_t
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
const OT::GSUBGPOS &g;
|
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:
|
private:
|
||||||
hb_set_t visited_script;
|
hb_set_t visited_script;
|
||||||
@ -1055,37 +1095,31 @@ struct hb_collect_features_context_t
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
langsys_collect_features (hb_collect_features_context_t *c,
|
langsys_collect_features (hb_collect_features_context_t *c,
|
||||||
const OT::LangSys &l,
|
const OT::LangSys &l)
|
||||||
const hb_tag_t *features)
|
|
||||||
{
|
{
|
||||||
if (c->visited (l)) return;
|
if (c->visited (l)) return;
|
||||||
|
|
||||||
if (!features)
|
if (!c->has_feature_filter)
|
||||||
{
|
{
|
||||||
/* All features. */
|
/* All features. */
|
||||||
if (l.has_required_feature () && !c->visited_feature_indices (1))
|
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))
|
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
|
else
|
||||||
{
|
{
|
||||||
/* Ugh. Any faster way? */
|
if (c->feature_indices_filter.is_empty()) return;
|
||||||
for (; *features; features++)
|
|
||||||
{
|
|
||||||
hb_tag_t feature_tag = *features;
|
|
||||||
unsigned int num_features = l.get_feature_count ();
|
unsigned int num_features = l.get_feature_count ();
|
||||||
for (unsigned int i = 0; i < num_features; i++)
|
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_indices->add (feature_index);
|
||||||
{
|
c->feature_indices_filter.del (feature_index);
|
||||||
c->feature_indexes->add (feature_index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1093,8 +1127,7 @@ langsys_collect_features (hb_collect_features_context_t *c,
|
|||||||
static void
|
static void
|
||||||
script_collect_features (hb_collect_features_context_t *c,
|
script_collect_features (hb_collect_features_context_t *c,
|
||||||
const OT::Script &s,
|
const OT::Script &s,
|
||||||
const hb_tag_t *languages,
|
const hb_tag_t *languages)
|
||||||
const hb_tag_t *features)
|
|
||||||
{
|
{
|
||||||
if (c->visited (s)) return;
|
if (c->visited (s)) return;
|
||||||
|
|
||||||
@ -1103,14 +1136,13 @@ script_collect_features (hb_collect_features_context_t *c,
|
|||||||
/* All languages. */
|
/* All languages. */
|
||||||
if (s.has_default_lang_sys ())
|
if (s.has_default_lang_sys ())
|
||||||
langsys_collect_features (c,
|
langsys_collect_features (c,
|
||||||
s.get_default_lang_sys (),
|
s.get_default_lang_sys ());
|
||||||
features);
|
|
||||||
|
|
||||||
unsigned int count = s.get_lang_sys_count ();
|
unsigned int count = s.get_lang_sys_count ();
|
||||||
for (unsigned int language_index = 0; language_index < count; language_index++)
|
for (unsigned int language_index = 0; language_index < count; language_index++)
|
||||||
langsys_collect_features (c,
|
langsys_collect_features (c,
|
||||||
s.get_lang_sys (language_index),
|
s.get_lang_sys (language_index));
|
||||||
features);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1119,8 +1151,8 @@ script_collect_features (hb_collect_features_context_t *c,
|
|||||||
unsigned int language_index;
|
unsigned int language_index;
|
||||||
if (s.find_lang_sys_index (*languages, &language_index))
|
if (s.find_lang_sys_index (*languages, &language_index))
|
||||||
langsys_collect_features (c,
|
langsys_collect_features (c,
|
||||||
s.get_lang_sys (language_index),
|
s.get_lang_sys (language_index));
|
||||||
features);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1151,7 +1183,7 @@ hb_ot_layout_collect_features (hb_face_t *face,
|
|||||||
const hb_tag_t *features,
|
const hb_tag_t *features,
|
||||||
hb_set_t *feature_indexes /* OUT */)
|
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)
|
if (!scripts)
|
||||||
{
|
{
|
||||||
/* All scripts. */
|
/* All scripts. */
|
||||||
@ -1159,8 +1191,7 @@ hb_ot_layout_collect_features (hb_face_t *face,
|
|||||||
for (unsigned int script_index = 0; script_index < count; script_index++)
|
for (unsigned int script_index = 0; script_index < count; script_index++)
|
||||||
script_collect_features (&c,
|
script_collect_features (&c,
|
||||||
c.g.get_script (script_index),
|
c.g.get_script (script_index),
|
||||||
languages,
|
languages);
|
||||||
features);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1170,8 +1201,7 @@ hb_ot_layout_collect_features (hb_face_t *face,
|
|||||||
if (c.g.find_script_index (*scripts, &script_index))
|
if (c.g.find_script_index (*scripts, &script_index))
|
||||||
script_collect_features (&c,
|
script_collect_features (&c,
|
||||||
c.g.get_script (script_index),
|
c.g.get_script (script_index),
|
||||||
languages,
|
languages);
|
||||||
features);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1358,7 +1388,8 @@ hb_ot_layout_has_substitution (hb_face_t *face)
|
|||||||
* @lookup_index: The index of the lookup to query
|
* @lookup_index: The index of the lookup to query
|
||||||
* @glyphs: The sequence of glyphs to query for substitution
|
* @glyphs: The sequence of glyphs to query for substitution
|
||||||
* @glyphs_length: The length of the glyph sequence
|
* @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
|
* Tests whether a specified lookup in the specified face would
|
||||||
* trigger a substitution on the given glyph sequence.
|
* trigger a substitution on the given glyph sequence.
|
||||||
@ -1855,27 +1886,20 @@ apply_string (OT::hb_ot_apply_context_t *c,
|
|||||||
if (likely (!lookup.is_reverse ()))
|
if (likely (!lookup.is_reverse ()))
|
||||||
{
|
{
|
||||||
/* in/out forward substitution/positioning */
|
/* in/out forward substitution/positioning */
|
||||||
if (Proxy::table_index == 0u)
|
if (!Proxy::inplace)
|
||||||
buffer->clear_output ();
|
buffer->clear_output ();
|
||||||
buffer->idx = 0;
|
|
||||||
|
|
||||||
bool ret;
|
buffer->idx = 0;
|
||||||
ret = apply_forward (c, accel);
|
apply_forward (c, accel);
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
if (!Proxy::inplace)
|
if (!Proxy::inplace)
|
||||||
buffer->swap_buffers ();
|
buffer->swap_buffers ();
|
||||||
else
|
|
||||||
assert (!buffer->has_separate_output ());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* in-place backward substitution/positioning */
|
/* in-place backward substitution/positioning */
|
||||||
if (Proxy::table_index == 0u)
|
assert (!buffer->have_output);
|
||||||
buffer->remove_output ();
|
|
||||||
buffer->idx = buffer->len - 1;
|
buffer->idx = buffer->len - 1;
|
||||||
|
|
||||||
apply_backward (c, accel);
|
apply_backward (c, accel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1891,7 +1915,8 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
|
|||||||
OT::hb_ot_apply_context_t c (table_index, font, buffer);
|
OT::hb_ot_apply_context_t c (table_index, font, buffer);
|
||||||
c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
|
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];
|
const stage_map_t *stage = &stages[table_index][stage_index];
|
||||||
for (; i < stage->last_lookup; i++)
|
for (; i < stage->last_lookup; i++)
|
||||||
{
|
{
|
||||||
@ -1901,11 +1926,8 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
|
|||||||
c.set_lookup_mask (lookups[table_index][i].mask);
|
c.set_lookup_mask (lookups[table_index][i].mask);
|
||||||
c.set_auto_zwj (lookups[table_index][i].auto_zwj);
|
c.set_auto_zwj (lookups[table_index][i].auto_zwj);
|
||||||
c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
|
c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
|
||||||
if (lookups[table_index][i].random)
|
c.set_random (lookups[table_index][i].random);
|
||||||
{
|
|
||||||
c.set_random (true);
|
|
||||||
buffer->unsafe_to_break_all ();
|
|
||||||
}
|
|
||||||
apply_string<Proxy> (&c,
|
apply_string<Proxy> (&c,
|
||||||
proxy.table.get_lookup (lookup_index),
|
proxy.table.get_lookup (lookup_index),
|
||||||
proxy.accels[lookup_index]);
|
proxy.accels[lookup_index]);
|
||||||
@ -1913,11 +1935,8 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stage->pause_func)
|
if (stage->pause_func)
|
||||||
{
|
|
||||||
buffer->clear_output ();
|
|
||||||
stage->pause_func (plan, font, buffer);
|
stage->pause_func (plan, font, buffer);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
|
void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
|
||||||
|
@ -54,7 +54,6 @@ hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
|
|||||||
face = face_;
|
face = face_;
|
||||||
props = *props_;
|
props = *props_;
|
||||||
|
|
||||||
|
|
||||||
/* Fetch script/language indices for GSUB/GPOS. We need these later to skip
|
/* Fetch script/language indices for GSUB/GPOS. We need these later to skip
|
||||||
* features not available in either table and not waste precious bits for them. */
|
* features not available in either table and not waste precious bits for them. */
|
||||||
|
|
||||||
@ -63,12 +62,28 @@ hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
|
|||||||
hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
|
hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
|
||||||
hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
|
hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
|
||||||
|
|
||||||
hb_ot_tags_from_script_and_language (props.script, props.language, &script_count, script_tags, &language_count, language_tags);
|
hb_ot_tags_from_script_and_language (props.script,
|
||||||
|
props.language,
|
||||||
|
&script_count,
|
||||||
|
script_tags,
|
||||||
|
&language_count,
|
||||||
|
language_tags);
|
||||||
|
|
||||||
for (unsigned int table_index = 0; table_index < 2; table_index++) {
|
for (unsigned int table_index = 0; table_index < 2; table_index++)
|
||||||
|
{
|
||||||
hb_tag_t table_tag = table_tags[table_index];
|
hb_tag_t table_tag = table_tags[table_index];
|
||||||
found_script[table_index] = (bool) hb_ot_layout_table_select_script (face, table_tag, script_count, script_tags, &script_index[table_index], &chosen_script[table_index]);
|
found_script[table_index] = (bool) hb_ot_layout_table_select_script (face,
|
||||||
hb_ot_layout_script_select_language (face, table_tag, script_index[table_index], language_count, language_tags, &language_index[table_index]);
|
table_tag,
|
||||||
|
script_count,
|
||||||
|
script_tags,
|
||||||
|
&script_index[table_index],
|
||||||
|
&chosen_script[table_index]);
|
||||||
|
hb_ot_layout_script_select_language (face,
|
||||||
|
table_tag,
|
||||||
|
script_index[table_index],
|
||||||
|
language_count,
|
||||||
|
language_tags,
|
||||||
|
&language_index[table_index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,9 +165,8 @@ void
|
|||||||
hb_ot_map_builder_t::compile (hb_ot_map_t &m,
|
hb_ot_map_builder_t::compile (hb_ot_map_t &m,
|
||||||
const hb_ot_shape_plan_key_t &key)
|
const hb_ot_shape_plan_key_t &key)
|
||||||
{
|
{
|
||||||
static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
|
unsigned int global_bit_shift = 8 * sizeof (hb_mask_t) - 1;
|
||||||
unsigned int global_bit_mask = HB_GLYPH_FLAG_DEFINED + 1;
|
unsigned int global_bit_mask = 1u << global_bit_shift;
|
||||||
unsigned int global_bit_shift = hb_popcount (HB_GLYPH_FLAG_DEFINED);
|
|
||||||
|
|
||||||
m.global_mask = global_bit_mask;
|
m.global_mask = global_bit_mask;
|
||||||
|
|
||||||
@ -205,7 +219,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
|
|||||||
|
|
||||||
|
|
||||||
/* Allocate bits now */
|
/* 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++)
|
for (unsigned int i = 0; i < feature_infos.length; i++)
|
||||||
{
|
{
|
||||||
@ -220,7 +235,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
|
|||||||
/* Limit bits per feature. */
|
/* Limit bits per feature. */
|
||||||
bits_needed = hb_min (HB_OT_MAP_MAX_BITS, hb_bit_storage (info->max_value));
|
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. */
|
continue; /* Feature disabled, or not enough bits. */
|
||||||
|
|
||||||
|
|
||||||
@ -274,7 +289,6 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
|
|||||||
}
|
}
|
||||||
map->_1_mask = (1u << map->shift) & map->mask;
|
map->_1_mask = (1u << map->shift) & map->mask;
|
||||||
map->needs_fallback = !found;
|
map->needs_fallback = !found;
|
||||||
|
|
||||||
}
|
}
|
||||||
feature_infos.shrink (0); /* Done with these */
|
feature_infos.shrink (0); /* Done with these */
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ struct maxp
|
|||||||
maxpV1Tail *dest_v1 = c->serializer->embed<maxpV1Tail> (src_v1);
|
maxpV1Tail *dest_v1 = c->serializer->embed<maxpV1Tail> (src_v1);
|
||||||
if (unlikely (!dest_v1)) return_trace (false);
|
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);
|
drop_hint_fields (dest_v1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ struct name
|
|||||||
this->format = 0;
|
this->format = 0;
|
||||||
this->count = it.len ();
|
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);
|
if (unlikely (!name_records)) return_trace (false);
|
||||||
|
|
||||||
hb_array_t<NameRecord> records (name_records, it.len ());
|
hb_array_t<NameRecord> records (name_records, it.len ());
|
||||||
@ -228,7 +228,7 @@ struct name
|
|||||||
records.qsort ();
|
records.qsort ();
|
||||||
|
|
||||||
c->copy_all (records, src_string_pool);
|
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);
|
||||||
@ -249,7 +249,11 @@ struct name
|
|||||||
+ nameRecordZ.as_array (count)
|
+ nameRecordZ.as_array (count)
|
||||||
| hb_filter (c->plan->name_ids, &NameRecord::nameID)
|
| hb_filter (c->plan->name_ids, &NameRecord::nameID)
|
||||||
| hb_filter (c->plan->name_languages, &NameRecord::languageID)
|
| 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));
|
name_prime->serialize (c->serializer, it, hb_addressof (this + stringOffset));
|
||||||
|
@ -156,7 +156,8 @@ hb_ot_name_get_utf (hb_face_t *face,
|
|||||||
*
|
*
|
||||||
* Fetches a font name from the OpenType 'name' table.
|
* Fetches a font name from the OpenType 'name' table.
|
||||||
* If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
|
* If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
|
||||||
* Returns string in UTF-8 encoding.
|
* Returns string in UTF-8 encoding. A NUL terminator is always written
|
||||||
|
* for convenience, and isn't included in the output @text_size.
|
||||||
*
|
*
|
||||||
* Returns: full length of the requested string, or 0 if not found.
|
* Returns: full length of the requested string, or 0 if not found.
|
||||||
* Since: 2.1.0
|
* Since: 2.1.0
|
||||||
@ -183,7 +184,8 @@ hb_ot_name_get_utf8 (hb_face_t *face,
|
|||||||
*
|
*
|
||||||
* Fetches a font name from the OpenType 'name' table.
|
* Fetches a font name from the OpenType 'name' table.
|
||||||
* If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
|
* If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
|
||||||
* Returns string in UTF-16 encoding.
|
* Returns string in UTF-16 encoding. A NUL terminator is always written
|
||||||
|
* for convenience, and isn't included in the output @text_size.
|
||||||
*
|
*
|
||||||
* Returns: full length of the requested string, or 0 if not found.
|
* Returns: full length of the requested string, or 0 if not found.
|
||||||
* Since: 2.1.0
|
* Since: 2.1.0
|
||||||
@ -209,7 +211,8 @@ hb_ot_name_get_utf16 (hb_face_t *face,
|
|||||||
*
|
*
|
||||||
* Fetches a font name from the OpenType 'name' table.
|
* Fetches a font name from the OpenType 'name' table.
|
||||||
* If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
|
* If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
|
||||||
* Returns string in UTF-32 encoding.
|
* Returns string in UTF-32 encoding. A NUL terminator is always written
|
||||||
|
* for convenience, and isn't included in the output @text_size.
|
||||||
*
|
*
|
||||||
* Returns: full length of the requested string, or 0 if not found.
|
* Returns: full length of the requested string, or 0 if not found.
|
||||||
* Since: 2.1.0
|
* Since: 2.1.0
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
|
|
||||||
#include "hb-open-type.hh"
|
#include "hb-open-type.hh"
|
||||||
#include "hb-ot-os2-unicode-ranges.hh"
|
#include "hb-ot-os2-unicode-ranges.hh"
|
||||||
#include "hb-ot-cmap-table.hh"
|
|
||||||
|
|
||||||
#include "hb-set.hh"
|
#include "hb-set.hh"
|
||||||
|
|
||||||
@ -172,33 +171,17 @@ struct OS2
|
|||||||
TRACE_SUBSET (this);
|
TRACE_SUBSET (this);
|
||||||
OS2 *os2_prime = c->serializer->embed (this);
|
OS2 *os2_prime = c->serializer->embed (this);
|
||||||
if (unlikely (!os2_prime)) return_trace (false);
|
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
|
/* when --gids option is not used, no need to do collect_mapping that is
|
||||||
* iterating all codepoints in each subtable, which is not efficient */
|
* iterating all codepoints in each subtable, which is not efficient */
|
||||||
uint16_t min_cp, max_cp;
|
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->usFirstCharIndex = min_cp;
|
||||||
os2_prime->usLastCharIndex = max_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);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
130
gfx/harfbuzz/src/hb-ot-post-table-v2subset.hh
Normal file
130
gfx/harfbuzz/src/hb-ot-post-table-v2subset.hh
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2021 Google, Inc.
|
||||||
|
*
|
||||||
|
* This is part of HarfBuzz, a text shaping library.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, without written agreement and without
|
||||||
|
* license or royalty fees, to use, copy, modify, and distribute this
|
||||||
|
* software and its documentation for any purpose, provided that the
|
||||||
|
* above copyright notice and the following two paragraphs appear in
|
||||||
|
* all copies of this software.
|
||||||
|
*
|
||||||
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||||
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||||
|
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
* DAMAGE.
|
||||||
|
*
|
||||||
|
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||||
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||||
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HB_OT_POST_TABLE_V2SUBSET_HH
|
||||||
|
#define HB_OT_POST_TABLE_V2SUBSET_HH
|
||||||
|
|
||||||
|
#include "hb-open-type.hh"
|
||||||
|
#include "hb-ot-post-table.hh"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* post -- PostScript
|
||||||
|
* https://docs.microsoft.com/en-us/typography/opentype/spec/post
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OT {
|
||||||
|
template<typename Iterator>
|
||||||
|
HB_INTERNAL bool postV2Tail::serialize (hb_serialize_context_t *c,
|
||||||
|
Iterator it,
|
||||||
|
const void* _post) const
|
||||||
|
{
|
||||||
|
TRACE_SERIALIZE (this);
|
||||||
|
auto *out = c->start_embed (this);
|
||||||
|
if (unlikely (!c->check_success (out))) return_trace (false);
|
||||||
|
if (!out->glyphNameIndex.serialize (c, + it
|
||||||
|
| hb_map (hb_second)))
|
||||||
|
return_trace (false);
|
||||||
|
|
||||||
|
hb_set_t copied_indices;
|
||||||
|
for (const auto& _ : + it )
|
||||||
|
{
|
||||||
|
unsigned glyph_id = _.first;
|
||||||
|
unsigned new_index = _.second;
|
||||||
|
|
||||||
|
if (new_index < 258) continue;
|
||||||
|
if (copied_indices.has (new_index)) continue;
|
||||||
|
copied_indices.add (new_index);
|
||||||
|
|
||||||
|
hb_bytes_t s = reinterpret_cast<const post::accelerator_t*> (_post)->find_glyph_name (glyph_id);
|
||||||
|
HBUINT8 *o = c->allocate_size<HBUINT8> (HBUINT8::static_size * (s.length + 1));
|
||||||
|
if (unlikely (!o)) return_trace (false);
|
||||||
|
if (!c->check_assign (o[0], s.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
|
||||||
|
memcpy (o+1, s.arrayZ, HBUINT8::static_size * s.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return_trace (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
|
||||||
|
{
|
||||||
|
TRACE_SUBSET (this);
|
||||||
|
|
||||||
|
const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
|
||||||
|
unsigned num_glyphs = c->plan->num_output_glyphs ();
|
||||||
|
hb_map_t old_new_index_map, old_gid_new_index_map;
|
||||||
|
unsigned i = 0;
|
||||||
|
|
||||||
|
post::accelerator_t _post;
|
||||||
|
_post.init (c->plan->source);
|
||||||
|
|
||||||
|
for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
|
||||||
|
{
|
||||||
|
hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
|
||||||
|
unsigned old_index = glyphNameIndex[old_gid];
|
||||||
|
|
||||||
|
unsigned new_index;
|
||||||
|
if (old_index <= 257) new_index = old_index;
|
||||||
|
else if (old_new_index_map.has (old_index)) new_index = old_new_index_map.get (old_index);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hb_bytes_t s = _post.find_glyph_name (old_gid);
|
||||||
|
int standard_glyph_index = -1;
|
||||||
|
for (unsigned i = 0; i < format1_names_length; i++)
|
||||||
|
{
|
||||||
|
if (s == format1_names (i))
|
||||||
|
{
|
||||||
|
standard_glyph_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (standard_glyph_index == -1)
|
||||||
|
{
|
||||||
|
new_index = 258 + i;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ new_index = standard_glyph_index; }
|
||||||
|
old_new_index_map.set (old_index, new_index);
|
||||||
|
}
|
||||||
|
old_gid_new_index_map.set (old_gid, new_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto index_iter =
|
||||||
|
+ hb_range (num_glyphs)
|
||||||
|
| hb_map (reverse_glyph_map)
|
||||||
|
| hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
|
||||||
|
{
|
||||||
|
unsigned new_index = old_gid_new_index_map.get (old_gid);
|
||||||
|
return hb_pair_t<unsigned, unsigned> (old_gid, new_index);
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
bool ret = serialize (c->serializer, index_iter, &_post);
|
||||||
|
_post.fini ();
|
||||||
|
return_trace (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace OT */
|
||||||
|
#endif /* HB_OT_POST_TABLE_V2SUBSET_HH */
|
@ -55,6 +55,13 @@ struct postV2Tail
|
|||||||
return_trace (glyphNameIndex.sanitize (c));
|
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:
|
protected:
|
||||||
Array16Of<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'
|
* ordinal number of the glyph in 'post'
|
||||||
@ -71,13 +78,18 @@ struct post
|
|||||||
{
|
{
|
||||||
static constexpr hb_tag_t tableTag = HB_OT_TAG_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> ();
|
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);
|
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
|
bool subset (hb_subset_context_t *c) const
|
||||||
@ -86,13 +98,19 @@ struct post
|
|||||||
post *post_prime = c->serializer->start_embed<post> ();
|
post *post_prime = c->serializer->start_embed<post> ();
|
||||||
if (unlikely (!post_prime)) return_trace (false);
|
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);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct accelerator_t
|
struct accelerator_t
|
||||||
{
|
{
|
||||||
|
friend struct postV2Tail;
|
||||||
void init (hb_face_t *face)
|
void init (hb_face_t *face)
|
||||||
{
|
{
|
||||||
index_to_offset.init ();
|
index_to_offset.init ();
|
||||||
@ -117,7 +135,7 @@ struct post
|
|||||||
void fini ()
|
void fini ()
|
||||||
{
|
{
|
||||||
index_to_offset.fini ();
|
index_to_offset.fini ();
|
||||||
free (gids_sorted_by_name.get ());
|
hb_free (gids_sorted_by_name.get ());
|
||||||
table.destroy ();
|
table.destroy ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +166,7 @@ struct post
|
|||||||
|
|
||||||
if (unlikely (!gids))
|
if (unlikely (!gids))
|
||||||
{
|
{
|
||||||
gids = (uint16_t *) malloc (count * sizeof (gids[0]));
|
gids = (uint16_t *) hb_malloc (count * sizeof (gids[0]));
|
||||||
if (unlikely (!gids))
|
if (unlikely (!gids))
|
||||||
return false; /* Anything better?! */
|
return false; /* Anything better?! */
|
||||||
|
|
||||||
@ -158,7 +176,7 @@ struct post
|
|||||||
|
|
||||||
if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids)))
|
if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids)))
|
||||||
{
|
{
|
||||||
free (gids);
|
hb_free (gids);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,7 +290,7 @@ static arabic_fallback_plan_t *
|
|||||||
arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
|
arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
|
||||||
hb_font_t *font)
|
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))
|
if (unlikely (!fallback_plan))
|
||||||
return const_cast<arabic_fallback_plan_t *> (&Null (arabic_fallback_plan_t));
|
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;
|
return fallback_plan;
|
||||||
|
|
||||||
assert (fallback_plan->num_lookups == 0);
|
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));
|
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 ();
|
fallback_plan->accel_array[i].fini ();
|
||||||
if (fallback_plan->free_lookups)
|
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
|
static void
|
||||||
|
@ -259,7 +259,7 @@ struct arabic_shape_plan_t
|
|||||||
void *
|
void *
|
||||||
data_create_arabic (const hb_ot_shape_plan_t *plan)
|
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))
|
if (unlikely (!arabic_plan))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@ -282,7 +282,7 @@ data_destroy_arabic (void *data)
|
|||||||
|
|
||||||
arabic_fallback_plan_destroy (arabic_plan->fallback_plan);
|
arabic_fallback_plan_destroy (arabic_plan->fallback_plan);
|
||||||
|
|
||||||
free (data);
|
hb_free (data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -80,7 +80,7 @@ struct hangul_shape_plan_t
|
|||||||
static void *
|
static void *
|
||||||
data_create_hangul (const hb_ot_shape_plan_t *plan)
|
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))
|
if (unlikely (!hangul_plan))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ data_create_hangul (const hb_ot_shape_plan_t *plan)
|
|||||||
static void
|
static void
|
||||||
data_destroy_hangul (void *data)
|
data_destroy_hangul (void *data)
|
||||||
{
|
{
|
||||||
free (data);
|
hb_free (data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Constants for algorithmic hangul syllable [de]composition. */
|
/* Constants for algorithmic hangul syllable [de]composition. */
|
||||||
|
@ -106,7 +106,8 @@ indic_features[] =
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Basic 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('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS},
|
||||||
{HB_TAG('a','k','h','n'), 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},
|
{HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS},
|
||||||
/*
|
/*
|
||||||
* Other features.
|
* Other features.
|
||||||
* These features are applied all at once, after final_reordering
|
* These features are applied all at once, after final_reordering, constrained
|
||||||
* but before clearing syllables.
|
* to the syllable.
|
||||||
* Default Bengali font in Windows for example has intermixed
|
* Default Bengali font in Windows for example has intermixed
|
||||||
* lookups for init,pres,abvs,blws features.
|
* lookups for init,pres,abvs,blws features.
|
||||||
*/
|
*/
|
||||||
@ -257,7 +258,7 @@ struct indic_shape_plan_t
|
|||||||
static void *
|
static void *
|
||||||
data_create_indic (const hb_ot_shape_plan_t *plan)
|
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))
|
if (unlikely (!indic_plan))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@ -300,7 +301,7 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
|
|||||||
static void
|
static void
|
||||||
data_destroy_indic (void *data)
|
data_destroy_indic (void *data)
|
||||||
{
|
{
|
||||||
free (data);
|
hb_free (data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static indic_position_t
|
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,
|
hb_syllabic_insert_dotted_circles (font, buffer,
|
||||||
indic_broken_cluster,
|
indic_broken_cluster,
|
||||||
OT_DOTTEDCIRCLE,
|
OT_DOTTEDCIRCLE,
|
||||||
OT_Repha);
|
OT_Repha,
|
||||||
|
POS_END);
|
||||||
|
|
||||||
foreach_syllable (buffer, start, end)
|
foreach_syllable (buffer, start, end)
|
||||||
initial_reordering_syllable_indic (plan, font->face, buffer, start, end);
|
initial_reordering_syllable_indic (plan, font->face, buffer, start, end);
|
||||||
|
@ -42,7 +42,8 @@ khmer_features[] =
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Basic 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('p','r','e','f'), F_MANUAL_JOINERS},
|
||||||
{HB_TAG('b','l','w','f'), F_MANUAL_JOINERS},
|
{HB_TAG('b','l','w','f'), F_MANUAL_JOINERS},
|
||||||
@ -147,7 +148,7 @@ struct khmer_shape_plan_t
|
|||||||
static void *
|
static void *
|
||||||
data_create_khmer (const hb_ot_shape_plan_t *plan)
|
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))
|
if (unlikely (!khmer_plan))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@ -161,7 +162,7 @@ data_create_khmer (const hb_ot_shape_plan_t *plan)
|
|||||||
static void
|
static void
|
||||||
data_destroy_khmer (void *data)
|
data_destroy_khmer (void *data)
|
||||||
{
|
{
|
||||||
free (data);
|
hb_free (data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -41,7 +41,8 @@ myanmar_basic_features[] =
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* 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('r','p','h','f'),
|
||||||
HB_TAG('p','r','e','f'),
|
HB_TAG('p','r','e','f'),
|
||||||
|
@ -34,7 +34,8 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
|
|||||||
hb_buffer_t *buffer,
|
hb_buffer_t *buffer,
|
||||||
unsigned int broken_syllable_type,
|
unsigned int broken_syllable_type,
|
||||||
unsigned int dottedcircle_category,
|
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))
|
if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
|
||||||
return;
|
return;
|
||||||
@ -61,6 +62,8 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
|
|||||||
hb_glyph_info_t dottedcircle = {0};
|
hb_glyph_info_t dottedcircle = {0};
|
||||||
dottedcircle.codepoint = 0x25CCu;
|
dottedcircle.codepoint = 0x25CCu;
|
||||||
dottedcircle.complex_var_u8_category() = dottedcircle_category;
|
dottedcircle.complex_var_u8_category() = dottedcircle_category;
|
||||||
|
if (dottedcircle_position != -1)
|
||||||
|
dottedcircle.complex_var_u8_auxiliary() = dottedcircle_position;
|
||||||
dottedcircle.codepoint = dottedcircle_glyph;
|
dottedcircle.codepoint = dottedcircle_glyph;
|
||||||
|
|
||||||
buffer->clear_output ();
|
buffer->clear_output ();
|
||||||
|
@ -35,7 +35,8 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
|
|||||||
hb_buffer_t *buffer,
|
hb_buffer_t *buffer,
|
||||||
unsigned int broken_syllable_type,
|
unsigned int broken_syllable_type,
|
||||||
unsigned int dottedcircle_category,
|
unsigned int dottedcircle_category,
|
||||||
int repha_category = -1);
|
int repha_category = -1,
|
||||||
|
int dottedcircle_position = -1);
|
||||||
|
|
||||||
|
|
||||||
#endif /* HB_OT_SHAPE_COMPLEX_SYLLABIC_HH */
|
#endif /* HB_OT_SHAPE_COMPLEX_SYLLABIC_HH */
|
||||||
|
@ -375,7 +375,9 @@ hb_iter_with_fallback_t<machine_index_t<Iter>,
|
|||||||
typename Iter::item_t>
|
typename Iter::item_t>
|
||||||
{
|
{
|
||||||
machine_index_t (const Iter& it) : it (it) {}
|
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_random_access_iterator = Iter::is_random_access_iterator;
|
||||||
static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
|
static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
|
||||||
|
@ -47,7 +47,8 @@ use_basic_features[] =
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* 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('r','k','r','f'),
|
||||||
HB_TAG('a','b','v','f'),
|
HB_TAG('a','b','v','f'),
|
||||||
@ -154,7 +155,7 @@ struct use_shape_plan_t
|
|||||||
static void *
|
static void *
|
||||||
data_create_use (const hb_ot_shape_plan_t *plan)
|
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))
|
if (unlikely (!use_plan))
|
||||||
return nullptr;
|
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);
|
use_plan->arabic_plan = (arabic_shape_plan_t *) data_create_arabic (plan);
|
||||||
if (unlikely (!use_plan->arabic_plan))
|
if (unlikely (!use_plan->arabic_plan))
|
||||||
{
|
{
|
||||||
free (use_plan);
|
hb_free (use_plan);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -181,7 +182,7 @@ data_destroy_use (void *data)
|
|||||||
if (use_plan->arabic_plan)
|
if (use_plan->arabic_plan)
|
||||||
data_destroy_arabic (use_plan->arabic_plan);
|
data_destroy_arabic (use_plan->arabic_plan);
|
||||||
|
|
||||||
free (data);
|
hb_free (data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -149,13 +149,17 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
|
|||||||
* Decide who does positioning. GPOS, kerx, kern, or fallback.
|
* Decide who does positioning. GPOS, kerx, kern, or fallback.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (0)
|
#ifndef HB_NO_AAT_SHAPE
|
||||||
|
bool has_gsub = hb_ot_layout_has_substitution (face);
|
||||||
|
#endif
|
||||||
|
bool has_gpos = !disable_gpos && hb_ot_layout_has_positioning (face);
|
||||||
|
if (false)
|
||||||
;
|
;
|
||||||
#ifndef HB_NO_AAT_SHAPE
|
#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;
|
plan.apply_kerx = true;
|
||||||
#endif
|
#endif
|
||||||
else if (!apply_morx && !disable_gpos && hb_ot_layout_has_positioning (face))
|
else if (!apply_morx && has_gpos)
|
||||||
plan.apply_gpos = true;
|
plan.apply_gpos = true;
|
||||||
|
|
||||||
if (!plan.apply_kerx && (!has_gpos_kern || !plan.apply_gpos))
|
if (!plan.apply_kerx && (!has_gpos_kern || !plan.apply_gpos))
|
||||||
@ -172,6 +176,8 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plan.apply_fallback_kern = !(plan.apply_gpos || plan.apply_kerx || plan.apply_kern);
|
||||||
|
|
||||||
plan.zero_marks = script_zero_marks &&
|
plan.zero_marks = script_zero_marks &&
|
||||||
!plan.apply_kerx &&
|
!plan.apply_kerx &&
|
||||||
(!plan.apply_kern
|
(!plan.apply_kern
|
||||||
@ -272,11 +278,12 @@ hb_ot_shape_plan_t::position (hb_font_t *font,
|
|||||||
else if (this->apply_kerx)
|
else if (this->apply_kerx)
|
||||||
hb_aat_layout_position (this, font, buffer);
|
hb_aat_layout_position (this, font, buffer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HB_NO_OT_KERN
|
#ifndef HB_NO_OT_KERN
|
||||||
else if (this->apply_kern)
|
if (this->apply_kern)
|
||||||
hb_ot_layout_kern (this, font, buffer);
|
hb_ot_layout_kern (this, font, buffer);
|
||||||
#endif
|
#endif
|
||||||
else
|
else if (this->apply_fallback_kern)
|
||||||
_hb_ot_shape_fallback_kern (this, font, buffer);
|
_hb_ot_shape_fallback_kern (this, font, buffer);
|
||||||
|
|
||||||
#ifndef HB_NO_AAT_SHAPE
|
#ifndef HB_NO_AAT_SHAPE
|
||||||
@ -321,7 +328,8 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
|
|||||||
map->enable_feature (HB_TAG('r','v','r','n'));
|
map->enable_feature (HB_TAG('r','v','r','n'));
|
||||||
map->add_gsub_pause (nullptr);
|
map->add_gsub_pause (nullptr);
|
||||||
|
|
||||||
switch (planner->props.direction) {
|
switch (planner->props.direction)
|
||||||
|
{
|
||||||
case HB_DIRECTION_LTR:
|
case HB_DIRECTION_LTR:
|
||||||
map->enable_feature (HB_TAG ('l','t','r','a'));
|
map->enable_feature (HB_TAG ('l','t','r','a'));
|
||||||
map->enable_feature (HB_TAG ('l','t','r','m'));
|
map->enable_feature (HB_TAG ('l','t','r','m'));
|
||||||
@ -369,6 +377,10 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
|
|||||||
map->add_feature (horizontal_features[i]);
|
map->add_feature (horizontal_features[i]);
|
||||||
else
|
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
|
/* 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.
|
* matter which script/langsys it is listed (or not) under.
|
||||||
* See various bugs referenced from:
|
* See various bugs referenced from:
|
||||||
@ -486,6 +498,14 @@ hb_set_unicode_props (hb_buffer_t *buffer)
|
|||||||
{
|
{
|
||||||
_hb_glyph_info_set_continuation (&info[i]);
|
_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
|
#ifndef HB_NO_EMOJI_SEQUENCES
|
||||||
else if (unlikely (_hb_glyph_info_is_zwj (&info[i])))
|
else if (unlikely (_hb_glyph_info_is_zwj (&info[i])))
|
||||||
{
|
{
|
||||||
@ -541,6 +561,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
|
|||||||
info.cluster = buffer->cur().cluster;
|
info.cluster = buffer->cur().cluster;
|
||||||
info.mask = buffer->cur().mask;
|
info.mask = buffer->cur().mask;
|
||||||
(void) buffer->output_info (info);
|
(void) buffer->output_info (info);
|
||||||
|
|
||||||
buffer->swap_buffers ();
|
buffer->swap_buffers ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,6 +585,36 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
|
|||||||
hb_direction_t direction = buffer->props.direction;
|
hb_direction_t direction = buffer->props.direction;
|
||||||
hb_direction_t horiz_dir = hb_script_get_horizontal_direction (buffer->props.script);
|
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:
|
/* TODO vertical:
|
||||||
* The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
|
* 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
|
* Ogham fonts are supposed to be implemented BTT or not. Need to research that
|
||||||
@ -1117,8 +1168,6 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
|
|||||||
|
|
||||||
_hb_buffer_allocate_unicode_vars (c->buffer);
|
_hb_buffer_allocate_unicode_vars (c->buffer);
|
||||||
|
|
||||||
c->buffer->clear_output ();
|
|
||||||
|
|
||||||
hb_ot_shape_initialize_masks (c);
|
hb_ot_shape_initialize_masks (c);
|
||||||
hb_set_unicode_props (c->buffer);
|
hb_set_unicode_props (c->buffer);
|
||||||
hb_insert_dotted_circle (c->buffer, c->font);
|
hb_insert_dotted_circle (c->buffer, c->font);
|
||||||
@ -1128,7 +1177,8 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
|
|||||||
hb_ensure_native_direction (c->buffer);
|
hb_ensure_native_direction (c->buffer);
|
||||||
|
|
||||||
if (c->plan->shaper->preprocess_text &&
|
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);
|
c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
|
||||||
(void) c->buffer->message(c->font, "end preprocess-text");
|
(void) c->buffer->message(c->font, "end preprocess-text");
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,7 @@ struct hb_ot_shape_plan_t
|
|||||||
#else
|
#else
|
||||||
static constexpr bool apply_kern = false;
|
static constexpr bool apply_kern = false;
|
||||||
#endif
|
#endif
|
||||||
|
bool apply_fallback_kern : 1;
|
||||||
#ifndef HB_NO_AAT_SHAPE
|
#ifndef HB_NO_AAT_SHAPE
|
||||||
bool apply_kerx : 1;
|
bool apply_kerx : 1;
|
||||||
bool apply_morx : 1;
|
bool apply_morx : 1;
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
*
|
*
|
||||||
* on files with these headers:
|
* on files with these headers:
|
||||||
*
|
*
|
||||||
* <meta name="updated_at" content="2021-02-12 04:08 PM" />
|
* <meta name="updated_at" content="2021-09-02 09:40 PM" />
|
||||||
* File-Date: 2021-03-05
|
* File-Date: 2021-08-06
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef HB_OT_TAG_TABLE_HH
|
#ifndef HB_OT_TAG_TABLE_HH
|
||||||
@ -93,6 +93,7 @@ static const LangTag ot_languages[] = {
|
|||||||
{"auz", HB_TAG('A','R','A',' ')}, /* Uzbeki Arabic -> Arabic */
|
{"auz", HB_TAG('A','R','A',' ')}, /* Uzbeki Arabic -> Arabic */
|
||||||
{"av", HB_TAG('A','V','R',' ')}, /* Avaric -> Avar */
|
{"av", HB_TAG('A','V','R',' ')}, /* Avaric -> Avar */
|
||||||
{"avl", HB_TAG('A','R','A',' ')}, /* Eastern Egyptian Bedawi Arabic -> Arabic */
|
{"avl", HB_TAG('A','R','A',' ')}, /* Eastern Egyptian Bedawi Arabic -> Arabic */
|
||||||
|
/*{"avn", HB_TAG('A','V','N',' ')},*/ /* Avatime */
|
||||||
/*{"awa", HB_TAG('A','W','A',' ')},*/ /* Awadhi */
|
/*{"awa", HB_TAG('A','W','A',' ')},*/ /* Awadhi */
|
||||||
{"ay", HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */
|
{"ay", HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */
|
||||||
{"ayc", HB_TAG('A','Y','M',' ')}, /* Southern Aymara -> Aymara */
|
{"ayc", HB_TAG('A','Y','M',' ')}, /* Southern Aymara -> Aymara */
|
||||||
@ -345,6 +346,7 @@ static const LangTag ot_languages[] = {
|
|||||||
{"cth", HB_TAG('Q','I','N',' ')}, /* Thaiphum Chin -> Chin */
|
{"cth", HB_TAG('Q','I','N',' ')}, /* Thaiphum Chin -> Chin */
|
||||||
{"ctl", HB_TAG('C','C','H','N')}, /* Tlacoatzintepec Chinantec -> Chinantec */
|
{"ctl", HB_TAG('C','C','H','N')}, /* Tlacoatzintepec Chinantec -> Chinantec */
|
||||||
{"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol -> Bikol */
|
{"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol -> Bikol */
|
||||||
|
/*{"ctt", HB_TAG('C','T','T',' ')},*/ /* Wayanad Chetti */
|
||||||
{"ctu", HB_TAG('M','Y','N',' ')}, /* Chol -> Mayan */
|
{"ctu", HB_TAG('M','Y','N',' ')}, /* Chol -> Mayan */
|
||||||
{"cu", HB_TAG('C','S','L',' ')}, /* Church Slavonic */
|
{"cu", HB_TAG('C','S','L',' ')}, /* Church Slavonic */
|
||||||
{"cuc", HB_TAG('C','C','H','N')}, /* Usila Chinantec -> Chinantec */
|
{"cuc", HB_TAG('C','C','H','N')}, /* Usila Chinantec -> Chinantec */
|
||||||
@ -537,23 +539,27 @@ static const LangTag ot_languages[] = {
|
|||||||
{"ha", HB_TAG('H','A','U',' ')}, /* Hausa */
|
{"ha", HB_TAG('H','A','U',' ')}, /* Hausa */
|
||||||
{"haa", HB_TAG('A','T','H',' ')}, /* Han -> Athapaskan */
|
{"haa", HB_TAG('A','T','H',' ')}, /* Han -> Athapaskan */
|
||||||
{"hae", HB_TAG('O','R','O',' ')}, /* Eastern Oromo -> Oromo */
|
{"hae", HB_TAG('O','R','O',' ')}, /* Eastern Oromo -> Oromo */
|
||||||
{"hai", HB_TAG_NONE }, /* Haida [macrolanguage] != Haitian (Haitian Creole) */
|
{"hai", HB_TAG('H','A','I','0')}, /* Haida [macrolanguage] */
|
||||||
{"hak", HB_TAG('Z','H','S',' ')}, /* Hakka Chinese -> Chinese, Simplified */
|
{"hak", HB_TAG('Z','H','S',' ')}, /* Hakka Chinese -> Chinese, Simplified */
|
||||||
{"hal", HB_TAG_NONE }, /* Halang != Halam (Falam Chin) */
|
{"hal", HB_TAG_NONE }, /* Halang != Halam (Falam Chin) */
|
||||||
{"har", HB_TAG('H','R','I',' ')}, /* Harari */
|
{"har", HB_TAG('H','R','I',' ')}, /* Harari */
|
||||||
/*{"haw", HB_TAG('H','A','W',' ')},*/ /* Hawaiian */
|
/*{"haw", HB_TAG('H','A','W',' ')},*/ /* Hawaiian */
|
||||||
|
{"hax", HB_TAG('H','A','I','0')}, /* Southern Haida -> Haida */
|
||||||
/*{"hay", HB_TAG('H','A','Y',' ')},*/ /* Haya */
|
/*{"hay", HB_TAG('H','A','Y',' ')},*/ /* Haya */
|
||||||
/*{"haz", HB_TAG('H','A','Z',' ')},*/ /* Hazaragi */
|
/*{"haz", HB_TAG('H','A','Z',' ')},*/ /* Hazaragi */
|
||||||
{"hbn", HB_TAG_NONE }, /* Heiban != Hammer-Banna */
|
{"hbn", HB_TAG_NONE }, /* Heiban != Hammer-Banna */
|
||||||
{"hca", HB_TAG('C','P','P',' ')}, /* Andaman Creole Hindi -> Creoles */
|
{"hca", HB_TAG('C','P','P',' ')}, /* Andaman Creole Hindi -> Creoles */
|
||||||
|
{"hdn", HB_TAG('H','A','I','0')}, /* Northern Haida -> Haida */
|
||||||
{"he", HB_TAG('I','W','R',' ')}, /* Hebrew */
|
{"he", HB_TAG('I','W','R',' ')}, /* Hebrew */
|
||||||
{"hea", HB_TAG('H','M','N',' ')}, /* Northern Qiandong Miao -> Hmong */
|
{"hea", HB_TAG('H','M','N',' ')}, /* Northern Qiandong Miao -> Hmong */
|
||||||
|
/*{"hei", HB_TAG('H','E','I',' ')},*/ /* Heiltsuk */
|
||||||
{"hi", HB_TAG('H','I','N',' ')}, /* Hindi */
|
{"hi", HB_TAG('H','I','N',' ')}, /* Hindi */
|
||||||
/*{"hil", HB_TAG('H','I','L',' ')},*/ /* Hiligaynon */
|
/*{"hil", HB_TAG('H','I','L',' ')},*/ /* Hiligaynon */
|
||||||
{"hji", HB_TAG('M','L','Y',' ')}, /* Haji -> Malay */
|
{"hji", HB_TAG('M','L','Y',' ')}, /* Haji -> Malay */
|
||||||
{"hlt", HB_TAG('Q','I','N',' ')}, /* Matu Chin -> Chin */
|
{"hlt", HB_TAG('Q','I','N',' ')}, /* Matu Chin -> Chin */
|
||||||
{"hma", HB_TAG('H','M','N',' ')}, /* Southern Mashan Hmong -> Hmong */
|
{"hma", HB_TAG('H','M','N',' ')}, /* Southern Mashan Hmong -> Hmong */
|
||||||
{"hmc", HB_TAG('H','M','N',' ')}, /* Central Huishui Hmong -> Hmong */
|
{"hmc", HB_TAG('H','M','N',' ')}, /* Central Huishui Hmong -> Hmong */
|
||||||
|
{"hmd", HB_TAG('H','M','D',' ')}, /* Large Flowery Miao -> A-Hmao */
|
||||||
{"hmd", HB_TAG('H','M','N',' ')}, /* Large Flowery Miao -> Hmong */
|
{"hmd", HB_TAG('H','M','N',' ')}, /* Large Flowery Miao -> Hmong */
|
||||||
{"hme", HB_TAG('H','M','N',' ')}, /* Eastern Huishui Hmong -> Hmong */
|
{"hme", HB_TAG('H','M','N',' ')}, /* Eastern Huishui Hmong -> Hmong */
|
||||||
{"hmg", HB_TAG('H','M','N',' ')}, /* Southwestern Guiyang Hmong -> Hmong */
|
{"hmg", HB_TAG('H','M','N',' ')}, /* Southwestern Guiyang Hmong -> Hmong */
|
||||||
@ -569,6 +575,7 @@ static const LangTag ot_languages[] = {
|
|||||||
{"hms", HB_TAG('H','M','N',' ')}, /* Southern Qiandong Miao -> Hmong */
|
{"hms", HB_TAG('H','M','N',' ')}, /* Southern Qiandong Miao -> Hmong */
|
||||||
{"hmw", HB_TAG('H','M','N',' ')}, /* Western Mashan Hmong -> Hmong */
|
{"hmw", HB_TAG('H','M','N',' ')}, /* Western Mashan Hmong -> Hmong */
|
||||||
{"hmy", HB_TAG('H','M','N',' ')}, /* Southern Guiyang Hmong -> Hmong */
|
{"hmy", HB_TAG('H','M','N',' ')}, /* Southern Guiyang Hmong -> Hmong */
|
||||||
|
{"hmz", HB_TAG('H','M','Z',' ')}, /* Hmong Shua -> Hmong Shuat */
|
||||||
{"hmz", HB_TAG('H','M','N',' ')}, /* Hmong Shua -> Hmong */
|
{"hmz", HB_TAG('H','M','N',' ')}, /* Hmong Shua -> Hmong */
|
||||||
/*{"hnd", HB_TAG('H','N','D',' ')},*/ /* Southern Hindko -> Hindko */
|
/*{"hnd", HB_TAG('H','N','D',' ')},*/ /* Southern Hindko -> Hindko */
|
||||||
{"hne", HB_TAG('C','H','H',' ')}, /* Chhattisgarhi -> Chattisgarhi */
|
{"hne", HB_TAG('C','H','H',' ')}, /* Chhattisgarhi -> Chattisgarhi */
|
||||||
@ -625,6 +632,7 @@ static const LangTag ot_languages[] = {
|
|||||||
{"inh", HB_TAG('I','N','G',' ')}, /* Ingush */
|
{"inh", HB_TAG('I','N','G',' ')}, /* Ingush */
|
||||||
{"io", HB_TAG('I','D','O',' ')}, /* Ido */
|
{"io", HB_TAG('I','D','O',' ')}, /* Ido */
|
||||||
{"iri", HB_TAG_NONE }, /* Rigwe != Irish */
|
{"iri", HB_TAG_NONE }, /* Rigwe != Irish */
|
||||||
|
/*{"iru", HB_TAG('I','R','U',' ')},*/ /* Irula */
|
||||||
{"is", HB_TAG('I','S','L',' ')}, /* Icelandic */
|
{"is", HB_TAG('I','S','L',' ')}, /* Icelandic */
|
||||||
{"ism", HB_TAG_NONE }, /* Masimasi != Inari Sami */
|
{"ism", HB_TAG_NONE }, /* Masimasi != Inari Sami */
|
||||||
{"it", HB_TAG('I','T','A',' ')}, /* Italian */
|
{"it", HB_TAG('I','T','A',' ')}, /* Italian */
|
||||||
@ -660,6 +668,7 @@ static const LangTag ot_languages[] = {
|
|||||||
{"kac", HB_TAG_NONE }, /* Kachin != Kachchi */
|
{"kac", HB_TAG_NONE }, /* Kachin != Kachchi */
|
||||||
{"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */
|
{"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */
|
||||||
{"kar", HB_TAG('K','R','N',' ')}, /* Karen [family] */
|
{"kar", HB_TAG('K','R','N',' ')}, /* Karen [family] */
|
||||||
|
/*{"kaw", HB_TAG('K','A','W',' ')},*/ /* Kawi (Old Javanese) */
|
||||||
{"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */
|
{"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */
|
||||||
{"kby", HB_TAG('K','N','R',' ')}, /* Manga Kanuri -> Kanuri */
|
{"kby", HB_TAG('K','N','R',' ')}, /* Manga Kanuri -> Kanuri */
|
||||||
{"kca", HB_TAG('K','H','K',' ')}, /* Khanty -> Khanty-Kazim */
|
{"kca", HB_TAG('K','H','K',' ')}, /* Khanty -> Khanty-Kazim */
|
||||||
@ -779,6 +788,7 @@ static const LangTag ot_languages[] = {
|
|||||||
{"kvu", HB_TAG('K','R','N',' ')}, /* Yinbaw Karen -> Karen */
|
{"kvu", HB_TAG('K','R','N',' ')}, /* Yinbaw Karen -> Karen */
|
||||||
{"kvy", HB_TAG('K','R','N',' ')}, /* Yintale Karen -> Karen */
|
{"kvy", HB_TAG('K','R','N',' ')}, /* Yintale Karen -> Karen */
|
||||||
{"kw", HB_TAG('C','O','R',' ')}, /* Cornish */
|
{"kw", HB_TAG('C','O','R',' ')}, /* Cornish */
|
||||||
|
/*{"kwk", HB_TAG('K','W','K',' ')},*/ /* Kwakiutl -> Kwakʼwala */
|
||||||
{"kww", HB_TAG('C','P','P',' ')}, /* Kwinti -> Creoles */
|
{"kww", HB_TAG('C','P','P',' ')}, /* Kwinti -> Creoles */
|
||||||
{"kwy", HB_TAG('K','O','N','0')}, /* San Salvador Kongo -> Kongo */
|
{"kwy", HB_TAG('K','O','N','0')}, /* San Salvador Kongo -> Kongo */
|
||||||
{"kxc", HB_TAG('K','M','S',' ')}, /* Konso -> Komso */
|
{"kxc", HB_TAG('K','M','S',' ')}, /* Konso -> Komso */
|
||||||
@ -806,6 +816,7 @@ static const LangTag ot_languages[] = {
|
|||||||
{"lcf", HB_TAG('M','L','Y',' ')}, /* Lubu -> Malay */
|
{"lcf", HB_TAG('M','L','Y',' ')}, /* Lubu -> Malay */
|
||||||
{"ldi", HB_TAG('K','O','N','0')}, /* Laari -> Kongo */
|
{"ldi", HB_TAG('K','O','N','0')}, /* Laari -> Kongo */
|
||||||
{"ldk", HB_TAG_NONE }, /* Leelau != Ladakhi */
|
{"ldk", HB_TAG_NONE }, /* Leelau != Ladakhi */
|
||||||
|
/*{"lef", HB_TAG('L','E','F',' ')},*/ /* Lelemi */
|
||||||
/*{"lez", HB_TAG('L','E','Z',' ')},*/ /* Lezghian -> Lezgi */
|
/*{"lez", HB_TAG('L','E','Z',' ')},*/ /* Lezghian -> Lezgi */
|
||||||
{"lg", HB_TAG('L','U','G',' ')}, /* Ganda */
|
{"lg", HB_TAG('L','U','G',' ')}, /* Ganda */
|
||||||
{"li", HB_TAG('L','I','M',' ')}, /* Limburgish */
|
{"li", HB_TAG('L','I','M',' ')}, /* Limburgish */
|
||||||
@ -832,6 +843,7 @@ static const LangTag ot_languages[] = {
|
|||||||
{"lo", HB_TAG('L','A','O',' ')}, /* Lao */
|
{"lo", HB_TAG('L','A','O',' ')}, /* Lao */
|
||||||
/*{"lom", HB_TAG('L','O','M',' ')},*/ /* Loma (Liberia) */
|
/*{"lom", HB_TAG('L','O','M',' ')},*/ /* Loma (Liberia) */
|
||||||
{"lou", HB_TAG('C','P','P',' ')}, /* Louisiana Creole -> Creoles */
|
{"lou", HB_TAG('C','P','P',' ')}, /* Louisiana Creole -> Creoles */
|
||||||
|
/*{"lpo", HB_TAG('L','P','O',' ')},*/ /* Lipo */
|
||||||
/*{"lrc", HB_TAG('L','R','C',' ')},*/ /* Northern Luri -> Luri */
|
/*{"lrc", HB_TAG('L','R','C',' ')},*/ /* Northern Luri -> Luri */
|
||||||
{"lri", HB_TAG('L','U','H',' ')}, /* Marachi -> Luyia */
|
{"lri", HB_TAG('L','U','H',' ')}, /* Marachi -> Luyia */
|
||||||
{"lrm", HB_TAG('L','U','H',' ')}, /* Marama -> Luyia */
|
{"lrm", HB_TAG('L','U','H',' ')}, /* Marama -> Luyia */
|
||||||
@ -1231,6 +1243,7 @@ static const LangTag ot_languages[] = {
|
|||||||
{"rbl", HB_TAG('B','I','K',' ')}, /* Miraya Bikol -> Bikol */
|
{"rbl", HB_TAG('B','I','K',' ')}, /* Miraya Bikol -> Bikol */
|
||||||
{"rcf", HB_TAG('C','P','P',' ')}, /* Réunion Creole French -> Creoles */
|
{"rcf", HB_TAG('C','P','P',' ')}, /* Réunion Creole French -> Creoles */
|
||||||
/*{"rej", HB_TAG('R','E','J',' ')},*/ /* Rejang */
|
/*{"rej", HB_TAG('R','E','J',' ')},*/ /* Rejang */
|
||||||
|
/*{"rhg", HB_TAG('R','H','G',' ')},*/ /* Rohingya */
|
||||||
/*{"ria", HB_TAG('R','I','A',' ')},*/ /* Riang (India) */
|
/*{"ria", HB_TAG('R','I','A',' ')},*/ /* Riang (India) */
|
||||||
{"rif", HB_TAG('R','I','F',' ')}, /* Tarifit */
|
{"rif", HB_TAG('R','I','F',' ')}, /* Tarifit */
|
||||||
{"rif", HB_TAG('B','B','R',' ')}, /* Tarifit -> Berber */
|
{"rif", HB_TAG('B','B','R',' ')}, /* Tarifit -> Berber */
|
||||||
@ -1286,6 +1299,7 @@ static const LangTag ot_languages[] = {
|
|||||||
{"sek", HB_TAG('A','T','H',' ')}, /* Sekani -> Athapaskan */
|
{"sek", HB_TAG('A','T','H',' ')}, /* Sekani -> Athapaskan */
|
||||||
/*{"sel", HB_TAG('S','E','L',' ')},*/ /* Selkup */
|
/*{"sel", HB_TAG('S','E','L',' ')},*/ /* Selkup */
|
||||||
{"sez", HB_TAG('Q','I','N',' ')}, /* Senthang Chin -> Chin */
|
{"sez", HB_TAG('Q','I','N',' ')}, /* Senthang Chin -> Chin */
|
||||||
|
{"sfm", HB_TAG('S','F','M',' ')}, /* Small Flowery Miao */
|
||||||
{"sfm", HB_TAG('H','M','N',' ')}, /* Small Flowery Miao -> Hmong */
|
{"sfm", HB_TAG('H','M','N',' ')}, /* Small Flowery Miao -> Hmong */
|
||||||
{"sg", HB_TAG('S','G','O',' ')}, /* Sango */
|
{"sg", HB_TAG('S','G','O',' ')}, /* Sango */
|
||||||
/*{"sga", HB_TAG('S','G','A',' ')},*/ /* Old Irish (to 900) */
|
/*{"sga", HB_TAG('S','G','A',' ')},*/ /* Old Irish (to 900) */
|
||||||
@ -1413,6 +1427,7 @@ static const LangTag ot_languages[] = {
|
|||||||
{"tkg", HB_TAG('M','L','G',' ')}, /* Tesaka Malagasy -> Malagasy */
|
{"tkg", HB_TAG('M','L','G',' ')}, /* Tesaka Malagasy -> Malagasy */
|
||||||
{"tkm", HB_TAG_NONE }, /* Takelma != Turkmen */
|
{"tkm", HB_TAG_NONE }, /* Takelma != Turkmen */
|
||||||
{"tl", HB_TAG('T','G','L',' ')}, /* Tagalog */
|
{"tl", HB_TAG('T','G','L',' ')}, /* Tagalog */
|
||||||
|
/*{"tli", HB_TAG('T','L','I',' ')},*/ /* Tlingit */
|
||||||
{"tmg", HB_TAG('C','P','P',' ')}, /* Ternateño -> Creoles */
|
{"tmg", HB_TAG('C','P','P',' ')}, /* Ternateño -> Creoles */
|
||||||
{"tmh", HB_TAG('T','M','H',' ')}, /* Tamashek [macrolanguage] */
|
{"tmh", HB_TAG('T','M','H',' ')}, /* Tamashek [macrolanguage] */
|
||||||
{"tmh", HB_TAG('B','B','R',' ')}, /* Tamashek [macrolanguage] -> Berber */
|
{"tmh", HB_TAG('B','B','R',' ')}, /* Tamashek [macrolanguage] -> Berber */
|
||||||
@ -1499,6 +1514,7 @@ static const LangTag ot_languages[] = {
|
|||||||
{"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */
|
{"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */
|
||||||
{"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */
|
{"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */
|
||||||
{"wbr", HB_TAG('R','A','J',' ')}, /* Wagdi -> Rajasthani */
|
{"wbr", HB_TAG('R','A','J',' ')}, /* Wagdi -> Rajasthani */
|
||||||
|
/*{"wci", HB_TAG('W','C','I',' ')},*/ /* Waci Gbe */
|
||||||
{"wea", HB_TAG('K','R','N',' ')}, /* Wewaw -> Karen */
|
{"wea", HB_TAG('K','R','N',' ')}, /* Wewaw -> Karen */
|
||||||
{"wes", HB_TAG('C','P','P',' ')}, /* Cameroon Pidgin -> Creoles */
|
{"wes", HB_TAG('C','P','P',' ')}, /* Cameroon Pidgin -> Creoles */
|
||||||
{"weu", HB_TAG('Q','I','N',' ')}, /* Rawngtu Chin -> Chin */
|
{"weu", HB_TAG('Q','I','N',' ')}, /* Rawngtu Chin -> Chin */
|
||||||
@ -1533,6 +1549,8 @@ static const LangTag ot_languages[] = {
|
|||||||
{"xsl", HB_TAG('S','L','A',' ')}, /* South Slavey -> Slavey */
|
{"xsl", HB_TAG('S','L','A',' ')}, /* South Slavey -> Slavey */
|
||||||
{"xsl", HB_TAG('A','T','H',' ')}, /* South Slavey -> Athapaskan */
|
{"xsl", HB_TAG('A','T','H',' ')}, /* South Slavey -> Athapaskan */
|
||||||
{"xst", HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) -> Silte Gurage */
|
{"xst", HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) -> Silte Gurage */
|
||||||
|
/*{"xub", HB_TAG('X','U','B',' ')},*/ /* Betta Kurumba -> Bette Kuruma */
|
||||||
|
/*{"xuj", HB_TAG('X','U','J',' ')},*/ /* Jennu Kurumba -> Jennu Kuruma */
|
||||||
{"xup", HB_TAG('A','T','H',' ')}, /* Upper Umpqua -> Athapaskan */
|
{"xup", HB_TAG('A','T','H',' ')}, /* Upper Umpqua -> Athapaskan */
|
||||||
{"xwo", HB_TAG('T','O','D',' ')}, /* Written Oirat -> Todo */
|
{"xwo", HB_TAG('T','O','D',' ')}, /* Written Oirat -> Todo */
|
||||||
{"yaj", HB_TAG('B','A','D','0')}, /* Banda-Yangere -> Banda */
|
{"yaj", HB_TAG('B','A','D','0')}, /* Banda-Yangere -> Banda */
|
||||||
@ -1543,13 +1561,16 @@ static const LangTag ot_languages[] = {
|
|||||||
{"ybb", HB_TAG('B','M','L',' ')}, /* Yemba -> Bamileke */
|
{"ybb", HB_TAG('B','M','L',' ')}, /* Yemba -> Bamileke */
|
||||||
{"ybd", HB_TAG('A','R','K',' ')}, /* Yangbye (retired code) -> Rakhine */
|
{"ybd", HB_TAG('A','R','K',' ')}, /* Yangbye (retired code) -> Rakhine */
|
||||||
{"ydd", HB_TAG('J','I','I',' ')}, /* Eastern Yiddish -> Yiddish */
|
{"ydd", HB_TAG('J','I','I',' ')}, /* Eastern Yiddish -> Yiddish */
|
||||||
|
/*{"ygp", HB_TAG('Y','G','P',' ')},*/ /* Gepo */
|
||||||
{"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */
|
{"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */
|
||||||
{"yih", HB_TAG('J','I','I',' ')}, /* Western Yiddish -> Yiddish */
|
{"yih", HB_TAG('J','I','I',' ')}, /* Western Yiddish -> Yiddish */
|
||||||
{"yim", HB_TAG_NONE }, /* Yimchungru Naga != Yi Modern */
|
{"yim", HB_TAG_NONE }, /* Yimchungru Naga != Yi Modern */
|
||||||
|
/*{"yna", HB_TAG('Y','N','A',' ')},*/ /* Aluo */
|
||||||
{"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */
|
{"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */
|
||||||
{"yos", HB_TAG('Q','I','N',' ')}, /* Yos (retired code) -> Chin */
|
{"yos", HB_TAG('Q','I','N',' ')}, /* Yos (retired code) -> Chin */
|
||||||
{"yua", HB_TAG('M','Y','N',' ')}, /* Yucateco -> Mayan */
|
{"yua", HB_TAG('M','Y','N',' ')}, /* Yucateco -> Mayan */
|
||||||
{"yue", HB_TAG('Z','H','H',' ')}, /* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */
|
{"yue", HB_TAG('Z','H','H',' ')}, /* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */
|
||||||
|
/*{"ywq", HB_TAG('Y','W','Q',' ')},*/ /* Wuding-Luquan Yi */
|
||||||
{"za", HB_TAG('Z','H','A',' ')}, /* Zhuang [macrolanguage] */
|
{"za", HB_TAG('Z','H','A',' ')}, /* Zhuang [macrolanguage] */
|
||||||
{"zch", HB_TAG('Z','H','A',' ')}, /* Central Hongshuihe Zhuang -> Zhuang */
|
{"zch", HB_TAG('Z','H','A',' ')}, /* Central Hongshuihe Zhuang -> Zhuang */
|
||||||
{"zdj", HB_TAG('C','M','R',' ')}, /* Ngazidja Comorian -> Comorian */
|
{"zdj", HB_TAG('C','M','R',' ')}, /* Ngazidja Comorian -> Comorian */
|
||||||
|
@ -522,7 +522,7 @@ hb_ot_tags_to_script_and_language (hb_tag_t script_tag,
|
|||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
const char *lang_str = hb_language_to_string (*language);
|
const char *lang_str = hb_language_to_string (*language);
|
||||||
size_t len = strlen (lang_str);
|
size_t len = strlen (lang_str);
|
||||||
buf = (unsigned char *) malloc (len + 16);
|
buf = (unsigned char *) hb_malloc (len + 16);
|
||||||
if (unlikely (!buf))
|
if (unlikely (!buf))
|
||||||
{
|
{
|
||||||
*language = nullptr;
|
*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)
|
for (shift = 28; shift >= 0; shift -= 4)
|
||||||
buf[len++] = TOHEX (script_tag >> shift);
|
buf[len++] = TOHEX (script_tag >> shift);
|
||||||
*language = hb_language_from_string ((char *) buf, len);
|
*language = hb_language_from_string ((char *) buf, len);
|
||||||
free (buf);
|
hb_free (buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,11 +142,13 @@ struct AxisRecord
|
|||||||
max = hb_max (default_, maxValue / 65536.f);
|
max = hb_max (default_, maxValue / 65536.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
Tag axisTag; /* Tag identifying the design variation for the axis. */
|
Tag axisTag; /* Tag identifying the design variation for the axis. */
|
||||||
|
protected:
|
||||||
HBFixed minValue; /* The minimum coordinate value for the axis. */
|
HBFixed minValue; /* The minimum coordinate value for the axis. */
|
||||||
HBFixed defaultValue; /* The default coordinate value for the axis. */
|
HBFixed defaultValue; /* The default coordinate value for the axis. */
|
||||||
HBFixed maxValue; /* The maximum coordinate value for the axis. */
|
HBFixed maxValue; /* The maximum coordinate value for the axis. */
|
||||||
|
public:
|
||||||
HBUINT16 flags; /* Axis flags. */
|
HBUINT16 flags; /* Axis flags. */
|
||||||
NameID axisNameID; /* The name ID for entries in the 'name' table that
|
NameID axisNameID; /* The name ID for entries in the 'name' table that
|
||||||
* provide a display name for this axis. */
|
* 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);
|
return axes.lfind (tag, axis_index) && (axes[*axis_index].get_axis_deprecated (info), true);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool
|
bool
|
||||||
find_axis_info (hb_tag_t tag, hb_ot_var_axis_info_t *info) const
|
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
|
hb_array_t<const AxisRecord> get_axes () const
|
||||||
{ return hb_array (&(this+firstAxis), axisCount); }
|
{ return hb_array (&(this+firstAxis), axisCount); }
|
||||||
|
|
||||||
|
@ -419,7 +419,9 @@ struct gvar
|
|||||||
out->glyphCount = num_glyphs;
|
out->glyphCount = num_glyphs;
|
||||||
|
|
||||||
unsigned int subset_data_size = 0;
|
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;
|
hb_codepoint_t old_gid;
|
||||||
if (!c->plan->old_gid_for_new_gid (gid, &old_gid)) continue;
|
if (!c->plan->old_gid_for_new_gid (gid, &old_gid)) continue;
|
||||||
@ -449,7 +451,9 @@ struct gvar
|
|||||||
out->dataZ = subset_data - (char *) out;
|
out->dataZ = subset_data - (char *) out;
|
||||||
|
|
||||||
unsigned int glyph_offset = 0;
|
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_codepoint_t old_gid;
|
||||||
hb_bytes_t var_data_bytes = c->plan->old_gid_for_new_gid (gid, &old_gid)
|
hb_bytes_t var_data_bytes = c->plan->old_gid_for_new_gid (gid, &old_gid)
|
||||||
|
@ -54,7 +54,7 @@ struct DeltaSetIndexMap
|
|||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (output_map.length && ((((inner_bit_count-1)&~0xF)!=0) || (((width-1)&~0x3)!=0))))
|
if (unlikely (output_map.length && ((((inner_bit_count-1)&~0xF)!=0) || (((width-1)&~0x3)!=0))))
|
||||||
return_trace (false);
|
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);
|
format = ((width-1)<<4)|(inner_bit_count-1);
|
||||||
mapCount = output_map.length;
|
mapCount = output_map.length;
|
||||||
@ -272,7 +272,7 @@ struct hvarvvar_subset_plan_t
|
|||||||
index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan);
|
index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan);
|
||||||
if (index_maps[0] == &Null (DeltaSetIndexMap))
|
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);
|
outer_map.add (0);
|
||||||
for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++)
|
for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++)
|
||||||
{
|
{
|
||||||
@ -367,15 +367,15 @@ struct HVARVVAR
|
|||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (im_plans[index_map_subset_plan_t::ADV_INDEX].is_identity ())
|
if (im_plans[index_map_subset_plan_t::ADV_INDEX].is_identity ())
|
||||||
advMap = 0;
|
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);
|
return_trace (false);
|
||||||
if (im_plans[index_map_subset_plan_t::LSB_INDEX].is_identity ())
|
if (im_plans[index_map_subset_plan_t::LSB_INDEX].is_identity ())
|
||||||
lsbMap = 0;
|
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);
|
return_trace (false);
|
||||||
if (im_plans[index_map_subset_plan_t::RSB_INDEX].is_identity ())
|
if (im_plans[index_map_subset_plan_t::RSB_INDEX].is_identity ())
|
||||||
rsbMap = 0;
|
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 (false);
|
||||||
|
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
@ -398,8 +398,10 @@ struct HVARVVAR
|
|||||||
out->version.major = 1;
|
out->version.major = 1;
|
||||||
out->version.minor = 0;
|
out->version.minor = 0;
|
||||||
|
|
||||||
if (unlikely (!out->varStore.serialize (c->serializer, out)
|
if (unlikely (!out->varStore
|
||||||
.serialize (c->serializer, hvar_plan.var_store, hvar_plan.inner_maps.as_array ())))
|
.serialize_serialize (c->serializer,
|
||||||
|
hvar_plan.var_store,
|
||||||
|
hvar_plan.inner_maps.as_array ())))
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
|
|
||||||
return_trace (out->T::serialize_index_maps (c->serializer,
|
return_trace (out->T::serialize_index_maps (c->serializer,
|
||||||
@ -466,7 +468,7 @@ struct VVAR : HVARVVAR {
|
|||||||
return_trace (false);
|
return_trace (false);
|
||||||
if (!im_plans[index_map_subset_plan_t::VORG_INDEX].get_map_count ())
|
if (!im_plans[index_map_subset_plan_t::VORG_INDEX].get_map_count ())
|
||||||
vorgMap = 0;
|
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 (false);
|
||||||
|
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
|
@ -41,7 +41,7 @@ struct hb_pool_t
|
|||||||
{
|
{
|
||||||
next = nullptr;
|
next = nullptr;
|
||||||
|
|
||||||
for (chunk_t *_ : chunks) ::free (_);
|
for (chunk_t *_ : chunks) hb_free (_);
|
||||||
|
|
||||||
chunks.fini ();
|
chunks.fini ();
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ struct hb_pool_t
|
|||||||
if (unlikely (!next))
|
if (unlikely (!next))
|
||||||
{
|
{
|
||||||
if (unlikely (!chunks.alloc (chunks.length + 1))) return nullptr;
|
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;
|
if (unlikely (!chunk)) return nullptr;
|
||||||
chunks.push (chunk);
|
chunks.push (chunk);
|
||||||
next = chunk->thread ();
|
next = chunk->thread ();
|
||||||
@ -65,7 +65,7 @@ struct hb_pool_t
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free (T* obj)
|
void release (T* obj)
|
||||||
{
|
{
|
||||||
* (T**) obj = next;
|
* (T**) obj = next;
|
||||||
next = obj;
|
next = obj;
|
||||||
|
@ -102,7 +102,7 @@ struct graph_t
|
|||||||
{
|
{
|
||||||
fini ();
|
fini ();
|
||||||
unsigned size = object.tail - object.head;
|
unsigned size = object.tail - object.head;
|
||||||
head = (char*) malloc (size);
|
head = (char*) hb_malloc (size);
|
||||||
if (!head) return false;
|
if (!head) return false;
|
||||||
|
|
||||||
memcpy (head, object.head, size);
|
memcpy (head, object.head, size);
|
||||||
@ -116,7 +116,7 @@ struct graph_t
|
|||||||
void fini ()
|
void fini ()
|
||||||
{
|
{
|
||||||
if (!head) return;
|
if (!head) return;
|
||||||
free (head);
|
hb_free (head);
|
||||||
head = nullptr;
|
head = nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -531,7 +531,7 @@ struct graph_t
|
|||||||
|
|
||||||
const auto& child = vertices_[link.objidx].obj;
|
const auto& child = vertices_[link.objidx].obj;
|
||||||
int64_t child_weight = child.tail - child.head +
|
int64_t child_weight = child.tail - child.head +
|
||||||
(!link.is_wide ? (1 << 16) : ((int64_t) 1 << 32));
|
((int64_t) 1 << (link.width * 8));
|
||||||
int64_t child_distance = next_distance + child_weight;
|
int64_t child_distance = next_distance + child_weight;
|
||||||
|
|
||||||
if (child_distance < vertices_[link.objidx].distance)
|
if (child_distance < vertices_[link.objidx].distance)
|
||||||
@ -578,15 +578,17 @@ struct graph_t
|
|||||||
{
|
{
|
||||||
if (link.is_signed)
|
if (link.is_signed)
|
||||||
{
|
{
|
||||||
if (link.is_wide)
|
if (link.width == 4)
|
||||||
return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31);
|
return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31);
|
||||||
else
|
else
|
||||||
return offset >= -(1 << 15) && offset < (1 << 15);
|
return offset >= -(1 << 15) && offset < (1 << 15);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (link.is_wide)
|
if (link.width == 4)
|
||||||
return offset >= 0 && offset < ((int64_t) 1 << 32);
|
return offset >= 0 && offset < ((int64_t) 1 << 32);
|
||||||
|
else if (link.width == 3)
|
||||||
|
return offset >= 0 && offset < ((int32_t) 1 << 24);
|
||||||
else
|
else
|
||||||
return offset >= 0 && offset < (1 << 16);
|
return offset >= 0 && offset < (1 << 16);
|
||||||
}
|
}
|
||||||
@ -627,21 +629,30 @@ struct graph_t
|
|||||||
char* head,
|
char* head,
|
||||||
hb_serialize_context_t* c) const
|
hb_serialize_context_t* c) const
|
||||||
{
|
{
|
||||||
if (link.is_wide)
|
switch (link.width)
|
||||||
{
|
{
|
||||||
|
case 4:
|
||||||
if (link.is_signed)
|
if (link.is_signed)
|
||||||
{
|
{
|
||||||
serialize_link_of_type<OT::HBINT32> (link, head, c);
|
serialize_link_of_type<OT::HBINT32> (link, head, c);
|
||||||
} else {
|
} else {
|
||||||
serialize_link_of_type<OT::HBUINT32> (link, head, c);
|
serialize_link_of_type<OT::HBUINT32> (link, head, c);
|
||||||
}
|
}
|
||||||
} else {
|
return;
|
||||||
|
case 2:
|
||||||
if (link.is_signed)
|
if (link.is_signed)
|
||||||
{
|
{
|
||||||
serialize_link_of_type<OT::HBINT16> (link, head, c);
|
serialize_link_of_type<OT::HBINT16> (link, head, c);
|
||||||
} else {
|
} else {
|
||||||
serialize_link_of_type<OT::HBUINT16> (link, head, c);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ struct hb_serialize_context_t
|
|||||||
|
|
||||||
struct link_t
|
struct link_t
|
||||||
{
|
{
|
||||||
bool is_wide: 1;
|
unsigned width: 3;
|
||||||
bool is_signed: 1;
|
bool is_signed: 1;
|
||||||
unsigned whence: 2;
|
unsigned whence: 2;
|
||||||
unsigned position: 28;
|
unsigned position: 28;
|
||||||
@ -102,10 +102,11 @@ struct hb_serialize_context_t
|
|||||||
char *tail;
|
char *tail;
|
||||||
object_t *current; // Just for sanity check
|
object_t *current; // Just for sanity check
|
||||||
unsigned num_links;
|
unsigned num_links;
|
||||||
|
hb_serialize_error_t errors;
|
||||||
};
|
};
|
||||||
|
|
||||||
snapshot_t snapshot ()
|
snapshot_t snapshot ()
|
||||||
{ return snapshot_t { head, tail, current, current->links.length }; }
|
{ return snapshot_t { head, tail, current, current->links.length, errors }; }
|
||||||
|
|
||||||
hb_serialize_context_t (void *start_, unsigned int size) :
|
hb_serialize_context_t (void *start_, unsigned int size) :
|
||||||
start ((char *) start_),
|
start ((char *) start_),
|
||||||
@ -136,6 +137,12 @@ struct hb_serialize_context_t
|
|||||||
HB_NODISCARD bool ran_out_of_room () const { return errors & HB_SERIALIZE_ERROR_OUT_OF_ROOM; }
|
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 offset_overflow () const { return errors & HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
|
||||||
HB_NODISCARD bool only_offset_overflow () const { return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
|
HB_NODISCARD bool only_offset_overflow () const { return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
|
||||||
|
HB_NODISCARD bool only_overflow () const
|
||||||
|
{
|
||||||
|
return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW
|
||||||
|
|| errors == HB_SERIALIZE_ERROR_INT_OVERFLOW
|
||||||
|
|| errors == HB_SERIALIZE_ERROR_ARRAY_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
void reset (void *start_, unsigned int size)
|
void reset (void *start_, unsigned int size)
|
||||||
{
|
{
|
||||||
@ -254,7 +261,7 @@ struct hb_serialize_context_t
|
|||||||
current = current->next;
|
current = current->next;
|
||||||
revert (obj->head, obj->tail);
|
revert (obj->head, obj->tail);
|
||||||
obj->fini ();
|
obj->fini ();
|
||||||
object_pool.free (obj);
|
object_pool.release (obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set share to false when an object is unlikely sharable with others
|
/* Set share to false when an object is unlikely sharable with others
|
||||||
@ -317,9 +324,11 @@ struct hb_serialize_context_t
|
|||||||
|
|
||||||
void revert (snapshot_t snap)
|
void revert (snapshot_t snap)
|
||||||
{
|
{
|
||||||
if (unlikely (in_error ())) return;
|
// Overflows that happened after the snapshot will be erased by the revert.
|
||||||
|
if (unlikely (in_error () && !only_overflow ())) return;
|
||||||
assert (snap.current == current);
|
assert (snap.current == current);
|
||||||
current->links.shrink (snap.num_links);
|
current->links.shrink (snap.num_links);
|
||||||
|
errors = snap.errors;
|
||||||
revert (snap.head, snap.tail);
|
revert (snap.head, snap.tail);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,7 +363,6 @@ struct hb_serialize_context_t
|
|||||||
whence_t whence = Head,
|
whence_t whence = Head,
|
||||||
unsigned bias = 0)
|
unsigned bias = 0)
|
||||||
{
|
{
|
||||||
static_assert (sizeof (T) == 2 || sizeof (T) == 4, "");
|
|
||||||
if (unlikely (in_error ())) return;
|
if (unlikely (in_error ())) return;
|
||||||
|
|
||||||
if (!objidx)
|
if (!objidx)
|
||||||
@ -364,8 +372,10 @@ struct hb_serialize_context_t
|
|||||||
assert (current->head <= (const char *) &ofs);
|
assert (current->head <= (const char *) &ofs);
|
||||||
|
|
||||||
auto& link = *current->links.push ();
|
auto& link = *current->links.push ();
|
||||||
|
if (current->links.in_error ())
|
||||||
|
err (HB_SERIALIZE_ERROR_OTHER);
|
||||||
|
|
||||||
link.is_wide = sizeof (T) == 4;
|
link.width = sizeof (T);
|
||||||
link.is_signed = hb_is_signed (hb_unwrap_type (T));
|
link.is_signed = hb_is_signed (hb_unwrap_type (T));
|
||||||
link.whence = (unsigned) whence;
|
link.whence = (unsigned) whence;
|
||||||
link.position = (const char *) &ofs - current->head;
|
link.position = (const char *) &ofs - current->head;
|
||||||
@ -405,15 +415,19 @@ struct hb_serialize_context_t
|
|||||||
offset -= link.bias;
|
offset -= link.bias;
|
||||||
if (link.is_signed)
|
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);
|
assign_offset<int32_t> (parent, link, offset);
|
||||||
else
|
else
|
||||||
assign_offset<int16_t> (parent, link, offset);
|
assign_offset<int16_t> (parent, link, offset);
|
||||||
}
|
}
|
||||||
else
|
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);
|
assign_offset<uint32_t> (parent, link, offset);
|
||||||
|
else if (link.width == 3)
|
||||||
|
assign_offset<uint32_t, 3> (parent, link, offset);
|
||||||
else
|
else
|
||||||
assign_offset<uint16_t> (parent, link, offset);
|
assign_offset<uint16_t> (parent, link, offset);
|
||||||
}
|
}
|
||||||
@ -446,16 +460,16 @@ struct hb_serialize_context_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
Type *allocate_size (unsigned int size)
|
Type *allocate_size (size_t size)
|
||||||
{
|
{
|
||||||
if (unlikely (in_error ())) 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 (HB_SERIALIZE_ERROR_OUT_OF_ROOM);
|
err (HB_SERIALIZE_ERROR_OUT_OF_ROOM);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
memset (this->head, 0, size);
|
hb_memset (this->head, 0, size);
|
||||||
char *ret = this->head;
|
char *ret = this->head;
|
||||||
this->head += size;
|
this->head += size;
|
||||||
return reinterpret_cast<Type *> (ret);
|
return reinterpret_cast<Type *> (ret);
|
||||||
@ -510,18 +524,19 @@ struct hb_serialize_context_t
|
|||||||
hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; }
|
hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; }
|
||||||
|
|
||||||
template <typename Type>
|
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;
|
if (unlikely (in_error ())) return nullptr;
|
||||||
|
|
||||||
assert (this->start <= (char *) obj);
|
assert (this->start <= (char *) obj);
|
||||||
assert ((char *) obj <= this->head);
|
assert ((char *) obj <= this->head);
|
||||||
assert ((char *) obj + size >= this->head);
|
assert ((size_t) (this->head - (char *) obj) <= size);
|
||||||
if (unlikely (!this->allocate_size<Type> (((char *) obj) + size - this->head))) return nullptr;
|
if (unlikely (((char *) obj + size < (char *) obj) ||
|
||||||
|
!this->allocate_size<Type> (((char *) obj) + size - this->head))) return nullptr;
|
||||||
return reinterpret_cast<Type *> (obj);
|
return reinterpret_cast<Type *> (obj);
|
||||||
}
|
}
|
||||||
template <typename Type>
|
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); }
|
{ return extend_size (hb_addressof (obj), size); }
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
@ -544,7 +559,11 @@ struct hb_serialize_context_t
|
|||||||
unsigned int len = (this->head - this->start)
|
unsigned int len = (this->head - this->start)
|
||||||
+ (this->end - this->tail);
|
+ (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 ();
|
if (unlikely (!p)) return hb_bytes_t ();
|
||||||
|
|
||||||
memcpy (p, this->start, this->head - this->start);
|
memcpy (p, this->start, this->head - this->start);
|
||||||
@ -559,17 +578,17 @@ struct hb_serialize_context_t
|
|||||||
hb_bytes_t b = copy_bytes ();
|
hb_bytes_t b = copy_bytes ();
|
||||||
return hb_blob_create (b.arrayZ, b.length,
|
return hb_blob_create (b.arrayZ, b.length,
|
||||||
HB_MEMORY_MODE_WRITABLE,
|
HB_MEMORY_MODE_WRITABLE,
|
||||||
(char *) b.arrayZ, free);
|
(char *) b.arrayZ, hb_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hb_vector_t<object_t *>& object_graph() const
|
const hb_vector_t<object_t *>& object_graph() const
|
||||||
{ return packed; }
|
{ return packed; }
|
||||||
|
|
||||||
private:
|
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)
|
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);
|
assert (0 == off);
|
||||||
check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
|
check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ hb_set_destroy (hb_set_t *set)
|
|||||||
|
|
||||||
set->fini_shallow ();
|
set->fini_shallow ();
|
||||||
|
|
||||||
free (set);
|
hb_free (set);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -169,7 +169,25 @@ hb_set_get_user_data (hb_set_t *set,
|
|||||||
hb_bool_t
|
hb_bool_t
|
||||||
hb_set_allocation_successful (const hb_set_t *set)
|
hb_set_allocation_successful (const hb_set_t *set)
|
||||||
{
|
{
|
||||||
return set->successful;
|
return !set->in_error ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -183,9 +201,7 @@ hb_set_allocation_successful (const hb_set_t *set)
|
|||||||
void
|
void
|
||||||
hb_set_clear (hb_set_t *set)
|
hb_set_clear (hb_set_t *set)
|
||||||
{
|
{
|
||||||
if (unlikely (hb_object_is_immutable (set)))
|
/* Immutible-safe. */
|
||||||
return;
|
|
||||||
|
|
||||||
set->clear ();
|
set->clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,6 +252,7 @@ void
|
|||||||
hb_set_add (hb_set_t *set,
|
hb_set_add (hb_set_t *set,
|
||||||
hb_codepoint_t codepoint)
|
hb_codepoint_t codepoint)
|
||||||
{
|
{
|
||||||
|
/* Immutible-safe. */
|
||||||
set->add (codepoint);
|
set->add (codepoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,6 +272,7 @@ hb_set_add_range (hb_set_t *set,
|
|||||||
hb_codepoint_t first,
|
hb_codepoint_t first,
|
||||||
hb_codepoint_t last)
|
hb_codepoint_t last)
|
||||||
{
|
{
|
||||||
|
/* Immutible-safe. */
|
||||||
set->add_range (first, last);
|
set->add_range (first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,6 +289,7 @@ void
|
|||||||
hb_set_del (hb_set_t *set,
|
hb_set_del (hb_set_t *set,
|
||||||
hb_codepoint_t codepoint)
|
hb_codepoint_t codepoint)
|
||||||
{
|
{
|
||||||
|
/* Immutible-safe. */
|
||||||
set->del (codepoint);
|
set->del (codepoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,6 +302,9 @@ hb_set_del (hb_set_t *set,
|
|||||||
* Removes all of the elements from @first to @last
|
* Removes all of the elements from @first to @last
|
||||||
* (inclusive) from @set.
|
* (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
|
* Since: 0.9.7
|
||||||
**/
|
**/
|
||||||
void
|
void
|
||||||
@ -290,6 +312,7 @@ hb_set_del_range (hb_set_t *set,
|
|||||||
hb_codepoint_t first,
|
hb_codepoint_t first,
|
||||||
hb_codepoint_t last)
|
hb_codepoint_t last)
|
||||||
{
|
{
|
||||||
|
/* Immutible-safe. */
|
||||||
set->del_range (first, last);
|
set->del_range (first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,7 +332,7 @@ hb_bool_t
|
|||||||
hb_set_is_equal (const hb_set_t *set,
|
hb_set_is_equal (const hb_set_t *set,
|
||||||
const hb_set_t *other)
|
const hb_set_t *other)
|
||||||
{
|
{
|
||||||
return set->is_equal (other);
|
return set->is_equal (*other);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -327,7 +350,7 @@ hb_bool_t
|
|||||||
hb_set_is_subset (const hb_set_t *set,
|
hb_set_is_subset (const hb_set_t *set,
|
||||||
const hb_set_t *larger_set)
|
const hb_set_t *larger_set)
|
||||||
{
|
{
|
||||||
return set->is_subset (larger_set);
|
return set->is_subset (*larger_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -343,7 +366,8 @@ void
|
|||||||
hb_set_set (hb_set_t *set,
|
hb_set_set (hb_set_t *set,
|
||||||
const hb_set_t *other)
|
const hb_set_t *other)
|
||||||
{
|
{
|
||||||
set->set (other);
|
/* Immutible-safe. */
|
||||||
|
set->set (*other);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -359,7 +383,8 @@ void
|
|||||||
hb_set_union (hb_set_t *set,
|
hb_set_union (hb_set_t *set,
|
||||||
const hb_set_t *other)
|
const hb_set_t *other)
|
||||||
{
|
{
|
||||||
set->union_ (other);
|
/* Immutible-safe. */
|
||||||
|
set->union_ (*other);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -375,7 +400,8 @@ void
|
|||||||
hb_set_intersect (hb_set_t *set,
|
hb_set_intersect (hb_set_t *set,
|
||||||
const hb_set_t *other)
|
const hb_set_t *other)
|
||||||
{
|
{
|
||||||
set->intersect (other);
|
/* Immutible-safe. */
|
||||||
|
set->intersect (*other);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -391,7 +417,8 @@ void
|
|||||||
hb_set_subtract (hb_set_t *set,
|
hb_set_subtract (hb_set_t *set,
|
||||||
const hb_set_t *other)
|
const hb_set_t *other)
|
||||||
{
|
{
|
||||||
set->subtract (other);
|
/* Immutible-safe. */
|
||||||
|
set->subtract (*other);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -408,25 +435,24 @@ void
|
|||||||
hb_set_symmetric_difference (hb_set_t *set,
|
hb_set_symmetric_difference (hb_set_t *set,
|
||||||
const hb_set_t *other)
|
const hb_set_t *other)
|
||||||
{
|
{
|
||||||
set->symmetric_difference (other);
|
/* Immutible-safe. */
|
||||||
|
set->symmetric_difference (*other);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HB_DISABLE_DEPRECATED
|
|
||||||
/**
|
/**
|
||||||
* hb_set_invert:
|
* hb_set_invert:
|
||||||
* @set: A set
|
* @set: A set
|
||||||
*
|
*
|
||||||
* Inverts the contents of @set.
|
* Inverts the contents of @set.
|
||||||
*
|
*
|
||||||
* Since: 0.9.10
|
* Since: 3.0.0
|
||||||
*
|
|
||||||
* Deprecated: 1.6.1
|
|
||||||
**/
|
**/
|
||||||
void
|
void
|
||||||
hb_set_invert (hb_set_t *set HB_UNUSED)
|
hb_set_invert (hb_set_t *set)
|
||||||
{
|
{
|
||||||
|
/* Immutible-safe. */
|
||||||
|
set->invert ();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hb_set_get_population:
|
* hb_set_get_population:
|
||||||
|
@ -85,12 +85,18 @@ hb_set_get_user_data (hb_set_t *set,
|
|||||||
HB_EXTERN hb_bool_t
|
HB_EXTERN hb_bool_t
|
||||||
hb_set_allocation_successful (const hb_set_t *set);
|
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_EXTERN void
|
||||||
hb_set_clear (hb_set_t *set);
|
hb_set_clear (hb_set_t *set);
|
||||||
|
|
||||||
HB_EXTERN hb_bool_t
|
HB_EXTERN hb_bool_t
|
||||||
hb_set_is_empty (const hb_set_t *set);
|
hb_set_is_empty (const hb_set_t *set);
|
||||||
|
|
||||||
|
HB_EXTERN void
|
||||||
|
hb_set_invert (hb_set_t *set);
|
||||||
|
|
||||||
HB_EXTERN hb_bool_t
|
HB_EXTERN hb_bool_t
|
||||||
hb_set_has (const hb_set_t *set,
|
hb_set_has (const hb_set_t *set,
|
||||||
hb_codepoint_t codepoint);
|
hb_codepoint_t codepoint);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2012,2017 Google, Inc.
|
* Copyright © 2012,2017 Google, Inc.
|
||||||
|
* Copyright © 2021 Behdad Esfahbod
|
||||||
*
|
*
|
||||||
* This is part of HarfBuzz, a text shaping library.
|
* This is part of HarfBuzz, a text shaping library.
|
||||||
*
|
*
|
||||||
@ -28,315 +29,52 @@
|
|||||||
#define HB_SET_HH
|
#define HB_SET_HH
|
||||||
|
|
||||||
#include "hb.hh"
|
#include "hb.hh"
|
||||||
#include "hb-machinery.hh"
|
#include "hb-bit-set-invertible.hh"
|
||||||
|
|
||||||
|
|
||||||
/*
|
template <typename impl_t>
|
||||||
* hb_set_t
|
struct hb_sparseset_t
|
||||||
*/
|
|
||||||
|
|
||||||
/* TODO Keep a free-list so we can free 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 (); }
|
|
||||||
|
|
||||||
struct page_map_t
|
|
||||||
{
|
|
||||||
int cmp (const page_map_t &o) const { return (int) o.major - (int) major; }
|
|
||||||
|
|
||||||
uint32_t major;
|
|
||||||
uint32_t index;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct page_t
|
|
||||||
{
|
|
||||||
void init0 () { v.clear (); }
|
|
||||||
void init1 () { v.clear (0xFF); }
|
|
||||||
|
|
||||||
unsigned int len () const
|
|
||||||
{ return ARRAY_LENGTH_CONST (v); }
|
|
||||||
|
|
||||||
bool is_empty () const
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < len (); i++)
|
|
||||||
if (v[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add (hb_codepoint_t g) { elt (g) |= mask (g); }
|
|
||||||
void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
|
|
||||||
bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
|
|
||||||
|
|
||||||
void add_range (hb_codepoint_t a, hb_codepoint_t b)
|
|
||||||
{
|
|
||||||
elt_t *la = &elt (a);
|
|
||||||
elt_t *lb = &elt (b);
|
|
||||||
if (la == lb)
|
|
||||||
*la |= (mask (b) << 1) - mask(a);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*la |= ~(mask (a) - 1);
|
|
||||||
la++;
|
|
||||||
|
|
||||||
memset (la, 0xff, (char *) lb - (char *) la);
|
|
||||||
|
|
||||||
*lb |= ((mask (b) << 1) - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void del_range (hb_codepoint_t a, hb_codepoint_t b)
|
|
||||||
{
|
|
||||||
elt_t *la = &elt (a);
|
|
||||||
elt_t *lb = &elt (b);
|
|
||||||
if (la == lb)
|
|
||||||
*la &= ~((mask (b) << 1) - mask(a));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*la &= mask (a) - 1;
|
|
||||||
la++;
|
|
||||||
|
|
||||||
memset (la, 0, (char *) lb - (char *) la);
|
|
||||||
|
|
||||||
*lb &= ~((mask (b) << 1) - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_equal (const page_t *other) const
|
|
||||||
{
|
|
||||||
return 0 == hb_memcmp (&v, &other->v, sizeof (v));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int get_population () const
|
|
||||||
{
|
|
||||||
unsigned int pop = 0;
|
|
||||||
for (unsigned int i = 0; i < len (); i++)
|
|
||||||
pop += hb_popcount (v[i]);
|
|
||||||
return pop;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool next (hb_codepoint_t *codepoint) const
|
|
||||||
{
|
|
||||||
unsigned int m = (*codepoint + 1) & MASK;
|
|
||||||
if (!m)
|
|
||||||
{
|
|
||||||
*codepoint = INVALID;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
unsigned int i = m / ELT_BITS;
|
|
||||||
unsigned int j = m & ELT_MASK;
|
|
||||||
|
|
||||||
const elt_t vv = v[i] & ~((elt_t (1) << j) - 1);
|
|
||||||
for (const elt_t *p = &vv; i < len (); p = &v[++i])
|
|
||||||
if (*p)
|
|
||||||
{
|
|
||||||
*codepoint = i * ELT_BITS + elt_get_min (*p);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
*codepoint = INVALID;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool previous (hb_codepoint_t *codepoint) const
|
|
||||||
{
|
|
||||||
unsigned int m = (*codepoint - 1) & MASK;
|
|
||||||
if (m == MASK)
|
|
||||||
{
|
|
||||||
*codepoint = INVALID;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
unsigned int i = m / ELT_BITS;
|
|
||||||
unsigned int j = m & ELT_MASK;
|
|
||||||
|
|
||||||
/* Fancy mask to avoid shifting by elt_t bitsize, which is undefined. */
|
|
||||||
const elt_t mask = j < 8 * sizeof (elt_t) - 1 ?
|
|
||||||
((elt_t (1) << (j + 1)) - 1) :
|
|
||||||
(elt_t) -1;
|
|
||||||
const elt_t vv = v[i] & mask;
|
|
||||||
const elt_t *p = &vv;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (*p)
|
|
||||||
{
|
|
||||||
*codepoint = i * ELT_BITS + elt_get_max (*p);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ((int) i <= 0) break;
|
|
||||||
p = &v[--i];
|
|
||||||
}
|
|
||||||
|
|
||||||
*codepoint = INVALID;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
hb_codepoint_t get_min () const
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < len (); i++)
|
|
||||||
if (v[i])
|
|
||||||
return i * ELT_BITS + elt_get_min (v[i]);
|
|
||||||
return INVALID;
|
|
||||||
}
|
|
||||||
hb_codepoint_t get_max () const
|
|
||||||
{
|
|
||||||
for (int i = len () - 1; i >= 0; i--)
|
|
||||||
if (v[i])
|
|
||||||
return i * ELT_BITS + elt_get_max (v[i]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef unsigned long long elt_t;
|
|
||||||
static constexpr unsigned PAGE_BITS = 512;
|
|
||||||
static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
|
|
||||||
|
|
||||||
static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
|
|
||||||
static unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; }
|
|
||||||
|
|
||||||
typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
|
|
||||||
|
|
||||||
static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
|
|
||||||
static constexpr unsigned ELT_MASK = ELT_BITS - 1;
|
|
||||||
static constexpr unsigned BITS = sizeof (vector_t) * 8;
|
|
||||||
static constexpr unsigned MASK = BITS - 1;
|
|
||||||
static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
|
|
||||||
|
|
||||||
elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
|
|
||||||
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); }
|
|
||||||
|
|
||||||
vector_t v;
|
|
||||||
};
|
|
||||||
static_assert (page_t::PAGE_BITS == sizeof (page_t) * 8, "");
|
|
||||||
|
|
||||||
hb_object_header_t header;
|
hb_object_header_t header;
|
||||||
bool successful; /* Allocations successful */
|
impl_t s;
|
||||||
mutable unsigned int population;
|
|
||||||
hb_sorted_vector_t<page_map_t> page_map;
|
|
||||||
hb_vector_t<page_t> pages;
|
|
||||||
|
|
||||||
void init_shallow ()
|
hb_sparseset_t () { init (); }
|
||||||
{
|
~hb_sparseset_t () { fini (); }
|
||||||
successful = true;
|
|
||||||
population = 0;
|
hb_sparseset_t (const hb_sparseset_t& other) : hb_sparseset_t () { set (other); }
|
||||||
page_map.init ();
|
void operator= (const hb_sparseset_t& other) { set (other); }
|
||||||
pages.init ();
|
// TODO Add move construtor/assign
|
||||||
}
|
// TODO Add constructor for Iterator
|
||||||
|
|
||||||
|
void init_shallow () { s.init (); }
|
||||||
void init ()
|
void init ()
|
||||||
{
|
{
|
||||||
hb_object_init (this);
|
hb_object_init (this);
|
||||||
init_shallow ();
|
init_shallow ();
|
||||||
}
|
}
|
||||||
void fini_shallow ()
|
void fini_shallow () { s.fini (); }
|
||||||
{
|
|
||||||
population = 0;
|
|
||||||
page_map.fini ();
|
|
||||||
pages.fini ();
|
|
||||||
}
|
|
||||||
void fini ()
|
void fini ()
|
||||||
{
|
{
|
||||||
hb_object_fini (this);
|
hb_object_fini (this);
|
||||||
fini_shallow ();
|
fini_shallow ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool in_error () const { return !successful; }
|
|
||||||
|
|
||||||
bool resize (unsigned int count)
|
|
||||||
{
|
|
||||||
if (unlikely (count > pages.length && !successful)) return false;
|
|
||||||
if (!pages.resize (count) || !page_map.resize (count))
|
|
||||||
{
|
|
||||||
pages.resize (page_map.length);
|
|
||||||
successful = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset ()
|
|
||||||
{
|
|
||||||
successful = true;
|
|
||||||
clear ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear ()
|
|
||||||
{
|
|
||||||
if (resize (0))
|
|
||||||
population = 0;
|
|
||||||
}
|
|
||||||
bool is_empty () const
|
|
||||||
{
|
|
||||||
unsigned int count = pages.length;
|
|
||||||
for (unsigned int i = 0; i < count; i++)
|
|
||||||
if (!pages[i].is_empty ())
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
explicit operator bool () const { return !is_empty (); }
|
explicit operator bool () const { return !is_empty (); }
|
||||||
|
|
||||||
void dirty () { population = UINT_MAX; }
|
void err () { s.err (); }
|
||||||
|
bool in_error () const { return s.in_error (); }
|
||||||
|
|
||||||
void add (hb_codepoint_t g)
|
void reset () { s.reset (); }
|
||||||
{
|
void clear () { s.clear (); }
|
||||||
if (unlikely (!successful)) return;
|
void invert () { s.invert (); }
|
||||||
if (unlikely (g == INVALID)) return;
|
bool is_empty () const { return s.is_empty (); }
|
||||||
dirty ();
|
|
||||||
page_t *page = page_for_insert (g); if (unlikely (!page)) return;
|
|
||||||
page->add (g);
|
|
||||||
}
|
|
||||||
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
|
|
||||||
{
|
|
||||||
if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
|
|
||||||
if (unlikely (a > b || a == INVALID || b == INVALID)) return false;
|
|
||||||
dirty ();
|
|
||||||
unsigned int ma = get_major (a);
|
|
||||||
unsigned int mb = get_major (b);
|
|
||||||
if (ma == mb)
|
|
||||||
{
|
|
||||||
page_t *page = page_for_insert (a); if (unlikely (!page)) return false;
|
|
||||||
page->add_range (a, b);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
page_t *page = page_for_insert (a); if (unlikely (!page)) return false;
|
|
||||||
page->add_range (a, major_start (ma + 1) - 1);
|
|
||||||
|
|
||||||
for (unsigned int m = ma + 1; m < mb; m++)
|
void add (hb_codepoint_t g) { s.add (g); }
|
||||||
{
|
bool add_range (hb_codepoint_t a, hb_codepoint_t b) { return s.add_range (a, b); }
|
||||||
page = page_for_insert (major_start (m)); if (unlikely (!page)) return false;
|
|
||||||
page->init1 ();
|
|
||||||
}
|
|
||||||
|
|
||||||
page = page_for_insert (b); if (unlikely (!page)) return false;
|
|
||||||
page->add_range (major_start (mb), b);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
|
void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
|
||||||
{
|
{ s.add_array (array, count, stride); }
|
||||||
if (unlikely (!successful)) return;
|
|
||||||
if (!count) return;
|
|
||||||
dirty ();
|
|
||||||
hb_codepoint_t g = *array;
|
|
||||||
while (count)
|
|
||||||
{
|
|
||||||
unsigned int m = get_major (g);
|
|
||||||
page_t *page = page_for_insert (g); if (unlikely (!page)) return;
|
|
||||||
unsigned int start = major_start (m);
|
|
||||||
unsigned int end = major_start (m + 1);
|
|
||||||
do
|
|
||||||
{
|
|
||||||
page->add (g);
|
|
||||||
|
|
||||||
array = &StructAtOffsetUnaligned<T> (array, stride);
|
|
||||||
count--;
|
|
||||||
}
|
|
||||||
while (count && (g = *array, start <= g && g < end));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
|
void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
|
||||||
|
|
||||||
@ -344,108 +82,14 @@ struct hb_set_t
|
|||||||
* Used for faster rejection of corrupt data. */
|
* Used for faster rejection of corrupt data. */
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
|
bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
|
||||||
{
|
{ return s.add_sorted_array (array, count, stride); }
|
||||||
if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
|
|
||||||
if (!count) return true;
|
|
||||||
dirty ();
|
|
||||||
hb_codepoint_t g = *array;
|
|
||||||
hb_codepoint_t last_g = g;
|
|
||||||
while (count)
|
|
||||||
{
|
|
||||||
unsigned int m = get_major (g);
|
|
||||||
page_t *page = page_for_insert (g); if (unlikely (!page)) return false;
|
|
||||||
unsigned int end = major_start (m + 1);
|
|
||||||
do
|
|
||||||
{
|
|
||||||
/* If we try harder we can change the following comparison to <=;
|
|
||||||
* Not sure if it's worth it. */
|
|
||||||
if (g < last_g) return false;
|
|
||||||
last_g = g;
|
|
||||||
page->add (g);
|
|
||||||
|
|
||||||
array = (const T *) ((const char *) array + stride);
|
|
||||||
count--;
|
|
||||||
}
|
|
||||||
while (count && (g = *array, g < end));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
|
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)
|
void del (hb_codepoint_t g) { s.del (g); }
|
||||||
{
|
void del_range (hb_codepoint_t a, hb_codepoint_t b) { s.del_range (a, b); }
|
||||||
/* TODO perform op even if !successful. */
|
|
||||||
if (unlikely (!successful)) return;
|
|
||||||
page_t *page = page_for (g);
|
|
||||||
if (!page)
|
|
||||||
return;
|
|
||||||
dirty ();
|
|
||||||
page->del (g);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
bool get (hb_codepoint_t g) const { return s.get (g); }
|
||||||
void del_pages (int ds, int de)
|
|
||||||
{
|
|
||||||
if (ds <= de)
|
|
||||||
{
|
|
||||||
// Pre-allocate the workspace that compact() will need so we can bail on allocation failure
|
|
||||||
// before attempting to rewrite the page map.
|
|
||||||
hb_vector_t<unsigned> compact_workspace;
|
|
||||||
if (unlikely (!allocate_compact_workspace (compact_workspace))) return;
|
|
||||||
|
|
||||||
unsigned int write_index = 0;
|
|
||||||
for (unsigned int i = 0; i < page_map.length; i++)
|
|
||||||
{
|
|
||||||
int m = (int) page_map[i].major;
|
|
||||||
if (m < ds || de < m)
|
|
||||||
page_map[write_index++] = page_map[i];
|
|
||||||
}
|
|
||||||
compact (compact_workspace, write_index);
|
|
||||||
resize (write_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
void del_range (hb_codepoint_t a, hb_codepoint_t b)
|
|
||||||
{
|
|
||||||
/* TODO perform op even if !successful. */
|
|
||||||
if (unlikely (!successful)) return;
|
|
||||||
if (unlikely (a > b || a == INVALID || b == INVALID)) return;
|
|
||||||
dirty ();
|
|
||||||
unsigned int ma = get_major (a);
|
|
||||||
unsigned int mb = get_major (b);
|
|
||||||
/* Delete pages from ds through de if ds <= de. */
|
|
||||||
int ds = (a == major_start (ma))? (int) ma: (int) (ma + 1);
|
|
||||||
int de = (b + 1 == major_start (mb + 1))? (int) mb: ((int) mb - 1);
|
|
||||||
if (ds > de || (int) ma < ds)
|
|
||||||
{
|
|
||||||
page_t *page = page_for (a);
|
|
||||||
if (page)
|
|
||||||
{
|
|
||||||
if (ma == mb)
|
|
||||||
page->del_range (a, b);
|
|
||||||
else
|
|
||||||
page->del_range (a, major_start (ma + 1) - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (de < (int) mb && ma != mb)
|
|
||||||
{
|
|
||||||
page_t *page = page_for (b);
|
|
||||||
if (page)
|
|
||||||
page->del_range (major_start (mb), b);
|
|
||||||
}
|
|
||||||
del_pages (ds, de);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get (hb_codepoint_t g) const
|
|
||||||
{
|
|
||||||
const page_t *page = page_for (g);
|
|
||||||
if (!page)
|
|
||||||
return false;
|
|
||||||
return page->get (g);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Has interface. */
|
/* Has interface. */
|
||||||
static constexpr bool SENTINEL = false;
|
static constexpr bool SENTINEL = false;
|
||||||
@ -456,464 +100,49 @@ struct hb_set_t
|
|||||||
bool operator () (hb_codepoint_t k) const { return has (k); }
|
bool operator () (hb_codepoint_t k) const { return has (k); }
|
||||||
|
|
||||||
/* Sink interface. */
|
/* Sink interface. */
|
||||||
hb_set_t& operator << (hb_codepoint_t v)
|
hb_sparseset_t& operator << (hb_codepoint_t v)
|
||||||
{ add (v); return *this; }
|
{ add (v); return *this; }
|
||||||
hb_set_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
|
hb_sparseset_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
|
||||||
{ add_range (range.first, range.second); return *this; }
|
{ add_range (range.first, range.second); return *this; }
|
||||||
|
|
||||||
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
|
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
|
||||||
{
|
{ return s.intersects (first, last); }
|
||||||
hb_codepoint_t c = first - 1;
|
|
||||||
return next (&c) && c <= last;
|
|
||||||
}
|
|
||||||
void set (const hb_set_t *other)
|
|
||||||
{
|
|
||||||
if (unlikely (!successful)) return;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_equal (const hb_set_t *other) const
|
void set (const hb_sparseset_t &other) { s.set (other.s); }
|
||||||
{
|
|
||||||
if (get_population () != other->get_population ())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
unsigned int na = pages.length;
|
bool is_equal (const hb_sparseset_t &other) const { return s.is_equal (other.s); }
|
||||||
unsigned int nb = other->pages.length;
|
|
||||||
|
|
||||||
unsigned int a = 0, b = 0;
|
bool is_subset (const hb_sparseset_t &larger_set) const { return s.is_subset (larger_set.s); }
|
||||||
for (; a < na && b < nb; )
|
|
||||||
{
|
|
||||||
if (page_at (a).is_empty ()) { a++; continue; }
|
|
||||||
if (other->page_at (b).is_empty ()) { b++; continue; }
|
|
||||||
if (page_map[a].major != other->page_map[b].major ||
|
|
||||||
!page_at (a).is_equal (&other->page_at (b)))
|
|
||||||
return false;
|
|
||||||
a++;
|
|
||||||
b++;
|
|
||||||
}
|
|
||||||
for (; a < na; a++)
|
|
||||||
if (!page_at (a).is_empty ()) { return false; }
|
|
||||||
for (; b < nb; b++)
|
|
||||||
if (!other->page_at (b).is_empty ()) { return false; }
|
|
||||||
|
|
||||||
return true;
|
void union_ (const hb_sparseset_t &other) { s.union_ (other.s); }
|
||||||
}
|
void intersect (const hb_sparseset_t &other) { s.intersect (other.s); }
|
||||||
|
void subtract (const hb_sparseset_t &other) { s.subtract (other.s); }
|
||||||
|
void symmetric_difference (const hb_sparseset_t &other) { s.symmetric_difference (other.s); }
|
||||||
|
|
||||||
bool is_subset (const hb_set_t *larger_set) const
|
bool next (hb_codepoint_t *codepoint) const { return s.next (codepoint); }
|
||||||
{
|
bool previous (hb_codepoint_t *codepoint) const { return s.previous (codepoint); }
|
||||||
if (get_population () > larger_set->get_population ())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* TODO Optimize to use pages. */
|
|
||||||
hb_codepoint_t c = INVALID;
|
|
||||||
while (next (&c))
|
|
||||||
if (!larger_set->has (c))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool allocate_compact_workspace(hb_vector_t<unsigned>& workspace)
|
|
||||||
{
|
|
||||||
if (unlikely(!workspace.resize (pages.length)))
|
|
||||||
{
|
|
||||||
successful = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* workspace should be a pre-sized vector allocated to hold at exactly pages.length
|
|
||||||
* elements.
|
|
||||||
*/
|
|
||||||
void compact (hb_vector_t<unsigned>& workspace,
|
|
||||||
unsigned int length)
|
|
||||||
{
|
|
||||||
assert(workspace.length == pages.length);
|
|
||||||
hb_vector_t<unsigned>& old_index_to_page_map_index = workspace;
|
|
||||||
|
|
||||||
hb_fill (old_index_to_page_map_index.writer(), 0xFFFFFFFF);
|
|
||||||
/* TODO(iter) Rewrite as dagger? */
|
|
||||||
for (unsigned i = 0; i < length; i++)
|
|
||||||
old_index_to_page_map_index[page_map[i].index] = i;
|
|
||||||
|
|
||||||
compact_pages (old_index_to_page_map_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void compact_pages (const hb_vector_t<unsigned>& old_index_to_page_map_index)
|
|
||||||
{
|
|
||||||
unsigned int write_index = 0;
|
|
||||||
for (unsigned int i = 0; i < pages.length; i++)
|
|
||||||
{
|
|
||||||
if (old_index_to_page_map_index[i] == 0xFFFFFFFF) continue;
|
|
||||||
|
|
||||||
if (write_index < i)
|
|
||||||
pages[write_index] = pages[i];
|
|
||||||
|
|
||||||
page_map[old_index_to_page_map_index[i]].index = write_index;
|
|
||||||
write_index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Op>
|
|
||||||
void process (const Op& op, const hb_set_t *other)
|
|
||||||
{
|
|
||||||
const bool passthru_left = op (1, 0);
|
|
||||||
const bool passthru_right = op (0, 1);
|
|
||||||
|
|
||||||
if (unlikely (!successful)) return;
|
|
||||||
|
|
||||||
dirty ();
|
|
||||||
|
|
||||||
unsigned int na = pages.length;
|
|
||||||
unsigned int nb = other->pages.length;
|
|
||||||
unsigned int next_page = na;
|
|
||||||
|
|
||||||
unsigned int count = 0, newCount = 0;
|
|
||||||
unsigned int a = 0, b = 0;
|
|
||||||
unsigned int write_index = 0;
|
|
||||||
|
|
||||||
// Pre-allocate the workspace that compact() will need so we can bail on allocation failure
|
|
||||||
// before attempting to rewrite the page map.
|
|
||||||
hb_vector_t<unsigned> compact_workspace;
|
|
||||||
if (!passthru_left && unlikely (!allocate_compact_workspace (compact_workspace))) return;
|
|
||||||
|
|
||||||
for (; a < na && b < nb; )
|
|
||||||
{
|
|
||||||
if (page_map[a].major == other->page_map[b].major)
|
|
||||||
{
|
|
||||||
if (!passthru_left)
|
|
||||||
{
|
|
||||||
// Move page_map entries that we're keeping from the left side set
|
|
||||||
// to the front of the page_map vector. This isn't necessary if
|
|
||||||
// passthru_left is set since no left side pages will be removed
|
|
||||||
// in that case.
|
|
||||||
if (write_index < a)
|
|
||||||
page_map[write_index] = page_map[a];
|
|
||||||
write_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
count++;
|
|
||||||
a++;
|
|
||||||
b++;
|
|
||||||
}
|
|
||||||
else if (page_map[a].major < other->page_map[b].major)
|
|
||||||
{
|
|
||||||
if (passthru_left)
|
|
||||||
count++;
|
|
||||||
a++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (passthru_right)
|
|
||||||
count++;
|
|
||||||
b++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (passthru_left)
|
|
||||||
count += na - a;
|
|
||||||
if (passthru_right)
|
|
||||||
count += nb - b;
|
|
||||||
|
|
||||||
if (!passthru_left)
|
|
||||||
{
|
|
||||||
na = write_index;
|
|
||||||
next_page = write_index;
|
|
||||||
compact (compact_workspace, write_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!resize (count))
|
|
||||||
return;
|
|
||||||
|
|
||||||
newCount = count;
|
|
||||||
|
|
||||||
/* Process in-place backward. */
|
|
||||||
a = na;
|
|
||||||
b = nb;
|
|
||||||
for (; a && b; )
|
|
||||||
{
|
|
||||||
if (page_map[a - 1].major == other->page_map[b - 1].major)
|
|
||||||
{
|
|
||||||
a--;
|
|
||||||
b--;
|
|
||||||
count--;
|
|
||||||
page_map[count] = page_map[a];
|
|
||||||
page_at (count).v = op (page_at (a).v, other->page_at (b).v);
|
|
||||||
}
|
|
||||||
else if (page_map[a - 1].major > other->page_map[b - 1].major)
|
|
||||||
{
|
|
||||||
a--;
|
|
||||||
if (passthru_left)
|
|
||||||
{
|
|
||||||
count--;
|
|
||||||
page_map[count] = page_map[a];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
b--;
|
|
||||||
if (passthru_right)
|
|
||||||
{
|
|
||||||
count--;
|
|
||||||
page_map[count].major = other->page_map[b].major;
|
|
||||||
page_map[count].index = next_page++;
|
|
||||||
page_at (count).v = other->page_at (b).v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (passthru_left)
|
|
||||||
while (a)
|
|
||||||
{
|
|
||||||
a--;
|
|
||||||
count--;
|
|
||||||
page_map[count] = page_map [a];
|
|
||||||
}
|
|
||||||
if (passthru_right)
|
|
||||||
while (b)
|
|
||||||
{
|
|
||||||
b--;
|
|
||||||
count--;
|
|
||||||
page_map[count].major = other->page_map[b].major;
|
|
||||||
page_map[count].index = next_page++;
|
|
||||||
page_at (count).v = other->page_at (b).v;
|
|
||||||
}
|
|
||||||
assert (!count);
|
|
||||||
if (pages.length > newCount)
|
|
||||||
// This resize() doesn't need to be checked because we can't get here
|
|
||||||
// if the set is currently in_error() and this only resizes downwards
|
|
||||||
// which will always succeed if the set is not in_error().
|
|
||||||
resize (newCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
void union_ (const hb_set_t *other)
|
|
||||||
{
|
|
||||||
process (hb_bitwise_or, other);
|
|
||||||
}
|
|
||||||
void intersect (const hb_set_t *other)
|
|
||||||
{
|
|
||||||
process (hb_bitwise_and, other);
|
|
||||||
}
|
|
||||||
void subtract (const hb_set_t *other)
|
|
||||||
{
|
|
||||||
process (hb_bitwise_sub, other);
|
|
||||||
}
|
|
||||||
void symmetric_difference (const hb_set_t *other)
|
|
||||||
{
|
|
||||||
process (hb_bitwise_xor, other);
|
|
||||||
}
|
|
||||||
bool next (hb_codepoint_t *codepoint) const
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (pages[page_map[i].index].next (codepoint))
|
|
||||||
{
|
|
||||||
*codepoint += page_map[i].major * page_t::PAGE_BITS;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
for (; i < page_map.length; i++)
|
|
||||||
{
|
|
||||||
hb_codepoint_t m = pages[page_map[i].index].get_min ();
|
|
||||||
if (m != INVALID)
|
|
||||||
{
|
|
||||||
*codepoint = page_map[i].major * page_t::PAGE_BITS + m;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*codepoint = INVALID;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool previous (hb_codepoint_t *codepoint) const
|
|
||||||
{
|
|
||||||
if (unlikely (*codepoint == INVALID)) {
|
|
||||||
*codepoint = get_max ();
|
|
||||||
return *codepoint != INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
page_map_t map = {get_major (*codepoint), 0};
|
|
||||||
unsigned int i;
|
|
||||||
page_map.bfind (map, &i, HB_BFIND_NOT_FOUND_STORE_CLOSEST);
|
|
||||||
if (i < page_map.length && page_map[i].major == map.major)
|
|
||||||
{
|
|
||||||
if (pages[page_map[i].index].previous (codepoint))
|
|
||||||
{
|
|
||||||
*codepoint += page_map[i].major * page_t::PAGE_BITS;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i--;
|
|
||||||
for (; (int) i >= 0; i--)
|
|
||||||
{
|
|
||||||
hb_codepoint_t m = pages[page_map[i].index].get_max ();
|
|
||||||
if (m != INVALID)
|
|
||||||
{
|
|
||||||
*codepoint = page_map[i].major * page_t::PAGE_BITS + m;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*codepoint = INVALID;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
|
bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
|
||||||
{
|
{ return s.next_range (first, last); }
|
||||||
hb_codepoint_t i;
|
|
||||||
|
|
||||||
i = *last;
|
|
||||||
if (!next (&i))
|
|
||||||
{
|
|
||||||
*last = *first = INVALID;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO Speed up. */
|
|
||||||
*last = *first = i;
|
|
||||||
while (next (&i) && i == *last + 1)
|
|
||||||
(*last)++;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
|
bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
|
||||||
{
|
{ return s.previous_range (first, last); }
|
||||||
hb_codepoint_t i;
|
|
||||||
|
|
||||||
i = *first;
|
unsigned int get_population () const { return s.get_population (); }
|
||||||
if (!previous (&i))
|
hb_codepoint_t get_min () const { return s.get_min (); }
|
||||||
{
|
hb_codepoint_t get_max () const { return s.get_max (); }
|
||||||
*last = *first = INVALID;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO Speed up. */
|
static constexpr hb_codepoint_t INVALID = impl_t::INVALID;
|
||||||
*last = *first = i;
|
|
||||||
while (previous (&i) && i == *first - 1)
|
|
||||||
(*first)--;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int get_population () const
|
|
||||||
{
|
|
||||||
if (population != UINT_MAX)
|
|
||||||
return population;
|
|
||||||
|
|
||||||
unsigned int pop = 0;
|
|
||||||
unsigned int count = pages.length;
|
|
||||||
for (unsigned int i = 0; i < count; i++)
|
|
||||||
pop += pages[i].get_population ();
|
|
||||||
|
|
||||||
population = pop;
|
|
||||||
return pop;
|
|
||||||
}
|
|
||||||
hb_codepoint_t get_min () const
|
|
||||||
{
|
|
||||||
unsigned int count = pages.length;
|
|
||||||
for (unsigned int i = 0; i < count; i++)
|
|
||||||
if (!page_at (i).is_empty ())
|
|
||||||
return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_min ();
|
|
||||||
return INVALID;
|
|
||||||
}
|
|
||||||
hb_codepoint_t get_max () const
|
|
||||||
{
|
|
||||||
unsigned int count = pages.length;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Iterator implementation.
|
* Iterator implementation.
|
||||||
*/
|
*/
|
||||||
struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
|
using iter_t = typename impl_t::iter_t;
|
||||||
{
|
iter_t iter () const { return iter_t (this->s); }
|
||||||
static constexpr bool is_sorted_iterator = true;
|
|
||||||
iter_t (const hb_set_t &s_ = Null (hb_set_t),
|
|
||||||
bool init = true) : s (&s_), v (INVALID), l(0)
|
|
||||||
{
|
|
||||||
if (init)
|
|
||||||
{
|
|
||||||
l = s->get_population () + 1;
|
|
||||||
__next__ ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef hb_codepoint_t __item_t__;
|
|
||||||
hb_codepoint_t __item__ () const { return v; }
|
|
||||||
bool __more__ () const { return v != INVALID; }
|
|
||||||
void __next__ () { s->next (&v); if (l) l--; }
|
|
||||||
void __prev__ () { s->previous (&v); }
|
|
||||||
unsigned __len__ () const { return l; }
|
|
||||||
iter_t end () const { return iter_t (*s, false); }
|
|
||||||
bool operator != (const iter_t& o) const
|
|
||||||
{ return s != o.s || v != o.v; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const hb_set_t *s;
|
|
||||||
hb_codepoint_t v;
|
|
||||||
unsigned l;
|
|
||||||
};
|
|
||||||
iter_t iter () const { return iter_t (*this); }
|
|
||||||
operator iter_t () const { return iter (); }
|
operator iter_t () const { return iter (); }
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
page_t *page_for_insert (hb_codepoint_t g)
|
|
||||||
{
|
|
||||||
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 (!resize (pages.length + 1))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
pages[map.index].init0 ();
|
|
||||||
memmove (page_map + i + 1,
|
|
||||||
page_map + i,
|
|
||||||
(page_map.length - 1 - i) * page_map.item_size);
|
|
||||||
page_map[i] = map;
|
|
||||||
}
|
|
||||||
return &pages[page_map[i].index];
|
|
||||||
}
|
|
||||||
page_t *page_for (hb_codepoint_t g)
|
|
||||||
{
|
|
||||||
page_map_t key = {get_major (g)};
|
|
||||||
const page_map_t *found = page_map.bsearch (key);
|
|
||||||
if (found)
|
|
||||||
return &pages[found->index];
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
const page_t *page_for (hb_codepoint_t g) const
|
|
||||||
{
|
|
||||||
page_map_t key = {get_major (g)};
|
|
||||||
const page_map_t *found = page_map.bsearch (key);
|
|
||||||
if (found)
|
|
||||||
return &pages[found->index];
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
|
|
||||||
const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
|
|
||||||
unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
|
|
||||||
hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct hb_set_t : hb_sparseset_t<hb_bit_set_invertible_t> {};
|
||||||
|
|
||||||
|
static_assert (hb_set_t::INVALID == HB_SET_VALUE_INVALID, "");
|
||||||
|
|
||||||
|
|
||||||
#endif /* HB_SET_HH */
|
#endif /* HB_SET_HH */
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user