rustybuzz-0.18.0/.cargo_vcs_info.json 0000644 00000000136 00000000001 0013223 0 ustar {
"git": {
"sha1": "f5a23d3648aae17e8540e03cbf2b50f97a927bbc"
},
"path_in_vcs": ""
} rustybuzz-0.18.0/.github/workflows/main.yml 0000644 0000000 0000000 00000000703 10461020230 0017057 0 ustar 0000000 0000000 name: Rust
on: [push, pull_request]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-14]
rust: [stable]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Build without std
run: cargo build --no-default-features
- name: Build with std
run: cargo build
- name: Run tests
run: cargo test --verbose
rustybuzz-0.18.0/.gitignore 0000644 0000000 0000000 00000000102 10461020230 0013774 0 ustar 0000000 0000000 /target
Cargo.lock
.directory
.DS_Store
/src/complex/*.ri
.vscode
rustybuzz-0.18.0/CHANGELOG.md 0000644 0000000 0000000 00000020762 10461020230 0013633 0 ustar 0000000 0000000 # Change Log
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
## [0.18.0] - 2024-08-10
### Added
- WASM shapers support.
Thanks to [@asibahi](https://github.com/asibahi).
- Some performance improvements.
Thanks to [@LaurenzV](https://github.com/LaurenzV).
### Fixed
- Multiple bugs.
Thanks to [@LaurenzV](https://github.com/LaurenzV).
- `kerx` table parsing in some Apple fonts.
- Allow `hb_buffer_t::serial` to overflow/wrap-around instead of panicking.
## [0.17.0] - 2024-07-02
### Changed
- Bump `ttf-parser`.
## [0.16.0] - 2024-07-02
- Sync with HarfBuzz 9.0.0.
Thanks to [@LaurenzV](https://github.com/LaurenzV).
### Changed
- Bump `ttf-parser`.
- Use `core_maths` instead of `libm`. Should simplify the build process.
### Removed
- `no-std-float` build flag. Should be handled automatically now.
## [0.15.0] - 2024-06-29
- Sync with HarfBuzz 8.5.0 🎉
`rustybuzz` is finally in-sync with `harfbuzz`.
Thanks to [@LaurenzV](https://github.com/LaurenzV).
### Changed
- When building without the `std` feature one must enable `no-std-float` feature instead.
### Fixed
- `gvar` phantom points handling which fixes some variable fonts shaping.
## [0.14.1] - 2024-06-12
### Fixed
- `no_std` build.
Thanks to [@jackpot51](https://github.com/jackpot51)
## [0.14.0] - 2024-05-10
- Sync with HarfBuzz 4.3.0.
Thanks to [@Pi-Cla](https://github.com/Pi-Cla) and [@LaurenzV](https://github.com/LaurenzV).
### Changed
- Bump `ttf-parser`.
- Bump Rust Edition to 2021.
## [0.13.0] - 2024-02-18
- Sync with HarfBuzz 4.1.0.
Thanks to [@LaurenzV](https://github.com/LaurenzV).
## [0.12.1] - 2023-12-16
### Added
- Derive `Hash` for `Feature`.
Thanks to [@laurmaedje](https://github.com/laurmaedje).
- `ShapePlan` is `Send` and `Sync` now.
Thanks to [@laurmaedje](https://github.com/laurmaedje).
## [0.12.0] - 2023-11-29
### Added
- Sync with HarfBuzz 2.9.1.
Thanks to [@bluebear94](https://github.com/bluebear94).
- `UnicodeBuffer::set_pre_context` and `UnicodeBuffer::set_post_context`.
Thanks to [@bluebear94](https://github.com/bluebear94).
- `shape_with_plan` function to allow cached `ShapePlan`s.
Thanks to [@vorporeal](https://github.com/vorporeal).
## [0.11.0] - 2023-10-15
### Added
- Sync with HarfBuzz 2.9.0.
Thanks to [@bluebear94](https://github.com/bluebear94).
## [0.10.0] - 2023-09-10
### Added
- Sync with HarfBuzz 2.8.0.
## [0.9.0] - 2023-09-09
### Added
- Sync with HarfBuzz 2.7.4. Thanks to [@bluebear94](https://github.com/bluebear94).
- State machines are autogenerated via `ragel` instead of manually translating them from C now.
Thanks to [@notgull](https://github.com/notgull).
### Changed
- Use `unicode-properties` crate instead of `unicode-general-category`.
Should significantly reduce compilation times.
Thanks to [@eddyb](https://github.com/eddyb).
### Fixed
- Panic in the Universal shaper. Thanks to [@notgull](https://github.com/notgull).
## [0.8.0] - 2023-06-12
### Changed
- Bump `ttf-parser`.
## [0.7.0] - 2023-02-04
### Added
- `UnicodeBuffer::add` thanks to [@bluebear94](https://github.com/bluebear94).
### Changed
- Bump `ttf-parser`.
- `Face::from_face` no longer returns `Option`.
## [0.6.0] - 2022-10-24
### Added
- `ttf-parser` is reexported now.
### Changed
- Bump `ttf-parser`.
## [0.5.3] - 2022-10-24
### Changed
- Revert 0.5.2 because it was a breaking change.
## [0.5.2] - 2022-10-22
### Added
- `ttf-parser` is reexported now.
### Changed
- Bump `ttf-parser`.
## [0.5.1] - 2022-06-11
### Added
- Implement `PartialOrd`, `Ord` and `Hash` for `Script`.
### Fixed
- `no_std` support thanks to [@CryZe](https://github.com/CryZe).
## [0.5.0] - 2022-02-20
### Changed
- `GSUB`, `GPOS`, `ankr`, `feat`, `kern`, `kerx`, `morx` and `trak`
tables parsing was moved to `ttf-parser`.
- `rustybuzz` no longer do any TrueType parsing. Everything is handled by `ttf-parser`.
### Fixed
- Multiple issues in AAT Lookup Table parsing.
## [0.4.0] - 2021-06-27
### Added
- `Face::from_face`, so you can create `rustybuzz::Face` directly from `ttf_parser::Face`.
Thanks to [@lain-dono](https://github.com/lain-dono)
- `no_std` support thanks to [@CryZe](https://github.com/CryZe).
- `GlyphInfo::unsafe_to_break` thanks to [@glowcoil](https://github.com/glowcoil).
### Changed
- Sync with harfbuzz 2.7.1
- Rename `GlyphInfo.codepoint` into `GlyphInfo.glyph_id` to remove confusion.
## [0.3.0] - 2020-12-05
### Ported
- Everything! 🎉
- Tables: `GSUB`, `GPOS`, `GDEF`, `ankr`, `feat`, `kern`, `kerx`, `morx`, `trak`.
- Main shaping logic.
- `hb_shape_plan_t` and `hb_ot_shape_plan_t`
- `hb_ot_map_t`
- `hb_ot_complex_shaper_t`
- OpenType layout (GSUB, GPOS).
- AAT layout.
- Normalization.
- Fallback shaper.
- Kerning.
### Changed
- Rename `Font` to `Face`.
Most of the changes in this release were made by [laurmaedje](https://github.com/laurmaedje).
## [0.2.0] - 2020-07-25
### Ported
- All complex shapers.
- Tables: `CBDT`, `CFF`, `CFF2`, `HVAR`, `MVAR`, `OS/2`, `SVG`, `VORG`, `VVAR`,
`avar`, `cmap`, `fvar`, `glyf`, `gvar`, `hhea`, `hmtx`, `post`, `sbix`, `vhea`, `vmtx`.
- `hb_buffer_t`
- `hb_script_t`
- `hb_feature_t`
- `hb_variation_t`
- `hb_language_t`
- `hb_font_t`
- `hb-ot-metrics`
- Unicode functions and tables.
- Buffer serialization.
### Changed
- Update to HarfBuzz 2.7.0
- Rename `Font::from_data` into `Font::from_slice`.
- Font is parsed via `ttf-parser` first.
And if the parsing fails, the `Font` will not be created.
`harfbuzz` allows malformed fonts.
### Removed
- `hb_font_funcs_t`. Only the embedded TrueType implementation is used.
- `hb_unicode_funcs_t`. Only the embedded Unicode implementation is used.
- `Font::set_scale`/`hb_font_set_scale`/`--font-size`. Shaping is always in font units now.
This simplifies the code quite a lot.
- Shaping plan caching.
- Fallback shaper.
- Unused `hdmx` table.
## [0.1.1] - 2020-07-04
### Fixed
- Compilation with an old XCode.
## 0.1.0 - 2020-07-04
At this point, this is just a simple Rust bindings to a stripped down harfbuzz.
### Added
- An absolute minimum Rust API.
- harfbuzz's shaping test suite had been ported to Rust.
### Changed
- harfbuzz source code was reformatted using clang-format.
### Removed
- Subsetting. This is probably a bit controversial, but I want to port only the shaper for now.
This is also removes around 7000 LOC.
- Arabic fallback shaper. Since it requires subsetting.
- Unused TrueType tables: BASE, COLR, CPAL, JSTF, MATH, STAT, bsln, fdsc, gasp, just, lcar, ltag, meta, name, opbd.
- All external dependencies: coretext, directwrite, freetype, gdi, glib, gobject, graphite, icu, uniscribe.
Embedded harfbuzz relies only on internal TrueType implementation.
- Most of the non-shaping harfbuzz API.
[Unreleased]: https://github.com/RazrFalcon/rustybuzz/compare/v0.18.0...HEAD
[0.18.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.17.0...v0.18.0
[0.17.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.16.0...v0.17.0
[0.16.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.15.0...v0.16.0
[0.15.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.14.1...v0.15.0
[0.14.1]: https://github.com/RazrFalcon/rustybuzz/compare/v0.14.0...v0.14.1
[0.14.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.13.0...v0.14.0
[0.13.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.12.1...v0.13.0
[0.12.1]: https://github.com/RazrFalcon/rustybuzz/compare/v0.12.0...v0.12.1
[0.12.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.11.0...v0.12.0
[0.11.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.10.0...v0.11.0
[0.10.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.9.0...v0.10.0
[0.9.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.8.0...v0.9.0
[0.8.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.7.0...v0.8.0
[0.7.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.6.0...v0.7.0
[0.6.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.5.3...v0.6.0
[0.5.3]: https://github.com/RazrFalcon/rustybuzz/compare/v0.5.2...v0.5.3
[0.5.2]: https://github.com/RazrFalcon/rustybuzz/compare/v0.5.1...v0.5.2
[0.5.1]: https://github.com/RazrFalcon/rustybuzz/compare/v0.5.0...v0.5.1
[0.5.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.4.0...v0.5.0
[0.4.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.3.0...v0.4.0
[0.3.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/RazrFalcon/rustybuzz/compare/v0.1.1...v0.2.0
[0.1.1]: https://github.com/RazrFalcon/rustybuzz/compare/v0.1.0...v0.1.1
rustybuzz-0.18.0/Cargo.lock 0000644 00000021601 00000000001 0011176 0 ustar # This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "arrayvec"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "autocfg"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "bytemuck"
version = "1.16.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "core_maths"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b02505ccb8c50b0aa21ace0fc08c3e53adebd4e58caa18a36152803c7709a3"
dependencies = [
"libm",
]
[[package]]
name = "downcast-rs"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
dependencies = [
"ahash",
]
[[package]]
name = "indexmap-nostd"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590"
[[package]]
name = "libc"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libm"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "multi-stash"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "685a9ac4b61f4e728e1d2c6a7844609c16527aeb5e6c865915c08e619c16410f"
[[package]]
name = "num-derive"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "pico-args"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustybuzz"
version = "0.18.0"
dependencies = [
"bitflags",
"bytemuck",
"core_maths",
"libc",
"log",
"pico-args",
"smallvec",
"ttf-parser",
"unicode-bidi-mirroring",
"unicode-ccc",
"unicode-properties",
"unicode-script",
"wasmi",
]
[[package]]
name = "serde"
version = "1.0.205"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.205"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]]
name = "string-interner"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c6a0d765f5807e98a091107bae0a56ea3799f66a5de47b2c84c94a39c09974e"
dependencies = [
"cfg-if",
"hashbrown",
"serde",
]
[[package]]
name = "syn"
version = "2.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "ttf-parser"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5be21190ff5d38e8b4a2d3b6a3ae57f612cc39c96e83cedeaf7abc338a8bac4a"
dependencies = [
"core_maths",
]
[[package]]
name = "unicode-bidi-mirroring"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64af057ad7466495ca113126be61838d8af947f41d93a949980b2389a118082f"
[[package]]
name = "unicode-ccc"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "260bc6647b3893a9a90668360803a15f96b85a5257b1c3a0c3daf6ae2496de42"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-properties"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291"
[[package]]
name = "unicode-script"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad8d71f5726e5f285a935e9fe8edfd53f0491eb6e9a5774097fdabee7cd8c9cd"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasmi"
version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c77715a28de774a980a45670db0d01dc1596abd8c71b5d1032da4f75b8439cf"
dependencies = [
"arrayvec",
"multi-stash",
"num-derive",
"num-traits",
"smallvec",
"spin",
"wasmi_collections",
"wasmi_core",
"wasmparser-nostd",
]
[[package]]
name = "wasmi_collections"
version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c413f056317e1e7459592b22e18d068d68f9035f8b3b9b0ee183494fc92e468"
dependencies = [
"ahash",
"hashbrown",
"string-interner",
]
[[package]]
name = "wasmi_core"
version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "771f23d12347e60d4cd2ef74636013cd14030ada552668ddcc228d7001a6bf86"
dependencies = [
"downcast-rs",
"libm",
"num-traits",
"paste",
]
[[package]]
name = "wasmparser-nostd"
version = "0.100.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5a015fe95f3504a94bb1462c717aae75253e39b9dd6c3fb1062c934535c64aa"
dependencies = [
"indexmap-nostd",
]
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
rustybuzz-0.18.0/Cargo.toml 0000644 00000003566 00000000001 0011233 0 ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
name = "rustybuzz"
version = "0.18.0"
authors = ["Yevhenii Reizner "]
exclude = [
"benches/",
"tests/",
]
description = "A complete harfbuzz shaping algorithm port to Rust."
documentation = "https://docs.rs/rustybuzz/"
readme = "README.md"
keywords = [
"text",
"shaping",
"opentype",
"truetype",
]
categories = ["text-processing"]
license = "MIT"
repository = "https://github.com/RazrFalcon/rustybuzz"
[dependencies.bitflags]
version = "2.4.1"
[dependencies.bytemuck]
version = "1.5"
features = ["extern_crate_alloc"]
[dependencies.core_maths]
version = "0.1.0"
[dependencies.log]
version = "0.4.22"
[dependencies.smallvec]
version = "1.6"
[dependencies.ttf-parser]
version = "0.24.1"
features = [
"opentype-layout",
"apple-layout",
"variable-fonts",
"glyph-names",
"no-std-float",
]
default-features = false
[dependencies.unicode-bidi-mirroring]
version = "0.3.0"
[dependencies.unicode-ccc]
version = "0.3.0"
[dependencies.unicode-properties]
version = "0.1.0"
features = ["general-category"]
default-features = false
[dependencies.unicode-script]
version = "0.5.2"
[dependencies.wasmi]
version = "0.36.0"
optional = true
[dev-dependencies.libc]
version = "0.2"
[dev-dependencies.pico-args]
version = "0.5"
features = ["eq-separator"]
[features]
default = ["std"]
std = ["ttf-parser/std"]
wasm-shaper = [
"std",
"dep:wasmi",
]
rustybuzz-0.18.0/Cargo.toml.orig 0000644 00000002314 00000000001 0012160 0 ustar [package]
name = "rustybuzz"
version = "0.18.0"
authors = ["Yevhenii Reizner "]
edition = "2021"
description = "A complete harfbuzz shaping algorithm port to Rust."
documentation = "https://docs.rs/rustybuzz/"
readme = "README.md"
repository = "https://github.com/RazrFalcon/rustybuzz"
license = "MIT"
keywords = ["text", "shaping", "opentype", "truetype"]
categories = ["text-processing"]
exclude = ["benches/", "tests/"]
[dependencies]
bitflags = "2.4.1"
bytemuck = { version = "1.5", features = ["extern_crate_alloc"] }
core_maths = "0.1.0" # only for no_std builds
smallvec = "1.6"
unicode-bidi-mirroring = "0.3.0"
unicode-ccc = "0.3.0"
unicode-properties = { version = "0.1.0", default-features = false, features = ["general-category"] }
unicode-script = "0.5.2"
wasmi = { version = "0.36.0", optional = true }
log = "0.4.22"
[dependencies.ttf-parser]
version = "0.24.1"
default-features = false
features = [
"opentype-layout",
"apple-layout",
"variable-fonts",
"glyph-names",
"no-std-float",
]
[features]
default = ["std"]
std = ["ttf-parser/std"]
wasm-shaper = ["std", "dep:wasmi"]
[dev-dependencies]
pico-args = { version = "0.5", features = ["eq-separator"] }
libc = "0.2"
rustybuzz-0.18.0/Cargo.toml.orig 0000644 0000000 0000000 00000002314 10461020230 0014702 0 ustar 0000000 0000000 [package]
name = "rustybuzz"
version = "0.18.0"
authors = ["Yevhenii Reizner "]
edition = "2021"
description = "A complete harfbuzz shaping algorithm port to Rust."
documentation = "https://docs.rs/rustybuzz/"
readme = "README.md"
repository = "https://github.com/RazrFalcon/rustybuzz"
license = "MIT"
keywords = ["text", "shaping", "opentype", "truetype"]
categories = ["text-processing"]
exclude = ["benches/", "tests/"]
[dependencies]
bitflags = "2.4.1"
bytemuck = { version = "1.5", features = ["extern_crate_alloc"] }
core_maths = "0.1.0" # only for no_std builds
smallvec = "1.6"
unicode-bidi-mirroring = "0.3.0"
unicode-ccc = "0.3.0"
unicode-properties = { version = "0.1.0", default-features = false, features = ["general-category"] }
unicode-script = "0.5.2"
wasmi = { version = "0.36.0", optional = true }
log = "0.4.22"
[dependencies.ttf-parser]
version = "0.24.1"
default-features = false
features = [
"opentype-layout",
"apple-layout",
"variable-fonts",
"glyph-names",
"no-std-float",
]
[features]
default = ["std"]
std = ["ttf-parser/std"]
wasm-shaper = ["std", "dep:wasmi"]
[dev-dependencies]
pico-args = { version = "0.5", features = ["eq-separator"] }
libc = "0.2"
rustybuzz-0.18.0/LICENSE 0000644 0000000 0000000 00000002135 10461020230 0013021 0 ustar 0000000 0000000 The MIT License (MIT)
Copyright (c) HarfBuzz developers
Copyright (c) 2020 Yevhenii Reizner
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
rustybuzz-0.18.0/README.md 0000644 0000000 0000000 00000014621 10461020230 0013276 0 ustar 0000000 0000000 # rustybuzz

[](https://crates.io/crates/rustybuzz)
[](https://docs.rs/rustybuzz)
`rustybuzz` is a complete [harfbuzz](https://github.com/harfbuzz/harfbuzz)'s
shaping algorithm port to Rust.
Matches `harfbuzz` v9.0.0
## Why?
Because you can add `rustybuzz = "*"` to your project and it just works.
No need for a C++ compiler. No need to configure anything. No need to link to system libraries.
## Conformance
rustybuzz passes nearly all of harfbuzz shaping tests (2221 out of 2252 to be more precise).
So it's mostly identical, but there are still some tiny edge-cases which
are not implemented yet or cannot be implemented at all.
## Major changes
- Subsetting removed.
- TrueType parsing is completely handled by the
[ttf-parser](https://github.com/RazrFalcon/ttf-parser).
And while the parsing algorithm is very different, it's not better or worse, just different.
- Malformed fonts will cause an error. HarfBuzz uses fallback/dummy shaper in this case.
- No font size property. Shaping is always using UnitsPerEm. You should scale the result manually.
- Most of the TrueType and Unicode handling code was moved into separate crates.
- rustybuzz doesn't interact with any system libraries and must produce exactly the same
results on all OS'es and targets.
- `mort` table is not supported, since it's deprecated by Apple.
- No Arabic fallback shaper, since it requires subsetting.
- No `graphite` library support.
- `avar2` as well as other parts of the boring-expansion-spec are not supported yet.
## Performance
At the moment, performance isn't that great. We're 1.5-2x slower than harfbuzz.
See [benches/README.md](./benches/README.md) for details.
## Notes about the port
rustybuzz is not a faithful port.
harfbuzz can roughly be split into 6 parts: shaping, subsetting, TrueType parsing,
Unicode routines, custom containers and utilities (harfbuzz doesn't use C++ std)
and glue for system/3rd party libraries. In the mean time, rustybuzz contains only shaping.
All of the TrueType parsing was moved to the [ttf-parser](https://github.com/RazrFalcon/ttf-parser).
Subsetting was removed. Unicode code was mostly moved to external crates.
We don't need custom containers because Rust's std is good enough.
And we do not use any non Rust libraries, so no glue code either.
In the end, we still have around 23 KLOC. While harfbuzz is around 80 KLOC.
## Lines of code
As mentioned above, rustybuzz has around 23 KLOC. But this is not strictly true,
because there are a lot of auto-generated data tables.
You can find the "real" code size using:
```sh
tokei --exclude hb/unicode_norm.rs --exclude hb/ot_shaper_vowel_constraints.rs \
--exclude '*_machine.rs' --exclude '*_table.rs' src
```
Which gives us around 17 KLOC, which is still a lot.
## Future work
Since the port is finished, there is not much to do other than syncing it with
a new harfbuzz releases. However, there is still lots of potential areas of improvement:
- **Wider test coverage**: Currently, we only test the result of the positioned glyphs in the shaping output.
We should add tests so that we can test other parts of the API as well, such as glyph extents and glyph flags.
- **Fuzzing against harfbuzz**: While `rustybuzz` passes the whole `harfbuzz` test suite, this does not mean that
output will always be 100% identical to `harfbuzz`. Given the complexity of the code base, there are bound to be
other bugs that just have not been discovered yet. One potential way of addressing this issue could be to create a
fuzzer that takes random fonts, and shapes them with a random set of Unicode codepoints as well as
input settings. In case of a discovered discrepancy, this test case could then be investigated and once the
bug has been identified, added to our custom test suite. On the one hand we could use the Google Fonts font
collection for this so that the fonts can be added to the repository,
but we could also just use MacOS/Windows system fonts and only test them in CI, similarly
to how it's currently done for AAT in `harfbuzz`.
- **Performance**: `harfbuzz` contains tons of optimization structures
(accelerators and caches) which have not been included in `rustybuzz`. As a result of this,
performance is much worse in many cases, as mentioned above (although in the grand scheme of things
`rustybuzz` is still very performant), but the upside of excluding all those optimizations is that
the code base is much simpler and straightforward. This makes it a lot easier to backport new changes
(which already is a very difficult task). Now that we are back in sync with `harfbuzz`, we can consider
attempting to port some of the major optimization improvements from `harfbuzz`, but we should do so carefully
to not make it even harder to keep the code bases in sync.
- **Code alignment**: `rustybuzz` tries its best to make the code base look like a 1:1 C++ to Rust translation,
which is the case for most parts of the code, but there also are many variations (most notable in AAT) that arise
from the fact that a lot of the C++ concepts are not straightforward to port. Nevertheless, there probably still
are parts of the code that probably could be made more similar, given that someone puts time into looking into that.
All of this is a lot of work, so contributions are more than welcome.
## Safety
The library is completely safe.
We do have one `unsafe` to cast between two POD structures, which is perfectly safe.
But except that, there are no `unsafe` in this library and in most of its dependencies
(excluding `bytemuck`).
## Alternatives
- [harfbuzz_rs](https://crates.io/crates/harfbuzz_rs) - bindings to the actual harfbuzz library.
As of v2 doesn't expose subsetting and glyph outlining, which harfbuzz supports.
- [allsorts](https://github.com/yeslogic/allsorts) - shaper and subsetter.
As of v0.6 doesn't support variable fonts and
[Apple Advanced Typography](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6AATIntro.html).
Relies on some unsafe code.
- [swash](https://github.com/dfrg/swash) - Supports variable fonts, text layout and rendering.
No subsetting. Relies on some unsafe code. As of v0.1.4 has zero tests.
## License
`rustybuzz` is licensed under the **MIT**.
`harfbuzz` is [licensed](https://github.com/harfbuzz/harfbuzz/blob/master/COPYING) under the **Old MIT**
rustybuzz-0.18.0/docs/backporting.md 0000644 0000000 0000000 00000010437 10461020230 0015575 0 ustar 0000000 0000000 # Backporting Process
## Intro
While the _porting_ process of `rustybuzz` is complete, _backporting_ is a never-ending task.
And even if we would be able to port simple commits in 5min, multiply it by a thousand
and you would understand why we're so behind. This is why any help is welcome.
If you want to help, you don't have to know anything about text shaping, fonts or even
C++ and Rust. Most `harfbuzz` commits consist of minor tweaks and fixes, which can easily be ported
by anyone with even basic CS knowledge.
If you have any questions, we have a dedicated [discussion] for backporting.
## Working Environment
Ideally, you should use Linux or macOS. While working on Windows is potentially possible,
it would be pain. Mainly because of `harfbuzz` and not `rustybuzz`. `harfbuzz` relies on
many Unix tools.
For one, you would need at least: git, Python, Rust, clang/gcc and meson.
Potentially even [ragel](./ragel.md), but it has to be built from sources.
## General Algorithm
The porting algorithm is quite simple and applies to most projects.
1. Take the latest not ported `harfbuzz` commit.
You can find the last ported in `rustybuzz` commit messages.
1. Analyze it to make sure it applies to `rustybuzz` or not.
1. Port it to `rustybuzz`.
1. Port `harfbuzz` tests (if needed).
1. Run `rustybuzz` tests (`cargo test`).
1. Run auto-format `cargo fmt`.
1. Commit.
1. Rinse and repeat.
Overall, if tests are passing - we're good. Everything else doesn't really matter.
## Analyzing Changes
The main difference between `harfbuzz` and `rustybuzz` is that `rustybuzz` is just a shaper,
while `harfbuzz` is collection of things. More specifically, `harfbuzz` includes:
shaping, subsetting, fonts parsing, Unicode tables, precompiled state-machines,
custom C++ containers (instead of std one) and bindings to 3rd-party libraries.
`rustybuzz` doesn't have subsetting. If you see changes in a file/function
with a name `subset` or a commit with the `[subset]` prefix, you can easily skip those.
Fonts parsing is done via [`ttf-parser`](https://github.com/RazrFalcon/ttf-parser)
and any changes to the fonts parsing in `harfbuzz` probably do not affect us,
unless new tests are failing. In which case better ask about in the [discussion].
Unicode tables and related routines are done differently in `rustybuzz`,
usually by using 3rd-party crates instead of a custom solution.
Again, better ask about such changes in the [discussion].
Precompiled state-machines are generated by [ragel](./ragel.md).
Follow the linked instruction if you see that any of `*.rl` files had changed.
We do not use any custom C++ containers `harfbuzz` implements and rely on Rust's std instead.
So changes to those can be ignored as well.
Changes to the `harfbuzz` build systems (it has 3... welcome to C++) should be completely ignored
as well.
Overall, if you see a change in a `hb-ot-*` file - this change probably affects `rustybuzz`.
## Updating Tests
Almost all of `harfbuzz` shaping tests (found in `test/shaping`) are as simple as
font + text = glyph ids + positions.
The difference is that `harfbuzz` uses Python to run tests, while we auto-generate
the default Rust tests. And to do so, we use `scripts/gen-shaping-tests.py`.
But to get the expected output, we first have to build `harfbuzz` at the commit we're porting.
You cannot use the latest `harfbuzz` version to do so. For example the one installed on your
system if you're using Linux.
The easies way to do so is to use `meson`:
```sh
git clone https://github.com/harfbuzz/harfbuzz
cd harfbuzz
git checkout HASH # put the required hash here
meson builddir --reconfigure # `--reconfigure` is needed only on the first run
ninja -Cbuilddir
```
Now you can run:
```sh
# Pass harfbuzz clone dir, not `harfbuzz/src` one.
cd rustybuzz/scripts
./gen-shaping-tests.py /path/to/harfbuzz
```
It will do everything for you. All you need is to run `cargo test` afterward to make sure
all tests are passing.
If not, then either your change was incorrect or there is a bug in `rustybuzz`.
## Commit Messages
Make sure each `rustybuzz` commit contains a link to the related `harfbuzz` commit.
[Example](https://github.com/RazrFalcon/rustybuzz/commit/5637691426b72dcac2c56a3d1fabe104438b5db7).
Commit message itself can be copy-pasted from `harfbuzz`.
[discussion]: https://github.com/RazrFalcon/rustybuzz/discussions/79
rustybuzz-0.18.0/docs/ragel.md 0000644 0000000 0000000 00000004562 10461020230 0014366 0 ustar 0000000 0000000 # State machines generation using ragel
HarfBuzz uses [ragel](https://github.com/adrian-thurston/ragel) to generate
state machines for some shapers.
The produced C code is rather low-level and relies on `goto` a lot,
therefore converting it to Rust by hand is rather problematic.
And this is the code that updates relatively often.
Can we use `ragel` to generate Rust code directly? Not using the stable `ragel`.
But the latest development branch does have a native Rust support.
Therefore to use `ragel` directly, we have to use the latest devel version and modify
ragel scripts a bit.
## Build ragel
`ragel` is a C++ project that uses the dreadful `autotools`.
Good luck building it on Windows. But on Unix-like OSes it should be relatively easy.
It also requires a 3rdparty dependency of
[colm](https://github.com/adrian-thurston/colm), which we have to build first.
In case of macOS, we would need:
```sh
brew install automake autoconf libtool
```
And now we can build `ragel`:
```sh
# build `colm` first
git clone https://github.com/adrian-thurston/colm
cd colm
./autogen.sh
./configure --prefix=/path/to/colm/install # prefer a custom path to /usr/local
make
make install
cd ..
git clone https://github.com/adrian-thurston/ragel
./autogen.sh
# --with-colm takes the same path we used above
./configure --prefix=/path/to/ragel/install --with-colm=/path/to/colm/install
make
make install
```
## Running ragel
Now we can convert our ragel scripts using:
```sh
/path/to/ragel/install/bin/ragel-rust -e -F1 src/hb/ot_shape_complex_indic_machine.rl # or any other .rl file
```
That's it!
PS: `ragel` will create temporary `*.ri` files. They can be safely removed.
## Code format
`ragel` uses strange code formatting for the Rust output, therefore running `cargo fmt`
is required.
## Comments
`ragel` doesn't preserve any comments, therefore we have to add
```c
// This file is autogenerated. Do not edit it!
//
// See docs/ragel.md for details.
```
Manually to each generated file.
## The Universal state machine
The `universal_machine.rl` is special since we have to modify its output manually
because we cannot express our needs via `ragel` directly.
The change is simple. After the `universal_machine.rs` is generated, Rust will complain about
about some variables set to 0. Like `ts = 0;`.
In all those cases `0` should simply be replaced with `p0`.
There are no better solution for now...
rustybuzz-0.18.0/examples/shape.rs 0000644 0000000 0000000 00000022147 10461020230 0015305 0 ustar 0000000 0000000 use std::path::PathBuf;
use std::str::FromStr;
const HELP: &str = "\
USAGE:
shape [OPTIONS] [TEXT]
OPTIONS:
-h, --help Show help options
--version Show version number
--font-file PATH Set font file-name
--face-index INDEX Set face index [default: 0]
--font-ptem NUMBER Set font point-size
--variations LIST Set comma-separated list of font variations
--text TEXT Set input text
--text-file PATH Set input text file
-u, --unicodes LIST Set comma-separated list of input Unicode codepoints
Examples: 'U+0056,U+0057'
--direction DIRECTION Set text direction
[possible values: ltr, rtl, ttb, btt]
--language LANG Set text language [default: LC_CTYPE]
--script TAG Set text script as ISO-15924 tag
--utf8-clusters Use UTF-8 byte indices, not char indices
--cluster-level N Cluster merging level [default: 0]
[possible values: 0, 1, 2]
--features LIST Set comma-separated list of font features
--no-glyph-names Output glyph indices instead of names
--no-positions Do not output glyph positions
--no-advances Do not output glyph advances
--no-clusters Do not output cluster indices
--show-extents Output glyph extents
--show-flags Output glyph flags
--single-par Treat the input string as a single paragraph
--ned No Extra Data; Do not output clusters or advances
ARGS:
A font file
[TEXT] An optional text
";
struct Args {
help: bool,
version: bool,
font_file: Option,
face_index: u32,
font_ptem: Option,
variations: Vec,
text: Option,
text_file: Option,
unicodes: Option,
direction: Option,
language: rustybuzz::Language,
script: Option,
utf8_clusters: bool,
cluster_level: rustybuzz::BufferClusterLevel,
features: Vec,
no_glyph_names: bool,
no_positions: bool,
no_advances: bool,
no_clusters: bool,
show_extents: bool,
show_flags: bool,
single_par: bool,
ned: bool,
free: Vec,
}
fn parse_args() -> Result {
let mut args = pico_args::Arguments::from_env();
let args = Args {
help: args.contains(["-h", "--help"]),
version: args.contains("--version"),
font_file: args.opt_value_from_str("--font-file")?,
face_index: args.opt_value_from_str("--face-index")?.unwrap_or(0),
font_ptem: args.opt_value_from_str("--font-ptem")?,
variations: args
.opt_value_from_fn("--variations", parse_variations)?
.unwrap_or_default(),
text: args.opt_value_from_str("--text")?,
text_file: args.opt_value_from_str("--text-file")?,
unicodes: args.opt_value_from_fn(["-u", "--unicodes"], parse_unicodes)?,
direction: args.opt_value_from_str("--direction")?,
language: args
.opt_value_from_str("--language")?
.unwrap_or(system_language()),
script: args.opt_value_from_str("--script")?,
utf8_clusters: args.contains("--utf8-clusters"),
cluster_level: args
.opt_value_from_fn("--cluster-level", parse_cluster)?
.unwrap_or_default(),
features: args
.opt_value_from_fn("--features", parse_features)?
.unwrap_or_default(),
no_glyph_names: args.contains("--no-glyph-names"),
no_positions: args.contains("--no-positions"),
no_advances: args.contains("--no-advances"),
no_clusters: args.contains("--no-clusters"),
show_extents: args.contains("--show-extents"),
show_flags: args.contains("--show-flags"),
single_par: args.contains("--single-par"),
ned: args.contains("--ned"),
free: args
.finish()
.iter()
.map(|s| s.to_string_lossy().to_string())
.collect(),
};
Ok(args)
}
fn main() {
let args = match parse_args() {
Ok(v) => v,
Err(e) => {
eprintln!("Error: {}.", e);
std::process::exit(1);
}
};
if args.version {
println!("{}", env!("CARGO_PKG_VERSION"));
return;
}
if args.help {
print!("{}", HELP);
return;
}
let mut font_set_as_free_arg = false;
let font_path = if let Some(path) = args.font_file {
path.clone()
} else if !args.free.is_empty() {
font_set_as_free_arg = true;
PathBuf::from(&args.free[0])
} else {
eprintln!("Error: font is not set.");
std::process::exit(1);
};
if !font_path.exists() {
eprintln!("Error: '{}' does not exist.", font_path.display());
std::process::exit(1);
}
let font_data = std::fs::read(font_path).unwrap();
let mut face = rustybuzz::Face::from_slice(&font_data, args.face_index).unwrap();
face.set_points_per_em(args.font_ptem);
if !args.variations.is_empty() {
face.set_variations(&args.variations);
}
let text = if let Some(path) = args.text_file {
std::fs::read_to_string(path).unwrap()
} else if args.free.len() == 2 && font_set_as_free_arg {
args.free[1].clone()
} else if args.free.len() == 1 && !font_set_as_free_arg {
args.free[0].clone()
} else if let Some(ref text) = args.unicodes {
text.clone()
} else if let Some(ref text) = args.text {
text.clone()
} else {
eprintln!("Error: text is not set.");
std::process::exit(1);
};
let lines = if args.single_par {
vec![text.as_str()]
} else {
text.split("\n").filter(|s| !s.is_empty()).collect()
};
for text in lines {
let mut buffer = rustybuzz::UnicodeBuffer::new();
buffer.push_str(&text);
if let Some(d) = args.direction {
buffer.set_direction(d);
}
buffer.set_language(args.language.clone());
if let Some(script) = args.script {
buffer.set_script(script);
}
buffer.set_cluster_level(args.cluster_level);
if !args.utf8_clusters {
buffer.reset_clusters();
}
let glyph_buffer = rustybuzz::shape(&face, &args.features, buffer);
let mut format_flags = rustybuzz::SerializeFlags::default();
if args.no_glyph_names {
format_flags |= rustybuzz::SerializeFlags::NO_GLYPH_NAMES;
}
if args.no_clusters || args.ned {
format_flags |= rustybuzz::SerializeFlags::NO_CLUSTERS;
}
if args.no_positions {
format_flags |= rustybuzz::SerializeFlags::NO_POSITIONS;
}
if args.no_advances || args.ned {
format_flags |= rustybuzz::SerializeFlags::NO_ADVANCES;
}
if args.show_extents {
format_flags |= rustybuzz::SerializeFlags::GLYPH_EXTENTS;
}
if args.show_flags {
format_flags |= rustybuzz::SerializeFlags::GLYPH_FLAGS;
}
println!("{}", glyph_buffer.serialize(&face, format_flags));
}
}
fn parse_unicodes(s: &str) -> Result {
let mut text = String::new();
for u in s.split(',') {
let u = u32::from_str_radix(&u[2..], 16)
.map_err(|_| format!("'{}' is not a valid codepoint", u))?;
let c = char::try_from(u).map_err(|_| format!("{} is not a valid codepoint", u))?;
text.push(c);
}
Ok(text)
}
fn parse_features(s: &str) -> Result, String> {
let mut features = Vec::new();
for f in s.split(',') {
features.push(rustybuzz::Feature::from_str(&f)?);
}
Ok(features)
}
fn parse_variations(s: &str) -> Result, String> {
let mut variations = Vec::new();
for v in s.split(',') {
variations.push(rustybuzz::Variation::from_str(&v)?);
}
Ok(variations)
}
fn parse_cluster(s: &str) -> Result {
match s {
"0" => Ok(rustybuzz::BufferClusterLevel::MonotoneGraphemes),
"1" => Ok(rustybuzz::BufferClusterLevel::MonotoneCharacters),
"2" => Ok(rustybuzz::BufferClusterLevel::Characters),
_ => Err(format!("invalid cluster level")),
}
}
fn system_language() -> rustybuzz::Language {
unsafe {
libc::setlocale(libc::LC_ALL, b"\0" as *const _ as *const i8);
let s = libc::setlocale(libc::LC_CTYPE, std::ptr::null());
let s = std::ffi::CStr::from_ptr(s);
let s = s.to_str().expect("locale must be ASCII");
rustybuzz::Language::from_str(s).unwrap()
}
}
rustybuzz-0.18.0/src/hb/aat_layout.rs 0000644 0000000 0000000 00000116023 10461020230 0015706 0 ustar 0000000 0000000 #![allow(dead_code)]
use super::buffer::{hb_buffer_t, hb_glyph_info_t};
use super::hb_tag_t;
use super::ot_shape_plan::hb_ot_shape_plan_t;
use super::{aat_layout_kerx_table, aat_layout_morx_table, aat_layout_trak_table};
use super::{aat_map, hb_font_t};
use crate::hb::aat_layout_common::hb_aat_apply_context_t;
pub type hb_aat_layout_feature_type_t = u8;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_INVALID: u8 = 0xFF;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT: u8 = 5;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING: u8 = 6;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE: u8 = 8;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE: u8 = 9;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION: u8 = 10;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS: u8 = 11;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE: u8 = 13;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS: u8 = 14;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS: u8 = 15;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE: u8 = 16;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES: u8 = 17;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE: u8 = 18;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS: u8 = 19;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE: u8 = 20;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE: u8 = 21;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING: u8 = 22;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION: u8 = 23;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE: u8 = 24;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE: u8 = 25;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE: u8 = 26;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE: u8 = 27;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA: u8 = 28;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE: u8 = 29;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE: u8 = 30;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE: u8 = 31;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN: u8 = 32;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT: u8 = 33;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA: u8 = 34;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES: u8 = 35;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES: u8 = 36;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE: u8 = 37;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE: u8 = 38;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE: u8 = 39;
pub const HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE: u8 = 103;
pub type hb_aat_layout_feature_selector_t = u8;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID: u8 = 0xFF;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_ON: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_OFF: u8 = 1;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_ON: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_OFF: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_ON: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_OFF: u8 = 5;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_ON: u8 = 6;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_OFF: u8 = 7;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_ON: u8 = 8;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_OFF: u8 = 9;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_ON: u8 = 10;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_OFF: u8 = 11;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_ON: u8 = 12;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_OFF: u8 = 13;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_ON: u8 = 14;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_OFF: u8 = 15;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_ON: u8 = 16;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_OFF: u8 = 17;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_ON: u8 = 18;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_OFF: u8 = 19;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON: u8 = 20;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF: u8 = 21;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_UNCONNECTED: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_PARTIALLY_CONNECTED: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CURSIVE: u8 = 2;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_AND_LOWER_CASE: u8 = 0; /* deprecated */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_CAPS: u8 = 1; /* deprecated */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_LOWER_CASE: u8 = 2; /* deprecated */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS: u8 = 3; /* deprecated */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS: u8 = 4; /* deprecated */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS_AND_SMALL_CAPS: u8 = 5; /* deprecated */
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF: u8 = 1;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_ON: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_OFF: u8 = 1;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_NUMBERS: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_NUMBERS: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_NUMBERS: u8 = 3;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_ON: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_OFF: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_ON: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_OFF: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_ON: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_OFF: u8 = 5;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_ON: u8 = 6;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_OFF: u8 = 7;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_ON: u8 = 8;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_OFF: u8 = 9;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SHOW_DIACRITICS: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HIDE_DIACRITICS: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DECOMPOSE_DIACRITICS: u8 = 2;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SUPERIORS: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_INFERIORS: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ORDINALS: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS: u8 = 4;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_VERTICAL_FRACTIONS: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS: u8 = 2;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_ON: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_OFF: u8 = 1;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_ON: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_OFF: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_ON: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_OFF: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF: u8 = 5;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_ON: u8 = 6;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_OFF: u8 = 7;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_ON: u8 = 8;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_OFF: u8 = 9;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_ON: u8 = 10;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_OFF: u8 = 11;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_ON: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_OFF: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_ON: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_OFF: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_ON: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_OFF: u8 = 5;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_ON: u8 = 6;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_OFF: u8 = 7;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_ON: u8 = 8;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_OFF: u8 = 9;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_ON: u8 = 10;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_OFF: u8 = 11;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ORNAMENTS: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DINGBATS: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_PI_CHARACTERS: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_FLEURONS: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DECORATIVE_BORDERS: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_INTERNATIONAL_SYMBOLS: u8 = 5;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_MATH_SYMBOLS: u8 = 6;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ALTERNATES: u8 = 0;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL1: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL2: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL3: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL4: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL5: u8 = 4;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLE_OPTIONS: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DISPLAY_TEXT: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ENGRAVED_TEXT: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ILLUMINATED_CAPS: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_TITLING_CAPS: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_TALL_CAPS: u8 = 5;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_CHARACTERS: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SIMPLIFIED_CHARACTERS: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1978_CHARACTERS: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1983_CHARACTERS: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1990_CHARACTERS: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_ONE: u8 = 5;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_TWO: u8 = 6;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_THREE: u8 = 7;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FOUR: u8 = 8;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FIVE: u8 = 9;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPERT_CHARACTERS: u8 = 10;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS2004_CHARACTERS: u8 = 11;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HOJO_CHARACTERS: u8 = 12;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_NLCCHARACTERS: u8 = 13;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_NAMES_CHARACTERS: u8 = 14;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_NUMBERS: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_NUMBERS: u8 = 1;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_TEXT: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_TEXT: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT: u8 = 5;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT: u8 = 6;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HIRAGANA_TO_KATAKANA: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_KATAKANA_TO_HIRAGANA: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_KANA_TO_ROMANIZATION: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_HIRAGANA: u8 = 5;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_KATAKANA: u8 = 6;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_ONE: u8 = 7;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_TWO: u8 = 8;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_THREE: u8 = 9;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ANNOTATION: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_BOX_ANNOTATION: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ROUNDED_BOX_ANNOTATION: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CIRCLE_ANNOTATION: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_CIRCLE_ANNOTATION: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_PARENTHESIS_ANNOTATION: u8 = 5;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIOD_ANNOTATION: u8 = 6;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMAN_NUMERAL_ANNOTATION: u8 = 7;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAMOND_ANNOTATION: u8 = 8;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_BOX_ANNOTATION: u8 = 9;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_ROUNDED_BOX_ANNOTATIO: u8 = 10;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_KANA: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_KANA: u8 = 1;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_IDEOGRAPHS: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_IDEOGRAPHS: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_IDEOGRAPHS: u8 = 2;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_ON: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_OFF: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_ON: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_OFF: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_ON: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_OFF: u8 = 5;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_RUBY_KANA: u8 = 0; /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF instead */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA: u8 = 1; /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON instead */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF: u8 = 3;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_SYMBOL_ALTERNATIVES: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_ONE: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_TWO: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_THREE: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FOUR: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FIVE: u8 = 5;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_IDEOGRAPHIC_ALTERNATIVES: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_ONE: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_TWO: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_THREE: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FOUR: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FIVE: u8 = 5;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_CENTERED: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_HBASELINE: u8 = 1;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_ITALIC_ROMAN: u8 = 0; /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF instead */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN: u8 = 1; /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON instead */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF: u8 = 3;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_ON: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_OFF: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_ON: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_OFF: u8 = 3;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF: u8 = 3;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLISTIC_ALTERNATES: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_ON: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_OFF: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_ON: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_OFF: u8 = 5;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_ON: u8 = 6;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_OFF: u8 = 7;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_ON: u8 = 8;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_OFF: u8 = 9;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_ON: u8 = 10;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_OFF: u8 = 11;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_ON: u8 = 12;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_OFF: u8 = 13;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_ON: u8 = 14;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_OFF: u8 = 15;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_ON: u8 = 16;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_OFF: u8 = 17;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_ON: u8 = 18;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_OFF: u8 = 19;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_ON: u8 = 20;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_OFF: u8 = 21;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_ON: u8 = 22;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_OFF: u8 = 23;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_ON: u8 = 24;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_OFF: u8 = 25;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_ON: u8 = 26;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_OFF: u8 = 27;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_ON: u8 = 28;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_OFF: u8 = 29;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_ON: u8 = 30;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_OFF: u8 = 31;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_ON: u8 = 32;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_OFF: u8 = 33;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_ON: u8 = 34;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_OFF: u8 = 35;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_ON: u8 = 36;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_OFF: u8 = 37;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_ON: u8 = 38;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_OFF: u8 = 39;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_ON: u8 = 40;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_OFF: u8 = 41;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_ON: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_OFF: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_ON: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_OFF: u8 = 3;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_ON: u8 = 4;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_OFF: u8 = 5;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_PETITE_CAPS: u8 = 2;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_SMALL_CAPS: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_PETITE_CAPS: u8 = 2;
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE */
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_CJK_ROMAN: u8 = 0;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_CJK_ROMAN: u8 = 1;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_CJK_ROMAN: u8 = 2;
pub const HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_CJK_ROMAN: u8 = 3;
pub struct hb_aat_feature_mapping_t {
pub ot_feature_tag: hb_tag_t,
pub aat_feature_type: hb_aat_layout_feature_type_t,
pub selector_to_enable: u8,
pub selector_to_disable: u8,
}
impl hb_aat_feature_mapping_t {
const fn new(
ot_feature_tag: &[u8; 4],
aat_feature_type: hb_aat_layout_feature_type_t,
selector_to_enable: u8,
selector_to_disable: u8,
) -> Self {
hb_aat_feature_mapping_t {
ot_feature_tag: hb_tag_t::from_bytes(ot_feature_tag),
aat_feature_type,
selector_to_enable,
selector_to_disable,
}
}
}
/// Mapping from OpenType feature tags to AAT feature names and selectors.
///
/// Table data courtesy of Apple.
/// Converted from mnemonics to integers when moving to this file.
#[rustfmt::skip]
pub const feature_mappings: &[hb_aat_feature_mapping_t] = &[
hb_aat_feature_mapping_t::new(b"afrc", HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_VERTICAL_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS),
hb_aat_feature_mapping_t::new(b"c2pc", HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_PETITE_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE),
hb_aat_feature_mapping_t::new(b"c2sc", HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE),
hb_aat_feature_mapping_t::new(b"calt", HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_OFF),
hb_aat_feature_mapping_t::new(b"case", HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_OFF),
hb_aat_feature_mapping_t::new(b"clig", HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_OFF),
hb_aat_feature_mapping_t::new(b"cpsp", HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_OFF),
hb_aat_feature_mapping_t::new(b"cswh", HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_OFF),
hb_aat_feature_mapping_t::new(b"dlig", HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_OFF),
hb_aat_feature_mapping_t::new(b"expt", HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPERT_CHARACTERS, 16),
hb_aat_feature_mapping_t::new(b"frac", HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS),
hb_aat_feature_mapping_t::new(b"fwid", HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT, 7),
hb_aat_feature_mapping_t::new(b"halt", HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT, 7),
hb_aat_feature_mapping_t::new(b"hist", 40, 0, 1),
hb_aat_feature_mapping_t::new(b"hkna", HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF),
hb_aat_feature_mapping_t::new(b"hlig", HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF),
hb_aat_feature_mapping_t::new(b"hngl", HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION, HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION),
hb_aat_feature_mapping_t::new(b"hojo", HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_HOJO_CHARACTERS, 16),
hb_aat_feature_mapping_t::new(b"hwid", HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_TEXT, 7),
hb_aat_feature_mapping_t::new(b"ital", HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN, HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF),
hb_aat_feature_mapping_t::new(b"jp04", HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS2004_CHARACTERS, 16),
hb_aat_feature_mapping_t::new(b"jp78", HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1978_CHARACTERS, 16),
hb_aat_feature_mapping_t::new(b"jp83", HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1983_CHARACTERS, 16),
hb_aat_feature_mapping_t::new(b"jp90", HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1990_CHARACTERS, 16),
hb_aat_feature_mapping_t::new(b"liga", HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_OFF),
hb_aat_feature_mapping_t::new(b"lnum", HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_NUMBERS, 2),
hb_aat_feature_mapping_t::new(b"mgrk", HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS, HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_OFF),
hb_aat_feature_mapping_t::new(b"nlck", HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_NLCCHARACTERS, 16),
hb_aat_feature_mapping_t::new(b"onum", HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_NUMBERS, 2),
hb_aat_feature_mapping_t::new(b"ordn", HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_ORDINALS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION),
hb_aat_feature_mapping_t::new(b"palt", HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, 7),
hb_aat_feature_mapping_t::new(b"pcap", HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_PETITE_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE),
hb_aat_feature_mapping_t::new(b"pkna", HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, 7),
hb_aat_feature_mapping_t::new(b"pnum", HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS, 4),
hb_aat_feature_mapping_t::new(b"pwid", HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, 7),
hb_aat_feature_mapping_t::new(b"qwid", HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT, 7),
hb_aat_feature_mapping_t::new(b"rlig", HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF),
hb_aat_feature_mapping_t::new(b"ruby", HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF),
hb_aat_feature_mapping_t::new(b"sinf", HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION),
hb_aat_feature_mapping_t::new(b"smcp", HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE),
hb_aat_feature_mapping_t::new(b"smpl", HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_SIMPLIFIED_CHARACTERS, 16),
hb_aat_feature_mapping_t::new(b"ss01", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_OFF),
hb_aat_feature_mapping_t::new(b"ss02", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_OFF),
hb_aat_feature_mapping_t::new(b"ss03", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_OFF),
hb_aat_feature_mapping_t::new(b"ss04", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_OFF),
hb_aat_feature_mapping_t::new(b"ss05", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_OFF),
hb_aat_feature_mapping_t::new(b"ss06", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_OFF),
hb_aat_feature_mapping_t::new(b"ss07", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_OFF),
hb_aat_feature_mapping_t::new(b"ss08", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_OFF),
hb_aat_feature_mapping_t::new(b"ss09", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_OFF),
hb_aat_feature_mapping_t::new(b"ss10", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_OFF),
hb_aat_feature_mapping_t::new(b"ss11", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_OFF),
hb_aat_feature_mapping_t::new(b"ss12", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_OFF),
hb_aat_feature_mapping_t::new(b"ss13", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_OFF),
hb_aat_feature_mapping_t::new(b"ss14", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_OFF),
hb_aat_feature_mapping_t::new(b"ss15", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_OFF),
hb_aat_feature_mapping_t::new(b"ss16", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_OFF),
hb_aat_feature_mapping_t::new(b"ss17", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_OFF),
hb_aat_feature_mapping_t::new(b"ss18", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_OFF),
hb_aat_feature_mapping_t::new(b"ss19", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_OFF),
hb_aat_feature_mapping_t::new(b"ss20", HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_OFF),
hb_aat_feature_mapping_t::new(b"subs", HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION),
hb_aat_feature_mapping_t::new(b"sups", HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUPERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION),
hb_aat_feature_mapping_t::new(b"swsh", HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_OFF),
hb_aat_feature_mapping_t::new(b"titl", HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_TITLING_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLE_OPTIONS),
hb_aat_feature_mapping_t::new(b"tnam", HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_NAMES_CHARACTERS, 16),
hb_aat_feature_mapping_t::new(b"tnum", HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_NUMBERS, 4),
hb_aat_feature_mapping_t::new(b"trad", HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_CHARACTERS, 16),
hb_aat_feature_mapping_t::new(b"twid", HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_TEXT, 7),
hb_aat_feature_mapping_t::new(b"unic", HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE, 14, 15),
hb_aat_feature_mapping_t::new(b"valt", HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, 7),
hb_aat_feature_mapping_t::new(b"vert", HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF),
hb_aat_feature_mapping_t::new(b"vhal", HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT, 7),
hb_aat_feature_mapping_t::new(b"vkna", HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF),
hb_aat_feature_mapping_t::new(b"vpal", HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, 7),
hb_aat_feature_mapping_t::new(b"vrt2", HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF),
hb_aat_feature_mapping_t::new(b"vrtr", HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION, 2, 3),
hb_aat_feature_mapping_t::new(b"zero", HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF),
];
mod AAT {
pub const DELETED_GLYPH: u32 = 0xFFFF;
}
pub fn hb_aat_layout_substitute(
plan: &hb_ot_shape_plan_t,
face: &hb_font_t,
buffer: &mut hb_buffer_t,
) {
let mut builder = aat_map::hb_aat_map_builder_t::default();
for feature in &plan.user_features {
builder.add_feature(face, feature);
}
let mut aat_map = aat_map::hb_aat_map_t::default();
if plan.apply_morx {
builder.compile(face, &mut aat_map);
}
let mut c = hb_aat_apply_context_t::new(face, buffer);
aat_layout_morx_table::apply(&mut c, &mut aat_map);
}
pub fn hb_aat_layout_zero_width_deleted_glyphs(buffer: &mut hb_buffer_t) {
for i in 0..buffer.len {
if buffer.info[i].glyph_id == AAT::DELETED_GLYPH {
buffer.pos[i].x_advance = 0;
buffer.pos[i].y_advance = 0;
buffer.pos[i].x_offset = 0;
buffer.pos[i].y_offset = 0;
}
}
}
fn is_deleted_glyph(info: &hb_glyph_info_t) -> bool {
info.glyph_id == AAT::DELETED_GLYPH
}
pub fn hb_aat_layout_remove_deleted_glyphs(buffer: &mut hb_buffer_t) {
buffer.delete_glyphs_inplace(is_deleted_glyph)
}
pub fn hb_aat_layout_position(
plan: &hb_ot_shape_plan_t,
face: &hb_font_t,
buffer: &mut hb_buffer_t,
) {
aat_layout_kerx_table::apply(plan, face, buffer);
}
pub fn hb_aat_layout_track(plan: &hb_ot_shape_plan_t, face: &hb_font_t, buffer: &mut hb_buffer_t) {
aat_layout_trak_table::apply(plan, face, buffer);
}
rustybuzz-0.18.0/src/hb/aat_layout_common.rs 0000644 0000000 0000000 00000001112 10461020230 0017246 0 ustar 0000000 0000000 use crate::hb::aat_map::range_flags_t;
use crate::hb::buffer::hb_buffer_t;
use crate::hb::face::hb_font_t;
use crate::hb::hb_mask_t;
pub struct hb_aat_apply_context_t<'a> {
pub face: &'a hb_font_t<'a>,
pub buffer: &'a mut hb_buffer_t,
pub range_flags: Option<&'a mut [range_flags_t]>,
pub subtable_flags: hb_mask_t,
}
impl<'a> hb_aat_apply_context_t<'a> {
pub fn new(face: &'a hb_font_t<'a>, buffer: &'a mut hb_buffer_t) -> Self {
Self {
face,
buffer,
range_flags: None,
subtable_flags: 0,
}
}
}
rustybuzz-0.18.0/src/hb/aat_layout_kerx_table.rs 0000644 0000000 0000000 00000035115 10461020230 0020110 0 ustar 0000000 0000000 use core::convert::TryFrom;
use ttf_parser::{ankr, apple_layout, kerx, FromData, GlyphId};
use super::buffer::*;
use super::hb_font_t;
use super::ot_layout::TableIndex;
use super::ot_layout_common::lookup_flags;
use super::ot_layout_gpos_table::attach_type;
use super::ot_layout_gsubgpos::{skipping_iterator_t, OT::hb_ot_apply_context_t};
use super::ot_shape_plan::hb_ot_shape_plan_t;
// TODO: Use set_digest, similarly to how it's used in harfbuzz.
trait ExtendedStateTableExt {
fn class(&self, glyph_id: GlyphId) -> Option;
fn entry(&self, state: u16, class: u16) -> Option>;
}
impl ExtendedStateTableExt for kerx::Subtable1<'_> {
fn class(&self, glyph_id: GlyphId) -> Option {
self.state_table.class(glyph_id)
}
fn entry(
&self,
state: u16,
class: u16,
) -> Option> {
self.state_table.entry(state, class)
}
}
impl ExtendedStateTableExt for kerx::Subtable4<'_> {
fn class(&self, glyph_id: GlyphId) -> Option {
self.state_table.class(glyph_id)
}
fn entry(
&self,
state: u16,
class: u16,
) -> Option> {
self.state_table.entry(state, class)
}
}
pub(crate) fn apply(
plan: &hb_ot_shape_plan_t,
face: &hb_font_t,
buffer: &mut hb_buffer_t,
) -> Option<()> {
buffer.unsafe_to_concat(None, None);
let mut seen_cross_stream = false;
for subtable in face.tables().kerx?.subtables {
if subtable.variable {
continue;
}
if buffer.direction.is_horizontal() != subtable.horizontal {
continue;
}
let reverse = buffer.direction.is_backward();
if !seen_cross_stream && subtable.has_cross_stream {
seen_cross_stream = true;
// Attach all glyphs into a chain.
for pos in &mut buffer.pos {
pos.set_attach_type(attach_type::CURSIVE);
pos.set_attach_chain(if buffer.direction.is_forward() { -1 } else { 1 });
// We intentionally don't set BufferScratchFlags::HAS_GPOS_ATTACHMENT,
// since there needs to be a non-zero attachment for post-positioning to
// be needed.
}
}
if reverse {
buffer.reverse();
}
match subtable.format {
kerx::Format::Format0(_) => {
if !plan.requested_kerning {
continue;
}
apply_simple_kerning(&subtable, plan, face, buffer);
}
kerx::Format::Format1(ref sub) => {
let mut driver = Driver1 {
stack: [0; 8],
depth: 0,
};
apply_state_machine_kerning(&subtable, sub, &mut driver, plan, buffer);
}
kerx::Format::Format2(_) => {
if !plan.requested_kerning {
continue;
}
buffer.unsafe_to_concat(None, None);
apply_simple_kerning(&subtable, plan, face, buffer);
}
kerx::Format::Format4(ref sub) => {
let mut driver = Driver4 {
mark_set: false,
mark: 0,
ankr_table: face.tables().ankr.clone(),
};
apply_state_machine_kerning(&subtable, sub, &mut driver, plan, buffer);
}
kerx::Format::Format6(_) => {
if !plan.requested_kerning {
continue;
}
apply_simple_kerning(&subtable, plan, face, buffer);
}
}
if reverse {
buffer.reverse();
}
}
Some(())
}
fn apply_simple_kerning(
subtable: &kerx::Subtable,
plan: &hb_ot_shape_plan_t,
face: &hb_font_t,
buffer: &mut hb_buffer_t,
) {
let mut ctx = hb_ot_apply_context_t::new(TableIndex::GPOS, face, buffer);
ctx.set_lookup_mask(plan.kern_mask);
ctx.lookup_props = u32::from(lookup_flags::IGNORE_FLAGS);
let horizontal = ctx.buffer.direction.is_horizontal();
let mut i = 0;
while i < ctx.buffer.len {
if (ctx.buffer.info[i].mask & plan.kern_mask) == 0 {
i += 1;
continue;
}
let mut iter = skipping_iterator_t::new(&ctx, i, false);
let mut unsafe_to = 0;
if !iter.next(Some(&mut unsafe_to)) {
ctx.buffer.unsafe_to_concat(Some(i), Some(unsafe_to));
i += 1;
continue;
}
let j = iter.index();
let info = &ctx.buffer.info;
let kern = subtable
.glyphs_kerning(info[i].as_glyph(), info[j].as_glyph())
.unwrap_or(0);
let kern = i32::from(kern);
let pos = &mut ctx.buffer.pos;
if kern != 0 {
if horizontal {
if subtable.has_cross_stream {
pos[j].y_offset = kern;
ctx.buffer.scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
} else {
let kern1 = kern >> 1;
let kern2 = kern - kern1;
pos[i].x_advance += kern1;
pos[j].x_advance += kern2;
pos[j].x_offset += kern2;
}
} else {
if subtable.has_cross_stream {
pos[j].x_offset = kern;
ctx.buffer.scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
} else {
let kern1 = kern >> 1;
let kern2 = kern - kern1;
pos[i].y_advance += kern1;
pos[j].y_advance += kern2;
pos[j].y_offset += kern2;
}
}
ctx.buffer.unsafe_to_break(Some(i), Some(j + 1))
}
i = j;
}
}
const START_OF_TEXT: u16 = 0;
trait KerxEntryDataExt {
fn action_index(self) -> u16;
fn is_actionable(&self) -> bool;
}
impl KerxEntryDataExt for apple_layout::GenericStateEntry {
fn action_index(self) -> u16 {
self.extra.action_index
}
fn is_actionable(&self) -> bool {
self.extra.action_index != 0xFFFF
}
}
fn apply_state_machine_kerning(
subtable: &kerx::Subtable,
state_table: &T,
driver: &mut dyn StateTableDriver,
plan: &hb_ot_shape_plan_t,
buffer: &mut hb_buffer_t,
) where
T: ExtendedStateTableExt,
E: FromData + Copy,
apple_layout::GenericStateEntry: KerxEntryDataExt,
{
let mut state = START_OF_TEXT;
buffer.idx = 0;
loop {
let class = if buffer.idx < buffer.len {
state_table
.class(buffer.info[buffer.idx].as_glyph())
.unwrap_or(1)
} else {
u16::from(apple_layout::class::END_OF_TEXT)
};
let entry: apple_layout::GenericStateEntry = match state_table.entry(state, class) {
Some(v) => v,
None => break,
};
// Unsafe-to-break before this if not in state 0, as things might
// go differently if we start from state 0 here.
if state != START_OF_TEXT && buffer.backtrack_len() != 0 && buffer.idx < buffer.len {
// If there's no value and we're just epsilon-transitioning to state 0, safe to break.
if entry.is_actionable() || !(entry.new_state == START_OF_TEXT && !entry.has_advance())
{
buffer.unsafe_to_break_from_outbuffer(
Some(buffer.backtrack_len() - 1),
Some(buffer.idx + 1),
);
}
}
// Unsafe-to-break if end-of-text would kick in here.
if buffer.idx + 2 <= buffer.len {
let end_entry: Option> =
state_table.entry(state, u16::from(apple_layout::class::END_OF_TEXT));
let end_entry = match end_entry {
Some(v) => v,
None => break,
};
if end_entry.is_actionable() {
buffer.unsafe_to_break(Some(buffer.idx), Some(buffer.idx + 2));
}
}
let _ = driver.transition(
state_table,
entry,
subtable.has_cross_stream,
subtable.tuple_count,
plan,
buffer,
);
state = entry.new_state;
if buffer.idx >= buffer.len {
break;
}
if entry.has_advance() || buffer.max_ops <= 0 {
buffer.next_glyph();
}
buffer.max_ops -= 1;
}
}
trait StateTableDriver {
fn transition(
&mut self,
aat: &Table,
entry: apple_layout::GenericStateEntry,
has_cross_stream: bool,
tuple_count: u32,
plan: &hb_ot_shape_plan_t,
buffer: &mut hb_buffer_t,
) -> Option<()>;
}
struct Driver1 {
stack: [usize; 8],
depth: usize,
}
impl StateTableDriver, kerx::EntryData> for Driver1 {
fn transition(
&mut self,
aat: &kerx::Subtable1,
entry: apple_layout::GenericStateEntry,
has_cross_stream: bool,
tuple_count: u32,
plan: &hb_ot_shape_plan_t,
buffer: &mut hb_buffer_t,
) -> Option<()> {
if entry.has_reset() {
self.depth = 0;
}
if entry.has_push() {
if self.depth < self.stack.len() {
self.stack[self.depth] = buffer.idx;
self.depth += 1;
} else {
self.depth = 0; // Probably not what CoreText does, but better?
}
}
if entry.is_actionable() && self.depth != 0 {
let tuple_count = u16::try_from(tuple_count.max(1)).ok()?;
let mut action_index = entry.action_index();
// From Apple 'kern' spec:
// "Each pops one glyph from the kerning stack and applies the kerning value to it.
// The end of the list is marked by an odd value...
let mut last = false;
while !last && self.depth != 0 {
self.depth -= 1;
let idx = self.stack[self.depth];
let mut v = aat.glyphs_kerning(action_index)? as i32;
action_index = action_index.checked_add(tuple_count)?;
if idx >= buffer.len {
continue;
}
// "The end of the list is marked by an odd value..."
last = v & 1 != 0;
v &= !1;
// Testing shows that CoreText only applies kern (cross-stream or not)
// if none has been applied by previous subtables. That is, it does
// NOT seem to accumulate as otherwise implied by specs.
let mut has_gpos_attachment = false;
let glyph_mask = buffer.info[idx].mask;
let pos = &mut buffer.pos[idx];
if buffer.direction.is_horizontal() {
if has_cross_stream {
// The following flag is undocumented in the spec, but described
// in the 'kern' table example.
if v == -0x8000 {
pos.set_attach_type(0);
pos.set_attach_chain(0);
pos.y_offset = 0;
} else if pos.attach_type() != 0 {
pos.y_offset += v;
has_gpos_attachment = true;
}
} else if glyph_mask & plan.kern_mask != 0 {
pos.x_advance += v;
pos.x_offset += v;
}
} else {
if has_cross_stream {
// CoreText doesn't do crossStream kerning in vertical. We do.
if v == -0x8000 {
pos.set_attach_type(0);
pos.set_attach_chain(0);
pos.x_offset = 0;
} else if pos.attach_type() != 0 {
pos.x_offset += v;
has_gpos_attachment = true;
}
} else if glyph_mask & plan.kern_mask != 0 {
if pos.y_offset == 0 {
pos.y_advance += v;
pos.y_offset += v;
}
}
}
if has_gpos_attachment {
buffer.scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
}
}
}
Some(())
}
}
struct Driver4<'a> {
mark_set: bool,
mark: usize,
ankr_table: Option>,
}
impl StateTableDriver, kerx::EntryData> for Driver4<'_> {
fn transition(
&mut self,
aat: &kerx::Subtable4,
entry: apple_layout::GenericStateEntry,
_has_cross_stream: bool,
_tuple_count: u32,
_opt: &hb_ot_shape_plan_t,
buffer: &mut hb_buffer_t,
) -> Option<()> {
if self.mark_set && entry.is_actionable() && buffer.idx < buffer.len {
if let Some(ref ankr_table) = self.ankr_table {
let point = aat.anchor_points.get(entry.action_index())?;
let mark_idx = buffer.info[self.mark].as_glyph();
let mark_anchor = ankr_table
.points(mark_idx)
.and_then(|list| list.get(u32::from(point.0)))
.unwrap_or_default();
let curr_idx = buffer.cur(0).as_glyph();
let curr_anchor = ankr_table
.points(curr_idx)
.and_then(|list| list.get(u32::from(point.1)))
.unwrap_or_default();
let pos = buffer.cur_pos_mut();
pos.x_offset = i32::from(mark_anchor.x - curr_anchor.x);
pos.y_offset = i32::from(mark_anchor.y - curr_anchor.y);
}
buffer.cur_pos_mut().set_attach_type(attach_type::MARK);
let idx = buffer.idx;
buffer
.cur_pos_mut()
.set_attach_chain(self.mark as i16 - idx as i16);
buffer.scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
}
if entry.has_mark() {
self.mark_set = true;
self.mark = buffer.idx;
}
Some(())
}
}
rustybuzz-0.18.0/src/hb/aat_layout_morx_table.rs 0000644 0000000 0000000 00000072476 10461020230 0020137 0 ustar 0000000 0000000 use super::aat_layout::*;
use super::aat_map::{hb_aat_map_builder_t, hb_aat_map_t, range_flags_t};
use super::buffer::{hb_buffer_t, UnicodeProps};
use super::{hb_font_t, hb_glyph_info_t};
use crate::hb::aat_layout_common::hb_aat_apply_context_t;
use crate::hb::ot_layout::MAX_CONTEXT_LENGTH;
use alloc::vec;
use ttf_parser::{apple_layout, morx, FromData, GlyphId, LazyArray32};
// TODO: Use set_digest, similarly to how it's used in harfbuzz.
// Chain::compile_flags in harfbuzz
pub fn compile_flags(
face: &hb_font_t,
builder: &hb_aat_map_builder_t,
map: &mut hb_aat_map_t,
) -> Option<()> {
let has_feature = |kind: u16, setting: u16| {
builder
.current_features
.binary_search_by(|probe| {
if probe.kind != kind {
probe.kind.cmp(&kind)
} else {
probe.setting.cmp(&setting)
}
})
.is_ok()
};
let chains = face.tables().morx.as_ref()?.chains;
let chain_len = chains.clone().into_iter().count();
map.chain_flags.resize(chain_len, vec![]);
for (chain, chain_flags) in chains.into_iter().zip(map.chain_flags.iter_mut()) {
let mut flags = chain.default_flags;
for feature in chain.features {
// Check whether this type/setting pair was requested in the map,
// and if so, apply its flags.
if has_feature(feature.kind, feature.setting) {
flags &= feature.disable_flags;
flags |= feature.enable_flags;
} else if feature.kind == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE as u16
&& feature.setting == u16::from(HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS)
{
// Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342
let ok = has_feature(
HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE as u16,
u16::from(HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS),
);
if ok {
flags &= feature.disable_flags;
flags |= feature.enable_flags;
}
}
// TODO: Port the following commit: https://github.com/harfbuzz/harfbuzz/commit/2124ad890
}
chain_flags.push(range_flags_t {
flags,
cluster_first: builder.range_first as u32,
cluster_last: builder.range_last as u32,
});
}
Some(())
}
// Chain::apply in harfbuzz
pub fn apply<'a>(c: &mut hb_aat_apply_context_t<'a>, map: &'a mut hb_aat_map_t) -> Option<()> {
c.buffer.unsafe_to_concat(None, None);
let chains = c.face.tables().morx.as_ref()?.chains;
let chain_len = chains.clone().into_iter().count();
map.chain_flags.resize(chain_len, vec![]);
for (chain, chain_flags) in chains.into_iter().zip(map.chain_flags.iter_mut()) {
c.range_flags = Some(chain_flags.as_mut_slice());
for subtable in chain.subtables {
if let Some(range_flags) = c.range_flags.as_ref() {
if range_flags.len() == 1 && (subtable.feature_flags & range_flags[0].flags == 0) {
continue;
}
}
c.subtable_flags = subtable.feature_flags;
if !subtable.coverage.is_all_directions()
&& c.buffer.direction.is_vertical() != subtable.coverage.is_vertical()
{
continue;
}
// 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.
//
// Quoting the spec:
// """
// Bits 28 and 30 of the coverage field control the order in which
// glyphs are processed when the subtable is run by the layout engine.
// Bit 28 is used to indicate if the glyph processing direction is
// the same as logical order or layout order. Bit 30 is used to
// indicate whether glyphs are processed forwards or backwards within
// that order.
//
// Bit 30 Bit 28 Interpretation for Horizontal Text
// 0 0 The subtable is processed in layout order
// (the same order as the glyphs, which is
// always left-to-right).
// 1 0 The subtable is processed in reverse layout order
// (the order opposite that of the glyphs, which is
// always right-to-left).
// 0 1 The subtable is processed in logical order
// (the same order as the characters, which may be
// left-to-right or right-to-left).
// 1 1 The subtable is processed in reverse logical order
// (the order opposite that of the characters, which
// may be right-to-left or left-to-right).
let reverse = if subtable.coverage.is_logical() {
subtable.coverage.is_backwards()
} else {
subtable.coverage.is_backwards() != c.buffer.direction.is_backward()
};
if reverse {
c.buffer.reverse();
}
apply_subtable(&subtable.kind, c);
if reverse {
c.buffer.reverse();
}
}
}
Some(())
}
trait driver_context_t {
fn in_place(&self) -> bool;
fn can_advance(&self, entry: &apple_layout::GenericStateEntry) -> bool;
fn is_actionable(
&self,
entry: &apple_layout::GenericStateEntry,
buffer: &hb_buffer_t,
) -> bool;
fn transition(
&mut self,
entry: &apple_layout::GenericStateEntry,
buffer: &mut hb_buffer_t,
) -> Option<()>;
}
const START_OF_TEXT: u16 = 0;
fn drive(
machine: &apple_layout::ExtendedStateTable,
c: &mut dyn driver_context_t,
ac: &mut hb_aat_apply_context_t,
) {
if !c.in_place() {
ac.buffer.clear_output();
}
let mut state = START_OF_TEXT;
let mut last_range = ac.range_flags.as_ref().and_then(|rf| {
if rf.len() > 1 {
rf.first().map(|_| 0usize)
} else {
// If there's only one range, we already checked the flag.
None
}
});
ac.buffer.idx = 0;
loop {
// This block copied from NoncontextualSubtable::apply. Keep in sync.
if let Some(range_flags) = ac.range_flags.as_ref() {
if let Some(last_range) = last_range.as_mut() {
let mut range = *last_range;
if ac.buffer.idx < ac.buffer.len {
let cluster = ac.buffer.cur(0).cluster;
while cluster < range_flags[range].cluster_first {
range -= 1;
}
while cluster > range_flags[range].cluster_last {
range += 1;
}
*last_range = range;
}
if range_flags[range].flags & ac.subtable_flags == 0 {
if ac.buffer.idx == ac.buffer.len || !ac.buffer.successful {
break;
}
state = START_OF_TEXT;
ac.buffer.next_glyph();
continue;
}
}
}
let class = if ac.buffer.idx < ac.buffer.len {
machine.class(ac.buffer.cur(0).as_glyph()).unwrap_or(1)
} else {
u16::from(apple_layout::class::END_OF_TEXT)
};
let entry: apple_layout::GenericStateEntry = match machine.entry(state, class) {
Some(v) => v,
None => break,
};
let next_state = entry.new_state;
// Conditions under which it's guaranteed safe-to-break before current glyph:
//
// 1. There was no action in this transition; and
//
// 2. If we break before current glyph, the results will be the same. That
// is guaranteed if:
//
// 2a. We were already in start-of-text state; or
//
// 2b. We are epsilon-transitioning to start-of-text state; or
//
// 2c. Starting from start-of-text state seeing current glyph:
//
// 2c'. There won't be any actions; and
//
// 2c". We would end up in the same state that we were going to end up
// in now, including whether epsilon-transitioning.
//
// and
//
// 3. If we break before current glyph, there won't be any end-of-text action
// after previous glyph.
//
// This triples the transitions we need to look up, but is worth returning
// granular unsafe-to-break results. See eg.:
//
// https://github.com/harfbuzz/harfbuzz/issues/2860
let is_safe_to_break_extra = || {
// 2c
let wouldbe_entry = match machine.entry(START_OF_TEXT, class) {
Some(v) => v,
None => return false,
};
// 2c'
if c.is_actionable(&wouldbe_entry, &ac.buffer) {
return false;
}
// 2c"
return next_state == wouldbe_entry.new_state
&& c.can_advance(&entry) == c.can_advance(&wouldbe_entry);
};
let is_safe_to_break = || {
// 1
if c.is_actionable(&entry, &ac.buffer) {
return false;
}
// 2
let ok = state == START_OF_TEXT
|| (!c.can_advance(&entry) && next_state == START_OF_TEXT)
|| is_safe_to_break_extra();
if !ok {
return false;
}
// 3
let end_entry = match machine.entry(state, u16::from(apple_layout::class::END_OF_TEXT))
{
Some(v) => v,
None => return false,
};
return !c.is_actionable(&end_entry, &ac.buffer);
};
if !is_safe_to_break() && ac.buffer.backtrack_len() > 0 && ac.buffer.idx < ac.buffer.len {
ac.buffer.unsafe_to_break_from_outbuffer(
Some(ac.buffer.backtrack_len() - 1),
Some(ac.buffer.idx + 1),
);
}
c.transition(&entry, ac.buffer);
state = next_state;
if ac.buffer.idx >= ac.buffer.len || !ac.buffer.successful {
break;
}
if c.can_advance(&entry) {
ac.buffer.next_glyph();
} else {
if ac.buffer.max_ops <= 0 {
ac.buffer.next_glyph();
}
ac.buffer.max_ops -= 1;
}
}
if !c.in_place() {
ac.buffer.sync();
}
}
fn apply_subtable(kind: &morx::SubtableKind, ac: &mut hb_aat_apply_context_t) {
match kind {
morx::SubtableKind::Rearrangement(ref table) => {
let mut c = RearrangementCtx { start: 0, end: 0 };
drive::<()>(table, &mut c, ac);
}
morx::SubtableKind::Contextual(ref table) => {
let mut c = ContextualCtx {
mark_set: false,
face_if_has_glyph_classes:
matches!(ac.face.tables().gdef, Some(gdef) if gdef.has_glyph_classes())
.then_some(ac.face),
mark: 0,
table,
};
drive::(&table.state, &mut c, ac);
}
morx::SubtableKind::Ligature(ref table) => {
let mut c = LigatureCtx {
table,
match_length: 0,
match_positions: [0; LIGATURE_MAX_MATCHES],
};
drive::(&table.state, &mut c, ac);
}
morx::SubtableKind::NonContextual(ref lookup) => {
let face_if_has_glyph_classes =
matches!(ac.face.tables().gdef, Some(gdef) if gdef.has_glyph_classes())
.then_some(ac.face);
let mut last_range = ac.range_flags.as_ref().and_then(|rf| {
if rf.len() > 1 {
rf.first().map(|_| 0usize)
} else {
// If there's only one range, we already checked the flag.
None
}
});
for info in 0..ac.buffer.len {
// This block copied from StateTableDriver::drive. Keep in sync.
if let Some(range_flags) = ac.range_flags.as_ref() {
if let Some(last_range) = last_range.as_mut() {
let mut range = *last_range;
if ac.buffer.idx < ac.buffer.len {
// We need to access info
let cluster = ac.buffer.cur(0).cluster;
while cluster < range_flags[range].cluster_first {
range -= 1;
}
while cluster > range_flags[range].cluster_last {
range += 1;
}
*last_range = range;
}
if range_flags[range].flags & ac.subtable_flags == 0 {
continue;
}
}
}
let info = &mut ac.buffer.info[info];
if let Some(replacement) = lookup.value(info.as_glyph()) {
info.glyph_id = u32::from(replacement);
if let Some(face) = face_if_has_glyph_classes {
info.set_glyph_props(face.glyph_props(GlyphId(replacement)));
}
}
}
}
morx::SubtableKind::Insertion(ref table) => {
let mut c = InsertionCtx {
mark: 0,
glyphs: table.glyphs,
};
drive::(&table.state, &mut c, ac);
}
}
}
struct RearrangementCtx {
start: usize,
end: usize,
}
impl RearrangementCtx {
const MARK_FIRST: u16 = 0x8000;
const DONT_ADVANCE: u16 = 0x4000;
const MARK_LAST: u16 = 0x2000;
const VERB: u16 = 0x000F;
}
impl driver_context_t<()> for RearrangementCtx {
fn in_place(&self) -> bool {
true
}
fn can_advance(&self, entry: &apple_layout::GenericStateEntry<()>) -> bool {
entry.flags & Self::DONT_ADVANCE == 0
}
fn is_actionable(&self, entry: &apple_layout::GenericStateEntry<()>, _: &hb_buffer_t) -> bool {
entry.flags & Self::VERB != 0 && self.start < self.end
}
fn transition(
&mut self,
entry: &apple_layout::GenericStateEntry<()>,
buffer: &mut hb_buffer_t,
) -> Option<()> {
let flags = entry.flags;
if flags & Self::MARK_FIRST != 0 {
self.start = buffer.idx;
}
if flags & Self::MARK_LAST != 0 {
self.end = (buffer.idx + 1).min(buffer.len);
}
if flags & Self::VERB != 0 && self.start < self.end {
// The following map has two nibbles, for start-side
// and end-side. Values of 0,1,2 mean move that many
// to the other side. Value of 3 means move 2 and
// flip them.
const MAP: [u8; 16] = [
0x00, // 0 no change
0x10, // 1 Ax => xA
0x01, // 2 xD => Dx
0x11, // 3 AxD => DxA
0x20, // 4 ABx => xAB
0x30, // 5 ABx => xBA
0x02, // 6 xCD => CDx
0x03, // 7 xCD => DCx
0x12, // 8 AxCD => CDxA
0x13, // 9 AxCD => DCxA
0x21, // 10 ABxD => DxAB
0x31, // 11 ABxD => DxBA
0x22, // 12 ABxCD => CDxAB
0x32, // 13 ABxCD => CDxBA
0x23, // 14 ABxCD => DCxAB
0x33, // 15 ABxCD => DCxBA
];
let m = MAP[usize::from(flags & Self::VERB)];
let l = 2.min(m >> 4) as usize;
let r = 2.min(m & 0x0F) as usize;
let reverse_l = 3 == (m >> 4);
let reverse_r = 3 == (m & 0x0F);
if (self.end - self.start >= l + r) && (self.end - self.start <= MAX_CONTEXT_LENGTH) {
buffer.merge_clusters(self.start, (buffer.idx + 1).min(buffer.len));
buffer.merge_clusters(self.start, self.end);
let mut buf = [hb_glyph_info_t::default(); 4];
for (i, glyph_info) in buf[..l].iter_mut().enumerate() {
*glyph_info = buffer.info[self.start + i];
}
for i in 0..r {
buf[i + 2] = buffer.info[self.end - r + i];
}
if l > r {
for i in 0..(self.end - self.start - l - r) {
buffer.info[self.start + r + i] = buffer.info[self.start + l + i];
}
} else if l < r {
for i in (0..(self.end - self.start - l - r)).rev() {
buffer.info[self.start + r + i] = buffer.info[self.start + l + i];
}
}
for i in 0..r {
buffer.info[self.start + i] = buf[2 + i];
}
for i in 0..l {
buffer.info[self.end - l + i] = buf[i];
}
if reverse_l {
buffer.info.swap(self.end - 1, self.end - 2);
}
if reverse_r {
buffer.info.swap(self.start, self.start + 1);
}
}
}
Some(())
}
}
struct ContextualCtx<'a> {
mark_set: bool,
face_if_has_glyph_classes: Option<&'a hb_font_t<'a>>,
mark: usize,
table: &'a morx::ContextualSubtable<'a>,
}
impl ContextualCtx<'_> {
const SET_MARK: u16 = 0x8000;
const DONT_ADVANCE: u16 = 0x4000;
}
impl driver_context_t for ContextualCtx<'_> {
fn in_place(&self) -> bool {
true
}
fn can_advance(
&self,
entry: &apple_layout::GenericStateEntry,
) -> bool {
entry.flags & Self::DONT_ADVANCE == 0
}
fn is_actionable(
&self,
entry: &apple_layout::GenericStateEntry,
buffer: &hb_buffer_t,
) -> bool {
if buffer.idx == buffer.len && !self.mark_set {
return false;
}
entry.extra.mark_index != 0xFFFF || entry.extra.current_index != 0xFFFF
}
fn transition(
&mut self,
entry: &apple_layout::GenericStateEntry,
buffer: &mut hb_buffer_t,
) -> Option<()> {
// Looks like CoreText applies neither mark nor current substitution for
// end-of-text if mark was not explicitly set.
if buffer.idx == buffer.len && !self.mark_set {
return Some(());
}
let mut replacement = None;
if entry.extra.mark_index != 0xFFFF {
let lookup = self.table.lookup(u32::from(entry.extra.mark_index))?;
replacement = lookup.value(buffer.info[self.mark].as_glyph());
}
if let Some(replacement) = replacement {
buffer.unsafe_to_break(Some(self.mark), Some((buffer.idx + 1).min(buffer.len)));
buffer.info[self.mark].glyph_id = u32::from(replacement);
if let Some(face) = self.face_if_has_glyph_classes {
buffer.info[self.mark].set_glyph_props(face.glyph_props(GlyphId(replacement)));
}
}
replacement = None;
let idx = buffer.idx.min(buffer.len - 1);
if entry.extra.current_index != 0xFFFF {
let lookup = self.table.lookup(u32::from(entry.extra.current_index))?;
replacement = lookup.value(buffer.info[idx].as_glyph());
}
if let Some(replacement) = replacement {
buffer.info[idx].glyph_id = u32::from(replacement);
if let Some(face) = self.face_if_has_glyph_classes {
buffer.info[self.mark].set_glyph_props(face.glyph_props(GlyphId(replacement)));
}
}
if entry.flags & Self::SET_MARK != 0 {
self.mark_set = true;
self.mark = buffer.idx;
}
Some(())
}
}
struct InsertionCtx<'a> {
mark: u32,
glyphs: LazyArray32<'a, GlyphId>,
}
impl InsertionCtx<'_> {
const SET_MARK: u16 = 0x8000;
const DONT_ADVANCE: u16 = 0x4000;
const CURRENT_INSERT_BEFORE: u16 = 0x0800;
const MARKED_INSERT_BEFORE: u16 = 0x0400;
const CURRENT_INSERT_COUNT: u16 = 0x03E0;
const MARKED_INSERT_COUNT: u16 = 0x001F;
}
impl driver_context_t for InsertionCtx<'_> {
fn in_place(&self) -> bool {
false
}
fn can_advance(
&self,
entry: &apple_layout::GenericStateEntry,
) -> bool {
entry.flags & Self::DONT_ADVANCE == 0
}
fn is_actionable(
&self,
entry: &apple_layout::GenericStateEntry,
_: &hb_buffer_t,
) -> bool {
(entry.flags & (Self::CURRENT_INSERT_COUNT | Self::MARKED_INSERT_COUNT) != 0)
&& (entry.extra.current_insert_index != 0xFFFF
|| entry.extra.marked_insert_index != 0xFFFF)
}
fn transition(
&mut self,
entry: &apple_layout::GenericStateEntry,
buffer: &mut hb_buffer_t,
) -> Option<()> {
let flags = entry.flags;
let mark_loc = buffer.out_len;
if entry.extra.marked_insert_index != 0xFFFF {
let count = flags & Self::MARKED_INSERT_COUNT;
buffer.max_ops -= i32::from(count);
if buffer.max_ops <= 0 {
return Some(());
}
let start = entry.extra.marked_insert_index;
let before = flags & Self::MARKED_INSERT_BEFORE != 0;
let end = buffer.out_len;
buffer.move_to(self.mark as usize);
if buffer.idx < buffer.len && !before {
buffer.copy_glyph();
}
// TODO We ignore KashidaLike setting.
for i in 0..count {
let i = u32::from(start + i);
buffer.output_glyph(u32::from(self.glyphs.get(i)?.0));
}
if buffer.idx < buffer.len && !before {
buffer.skip_glyph();
}
buffer.move_to(end + usize::from(count));
buffer.unsafe_to_break_from_outbuffer(
Some(self.mark as usize),
Some((buffer.idx + 1).min(buffer.len)),
);
}
if flags & Self::SET_MARK != 0 {
self.mark = mark_loc as u32;
}
if entry.extra.current_insert_index != 0xFFFF {
let count = (flags & Self::CURRENT_INSERT_COUNT) >> 5;
buffer.max_ops -= i32::from(count);
if buffer.max_ops < 0 {
return Some(());
}
let start = entry.extra.current_insert_index;
let before = flags & Self::CURRENT_INSERT_BEFORE != 0;
let end = buffer.out_len;
if buffer.idx < buffer.len && !before {
buffer.copy_glyph();
}
// TODO We ignore KashidaLike setting.
for i in 0..count {
let i = u32::from(start + i);
buffer.output_glyph(u32::from(self.glyphs.get(i)?.0));
}
if buffer.idx < buffer.len && !before {
buffer.skip_glyph();
}
// Humm. Not sure where to move to. There's this wording under
// DontAdvance flag:
//
// "If set, don't update the glyph index before going to the new state.
// This does not mean that the glyph pointed to is the same one as
// before. If you've made insertions immediately downstream of the
// current glyph, the next glyph processed would in fact be the first
// one inserted."
//
// This suggests that if DontAdvance is NOT set, we should move to
// end+count. If it *was*, then move to end, such that newly inserted
// glyphs are now visible.
//
// https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417
buffer.move_to(if flags & Self::DONT_ADVANCE != 0 {
end
} else {
end + usize::from(count)
});
}
Some(())
}
}
const LIGATURE_MAX_MATCHES: usize = 64;
struct LigatureCtx<'a> {
table: &'a morx::LigatureSubtable<'a>,
match_length: usize,
match_positions: [usize; LIGATURE_MAX_MATCHES],
}
impl LigatureCtx<'_> {
const SET_COMPONENT: u16 = 0x8000;
const DONT_ADVANCE: u16 = 0x4000;
const PERFORM_ACTION: u16 = 0x2000;
const LIG_ACTION_LAST: u32 = 0x80000000;
const LIG_ACTION_STORE: u32 = 0x40000000;
const LIG_ACTION_OFFSET: u32 = 0x3FFFFFFF;
}
impl driver_context_t for LigatureCtx<'_> {
fn in_place(&self) -> bool {
false
}
fn can_advance(&self, entry: &apple_layout::GenericStateEntry) -> bool {
entry.flags & Self::DONT_ADVANCE == 0
}
fn is_actionable(&self, entry: &apple_layout::GenericStateEntry, _: &hb_buffer_t) -> bool {
entry.flags & Self::PERFORM_ACTION != 0
}
fn transition(
&mut self,
entry: &apple_layout::GenericStateEntry,
buffer: &mut hb_buffer_t,
) -> Option<()> {
if entry.flags & Self::SET_COMPONENT != 0 {
// Never mark same index twice, in case DONT_ADVANCE was used...
if self.match_length != 0
&& self.match_positions[(self.match_length - 1) % LIGATURE_MAX_MATCHES]
== buffer.out_len
{
self.match_length -= 1;
}
self.match_positions[self.match_length % LIGATURE_MAX_MATCHES] = buffer.out_len;
self.match_length += 1;
}
if entry.flags & Self::PERFORM_ACTION != 0 {
let end = buffer.out_len;
if self.match_length == 0 {
return Some(());
}
if buffer.idx >= buffer.len {
return Some(()); // TODO: Work on previous instead?
}
let mut cursor = self.match_length;
let mut ligature_actions_index = entry.extra;
let mut ligature_idx = 0;
loop {
if cursor == 0 {
// Stack underflow. Clear the stack.
self.match_length = 0;
break;
}
cursor -= 1;
buffer.move_to(self.match_positions[cursor % LIGATURE_MAX_MATCHES]);
// We cannot use ? in this loop, because we must call
// buffer.move_to(end) in the end.
let action = match self
.table
.ligature_actions
.get(u32::from(ligature_actions_index))
{
Some(v) => v,
None => break,
};
let mut uoffset = action & Self::LIG_ACTION_OFFSET;
if uoffset & 0x20000000 != 0 {
uoffset |= 0xC0000000; // Sign-extend.
}
let offset = uoffset as i32;
let component_idx = (buffer.cur(0).glyph_id as i32 + offset) as u32;
ligature_idx += match self.table.components.get(component_idx) {
Some(v) => v,
None => break,
};
if (action & (Self::LIG_ACTION_STORE | Self::LIG_ACTION_LAST)) != 0 {
let lig = match self.table.ligatures.get(u32::from(ligature_idx)) {
Some(v) => v,
None => break,
};
buffer.replace_glyph(u32::from(lig.0));
let lig_end =
self.match_positions[(self.match_length - 1) % LIGATURE_MAX_MATCHES] + 1;
// Now go and delete all subsequent components.
while self.match_length - 1 > cursor {
self.match_length -= 1;
buffer.move_to(
self.match_positions[self.match_length % LIGATURE_MAX_MATCHES],
);
let cur_unicode = buffer.cur(0).unicode_props();
buffer
.cur_mut(0)
.set_unicode_props(cur_unicode | UnicodeProps::IGNORABLE.bits());
buffer.replace_glyph(0xFFFF);
}
buffer.move_to(lig_end);
buffer.merge_out_clusters(
self.match_positions[cursor % LIGATURE_MAX_MATCHES],
buffer.out_len,
);
}
ligature_actions_index += 1;
if action & Self::LIG_ACTION_LAST != 0 {
break;
}
}
buffer.move_to(end);
}
Some(())
}
}
rustybuzz-0.18.0/src/hb/aat_layout_trak_table.rs 0000644 0000000 0000000 00000006057 10461020230 0020103 0 ustar 0000000 0000000 #[cfg(not(feature = "std"))]
use core_maths::CoreFloat;
use super::buffer::hb_buffer_t;
use super::hb_font_t;
use super::ot_shape_plan::hb_ot_shape_plan_t;
pub fn apply(plan: &hb_ot_shape_plan_t, face: &hb_font_t, buffer: &mut hb_buffer_t) -> Option<()> {
let trak_mask = plan.trak_mask;
let ptem = face.points_per_em?;
if ptem <= 0.0 {
return None;
}
let trak = face.tables().trak?;
if !buffer.have_positions {
buffer.clear_positions();
}
if buffer.direction.is_horizontal() {
let tracking = trak.hor_tracking(ptem)?;
let advance_to_add = tracking;
let offset_to_add = tracking / 2;
foreach_grapheme!(buffer, start, end, {
if buffer.info[start].mask & trak_mask != 0 {
buffer.pos[start].x_advance += advance_to_add;
buffer.pos[start].x_offset += offset_to_add;
}
});
} else {
let tracking = trak.ver_tracking(ptem)?;
let advance_to_add = tracking;
let offset_to_add = tracking / 2;
foreach_grapheme!(buffer, start, end, {
if buffer.info[start].mask & trak_mask != 0 {
buffer.pos[start].y_advance += advance_to_add;
buffer.pos[start].y_offset += offset_to_add;
}
});
}
Some(())
}
trait TrackTableExt {
fn hor_tracking(&self, ptem: f32) -> Option;
fn ver_tracking(&self, ptem: f32) -> Option;
}
impl TrackTableExt for ttf_parser::trak::Table<'_> {
fn hor_tracking(&self, ptem: f32) -> Option {
self.horizontal.tracking(ptem)
}
fn ver_tracking(&self, ptem: f32) -> Option {
self.vertical.tracking(ptem)
}
}
trait TrackTableDataExt {
fn tracking(&self, ptem: f32) -> Option;
fn interpolate_at(
&self,
idx: u16,
target_size: f32,
track: &ttf_parser::trak::Track,
) -> Option;
}
impl TrackTableDataExt for ttf_parser::trak::TrackData<'_> {
fn tracking(&self, ptem: f32) -> Option {
// Choose track.
let track = self.tracks.into_iter().find(|t| t.value == 0.0)?;
// Choose size.
if self.sizes.is_empty() {
return None;
}
let mut idx = self
.sizes
.into_iter()
.position(|s| s.0 >= ptem)
.unwrap_or(self.sizes.len() as usize - 1);
if idx > 0 {
idx -= 1;
}
self.interpolate_at(idx as u16, ptem, &track)
.map(|n| n.round() as i32)
}
fn interpolate_at(
&self,
idx: u16,
target_size: f32,
track: &ttf_parser::trak::Track,
) -> Option {
debug_assert!(idx < self.sizes.len() - 1);
let s0 = self.sizes.get(idx)?.0;
let s1 = self.sizes.get(idx + 1)?.0;
let t = if s0 == s1 {
0.0
} else {
(target_size - s0) / (s1 - s0)
};
let n =
t * (track.values.get(idx + 1)? as f32) + (1.0 - t) * (track.values.get(idx)? as f32);
Some(n)
}
}
rustybuzz-0.18.0/src/hb/aat_map.rs 0000644 0000000 0000000 00000020146 10461020230 0015146 0 ustar 0000000 0000000 use crate::hb::common::{HB_FEATURE_GLOBAL_END, HB_FEATURE_GLOBAL_START};
use crate::Feature;
use alloc::vec;
use alloc::vec::Vec;
use core::cmp::Ordering;
use super::aat_layout::*;
use super::{hb_font_t, hb_mask_t, hb_tag_t};
#[derive(Default)]
pub struct hb_aat_map_t {
pub chain_flags: Vec>,
}
#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct feature_info_t {
pub kind: u16,
pub setting: u16,
pub is_exclusive: bool,
}
impl Ord for feature_info_t {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
impl PartialOrd for feature_info_t {
fn partial_cmp(&self, other: &Self) -> Option {
if self.kind != other.kind {
Some(self.kind.cmp(&other.kind))
} else if !self.is_exclusive && (self.setting & !1) != (other.setting & !1) {
Some(self.setting.cmp(&other.setting))
} else {
Some(core::cmp::Ordering::Equal)
}
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct feature_range_t {
pub info: feature_info_t,
pub start: u32,
pub end: u32,
}
#[derive(Copy, Clone, Eq, PartialEq)]
struct feature_event_t {
pub index: usize,
pub start: bool,
pub feature: feature_info_t,
}
#[derive(Copy, Clone)]
pub struct range_flags_t {
pub flags: hb_mask_t,
pub cluster_first: u32,
pub cluster_last: u32, // end - 1
}
impl Ord for feature_event_t {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
impl PartialOrd for feature_event_t {
fn partial_cmp(&self, other: &Self) -> Option {
if self.index != other.index {
Some(self.index.cmp(&other.index))
} else if self.start != other.start {
Some(self.start.cmp(&other.start))
} else {
Some(Ordering::Equal)
}
}
}
pub struct hb_aat_map_builder_t {
pub current_features: Vec,
pub features: Vec,
pub range_first: usize,
pub range_last: usize,
}
impl Default for hb_aat_map_builder_t {
fn default() -> Self {
Self {
range_first: HB_FEATURE_GLOBAL_START as usize,
range_last: HB_FEATURE_GLOBAL_END as usize,
current_features: Vec::default(),
features: Vec::default(),
}
}
}
impl hb_aat_map_builder_t {
pub fn add_feature(&mut self, face: &hb_font_t, feature: &Feature) -> Option<()> {
let feat = face.tables().feat?;
if feature.tag == hb_tag_t::from_bytes(b"aalt") {
let exposes_feature = feat
.names
.find(HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES as u16)
.map(|f| f.setting_names.len() != 0)
.unwrap_or(false);
if !exposes_feature {
return Some(());
}
self.features.push(feature_range_t {
start: feature.start,
end: feature.end,
info: feature_info_t {
kind: HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES as u16,
setting: u16::try_from(feature.value).unwrap(),
is_exclusive: true,
},
});
}
let idx = feature_mappings
.binary_search_by(|map| map.ot_feature_tag.cmp(&feature.tag))
.ok()?;
let mapping = &feature_mappings[idx];
let mut feature_name = feat.names.find(mapping.aat_feature_type as u16);
match feature_name {
Some(feature) if feature.setting_names.len() != 0 => {}
_ => {
// Special case: Chain::compile_flags will fall back to the deprecated version of
// small-caps if necessary, so we need to check for that possibility.
// https://github.com/harfbuzz/harfbuzz/issues/2307
if mapping.aat_feature_type == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE
&& mapping.selector_to_enable
== HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS
{
feature_name = feat
.names
.find(HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE as u16);
}
}
}
match feature_name {
Some(feature_name) if feature_name.setting_names.len() != 0 => {
let setting = if feature.value != 0 {
mapping.selector_to_enable
} else {
mapping.selector_to_disable
} as u16;
self.features.push(feature_range_t {
start: feature.start,
end: feature.end,
info: feature_info_t {
kind: mapping.aat_feature_type as u16,
setting,
is_exclusive: feature_name.exclusive,
},
});
}
_ => {}
}
Some(())
}
pub fn compile(&mut self, face: &hb_font_t, m: &mut hb_aat_map_t) {
// Compute active features per range, and compile each.
let mut feature_events = vec![];
for feature in &self.features {
if feature.start == feature.end {
continue;
}
feature_events.push(feature_event_t {
index: feature.start as usize,
start: true,
feature: feature.info,
});
feature_events.push(feature_event_t {
index: feature.end as usize,
start: false,
feature: feature.info,
})
}
feature_events.sort();
// Add a strategic final event.
feature_events.push(feature_event_t {
index: u32::MAX as usize,
start: false,
feature: feature_info_t::default(),
});
// Scan events and save features for each range.
let mut active_features = vec![];
let mut last_index = 0;
for event in &feature_events {
if event.index != last_index {
// Save a snapshot of active features and the range.
// Sort features and merge duplicates.
self.current_features = active_features.clone();
self.range_first = last_index;
self.range_last = event.index.wrapping_sub(1);
if self.current_features.len() != 0 {
self.current_features.sort();
let mut j = 0;
for i in 1..self.current_features.len() {
// Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
// respectively, so we mask out the low-order bit when checking for "duplicates"
// (selectors referring to the same feature setting) here.
let non_exclusive = !self.current_features[i].is_exclusive
&& (self.current_features[i].setting & !1)
!= (self.current_features[j].setting & !1);
if self.current_features[i].kind != self.current_features[j].kind
|| non_exclusive
{
j += 1;
self.current_features[j] = self.current_features[i];
}
}
self.current_features.truncate(j + 1);
}
super::aat_layout_morx_table::compile_flags(face, self, m);
last_index = event.index;
}
if event.start {
active_features.push(event.feature);
} else {
if let Some(index) = active_features.iter().position(|&f| f == event.feature) {
active_features.remove(index);
}
}
}
for chain_flags in m.chain_flags.iter_mut() {
if let Some(last) = chain_flags.last_mut() {
last.cluster_last = HB_FEATURE_GLOBAL_END;
}
}
}
}
rustybuzz-0.18.0/src/hb/algs.rs 0000644 0000000 0000000 00000001172 10461020230 0014470 0 ustar 0000000 0000000 // FLAG macro in harfbuzz.
#[inline]
pub const fn rb_flag(x: u32) -> u32 {
1 << x
}
// FLAG_UNSAFE macro in harfbuzz.
#[inline]
pub fn rb_flag_unsafe(x: u32) -> u32 {
if x < 32 {
1 << x
} else {
0
}
}
// FLAG_RANGE macro in harfbuzz.
#[inline]
pub fn rb_flag_range(x: u32, y: u32) -> u32 {
(x < y) as u32 + rb_flag(y + 1) - rb_flag(x)
}
// FLAG64 macro in harfbuzz.
#[inline]
pub const fn rb_flag64(x: u32) -> u64 {
1 << x as u64
}
// FLAG64_UNSAFE macro in harfbuzz.
#[inline]
pub fn rb_flag64_unsafe(x: u32) -> u64 {
if x < 64 {
1 << (x as u64)
} else {
0
}
}
rustybuzz-0.18.0/src/hb/buffer.rs 0000644 0000000 0000000 00000154731 10461020230 0015025 0 ustar 0000000 0000000 use alloc::{string::String, vec::Vec};
use core::cmp::min;
use core::convert::TryFrom;
use ttf_parser::GlyphId;
use super::buffer::glyph_flag::{SAFE_TO_INSERT_TATWEEL, UNSAFE_TO_BREAK, UNSAFE_TO_CONCAT};
use super::face::hb_glyph_extents_t;
use super::unicode::{CharExt, GeneralCategoryExt};
use super::{hb_font_t, hb_mask_t};
use crate::hb::set_digest::{hb_set_digest_ext, hb_set_digest_t};
use crate::{script, BufferClusterLevel, BufferFlags, Direction, Language, Script, SerializeFlags};
const CONTEXT_LENGTH: usize = 5;
pub mod glyph_flag {
/// Indicates that if input text is broken at the
/// beginning of the cluster this glyph is part of,
/// then both sides need to be re-shaped, as the
/// result might be different.
///
/// On the flip side, it means that when
/// this flag is not present, then it is safe
/// to break the glyph-run at the beginning of
/// this cluster, and the two sides will represent
/// the exact same result one would get if breaking
/// input text at the beginning of this cluster and
/// shaping the two sides separately.
///
/// This can be used to optimize paragraph layout,
/// by avoiding re-shaping of each line after line-breaking.
pub const UNSAFE_TO_BREAK: u32 = 0x00000001;
/// Indicates that if input text is changed on one side
/// of the beginning of the cluster this glyph is part
/// of, then the shaping results for the other side
/// might change.
///
/// Note that the absence of this flag will NOT by
/// itself mean that it IS safe to concat text. Only
/// two pieces of text both of which clear of this
/// flag can be concatenated safely.
///
/// This can be used to optimize paragraph layout,
/// by avoiding re-shaping of each line after
/// line-breaking, by limiting the reshaping to a
/// small piece around the breaking position only,
/// even if the breaking position carries the
/// UNSAFE_TO_BREAK or when hyphenation or
/// other text transformation happens at
/// line-break position, in the following way:
///
/// 1. Iterate back from the line-break
/// position until the first cluster
/// start position that is NOT unsafe-to-concat,
/// 2. shape the segment from there till the
/// end of line, 3. check whether the resulting
/// glyph-run also is clear of the unsafe-to-concat
/// at its start-of-text position; if it is, just
/// splice it into place and the line is shaped;
/// If not, move on to a position further back that
/// is clear of unsafe-to-concat and retry from
/// there, and repeat.
///
/// At the start of next line a similar
/// algorithm can be implemented.
/// That is: 1. Iterate forward from
/// the line-break position until the first cluster
/// start position that is NOT unsafe-to-concat, 2.
/// shape the segment from beginning of the line to
/// that position, 3. check whether the resulting
/// glyph-run also is clear of the unsafe-to-concat
/// at its end-of-text position; if it is, just splice
/// it into place and the beginning is shaped; If not,
/// move on to a position further forward that is clear
/// of unsafe-to-concat and retry up to there, and repeat.
///
/// A slight complication will arise in the
/// implementation of the algorithm above,
/// because while
/// our buffer API has a way to return flags
/// for position corresponding to
/// start-of-text, there is currently no
/// position corresponding to end-of-text.
/// This limitation can be alleviated by
/// shaping more text than needed and
/// looking for unsafe-to-concat flag
/// within text clusters.
///
/// The UNSAFE_TO_BREAK flag will always imply this flag.
/// To use this flag, you must enable the buffer flag
/// PRODUCE_UNSAFE_TO_CONCAT during shaping, otherwise
/// the buffer flag will not be reliably produced.
pub const UNSAFE_TO_CONCAT: u32 = 0x00000002;
/// In scripts that use elongation (Arabic,
/// Mongolian, Syriac, etc.), this flag signifies
/// that it is safe to insert a U+0640 TATWEEL
/// character *before* this cluster for elongation.
pub const SAFE_TO_INSERT_TATWEEL: u32 = 0x00000004;
/// All the currently defined flags.
pub const DEFINED: u32 = 0x00000007; // OR of all defined flags
}
/// Holds the positions of the glyph in both horizontal and vertical directions.
///
/// All positions are relative to the current point.
#[repr(C)]
#[derive(Clone, Copy, Default, Debug)]
pub struct GlyphPosition {
/// How much the line advances after drawing this glyph when setting text in
/// horizontal direction.
pub x_advance: i32,
/// How much the line advances after drawing this glyph when setting text in
/// vertical direction.
pub y_advance: i32,
/// How much the glyph moves on the X-axis before drawing it, this should
/// not affect how much the line advances.
pub x_offset: i32,
/// How much the glyph moves on the Y-axis before drawing it, this should
/// not affect how much the line advances.
pub y_offset: i32,
pub(crate) var: u32,
}
unsafe impl bytemuck::Zeroable for GlyphPosition {}
unsafe impl bytemuck::Pod for GlyphPosition {}
impl GlyphPosition {
#[inline]
pub(crate) fn attach_chain(&self) -> i16 {
// glyph to which this attaches to, relative to current glyphs;
// negative for going back, positive for forward.
let v: &[i16; 2] = bytemuck::cast_ref(&self.var);
v[0]
}
#[inline]
pub(crate) fn set_attach_chain(&mut self, n: i16) {
let v: &mut [i16; 2] = bytemuck::cast_mut(&mut self.var);
v[0] = n;
}
#[inline]
pub(crate) fn attach_type(&self) -> u8 {
// attachment type
// Note! if attach_chain() is zero, the value of attach_type() is irrelevant.
let v: &[u8; 4] = bytemuck::cast_ref(&self.var);
v[2]
}
#[inline]
pub(crate) fn set_attach_type(&mut self, n: u8) {
let v: &mut [u8; 4] = bytemuck::cast_mut(&mut self.var);
v[2] = n;
}
}
/// A glyph info.
#[repr(C)]
#[derive(Clone, Copy, Default, Debug)]
pub struct hb_glyph_info_t {
// NOTE: Stores a Unicode codepoint before shaping and a glyph ID after.
// Just like harfbuzz, we are using the same variable for two purposes.
// Occupies u32 as a codepoint and u16 as a glyph id.
/// A selected glyph.
///
/// Guarantee to be <= `u16::MAX`.
pub glyph_id: u32,
pub(crate) mask: hb_mask_t,
/// An index to the start of the grapheme cluster in the original string.
///
/// [Read more on clusters](https://harfbuzz.github.io/clusters.html).
pub cluster: u32,
pub(crate) var1: u32,
pub(crate) var2: u32,
}
unsafe impl bytemuck::Zeroable for hb_glyph_info_t {}
unsafe impl bytemuck::Pod for hb_glyph_info_t {}
impl hb_glyph_info_t {
/// Indicates that if input text is broken at the beginning of the cluster this glyph
/// is part of, then both sides need to be re-shaped, as the result might be different.
///
/// On the flip side, it means that when this flag is not present,
/// then it's safe to break the glyph-run at the beginning of this cluster,
/// and the two sides represent the exact same result one would get if breaking input text
/// at the beginning of this cluster and shaping the two sides separately.
/// This can be used to optimize paragraph layout, by avoiding re-shaping of each line
/// after line-breaking, or limiting the reshaping to a small piece around
/// the breaking point only.
pub fn unsafe_to_break(&self) -> bool {
self.mask & glyph_flag::UNSAFE_TO_BREAK != 0
}
#[inline]
pub(crate) fn as_char(&self) -> char {
char::try_from(self.glyph_id).unwrap()
}
#[inline]
pub(crate) fn as_glyph(&self) -> GlyphId {
debug_assert!(self.glyph_id <= u32::from(u16::MAX));
GlyphId(self.glyph_id as u16)
}
// Var allocation: unicode_props
// Used during the entire shaping process to store unicode properties
#[inline]
pub(crate) fn unicode_props(&self) -> u16 {
let v: &[u16; 2] = bytemuck::cast_ref(&self.var2);
v[0]
}
#[inline]
pub(crate) fn set_unicode_props(&mut self, n: u16) {
let v: &mut [u16; 2] = bytemuck::cast_mut(&mut self.var2);
v[0] = n;
}
pub(crate) fn init_unicode_props(&mut self, scratch_flags: &mut hb_buffer_scratch_flags_t) {
let u = self.as_char();
let gc = u.general_category();
let mut props = gc.to_rb() as u16;
if u as u32 >= 0x80 {
*scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
if u.is_default_ignorable() {
props |= UnicodeProps::IGNORABLE.bits();
*scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
match u as u32 {
0x200C => props |= UnicodeProps::CF_ZWNJ.bits(),
0x200D => props |= UnicodeProps::CF_ZWJ.bits(),
// Mongolian Free Variation Selectors need to be remembered
// because although we need to hide them like default-ignorables,
// they need to non-ignorable during shaping. This is similar to
// what we do for joiners in Indic-like shapers, but since the
// FVSes are GC=Mn, we have use a separate bit to remember them.
// Fixes:
// https://github.com/harfbuzz/harfbuzz/issues/234
0x180B..=0x180D | 0x180F => props |= UnicodeProps::HIDDEN.bits(),
// TAG characters need similar treatment. Fixes:
// https://github.com/harfbuzz/harfbuzz/issues/463
0xE0020..=0xE007F => props |= UnicodeProps::HIDDEN.bits(),
// COMBINING GRAPHEME JOINER should not be skipped; at least some times.
// https://github.com/harfbuzz/harfbuzz/issues/554
0x034F => {
props |= UnicodeProps::HIDDEN.bits();
*scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_CGJ;
}
_ => {}
}
}
if gc.is_mark() {
props |= UnicodeProps::CONTINUATION.bits();
props |= (u.modified_combining_class() as u16) << 8;
}
}
self.set_unicode_props(props);
}
#[inline]
pub(crate) fn is_hidden(&self) -> bool {
self.unicode_props() & UnicodeProps::HIDDEN.bits() != 0
}
#[inline]
pub(crate) fn unhide(&mut self) {
let mut n = self.unicode_props();
n &= !UnicodeProps::HIDDEN.bits();
self.set_unicode_props(n);
}
#[inline]
pub(crate) fn lig_props(&self) -> u8 {
let v: &[u8; 4] = bytemuck::cast_ref(&self.var1);
v[2]
}
#[inline]
pub(crate) fn set_lig_props(&mut self, n: u8) {
let v: &mut [u8; 4] = bytemuck::cast_mut(&mut self.var1);
v[2] = n;
}
#[inline]
pub(crate) fn glyph_props(&self) -> u16 {
let v: &[u16; 2] = bytemuck::cast_ref(&self.var1);
v[0]
}
#[inline]
pub(crate) fn set_glyph_props(&mut self, n: u16) {
let v: &mut [u16; 2] = bytemuck::cast_mut(&mut self.var1);
v[0] = n;
}
#[inline]
pub(crate) fn syllable(&self) -> u8 {
let v: &[u8; 4] = bytemuck::cast_ref(&self.var1);
v[3]
}
#[inline]
pub(crate) fn set_syllable(&mut self, n: u8) {
let v: &mut [u8; 4] = bytemuck::cast_mut(&mut self.var1);
v[3] = n;
}
// Var allocation: glyph_index
// Used during the normalization process to store glyph indices
#[inline]
pub(crate) fn glyph_index(&mut self) -> u32 {
self.var1
}
#[inline]
pub(crate) fn set_glyph_index(&mut self, n: u32) {
self.var1 = n;
}
}
pub type hb_buffer_cluster_level_t = u32;
pub const HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES: u32 = 0;
pub const HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS: u32 = 1;
pub const HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: u32 = 2;
pub const HB_BUFFER_CLUSTER_LEVEL_DEFAULT: u32 = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES;
pub struct hb_buffer_t {
// Information about how the text in the buffer should be treated.
pub flags: BufferFlags,
pub cluster_level: hb_buffer_cluster_level_t,
pub invisible: Option,
// Buffer contents.
pub direction: Direction,
pub script: Option