Compare commits

...

728 commits
10.3.0 ... main

Author SHA1 Message Date
Garret Rieger
efcb7d3de1 [subset] close unicodes over bidi mirror variants during subsetting.
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 3s
Fixes #5281. Does the closure by default, but I've introduced a new flag and option to disable this behaviour since some users may want to get the minimal set if they know they don't need the mirrored variants.
2025-04-11 18:13:28 -06:00
Garret Rieger
5afbd187b6 [subset] Split subset plan variations function into separate file.
Some checks failed
Scorecard supply-chain security / Scorecard analysis (push) Failing after 7s
arm / arm-none-eabi (push) Has been cancelled
configs-ci / build (push) Has been cancelled
fontations / build (push) Has been cancelled
linux-ci / build (push) Has been cancelled
macos-ci / build (push) Has been cancelled
msvc / msvc-2019-amd64 (push) Has been cancelled
msvc / msvc-2019-x86 (push) Has been cancelled
msys2 / CLANG64 (push) Has been cancelled
msys2 / MINGW32 (push) Has been cancelled
msys2 / MINGW64 (push) Has been cancelled
Compile times for hb-subset-plan.cc go from 16s -> 13s.
2025-04-09 17:08:06 -06:00
Behdad Esfahbod
e6b5dba369 [README] Add Subsetter study 2025-04-09 16:53:22 -06:00
Garret Rieger
d3ccdcdd80 [subset] Move GDEF subset planning into hb-subset-plan-layout.cc 2025-04-09 16:45:07 -06:00
Garret Rieger
b33f2e26ee [subset] Start splitting layout specific subset plan functionality.
The aim is to reduce the compiled time of hb-subset-plan.cc which on my machine takes almost 30s to compile.
2025-04-09 16:45:07 -06:00
Behdad Esfahbod
ab3235150d [common] Move hb_script_t enum to a separate file
Fixes https://github.com/harfbuzz/harfbuzz/issues/5271
2025-04-09 10:43:02 -06:00
Behdad Esfahbod
5f80cc1600 [directwrite] Fix build
Some checks failed
Scorecard supply-chain security / Scorecard analysis (push) Failing after 13m20s
arm / arm-none-eabi (push) Has been cancelled
configs-ci / build (push) Has been cancelled
fontations / build (push) Has been cancelled
linux-ci / build (push) Has been cancelled
macos-ci / build (push) Has been cancelled
msys2 / CLANG64 (push) Has been cancelled
msys2 / MINGW32 (push) Has been cancelled
msys2 / MINGW64 (push) Has been cancelled
msvc / msvc-2019-amd64 (push) Has been cancelled
msvc / msvc-2019-x86 (push) Has been cancelled
2025-04-08 02:13:39 -06:00
Behdad Esfahbod
6b0124284b [mutex] Delete copy constructors 2025-04-08 01:58:10 -06:00
Behdad Esfahbod
caa9cf2e85 [atomic] Remove unnecessary macro
Had typo in it as well.
2025-04-08 01:50:51 -06:00
Behdad Esfahbod
c7f980907f [GPOS] Short-circuit variations if no axis set
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 5s
2025-04-07 16:37:00 -06:00
Garret Rieger
b1a0a4c228 In OT::VarData::Serialize don't attempt to serialize an empty set of rows.
Protects against incorrectly accessing rows[0] when rows is empty.
2025-04-07 13:11:39 -06:00
dependabot[bot]
6dff699f3f Bump fonttools from 4.56.0 to 4.57.0 in /.ci
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 2s
Bumps [fonttools](https://github.com/fonttools/fonttools) from 4.56.0 to 4.57.0.
- [Release notes](https://github.com/fonttools/fonttools/releases)
- [Changelog](https://github.com/fonttools/fonttools/blob/main/NEWS.rst)
- [Commits](https://github.com/fonttools/fonttools/compare/4.56.0...4.57.0)

---
updated-dependencies:
- dependency-name: fonttools
  dependency-version: 4.57.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-07 14:00:02 +02:00
dependabot[bot]
6697cd833a Bump github/codeql-action from 3.28.13 to 3.28.14
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.28.13 to 3.28.14.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](1b549b9259...fc7e4a0fa0)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.28.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-07 13:52:23 +02:00
Khaled Hosny
2c4bc83244 [ot-math] Fix build with HB_NO_MATH 2025-04-07 13:43:16 +02:00
Behdad Esfahbod
e31721b5cf [test/shape] Write cmdline as test description
Some checks failed
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 5s
2025-04-06 21:41:09 -06:00
Behdad Esfahbod
a9e2c8f3aa
Merge pull request #5264 from harfbuzz/tap2
Tap2
2025-04-06 19:34:18 -06:00
Behdad Esfahbod
a3d626b4b9 [test-object] Hopefully last ubsan fix
API change:
- hb_face_is_immutable() now takes `hb_face_t *` instead of previous
  `const hb_face_t *`.  This should not pose any problem for any
  clients in our belief.
2025-04-06 19:16:43 -06:00
Behdad Esfahbod
b99382e292 [test-unicode] Try disabling one test under ubsan 2025-04-06 18:53:53 -06:00
Behdad Esfahbod
ba4a92c53b [test-object] Fix ubsan issues 2025-04-06 18:48:39 -06:00
Behdad Esfahbod
8a1ba4d151 [test-object] See if this helps make ubsan happy 2025-04-06 18:12:22 -06:00
Behdad Esfahbod
fb04a306fc [test/api] Fix a few ubsan issues 2025-04-06 18:08:50 -06:00
Behdad Esfahbod
b43901151f [test-draw] Make ubsan happy 2025-04-06 17:28:03 -06:00
Behdad Esfahbod
b106a9ef58 [CI] Put back the meson-default sanitizer options 2025-04-06 16:36:50 -06:00
Behdad Esfahbod
59771e5613 [CI] Redirect sanitizer outputs to stderr 2025-04-06 16:28:40 -06:00
Behdad Esfahbod
fd9903fc4e [hb-subset] Try to fix leak 2025-04-06 16:20:23 -06:00
Behdad Esfahbod
f09c4d6dd8 [test/subset] Fix a regular expression 2025-04-06 15:54:21 -06:00
Behdad Esfahbod
1f0559392d [test/subset] Massage more 2025-04-06 15:50:20 -06:00
Behdad Esfahbod
d8f00171d7 [test/subset] black 2025-04-06 15:33:25 -06:00
Behdad Esfahbod
cc065cf2e5 [test/subset] Better report passed tests 2025-04-06 15:33:08 -06:00
Behdad Esfahbod
c60067c675 [test/subset] See if this fixes CI
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 0s
2025-04-06 15:25:58 -06:00
Behdad Esfahbod
8456c33ac3 [test/shape] Respect @face-loaders directive 2025-04-06 14:33:44 -06:00
Behdad Esfahbod
1f1cbb64ee
Merge pull request #5260 from harfbuzz/tap
Use TAP protocol for tests
2025-04-06 14:30:07 -06:00
Behdad Esfahbod
aa6a37de61 [test/subset] Port to TAP 2025-04-06 14:18:18 -06:00
Behdad Esfahbod
ba309a1826 [test/fuzzing] Port all to TAP 2025-04-06 13:54:47 -06:00
Behdad Esfahbod
58d7ab2d59 [meson] Remove unneeded dependencies 2025-04-06 13:42:13 -06:00
Behdad Esfahbod
328509ef66 [tap] Try to fix cross64 build 2025-04-06 13:34:04 -06:00
Behdad Esfahbod
03f4230188 [mac] Add tests for --face-loader
https://github.com/harfbuzz/harfbuzz/issues/5142
2025-04-06 13:32:28 -06:00
Behdad Esfahbod
5a46872853 Add test for https://github.com/harfbuzz/harfbuzz/issues/5232 2025-04-06 13:32:28 -06:00
Khaled Hosny
9718681c99 [meson] Require 0.60.0
Fixes https://github.com/harfbuzz/harfbuzz/issues/5261
2025-04-06 13:23:43 -06:00
Behdad Esfahbod
2b5ae9dec3 [meson] Use a glob.py instead of ls / dir 2025-04-06 12:52:31 -06:00
Behdad Esfahbod
155e1e633b [test/api] Use g_assert_true instead of g_assert
The latter terminates the program. The former marks the test
as failing.
2025-04-06 03:49:15 -06:00
Behdad Esfahbod
f73039422e [CI] See if this fixes crossbuild 64 2025-04-06 03:35:05 -06:00
Behdad Esfahbod
5efdb884a5 [run-tests] Fix remaining bot fails, fingers crossed 2025-04-06 03:21:15 -06:00
Behdad Esfahbod
8132a6607f [shape/run-tests] Don't return non-zero
TAP protocol.
2025-04-06 03:12:38 -06:00
Behdad Esfahbod
b2179dcfcd [meson.build] Another try 2025-04-06 03:03:41 -06:00
Behdad Esfahbod
a777a9c535 [meson.build] Try fix using of find 2025-04-06 02:47:06 -06:00
Behdad Esfahbod
e332777763 [fuzzing/subset] Make TAP protocol 2025-04-06 02:34:48 -06:00
Behdad Esfahbod
740a103ba1 [meson] See if this fixes bots 2025-04-06 02:34:48 -06:00
Behdad Esfahbod
a530672f04 [meson.build] Don't use str.replace() method
Too recent.
2025-04-06 02:34:48 -06:00
Behdad Esfahbod
628a9ee28a [check-static-inits] objdump all objects together
We won't see which object has the bad initializers anymore.
We can later adapt to objdump each object one by one if
any error was found.

Changes test runtime from 1s down to 0.15s.
2025-04-06 02:34:48 -06:00
Behdad Esfahbod
fbda749bdb [meson.build] Try to bring down required version
range() not found
2025-04-06 02:34:48 -06:00
Behdad Esfahbod
da5a9fb860 [meson.build] Remove unused fs module 2025-04-06 02:34:48 -06:00
Behdad Esfahbod
b01cea95e1 [meson] Cosmetic 2025-04-06 02:34:48 -06:00
Behdad Esfahbod
1db93d2f6d [test/fuzzing/subset] Run chunks in parallel 2025-04-06 02:34:48 -06:00
Behdad Esfahbod
ee50fad676 [run-tests] black 2025-04-06 02:34:48 -06:00
Behdad Esfahbod
db953a43d0 [meson.build] Cosmetic 2025-04-06 02:34:48 -06:00
Behdad Esfahbod
69fd949014 [test/shape] Run using TAP protocol
Run all tests for a suite in one process. Saves runtime from
3s to 2s.
2025-04-06 02:34:48 -06:00
Behdad Esfahbod
2834900d92 [test/shape] Run each test suite in one process 2025-04-06 02:34:48 -06:00
Behdad Esfahbod
e4e4d66523 [test/api] Test remaining tests to TAP 2025-04-06 02:34:48 -06:00
Behdad Esfahbod
c523f9ac13 [test/shape] Use TAP
Checkpoint.
2025-04-06 02:34:48 -06:00
Behdad Esfahbod
f69ecc9438 [test/api] Set protocol:tap 2025-04-06 02:34:48 -06:00
Behdad Esfahbod
6acb2942e8 [ft] Fix compiler warnings
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 5s
2025-04-06 02:34:34 -06:00
Behdad Esfahbod
bee08cf290 [hb-test] Don't convert _ in test names to /
Some checks failed
msys2 / MINGW64 (push) Waiting to run
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
Slash is used for grouping...
2025-04-05 23:27:26 -06:00
Behdad Esfahbod
a46b93208a [subset] Remove printf from library! 2025-04-05 23:27:15 -06:00
Behdad Esfahbod
3cf48234b9 [hb-test.h] Remove unsed functions 2025-04-05 23:26:59 -06:00
Behdad Esfahbod
112b599826 [test] Minor use hb_test_init 2025-04-05 22:37:10 -06:00
Behdad Esfahbod
6c98519c7e [test/api] Simplify deps 2025-04-05 21:41:01 -06:00
Khaled Hosny
0a5cc89e00 Improve OSS-Fuzz build log URL [ci skip] 2025-04-06 04:08:22 +02:00
Behdad Esfahbod
d9304b69e0 [subset] Fix i686 oss-fuzz build hopefully 2025-04-05 20:04:10 -06:00
Khaled Hosny
58170206a1 Typo [ci skip] 2025-04-06 03:55:56 +02:00
Khaled Hosny
a24c40dfb4 [test/ot-math] Do away with global variables 2025-04-06 03:22:20 +02:00
Khaled Hosny
d74606bbff [test/ot-math] Port to use hb_test_open_font_file()
Avoids the unnecessary dependency on FreeType.
2025-04-06 03:22:20 +02:00
Khaled Hosny
2d8e5255f3 [test/ot-math] Add a test for the Cambria Math workaround 2025-04-06 02:48:49 +02:00
Khaled Hosny
f57b43c980 [ot-math] Workaround bad displayOperatorMinHeight in Cambria Math
See https://github.com/harfbuzz/harfbuzz/issues/4653 for details
2025-04-06 02:48:49 +02:00
Behdad Esfahbod
52a4bea109
Merge pull request #5255 from harfbuzz/subset-test-less
Reduce tested combinations of subset & threads tests
2025-04-05 17:26:09 -06:00
Behdad Esfahbod
b53000403e [run-fuzzer-tests] Remove duplicate chunksize 2025-04-05 17:15:50 -06:00
Behdad Esfahbod
7dcd69544b [test/shape/threads] Reduce number of tested combinations 2025-04-05 17:08:31 -06:00
Behdad Esfahbod
c42b6ea829 [test] Adjust subdir order 2025-04-05 17:04:56 -06:00
Behdad Esfahbod
e5541a0b63 [subset/test/cmap14] Reduce tested combinations
Fixes https://github.com/harfbuzz/harfbuzz/issues/5254
2025-04-05 17:02:31 -06:00
Behdad Esfahbod
d65fa93440 [subset/test/basics.tests] Reduce tested combinations 2025-04-05 16:58:06 -06:00
Behdad Esfahbod
00b4f86e5f [hb-subset] In batch mode preprocess font once
Speeds up cmap.tests from 3s to under .5s.
2025-04-05 16:20:05 -06:00
Behdad Esfahbod
267de2bb90 [hb-view] Report success/failure in --batch mode
Otherwise client can't know when the job is done.
2025-04-05 16:14:24 -06:00
Behdad Esfahbod
5194ec4758 [test/subset] Use --preprocess instead of --preprocess-face
The latter is obsolete and alias to the former.
2025-04-05 16:08:18 -06:00
Behdad Esfahbod
fa737da022 [hb-subset] Speed up parsing glyphs-file
Cache the font used to load glyph names.
2025-04-05 16:02:09 -06:00
Behdad Esfahbod
54295ccf45 [hb-subset] Speed up parsing glyphs-file
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
Cache the font used to load glyph names.
2025-04-05 15:26:07 -06:00
Behdad Esfahbod
0fecd2ecc3 [hb-subset] Accept gidXXX-style glyph names 2025-04-05 15:20:49 -06:00
Behdad Esfahbod
a637c08d5a [hb-subset] Fix leak 2025-04-05 15:02:28 -06:00
Khaled Hosny
866096d04a [ci] Install help2man on the linux-ci workflow
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
Generating manpages is not tested on any CI jobs otherwise.
2025-04-05 13:43:04 +02:00
Behdad Esfahbod
b6cbd6a0fc [README] Add another link
Some checks failed
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
2025-04-04 19:07:04 -06:00
Behdad Esfahbod
2f86ab8d47 [README] Cosmetic 2025-04-04 18:29:33 -06:00
Behdad Esfahbod
9971d84ea7 [README] Cosmetic 2025-04-04 18:28:14 -06:00
Behdad Esfahbod
bf3ce2cb6b [README] Cosmetic 2025-04-04 18:27:01 -06:00
Behdad Esfahbod
90331b41ef [README] Cosmetic 2025-04-04 18:26:06 -06:00
Behdad Esfahbod
3207575979 [subset] Allow options before --font-file
Fixes https://github.com/harfbuzz/harfbuzz/issues/4913
2025-04-04 18:13:36 -06:00
Behdad Esfahbod
0457d3d734 [buffer-deserialize] Ignore glyph extents
Fixes https://github.com/harfbuzz/harfbuzz/issues/5169
2025-04-04 16:17:32 -06:00
Behdad Esfahbod
9ddf3da71e [benchmark-shape] Accept one variation on the cmd-line 2025-04-04 16:04:07 -06:00
Khaled Hosny
43a7784922 11.0.1
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
2025-04-04 22:41:26 +02:00
Behdad Esfahbod
13752124d7 Fix compiler warnings 2025-04-04 14:00:25 -06:00
Behdad Esfahbod
623a7a4198 Whitespace 2025-04-04 13:25:06 -06:00
Behdad Esfahbod
c44f1e71d7 Cosmetic 2025-04-04 13:23:42 -06:00
Behdad Esfahbod
1337912680 Cosmetic 2025-04-04 13:00:30 -06:00
Behdad Esfahbod
cc782b5427 [RELEASING] Cosmetic 2025-04-04 12:59:43 -06:00
Behdad Esfahbod
7ba4e87934 [VarStore] Fix storage shift
Use all bits. That's what I meant.
2025-04-04 12:41:38 -06:00
Behdad Esfahbod
089a9961ad [README] Expand on API/ABI guarantee 2025-04-04 12:30:13 -06:00
Khaled Hosny
a55305038c [coretext] Fix -Wformat warning
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
../src/hb-coretext.cc:202:62: warning: format specifies type 'int' but the argument has type 'unsigned int' [-Wformat]
  202 |     DEBUG_MSG (CORETEXT, blob, "TTC index %d not supported", ttc_index);
      |                                           ~~                 ^~~~~~~~~
      |                                           %u

../src/hb-coretext.cc:417:65: warning: format specifies type 'int' but the argument has type 'unsigned int' [-Wformat]
  417 |     DEBUG_MSG (CORETEXT, nullptr, "TTC index %d not supported", ttc_index);
      |                                              ~~                 ^~~~~~~~~
      |                                              %u
2025-04-04 13:27:31 +02:00
Behdad Esfahbod
8994e91487
Merge pull request #5241 from harfbuzz/font-gdef-varstore
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
[shape] Use font-data for GDEF varStore cache
2025-04-03 22:50:49 -06:00
Behdad Esfahbod
d515630f6b [shape-font] Simplify logic 2025-04-03 22:31:13 -06:00
Behdad Esfahbod
d30d7f6b2b [ItemVariationStore] Use atomic int for cache 2025-04-03 22:25:34 -06:00
Behdad Esfahbod
9cae040bb4 [ItemVariationStore] Make cache atomic floats
Doesn't work with intrinsic atomic implementations. Disabled that.
Going through the C++11 atomics path now.

Will fix in next commit.
2025-04-03 22:18:14 -06:00
Behdad Esfahbod
810fbedf27 [shape] Use font-data for GDEF varStore cache
Last remaining alloc during shaping is gone!

Fixes https://github.com/harfbuzz/harfbuzz/issues/5237
2025-04-03 22:13:10 -06:00
Behdad Esfahbod
6cc9c01aaa
Merge pull request #5242 from harfbuzz/c++-atomics
Do our C++11 atomics build anywhere??
2025-04-03 22:12:26 -06:00
Behdad Esfahbod
e10d647a73 [atomic] Re-enable intrinsics implementation 2025-04-03 22:01:37 -06:00
Behdad Esfahbod
e404cf0860 [atomic] Fix C++11 implementation
Surprised no one has been using it.
2025-04-03 21:57:15 -06:00
Behdad Esfahbod
e480d9de96 Do our C++11 atomics build anywhere?? 2025-04-03 21:44:23 -06:00
Behdad Esfahbod
60fc8b4cbc [README] Add Python 2025-04-03 16:18:38 -06:00
Behdad Esfahbod
062c3b4d80 [README] Remove stale text 2025-04-03 16:16:57 -06:00
Behdad Esfahbod
2152ff779c [README] Link some developer documents 2025-04-03 16:15:00 -06:00
Behdad Esfahbod
18ab0f5522 [font] Fix serial_coords
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 2s
2025-04-03 04:04:40 -06:00
Behdad Esfahbod
c6c8dcdeca
Merge pull request #5239 from harfbuzz/alloc-free-var-shaping
Alloc free var shaping
2025-04-03 03:18:53 -06:00
Behdad Esfahbod
6f5b8d59c7 [ot-font] Streamline advance cache management 2025-04-03 02:57:48 -06:00
Behdad Esfahbod
7da049ed42 [varStore] Add clear_cache() 2025-04-02 15:22:13 -06:00
Behdad Esfahbod
da0c459dd4 [ot-font] Use helpers to acquire/release varStore cache 2025-04-02 15:22:13 -06:00
Behdad Esfahbod
37989fb4cd [ot-font] Adjust cache creation criteria for v_advances
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
2025-04-02 15:03:07 -06:00
Behdad Esfahbod
d3e4977c70 [gvar] Comment
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
2025-04-02 14:04:16 -06:00
Behdad Esfahbod
ef8c25ad9f [ot-font] Make advance-cache invalidation threadsafe
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
Hopefully.
2025-04-02 04:00:03 -06:00
Behdad Esfahbod
bbf0c6e781 [font] Bump coords serial if face changed
Such that ot-font clears its advance cache
2025-04-02 02:11:25 -06:00
Behdad Esfahbod
321c14c920
Merge pull request #5236 from harfbuzz/cmap-cache
Some checks failed
arm / arm-none-eabi (push) Waiting to run
fontations / build (push) Waiting to run
configs-ci / build (push) Waiting to run
linux-ci / build (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 2s
[cmap] Move cache from face user-data to cmap accelerator
2025-04-01 21:39:00 -06:00
Behdad Esfahbod
7f5fafec0d [GDEF] Simplify cache declaration 2025-04-01 21:35:28 -06:00
Behdad Esfahbod
8864c264b9 [cmap] Fix initialization 2025-04-01 21:22:16 -06:00
Behdad Esfahbod
3d0816c7c4 [cache] Simplify cache declarations 2025-04-01 21:18:29 -06:00
Behdad Esfahbod
591f00a281 [cmap] Move cache from face to cmap accelerator
No need to use user-data for it.

Fixes https://github.com/harfbuzz/harfbuzz/issues/5235
2025-04-01 21:09:06 -06:00
Behdad Esfahbod
7ebe6b48b6 [cmap] Whitespace 2025-04-01 20:46:55 -06:00
Behdad Esfahbod
4d5348d660 [set-digest] Comments 2025-04-01 18:12:56 -06:00
Behdad Esfahbod
bed2d3dd2b [cache] Add assertion for cache size
Expand cmap cache since free.
2025-04-01 17:52:57 -06:00
Behdad Esfahbod
89ab5f2b21 [cache] Comments 2025-04-01 17:48:08 -06:00
Behdad Esfahbod
48e7e5a008 [cache] Document 2025-04-01 17:43:35 -06:00
Behdad Esfahbod
9f83bbbe64
Merge pull request #5233 from harfbuzz/aat-deleted-glyph-marks
Some checks failed
Scorecard supply-chain security / Scorecard analysis (push) Failing after 2s
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Fix AAT deleted glyph marks interaction with fallback mark positioning
2025-04-01 04:15:24 -06:00
Behdad Esfahbod
91fd40ac7c [shape] Skip hidden / ignorables during fallback mark positioning
Fixes https://github.com/harfbuzz/harfbuzz/issues/5232
2025-04-01 04:03:41 -06:00
Behdad Esfahbod
ca66c64655 [aat] Better handle deleted-glyphs
1. Set their GDEF property. Probably irrelevant to morx shaping.
2. Add them to buffer contents, since that can trigger a state
machine start action too.
2025-04-01 03:25:41 -06:00
Garret Rieger
a1e587b75a [subset] Add hb_subset_cff_get_charstrings_index and hb_subset_cff2_get_charstrings_index.
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
These methods allow retrieving the entire charstrings index structure from a CFF or CFF2 table.
2025-03-31 16:28:28 -06:00
Behdad Esfahbod
a5b00faaf8 Fix build with HB_NO_DRAW 2025-03-31 14:29:16 -06:00
Behdad Esfahbod
d53cbeee41 [font] Fix warnings 2025-03-31 14:29:16 -06:00
dependabot[bot]
7c368dabae Bump setuptools from 77.0.3 to 78.1.0 in /.ci
Bumps [setuptools](https://github.com/pypa/setuptools) from 77.0.3 to 78.1.0.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v77.0.3...v78.1.0)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-31 14:23:31 -06:00
dependabot[bot]
674ce63021 Bump github/codeql-action from 3.28.12 to 3.28.13
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.28.12 to 3.28.13.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](5f8171a638...1b549b9259)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-31 14:23:19 -06:00
dependabot[bot]
4f5b31b7ea Bump actions/setup-python from 5.4.0 to 5.5.0
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.4.0 to 5.5.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](42375524e2...8d9ed9ac5c)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-31 14:23:07 -06:00
Behdad Esfahbod
4cf4099f07 [ot/ft] Round glyph extents instead of floor/ceil
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
1. The floor/ceil was being applied in the wrong order for y direction.
2. If the scale is negative, the floor/ceil should be reversed.

Just round them instead. That's what coretext / directwrite / fontations
font-funcs do.
2025-03-30 22:59:54 -06:00
Behdad Esfahbod
4954edb2b1 [test/vertical] Add more tests
Some checks failed
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
arm / arm-none-eabi (push) Has been cancelled
configs-ci / build (push) Has been cancelled
fontations / build (push) Has been cancelled
linux-ci / build (push) Has been cancelled
macos-ci / build (push) Has been cancelled
msys2 / CLANG64 (push) Has been cancelled
msys2 / MINGW32 (push) Has been cancelled
msys2 / MINGW64 (push) Has been cancelled
msvc / msvc-2019-amd64 (push) Has been cancelled
msvc / msvc-2019-x86 (push) Has been cancelled
2025-03-28 19:19:57 -06:00
Behdad Esfahbod
afa0549dff [fontations] More idiomatic 2025-03-28 18:38:40 -06:00
Behdad Esfahbod
67314b205a [test/vertical] Enable some on fontations 2025-03-28 16:41:41 -06:00
Behdad Esfahbod
c260550ae5 [test/shape] Improve run-tests output on failure 2025-03-28 16:34:12 -06:00
Behdad Esfahbod
18ced8dbb1 [test/vertical] Add more tests 2025-03-28 16:31:46 -06:00
Behdad Esfahbod
17c875c309 [buffer] Minor add a function 2025-03-28 16:26:27 -06:00
Behdad Esfahbod
ea08b04752 [util] Fix --glyphs output with negative numbers 2025-03-28 16:25:58 -06:00
Behdad Esfahbod
cb44134cbf [test/vertical] Test more font-funcs 2025-03-28 15:56:13 -06:00
Behdad Esfahbod
ef95dc0e7f [vmtx] Fix v_origin when no vmtx available 2025-03-28 15:50:05 -06:00
Behdad Esfahbod
c39ac0e171 [ot] Make v_origin work for more glyph formats 2025-03-28 14:24:39 -06:00
Behdad Esfahbod
1358e38154 [fontations] Implement last bits of v_origin 2025-03-28 13:15:37 -06:00
Behdad Esfahbod
1dac21c177 [errors] Add -Wuninitialized
Works with newer clang I think.
2025-03-28 12:44:20 -06:00
Behdad Esfahbod
22f81f70cb [font] Fix var initialization 2025-03-28 12:41:01 -06:00
Behdad Esfahbod
aad5780f53 [font] Move outline emboldening to font layer
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
Such that it works on all font-funcs.
2025-03-28 00:37:20 -06:00
Behdad Esfahbod
83481d65d0 [font] Move emboldening advances to the font layer
Instead of each font-funcs impl.

TODO: Do the same for draw_glyphs.
2025-03-28 00:21:20 -06:00
Behdad Esfahbod
a588761198 [font] Fix void return 2025-03-28 00:09:26 -06:00
Behdad Esfahbod
1f6da390e0 [fontations] Implement one fallback case in get_v_origin 2025-03-27 20:05:13 -06:00
Behdad Esfahbod
449752c57c [fontations] Fix get_v_advances() fallback
Was crashing without vmtx before.
2025-03-27 20:02:08 -06:00
Behdad Esfahbod
b808d1746d [fontations] Move variable scope 2025-03-27 19:52:42 -06:00
Behdad Esfahbod
9d584c4d3d [fontations] Remove stale comment 2025-03-27 19:34:54 -06:00
Behdad Esfahbod
82d664519c [subset] Fix check-symbols test
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
2025-03-27 17:47:56 -06:00
Behdad Esfahbod
7ba0368200 [test] Enable aat-trak on all font funcs now 2025-03-27 17:14:22 -06:00
Garret Rieger
283ab21841 [subset] remove CFF/CFF2 table presence checks.
Not needed now that we are checking accelerator validity.
2025-03-27 16:35:35 -06:00
Behdad Esfahbod
0752e5852b
Merge pull request #5219 from harfbuzz/gid_data
[subset] Add API for retrieving the raw per glyph outline data from CFF and CFF2.
2025-03-27 16:12:14 -06:00
Garret Rieger
ae8b288db7 [subset] Correctly handle lifetime of charstrings data blob returned by hb_subset_cff_get_charstring_data. 2025-03-27 22:07:06 +00:00
Behdad Esfahbod
c50c0a39e5
Merge pull request #5223 from harfbuzz/trak-back
Revert "[ot-font/trak] Move trak application to ot-font instead of ot…
2025-03-27 15:43:49 -06:00
Behdad Esfahbod
b4fd777c23 [aat] Remove hb_aat_layout_get_tracking() again
https://github.com/harfbuzz/harfbuzz/pull/5223
2025-03-27 15:37:01 -06:00
Qunxin Liu
5ebe36e1ac [subset] bug fix for CaretValueFormat3
Don't return false in case of a Hinting Device table
2025-03-27 15:12:42 -06:00
Behdad Esfahbod
208ffb3f1f [coretext-font] Undo tracking in get_[hv]_advances()
Fixes https://github.com/harfbuzz/harfbuzz/issues/5221
2025-03-27 15:10:52 -06:00
Behdad Esfahbod
dda1d95af2 Revert "[ot-font/trak] Move trak application to ot-font instead of ot-shape"
This reverts commits ffae5b040d and
17c11ec523.

Plus manual modifications.

See https://github.com/harfbuzz/harfbuzz/issues/5221
2025-03-27 14:44:52 -06:00
Garret Rieger
0d4053b11d [subset] Add hb-subset.h API for retrieving the raw per glyph outline data from CFF and CFF2. 2025-03-27 20:20:52 +00:00
Behdad Esfahbod
7c90f446c2
Merge pull request #5216 from harfbuzz/manpages
[util] Towards building manpages
2025-03-27 14:13:04 -06:00
Behdad Esfahbod
d47a47e20b [util] Make --help less verbose again
Just the main page gets env-vars, exit-codes, and see-also.
2025-03-27 13:59:08 -06:00
Khaled Hosny
7ab42f9af3 [util] Build man pages only if docs are enabled 2025-03-27 21:31:29 +02:00
Khaled Hosny
9609f50bad [util] Build man page only if the corresponding util is built 2025-03-27 21:31:29 +02:00
Khaled Hosny
9a80c0da84 [util] Install man pages 2025-03-27 21:16:12 +02:00
John Bampton
ba6869848f src: fix spelling in code comments
Co-authored-by: Max Base <MaxBaseCode@gmail.com>
2025-03-27 12:18:07 -06:00
Behdad Esfahbod
7f10c0edfd [util] Towards building manpages
TODO:
1. Only when docs are enabled?
2. Installdir
3. How to include in release?

Fixes https://github.com/harfbuzz/harfbuzz/issues/5208
2025-03-26 22:21:51 -06:00
Behdad Esfahbod
bd5b8a1feb [util] Report exit codes in help
Some checks failed
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
arm / arm-none-eabi (push) Waiting to run
2025-03-26 21:35:32 -06:00
Behdad Esfahbod
e4410a85fa [util] Simplify envvar reporting 2025-03-26 21:35:32 -06:00
Khaled Hosny
a6f563247e [util] Fix Windows build
Windows headers define `environ`.
2025-03-27 03:26:20 +02:00
Behdad Esfahbod
93288a1ced [util] Fix crasher 2025-03-27 03:26:20 +02:00
Behdad Esfahbod
a410a042c7 [util] Add environment and see also sections
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
Part of https://github.com/harfbuzz/harfbuzz/issues/5208
2025-03-26 18:09:07 -06:00
Behdad Esfahbod
4d83b238ea [util] Link to website for more info / reporting bugs
Part of https://github.com/harfbuzz/harfbuzz/issues/5208
2025-03-26 13:01:34 -06:00
Behdad Esfahbod
59001aa952 [util] Add brief --help descriptions
Part of https://github.com/harfbuzz/harfbuzz/issues/5208
2025-03-26 12:33:06 -06:00
Behdad Esfahbod
3d3f241941 [util] Improve help messages a bit
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
Part of https://github.com/harfbuzz/harfbuzz/issues/5208
2025-03-26 01:18:09 -06:00
Behdad Esfahbod
75643768de [util] List available shapers in --help-all
Remove it from --version.

Part of https://github.com/harfbuzz/harfbuzz/issues/5208
2025-03-26 01:00:38 -06:00
Behdad Esfahbod
29c800bd8d [util] Return diff values for diff failures
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 0s
Need documentation in the help output...

Fixes https://github.com/harfbuzz/harfbuzz/issues/5164
2025-03-25 16:55:03 -06:00
Qunxin Liu
192d264ae7 [subset] remove divisions when computing the cost of binary search 2025-03-25 15:37:14 -06:00
Behdad Esfahbod
4d2a362f84 [test/subset] Remove tempdir
Was creating a tempdir in /tmp for every single test item,
and not removing it.  Create one per test file, and remove
if test successful.
2025-03-25 15:36:39 -06:00
Behdad Esfahbod
bed29d1cd3
Merge pull request #5211 from harfbuzz/aots-update
Aots update
2025-03-25 15:19:56 -06:00
Behdad Esfahbod
e16a985798 [test/shape/aots] Add directive to run with ot shaper only 2025-03-25 15:17:23 -06:00
Behdad Esfahbod
851d3e33b5 [aots] Fix compile error
Also requires https://github.com/adobe-type-tools/aots/pull/5 to
be merged. Or if that repo is inactive, we can switch to my fork.
2025-03-25 15:06:24 -06:00
Behdad Esfahbod
2b5f244639 [util] Remove hb-ot-shape-closure
Not used...
2025-03-25 14:12:36 -06:00
Behdad Esfahbod
eec9108416 [test/shape] Adjust uniscribe test 2025-03-25 13:56:12 -06:00
Behdad Esfahbod
fea0c0df33 [fontations] More idiomatic 2025-03-25 12:34:00 -06:00
Behdad Esfahbod
fe51e23738
Merge pull request #5206 from harfbuzz/tests-improvements
Some small test improvements
2025-03-25 12:20:02 -06:00
Khaled Hosny
188531b3ba [circleci] Drop minsize job
It is causing trouble again and it was never that useful.
2025-03-25 19:24:00 +02:00
Khaled Hosny
d81d4dfbd3 [circleci] Lets see of using Ubuntu 24.04 fixes the minsize job 2025-03-25 19:24:00 +02:00
Khaled Hosny
614013940d [test/shape] Update comment 2025-03-25 19:24:00 +02:00
Khaled Hosny
190ad35f71 [test/shape] Don’t skip test if hb-shape --list-* fails
This can happen with Wine when, e.g., `WINEPATH` is not set, and we
would silently skip the tests because lists of supported shapers etc.
are empty.
2025-03-25 16:34:19 +02:00
Khaled Hosny
6cf308c857 [test/shape] Remove @font-funcs-=directwrite from directwrite test
The directwrite font functions support variations now, so this is no
longer needed.
2025-03-25 10:34:43 +02:00
Khaled Hosny
1402ecfecf [test/shape] Use @shapers directive in uniscribe test 2025-03-25 10:33:38 +02:00
Behdad Esfahbod
46a30fe390 [test/shape] Respect @shapers directive
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
2025-03-24 18:23:34 -06:00
Behdad Esfahbod
bb3a55a61a [fontations] Add TODO
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
msys2 / CLANG64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
2025-03-24 17:05:58 -06:00
Behdad Esfahbod
0affe12785 [fontations] Apply variations to glyph_v_advances 2025-03-24 17:00:57 -06:00
Behdad Esfahbod
83d3ffc5d1 [fontations] Hook up variations to v_origin
Output matches ot backend, but not ft. Not gonna dig down there
right now. I *think* ft doesn't implement VORG table IIRC.
2025-03-24 16:58:12 -06:00
Behdad Esfahbod
0ae4b8f48e [fontations] Implement glyph_v_advances
Without variations for now.
2025-03-24 16:45:35 -06:00
Behdad Esfahbod
aa450db1f7 [README.mingw.md] Update for newer meson
https://github.com/mesonbuild/meson/issues/14400
2025-03-24 16:35:51 -06:00
Behdad Esfahbod
10256a9fc7 [README.mingw] Reword 2025-03-24 16:13:14 -06:00
Behdad Esfahbod
6c337ddc24 [README.mingw] Add note re Apple silicon 2025-03-24 16:04:49 -06:00
Christoph Reiter
59c0deba8f [ci/msys2] Remove workaround for meson preferring system libraries
The workaround was added in #4354 to avoid the linker using system harfbuzz
over the just built one.

This is/was most likely https://github.com/mesonbuild/meson/pull/12861
which hopefully should be merged upstream for meson 1.8.

In MSYS2 we have backported this fix for over a year since
https://github.com/msys2/MINGW-packages/pull/20058 so using the meson
package provided by MSYS2 (as is the case here) should avoid the problem
already.
2025-03-24 13:36:00 -06:00
Christoph Reiter
7876aac4eb [ci/msys2] install pkgconf instead of pkg-config
It's the default implementation in MSYS2 and pacman was not installing
it anyway since it conflicted with pkgconf which was required by other
packages earlier in the install list.
2025-03-24 13:36:00 -06:00
Christoph Reiter
4901ecd66e [ci/msys2] Remove winjitdebug workaround
This was added in #3903 to workaround a Python crasher. The issue
has been fixed for a while now, so remove the workaround.
2025-03-24 13:36:00 -06:00
Behdad Esfahbod
589e78cec5 [fontations] Handle recursive clip-glyphs
This reverts 852f66a418 in spirit,
using a malloc-free implementation and keeping the fill-glyph
optimization.
2025-03-24 13:21:56 -06:00
Christoph Reiter
5c3f23c09c [ci/msys2] Add a job building in the clang/llvm environment
Clang is more strict in certain areas and will fail, like
https://github.com/harfbuzz/harfbuzz/pull/5079#issuecomment-2673805310
https://github.com/harfbuzz/harfbuzz/issues/5197

* Add CLANG64 to the matrix
* Install the virtual "cc" package which pulls in the default compiler
  for the respective environment
* Remove gcc-libs, it should be pulled in automatically
* Depend on MSYSTEM_PREFIX for deleting files to be environment agnostic
2025-03-24 20:53:59 +02:00
Behdad Esfahbod
b114518310 [directwrite] Link to library
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 0s
Instead of loading at runtime. I just want to see how CI deals with
this. Otherwise, not depending on dwrite is probably desired.
2025-03-24 15:31:36 +02:00
dependabot[bot]
eda33efc88 Bump ninja from 1.11.1.3 to 1.11.1.4 in /.ci
Bumps [ninja](https://github.com/scikit-build/ninja-python-distributions) from 1.11.1.3 to 1.11.1.4.
- [Release notes](https://github.com/scikit-build/ninja-python-distributions/releases)
- [Changelog](https://github.com/scikit-build/ninja-python-distributions/blob/master/HISTORY.rst)
- [Commits](https://github.com/scikit-build/ninja-python-distributions/compare/1.11.1.3...1.11.1.4)

---
updated-dependencies:
- dependency-name: ninja
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-24 15:18:36 +02:00
Khaled Hosny
c141541159 [circleci] Add timeout multiplier when running tests under wine
We are getting occasional timeout.
2025-03-24 15:17:51 +02:00
dependabot[bot]
2fd2f8e711 Bump setuptools from 76.0.0 to 77.0.3 in /.ci
Bumps [setuptools](https://github.com/pypa/setuptools) from 76.0.0 to 77.0.3.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v76.0.0...v77.0.3)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-24 15:14:49 +02:00
dependabot[bot]
b690de572c Bump github/codeql-action from 3.28.11 to 3.28.12
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.28.11 to 3.28.12.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](6bb031afdd...5f8171a638)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-24 15:14:25 +02:00
dependabot[bot]
9c63dcb3fe Bump actions/upload-artifact from 4.6.1 to 4.6.2
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.1 to 4.6.2.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](4cec3d8aa0...ea165f8d65)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-24 15:14:07 +02:00
Behdad Esfahbod
ba709a385e [dwrite] Fix cast-align error-warning
Fixes https://github.com/harfbuzz/harfbuzz/issues/5197
2025-03-24 02:08:04 -06:00
Behdad Esfahbod
0849d3d8b6 [fontations] Minor shuffle 2025-03-24 02:08:04 -06:00
Behdad Esfahbod
8e1502cce8 [fontations] Implement glyph_v_origin 2025-03-24 02:08:04 -06:00
Khaled Hosny
2ed9c2826a [circleci] Fix YAML lint error [ci skip] 2025-03-24 01:24:39 +02:00
Khaled Hosny
48ce9c397e [ci] Try to fix uploading Windows binaries [ci skip]
We will find out if it works when cutting the next release.
2025-03-24 01:05:24 +02:00
Khaled Hosny
ea6a172f84 11.0.0 2025-03-24 00:33:53 +02:00
Behdad Esfahbod
7599d097c9 [README.mingw] Adjust
Installing system HarfBuzz makes it override our own build.
2025-03-23 15:12:02 -06:00
Behdad Esfahbod
7612ec44dc [util] Show glyph extents only if available 2025-03-23 13:11:23 -06:00
Behdad Esfahbod
391cbed883 [fontations] Support non-uniform scales 2025-03-23 12:58:34 -06:00
Behdad Esfahbod
4cc66435f9
Merge pull request #5188 from harfbuzz/text-rendering-tests-fontations
Text rendering tests fontations
2025-03-23 12:06:54 -06:00
Behdad Esfahbod
74c82b3a29 Blacken 2025-03-23 11:52:45 -06:00
Behdad Esfahbod
f0e260ad73 [text-rendering-tests] Run against ot,ft only
See https://github.com/harfbuzz/harfbuzz/pull/5188
2025-03-23 11:51:58 -06:00
Behdad Esfahbod
af6b6b4828 [README] More 2025-03-23 09:54:49 -06:00
Behdad Esfahbod
4f12035e5d [README.mingw] Update as per recent changes 2025-03-23 09:52:00 -06:00
Behdad Esfahbod
e4b633deb8
Merge pull request #5194 from harfbuzz/test-directwite-variations
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
[test/directwrite] Make the variations test actually test variations
2025-03-23 09:21:47 -06:00
Khaled Hosny
8d62ad3b35 [directwrite] Don’t release IDWriteFace pass to hb_directwrite_font_create
That was a leftover from previous code and is incorrect now as we would
be double releasing it.
2025-03-23 15:40:41 +02:00
Khaled Hosny
c226da8c35 [test/directwrite] Make the variations test actually test variations 2025-03-23 15:40:41 +02:00
Behdad Esfahbod
f48d641483
Merge pull request #5191 from harfbuzz/ci-exe-wrapper
Some checks failed
arm / arm-none-eabi (push) Waiting to run
configs-ci / build (push) Waiting to run
fontations / build (push) Waiting to run
linux-ci / build (push) Waiting to run
macos-ci / build (push) Waiting to run
msvc / msvc-2019-amd64 (push) Waiting to run
msvc / msvc-2019-x86 (push) Waiting to run
msys2 / MINGW32 (push) Waiting to run
msys2 / MINGW64 (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Failing after 7s
Revert "[ci] Don’t set exe_wrapper in the cross files"
2025-03-22 20:36:59 -06:00
Behdad Esfahbod
018858b2ce
Merge branch 'main' into ci-exe-wrapper 2025-03-22 20:24:44 -06:00
Behdad Esfahbod
2421efc17b
Merge pull request #5192 from harfbuzz/dwrite-font-vars
[directwrite] Clean up API / font handling and make variations work on font-funcs
2025-03-22 20:23:29 -06:00
Behdad Esfahbod
3259f9f89a [test-directwrite] Fix test 2025-03-22 20:14:01 -06:00
Behdad Esfahbod
55743b239f [test/shape] Skip uniscribe/directwrite shapers under Wine 2025-03-22 19:56:00 -06:00
Behdad Esfahbod
9afdc7e1d2 [test-directwrite] Simplify 2025-03-22 19:48:15 -06:00
Khaled Hosny
1c7a1c7b04 [test-directwrite] Don’t fail if Bahnschrift can’t be loaded under Wine
It is unlikely to be present if one is not running on Windows.
2025-03-23 02:10:06 +02:00
Khaled Hosny
ed558e5da4 [test] Add name table to test/api/fonts/glyphs.ttf
Some version of Wine fails to load the font otherwise.
2025-03-23 01:28:41 +02:00
Behdad Esfahbod
45a724b90c [coretext] Make font-funcs respond to font changes
Fixes https://github.com/harfbuzz/harfbuzz/issues/5173
2025-03-22 17:20:07 -06:00
Behdad Esfahbod
f53befb6a0 [test/directwrite] Fix a leak 2025-03-22 16:54:56 -06:00
Behdad Esfahbod
b159f5c74e [directwrite] Fix docs 2025-03-22 16:46:43 -06:00
Behdad Esfahbod
298a367ad3 [directwrite] Graduate from experimental 2025-03-22 16:42:56 -06:00
Behdad Esfahbod
24a23aca69 [directwrite] Make font-funcs respond to font changes 2025-03-22 16:41:39 -06:00
Behdad Esfahbod
91bd6bf0df [directwrite] Make variations work on font-funcs 2025-03-22 16:38:56 -06:00
Khaled Hosny
40ef946ec5 [circleci] Set LANG=en_US.UTF-8 on cross-compile jobs
Otherwise GLib fails when running the tests under Wine with:
GLib-WARNING (recursed) **: Failed to determine console output code page: Invalid access.. Falling back to UTF-8
2025-03-23 00:16:02 +02:00
Khaled Hosny
b205a7fbe8 [circleci] Run tests on cross-compile jobs 2025-03-23 00:03:16 +02:00
Behdad Esfahbod
c274ee7b3e [directwrite] Add hb_font_t setter/getter from IDWriteFontFace
Changed API:
+hb_directwrite_font_create()

New API:
+hb_directwrite_font_get_dw_font_face()
2025-03-22 16:02:39 -06:00
Behdad Esfahbod
f0b0d92ab5 [directwrite] Deprecate hb_directwrite_font_get_dw_font() 2025-03-22 15:44:50 -06:00
Behdad Esfahbod
201a0fe361 [coretext] Fix a warning 2025-03-22 15:32:22 -06:00
Behdad Esfahbod
6e17bd374f [README.mingw] Add a couple Ubuntu lines 2025-03-22 15:15:19 -06:00
Khaled Hosny
7153e7814b [circleci] Install wine on cross-compile jobs 2025-03-22 23:09:33 +02:00
Khaled Hosny
8db34adc37 Revert "[ci] Don’t set exe_wrapper in the cross files"
This reverts commit e3dc86bb0f.
2025-03-22 23:04:23 +02:00
Behdad Esfahbod
e0aee5815a [test] Respect MESON_EXE_WRAPPER in more test runners
It's not working for me though. Meson doesn't seem to set WINEPATH
during testing.
2025-03-22 14:56:37 -06:00
Behdad Esfahbod
c3bc5e4c68
Merge pull request #5189 from harfbuzz/font-changed
[font] Simplify changed mechanism
2025-03-22 14:23:07 -06:00
Behdad Esfahbod
6509414227 [fontations] Make serial tracking atomic
Would shut up tsan if we ever tried it on this.
2025-03-22 14:19:34 -06:00
Behdad Esfahbod
977e4f94e0 [font] Simplify changed mechanism 2025-03-22 14:09:26 -06:00
Behdad Esfahbod
8ae92d0d83 [text-rendering-tests] Run against all font-funcs
One test is failing with fontations, and a few with directwrite.
2025-03-22 13:22:37 -06:00
Behdad Esfahbod
51a5618c54 [test] Update text-rendering-tests 2025-03-22 13:20:16 -06:00
Behdad Esfahbod
a388989af4 [README.mingw.md] Final touches, hopefully 2025-03-22 12:31:21 -06:00
Behdad Esfahbod
f7f9cd1296 [README.mingw.md] Review feedback 2025-03-22 11:42:32 -06:00
Behdad Esfahbod
e320109e5d
Merge pull request #5160 from harfbuzz/mingw-readme
[doc] Restore README.mingw.md
2025-03-22 01:30:45 -06:00
Behdad Esfahbod
f9ad7c37b1 [README.mingw.md] Update 2025-03-22 01:20:57 -06:00
Behdad Esfahbod
0b139a81fe [.ci/build-win.sh] Enable tests 2025-03-22 01:05:26 -06:00
Khaled Hosny
4fd4dbb896 [doc] Restore README.mingw.md
It got deleted in cf1fdf1632 but it is
still useful. Needs to be updated to meson world, though.
2025-03-22 00:34:27 -06:00
Behdad Esfahbod
475afee0b8 Change file permission 2025-03-22 00:21:20 -06:00
Behdad Esfahbod
0eeb6ccb42 [perf] Bikeshedding 2025-03-21 17:36:43 -06:00
Behdad Esfahbod
cfb962d73c [fontations] Use the proposed pop_layer_with_mode
Reduces the last Vec use.

https://github.com/googlefonts/fontations/pull/1419
2025-03-21 15:03:28 -06:00
Behdad Esfahbod
9fa31d1ed2 [fontations] Enable lto in dev builds as well
Otherwise our check-symbols test will fail.
2025-03-21 14:44:03 -06:00
Behdad Esfahbod
852f66a418 [fontations] Implement fill-glyph
Gets rid of one Vec.

Supersedes:
https://github.com/harfbuzz/harfbuzz/pull/5180
https://github.com/harfbuzz/harfbuzz/pull/5184
2025-03-21 14:14:12 -06:00
Behdad Esfahbod
c867bc976a [test] Minor, adjust usage 2025-03-21 00:59:35 -06:00
Behdad Esfahbod
a551736532 [test] Add hb-paint-all 2025-03-20 23:23:58 -06:00
Behdad Esfahbod
6a82561f00 [hb-draw-all] Error handling 2025-03-20 23:21:28 -06:00
Behdad Esfahbod
cc0451c949 [cff2] Malloc-free draw of var blends 2025-03-20 20:57:31 -06:00
Behdad Esfahbod
e2a24ce13a
Merge pull request #5177 from harfbuzz/exe_wrapper
[test] Allow running test suite under wine
2025-03-20 19:14:58 -06:00
Behdad Esfahbod
be90974de8 [test/draw] Add meson.build 2025-03-20 19:12:29 -06:00
Behdad Esfahbod
1d25de8316 [test] Add draw/hb-draw-all 2025-03-20 19:11:26 -06:00
Khaled Hosny
e3dc86bb0f [ci] Don’t set exe_wrapper in the cross files
Complicates the build setup. Keep it commented in case one wants to
enable it locally.
2025-03-21 03:02:56 +02:00
Khaled Hosny
a189b0f772 Revert "[ci] Install wine on Windows cross-compile jobs"
This reverts commit ca14981262.
2025-03-21 03:02:19 +02:00
Khaled Hosny
ca14981262 [ci] Install wine on Windows cross-compile jobs 2025-03-21 02:34:40 +02:00
Khaled Hosny
12e31ab7e8 [test] Allow running test suite under wine
Set exe_wrapper in the Windows cross files, which will cause unit tests
to be run with wine.

When we call the binary ourselves, e.g. in shape run-tests.py, we need
to check for MESON_EXE_WRAPPER env var (which meson sets automatically
if exe_wrapper is set) and use it.
2025-03-21 02:27:45 +02:00
Khaled Hosny
14c07dcfa7 [test] Make context-matching test pass with coretext font functions
Remove the CBDT/CBLC tables not needed for the test and a glyf/loca
tables with blank glyphs to make Core Text load the font.
2025-03-20 18:05:30 -06:00
Behdad Esfahbod
b2f7f6db1a
Merge pull request #5165 from harfbuzz/fontations-glyph-name
Fontations glyph name
2025-03-20 14:35:55 -06:00
Behdad Esfahbod
64dcece342 [fontations] Clean up atomic initialization based on review 2025-03-20 14:05:57 -06:00
Behdad Esfahbod
4107cceea1 [fontations] Roll skrifa forward
Tests pass now.
2025-03-20 14:00:06 -06:00
Behdad Esfahbod
c84b9dca24
Merge pull request #5170 from harfbuzz/directwrite-shape-variations
[directwrite] Copy font variations when shaping
2025-03-20 11:18:58 -06:00
Ozkan Sezer
e57e728532 cmake: add missing FT_Get_Transform check 2025-03-20 13:18:45 +02:00
Khaled Hosny
686503e2e0 [directwrite] Copy font variations when shaping 2025-03-20 01:59:56 +02:00
Behdad Esfahbod
24ad0dd46b [fontations] Implement glyph_from_name (with caching) 2025-03-19 16:09:05 -06:00
Behdad Esfahbod
b3d48c2c1b [coretext] Only try setting variations if a variable font
Seems to fix https://github.com/harfbuzz/harfbuzz/issues/5163
2025-03-19 15:16:11 -06:00
Behdad Esfahbod
4822cb7672 [hb-info] Report WebAssembly in technology 2025-03-19 15:14:58 -06:00
Behdad Esfahbod
60ce16f221 [CI] Fix build 2025-03-19 13:22:27 -06:00
Behdad Esfahbod
34b9100c67 [hb-info] Fix argument parsing vs default behavior
Default was if no args other than one font was provided, then
--show-all was enabled. This broke if eg. --face-loader=ft was
provided, then suddenly nothing was shown. Fix it to --show-all
if no "query" options are provided.
2025-03-19 13:15:44 -06:00
Behdad Esfahbod
82e0ff6da0 [fontations] Implement get_glyph_name 2025-03-19 12:52:22 -06:00
Behdad Esfahbod
1a8352cfdb [fontations] Roll skrifa to 0.29 2025-03-19 12:51:29 -06:00
Khaled Hosny
59aee7f3e8 [directwrite] Fix copying variations in hb_directwrite_font_create()
I missed the endianness mismatch between HarfBuzz and DirectWrite tags.
2025-03-19 14:47:22 +02:00
Behdad Esfahbod
0349359ce6 [tests] Fix one test 2025-03-18 14:59:26 -06:00
Behdad Esfahbod
38889c3ad6 [coretext] Fix loading named instances
Needs tests...

TTC indices > 0 can't be loaded with CoreText API it seems.

Fixes https://github.com/harfbuzz/harfbuzz/issues/5158
2025-03-18 03:28:44 -06:00
Behdad Esfahbod
472e65dd0f [cff] Allow empty private dict (again)
Fixes https://github.com/harfbuzz/harfbuzz/issues/5162
2025-03-18 03:17:49 -06:00
Behdad Esfahbod
0ebcc66506 [coretext] Fix glyph bounds 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
696b4a26a8 [coretext] Blocklist one more shape test 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
ad9c473759 [test/shape] Make output less verbose 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
630bc9b45d [coretext] Disable variation-selectors test :-( 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
719dafdaad [test/shape] Allow comments in directives
Also adjust tests for directwrite font-funcs.
2025-03-17 21:05:21 -06:00
Behdad Esfahbod
27bb37c5d0 [test/shape] Fix reporting 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
b24a93c68e [util] Reload face if face-loader changed 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
9a0802dbe5 [test/shape] Comments 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
ee34711d64 [test/shape] Allow directives to instruct what backends to test 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
220a8b9496 [test/shape] Massage script some more 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
7c248cccb5 [test/shape] Var rename 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
3e137c8e8a [test/shape] Minor massage the runner 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
cf1772a492 [test/shape] Compare results without glyph names if needed
Enable fontations font-funcs, which mostly passes now.
2025-03-17 21:05:21 -06:00
Behdad Esfahbod
a37fb2fbf7 [test/shape] Rename a couple of variables 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
24f9fd46ce [test/shape] Restart hb-shape --batch process if killed 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
5b3bf25bb8 [test/shape] Test all font-funcs backends if none specified
Disable fontations as it doesn't implement glyph names currently.
2025-03-17 21:05:21 -06:00
Behdad Esfahbod
f16196a00e [test-shape] Assume ot shaper is default 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
0d5795c0a5 [test/shape] Report shaper, face-loader, font-funcs 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
aacc667e51 [test/shape/run-tests] Streamline testing other backends 2025-03-17 21:05:21 -06:00
Behdad Esfahbod
cdfbb7efb9 [ci] Massage cross-win building
Move install dir inside build dir.
2025-03-17 18:02:08 -06:00
Khaled Hosny
ee15f723fd [ci] Remove the unused second argument to build-win.sh 2025-03-18 01:33:23 +02:00
Khaled Hosny
9298b31046 [ci] Pass the rest of arguments to meson 2025-03-18 01:26:43 +02:00
Khaled Hosny
286e832854 [ci] Use release buildtype when cross-compiling 2025-03-17 22:03:59 +02:00
Khaled Hosny
a520ee9503 [ci] Simplify cross-build script
Tell meson to strip the binaries and call meson install so they are
actually striped, and copy binaries from install dir.
2025-03-17 22:03:59 +02:00
Khaled Hosny
d65fd65608 [ci] Explicitly disabled more auto options when cross-compiling 2025-03-17 22:03:59 +02:00
Khaled Hosny
1a7b31f260 [ci] Fix meson deprecation warning
DEPRECATION: c_args in the [properties] section of the machine file is deprecated, use the [built-in options] section.
DEPRECATION: c_link_args in the [properties] section of the machine file is deprecated, use the [built-in options] section.
DEPRECATION: cpp_args in the [properties] section of the machine file is deprecated, use the [built-in options] section.
DEPRECATION: cpp_link_args in the [properties] section of the machine file is deprecated, use the [built-in options] section.
2025-03-17 22:03:59 +02:00
Khaled Hosny
7272abc35e [ci] Merge build-win32.sh and build-win64.sh 2025-03-17 22:03:59 +02:00
Khaled Hosny
6a50badb57 [ci] Disable libffi tests
They don’t build on MingW with -fno-exceptions
2025-03-17 17:41:27 +02:00
Khaled Hosny
4dc25e7066 [ci] Add libffi warp with fallback download URL
To fix failing CI runs because freedesktop.org is down.
2025-03-17 17:41:27 +02:00
Behdad Esfahbod
f9aabf7062
Merge pull request #5156 from harfbuzz/coretext-variations-always
[coretext] Always set all variation axes
2025-03-17 09:02:41 -06:00
Behdad Esfahbod
38db0f4c12 [coretext] Always set all variation axes 2025-03-17 08:51:39 -06:00
Behdad Esfahbod
6ccfadb911
Merge pull request #5153 from harfbuzz/coretext-variations
[coretext] Always set all variations
2025-03-16 21:12:14 -06:00
Behdad Esfahbod
422ffff15c [coretext] Always set all variations
Even when at default, looks like this is necessary.

Fixes https://github.com/harfbuzz/harfbuzz/issues/5142
2025-03-16 21:03:46 -06:00
Behdad Esfahbod
bd2bf3536c
Merge pull request #5152 from harfbuzz/fix-trak-finding
[trak] Fix track finding logic
2025-03-16 17:30:57 -06:00
Behdad Esfahbod
a9a3fd33a2 [trak] Fix track finding logic 2025-03-16 17:10:19 -06:00
Behdad Esfahbod
0a991cc543
Merge pull request #5151 from harfbuzz/slant-extents
[font] Move synthetic glyph extents into font layer
2025-03-16 11:46:44 -06:00
Behdad Esfahbod
14e5a046c8 [font] Move synthetic glyph extents into font layer
So it applies to all font-funcs.
2025-03-16 01:02:55 -06:00
Behdad Esfahbod
a95a500d3d
Merge pull request #5149 from harfbuzz/dwrite-fontfuncs
[directwrite] Add fontfuncs

Fixes #5143.
2025-03-15 21:27:17 -06:00
Behdad Esfahbod
8d8fe19099 [dwrite] Add font-funcs sketch
Small steps.

Fixes https://github.com/harfbuzz/harfbuzz/issues/5144
2025-03-15 21:03:30 -06:00
Behdad Esfahbod
08781f6f7d [dwrite] Set face index / glyph_count on hb-face 2025-03-15 20:05:01 -06:00
Behdad Esfahbod
93f8cbf4fa [meson] Add missing .hh files to sources
Manually checked with find and grep...
2025-03-15 19:23:52 -06:00
Behdad Esfahbod
6958064c7f
Merge pull request #5148 from harfbuzz/paint-font-transform
[paint] Add push_font_transform() / push_inverse_font_transform()
2025-03-15 18:45:00 -06:00
Behdad Esfahbod
000a0ad7a6 [paint] Add push_font_transform() / push_inverse_font_transform()
Fixes https://github.com/harfbuzz/harfbuzz/issues/5146
2025-03-15 18:35:32 -06:00
Behdad Esfahbod
e6519fcb2b
Merge pull request #5147 from harfbuzz/dwrite2
[dwrite] More work
2025-03-15 14:27:04 -06:00
Behdad Esfahbod
e1d395f4b5 [dwrite] Minor cleanup 2025-03-15 14:13:02 -06:00
Behdad Esfahbod
db8d099d4d [dwrite] Split shape code into its own file 2025-03-15 13:59:16 -06:00
Behdad Esfahbod
13849d4205 [dwrite] More cleanup 2025-03-15 13:25:49 -06:00
Behdad Esfahbod
e9d5ecca1d [directwrite] Simplify more 2025-03-15 13:15:03 -06:00
Behdad Esfahbod
d2b722803f [directwrite] Rely on more reference-counting for lifetime 2025-03-15 12:55:27 -06:00
Behdad Esfahbod
41d722c3d2 [directwrite] Remove unused member 2025-03-15 12:52:24 -06:00
Behdad Esfahbod
9d6e24a1d2 [draw] Fix build 2025-03-14 22:32:17 -06:00
Behdad Esfahbod
c1ed463195 [fontations] rustfmt 2025-03-14 22:14:28 -06:00
Behdad Esfahbod
bd05b260af [draw] Document slant_xy 2025-03-14 22:10:29 -06:00
Behdad Esfahbod
da4758e791 [draw] Apply synthetic slant to hb_draw_move_to() etc
Makes fontations draw slanted as well.

Fixes https://github.com/harfbuzz/harfbuzz/issues/5145
2025-03-14 22:07:45 -06:00
Behdad Esfahbod
b3a293813a [directwrite] Minor cleanup 2025-03-14 17:26:33 -06:00
Behdad Esfahbod
bda5b832b0 [directwrite] Mutex for font registration 2025-03-14 03:40:15 -06:00
Behdad Esfahbod
09d983258b [directwrite] Rename a function 2025-03-14 03:13:32 -06:00
Behdad Esfahbod
d441b4cbc7
Merge pull request #5140 from harfbuzz/directwrite-loader
[directwrite] Add hb_directwrite_face_create_from_blob_or_fail()
2025-03-14 03:05:26 -06:00
Behdad Esfahbod
e92cd9f769 [directwrite] Massage more
I think this is it!
2025-03-14 02:46:11 -06:00
Behdad Esfahbod
1e9d101ed7 [directwrite] Add hb_directwrite_face_create_from_file_or_fail()
Just loads the blob from file and creates a face from it.

New API:
+hb_directwrite_face_create_from_file_or_fail()
2025-03-14 02:14:23 -06:00
Behdad Esfahbod
c73b54bcca [directwrite] Massage more 2025-03-14 02:09:01 -06:00
Behdad Esfahbod
db93dbb286 [directwrite] More cleanup 2025-03-14 01:50:08 -06:00
Behdad Esfahbod
9e5a767855 [directwrite] Add singleton dwrite_dll 2025-03-14 01:22:05 -06:00
Behdad Esfahbod
64716226d2 [directwrite] Shuffle code around 2025-03-14 01:13:04 -06:00
Behdad Esfahbod
27fc376fe9 [directwrite] Addd lifecycle management to a few of objects 2025-03-13 18:27:59 -06:00
Behdad Esfahbod
aacaa8bba3 [directwrite] Flip loader & stream around 2025-03-13 17:18:31 -06:00
Behdad Esfahbod
2502d0b698 [directwrite] Use blob directly in the interface 2025-03-13 17:00:50 -06:00
Behdad Esfahbod
d0fef9a1fc [directwrite] Don't release the library
It crashes. Going to fix it to use a singleton, but for now
just not crash.
2025-03-13 16:56:47 -06:00
Behdad Esfahbod
ad3225c648 [direcwrite] Make blob immutable 2025-03-13 16:30:09 -06:00
Behdad Esfahbod
00360049e3 [directwrite] Handle failures in new API
Still crashes...
2025-03-13 16:22:45 -06:00
Behdad Esfahbod
f6744c2c73 [ci] Add pkg-config to win cross-compiling environment 2025-03-13 15:55:57 -06:00
Behdad Esfahbod
379688c566 [test-face] Relax on face load failure 2025-03-13 14:47:34 -06:00
Behdad Esfahbod
344915c9ea [face] Hook up directwrite face loader 2025-03-13 14:30:56 -06:00
Behdad Esfahbod
b0a5920d1a [directwrite] Add hb_directwrite_face_create_from_blob_or_fail()
Part of https://github.com/harfbuzz/harfbuzz/issues/5082

New API:
+hb_directwrite_face_create_from_blob_or_fail()
2025-03-13 14:27:37 -06:00
Behdad Esfahbod
7e4698abe2 [coretext] Move more code around 2025-03-13 14:16:08 -06:00
Behdad Esfahbod
471ac1cdc0
Merge pull request #5139 from harfbuzz/set-malloc-fix
[set] Fix reallocation
2025-03-13 13:41:43 -06:00
Behdad Esfahbod
5f61ccf07d [set] Fix reallocation
Was shrinking malloced vectors inadverently.
2025-03-13 13:22:28 -06:00
Behdad Esfahbod
a0fbd25e10
Merge pull request #5138 from harfbuzz/kerx-malloc
[kern/kerx]  zero-malloc
2025-03-13 12:01:01 -06:00
Behdad Esfahbod
c2f8066b2f [aat] Fix another malloc-fail crasher 2025-03-13 11:43:03 -06:00
Behdad Esfahbod
b57d2a2050 [aat] Fix a leak 2025-03-13 11:19:48 -06:00
Behdad Esfahbod
d6f5cbdd8c [aat] Fix a compiler warning 2025-03-13 11:14:54 -06:00
Behdad Esfahbod
64240602b4 [aat] Fix memfail crash 2025-03-13 10:56:39 -06:00
Behdad Esfahbod
7b8ae3d067 [kern/kerx] Make zero-malloc 2025-03-13 10:44:40 -06:00
Behdad Esfahbod
0f18838c69 [mort] Update with morx change 2025-03-13 08:52:19 -06:00
Behdad Esfahbod
a115228329
Merge pull request #5137 from harfbuzz/aat-mallocs
[aat] Reduce mallocs
2025-03-13 08:32:30 -06:00
Behdad Esfahbod
e5a01efd07 [aat] Put back one set of compiled map in the plan
Use it if there's no user features. Reduces mallocs.
2025-03-13 02:47:20 -06:00
Behdad Esfahbod
7b48aa37a7 [aat] Reduce mallocs
Untested.
2025-03-13 01:07:35 -06:00
Behdad Esfahbod
792b9b9337 [bit-vector] Add a has() 2025-03-12 23:56:52 -06:00
Behdad Esfahbod
43d421d388 [aat] Speed up deleted-glyph removal 2025-03-12 23:36:09 -06:00
Behdad Esfahbod
aa233ecedc [bit-vector] Add a hb_bit_vector_t type
Unused.
2025-03-12 23:05:04 -06:00
Behdad Esfahbod
402876d489
Merge pull request #5136 from harfbuzz/kerx-fix
Kerx fix
2025-03-12 22:48:59 -06:00
Behdad Esfahbod
c38d518718 [aat/kerx] Fix initial-glyph collection logic
Test:
$ hb-shape GeezaPro.ttc --unicodes U+064A,U+064E,U+0651,U+0629
2025-03-12 22:39:33 -06:00
Behdad Esfahbod
2449eb0882 [aat] Adjust filtering to match collect_glyphs() 2025-03-12 21:03:24 -06:00
Behdad Esfahbod
6388ce2224 [kerx] We don't need right_set in machine kerning 2025-03-12 20:58:06 -06:00
Behdad Esfahbod
b861b54178 [kerx] Cosmetic 2025-03-12 20:56:16 -06:00
Behdad Esfahbod
7146e5818f [kerx] Remove redundant check 2025-03-12 20:11:30 -06:00
Behdad Esfahbod
41b396c64b [kerx] Setup buffer glyphset 2025-03-12 20:02:58 -06:00
Behdad Esfahbod
83e0944f0f [kerx] Use a machine class cache
Like in morx.
2025-03-12 19:58:35 -06:00
Behdad Esfahbod
02733deded [kerx] Skip machine subtables that don't intersect the buffer
We do this extensively in morx. Do it here too.

Still no machine class cache in kerx.

Speeds up GeezaPro shaping Arabic text by 20%.
2025-03-12 19:44:07 -06:00
Behdad Esfahbod
45b2d28d04 Revert "[aat] Clear buffer glyph set"
This reverts commit b1a9219ac5.

Was unnecessary. collect_codepoints() clears the set.
2025-03-12 19:18:12 -06:00
Behdad Esfahbod
d76a23a3f1 [aat] Micro-optimize 2025-03-12 19:16:59 -06:00
Behdad Esfahbod
b1a9219ac5 [aat] Clear buffer glyph set
Should be clear already but no harm.
2025-03-12 19:13:14 -06:00
Behdad Esfahbod
54962b3fce [morx] Consolidate a check 2025-03-12 19:03:50 -06:00
Behdad Esfahbod
4807a021a1 [atomic] Kill hb_atomic_ptr_t<T>
Use hb_atomic_t<T *> instead.
2025-03-12 18:27:27 -06:00
Behdad Esfahbod
829d1eda16 [atomic] Clean up atomic_ptr_t 2025-03-12 18:19:04 -06:00
Behdad Esfahbod
a0d76c5b37 [atomic] Templatize 2025-03-12 17:16:55 -06:00
Behdad Esfahbod
bdee8658c6 [post] Fix a pointer type 2025-03-12 17:13:48 -06:00
Behdad Esfahbod
469502c99b [test-paint] Test fontations too
Luckily it passes!
2025-03-12 11:02:43 -06:00
Behdad Esfahbod
fbb81e344b [fontations] Adjust alignment requirement 2025-03-12 00:52:12 -06:00
Behdad Esfahbod
8d300049f5 [fontations] Assert layout alignment 2025-03-12 00:43:10 -06:00
Behdad Esfahbod
05cfdb9105 [fontations] link_with instead of link_whole
Now that the hb-fontations symbol is called from libharfbuzz,
it gets pulled in properly.
2025-03-12 00:08:42 -06:00
Behdad Esfahbod
0b2a0bac47
Merge pull request #5130 from harfbuzz/malloc-rust
[fontations] Make fontations use hb_malloc et al
2025-03-11 23:04:11 -06:00
Behdad Esfahbod
5bf81c3758 [common] Make hb_malloc() et al public
New API:
+hb_malloc()
+hb_calloc()
+hb_realloc()
+hb_free()
2025-03-11 22:52:34 -06:00
Behdad Esfahbod
a2c7dc0669
Merge pull request #5133 from harfbuzz/hb-coretext.cc
[coretext] Split common code into hb-coretext.cc
2025-03-11 20:43:32 -06:00
Behdad Esfahbod
f0a67e9948 [coretext] Split common code into hb-coretext.cc 2025-03-11 20:37:30 -06:00
Behdad Esfahbod
d014efd03d
Merge pull request #5131 from harfbuzz/using2
Add hb_ft_face_create_from_blob_or_fail() et al
2025-03-11 13:37:48 -06:00
Behdad Esfahbod
759e1881e8 [coretext] Fix loading TTC files 2025-03-11 12:46:27 -06:00
Behdad Esfahbod
15fcfcb606
Merge pull request #5129 from harfbuzz/buffer-deserialize
Fix buffer deserialize
2025-03-11 12:01:20 -06:00
Behdad Esfahbod
5e6da54166 [test] Minor, accept absolute font paths 2025-03-11 12:00:18 -06:00
Behdad Esfahbod
8687f5c38e [face] Add tests for new constructors 2025-03-11 11:56:00 -06:00
Behdad Esfahbod
8e8a9f6f40 [face] Add hb_face_create_or_fail_using()
Fixes https://github.com/harfbuzz/harfbuzz/issues/5117

Untested.

New API:
+hb_face_create_or_fail_using
2025-03-11 11:56:00 -06:00
Behdad Esfahbod
cbc205c2f0 [font/face] Refactor some code 2025-03-11 11:56:00 -06:00
Behdad Esfahbod
b1c50eb938 [face] Rename a variable 2025-03-11 11:56:00 -06:00
Behdad Esfahbod
f98c203e7a [coretext] Add hb_coretext_face_create_from_blob_or_fail()
Part of https://github.com/harfbuzz/harfbuzz/issues/5117

Untested.

New API:
+hb_coretext_face_create_from_blob_or_fail()
2025-03-11 11:56:00 -06:00
Behdad Esfahbod
8ca9fe7617 [face] Avoid edit-sanitizing in hb_face_count() 2025-03-11 11:56:00 -06:00
Behdad Esfahbod
e4fe8bf95e [ft] Add hb_ft_face_create_from_blob_or_fail()
Part of https://github.com/harfbuzz/harfbuzz/issues/5117

Untested.

New API:
+hb_ft_face_create_from_blob_or_fail()
2025-03-11 11:56:00 -06:00
Behdad Esfahbod
3c30562dc7
Merge pull request #5132 from harfbuzz/cplusplus-more
[test-cplusplus] Add more headers
2025-03-11 11:55:46 -06:00
Behdad Esfahbod
756668d35c [directwrite] Drop dependency again as per review
https://github.com/harfbuzz/harfbuzz/pull/5132#issuecomment-2714186460
2025-03-11 11:27:02 -06:00
Behdad Esfahbod
6b2f859232 [test-c] Disable gobject include
It can't find its dependent headers since not installed.
2025-03-11 00:37:11 -06:00
Behdad Esfahbod
8ca892b0e2 [directwrite] Simplify headers 2025-03-11 00:24:11 -06:00
Behdad Esfahbod
d247c116fb [test-draw] Test all font funcs 2025-03-11 00:15:40 -06:00
Behdad Esfahbod
d2ccf595bd Directwrite is a C++ header? 2025-03-11 00:15:19 -06:00
Behdad Esfahbod
41dcc493e5 [test-cplusplus] Simplify 2025-03-10 23:49:05 -06:00
Behdad Esfahbod
57deae5fd4 [meson] Check correct dependency
Ouch!
2025-03-10 23:40:22 -06:00
Behdad Esfahbod
dbad6cdfec [test-c(plusplus)] Add more headers 2025-03-10 23:23:16 -06:00
Behdad Esfahbod
3c02fcd0e8 [test-multithread] Simplify 2025-03-10 23:16:30 -06:00
Behdad Esfahbod
4323c6643b [fontations] Make fontations use hb_malloc et al 2025-03-10 20:09:34 -06:00
Behdad Esfahbod
7a912c4746 [buffer-deserialize] Fix return value and parsing
I think I got it right.

Alternative to https://github.com/harfbuzz/harfbuzz/pull/5028
2025-03-10 16:20:16 -06:00
Behdad Esfahbod
c2e92b6f7b [ragel] Update output files 2025-03-10 16:18:48 -06:00
Behdad Esfahbod
5a03844914 [gen-ragel-artifacts] Fail if ragel failed 2025-03-10 14:54:13 -06:00
dependabot[bot]
2edab536bd Bump setuptools from 75.8.2 to 76.0.0 in /.ci
Bumps [setuptools](https://github.com/pypa/setuptools) from 75.8.2 to 76.0.0.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v75.8.2...v76.0.0)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-10 14:57:08 +02:00
dependabot[bot]
18e9550579 Bump github/codeql-action from 3.28.10 to 3.28.11
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.28.10 to 3.28.11.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](b56ba49b26...6bb031afdd)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-10 14:56:55 +02:00
Behdad Esfahbod
9c0ac9aec4
Merge pull request #5069 from harfbuzz/cluster-level-graphemes
[buffer] Add HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES
2025-03-10 02:52:26 -06:00
Khaled Hosny
8ee8e0a213 [ci] Enable doc_tests on linux-ci only
One workflow is enough.
2025-03-10 10:36:55 +02:00
Khaled Hosny
885eef8ea5 [buffer/doc] Add docs for the new cluster level macros 2025-03-10 10:34:43 +02:00
Behdad Esfahbod
d8a774c011 [test] Add test for new grapheme cluster level 2025-03-10 01:04:35 -06:00
Behdad Esfahbod
f88fe4d403 [util] Update for new grapheme cluster level 2025-03-10 01:02:56 -06:00
Behdad Esfahbod
1531be8a1d [buffer] Add docs for the new cluster level 2025-03-10 01:02:11 -06:00
Behdad Esfahbod
9305aae476 [ot-layout] Revert back logic 2025-03-10 00:52:00 -06:00
Behdad Esfahbod
7518718671 [buffer] Add HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES
https://github.com/harfbuzz/harfbuzz/discussions/5026#discussioncomment-12168668
2025-03-10 00:52:00 -06:00
Behdad Esfahbod
62c320a2d6
Merge pull request #5126 from harfbuzz/aat-deleted-glyph-more
[aat/morx] Use a separate bit for deleted-glyphs
2025-03-09 21:02:48 -06:00
Behdad Esfahbod
0b62666ece [aat/morx] Use a separate bit for deleted-glyphs
Should address:
https://github.com/harfbuzz/harfbuzz/pull/5119#issuecomment-2709170388
2025-03-09 19:38:32 -06:00
Behdad Esfahbod
bcbd1df3dd
Merge pull request #5125 from harfbuzz/fontations-serial
[fontations] Check for font serial change automatically
2025-03-09 19:03:05 -06:00
Behdad Esfahbod
e77fb46335 [fontations] Do double-checked locking
See if tsan likes this. It liked the previous version.
2025-03-09 18:53:36 -06:00
Behdad Esfahbod
780809fb0c [fontations] Check for font serial change automatically
Let's see what tsan thinks... I also have not profiled this.

It also doesn't hold the mutex for the whole use time. It
probably should or bad things might happen.
2025-03-09 18:43:47 -06:00
Behdad Esfahbod
9f8e7ebf24
Merge pull request #5119 from harfbuzz/aat-deleted-glyph
[AAT] Clean up deleted-glyph handling
2025-03-09 18:09:58 -06:00
Behdad Esfahbod
ff76244ea6 [aat/morx] Delete deleted glyphs again
But also check for default-ignorable bit this time.
2025-03-09 17:24:40 -06:00
Behdad Esfahbod
dc048b7c88 [aat/morx] Set glyph props consistently 2025-03-09 16:53:24 -06:00
Behdad Esfahbod
4ec560dd02 [aat/morx] Refactor all glyph replacements into the context 2025-03-09 16:53:24 -06:00
Behdad Esfahbod
c6972ac6dd [aat] Towards removing special deleting of 0xFFFF
See https://github.com/harfbuzz/harfbuzz/discussions/5118

Remove the removal. Depend on the default_ignorable flag
to hide them later.

Test output adjusted.
2025-03-09 16:53:24 -06:00
Behdad Esfahbod
ec4d4b01e8 [morx] Update buffer on changes, in one more place
Was missed out before I believe.
2025-03-09 16:53:24 -06:00
Behdad Esfahbod
c88e819965 Fix compiler warning 2025-03-09 16:53:03 -06:00
Behdad Esfahbod
d067f2b224 [font] get_acquire() the serial 2025-03-09 06:17:48 -06:00
Behdad Esfahbod
0a01fc558b
Merge pull request #5122 from harfbuzz/using
Add API for querying font-funcs / face-loaders and setting them using strings
2025-03-09 05:28:09 -06:00
Behdad Esfahbod
ec6f99c5ea [fontations] Give clippy test more time 2025-03-09 05:18:13 -06:00
Behdad Esfahbod
9e639e676a [face] Review 2025-03-09 05:10:50 -06:00
Behdad Esfahbod
1e812e43b3 [ft] Another try at making tsan happy maybe 2025-03-09 03:39:52 -06:00
Behdad Esfahbod
7791f50e3a [ft] Use a lock-guard 2025-03-09 03:34:28 -06:00
Behdad Esfahbod
aa268fc8ef [font/ft] See if tsan is happy with atomic_int_t serials 2025-03-09 03:31:01 -06:00
Behdad Esfahbod
6ae7ef0659 [ft] See if I can make tsan happy 2025-03-09 03:19:22 -06:00
Behdad Esfahbod
a83faa061c [ft] Automatically pick up font serial changes
Part of https://github.com/harfbuzz/harfbuzz/issues/5124
2025-03-09 03:07:45 -06:00
Behdad Esfahbod
402f89cb79 [face] Rename a variable 2025-03-09 01:52:28 -07:00
Behdad Esfahbod
5cf1fa3add [face] Fix docs 2025-03-09 01:47:23 -07:00
Behdad Esfahbod
2ecc68c12f [face] Fix HB_LEAN build 2025-03-09 01:46:07 -07:00
Behdad Esfahbod
6b9d9f7259 [face] Add HB_FACE_LOADER env var 2025-03-09 01:41:49 -07:00
Behdad Esfahbod
9d05b03f83 [font] Add HB_FONT_FUNCS work into hb_font_set_funcs_using() 2025-03-09 01:34:37 -07:00
Behdad Esfahbod
39ade99d47 [face] Two new APIs:
+ hb_face_create_from_file_or_fail_using()
+ hb_face_list_loaders()
2025-03-09 01:25:52 -07:00
Matthias Clasen
79c991e143 Improve docs for feature and variation serialization
Clarify that the serialized forms of features and variations
won't have any whitespace in them. This can help for parsing
when embedding these strings into larger serializations.
2025-03-08 18:00:43 -07:00
Behdad Esfahbod
50ea460b93 Review 2025-03-08 16:07:44 -07:00
Behdad Esfahbod
43ff0f73cc [fontations] Relax dependency numbers 2025-03-08 13:30:10 -07:00
Behdad Esfahbod
437ce95059 [util] Add --list-font-funcs 2025-03-08 13:12:15 -07:00
Behdad Esfahbod
68b07475a7 [font-funcs] Support HB_FONT_FUNCS env var 2025-03-08 12:41:50 -07:00
Behdad Esfahbod
5a12bf417b [font-funcs-using] Treat empty string like nullptr 2025-03-08 12:31:07 -07:00
Behdad Esfahbod
712a403bec [font-funcs-using] Apply review feedback 2025-03-08 12:23:41 -07:00
Behdad Esfahbod
fae9d2ab27 [fontations] Add dependencies 2025-03-08 12:15:25 -07:00
Behdad Esfahbod
e8ddb4325b [fontations] Consolidate args a bit 2025-03-08 12:13:31 -07:00
Behdad Esfahbod
c3eac5c0f3 [test-threads] Test all font-funcs
Fontations & Coretext are new and seems to pass.
2025-03-08 11:57:31 -07:00
Behdad Esfahbod
2a878b1b76 [font-funcs] Add two new API
+ hb_font_set_funcs_using()
+ hb_font_list_funcs()

Part of https://github.com/harfbuzz/harfbuzz/issues/5117
2025-03-08 11:50:53 -07:00
Khaled Hosny
e9348cd76d [ci] Port minsize job from Alpine to Ubuntu
Alpine is frequently failing with compiler crashing, but we don’t really
need Alpine. No other job building with --buildtype=minsize, so keep it
but use Ubuntu.
2025-03-08 12:43:49 +02:00
Behdad Esfahbod
27fa1c4229
Merge pull request #5120 from harfbuzz/fontations-shrink
Fontations shrink
2025-03-07 22:01:23 -07:00
Behdad Esfahbod
080bd09db3 [fontations/ci] Fix 2025-03-07 21:48:17 -07:00
Behdad Esfahbod
3f6da0a367 [fontations] Run rustfmt & clippy as tests 2025-03-07 21:43:34 -07:00
Behdad Esfahbod
4bb7f61050 [fontations] Minor remove a type 2025-03-07 21:33:53 -07:00
Behdad Esfahbod
aabf8aadf8 [fontations] Use proper meson function for running commands 2025-03-07 21:32:05 -07:00
Behdad Esfahbod
52852c6cb6 [check-symbols] Ignore another rust symbol 2025-03-07 21:28:25 -07:00
Behdad Esfahbod
77314a3be7 [check-symbols] Don't run c++filt
For adding to ignore list, we want to see the original symbol
name. One can always c++filt themselves.
2025-03-07 21:19:09 -07:00
Behdad Esfahbod
5c01d8298c [fontations/ci] Try to fix 2025-03-07 21:15:08 -07:00
Behdad Esfahbod
bd66336d45 [fontations] Add clippy-check target 2025-03-07 21:13:28 -07:00
Behdad Esfahbod
8fd718c9eb [fontations] Add fmt-check target 2025-03-07 21:09:17 -07:00
Behdad Esfahbod
a68f458612 [fontations] Make 'ninja -Cbuild clippy' apply fixes 2025-03-07 21:05:59 -07:00
Behdad Esfahbod
f7cb3a3c8e [ci/fontations] Directly ask for nightly 2025-03-07 21:00:13 -07:00
Behdad Esfahbod
6c1f27faab [fontations] Disable overflow-checks 2025-03-07 18:38:54 -07:00
Behdad Esfahbod
514b28af3c [fontations] Pass optimization-level from meson to rustc 2025-03-07 18:37:17 -07:00
Behdad Esfahbod
55ca000b0e [fontations] Re-enable check-symbols test
Now that we build with lto, not many extra symbols are exported.
Ignore them.
2025-03-07 18:20:57 -07:00
Behdad Esfahbod
73f1c2ba43 Just a chmod a+x two Python scripts 2025-03-07 18:19:29 -07:00
Behdad Esfahbod
ecb9e393f2 [fontations] Shrink the library more 2025-03-07 17:57:11 -07:00
Behdad Esfahbod
493bf07596 [fontations] One more shrinkage 2025-03-07 17:50:20 -07:00
Behdad Esfahbod
78b3234396 [fontations] Shrink a bit more
Going through ideas from:
https://github.com/googlefonts/use-skrifa?tab=readme-ov-file
https://github.com/johnthagen/min-sized-rust
2025-03-07 17:48:38 -07:00
Behdad Esfahbod
52ad51382a [fontations] Enable lto
Makes library size shrink by half, as well as remove all the cruft
from the public symbol list.
2025-03-07 17:45:31 -07:00
Behdad Esfahbod
4e5358a288 [COLRv1] Fix comments
Fixes https://github.com/harfbuzz/harfbuzz/issues/5116
2025-03-07 15:18:28 -07:00
Behdad Esfahbod
e27e7f1c7d [perf] README minor 2025-03-07 14:01:57 -07:00
Behdad Esfahbod
460a8225ba [perf] Improve README 2025-03-07 13:33:08 -07:00
Behdad Esfahbod
575e70b063 [COLR] Use palette 0 if palette index out of range
Fixes https://github.com/harfbuzz/harfbuzz/issues/5112
2025-03-07 12:51:44 -07:00
Matthias Clasen
41e14f7029 [test-paint] Use latest test fonts
Update the color test fonts from https://github.com/googlefonts/color-fonts/
repository and update the test results.
2025-03-07 10:48:46 -07:00
Khaled Hosny
b8b56c4a67 [directwrite] Add comment [ci skip] 2025-03-07 14:30:53 +02:00
Khaled Hosny
a356603061 [directwrite/test] Add test that actually works
Apparently DirectWrite does not allow disabling calt in Arabic, so test
liga in Latin and ss01 in Arabic.
2025-03-07 14:30:53 +02:00
Khaled Hosny
9abaf193d3 [directwrite] Fix applying features to directwrite shaper
The range_features was ending up with random data because
hb_ms_make_feature_ranges() keeps pointers to data allocated in
feature_records and range_records, but that data was getting freed
before range_features was used. Change the variable scope to avoid
freeing the data too early.

Fixes https://github.com/harfbuzz/harfbuzz/issues/5113
2025-03-07 14:30:53 +02:00
Behdad Esfahbod
fe8a3972dd [fontations] Speed up glyph_extents if x_scale == y_scale 2025-03-06 23:52:08 -07:00
Behdad Esfahbod
abc468275b [fontations] Cache GlyphMetrics objects 2025-03-06 23:50:05 -07:00
Behdad Esfahbod
6506bd7e82
Merge pull request #4498 from harfbuzz/PaintColrLayers
[COLRv1] Optimize PaintColrLayers instead of PaintComposite
2025-03-06 20:00:54 -07:00
Matthias Clasen
9fbc2d23b5 [test-paint] Regenerate the test output
This commit updates the expected output of the paint tests
to what the current code produces.
2025-03-06 20:11:23 -05:00
Matthias Clasen
0ce90f60ab [test-paint] Make it easier to regenerate test output
This command will regenerate the expected output for all the
paint tests:

GENERATE_DATA=1 G_TEST_SRCDIR=./test/api ./build/test/api/test-paint
2025-03-06 20:10:13 -05:00
Behdad Esfahbod
bf55e33287 [ft-colr] Protect against out-of-bounds color indices 2025-03-06 17:38:50 -07:00
Behdad Esfahbod
8685653cc7 [ft-colr] Fix crash if palette index is out-of-range 2025-03-06 17:28:09 -07:00
Behdad Esfahbod
ad9fa13d23 [fontations] Render nothing if palette index out of range
Matches ot. Ft crashes currently.
2025-03-06 17:25:56 -07:00
Behdad Esfahbod
cd45a7f531 [fontations] Add a constructor 2025-03-06 16:11:01 -07:00
Behdad Esfahbod
44705c1acb [fontations] Fix clippy target
To build in the build dir
2025-03-06 15:34:27 -07:00
Simon Cozens
cda4b56bfe "where" not needed for trait impl 2025-03-06 15:29:21 -07:00
Simon Cozens
e8bed99b16 Banish static lifetimes 2025-03-06 15:29:21 -07:00
Behdad Esfahbod
1147c0e1ca [fontations] Clean up data passing 2025-03-06 14:57:06 -07:00
Behdad Esfahbod
ad0bcec378 [cairo] More printf removal 2025-03-06 14:51:06 -07:00
Behdad Esfahbod
0d70cfacb2 Revert accidental changes 2025-03-06 14:50:39 -07:00
Behdad Esfahbod
77a319daa6 [fontations] Fix color-line extend fetching
This fixes the last bug I know.
2025-03-06 14:48:51 -07:00
Garret Rieger
fc8334d96b Final cleanups. 2025-03-06 14:04:37 -07:00
Garret Rieger
a20138dcfc More cleanups 2025-03-06 14:04:37 -07:00
Garret Rieger
f379505d4d Add struct_at/struct_at_mut helpers for accessing c arrays. 2025-03-06 14:04:37 -07:00
Khaled Hosny
123a0d68a1 Use gnu_printf format annotation under MingW with GCC only
Fixes https://github.com/harfbuzz/harfbuzz/issues/5106
2025-03-06 22:21:35 +02:00
Khaled Hosny
462a54895b [ci] Use newer Ubuntu release for cross compilation
Cairo sets -D_FORTIFY_SOURCE when building with optimizations, but it
was broken in some MingW releases. Updating seems to fix it.
2025-03-06 22:08:13 +02:00
Khaled Hosny
3985939842 Reapply "[meson] Add buildtype=debugoptimize by default"
This reverts commit 958e2c5331.
2025-03-06 22:08:13 +02:00
Behdad Esfahbod
597a934368 [fontations] Add target fmt for rustfmt 2025-03-06 12:50:42 -07:00
Behdad Esfahbod
4a3329dafb [fontations] Fix clippy rule 2025-03-06 12:46:35 -07:00
Behdad Esfahbod
4b035ae611 Fix build 2025-03-06 12:44:49 -07:00
Behdad Esfahbod
34a919b980 [fontations] Clippy 2025-03-06 12:42:42 -07:00
Behdad Esfahbod
547027837e [fontations] Add clippy target 2025-03-06 12:40:50 -07:00
Behdad Esfahbod
d9b1101de6 [fontations] Mark the whole public function unsafe 2025-03-06 12:06:12 -07:00
Behdad Esfahbod
b5d2ec4f83 [fontations] clippy 2025-03-06 12:02:12 -07:00
Behdad Esfahbod
92af2e47fc [fontations] Do a bounds check 2025-03-06 11:33:22 -07:00
Khaled Hosny
3ce6b720ac [fontations] slice::from_raw_parts requires the pointer to be non-null 2025-03-06 04:23:24 +02:00
Khaled Hosny
aecc9110a3 [fontations/test] Add to test-draw 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
a6d295fa1e [fontations] Disable symbol check
Since all of rust crates become public symbols. Sigh.
2025-03-06 04:23:24 +02:00
Khaled Hosny
6b035cd7b7 [fontations] Make check-header-guards happy 2025-03-06 04:23:24 +02:00
Khaled Hosny
83e58980a6 [fontations/ci] Fix package name 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
91f4a67d5d [fontations] Fix translucent foreground colors 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
43e82682c5 [cairo] Fix infinite loop in sweep-gradient code
Tested with U+F1314 from var font from:
https://github.com/googlefonts/color-fonts/blob/main/glyph_descriptions.md
2025-03-06 04:23:24 +02:00
Khaled Hosny
2c11c9db52 [ci] Give fontations a try 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
dedc05c220 [paint] Fix typo in radial-gradients! 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
9b4eaff867 [fontations] Fix palette handling
What a pain...
2025-03-06 04:23:24 +02:00
Behdad Esfahbod
3a699c3764 [fontations] Fix anchor unreduction 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
b5ad6de8d6 [fontations] Unreduce LinearGradient anchors
Oh well...
2025-03-06 04:23:24 +02:00
Behdad Esfahbod
a2d9c29b08 [fontations] Comment 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
b5a04a9600 [fontations] Fix sweep gradients 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
e10e5c3764 [fontations] Implement sweep gradients
Untested. Also, radial gradients seem faulty.
2025-03-06 04:23:24 +02:00
Behdad Esfahbod
865d75ef30 [fontations] Implement radial gradients 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
d72968efac [fontations] Refactor make_color_line 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
4b1f655a83 [fontations] Implement LinearGradients 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
1a39f8935e [fontations] Implement solid paint 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
5b27f32876 [fontations] Implement most of paint API 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
d069e79016 [fontations] Fix pointer unsafe play 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
dbc04d1c7d [fontations] Roll skrifa forward
Remove the rest.
2025-03-06 04:23:24 +02:00
Behdad Esfahbod
6e472748d7 [fontations] Set Location only if non-zero 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
024e9356eb [fontations] Use a slice 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
3f57f76e99 [fontations] Cache OutlineGlyphCollection
As advised by Chad.  Speeds up drawing benchmark 2x.
2025-03-06 04:23:24 +02:00
Behdad Esfahbod
c4932fa57a [fontations] Fix life-cycle double-free 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
e054db4ae2 [fontations] Hook up to benchmark-font 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
ea5a14f7bc [fontations] Implement draw_glyph 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
87c62f4ebb [fontations] Boilerplate for draw_glyph 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
bc2851b407 [fontations] Implement font_h_extents 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
b9a4d148c9 [fontations] Implement get_glyph_extents 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
f2e5955e1e [fontations] Cache a x_size and y_size 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
166e630768 [fontations] Implement get_variation_glyph 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
83e85d2ac1 [fontations] rustfmt 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
156b77327e [fontations] Don't derive Copy et al since our types are not 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
74bd99e40e [fontations] Set font variations 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
7a65fdcabf [fontations] Cache location 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
c969c2dec0 [fontations] Cache Size 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
d19e45a1f5 [fontations] Support buildtype debugoptimized really 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
51c68eb29d [fontations] Cache charmap 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
f400d8b30c [fontations] Pass meson buildtype to cargo 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
1705723d7e [fontations] Cache static fontfuncs object 2025-03-06 04:23:24 +02:00
Khaled Hosny
7871ee5b6c [fontations/meson] Use link_whole instead of link_with
Instead of passing `--whole-archive` manually to the linker which has a
different name on macOS linker.
2025-03-06 04:23:24 +02:00
Khaled Hosny
c6d2e9e855 [fontations/doc] Add section 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
afe1af8fa9 [fontations] Implement get_nominal_glyphs()
Shapes now.
2025-03-06 04:23:24 +02:00
Behdad Esfahbod
e801e484f1 [fontations] Remove get_glyph_h_advance() 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
1390da5d12 [fontations] Implement get_glyph_h_advances() 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
94a6cfba89 [fontations] Working get_glyph_advance() 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
77b20cf7b9 Update src/hb-fontations.h
Co-authored-by: Khaled Hosny <khaled@aliftype.com>
2025-03-06 04:23:24 +02:00
Behdad Esfahbod
0113c86a2f [fontations] Hide internal symbols 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
71accd5e14 [fontations] Hide one symbol
How do I hide the other internal extern "C" symbols?
2025-03-06 04:23:24 +02:00
Behdad Esfahbod
9d754188c6 [meson] Fix unintended change to coretext 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
9439e1fdad [fontations] Links finally 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
6cac2a1ae0 [fontations] Ouch 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
395270e494 [fontations] Try folding into libharfbuzz 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
2a06b85d4e [fontations] Try using an intermediate library
Still doesn't link.
2025-03-06 04:23:24 +02:00
Behdad Esfahbod
f28daba53c [fontations] I don't know... 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
161b20f333 Try building with cargo 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
e806c9ae2a [fontations] Only require rust if building with fontations 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
e1c934421a [fontations] More experiments 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
db6431f140 [fontations] Fix a warning 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
bed809bc6b [fontations] Add to docs
Module itself undocumented so far.
2025-03-06 04:23:24 +02:00
Behdad Esfahbod
26da19f6ea Kinda builds now with bindgen
Requires nightly.
2025-03-06 04:23:24 +02:00
Behdad Esfahbod
3ba4266daa [fontations] bindgen hb.rs 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
f9b4706151 [fontations] Use as dependency, not library
Since it's optional.
2025-03-06 04:23:24 +02:00
Behdad Esfahbod
2abe54fc9c Almost works! 2025-03-06 04:23:24 +02:00
Behdad Esfahbod
ad8e4a29b9 [fontations] Start building a libharfbuzz-fontations 2025-03-06 04:23:24 +02:00
Patrik Weiskircher
ca3cd48fa3 Fix memory leak in hb_coretext_get_glyph_name 2025-03-04 16:59:21 +02:00
Behdad Esfahbod
718542ef7a [util] Space 2025-03-03 22:45:15 -07:00
Behdad Esfahbod
c544028700 [meson] Remove -Wno-non-virtual-dtor
No idea why it was there to begin with. We control warnings
from hb.hh.
2025-03-04 05:36:01 +02:00
Behdad Esfahbod
958e2c5331 Revert "[meson] Add buildtype=debugoptimize by default"
This reverts commit c4b572a24c.

This broke CI. Reverting till we figure it out.
2025-03-03 20:22:35 -07:00
Behdad Esfahbod
c4b572a24c [meson] Add buildtype=debugoptimize by default
Fixes https://github.com/harfbuzz/harfbuzz/issues/5103
2025-03-03 19:13:34 -07:00
Behdad Esfahbod
50fe45f43c [COLR] Fix memory leak 2025-03-03 16:31:41 -07:00
Alfred Wingate
628b868f44 meson: refactor freetype dependency logic
Simplify and respect -Dfreetype=disabled again.

Bug: https://bugs.gentoo.org/950274
Fixes: 1ad48fddd0
See-Also: 604fe80707
Signed-off-by: Alfred Wingate <parona@protonmail.com>
2025-03-04 01:12:05 +02:00
Behdad Esfahbod
9c6b6998ef [VARC] Fix sign of returned extents 2025-03-03 11:48:17 -07:00
dependabot[bot]
2a471ed125 Bump setuptools from 73.0.1 to 75.8.2 in /.ci
Bumps [setuptools](https://github.com/pypa/setuptools) from 73.0.1 to 75.8.2.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v73.0.1...v75.8.2)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-03 11:33:11 -07:00
Behdad Esfahbod
e9134c8ce3 [COLR] Reduce malloc pressure
By caching paint-extents.
2025-03-03 02:18:49 -07:00
Behdad Esfahbod
9efd17e225 [COLR] Switch to using (existing) accelerator 2025-03-03 02:17:13 -07:00
Behdad Esfahbod
17ddc84406 [VARC] Fix scratch caching 2025-03-03 01:27:32 -07:00
Behdad Esfahbod
a62058eee8 [VARC] Separate varc scratch from glyf scratch 2025-03-03 01:19:52 -07:00
Behdad Esfahbod
3199d1c1f5 [VARC] Use a context object to pass arguments around 2025-03-02 18:35:46 -07:00
Behdad Esfahbod
e0c6c98025 [VARC] Implement get_extents()
Fixes https://github.com/harfbuzz/harfbuzz/issues/5007
2025-03-02 16:56:20 -07:00
Behdad Esfahbod
d1826ca626 [TupleValues] Fix regression
Introduced in 043980a60e
2025-03-02 15:45:35 -07:00
Behdad Esfahbod
d9628a5643 [MultiVarData] Micro-optimize 2025-03-02 13:00:55 -07:00
Behdad Esfahbod
c81b1c43b1 [MultiVarData] Remove a likely 2025-03-02 12:43:28 -07:00
Behdad Esfahbod
ad0a5c93b5 [vector] Add fast path in extend() for length-known iterators 2025-03-01 16:02:10 -07:00
Behdad Esfahbod
7e3c96582f [VARC] Reuse parent MultiVarStore cache if coords didn't change
Minor optimization; applicable to the test hangul font mostly.
2025-03-01 15:09:58 -07:00
Khaled Hosny
3ef8709829 10.4.0 2025-03-01 00:59:49 +02:00
Behdad Esfahbod
75ce774bc3 [gvar] Use a method for add_delta 2025-02-28 15:25:23 -07:00
Khaled Hosny
532ed228e7 [docs] Move all deprecated APIs to the deprecated section 2025-02-28 23:56:03 +02:00
Khaled Hosny
69e1c3c352 [ft] Add hb_ft_font_get_ft_face()
A new name for hb_ft_font_get_face(), which is now deprecated.

Fixes  https://github.com/harfbuzz/harfbuzz/issues/5084
2025-02-28 23:56:03 +02:00
Khaled Hosny
484e8d4997 [directwrite] Add hb_directwrite_face_get_dw_font_face()
A new name for hb_directwrite_face_get_font_face(), which is now
deprecated.

Part of https://github.com/harfbuzz/harfbuzz/issues/5084
2025-02-28 23:56:03 +02:00
Behdad Esfahbod
8226f597ac [decycler] Add a couple more tests 2025-02-28 13:49:44 -07:00
Behdad Esfahbod
64dbeaf0f4 [glyf] Mover decycler to the scratch pad 2025-02-28 01:13:25 -07:00
Behdad Esfahbod
d59d435ec6 [decycler] Comments 2025-02-27 22:41:03 -07:00
Behdad Esfahbod
cb781f53aa [BASE] Fix a TODO item 2025-02-27 10:15:22 -07:00
Khaled Hosny
1a759886d9 Improve GitHub Actions badges [ci skip] 2025-02-27 15:45:28 +02:00
Khaled Hosny
527a209674 Remove Codacy badge [ci skip]
It takes long time on PRs and no one actually looks into its reports.
The service has just been disabled and the badge is a dead link now.
2025-02-27 15:31:56 +02:00
Behdad Esfahbod
4be765c083 Fix config build 2025-02-27 02:26:08 -07:00
Behdad Esfahbod
4a43373aec [MultiVarData] Unroll another loop 2025-02-26 17:24:28 -07:00
Behdad Esfahbod
00541f1952
Merge pull request #4970 from harfbuzz/GVAR
Add `GVAR` table
2025-02-26 16:22:48 -07:00
Behdad Esfahbod
a0543453de [CBDT] Change has_data() to be more accurate
get_length() was returning the Null table length if table
was not present.
2025-02-26 15:36:03 -07:00
Behdad Esfahbod
7504c67fb7 [CBDT] Return immediately if no data 2025-02-26 15:24:40 -07:00
Behdad Esfahbod
9d149c5284 [test-paint] Redirect generated output to stderr 2025-02-26 15:07:46 -07:00
Behdad Esfahbod
753093d60e [test-colrv1] Add test files from https://roettsch.es/var_colrv1.html
These are not currently used for any testing. To be used later.
2025-02-26 14:41:04 -07:00
Behdad Esfahbod
6fe1441782 [test-paint] Update comment 2025-02-26 14:40:08 -07:00
Behdad Esfahbod
17a83b748e [COLRv1] Optimize PaintColrLayers instead of PaintComposite
See https://github.com/googlefonts/colr-gradients-spec/issues/369#issuecomment-1816913943
and onwards.
2025-02-26 14:40:02 -07:00
Behdad Esfahbod
44b7ba51a3 [GVAR] Hide behind HB_NO_BEYOND_64K 2025-02-26 14:21:15 -07:00
Behdad Esfahbod
13900ce40d [GVAR] Hook up to face and glyf table 2025-02-26 14:21:15 -07:00
Behdad Esfahbod
ffe955b9f9 [GVAR] Change offsetToData size to 24bit
As per https://github.com/harfbuzz/boring-expansion-spec/issues/162
2025-02-26 14:21:15 -07:00
Behdad Esfahbod
894fee6db3 [GVAR] Implement table
Unused. It's just like `gvar` but with 24bit glyphCount.
2025-02-26 14:21:15 -07:00
Behdad Esfahbod
4d3642c188 [face] Fix a malloc fail infinite-loop error 2025-02-26 14:20:45 -07:00
Behdad Esfahbod
6fbd6bb34e [face] Avoid infinite-loop in building a face blob 2025-02-26 14:06:35 -07:00
Behdad Esfahbod
6a7b4dcae6 [VARC] Reduce stack usage on 32bit systems 2025-02-26 13:25:50 -07:00
Behdad Esfahbod
84ffb7e477 [SimpleGlyph] Minor use an intermediate variable 2025-02-26 12:53:58 -07:00
Behdad Esfahbod
54db2b2ed6 [SimpleGlyph] Remove a conditional from hot path
5% speedup in Roboto-Regular draw benchmark
2025-02-26 12:53:52 -07:00
Behdad Esfahbod
bb4d37b052 [VARC/coord-setter] Reduce stack allocation on 32bit systems 2025-02-26 12:17:27 -07:00
Behdad Esfahbod
51d3489ca1 [Composite] Fix memory-free rendering 2025-02-26 12:09:31 -07:00
Behdad Esfahbod
a037d3815f [vector] Fix operator = 2025-02-26 12:05:12 -07:00
Behdad Esfahbod
59e6a1c477 [glyf/Composite] Malloc-free 2025-02-26 11:34:04 -07:00
Behdad Esfahbod
3c4cb472d1 [VARC] Fix uninitialized value
Fixes https://oss-fuzz.com/testcase-detail/6089638800588800
2025-02-26 10:48:36 -07:00
Behdad Esfahbod
fcbf14a0e5 [CompositeGlyph] Adjust pre-allocation 2025-02-25 20:16:18 -07:00
Behdad Esfahbod
6ca8852eff [glyf] Return earlier if table is empty 2025-02-25 19:57:43 -07:00
Behdad Esfahbod
0cd98ebbf7 [vector] Add a missing fast-path 2025-02-25 18:53:04 -07:00
Behdad Esfahbod
41626401b0 [vector] Add faster extend() for array types 2025-02-25 18:48:34 -07:00
Behdad Esfahbod
aaf5c06d62 [vector] Rewrite copy_array() to extend vector 2025-02-25 18:45:38 -07:00
Behdad Esfahbod
40c77a1c5a Remove a redundant method 2025-02-25 18:37:20 -07:00
Behdad Esfahbod
81339256da [gvar] Rename two variables 2025-02-25 18:02:26 -07:00
Behdad Esfahbod
87830b62c6 [gvar] Remove unused method 2025-02-25 18:02:26 -07:00
Behdad Esfahbod
7614320a13 [glyf] Reduce malloc pressure
Benchmark 15% faster for draw.
2025-02-25 16:59:37 -07:00
Behdad Esfahbod
882d328839 [glyf] Port to decycler for composite glyphs
5% speed up drawing Roboto-Regular.ttf.
2025-02-25 16:35:32 -07:00
Behdad Esfahbod
ffee85d67f [VARC] Minor simplify pointer math 2025-02-25 16:20:42 -07:00
Behdad Esfahbod
dcb80ecbd9 [gvar] Use a method 2025-02-25 15:58:37 -07:00
Behdad Esfahbod
23937e8cd5 [gvar] Combine two loops 2025-02-25 15:48:23 -07:00
Behdad Esfahbod
9b451f2055 [gvar] Minor remove a variable 2025-02-25 15:16:09 -07:00
Behdad Esfahbod
7222c1e50f [path-builder] Add a constexpr 2025-02-25 15:13:20 -07:00
Behdad Esfahbod
e450552d07 [coord-setter] Fix memory access in case of malloc failure
Fixes https://oss-fuzz.com/testcase-detail/5383702943432704
2025-02-25 14:54:37 -07:00
Behdad Esfahbod
b12612f525 Fix compiler warnings 2025-02-25 13:47:06 -07:00
Behdad Esfahbod
8280ef7d93
Merge pull request #5089 from harfbuzz/vector-explicit
[vector] Disallow accidental creation of transient vectors
2025-02-25 12:18:43 -07:00
Garret Rieger
ea1434b897 Split iup glyf partial instance tests into a separate set which ignores due to IUP rounding differences fonttools. 2025-02-25 19:02:11 +00:00
Behdad Esfahbod
aaecaa4c0e [vector] Disallow accidental creation of transient vectors
Fix sites that were doing this under our feet.

This lowers precision of some instancing operations from double
to float, which modifies a few results by rounding error.

TODO: Update tests.
2025-02-25 19:02:11 +00:00
Behdad Esfahbod
f71faf5fec [VARC] Fix buffer scratch borrowing 2025-02-25 11:35:21 -07:00
Behdad Esfahbod
e76b689fe1 [VARC] Fix resource leak 2025-02-25 11:23:48 -07:00
Behdad Esfahbod
827be1b23c Revert "[MultiVarStore] Micro-optimize"
This reverts commit 13d98f1ded.

This broke bots. I don't fully understand why tests pass locally.
2025-02-25 10:23:10 -07:00
Behdad Esfahbod
13d98f1ded [MultiVarStore] Micro-optimize 2025-02-25 01:40:19 -07:00
Behdad Esfahbod
9a0cf8d641 [test/subset/cff-japanese] Shrink test
Was taking too long.
2025-02-25 00:19:25 -07:00
Behdad Esfahbod
084fb3ab4f [test/subset/cmap] Shrink test
Was taking more than the rest of the test suite combined.
2025-02-25 00:16:27 -07:00
Behdad Esfahbod
51d8ef48d9 [gvar] Cache shared_indices as well 2025-02-25 00:09:28 -07:00
Behdad Esfahbod
47124e6337 [VARC] Avoid creating cache if there's no VARC table 2025-02-24 23:25:50 -07:00
Behdad Esfahbod
d5d199fbc7 [VARC] Reduce malloc pressure
By caching one hb_glyf_scratch_t on the VARC accelerator.
2025-02-24 23:20:12 -07:00
Behdad Esfahbod
2c5ab14aaa [coord-setter] Increase static array size 2025-02-24 22:50:42 -07:00
Behdad Esfahbod
a058a1f223 [TupleValues] Unroll a loop 2025-02-24 21:53:17 -07:00
Behdad Esfahbod
13ee8edf06 [vector] Speed up extend() 2025-02-24 21:17:58 -07:00
Behdad Esfahbod
46485124ea [vector] Simplify a method 2025-02-24 21:04:34 -07:00
Behdad Esfahbod
6fe550306c [TupleValues] Don't overshadow end() method 2025-02-24 20:57:30 -07:00
Behdad Esfahbod
97a5c52af4 [VARC/MultiVarStore] Reduce malloc pressure more 2025-02-24 20:53:19 -07:00
Behdad Esfahbod
6938ee0342 [VARC] More nuanced caching 2025-02-24 20:44:15 -07:00
Behdad Esfahbod
74bb7c52f3 Fix a compiler warning 2025-02-24 20:21:38 -07:00
Behdad Esfahbod
081fcbdf5a [VARC] Minor move variable closer to use 2025-02-24 20:15:24 -07:00
Behdad Esfahbod
0a1b26b862 [coord-setter] Reduce malloc pressure
~15% speedup benchmark-font draw of varc-hanzi.ttf
2025-02-24 20:07:59 -07:00
Behdad Esfahbod
76c3beaf36 [VARC] Reduce malloc overhead 2025-02-24 19:50:51 -07:00
Behdad Esfahbod
2099db378a [TupleValues] Optimize decoding 2025-02-24 15:13:08 -07:00
Behdad Esfahbod
043980a60e [TupleValues] Micro-optimize 2025-02-24 11:23:11 -07:00
dependabot[bot]
474c6e43a6 Bump github/codeql-action from 3.28.9 to 3.28.10
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.28.9 to 3.28.10.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](9e8d0789d4...b56ba49b26)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-24 13:23:08 +02:00
dependabot[bot]
22e5469cec Bump ossf/scorecard-action from 2.4.0 to 2.4.1
Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.4.0 to 2.4.1.
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](62b2cac7ed...f49aabe0b5)

---
updated-dependencies:
- dependency-name: ossf/scorecard-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-24 13:22:54 +02:00
dependabot[bot]
5f23b9767a Bump actions/upload-artifact from 4.6.0 to 4.6.1
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.0 to 4.6.1.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](65c4c4a1dd...4cec3d8aa0)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-24 13:22:43 +02:00
Behdad Esfahbod
1ba907209f [VARC] Speed up MultiVarData::get_delta 2025-02-23 21:52:30 -07:00
Khaled Hosny
e41dc20c1c [directwrite] Fix -Wcast-align warning
https://github.com/harfbuzz/harfbuzz/pull/5079#issuecomment-2673805310
2025-02-21 10:38:52 +02:00
898 changed files with 15275 additions and 9898 deletions

48
.ci/build-win.sh Executable file
View file

@ -0,0 +1,48 @@
#!/bin/bash
set -ex
if [ "$#" -lt 1 ]
then
echo "Usage $0 ARCH (ARCH can be 32 or 64)"
exit 1
fi
ARCH=$1
shift
BUILD=build-win${ARCH}
INSTALL=install-win${ARCH}
DIST=harfbuzz-win${ARCH}
meson setup \
--buildtype=release \
--prefix="${PWD}/${BUILD}/${INSTALL}" \
--cross-file=.ci/win${ARCH}-cross-file.txt \
--wrap-mode=default \
--strip \
-Dtests=enabled \
-Dcairo=enabled \
-Dcairo:fontconfig=disabled \
-Dcairo:freetype=disabled \
-Dcairo:dwrite=disabled \
-Dcairo:tests=disabled \
-Dglib=enabled \
-Dlibffi:tests=false \
-Dfreetype=disabled \
-Dicu=disabled \
-Dchafa=disabled \
-Dgdi=enabled \
-Ddirectwrite=enabled \
${BUILD} \
"$@"
# building with all the cores won't work fine with CricleCI for some reason
meson compile -C ${BUILD} -j3
meson install -C ${BUILD}
mkdir ${BUILD}/${DIST}
cp ${BUILD}/${INSTALL}/bin/hb-*.exe ${BUILD}/${DIST}
cp ${BUILD}/${INSTALL}/bin/*.dll ${BUILD}/${DIST}
rm -f ${DIST}.zip
(cd ${BUILD} && zip -r ../${DIST}.zip ${DIST})
echo "${DIST}.zip is ready."

View file

@ -1,28 +0,0 @@
#!/bin/bash
set -e
meson --cross-file=.ci/win32-cross-file.txt \
--wrap-mode=default \
-Dtests=disabled \
-Dcairo=enabled \
-Dcairo:fontconfig=disabled \
-Dcairo:freetype=disabled \
-Dcairo:dwrite=disabled \
-Dcairo:tests=disabled \
-Dglib=enabled \
-Dfreetype=disabled \
-Dgdi=enabled \
-Ddirectwrite=enabled \
win32build \
$@
ninja -Cwin32build -j3 # building with all the cores won't work fine with CricleCI for some reason
rm -rf win32build/harfbuzz-win32
mkdir win32build/harfbuzz-win32
cp win32build/util/hb-*.exe win32build/harfbuzz-win32
find win32build -name '*.dll' -exec cp {} win32build/harfbuzz-win32 \;
i686-w64-mingw32-strip win32build/harfbuzz-win32/*.{dll,exe}
rm -f harfbuzz-win32.zip
(cd win32build && zip -r ../harfbuzz-win32.zip harfbuzz-win32)
echo "harfbuzz-win32.zip is ready."

View file

@ -1,28 +0,0 @@
#!/bin/bash
set -e
meson --cross-file=.ci/win64-cross-file.txt \
--wrap-mode=default \
-Dtests=disabled \
-Dcairo=enabled \
-Dcairo:fontconfig=disabled \
-Dcairo:freetype=disabled \
-Dcairo:dwrite=disabled \
-Dcairo:tests=disabled \
-Dglib=enabled \
-Dfreetype=disabled \
-Dgdi=enabled \
-Ddirectwrite=enabled \
win64build \
$@
ninja -Cwin64build -j3 # building with all the cores won't work fine with CricleCI for some reason
rm -rf win64build/harfbuzz-win64
mkdir win64build/harfbuzz-win64
cp win64build/util/hb-*.exe win64build/harfbuzz-win64
find win64build -name '*.dll' -exec cp {} win64build/harfbuzz-win64 \;
x86_64-w64-mingw32-strip win64build/harfbuzz-win64/*.{dll,exe}
rm -f harfbuzz-win64.zip
(cd win64build && zip -r ../harfbuzz-win64.zip harfbuzz-win64)
echo "harfbuzz-win64.zip is ready."

View file

@ -11,12 +11,11 @@ fi
if ! hash ghr 2> /dev/null; then
_GHR_VER=v0.14.0
_GHR=ghr_${_GHR_VER}_linux_amd64
mkdir -p $HOME/.local/bin
curl -sfL https://github.com/tcnksm/ghr/releases/download/$_GHR_VER/$_GHR.tar.gz |
tar xz -C $HOME/.local/bin --strip-components=1 $_GHR/ghr
tar xz -C . --strip-components=1 $_GHR/ghr
fi
ghr -replace \
./ghr -replace \
-u $CIRCLE_PROJECT_USERNAME \
-r $CIRCLE_PROJECT_REPONAME \
$CIRCLE_TAG \

View file

@ -4,55 +4,55 @@
#
# pip-compile --generate-hashes .ci/requirements-fonttools.in
#
fonttools==4.56.0 \
--hash=sha256:003548eadd674175510773f73fb2060bb46adb77c94854af3e0cc5bc70260049 \
--hash=sha256:0073b62c3438cf0058488c002ea90489e8801d3a7af5ce5f7c05c105bee815c3 \
--hash=sha256:1088182f68c303b50ca4dc0c82d42083d176cba37af1937e1a976a31149d4d14 \
--hash=sha256:133bedb9a5c6376ad43e6518b7e2cd2f866a05b1998f14842631d5feb36b5786 \
--hash=sha256:14a3e3e6b211660db54ca1ef7006401e4a694e53ffd4553ab9bc87ead01d0f05 \
--hash=sha256:17f39313b649037f6c800209984a11fc256a6137cbe5487091c6c7187cae4685 \
--hash=sha256:193b86e9f769320bc98ffdb42accafb5d0c8c49bd62884f1c0702bc598b3f0a2 \
--hash=sha256:2d351275f73ebdd81dd5b09a8b8dac7a30f29a279d41e1c1192aedf1b6dced40 \
--hash=sha256:300c310bb725b2bdb4f5fc7e148e190bd69f01925c7ab437b9c0ca3e1c7cd9ba \
--hash=sha256:331954d002dbf5e704c7f3756028e21db07097c19722569983ba4d74df014000 \
--hash=sha256:38b947de71748bab150259ee05a775e8a0635891568e9fdb3cdd7d0e0004e62f \
--hash=sha256:3cf4f8d2a30b454ac682e12c61831dcb174950c406011418e739de592bbf8f76 \
--hash=sha256:3fd3fccb7b9adaaecfa79ad51b759f2123e1aba97f857936ce044d4f029abd71 \
--hash=sha256:442ad4122468d0e47d83bc59d0e91b474593a8c813839e1872e47c7a0cb53b10 \
--hash=sha256:47b5e4680002ae1756d3ae3b6114e20aaee6cc5c69d1e5911f5ffffd3ee46c6b \
--hash=sha256:53f5e9767978a4daf46f28e09dbeb7d010319924ae622f7b56174b777258e5ba \
--hash=sha256:62b4c6802fa28e14dba010e75190e0e6228513573f1eeae57b11aa1a39b7e5b1 \
--hash=sha256:62cc1253827d1e500fde9dbe981219fea4eb000fd63402283472d38e7d8aa1c6 \
--hash=sha256:654ac4583e2d7c62aebc6fc6a4c6736f078f50300e18aa105d87ce8925cfac31 \
--hash=sha256:661a8995d11e6e4914a44ca7d52d1286e2d9b154f685a4d1f69add8418961563 \
--hash=sha256:6c1d38642ca2dddc7ae992ef5d026e5061a84f10ff2b906be5680ab089f55bb8 \
--hash=sha256:6e81c1cc80c1d8bf071356cc3e0e25071fbba1c75afc48d41b26048980b3c771 \
--hash=sha256:705837eae384fe21cee5e5746fd4f4b2f06f87544fa60f60740007e0aa600311 \
--hash=sha256:7ef04bc7827adb7532be3d14462390dd71287644516af3f1e67f1e6ff9c6d6df \
--hash=sha256:86b2a1013ef7a64d2e94606632683f07712045ed86d937c11ef4dde97319c086 \
--hash=sha256:8d1613abd5af2f93c05867b3a3759a56e8bf97eb79b1da76b2bc10892f96ff16 \
--hash=sha256:965d0209e6dbdb9416100123b6709cb13f5232e2d52d17ed37f9df0cc31e2b35 \
--hash=sha256:96a4271f63a615bcb902b9f56de00ea225d6896052c49f20d0c91e9f43529a29 \
--hash=sha256:9d94449ad0a5f2a8bf5d2f8d71d65088aee48adbe45f3c5f8e00e3ad861ed81a \
--hash=sha256:9da650cb29bc098b8cfd15ef09009c914b35c7986c8fa9f08b51108b7bc393b4 \
--hash=sha256:a05d1f07eb0a7d755fbe01fee1fd255c3a4d3730130cf1bfefb682d18fd2fcea \
--hash=sha256:a114d1567e1a1586b7e9e7fc2ff686ca542a82769a296cef131e4c4af51e58f4 \
--hash=sha256:a1af375734018951c31c0737d04a9d5fd0a353a0253db5fbed2ccd44eac62d8c \
--hash=sha256:b23d30a2c0b992fb1c4f8ac9bfde44b5586d23457759b6cf9a787f1a35179ee0 \
--hash=sha256:bc871904a53a9d4d908673c6faa15689874af1c7c5ac403a8e12d967ebd0c0dc \
--hash=sha256:bce60f9a977c9d3d51de475af3f3581d9b36952e1f8fc19a1f2254f1dda7ce9c \
--hash=sha256:bd9825822e7bb243f285013e653f6741954d8147427aaa0324a862cdbf4cbf62 \
--hash=sha256:ca7962e8e5fc047cc4e59389959843aafbf7445b6c08c20d883e60ced46370a5 \
--hash=sha256:d0cb73ccf7f6d7ca8d0bc7ea8ac0a5b84969a41c56ac3ac3422a24df2680546f \
--hash=sha256:d54a45d30251f1d729e69e5b675f9a08b7da413391a1227781e2a297fa37f6d2 \
--hash=sha256:d6ca96d1b61a707ba01a43318c9c40aaf11a5a568d1e61146fafa6ab20890793 \
--hash=sha256:d6f195c14c01bd057bc9b4f70756b510e009c83c5ea67b25ced3e2c38e6ee6e9 \
--hash=sha256:e2cad98c94833465bcf28f51c248aaf07ca022efc6a3eba750ad9c1e0256d278 \
--hash=sha256:e2e993e8db36306cc3f1734edc8ea67906c55f98683d6fd34c3fc5593fdbba4c \
--hash=sha256:e9270505a19361e81eecdbc2c251ad1e1a9a9c2ad75fa022ccdee533f55535dc \
--hash=sha256:f20e2c0dfab82983a90f3d00703ac0960412036153e5023eed2b4641d7d5e692 \
--hash=sha256:f36a0868f47b7566237640c026c65a86d09a3d9ca5df1cd039e30a1da73098a0 \
--hash=sha256:f59746f7953f69cc3290ce2f971ab01056e55ddd0fb8b792c31a8acd7fee2d28 \
--hash=sha256:fa760e5fe8b50cbc2d71884a1eff2ed2b95a005f02dda2fa431560db0ddd927f \
--hash=sha256:ffda9b8cd9cb8b301cae2602ec62375b59e2e2108a117746f12215145e3f786c
fonttools==4.57.0 \
--hash=sha256:03290e818782e7edb159474144fca11e36a8ed6663d1fcbd5268eb550594fd8e \
--hash=sha256:0425c2e052a5f1516c94e5855dbda706ae5a768631e9fcc34e57d074d1b65b92 \
--hash=sha256:05efceb2cb5f6ec92a4180fcb7a64aa8d3385fd49cfbbe459350229d1974f0b1 \
--hash=sha256:17168a4670bbe3775f3f3f72d23ee786bd965395381dfbb70111e25e81505b9d \
--hash=sha256:3122c604a675513c68bd24c6a8f9091f1c2376d18e8f5fe5a101746c81b3e98f \
--hash=sha256:34687a5d21f1d688d7d8d416cb4c5b9c87fca8a1797ec0d74b9fdebfa55c09ab \
--hash=sha256:3871349303bdec958360eedb619169a779956503ffb4543bb3e6211e09b647c4 \
--hash=sha256:39acf68abdfc74e19de7485f8f7396fa4d2418efea239b7061d6ed6a2510c746 \
--hash=sha256:3cf97236b192a50a4bf200dc5ba405aa78d4f537a2c6e4c624bb60466d5b03bd \
--hash=sha256:408ce299696012d503b714778d89aa476f032414ae57e57b42e4b92363e0b8ef \
--hash=sha256:44c26a311be2ac130f40a96769264809d3b0cb297518669db437d1cc82974888 \
--hash=sha256:46370ac47a1e91895d40e9ad48effbe8e9d9db1a4b80888095bc00e7beaa042f \
--hash=sha256:4dea5893b58d4637ffa925536462ba626f8a1b9ffbe2f5c272cdf2c6ebadb817 \
--hash=sha256:51d8482e96b28fb28aa8e50b5706f3cee06de85cbe2dce80dbd1917ae22ec5a6 \
--hash=sha256:541cb48191a19ceb1a2a4b90c1fcebd22a1ff7491010d3cf840dd3a68aebd654 \
--hash=sha256:579ba873d7f2a96f78b2e11028f7472146ae181cae0e4d814a37a09e93d5c5cc \
--hash=sha256:57e30241524879ea10cdf79c737037221f77cc126a8cdc8ff2c94d4a522504b9 \
--hash=sha256:69ab81b66ebaa8d430ba56c7a5f9abe0183afefd3a2d6e483060343398b13fb1 \
--hash=sha256:6e3e1ec10c29bae0ea826b61f265ec5c858c5ba2ce2e69a71a62f285cf8e4595 \
--hash=sha256:727ece10e065be2f9dd239d15dd5d60a66e17eac11aea47d447f9f03fdbc42de \
--hash=sha256:7339e6a3283e4b0ade99cade51e97cde3d54cd6d1c3744459e886b66d630c8b3 \
--hash=sha256:767604f244dc17c68d3e2dbf98e038d11a18abc078f2d0f84b6c24571d9c0b13 \
--hash=sha256:7a64edd3ff6a7f711a15bd70b4458611fb240176ec11ad8845ccbab4fe6745db \
--hash=sha256:81aa97669cd726349eb7bd43ca540cf418b279ee3caba5e2e295fb4e8f841c02 \
--hash=sha256:84c41ba992df5b8d680b89fd84c6a1f2aca2b9f1ae8a67400c8930cd4ea115f6 \
--hash=sha256:84fd56c78d431606332a0627c16e2a63d243d0d8b05521257d77c6529abe14d8 \
--hash=sha256:889e45e976c74abc7256d3064aa7c1295aa283c6bb19810b9f8b604dfe5c7f31 \
--hash=sha256:8e2e12d0d862f43d51e5afb8b9751c77e6bec7d2dc00aad80641364e9df5b199 \
--hash=sha256:967b65232e104f4b0f6370a62eb33089e00024f2ce143aecbf9755649421c683 \
--hash=sha256:9d077f909f2343daf4495ba22bb0e23b62886e8ec7c109ee8234bdbd678cf344 \
--hash=sha256:9d57b4e23ebbe985125d3f0cabbf286efa191ab60bbadb9326091050d88e8213 \
--hash=sha256:a1968f2a2003c97c4ce6308dc2498d5fd4364ad309900930aa5a503c9851aec8 \
--hash=sha256:a2a722c0e4bfd9966a11ff55c895c817158fcce1b2b6700205a376403b546ad9 \
--hash=sha256:a97bb05eb24637714a04dee85bdf0ad1941df64fe3b802ee4ac1c284a5f97b7c \
--hash=sha256:aff40f8ac6763d05c2c8f6d240c6dac4bb92640a86d9b0c3f3fff4404f34095c \
--hash=sha256:babe8d1eb059a53e560e7bf29f8e8f4accc8b6cfb9b5fd10e485bde77e71ef41 \
--hash=sha256:bbceffc80aa02d9e8b99f2a7491ed8c4a783b2fc4020119dc405ca14fb5c758c \
--hash=sha256:c59375e85126b15a90fcba3443eaac58f3073ba091f02410eaa286da9ad80ed8 \
--hash=sha256:ca2aed95855506b7ae94e8f1f6217b7673c929e4f4f1217bcaa236253055cb36 \
--hash=sha256:cc066cb98b912f525ae901a24cd381a656f024f76203bc85f78fcc9e66ae5aec \
--hash=sha256:cdef9a056c222d0479a1fdb721430f9efd68268014c54e8166133d2643cb05d9 \
--hash=sha256:d07f1b64008e39fceae7aa99e38df8385d7d24a474a8c9872645c4397b674481 \
--hash=sha256:d639397de852f2ccfb3134b152c741406752640a266d9c1365b0f23d7b88077f \
--hash=sha256:dff02c5c8423a657c550b48231d0a48d7e2b2e131088e55983cfe74ccc2c7cc9 \
--hash=sha256:e952c684274a7714b3160f57ec1d78309f955c6335c04433f07d36c5eb27b1f9 \
--hash=sha256:ea1e9e43ca56b0c12440a7c689b1350066595bebcaa83baad05b8b2675129d98 \
--hash=sha256:f022601f3ee9e1f6658ed6d184ce27fa5216cee5b82d279e0f0bde5deebece72 \
--hash=sha256:f0e9618630edd1910ad4f07f60d77c184b2f572c8ee43305ea3265675cbbfe7e \
--hash=sha256:f1d6bc9c23356908db712d282acb3eebd4ae5ec6d8b696aa40342b1d84f8e9e3 \
--hash=sha256:f4376819c1c778d59e0a31db5dc6ede854e9edf28bbfa5b756604727f7f800ac
# via -r requirements-fonttools.in

View file

@ -4,146 +4,84 @@
#
# pip-compile --allow-unsafe --generate-hashes --output-file=.ci/requirements.txt .ci/requirements.in
#
fonttools==4.56.0 \
--hash=sha256:003548eadd674175510773f73fb2060bb46adb77c94854af3e0cc5bc70260049 \
--hash=sha256:0073b62c3438cf0058488c002ea90489e8801d3a7af5ce5f7c05c105bee815c3 \
--hash=sha256:1088182f68c303b50ca4dc0c82d42083d176cba37af1937e1a976a31149d4d14 \
--hash=sha256:133bedb9a5c6376ad43e6518b7e2cd2f866a05b1998f14842631d5feb36b5786 \
--hash=sha256:14a3e3e6b211660db54ca1ef7006401e4a694e53ffd4553ab9bc87ead01d0f05 \
--hash=sha256:17f39313b649037f6c800209984a11fc256a6137cbe5487091c6c7187cae4685 \
--hash=sha256:193b86e9f769320bc98ffdb42accafb5d0c8c49bd62884f1c0702bc598b3f0a2 \
--hash=sha256:2d351275f73ebdd81dd5b09a8b8dac7a30f29a279d41e1c1192aedf1b6dced40 \
--hash=sha256:300c310bb725b2bdb4f5fc7e148e190bd69f01925c7ab437b9c0ca3e1c7cd9ba \
--hash=sha256:331954d002dbf5e704c7f3756028e21db07097c19722569983ba4d74df014000 \
--hash=sha256:38b947de71748bab150259ee05a775e8a0635891568e9fdb3cdd7d0e0004e62f \
--hash=sha256:3cf4f8d2a30b454ac682e12c61831dcb174950c406011418e739de592bbf8f76 \
--hash=sha256:3fd3fccb7b9adaaecfa79ad51b759f2123e1aba97f857936ce044d4f029abd71 \
--hash=sha256:442ad4122468d0e47d83bc59d0e91b474593a8c813839e1872e47c7a0cb53b10 \
--hash=sha256:47b5e4680002ae1756d3ae3b6114e20aaee6cc5c69d1e5911f5ffffd3ee46c6b \
--hash=sha256:53f5e9767978a4daf46f28e09dbeb7d010319924ae622f7b56174b777258e5ba \
--hash=sha256:62b4c6802fa28e14dba010e75190e0e6228513573f1eeae57b11aa1a39b7e5b1 \
--hash=sha256:62cc1253827d1e500fde9dbe981219fea4eb000fd63402283472d38e7d8aa1c6 \
--hash=sha256:654ac4583e2d7c62aebc6fc6a4c6736f078f50300e18aa105d87ce8925cfac31 \
--hash=sha256:661a8995d11e6e4914a44ca7d52d1286e2d9b154f685a4d1f69add8418961563 \
--hash=sha256:6c1d38642ca2dddc7ae992ef5d026e5061a84f10ff2b906be5680ab089f55bb8 \
--hash=sha256:6e81c1cc80c1d8bf071356cc3e0e25071fbba1c75afc48d41b26048980b3c771 \
--hash=sha256:705837eae384fe21cee5e5746fd4f4b2f06f87544fa60f60740007e0aa600311 \
--hash=sha256:7ef04bc7827adb7532be3d14462390dd71287644516af3f1e67f1e6ff9c6d6df \
--hash=sha256:86b2a1013ef7a64d2e94606632683f07712045ed86d937c11ef4dde97319c086 \
--hash=sha256:8d1613abd5af2f93c05867b3a3759a56e8bf97eb79b1da76b2bc10892f96ff16 \
--hash=sha256:965d0209e6dbdb9416100123b6709cb13f5232e2d52d17ed37f9df0cc31e2b35 \
--hash=sha256:96a4271f63a615bcb902b9f56de00ea225d6896052c49f20d0c91e9f43529a29 \
--hash=sha256:9d94449ad0a5f2a8bf5d2f8d71d65088aee48adbe45f3c5f8e00e3ad861ed81a \
--hash=sha256:9da650cb29bc098b8cfd15ef09009c914b35c7986c8fa9f08b51108b7bc393b4 \
--hash=sha256:a05d1f07eb0a7d755fbe01fee1fd255c3a4d3730130cf1bfefb682d18fd2fcea \
--hash=sha256:a114d1567e1a1586b7e9e7fc2ff686ca542a82769a296cef131e4c4af51e58f4 \
--hash=sha256:a1af375734018951c31c0737d04a9d5fd0a353a0253db5fbed2ccd44eac62d8c \
--hash=sha256:b23d30a2c0b992fb1c4f8ac9bfde44b5586d23457759b6cf9a787f1a35179ee0 \
--hash=sha256:bc871904a53a9d4d908673c6faa15689874af1c7c5ac403a8e12d967ebd0c0dc \
--hash=sha256:bce60f9a977c9d3d51de475af3f3581d9b36952e1f8fc19a1f2254f1dda7ce9c \
--hash=sha256:bd9825822e7bb243f285013e653f6741954d8147427aaa0324a862cdbf4cbf62 \
--hash=sha256:ca7962e8e5fc047cc4e59389959843aafbf7445b6c08c20d883e60ced46370a5 \
--hash=sha256:d0cb73ccf7f6d7ca8d0bc7ea8ac0a5b84969a41c56ac3ac3422a24df2680546f \
--hash=sha256:d54a45d30251f1d729e69e5b675f9a08b7da413391a1227781e2a297fa37f6d2 \
--hash=sha256:d6ca96d1b61a707ba01a43318c9c40aaf11a5a568d1e61146fafa6ab20890793 \
--hash=sha256:d6f195c14c01bd057bc9b4f70756b510e009c83c5ea67b25ced3e2c38e6ee6e9 \
--hash=sha256:e2cad98c94833465bcf28f51c248aaf07ca022efc6a3eba750ad9c1e0256d278 \
--hash=sha256:e2e993e8db36306cc3f1734edc8ea67906c55f98683d6fd34c3fc5593fdbba4c \
--hash=sha256:e9270505a19361e81eecdbc2c251ad1e1a9a9c2ad75fa022ccdee533f55535dc \
--hash=sha256:f20e2c0dfab82983a90f3d00703ac0960412036153e5023eed2b4641d7d5e692 \
--hash=sha256:f36a0868f47b7566237640c026c65a86d09a3d9ca5df1cd039e30a1da73098a0 \
--hash=sha256:f59746f7953f69cc3290ce2f971ab01056e55ddd0fb8b792c31a8acd7fee2d28 \
--hash=sha256:fa760e5fe8b50cbc2d71884a1eff2ed2b95a005f02dda2fa431560db0ddd927f \
--hash=sha256:ffda9b8cd9cb8b301cae2602ec62375b59e2e2108a117746f12215145e3f786c
fonttools==4.57.0 \
--hash=sha256:03290e818782e7edb159474144fca11e36a8ed6663d1fcbd5268eb550594fd8e \
--hash=sha256:0425c2e052a5f1516c94e5855dbda706ae5a768631e9fcc34e57d074d1b65b92 \
--hash=sha256:05efceb2cb5f6ec92a4180fcb7a64aa8d3385fd49cfbbe459350229d1974f0b1 \
--hash=sha256:17168a4670bbe3775f3f3f72d23ee786bd965395381dfbb70111e25e81505b9d \
--hash=sha256:3122c604a675513c68bd24c6a8f9091f1c2376d18e8f5fe5a101746c81b3e98f \
--hash=sha256:34687a5d21f1d688d7d8d416cb4c5b9c87fca8a1797ec0d74b9fdebfa55c09ab \
--hash=sha256:3871349303bdec958360eedb619169a779956503ffb4543bb3e6211e09b647c4 \
--hash=sha256:39acf68abdfc74e19de7485f8f7396fa4d2418efea239b7061d6ed6a2510c746 \
--hash=sha256:3cf97236b192a50a4bf200dc5ba405aa78d4f537a2c6e4c624bb60466d5b03bd \
--hash=sha256:408ce299696012d503b714778d89aa476f032414ae57e57b42e4b92363e0b8ef \
--hash=sha256:44c26a311be2ac130f40a96769264809d3b0cb297518669db437d1cc82974888 \
--hash=sha256:46370ac47a1e91895d40e9ad48effbe8e9d9db1a4b80888095bc00e7beaa042f \
--hash=sha256:4dea5893b58d4637ffa925536462ba626f8a1b9ffbe2f5c272cdf2c6ebadb817 \
--hash=sha256:51d8482e96b28fb28aa8e50b5706f3cee06de85cbe2dce80dbd1917ae22ec5a6 \
--hash=sha256:541cb48191a19ceb1a2a4b90c1fcebd22a1ff7491010d3cf840dd3a68aebd654 \
--hash=sha256:579ba873d7f2a96f78b2e11028f7472146ae181cae0e4d814a37a09e93d5c5cc \
--hash=sha256:57e30241524879ea10cdf79c737037221f77cc126a8cdc8ff2c94d4a522504b9 \
--hash=sha256:69ab81b66ebaa8d430ba56c7a5f9abe0183afefd3a2d6e483060343398b13fb1 \
--hash=sha256:6e3e1ec10c29bae0ea826b61f265ec5c858c5ba2ce2e69a71a62f285cf8e4595 \
--hash=sha256:727ece10e065be2f9dd239d15dd5d60a66e17eac11aea47d447f9f03fdbc42de \
--hash=sha256:7339e6a3283e4b0ade99cade51e97cde3d54cd6d1c3744459e886b66d630c8b3 \
--hash=sha256:767604f244dc17c68d3e2dbf98e038d11a18abc078f2d0f84b6c24571d9c0b13 \
--hash=sha256:7a64edd3ff6a7f711a15bd70b4458611fb240176ec11ad8845ccbab4fe6745db \
--hash=sha256:81aa97669cd726349eb7bd43ca540cf418b279ee3caba5e2e295fb4e8f841c02 \
--hash=sha256:84c41ba992df5b8d680b89fd84c6a1f2aca2b9f1ae8a67400c8930cd4ea115f6 \
--hash=sha256:84fd56c78d431606332a0627c16e2a63d243d0d8b05521257d77c6529abe14d8 \
--hash=sha256:889e45e976c74abc7256d3064aa7c1295aa283c6bb19810b9f8b604dfe5c7f31 \
--hash=sha256:8e2e12d0d862f43d51e5afb8b9751c77e6bec7d2dc00aad80641364e9df5b199 \
--hash=sha256:967b65232e104f4b0f6370a62eb33089e00024f2ce143aecbf9755649421c683 \
--hash=sha256:9d077f909f2343daf4495ba22bb0e23b62886e8ec7c109ee8234bdbd678cf344 \
--hash=sha256:9d57b4e23ebbe985125d3f0cabbf286efa191ab60bbadb9326091050d88e8213 \
--hash=sha256:a1968f2a2003c97c4ce6308dc2498d5fd4364ad309900930aa5a503c9851aec8 \
--hash=sha256:a2a722c0e4bfd9966a11ff55c895c817158fcce1b2b6700205a376403b546ad9 \
--hash=sha256:a97bb05eb24637714a04dee85bdf0ad1941df64fe3b802ee4ac1c284a5f97b7c \
--hash=sha256:aff40f8ac6763d05c2c8f6d240c6dac4bb92640a86d9b0c3f3fff4404f34095c \
--hash=sha256:babe8d1eb059a53e560e7bf29f8e8f4accc8b6cfb9b5fd10e485bde77e71ef41 \
--hash=sha256:bbceffc80aa02d9e8b99f2a7491ed8c4a783b2fc4020119dc405ca14fb5c758c \
--hash=sha256:c59375e85126b15a90fcba3443eaac58f3073ba091f02410eaa286da9ad80ed8 \
--hash=sha256:ca2aed95855506b7ae94e8f1f6217b7673c929e4f4f1217bcaa236253055cb36 \
--hash=sha256:cc066cb98b912f525ae901a24cd381a656f024f76203bc85f78fcc9e66ae5aec \
--hash=sha256:cdef9a056c222d0479a1fdb721430f9efd68268014c54e8166133d2643cb05d9 \
--hash=sha256:d07f1b64008e39fceae7aa99e38df8385d7d24a474a8c9872645c4397b674481 \
--hash=sha256:d639397de852f2ccfb3134b152c741406752640a266d9c1365b0f23d7b88077f \
--hash=sha256:dff02c5c8423a657c550b48231d0a48d7e2b2e131088e55983cfe74ccc2c7cc9 \
--hash=sha256:e952c684274a7714b3160f57ec1d78309f955c6335c04433f07d36c5eb27b1f9 \
--hash=sha256:ea1e9e43ca56b0c12440a7c689b1350066595bebcaa83baad05b8b2675129d98 \
--hash=sha256:f022601f3ee9e1f6658ed6d184ce27fa5216cee5b82d279e0f0bde5deebece72 \
--hash=sha256:f0e9618630edd1910ad4f07f60d77c184b2f572c8ee43305ea3265675cbbfe7e \
--hash=sha256:f1d6bc9c23356908db712d282acb3eebd4ae5ec6d8b696aa40342b1d84f8e9e3 \
--hash=sha256:f4376819c1c778d59e0a31db5dc6ede854e9edf28bbfa5b756604727f7f800ac
# via -r requirements-fonttools.in
markupsafe==2.1.3 \
--hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \
--hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \
--hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \
--hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \
--hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \
--hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \
--hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \
--hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \
--hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \
--hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \
--hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \
--hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \
--hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \
--hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
--hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
--hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
--hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \
--hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
--hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
--hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
--hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \
--hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \
--hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
--hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
--hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
--hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \
--hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
--hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
--hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
--hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \
--hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \
--hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \
--hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \
--hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \
--hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \
--hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \
--hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \
--hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \
--hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \
--hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \
--hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \
--hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \
--hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \
--hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \
--hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \
--hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \
--hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \
--hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \
--hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \
--hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \
--hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \
--hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \
--hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \
--hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \
--hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
--hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
--hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
--hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \
--hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \
--hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11
# via jinja2
meson==1.7.0 \
--hash=sha256:08efbe84803eed07f863b05092d653a9d348f7038761d900412fddf56deb0284 \
--hash=sha256:ae3f12953045f3c7c60e27f2af1ad862f14dee125b4ed9bcb8a842a5080dbf85
# via -r requirements.in
ninja==1.11.1.3 \
--hash=sha256:04d48d14ea7ba11951c156599ab526bdda575450797ff57c6fdf99b2554d09c7 \
--hash=sha256:114ed5c61c8474df6a69ab89097a20749b769e2c219a452cb2fadc49b0d581b0 \
--hash=sha256:17978ad611d8ead578d83637f5ae80c2261b033db0b493a7ce94f88623f29e1b \
--hash=sha256:1ad2112c2b0159ed7c4ae3731595191b1546ba62316fc40808edecd0306fefa3 \
--hash=sha256:2883ea46b3c5079074f56820f9989c6261fcc6fd873d914ee49010ecf283c3b2 \
--hash=sha256:28aea3c1c280cba95b8608d50797169f3a34280e3e9a6379b6e340f0c9eaeeb0 \
--hash=sha256:2b4879ea3f1169f3d855182c57dcc84d1b5048628c8b7be0d702b81882a37237 \
--hash=sha256:53409151da081f3c198bb0bfc220a7f4e821e022c5b7d29719adda892ddb31bb \
--hash=sha256:56ada5d33b8741d298836644042faddebc83ee669782d661e21563034beb5aba \
--hash=sha256:7fa2247fce98f683bc712562d82b22b8a0a5c000738a13147ca2d1b68c122298 \
--hash=sha256:8c4bdb9fd2d0c06501ae15abfd23407660e95659e384acd36e013b6dd7d8a8e4 \
--hash=sha256:a27e78ca71316c8654965ee94b286a98c83877bfebe2607db96897bbfe458af0 \
--hash=sha256:a38c6c6c8032bed68b70c3b065d944c35e9f903342875d3a3218c1607987077c \
--hash=sha256:a4a3b71490557e18c010cbb26bd1ea9a0c32ee67e8f105e9731515b6e0af792e \
--hash=sha256:b6966f83064a88a51693073eea3decd47e08c3965241e09578ef7aa3a7738329 \
--hash=sha256:bc3ebc8b2e47716149f3541742b5cd8e0b08f51013b825c05baca3e34854370d \
--hash=sha256:edfa0d2e9d7ead1635b03e40a32ad56cc8f56798b6e2e9848d8300b174897076
ninja==1.11.1.4 \
--hash=sha256:055f386fb550c2c9d6157e45e20a84d29c47968876b9c5794ae2aec46f952306 \
--hash=sha256:096487995473320de7f65d622c3f1d16c3ad174797602218ca8c967f51ec38a0 \
--hash=sha256:2ab67a41c90bea5ec4b795bab084bc0b3b3bb69d3cd21ca0294fc0fc15a111eb \
--hash=sha256:4617b3c12ff64b611a7d93fd9e378275512bb36eff8babff7c83f5116b4f8d66 \
--hash=sha256:5713cf50c5be50084a8693308a63ecf9e55c3132a78a41ab1363a28b6caaaee1 \
--hash=sha256:6aa39f6e894e0452e5b297327db00019383ae55d5d9c57c73b04f13bf79d438a \
--hash=sha256:9c29bb66d2aa46a2409ab369ea804c730faec7652e8c22c1e428cc09216543e5 \
--hash=sha256:b33923c8da88e8da20b6053e38deb433f53656441614207e01d283ad02c5e8e7 \
--hash=sha256:c3b96bd875f3ef1db782470e9e41d7508905a0986571f219d20ffed238befa15 \
--hash=sha256:cede0af00b58e27b31f2482ba83292a8e9171cdb9acc2c867a3b6e40b3353e43 \
--hash=sha256:cf4453679d15babc04ba023d68d091bb613091b67101c88f85d2171c6621c6eb \
--hash=sha256:cf554e73f72c04deb04d0cf51f5fdb1903d9c9ca3d2344249c8ce3bd616ebc02 \
--hash=sha256:cfdd09776436a1ff3c4a2558d3fc50a689fb9d7f1bdbc3e6f7b8c2991341ddb3 \
--hash=sha256:d3090d4488fadf6047d0d7a1db0c9643a8d391f0d94729554dbb89b5bdc769d7 \
--hash=sha256:d4a6f159b08b0ac4aca5ee1572e3e402f969139e71d85d37c0e2872129098749 \
--hash=sha256:ecce44a00325a93631792974659cf253a815cc6da4ec96f89742925dfc295a0d \
--hash=sha256:f6186d7607bb090c3be1e10c8a56b690be238f953616626f5032238c66e56867
# via -r requirements.in
# The following packages are considered to be unsafe in a requirements file:
setuptools==73.0.1 \
--hash=sha256:b208925fcb9f7af924ed2dc04708ea89791e24bde0d3020b27df0e116088b34e \
--hash=sha256:d59a3e788ab7e012ab2c4baed1b376da6366883ee20d7a5fc426816e3d7b1193
setuptools==78.1.0 \
--hash=sha256:18fd474d4a82a5f83dac888df697af65afa82dec7323d09c3e37d1f14288da54 \
--hash=sha256:3e386e96793c8702ae83d17b853fb93d3e09ef82ec62722e61da5cd22376dcd8
# via -r requirements.in

View file

@ -4,7 +4,7 @@ cpu_family = 'x86'
cpu = 'i686'
endian = 'little'
[properties]
[built-in options]
c_args = []
c_link_args = ['-static-libgcc', '-Wl,-Bstatic', '-lpthread']
cpp_args = []
@ -18,3 +18,5 @@ ld = 'i686-w64-mingw32-ld'
objcopy = 'i686-w64-mingw32-objcopy'
strip = 'i686-w64-mingw32-strip'
windres = 'i686-w64-mingw32-windres'
pkg-config = 'i686-w64-mingw32-pkg-config'
exe_wrapper = 'wine'

View file

@ -4,7 +4,7 @@ cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
[properties]
[built-in options]
c_args = []
c_link_args = ['-static-libgcc', '-Wl,-Bstatic', '-lpthread']
cpp_args = []
@ -18,3 +18,5 @@ ld = 'x86_64-w64-mingw32-ld'
objcopy = 'x86_64-w64-mingw32-objcopy'
strip = 'x86_64-w64-mingw32-strip'
windres = 'x86_64-w64-mingw32-windres'
pkg-config = 'x86_64-w64-mingw32-pkg-config'
exe_wrapper = 'wine'

View file

@ -3,10 +3,10 @@ version: 2.1
executors:
win32-executor:
docker:
- image: cimg/base:2023.10
- image: ubuntu:24.04
win64-executor:
docker:
- image: cimg/base:2023.10
- image: ubuntu:24.04
dist-executor:
docker:
- image: cimg/base:2023.10
@ -37,7 +37,7 @@ jobs:
- run: meson dist --no-tests -Cbuild
- persist_to_workspace:
root: .
paths: build/meson-dist/harfbuzz-*.tar.xz
paths: [build/meson-dist/harfbuzz-*.tar.xz]
publish-dist:
executor: dist-executor
@ -58,20 +58,6 @@ jobs:
- run: meson compile -Cbuild -j9
- run: RUN_VALGRIND=1 meson test -Cbuild -t 10 --no-suite=slow --wrap='valgrind --leak-check=full --error-exitcode=1' --print-errorlogs --num-processes=$(($(nproc)/2 + 1))
alpine:
docker:
- image: alpine
steps:
- checkout
- run: apk update && apk add ragel gcc g++ glib-dev freetype-dev cairo-dev git py3-pip ninja
- run: |
python3 -m venv venv
source venv/bin/activate
pip3 install meson==0.56.0
meson setup build --buildtype=minsize
meson compile -Cbuild -j9
meson test -Cbuild --print-errorlogs
asan-ubsan:
docker:
- image: ubuntu
@ -80,9 +66,11 @@ jobs:
- run: apt update || true
- run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip python3-venv ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
- run: |
export ASAN_OPTIONS=log_path=stderr:halt_on_error=1:abort_on_error=1
export UBSAN_OPTIONS=log_path=stderr:halt_on_error=1:abort_on_error=1:print_stacktrace=1
python3 -m venv venv
source venv/bin/activate
pip3 install meson==0.56.0
pip3 install meson==0.60.0
CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=address,undefined --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
meson compile -Cbuild -j9
meson test -Cbuild -t 10 --print-errorlogs | asan_symbolize | c++filt
@ -95,9 +83,10 @@ jobs:
- run: apt update || true
- run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip python3-venv ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
- run: |
export TSAN_OPTIONS=log_path=stderr:halt_on_error=1:abort_on_error=1
python3 -m venv venv
source venv/bin/activate
pip3 install meson==0.56.0
pip3 install meson==0.60.0
CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=thread --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
meson compile -Cbuild -j9
meson test -Cbuild -t 10 --print-errorlogs | asan_symbolize | c++filt
@ -110,9 +99,10 @@ jobs:
- run: apt update || true
- run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip python3-venv ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
- run: |
export MSAN_OPTIONS=log_path=stderr:halt_on_error=1:abort_on_error=1:print_stacktrace=1
python3 -m venv venv
source venv/bin/activate
pip3 install meson==0.56.0
pip3 install meson==0.60.0
# msan, needs --force-fallback-for=glib,freetype2 also which doesn't work yet but runs fuzzer cases at least
CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=memory --buildtype=debugoptimized --wrap-mode=nodownload -Dauto_features=disabled -Dtests=enabled -Dexperimental_api=true
meson compile -Cbuild -j9
@ -131,17 +121,21 @@ jobs:
executor: win32-executor
steps:
- checkout
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build python3 python3-pip python3-venv git g++-mingw-w64-i686 zip
- run: dpkg --add-architecture i386
- run: apt update
- run: DEBIAN_FRONTEND=noninteractive apt install -y ninja-build python3 python3-pip python3-venv git g++-mingw-w64-i686 zip wine wine32
- run: |
export LANG=en_US.UTF-8
python3 -m venv venv
source venv/bin/activate
pip3 install meson==1.6.0
bash .ci/build-win32.sh
bash .ci/build-win.sh 32
meson devenv -Cbuild-win32 meson test -t 10 --print-errorlogs --suite=harfbuzz
- store_artifacts:
path: harfbuzz-win32.zip
- persist_to_workspace:
root: .
paths: harfbuzz-win32.zip
paths: [harfbuzz-win32.zip]
publish-win32:
executor: win32-executor
@ -149,6 +143,8 @@ jobs:
- checkout
- attach_workspace:
at: .
- run: apt update
- run: DEBIAN_FRONTEND=noninteractive apt install -y curl
- run: |
mv harfbuzz-win32{,-$CIRCLE_TAG}.zip
.ci/publish_release_artifact.sh harfbuzz-win32-$CIRCLE_TAG.zip
@ -157,17 +153,21 @@ jobs:
executor: win64-executor
steps:
- checkout
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build python3 python3-pip python3-venv git g++-mingw-w64-x86-64 zip
- run: dpkg --add-architecture i386
- run: apt update
- run: DEBIAN_FRONTEND=noninteractive apt install -y ninja-build python3 python3-pip python3-venv git g++-mingw-w64-x86-64 zip wine wine64 wine32:i386
- run: |
export LANG=en_US.UTF-8
python3 -m venv venv
source venv/bin/activate
pip3 install meson==1.6.0
bash .ci/build-win64.sh
bash .ci/build-win.sh 64
meson devenv -Cbuild-win64 meson test -t 10 --print-errorlogs --suite=harfbuzz
- store_artifacts:
path: harfbuzz-win64.zip
- persist_to_workspace:
root: .
paths: harfbuzz-win64.zip
paths: [harfbuzz-win64.zip]
publish-win64:
executor: win64-executor
@ -175,6 +175,8 @@ jobs:
- checkout
- attach_workspace:
at: .
- run: apt update
- run: DEBIAN_FRONTEND=noninteractive apt install -y curl
- run: |
mv harfbuzz-win64{,-$CIRCLE_TAG}.zip
.ci/publish_release_artifact.sh harfbuzz-win64-$CIRCLE_TAG.zip
@ -199,7 +201,6 @@ workflows:
branches:
ignore: /.*/
- fedora-valgrind
- alpine
- asan-ubsan
- tsan
- msan

View file

@ -21,7 +21,7 @@ jobs:
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts

63
.github/workflows/fontations.yml vendored Normal file
View file

@ -0,0 +1,63 @@
name: fontations
on:
push:
branches: [ main ]
tags: ["*.*.*"]
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Ccache
uses: hendrikmuhs/ccache-action@a1209f81afb8c005c13b4296c32e363431bffea5 # v1.2.17
with:
key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }}
- uses: dtolnay/rust-toolchain@nightly
- name: Install Dependencies
run: |
rustup component add \
rust-src \
rustfmt \
clippy \
--toolchain nightly-x86_64-unknown-linux-gnu
sudo apt-get update
sudo apt-get install \
gcc \
gobject-introspection \
gtk-doc-tools \
libcairo2-dev \
libfreetype6-dev \
libgirepository1.0-dev \
libglib2.0-dev \
libgraphite2-dev \
libicu-dev \
pkg-config \
bindgen
- name: Setup Python
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with:
python-version: '3.12'
- name: Install Python Dependencies
run: pip3 install -r .ci/requirements.txt --require-hashes
- name: Setup Meson
run: |
ccache --version
meson setup build \
-Dauto_features=enabled \
-Dchafa=disabled \
-Dgraphite=enabled \
-Doptimization=2 \
-Dfontations=enabled
- name: Build
run: meson compile -Cbuild
- name: Test
run: RUST_BACKTRACE=1 meson test --print-errorlogs -Cbuild

View file

@ -34,9 +34,10 @@ jobs:
libglib2.0-dev \
libgraphite2-dev \
libicu-dev \
pkg-config
pkg-config \
help2man
- name: Setup Python
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with:
python-version: '3.12'
- name: Install Python Dependencies

View file

@ -36,7 +36,7 @@ jobs:
ninja \
pkgconf
- name: Setup Python
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with:
python-version: '3.12'
- name: Install Python Dependencies

View file

@ -35,7 +35,7 @@ jobs:
variant: sccache
key: ${{ github.job }}-${{ matrix.os }}-${{ matrix.ARCH }}
- name: Setup Python
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with:
python-version: '3.12'
- name: Setup MSVC

View file

@ -21,13 +21,10 @@ jobs:
MSYS2_ARCH: i686
- MSYSTEM: MINGW64
MSYS2_ARCH: x86_64
- MSYSTEM: CLANG64
MSYS2_ARCH: clang-x86_64
name: ${{ matrix.MSYSTEM }}
env:
# XXX: For some reason enabling jit debugging "fixes" random python crashes
# see https://github.com/msys2/MINGW-packages/issues/11864
MSYS: "winjitdebug"
defaults:
run:
shell: msys2 {0}
@ -42,8 +39,7 @@ jobs:
install: >-
mingw-w64-${{ matrix.MSYS2_ARCH }}-cairo
mingw-w64-${{ matrix.MSYS2_ARCH }}-freetype
mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc
mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc-libs
mingw-w64-${{ matrix.MSYS2_ARCH }}-cc
mingw-w64-${{ matrix.MSYS2_ARCH }}-gettext
mingw-w64-${{ matrix.MSYS2_ARCH }}-glib2
mingw-w64-${{ matrix.MSYS2_ARCH }}-gobject-introspection
@ -51,12 +47,9 @@ jobs:
mingw-w64-${{ matrix.MSYS2_ARCH }}-icu
mingw-w64-${{ matrix.MSYS2_ARCH }}-meson
mingw-w64-${{ matrix.MSYS2_ARCH }}-ninja
mingw-w64-${{ matrix.MSYS2_ARCH }}-pkg-config
mingw-w64-${{ matrix.MSYS2_ARCH }}-pkgconf
mingw-w64-${{ matrix.MSYS2_ARCH }}-python
mingw-w64-${{ matrix.MSYS2_ARCH }}-python-pip
- name: Remove installed HarfBuzz DLLs
run: |
rm -f -v /ming*/bin/libharfbuzz-*.dll
- name: Install Python Dependencies
run: |
pip3 install -r .ci/requirements-fonttools.txt --require-hashes
@ -76,7 +69,7 @@ jobs:
run: meson test --print-errorlogs --suite=harfbuzz -Cbuild
- name: Upload DLLs
if: always()
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: libharfbuzz-${{ matrix.MSYS2_ARCH }}
path: ./build/src/libharfbuzz-*.dll

View file

@ -34,7 +34,7 @@ jobs:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
with:
results_file: results.sarif
results_format: sarif
@ -51,7 +51,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: SARIF file
path: results.sarif
@ -59,6 +59,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9
uses: github/codeql-action/upload-sarif@fc7e4a0fa01c3cca5fd6a1fddec5c0740c977aa2 # v3.28.14
with:
sarif_file: results.sarif

View file

@ -233,7 +233,7 @@ if (HB_HAVE_FREETYPE AND NOT TARGET freetype)
set (CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${FREETYPE_INCLUDE_DIRS})
set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${FREETYPE_LIBRARIES})
check_funcs(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var)
check_funcs(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var FT_Get_Transform)
endif ()
if (HB_HAVE_FREETYPE)

117
NEWS
View file

@ -1,7 +1,118 @@
Overview of changes leading to 11.0.1
Friday, April 4, 2025
====================================
- The change in version 10.3.0 to apply “trak” table tracking values to glyph
advances directly has been reverted as it required every font functions
implementation to handle it, which breaks existing custom font functions.
Tracking is instead back to being applied during shaping.
- When `directwrite` integration is enabled, we now link to `dwrite.dll`
instead of dynamically loading it.
- A new experimental APIs for getting raw “CFF” and “CFF2” CharStrings.
- We now provide manpages for the various command line utilities. Building
manpages requires “help2man” and will be skipped if it is not present.
- The command line utilities now set different return value for different kinds
of failures. Details are provided in the manpages.
- Various fixes and improvements to `fontations` font functions.
- All shaping operations using the `ot` shaper have become memory
allocation-free.
- Glyph extents returned by `hb-ot` and `hb-ft` font functions are now rounded
in stead of flooring/ceiling them, which also matches what other font
libraries do.
- Fix “AAT” deleted glyph marks interfering with fallback mark positioning.
- Glyph outlines emboldening have been moved out of `hb-ot` and `hb-ft` font
functions to the HarfBuzz font layer, so that it works with any font
functions implementation.
- Fix our fallback C++11 atomics integration, which seems to not be widely
used.
- Various testing fixes and improvements.
- Various subsetting fixes and improvements.
- Various other fixes and improvements.
Overview of changes leading to 11.0.0
Monday, March 24, 2025
====================================
- There are three new font-functions implementations (integrations) in this
release:
* `hb-coretext` has gained one, calling into the CoreText library,
* `hb-directwrite` has gained one, calling into the DirectWrite library.
* `hb-fontations` has gained one, calling into the Skrifa Rust library.
All three are mostly useful for performance and correctness testing, but some
clients might find them useful.
An API is added to use them from a single API by providing a backend name
string:
* `hb_font_set_funcs_using()`
- Several new APIs are added, to load a font-face using different
"face-loaders", and a single entry point to them all using a loader name
string:
* `hb_ft_face_create_from_file_or_fail()` and
`hb_ft_face_create_from_blob_or_fail()`
* `hb_coretext_face_create_from_file_or_fail()` and
`hb_coretext_face_create_from_blob_or_fail()`
* `hb_directwrite_face_create_from_file_or_fail()` and
`hb_directwrite_face_create_from_blob_or_fail()`
* `hb_face_create_from_file_or_fail_using()`
- All drawing and painting operations using the default, `hb-ot` functions have
become memory allocation-free.
- Several performance optimizations have been implemented.
- Application of the `trak` table during shaping has been improved.
- The `directwrite` shaper now supports font variations, and correctly applies
user features.
- The `hb-directwrite` API and shaper has graduated from experimental.
- Various bug fixes and other improvements.
- New API:
+hb_malloc
+hb_calloc
+hb_realloc
+hb_free
+hb_face_list_loaders
+hb_face_create_or_fail_using
+hb_face_create_from_file_or_fail_using
+hb_font_list_funcs
+hb_font_set_funcs_using
+hb_coretext_face_create_from_blob_or_fail
+hb_directwrite_face_create_from_file_or_fail
+hb_directwrite_face_create_from_blob_or_fail
+hb_directwrite_font_create
+hb_directwrite_font_get_dw_font_face
+hb_directwrite_font_set_funcs
+hb_fontations_font_set_funcs
+hb_ft_face_create_from_blob_or_fail
+hb_paint_push_font_transform
+hb_paint_push_inverse_font_transform
+HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES
+HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE
+HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES
+HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS
- Deprecated API:
+hb_directwrite_font_get_dw_font
Overview of changes leading to 10.4.0
Saturday, March 1, 2025
====================================
- Drawing glyphs using hb-draw API now avoids any “malloc” calls, which
improves drawing performance by 10+%.
- Add support new “GVAR” table fonts with more than 65535 glyphs. Support is
currently behind a compilation flag and is disabled by default.
- Some hb-directwrite and hb-ft APIs got renamed with more clear names and the
old names are deprecated.
- Various build and fuzzing fixes.
- New API:
+hb_directwrite_face_get_dw_font_face()
+hb_ft_font_get_ft_face()
- Deprecated API:
+hb_directwrite_face_get_font_face()
+hb_ft_font_get_face()
Overview of changes leading to 10.3.0
Thursday, February 11, 2025
====================================
- Vastly improved “AAT” shaping performance. LucidaGrande benchmark-shape
before: 14.6ms after: 5.9ms.
- Improved OpenType shaping performance (kerning / ligature), at the expense of
@ -226,10 +337,10 @@ Saturday, November 11, 2023
tools. Old option is kept as an alias.
- New API:
HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION
+HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION
- Deprecated API:
HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION
+HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION
Overview of changes leading to 8.2.2
Wednesday, October 18, 2023

View file

@ -1,8 +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/actions/workflows/linux-ci.yml/badge.svg)](https://github.com/harfbuzz/harfbuzz/actions/workflows/linux-ci.yml)
[![macoOS CI Status](https://github.com/harfbuzz/harfbuzz/actions/workflows/macos-ci.yml/badge.svg)](https://github.com/harfbuzz/harfbuzz/actions/workflows/macos-ci.yml)
[![Windows CI Status](https://github.com/harfbuzz/harfbuzz/actions/workflows/msvc-ci.yml/badge.svg)](https://github.com/harfbuzz/harfbuzz/actions/workflows/msvc-ci.yml)
[![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#harfbuzz)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/15166/badge.svg)](https://scan.coverity.com/projects/harfbuzz)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://app.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/harfbuzz/harfbuzz/badge)](https://securityscorecards.dev/viewer/?uri=github.com/harfbuzz/harfbuzz)
@ -34,13 +35,20 @@ will also find Win32/Win64 binary bundles that include `libharfbuzz` DLL,
`hb-view.exe`, `hb-shape.exe`, and all dependencies.
The canonical source tree is available on [github][4].
Both development and user support discussion around HarfBuzz happens on
[github][4] as well.
The API that comes with `hb.h` will not change incompatibly. Other, peripheral,
headers are more likely to go through minor modifications, but again, we do our
best to never change API in an incompatible way. We will never break the ABI.
If you are not sure whether Pango or HarfBuzz is right for you, read [Pango vs
HarfBuzz][5].
The API and ABI are stable even across major version number jumps. In fact,
current HarfBuzz is API/ABI compatible all the way back to the 0.9.x series.
If one day we need to break the API/ABI, that would be called a new a library.
As such, we bump the major version number only when we add major new features,
the minor version when there is new API, and the micro version when there
are bug fixes.
## Development
@ -50,24 +58,38 @@ For custom configurations, see [CONFIG.md](CONFIG.md).
For testing and profiling, see [TESTING.md](TESTING.md).
For using with Python, see [README.python.md](README.python.md). There is also [uharfbuzz](https://github.com/harfbuzz/uharfbuzz).
For cross-compiling to Windows from Linux or macOS, see [README.mingw.md](README.mingw.md).
To report bugs or submit patches please use [github][4] issues and pull-requests.
### Developer documents
To get a better idea of where HarfBuzz stands in the text rendering stack you
may want to read [State of Text Rendering 2024][6].
Here are a few presentation slides about HarfBuzz at the
Internationalization and Unicode Conference over the years:
* November 2014, [Unicode, OpenType, and HarfBuzz: Closing the Circle][7],
* October 2012, [HarfBuzz, The Free and Open Text Shaping Engine][8],
* October 2009, [HarfBuzz: the Free and Open Shaping Engine][9].
- 2014 [Unicode, OpenType, and HarfBuzz: Closing the Circle][7]
- 2012 [HarfBuzz, The Free and Open Text Shaping Engine][8]
- 2016 [Ten Years of HarfBuzz][20]
- 2009 [HarfBuzz: the Free and Open Shaping Engine][9]
Both development and user support discussion around HarfBuzz happens on the
[github][4].
More presentations and papers are available on [behdad][11]'s website.
In particular, the following _studies_ are relevant to HarfBuzz development:
To report bugs or submit patches please use [github][4] issues and
pull-requests.
- 2025 [Subsetting][21]
- 2025 [Caching][12]
- 2025 [`hb-decycler`][13]
- 2022 [`hb-iter`][14]
- 2022 [A C library written in C++][15]
- 2022 [The case of the slow `hb-ft` `>h_advance` function][18]
- 2022 [PackTab: A static integer table packer][16]
- 2020 [HarfBuzz OT+AAT "Unishaper"][19]
- 2014 [Building the Indic Shaper][17]
- 2012 [Memory Consumption][10]
For a comparison of old vs new HarfBuzz memory consumption see [this][10].
<!--See past and upcoming [HarfBuzz Hackfests](https://freedesktop.org/wiki/Software/HarfBuzz/Hackfests/)!-->
## Name
@ -84,6 +106,8 @@ transliterated using the Latin script. It also means "talkative" or
> TrueType that adds support for complex script rendering, and HarfBuzz is an
> implementation of OpenType complex text shaping.
## Distribution
<details>
<summary>Packaging status of HarfBuzz</summary>
@ -95,9 +119,19 @@ transliterated using the Latin script. It also means "talkative" or
[2]: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6AATIntro.html
[3]: https://github.com/harfbuzz/harfbuzz/releases
[4]: https://github.com/harfbuzz/harfbuzz
[5]: http://mces.blogspot.com/2009/11/pango-vs-harfbuzz.html
[6]: http://behdad.org/text2024
[7]: https://goo.gl/FSIQuC
[8]: https://goo.gl/2wSRu
[7]: https://docs.google.com/presentation/d/1x97pfbB1gbD53Yhz6-_yBUozQMVJ_5yMqqR_D-R7b7I/preview
[8]: https://docs.google.com/presentation/d/1ySTZaXP5XKFg0OpmHZM00v5b17GSr3ojnzJekl4U8qI/preview
[9]: http://behdad.org/download/Presentations/slippy/harfbuzz_slides.pdf
[10]: https://goo.gl/woyty
[10]: https://docs.google.com/document/d/12jfNpQJzeVIAxoUSpk7KziyINAa1msbGliyXqguS86M/preview
[11]: https://behdad.org/
[12]: https://docs.google.com/document/d/1_VgObf6Je0J8byMLsi7HCQHnKo2emGnx_ib_sHo-bt4/preview
[13]: https://docs.google.com/document/d/1Y-u08l9YhObRVObETZt1k8f_5lQdOix9TRH3zEXaoAw/preview
[14]: https://docs.google.com/document/d/1o-xvxCbgMe9JYFHLVnPjk01ZY_8Cj0vB9-KTI1d0nyk/preview
[15]: https://docs.google.com/document/d/18hI56KJpvXtwWbc9QSaz9zzhJwIMnrJ-zkAaKS-W-8k/preview
[16]: https://docs.google.com/document/d/1Xq3owVt61HVkJqbLFHl73il6pcTy6PdPJJ7bSouQiQw/preview
[17]: https://docs.google.com/document/d/1wMPwVNBvsIriamcyBO5aNs7Cdr8lmbwLJ8GmZBAswF4/preview
[18]: https://docs.google.com/document/d/1wskYbA-czBt57oH9gEuGf3sWbTx7bfOiEIcDs36-heo/preview
[19]: https://prezi.com/view/THNPJGFVDUCWoM20syev/
[20]: https://behdad.org/doc/harfbuzz10years-slides.pdf
[21]: https://docs.google.com/document/d/1_vZrt97OorJ0jA1YzJ29LRcGr3YGrNJANdOABjVZGEs/preview

216
README.mingw.md Normal file
View file

@ -0,0 +1,216 @@
Most HarfBuzz developers do so on Linux or macOS. However, HarfBuzz is a
cross-platform library and it is important to ensure that it works on Windows
as well. In particular, we use this workflow to develop and test the HarfBuzz
Uniscribe shaper and DirectWrite shaper and font backend, all from Linux or
macOS.
This document provides instructions for cross-compiling HarfBuzz on Linux or
macOS, for Windows, using the MinGW toolchain, and running tests and utilties
under Wine.
We then discuss using native Windows Uniscribe or DirectWrite DLLs, which
allows you to test HarfBuzz's shaping against the Microsoft shaping engines
instead of those provided by Wine.
This document assumes that you are familiar with building HarfBuzz on Linux or
macOS.
You can build for 32bit or 64bit Windows. If your intention is to use a native
Uniscribe usp10.dll from Windows 7 or before, you would need to build for 32bit.
If you want to use a native DirectWrite DLL from Windows 10 or later, you would
need to build for 64bit.
We suggest you read to the end of this document before starting, as it provides
a few different ways to build and test HarfBuzz for Windows.
1. Install Wine.
- Fedora: `dnf install wine`.
- Ubuntu, 32bit: `apt install wine wine32`.
- Ubuntu, 64bit: `apt install wine wine64`.
- Mac: `brew install wine-stable`.
Note that to run Wine on Apple silicon systems, you need the Apple Rosetta translator.
Follow the instructions you got from brew. This should do it:
- `softwareupdate --install-rosetta --agree-to-license`
2. Install the `mingw-w64` cross-compiler.
- Fedora, 32bit: `dnf install mingw32-gcc-c++`
- Fedora, 64bit: `dnf install mingw64-gcc-c++`
- Ubuntu, 32bit: `apt install g++-mingw-w64-i686`
- Ubuntu, 64bit: `apt install g++-mingw-w64-x86-64`
- Mac: `brew install mingw-w64`
3. Install dependencies.
First, make sure you do not have the mingw32 harfbuzz package, as that will
override our own build with older `meson`:
- Fedora, 32bit: `dnf remove mingw32-harfbuzz`
- Fedora, 64bit: `dnf remove mingw64-harfbuzz`
Then install the actual dependencies:
- Fedora, 32bit: `dnf install mingw32-glib2 mingw32-cairo mingw32-freetype`
- Fedora, 64bit: `dnf install mingw64-glib2 mingw64-cairo mingw64-freetype`
If you cannot find these packages for your distribution, or you are on macOS,
you can skip to the next step, as meson will automatically download and build
the dependencies for you.
4. If you are familiar with `meson`, you can use the cross-compile files we
provide to find your way around. But we do not recommend this way. Read until
the end of this section before deciding which one to use.
- 32bit: `meson --cross-file=.ci/win32-cross-file.txt build-win -Dglib-enabled -Dcairo=enabled -Dgdi=enabled -Ddirectwrite=enabled`
- 64bit: `meson --cross-file=.ci/win64-cross-file.txt build-win -Dglib-enabled -Dcairo=enabled -Dgdi=enabled -Ddirectwrite=enabled`
In which case, you will proceed to run `ninja` as usual to build:
- `ninja -C build-win`
Or you can simply invoke the scripts we provide for our Continuous Integration
system, to configure and build HarfBuzz for you. This is the easiest way to
build HarfBuzz for Windows and how we build our Windows binaries:
- 32bit: `./.ci/build-win.sh 32 && ln -s build-win32 build-win`
- 64bit: `./.ci/build-win.sh 64 && ln -s build-win64 build-win`
This might take a while, since, if you do not have the dependencies installed,
meson will download and build them for you.
5. If everything succeeds, you should have the `hb-shape.exe`, `hb-view.exe`,
`hb-subset.exe`, and `hb-info.exe` executables in `build-win/util`.
6. Configure your wine to find system mingw libraries. While there, set it also
to find the built HarfBuzz DLLs:
- Fedora, 32bit: `export WINEPATH="$HOME/harfbuzz/build-win/src;/usr/i686-w64-mingw32/sys-root/mingw/bin"`
- Fedora, 64bit: `export WINEPATH="$HOME/harfbuzz/build-win/src;/usr/x86_64-w64-mingw32/sys-root/mingw/bin"`
- Other systems: `export WINEPATH="$HOME/harfbuzz/build-win/src"`
Adjust for the path where you have built HarfBuzz. You might want to add this
to your `.bashrc` or `.zshrc` file.
Alternatively, can skip this step if commands are run through the `meson devenv`
command, which we will introduce in the next step. I personally find it more
convenient to set the `WINEPATH` variable, as it allows me to run the executables
directly from the shell.
7. Run the `hb-shape` executable under Wine:
- `wine build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test`
Or using `meson devenv to do the same:
- `meson devenv -C build-win util/hb-shape.exe $PWD/perf/fonts/Roboto-Regular.ttf Test`
You probably will get lots of Wine warnings, but if all works fine, you
should see:
```
[gid57=0+1123|gid74=1+1086|gid88=2+1057|gid89=3+670]
```
You can make Wine less verbose, without hiding all errors, by setting:
- `export WINEDEBUG=fixme-all,warn-all,err-plugplay,err-seh,err-rpc,err-ntoskrnl,err-winediag,err-systray,err-hid`
Add this to your `.bashrc` or `.zshrc` file as well.
Next, let's try some non-Latin text. Unfortunately, the command-line parsing of
our cross-compiled glib is not quite Unicode-aware, at least when run under
Wine. So you will need to find some other way to feed Unicode text to the
shaper. There are three different ways you can try:
- `echo حرف | wine build-win/util/hb-shape.exe perf/fonts/Amiri-Regular.ttf`
- `wine build-win/util/hb-shape.exe perf/fonts/Amiri-Regular.ttf -u 062D,0631,0641`
- `wine build-win/util/hb-shape.exe perf/fonts/Amiri-Regular.ttf --text-file harf.txt`
To get the Unicode codepoints for a string, you can use the `hb-unicode-decode`
utility:
```
$ test/shape/hb-unicode-decode حرف
U+062D,U+0631,U+0641
```
8. Next, let's try the `hb-view` utility. By default, `hb-view` outputs ANSI text,
which Wine will not display correctly. You can use the `-o` option to redirect the
output to a file, or just redirect the output using the shell, which will produce
a PNG file.
- `wine build-win/util/hb-view.exe perf/fonts/Roboto-Regular.ttf Test > test.png`
7. As noted, if your Linux has `binfmt_misc` enabled, you can run the executables
directly. If not, you can modify the cross-file to use the `exe_wrapper` option as
specified before.
- `build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test`
If that does not work, you can use the `wine` command as shown above.
10. You can try running the test suite. If on Linux with `binfmt_misc` enabled, you
can run the tests directly:
- `ninja -C build-win test`
For other situations, use `meson devenv`:
- `meson devenv -C build-win ninja test`
This might take a couple of minutes to run. Running under Wine is expensive, so
be patient.
If all goes well, tests should run. If all is well, you should probably see about
400 tests pass, some skipped, but none failing.
11. In the above testing situation, the `directwrite` test will be disabled
automatically upon detection of running under Wine. The reason the `directwrite`
test would otherwise fails is that we are running against the Wine-provided
DirectWrite DLL, which is an incomplete reimplementation of the DirectWrite API
by Wine, and not the real thing.
If you want to test the Uniscribe or DirectWrite shapers against the real
Uniscribe / DirectWrite, you can follow the instructions below.
11. Old Uniscribe: Assuming a 32bit build for now.
Bring a 32bit version of `usp10.dll` for yourself from
`C:\Windows\SysWOW64\usp10.dll` of your 64bit Windows installation,
or `C:\Windows\System32\usp10.dll` for 32bit Windows installation.
You want one from Windows 7 or earlier. One that is not just a proxy for
`TextShaping.dll`. Rule of thumb, your `usp10.dll` should have a size more
than 500kb.
Put the file in `~/.wine/drive_c/windows/syswow64/` so wine can find it.
You can now tell wine to use the native `usp10.dll`:
- `export WINEDLLOVERRIDES="usp10=n"`
- `wine build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test --shaper=uniscribe`
12. DirectWrite and new Uniscribe: You can use the same method to test the
DirectWrite shaper against the native DirectWrite DLL. Try with a 64bit build
this time.
Bring `TextShaping.dll`, `DWrite.dll`, and `usp10.dll` from your 64bit Windows
installation (`C:\Windows\System32`) to `~/.wine/drive_c/windows/system32/`.
You want the ones from Windows 10 or later. You might have some luck downloading
them from the internet, but be careful with the source. I had success with the
DLLs from [https://dllme.com](dllme.com), but I cannot vouch for the site.
You can now tell wine to use the native DirectWrite:
- `export WINEDLLOVERRIDES="textshaping,dwrite,usp10=n"`
- `wine build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test --shaper=directwrite`
If all works well, you should be able to rerun the tests and see all pass this time.
13. For some old instructions on how to test HarfBuzz's native Indic shaper against
Uniscribe, see: https://github.com/harfbuzz/harfbuzz/issues/3671
14. That's it! If you made it this far, you are now able to develop and test
HarfBuzz on Windows, from Linux or macOS. Enjoy!

View file

@ -3,21 +3,21 @@
- [ ] Open gitk and review changes since last release.
- [ ] Print all public API changes:
`git diff $(git describe | sed 's/-.*//').. src/*.h`
`git diff $(git describe | sed 's/-.*//').. src/*.h`
- [ ] Document them in NEWS.
All API and API semantic changes should be clearly marked as API additions, API changes, or API deletions.
All API and API semantic changes should be clearly marked as API additions, API changes, or API deletions.
- [ ] Document deprecations.
Ensure all new API / deprecations are in listed correctly in docs/harfbuzz-sections.txt.
If release added new API, add entry for new API index at the end of docs/harfbuzz-docs.xml.
Ensure all new API / deprecations are listed correctly in docs/harfbuzz-sections.txt.
If release added new API, add entry for new API index at the end of docs/harfbuzz-docs.xml.
If there's a backward-incompatible API change (including deletions for API used anywhere), that's a release blocker.
Do NOT release.
If there's a backward-incompatible API change (including deletions for API used anywhere), that's a release blocker.
Do NOT release.
- [ ] Based on severity of changes, decide whether it's a minor or micro release number bump.
- [ ] Search for 'XSince: REPLACEME' on the repository and replace it with the chosen version for the release, e.g. 'Since: 1.4.7'.
- [ ] Search for 'REPLACEME' on the repository and replace it with the chosen version for the release, e.g. 'Since: 1.4.7'.
- [ ] Make sure you have correct date and new version at the top of NEWS file.
@ -26,12 +26,16 @@
- [ ] Do a `meson test -Cbuild` so it both checks the tests and updates hb-version.h (use `git diff` to see if is really updated).
- [ ] Commit NEWS, meson.build, and src/hb-version.h, as well as any REPLACEME changes you made.
The commit message is simply the release number, e. g. "1.4.7"
The commit message is simply the release number, e. g. "1.4.7"
- [ ] Do a `meson dist -Cbuild` that runs the tests against the latest committed changes.
If doesn't pass, something fishy is going on, reset the repo and start over.
If it does not pass, something fishy is going on, reset the repo and start over.
- [ ] Tag the release and sign it: e.g. `git tag -s 1.4.7 -m 1.4.7`.
Enter your GPG password.
- [ ] Push the commit and tag out: `git push --follow-tags`.
- [ ] There should be a GitHub release automatically created.
When it does, go to that release page and add description.
The description should be the NEWS file additions.

View file

@ -90,15 +90,16 @@
<chapter id="integration-api">
<title>Integration API</title>
<xi:include href="xml/hb-cairo.xml"/>
<xi:include href="xml/hb-coretext.xml"/>
<xi:include href="xml/hb-directwrite.xml"/>
<xi:include href="xml/hb-ft.xml"/>
<xi:include href="xml/hb-fontations.xml"/>
<xi:include href="xml/hb-gdi.xml"/>
<xi:include href="xml/hb-glib.xml"/>
<xi:include href="xml/hb-graphite2.xml"/>
<xi:include href="xml/hb-icu.xml"/>
<xi:include href="xml/hb-uniscribe.xml"/>
<xi:include href="xml/hb-gdi.xml"/>
<xi:include href="xml/hb-directwrite.xml"/>
<xi:include href="xml/hb-cairo.xml"/>
</chapter>
<chapter id="style-api">
@ -120,6 +121,8 @@
<index id="api-index-full"><title>API Index</title><xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include></index>
<index id="deprecated-api-index"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include></index>
<index id="api-index-11-0-0"><title>Index of new symbols in 11.0.0</title><xi:include href="xml/api-index-11.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-10-4-0"><title>Index of new symbols in 10.4.0</title><xi:include href="xml/api-index-10.4.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-10-3-0"><title>Index of new symbols in 10.3.0</title><xi:include href="xml/api-index-10.3.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-10-2-0"><title>Index of new symbols in 10.2.0</title><xi:include href="xml/api-index-10.2.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-10-1-0"><title>Index of new symbols in 10.1.0</title><xi:include href="xml/api-index-10.1.0.xml"><xi:fallback /></xi:include></index>

View file

@ -114,6 +114,9 @@ hb_glyph_position_t
hb_buffer_content_type_t
hb_buffer_flags_t
hb_buffer_cluster_level_t
HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS
HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES
HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE
hb_segment_properties_t
hb_buffer_serialize_format_t
hb_buffer_serialize_flags_t
@ -181,6 +184,10 @@ uint8_t
HB_EXTERN
HB_DEPRECATED
HB_DEPRECATED_FOR
hb_malloc
hb_calloc
hb_realloc
hb_free
<SUBSECTION Private>
HB_H_IN
HB_OT_H_IN
@ -285,6 +292,8 @@ hb_paint_custom_palette_color_func_t
hb_paint_funcs_set_custom_palette_color_func
hb_paint_push_transform
hb_paint_push_font_transform
hb_paint_push_inverse_font_transform
hb_paint_pop_transform
hb_paint_color_glyph
hb_paint_push_clip_glyph
@ -332,6 +341,10 @@ hb_font_funcs_set_glyph_shape_func
hb_font_get_glyph_v_kerning
hb_font_get_glyph_v_kerning_func_t
HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION
hb_directwrite_face_get_font_face
hb_directwrite_font_get_dw_font
hb_ft_font_get_face
hb_graphite2_font_get_gr_font
</SECTION>
<SECTION>
@ -341,6 +354,7 @@ HB_CORETEXT_TAG_MORT
HB_CORETEXT_TAG_MORX
hb_coretext_face_create
hb_coretext_face_create_from_file_or_fail
hb_coretext_face_create_from_blob_or_fail
hb_coretext_font_create
hb_coretext_face_get_cg_font
hb_coretext_font_get_ct_font
@ -350,9 +364,12 @@ hb_coretext_font_set_funcs
<SECTION>
<FILE>hb-directwrite</FILE>
hb_directwrite_face_create
hb_directwrite_face_get_font_face
hb_directwrite_face_create_from_file_or_fail
hb_directwrite_face_create_from_blob_or_fail
hb_directwrite_face_get_dw_font_face
hb_directwrite_font_create
hb_directwrite_font_get_dw_font
hb_directwrite_font_get_dw_font_face
hb_directwrite_font_set_funcs
</SECTION>
<SECTION>
@ -361,7 +378,10 @@ hb_face_count
hb_face_t
hb_face_create
hb_face_create_or_fail
hb_face_create_or_fail_using
hb_face_create_from_file_or_fail
hb_face_create_from_file_or_fail_using
hb_face_list_loaders
hb_reference_table_func_t
hb_face_create_for_tables
hb_face_get_empty
@ -455,6 +475,8 @@ hb_font_get_serial
hb_font_changed
hb_font_set_funcs
hb_font_set_funcs_data
hb_font_set_funcs_using
hb_font_list_funcs
hb_font_subtract_glyph_origin_for_direction
hb_font_funcs_create
hb_font_funcs_get_empty
@ -514,16 +536,23 @@ hb_font_extents_t
hb_glyph_extents_t
</SECTION>
<SECTION>
<FILE>hb-fontations</FILE>
hb_fontations_font_set_funcs
</SECTION>
<SECTION>
<FILE>hb-ft</FILE>
hb_ft_face_create
hb_ft_face_create_cached
hb_ft_face_create_referenced
hb_ft_face_create_from_file_or_fail
hb_ft_face_create_from_blob_or_fail
hb_ft_font_create
hb_ft_font_create_referenced
hb_ft_font_changed
hb_ft_font_get_face
hb_ft_font_get_ft_face
hb_ft_font_lock_face
hb_ft_font_unlock_face
hb_ft_font_set_load_flags
@ -549,7 +578,6 @@ hb_glib_blob_create
<FILE>hb-graphite2</FILE>
HB_GRAPHITE2_TAG_SILF
hb_graphite2_face_get_gr_face
hb_graphite2_font_get_gr_font
</SECTION>
<SECTION>
@ -927,6 +955,10 @@ hb_subset_serialize_object_t
hb_subset_serialize_or_fail
<SUBSECTION Private>
hb_subset_input_override_name_table
hb_subset_cff_get_charstring_data
hb_subset_cff_get_charstrings_index
hb_subset_cff2_get_charstring_data
hb_subset_cff2_get_charstrings_index
</SECTION>
<SECTION>

View file

@ -1,11 +1,12 @@
project('harfbuzz', 'c', 'cpp',
meson_version: '>= 0.55.0',
version: '10.3.0',
project('harfbuzz', ['c', 'cpp'],
meson_version: '>= 0.60.0',
version: '11.0.1',
default_options: [
'cpp_eh=none', # Just to support msvc, we are passing -fno-exceptions also anyway
# 'cpp_rtti=false', # Do NOT enable, wraps inherit it and ICU needs RTTI
'cpp_std=c++11',
'wrap_mode=nofallback', # Use --wrap-mode=default to revert, https://github.com/harfbuzz/harfbuzz/pull/2548
'buildtype=debugoptimized',
],
)
@ -102,44 +103,36 @@ check_funcs = [
m_dep = cpp.find_library('m', required: false)
if meson.version().version_compare('>=0.60.0')
# Painful hack to handle multiple dependencies but also respect options
if get_option('freetype').disabled()
freetype_dep = dependency('', required: false)
else
# Sadly, FreeType's versioning schemes are different between pkg-config and CMake
# pkg-config: freetype2, cmake: Freetype
# Try pkg-config name
freetype_dep = dependency('freetype2',
version: freetype_min_version,
method: 'pkg-config',
required: false,
allow_fallback: false)
if not freetype_dep.found()
freetype_dep = dependency('FreeType',
# Try cmake name
freetype_dep = dependency('Freetype',
version: freetype_min_version_actual,
method: 'cmake',
required: get_option('freetype'),
default_options: ['harfbuzz=disabled'],
allow_fallback: true)
endif
else
# painful hack to handle multiple dependencies but also respect options
freetype_opt = get_option('freetype')
# we want to handle enabled manually after fallbacks, but also handle disabled normally
if freetype_opt.enabled()
freetype_opt = false
endif
# try pkg-config name
freetype_dep = dependency('freetype2', version: freetype_min_version, method: 'pkg-config', required: freetype_opt)
# when disabled, leave it not-found
if not freetype_dep.found() and not get_option('freetype').disabled()
# Try cmake name
freetype_dep = dependency('Freetype', version: freetype_min_version_actual, method: 'cmake', required: false)
# Subproject fallback, `allow_fallback: true` means the fallback will be
# tried even if the freetype option is set to `auto`.
required: false,
allow_fallback: false)
# Subproject fallback
if not freetype_dep.found()
freetype_dep = dependency('freetype2',
version: freetype_min_version,
method: 'pkg-config',
freetype_proj = subproject('freetype2',
version: freetype_min_version_actual,
required: get_option('freetype'),
default_options: ['harfbuzz=disabled'],
allow_fallback: true)
default_options: ['harfbuzz=disabled'])
if freetype_proj.found()
freetype_dep = freetype_proj.get_variable('freetype_dep')
else
freetype_dep = dependency('', required: false)
endif
endif
endif
endif
@ -152,38 +145,12 @@ wasm_dep = cpp.find_library('iwasm', required: get_option('wasm'))
# How to check whether iwasm was built, and hence requires, LLVM?
#llvm_dep = cpp.find_library('LLVM-15', required: get_option('wasm'))
if meson.version().version_compare('>=0.60.0')
# pkg-config: icu-uc, cmake: ICU but with components
icu_dep = dependency('icu-uc', 'ICU',
version: icu_min_version,
components: 'uc',
required: get_option('icu'),
allow_fallback: true)
else
# painful hack to handle multiple dependencies but also respect options
icu_opt = get_option('icu')
# we want to handle enabled manually after fallbacks, but also handle disabled normally
if icu_opt.enabled()
icu_opt = false
endif
# try pkg-config name
icu_dep = dependency('icu-uc', version: icu_min_version, method: 'pkg-config', required: icu_opt)
# when disabled, leave it not-found
if not icu_dep.found() and not get_option('icu').disabled()
# Try cmake name
icu_dep = dependency('ICU', version: icu_min_version, method: 'cmake', components: 'uc', required: false)
# Try again with subproject fallback. `allow_fallback: true` means the
# fallback will be tried even if the icu option is set to `auto`, but
# we cannot pass this option until Meson 0.59.0, because no wrap file
# is checked into git.
if not icu_dep.found()
icu_dep = dependency('icu-uc',
version: icu_min_version,
method: 'pkg-config',
required: get_option('icu'))
endif
endif
endif
# pkg-config: icu-uc, cmake: ICU but with components
icu_dep = dependency('icu-uc', 'ICU',
version: icu_min_version,
components: 'uc',
required: get_option('icu'),
allow_fallback: true)
if icu_dep.found() and icu_dep.version().version_compare('>=75.1') and (get_option('cpp_std') == 'c++11' or get_option('cpp_std') == 'c++14')
cpp17_arg = cpp.get_argument_syntax() == 'msvc' ? '/std:c++17' : '-std=c++17'
@ -227,16 +194,18 @@ endif
chafa_dep = dependency('chafa', version: chafa_min_version, required: get_option('chafa'))
fontations_dep_found = false
if get_option('fontations').enabled()
add_languages(['rust'], native: false, required : true)
fontations_dep_found = true
endif
conf = configuration_data()
incconfig = include_directories('.')
add_project_arguments('-DHAVE_CONFIG_H', language: ['c', 'cpp'])
warn_cflags = [
'-Wno-non-virtual-dtor',
]
cpp_args = cpp.get_supported_arguments(warn_cflags)
cpp_args = []
if glib_dep.found()
conf.set('HAVE_GLIB', 1)
@ -272,6 +241,10 @@ if chafa_dep.found()
conf.set('HAVE_CHAFA', 1)
endif
if fontations_dep_found
conf.set('HAVE_FONTATIONS', 1)
endif
if wasm_dep.found()
conf.set('HAVE_WASM', 1)
conf.set('HB_WASM_MODULE_DIR', '"'+get_option('prefix')+'/'+get_option('libdir')+'/harfbuzz/wasm"')
@ -315,7 +288,7 @@ endif
gdi_uniscribe_deps = []
# GDI (Uniscribe) (Windows)
if host_machine.system() == 'windows' and not get_option('gdi').disabled()
if (get_option('directwrite').enabled() and
if (get_option('gdi').enabled() and
not (cpp.has_header('usp10.h') and cpp.has_header('windows.h')))
error('GDI/Uniscribe was enabled explicitly, but required headers are missing.')
endif
@ -333,13 +306,16 @@ if host_machine.system() == 'windows' and not get_option('gdi').disabled()
endif
endif
directwrite_dep = []
# DirectWrite (Windows)
if host_machine.system() == 'windows' and not get_option('directwrite').disabled()
if get_option('directwrite').enabled() and not cpp.has_header('dwrite_1.h')
if get_option('directwrite').enabled() and not cpp.has_header('dwrite_3.h')
error('DirectWrite was enabled explicitly, but required header is missing.')
endif
conf.set('HAVE_DIRECTWRITE', 1)
directwrite_dep = cpp.find_library('dwrite', required: get_option('directwrite'))
if directwrite_dep.found()
conf.set('HAVE_DIRECTWRITE', 1)
endif
endif
# CoreText (macOS)
@ -464,12 +440,10 @@ configure_file(output: 'config.h', configuration: conf)
alias_target('lib', libharfbuzz)
alias_target('libs', libharfbuzz, libharfbuzz_subset)
if meson.version().version_compare('>=0.57.0')
# Re glib, see https://github.com/harfbuzz/harfbuzz/issues/4153#issuecomment-2646347531
add_test_setup('default',
exclude_suites: ['google-benchmark'],
is_default: glib_dep.type_name() != 'internal' and not meson.is_subproject())
endif
# Re glib, see https://github.com/harfbuzz/harfbuzz/issues/4153#issuecomment-2646347531
add_test_setup('default',
exclude_suites: ['google-benchmark'],
is_default: glib_dep.type_name() != 'internal' and not meson.is_subproject())
build_summary = {
'Directories':

View file

@ -15,10 +15,12 @@ option('graphite2', type: 'feature', value: 'disabled',
description: 'Enable Graphite2 complementary shaper')
option('freetype', type: 'feature', value: 'auto',
description: 'Enable freetype interop helpers')
option('fontations', type: 'feature', value: 'disabled',
description: 'Enabled fontations font functions')
option('gdi', type: 'feature', value: 'disabled',
description: 'Enable GDI helpers and Uniscribe shaper backend (Windows only)')
option('directwrite', type: 'feature', value: 'disabled',
description: 'Enable DirectWrite shaper backend on Windows (experimental)')
description: 'Enable DirectWrite shaper backend on Windows')
option('coretext', type: 'feature', value: 'disabled',
description: 'Enable CoreText shaper backend on macOS')
option('wasm', type: 'feature', value: 'disabled',

View file

@ -4,17 +4,21 @@ Benchmarks are implemented using [Google Benchmark](https://github.com/google/be
To build the benchmarks in this directory you need to set the benchmark
option while configuring the build with meson:
```
meson build -Dbenchmark=enabled --buildtype=release
```
or:
```
meson build -Dbenchmark=enabled --buildtype=debugoptimized
```
The default build type is `debugoptimized`, which is good enough for
benchmarking, but you can also get the fastest mode with `release`
build type:
```
meson build -Dbenchmark=enabled --buildtype=release
```
Then build a specific benchmark binaries with ninja:
You should, of course, enable features you want to benchmark, like
`-Dfreetype`, `-Dfontations`, `-Dcoretext`, etc.
Then build a specific benchmark binaries with ninja, eg.:
```
ninja -Cbuild perf/benchmark-set
```
@ -33,22 +37,47 @@ It's possible to filter the benchmarks being run and customize the output
via flags to the benchmark binary. See the
[Google Benchmark User Guide](https://github.com/google/benchmark/blob/main/docs/user_guide.md#user-guide) for more details.
The most useful benchmark is `benchmark-font`. You can provide custom fonts to it too.
For example, to run only the "paint" benchmarks, against a given font, you can do:
```
./build/perf/benchmark-font NotoColorEmoji-Regular.ttf --benchmark_filter="paint"
```
Some useful options are: `--benchmark_repetitions=5` to run the benchmark 5 times,
`--benchmark_min_time=.1s` to run the benchmark for at least .1 seconds (defaults
to .5s), and `--benchmark_filter=...` to filter the benchmarks by regular expression.
To compare before/after benchmarks, you need to save the benchmark results in files
for both runs. Use `--benchmark_out=results.json` to output the results in JSON format.
Then you can use:
```
./subprojects/benchmark-1.8.4/tools/compare.py benchmarks before.json after.json
```
Substitute your version of benchmark instead of 1.8.4.
# Profiling
Configure the build to include debug information for profiling:
If you like to disable optimizations and enable frame pointers for better profiling output,
you can do so with the following meson command:
```
CXXFLAGS="-fno-omit-frame-pointer" meson --reconfigure build -Dbenchmark=enabled --buildtype=debug
ninja -Cbuild
```
However, this will slow down the benchmarks significantly and might give you inaccurate
information as to where to optimize. It's better to profile the `debugoptimized` build (the default).
Then run the benchmark with perf:
```
perf record -g build/perf/benchmark-subset --benchmark_filter="BM_subset_codepoints/subset_notocjk/100000" --benchmark_repetitions=5
```
You probably want to filter to a specific benchmark of interest and set the number of repititions high enough to get a good sampling of profile data.
You probably want to filter to a specific benchmark of interest and set the number of
repititions high enough to get a good sampling of profile data.
Finally view the profile with:
```
perf report
```
Another useful `perf` tool is the `perf stat` command, which can give you a quick overview
of the performance of a benchmark, as well as stalled cycles, cache misses, and mispredicted branches.

View file

@ -21,8 +21,6 @@ struct test_input_t
static test_input_t *tests = default_tests;
static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
enum backend_t { HARFBUZZ, FREETYPE, CORETEXT };
enum operation_t
{
nominal_glyphs,
@ -81,7 +79,8 @@ _draw_funcs_create (void)
}
static void BM_Font (benchmark::State &state,
bool is_var, backend_t backend, operation_t operation,
bool is_var, const char * backend,
operation_t operation,
const test_input_t &test_input)
{
hb_font_t *font;
@ -100,23 +99,12 @@ static void BM_Font (benchmark::State &state,
hb_font_set_variations (font, &wght, 1);
}
switch (backend)
bool ret = hb_font_set_funcs_using (font, backend);
if (!ret)
{
case HARFBUZZ:
hb_ot_font_set_funcs (font);
break;
case FREETYPE:
#ifdef HAVE_FREETYPE
hb_ft_font_set_funcs (font);
#endif
break;
case CORETEXT:
#ifdef HAVE_CORETEXT
hb_coretext_font_set_funcs (font);
#endif
break;
state.SkipWithError("Backend failed to initialize for font.");
hb_font_destroy (font);
return;
}
switch (operation)
@ -204,23 +192,12 @@ static void BM_Font (benchmark::State &state,
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
switch (backend)
bool ret = hb_font_set_funcs_using (font, backend);
if (!ret)
{
case HARFBUZZ:
hb_ot_font_set_funcs (font);
break;
case FREETYPE:
#ifdef HAVE_FREETYPE
hb_ft_font_set_funcs (font);
#endif
break;
case CORETEXT:
#ifdef HAVE_CORETEXT
hb_coretext_font_set_funcs (font);
#endif
break;
state.SkipWithError("Backend failed to initialize for font.");
hb_font_destroy (font);
return;
}
hb_buffer_t *buffer = hb_buffer_create ();
@ -240,8 +217,7 @@ static void BM_Font (benchmark::State &state,
hb_font_destroy (font);
}
static void test_backend (backend_t backend,
const char *backend_name,
static void test_backend (const char *backend,
bool variable,
operation_t op,
const char *op_name,
@ -255,7 +231,7 @@ static void test_backend (backend_t backend,
strcat (name, p ? p + 1 : test_input.font_path);
strcat (name, variable ? "/var" : "");
strcat (name, "/");
strcat (name, backend_name);
strcat (name, backend);
benchmark::RegisterBenchmark (name, BM_Font, variable, backend, op, test_input)
->Unit(time_unit);
@ -265,6 +241,7 @@ static void test_operation (operation_t op,
const char *op_name,
benchmark::TimeUnit time_unit)
{
const char **supported_backends = hb_font_list_funcs ();
for (unsigned i = 0; i < num_tests; i++)
{
auto& test_input = tests[i];
@ -272,13 +249,8 @@ static void test_operation (operation_t op,
{
bool is_var = (bool) variable;
test_backend (HARFBUZZ, "hb", is_var, op, op_name, time_unit, test_input);
#ifdef HAVE_FREETYPE
test_backend (FREETYPE, "ft", is_var, op, op_name, time_unit, test_input);
#endif
#ifdef HAVE_CORETEXT
test_backend (CORETEXT, "coretext", is_var, op, op_name, time_unit, test_input);
#endif
for (const char **backend = supported_backends; *backend; backend++)
test_backend (*backend, is_var, op, op_name, time_unit, test_input);
}
}
}

View file

@ -33,6 +33,7 @@ struct test_input_t
static test_input_t *tests = default_tests;
static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
const char *variation = nullptr;
static void BM_Shape (benchmark::State &state,
const char *shaper,
@ -46,6 +47,13 @@ static void BM_Shape (benchmark::State &state,
hb_face_destroy (face);
}
if (variation)
{
hb_variation_t var;
hb_variation_from_string (variation, -1, &var);
hb_font_set_variations (font, &var, 1);
}
hb_blob_t *text_blob = hb_blob_create_from_file_or_fail (input.text_path);
assert (text_blob);
unsigned orig_text_length;
@ -99,16 +107,16 @@ int main(int argc, char** argv)
{
benchmark::Initialize(&argc, argv);
test_input_t static_test = {};
if (argc > 2)
{
num_tests = (argc - 1) / 2;
tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
for (unsigned i = 0; i < num_tests; i++)
{
tests[i].font_path = argv[1 + i * 2];
tests[i].text_path = argv[2 + i * 2];
}
static_test.font_path = argv[1];
static_test.text_path = argv[2];
tests = &static_test;
num_tests = 1;
}
if (argc > 3)
variation = argv[3];
for (unsigned i = 0; i < num_tests; i++)
{
@ -120,7 +128,4 @@ int main(int argc, char** argv)
benchmark::RunSpecifiedBenchmarks();
benchmark::Shutdown();
if (tests != default_tests)
free (tests);
}

View file

@ -36,6 +36,9 @@
#ifdef HAVE_FREETYPE
#include <hb-ft.h>
#endif
#ifdef HAVE_FONTATIONS
#include <hb-fontations.h>
#endif
#ifdef HAVE_CORETEXT
#include <hb-coretext.h>
#endif
@ -53,22 +56,7 @@ static inline hb_face_t *
hb_benchmark_face_create_from_file_or_fail (const char *font_path,
unsigned face_index)
{
const char *loader = getenv ("HB_FACE_LOADER");
if (loader && !*loader)
loader = nullptr;
#ifdef HAVE_FREETYPE
if (loader && !strcmp (loader, "ft"))
return hb_ft_face_create_from_file_or_fail (font_path, face_index);
#endif
#ifdef HAVE_CORETEXT
if (loader && !strcmp (loader, "coretext"))
return hb_coretext_face_create_from_file_or_fail (font_path, face_index);
#endif
if (!loader || !strcmp (loader, "ot"))
return hb_face_create_from_file_or_fail (font_path, face_index);
assert (false);
return hb_face_create_from_file_or_fail_using (font_path, face_index, nullptr);
}
HB_END_DECLS

45
perf/hb-draw-all.c Normal file
View file

@ -0,0 +1,45 @@
#include <hb.h>
#include <stdlib.h>
#include <stdio.h>
int main (int argc, char **argv)
{
if (argc < 2)
{
fprintf (stderr, "Usage: %s font-file [font-funcs] [wght]\n", argv[0]);
return 1;
}
hb_face_t *face = hb_face_create_from_file_or_fail (argv[1], 0);
if (!face)
{
fprintf (stderr, "Failed to create face\n");
return 1;
}
hb_font_t *font = hb_font_create (face);
if (argc > 2)
hb_font_set_funcs_using (font, argv[2]);
if (argc > 3)
{
hb_variation_t variations[] = {
{ HB_TAG ('w', 'g', 'h', 't'), atoi (argv[3]) },
};
hb_font_set_variations (font, variations, 1);
}
hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
unsigned glyph_count = hb_face_get_glyph_count (face);
for (unsigned gid = 0; gid < glyph_count; gid++)
hb_font_draw_glyph (font, gid, funcs, NULL);
hb_draw_funcs_destroy (funcs);
hb_font_destroy (font);
hb_face_destroy (face);
return 0;
}

45
perf/hb-paint-all.c Normal file
View file

@ -0,0 +1,45 @@
#include <hb.h>
#include <stdlib.h>
#include <stdio.h>
int main (int argc, char **argv)
{
if (argc < 2)
{
fprintf (stderr, "Usage: %s font-file [font-funcs] [wght]\n", argv[0]);
return 1;
}
hb_face_t *face = hb_face_create_from_file_or_fail (argv[1], 0);
if (!face)
{
fprintf (stderr, "Failed to create face\n");
return 1;
}
hb_font_t *font = hb_font_create (face);
if (argc > 2)
hb_font_set_funcs_using (font, argv[2]);
if (argc > 3)
{
hb_variation_t variations[] = {
{ HB_TAG ('w', 'g', 'h', 't'), atoi (argv[3]) },
};
hb_font_set_variations (font, variations, 1);
}
hb_paint_funcs_t *funcs = hb_paint_funcs_create ();
unsigned glyph_count = hb_face_get_glyph_count (face);
for (unsigned gid = 0; gid < glyph_count; gid++)
hb_font_paint_glyph (font, gid, funcs, NULL, 0, 0);
hb_paint_funcs_destroy (funcs);
hb_font_destroy (font);
hb_face_destroy (face);
return 0;
}

View file

@ -38,3 +38,17 @@ foreach source : benchmarks_subset
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
endforeach
hb_draw_all = executable('hb-draw-all', ['hb-draw-all.c'],
cpp_args: cpp_args,
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
)
meson.override_find_program('hb-draw-all', hb_draw_all)
hb_paint_all = executable('hb-paint-all', ['hb-paint-all.c'],
cpp_args: cpp_args,
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
)
meson.override_find_program('hb-paint-all', hb_paint_all)

View file

@ -941,10 +941,12 @@ struct CBDT
}
}
bool has_data () const { return cbdt.get_length (); }
bool has_data () const { return cbdt->version.major; }
bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
{
if (!has_data ()) return false;
hb_glyph_extents_t extents;
hb_glyph_extents_t pixel_extents;
hb_blob_t *blob = reference_png (font, glyph);

View file

@ -47,6 +47,11 @@ namespace OT {
struct hb_paint_context_t;
}
struct hb_colr_scratch_t
{
hb_paint_extents_context_t paint_extents;
};
namespace OT {
struct COLR;
@ -90,7 +95,8 @@ public:
font (font_),
palette (
#ifndef HB_NO_COLOR
font->face->table.CPAL->get_palette_colors (palette_)
// https://github.com/harfbuzz/harfbuzz/issues/5116
font->face->table.CPAL->get_palette_colors (palette_ < font->face->table.CPAL->get_palette_count () ? palette_ : 0)
#endif
),
foreground (foreground_),
@ -932,9 +938,9 @@ struct PaintGlyph
void paint_glyph (hb_paint_context_t *c) const
{
TRACE_PAINT (this);
c->funcs->push_inverse_root_transform (c->data, c->font);
c->funcs->push_inverse_font_transform (c->data, c->font);
c->funcs->push_clip_glyph (c->data, gid, c->font);
c->funcs->push_root_transform (c->data, c->font);
c->funcs->push_font_transform (c->data, c->font);
c->recurse (this+paint);
c->funcs->pop_transform (c->data);
c->funcs->pop_clip (c->data);
@ -1511,10 +1517,12 @@ struct PaintComposite
void paint_glyph (hb_paint_context_t *c) const
{
TRACE_PAINT (this);
c->funcs->push_group (c->data);
c->recurse (this+backdrop);
c->funcs->push_group (c->data);
c->recurse (this+src);
c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode);
c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
}
HBUINT8 format; /* format = 32 */
@ -2079,6 +2087,8 @@ struct COLR
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
bool has_data () const { return has_v0_data () || version; }
bool has_v0_data () const { return numBaseGlyphs; }
bool has_v1_data () const
{
@ -2112,7 +2122,53 @@ struct COLR
{
accelerator_t (hb_face_t *face)
{ colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
~accelerator_t () { this->colr.destroy (); }
~accelerator_t ()
{
auto *scratch = cached_scratch.get_relaxed ();
if (scratch)
{
scratch->~hb_colr_scratch_t ();
hb_free (scratch);
}
colr.destroy ();
}
bool has_data () const { return colr->has_data (); }
#ifndef HB_NO_PAINT
bool
get_extents (hb_font_t *font,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents) const
{
if (unlikely (!has_data ())) return false;
hb_colr_scratch_t *scratch = acquire_scratch ();
if (unlikely (!scratch)) return true;
bool ret = colr->get_extents (font, glyph, extents, *scratch);
release_scratch (scratch);
return ret;
}
bool paint_glyph (hb_font_t *font,
hb_codepoint_t glyph,
hb_paint_funcs_t *funcs, void *data,
unsigned int palette_index,
hb_color_t foreground,
bool clip = true) const
{
if (unlikely (!has_data ())) return false;
hb_colr_scratch_t *scratch = acquire_scratch ();
if (unlikely (!scratch)) return true;
bool ret = colr->paint_glyph (font, glyph, funcs, data, palette_index, foreground, clip, *scratch);
release_scratch (scratch);
return ret;
}
#endif
bool is_valid () { return colr.get_blob ()->length; }
@ -2148,7 +2204,33 @@ struct COLR
{ return colr->get_delta_set_index_map_ptr (); }
private:
hb_colr_scratch_t *acquire_scratch () const
{
hb_colr_scratch_t *scratch = cached_scratch.get_acquire ();
if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
{
scratch = (hb_colr_scratch_t *) hb_calloc (1, sizeof (hb_colr_scratch_t));
if (unlikely (!scratch))
return nullptr;
}
return scratch;
}
void release_scratch (hb_colr_scratch_t *scratch) const
{
if (!cached_scratch.cmpexch (nullptr, scratch))
{
scratch->~hb_colr_scratch_t ();
hb_free (scratch);
}
}
public:
hb_blob_ptr_t<COLR> colr;
private:
hb_atomic_t<hb_colr_scratch_t *> cached_scratch;
};
void closure_glyphs (hb_codepoint_t glyph,
@ -2520,7 +2602,10 @@ struct COLR
#ifndef HB_NO_PAINT
bool
get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
get_extents (hb_font_t *font,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
hb_colr_scratch_t &scratch) const
{
ItemVarStoreInstancer instancer (get_var_store_ptr (),
@ -2534,10 +2619,10 @@ struct COLR
}
auto *extents_funcs = hb_paint_extents_get_funcs ();
hb_paint_extents_context_t extents_data;
bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0));
scratch.paint_extents.clear ();
bool ret = paint_glyph (font, glyph, extents_funcs, &scratch.paint_extents, 0, HB_COLOR(0,0,0,0), true, scratch);
hb_extents_t e = extents_data.get_extents ();
auto e = scratch.paint_extents.get_extents ();
if (e.is_void ())
{
extents->x_bearing = 0;
@ -2547,6 +2632,7 @@ struct COLR
}
else
{
// Ugh. We need to undo the synthetic slant here. Leave it for now. :-(.
extents->x_bearing = e.xmin;
extents->y_bearing = e.ymax;
extents->width = e.xmax - e.xmin;
@ -2583,7 +2669,12 @@ struct COLR
#ifndef HB_NO_PAINT
bool
paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
paint_glyph (hb_font_t *font,
hb_codepoint_t glyph,
hb_paint_funcs_t *funcs, void *data,
unsigned int palette_index, hb_color_t foreground,
bool clip,
hb_colr_scratch_t &scratch) const
{
ItemVarStoreInstancer instancer (get_var_store_ptr (),
get_delta_set_index_map_ptr (),
@ -2609,6 +2700,7 @@ struct COLR
if (get_clip (glyph, &extents, instancer))
{
font->scale_glyph_extents (&extents);
font->synthetic_glyph_extents (&extents);
c.funcs->push_clip_rectangle (c.data,
extents.x_bearing,
extents.y_bearing + extents.height,
@ -2618,15 +2710,16 @@ struct COLR
else
{
auto *extents_funcs = hb_paint_extents_get_funcs ();
hb_paint_extents_context_t extents_data;
scratch.paint_extents.clear ();
paint_glyph (font, glyph,
extents_funcs, &extents_data,
extents_funcs, &scratch.paint_extents,
palette_index, foreground,
false);
false,
scratch);
hb_extents_t extents = extents_data.get_extents ();
is_bounded = extents_data.is_bounded ();
auto extents = scratch.paint_extents.get_extents ();
is_bounded = scratch.paint_extents.is_bounded ();
c.funcs->push_clip_rectangle (c.data,
extents.xmin,
@ -2636,7 +2729,7 @@ struct COLR
}
}
c.funcs->push_root_transform (c.data, font);
c.funcs->push_font_transform (c.data, font);
if (is_bounded)
c.recurse (*paint);
@ -2714,9 +2807,7 @@ void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
return;
const Paint &paint = paint_offset_lists.get_paint (i);
c->funcs->push_group (c->data);
c->recurse (paint);
c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
}
}
@ -2728,7 +2819,7 @@ void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
if (unlikely (!node.visit (gid)))
return;
c->funcs->push_inverse_root_transform (c->data, c->font);
c->funcs->push_inverse_font_transform (c->data, c->font);
if (c->funcs->color_glyph (c->data, gid, c->font))
{
c->funcs->pop_transform (c->data);

View file

@ -77,7 +77,7 @@ struct CoverageFormat1_3
bool intersects (const hb_set_t *glyphs) const
{
if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2)
if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len))
{
for (auto g : *glyphs)
if (get_coverage (g) != NOT_COVERED)

View file

@ -120,7 +120,7 @@ struct CoverageFormat2_4
bool intersects (const hb_set_t *glyphs) const
{
if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len))
{
for (auto g : *glyphs)
if (get_coverage (g) != NOT_COVERED)

View file

@ -205,20 +205,19 @@ struct CaretValueFormat3
unsigned varidx = (this+deviceTable).get_variation_index ();
hb_pair_t<unsigned, int> *new_varidx_delta;
if (!c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta))
return_trace (false);
if (c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta)) {
uint32_t new_varidx = hb_first (*new_varidx_delta);
int delta = hb_second (*new_varidx_delta);
if (delta != 0)
{
if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
}
uint32_t new_varidx = hb_first (*new_varidx_delta);
int delta = hb_second (*new_varidx_delta);
if (delta != 0)
{
if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
if (!c->serializer->embed (deviceTable))
return_trace (false);
@ -1015,7 +1014,8 @@ struct GDEF
hb_blob_ptr_t<GDEF> table;
#ifndef HB_NO_GDEF_CACHE
hb_vector_t<hb_set_digest_t> mark_glyph_set_digests;
mutable hb_cache_t<21, 3, 8> glyph_props_cache;
mutable hb_cache_t<21, 3> glyph_props_cache;
static_assert (sizeof (glyph_props_cache) == 512, "");
#endif
};

View file

@ -54,7 +54,7 @@ struct PairPosFormat1_3
{
auto &cov = this+coverage;
if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4)
if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len))
{
for (hb_codepoint_t g : glyphs->iter())
{

View file

@ -126,25 +126,19 @@ hb_transforming_pen_get_funcs ()
return static_transforming_pen_funcs.get_unconst ();
}
hb_ubytes_t
VarComponent::get_path_at (hb_font_t *font,
VarComponent::get_path_at (const hb_varc_context_t &c,
hb_codepoint_t parent_gid,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_transform_t total_transform,
hb_ubytes_t total_record,
hb_decycler_t *decycler,
signed *edges_left,
signed depth_left,
VarRegionList::cache_t *cache) const
{
const unsigned char *end = total_record.arrayZ + total_record.length;
const unsigned char *record = total_record.arrayZ;
auto &VARC = *font->face->table.VARC;
auto &VARC = *c.font->face->table.VARC->table;
auto &varStore = &VARC+VARC.varStore;
auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache);
#define READ_UINT32VAR(name) \
HB_STMT_START { \
@ -187,22 +181,25 @@ VarComponent::get_path_at (hb_font_t *font,
unsigned conditionIndex;
READ_UINT32VAR (conditionIndex);
const auto &condition = (&VARC+VARC.conditionList)[conditionIndex];
auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache);
show = condition.evaluate (coords.arrayZ, coords.length, &instancer);
}
// Axis values
hb_vector_t<unsigned> axisIndices;
hb_vector_t<float> axisValues;
auto &axisIndices = c.scratch.axisIndices;
axisIndices.clear ();
auto &axisValues = c.scratch.axisValues;
axisValues.clear ();
if (flags & (unsigned) flags_t::HAVE_AXES)
{
unsigned axisIndicesIndex;
READ_UINT32VAR (axisIndicesIndex);
axisIndices = (&VARC+VARC.axisIndicesList)[axisIndicesIndex];
axisIndices.extend ((&VARC+VARC.axisIndicesList)[axisIndicesIndex]);
axisValues.resize (axisIndices.length);
const HBUINT8 *p = (const HBUINT8 *) record;
TupleValues::decompile (p, axisValues, (const HBUINT8 *) end);
record += (const unsigned char *) p - record;
record = (const unsigned char *) p;
}
// Apply variations if any
@ -219,7 +216,7 @@ VarComponent::get_path_at (hb_font_t *font,
* limit on the max number of coords for now. */
if ((flags & (unsigned) flags_t::RESET_UNSPECIFIED_AXES) ||
coords.length > HB_VAR_COMPOSITE_MAX_AXES)
component_coords = hb_array<int> (font->coords, font->num_coords);
component_coords = hb_array<int> (c.font->coords, c.font->num_coords);
// Transform
@ -313,13 +310,18 @@ VarComponent::get_path_at (hb_font_t *font,
transform.scaleY = transform.scaleX;
total_transform.transform (transform.to_transform ());
total_transform.scale (font->x_mult ? 1.f / font->x_multf : 0.f,
font->y_mult ? 1.f / font->y_multf : 0.f);
total_transform.scale (c.font->x_mult ? 1.f / c.font->x_multf : 0.f,
c.font->y_mult ? 1.f / c.font->y_multf : 0.f);
VARC.get_path_at (font, gid,
draw_session, component_coords, total_transform,
bool same_coords = component_coords.length == coords.length &&
component_coords.arrayZ == coords.arrayZ;
c.depth_left--;
VARC.get_path_at (c, gid,
component_coords, total_transform,
parent_gid,
decycler, edges_left, depth_left - 1);
same_coords ? cache : nullptr);
c.depth_left++;
}
#undef PROCESS_TRANSFORM_COMPONENTS
@ -329,15 +331,12 @@ VarComponent::get_path_at (hb_font_t *font,
}
bool
VARC::get_path_at (hb_font_t *font,
VARC::get_path_at (const hb_varc_context_t &c,
hb_codepoint_t glyph,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_transform_t transform,
hb_codepoint_t parent_glyph,
hb_decycler_t *decycler,
signed *edges_left,
signed depth_left) const
VarRegionList::cache_t *parent_cache) const
{
// Don't recurse on the same glyph.
unsigned idx = glyph == parent_glyph ?
@ -345,50 +344,69 @@ VARC::get_path_at (hb_font_t *font,
(this+coverage).get_coverage (glyph);
if (idx == NOT_COVERED)
{
// Build a transforming pen to apply the transform.
hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs ();
hb_transforming_pen_context_t context {transform,
draw_session.funcs,
draw_session.draw_data,
&draw_session.st};
hb_draw_session_t transformer_session {transformer_funcs, &context};
hb_draw_session_t &shape_draw_session = transform.is_identity () ? draw_session : transformer_session;
if (c.draw_session)
{
// Build a transforming pen to apply the transform.
hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs ();
hb_transforming_pen_context_t context {transform,
c.draw_session->funcs,
c.draw_session->draw_data,
&c.draw_session->st};
hb_draw_session_t transformer_session {transformer_funcs, &context};
hb_draw_session_t &shape_draw_session = transform.is_identity () ? *c.draw_session : transformer_session;
if (!font->face->table.glyf->get_path_at (font, glyph, shape_draw_session, coords))
if (!c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch))
#ifndef HB_NO_CFF
if (!font->face->table.cff2->get_path_at (font, glyph, shape_draw_session, coords))
if (!font->face->table.cff1->get_path (font, glyph, shape_draw_session)) // Doesn't have variations
if (!c.font->face->table.cff2->get_path_at (c.font, glyph, shape_draw_session, coords))
if (!c.font->face->table.cff1->get_path (c.font, glyph, shape_draw_session)) // Doesn't have variations
#endif
return false;
return false;
}
else if (c.extents)
{
hb_glyph_extents_t glyph_extents;
if (!c.font->face->table.glyf->get_extents_at (c.font, glyph, &glyph_extents, coords))
#ifndef HB_NO_CFF
if (!c.font->face->table.cff2->get_extents_at (c.font, glyph, &glyph_extents, coords))
if (!c.font->face->table.cff1->get_extents (c.font, glyph, &glyph_extents)) // Doesn't have variations
#endif
return false;
hb_extents_t comp_extents (glyph_extents);
transform.transform_extents (comp_extents);
c.extents->union_ (comp_extents);
}
return true;
}
if (depth_left <= 0)
if (c.depth_left <= 0)
return true;
if (*edges_left <= 0)
if (c.edges_left <= 0)
return true;
(*edges_left)--;
(c.edges_left)--;
hb_decycler_node_t node (*decycler);
hb_decycler_node_t node (c.decycler);
if (unlikely (!node.visit (glyph)))
return true;
hb_ubytes_t record = (this+glyphRecords)[idx];
VarRegionList::cache_t *cache = record.length >= 64 ? // Heuristic
(this+varStore).create_cache ()
: nullptr;
VarRegionList::cache_t static_cache[sizeof (void *) * 16];
VarRegionList::cache_t *cache = parent_cache ?
parent_cache :
(this+varStore).create_cache (hb_array (static_cache));
transform.scale (font->x_multf, font->y_multf);
transform.scale (c.font->x_multf, c.font->y_multf);
VarCompositeGlyph::get_path_at (font, glyph,
draw_session, coords, transform,
VarCompositeGlyph::get_path_at (c,
glyph,
coords, transform,
record,
decycler, edges_left, depth_left,
cache);
(this+varStore).destroy_cache (cache);
if (cache != parent_cache)
(this+varStore).destroy_cache (cache, hb_array (static_cache));
return true;
}

View file

@ -21,6 +21,24 @@ namespace OT {
#ifndef HB_NO_VAR_COMPOSITES
struct hb_varc_scratch_t
{
hb_vector_t<unsigned> axisIndices;
hb_vector_t<float> axisValues;
hb_glyf_scratch_t glyf_scratch;
};
struct hb_varc_context_t
{
hb_font_t *font;
hb_draw_session_t *draw_session;
hb_extents_t *extents;
mutable hb_decycler_t decycler;
mutable signed edges_left;
mutable signed depth_left;
hb_varc_scratch_t &scratch;
};
struct VarComponent
{
enum class flags_t : uint32_t
@ -44,39 +62,32 @@ struct VarComponent
};
HB_INTERNAL hb_ubytes_t
get_path_at (hb_font_t *font,
get_path_at (const hb_varc_context_t &c,
hb_codepoint_t parent_gid,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_transform_t transform,
hb_ubytes_t record,
hb_decycler_t *decycler,
signed *edges_left,
signed depth_left,
VarRegionList::cache_t *cache = nullptr) const;
};
struct VarCompositeGlyph
{
static void
get_path_at (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_session_t &draw_session,
get_path_at (const hb_varc_context_t &c,
hb_codepoint_t gid,
hb_array_t<const int> coords,
hb_transform_t transform,
hb_ubytes_t record,
hb_decycler_t *decycler,
signed *edges_left,
signed depth_left,
VarRegionList::cache_t *cache = nullptr)
VarRegionList::cache_t *cache)
{
while (record)
{
const VarComponent &comp = * (const VarComponent *) (record.arrayZ);
record = comp.get_path_at (font, glyph,
draw_session, coords, transform,
record = comp.get_path_at (c,
gid,
coords, transform,
record,
decycler, edges_left, depth_left, cache);
cache);
}
}
};
@ -90,31 +101,48 @@ struct VARC
static constexpr hb_tag_t tableTag = HB_TAG ('V', 'A', 'R', 'C');
HB_INTERNAL bool
get_path_at (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_session_t &draw_session,
get_path_at (const hb_varc_context_t &c,
hb_codepoint_t gid,
hb_array_t<const int> coords,
hb_transform_t transform,
hb_codepoint_t parent_glyph,
hb_decycler_t *decycler,
signed *edges_left,
signed depth_left) const;
hb_transform_t transform = HB_TRANSFORM_IDENTITY,
hb_codepoint_t parent_gid = HB_CODEPOINT_INVALID,
VarRegionList::cache_t *parent_cache = nullptr) const;
bool
get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
get_path (hb_font_t *font,
hb_codepoint_t gid,
hb_draw_session_t &draw_session,
hb_varc_scratch_t &scratch) const
{
hb_decycler_t decycler;
signed edges = HB_MAX_GRAPH_EDGE_COUNT;
hb_varc_context_t c {font,
&draw_session,
nullptr,
hb_decycler_t {},
HB_MAX_GRAPH_EDGE_COUNT,
HB_MAX_NESTING_LEVEL,
scratch};
return get_path_at (font,
gid,
draw_session,
hb_array (font->coords, font->num_coords),
HB_TRANSFORM_IDENTITY,
HB_CODEPOINT_INVALID,
&decycler,
&edges,
HB_MAX_NESTING_LEVEL); }
return get_path_at (c, gid,
hb_array (font->coords, font->num_coords));
}
bool
get_extents (hb_font_t *font,
hb_codepoint_t gid,
hb_extents_t *extents,
hb_varc_scratch_t &scratch) const
{
hb_varc_context_t c {font,
nullptr,
extents,
hb_decycler_t {},
HB_MAX_GRAPH_EDGE_COUNT,
HB_MAX_NESTING_LEVEL,
scratch};
return get_path_at (c, gid,
hb_array (font->coords, font->num_coords));
}
bool sanitize (hb_sanitize_context_t *c) const
{
@ -129,6 +157,89 @@ struct VARC
glyphRecords.sanitize (c, this));
}
struct accelerator_t
{
friend struct VarComponent;
accelerator_t (hb_face_t *face)
{
table = hb_sanitize_context_t ().reference_table<VARC> (face);
}
~accelerator_t ()
{
auto *scratch = cached_scratch.get_relaxed ();
if (scratch)
{
scratch->~hb_varc_scratch_t ();
hb_free (scratch);
}
table.destroy ();
}
bool
get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
{
if (!table->has_data ()) return false;
auto *scratch = acquire_scratch ();
if (unlikely (!scratch)) return true;
bool ret = table->get_path (font, gid, draw_session, *scratch);
release_scratch (scratch);
return ret;
}
bool
get_extents (hb_font_t *font,
hb_codepoint_t gid,
hb_glyph_extents_t *extents) const
{
if (!table->has_data ()) return false;
hb_extents_t f_extents;
auto *scratch = acquire_scratch ();
if (unlikely (!scratch)) return true;
bool ret = table->get_extents (font, gid, &f_extents, *scratch);
release_scratch (scratch);
if (ret)
*extents = f_extents.to_glyph_extents (font->x_scale < 0, font->y_scale < 0);
return ret;
}
private:
hb_varc_scratch_t *acquire_scratch () const
{
hb_varc_scratch_t *scratch = cached_scratch.get_acquire ();
if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
{
scratch = (hb_varc_scratch_t *) hb_calloc (1, sizeof (hb_varc_scratch_t));
if (unlikely (!scratch))
return nullptr;
}
return scratch;
}
void release_scratch (hb_varc_scratch_t *scratch) const
{
if (!cached_scratch.cmpexch (nullptr, scratch))
{
scratch->~hb_varc_scratch_t ();
hb_free (scratch);
}
}
private:
hb_blob_ptr_t<VARC> table;
hb_atomic_t<hb_varc_scratch_t *> cached_scratch;
};
bool has_data () const { return version.major != 0; }
protected:
FixedVersion<> version; /* Version identifier */
Offset32To<Coverage> coverage;
@ -140,6 +251,10 @@ struct VARC
DEFINE_SIZE_STATIC (24);
};
struct VARC_accelerator_t : VARC::accelerator_t {
VARC_accelerator_t (hb_face_t *face) : VARC::accelerator_t (face) {}
};
#endif
//}

View file

@ -11,22 +11,48 @@ namespace OT {
struct coord_setter_t
{
coord_setter_t (hb_array_t<const int> coords) :
coords (coords) {}
coord_setter_t (hb_array_t<const int> coords_)
{
length = coords_.length;
if (length <= ARRAY_LENGTH (static_coords))
hb_memcpy (static_coords, coords_.arrayZ, length * sizeof (int));
else
dynamic_coords.extend (coords_);
}
int& operator [] (unsigned idx)
{
if (unlikely (idx >= HB_VAR_COMPOSITE_MAX_AXES))
return Crap(int);
if (coords.length < idx + 1)
coords.resize (idx + 1);
return coords[idx];
if (length <= ARRAY_LENGTH (static_coords))
{
if (idx < ARRAY_LENGTH (static_coords))
{
while (length <= idx)
static_coords[length++] = 0;
return static_coords[idx];
}
else
dynamic_coords.extend (hb_array (static_coords, length));
}
if (dynamic_coords.length <= idx)
{
if (unlikely (!dynamic_coords.resize (idx + 1)))
return Crap(int);
length = idx + 1;
}
return dynamic_coords.arrayZ[idx];
}
hb_array_t<int> get_coords ()
{ return coords.as_array (); }
{ return length <= ARRAY_LENGTH (static_coords) ? hb_array (static_coords, length) : dynamic_coords.as_array (); }
hb_vector_t<int> coords;
private:
hb_vector_t<int> dynamic_coords;
unsigned length;
int static_coords[sizeof (void *) * 8];
};

View file

@ -143,7 +143,7 @@ struct CompositeGlyphRecord
float matrix[4];
contour_point_t trans;
get_transformation (matrix, trans);
if (unlikely (!points.alloc (points.length + 4))) return false; // For phantom points
if (unlikely (!points.alloc (points.length + 1 + 4))) return false; // For phantom points
points.push (trans);
return true;
}

View file

@ -251,7 +251,8 @@ struct Glyph
composite_contours_p = nullptr;
}
if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
hb_glyf_scratch_t scratch;
if (!get_points (font, glyf, all_points, scratch, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
return false;
// .notdef, set type to empty so we only update metrics and don't compile bytes for
@ -305,6 +306,7 @@ struct Glyph
template <typename accelerator_t>
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
contour_point_vector_t &all_points /* OUT */,
hb_glyf_scratch_t &scratch,
contour_point_vector_t *points_with_deltas = nullptr, /* OUT */
head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
unsigned *composite_contours = nullptr, /* OUT */
@ -312,7 +314,6 @@ struct Glyph
bool use_my_metrics = true,
bool phantom_only = false,
hb_array_t<const int> coords = hb_array_t<const int> (),
hb_map_t *current_glyphs = nullptr,
unsigned int depth = 0,
unsigned *edge_count = nullptr) const
{
@ -322,10 +323,6 @@ struct Glyph
if (unlikely (*edge_count > HB_MAX_GRAPH_EDGE_COUNT)) return false;
(*edge_count)++;
hb_map_t current_glyphs_stack;
if (current_glyphs == nullptr)
current_glyphs = &current_glyphs_stack;
if (head_maxp_info)
{
head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
@ -334,8 +331,7 @@ struct Glyph
if (!coords)
coords = hb_array (font->coords, font->num_coords);
contour_point_vector_t stack_points;
contour_point_vector_t &points = type == SIMPLE ? all_points : stack_points;
contour_point_vector_t &points = type == SIMPLE ? all_points : scratch.comp_points;
unsigned old_length = points.length;
switch (type) {
@ -388,36 +384,53 @@ struct Glyph
#ifndef HB_NO_VAR
if (coords)
glyf_accelerator.gvar->apply_deltas_to_points (gid,
coords,
points.as_array ().sub_array (old_length),
phantom_only && type == SIMPLE);
{
#ifndef HB_NO_BEYOND_64K
if (glyf_accelerator.GVAR->has_data ())
glyf_accelerator.GVAR->apply_deltas_to_points (gid,
coords,
points.as_array ().sub_array (old_length),
scratch,
phantom_only && type == SIMPLE);
else
#endif
glyf_accelerator.gvar->apply_deltas_to_points (gid,
coords,
points.as_array ().sub_array (old_length),
scratch,
phantom_only && type == SIMPLE);
}
#endif
// mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
// with child glyphs' points
if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE)
{
if (unlikely (!points_with_deltas->resize (points.length))) return false;
assert (old_length == 0);
*points_with_deltas = points;
}
float shift = 0;
switch (type) {
case SIMPLE:
if (depth == 0 && head_maxp_info)
head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4);
shift = phantoms[PHANTOM_LEFT].x;
break;
case COMPOSITE:
{
hb_decycler_node_t decycler_node (scratch.decycler);
unsigned int comp_index = 0;
for (auto &item : get_composite_iterator ())
{
hb_codepoint_t item_gid = item.get_gid ();
if (unlikely (current_glyphs->has (item_gid)))
if (unlikely (!decycler_node.visit (item_gid)))
{
comp_index++;
continue;
current_glyphs->add (item_gid);
}
unsigned old_count = all_points.length;
@ -426,6 +439,7 @@ struct Glyph
.get_points (font,
glyf_accelerator,
all_points,
scratch,
points_with_deltas,
head_maxp_info,
composite_contours,
@ -433,14 +447,16 @@ struct Glyph
use_my_metrics,
phantom_only,
coords,
current_glyphs,
depth + 1,
edge_count)))
{
current_glyphs->del (item_gid);
points.resize (old_length);
return false;
}
// points might have been reallocated. Relocate phantoms.
phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
auto comp_points = all_points.as_array ().sub_array (old_count);
/* Copy phantom points from component if USE_MY_METRICS flag set */
@ -455,7 +471,7 @@ struct Glyph
item.get_transformation (matrix, default_trans);
/* Apply component transformation & translation (with deltas applied) */
item.transform_points (comp_points, matrix, points[comp_index]);
item.transform_points (comp_points, matrix, points[old_length + comp_index]);
}
if (item.is_anchored () && !phantom_only)
@ -476,12 +492,11 @@ struct Glyph
if (all_points.length > HB_GLYF_MAX_POINTS)
{
current_glyphs->del (item_gid);
points.resize (old_length);
return false;
}
comp_index++;
current_glyphs->del (item_gid);
}
if (head_maxp_info && depth == 0)
@ -492,9 +507,13 @@ struct Glyph
head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index);
}
all_points.extend (phantoms);
shift = phantoms[PHANTOM_LEFT].x;
points.resize (old_length);
} break;
case EMPTY:
all_points.extend (phantoms);
shift = phantoms[PHANTOM_LEFT].x;
points.resize (old_length);
break;
}
@ -503,10 +522,9 @@ struct Glyph
/* Undocumented rasterizer behavior:
* Shift points horizontally by the updated left side bearing
*/
float v = -phantoms[PHANTOM_LEFT].x;
if (v)
if (shift)
for (auto &point : all_points)
point.x += v;
point.x -= shift;
}
return !all_points.in_error ();

View file

@ -127,19 +127,20 @@ struct SimpleGlyph
hb_array_t<contour_point_t> points_ /* IN/OUT */,
const HBUINT8 *end)
{
auto *points = points_.arrayZ;
unsigned count = points_.length;
for (unsigned int i = 0; i < count;)
{
if (unlikely (p + 1 > end)) return false;
uint8_t flag = *p++;
points_.arrayZ[i++].flag = flag;
points[i++].flag = flag;
if (flag & FLAG_REPEAT)
{
if (unlikely (p + 1 > end)) return false;
unsigned int repeat_count = *p++;
unsigned stop = hb_min (i + repeat_count, count);
for (; i < stop; i++)
points_.arrayZ[i].flag = flag;
points[i].flag = flag;
}
}
return true;
@ -160,10 +161,7 @@ struct SimpleGlyph
if (flag & short_flag)
{
if (unlikely (p + 1 > end)) return false;
if (flag & same_flag)
v += *p++;
else
v -= *p++;
v += (bool(flag & same_flag) * 2 - 1) * *p++;
}
else
{
@ -190,7 +188,7 @@ struct SimpleGlyph
unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
unsigned old_length = points.length;
points.alloc_exact (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy
points.alloc (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy
if (unlikely (!points.resize (points.length + num_points, false))) return false;
auto points_ = points.as_array ().sub_array (old_length);
if (!phantom_only)

View file

@ -172,6 +172,9 @@ struct glyf_accelerator_t
glyf_table = nullptr;
#ifndef HB_NO_VAR
gvar = nullptr;
#ifndef HB_NO_BEYOND_64K
GVAR = nullptr;
#endif
#endif
hmtx = nullptr;
#ifndef HB_NO_VERTICAL
@ -187,6 +190,9 @@ struct glyf_accelerator_t
glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
#ifndef HB_NO_VAR
gvar = face->table.gvar;
#ifndef HB_NO_BEYOND_64K
GVAR = face->table.GVAR;
#endif
#endif
hmtx = face->table.hmtx;
#ifndef HB_NO_VERTICAL
@ -198,6 +204,13 @@ struct glyf_accelerator_t
}
~glyf_accelerator_t ()
{
auto *scratch = cached_scratch.get_relaxed ();
if (scratch)
{
scratch->~hb_glyf_scratch_t ();
hb_free (scratch);
}
glyf_table.destroy ();
}
@ -206,21 +219,16 @@ struct glyf_accelerator_t
protected:
template<typename T>
bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer,
hb_array_t<const int> coords = hb_array_t<const int> ()) const
hb_array_t<const int> coords,
hb_glyf_scratch_t &scratch) const
{
if (!coords)
coords = hb_array (font->coords, font->num_coords);
if (gid >= num_glyphs) return false;
/* Making this allocfree is not that easy
https://github.com/harfbuzz/harfbuzz/issues/2095
mostly because of gvar handling in VF fonts,
perhaps a separate path for non-VF fonts can be considered */
contour_point_vector_t all_points;
auto &all_points = scratch.all_points;
all_points.resize (0);
bool phantom_only = !consumer.is_consuming_contour_points ();
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only, coords)))
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords)))
return false;
unsigned count = all_points.length;
@ -372,7 +380,12 @@ struct glyf_accelerator_t
contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
if (font->num_coords)
success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false));
{
hb_glyf_scratch_t scratch;
success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false),
hb_array (font->coords, font->num_coords),
scratch);
}
if (unlikely (!success))
return
@ -392,9 +405,11 @@ struct glyf_accelerator_t
if (unlikely (gid >= num_glyphs)) return false;
hb_glyph_extents_t extents;
hb_glyf_scratch_t scratch;
contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms, false))))
if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms, false),
hb_array (font->coords, font->num_coords),
scratch)))
return false;
*lsb = is_vertical
@ -414,13 +429,29 @@ struct glyf_accelerator_t
}
public:
bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
bool get_extents (hb_font_t *font,
hb_codepoint_t gid,
hb_glyph_extents_t *extents) const
{ return get_extents_at (font, gid, extents, hb_array (font->coords, font->num_coords)); }
bool get_extents_at (hb_font_t *font,
hb_codepoint_t gid,
hb_glyph_extents_t *extents,
hb_array_t<const int> coords) const
{
if (unlikely (gid >= num_glyphs)) return false;
#ifndef HB_NO_VAR
if (font->num_coords)
return get_points (font, gid, points_aggregator_t (font, extents, nullptr, true));
if (coords)
{
hb_glyf_scratch_t scratch;
return get_points (font,
gid,
points_aggregator_t (font, extents, nullptr, true),
coords,
scratch);
}
#endif
return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents);
}
@ -455,15 +486,52 @@ struct glyf_accelerator_t
bool
get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
{ return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session)); }
{
if (!has_data ()) return false;
hb_glyf_scratch_t *scratch;
// Borrow the cached strach buffer.
{
scratch = cached_scratch.get_acquire ();
if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
{
scratch = (hb_glyf_scratch_t *) hb_calloc (1, sizeof (hb_glyf_scratch_t));
if (unlikely (!scratch))
return true;
}
}
bool ret = get_points (font, gid, glyf_impl::path_builder_t (font, draw_session),
hb_array (font->coords, font->num_coords),
*scratch);
// Put it back.
if (!cached_scratch.cmpexch (nullptr, scratch))
{
scratch->~hb_glyf_scratch_t ();
hb_free (scratch);
}
return ret;
}
bool
get_path_at (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session,
hb_array_t<const int> coords) const
{ return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), coords); }
hb_array_t<const int> coords,
hb_glyf_scratch_t &scratch) const
{
if (!has_data ()) return false;
return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session),
coords,
scratch);
}
#ifndef HB_NO_VAR
const gvar_accelerator_t *gvar;
#ifndef HB_NO_BEYOND_64K
const GVAR_accelerator_t *GVAR;
#endif
#endif
const hmtx_accelerator_t *hmtx;
#ifndef HB_NO_VERTICAL
@ -475,6 +543,7 @@ struct glyf_accelerator_t
unsigned int num_glyphs;
hb_blob_ptr_t<loca> loca_table;
hb_blob_ptr_t<glyf> glyf_table;
hb_atomic_t<hb_glyf_scratch_t *> cached_scratch;
};

View file

@ -42,7 +42,7 @@ struct path_builder_t
{
bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
#ifdef HB_NO_CUBIC_GLYF
bool is_cubic = false;
constexpr bool is_cubic = false;
#else
bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC);
#endif

2
src/addTable.py Normal file → Executable file
View file

@ -1,3 +1,5 @@
#!/usr/bin/env python3
import sys
from fontTools.ttLib import TTFont
from fontTools.ttLib.tables.DefaultTable import DefaultTable

View file

@ -22,30 +22,30 @@ if not OBJS:
stat = 0
tested = 0
for obj in OBJS:
result = subprocess.run(objdump.split () + ['-t', obj], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
result = subprocess.run(objdump.split () + ['-t'] + OBJS, 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
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')
else:
print ('objdump returned error:\n%s' % (result.stderr.decode ('utf-8')))
stat = 2
else:
tested = 1
result = result.stdout.decode ('utf-8')
result = result.stdout.decode ('utf-8')
# Checking that no object file has static initializers
for l in re.findall (r'^.*\.[cd]tors.*$', result, re.MULTILINE):
if not re.match (r'.*\b0+\b', l):
print ('Ouch, %s has static initializers/finalizers' % obj)
stat = 1
# Checking that no object file has static initializers
for l in re.findall (r'^.*\.[cd]tors.*$', result, re.MULTILINE):
if not re.match (r'.*\b0+\b', l):
print ('Ouch, library has static initializers/finalizers')
stat = 1
# Checking that no object file has lazy static C++ constructors/destructors or other such stuff
if ('__cxa_' in result) and ('__ubsan_handle' not in result):
print ('Ouch, %s has lazy static C++ constructors/destructors or other such stuff' % obj)
stat = 1
# Checking that no object file has lazy static C++ constructors/destructors or other such stuff
if ('__cxa_' in result) and ('__ubsan_handle' not in result):
print ('Ouch, library has lazy static C++ constructors/destructors or other such stuff')
stat = 1
tested += 1
sys.exit (stat if tested else 77)

View file

@ -7,18 +7,26 @@ os.environ['LC_ALL'] = 'C' # otherwise 'nm' prints in wrong order
builddir = os.getenv ('builddir', os.path.dirname (__file__))
libs = os.getenv ('libs', '.libs')
IGNORED_SYMBOLS = '|'.join(['_fini', '_init', '_fdata', '_ftext', '_fbss',
IGNORED_SYMBOLS = ['_fini', '_init', '_fdata', '_ftext', '_fbss',
'__bss_start', '__bss_start__', '__bss_end__', '_edata', '_end', '_bss_end__',
'__end__', '__gcov_.*', 'llvm_.*', 'flush_fn_list', 'writeout_fn_list', 'mangle_path',
'lprofDirMode', 'reset_fn_list'])
'lprofDirMode', 'reset_fn_list']
# Rust
IGNORED_SYMBOLS += [
'rust_eh_personality',
'_ZN3std9panicking11EMPTY_PANIC.*', # 'std::panicking::EMPTY_PANIC::.*'
'_ZN3std3sys3pal4unix4args3imp15ARGV_INIT_ARRAY.*', # 'std::sys::pal::unix::args::imp::ARGV_INIT_ARRAY::.*'
'_ZN17compiler_builtins4math4libm7generic4sqrt9RSQRT_TAB.*', # 'compiler_builtins::math::libm::generic::sqrt::RSQRT_TAB::.*'
]
IGNORED_SYMBOLS = '|'.join (IGNORED_SYMBOLS)
nm = os.getenv ('NM', shutil.which ('nm'))
if not nm:
print ('check-symbols.py: \'nm\' not found; skipping test')
sys.exit (77)
cxxfilt = shutil.which ('c++filt')
tested = False
stat = 0
@ -34,12 +42,6 @@ for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject'
for s in re.findall (r'^.+ [BCDGIRSTu] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE)
if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)]
# run again c++filt also if is available
if cxxfilt:
EXPORTED_SYMBOLS = subprocess.check_output (
[cxxfilt], input='\n'.join (EXPORTED_SYMBOLS).encode ()
).decode ('utf-8').splitlines ()
prefix = (symprefix + os.path.basename (so)).replace ('libharfbuzz', 'hb').replace ('-', '_').split ('.')[0]
print ('Checking that %s does not expose internal symbols' % so)

95
src/fontations/Cargo.lock generated Normal file
View file

@ -0,0 +1,95 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "bytemuck"
version = "1.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540"
dependencies = [
"bytemuck_derive",
]
[[package]]
name = "bytemuck_derive"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "font-types"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d868ec188a98bb014c606072edd47e52e7ab7297db943b0b28503121e1d037bd"
dependencies = [
"bytemuck",
]
[[package]]
name = "harfbuzz_fontations"
version = "0.0.0"
dependencies = [
"read-fonts",
"skrifa",
]
[[package]]
name = "proc-macro2"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801"
dependencies = [
"proc-macro2",
]
[[package]]
name = "read-fonts"
version = "0.27.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f14974c88fb4fd0a7203719f98020209248c9dbebaf9d10d860337797a905097"
dependencies = [
"bytemuck",
"font-types",
]
[[package]]
name = "skrifa"
version = "0.29.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c0ca53de9bb9bee1720c727606275148463cd938eb6bde249dcedeec4967747"
dependencies = [
"bytemuck",
"read-fonts",
]
[[package]]
name = "syn"
version = "2.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"

28
src/fontations/Cargo.toml Normal file
View file

@ -0,0 +1,28 @@
[package]
name = "harfbuzz_fontations"
edition = "2021"
[dependencies]
read-fonts = "0.27"
skrifa = "0.29.2"
[lib]
name = "harfbuzz_fontations"
path = "lib.rs"
crate-type = ["staticlib"]
[profile.release]
strip = true
lto = "fat"
panic = "abort"
overflow-checks = false
codegen-units = 1
[profile.debugoptimized]
inherits = "release"
debug = true
codegen-units = 16
strip = false
[profile.dev]
lto = "fat"

1132
src/fontations/lib.rs Normal file

File diff suppressed because it is too large Load diff

105
src/fontations/meson.build Normal file
View file

@ -0,0 +1,105 @@
rust = import('unstable-rust')
hb_rs = rust.bindgen(
input : '../hb.h',
output : 'hb.rs',
include_directories: incsrc,
args : ['--allowlist-function=hb_.*',
'--allowlist-type=hb_.*',
'--no-copy=hb_.*',
],
)
cargo = find_program('cargo')
rustfmt = find_program('rustfmt')
rust_flags = ''
cargo_args = [
'--package', 'harfbuzz_fontations',
'--lib',
'--target-dir', meson.current_build_dir(),
'--manifest-path', meson.current_source_dir() / 'Cargo.toml',
'-Z', 'build-std=std,panic_abort',
'-Z', 'build-std-features=panic_immediate_abort',
]
buildtype = get_option('buildtype')
if buildtype == 'release' or buildtype == 'debugoptimized'
cargo_args += ['--profile', buildtype]
endif
opt_level = get_option('optimization')
rust_flags += ' -C opt-level=' + opt_level
harfbuzz_fontations = custom_target(
'harfbuzz_fontations',
input: ['lib.rs', 'Cargo.toml', 'Cargo.lock'],
output: ['libharfbuzz_fontations.a'],
depends: [hb_rs],
env: ['OUT_DIR=' + meson.current_build_dir(),
'RUSTFLAGS=' + rust_flags,
],
command: [
cargo, 'build',
] + cargo_args + [
'-Z', 'unstable-options',
'--artifact-dir', meson.current_build_dir(),
],
install: true,
install_dir: join_paths(get_option('prefix'), 'lib'),
)
harfbuzz_fontations_dep = declare_dependency(
link_with: harfbuzz_fontations,
)
clippy_fix = run_target(
'clippy-fix',
env: ['OUT_DIR=' + meson.current_build_dir()],
depends: [hb_rs, harfbuzz_fontations],
command: [
cargo, 'clippy',
] + cargo_args + [
'--allow-dirty', '--fix',
],
)
if get_option('tests').enabled() and cargo.found()
test(
'clippy',
cargo,
env: ['OUT_DIR=' + meson.current_build_dir()],
depends: [hb_rs, harfbuzz_fontations],
args: [
'clippy',
] + cargo_args + [
'--', '-D', 'warnings',
],
timeout: 120,
)
endif
rustfmt_fix = run_target(
'rustfmt-fix',
env: ['OUT_DIR=' + meson.current_build_dir()],
depends: [hb_rs],
command: [
rustfmt,
'--edition', '2021',
'--',
meson.current_source_dir() / 'lib.rs',
],
)
if get_option('tests').enabled() and rustfmt.found()
test(
'rustfmt',
rustfmt,
env: ['OUT_DIR=' + meson.current_build_dir()],
depends: [hb_rs],
args: [
'--check',
'--edition', '2021',
'--',
meson.current_source_dir() / 'lib.rs',
],
)
endif

View file

@ -21,6 +21,10 @@ if '--experimental-api' not in sys.argv:
experimental_symbols = \
"""hb_shape_justify
hb_subset_input_override_name_table
hb_subset_cff_get_charstring_data
hb_subset_cff_get_charstrings_index
hb_subset_cff2_get_charstring_data
hb_subset_cff2_get_charstrings_index
""".splitlines ()
symbols = [x for x in symbols if x not in experimental_symbols]
symbols = "\n".join (symbols)

View file

@ -19,7 +19,9 @@ outdir = os.path.dirname (OUTPUT)
shutil.copy (INPUT, outdir)
rl = os.path.basename (INPUT)
hh = rl.replace ('.rl', '.hh')
subprocess.Popen (ragel.split() + ['-e', '-F1', '-o', hh, rl], cwd=outdir).wait ()
ret = subprocess.Popen (ragel.split() + ['-e', '-F1', '-o', hh, rl], cwd=outdir).wait ()
if ret:
sys.exit (ret)
# copy it also to src/
shutil.copyfile (os.path.join (outdir, hh), os.path.join (CURRENT_SOURCE_DIR, hh))

View file

@ -57,6 +57,8 @@
#include "hb-subset-input.cc"
#include "hb-subset-instancer-iup.cc"
#include "hb-subset-instancer-solver.cc"
#include "hb-subset-plan-layout.cc"
#include "hb-subset-plan-var.cc"
#include "hb-subset-plan.cc"
#include "hb-subset-serialize.cc"
#include "hb-subset.cc"

View file

@ -8,6 +8,9 @@
#include "hb-common.cc"
#include "hb-coretext-font.cc"
#include "hb-coretext-shape.cc"
#include "hb-coretext.cc"
#include "hb-directwrite-font.cc"
#include "hb-directwrite-shape.cc"
#include "hb-directwrite.cc"
#include "hb-draw.cc"
#include "hb-face-builder.cc"

View file

@ -29,6 +29,8 @@
#include "hb-aat-layout.hh"
#include "hb-aat-map.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-layout-gdef-table.hh"
#include "hb-open-type.hh"
#include "hb-cache.hh"
#include "hb-bit-set.hh"
@ -48,6 +50,61 @@ struct ankr;
using hb_aat_class_cache_t = hb_cache_t<15, 8, 7>;
static_assert (sizeof (hb_aat_class_cache_t) == 256, "");
struct hb_aat_scratch_t
{
hb_aat_scratch_t () = default;
hb_aat_scratch_t (const hb_aat_scratch_t &) = delete;
hb_aat_scratch_t (hb_aat_scratch_t &&o)
{
buffer_glyph_set.set_relaxed (o.buffer_glyph_set.get_relaxed ());
o.buffer_glyph_set.set_relaxed (nullptr);
}
hb_aat_scratch_t & operator = (hb_aat_scratch_t &&o)
{
buffer_glyph_set.set_relaxed (o.buffer_glyph_set.get_relaxed ());
o.buffer_glyph_set.set_relaxed (nullptr);
return *this;
}
~hb_aat_scratch_t ()
{
auto *s = buffer_glyph_set.get_relaxed ();
if (unlikely (!s))
return;
s->fini ();
hb_free (s);
}
hb_bit_set_t *create_buffer_glyph_set () const
{
hb_bit_set_t *s = buffer_glyph_set.get_acquire ();
if (s && buffer_glyph_set.cmpexch (s, nullptr))
return s;
s = (hb_bit_set_t *) hb_calloc (1, sizeof (hb_bit_set_t));
if (unlikely (!s))
return nullptr;
s->init ();
return s;
}
void destroy_buffer_glyph_set (hb_bit_set_t *s) const
{
if (unlikely (!s))
return;
if (buffer_glyph_set.cmpexch (nullptr, s))
return;
s->fini ();
hb_free (s);
}
mutable hb_atomic_t<hb_bit_set_t *> buffer_glyph_set;
};
enum { DELETED_GLYPH = 0xFFFF };
#define HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED HB_BUFFER_SCRATCH_FLAG_SHAPER0
struct hb_aat_apply_context_t :
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
{
@ -64,10 +121,11 @@ struct hb_aat_apply_context_t :
hb_buffer_t *buffer;
hb_sanitize_context_t sanitizer;
const ankr *ankr_table;
const OT::GDEF *gdef_table;
const OT::GDEF &gdef;
bool has_glyph_classes;
const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
bool using_buffer_glyph_set = false;
hb_bit_set_t buffer_glyph_set;
hb_bit_set_t *buffer_glyph_set = nullptr;
const hb_bit_set_t *left_set = nullptr;
const hb_bit_set_t *right_set = nullptr;
const hb_bit_set_t *machine_glyph_set = nullptr;
@ -90,15 +148,15 @@ struct hb_aat_apply_context_t :
void setup_buffer_glyph_set ()
{
using_buffer_glyph_set = buffer->len >= 4;
using_buffer_glyph_set = buffer->len >= 4 && buffer_glyph_set;
if (using_buffer_glyph_set)
buffer->collect_codepoints (buffer_glyph_set);
if (likely (using_buffer_glyph_set))
buffer->collect_codepoints (*buffer_glyph_set);
}
bool buffer_intersects_machine () const
{
if (using_buffer_glyph_set)
return buffer_glyph_set.intersects (*machine_glyph_set);
if (likely (using_buffer_glyph_set))
return buffer_glyph_set->intersects (*machine_glyph_set);
// Faster for shorter buffers.
for (unsigned i = 0; i < buffer->len; i++)
@ -106,6 +164,69 @@ struct hb_aat_apply_context_t :
return true;
return false;
}
template <typename T>
HB_NODISCARD bool output_glyphs (unsigned int count,
const T *glyphs)
{
if (likely (using_buffer_glyph_set))
buffer_glyph_set->add_array (glyphs, count);
for (unsigned int i = 0; i < count; i++)
{
if (glyphs[i] == DELETED_GLYPH)
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
_hb_glyph_info_set_aat_deleted (&buffer->cur());
}
else
{
#ifndef HB_NO_OT_LAYOUT
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->cur(),
gdef.get_glyph_props (glyphs[i]));
#endif
}
if (unlikely (!buffer->output_glyph (glyphs[i]))) return false;
}
return true;
}
HB_NODISCARD bool replace_glyph (hb_codepoint_t glyph)
{
if (glyph == DELETED_GLYPH)
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
_hb_glyph_info_set_aat_deleted (&buffer->cur());
}
if (likely (using_buffer_glyph_set))
buffer_glyph_set->add (glyph);
#ifndef HB_NO_OT_LAYOUT
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->cur(),
gdef.get_glyph_props (glyph));
#endif
return buffer->replace_glyph (glyph);
}
HB_NODISCARD bool delete_glyph ()
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
_hb_glyph_info_set_aat_deleted (&buffer->cur());
return buffer->replace_glyph (DELETED_GLYPH);
}
void replace_glyph_inplace (unsigned i, hb_codepoint_t glyph)
{
buffer->info[i].codepoint = glyph;
if (likely (using_buffer_glyph_set))
buffer_glyph_set->add (glyph);
#ifndef HB_NO_OT_LAYOUT
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->info[i],
gdef.get_glyph_props (glyph));
#endif
}
};
@ -113,8 +234,6 @@ struct hb_aat_apply_context_t :
* Lookup Table
*/
enum { DELETED_GLYPH = 0xFFFF };
template <typename T> struct Lookup;
template <typename T>
@ -179,6 +298,7 @@ struct LookupSegmentSingle
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
if (first == DELETED_GLYPH) return;
if (!filter (value)) return;
glyphs.add_range (first, last);
}
@ -268,6 +388,7 @@ struct LookupSegmentArray
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const void *base, const filter_t &filter) const
{
if (first == DELETED_GLYPH) return;
const auto &values = base+valuesZ;
for (hb_codepoint_t i = first; i <= last; i++)
if (filter (values[i - first]))
@ -368,6 +489,7 @@ struct LookupSingle
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
if (glyph == DELETED_GLYPH) return;
if (!filter (value)) return;
glyphs.add (glyph);
}
@ -746,6 +868,10 @@ struct StateTable
}
// And glyphs in those classes.
if (filter (CLASS_DELETED_GLYPH))
glyphs.add (DELETED_GLYPH);
(this+classTable).collect_glyphs_filtered (glyphs, num_glyphs, filter);
}

View file

@ -185,6 +185,9 @@ struct Format1Entry<true>
DEFINE_SIZE_STATIC (2);
};
static bool initiateAction (const Entry<EntryData> &entry)
{ return entry.flags & Push; }
static bool performAction (const Entry<EntryData> &entry)
{ return entry.data.kernActionIndex != 0xFFFF; }
@ -325,8 +328,9 @@ struct KerxSubTableFormat1
}
else if (buffer->info[idx].mask & kern_mask)
{
o.x_advance += c->font->em_scale_x (v);
o.x_offset += c->font->em_scale_x (v);
auto scaled = c->font->em_scale_x (v);
o.x_advance += scaled;
o.x_offset += scaled;
}
}
else
@ -394,10 +398,8 @@ struct KerxSubTableFormat1
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
{
set_t set;
machine.collect_glyphs (set, num_glyphs);
left_set.union_ (set);
right_set.union_ (set);
machine.collect_initial_glyphs (left_set, num_glyphs, *this);
//machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
}
protected:
@ -671,10 +673,8 @@ struct KerxSubTableFormat4
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
{
set_t set;
machine.collect_glyphs (set, num_glyphs);
left_set.union_ (set);
right_set.union_ (set);
machine.collect_initial_glyphs (left_set, num_glyphs, *this);
//machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
}
protected:
@ -921,7 +921,18 @@ struct KerxSubTable
* The 'kerx' Table
*/
using kern_accelerator_data_t = hb_vector_t<hb_pair_t<hb_bit_set_t, hb_bit_set_t>>;
struct kern_subtable_accelerator_data_t
{
hb_bit_set_t left_set;
hb_bit_set_t right_set;
mutable hb_aat_class_cache_t class_cache;
};
struct kern_accelerator_data_t
{
hb_vector_t<kern_subtable_accelerator_data_t> subtable_accels;
hb_aat_scratch_t scratch;
};
template <typename T>
struct KerxTable
@ -985,6 +996,8 @@ struct KerxTable
{
c->buffer->unsafe_to_concat ();
c->setup_buffer_glyph_set ();
typedef typename T::SubTable SubTable;
bool ret = false;
@ -996,12 +1009,25 @@ struct KerxTable
{
bool reverse;
auto &subtable_accel = accel_data.subtable_accels[i];
if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation))
goto skip;
if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ())
goto skip;
c->left_set = &subtable_accel.left_set;
c->right_set = &subtable_accel.right_set;
c->machine_glyph_set = &subtable_accel.left_set;
c->machine_class_cache = &subtable_accel.class_cache;
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped subtable %u because no glyph matches", c->lookup_index);
goto skip;
}
reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
@ -1028,9 +1054,6 @@ struct KerxTable
if (reverse)
c->buffer->reverse ();
c->left_set = &accel_data[i].first;
c->right_set = &accel_data[i].second;
{
/* See comment in sanitize() for conditional here. */
hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr);
@ -1106,9 +1129,13 @@ struct KerxTable
unsigned int count = thiz()->tableCount;
for (unsigned int i = 0; i < count; i++)
{
hb_bit_set_t left_set, right_set;
st->collect_glyphs (left_set, right_set, num_glyphs);
accel_data.push (hb_pair (left_set, right_set));
auto &subtable_accel = *accel_data.subtable_accels.push ();
if (unlikely (accel_data.subtable_accels.in_error ()))
return accel_data;
st->collect_glyphs (subtable_accel.left_set, subtable_accel.right_set, num_glyphs);
subtable_accel.class_cache.clear ();
st = &StructAfter<SubTable> (*st);
}
@ -1137,6 +1164,7 @@ struct KerxTable
hb_blob_ptr_t<T> table;
kern_accelerator_data_t accel_data;
hb_aat_scratch_t scratch;
};
};

View file

@ -30,8 +30,6 @@
#include "hb-open-type.hh"
#include "hb-aat-layout-common.hh"
#include "hb-ot-layout.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-layout-gdef-table.hh"
#include "hb-aat-map.hh"
/*
@ -178,12 +176,6 @@ struct RearrangementSubtable
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
return_trace (false);
}
driver.drive (&dc, c);
return_trace (dc.ret);
@ -242,9 +234,7 @@ struct ContextualSubtable
ret (false),
c (c_),
table (table_),
gdef (*c->gdef_table),
mark_set (false),
has_glyph_classes (gdef.has_glyph_classes ()),
mark (0),
subs (table+table->substitutionTables) {}
@ -281,12 +271,7 @@ struct ContextualSubtable
if (replacement)
{
buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
hb_codepoint_t glyph = *replacement;
buffer->info[mark].codepoint = glyph;
c->buffer_glyph_set.add (glyph);
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->info[mark],
gdef.get_glyph_props (*replacement));
c->replace_glyph_inplace (mark, *replacement);
ret = true;
}
@ -312,12 +297,7 @@ struct ContextualSubtable
}
if (replacement)
{
hb_codepoint_t glyph = *replacement;
buffer->info[idx].codepoint = glyph;
c->buffer_glyph_set.add (glyph);
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->info[idx],
gdef.get_glyph_props (*replacement));
c->replace_glyph_inplace (idx, *replacement);
ret = true;
}
@ -333,9 +313,7 @@ struct ContextualSubtable
hb_aat_apply_context_t *c;
const ContextualSubtable *table;
private:
const OT::GDEF &gdef;
bool mark_set;
bool has_glyph_classes;
unsigned int mark;
const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false> &subs;
};
@ -348,12 +326,6 @@ struct ContextualSubtable
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
return_trace (false);
}
driver.drive (&dc, c);
return_trace (dc.ret);
@ -581,7 +553,7 @@ struct LigatureSubtable
hb_codepoint_t lig = ligatureData;
DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
if (unlikely (!buffer->replace_glyph (lig))) return;
if (unlikely (!c->replace_glyph (lig))) return;
unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
/* Now go and delete all subsequent components. */
@ -589,8 +561,7 @@ struct LigatureSubtable
{
DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
_hb_glyph_info_set_default_ignorable (&buffer->cur());
if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
if (!c->delete_glyph ()) return;
}
if (unlikely (!buffer->move_to (lig_end))) return;
@ -624,12 +595,6 @@ struct LigatureSubtable
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
return_trace (false);
}
driver.drive (&dc, c);
return_trace (dc.ret);
@ -665,15 +630,6 @@ struct NoncontextualSubtable
{
TRACE_APPLY (this);
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
return_trace (false);
}
const OT::GDEF &gdef (*c->gdef_table);
bool has_glyph_classes = gdef.has_glyph_classes ();
bool ret = false;
unsigned int num_glyphs = c->face->get_num_glyphs ();
@ -703,12 +659,7 @@ struct NoncontextualSubtable
const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
if (replacement)
{
hb_codepoint_t glyph = *replacement;
info[i].codepoint = glyph;
c->buffer_glyph_set.add (glyph);
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&info[i],
gdef.get_glyph_props (*replacement));
c->replace_glyph_inplace (i, *replacement);
ret = true;
}
}
@ -850,9 +801,7 @@ struct InsertionSubtable
if (buffer->idx < buffer->len && !before)
if (unlikely (!buffer->copy_glyph ())) return;
/* TODO We ignore KashidaLike setting. */
if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
for (unsigned int i = 0; i < count; i++)
c->buffer_glyph_set.add (glyphs[i]);
if (unlikely (!c->output_glyphs (count, glyphs))) return;
ret = true;
if (buffer->idx < buffer->len && !before)
buffer->skip_glyph ();
@ -881,7 +830,8 @@ struct InsertionSubtable
if (buffer->idx < buffer->len && !before)
if (unlikely (!buffer->copy_glyph ())) return;
/* TODO We ignore KashidaLike setting. */
if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
if (unlikely (!c->output_glyphs (count, glyphs))) return;
ret = true;
if (buffer->idx < buffer->len && !before)
buffer->skip_glyph ();
@ -921,12 +871,6 @@ struct InsertionSubtable
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches");
return_trace (false);
}
driver.drive (&dc, c);
return_trace (dc.ret);
@ -1224,6 +1168,7 @@ struct Chain
if (hb_none (hb_iter (c->range_flags) |
hb_map ([subtable_flags] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable_flags & (_.flags); })))
goto skip;
c->subtable_flags = subtable_flags;
c->machine_glyph_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t);
c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr;
@ -1233,6 +1178,12 @@ struct Chain
bool (coverage & ChainSubtable<Types>::Vertical))
goto skip;
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable %u because no glyph matches", c->lookup_index);
goto skip;
}
/* Buffer contents is always in logical direction. Determine if
* we need to reverse before applying this subtable. We reverse
* back after if we did reverse indeed.
@ -1376,7 +1327,7 @@ struct mortmorx
this->chain_count = table->get_chain_count ();
this->accels = (hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *) hb_calloc (this->chain_count, sizeof (*accels));
this->accels = (hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *) hb_calloc (this->chain_count, sizeof (*accels));
if (unlikely (!this->accels))
{
this->chain_count = 0;
@ -1423,7 +1374,8 @@ struct mortmorx
hb_blob_ptr_t<T> table;
unsigned int chain_count;
hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *accels;
hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *accels;
hb_aat_scratch_t scratch;
};

View file

@ -31,6 +31,7 @@
#include "hb-aat-layout-common.hh"
#include "hb-ot-layout.hh"
#include "hb-open-type.hh"
#include "hb-ot-stat-table.hh"
/*
* trak -- Tracking
@ -115,7 +116,7 @@ struct TrackTableEntry
protected:
F16DOT16 track; /* Track value for this record. */
NameID trackNameID; /* The 'name' table index for this track.
OT::NameID trackNameID; /* The 'name' table index for this track.
* (a short word or phrase like "loose"
* or "very tight") */
NNOffset16To<UnsizedArrayOf<FWORD>>
@ -142,9 +143,9 @@ struct TrackData
unsigned j = count - 1;
// Find the two entries that track is between.
while (i + 1 < count && trackTable[i + 1].get_track_value () < track)
while (i + 1 < count && trackTable[i + 1].get_track_value () <= track)
i++;
while (j > 0 && trackTable[j - 1].get_track_value () > track)
while (j > 0 && trackTable[j - 1].get_track_value () >= track)
j--;
// Exact match.
@ -200,6 +201,46 @@ struct trak
float ptem = font->ptem > 0.f ? font->ptem : HB_CORETEXT_DEFAULT_FONT_SIZE;
return font->em_scalef_y ((this+vertData).get_tracking (this, ptem, track));
}
hb_position_t get_tracking (hb_font_t *font, hb_direction_t dir, float track = 0.f) const
{
#ifndef HB_NO_STYLE
if (!font->face->table.STAT->has_data ())
return 0;
return HB_DIRECTION_IS_HORIZONTAL (dir) ?
get_h_tracking (font, track) :
get_v_tracking (font, track);
#else
return 0;
#endif
}
bool apply (hb_aat_apply_context_t *c, float track = 0.f) const
{
TRACE_APPLY (this);
float ptem = c->font->ptem;
if (unlikely (ptem <= 0.f))
{
/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
ptem = HB_CORETEXT_DEFAULT_FONT_SIZE;
}
hb_buffer_t *buffer = c->buffer;
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
{
hb_position_t advance_to_add = get_h_tracking (c->font, track);
foreach_grapheme (buffer, start, end)
buffer->pos[start].x_advance += advance_to_add;
}
else
{
hb_position_t advance_to_add = get_v_tracking (c->font, track);
foreach_grapheme (buffer, start, end)
buffer->pos[start].y_advance += advance_to_add;
}
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{

View file

@ -34,7 +34,7 @@
#include "hb-aat-layout-just-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-layout-kerx-table.hh"
#include "hb-aat-layout-morx-table.hh"
#include "hb-aat-layout-trak-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-layout-trak-table.hh"
#include "hb-aat-ltag-table.hh"
#include "hb-ot-layout-gsub-table.hh"
@ -58,13 +58,14 @@ AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *p
buffer (buffer_),
sanitizer (),
ankr_table (&Null (AAT::ankr)),
gdef_table (
gdef (
#ifndef HB_NO_OT_LAYOUT
face->table.GDEF->table
*face->table.GDEF->table
#else
&Null (GDEF)
Null (GDEF)
#endif
),
has_glyph_classes (gdef.has_glyph_classes ()),
lookup_index (0)
{
sanitizer.init (blob);
@ -203,7 +204,7 @@ hb_aat_layout_find_feature_mapping (hb_tag_t tag)
#endif
#ifndef HB_NO_AAT
#ifndef HB_NO_AAT_SHAPE
/*
* mort/morx/kerx/trak
@ -287,11 +288,14 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
const hb_feature_t *features,
unsigned num_features)
{
hb_aat_map_builder_t builder (font->face, plan->props);
for (unsigned i = 0; i < num_features; i++)
builder.add_feature (features[i]);
hb_aat_map_t map;
builder.compile (map);
if (num_features)
{
hb_aat_map_builder_t builder (font->face, plan->props);
for (unsigned i = 0; i < num_features; i++)
builder.add_feature (features[i]);
builder.compile (map);
}
{
auto &accel = *font->face->table.morx;
@ -300,7 +304,10 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
{
AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
if (!buffer->message (font, "start table morx")) return;
morx.apply (&c, map, accel);
c.buffer_glyph_set = accel.scratch.create_buffer_glyph_set ();
morx.apply (&c, num_features ? map : plan->aat_map, accel);
accel.scratch.destroy_buffer_glyph_set (c.buffer_glyph_set);
c.buffer_glyph_set = nullptr;
(void) buffer->message (font, "end table morx");
return;
}
@ -313,34 +320,24 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
{
AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
if (!buffer->message (font, "start table mort")) return;
mort.apply (&c, map, accel);
mort.apply (&c, num_features ? map : plan->aat_map, accel);
(void) buffer->message (font, "end table mort");
return;
}
}
}
void
hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
for (unsigned int i = 0; i < count; i++)
if (unlikely (info[i].codepoint == AAT::DELETED_GLYPH))
pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
}
static bool
is_deleted_glyph (const hb_glyph_info_t *info)
{
return info->codepoint == AAT::DELETED_GLYPH;
return _hb_glyph_info_is_aat_deleted (info);
}
void
hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
{
buffer->delete_glyphs_inplace (is_deleted_glyph);
if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED)
buffer->delete_glyphs_inplace (is_deleted_glyph);
}
/**
@ -371,8 +368,11 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
if (!buffer->message (font, "start table kerx")) return;
c.buffer_glyph_set = accel.scratch.create_buffer_glyph_set ();
c.set_ankr_table (font->face->table.ankr.get ());
accel.apply (&c);
accel.scratch.destroy_buffer_glyph_set (c.buffer_glyph_set);
c.buffer_glyph_set = nullptr;
(void) buffer->message (font, "end table kerx");
}
@ -394,6 +394,17 @@ hb_aat_layout_has_tracking (hb_face_t *face)
return face->table.trak->has_data ();
}
void
hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
const AAT::trak& trak = *font->face->table.trak;
AAT::hb_aat_apply_context_t c (plan, font, buffer);
trak.apply (&c);
}
/**
* hb_aat_layout_get_feature_types:
* @face: #hb_face_t to work upon

View file

@ -60,9 +60,6 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
const hb_feature_t *features,
unsigned num_features);
HB_INTERNAL void
hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer);
HB_INTERNAL void
hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer);
@ -71,5 +68,10 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
HB_INTERNAL void
hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
#endif /* HB_AAT_LAYOUT_HH */

View file

@ -85,6 +85,11 @@ void
hb_aat_map_builder_t::compile (hb_aat_map_t &m)
{
/* Compute active features per range, and compile each. */
if (!features.length)
{
hb_aat_layout_compile_map (this, &m);
return;
}
/* Sort features by start/end events. */
hb_vector_t<feature_event_t> feature_events;

View file

@ -80,15 +80,14 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#include <atomic>
#define _hb_memory_barrier() std::atomic_thread_fence(std::memory_order_ack_rel)
#define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire)
#define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release)
#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_relaxed))
#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_release))
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_relaxed))
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_acquire))
#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_relaxed))
#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_release))
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_relaxed))
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_acquire))
#define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
@ -149,62 +148,47 @@ static inline void _hb_compiler_memory_r_barrier () {}
#define hb_atomic_ptr_impl_get_relaxed(P) (*(P))
#endif
#ifndef hb_atomic_int_impl_set
inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; }
inline void hb_atomic_int_impl_set (short *AI, short v) { _hb_memory_w_barrier (); *AI = v; }
template <typename T>
inline void hb_atomic_int_impl_set (T *AI, T v) { _hb_memory_w_barrier (); *AI = v; }
#endif
#ifndef hb_atomic_int_impl_get
inline int hb_atomic_int_impl_get (const int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; }
inline short hb_atomic_int_impl_get (const short *AI) { short v = *AI; _hb_memory_r_barrier (); return v; }
template <typename T>
inline T hb_atomic_int_impl_get (const T *AI) { T v = *AI; _hb_memory_r_barrier (); return v; }
#endif
#ifndef hb_atomic_ptr_impl_get
inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; }
#endif
struct hb_atomic_short_t
template <typename T>
struct hb_atomic_t
{
hb_atomic_short_t () = default;
constexpr hb_atomic_short_t (short v) : v (v) {}
hb_atomic_t () = default;
constexpr hb_atomic_t (T v) : v (v) {}
hb_atomic_short_t& operator = (short v_) { set_relaxed (v_); return *this; }
operator short () const { return get_relaxed (); }
hb_atomic_t& operator = (T v_) { set_relaxed (v_); return *this; }
operator T () const { return get_relaxed (); }
void set_relaxed (short v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
void set_release (short v_) { hb_atomic_int_impl_set (&v, v_); }
short get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
short get_acquire () const { return hb_atomic_int_impl_get (&v); }
short inc () { return hb_atomic_int_impl_add (&v, 1); }
short dec () { return hb_atomic_int_impl_add (&v, -1); }
void set_relaxed (T v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
void set_release (T v_) { hb_atomic_int_impl_set (&v, v_); }
T get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
T get_acquire () const { return hb_atomic_int_impl_get (&v); }
T inc () { return hb_atomic_int_impl_add (&v, 1); }
T dec () { return hb_atomic_int_impl_add (&v, -1); }
short v = 0;
int operator ++ (int) { return inc (); }
int operator -- (int) { return dec (); }
long operator |= (long v_) { set_relaxed (get_relaxed () | v_); return *this; }
T v = 0;
};
struct hb_atomic_int_t
template <typename T>
struct hb_atomic_t<T*>
{
hb_atomic_int_t () = default;
constexpr hb_atomic_int_t (int v) : v (v) {}
hb_atomic_int_t& operator = (int v_) { set_relaxed (v_); return *this; }
operator int () const { return get_relaxed (); }
void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
void set_release (int v_) { hb_atomic_int_impl_set (&v, v_); }
int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
int get_acquire () const { return hb_atomic_int_impl_get (&v); }
int inc () { return hb_atomic_int_impl_add (&v, 1); }
int dec () { return hb_atomic_int_impl_add (&v, -1); }
int v = 0;
};
template <typename P>
struct hb_atomic_ptr_t
{
typedef hb_remove_pointer<P> T;
hb_atomic_ptr_t () = default;
constexpr hb_atomic_ptr_t (T* v) : v (v) {}
hb_atomic_ptr_t (const hb_atomic_ptr_t &other) = delete;
hb_atomic_t () = default;
constexpr hb_atomic_t (T* v) : v (v) {}
hb_atomic_t (const hb_atomic_t &other) = delete;
void init (T* v_ = nullptr) { set_relaxed (v_); }
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }

View file

@ -77,7 +77,7 @@ struct hb_bit_set_t
bool successful = true; /* Allocations successful */
mutable unsigned int population = 0;
mutable hb_atomic_int_t last_page_lookup = 0;
mutable hb_atomic_t<unsigned> last_page_lookup = 0;
hb_sorted_vector_t<page_map_t> page_map;
hb_vector_t<page_t> pages;
@ -88,7 +88,7 @@ struct hb_bit_set_t
{
if (unlikely (!successful)) return false;
if (pages.length < count && count <= 2)
if (pages.length < count && (unsigned) pages.allocated < count && count <= 2)
exact_size = true; // Most sets are small and local
if (unlikely (!pages.resize (count, clear, exact_size) ||

195
src/hb-bit-vector.hh Normal file
View file

@ -0,0 +1,195 @@
/*
* 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.
*
* Author(s): Behdad Esfahbod
*/
#ifndef HB_BIT_VECTOR_HH
#define HB_BIT_VECTOR_HH
#include "hb.hh"
#include "hb-atomic.hh"
struct hb_min_max_t
{
void add (hb_codepoint_t v) { min_v = hb_min (min_v, v); max_v = hb_max (max_v, v); }
void add_range (hb_codepoint_t a, hb_codepoint_t b)
{
min_v = hb_min (min_v, a);
max_v = hb_max (max_v, b);
}
template <typename set_t>
void union_ (const set_t &set)
{
hb_codepoint_t set_min = set.get_min ();
if (unlikely (set_min == HB_CODEPOINT_INVALID))
return;
hb_codepoint_t set_max = set.get_max ();
min_v = hb_min (min_v, set_min);
max_v = hb_max (max_v, set_max);
}
hb_codepoint_t get_min () const { return min_v; }
hb_codepoint_t get_max () const { return max_v; }
private:
hb_codepoint_t min_v = HB_CODEPOINT_INVALID;
hb_codepoint_t max_v = 0;
};
template <bool atomic = false>
struct hb_bit_vector_t
{
using int_t = uint64_t;
using elt_t = typename std::conditional<atomic, hb_atomic_t<int_t>, int_t>::type;
hb_bit_vector_t () = delete;
hb_bit_vector_t (const hb_bit_vector_t &other) = delete;
hb_bit_vector_t &operator= (const hb_bit_vector_t &other) = delete;
// Move
hb_bit_vector_t (hb_bit_vector_t &&other)
: min_v (other.min_v), max_v (other.max_v), count (other.count), elts (other.elts)
{
other.min_v = other.max_v = other.count = 0;
other.elts = nullptr;
}
hb_bit_vector_t &operator= (hb_bit_vector_t &&other)
{
hb_swap (min_v, other.min_v);
hb_swap (max_v, other.max_v);
hb_swap (count, other.count);
hb_swap (elts, other.elts);
return *this;
}
hb_bit_vector_t (unsigned min_v, unsigned max_v)
: min_v (min_v), max_v (max_v)
{
if (unlikely (min_v >= max_v))
{
min_v = max_v = count = 0;
return;
}
unsigned num = (max_v - min_v + sizeof (int_t) * 8) / (sizeof (int_t) * 8);
elts = (elt_t *) hb_calloc (num, sizeof (int_t));
if (unlikely (!elts))
{
min_v = max_v = count = 0;
return;
}
count = max_v - min_v + 1;
}
~hb_bit_vector_t ()
{
hb_free (elts);
}
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 value) { if (value) add (g); else del (g); }
bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
bool has (hb_codepoint_t g) const { return get (g); }
bool may_have (hb_codepoint_t g) const { return get (g); }
bool operator [] (hb_codepoint_t g) const { return get (g); }
bool operator () (hb_codepoint_t g) const { return get (g); }
void add_range (hb_codepoint_t a, hb_codepoint_t b)
{
if (unlikely (!count || a > b || a < min_v || b > max_v))
return;
elt_t *la = &elt (a);
elt_t *lb = &elt (b);
if (la == lb)
*la |= (mask (b) << 1) - mask(a);
else
{
*la |= ~(mask (a) - 1llu);
la++;
hb_memset (la, 0xff, (char *) lb - (char *) la);
*lb |= ((mask (b) << 1) - 1llu);
}
}
void del_range (hb_codepoint_t a, hb_codepoint_t b)
{
if (unlikely (!count || a > b || a < min_v || b > max_v))
return;
elt_t *la = &elt (a);
elt_t *lb = &elt (b);
if (la == lb)
*la &= ~((mask (b) << 1llu) - mask(a));
else
{
*la &= mask (a) - 1;
la++;
hb_memset (la, 0, (char *) lb - (char *) la);
*lb &= ~((mask (b) << 1) - 1llu);
}
}
void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
{ if (v) add_range (a, b); else del_range (a, b); }
template <typename set_t>
void union_ (const set_t &set)
{
for (hb_codepoint_t g : set)
add (g);
}
static const unsigned int ELT_BITS = sizeof (elt_t) * 8;
static constexpr unsigned ELT_MASK = ELT_BITS - 1;
static constexpr elt_t zero = 0;
elt_t &elt (hb_codepoint_t g)
{
g -= min_v;
if (unlikely (g >= count))
return Crap(elt_t);
return elts[g / ELT_BITS];
}
const elt_t& elt (hb_codepoint_t g) const
{
g -= min_v;
if (unlikely (g >= count))
return Null(elt_t);
return elts[g / ELT_BITS];
}
static constexpr int_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); }
hb_codepoint_t min_v = 0, max_v = 0, count = 0;
elt_t *elts = nullptr;
};
#endif /* HB_BIT_VECTOR_HH */

File diff suppressed because it is too large Load diff

View file

@ -91,6 +91,8 @@ yoffset = "\"dy\"" colon (num >tok %parse_y_offset);
xadvance= "\"ax\"" colon (num >tok %parse_x_advance);
yadvance= "\"ay\"" colon (num >tok %parse_y_advance);
glyphflags="\"fl\"" colon (unum >tok %parse_glyph_flags);
# Not parsed. Ignored.
glyphextents="\""("xb"|"yb"|"w"|"h")"\"" colon (num >tok);
element = glyph @ensure_glyphs
| unicode @ensure_unicode
@ -99,14 +101,16 @@ element = glyph @ensure_glyphs
| yoffset
| xadvance
| yadvance
| glyphflags;
| glyphflags
| glyphextents
;
item =
( '{' space* element (comma element)* space* '}')
( '{' space* element (comma element)* space* '}' space* (','|']') space* )
>clear_item
@add_item
;
main := space* '['? space* item (comma item)* space* (','|']')?;
main := space* '['? space* item*;
}%%
@ -133,7 +137,7 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
*end_ptr = p;
return p == pe && *(p-1) != ']';
return p == pe;
}
#endif /* HB_BUFFER_DESERIALIZE_JSON_HH */

File diff suppressed because it is too large Load diff

View file

@ -41,10 +41,9 @@ action clear_item {
}
action add_item {
buffer->add_info (info);
buffer->add_info_and_pos (info, pos);
if (unlikely (!buffer->successful))
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
@ -77,7 +76,9 @@ glyph = (glyph_id | glyph_name) >tok %parse_glyph;
cluster = '=' (unum >tok %parse_cluster);
offsets = '@' (num >tok %parse_x_offset) ',' (num >tok %parse_y_offset );
advances= '+' (num >tok %parse_x_advance) (',' (num >tok %parse_y_advance))?;
glyphflags= '#' (unum >tok %parse_glyph_flags);
glyphflags = '#' (unum >tok %parse_glyph_flags);
# Not parsed. Ignored.
glyphextents = '<' (num ',' num ',' num ',' num) '>';
glyph_item =
(
@ -86,14 +87,16 @@ glyph_item =
offsets?
advances?
glyphflags?
glyphextents?
( '|' | ']')
)
>clear_item
%add_item
;
glyphs = glyph_item (space* '|' space* glyph_item)* space*;
glyphs = '['? glyph_item* ;
main := space* glyphs;
main := glyphs;
}%%
@ -104,28 +107,11 @@ _hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
const char **end_ptr,
hb_font_t *font)
{
const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
const char *p = buf, *pe = buf + buf_len, *eof = pe;
/* Ensure we have positions. */
(void) hb_buffer_get_glyph_positions (buffer, nullptr);
while (p < pe && ISSPACE (*p))
p++;
if (p < pe && *p == (buffer->len ? '|' : '['))
*end_ptr = ++p;
const char *end = strchr ((char *) p, ']');
if (end)
pe = eof = end;
else
{
end = strrchr ((char *) p, '|');
if (end)
pe = eof = end;
else
pe = eof = p;
}
const char *tok = nullptr;
int cs;
hb_glyph_info_t info = {0};
@ -135,13 +121,6 @@ _hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
write exec;
}%%
if (pe < orig_pe && *pe == ']')
{
pe++;
if (p == pe)
p++;
}
*end_ptr = p;
return p == pe;

View file

@ -34,135 +34,106 @@
#line 36 "hb-buffer-deserialize-text-unicode.hh"
static const unsigned char _deserialize_text_unicode_trans_keys[] = {
0u, 0u, 9u, 117u, 43u, 102u, 48u, 102u, 48u, 57u, 9u, 124u, 9u, 124u, 9u, 124u,
9u, 124u, 0
0u, 0u, 43u, 102u, 48u, 102u, 48u, 124u, 48u, 57u, 62u, 124u, 48u, 124u, 60u, 117u,
85u, 117u, 85u, 117u, 0
};
static const char _deserialize_text_unicode_key_spans[] = {
0, 109, 60, 55, 10, 116, 116, 116,
116
0, 60, 55, 77, 10, 63, 77, 58,
33, 33
};
static const short _deserialize_text_unicode_index_offsets[] = {
0, 0, 110, 171, 227, 238, 355, 472,
589
0, 0, 61, 117, 195, 206, 270, 348,
407, 441
};
static const char _deserialize_text_unicode_indicies[] = {
0, 0, 0, 0, 0, 1, 1,
0, 1, 1, 1, 1, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 2,
2, 2, 2, 2, 2, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 2,
2, 2, 2, 2, 2, 1, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 2,
2, 2, 2, 2, 2, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 2,
2, 2, 2, 2, 2, 1, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
1, 1, 1, 4, 5, 1, 1, 3,
3, 3, 3, 3, 3, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 3,
3, 3, 3, 3, 3, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 5, 1, 6, 7, 7, 7,
7, 7, 7, 7, 7, 7, 1, 8,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 2, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 8, 1, 9,
9, 9, 9, 9, 9, 9, 9, 9,
9, 1, 1, 1, 1, 8, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 2, 1, 3,
1, 1, 1, 1, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 1, 1,
1, 1, 1, 1, 1, 4, 4, 4,
4, 4, 4, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 4, 4, 4,
4, 4, 4, 1, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 1, 1,
1, 1, 1, 1, 1, 4, 4, 4,
4, 4, 4, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 4, 4, 4,
4, 4, 4, 1, 5, 6, 6, 6,
6, 6, 6, 6, 6, 6, 1, 7,
7, 7, 7, 7, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 7, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
1, 1, 1, 9, 1, 1, 1, 8,
8, 8, 8, 8, 8, 1, 1, 1,
1, 1, 1, 8, 1, 10, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 8,
8, 8, 8, 8, 8, 1, 1, 1,
1, 1, 1, 1, 1, 1, 11, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 10, 1, 11, 11, 11, 11,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 11, 1,
11, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 11, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
11, 1, 12, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0,
1, 12, 12, 12, 12, 12, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
12, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 13, 1, 12, 12,
12, 12, 12, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 12, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 13, 1, 0
1, 1, 12, 1, 0
};
static const char _deserialize_text_unicode_trans_targs[] = {
1, 0, 2, 3, 5, 7, 8, 6,
5, 4, 1, 6, 6, 1, 8
2, 0, 3, 3, 4, 9, 5, 6,
9, 6, 8, 1, 1
};
static const char _deserialize_text_unicode_trans_actions[] = {
0, 0, 1, 0, 2, 2, 2, 3,
0, 4, 3, 0, 5, 5, 0
0, 0, 1, 0, 2, 2, 1, 1,
3, 0, 0, 4, 6
};
static const char _deserialize_text_unicode_eof_actions[] = {
0, 0, 0, 0, 0, 3, 0, 5,
5
0, 0, 0, 0, 0, 0, 0, 0,
0, 5
};
static const int deserialize_text_unicode_start = 1;
static const int deserialize_text_unicode_first_final = 5;
static const int deserialize_text_unicode_start = 7;
static const int deserialize_text_unicode_first_final = 7;
static const int deserialize_text_unicode_error = 0;
static const int deserialize_text_unicode_en_main = 1;
static const int deserialize_text_unicode_en_main = 7;
#line 79 "hb-buffer-deserialize-text-unicode.rl"
#line 80 "hb-buffer-deserialize-text-unicode.rl"
static hb_bool_t
@ -172,37 +143,19 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
const char **end_ptr,
hb_font_t *font)
{
const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
while (p < pe && ISSPACE (*p))
p++;
if (p < pe && *p == (buffer->len ? '|' : '<'))
*end_ptr = ++p;
const char *end = strchr ((char *) p, '>');
if (end)
pe = eof = end;
else
{
end = strrchr ((char *) p, '|');
if (end)
pe = eof = end;
else
pe = eof = p;
}
const char *p = buf, *pe = buf + buf_len, *eof = pe;
const char *tok = nullptr;
int cs;
hb_glyph_info_t info = {0};
const hb_glyph_position_t pos = {0};
#line 201 "hb-buffer-deserialize-text-unicode.hh"
#line 154 "hb-buffer-deserialize-text-unicode.hh"
{
cs = deserialize_text_unicode_start;
}
#line 206 "hb-buffer-deserialize-text-unicode.hh"
#line 159 "hb-buffer-deserialize-text-unicode.hh"
{
int _slen;
int _trans;
@ -227,38 +180,27 @@ _resume:
goto _again;
switch ( _deserialize_text_unicode_trans_actions[_trans] ) {
case 1:
case 4:
#line 38 "hb-buffer-deserialize-text-unicode.rl"
{
hb_memset (&info, 0, sizeof (info));
}
break;
case 2:
case 1:
#line 51 "hb-buffer-deserialize-text-unicode.rl"
{
tok = p;
}
break;
case 4:
case 2:
#line 55 "hb-buffer-deserialize-text-unicode.rl"
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
break;
case 3:
#line 55 "hb-buffer-deserialize-text-unicode.rl"
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
#line 42 "hb-buffer-deserialize-text-unicode.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
if (buffer->have_positions)
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 5:
#line 57 "hb-buffer-deserialize-text-unicode.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
break;
case 6:
#line 42 "hb-buffer-deserialize-text-unicode.rl"
{
buffer->add_info (info);
@ -267,9 +209,13 @@ _resume:
if (buffer->have_positions)
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
#line 38 "hb-buffer-deserialize-text-unicode.rl"
{
hb_memset (&info, 0, sizeof (info));
}
break;
#line 273 "hb-buffer-deserialize-text-unicode.hh"
#line 219 "hb-buffer-deserialize-text-unicode.hh"
}
_again:
@ -281,22 +227,7 @@ _again:
if ( p == eof )
{
switch ( _deserialize_text_unicode_eof_actions[cs] ) {
case 3:
#line 55 "hb-buffer-deserialize-text-unicode.rl"
{if (!parse_hex (tok, p, &info.codepoint )) return false; }
#line 42 "hb-buffer-deserialize-text-unicode.rl"
{
buffer->add_info (info);
if (unlikely (!buffer->successful))
return false;
if (buffer->have_positions)
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 5:
#line 57 "hb-buffer-deserialize-text-unicode.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
#line 42 "hb-buffer-deserialize-text-unicode.rl"
{
buffer->add_info (info);
@ -307,23 +238,16 @@ _again:
*end_ptr = p;
}
break;
#line 311 "hb-buffer-deserialize-text-unicode.hh"
#line 242 "hb-buffer-deserialize-text-unicode.hh"
}
}
_out: {}
}
#line 115 "hb-buffer-deserialize-text-unicode.rl"
#line 98 "hb-buffer-deserialize-text-unicode.rl"
if (pe < orig_pe && *pe == '>')
{
pe++;
if (p == pe)
p++;
}
*end_ptr = p;
return p == pe;

View file

@ -67,14 +67,15 @@ unicode_item =
(
unicode
cluster?
('|' | '>')
)
>clear_item
%add_item
;
unicodes = unicode_item (space* '|' space* unicode_item)* space*;
unicodes = '<'? unicode_item*;
main := space* unicodes;
main := unicodes;
}%%
@ -85,25 +86,7 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
const char **end_ptr,
hb_font_t *font)
{
const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
while (p < pe && ISSPACE (*p))
p++;
if (p < pe && *p == (buffer->len ? '|' : '<'))
*end_ptr = ++p;
const char *end = strchr ((char *) p, '>');
if (end)
pe = eof = end;
else
{
end = strrchr ((char *) p, '|');
if (end)
pe = eof = end;
else
pe = eof = p;
}
const char *p = buf, *pe = buf + buf_len, *eof = pe;
const char *tok = nullptr;
int cs;
@ -114,13 +97,6 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
write exec;
}%%
if (pe < orig_pe && *pe == '>')
{
pe++;
if (p == pe)
p++;
}
*end_ptr = p;
return p == pe;

View file

@ -169,11 +169,13 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
{
hb_glyph_extents_t extents;
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
extents.x_bearing, extents.y_bearing));
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
extents.width, extents.height));
if (hb_font_get_glyph_extents(font, info[i].codepoint, &extents))
{
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
extents.x_bearing, extents.y_bearing));
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
extents.width, extents.height));
}
}
*p++ = '}';
@ -318,8 +320,8 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
{
hb_glyph_extents_t extents;
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
if (hb_font_get_glyph_extents(font, info[i].codepoint, &extents))
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
}
if (i == end-1) {
@ -737,8 +739,7 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
* Deserializes glyphs @buffer from textual representation in the format
* produced by hb_buffer_serialize_glyphs().
*
* Return value: `true` if parse was successful, `false` if an error
* occurred.
* Return value: `true` if the full string was parsed, `false` otherwise.
*
* Since: 0.9.7
**/
@ -810,8 +811,7 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
* Deserializes Unicode @buffer from textual representation in the format
* produced by hb_buffer_serialize_unicode().
*
* Return value: `true` if parse was successful, `false` if an error
* occurred.
* Return value: `true` if the full string was parsed, `false` otherwise.
*
* Since: 2.7.3
**/

View file

@ -63,24 +63,25 @@ static bool
buffer_verify_monotone (hb_buffer_t *buffer,
hb_font_t *font)
{
/* Check that clusters are monotone. */
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ||
buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
{
bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
unsigned int num_glyphs;
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
for (unsigned int i = 1; i < num_glyphs; i++)
if (info[i-1].cluster != info[i].cluster &&
(info[i-1].cluster < info[i].cluster) != is_forward)
{
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone.");
return false;
}
/* Cannot perform this check without monotone clusters. */
return true;
}
bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
unsigned int num_glyphs;
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
for (unsigned int i = 1; i < num_glyphs; i++)
if (info[i-1].cluster != info[i].cluster &&
(info[i-1].cluster < info[i].cluster) != is_forward)
{
buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone.");
return false;
}
return true;
}
@ -92,8 +93,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
unsigned int num_features,
const char * const *shapers)
{
if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
{
/* Cannot perform this check without monotone clusters. */
return true;
@ -207,8 +207,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
unsigned int num_features,
const char * const *shapers)
{
if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
{
/* Cannot perform this check without monotone clusters. */
return true;

View file

@ -370,6 +370,18 @@ hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
len++;
}
void
hb_buffer_t::add_info_and_pos (const hb_glyph_info_t &glyph_info,
const hb_glyph_position_t &glyph_pos)
{
if (unlikely (!ensure (len + 1))) return;
info[len] = glyph_info;
assert (have_positions);
pos[len] = glyph_pos;
len++;
}
void
@ -518,7 +530,7 @@ void
hb_buffer_t::merge_clusters_impl (unsigned int start,
unsigned int end)
{
if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
{
unsafe_to_break (start, end);
return;
@ -551,7 +563,7 @@ void
hb_buffer_t::merge_out_clusters (unsigned int start,
unsigned int end)
{
if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
return;
if (unlikely (end - start < 2))

View file

@ -422,18 +422,34 @@ hb_buffer_get_flags (const hb_buffer_t *buffer);
* @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: Don't group cluster values.
* @HB_BUFFER_CLUSTER_LEVEL_DEFAULT: Default cluster level,
* equal to @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES.
*
* @HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES: Only group clusters, but don't enforce monotone order.
*
* Data type for holding HarfBuzz's clustering behavior options. The cluster level
* dictates one aspect of how HarfBuzz will treat non-base characters
* dictates one aspect of how HarfBuzz will treat non-base characters
* during shaping.
*
* In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES, non-base
* characters are merged into the cluster of the base character that precedes them.
* There is also cluster merging every time the clusters will otherwise become non-monotone.
*
* In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS, non-base characters are initially
* assigned their own cluster values, which are not merged into preceding base
* clusters. This allows HarfBuzz to perform additional operations like reorder
* sequences of adjacent marks.
* sequences of adjacent marks. The output is still monotone, but the cluster
* values are more granular.
*
* In @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS, non-base characters are assigned their
* own cluster values, which are not merged into preceding base clusters. Moreover,
* the cluster values are not merged into monotone order. This is the most granular
* cluster level, and it is useful for clients that need to know the exact cluster
* values of each character, but is harder to use for clients, since clusters
* might appear in any order.
*
* In @HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES, non-base characters are merged into the
* cluster of the base character that precedes them. This is similar to the Unicode
* Grapheme Cluster algorithm, but it is not exactly the same. The output is
* not forced to be monotone. This is useful for clients that want to use HarfBuzz
* as a cheap implementation of the Unicode Grapheme Cluster algorithm.
*
* @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES is the default, because it maintains
* backward compatibility with older versions of HarfBuzz. New client programs that
@ -446,9 +462,52 @@ typedef enum {
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES = 0,
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS = 1,
HB_BUFFER_CLUSTER_LEVEL_CHARACTERS = 2,
HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES = 3,
HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES
} hb_buffer_cluster_level_t;
/**
* HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE:
* @level: #hb_buffer_cluster_level_t to test
*
* Tests whether a cluster level groups cluster values into monotone order.
* Requires that the level be valid.
*
* Since: 11.0.0
*/
#define HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE(level) \
((bool) ((1u << (unsigned) (level)) & \
((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) | \
(1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS))))
/**
* HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES:
* @level: #hb_buffer_cluster_level_t to test
*
* Tests whether a cluster level groups cluster values by graphemes. Requires
* that the level be valid.
*
* Since: 11.0.0
*/
#define HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES(level) \
((bool) ((1u << (unsigned) (level)) & \
((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) | \
(1u << HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES))))
/**
* HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS
* @level: #hb_buffer_cluster_level_t to test
*
* Tests whether a cluster level does not group cluster values by graphemes.
* Requires that the level be valid.
*
* Since: 11.0.0
*/
#define HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS(level) \
((bool) ((1u << (unsigned) (level)) & \
((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARCATERS) | \
(1u << HB_BUFFER_CLUSTER_LEVEL_CHARACTERS))))
HB_EXTERN void
hb_buffer_set_cluster_level (hb_buffer_t *buffer,
hb_buffer_cluster_level_t cluster_level);

View file

@ -229,6 +229,8 @@ struct hb_buffer_t
HB_INTERNAL void add (hb_codepoint_t codepoint,
unsigned int cluster);
HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
HB_INTERNAL void add_info_and_pos (const hb_glyph_info_t &glyph_info,
const hb_glyph_position_t &glyph_pos);
void reverse_range (unsigned start, unsigned end)
{

View file

@ -30,18 +30,31 @@
#include "hb.hh"
/* Implements a lockfree cache for int->int functions.
/* Implements a lockfree and thread-safe cache for int->int functions,
* using (optionally) _relaxed_ atomic integer operations.
*
* The cache is a fixed-size array of 16-bit or 32-bit integers.
* The key is split into two parts: the cache index and the rest.
* The cache is a fixed-size array of 16-bit or 32-bit integers,
* typically 256 elements.
*
* The cache index is used to index into the array. The rest is used
* to store the key and the value.
* The key is split into two parts: the cache index (high bits)
* and the rest (low bits).
*
* The cache index is used to index into the array. The array
* member is a 16-bit or 32-bit integer that is used *both*
* to store the low bits of the key, and the value.
*
* The value is stored in the least significant bits of the integer.
* The key is stored in the most significant bits of the integer.
* The key is shifted by cache_bits to the left to make room for the
* value.
* The low bits of the key are stored in the most significant bits
* of the integer.
*
* A cache hit is detected by comparing the low bits of the key
* with the high bits of the integer at the array position indexed
* by the high bits of the key. If they match, the value is extracted
* from the least significant bits of the integer and returned.
* Otherwise, a cache miss is reported.
*
* Cache operations (storage and retrieval) involve just a few
* arithmetic operations and a single memory access.
*/
template <unsigned int key_bits=16,
@ -52,11 +65,11 @@ struct hb_cache_t
{
using item_t = typename std::conditional<thread_safe,
typename std::conditional<key_bits + value_bits - cache_bits <= 16,
hb_atomic_short_t,
hb_atomic_int_t>::type,
hb_atomic_t<unsigned short>,
hb_atomic_t<unsigned int>>::type,
typename std::conditional<key_bits + value_bits - cache_bits <= 16,
short,
int>::type
unsigned short,
unsigned int>::type
>::type;
static_assert ((key_bits >= cache_bits), "");

View file

@ -726,6 +726,9 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
float span;
span = angles[n_stops - 1] - angles[0];
if (!span)
goto done;
k = 0;
if (angles[0] >= 0)
{

View file

@ -71,7 +71,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
template <typename ACC>
cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
const int *coords_=nullptr, unsigned int num_coords_=0)
: SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs)
: SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs),
cached_scalars_vector (&acc.cached_scalars_vector)
{
coords = coords_;
num_coords = num_coords_;
@ -80,9 +81,39 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
set_ivs (acc.privateDicts[fd].ivs);
}
void fini ()
~cff2_cs_interp_env_t ()
{
SUPER::fini ();
release_scalars_vector (scalars);
}
hb_vector_t<float> *acquire_scalars_vector () const
{
hb_vector_t<float> *scalars = cached_scalars_vector->get_acquire ();
if (!scalars || !cached_scalars_vector->cmpexch (scalars, nullptr))
{
scalars = (hb_vector_t<float> *) hb_calloc (1, sizeof (hb_vector_t<float>));
if (unlikely (!scalars))
return nullptr;
scalars->init ();
}
return scalars;
}
void release_scalars_vector (hb_vector_t<float> *scalars) const
{
if (!scalars)
return;
scalars->clear ();
if (!cached_scalars_vector->cmpexch (nullptr, scalars))
{
scalars->fini ();
hb_free (scalars);
}
scalars = nullptr;
}
op_code_t fetch_op ()
@ -111,14 +142,20 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
{
if (!seen_blend)
{
region_count = varStore->varStore.get_region_index_count (get_ivs ());
if (do_blend)
scalars = acquire_scalars_vector ();
if (unlikely (!scalars))
SUPER::set_error ();
else
{
if (unlikely (!scalars.resize_exact (region_count)))
SUPER::set_error ();
else
varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
&scalars[0], region_count);
region_count = varStore->varStore.get_region_index_count (get_ivs ());
if (do_blend)
{
if (unlikely (!scalars->resize_exact (region_count)))
SUPER::set_error ();
else
varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
&(*scalars)[0], region_count);
}
}
seen_blend = true;
}
@ -149,11 +186,11 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
double v = 0;
if (do_blend)
{
if (likely (scalars.length == deltas.length))
if (likely (scalars && scalars->length == deltas.length))
{
unsigned count = scalars.length;
unsigned count = scalars->length;
for (unsigned i = 0; i < count; i++)
v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real ();
v += (double) scalars->arrayZ[i] * deltas.arrayZ[i].to_real ();
}
}
return v;
@ -167,7 +204,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
const CFF2ItemVariationStore *varStore;
unsigned int region_count;
unsigned int ivs;
hb_vector_t<float> scalars;
hb_vector_t<float> *scalars = nullptr;
hb_atomic_t<hb_vector_t<float> *> *cached_scalars_vector = nullptr;
bool do_blend;
bool seen_vsindex_ = false;
bool seen_blend = false;

View file

@ -42,7 +42,7 @@
/* hb_options_t */
hb_atomic_int_t _hb_options;
hb_atomic_t<unsigned> _hb_options;
void
_hb_options_init ()
@ -273,7 +273,7 @@ struct hb_language_item_t {
/* Thread-safe lockfree language list */
static hb_atomic_ptr_t <hb_language_item_t> langs;
static hb_atomic_t<hb_language_item_t *> langs;
static inline void
free_langs ()
@ -403,7 +403,7 @@ hb_language_to_string (hb_language_t language)
hb_language_t
hb_language_get_default ()
{
static hb_atomic_ptr_t <hb_language_t> default_language;
static hb_atomic_t<hb_language_t> default_language;
hb_language_t language = default_language;
if (unlikely (language == HB_LANGUAGE_INVALID))
@ -968,6 +968,9 @@ hb_feature_from_string (const char *str, int len,
* understood by hb_feature_from_string(). The client in responsible for
* allocating big enough size for @buf, 128 bytes is more than enough.
*
* Note that the feature value will be omitted if it is '1', but the
* string won't include any whitespace.
*
* Since: 0.9.5
**/
void
@ -1121,6 +1124,8 @@ get_C_locale ()
* understood by hb_variation_from_string(). The client in responsible for
* allocating big enough size for @buf, 128 bytes is more than enough.
*
* Note that the string won't include any whitespace.
*
* Since: 1.4.2
*/
void
@ -1212,6 +1217,58 @@ uint8_t
return hb_color_get_blue (color);
}
/**
* hb_malloc:
* @size: The size of the memory to allocate.
*
* Allocates @size bytes of memory, using the allocator set at
* compile-time. Typically just malloc().
*
* Return value: A pointer to the allocated memory.
*
* Since: 11.0.0
**/
void* hb_malloc(size_t size) { return hb_malloc_impl (size); }
/**
* hb_calloc:
* @nmemb: The number of elements to allocate.
* @size: The size of each element.
*
* Allocates @nmemb elements of @size bytes each, initialized to zero,
* using the allocator set at compile-time. Typically just calloc().
*
* Return value: A pointer to the allocated memory.
*
* Since: 11.0.0
**/
void* hb_calloc(size_t nmemb, size_t size) { return hb_calloc_impl (nmemb, size); }
/**
* hb_realloc:
* @ptr: The pointer to the memory to reallocate.
* @size: The new size of the memory.
*
* Reallocates the memory pointed to by @ptr to @size bytes, using the
* allocator set at compile-time. Typically just realloc().
*
* Return value: A pointer to the reallocated memory.
*
* Since: 11.0.0
**/
void* hb_realloc(void *ptr, size_t size) { return hb_realloc_impl (ptr, size); }
/**
* hb_free:
* @ptr: The pointer to the memory to free.
*
* Frees the memory pointed to by @ptr, using the allocator set at
* compile-time. Typically just free().
*
* Since: 11.0.0
**/
void hb_free(void *ptr) { hb_free_impl (ptr); }
/* If there is no visibility control, then hb-static.cc will NOT
* define anything. Instead, we get it to define one set in here

View file

@ -65,6 +65,7 @@ typedef unsigned __int64 uint64_t;
#else
# include <inttypes.h>
#endif
#include <stddef.h>
#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#define HB_DEPRECATED __attribute__((__deprecated__))
@ -337,437 +338,7 @@ HB_EXTERN hb_bool_t
hb_language_matches (hb_language_t language,
hb_language_t specific);
/**
* hb_script_t:
* @HB_SCRIPT_COMMON: `Zyyy`
* @HB_SCRIPT_INHERITED: `Zinh`
* @HB_SCRIPT_UNKNOWN: `Zzzz`
* @HB_SCRIPT_ARABIC: `Arab`
* @HB_SCRIPT_ARMENIAN: `Armn`
* @HB_SCRIPT_BENGALI: `Beng`
* @HB_SCRIPT_CYRILLIC: `Cyrl`
* @HB_SCRIPT_DEVANAGARI: `Deva`
* @HB_SCRIPT_GEORGIAN: `Geor`
* @HB_SCRIPT_GREEK: `Grek`
* @HB_SCRIPT_GUJARATI: `Gujr`
* @HB_SCRIPT_GURMUKHI: `Guru`
* @HB_SCRIPT_HANGUL: `Hang`
* @HB_SCRIPT_HAN: `Hani`
* @HB_SCRIPT_HEBREW: `Hebr`
* @HB_SCRIPT_HIRAGANA: `Hira`
* @HB_SCRIPT_KANNADA: `Knda`
* @HB_SCRIPT_KATAKANA: `Kana`
* @HB_SCRIPT_LAO: `Laoo`
* @HB_SCRIPT_LATIN: `Latn`
* @HB_SCRIPT_MALAYALAM: `Mlym`
* @HB_SCRIPT_ORIYA: `Orya`
* @HB_SCRIPT_TAMIL: `Taml`
* @HB_SCRIPT_TELUGU: `Telu`
* @HB_SCRIPT_THAI: `Thai`
* @HB_SCRIPT_TIBETAN: `Tibt`
* @HB_SCRIPT_BOPOMOFO: `Bopo`
* @HB_SCRIPT_BRAILLE: `Brai`
* @HB_SCRIPT_CANADIAN_SYLLABICS: `Cans`
* @HB_SCRIPT_CHEROKEE: `Cher`
* @HB_SCRIPT_ETHIOPIC: `Ethi`
* @HB_SCRIPT_KHMER: `Khmr`
* @HB_SCRIPT_MONGOLIAN: `Mong`
* @HB_SCRIPT_MYANMAR: `Mymr`
* @HB_SCRIPT_OGHAM: `Ogam`
* @HB_SCRIPT_RUNIC: `Runr`
* @HB_SCRIPT_SINHALA: `Sinh`
* @HB_SCRIPT_SYRIAC: `Syrc`
* @HB_SCRIPT_THAANA: `Thaa`
* @HB_SCRIPT_YI: `Yiii`
* @HB_SCRIPT_DESERET: `Dsrt`
* @HB_SCRIPT_GOTHIC: `Goth`
* @HB_SCRIPT_OLD_ITALIC: `Ital`
* @HB_SCRIPT_BUHID: `Buhd`
* @HB_SCRIPT_HANUNOO: `Hano`
* @HB_SCRIPT_TAGALOG: `Tglg`
* @HB_SCRIPT_TAGBANWA: `Tagb`
* @HB_SCRIPT_CYPRIOT: `Cprt`
* @HB_SCRIPT_LIMBU: `Limb`
* @HB_SCRIPT_LINEAR_B: `Linb`
* @HB_SCRIPT_OSMANYA: `Osma`
* @HB_SCRIPT_SHAVIAN: `Shaw`
* @HB_SCRIPT_TAI_LE: `Tale`
* @HB_SCRIPT_UGARITIC: `Ugar`
* @HB_SCRIPT_BUGINESE: `Bugi`
* @HB_SCRIPT_COPTIC: `Copt`
* @HB_SCRIPT_GLAGOLITIC: `Glag`
* @HB_SCRIPT_KHAROSHTHI: `Khar`
* @HB_SCRIPT_NEW_TAI_LUE: `Talu`
* @HB_SCRIPT_OLD_PERSIAN: `Xpeo`
* @HB_SCRIPT_SYLOTI_NAGRI: `Sylo`
* @HB_SCRIPT_TIFINAGH: `Tfng`
* @HB_SCRIPT_BALINESE: `Bali`
* @HB_SCRIPT_CUNEIFORM: `Xsux`
* @HB_SCRIPT_NKO: `Nkoo`
* @HB_SCRIPT_PHAGS_PA: `Phag`
* @HB_SCRIPT_PHOENICIAN: `Phnx`
* @HB_SCRIPT_CARIAN: `Cari`
* @HB_SCRIPT_CHAM: `Cham`
* @HB_SCRIPT_KAYAH_LI: `Kali`
* @HB_SCRIPT_LEPCHA: `Lepc`
* @HB_SCRIPT_LYCIAN: `Lyci`
* @HB_SCRIPT_LYDIAN: `Lydi`
* @HB_SCRIPT_OL_CHIKI: `Olck`
* @HB_SCRIPT_REJANG: `Rjng`
* @HB_SCRIPT_SAURASHTRA: `Saur`
* @HB_SCRIPT_SUNDANESE: `Sund`
* @HB_SCRIPT_VAI: `Vaii`
* @HB_SCRIPT_AVESTAN: `Avst`
* @HB_SCRIPT_BAMUM: `Bamu`
* @HB_SCRIPT_EGYPTIAN_HIEROGLYPHS: `Egyp`
* @HB_SCRIPT_IMPERIAL_ARAMAIC: `Armi`
* @HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: `Phli`
* @HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: `Prti`
* @HB_SCRIPT_JAVANESE: `Java`
* @HB_SCRIPT_KAITHI: `Kthi`
* @HB_SCRIPT_LISU: `Lisu`
* @HB_SCRIPT_MEETEI_MAYEK: `Mtei`
* @HB_SCRIPT_OLD_SOUTH_ARABIAN: `Sarb`
* @HB_SCRIPT_OLD_TURKIC: `Orkh`
* @HB_SCRIPT_SAMARITAN: `Samr`
* @HB_SCRIPT_TAI_THAM: `Lana`
* @HB_SCRIPT_TAI_VIET: `Tavt`
* @HB_SCRIPT_BATAK: `Batk`
* @HB_SCRIPT_BRAHMI: `Brah`
* @HB_SCRIPT_MANDAIC: `Mand`
* @HB_SCRIPT_CHAKMA: `Cakm`
* @HB_SCRIPT_MEROITIC_CURSIVE: `Merc`
* @HB_SCRIPT_MEROITIC_HIEROGLYPHS: `Mero`
* @HB_SCRIPT_MIAO: `Plrd`
* @HB_SCRIPT_SHARADA: `Shrd`
* @HB_SCRIPT_SORA_SOMPENG: `Sora`
* @HB_SCRIPT_TAKRI: `Takr`
* @HB_SCRIPT_BASSA_VAH: `Bass`, Since: 0.9.30
* @HB_SCRIPT_CAUCASIAN_ALBANIAN: `Aghb`, Since: 0.9.30
* @HB_SCRIPT_DUPLOYAN: `Dupl`, Since: 0.9.30
* @HB_SCRIPT_ELBASAN: `Elba`, Since: 0.9.30
* @HB_SCRIPT_GRANTHA: `Gran`, Since: 0.9.30
* @HB_SCRIPT_KHOJKI: `Khoj`, Since: 0.9.30
* @HB_SCRIPT_KHUDAWADI: `Sind`, Since: 0.9.30
* @HB_SCRIPT_LINEAR_A: `Lina`, Since: 0.9.30
* @HB_SCRIPT_MAHAJANI: `Mahj`, Since: 0.9.30
* @HB_SCRIPT_MANICHAEAN: `Mani`, Since: 0.9.30
* @HB_SCRIPT_MENDE_KIKAKUI: `Mend`, Since: 0.9.30
* @HB_SCRIPT_MODI: `Modi`, Since: 0.9.30
* @HB_SCRIPT_MRO: `Mroo`, Since: 0.9.30
* @HB_SCRIPT_NABATAEAN: `Nbat`, Since: 0.9.30
* @HB_SCRIPT_OLD_NORTH_ARABIAN: `Narb`, Since: 0.9.30
* @HB_SCRIPT_OLD_PERMIC: `Perm`, Since: 0.9.30
* @HB_SCRIPT_PAHAWH_HMONG: `Hmng`, Since: 0.9.30
* @HB_SCRIPT_PALMYRENE: `Palm`, Since: 0.9.30
* @HB_SCRIPT_PAU_CIN_HAU: `Pauc`, Since: 0.9.30
* @HB_SCRIPT_PSALTER_PAHLAVI: `Phlp`, Since: 0.9.30
* @HB_SCRIPT_SIDDHAM: `Sidd`, Since: 0.9.30
* @HB_SCRIPT_TIRHUTA: `Tirh`, Since: 0.9.30
* @HB_SCRIPT_WARANG_CITI: `Wara`, Since: 0.9.30
* @HB_SCRIPT_AHOM: `Ahom`, Since: 0.9.30
* @HB_SCRIPT_ANATOLIAN_HIEROGLYPHS: `Hluw`, Since: 0.9.30
* @HB_SCRIPT_HATRAN: `Hatr`, Since: 0.9.30
* @HB_SCRIPT_MULTANI: `Mult`, Since: 0.9.30
* @HB_SCRIPT_OLD_HUNGARIAN: `Hung`, Since: 0.9.30
* @HB_SCRIPT_SIGNWRITING: `Sgnw`, Since: 0.9.30
* @HB_SCRIPT_ADLAM: `Adlm`, Since: 1.3.0
* @HB_SCRIPT_BHAIKSUKI: `Bhks`, Since: 1.3.0
* @HB_SCRIPT_MARCHEN: `Marc`, Since: 1.3.0
* @HB_SCRIPT_OSAGE: `Osge`, Since: 1.3.0
* @HB_SCRIPT_TANGUT: `Tang`, Since: 1.3.0
* @HB_SCRIPT_NEWA: `Newa`, Since: 1.3.0
* @HB_SCRIPT_MASARAM_GONDI: `Gonm`, Since: 1.6.0
* @HB_SCRIPT_NUSHU: `Nshu`, Since: 1.6.0
* @HB_SCRIPT_SOYOMBO: `Soyo`, Since: 1.6.0
* @HB_SCRIPT_ZANABAZAR_SQUARE: `Zanb`, Since: 1.6.0
* @HB_SCRIPT_DOGRA: `Dogr`, Since: 1.8.0
* @HB_SCRIPT_GUNJALA_GONDI: `Gong`, Since: 1.8.0
* @HB_SCRIPT_HANIFI_ROHINGYA: `Rohg`, Since: 1.8.0
* @HB_SCRIPT_MAKASAR: `Maka`, Since: 1.8.0
* @HB_SCRIPT_MEDEFAIDRIN: `Medf`, Since: 1.8.0
* @HB_SCRIPT_OLD_SOGDIAN: `Sogo`, Since: 1.8.0
* @HB_SCRIPT_SOGDIAN: `Sogd`, Since: 1.8.0
* @HB_SCRIPT_ELYMAIC: `Elym`, Since: 2.4.0
* @HB_SCRIPT_NANDINAGARI: `Nand`, Since: 2.4.0
* @HB_SCRIPT_NYIAKENG_PUACHUE_HMONG: `Hmnp`, Since: 2.4.0
* @HB_SCRIPT_WANCHO: `Wcho`, Since: 2.4.0
* @HB_SCRIPT_CHORASMIAN: `Chrs`, Since: 2.6.7
* @HB_SCRIPT_DIVES_AKURU: `Diak`, Since: 2.6.7
* @HB_SCRIPT_KHITAN_SMALL_SCRIPT: `Kits`, Since: 2.6.7
* @HB_SCRIPT_YEZIDI: `Yezi`, Since: 2.6.7
* @HB_SCRIPT_CYPRO_MINOAN: `Cpmn`, Since: 3.0.0
* @HB_SCRIPT_OLD_UYGHUR: `Ougr`, Since: 3.0.0
* @HB_SCRIPT_TANGSA: `Tnsa`, Since: 3.0.0
* @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0
* @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0
* @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0
* @HB_SCRIPT_KAWI: `Kawi`, Since: 5.2.0
* @HB_SCRIPT_NAG_MUNDARI: `Nagm`, Since: 5.2.0
* @HB_SCRIPT_GARAY: `Gara`, Since: 10.0.0
* @HB_SCRIPT_GURUNG_KHEMA: `Gukh`, Since: 10.0.0
* @HB_SCRIPT_KIRAT_RAI: `Krai`, Since: 10.0.0
* @HB_SCRIPT_OL_ONAL: `Onao`, Since: 10.0.0
* @HB_SCRIPT_SUNUWAR: `Sunu`, Since: 10.0.0
* @HB_SCRIPT_TODHRI: `Todr`, Since: 10.0.0
* @HB_SCRIPT_TULU_TIGALARI: `Tutg`, Since: 10.0.0
* @HB_SCRIPT_INVALID: No script set
*
* Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
* to the four-letter values defined by [ISO 15924](https://unicode.org/iso15924/).
*
* See also the Script (sc) property of the Unicode Character Database.
*
**/
/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
typedef enum
{
HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'), /*1.1*/
HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'), /*1.1*/
HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'), /*5.0*/
HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'), /*1.1*/
HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'), /*1.1*/
HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'), /*1.1*/
HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'), /*1.1*/
HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'), /*1.1*/
HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'), /*1.1*/
HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'), /*1.1*/
HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'), /*1.1*/
HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'), /*1.1*/
HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'), /*1.1*/
HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'), /*1.1*/
HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'), /*1.1*/
HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'), /*1.1*/
HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'), /*1.1*/
HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'), /*1.1*/
HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'), /*1.1*/
HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'), /*1.1*/
HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'), /*1.1*/
HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'), /*1.1*/
HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'), /*1.1*/
HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'), /*1.1*/
HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'), /*1.1*/
HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'), /*2.0*/
HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'), /*3.0*/
HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'), /*3.0*/
HB_SCRIPT_CANADIAN_SYLLABICS = HB_TAG ('C','a','n','s'), /*3.0*/
HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'), /*3.0*/
HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'), /*3.0*/
HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'), /*3.0*/
HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'), /*3.0*/
HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'), /*3.0*/
HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'), /*3.0*/
HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'), /*3.0*/
HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'), /*3.0*/
HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'), /*3.0*/
HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'), /*3.0*/
HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'), /*3.0*/
HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'), /*3.1*/
HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'), /*3.1*/
HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'), /*3.1*/
HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'), /*3.2*/
HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'), /*3.2*/
HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'), /*3.2*/
HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'), /*3.2*/
HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'), /*4.0*/
HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'), /*4.0*/
HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'), /*4.0*/
HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'), /*4.0*/
HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'), /*4.0*/
HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'), /*4.0*/
HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'), /*4.0*/
HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'), /*4.1*/
HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'), /*4.1*/
HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'), /*4.1*/
HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'), /*4.1*/
HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'), /*4.1*/
HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'), /*4.1*/
HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'), /*4.1*/
HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'), /*4.1*/
HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'), /*5.0*/
HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'), /*5.0*/
HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'), /*5.0*/
HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'), /*5.0*/
HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'), /*5.0*/
HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'), /*5.1*/
HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'), /*5.1*/
HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'), /*5.1*/
HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'), /*5.1*/
HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'), /*5.1*/
HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'), /*5.1*/
HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'), /*5.1*/
HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'), /*5.1*/
HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'), /*5.1*/
HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'), /*5.1*/
HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'), /*5.1*/
HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'), /*5.2*/
HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'), /*5.2*/
HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'), /*5.2*/
HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'), /*5.2*/
HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'), /*5.2*/
HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'), /*5.2*/
HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'), /*5.2*/
HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'), /*5.2*/
HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'), /*5.2*/
HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'), /*5.2*/
HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'), /*5.2*/
HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'), /*5.2*/
HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'), /*5.2*/
HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'), /*5.2*/
HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'), /*5.2*/
HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'), /*6.0*/
HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'), /*6.0*/
HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'), /*6.0*/
HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'), /*6.1*/
HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'), /*6.1*/
HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'), /*6.1*/
HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'), /*6.1*/
HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'), /*6.1*/
HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'), /*6.1*/
HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'), /*6.1*/
/*
* Since: 0.9.30
*/
HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'), /*7.0*/
HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'), /*7.0*/
HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'), /*7.0*/
HB_SCRIPT_ELBASAN = HB_TAG ('E','l','b','a'), /*7.0*/
HB_SCRIPT_GRANTHA = HB_TAG ('G','r','a','n'), /*7.0*/
HB_SCRIPT_KHOJKI = HB_TAG ('K','h','o','j'), /*7.0*/
HB_SCRIPT_KHUDAWADI = HB_TAG ('S','i','n','d'), /*7.0*/
HB_SCRIPT_LINEAR_A = HB_TAG ('L','i','n','a'), /*7.0*/
HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'), /*7.0*/
HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'), /*7.0*/
HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'), /*7.0*/
HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'), /*7.0*/
HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'), /*7.0*/
HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'), /*7.0*/
HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'), /*7.0*/
HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'), /*7.0*/
HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'), /*7.0*/
HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'), /*7.0*/
HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'), /*7.0*/
HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'), /*7.0*/
HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'), /*7.0*/
HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'), /*7.0*/
HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'), /*7.0*/
HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'), /*8.0*/
HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'), /*8.0*/
HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'), /*8.0*/
HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'), /*8.0*/
HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'), /*8.0*/
HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'), /*8.0*/
/*
* Since 1.3.0
*/
HB_SCRIPT_ADLAM = HB_TAG ('A','d','l','m'), /*9.0*/
HB_SCRIPT_BHAIKSUKI = HB_TAG ('B','h','k','s'), /*9.0*/
HB_SCRIPT_MARCHEN = HB_TAG ('M','a','r','c'), /*9.0*/
HB_SCRIPT_OSAGE = HB_TAG ('O','s','g','e'), /*9.0*/
HB_SCRIPT_TANGUT = HB_TAG ('T','a','n','g'), /*9.0*/
HB_SCRIPT_NEWA = HB_TAG ('N','e','w','a'), /*9.0*/
/*
* Since 1.6.0
*/
HB_SCRIPT_MASARAM_GONDI = HB_TAG ('G','o','n','m'), /*10.0*/
HB_SCRIPT_NUSHU = HB_TAG ('N','s','h','u'), /*10.0*/
HB_SCRIPT_SOYOMBO = HB_TAG ('S','o','y','o'), /*10.0*/
HB_SCRIPT_ZANABAZAR_SQUARE = HB_TAG ('Z','a','n','b'), /*10.0*/
/*
* Since 1.8.0
*/
HB_SCRIPT_DOGRA = HB_TAG ('D','o','g','r'), /*11.0*/
HB_SCRIPT_GUNJALA_GONDI = HB_TAG ('G','o','n','g'), /*11.0*/
HB_SCRIPT_HANIFI_ROHINGYA = HB_TAG ('R','o','h','g'), /*11.0*/
HB_SCRIPT_MAKASAR = HB_TAG ('M','a','k','a'), /*11.0*/
HB_SCRIPT_MEDEFAIDRIN = HB_TAG ('M','e','d','f'), /*11.0*/
HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'), /*11.0*/
HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'), /*11.0*/
/*
* Since 2.4.0
*/
HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'), /*12.0*/
HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'), /*12.0*/
HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'), /*12.0*/
HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'), /*12.0*/
/*
* Since 2.6.7
*/
HB_SCRIPT_CHORASMIAN = HB_TAG ('C','h','r','s'), /*13.0*/
HB_SCRIPT_DIVES_AKURU = HB_TAG ('D','i','a','k'), /*13.0*/
HB_SCRIPT_KHITAN_SMALL_SCRIPT = HB_TAG ('K','i','t','s'), /*13.0*/
HB_SCRIPT_YEZIDI = HB_TAG ('Y','e','z','i'), /*13.0*/
/*
* Since 3.0.0
*/
HB_SCRIPT_CYPRO_MINOAN = HB_TAG ('C','p','m','n'), /*14.0*/
HB_SCRIPT_OLD_UYGHUR = HB_TAG ('O','u','g','r'), /*14.0*/
HB_SCRIPT_TANGSA = HB_TAG ('T','n','s','a'), /*14.0*/
HB_SCRIPT_TOTO = HB_TAG ('T','o','t','o'), /*14.0*/
HB_SCRIPT_VITHKUQI = HB_TAG ('V','i','t','h'), /*14.0*/
/*
* Since 3.4.0
*/
HB_SCRIPT_MATH = HB_TAG ('Z','m','t','h'),
/*
* Since 5.2.0
*/
HB_SCRIPT_KAWI = HB_TAG ('K','a','w','i'), /*15.0*/
HB_SCRIPT_NAG_MUNDARI = HB_TAG ('N','a','g','m'), /*15.0*/
/*
* Since 10.0.0
*/
HB_SCRIPT_GARAY = HB_TAG ('G','a','r','a'), /*16.0*/
HB_SCRIPT_GURUNG_KHEMA = HB_TAG ('G','u','k','h'), /*16.0*/
HB_SCRIPT_KIRAT_RAI = HB_TAG ('K','r','a','i'), /*16.0*/
HB_SCRIPT_OL_ONAL = HB_TAG ('O','n','a','o'), /*16.0*/
HB_SCRIPT_SUNUWAR = HB_TAG ('S','u','n','u'), /*16.0*/
HB_SCRIPT_TODHRI = HB_TAG ('T','o','d','r'), /*16.0*/
HB_SCRIPT_TULU_TIGALARI = HB_TAG ('T','u','t','g'), /*16.0*/
/* No script set. */
HB_SCRIPT_INVALID = HB_TAG_NONE,
/*< private >*/
/* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
* without risking undefined behavior. We have two, for historical reasons.
* HB_TAG_MAX used to be unsigned, but that was invalid Ansi C, so was changed
* to _HB_SCRIPT_MAX_VALUE to be equal to HB_TAG_MAX_SIGNED as well.
*
* See this thread for technicalities:
*
* https://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
*/
_HB_SCRIPT_MAX_VALUE = HB_TAG_MAX_SIGNED, /*< skip >*/
_HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_script_t;
#include "hb-script-list.h"
/* Script functions */
@ -948,6 +519,16 @@ typedef struct hb_glyph_extents_t {
*/
typedef struct hb_font_t hb_font_t;
/* Not of much use to clients. */
HB_EXTERN void*
hb_malloc (size_t size);
HB_EXTERN void*
hb_calloc (size_t nmemb, size_t size);
HB_EXTERN void*
hb_realloc (void *ptr, size_t size);
HB_EXTERN void
hb_free (void *ptr);
HB_END_DECLS
#endif /* HB_COMMON_H */

View file

@ -146,6 +146,7 @@
#ifdef HB_NO_DRAW
#define HB_NO_OUTLINE
#define HB_NO_PAINT
#endif
#ifdef HB_NO_GETENV
@ -191,7 +192,6 @@
#ifdef HB_MINIMIZE_MEMORY_USAGE
#define HB_NO_GDEF_CACHE
#define HB_NO_OT_LAYOUT_LOOKUP_CACHE
#define HB_NO_OT_FONT_ADVANCE_CACHE
#define HB_NO_OT_FONT_CMAP_CACHE
#endif

View file

@ -28,7 +28,8 @@
#ifdef HAVE_CORETEXT
#include "hb-coretext.h"
#include "hb-coretext.hh"
#include "hb-aat-layout-trak-table.hh"
#include "hb-draw.hh"
#include "hb-font.hh"
@ -42,24 +43,17 @@
# define kCTFontOrientationVertical kCTFontVerticalOrientation
#endif
#define MAX_GLYPHS 64u
static void
_hb_coretext_font_destroy (void *font_data)
{
CTFontRef ct_font = (CTFontRef) font_data;
CFRelease (ct_font);
}
#define MAX_GLYPHS 256u
static hb_bool_t
hb_coretext_get_nominal_glyph (hb_font_t *font HB_UNUSED,
void *font_data,
hb_coretext_get_nominal_glyph (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t unicode,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
UniChar ch[2];
CGGlyph cg_glyph[2];
unsigned count = 0;
@ -85,7 +79,7 @@ hb_coretext_get_nominal_glyph (hb_font_t *font HB_UNUSED,
}
static unsigned int
hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
hb_coretext_get_nominal_glyphs (hb_font_t *font,
void *font_data,
unsigned int count,
const hb_codepoint_t *first_unicode,
@ -94,6 +88,8 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
unsigned int glyph_stride,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
// If any non-BMP codepoint is requested, use the slow path.
bool slow_path = false;
auto *unicode = first_unicode;
@ -119,8 +115,6 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
return count;
}
CTFontRef ct_font = (CTFontRef) font_data;
UniChar ch[MAX_GLYPHS];
CGGlyph cg_glyph[MAX_GLYPHS];
for (unsigned i = 0; i < count; i += MAX_GLYPHS)
@ -152,14 +146,14 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
}
static hb_bool_t
hb_coretext_get_variation_glyph (hb_font_t *font HB_UNUSED,
void *font_data,
hb_coretext_get_variation_glyph (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t unicode,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
UniChar ch[4];
CGGlyph cg_glyph[4];
@ -194,12 +188,17 @@ hb_coretext_get_variation_glyph (hb_font_t *font HB_UNUSED,
if (cg_glyph[i])
return false;
// Humm. CoreText falls back to the default glyph if the variation selector
// is not supported. We cannot truly detect that case. So, in essence,
// we are always returning true here...
*glyph = cg_glyph[0];
return true;
}
static void
hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
hb_coretext_get_glyph_h_advances (hb_font_t* font,
void* font_data HB_UNUSED,
unsigned count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
@ -207,10 +206,11 @@ hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
hb_position_t tracking = font->face->table.trak->get_tracking (font, HB_DIRECTION_LTR, 0.f);
CGGlyph cg_glyph[MAX_GLYPHS];
CGSize advances[MAX_GLYPHS];
@ -225,7 +225,7 @@ hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationHorizontal, cg_glyph, advances, c);
for (unsigned j = 0; j < c; j++)
{
*first_advance = round (advances[j].width * x_mult);
*first_advance = round (advances[j].width * x_mult) - tracking;
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
}
}
@ -233,7 +233,8 @@ hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
#ifndef HB_NO_VERTICAL
static void
hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data,
hb_coretext_get_glyph_v_advances (hb_font_t* font,
void* font_data HB_UNUSED,
unsigned count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
@ -241,10 +242,11 @@ hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat y_mult = (CGFloat) -font->y_scale / ct_font_size;
hb_position_t tracking = font->face->table.trak->get_tracking (font, HB_DIRECTION_TTB, 0.f);
CGGlyph cg_glyph[MAX_GLYPHS];
CGSize advances[MAX_GLYPHS];
@ -259,23 +261,21 @@ hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data,
CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationVertical, cg_glyph, advances, c);
for (unsigned j = 0; j < c; j++)
{
*first_advance = round (advances[j].width * y_mult);
*first_advance = round (advances[j].width * y_mult) - tracking;
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
}
}
}
#endif
#ifndef HB_NO_VERTICAL
static hb_bool_t
hb_coretext_get_glyph_v_origin (hb_font_t *font,
void *font_data,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat x_mult = (CGFloat) -font->x_scale / ct_font_size;
@ -294,12 +294,12 @@ hb_coretext_get_glyph_v_origin (hb_font_t *font,
static hb_bool_t
hb_coretext_get_glyph_extents (hb_font_t *font,
void *font_data,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
@ -310,20 +310,21 @@ hb_coretext_get_glyph_extents (hb_font_t *font,
kCTFontOrientationDefault, glyphs, NULL, 1);
extents->x_bearing = round (bounds.origin.x * x_mult);
extents->y_bearing = round (bounds.origin.y * y_mult);
extents->y_bearing = round ((bounds.origin.y + bounds.size.height) * y_mult);
extents->width = round (bounds.size.width * x_mult);
extents->height = round (bounds.size.height * y_mult);
extents->height = round (bounds.origin.y * y_mult) - extents->y_bearing;
return true;
}
static hb_bool_t
hb_coretext_get_font_h_extents (hb_font_t *font,
void *font_data,
void *font_data HB_UNUSED,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
@ -371,7 +372,7 @@ hb_coretext_draw_glyph (hb_font_t *font,
hb_draw_funcs_t *draw_funcs, void *draw_data,
void *user_data)
{
CTFontRef ct_font = (CTFontRef) font_data;
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
@ -415,17 +416,20 @@ hb_coretext_get_glyph_name (hb_font_t *font,
(UInt8 *) name, size, &len);
name[len] = '\0';
CFRelease (cf_name);
return true;
}
static hb_bool_t
hb_coretext_get_glyph_from_name (hb_font_t *font HB_UNUSED,
void *font_data,
hb_coretext_get_glyph_from_name (hb_font_t *font,
void *font_data HB_UNUSED,
const char *name, int len,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
if (len == -1)
len = strlen (name);
@ -458,10 +462,8 @@ static struct hb_coretext_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t
hb_font_funcs_set_font_h_extents_func (funcs, hb_coretext_get_font_h_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_h_advances_func (funcs, hb_coretext_get_glyph_h_advances, nullptr, nullptr);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_coretext_get_glyph_h_origin, nullptr, nullptr);
#ifndef HB_NO_VERTICAL
//hb_font_funcs_set_font_v_extents_func (funcs, hb_coretext_get_font_v_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_v_advances_func (funcs, hb_coretext_get_glyph_v_advances, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_coretext_get_glyph_v_origin, nullptr, nullptr);
#endif
@ -530,8 +532,7 @@ hb_coretext_font_set_funcs (hb_font_t *font)
hb_font_set_funcs (font,
_hb_coretext_get_font_funcs (),
(void *) CFRetain (ct_font),
_hb_coretext_font_destroy);
nullptr, nullptr);
}
#undef MAX_GLYPHS

View file

@ -32,279 +32,9 @@
#include "hb-shaper-impl.hh"
#include "hb-coretext.h"
#include "hb-coretext.hh"
#include "hb-aat-layout.hh"
/**
* SECTION:hb-coretext
* @title: hb-coretext
* @short_description: CoreText integration
* @include: hb-coretext.h
*
* Functions for using HarfBuzz with the CoreText fonts.
**/
static CTFontRef create_ct_font (CGFontRef cg_font, CGFloat font_size);
static void
release_table_data (void *user_data)
{
CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
CFRelease(cf_data);
}
static hb_blob_t *
_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
if (unlikely (!cf_data))
return nullptr;
const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
const size_t length = CFDataGetLength (cf_data);
if (!data || !length)
{
CFRelease (cf_data);
return nullptr;
}
return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
release_table_data);
}
static unsigned
_hb_cg_get_table_tags (const hb_face_t *face HB_UNUSED,
unsigned int start_offset,
unsigned int *table_count,
hb_tag_t *table_tags,
void *user_data)
{
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
CTFontRef ct_font = create_ct_font (cg_font, (CGFloat) HB_CORETEXT_DEFAULT_FONT_SIZE);
auto arr = CTFontCopyAvailableTables (ct_font, kCTFontTableOptionNoOptions);
unsigned population = (unsigned) CFArrayGetCount (arr);
unsigned end_offset;
if (!table_count)
goto done;
if (unlikely (start_offset >= population))
{
*table_count = 0;
goto done;
}
end_offset = start_offset + *table_count;
if (unlikely (end_offset < start_offset))
{
*table_count = 0;
goto done;
}
end_offset= hb_min (end_offset, (unsigned) population);
*table_count = end_offset - start_offset;
for (unsigned i = start_offset; i < end_offset; i++)
{
CTFontTableTag tag = (CTFontTableTag)(uintptr_t) CFArrayGetValueAtIndex (arr, i);
table_tags[i - start_offset] = tag;
}
done:
CFRelease (arr);
CFRelease (ct_font);
return population;
}
static void
_hb_cg_font_release (void *data)
{
CGFontRelease ((CGFontRef) data);
}
static CTFontDescriptorRef
get_last_resort_font_desc ()
{
// TODO Handle allocation failures?
CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
(const void **) &last_resort,
1,
&kCFTypeArrayCallBacks);
CFRelease (last_resort);
CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
(const void **) &kCTFontCascadeListAttribute,
(const void **) &cascade_list,
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease (cascade_list);
CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
CFRelease (attributes);
return font_desc;
}
static void
release_data (void *info, const void *data, size_t size)
{
assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
hb_blob_destroy ((hb_blob_t *) info);
}
static CGFontRef
create_cg_font (hb_face_t *face)
{
CGFontRef cg_font = nullptr;
if (face->destroy == _hb_cg_font_release)
{
cg_font = CGFontRetain ((CGFontRef) face->user_data);
}
else
{
hb_blob_t *blob = hb_face_reference_blob (face);
unsigned int blob_length;
const char *blob_data = hb_blob_get_data (blob, &blob_length);
if (unlikely (!blob_length))
DEBUG_MSG (CORETEXT, face, "Face has empty blob");
CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
if (likely (provider))
{
cg_font = CGFontCreateWithDataProvider (provider);
if (unlikely (!cg_font))
DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
CGDataProviderRelease (provider);
}
}
return cg_font;
}
static CTFontRef
create_ct_font (CGFontRef cg_font, CGFloat font_size)
{
CTFontRef ct_font = nullptr;
/* CoreText does not enable trak table usage / tracking when creating a CTFont
* using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
* to be through the CTFontCreateUIFontForLanguage call. */
CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
{
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
# define kCTFontUIFontSystem kCTFontSystemFontType
# define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
#endif
CTFontUIFontType font_type = kCTFontUIFontSystem;
if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
font_type = kCTFontUIFontEmphasizedSystem;
ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
{
CFRelease(ct_font);
ct_font = nullptr;
}
CFRelease (ct_result_name);
}
CFRelease (cg_postscript_name);
if (!ct_font)
ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
if (unlikely (!ct_font)) {
DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
return nullptr;
}
/* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
* bug indicate that the cascade list reconfiguration occasionally causes
* crashes in CoreText on OS X 10.9, thus let's skip this step on older
* operating system versions. Except for the emoji font, where _not_
* reconfiguring the cascade list causes CoreText crashes. For details, see
* crbug.com/549610 */
// 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
#pragma GCC diagnostic pop
CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
CFRelease (fontName);
if (!isEmojiFont)
return ct_font;
}
CFURLRef original_url = nullptr;
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
ATSFontRef atsFont;
FSRef fsref;
OSStatus status;
atsFont = CTFontGetPlatformFont (ct_font, NULL);
status = ATSFontGetFileReference (atsFont, &fsref);
if (status == noErr)
original_url = CFURLCreateFromFSRef (NULL, &fsref);
#else
original_url = (CFURLRef) CTFontCopyAttribute (ct_font, kCTFontURLAttribute);
#endif
/* Create font copy with cascade list that has LastResort first; this speeds up CoreText
* font fallback which we don't need anyway. */
{
CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
CFRelease (last_resort_font_desc);
if (new_ct_font)
{
/* The CTFontCreateCopyWithAttributes call fails to stay on the same font
* when reconfiguring the cascade list and may switch to a different font
* when there are fonts that go by the same name, since the descriptor is
* just name and size.
*
* Avoid reconfiguring the cascade lists if the new font is outside the
* system locations that we cannot access from the sandboxed renderer
* process in Blink. This can be detected by the new file URL location
* that the newly found font points to. */
CFURLRef new_url = nullptr;
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
status = ATSFontGetFileReference (atsFont, &fsref);
if (status == noErr)
new_url = CFURLCreateFromFSRef (NULL, &fsref);
#else
new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
#endif
// Keep reconfigured font if URL cannot be retrieved (seems to be the case
// on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
if (!original_url || !new_url || CFEqual (original_url, new_url)) {
CFRelease (ct_font);
ct_font = new_ct_font;
} else {
CFRelease (new_ct_font);
DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
}
if (new_url)
CFRelease (new_url);
}
else
DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
}
if (original_url)
CFRelease (original_url);
return ct_font;
}
hb_coretext_face_data_t *
_hb_coretext_shaper_face_data_create (hb_face_t *face)
{
@ -325,102 +55,6 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data)
CFRelease ((CGFontRef) data);
}
/**
* hb_coretext_face_create:
* @cg_font: The CGFontRef to work upon
*
* Creates an #hb_face_t face object from the specified
* CGFontRef.
*
* Return value: (transfer full): The new face object
*
* Since: 0.9.10
*/
hb_face_t *
hb_coretext_face_create (CGFontRef cg_font)
{
hb_face_t *face = hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
hb_face_set_get_table_tags_func (face, _hb_cg_get_table_tags, cg_font, nullptr);
return face;
}
/**
* hb_coretext_face_create_from_file_or_fail:
* @file_name: A font filename
* @index: The index of the face within the file
*
* Creates an #hb_face_t face object from the specified
* font file and face index.
*
* This is similar in functionality to hb_face_create_from_file_or_fail(),
* but uses the CoreText library for loading the font file.
*
* Return value: (transfer full): The new face object, or `NULL` if
* no face is found at the specified index or the file cannot be read.
*
* Since: 10.1.0
*/
hb_face_t *
hb_coretext_face_create_from_file_or_fail (const char *file_name,
unsigned int index)
{
auto url = CFURLCreateFromFileSystemRepresentation (nullptr,
(const UInt8 *) file_name,
strlen (file_name),
false);
if (unlikely (!url))
return nullptr;
auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromURL (url);
if (unlikely (!ct_font_desc_array))
{
CFRelease (url);
return nullptr;
}
auto ct_font_desc = (CFArrayGetCount (ct_font_desc_array) > index) ?
(CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, index) : nullptr;
if (unlikely (!ct_font_desc))
{
CFRelease (ct_font_desc_array);
CFRelease (url);
return nullptr;
}
CFRelease (url);
auto ct_font = ct_font_desc ? CTFontCreateWithFontDescriptor (ct_font_desc, 0, nullptr) : nullptr;
CFRelease (ct_font_desc_array);
if (unlikely (!ct_font))
return nullptr;
auto cg_font = ct_font ? CTFontCopyGraphicsFont (ct_font, nullptr) : nullptr;
CFRelease (ct_font);
if (unlikely (!cg_font))
return nullptr;
hb_face_t *face = hb_coretext_face_create (cg_font);
CFRelease (cg_font);
if (unlikely (hb_face_is_immutable (face)))
return nullptr;
return face;
}
/**
* hb_coretext_face_get_cg_font:
* @face: The #hb_face_t to work upon
*
* Fetches the CGFontRef associated with an #hb_face_t
* face object
*
* Return value: the CGFontRef found
*
* Since: 0.9.10
*/
CGFontRef
hb_coretext_face_get_cg_font (hb_face_t *face)
{
return (CGFontRef) (const void *) face->data.coretext;
}
hb_coretext_font_data_t *
_hb_coretext_shaper_font_data_create (hb_font_t *font)
@ -439,7 +73,9 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
return nullptr;
}
if (font->num_coords)
unsigned num_axes = hb_ot_var_get_axis_count (face);
// https://github.com/harfbuzz/harfbuzz/issues/5163
if (num_axes)
{
CFMutableDictionaryRef variations =
CFDictionaryCreateMutable (kCFAllocatorDefault,
@ -447,14 +83,15 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
for (unsigned i = 0; i < font->num_coords; i++)
unsigned count = hb_max (num_axes, font->num_coords);
for (unsigned i = 0; i < count; i++)
{
hb_ot_var_axis_info_t info;
unsigned int c = 1;
hb_ot_var_get_axis_infos (font->face, i, &c, &info);
if (font->design_coords[i] == info.default_value)
continue;
float v = hb_clamp (font->design_coords[i], info.min_value, info.max_value);
float v = i < font->num_coords ?
hb_clamp (font->design_coords[i], info.min_value, info.max_value) :
info.default_value;
CFNumberRef tag_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag);
CFNumberRef value_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &v);
@ -489,94 +126,6 @@ _hb_coretext_shaper_font_data_destroy (hb_coretext_font_data_t *data)
CFRelease ((CTFontRef) data);
}
/**
* hb_coretext_font_create:
* @ct_font: The CTFontRef to work upon
*
* Creates an #hb_font_t font object from the specified
* CTFontRef.
*
* The created font uses the default font functions implemented
* natively by HarfBuzz. If you want to use the CoreText font functions
* instead (rarely needed), you can do so by calling
* by hb_coretext_font_set_funcs().
*
* Return value: (transfer full): The new font object
*
* Since: 1.7.2
**/
hb_font_t *
hb_coretext_font_create (CTFontRef ct_font)
{
CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, nullptr);
hb_face_t *face = hb_coretext_face_create (cg_font);
CFRelease (cg_font);
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
if (unlikely (hb_object_is_immutable (font)))
return font;
hb_font_set_ptem (font, CTFontGetSize (ct_font));
/* Copy font variations */
CFDictionaryRef variations = CTFontCopyVariation (ct_font);
if (variations)
{
hb_vector_t<hb_variation_t> vars;
hb_vector_t<CFTypeRef> keys;
hb_vector_t<CFTypeRef> values;
CFIndex count = CFDictionaryGetCount (variations);
if (unlikely (!vars.alloc_exact (count) || !keys.resize_exact (count) || !values.resize_exact (count)))
goto done;
// Fetch them one by one and collect in a vector of our own.
CFDictionaryGetKeysAndValues (variations, keys.arrayZ, values.arrayZ);
for (CFIndex i = 0; i < count; i++)
{
int tag;
float value;
CFNumberGetValue ((CFNumberRef) keys.arrayZ[i], kCFNumberIntType, &tag);
CFNumberGetValue ((CFNumberRef) values.arrayZ[i], kCFNumberFloatType, &value);
hb_variation_t var = {tag, value};
vars.push (var);
}
hb_font_set_variations (font, vars.arrayZ, vars.length);
done:
CFRelease (variations);
}
/* Let there be dragons here... */
font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
// https://github.com/harfbuzz/harfbuzz/pull/4895#issuecomment-2408471254
//hb_coretext_font_set_funcs (font);
return font;
}
/**
* hb_coretext_font_get_ct_font:
* @font: #hb_font_t to work upon
*
* Fetches the CTFontRef associated with the specified
* #hb_font_t font object.
*
* Return value: the CTFontRef found
*
* Since: 0.9.10
*/
CTFontRef
hb_coretext_font_get_ct_font (hb_font_t *font)
{
CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext;
return ct_font ? (CTFontRef) ct_font : nullptr;
}
/*
* shaper
*/
@ -646,7 +195,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
* B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
* continue pointing to B2 even though B2 was merged into B1's
* cluster... */
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
if (HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (buffer->cluster_level))
{
hb_unicode_funcs_t *unicode = buffer->unicode;
unsigned int count = buffer->len;
@ -1010,7 +559,7 @@ resize_and_retry:
CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
unsigned int num_runs = CFArrayGetCount (glyph_runs);
DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
DEBUG_MSG (CORETEXT, nullptr, "Num runs: %u", num_runs);
buffer->len = 0;
uint32_t status_or = 0;
@ -1292,7 +841,7 @@ resize_and_retry:
* or the native OT backend, only that the cluster indices will be
* monotonic in the output buffer. */
if (count > 1 && (status_or & kCTRunStatusNonMonotonic) &&
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level))
{
hb_glyph_info_t *info = buffer->info;
if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))

572
src/hb-coretext.cc Normal file
View file

@ -0,0 +1,572 @@
/*
* Copyright © 2012,2013 Mozilla Foundation.
* Copyright © 2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Mozilla Author(s): Jonathan Kew
* Google Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#ifdef HAVE_CORETEXT
#include "hb-shaper-impl.hh"
#include "hb-coretext.hh"
/**
* SECTION:hb-coretext
* @title: hb-coretext
* @short_description: CoreText integration
* @include: hb-coretext.h
*
* Functions for using HarfBuzz with the CoreText fonts.
**/
static void
release_table_data (void *user_data)
{
CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
CFRelease(cf_data);
}
static hb_blob_t *
_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
if (unlikely (!cf_data))
return nullptr;
const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
const size_t length = CFDataGetLength (cf_data);
if (!data || !length)
{
CFRelease (cf_data);
return nullptr;
}
return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
release_table_data);
}
static unsigned
_hb_cg_get_table_tags (const hb_face_t *face HB_UNUSED,
unsigned int start_offset,
unsigned int *table_count,
hb_tag_t *table_tags,
void *user_data)
{
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
CTFontRef ct_font = create_ct_font (cg_font, (CGFloat) HB_CORETEXT_DEFAULT_FONT_SIZE);
auto arr = CTFontCopyAvailableTables (ct_font, kCTFontTableOptionNoOptions);
unsigned population = (unsigned) CFArrayGetCount (arr);
unsigned end_offset;
if (!table_count)
goto done;
if (unlikely (start_offset >= population))
{
*table_count = 0;
goto done;
}
end_offset = start_offset + *table_count;
if (unlikely (end_offset < start_offset))
{
*table_count = 0;
goto done;
}
end_offset= hb_min (end_offset, (unsigned) population);
*table_count = end_offset - start_offset;
for (unsigned i = start_offset; i < end_offset; i++)
{
CTFontTableTag tag = (CTFontTableTag)(uintptr_t) CFArrayGetValueAtIndex (arr, i);
table_tags[i - start_offset] = tag;
}
done:
CFRelease (arr);
CFRelease (ct_font);
return population;
}
static void
_hb_cg_font_release (void *data)
{
CGFontRelease ((CGFontRef) data);
}
static CTFontDescriptorRef
get_last_resort_font_desc ()
{
// TODO Handle allocation failures?
CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
(const void **) &last_resort,
1,
&kCFTypeArrayCallBacks);
CFRelease (last_resort);
CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
(const void **) &kCTFontCascadeListAttribute,
(const void **) &cascade_list,
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease (cascade_list);
CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
CFRelease (attributes);
return font_desc;
}
static void
release_data (void *info, const void *data, size_t size)
{
assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
hb_blob_destroy ((hb_blob_t *) info);
}
CGFontRef
create_cg_font (CFArrayRef ct_font_desc_array, unsigned int named_instance_index)
{
if (named_instance_index == 0)
{
// Default instance. We don't know which one is it. Return the first one.
// We will set the correct variations on it later.
}
else
named_instance_index--;
auto ct_font_desc = (CFArrayGetCount (ct_font_desc_array) > named_instance_index) ?
(CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, named_instance_index) : nullptr;
if (unlikely (!ct_font_desc))
{
CFRelease (ct_font_desc_array);
return nullptr;
}
auto ct_font = ct_font_desc ? CTFontCreateWithFontDescriptor (ct_font_desc, 0, nullptr) : nullptr;
CFRelease (ct_font_desc_array);
if (unlikely (!ct_font))
return nullptr;
auto cg_font = ct_font ? CTFontCopyGraphicsFont (ct_font, nullptr) : nullptr;
CFRelease (ct_font);
return cg_font;
}
CGFontRef
create_cg_font (hb_blob_t *blob, unsigned int index)
{
hb_blob_make_immutable (blob);
unsigned int blob_length;
const char *blob_data = hb_blob_get_data (blob, &blob_length);
if (unlikely (!blob_length))
DEBUG_MSG (CORETEXT, blob, "Empty blob");
unsigned ttc_index = index & 0xFFFF;
unsigned named_instance_index = index >> 16;
if (ttc_index != 0)
{
DEBUG_MSG (CORETEXT, blob, "TTC index %u not supported", ttc_index);
return nullptr; // CoreText does not support TTCs
}
if (unlikely (named_instance_index != 0))
{
auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromData (CFDataCreate (kCFAllocatorDefault, (const UInt8 *) blob_data, blob_length));
if (unlikely (!ct_font_desc_array))
return nullptr;
return create_cg_font (ct_font_desc_array, named_instance_index);
}
hb_blob_reference (blob);
CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
CGFontRef cg_font = nullptr;
if (likely (provider))
{
cg_font = CGFontCreateWithDataProvider (provider);
if (unlikely (!cg_font))
DEBUG_MSG (CORETEXT, blob, "CGFontCreateWithDataProvider() failed");
CGDataProviderRelease (provider);
}
return cg_font;
}
CGFontRef
create_cg_font (hb_face_t *face)
{
CGFontRef cg_font = nullptr;
if (face->destroy == _hb_cg_font_release)
cg_font = CGFontRetain ((CGFontRef) face->user_data);
else
{
hb_blob_t *blob = hb_face_reference_blob (face);
cg_font = create_cg_font (blob, face->index);
hb_blob_destroy (blob);
}
return cg_font;
}
CTFontRef
create_ct_font (CGFontRef cg_font, CGFloat font_size)
{
CTFontRef ct_font = nullptr;
/* CoreText does not enable trak table usage / tracking when creating a CTFont
* using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
* to be through the CTFontCreateUIFontForLanguage call. */
CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
{
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
# define kCTFontUIFontSystem kCTFontSystemFontType
# define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
#endif
CTFontUIFontType font_type = kCTFontUIFontSystem;
if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
font_type = kCTFontUIFontEmphasizedSystem;
ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
{
CFRelease(ct_font);
ct_font = nullptr;
}
CFRelease (ct_result_name);
}
CFRelease (cg_postscript_name);
if (!ct_font)
ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
if (unlikely (!ct_font)) {
DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
return nullptr;
}
/* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
* bug indicate that the cascade list reconfiguration occasionally causes
* crashes in CoreText on OS X 10.9, thus let's skip this step on older
* operating system versions. Except for the emoji font, where _not_
* reconfiguring the cascade list causes CoreText crashes. For details, see
* crbug.com/549610 */
// 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
#pragma GCC diagnostic pop
CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
CFRelease (fontName);
if (!isEmojiFont)
return ct_font;
}
CFURLRef original_url = nullptr;
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
ATSFontRef atsFont;
FSRef fsref;
OSStatus status;
atsFont = CTFontGetPlatformFont (ct_font, NULL);
status = ATSFontGetFileReference (atsFont, &fsref);
if (status == noErr)
original_url = CFURLCreateFromFSRef (NULL, &fsref);
#else
original_url = (CFURLRef) CTFontCopyAttribute (ct_font, kCTFontURLAttribute);
#endif
/* Create font copy with cascade list that has LastResort first; this speeds up CoreText
* font fallback which we don't need anyway. */
{
CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
CFRelease (last_resort_font_desc);
if (new_ct_font)
{
/* The CTFontCreateCopyWithAttributes call fails to stay on the same font
* when reconfiguring the cascade list and may switch to a different font
* when there are fonts that go by the same name, since the descriptor is
* just name and size.
*
* Avoid reconfiguring the cascade lists if the new font is outside the
* system locations that we cannot access from the sandboxed renderer
* process in Blink. This can be detected by the new file URL location
* that the newly found font points to. */
CFURLRef new_url = nullptr;
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
status = ATSFontGetFileReference (atsFont, &fsref);
if (status == noErr)
new_url = CFURLCreateFromFSRef (NULL, &fsref);
#else
new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
#endif
// Keep reconfigured font if URL cannot be retrieved (seems to be the case
// on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
if (!original_url || !new_url || CFEqual (original_url, new_url)) {
CFRelease (ct_font);
ct_font = new_ct_font;
} else {
CFRelease (new_ct_font);
DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
}
if (new_url)
CFRelease (new_url);
}
else
DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
}
if (original_url)
CFRelease (original_url);
return ct_font;
}
/**
* hb_coretext_face_create:
* @cg_font: The CGFontRef to work upon
*
* Creates an #hb_face_t face object from the specified
* CGFontRef.
*
* Return value: (transfer full): The new face object
*
* Since: 0.9.10
*/
hb_face_t *
hb_coretext_face_create (CGFontRef cg_font)
{
hb_face_t *face = hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
hb_face_set_get_table_tags_func (face, _hb_cg_get_table_tags, cg_font, nullptr);
return face;
}
/**
* hb_coretext_face_create_from_file_or_fail:
* @file_name: A font filename
* @index: The index of the face within the file
*
* Creates an #hb_face_t face object from the specified
* font file and face index.
*
* This is similar in functionality to hb_face_create_from_file_or_fail(),
* but uses the CoreText library for loading the font file.
*
* Return value: (transfer full): The new face object, or `NULL` if
* no face is found at the specified index or the file cannot be read.
*
* Since: 10.1.0
*/
hb_face_t *
hb_coretext_face_create_from_file_or_fail (const char *file_name,
unsigned int index)
{
auto url = CFURLCreateFromFileSystemRepresentation (nullptr,
(const UInt8 *) file_name,
strlen (file_name),
false);
if (unlikely (!url))
return nullptr;
auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromURL (url);
if (unlikely (!ct_font_desc_array))
{
CFRelease (url);
return nullptr;
}
unsigned ttc_index = index & 0xFFFF;
unsigned named_instance_index = index >> 16;
if (ttc_index != 0)
{
DEBUG_MSG (CORETEXT, nullptr, "TTC index %u not supported", ttc_index);
return nullptr; // CoreText does not support TTCs
}
auto cg_font = create_cg_font (ct_font_desc_array, named_instance_index);
CFRelease (url);
hb_face_t *face = hb_coretext_face_create (cg_font);
CFRelease (cg_font);
if (unlikely (hb_face_is_immutable (face)))
return nullptr;
hb_face_set_index (face, index);
return face;
}
/**
* hb_coretext_face_create_from_blob_or_fail:
* @blob: A blob containing the font data
* @index: The index of the face within the blob
*
* Creates an #hb_face_t face object from the specified
* blob and face index.
*
* This is similar in functionality to hb_face_create_from_blob_or_fail(),
* but uses the CoreText library for loading the font data.
*
* Return value: (transfer full): The new face object, or `NULL` if
* no face is found at the specified index or the blob cannot be read.
*
* Since: 11.0.0
*/
hb_face_t *
hb_coretext_face_create_from_blob_or_fail (hb_blob_t *blob,
unsigned int index)
{
auto cg_font = create_cg_font (blob, index);
if (unlikely (!cg_font))
return nullptr;
hb_face_t *face = hb_coretext_face_create (cg_font);
CFRelease (cg_font);
if (unlikely (hb_face_is_immutable (face)))
return nullptr;
hb_face_set_index (face, index);
return face;
}
/**
* hb_coretext_face_get_cg_font:
* @face: The #hb_face_t to work upon
*
* Fetches the CGFontRef associated with an #hb_face_t
* face object
*
* Return value: the CGFontRef found
*
* Since: 0.9.10
*/
CGFontRef
hb_coretext_face_get_cg_font (hb_face_t *face)
{
return (CGFontRef) (const void *) face->data.coretext;
}
/**
* hb_coretext_font_create:
* @ct_font: The CTFontRef to work upon
*
* Creates an #hb_font_t font object from the specified
* CTFontRef.
*
* The created font uses the default font functions implemented
* natively by HarfBuzz. If you want to use the CoreText font functions
* instead (rarely needed), you can do so by calling
* by hb_coretext_font_set_funcs().
*
* Return value: (transfer full): The new font object
*
* Since: 1.7.2
**/
hb_font_t *
hb_coretext_font_create (CTFontRef ct_font)
{
CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, nullptr);
hb_face_t *face = hb_coretext_face_create (cg_font);
CFRelease (cg_font);
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
if (unlikely (hb_object_is_immutable (font)))
return font;
hb_font_set_ptem (font, CTFontGetSize (ct_font));
/* Copy font variations */
CFDictionaryRef variations = CTFontCopyVariation (ct_font);
if (variations)
{
hb_vector_t<hb_variation_t> vars;
hb_vector_t<CFTypeRef> keys;
hb_vector_t<CFTypeRef> values;
CFIndex count = CFDictionaryGetCount (variations);
if (unlikely (!vars.alloc_exact (count) || !keys.resize_exact (count) || !values.resize_exact (count)))
goto done;
// Fetch them one by one and collect in a vector of our own.
CFDictionaryGetKeysAndValues (variations, keys.arrayZ, values.arrayZ);
for (CFIndex i = 0; i < count; i++)
{
int tag;
float value;
CFNumberGetValue ((CFNumberRef) keys.arrayZ[i], kCFNumberIntType, &tag);
CFNumberGetValue ((CFNumberRef) values.arrayZ[i], kCFNumberFloatType, &value);
hb_variation_t var = {tag, value};
vars.push (var);
}
hb_font_set_variations (font, vars.arrayZ, vars.length);
done:
CFRelease (variations);
}
/* Let there be dragons here... */
font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
// https://github.com/harfbuzz/harfbuzz/pull/4895#issuecomment-2408471254
//hb_coretext_font_set_funcs (font);
return font;
}
/**
* hb_coretext_font_get_ct_font:
* @font: #hb_font_t to work upon
*
* Fetches the CTFontRef associated with the specified
* #hb_font_t font object.
*
* Return value: the CTFontRef found
*
* Since: 0.9.10
*/
CTFontRef
hb_coretext_font_get_ct_font (hb_font_t *font)
{
return (CTFontRef) (const void *) font->data.coretext;
}
#endif

View file

@ -84,6 +84,10 @@ HB_EXTERN hb_face_t *
hb_coretext_face_create_from_file_or_fail (const char *file_name,
unsigned int index);
HB_EXTERN hb_face_t *
hb_coretext_face_create_from_blob_or_fail (hb_blob_t *blob,
unsigned int index);
HB_EXTERN hb_font_t *
hb_coretext_font_create (CTFontRef ct_font);

53
src/hb-coretext.hh Normal file
View file

@ -0,0 +1,53 @@
/*
* Copyright © 2012,2013 Mozilla Foundation.
* Copyright © 2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Mozilla Author(s): Jonathan Kew
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_CORETEXT_HH
#define HB_CORETEXT_HH
#include "hb.hh"
#include "hb-coretext.h"
#include "hb-aat-layout.hh"
HB_INTERNAL CGFontRef
create_cg_font (CFArrayRef ct_font_desc_array, unsigned int index);
HB_INTERNAL CGFontRef
create_cg_font (hb_blob_t *blob, unsigned int index);
HB_INTERNAL CGFontRef
create_cg_font (hb_face_t *face);
HB_INTERNAL CTFontRef
create_ct_font (CGFontRef cg_font, CGFloat font_size);
#endif /* HB_CORETEXT_HH */

View file

@ -49,15 +49,15 @@ struct hb_options_t
};
union hb_options_union_t {
int i;
unsigned i;
hb_options_t opts;
};
static_assert ((sizeof (hb_atomic_int_t) >= sizeof (hb_options_union_t)), "");
static_assert ((sizeof (hb_atomic_t<unsigned>) >= sizeof (hb_options_union_t)), "");
HB_INTERNAL void
_hb_options_init ();
extern HB_INTERNAL hb_atomic_int_t _hb_options;
extern HB_INTERNAL hb_atomic_t<unsigned> _hb_options;
static inline hb_options_t
hb_options ()

View file

@ -38,11 +38,11 @@
* For Floyd's tortoise and hare algorithm, see:
* https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare
*
* Like Floyd's algorithm, hb_decycler_t is O(n) in the number of nodes
* in the graph. Unlike Floyd's algorithm, hb_decycler_t is designed
* to be used in a DFS traversal, where the graph is not a simple
* linked list, but a tree with cycles. Like Floyd's algorithm, it is
* constant-memory (just two pointers).
* hb_decycler_t is O(n) in the number of nodes in the DFS traversal
* if there are no cycles. Unlike Floyd's algorithm, hb_decycler_t
* can be used in a DFS traversal, where the graph is not a simple
* linked list, but a tree with possible cycles. Like Floyd's algorithm,
* it is constant-memory (~three pointers).
*
* The decycler works by creating an implicit linked-list on the stack,
* of the path from the root to the current node, and apply Floyd's
@ -89,7 +89,7 @@ struct hb_decycler_t
friend struct hb_decycler_node_t;
private:
bool tortoise_asleep = true;
bool tortoise_awake = false;
hb_decycler_node_t *tortoise = nullptr;
hb_decycler_node_t *hare = nullptr;
};
@ -100,15 +100,18 @@ struct hb_decycler_node_t
{
u.decycler = &decycler;
decycler.tortoise_asleep = !decycler.tortoise_asleep;
decycler.tortoise_awake = !decycler.tortoise_awake;
if (!decycler.tortoise)
{
// First node.
assert (decycler.tortoise_awake);
assert (!decycler.hare);
decycler.tortoise = decycler.hare = this;
return;
}
if (!decycler.tortoise_asleep)
if (decycler.tortoise_awake)
decycler.tortoise = decycler.tortoise->u.next; // Time to move.
this->prev = decycler.hare;
@ -128,10 +131,10 @@ struct hb_decycler_node_t
prev->u.decycler = &decycler;
assert (decycler.tortoise);
if (!decycler.tortoise_asleep)
if (decycler.tortoise_awake)
decycler.tortoise = decycler.tortoise->prev;
decycler.tortoise_asleep = !decycler.tortoise_asleep;
decycler.tortoise_awake = !decycler.tortoise_awake;
}
bool visit (uintptr_t value_)

388
src/hb-directwrite-font.cc Normal file
View file

@ -0,0 +1,388 @@
/*
* Copyright © 2025 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.
*
* Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#ifdef HAVE_DIRECTWRITE
#include "hb-directwrite.h"
#include <d2d1.h>
#include "hb-draw.hh"
#include "hb-font.hh"
#include "hb-machinery.hh"
#define MAX_GLYPHS 256u
static unsigned int
hb_directwrite_get_nominal_glyphs (hb_font_t *font,
void *font_data HB_UNUSED,
unsigned int count,
const hb_codepoint_t *first_unicode,
unsigned int unicode_stride,
hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
void *user_data HB_UNUSED)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
for (unsigned i = 0; i < count;)
{
UINT32 unicodes[MAX_GLYPHS];
UINT16 gids[MAX_GLYPHS];
unsigned n = hb_min (MAX_GLYPHS, count - i);
for (unsigned j = 0; j < n; j++)
{
unicodes[j] = *first_unicode;
first_unicode = &StructAtOffset<const hb_codepoint_t> (first_unicode, unicode_stride);
}
if (!SUCCEEDED (dw_face->GetGlyphIndices (unicodes, n, gids)))
return i;
for (unsigned j = 0; j < n; j++)
{
if (!gids[j])
return i + j;
*first_glyph = gids[j];
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
}
i += n;
}
return count;
}
static hb_bool_t
hb_directwrite_get_font_h_extents (hb_font_t *font,
void *font_data HB_UNUSED,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
DWRITE_FONT_METRICS dw_metrics;
dw_face->GetMetrics (&dw_metrics);
metrics->ascender = font->em_scale_y (dw_metrics.ascent);
metrics->descender = -font->em_scale_y (dw_metrics.descent);
metrics->line_gap = font->em_scale_y (dw_metrics.lineGap);
return true;
}
static void
hb_directwrite_get_glyph_h_advances (hb_font_t* font,
void* font_data HB_UNUSED,
unsigned count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
IDWriteFontFace1 *dw_face1 = nullptr;
dw_face->QueryInterface (__uuidof(IDWriteFontFace1), (void**)&dw_face1);
assert (dw_face1);
for (unsigned i = 0; i < count;)
{
UINT16 gids[MAX_GLYPHS];
INT32 advances[MAX_GLYPHS];
unsigned n = hb_min (MAX_GLYPHS, count - i);
for (unsigned j = 0; j < n; j++)
{
gids[j] = *first_glyph;
advances[j] = 0;
first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
}
dw_face1->GetDesignGlyphAdvances (n, gids, advances, false);
for (unsigned j = 0; j < n; j++)
{
*first_advance = font->em_scale_x (advances[j]);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
}
i += n;
}
}
#ifndef HB_NO_VERTICAL
static void
hb_directwrite_get_glyph_v_advances (hb_font_t* font,
void* font_data HB_UNUSED,
unsigned count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
IDWriteFontFace1 *dw_face1 = nullptr;
dw_face->QueryInterface (__uuidof(IDWriteFontFace1), (void**)&dw_face1);
assert (dw_face1);
for (unsigned i = 0; i < count;)
{
UINT16 gids[MAX_GLYPHS];
INT32 advances[MAX_GLYPHS];
unsigned n = hb_min (MAX_GLYPHS, count - i);
for (unsigned j = 0; j < n; j++)
{
gids[j] = *first_glyph;
advances[j] = 0;
first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
}
dw_face1->GetDesignGlyphAdvances (n, gids, advances, true);
for (unsigned j = 0; j < n; j++)
{
*first_advance = -font->em_scale_y (advances[j]);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
}
i += n;
}
}
static hb_bool_t
hb_directwrite_get_glyph_v_origin (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
UINT16 gid = glyph;
DWRITE_GLYPH_METRICS metrics;
if (FAILED (dw_face->GetDesignGlyphMetrics (&gid, 1, &metrics)))
return false;
*x = font->em_scale_x (metrics.advanceWidth / 2);
*y = font->em_scale_y (metrics.verticalOriginY); // Untested
return true;
}
#endif
static hb_bool_t
hb_directwrite_get_glyph_extents (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
UINT16 gid = glyph;
DWRITE_GLYPH_METRICS metrics;
if (FAILED (dw_face->GetDesignGlyphMetrics (&gid, 1, &metrics)))
return false;
extents->x_bearing = font->em_scale_x (metrics.leftSideBearing);
extents->y_bearing = font->em_scale_y (metrics.verticalOriginY - metrics.topSideBearing);
extents->width = font->em_scale_x (metrics.advanceWidth - metrics.rightSideBearing) - extents->x_bearing;
extents->height = font->em_scale_y (metrics.verticalOriginY - metrics.advanceHeight + metrics.bottomSideBearing) - extents->y_bearing; // Magic
return true;
}
#ifndef HB_NO_DRAW
class GeometrySink : public IDWriteGeometrySink
{
hb_font_t *font;
hb_draw_session_t drawing;
public:
GeometrySink(hb_font_t *font,
hb_draw_funcs_t *draw_funcs,
void *draw_data)
: font (font), drawing ({draw_funcs, draw_data, font->slant}) {}
virtual ~GeometrySink() {}
HRESULT STDMETHODCALLTYPE Close() override { return S_OK; }
void STDMETHODCALLTYPE SetFillMode(D2D1_FILL_MODE) override {}
void STDMETHODCALLTYPE SetSegmentFlags(D2D1_PATH_SEGMENT) override {}
IFACEMETHOD(QueryInterface)(REFIID, void **) override { return E_NOINTERFACE; }
IFACEMETHOD_(ULONG, AddRef)() override { return 1; }
IFACEMETHOD_(ULONG, Release)() override { return 1; }
void STDMETHODCALLTYPE BeginFigure(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN) override
{
drawing.move_to (font->em_scalef_x (startPoint.x), -font->em_scalef_y (startPoint.y));
}
void STDMETHODCALLTYPE AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, UINT beziersCount) override
{
for (unsigned i = 0; i < beziersCount; ++i)
drawing.cubic_to (font->em_scalef_x (beziers[i].point1.x), -font->em_scalef_y (beziers[i].point1.y),
font->em_scalef_x (beziers[i].point2.x), -font->em_scalef_y (beziers[i].point2.y),
font->em_scalef_x (beziers[i].point3.x), -font->em_scalef_y (beziers[i].point3.y));
}
void STDMETHODCALLTYPE AddLines(const D2D1_POINT_2F *points, UINT pointsCount) override
{
for (unsigned i = 0; i < pointsCount; ++i)
drawing.line_to (font->em_scalef_x (points[i].x), -font->em_scalef_y (points[i].y));
}
void STDMETHODCALLTYPE EndFigure(D2D1_FIGURE_END) override
{
drawing.close_path ();
}
};
static void
hb_directwrite_draw_glyph (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_draw_funcs_t *draw_funcs, void *draw_data,
void *user_data)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
GeometrySink sink (font, draw_funcs, draw_data);
UINT16 gid = static_cast<UINT16>(glyph);
unsigned upem = font->face->get_upem();
(void) dw_face->GetGlyphRunOutline (upem,
&gid, nullptr, nullptr,
1,
false, false,
&sink);
}
#endif
static inline void free_static_directwrite_funcs ();
static struct hb_directwrite_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_directwrite_font_funcs_lazy_loader_t>
{
static hb_font_funcs_t *create ()
{
hb_font_funcs_t *funcs = hb_font_funcs_create ();
hb_font_funcs_set_nominal_glyphs_func (funcs, hb_directwrite_get_nominal_glyphs, nullptr, nullptr);
//hb_font_funcs_set_variation_glyph_func (funcs, hb_directwrite_get_variation_glyph, nullptr, nullptr);
hb_font_funcs_set_font_h_extents_func (funcs, hb_directwrite_get_font_h_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_h_advances_func (funcs, hb_directwrite_get_glyph_h_advances, nullptr, nullptr);
#ifndef HB_NO_VERTICAL
hb_font_funcs_set_glyph_v_advances_func (funcs, hb_directwrite_get_glyph_v_advances, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_directwrite_get_glyph_v_origin, nullptr, nullptr);
#endif
#ifndef HB_NO_DRAW
hb_font_funcs_set_draw_glyph_func (funcs, hb_directwrite_draw_glyph, nullptr, nullptr);
#endif
hb_font_funcs_set_glyph_extents_func (funcs, hb_directwrite_get_glyph_extents, nullptr, nullptr);
#ifndef HB_NO_OT_FONT_GLYPH_NAMES
//hb_font_funcs_set_glyph_name_func (funcs, hb_directwrite_get_glyph_name, nullptr, nullptr);
//hb_font_funcs_set_glyph_from_name_func (funcs, hb_directwrite_get_glyph_from_name, nullptr, nullptr);
#endif
hb_font_funcs_make_immutable (funcs);
hb_atexit (free_static_directwrite_funcs);
return funcs;
}
} static_directwrite_funcs;
static inline
void free_static_directwrite_funcs ()
{
static_directwrite_funcs.free_instance ();
}
static hb_font_funcs_t *
_hb_directwrite_get_font_funcs ()
{
return static_directwrite_funcs.get_unconst ();
}
/**
* hb_directwrite_font_set_funcs:
* @font: #hb_font_t to work upon
*
* Configures the font-functions structure of the specified
* #hb_font_t font object to use DirectWrite font functions.
*
* In particular, you can use this function to configure an
* existing #hb_face_t face object for use with DirectWrite font
* functions even if that #hb_face_t face object was initially
* created with hb_face_create(), and therefore was not
* initially configured to use DirectWrite font functions.
*
* <note>Note: Internally, this function creates a DirectWrite font.
* </note>
*
* Since: 11.0.0
**/
void
hb_directwrite_font_set_funcs (hb_font_t *font)
{
IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite;
if (unlikely (!dw_face))
{
hb_font_set_funcs (font,
hb_font_funcs_get_empty (),
nullptr, nullptr);
return;
}
dw_face->AddRef ();
hb_font_set_funcs (font,
_hb_directwrite_get_font_funcs (),
nullptr, nullptr);
}
#undef MAX_GLYPHS
#endif

656
src/hb-directwrite-shape.cc Normal file
View file

@ -0,0 +1,656 @@
/*
* 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.
*
* Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#ifdef HAVE_DIRECTWRITE
#include "hb-shaper-impl.hh"
#include "hb-directwrite.hh"
#include "hb-ms-feature-ranges.hh"
/*
* shaper face data
*/
hb_directwrite_face_data_t *
_hb_directwrite_shaper_face_data_create (hb_face_t *face)
{
hb_blob_t *blob = hb_face_reference_blob (face);
hb_directwrite_face_data_t *data = (hb_directwrite_face_data_t *) dw_face_create (blob, face->index);
hb_blob_destroy (blob);
return data;
}
void
_hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
{
((IDWriteFontFace *) data)->Release ();
}
/*
* shaper font data
*/
struct hb_directwrite_font_data_t {};
hb_directwrite_font_data_t *
_hb_directwrite_shaper_font_data_create (hb_font_t *font)
{
IDWriteFontFace *fontFace = (IDWriteFontFace *) (const void *) font->face->data.directwrite;
/*
* Set up variations.
*/
IDWriteFontFace5 *fontFaceVariations = nullptr;
{
IDWriteFontFace5 *fontFace5;
if (SUCCEEDED (fontFace->QueryInterface (__uuidof (IDWriteFontFace5), (void **) &fontFace5)))
{
IDWriteFontResource *fontResource;
if (SUCCEEDED (fontFace5->GetFontResource (&fontResource)))
{
hb_vector_t<DWRITE_FONT_AXIS_VALUE> axis_values;
if (likely (axis_values.resize_exact (font->num_coords)))
{
for (unsigned int i = 0; i < font->num_coords; i++)
{
hb_ot_var_axis_info_t info;
unsigned int c = 1;
hb_ot_var_get_axis_infos (font->face, i, &c, &info);
axis_values[i].axisTag = (DWRITE_FONT_AXIS_TAG) hb_uint32_swap (info.tag);
axis_values[i].value = i < font->num_coords ?
hb_clamp (font->design_coords[i], info.min_value, info.max_value) :
info.default_value;
}
fontResource->CreateFontFace (DWRITE_FONT_SIMULATIONS::DWRITE_FONT_SIMULATIONS_NONE,
axis_values.arrayZ, axis_values.length, &fontFaceVariations);
}
fontResource->Release ();
}
fontFace5->Release ();
}
}
return (hb_directwrite_font_data_t *) fontFaceVariations;
}
void
_hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data)
{
((IDWriteFontFace *) (const void *) data)->Release ();
}
// Most of TextAnalysis is originally written by Bas Schouten for Mozilla project
// but now is relicensed to MIT for HarfBuzz use
class TextAnalysis : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
{
private:
hb_reference_count_t mRefCount;
public:
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
{ return S_OK; }
IFACEMETHOD_ (ULONG, AddRef) ()
{
return mRefCount.inc () + 1;
}
IFACEMETHOD_ (ULONG, Release) ()
{
signed refCount = mRefCount.dec () - 1;
assert (refCount >= 0);
if (refCount)
return refCount;
delete this;
return 0;
}
// A single contiguous run of characters containing the same analysis
// results.
struct Run
{
uint32_t mTextStart; // starting text position of this run
uint32_t mTextLength; // number of contiguous code units covered
uint32_t mGlyphStart; // starting glyph in the glyphs array
uint32_t mGlyphCount; // number of glyphs associated with this run
// text
DWRITE_SCRIPT_ANALYSIS mScript;
uint8_t mBidiLevel;
bool mIsSideways;
bool ContainsTextPosition (uint32_t aTextPosition) const
{
return aTextPosition >= mTextStart &&
aTextPosition < mTextStart + mTextLength;
}
Run *nextRun;
};
public:
TextAnalysis (const wchar_t* text, uint32_t textLength,
const wchar_t* localeName, DWRITE_READING_DIRECTION readingDirection)
: mTextLength (textLength), mText (text), mLocaleName (localeName),
mReadingDirection (readingDirection), mCurrentRun (nullptr)
{
mRefCount.init ();
}
virtual ~TextAnalysis ()
{
// delete runs, except mRunHead which is part of the TextAnalysis object
for (Run *run = mRunHead.nextRun; run;)
{
Run *origRun = run;
run = run->nextRun;
delete origRun;
}
}
STDMETHODIMP
GenerateResults (IDWriteTextAnalyzer* textAnalyzer, Run **runHead)
{
// Analyzes the text using the script analyzer and returns
// the result as a series of runs.
HRESULT hr = S_OK;
// Initially start out with one result that covers the entire range.
// This result will be subdivided by the analysis processes.
mRunHead.mTextStart = 0;
mRunHead.mTextLength = mTextLength;
mRunHead.mBidiLevel =
(mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
mRunHead.nextRun = nullptr;
mCurrentRun = &mRunHead;
// Call each of the analyzers in sequence, recording their results.
if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this)))
*runHead = &mRunHead;
return hr;
}
// IDWriteTextAnalysisSource implementation
IFACEMETHODIMP
GetTextAtPosition (uint32_t textPosition,
OUT wchar_t const** textString,
OUT uint32_t* textLength)
{
if (textPosition >= mTextLength)
{
// No text at this position, valid query though.
*textString = nullptr;
*textLength = 0;
}
else
{
*textString = mText + textPosition;
*textLength = mTextLength - textPosition;
}
return S_OK;
}
IFACEMETHODIMP
GetTextBeforePosition (uint32_t textPosition,
OUT wchar_t const** textString,
OUT uint32_t* textLength)
{
if (textPosition == 0 || textPosition > mTextLength)
{
// Either there is no text before here (== 0), or this
// is an invalid position. The query is considered valid though.
*textString = nullptr;
*textLength = 0;
}
else
{
*textString = mText;
*textLength = textPosition;
}
return S_OK;
}
IFACEMETHODIMP_ (DWRITE_READING_DIRECTION)
GetParagraphReadingDirection () { return mReadingDirection; }
IFACEMETHODIMP GetLocaleName (uint32_t textPosition, uint32_t* textLength,
wchar_t const** localeName)
{ return S_OK; }
IFACEMETHODIMP
GetNumberSubstitution (uint32_t textPosition,
OUT uint32_t* textLength,
OUT IDWriteNumberSubstitution** numberSubstitution)
{
// We do not support number substitution.
*numberSubstitution = nullptr;
*textLength = mTextLength - textPosition;
return S_OK;
}
// IDWriteTextAnalysisSink implementation
IFACEMETHODIMP
SetScriptAnalysis (uint32_t textPosition, uint32_t textLength,
DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
{
SetCurrentRun (textPosition);
SplitCurrentRun (textPosition);
while (textLength > 0)
{
Run *run = FetchNextRun (&textLength);
run->mScript = *scriptAnalysis;
}
return S_OK;
}
IFACEMETHODIMP
SetLineBreakpoints (uint32_t textPosition,
uint32_t textLength,
const DWRITE_LINE_BREAKPOINT* lineBreakpoints)
{ return S_OK; }
IFACEMETHODIMP SetBidiLevel (uint32_t textPosition, uint32_t textLength,
uint8_t explicitLevel, uint8_t resolvedLevel)
{ return S_OK; }
IFACEMETHODIMP
SetNumberSubstitution (uint32_t textPosition, uint32_t textLength,
IDWriteNumberSubstitution* numberSubstitution)
{ return S_OK; }
protected:
Run *FetchNextRun (IN OUT uint32_t* textLength)
{
// Used by the sink setters, this returns a reference to the next run.
// Position and length are adjusted to now point after the current run
// being returned.
Run *origRun = mCurrentRun;
// Split the tail if needed (the length remaining is less than the
// current run's size).
if (*textLength < mCurrentRun->mTextLength)
SplitCurrentRun (mCurrentRun->mTextStart + *textLength);
else
// Just advance the current run.
mCurrentRun = mCurrentRun->nextRun;
*textLength -= origRun->mTextLength;
// Return a reference to the run that was just current.
return origRun;
}
void SetCurrentRun (uint32_t textPosition)
{
// Move the current run to the given position.
// Since the analyzers generally return results in a forward manner,
// this will usually just return early. If not, find the
// corresponding run for the text position.
if (mCurrentRun && mCurrentRun->ContainsTextPosition (textPosition))
return;
for (Run *run = &mRunHead; run; run = run->nextRun)
if (run->ContainsTextPosition (textPosition))
{
mCurrentRun = run;
return;
}
assert (0); // We should always be able to find the text position in one of our runs
}
void SplitCurrentRun (uint32_t splitPosition)
{
if (!mCurrentRun)
{
assert (0); // SplitCurrentRun called without current run
// Shouldn't be calling this when no current run is set!
return;
}
// Split the current run.
if (splitPosition <= mCurrentRun->mTextStart)
{
// No need to split, already the start of a run
// or before it. Usually the first.
return;
}
Run *newRun = new Run;
*newRun = *mCurrentRun;
// Insert the new run in our linked list.
newRun->nextRun = mCurrentRun->nextRun;
mCurrentRun->nextRun = newRun;
// Adjust runs' text positions and lengths.
uint32_t splitPoint = splitPosition - mCurrentRun->mTextStart;
newRun->mTextStart += splitPoint;
newRun->mTextLength -= splitPoint;
mCurrentRun->mTextLength = splitPoint;
mCurrentRun = newRun;
}
protected:
// Input
// (weak references are fine here, since this class is a transient
// stack-based helper that doesn't need to copy data)
uint32_t mTextLength;
const wchar_t* mText;
const wchar_t* mLocaleName;
DWRITE_READING_DIRECTION mReadingDirection;
// Current processing state.
Run *mCurrentRun;
// Output is a list of runs starting here
Run mRunHead;
};
/*
* shaper
*/
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)
{
IDWriteFontFace *fontFace = (IDWriteFontFace *) (const void *) font->data.directwrite;
auto *global = get_directwrite_global ();
if (unlikely (!global))
return false;
IDWriteFactory *dwriteFactory = global->dwriteFactory;
IDWriteTextAnalyzer* analyzer;
dwriteFactory->CreateTextAnalyzer (&analyzer);
unsigned int scratch_size;
hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
#define ALLOCATE_ARRAY(Type, name, len) \
Type *name = (Type *) scratch; \
do { \
unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
assert (_consumed <= scratch_size); \
scratch += _consumed; \
scratch_size -= _consumed; \
} while (0)
#define utf16_index() var1.u32
ALLOCATE_ARRAY (wchar_t, textString, buffer->len * 2);
unsigned int chars_len = 0;
for (unsigned int i = 0; i < buffer->len; i++)
{
hb_codepoint_t c = buffer->info[i].codepoint;
buffer->info[i].utf16_index () = chars_len;
if (likely (c <= 0xFFFFu))
textString[chars_len++] = c;
else if (unlikely (c > 0x10FFFFu))
textString[chars_len++] = 0xFFFDu;
else
{
textString[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
}
}
ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
/* Need log_clusters to assign features. */
chars_len = 0;
for (unsigned int i = 0; i < buffer->len; i++)
{
hb_codepoint_t c = buffer->info[i].codepoint;
unsigned int cluster = buffer->info[i].cluster;
log_clusters[chars_len++] = cluster;
if (hb_in_range (c, 0x10000u, 0x10FFFFu))
log_clusters[chars_len++] = cluster; /* Surrogates. */
}
DWRITE_READING_DIRECTION readingDirection;
readingDirection = buffer->props.direction ?
DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
/*
* There's an internal 16-bit limit on some things inside the analyzer,
* but we never attempt to shape a word longer than 64K characters
* in a single gfxShapedWord, so we cannot exceed that limit.
*/
uint32_t textLength = chars_len;
TextAnalysis analysis (textString, textLength, nullptr, readingDirection);
TextAnalysis::Run *runHead;
HRESULT hr;
hr = analysis.GenerateResults (analyzer, &runHead);
#define FAIL(...) \
HB_STMT_START { \
DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
return false; \
} HB_STMT_END
if (FAILED (hr))
FAIL ("Analyzer failed to generate results.");
uint32_t maxGlyphCount = 3 * textLength / 2 + 16;
uint32_t glyphCount;
bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
const wchar_t localeName[20] = {0};
if (buffer->props.language)
mbstowcs ((wchar_t*) localeName,
hb_language_to_string (buffer->props.language), 20);
/*
* Set up features.
*/
static_assert ((sizeof (DWRITE_TYPOGRAPHIC_FEATURES) == sizeof (hb_ms_features_t)), "");
static_assert ((sizeof (DWRITE_FONT_FEATURE) == sizeof (hb_ms_feature_t)), "");
hb_vector_t<hb_ms_features_t *> range_features;
hb_vector_t<uint32_t> range_char_counts;
// https://github.com/harfbuzz/harfbuzz/pull/5114
// The data allocated by these two vectors are used by the above two, so they
// should remain alive as long as the above two are.
hb_vector_t<hb_ms_feature_t> feature_records;
hb_vector_t<hb_ms_range_record_t> range_records;
if (num_features)
{
if (hb_ms_setup_features (features, num_features, feature_records, range_records))
{
hb_ms_make_feature_ranges (feature_records,
range_records,
0,
chars_len,
log_clusters,
range_features,
range_char_counts);
}
}
uint16_t* clusterMap;
clusterMap = new uint16_t[textLength];
DWRITE_SHAPING_TEXT_PROPERTIES* textProperties;
textProperties = new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
retry_getglyphs:
uint16_t* glyphIndices = new uint16_t[maxGlyphCount];
DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties;
glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
hr = analyzer->GetGlyphs (textString,
chars_len,
fontFace,
false,
isRightToLeft,
&runHead->mScript,
localeName,
nullptr,
(const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
range_char_counts.arrayZ,
range_features.length,
maxGlyphCount,
clusterMap,
textProperties,
glyphIndices,
glyphProperties,
&glyphCount);
if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
{
delete [] glyphIndices;
delete [] glyphProperties;
maxGlyphCount *= 2;
goto retry_getglyphs;
}
if (FAILED (hr))
FAIL ("Analyzer failed to get glyphs.");
float* glyphAdvances = new float[maxGlyphCount];
DWRITE_GLYPH_OFFSET* glyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount];
/* The -2 in the following is to compensate for possible
* alignment needed after the WORD array. sizeof (WORD) == 2. */
unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
/ (sizeof (WORD) +
sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) +
sizeof (int) +
sizeof (DWRITE_GLYPH_OFFSET) +
sizeof (uint32_t));
ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
#undef ALLOCATE_ARRAY
unsigned fontEmSize = font->face->get_upem ();
float x_mult = font->x_multf;
float y_mult = font->y_multf;
hr = analyzer->GetGlyphPlacements (textString,
clusterMap,
textProperties,
chars_len,
glyphIndices,
glyphProperties,
glyphCount,
fontFace,
fontEmSize,
false,
isRightToLeft,
&runHead->mScript,
localeName,
(const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
range_char_counts.arrayZ,
range_features.length,
glyphAdvances,
glyphOffsets);
if (FAILED (hr))
FAIL ("Analyzer failed to get glyph placements.");
/* Ok, we've got everything we need, now compose output buffer,
* very, *very*, carefully! */
/* Calculate visual-clusters. That's what we ship. */
for (unsigned int i = 0; i < glyphCount; i++)
vis_clusters[i] = (uint32_t) -1;
for (unsigned int i = 0; i < buffer->len; i++)
{
uint32_t *p =
&vis_clusters[log_clusters[buffer->info[i].utf16_index ()]];
*p = hb_min (*p, buffer->info[i].cluster);
}
for (unsigned int i = 1; i < glyphCount; i++)
if (vis_clusters[i] == (uint32_t) -1)
vis_clusters[i] = vis_clusters[i - 1];
#undef utf16_index
if (unlikely (!buffer->ensure (glyphCount)))
FAIL ("Buffer in error");
#undef FAIL
/* Set glyph infos */
buffer->len = 0;
for (unsigned int i = 0; i < glyphCount; i++)
{
hb_glyph_info_t *info = &buffer->info[buffer->len++];
info->codepoint = glyphIndices[i];
info->cluster = vis_clusters[i];
/* The rest is crap. Let's store position info there for now. */
info->mask = glyphAdvances[i];
info->var1.i32 = glyphOffsets[i].advanceOffset;
info->var2.i32 = glyphOffsets[i].ascenderOffset;
}
/* Set glyph positions */
buffer->clear_positions ();
for (unsigned int i = 0; i < glyphCount; i++)
{
hb_glyph_info_t *info = &buffer->info[i];
hb_glyph_position_t *pos = &buffer->pos[i];
/* TODO vertical */
pos->x_advance = round (x_mult * (int32_t) info->mask);
pos->x_offset = round (x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32));
pos->y_offset = round (y_mult * info->var2.i32);
}
if (isRightToLeft) hb_buffer_reverse (buffer);
buffer->clear_glyph_flags ();
buffer->unsafe_to_break ();
delete [] clusterMap;
delete [] glyphIndices;
delete [] textProperties;
delete [] glyphProperties;
delete [] glyphAdvances;
delete [] glyphOffsets;
/* Wow, done! */
return true;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -27,20 +27,45 @@
#include "hb.h"
#include <dwrite_3.h>
HB_BEGIN_DECLS
HB_EXTERN hb_face_t *
hb_directwrite_face_create (IDWriteFontFace *dw_face);
HB_EXTERN hb_face_t *
hb_directwrite_face_create_from_file_or_fail (const char *file_name,
unsigned int index);
HB_EXTERN hb_face_t *
hb_directwrite_face_create_from_blob_or_fail (hb_blob_t *blob,
unsigned int index);
HB_EXTERN IDWriteFontFace *
hb_directwrite_face_get_dw_font_face (hb_face_t *face);
HB_EXTERN hb_font_t *
hb_directwrite_font_create (IDWriteFontFace *dw_face);
HB_EXTERN IDWriteFontFace *
hb_directwrite_font_get_dw_font_face (hb_font_t *font);
HB_EXTERN void
hb_directwrite_font_set_funcs (hb_font_t *font);
#ifndef HB_DISABLE_DEPRECATED
HB_DEPRECATED_FOR (hb_directwrite_face_get_dw_font_face)
HB_EXTERN IDWriteFontFace *
hb_directwrite_face_get_font_face (hb_face_t *face);
HB_EXTERN hb_font_t *
hb_directwrite_font_create (IDWriteFont *dw_font);
HB_DEPRECATED
HB_EXTERN IDWriteFont *
hb_directwrite_font_get_dw_font (hb_font_t *font);
#endif
HB_END_DECLS
#endif /* HB_DIRECTWRITE_H */

223
src/hb-directwrite.hh Normal file
View file

@ -0,0 +1,223 @@
/*
* 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.
*
* Author(s): Behdad Esfahbod
*/
#ifndef HB_DIRECTWRITE_HH
#define HB_DIRECTWRITE_HH
#include "hb.hh"
#include "hb-directwrite.h"
#include "hb-mutex.hh"
#include "hb-map.hh"
/*
* DirectWrite font stream helpers
*/
// Have a look at to NativeFontResourceDWrite.cpp in Mozilla
/* Declare object creator for dynamic support of DWRITE */
typedef HRESULT (WINAPI *t_DWriteCreateFactory)(
DWRITE_FACTORY_TYPE factoryType,
REFIID iid,
IUnknown **factory
);
class DWriteFontFileLoader : public IDWriteFontFileLoader
{
private:
hb_reference_count_t mRefCount;
hb_mutex_t mutex;
hb_hashmap_t<uint64_t, IDWriteFontFileStream *> mFontStreams;
uint64_t mNextFontFileKey = 0;
public:
DWriteFontFileLoader ()
{
mRefCount.init ();
}
uint64_t RegisterFontFileStream (IDWriteFontFileStream *fontFileStream)
{
fontFileStream->AddRef ();
hb_lock_t lock {mutex};
mFontStreams.set (mNextFontFileKey, fontFileStream);
return mNextFontFileKey++;
}
void UnregisterFontFileStream (uint64_t fontFileKey)
{
hb_lock_t lock {mutex};
IDWriteFontFileStream *stream = mFontStreams.get (fontFileKey);
if (stream)
{
mFontStreams.del (fontFileKey);
stream->Release ();
}
}
// IUnknown interface
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
{ return S_OK; }
IFACEMETHOD_ (ULONG, AddRef) ()
{
return mRefCount.inc () + 1;
}
IFACEMETHOD_ (ULONG, Release) ()
{
signed refCount = mRefCount.dec () - 1;
assert (refCount >= 0);
if (refCount)
return refCount;
delete this;
return 0;
}
// IDWriteFontFileLoader methods
virtual HRESULT STDMETHODCALLTYPE
CreateStreamFromKey (void const* fontFileReferenceKey,
uint32_t fontFileReferenceKeySize,
OUT IDWriteFontFileStream** fontFileStream)
{
if (fontFileReferenceKeySize != sizeof (uint64_t))
return E_INVALIDARG;
uint64_t fontFileKey = * (uint64_t *) fontFileReferenceKey;
IDWriteFontFileStream *stream = mFontStreams.get (fontFileKey);
if (!stream)
return E_FAIL;
stream->AddRef ();
*fontFileStream = stream;
return S_OK;
}
virtual ~DWriteFontFileLoader()
{
for (auto v : mFontStreams.values ())
v->Release ();
}
};
class DWriteFontFileStream : public IDWriteFontFileStream
{
private:
hb_reference_count_t mRefCount;
hb_blob_t *mBlob;
uint8_t *mData;
unsigned mSize;
DWriteFontFileLoader *mLoader;
public:
uint64_t fontFileKey;
public:
DWriteFontFileStream (hb_blob_t *blob);
// IUnknown interface
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
{ return S_OK; }
IFACEMETHOD_ (ULONG, AddRef) ()
{
return mRefCount.inc () + 1;
}
IFACEMETHOD_ (ULONG, Release) ()
{
signed refCount = mRefCount.dec () - 1;
assert (refCount >= 0);
if (refCount)
return refCount;
delete this;
return 0;
}
// IDWriteFontFileStream methods
virtual HRESULT STDMETHODCALLTYPE
ReadFileFragment (void const** fragmentStart,
UINT64 fileOffset,
UINT64 fragmentSize,
OUT void** fragmentContext)
{
// We are required to do bounds checking.
if (fileOffset + fragmentSize > mSize) return E_FAIL;
// truncate the 64 bit fileOffset to size_t sized index into mData
size_t index = static_cast<size_t> (fileOffset);
// We should be alive for the duration of this.
*fragmentStart = &mData[index];
*fragmentContext = nullptr;
return S_OK;
}
virtual void STDMETHODCALLTYPE
ReleaseFileFragment (void* fragmentContext) {}
virtual HRESULT STDMETHODCALLTYPE
GetFileSize (OUT UINT64* fileSize)
{
*fileSize = mSize;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE
GetLastWriteTime (OUT UINT64* lastWriteTime) { return E_NOTIMPL; }
virtual ~DWriteFontFileStream();
};
struct hb_directwrite_global_t
{
hb_directwrite_global_t ()
{
HRESULT hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
(IUnknown**) &dwriteFactory);
if (unlikely (hr != S_OK))
return;
fontFileLoader = new DWriteFontFileLoader ();
dwriteFactory->RegisterFontFileLoader (fontFileLoader);
success = true;
}
~hb_directwrite_global_t ()
{
if (fontFileLoader)
fontFileLoader->Release ();
if (dwriteFactory)
dwriteFactory->Release ();
}
bool success = false;
IDWriteFactory *dwriteFactory;
DWriteFontFileLoader *fontFileLoader;
};
HB_INTERNAL hb_directwrite_global_t *
get_directwrite_global ();
HB_INTERNAL IDWriteFontFace *
dw_face_create (hb_blob_t *blob, unsigned index);
#endif /* HB_DIRECTWRITE_HH */

View file

@ -41,9 +41,16 @@ HB_BEGIN_DECLS
* @path_start_y: Y component of the start of current path
* @current_x: X component of current point
* @current_y: Y component of current point
* @slant_xy: Slanting factor for synthetic oblique, Since: 11.0.0
*
* Current drawing state.
*
* The @slant_xy is a slanting factor for synthetic oblique. If the font's
* oblique angle is not 0, this factor is used to slant the drawing. For
* fonts with uniform x and y scales, this factor is calculated as
* tan(oblique_angle). For fonts with non-uniform scales, this factor is
* calculated as tan(oblique_angle) * x_scale / y_scale, or 0 if y_scale is 0.
*
* Since: 4.0.0
**/
typedef struct hb_draw_state_t {
@ -55,6 +62,8 @@ typedef struct hb_draw_state_t {
float current_x;
float current_y;
float slant_xy;
/*< private >*/
hb_var_num_t reserved1;
hb_var_num_t reserved2;
@ -62,7 +71,6 @@ typedef struct hb_draw_state_t {
hb_var_num_t reserved4;
hb_var_num_t reserved5;
hb_var_num_t reserved6;
hb_var_num_t reserved7;
} hb_draw_state_t;
/**
@ -70,7 +78,7 @@ typedef struct hb_draw_state_t {
*
* The default #hb_draw_state_t at the start of glyph drawing.
*/
#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}}
#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}}
/**

View file

@ -99,6 +99,10 @@ struct hb_draw_funcs_t
float to_x, float to_y)
{
if (unlikely (st.path_open)) close_path (draw_data, st);
if (st.slant_xy)
to_x += to_y * st.slant_xy;
st.current_x = to_x;
st.current_y = to_y;
}
@ -109,7 +113,12 @@ struct hb_draw_funcs_t
float to_x, float to_y)
{
if (unlikely (!st.path_open)) start_path (draw_data, st);
if (st.slant_xy)
to_x += to_y * st.slant_xy;
emit_line_to (draw_data, st, to_x, to_y);
st.current_x = to_x;
st.current_y = to_y;
}
@ -121,7 +130,15 @@ struct hb_draw_funcs_t
float to_x, float to_y)
{
if (unlikely (!st.path_open)) start_path (draw_data, st);
if (st.slant_xy)
{
control_x += control_y * st.slant_xy;
to_x += to_y * st.slant_xy;
}
emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y);
st.current_x = to_x;
st.current_y = to_y;
}
@ -134,7 +151,16 @@ struct hb_draw_funcs_t
float to_x, float to_y)
{
if (unlikely (!st.path_open)) start_path (draw_data, st);
if (st.slant_xy)
{
control1_x += control1_y * st.slant_xy;
control2_x += control2_y * st.slant_xy;
to_x += to_y * st.slant_xy;
}
emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
st.current_x = to_x;
st.current_y = to_y;
}
@ -168,46 +194,32 @@ DECLARE_NULL_INSTANCE (hb_draw_funcs_t);
struct hb_draw_session_t
{
hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_ = 0.f)
: slant {slant_}, not_slanted {slant == 0.f},
funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT
{}
hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_xy = 0.f)
: funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT
{ st.slant_xy = slant_xy; }
~hb_draw_session_t () { close_path (); }
HB_ALWAYS_INLINE
void move_to (float to_x, float to_y)
{
if (likely (not_slanted))
funcs->move_to (draw_data, st,
to_x, to_y);
else
funcs->move_to (draw_data, st,
to_x + to_y * slant, to_y);
funcs->move_to (draw_data, st,
to_x, to_y);
}
HB_ALWAYS_INLINE
void line_to (float to_x, float to_y)
{
if (likely (not_slanted))
funcs->line_to (draw_data, st,
to_x, to_y);
else
funcs->line_to (draw_data, st,
to_x + to_y * slant, to_y);
funcs->line_to (draw_data, st,
to_x, to_y);
}
void
HB_ALWAYS_INLINE
quadratic_to (float control_x, float control_y,
float to_x, float to_y)
{
if (likely (not_slanted))
funcs->quadratic_to (draw_data, st,
control_x, control_y,
to_x, to_y);
else
funcs->quadratic_to (draw_data, st,
control_x + control_y * slant, control_y,
to_x + to_y * slant, to_y);
funcs->quadratic_to (draw_data, st,
control_x, control_y,
to_x, to_y);
}
void
HB_ALWAYS_INLINE
@ -215,16 +227,10 @@ struct hb_draw_session_t
float control2_x, float control2_y,
float to_x, float to_y)
{
if (likely (not_slanted))
funcs->cubic_to (draw_data, st,
control1_x, control1_y,
control2_x, control2_y,
to_x, to_y);
else
funcs->cubic_to (draw_data, st,
control1_x + control1_y * slant, control1_y,
control2_x + control2_y * slant, control2_y,
to_x + to_y * slant, to_y);
funcs->cubic_to (draw_data, st,
control1_x, control1_y,
control2_x, control2_y,
to_x, to_y);
}
HB_ALWAYS_INLINE
void close_path ()
@ -233,8 +239,6 @@ struct hb_draw_session_t
}
public:
float slant;
bool not_slanted;
hb_draw_funcs_t *funcs;
void *draw_data;
hb_draw_state_t st;

View file

@ -34,6 +34,16 @@
#include "hb-ot-face.hh"
#include "hb-ot-cmap-table.hh"
#ifdef HAVE_FREETYPE
#include "hb-ft.h"
#endif
#ifdef HAVE_CORETEXT
#include "hb-coretext.h"
#endif
#ifdef HAVE_DIRECTWRITE
#include "hb-directwrite.h"
#endif
/**
* SECTION:hb-face
@ -72,14 +82,14 @@ hb_face_count (hb_blob_t *blob)
if (unlikely (!blob))
return 0;
/* TODO We shouldn't be sanitizing blob. Port to run sanitizer and return if not sane. */
/* Make API signature const after. */
hb_blob_t *sanitized = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
const OT::OpenTypeFontFile& ot = *sanitized->as<OT::OpenTypeFontFile> ();
unsigned int ret = ot.get_face_count ();
hb_blob_destroy (sanitized);
hb_sanitize_context_t c (blob);
return ret;
const char *start = hb_blob_get_data (blob, nullptr);
auto *ot = reinterpret_cast<OT::OpenTypeFontFile *> (const_cast<char *> (start));
if (unlikely (!ot->sanitize (&c)))
return 0;
return ot->get_face_count ();
}
/*
@ -318,7 +328,209 @@ hb_face_create_from_file_or_fail (const char *file_name,
return face;
}
static struct supported_face_loaders_t {
char name[16];
hb_face_t * (*from_file) (const char *font_file, unsigned face_index);
hb_face_t * (*from_blob) (hb_blob_t *blob, unsigned face_index);
} supported_face_loaders[] =
{
{"ot",
#ifndef HB_NO_OPEN
hb_face_create_from_file_or_fail,
#else
nullptr,
#endif
hb_face_create_or_fail
},
#ifdef HAVE_FREETYPE
{"ft",
hb_ft_face_create_from_file_or_fail,
hb_ft_face_create_from_blob_or_fail
},
#endif
#ifdef HAVE_CORETEXT
{"coretext",
hb_coretext_face_create_from_file_or_fail,
hb_coretext_face_create_from_blob_or_fail
},
#endif
#ifdef HAVE_DIRECTWRITE
{"directwrite",
hb_directwrite_face_create_from_file_or_fail,
hb_directwrite_face_create_from_blob_or_fail
},
#endif
};
static const char *get_default_loader_name ()
{
static hb_atomic_t<const char *> static_loader_name;
const char *loader_name = static_loader_name.get_acquire ();
if (!loader_name)
{
loader_name = getenv ("HB_FACE_LOADER");
if (!loader_name)
loader_name = "";
if (!static_loader_name.cmpexch (nullptr, loader_name))
loader_name = static_loader_name.get_acquire ();
}
return loader_name;
}
/**
* hb_face_create_from_file_or_fail_using:
* @file_name: A font filename
* @index: The index of the face within the file
* @loader_name: (nullable): The name of the loader to use, or `NULL`
*
* A thin wrapper around the face loader functions registered with HarfBuzz.
* If @loader_name is `NULL` or the empty string, the first available loader
* is used.
*
* For example, the FreeType ("ft") loader might be able to load
* WOFF and WOFF2 files if FreeType is built with those features,
* whereas the OpenType ("ot") loader will not.
*
* Return value: (transfer full): The new face object, or `NULL` if
* the file cannot be read or the loader fails to load the face.
*
* Since: 11.0.0
**/
hb_face_t *
hb_face_create_from_file_or_fail_using (const char *file_name,
unsigned int index,
const char *loader_name)
{
// Duplicated in hb_face_create_or_fail_using
bool retry = false;
if (!loader_name || !*loader_name)
{
loader_name = get_default_loader_name ();
retry = true;
}
if (loader_name && !*loader_name) loader_name = nullptr;
retry:
for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
{
if (!loader_name || (supported_face_loaders[i].from_file && !strcmp (supported_face_loaders[i].name, loader_name)))
return supported_face_loaders[i].from_file (file_name, index);
}
if (retry)
{
retry = false;
loader_name = nullptr;
goto retry;
}
return nullptr;
}
/**
* hb_face_create_or_fail_using:
* @blob: #hb_blob_t to work upon
* @index: The index of the face within @blob
* @loader_name: (nullable): The name of the loader to use, or `NULL`
*
* A thin wrapper around the face loader functions registered with HarfBuzz.
* If @loader_name is `NULL` or the empty string, the first available loader
* is used.
*
* For example, the FreeType ("ft") loader might be able to load
* WOFF and WOFF2 files if FreeType is built with those features,
* whereas the OpenType ("ot") loader will not.
*
* Return value: (transfer full): The new face object, or `NULL` if
* the loader fails to load the face.
*
* Since: 11.0.0
**/
hb_face_t *
hb_face_create_or_fail_using (hb_blob_t *blob,
unsigned int index,
const char *loader_name)
{
// Duplicated in hb_face_create_from_file_or_fail_using
bool retry = false;
if (!loader_name || !*loader_name)
{
loader_name = get_default_loader_name ();
retry = true;
}
if (loader_name && !*loader_name) loader_name = nullptr;
retry:
for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
{
if (!loader_name || (supported_face_loaders[i].from_blob && !strcmp (supported_face_loaders[i].name, loader_name)))
return supported_face_loaders[i].from_blob (blob, index);
}
if (retry)
{
retry = false;
loader_name = nullptr;
goto retry;
}
return nullptr;
}
static inline void free_static_face_loader_list ();
static const char * const nil_face_loader_list[] = {nullptr};
static struct hb_face_loader_list_lazy_loader_t : hb_lazy_loader_t<const char *,
hb_face_loader_list_lazy_loader_t>
{
static const char ** create ()
{
const char **face_loader_list = (const char **) hb_calloc (1 + ARRAY_LENGTH (supported_face_loaders), sizeof (const char *));
if (unlikely (!face_loader_list))
return nullptr;
unsigned i;
for (i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
face_loader_list[i] = supported_face_loaders[i].name;
face_loader_list[i] = nullptr;
hb_atexit (free_static_face_loader_list);
return face_loader_list;
}
static void destroy (const char **l)
{ hb_free (l); }
static const char * const * get_null ()
{ return nil_face_loader_list; }
} static_face_loader_list;
static inline
void free_static_face_loader_list ()
{
static_face_loader_list.free_instance ();
}
/**
* hb_face_list_loaders:
*
* Retrieves the list of face loaders supported by HarfBuzz.
*
* Return value: (transfer none) (array zero-terminated=1): a
* `NULL`-terminated array of supported face loaders
* constant strings. The returned array is owned by HarfBuzz
* and should not be modified or freed.
*
* Since: 11.0.0
**/
const char **
hb_face_list_loaders ()
{
return static_face_loader_list.get_unconst ();
}
#endif
/**
* hb_face_get_empty:
@ -460,7 +672,7 @@ hb_face_make_immutable (hb_face_t *face)
* Since: 0.9.2
**/
hb_bool_t
hb_face_is_immutable (const hb_face_t *face)
hb_face_is_immutable (hb_face_t *face)
{
return hb_object_is_immutable (face);
}
@ -522,11 +734,15 @@ hb_face_reference_blob (hb_face_t *face)
for (unsigned offset = 0; offset < total_count; offset += count)
{
hb_face_get_table_tags (face, offset, &count, tags);
if (unlikely (!count))
break; // Allocation error
for (unsigned i = 0; i < count; i++)
{
hb_blob_t *table = hb_face_reference_table (face, tags[i]);
hb_face_builder_add_table (builder, tags[i], table);
hb_blob_destroy (table);
if (unlikely (!tags[i]))
continue;
hb_blob_t *table = hb_face_reference_table (face, tags[i]);
hb_face_builder_add_table (builder, tags[i], table);
hb_blob_destroy (table);
}
}

View file

@ -63,10 +63,24 @@ HB_EXTERN hb_face_t *
hb_face_create_or_fail (hb_blob_t *blob,
unsigned int index);
HB_EXTERN hb_face_t *
hb_face_create_or_fail_using (hb_blob_t *blob,
unsigned int index,
const char *loader_name);
HB_EXTERN hb_face_t *
hb_face_create_from_file_or_fail (const char *file_name,
unsigned int index);
HB_EXTERN hb_face_t *
hb_face_create_from_file_or_fail_using (const char *file_name,
unsigned int index,
const char *loader_name);
HB_EXTERN const char **
hb_face_list_loaders (void);
/**
* hb_reference_table_func_t:
* @face: an #hb_face_t to reference table for
@ -117,7 +131,7 @@ HB_EXTERN void
hb_face_make_immutable (hb_face_t *face);
HB_EXTERN hb_bool_t
hb_face_is_immutable (const hb_face_t *face);
hb_face_is_immutable (hb_face_t *face);
HB_EXTERN hb_blob_t *

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