pax_global_header00006660000000000000000000000064151351404620014513gustar00rootroot0000000000000052 comment=8ce647eea636793442d11080f5b8ba8b516f0117 uharfbuzz-0.53.3/000077500000000000000000000000001513514046200136235ustar00rootroot00000000000000uharfbuzz-0.53.3/.coveragerc000066400000000000000000000016151513514046200157470ustar00rootroot00000000000000[run] # measure 'branch' coverage in addition to 'statement' coverage # See: http://coverage.readthedocs.org/en/coverage-4.0.3/branch.html#branch branch = True plugins = Cython.Coverage # list of directories or packages to measure source = src/uharfbuzz # these are treated as equivalent when combining data [paths] source = src/uharfbuzz .tox/*/lib/python*/site-packages/uharfbuzz .tox/*/Lib/site-packages/uharfbuzz .tox/pypy*/site-packages/uharfbuzz [report] # Regexes for lines to exclude from consideration exclude_lines = # keywords to use in inline comments to skip coverage pragma: no cover # don't complain if tests don't hit defensive assertion code raise AssertionError raise NotImplementedError # don't complain if non-runnable code isn't run if 0: if __name__ == .__main__.: # ignore source code that can’t be found ignore_errors = True uharfbuzz-0.53.3/.github/000077500000000000000000000000001513514046200151635ustar00rootroot00000000000000uharfbuzz-0.53.3/.github/workflows/000077500000000000000000000000001513514046200172205ustar00rootroot00000000000000uharfbuzz-0.53.3/.github/workflows/ci.yml000066400000000000000000000074661513514046200203530ustar00rootroot00000000000000name: Build + Deploy on: push: branches: [main] tags: ["v*.*.*"] pull_request: branches: [main] jobs: build: runs-on: ${{ matrix.os }} defaults: run: shell: bash strategy: fail-fast: false matrix: os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest, windows-2025] steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.x" - name: Install dependencies run: pip install cibuildwheel - name: Build Wheels run: python -m cibuildwheel --output-dir wheelhouse - uses: actions/upload-artifact@v4 with: name: uharfbuzz-${{ matrix.os }} path: wheelhouse/*.whl deploy: name: Create and populate release needs: build runs-on: ubuntu-latest if: contains(github.ref, 'refs/tags/') env: GH_TOKEN: ${{ github.token }} environment: name: publish-to-pypi url: https://pypi.org/p/uharfbuzz permissions: id-token: write # IMPORTANT: mandatory for trusted publishing contents: write # Needed to create GH release steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.x" - name: Download artifacts uses: actions/download-artifact@v4 with: path: wheelhouse/ - name: Move wheels to dist/ directory run: | ls wheelhouse/* mkdir -p dist/ for wheel_dir in wheelhouse/uharfbuzz*/; do mv "${wheel_dir}"/*.whl dist/ done - name: Extract release notes from annotated tag message id: release_notes env: # e.g. v0.1.0a1, v1.2.0b2 or v2.3.0rc3, but not v1.0.0 PRERELEASE_TAG_PATTERN: "v[[:digit:]]+\\.[[:digit:]]+\\.[[:digit:]]+([ab]|rc)[[:digit:]]+" run: | # GH checkout action doesn't preserve tag annotations, we must fetch them # https://github.com/actions/checkout/issues/290 git fetch --tags --force # Dump tag message body to temporary .md file echo "$(git tag -l --format='%(contents:body)' ${{ github.ref_name }})" > "${{ runner.temp }}/release_body.md" # Set RELEASE_NAME env var to tag message subject echo "RELEASE_NAME=$(git tag -l --format='%(contents:subject)' ${{ github.ref_name }})" >> $GITHUB_ENV # if the tag has a pre-release suffix mark the Github Release accordingly if egrep -q "$PRERELEASE_TAG_PATTERN" <<< "${{ github.ref_name }}"; then echo "Tag contains a pre-release suffix" echo "IS_PRERELEASE=true" >> "$GITHUB_ENV" else echo "Tag does not contain pre-release suffix" echo "IS_PRERELEASE=false" >> "$GITHUB_ENV" fi - name: Create GitHub release id: create_release run: | notes="--notes-file \"${{ runner.temp }}/release_body.md\"" # If the notes file is empty, use --generate-notes instead if ! grep -q "[^[:space:]]" "${{ runner.temp }}/release_body.md"; then notes="--generate-notes" fi prerelease="" if [ "$IS_PRERELEASE" = true ]; then prerelease="--prerelease" fi gh release create ${{ github.ref }} \ --title "${{ env.RELEASE_NAME }}" \ $notes \ $prerelease - name: Build sdist run: | if [ "$IS_PRERELEASE" == true ]; then echo "DEBUG: This is a pre-release" else echo "DEBUG: This is a final release" fi pipx run build --sdist --outdir dist/ - name: Publish package distributions to PyPI uses: pypa/gh-action-pypi-publish@release/v1 uharfbuzz-0.53.3/.gitignore000066400000000000000000000006551513514046200156210ustar00rootroot00000000000000# compiled / optimized files __pycache__/ *.py[cod] *$py.class *.so *.dylib # Distribution / Packaging *.egg *.egg-info *.eggs MANIFEST build dist _skbuild/ venv/ # Unit test / coverage files .tox/* .cache/ .pytest_cache/ .coverage .coverage.* htmlcov/ # emacs backup files *~ # OSX Finder .DS_Store # Cython src/uharfbuzz/*.c src/uharfbuzz/*.cpp src/uharfbuzz/*.html # autogenerated version file src/uharfbuzz/_version.py uharfbuzz-0.53.3/.gitmodules000066400000000000000000000001241513514046200157750ustar00rootroot00000000000000[submodule "harfbuzz"] path = harfbuzz url = https://github.com/harfbuzz/harfbuzz uharfbuzz-0.53.3/.readthedocs.yml000066400000000000000000000015531513514046200167150ustar00rootroot00000000000000# Read the Docs configuration file for Sphinx projects # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 # Set the OS, Python version and other tools you might need build: os: ubuntu-24.04 tools: python: "3.12" # Build documentation in the "docs/" directory with Sphinx sphinx: configuration: docs/source/conf.py # Fail on all warnings to avoid broken references # TODO: Enable after README and repack_with_tag() warnings are corrected # fail_on_warning: true # Optional but recommended, declare the Python requirements required # to build your documentation # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html python: install: - requirements: docs/requirements.txt - requirements: requirements-dev.txt - method: pip path: . submodules: include: all recursive: true uharfbuzz-0.53.3/LICENSE000066400000000000000000000261351513514046200146370ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. uharfbuzz-0.53.3/MANIFEST.in000066400000000000000000000001561513514046200153630ustar00rootroot00000000000000recursive-include harfbuzz/src/ *.cc recursive-include harfbuzz/src/ *.h recursive-include harfbuzz/src/ *.hh uharfbuzz-0.53.3/README.md000066400000000000000000000056061513514046200151110ustar00rootroot00000000000000## uharfbuzz

uharfbuzz Logo

[![Build + Deploy](https://github.com/harfbuzz/uharfbuzz/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/harfbuzz/uharfbuzz/actions/workflows/ci.yml) [![PyPI](https://img.shields.io/pypi/v/uharfbuzz.svg)](https://pypi.org/project/uharfbuzz) [![Documentation Status](https://readthedocs.org/projects/uharfbuzz/badge/?version=stable)](https://uharfbuzz.readthedocs.io)
Streamlined Cython bindings for the [HarfBuzz][hb] shaping engine. ### Example ```python import sys import uharfbuzz as hb fontfile = sys.argv[1] text = sys.argv[2] blob = hb.Blob.from_file_path(fontfile) face = hb.Face(blob) font = hb.Font(face) buf = hb.Buffer() buf.add_str(text) buf.guess_segment_properties() features = {"kern": True, "liga": True} hb.shape(font, buf, features) infos = buf.glyph_infos positions = buf.glyph_positions for info, pos in zip(infos, positions): gid = info.codepoint glyph_name = font.glyph_to_string(gid) cluster = info.cluster x_advance = pos.x_advance x_offset = pos.x_offset y_offset = pos.y_offset print(f"{glyph_name} gid{gid}={cluster}@{x_advance},{y_offset}+{x_advance}") ``` ### Installation When building the uharfbuzz package, it automatically incorporates minimal HarfBuzz sources so you don't have to install the native HarfBuzz library. However, if you want to use uharfbuzz with your system-provided HarfBuzz (e.g., if you built it from sources with custom configuration), you can set `USE_SYSTEM_LIBS=1` environment variable (see example below). ```shell USE_SYSTEM_LIBS=1 pip install uharfbuzz --no-binary :uharfbuzz: ``` harfbuzz installation is found using `pkg-config`, so you must have harfbuzz's `.pc` files in your system. If you've built it from sources, meson installs them automatically. Otherwise, you may want to install harfbuzz development package, like `harfbuzz-devel` on Fedora-derived distros. ### How to make a release Use `git tag -a` to make a new annotated tag, or `git tag -s` for a GPG-signed annotated tag, if you prefer. Name the new tag with with a leading ‘v’ followed by three MAJOR.MINOR.PATCH digits, like in semantic versioning. Look at the existing tags for examples. In the tag message write some short release notes describing the changes since the previous tag. The subject line will be the release name and the message body will be the release notes. Finally, push the tag to the remote repository (e.g. assuming upstream is called origin): $ git push origin v0.4.3 This will trigger the CI to build the distribution packages and upload them to the Python Package Index automatically, if all the tests pass successfully. The CI will also automatically create a new Github Release and use the content of the annotated git tag for the release notes. [hb]: https://github.com/harfbuzz/harfbuzz uharfbuzz-0.53.3/docs/000077500000000000000000000000001513514046200145535ustar00rootroot00000000000000uharfbuzz-0.53.3/docs/.gitignore000066400000000000000000000000071513514046200165400ustar00rootroot00000000000000/build/uharfbuzz-0.53.3/docs/requirements.in000066400000000000000000000000761513514046200176310ustar00rootroot00000000000000Sphinx >= 7.4.7 sphinx-rtd-theme >= 2.0.0 myst-parser >= 4.0.0uharfbuzz-0.53.3/docs/requirements.txt000066400000000000000000000027111513514046200200400ustar00rootroot00000000000000# # This file is autogenerated by pip-compile with Python 3.13 # by the following command: # # pip-compile # alabaster==1.0.0 # via sphinx babel==2.17.0 # via sphinx certifi==2025.6.15 # via requests charset-normalizer==3.4.2 # via requests docutils==0.21.2 # via # myst-parser # sphinx # sphinx-rtd-theme idna==3.10 # via requests imagesize==1.4.1 # via sphinx jinja2==3.1.6 # via # myst-parser # sphinx markdown-it-py==3.0.0 # via # mdit-py-plugins # myst-parser markupsafe==3.0.2 # via jinja2 mdit-py-plugins==0.4.2 # via myst-parser mdurl==0.1.2 # via markdown-it-py myst-parser==4.0.1 # via -r requirements.in packaging==25.0 # via sphinx pygments==2.19.2 # via sphinx pyyaml==6.0.2 # via myst-parser requests==2.32.4 # via sphinx roman-numerals-py==3.1.0 # via sphinx snowballstemmer==3.0.1 # via sphinx sphinx==8.2.3 # via # -r requirements.in # myst-parser # sphinx-rtd-theme # sphinxcontrib-jquery sphinx-rtd-theme==3.0.2 # via -r requirements.in sphinxcontrib-applehelp==2.0.0 # via sphinx sphinxcontrib-devhelp==2.0.0 # via sphinx sphinxcontrib-htmlhelp==2.1.0 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx sphinxcontrib-qthelp==2.0.0 # via sphinx sphinxcontrib-serializinghtml==2.0.0 # via sphinx urllib3==2.6.3 # via requests uharfbuzz-0.53.3/docs/source/000077500000000000000000000000001513514046200160535ustar00rootroot00000000000000uharfbuzz-0.53.3/docs/source/conf.py000066400000000000000000000015671513514046200173630ustar00rootroot00000000000000# Configuration file for the Sphinx documentation builder. # # For the full list of built-in configuration values, see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information project = "uharfbuzz" copyright = "2024, Adrien Tétar" author = "HarfBuzz Contributors" # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration extensions = [ "sphinx.ext.autodoc", "myst_parser", ] # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output html_theme = "sphinx_rtd_theme" uharfbuzz-0.53.3/docs/source/index.rst000066400000000000000000000002611513514046200177130ustar00rootroot00000000000000uharfbuzz documentation ======================= .. include:: ../../README.md :parser: myst_parser.sphinx_ .. toctree:: :maxdepth: 1 :caption: Contents: reference uharfbuzz-0.53.3/docs/source/reference.rst000066400000000000000000000001571513514046200205460ustar00rootroot00000000000000API Reference ============= .. automodule:: uharfbuzz :members: :undoc-members: :show-inheritance:uharfbuzz-0.53.3/harfbuzz/000077500000000000000000000000001513514046200154565ustar00rootroot00000000000000uharfbuzz-0.53.3/logo.png000066400000000000000000003037501513514046200153010ustar00rootroot00000000000000PNG  IHDR  ph pHYs.#.#x?vtEXtSoftwarewww.inkscape.org< IDATxy|U߹3I,UMDe){b!3iA"B B[vED7DPeT,PQ@-I='s'yf}?sJ9* """""0l@h!"""" """""0l@h!"""" """""0l@h!"""" """""0l@h!"""" """""0l@h!"""" """""0l@h!"""" """""0l@h!"""" """""0l@h!"""" """""0l@h!"""" """""0l@h!""""Lts@4477:}Խk""""Ha+ c*vt`V奒f뛫^"""(|˵$%@Y `!!"" QDUs0KkO>sε!GDDDٱ! A>kT|%DbY 86 D}緱 L`IwwiӦԟ!"""Ol@`ҥ;UUErm躮4@$""" ^ۨ[k߮3b3n"""cB T!n2Tuuc/n:&t^>6oDkN?k!""" r1 AU}?1To?{ f0QbBTt:=65AgDD\/]5z{[*Dg?>|o """Ol@*gnRnb[}fWY'JU{<QaB)ԋ|UTqB"t KOQ57`Z|sUx [LlJnno︠Ի版{@zdm>, j>[[Nm|PYQZbrb?>D[=k#zv]]ͽ˖-Y""" Q|>}-G[HwWp+"ЫˌvW}i^lv/@onA"j8ًgz Ckkkco5.vEYbRD0oo׬2KZ[[GwtFUϯUF?4."rX{)fRT-Dqݖ;<>IDDDTg@6RWWs<<'oqQS!4ƛ)f-^xk;"pՃUWGT*zphL&1x~uvd2霑xuΌκ7SZ6W9]1=.G$""" ΀hnn6`ξB-pcS;sn[[Oix"2oA"sDDDD؀0sLLmggVK lJa􀒑fݱbĭ*Ѹ k XODDD\E#^.%R0m+8)p{H3&8˵|[U>{DDDD"n_UFPqA'zoXd=^lj@Stzp$"""Z hl93wo;A`p*ع ÒH$,Y։zFt:=^D'LUpܱSPn=%l EАe 8"""" `h&ov,{}wU*=1zCn}PNj:]##y@@XcLd|ɒ%[U%U= @Mj; wbD""KhDd2}Zkѣ|Q[v`ccC"mDj?M.򅪪ȟU+]eR)߻Sg@hf[R;x[%vϺᣍ1`싸pތI΍mm^}r{Q,ݓeݶXUD;5IDD4rqF g5ݹC͹)l]RX/[Z8/g}6GJUDDD#qfeߊEhmZR*A'cm8bFTe<~hiiZ`+$;FXtN3>t:=VD䪪Z+仮;9Rg[_[՝sVn+/ >Xm#ؾ$;WUE~6CDD4a/\>"D"=V W>姹jATE5Z,V`f&~|cEDD4,a-KOtg݅Z {S-3fܭ^f5kO utsoKVp}=DDD RT `=gob\~ͲJW~XHg[We\QcFU-MU\ OZ)"""14lrkhlX,q+pƍ} ޡ]p6 X,F,`v\rٻO* "F{{:7RHMͨEZ]~d2+6@88m;sT%3@$#qlZFSSS;Ƿu ϸm9b򩅈  uu583x6WT*"  L1q"?{0`DcDPUٙvλ ڽ\UYI$~Qҁ9DDD6 4,d2=|3}1gPoٱ!84;UyU< Df?D0?hy> ĂfAT7ޣ;CDDDfc ɷ^v_t,~x?+O{.gΝ;׺@F}Ƙ({^ï?WYgZ]u U|f Wݹ'cBC1XO> ѝzux -ӜDƘï?֬vH]"xegxF7񾷏=kcBCV.2~ۯ+"]Ff}z؈ڀ=Sot} 1ـ9%6\.*듫r KfUhE^3 ^ҲV qm}ެcf0|f@CDDDaBCADLv"+E+C ̨BiNkC-f#ƈѻ:uj+ | #""`BCN&$}rUژUAhDoeX eQ[;R6WTjN-j-nq\΀ /Tr迱!{3d κ})𑨈>OORSSs2qDnnhtAހ^*u, QJU}y_zݭDGRQt}*&'R&Y>yyEj8=9! ڒ_y $L= nP+^֚DfhaBCF&S~9U\P`۰j1Ҳ9{lvo╺qiW`m{d:AQu.༜p]mmm/' Tr΀^O#;EWjd ṛgv6#DDl@hq_0)UU@g%I?s8p+{z qToeDf?,/: q Ԓt:=>\AUN%b|v^PQ2|%"5v1 䃮ؙ JEwEllPD|b-7jX@OH- ŏ 8YM -&rѨY GlE揙L+T&"6 4e2zku_\]qIP4RU@^7D=Rta2?mڴ\clWi@o0Js"@8!cYͦ!MD4A-">[U=cY"C2҈)FO-z_YMQŧ{zV GUy 0ǍSs?"bZ=tz|h0aBZ$+x8Of] ~q*'HyZ3@4R\ @&ԗ;;;sHA1>{ U 0~YTi*wⓑ<Ͷ\JGF #l@h }rUFWW Ab;C2(_pJ}C=xN\^A3daSyY垶KH3 Ï5XNDUWW"?'"Hl@hPȭ@n"z 'Wl+OTqTg7'êeٲeutjHĹ|Ν+p`E  {<BٖLewy "~؀РZ }|rE$k= Pṙ#I/\c#xdGzXj6jէ,9v˿:W%BiH[W*p\ NUsxpnuË(~m~R(UOQK&CZ~Qwdɒ-qol@t:1U|G>%>___'~]"P^ya\kfh0cBJ4sc/]^ `PfDy&1Zè%JETiyŮ؜ES^p7H pFea7_%ͻN=ፆL@%"*ror 5 Yl@hX='WUŜm8P~6Qw%)뛝QLmmX.OD=+jp܀RIdX{ߝ3g\xʾ3O>(@3J0KxI{6\ID4Aze?xa8/<)Z-,HIob t-p{љ>ybR@)Yty#xUu][[[н)4Dd2|rU]̞;w LZ}]a2†X,l@wѥRL&w/[]]sW` W=)߀=~Aو`a. q} +'R+ &YX5g*;wc1 ~ 1x4LųDD 4ԍAnϿ[87){vPm5k\\(+Ϛ61dxh`BϦq~"@ue 7sq+lٽ۪z]5y}q]uû}@ʲn"MN4UX5L ޙQrYatSM6X,1/ [(M爈6 6 4(R[?hx@}., f ̬XyRmTrK? dž䣮HFfU?-[V#pdX, dpg] FK2 @"+| z!tuu~;F.2ׁM bl@hPS5p+v^,8׬ya6J>.s+ʮˏۡp6be?!(k=ӻҙA^VN>UPԨ赅,zvҞ={l;XZ\ YG3>3DD6l.-3'*_@Hr7*8S+d>)}Ʊ~;H87KS IDATWj͚ql[.O+xصg"b<6> 5"xgbiwF gF3Qyj%&hRT U\gSDD  ({1&7su9C-lMKR5xc/3.0F<7u (N%-gg;,VۛQª\yN=644)MTuB+\JD>6 4hq)---8bFoe ћbA/ⵄZJ}}}8鱀m]UiLUOo,iU9ɜ֧B UO^$"7Rv͚1K؃y: 9Sx RqT"HV]y0ླÊVUj̏lmp֢p^w*rݫ&_ӒUwdc0?MNDD} Uf-eNy)OUawYriHR"<Ʊ!1˴Φgm-!8|>? #x\O*/Gv^"%Ug'J&]-b~ҲOu4\.iy3&]NAGÓ='(ZWWs˭D⩐ C&y*>FVwKJ@J]@w#>QaB?WϨyzO(j>>7TXsN^ w_zOU I&1WX|RUDp̺U%͋Ÿ/!4 y\5DJↆ gS͡ggˋ+'N J/nXZ*j:">bBJ,@GD-]&ؼY:͘tNf Mt$577k# EdXY1Z~e-~|GKomKo@`kj|L&pg_ 5뾧TV1*{Ք?/&*w~ Or B؀Р#RPU+9m\ҳ\Ҟ[NF(־zeP#jފ2] QkWM$Ht6 ௞cVF)2l@hPO?[]]&9y3'}v/5Xt i铝˥6/J$D@en;.7D#x|hU{_\UAтŮaW\ZX59d2$9k+pf?ABwDtY.fN^67+*w$Q( :;;V.0 o?Uӗ9U. XٲeTeXsMՓ&mFu2? U:2[DX璈h`Amҫh6|G#;o/DkXқwmV*_e_>xdzMkϘt}!]׿fN.(d>FWU_3A>{7J 8MsV"df^*|!(ݽ ?~nhMM%-GT6 4$U@^\5ܙϷ^t,A~|/w_zO [;:};[:NUHu2|+P1/wuڼZ[[GDnskq 'Wz! lN EDE:S= l@hȈ=dۑXBֿz3emt:=y3'z=n-|v\ ^|~RdDd+T0韥W@4*|qm>Pt/.=}~P~D}{}au!0Gub/QC_\)҈zK7vowf '٥=އ1I59SyO<-pLTFD>G@ZL,fL,Z(ҮXQ"o_i))]xS@L@U:IU)biuVCQ(V;:~C, 6 4$%Wc)&8D;D~Ͷ)Xz@5\ĨHUÍMk]f3fL`Я566>N}AAy.hiNck68jU `6,u\dw1^jD'VMq=TR-}s}٥=]ND6 4bՃj%ޒJ1ݷj_~O~_%?g<[^-%וJؿ\q}>{~[}9` ӀAv |rUO$w8GEzwGZ}.x|ڣ3HķY!"6 4544=K|Z|NU+Ag*mqOSSiI}(` яp!f[>*Ou8<~Jj ت6~Eק oRɹ|6}D29A@nncFn 6w_zP+#"r`BF" 0XY"d2=~e[TЀ9ŒCe2x_wTeZ<5/sDL6̀[1^*D"M^2mڴ\\by1ݫ';7o "b\76 4aV(e2zʚڤJ<2)~kd2S;7@ bO7j@ܳ ڷӯb cH꤈DMËGzD؀аH$:bYYɳ"R'?2s{ʻ E}* .rͧFPN&n nCUqa,e(E6 TT8υD t5jԋ},}XD=;E;K 0TX[:ŒOrf2#"b;űa&an>Yӥ7v?v`~؜^/NlcSx"ru"\+7aftZ܂ٹܳxcԩ[Dajnn6'_U/O&v={䮪mdKz߀iz!~D"XdVo*}V~ ʙ[__?sҥ: @w] ky3'}=AfIksT9[~"Rud֪yF+{GaG[O<*wHBX"{O KxvpOSYsu6UPbysVSSS'ݷdpK""6 4"444tY\T>Sk$"+tOyF pނi9d2/譨` 6Y_ネA2DDЗE@}7Wsр}DD<c}UO}zu'5a7 ΕGYF˜}$"rbB#J 'bd-4ԉۭ#Ϡd̛1Fav"JUr1v>*d23S@t}z8DUB^BNxUـlNltULLj̘q |x62CJ@gg$DDNl@hĉ㏨aX]6,ism3͟14} sˌI Neݶn/̮\}.-?0w}WT:ǔJl@ Rg@?@wl.tzO* s/ׅp+ySSZO{^B/h6 4"9}x|-w۠tތIWA[^MVt3&M*2́b@?2uo"_@$q6 +txh&[#$9MFfX}s8TC.UhX9ئwRTc]]_ɳ"X,Fd~0o%TZ[*֎iFE']^2xl,6y@1F&h-544 (pH ܗ]<HC(*˵ H3}`7-C*mU=$ ֖)H]].њJX ˮo1x^[[*"B㏟b5 /+s٥jCCCWu G__^ Խj ^uCg!})nADD!¿7bޮ1ݜާQlŪѧE0CcV7rԆ*%lIJDE.HcD{Bpi] Q{pHCls@Zi?w  ܫ5 w}>K4#ȎDD6 Dϫydz٬{|\.>32}ݴS| %X^z fT<-`e=VMn Oz)Zb5DDЉ6jmmέY c\v0HKpOssQS{ <7L:c=+JaBn\z 9vu,tW@#ۨ0~=*A Q!L&}Dj^yh,6ξـ5~qǢ H& z}I wT0 o;}t]=ŕ:; \:?l@_p:Q6>\d~+i\^w3 X=a¬3ԀKs]V~ zCB0fL7TgݱXRgZ]N>Tyy*ՔC ΀B"h́/GȫXbF,6h8w[a^ rBlHAګPX >kjjv>-@g@ziF2Lc0}X{1XZ,w_l6vHu6 > a{z>`rKaB-Ϗ"ꅱX]sNgXR C/!+M$wn-ޫ^7:~SCC⤡|HA;@TN[) 2x&/Ǔ?uF^Xh1cr VȚO/*|kqq L#"8JZqsQB>K0ّRwo:9~]OO$֣f!Ȍ@Z2_cƌEx(좈 Eu{K?j)wpU;rg@dӊۖ.gHVʉ>c؀QaBD`L=zT HDe0)El ̀+f=#*|~eË=9Y[PŚqw^" ٳ\*^hjj 8Tk@§ HHDg9EMa b+d=L0h(ll@D7j*vZAwxXyk-g@Bb:MIըsҫrުBHP]nU3zt׼P+#""fȇg5Ǘ$o'`/gPh4`)ӚFn IDAT!&r30k^7"\z*{"ޱ6nmDD؀Qx;kU`N q΀X[;@ؓO> ڪbsdRFR $ Pq/܄sZYU>S?Jܗ hg-ɀnaljkGDG IT^]1#x5`  mmmk¬gSųi\SBtWTEPE3 FKFW ,"WzT[[ۏC "3 "r2|Bm@(8g@DΝkìgѴgl3vyp]|b>7>\ ܼjD9!*@Ojnుݛc_q|`qz-SzFD]\˩^Lըw/69P9| @o(IC"^]᱁k͚PpTtanY^ |˼L&庪^evraGq+N3FFu _8""l@ז-w[[+y6 ;@ %X<\ A[>X.7U=;T`'XX#ѨY6^C\buDDaBDڿ7#L&Se%@_߲_j?XlY]~Nޏ*({lUgAl6=@sU׆SQ!^)Da=+`$;{^D$[,1f2c%WՖbe޶jOĄ'Go{eE윦~mfl@׌ w,t@)|΀#U9Us.7=%V?TPITtn>y[++w؀Qm@w%dϐKr`{w&Euꞙf :HWqz1[c{_M2ɽ71˽IjlTw1adQ@4j}A`!!p6=yǧTa:}_f*QJ H % = ۿׅBgubwTBAO+J΢aI+~DsR޽G ˿w8k-tB !ʒN1qDtUh+ 26MIR47 lAH))SZdكle 25p񮮮zDD":BI"(KSSxn 3&@p Dmmm܁J<@?vM/6(2ya "zk~/:~홎.X`PH9ͽUBTH!DY*DqU/1#lb޾%j+o֘ -LEdMX94qeg0 8&/1r8z[.WBF!DYM?>b㻅ʦ d2B3phjΘlc l!' @ea-Tϟ?_ϯr@d2Qn3՜(]"x"~S%"f2&.%:eާڞV7 q;~ [3=!. @eaނW_j·@xgDV@T*J,Dk`!╹\wؠФ{gL z7{dI^ d&5!dtGK@W}N l<|d2B'tOL]LJh 0I~R(=ͺ_r]תQY wi {3[Պ82TAYMj j0v=Y-_ ׽W !D!"ͺ.Z .uamP%r1 ~ 藤^&6I҄pO1|HY_`S#Rwe2ؠ5ܘ?gO [xa~ٮS qj+] !P$Csx xIr(8WӇziX0 t>$d)I$R]g0n+B7YtwZ?f.T2OOA(6l@݃ ӞL&{+B * @l j_??lXEJ0oql`~ ^h Ɣ)SE,+ {u>8a"K,Xw^xO3~|bòP% gf,+WBԕ BQ6뉪^0h4j02fU@IM᳂"3ge8z.3nh?-Pl\p*ZROX~[Qtv} PB+(qcM!$N2/AaÚUX }}ڸ * ËǓf+|`DvVf] OXGMŰ>NpƯ^:ndܛRCi)f(!R$\׍Q`ߗ?J;{lc^}V@Qؼym1%[=gx0Pݮb"p4t6 \Fh\hҲ0am kt4ה2O:~bHDAhѢC6y8˹?~dɒwslV@9 &J8_(˶- [R껹\MEZn OZvM$ ^'',XٮYZ `j)cF"SJ9O!" @d"*%-3ŔrFG x]4e{1"u%O]S}M`: D?2Tɾ™Sh4h և&,}dR jtzX63ePb7wf>7K,;KsB@!Igg"oڎ'Pd2: L%/P?MMBp],>e~Տ~;_ X#IO?{2{\.7.uT pd3 1]΅{ @$S 3{f̘{nkyl509xZ\"}fjgR#B'uNrs WffLK&EPבDA0c64lu^{9CUВd&xy'eO?a4W00bH$TNt<n[)>=u=̟\twg&<_!Rj !6́;3֘w%Y,{'"ucX"}&؜Jem9!V糒}D"xlg46J<}RpZʬO)5Y ̟H$o:B1I" `لA~ޞ?]~`^g|֫GVMNaOPgR xj[}ܹsX景:ү@\NQ /0j\L!2ق%D{*βZ+~lo{Š~eѱ[DycUe~ `x)|mSW4!Ǵbjw2D"!b 58|8"b:-?`uμVU<|W>fn; ܂Ed. U}$rT`fRn%isPU0~ xD"aG!tQC6kMo]Ӟ&? f=3|_/h]]]yl,DGޫhSW?qd~@MxPWPxoB1H"Dm%ȠADM$5 [eωl6<8VGWq]dMKط؂񗛛>:+X,ya* |I {# @!p8fko^%"?: Ddgm*`!79e"KT,E?"5mmmx>zvB= BԈ뺇8/x$?{Pö6og™a`[-?c@VNAXk@`D"uIJnj -['o#!2B _P`On EW?<>!'e/I@շ`i6oZdɻ`Y,T*$r&0>slRd@@|ժ5W!D!j_y>+Oᴢי>w]Y)toyJ~`nKt1m%d ^իo+fCc f09f#O[5 SŊovttlBQ BTY6"<~1]jqNslM%" |ާH :@KDJ! @:jtko^ K\l?lV@ޚ;w%xj|U!X.Bԅ BT>"ʚpco ȘN|x+` T [ZkdbN`B!DmI"Deca $̇&9i<R"0=Ms2JEW0__dBaM!HUۯ>\# kUr<{FvD ~04eq ق%Bԁ BTR&wL`ͽ+Ke-k֬y>\@ 4]+Fk+jQmSw˖-xB! @%ĶX ]L&_7`Xwȉp*` JyV۽R!u Uy 7n6!ڂe,_J)]1<|(AzPz"l_;_!5$\@knp{#t=@PDT#!^$#iq,n{FV=) Ō~}H|h"j}vW BQ'QW744pWnz_kqp_(n{pGv?;1a H> !$Ltz3ζz24 *X,DXW@s_K`1,NߚJ6UyJB!$ejnn&{~ۯV U=Ȓ%KEBk"S5U˱yoM B!DI"DN9ӉTJ~y`HYfμ| ̽|oWI4-cRW!/ @(R8mdX6?@Cl\͈bK[}T?\,B!DI"D9p3621K~1}N,.Pb 1?^l1M B!DI"DxW [[M4J~ c|,HZ7$2-~g$N;}Gص]!C!JY^hۯuX|_2DڪGKeK"`<^b#FE俅K!'%"RV@(vʻߘM6W2p]#1k,YYzUIcYB!K!JF<=hV̝; A.c吧>iE,<Ŷތ.r@jV`  @!$Zgh]W~wJ3y|hc6HIcW˯ !H& !B{T9x24{љLTƝۯ2("tں!0l mݺrR0hF*W*۶ B=[.rg$89$Fk2|tS']k=qT%x@G IDATbس1BP|٬Gy9sTsJB!DMsOzmKyph(Zt6 Zc8C5 DKÆ5n痤(cpW~%tM:P,"ac~E+~ۂGY*8|lB!вxCKBsphG+7r-۶Z'aY%my}#81 Ѽq Y ̙T mr@X~0@A?$6 I_ !D aH(GQJё<`@@F"ƌgyfzN)ommm=S:Dח k3`ǒII"%f[E5lذ~;6@W[,ݴ~UP `4!D.B!i'LRO4777Gc1}Ў/b_4j1;#s5z{7ecf̘jkCB&h4_ͨF?ض-PX D £B,..򖦜6;OH$r,*}lΚ('VH{~UK>B⺺+f*|w,,V NPPfԃz&u"oJ e%nje-5{}RH"l~,Eǖso&e "1Xպ=@=@n(5" ځ,BJ h> s4{Np"lkDtʼnDl(d.S s4>v~`3"IftI~)C0(œmР!PK-_?3bq;s  B9r={t 3.&q"d- wJῈT pgFrk$"@(Z ]H$9D<܇r`BE&%]3#=V"Rw7[1 "! @G6fz\8T4ٔɸw3#ΦRW9'⋀ImΧ|D Jq 'x$^w}1pjń Dx6{ְ|KZ!]&_83C 'EDH)YwHgbܑLfљD*vfPsgRJ]x_Ϛ5g`[!lQ5{)0o`SWZ,Ut4nZV@.u?k6XEDkpFg+n3c84Z$"UY3v6M0Tdw&@x$bh  b?\vzm _*冎$Ck,PV@l\illZOگB,XSSJaN.W<3۶m[UL&{<2,Xc3N%i@u[lFE`GuNZ#>6o<44VV}RB1{rccx3Rogwk,6{}U&Wy~!N7477s\gbed2tttxL-DQtƣ$vFaLKE1icح(YBH]SO'ɅFʇ04LZf0 hGLCk @xOABk#>_韤R{zzntbZDP-pR+g=o,li%ݎ+E_QEZD,lx JS7;#pe~qX=@H{-n}UfQ] @{\.|ȯ.cW3+c*M@<./?4q 4Qbj0~N*0p|~!*jʔoE3^U%`3nL"5 !B3ufBU#dí Qr~~ݴw56o{'H*72JI"._1# 5?4{)Pm:3bC1wA':v9bQDb1cB쩦Li.KK|suttyH_;7^40: ͯ'"Pk,lXqOj(fJ^1`~՟7m+'ʿ{y$b'Dt0qcGs`S(A eU W==!p2kOy~6[ ,CI.u3z߉D(ji9|O@l|OF'7%Dg~ݴ{{#Jsh6hTպbsE|~y69WVk.$b@6=O yΌ{YCbUmеF!csP5(?Oq Rd'+ B=^XNzpMx(T00`1{DRb Lo?f8%B+^Psqc",|O}\{8jв#q4=oFfz[QDH72`k؅_`h&՞T @@l_P`~ՠ³\CZ?R'oΚ5\& ˬf/i'@Xn"Y` !lS^<3U|2ؽpH?RuSG1X3'?" Ǝ pR`KQuOR [Xѳ$뺇(eӻWΜyM k淵| De 6`fs ^E^RƏ6$N;HdRŒ;M/XL&͍1{\\X)ѣ_o%N~ԛ|*ۿ7"k!sU @@6yd|p+\PlѠVl;6uP _p%<-0{_f]Kj7S!n$av*2H_&l!Ǟ$K5ht>@Ag]YEvfo !@뾇یeFv߮/}Qq\Qo :S~a6,WAӺp1_}43YUʛ\vSDfy-PKvvBd]lr@~K4OҺHHD5Bl6[mrBuuuV ߷O/e~Mՙ'b&/16-V*xuk`W BԋR꒠1̎c@[$H_>&_[,g]y0r[-:p{U {뺇BjR5EC8rx6O~`L>d2t>g bhѢC9p5kU~2^nBv6>ϭ5fUِ @2( 5hr&>B*p]7N*MN xtr`(`DB!fko^L@s!MdYrFZ?kܫ{ @^эt:@Ŀ]Y i]]]~B24l233{W%Ic$<~ @s5(ꈱ .5]DWP bFd P6P_1q 󵦲:3Y]`rH4&sDh myO!Diz{7GٌUnJ$fc>J*5 #9?QgE]mhK&W{ZDrG)Sw<7w*miD @^)V8eل1 XLڧ+]D]$0؍dU?il؀1 |_w*];cނί ^+lG5Q~gl`3BACZPf}3(eD W܅EAD}^k:::6ןu"3uX4^ GW5FbFDۯxgP ՙ9}cX{olzX,tmDkjc[;!t:a;7aw30*J`2|,麌HaUs+>6&xz9M ϪS2rFf[y6O3$J@dfμм52~-?>/ԙbR).;鯀0o7M}V@FaÆZT¥;v~]%;\}T)`Dh:nGGǐoҸ/H CP;Jjykݭހշآ6)߭Wͅj^YOԁu\FZ\b!R @>*+~#FWi2y1nr>G"#*xa܄#?_1 w.yD)fGi>{8_fD"e|L&q]w.~\D"qݥCT&Nknn> ЭDt1my#Rd2'u~ ?ީHTC&5Hi3Y9Hl:ַvd"i6w'46,Ev5di6$N5eJA㘑gLǶ~1ۼiXsӼ^h͎9ebLD=jJ8VL+AlޑH~X}\.]f}CR4 \&9)"J47Gqx8AjM-< f2SO4Ÿ b |/}r[n@0& _h423^ZjDJDsL9i [WQrLf_~GQRX`BZ8SJ5!R_-[?Ru+N"H>Jw(Tlټ1,d.ܙH= ᯵$Ymu> ӫ:91TpoLt͍.["$"A*f+13W}Qb1= QƪM۶TKf:3=Ŷ 3}ܯշrkf"rqXlֽ@P s뺇 $* OEKG"J"l]58IINss6cpwfic#e2SNi}~ n+maR꿢c٬~XCFǿg?j:_։]QY!톭یѦh>C bCŬo5}@z tv{M%?ȼ-3g|>؃r`_rxE" (4xaӱn[~*濿LSM~Ffl !IRl( Iܑͺk-PԆmNο3ދv2!{)e/ډC}9bUMlD"Rz% ?x1j W0^톈6^-XJe6}1}o}WfuY.ˍf3}T :U),27߁:p8"b:}]Lb(AX q`|Pe+hg:d]cq5N$fWPm.J= Uwg^fs>.;c@`AdN@2 _[ `iflps?:'Vv|n8flH&3w T3Xk-w/89|,+ a?ۻ)UdؓHT]1+z^>f>DJaϱ(!f^Pچ{w/~0!Dˌ#3Z;'HƗr9X%< @>a*%CM>GBaz~'Lg[T0.,#F!/h}( Xlio8@nִ.\J\L)>_\#w(%)AWWP(|VT ` =yRvo9S @GDқhRXtmժ5_*:fꓰډBwR)hڳ.jw<'x̸w64q7l`#9'ԷOJ : AI1 чl.LCj G8}% cjVg@IAwbƊJ30ߑ+o ~>'^gsI(x3ָtC/;B:'}F$Ib) =>43zvՕH$V|\= @RhpC*\rꩭ\r^;Ɖwҗ84WmR`Է&tծ BS4p=㳍ͫ7o~RV{kcUY${O،e1'vO/ RhI1{+}.+8}r@W]Rdbjnؖ- t/d2DoɉD"W1G;`H>{F;"AcD@ P9n&*O{fI+jʔ`SȎ5&IbDRD8b賫V2pjK{|1|;B*3n"J޴4O6}V ?_-|+GVo8q_T9jKIӎ/Pzv"&sT<\5]͟?_'P9 Z qJlkVug)r\#Y)x2L$4aM/Pea &\ʀ"{WosqN9-_l<6n+7 @^O)*#|߾g ?tog[ΰaT2Pȶ9 ]kN&>b96ּo-C_pĊsaQm2}y[C$$H4|b%&bLXx<9q43nd*bf6s’yîW[l[h:зn\0h"Zֆ ]&/0a&.oC\9 Z1ȇЄFtuu%R߱T*e~7ق%j̢3c1p#ӱknp'D X^i8&P낮%KQ?tۊcpTCIJ}/@| =qiZѦKa@Ư 1]i͍اn߁(y_PCE&^"e3R"fL&_quo2fxj0}mEFӕ퀥aZŋӚN%RG3hx_M2Dx߼ymhMWX,aV3#N+N<>ܙ`[ U*Upfn^Zk-Fk}\XܧJܙ" B*Dۺ$!3sܙg&7a2|gǐ{s|f `` ߉F~ ^\3M:_[a0=hP,ylC<^f2d8R]j7\H27ެ3y!4fL"CǷNfByyFu0˗lks=/]zsOYtǠiuNoX[[wGi`WE.(XbFJ|Ϛ\byNW6.@gz:[B>hLNHە ŬEG"}-J}}AZmp> !w YbHiHC-x1x Z z V?q;H&`4#3ĺqo0QLM0X`ҥ1Qg Punv DE%6s99 ޔQ#7 Eg=&"2gwj2%o(4ZF4 Xݝ=o/6TM,[J\ゅ݆x0zhY 0y{rT~Um1S "_U+9c S-EvՆ\a+RN/0_Q1SOJk|8l=G$ O|m.dt(<?_\?5"<+JԷaF/'#z-ijxə e[c, 2s&&EѰKMHC*TmlǭFf^8e&82-ݖhWECoya+35 A!MS/xEIgZus\5Ui9򂳁(.itwf>xj0gn(%ϪahI1#J3{ao~Kva*ӷ:h/֝/<NvE\7~N2@12Kb{ufp(Tu%0#6"oYuqO}}W!he0TԸdiKY/39h̾S32GwRb1YˊDg ˢa+7NC <_k,Fgv>b1\fj@3ZE\9qi Y VfFBuv_NemV7!$՝U׫#52Dةwv_3O,V><Yg,fEbe{U`&(S^{;2LF"(eHN># 8R*1̒TϪSuyND ԵlD1)q6/[V7y;FgmϽ-^ ¬,n+T H#K^6ļNJv}}̮ɒM Lz䰏V%ZƧmVy._ʈ',!z)CmFJRٻؓ9T/ \xx</ŒSw`2A,fnY֡lP׋5D<udW8?, y.sF+|>@.חks3gRh^1ciϨ,l=9ܬ`%E"Y̟eZMiB ?x@~`Np]]~va*7MI5`1ϗHO+\}X,v3t62ϝB< ̞ÈTKEC4ʮ lNh$xQeNOL<=>Z4ɱͲ2^ʌ,ݡlY>$G7_@8h%&֊X̺Wa-4)x%gA9!!#WpBJfYY~Dqb4!j=3kӤ#+~U[F8x:9vV'ɶHȊKvFL_#>"u3EPHJ>HtƙİcxmcS(}"dU^^)uaNeΌvNWXQnfP"F[wa}cd 1>>xFeM/r#+R:Ct˚5ZM(.]@WhN4M30s -By x0gaH׶NX~jV,_nD+ywoUc(:LiuI&"HYYL"( < U)E 9Û(ޓxboI;bӜD1^ߙDmն eaF2HTc ڇ8.ou2&L,`mc'o fb+|x9c첲ҿ@K7hMS㦴*h$dא[,/Brp'dx= w:z6UvN>5"S(!RA+[4YێmW-xL 9u.S6 Þi0$B.K}nGp8lcƌ!FJÈeх˲&Xtucj2g [w6N+`4" A5k)aa0TјPBZxq\"ȶnpn߹8^9rѹUQnϔb!eE3PReU#rIv*/?HQrhN裏٠H|OIH'NT${|R)p8V_;1CG9p2kaIX:*3 5Ph555vuu;Pu4 cC!sdޛY9ZadHU{'XLu[C+7^-//(S)YTJ]I3/36~4n3 SČ[JuYYYN?]ݲJ LLL}S !ĭ%K6\|αXflxa Yʫ}u㝊˴i5e"?fI׬iK90GJ\4("$֏ӄ>f8i4JzUzOL Ȕ/&֍;@S>4-=l>xqG[[P(ԬFɓ'3~00t2d9}4:ձ<0}ai#xZv&tCYY9ɸ,^Mmm9iuYl6k ;;CJc֫IXT>ᦁv}`1 QSq۱@h "rn?q#c1k1O1w|>Y*%(8S]3["XkYXl U7$j"Ru ϙyS*3rSڿH-& 'TJr4Z+]iYeW[f462R@Ng<{[bE9 Ev}>~ b~΄Bu~!0'9ۄ]"7nF,fȡtz J[" #L4Oaݵ[yϴ1P 50 C1Ljnj9M]5}87 zXG$ެ^*%_6(Ǘ:̲]9WJ;m3@47!čʏa߹j\'#?Pj@x@D%B/kkHGV{c PAd.`E᫔5J%nQ|`[`8RUU^(Tu}0XuH*%h^%i0.6LvYsCnG84͂p>DK$T 1&Ծu71g @ {PƂi)Tmv3_,;wd'xmeuuR er1˪BH-%'!X3>ڸM7<zy_?lx\VV~6c+++9z?D1#8D39S.q۝cikйPUwiS]]:kN'V>-cMW]OQ6dT,Nmmm`9 h4}"lq ׌S@,R]/++_\hng'@Bb2Hp 0xgKMT: 51(ץ,_@ )--=pD|YMMv)~,);;O}t~ĢMͧ@jx6QFGiӝ- Ǣnx"2sP,̚r/"^t?$8pcxP9# `A߻i|Ҥc?"GSGKw`ޟw(3%7 =Ns<΂۰v͚WM>yӟz>\5^UUT`f۷ z[VF;;m47Ta A8.B TùGDo32j@LoZ4Gk%%@YxGV,.eN,,j<N&!F=3+ԣSڵk]KBhPG@4wLW\. gc<͖L$Re~~̠ N̜1BD}:Ov; 3TM_N 28 2-|euC\7ӵz&Շ_Qee8P._۶ĉ8D9`RL'4S-ѷ NeJRRT0x*=t MbIN"^t|(b1(Snv8%)a  #g>q hmmFw%݃x dּf-x!rHQ IDAT+F섡쬫HY֙444Lg.x22P 8%׏WʹVVVThbQ?n`4YڜӇ[txN,"k$#,fU8i0Km)1`ò{c)14CD5XVY2Ytoy'B&rk@dh(+pJGm|ƽ/9֫$""ܖߗ 3+*f:$%WpX$HáTK>[4If8([m((XC(znڅ#)|A"T[mꆪE FG7$˲-yi>?{L:,/pJ'M;b(19:'CwH4$PņS)94WӣЈF#'5AJ9`ʪlnwMܠLS) @JpJ[#h)'z!mw@Y")o2L/ X{"i0D( Zi4F8LZ?" cOpBh_ۮac|>}z,tkʤʑW~t/Nѥb߽ږW#+d03PQ""z9+; @#Hkk`xGcYD@ܧ۽[14/.(O܄ яKOܴINWܝnssN~_fueeLw1%͒kv@VU?WVVrMG^d|;޹C Ǥ13cC_{m<"t-0&"j`E \my*{AtPH͂ty}}}7u ՙEĎ]u"Gm,=y(%~^SSmER9f8p&[N3W ]cj[,ft7címSߠ&V~(N5MfLEDu̅B2m""Y&9TœE+3fWVVLӬ CgB>_QD|$3$Jpa@`z%4ug-haRt㿨ӯ|DZ/t݆G$@봗H'I4#4j@ +S^ctBЛ:<-kȲ %" )qv>u_bɮR{cL9Ct1=j(obĮ⑷u? b z'Dtiq nاg_ЙV:6U=3;I:n)Pɽ .ɢi悦i,8qbk p̻gCPs p̻i;bւU\q>buƍ&ID!3cV/n:zt)vqlaIGUgA,i+V,Ѫ?+D^c bڵeYO hnLTKKᰑJ"Ү1\N)N`;mhXBQ@w5)qbeee5z⑗{YaQ0h:Xr&~]Oѳ}dU3fIwsHJt>7ʈheaOp΂! iZ+ QyFs@: [VCqĉS AQ'ϡ&֏ ؤԶtSk Nsw1q*JGgcT,}X,[ah6JB3]_D8U sg3nۘj< oãg0,_wpH9+OH_=X ?"ȁ>i=Ynns;jG&L^ w R_|PthʔDbF67olSSVVr4G% #XG3Dtf>-_SNꕱHb19"zKJ1c-G7lM<^ !sv|s7hJDv7 qN3 U綁 +-bƳe[[78=P YmCuIضPWe~_m&cY)ȗC1Jo1N˞9V!=;S}rMwϬpx[>pQyyEo Bʾ M-R%<ںJ" ɰGp7L'xK8uY^IۜVF]t5BD!6mɓ'D"RB?3;p&Z8F8Qy(Oe1zkDFG^'h[6\4wĬʂX,=hى'nX'9G@@JtCRX^@8Y >::~_Ht›7 $Рnq$%VlR^_kN1J@ͮƩ~@Q+gU~/_I> !gvr$eĪ*SfGP[[+=AfܧyM_Gwh_j;1ުzdBgm{+^clY@> Z2smì~iΌa>zp+l)}Jݕ~ 5 6Mp7;\"zn%%vmfՀi@h65%hOʑ7 "]5r!o'`fX_Lv v &My*%tt݇&2F95QYq,y'3,tUӵx%X윏MD|lUU-0kqz٠OP`~2J6iD@X1qg[4Xhν) ~bFkD$Q-Yaկ3DtbZ[@ ]c'd#@Ӭhjݸ  }F?lR< \͍VZZ~èIc1%v8끕{A˰Ez8.Liot@KܱpwObՀVG"t?4DB@EfdZ#"[{BRpf(j)122oe%٤JnjS |s!Lw ϯF_'ffƬJ;/9 ;h420iB˝̸)C<+xRuHhIR7_]z*Q >#RҞsS%΁ z=<22V)@QΆ{"] 4"#7zB,OXy\>bKK&%jڄ8\j >xDb~UUVxGO(zJt`|Gv3`Vkw6mՀaVs"qפШ!> mc+*N*{XUF+6Z[7){=:" N86b1"gzKPui".U^gTDT~)' bCRaƳ!hi(ZK,Du"a2p!Y,[Xt=SEt}A)P++%]oxt+e9٬cW mh j1Q]jG"8 4-^t@_}UCjq@l"uB#VKFR)VG?6L(!EnU24 N|88蠲TJSSSA0gO속Ax_ojh; !t4M= 6VXxl1Sf̹PgzJ=O.yXhr} ]R)"T;3c+w =PJOb+b"Wx%#`I)Ynv}Pz4D= hI$lcEk딚9X.=d=V @&htSu~,`)8{,)xq,fLO&N2t7"2+(֨T,_?eʔiZ!9 nA5f!,|4avSx<|YQ'R :;0IW8(l\[[+!‹ie9agy^uINc׍+l&pj^̼܋fÙ%Wi>41{d ]A;E?0z[7kYa9 ]$Z[C@A`nRgz/P]DXTV Kq}F2u^RJfp Nk슖 S !cO"/-hhhE3o]>Ό1&]sa,N>@UɒUR b̘;w\eGz,m|oBZf*14ieg.j:78 ;&8t=z: @NLj¦$p"zS*DHc )?YyeY?B&JݪH;b(2F+=ғPv`l9 yB86KNr"r߅m>T*)Yq]6kMӬsŠ>HyO?ީ}E"mmG4kѪq3z%$=D"p- Bnlgt@Lpext ~Bu=gfemx)u!@sSwbBxEP2FWh~mmmox2FjKh!(̭<#V]]|9Yi9sg|76b0o.ʂ/⑑x%C]KD7K҅(/.f?.ڳ2̽vӯ/_3υZA~-TfzG#bOp.DqD|p'K0s> &;b/+} \!U۬ B=&_xGZ:L'e=384Cl3[᳗B!_ TpiyyI[̴eBd`QeYev{ ;ṁQwӦ|#%Б] U *:6NPݕי$ !w(e'!d'(gxc~>a,?.[ rj,L!:[]s@<\37M3ӌ+1"Əsr@x{ cJKKkŒi-A JW?^й{'UWXQLn(4 pQyy:s#ʨteaZ5+ydI$ˉp\cƧ_[^MZMx@>Y.)e.V}v־mC!SyᡏxlGmm9j.a;R4ͷM`ܬqUQZ{0u*}瀑q>~lj Ti"(c %?D?(Ss^CP n7s@zX>_2 mmn\T˘K3)Keƒ۠+++>{03{obŊCX̌c]K7mJ7eʔR5GD dC>Ws,>DT2f|nZBܓH `StHu?W(3̷WVV!+-ːR7|8;D- IDATY)dnq0 Є̭Dt392uT>j̲2!Vu`Zwx{Ji/%ٮ%7I SGaycͨvՐ/9pN,%Q]'!LX5 VZOYx|@bݘcCM0ة|u^;B9zUyD5`0cNNnŌ`s(zU, =s@<#:"I$K&d&3St[5D|L033}OMMM{,f}@yb!Uץ'9 FYR|X"]?$SGY؅ZA@b/㓈zŬg"֕t+f$MWgS?rtdûBxKvmďB:7MxHaJ\i`i lO:ȼ1Ry9|. CJޞ; ?ާQSpJG'v_~iLS)l<|c\FlGF E@\bҥ{ƝB]zUZw$| Ye+b6L<`ef*U4$+5o9 }Z1bD]qk&XT!@KI/H)U %JɷnY35K8q\ԆYÓ2* dn>Ȍ ݷ,?(++>@L󈰤=^n OD%WS$GzȲY~q-]+L B'o_@?=þVV EѡD *7@Y%-wNH\EcE6o _}iS.ZZ%"Ⱦ!Vw:Yxkkt4{Q%z|}ʇO86OΌ[uYL3ۏ;<`$ 4-R,k@+u꽗_~A5Lt-xYJ23 !@ «Kg3.7hG)H"3/tߺ`H}1-!S(tW ׏4 mbƋPoGZQE>aVƇa+ f/;F."q|,.B_BUW=*Eg2P7]_zF7m7@YO5<倸YFyN7oփMubo)+T >"h5$"y'Nluղ.`)3C0u񻦍T5db^Vl:*ӌ&aXea`YOE`smH՞kD#}z>'~Uk %9Lt)o`!)p3:=KY0L? ʹ~^,0G+ӕZ[9?ȴ3RffdEB$T^/Gv]uuu։&&{z@2: Dk0tJ/(UȹhBe]!G|Z0|%Z$R-L| ؿQ7}e[Yմ>9 N4t4s/oop4 [q*Xr22;:E2BDMtlcDPm 3@)%}hXQdhQqs~P#+ ft%MCMs Ŭ'D95Dt{2/ZSqG&׏i&`={[ǺL"y54˜SYxx)X bƵȡ)IyJuf-l@Wu-{#JKKO#RDmMgC^mW cJOT΅hf-Xct32XP`u~O}|$eh;8 ;"tX_Q/`v7`p :Ÿ ؛^ SW5LCDB_=)@ݐ)I\"jsjuuqm♋2pzIK7NY\WW7WlCD8#0˿jL#;H / |үܧݨ?HKkּ>/yaM1۩nSHX5Qf$DCB! -n!fOo(Z^t+{7JKݵc[HEFB V=nҬwCK8,G3IrD-.e]5鐒m.:L |ˬ ƚQ1 =MgCDoG,1&yL2xk9[q#r^{ i@9Td˸Skýv8,į0I<8}5ͪJ.DHaY|DŽBi9V ^ʏh4?3^4:ANrRY|nY1Ec?v0o}<1b!> ћ"K烙wWBd˘6w: !SegL藔?B3OyfXB5Fj1#5ߔЉU?+$7jMߡÖlnDvgiT>ˡďܶC2_i7,åmmDnGa$ 3:㒜zD{"\Tx"lͭUK]4# ҋ QY} H񝺠aE3E0{C5fY.Dͭ>L&|UږUsUTT(Ӱ  ;ṁ!OXcׂ.[w `י'%)ID4M{<QF@:::4?)G@"H83˥խGMtGigsq0lƗ+꟦\NkG:^H86+e@EH Py%` ^ãN{Ӡ|@Z27 "n`BJl{і{duuu|Zu|f'>XPK&1b0Fs\#}]XKyy2f5^-0352^X5@p>ֵ3iB3{)-'[c8Bu|ۮV]w:8 @fvݴ<$$-XAR.jHߏ`bxգK-d205*-ڃH\%k`^eYa5B BUVV:5o!T|lhV`4>Is/[y.4 )f([Ìqp!M*`6 'å 3n5-?1 ҧcZ䡄2ɝu'ScȪO$B7Kx 9]4 CG%NBvh?⚚9xH/!X-B2iWd:%9XjI_L;;'կja,utS'N]q]F+UK&N]!ԵI1^?V^'z0E:un>iʔ)I7)~2t|I Tz w]50w߯ԗ̎ypk_BsHi}>Q^gaMޙGY]{;3$j[p$A ̛Q+ XԺZ-M}/wfUZAlJ2=?Sx'sgN2G4!sg„ !\Ivۚ5M3jkkmt7y@qVDLߥ 6ĥч ]^ՉQ* =_1Ɂ9?XQ= dnUЗ,S'YnD4j(KIf9cJ'Ɩ-[^.++2JLp쿬pWe!ybSUm ]v6 8.]oG>q"ڈ~ԟBDZfߟ^$ {,︓e3`\ [7f\9& H $9f^Gx"U$-B!R[[" CP__? vXR!p"D#kU|Ela5 لRMlM9sZ:ȈFGVu7\?RXIħE5e!% |fY4٠$ zKέ Z[81إ29{|ė!Sڢ !{ZkFP  .wƿD.Pr 4W5AaYάH].PD(6>PSa_xQo4ې'mo@̧DlD"?bljV0˿ĺSTG'a\+lHd'!~uEP9?":)0,*R }#$Ia+'kQGUCJbAAQ9@;:j%ZZ,ffSoǧN <>jB Ta}>PCfFF n/}E@fۓbò2"~F!0O @os=qB3 bAh/Lz4,"LY`}/6m744*okkw} /3s"!ďT3@AB볘mgϞm/<“1`#0 \r#X>Hl |A4@ L(xe8$DY#ƏN{|@DϝQ5v1]F544D}BෙNe" ~MT'*iLtSioկ.5ǏoaL0v6WIr^nݚAOcOq >ŋ| );bmh˝3ccN( _1;}ԨQ\)5=@z:>YNLͤ0& _o"\:૯͙V1( kmݼl6aϤ@ P ~qBss֫>W3-ZB.4Ыk4=k}f"- _2 r+ Hm 0}E$[1sK2)N/6A()XIS•PPSL.j@zlf]b:\YGp{lh/{δkrvf5h:8 ˽Ziuy X CVTTު͙V.kV$mx*Jk|Y4~ϙ:u0+]?;_6m37"0㽱]e,˚rD Ǜx34_38hmƢE!xJUXqW h f 9|H{ ܷr{xG{ЇL K4wF<`…?F- <\6_Hi6mz@e OJ9EfR,: ԉTQ&V( ݾ])$-a|OT=ZbnDm>U;\+tzW 75sR'7oz.j@ @,HYJ\tٵs+t"8sC hb_~^aiUuuu"v)14MJ42mތѯ>+ltʝmvUۘ\]+Rs 3 8`[8;SK&Cv @DjMzР iaoT V%7Mܴi  !OJ[OUtbݘœP,H]sL+ w"B G͙^5rތ'ҝ.oM,VQhԛ ~wI94Ϳ0!l@e榍H\З:WW>*eNvSY  {-D֕Ji=h C$[˲~@DLәmޗD3ÿ6i7%g#Ga5b ̑HDg/dz}+q uuu9a..O>f=j_;5ieYieJoCEQ5 BHtRŕDv-34E$H>`#0 r^:eY9Y,ٰvHkz q4!)f@Z9=A#y}M}'W+f.^<X,rm $ @D M0\>ߤf"R*#ŸVlYld;3 @3rV& q'35[tvƇPys۞03m*"Y55ioM/(+XVq:ϟ?! 77-QFJ3ʹ90߃~@M P!`51-N:vΌz4+,khԺ.tB]o}k63˓}9Ūʒ DjPq`ۓٳ!d_;\@_ IDAT'Vۦ544cP|p9D g|>WQe,v`6BP4Wys b@dO\kg B  Y8SnK+\? knJRCǽRSKqԱ~\]彪qvOʫTt FɜU͙Q9g#D"Ѩ(p!frT |05 /2F{NT}6B*x״1is[[[rAG2AӁ׻<`[ t}kl<L4BH+)U4Ra~ZپFS<7qޫSyd3y ~ a7 fwJUuuuA"T.t3>@z/!OoH&]6z`U !zN>wFU_:aYVM,f-,;;$0FO,T'W@A-D2SgqT_ D̙>fyH٪6<3 M;6)%N3?jȴŭ)_~Jg ƌZZ߁!X򓞁ض(Dc&7ܲ#PiFS'|ίZDtgup%K\qHoKoÌWZ[۪nߡدzf$u|zp 0P0cٝ_,aT!0'2Θn(-^}3C$~ǜ&7[4mmf<їmO%UӒ brʴ:e#x:e"/h: SrI4jmvnB{&M&<@b1AUBD!2&)3lz@fO9kbq .@ŮvpTWeYӈp>$,Y!/j ׬iy:ՆYVxK| |x ˳)"˲iDWDH`HJ:Y _,FelG=1unnA/ᨓT3ʴ/Mht0 W@`r3 FqQ__?\V ^dQ\i4=y$6Lԛ%V#= r 2w3፶JWMJ~QIWDb}U#NVx+O*zd@ 5=@eY C[IyP3XqDgij̨|)*BGNbMޑZyM4A1h C>y2 z^u )dƤv.X `E 4r~L4Z@ H| %"/NG&v0ls&mnC- ng2o_0U䈉'hgL49T'5-%5x>،eYGq=.*%4M3 A!P2NJ>]1ƃ0|H(N:wZwϨ\KQWW'"Hu4jn3c< >>A6GTTL3"wI`M9,xp#mr>ܦgk|+~(bptت6wy㹂=q.+B:3^^oP >W >QrҷB W !0GE߀Γ՟f|ڶ]>)e+iHYo/1$twA˲~f8(_WHyΑMo@p"o8؀ƌӜ1`YW>ՠ bbm8bmBMNP4j=~"%fdžRm/SIF"pyER Xk/{"~;( }Р #ۊ~9l9k]E" $2"ҷA;}GZQVx}+t #Z86굳ggä́eY uĽyy\} &w6on[: 'a˲}پv3g>и N#qc>jwx\@7|r%k/}4h)6 ?˹M̲7 oeCG']TwhH2֮}uߟqhJT >$stӊ2 t{x] FG Et`_M@߀teYD@3wa30 ̩e*4[5wx8.@?|&rx-3-'Fȶ!`:,O8`Yz>Mi>W{.o*Ek(KL)p޻j/%pd[bތ3F g6a,v c~oB!OYYD8&5B|jРO'Ŧe(3:=|6r?4 z/l>yl~|?h @R0=N5=nD2 nzlf=˻XDGG֦n"rW4V444ZZN$N85/=q۔)S_HDZ[Zv:ZZ孢mC'oqjH$#qBc:gډts X4"}YL3೙&܌M=WWod²!3 4N F * aSA'Eʖ?YM:eBty }hzXI_0`gL~>B%MXeH"j>$2|B@ ߢt/v33n f}ߴ-` M 4Q%;x7uuu pjRҽ2M5)܈F r({lٳsgS}wegd jm<o333M3Mze/B\g-> ‡R?71s (%c1BR"*q3Jh{:]oAdz&2J57*;Rd {/MFad{{b)SyeYS3*c@ƶ.jnQMF0]zۗn ڌHpI~\OD";&d-%2$y%5l)AiJ|=)Om._eہ[># _Dq>}C@`f,7YӴ]3_|oeDD%^0K1W-,R'~kX#|x4|C{j BFdnǯ2i٤u܊Z2E Ex @#72sOg6Չ#:H\,;n>\ ޞL⯏ޏF\Hmn/T{tc)H$+"Me[if! [wyZny|+:,{Dh̲QH4<=Usù3+ !G {[| >ߤWe}O,hg+֮}& <Й/~0BbL`YG8}dl-`,V(3n(oR 4ut.%GdgMmߨDb}UbBShEV ^2)# `N`O+~p Y=nD"6vBk\hpx%:VL @:;1,#3*sG1Ygv3GZ[[&&B̸4ZNb ~ O#Ol) , H]gnrOju9COQ3ބǶy~s QadC@1zvg!,c)XͲB>P?RGxHg_m_$xW'7,kWUB@5BMڈIT[[[D7 t/aI$ey:jY>1'?6.u=,\"f> eKJEYN QM"5*߼aNXoڪ%WBǟN/(4߻ZJy~8h˜B_6",++|D"%% a@gD$8RxJJ_<`ǖe1dyة KLDD6?74446o<!PŞ n$"8-tgfǤgkjj>p=AyiiaB'aɓ&OkizNIqc1X'Œֶ3&W 'cDXl7pɌ@笱,kW!Ԟvxsu-1Z3nܜIZtb%--Gn~eUef&Gei~(Tf&Йv}Dj~Wz<#R#1\1@9a(F)aAP(d Xz-3wb=fB(/^S(2JJJG("LC̼%@=]7 PG0D%3гBQW$+.84O:;׽uTFӅV`?5tΧA3R<4 n4ҝ()]`<>e\%oAT&A.1`6mii̴8WeY~! /<3>il,وA. Ff$h"ޝСđFS ",RFT68eY' [ tr]fG_htbAN45_铚¡Dt MD{:m FG I8_CMI;0ف@LN]ٮ;ϲ3DrUB81~啎T"~JoIs3ic5 eRO:奁@P_SD$SI)qikwXND;wž;D8+*f:PӷXJDm_{;6suM`ɒ4La;z_;6iY֮DxleJwัc&<“D8]앭?F?aN_kvԧ pJqـ[~|䑵ۦ)67Zߥmy [~;#Vt}h fy[7ۿx_t0).Mz,V(ӬQ>lY֩Dx6 ̼b"WwZiESd| BcJ.$?>ufR)y.4lM m|,Y.۝8&c ;^|&xReL})n[5alI|\'L/eؐ2`$ʭoTofxIÚ5/di Q)f=@鬃y |}dKgt]'›6YێhdYዄB\fl$|il#@e:$kq}4 c!H>_yFJ%DJ mmZ+.tֳnxli}kbS >@'I9S`oEP@*T \Arf%:}g@/HK%`ͶEuMԬDI$)h&֬y(i .m#8*۹Ȍ#[榑e)*  q;;(f4L8CG3ijtrDwƋ$˽_x7k!ExG\Jyio"/$+y1Bdc@!9H쟀9Lt/|ENt*D(D=,4}@`ҒFU7ѷƵk_~z2[QM%r7ȑfi28QRz:iVVHLW{8Q٠RrA6gg渽  ˍ+"eit&3&ة~Jn)E"MTQ$X;Y;)4UR|aPA 5R)^)l hLmc•9OA~/}dR _xh!&sɭ+7'VUG~NH|ѢE;Kɓ},T]d4 R62J[)@߇ڧ5D9BhfpkKK:}[mE8AY_m%U0zJrLpkjjD;ȬZዪC7oY! ߵR+ CB)=5KjU+MP$>H\˜k ?J:uʔ% dso d+-[nod"1݋4͚V]'|t*g]w{ږz_$'' ]MH Ad8uA*ſYz"ή2#.@gݠ0,nncfg%%nx&IDh4Jxu̴h M_" np;;$KyṪie+Br ݼ}uMWD"aD|F}WCer]ՅLtu)@uuubԨY*+H)t֧t|m:e2! dϰƗU'X8B`GQ0#!%HQkQgPxg_>7W 'LAyXW9^ڐJq0(S!\F7.X`GF2B=fi  >x })6L{;wq݇}{=rl;+1m >T_"%ެBҲb }O@ Tm8At~_WG,Fttf5Fb݀T`px(5.C< `\UC[L)Dxb„ P(4-=We,3nL'T!ظ=^gĊLҺe +]9j+77|\WO(KE%Wv']m3R<<jVAJ, wLR(Dh "ː9+$@immr^8W|$PxwӔ`y^4(5{<Y8|AtgG2 D"q`ƧD=qTFcGQ eefƶ:Ұ @׻\MTh4t"&;W~V֎CŮD8Zҥ Tn`κ?B-U*藒o?~|Me7H$|I)yݝꟷ0|>LFEBQڰ @xX>PMETlV.h4M~hh$Vn5 ҽڑX_=MP(d ۏi0spagh{m]% wgYa.x5 Lw|5ۈh4ݡ!pZ~߶Lt@h鶓#5P(Tt5,k#@?s`Meݡ P|wv)Dmi~P(dx)-]H]eU )wՠh:Gtu"w|us-Ɩ@IUة64sa7~ {y׷6H)uF9rQFh!IIWCX f|ڗknkG}'z]Y\̜t`L㘹%O6fDT}6ƵG,,n=bYچHd'D}Z%%_k-!6ټyP!(c!@tF EVƆD"ܯFhI]] ˈЈ/2y7)Dէ|=g]+( 6rJ4@$~04N$n6Kwv"\tE݃sbisL 7 ,?d+L93e"6,0FيP()+pQ鵙K'[h'Qu8v[Z3Xu02 $ۿ,RqH:6`ޜxUޘgZ__C<͙3fmSSӽ٤ j4NR0,iƛA#: H3L/Y#kf[FѤ'og4ќڑ f4kZg5,(~-èP!pV?qb-=XcJ4t7z ыnpx%r ><,Bo4sQ&ETp n:=kVAGxF൭ ReƖ-cPF&eit%f¹89.W|cқ!_M{* :tWfF:o; 1rGLWOO{ƈFG21*̲O=\.qԢMl3$gNLT4D&2b8<)pi4@Q DBckb8(!86@Dŋ4~h4"IJ NR$9zx`qmN1G0%I򄄠 ӛş^c^Xla9`Be,M+c\^3B^orZxci4yH W8{;]N$,*m$V$7(J\w99h4EB,ɩDtPKP "zLJƶ&++G1ĕLp̩|Cx=leY*0?u͖ҸN|5/uU#AtîHgznxZ)_)$2aV/(l7rޛ0M#RBd @E" #Uh4}EH$&a*Kclpw2eҤIe;9F! rgؒ.+#GVYefbc4 SXBK Ö۪SE"qt3@3:䉢 @BP[1m 2_7KJ`#[z2"2]SScΥh4ŃeY L?"H.0S@r c„ e;?\5\0 xVdԨSчn?-RtU08K_ogjjܦn {tO'ExPa&v `nFT 2  v'F)$"ȏS~!$!0ZWرcd;;ƘKP!`WB-U-(_#W"ȏxXfNVF¸ t{vM#-+^kM)Qy\ p\}I3]Oħ52a`eYL3~F5MMܟ~G5 | ~ɮIf,$9-j}wwvgCv<Z@ˠnWm GGqw>qf;âEvzI9]5.^$wغ}%@gئSj < %mn"ڙHĺ6MZF),`>!G>;owSD -@Q_4JrψOؙ ,CD}>sH$2W͞=۶/  sR&:, M .!(<>LwCWﯙOHU9E@,> tGFqW[WxfgD"w-emm[Ƴ^y'.~pH`!@C.IJ @P kVFS!4#blE߯{}h&ErL̰{9E!.8Y6a%S)iy4j=LKFmbƑD8c]!P9f|*= %5M{=M&D멠.g=}SVt%Tdu~ӬyYeYGX)Ꞽ `AekB,),9Oٽ_h4}" @2` Ao}59'x_I$ 2".-'\Hĺ@t2FqE#rIDG0H;_ q"D[9v@qNAƆr+]q9|  %:gXl52~mmzZn?v75s39M%pR9 iP($m`pql*%'HȻ{<h4\ 3J\xV4y(u|5˲vPթTuh /2x)S*x3L#PRt-~IJťK7̩K6HW[]#V,3l8h!2gE0S/(EH)i{"a +Uq>0sXhZ@ yh4˲'Dcl?<#%9 HrNL{ ѓaؙ,X^׻ݍG{./ :>mgݑ.|g-"?~|ni4=MQ D'*WBH+ԏ3Mz5|R;WB}}aA!ucQD4YY ~h7.IWph4؂R1BB߃H={x1M[57 a`蔇םLvS?s45sK9T3b1;[Iq;C4pnwhz @9qd#NCvv6Yq{fDTŒ:nӦ!G%%Xdfkwh4}P(TZZZZAć0f:ȵ{$VR2&%vW$,v>3~V~jg,k,xضyYǦMC2ϘoNcu8hv" Fz@~h @KvD˻/OnD0qH&r$?y'' FsR"`i;F)Pht:^-++=o^>{+Q xXxޝGU` KWVB8նNFX䕶;̛ nADLx$ʛwV{ҥK8*/FN#;KL1 eDSlhiUqq3f̈{+G`p `C$hfLB,D |W׼nC hI,p*8#?f^YZYC8.`6^f\8h"1e'?'[ى6?eR# > ]׏"֎# V\7+ .k'[p~žhsϜ%(u{]]]mm-g?HvP0|% *@R̊(6 (nj1'av,cϋ$7fٶΕUUU]^gh-'JP~: RGRΎ5"X>B;nւ +n+kz v}Viʃ`fܯ%MYifיhM':;ڮĤRfJ@BsD ؞*g80B!M勆*++߁()% `wy,ݣ~qJus\w c)q*JPA?#%%B;dPt@XzX/qv=&od3dO B!~00{!%eߺ${Zқ&a-#f~bGn5QR ʧ</qNOIA0D"q"Y_oilTOmfѢEbɣ("9V3p8_+^ ;ٳOMzn-CY @u ? .ic&]k/>2*/.;d]_d;H0<"0 =P`F4Ff$%6ؤi&c%˙XQD(fmapprF"/KI/~Hݵ:3c8Gӿ'&z c6@+1O|N> |rdr竼.Y{RnRxY`/CН^~ H,f/T/H,vO$'9eYigLka6 黀x@&7KMR vOWrW p<0#(B,&Q(.vǯ@dXƌ~MJTPPZm\+rO0 :CǠɂ@ *.v/|r?rH)^OOce {KL+0(./g ,M 4IF}z\ ;?ht>SGb8E)̘ X{@_BBb #)V@|$b13o4hvU$w!D4R,e BČʌ0b +-_rdTZ]~4 IDAT| hT{[;8h;i̘Bw9$ xU’doqb1$~U]]}!0<kii #aɰa#f_Bɀ`aƊW힘yttG[Y6N|h<!;_T1=VS;r#n/s|" f Ŀ o{UG~c|u+cgF$N ]kP. D"r RBb@"*f ]D@fh02P 7oZ"Þ+yOb0m"Z,D37OdDe1&g׬p}%`u$.Ė, KԇlkkX`xws5o y^EyIK5@t 3GwZȄ%M_B0uz#'M /m RR4ei*k0=*?ſcʔI6x@;2!B;3wWE_́$ܱ׼v1sƫ3BU@E{L ( N4 P!&; jPP4`&ݿឿD| `-5 ^M~?e ;9Jӌ2b9iΣPGi31c]׿-'V,in gHa/g$>LŴӽL^WWWG>bȋb'j ?(bGf^,;&wI nR ASy>(kW"_~lI|fLE^3b/4z#nf:# `LZs_z.pm`>-Yz@ ..v?Ca h?~ nF!G&Gu6{ݚ5;]mO5O$@չF%G![㪪*LGO2"XpJT=킀bHxsM`8CULh#@ 7ɍͩjNd }ܗHf5nk:sLk ZpN<(0bG?NDHLuc*}3q0 J^ˋDJ3%"J^I1__FKlCSΌ\38e[VUUx9 @Qj&ZUF%EPڃ2`8i)wB.j/0zJdJ@h϶P(t0Q"%h63 ^EmR6u$\\\iƌ=4<,&Cd;=c n:vms򥘃:aG̼*%>&2>GA_7f+ 4@ @:$\Qo vpñ61s^ hbٲe\h^2D|_B~wh`Df_Dp =5Ekr>)((_`-fKpUw8@AZMo*@0䫮U볭=bUbį}>lp90#CBC `#vqE%{_@ۉlRn>%'C"VYoO6Z-"-<N ă `x?&yK;pJ3ٮ vG(T=r<`LƋn כ ziKs3jGȬHP=|"8J?McD0W9Fr dJ Dv \0vdڲtx'+H$ uU&C #PfJ_UVo uhx'@;hW "ekZ)b;t(**ږ{:686D) > LQ¥*IC,x<+_o #afF?~0` *b@S44C`M9A_g]׋hAfֈ(iA1e,KVP&gͪڑ]Ѻ!1 0p΄Q.R*P, J$ .>(w:~Rf]' %v)SP^Fx$@xG:4.2|8mOl1{b^ 0 4FbJѦ@Ōw xމhnё+M#`Uzc.^6?4uf)G3fMcc q( IUڸj.$̟3^~A^}zdC){~T:O;L"H@i^u]?J`aM~y(}V ̀xdT{8Lù3F6wxw.I hFx߽qؖyDCo0(qD# &8GM D*PlB0q6`.PnuHfD+k$3W[tx,|@ijR~1'=\_g$γ8P/~$",3>M>}R!J*OD`H84hɖ5oe}}揈xSLX^/\["(o׻פK2m*Qߨuً !Vhx9)JSh{F+W9`T1iA h*S2?vYlcalwA|;J#;6,ĮBD i0&x00Dx0 &!n-^uʈwJc?v[4㑮' AKV@ *.v_Gėgm;3B){8@o6N,2{䓑^iϙyf>S|H"}jJD$!*;H5'3phb @s|>AR 0h*K0v/fL;@hw@R;K;"Ԏ+wtnCcQ:;c@R` b ""%0@pha p3P a+?݉髕 @{%7D׸' .*B<۠E諯~a B).v?`r_F3} X?0m$hO ?Lx:IGqN+O D<,}|2/B|(\lyi[77]Wg! @SVH J:h&D"U.INu 0E;XH_'awf-$S1]ߐ M (dֆbt 2t.Ȯ?=RRWBww@ JU%:˧i!I3틞immg ۑEWff"UUU)WcMhЬ'|UuuMt3>`@r>(#0>7{=R -Jrpq<W}Z뽲.e,pz_kT{i#p8OMnK!P;i"u7沫ڟ α/np/zGg̘ё䛜@t]/t D@2(J%I!i`0XN$l%IӜDFSpJJRvpЈQ0'y^~w %s_{?UNBJCyZPEQz [1~BӉ~OJ1}:e4kfZ?}"cmkqKt]?I~~0]AQ|!H~EVӤi1&brn*(=d$-,Y~P)$ʌO9~#{^0,w8g***ۋ6 ]si}//4k?6=`%t"}!Z^g`?EQIFduPH! #^"^׊fy޷fjuuu/坝zj0(ZXtsa4"O?HfשuvvF}^#r<Du2("RG8qu{>`2[)UۃHt  ϝa !hTퟚ䎜@$+[bUUULEQ>ĩ/4$07ñGEOo`|"fEY>3-u:Fח|W`⻒U>~\9)J. -lJ24(({a~) V}˿QT^ GX]rc&Z0< l Cv1 [LGIhޯDt&Y2 TEQ3>G+YN-vdY: O25]tcEΟ3-:FG^sEA B_e9(JE5Utʏs\ʌGg<'vǓf+S7UDt'@f9.f竸H~Vjv$?Kz筳{jr:H((cƭ֙<.t]?H<`f7`WUUL]:<sA$N0uBΛ;wtc' |@P}koڄF횏lV`%]!LQE/ނr׸?Phx!2>k gT VWbu > gFnf<>j<Ƭ!\>qψd/ˢ˪ (VoSU5]$v'2$^MFӧVEQrH,{Šu+lkkF\ VTTn}TWWt:̴(ۧf!_V]S`\t& 3q/}b'0 ô3MLQK BCtOؼHTϹ|+EQ޳9KVjop '@cpaҤ Ya65MˌنDl֬FAڃଊ+w\ ,e@]\Ahj%|ŒOdmXiJQE%tðPi6^?#?+i}"%Y^]׋4e 1 0+t_:Vb#.MVL73wbF'(y&}\*'(o΂v?.Xhu|Ènp!<$Bm,&3~:V IDAT 7n"C4K|DוO_gzDi^0u c{'('V@C (9]Q8fŗV.2eʤL}w1˫ʻ{*^,~,"flaO~M]pes@3.I֬iRN@`%o|޾-懵I_Ґv0=5GEQv ńUZ`ҥC \i@`UnA:K̙y擎E_~` t]?Q\`e"Mv(J UUU-3lP SEQl!’}V,ZHL2ڍ{J׿6z|:e_C}4LvF ܿ#o_[.L;8.X Vw:{'(+π$<3]:ܬJ(" <,(uMzN70]'6ܻ!X}"Z3SEQ,z[y/\E˖-;y3_ {S\V<޽q4WBE~ fyWHڞu3_3qD|dɚA}1Z-6LQX"Z<*,ֹc*(I1^g\:nj10.rasQٳgvse*.v?l`Fi^BI3+EBX >Uӌ7;E?&a=hW[&uf0jEQ3C`cl3k.ZHL4B"!0!%sVna݂3w;\MߕDb"j=*M`08˅vbV$o`@0'‘1׸OCQ(#0 =(Y5kV\\x@0Ά| %~a[F1̳XzK1nQD Ѝ/GM,@Ysm᱘eZ0K_y\sw? HBu"wٴdE 7N3_((ֽƄ:f dز^ wlKn4ڹ y&08)\BDs[*e J'/1wZ6 t]/Y Jڗq >%{yR]]}tٰH~}Z6?4jlf*EQ+ϒYeuDkO-x zo4npxQ ,XI;Nʿ# `jDw9K/̃ )%~U0E|)D|[4~irJ{g(H",Yź_6=70^'~r d|K_}aFDB #%?K|[A{U(ݗW+ |!𤅮:;zm"6= `SEsYL/~‹p)@3>_cނ"Y\X7ر1&0# UZU>Wd0EEN1cFGf(J|#Mׁ+bf*^(b;`,ޏ#^ڧR:P`f3"ωpbƧO#Gn{Ҥ vi&,3_[\<3f9C"\~v{Zl3PHY\ÌfÐ?\oÅ8)IHWEVeFTx<uyRB 6[ym| {m(Jb`+!.Ly* .!4ňXlO5n*`yD"yeee[nDM` z1 ҔG &hdOT(u2!*ߦMS*훝(JΑ ԂصQi]xF; !~6-`I,&|qS 0k()_yCf֌?:{{;"E)S& gcf(>9)7hG{^ӂXx5b{g(6)Ń٬v@0fu=0Qz+ikmFP`YbR\h*b `H!ҕ+Ru "CD8=Awz(qgy@(/J_f}>I~DOOq(} ,𠳤lXh϶WVUUg P15jg.l8$}on ry<դZd-YgWGISV:F8;1#=|(JH8l0%t߿-Y(J P-C>$YӝzL!pmxtzx٭=sX=_Q7x5v<0:aGXj?EP) ?wcƿ])/1:X,E>AUKW#)GpT@nj*=Э>}4P(?  ]ozWbc<}4aq/"!B_%;[[VUU_(J6M~-~%i=O}ѱNfp@g(-o$A!s`}ɻB9d3SeZ<$mʍ=t[.9?D;#im.;?Ch 1?,3kV\>H_xDF x%_aOy@ktM \VJL!؟EQ%($*۵0eߒR;PjM1c3wDƽɾ5Pͅݙ2k4FDo :?% tXf:D8\a,bdR+b~@8&2F[;S\;mxT@ &4:#tXM[%pkkkDz\ q~DoFl8epc=#{b~}6V0㩘a<>zGלL031s!pSv EQ @|[00J O3p:" EE鿢VSH rlcЧ~h4z8I-w{>=*қ۫^p~l`kAx /UV7Ǥ`Wn z8tC @ 'Odxf5I/սY*O sLiW{0?]l'`6z>Ƌ|_[[cUUU9w[>PqWǹ<#z[FMֱ֎U9 ~B0mWLWm-COuB);1ø?<Eo|̄g0H>W8vmOgu]& +*$NΟÀq_5C|'V,X9 Tˢ`f07@;S ]קi&2eZH6)3 c)b~]H?& $s`>__vrs8REǦ s hFu8z555F#!p}F)pD.=OQQuAp9; Ser4^:>2H\E3sEQr*+%J;UI"MaF}sQG"޼y؍"rXRiuha'D3l8TtJ44,v~{+5m->b|6( =5 Y\$%~tТt6z(L! ՙU*slf.'BD|W<{5dB5UWWpdSjףMeo=3@XFb4Qf;e" 8$۝ζ?\(JRtR!M<8ފŰP(8}Gḟʖ(LX+ /;akQo 0w0s|{P `Ikk{u(FtB}O=zDhMT0nljlaٲe8Xfq8Lk#z~D1ÐSQ*K0X]E$P ;t4N f4E@xW#W;^D"DD'|<2]3'Ms>9gΜ8pK(ҿ@^|#C[`4qhflu+bY-uuuo8"Q x0f?NY);~(ݠ555'i-p@0+}ʻ`a5:!q)"&EQB05$x 8 ['$fxANke)39mY^`znۉQӬo!p&M|`ˏ%D3X6BVOYD555h(e8"^xW<0z罼(J$`08HʶJfk|ź!QA @|.㳼( F3k4Z NBn̼K|>߻4>/otRⶴ1N-v`hĆ;QxWB3Gb@%Dޞ7 –*IACӲBp,f2"R0EEJ hf4*Y~쓏MBLeƉ&wV8([J,|5\X_a׫m' S{|e̤i S9qE(uB[<Wԟk'WQ b)Ƶ4@5r rLO[&iUg'dL>׋0/Z;xw{ƫ%ržtYbI}}o `h@޾f*G:wH~{ty:߷O4ܹQηϖWp`415Gq+|sssDBEH:Uᕸw/dВLj94>%ݢENcG=ܗ577O;n:2We727w0VO\1_k0@bڵ8:I:6op7׭ddi"\Zg#2{L5G =6;*ʕݹ(tިtkRS_alښKc?9N?>=}q͚5Hh ?^W'Nv)BIM`"7Bip3oR-j}35[=r0=#&4דAzLOpk4eE$I^c%%e%SW*ɼ"2jKaʵܲaRu|%^-q07P`f9)ƍ~ wՏO\V O"wf ?> tyc$| egdzZL 3CM p˰~' y=Yό]$i'vd1^#HvF+-RXY(دxQY&NpzQ FId]f$K>!h3+wX/7*mw͜9sp7`@yܤIu/j3?kt)GfFNPOp) [:I_n u@Z)=nkwH ~5^Jo4XD(~1=~] T?HHD0әs!KDQy(|lƴDަ't\e: iK/itZs '#im5/%ibwmmmm۶&pLqcpZ3m ̢ٖUݮ?=m%{ Auuu=Դs0@(mi4v[NyIJdvH@ɮ]U#uGt)֓ᶪŋ&ѥ]ΤAz.c뇻Ѹ%ݵY;䮓M ~NϮT_8" ʇw]]]755m^297JI{ -{=g w:a^yMs` hIt}e*iIS*3/6H{BFL<(Ć u^ԑ;r #QQxtF="3#N2[HK52N M2Ӄ!!|>H8@! e˖M?~Gڵ$ڒm󖧇^4=_3JN05ȦZ&ɦTMUωvcD3D\fI,&rm6fhod o,XX7sNj~oU->^lHw{YtWIzϣ2fH=ZJ11be2cH?Vy6&J֮'R(~0v@Xϙ%]\EIvF߫w3;m|)/*M MY f)&lC=/;)]S$e[Udv?(2/]v\ywm[:;$pi[|,t+tB6E[vV[ͮ2C!fѡ)ّ IDATwo={S?Ɛ\.W[(^iV8D~JvU] v_tvwgΝ rAK:_C`pSQ߹=/2\r;M&^!!Do_k3WO[0NI@?H!L'Ru}nٟ|1lsM|EumPu-Ү 3{(=*͒#  dro";]gid6ɟG%8=k'2 rZ3 I(: SzLO! wqp7RzIj3$I:[$=4ÞAO'qNf:@P[[-ݣf:]'J:V-@%{&d D"<BiΞ`!AEJ~+g;`HtIzAք"{=zP(<ظu# dd2cȎu1чfָuf{6q֞}FCAQ\֬B!qE:DaufOR4m"KzQ%m4ӺF7i\BxqҤIgΜ~@"`@%BtH@3/>LS{Ӕrw797e6缔fBhR͋^ 0R@P˖-Z[[;լw>,SEdwlI&:{:OdI5gܵL]olG!!id%.+Ev63&yG,(NY -!f5$Ʃ7SԯߜvhxЦ$]t:@c,CfѢE_;OCotRw43goC?ÒNY~ۄ ?6͜93NN4̴Y"ͮ:1W \#ܓKQe?oV6뒦putt]Uξ f~.ifK_+:dnX]")濖G7i?]PW\o>?rw"ܳ~^vCPvLfA1:Plpۯ0zMYүwD^_?;ן_ d2U +/|HD{.Z }z*5vbӓDw[ںbNeq-?;PbC},Y=M-l%oݺpٲeSkkknT_e¸+/|̾V*|wI7]5VftU'Vx5.=E[[W'cO@ Z6rYqjĉ^7sݰ斩2_4핅Μﭰ5/~!(N>>3 %ɼ"ۆtz:༥כ{k[d)λ_O,+V)&3ُ7ۛJ`(ҷ⟭aW =r~ 7zsoUgfJZ׏2 \AA0`lKwƩuBϔߑ[KW_j*J w!v{!rʉhj+X[ܹsƒ] gRsZ~o;3[K0(+ϒﹲiR%\ /$ُАno=>$,T.ŪT$[ ɶn9#ϛ%ߓ5]qI:j@[&YS%Gk,r.M!z^U|pkf_fI`藕+WNw/xWƛ,Xz)aD:AJ] rDžff{ǜ|>qkzj@ݗ)vВRKƻ5C_[Rs6 )I1<,{!c@l+VxԺk\Q$SmoX*U0>Ld2@u,d2(osW(Tg.ZzGwI)geBH_3~Q5UIs'&CSx DBWa ڒ 4!o\}rOKVtG"70&@upDw5O'?#PSвZl`]Lf}o*:c@r\Rj01IDѨx#(}qM.?_l~>W*Ⱦ:o/62kֹ=Uf㞟@"(jiJ8fZJ5~آE N6X95fᆏ59RGb̓Ǻd2ǸԺ{G~IEz4 c;;Ql`ymkkA +-tAT*dj,c{eۏ.6vソcL3s х௼'~L,{ﻺ؀IQ$vWHXpaA_7]PΦm̽[Ơo(^h AKӏ\n~Uy;~|U9}qͺuӞ6}L蠆uC"#O@ u=,,>.Zznv7BEEӝ>}^Ƙ"r/$)\`3cٹ㛥4<40m.6χyf@\.w.YP555 [|Im2Y0{jnn./Վ@oixዳg~of(}{J 1AĉE7@1.ɼKҜtv(SߕwYl*6χxsD'#F 0\l(RѭeKႦ,.3.BWzCٛ` cXP-ISkfhhh,K*ks#]}^mDƨiw#^~۶EFwoKگL];)6}2M0@1覛n"Y̋хMMM]-]6eloԈ}g',)H 0T30&/4-N}7J*66{N;+z* `!cL.xLww?*Kc ]]]H }`CƐI!uff}պ`_pê7U@Ê];VEcm `,4Kf:4Nmْt:WNtbI}*7?Ƹ\0Z@1"ɜY.x a$^F^N}] GCRԦbcn\&痵ѫJ<r}]l#:;}V11N΂wlK^lL5}]n1P]!ru%1_ÇK /HvdZ{۫,: bkq$߸d3 'cTr{[ra jF.1˳T \\(_w)i&3+:m.OlJe2c1˷twJct\y:&~wO(:J1~M$h@*ܜ0fsWtΜ9Yp_[u}+oG| M8b31fy[C/nH֐1qSl c\' 1Tl6{>,Jl%뵝w ɘҪ+fn+::-555#.&b38}-(6v፷kOaO}rʉ:1 .wOd+.4ә1VEE]')1' Vg8^  @hii&Wc(Rp2Wel5F(j3{DIJD1]8{쇊 [(]C2&}<.OǘT*d`T U ,`}Rh"sV҄uWuκ-6PWW;k3}} T(^hȻO]lp!> ʘ_yͼEIq}E;`T!\.5Jb7Jڋ \P7R[F)=33kwmؾ}@F]TtmI,qI}wX|0\,)f!20ʹ[*N}̙ۋ]dP./68ᆲv(CF1j6vtl_Zlࢥwh}=U/_SX|p=brwccm хb$w5755u ^q81b7tI3InY`"ɵIweEO?t~YBf~7N)jkk>*iӼ? чb|EG^+]&-zˋ-_`w$<чn%?^UfB2qW%ŘgSmŢ-N]PZ-iCY.]3/6fOw9uVSBFnSg'w<&Ij`c3.gJr7ڸtQjPm+cӧ.[sTs dQIOtw')?&G O ˖-j]s|e A@./{vUkkfa[[*ΜfEѩ2=VVG,w[JVU[[ IŜ(OgTPTtIZٹL&澊=]9]5ɹ.}'5m9OһcD@ua P%wtlLjkN&w~h֬s

tG.>fKn=f韗MO@*1sz-ڛg2wUy{f,Nx3k~޾'|H-&|;PE\I;{E5[nej&kNH`g|lÆ ٹ34@, e-fя$Mφt[oE&?/i}iϜ/N;VԻ Ɔٙ2v@U"U*k9~&>"HBGG655z+\tmWm[̺C;|s!DwJs54/,_T%oNt$-8q---n?{OޫN[JniJݤI&}P @K/sO!Nd2jomm9k@NQ;xJxV_fl*6ܜ7.#3g2wߞ;g͚Q6^---ӒI4m54ojw9Zys3*ey!5 oo32{5sOe֣ªBd:xYyZ`l"l6{pf뷔*x{ssbJcOϺa{N{TA&yU%;!= 0@+DR~pwwqΜ9V45S\_󯧯-Ud"ݪ{n93g> N{ }] p>Չ&I˿xSIq%瞸U[q]o:묦vCPR6b]!i\?/.H?袥w%a,%R?kC?/5lHREW=-N ~bf?]B9ʋ' d^En}êOH%In6W.\[a&mmfVw;3J@,L.:w᭍kz+Zd9n)%JL? ;k N^w-j^iяk@Ly!_T_\#a]_r1BWfɗU}_7jkk=>bdE^҄\%J5oj'=-QkMson9:ǒNOoy*JV:ںd)LeWttt]` %]-52 ]ӗKz.o7]8_ds}Wқ{dV8W@y@ JssI&]p!hN:~| ^rBS~p6tCC??AknnNL4.ޙNWƽ}qͺuLS?R((={v=d2*TFw/ΚunC[ZZ%ѻ$-t Z-Jm` *]~Y.ɖ͢=HђߙE7KO=y@@].;=LܽC S^{gH6B~v)zCi0'C^] v rLfv&WIa[0 !NWHz{I Fe˖MR=owRAPqlyfv]Wה?0t E{⚵kL0qCHwZhQ4}HgK.XbX[IOHzXݣKROC` F uuuSԦ@Ű /!!!!!!!!!!!!!!!!!!!aCbeIENDB`uharfbuzz-0.53.3/pyproject.toml000066400000000000000000000026511513514046200165430ustar00rootroot00000000000000[build-system] requires = [ "setuptools >= 36.4", "wheel", "setuptools_scm >= 2.1", "cython >= 3.1", "pkgconfig" ] build-backend = "setuptools.build_meta" [tool.setuptools_scm] [tool.cibuildwheel] # Also skip wheels for free-threaded CPython 3.14 (e.g. 'cp314t') until we # actually support them. We currently aren't thread-safe as we define HB_NO_MT=1. # CPython abi3 wheels only need universal2 on macOS, skip the single-arch builds. skip = ["cp38-*", "cp39-*", "cp3??t-*", "cp*-macosx_x86_64", "cp*-macosx_arm64"] enable = ["pypy"] test-requires = "pytest" test-command = "pytest {project}/tests" [tool.cibuildwheel.macos] archs = ["x86_64", "universal2", "arm64"] [tool.cibuildwheel.linux] archs = ["native"] # Run abi3audit after the default repair commands to scan for abi3 violations # https://github.com/pypa/abi3audit # Only on Unix platforms (Linux/macOS) since Windows has no default repair command [[tool.cibuildwheel.overrides]] select = "cp*-{linux,macosx}*" inherit.repair-wheel-command = "append" repair-wheel-command = "pipx run abi3audit --strict --report {wheel}" # Disable Limited API for PyPy as the build currently fails, see: # https://github.com/harfbuzz/uharfbuzz/issues/262#issuecomment-3415144557 # https://cibuildwheel.pypa.io/en/stable/configuration/#overrides [[tool.cibuildwheel.overrides]] select = "pp*" environment = { USE_PY_LIMITED_API = "0" } [tool.black] extend-exclude = "harfbuzz" uharfbuzz-0.53.3/requirements-dev.txt000066400000000000000000000001511513514046200176600ustar00rootroot00000000000000cython>=3.1 # we need wheel >= 0.31.0 to support Markdown long_description wheel>=0.31 pytest coverage uharfbuzz-0.53.3/setup.cfg000066400000000000000000000000421513514046200154400ustar00rootroot00000000000000[metadata] license_file = LICENSE uharfbuzz-0.53.3/setup.py000077500000000000000000000145111513514046200153420ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import platform from io import open from typing import List from Cython.Build import cythonize from setuptools import Extension, setup def bool_from_environ(key: str, default: bool = False): value = os.environ.get(key) if not value: return default if value == "1": return True if value == "0": return False raise ValueError( f"Environment variable {key} has invalid value {value}. Please set it to 1, 0 or an empty string" ) here = os.path.abspath(os.path.dirname(__file__)) # Get the long description from the README file with open(os.path.join(here, "README.md"), encoding="utf-8") as f: long_description = f.read() use_system_libraries = bool_from_environ("USE_SYSTEM_LIBS") use_cython_linetrace = bool_from_environ("CYTHON_LINETRACE") use_cython_annotate = bool_from_environ("CYTHON_ANNOTATE") # Python Limited API for stable ABI support is enabled by default. # Set USE_PY_LIMITED_API=0 to turn it off. # https://docs.python.org/3.14/c-api/stable.html#limited-c-api use_py_limited_api = bool_from_environ("USE_PY_LIMITED_API", default=True) # NOTE: this must be kept in sync with python_requires='>=3.10' below limited_api_min_version = "0x030A0000" def _configure_extensions_with_system_libs() -> List[Extension]: import pkgconfig include_dirs = [] define_macros = [] libraries = [] library_dirs = [] harfbuzz_components = ["harfbuzz-subset"] for harfbuzz_component in harfbuzz_components: harfbuzz_component_configuration = pkgconfig.parse(harfbuzz_component) include_dirs += harfbuzz_component_configuration["include_dirs"] define_macros += harfbuzz_component_configuration["define_macros"] libraries += harfbuzz_component_configuration["libraries"] library_dirs += harfbuzz_component_configuration["library_dirs"] if use_cython_linetrace: define_macros.append(("CYTHON_TRACE_NOGIL", "1")) if use_py_limited_api: define_macros.append(("Py_LIMITED_API", limited_api_min_version)) extension = Extension( "uharfbuzz._harfbuzz", define_macros=define_macros, include_dirs=include_dirs, sources=[ "src/uharfbuzz/_harfbuzz.pyx", ], language="c++", libraries=libraries, library_dirs=library_dirs, py_limited_api=use_py_limited_api, ) extension_test = Extension( "uharfbuzz._harfbuzz_test", define_macros=define_macros, include_dirs=include_dirs, sources=[ "src/uharfbuzz/_draw_test_funcs.cc", "src/uharfbuzz/_harfbuzz_test.pyx", ], language="c++", libraries=libraries, library_dirs=library_dirs, py_limited_api=use_py_limited_api, ) return [extension, extension_test] def _configure_extensions_with_vendored_libs() -> List[Extension]: # We build with HB_EXPERIMENTAL_API to enable experimental HarfBuzz features # like VARC table support, but we must not use any experimental APIs as it # will break linking with system HarfBuzz that is built without these APIs. define_macros = [("HB_NO_MT", "1"), ("HB_EXPERIMENTAL_API", "1")] if use_cython_linetrace: define_macros.append(("CYTHON_TRACE_NOGIL", "1")) if use_py_limited_api: define_macros.append(("Py_LIMITED_API", limited_api_min_version)) extra_compile_args = [] extra_link_args = [] libraries = [] if platform.system() != "Windows": extra_compile_args.append("-std=c++11") extra_compile_args.append("-g0") define_macros.append(("HAVE_MMAP", "1")) define_macros.append(("HAVE_UNISTD_H", "1")) define_macros.append(("HAVE_SYS_MMAN_H", "1")) else: define_macros.append(("HAVE_DIRECTWRITE", "1")) define_macros.append(("HAVE_UNISCRIBE", "1")) libraries += ["usp10", "gdi32", "user32", "rpcrt4", "dwrite"] if platform.system() == "Darwin": define_macros.append(("HAVE_CORETEXT", "1")) extra_link_args.extend(["-framework", "ApplicationServices"]) extension = Extension( "uharfbuzz._harfbuzz", define_macros=define_macros, include_dirs=["harfbuzz/src"], sources=[ "harfbuzz/src/harfbuzz-subset.cc", "harfbuzz/src/hb-coretext.cc", "harfbuzz/src/hb-coretext-font.cc", "harfbuzz/src/hb-coretext-shape.cc", "harfbuzz/src/hb-directwrite.cc", "harfbuzz/src/hb-directwrite-font.cc", "harfbuzz/src/hb-directwrite-shape.cc", "harfbuzz/src/hb-uniscribe.cc", "src/uharfbuzz/_harfbuzz.pyx", ], language="c++", libraries=libraries, extra_compile_args=extra_compile_args, extra_link_args=extra_link_args, py_limited_api=use_py_limited_api, ) extension_test = Extension( "uharfbuzz._harfbuzz_test", define_macros=define_macros, include_dirs=["harfbuzz/src"], sources=[ "src/uharfbuzz/_draw_test_funcs.cc", "src/uharfbuzz/_harfbuzz_test.pyx", ], language="c++", libraries=libraries, extra_compile_args=extra_compile_args, extra_link_args=extra_link_args, py_limited_api=use_py_limited_api, ) return [extension, extension_test] def configure_extensions() -> List[Extension]: if use_system_libraries: return _configure_extensions_with_system_libs() else: return _configure_extensions_with_vendored_libs() setup( name="uharfbuzz", use_scm_version={"write_to": "src/uharfbuzz/_version.py"}, description="Streamlined Cython bindings for the harfbuzz shaping engine", long_description=long_description, long_description_content_type="text/markdown", author="Adrien Tétar", author_email="adri-from-59@hotmail.fr", url="https://github.com/trufont/uharfbuzz", license="Apache License 2.0", package_dir={"": "src"}, packages=["uharfbuzz"], zip_safe=False, setup_requires=["setuptools_scm"], python_requires=">=3.10", ext_modules=cythonize( configure_extensions(), annotate=use_cython_annotate, compiler_directives={"linetrace": use_cython_linetrace}, ), options={"bdist_wheel": {"py_limited_api": "cp310"}} if use_py_limited_api else {}, ) uharfbuzz-0.53.3/src/000077500000000000000000000000001513514046200144125ustar00rootroot00000000000000uharfbuzz-0.53.3/src/uharfbuzz/000077500000000000000000000000001513514046200164325ustar00rootroot00000000000000uharfbuzz-0.53.3/src/uharfbuzz/__init__.py000066400000000000000000000045011513514046200205430ustar00rootroot00000000000000try: from ._version import version as __version__ except ImportError: __version__ = "0.0.0+unknown" from ._harfbuzz import * __all__ = [ "Blob", "Buffer", "BufferClusterLevel", "BufferContentType", "BufferFlags", "Color", "ColorLine", "ColorStop", "DrawFuncs", "Face", "Font", "FontExtents", "FontFuncs", "GlyphExtents", "GlyphFlags", "GlyphInfo", "GlyphPosition", "HBObject", "HarfBuzzError", "Map", "MapIter", "OTColor", "OTColorLayer", "OTColorPalette", "OTColorPaletteFlags", "OTLayoutGlyphClass", "OTMathConstant", "OTMathGlyphPart", "OTMathGlyphPartFlags", "OTMathGlyphVariant", "OTMathKern", "OTMathKernEntry", "OTMetricsTag", "OTVarAxisFlags", "OTVarAxisInfo", "OTVarNamedInstance", "PaintCompositeMode", "PaintExtend", "PaintFuncs", "RepackerError", "Set", "SetIter", "SubsetFlags", "SubsetInput", "SubsetInputSets", "SubsetPlan", "__version__", "ot_color_glyph_get_layers", "ot_color_glyph_get_png", "ot_color_glyph_get_svg", "ot_color_glyph_has_paint", "ot_color_has_layers", "ot_color_has_paint", "ot_color_has_palettes", "ot_color_has_png", "ot_color_has_svg", "ot_color_palette_color_get_name_id", "ot_color_palette_get_colors", "ot_color_palette_get_count", "ot_color_palette_get_flags", "ot_color_palette_get_name_id", "ot_font_set_funcs", "ot_layout_get_baseline", "ot_layout_get_glyph_class", "ot_layout_has_glyph_classes", "ot_layout_has_positioning", "ot_layout_has_substitution", "ot_layout_language_get_feature_tags", "ot_layout_lookup_get_glyph_alternates", "ot_layout_script_get_language_tags", "ot_layout_table_get_script_tags", "ot_math_get_constant", "ot_math_get_glyph_assembly", "ot_math_get_glyph_italics_correction", "ot_math_get_glyph_kerning", "ot_math_get_glyph_kernings", "ot_math_get_glyph_top_accent_attachment", "ot_math_get_glyph_variants", "ot_math_get_min_connector_overlap", "ot_math_has_data", "ot_math_is_glyph_extended_shape", "ot_tag_to_language", "ot_tag_to_script", "repack", "repack_with_tag", "shape", "subset", "subset_preprocess", "version_string", ] uharfbuzz-0.53.3/src/uharfbuzz/_draw_test_funcs.cc000066400000000000000000000031521513514046200222730ustar00rootroot00000000000000#include #include #if defined (_MSC_VER) #define EXTERN __declspec (dllexport) extern #else #define EXTERN extern #endif extern "C" { EXTERN void _test_move_to (void *dfuncs, char *draw_data, void *st, float to_x, float to_y, void *user_data) { sprintf (draw_data + strlen (draw_data), "M%g,%g", to_x, to_y); } EXTERN void _test_line_to (void *dfuncs, char *draw_data, void *st, float to_x, float to_y, void *user_data) { sprintf (draw_data + strlen (draw_data), "L%g,%g", to_x, to_y); } EXTERN void _test_close_path (void *dfuncs, char *draw_data, void *st, void *user_data) { sprintf (draw_data + strlen (draw_data), "Z"); } EXTERN void _test_quadratic_to (void *dfuncs, char *draw_data, void *st, float c1_x, float c1_y, float to_x, float to_y, void *user_data) { sprintf (draw_data + strlen (draw_data), "Q%g,%g %g,%g", c1_x, c1_y, to_x, to_y); } EXTERN void _test_cubic_to (void *dfuncs, char *draw_data, void *st, float c1_x, float c1_y, float c2_x, float c2_y, float to_x, float to_y, void *user_data) { sprintf (draw_data + strlen (draw_data), "C%g,%g %g,%g %g,%g", c1_x, c1_y, c2_x, c2_y, to_x, to_y); } } uharfbuzz-0.53.3/src/uharfbuzz/_harfbuzz.pyx000066400000000000000000003640621513514046200212010ustar00rootroot00000000000000#cython: language_level=3 cimport cython import os import warnings from enum import IntEnum, IntFlag from .charfbuzz cimport * from libc.stdlib cimport free, malloc, calloc from libc.string cimport const_char from libc.math cimport isnan, NAN from cpython.pycapsule cimport PyCapsule_GetPointer, PyCapsule_IsValid from cpython.unicode cimport PyUnicode_GetLength, PyUnicode_AsUCS4Copy from cpython.mem cimport PyMem_Free from typing import Callable, Dict, List, Sequence, Tuple, Union, NamedTuple from pathlib import Path from functools import wraps # Declare Limited API types and functions (Python 3.3+) cdef extern from "Python.h": ctypedef uint32_t Py_UCS4 DEF STATIC_ARRAY_SIZE = 128 cdef int msgcallback(hb_buffer_t *buffer, hb_font_t *font, const char* message, void* userdata) noexcept: ret = (userdata)(message.decode('utf-8')) if ret is None: return 1 return ret def version_string() -> str: cdef const char* cstr = hb_version_string() cdef bytes packed = cstr return packed.decode() WARNED = set() def deprecated(replacement=None): """Decorator to raise a warning when a deprecated function is called.""" def decorator(func): @wraps(func) def wrapper(*args, **kwargs): message = f"{func.__name__!r} is deprecated" if replacement: message += f", use {replacement} instead" if message not in WARNED: warnings.warn(message, DeprecationWarning) WARNED.add(message) return func(*args, **kwargs) return wrapper return decorator class HarfBuzzError(Exception): pass class GlyphFlags(IntFlag): UNSAFE_TO_BREAK = HB_GLYPH_FLAG_UNSAFE_TO_BREAK UNSAFE_TO_CONCAT = HB_GLYPH_FLAG_UNSAFE_TO_CONCAT SAFE_TO_INSERT_TATWEEL = HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL cdef class GlyphInfo: cdef hb_glyph_info_t _hb_glyph_info # could maybe store Buffer to prevent GC cdef set(self, hb_glyph_info_t info): self._hb_glyph_info = info @property def codepoint(self) -> int: return self._hb_glyph_info.codepoint @property def cluster(self) -> int: return self._hb_glyph_info.cluster @property def flags(self) -> GlyphFlags: return GlyphFlags(self._hb_glyph_info.mask & HB_GLYPH_FLAG_DEFINED) cdef class GlyphPosition: cdef hb_glyph_position_t _hb_glyph_position # could maybe store Buffer to prevent GC cdef set(self, hb_glyph_position_t position): self._hb_glyph_position = position @property def position(self) -> Tuple[int, int, int, int]: return ( self._hb_glyph_position.x_offset, self._hb_glyph_position.y_offset, self._hb_glyph_position.x_advance, self._hb_glyph_position.y_advance ) @property def x_advance(self) -> int: return self._hb_glyph_position.x_advance @property def y_advance(self) -> int: return self._hb_glyph_position.y_advance @property def x_offset(self) -> int: return self._hb_glyph_position.x_offset @property def y_offset(self) -> int: return self._hb_glyph_position.y_offset class BufferFlags(IntFlag): DEFAULT = HB_BUFFER_FLAG_DEFAULT BOT = HB_BUFFER_FLAG_BOT EOT = HB_BUFFER_FLAG_EOT PRESERVE_DEFAULT_IGNORABLES = HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES REMOVE_DEFAULT_IGNORABLES = HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES DO_NOT_INSERT_DOTTED_CIRCLE = HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE VERIFY = HB_BUFFER_FLAG_VERIFY PRODUCE_UNSAFE_TO_CONCAT = HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT PRODUCE_SAFE_TO_INSERT_TATWEEL = HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL class BufferClusterLevel(IntEnum): MONOTONE_GRAPHEMES = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES MONOTONE_CHARACTERS = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS CHARACTERS = HB_BUFFER_CLUSTER_LEVEL_CHARACTERS GRAPHEMES = HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES DEFAULT = HB_BUFFER_CLUSTER_LEVEL_DEFAULT class BufferContentType(IntEnum): INVALID = HB_BUFFER_CONTENT_TYPE_INVALID UNICODE = HB_BUFFER_CONTENT_TYPE_UNICODE GLYPHS = HB_BUFFER_CONTENT_TYPE_GLYPHS class BufferSerializeFormat(IntEnum): TEXT = HB_BUFFER_SERIALIZE_FORMAT_TEXT JSON = HB_BUFFER_SERIALIZE_FORMAT_JSON INVALID = HB_BUFFER_SERIALIZE_FORMAT_INVALID class BufferSerializeFlags(IntFlag): DEFAULT = HB_BUFFER_SERIALIZE_FLAG_DEFAULT NO_CLUSTERS = HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS NO_POSITIONS = HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS NO_GLYPH_NAMES = HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES GLYPH_EXTENTS = HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS GLYPH_FLAGS = HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS NO_ADVANCES = HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES DEFINED = HB_BUFFER_SERIALIZE_FLAG_DEFINED cdef class Buffer: cdef hb_buffer_t* _hb_buffer cdef object _message_callback DEFAULT_REPLACEMENT_CODEPOINT = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT def __cinit__(self): self._hb_buffer = hb_buffer_create() if not hb_buffer_allocation_successful(self._hb_buffer): raise MemoryError() self._message_callback = None def __dealloc__(self): hb_buffer_destroy(self._hb_buffer) # DEPRECATED: use the normal constructor @classmethod def create(cls) -> Buffer: cdef Buffer inst = cls() return inst def __len__(self) -> int: return hb_buffer_get_length(self._hb_buffer) def reset(self): hb_buffer_reset (self._hb_buffer) def clear_contents(self): hb_buffer_clear_contents(self._hb_buffer) @property def direction(self) -> str: cdef const_char* cstr = hb_direction_to_string( hb_buffer_get_direction(self._hb_buffer)) cdef bytes packed = cstr return packed.decode() @direction.setter def direction(self, value: str): cdef bytes packed = value.encode() cdef char* cstr = packed hb_buffer_set_direction( self._hb_buffer, hb_direction_from_string(cstr, -1)) @property def glyph_infos(self) -> List[GlyphInfo]: cdef unsigned int count cdef hb_glyph_info_t* glyph_infos = hb_buffer_get_glyph_infos( self._hb_buffer, &count) cdef list infos = [] cdef GlyphInfo info cdef unsigned int i for i in range(count): info = GlyphInfo() info.set(glyph_infos[i]) infos.append(info) return infos @property def glyph_positions(self) -> List[GlyphPosition]: cdef unsigned int count cdef hb_glyph_position_t* glyph_positions = \ hb_buffer_get_glyph_positions(self._hb_buffer, &count) if glyph_positions is NULL: return None cdef list positions = [] cdef GlyphPosition position cdef unsigned int i for i in range(count): position = GlyphPosition() position.set(glyph_positions[i]) positions.append(position) return positions @property def language(self) -> str: cdef const_char* cstr = hb_language_to_string( hb_buffer_get_language(self._hb_buffer)) if cstr is NULL: return None cdef bytes packed = cstr return packed.decode() @language.setter def language(self, value: str): cdef bytes packed = value.encode() cdef char* cstr = packed hb_buffer_set_language( self._hb_buffer, hb_language_from_string(cstr, -1)) @property def script(self) -> str: cdef char cstr[5] hb_tag_to_string(hb_buffer_get_script(self._hb_buffer), cstr) cstr[4] = b'\0' if cstr[0] == b'\0': return None cdef bytes packed = cstr return packed.decode() @script.setter def script(self, value: str): cdef bytes packed = value.encode() cdef char* cstr = packed # all the *_from_string calls should probably be checked and throw an # exception if invalid hb_buffer_set_script( self._hb_buffer, hb_script_from_string(cstr, -1)) @property def flags(self) -> BufferFlags: level = hb_buffer_get_flags(self._hb_buffer) return BufferFlags(level) @flags.setter def flags(self, value: BufferFlags): level = BufferFlags(value) hb_buffer_set_flags(self._hb_buffer, level) @property def cluster_level(self) -> BufferClusterLevel: level = hb_buffer_get_cluster_level(self._hb_buffer) return BufferClusterLevel(level) @cluster_level.setter def cluster_level(self, value: BufferClusterLevel): level = BufferClusterLevel(value) hb_buffer_set_cluster_level(self._hb_buffer, level) @property def content_type(self) -> BufferContentType: level = hb_buffer_get_content_type(self._hb_buffer) return BufferContentType(level) @content_type.setter def content_type(self, value: BufferContentType): level = BufferContentType(value) hb_buffer_set_content_type(self._hb_buffer, level) @property def replacement_codepoint(self) -> int: return hb_buffer_get_replacement_codepoint(self._hb_buffer) @replacement_codepoint.setter def replacement_codepoint(self, value: int): hb_buffer_set_replacement_codepoint(self._hb_buffer, value) @property def invisible_glyph(self) -> int: return hb_buffer_get_invisible_glyph(self._hb_buffer) @invisible_glyph.setter def invisible_glyph(self, value: int): hb_buffer_set_invisible_glyph(self._hb_buffer, value) @property def not_found_glyph(self) -> int: return hb_buffer_get_not_found_glyph(self._hb_buffer) @not_found_glyph.setter def not_found_glyph(self, value: int): hb_buffer_set_not_found_glyph(self._hb_buffer, value) def set_language_from_ot_tag(self, value: str): cdef bytes packed = value.encode() cdef char* cstr = packed hb_buffer_set_language( self._hb_buffer, hb_ot_tag_to_language(hb_tag_from_string(cstr, -1))) def set_script_from_ot_tag(self, value: str): cdef bytes packed = value.encode() cdef char* cstr = packed hb_buffer_set_script( self._hb_buffer, hb_ot_tag_to_script(hb_tag_from_string(cstr, -1))) def add_codepoints(self, codepoints: List[int], item_offset: int = 0, item_length: int = -1): cdef unsigned int size = len(codepoints) cdef hb_codepoint_t* hb_codepoints if not size: return hb_codepoints = malloc( size * sizeof(hb_codepoint_t)) for i in range(size): hb_codepoints[i] = codepoints[i] hb_buffer_add_codepoints( self._hb_buffer, hb_codepoints, size, item_offset, item_length) free(hb_codepoints) if not hb_buffer_allocation_successful(self._hb_buffer): raise MemoryError() def add_utf8(self, text: bytes, item_offset: int = 0, item_length: int = -1): hb_buffer_add_utf8( self._hb_buffer, text, len(text), item_offset, item_length) if not hb_buffer_allocation_successful(self._hb_buffer): raise MemoryError() def add_str(self, text: str, item_offset: int = 0, item_length: int = -1): cdef Py_UCS4* ucs4_buffer cdef Py_ssize_t text_length ucs4_buffer = PyUnicode_AsUCS4Copy(text) if ucs4_buffer == NULL: raise MemoryError() try: text_length = PyUnicode_GetLength(text) if text_length == -1: raise ValueError("Invalid Unicode string") hb_buffer_add_utf32( self._hb_buffer, ucs4_buffer, text_length, item_offset, item_length ) if not hb_buffer_allocation_successful(self._hb_buffer): raise MemoryError() finally: PyMem_Free(ucs4_buffer) def guess_segment_properties(self): hb_buffer_guess_segment_properties(self._hb_buffer) def set_message_func(self, callback: Callable[str]): self._message_callback = callback hb_buffer_set_message_func(self._hb_buffer, msgcallback, callback, NULL) def serialize(self, font: Font, format: BufferSerializeFormat = BufferSerializeFormat.TEXT, flags: BufferSerializeFlags = BufferSerializeFlags.DEFAULT) -> str: cdef unsigned int num_glyphs = hb_buffer_get_length(self._hb_buffer) cdef unsigned int start = 0 cdef char cstr[STATIC_ARRAY_SIZE] cdef unsigned int consumed cdef bytes packed = b"" while start < num_glyphs: start += hb_buffer_serialize( self._hb_buffer, start, num_glyphs, cstr, STATIC_ARRAY_SIZE, &consumed, font._hb_font, format, flags ) if consumed == 0: break packed += cstr[:consumed] return packed.decode() cdef class Blob: cdef hb_blob_t* _hb_blob def __cinit__(self, bytes data = None): if data is not None: self._hb_blob = hb_blob_create( data, len(data), HB_MEMORY_MODE_DUPLICATE, NULL, NULL) else: self._hb_blob = hb_blob_get_empty() @staticmethod cdef Blob from_ptr(hb_blob_t* hb_blob): """Create Blob from a pointer taking ownership of a it.""" cdef Blob wrapper = Blob.__new__(Blob) wrapper._hb_blob = hb_blob return wrapper @classmethod def from_file_path(cls, filename: Union[str, Path]) -> Blob: cdef bytes packed = os.fsencode(filename) cdef hb_blob_t* blob = hb_blob_create_from_file_or_fail(packed) if blob == NULL: raise HarfBuzzError(f"Failed to open: {filename}") cdef Blob inst = cls(None) inst._hb_blob = blob return inst def __dealloc__(self): hb_blob_destroy(self._hb_blob) def __len__(self) -> int: return hb_blob_get_length(self._hb_blob) def __bool__(self) -> bool: return len(self) > 0 @property def data(self) -> bytes: """Return the blob's data as bytes.""" if not self: return b"" cdef unsigned int blob_length cdef const_char* blob_data = hb_blob_get_data(self._hb_blob, &blob_length) return blob_data[:blob_length] class OTVarAxisFlags(IntFlag): HIDDEN = HB_OT_VAR_AXIS_FLAG_HIDDEN class OTVarAxisInfo(NamedTuple): axis_index: int tag: str name_id: int flags: OTVarAxisFlags min_value: float default_value: float max_value: float class OTVarNamedInstance(NamedTuple): subfamily_name_id: int postscript_name_id: int design_coords: List[float] class Color(NamedTuple): red: int green: int blue: int alpha: int def to_int(self) -> int: return HB_COLOR(self.blue, self.green, self.red, self.alpha) @staticmethod def from_int(value: int) -> Color: r = hb_color_get_red(value) g = hb_color_get_green(value) b = hb_color_get_blue(value) a = hb_color_get_alpha(value) return Color(r, g, b, a) class OTColor(Color): name_id: int | None class OTColorPaletteFlags(IntFlag): DEFAULT = HB_OT_COLOR_PALETTE_FLAG_DEFAULT USABLE_WITH_LIGHT_BACKGROUND = HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND USABLE_WITH_DARK_BACKGROUND = HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND class OTColorPalette(NamedTuple): colors: List[OTColor] name_id: int | None flags: OTColorPaletteFlags class OTColorLayer(NamedTuple): glyph: int color_index: int class OTLayoutGlyphClass(IntEnum): UNCLASSIFIED = HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED BASE_GLYPH = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH LIGATURE = HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE MARK = HB_OT_LAYOUT_GLYPH_CLASS_MARK COMPONENT = HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT cdef hb_user_data_key_t k cdef hb_blob_t* _reference_table_func( hb_face_t* face, hb_tag_t tag, void* user_data) noexcept: cdef Face py_face = (hb_face_get_user_data(face, &k)) # cdef char cstr[5] hb_tag_to_string(tag, cstr) cstr[4] = b'\0' cdef bytes packed = cstr # cdef bytes table = py_face._reference_table_func( py_face, packed.decode(), user_data) if table is None: return NULL return hb_blob_create( table, len(table), HB_MEMORY_MODE_READONLY, NULL, NULL) class OTNameIdPredefined(IntEnum): COPYRIGHT = HB_OT_NAME_ID_COPYRIGHT FONT_FAMILY = HB_OT_NAME_ID_FONT_FAMILY FONT_SUBFAMILY = HB_OT_NAME_ID_FONT_SUBFAMILY UNIQUE_ID = HB_OT_NAME_ID_UNIQUE_ID FULL_NAME = HB_OT_NAME_ID_FULL_NAME VERSION_STRING = HB_OT_NAME_ID_VERSION_STRING POSTSCRIPT_NAME = HB_OT_NAME_ID_POSTSCRIPT_NAME TRADEMARK = HB_OT_NAME_ID_TRADEMARK MANUFACTURER = HB_OT_NAME_ID_MANUFACTURER DESIGNER = HB_OT_NAME_ID_DESIGNER DESCRIPTION = HB_OT_NAME_ID_DESCRIPTION VENDOR_URL = HB_OT_NAME_ID_VENDOR_URL DESIGNER_URL = HB_OT_NAME_ID_DESIGNER_URL LICENSE = HB_OT_NAME_ID_LICENSE LICENSE_URL = HB_OT_NAME_ID_LICENSE_URL TYPOGRAPHIC_FAMILY = HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY TYPOGRAPHIC_SUBFAMILY = HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY MAC_FULL_NAME = HB_OT_NAME_ID_MAC_FULL_NAME SAMPLE_TEXT = HB_OT_NAME_ID_SAMPLE_TEXT CID_FINDFONT_NAME = HB_OT_NAME_ID_CID_FINDFONT_NAME WWS_FAMILY = HB_OT_NAME_ID_WWS_FAMILY WWS_SUBFAMILY = HB_OT_NAME_ID_WWS_SUBFAMILY LIGHT_BACKGROUND = HB_OT_NAME_ID_LIGHT_BACKGROUND DARK_BACKGROUND = HB_OT_NAME_ID_DARK_BACKGROUND VARIATIONS_PS_PREFIX = HB_OT_NAME_ID_VARIATIONS_PS_PREFIX INVALID = HB_OT_NAME_ID_INVALID class OTNameEntry(NamedTuple): name_id: OTNameIdPredefined | int language: str | None cdef class Face: cdef hb_face_t* _hb_face cdef object _reference_table_func cdef Blob _blob def __cinit__(self, blob: Union[Blob, bytes] = None, int index=0): if blob is not None: if not isinstance(blob, Blob): self._blob = Blob(blob) else: self._blob = blob self._hb_face = hb_face_create(self._blob._hb_blob, index) else: self._hb_face = hb_face_get_empty() self._blob = None def __dealloc__(self): hb_face_destroy(self._hb_face) self._blob = None @staticmethod cdef Face from_ptr(hb_face_t* hb_face): """Create Face from a pointer taking ownership of a it.""" cdef Face wrapper = Face.__new__(Face) wrapper._hb_face = hb_face return wrapper # DEPRECATED: use the normal constructor @classmethod def create(cls, blob: bytes, index: int = 0) -> Face: cdef Face inst = cls(blob, index) return inst @classmethod def create_for_tables(cls, func: Callable[[ Face, str, # tag object # user_data ], bytes], user_data: object) -> Face: cdef Face inst = cls(None) inst._hb_face = hb_face_create_for_tables( _reference_table_func, user_data, NULL) hb_face_set_user_data(inst._hb_face, &k, inst, NULL, 0) inst._reference_table_func = func return inst @property def count(self) -> int: return hb_face_count(self._blob._hb_blob) @property def index(self) -> int: return hb_face_get_index(self._hb_face) @index.setter def index(self, value: int): hb_face_set_index(self._hb_face, value) @property def upem(self) -> int: return hb_face_get_upem(self._hb_face) @upem.setter def upem(self, value: int): hb_face_set_upem(self._hb_face, value) @property def glyph_count(self) -> int: return hb_face_get_glyph_count(self._hb_face) @glyph_count.setter def glyph_count(self, value: int): hb_face_set_glyph_count(self._hb_face, value) @property def blob(self) -> Blob: cdef hb_blob_t* blob = hb_face_reference_blob(self._hb_face) if blob is NULL: raise MemoryError() return Blob.from_ptr(blob) def reference_table(self, tag: str) -> Blob: cdef bytes packed = tag.encode() cdef hb_tag_t hb_tag = hb_tag_from_string(packed, -1) cdef hb_blob_t* blob = hb_face_reference_table(self._hb_face, hb_tag) if blob is NULL: raise MemoryError() return Blob.from_ptr(blob) @property def table_tags(self) -> List[str]: cdef unsigned int tag_count = STATIC_ARRAY_SIZE cdef hb_tag_t tags_array[STATIC_ARRAY_SIZE] cdef list tags = [] cdef char cstr[5] cdef unsigned int i cdef unsigned int start_offset = 0 while tag_count == STATIC_ARRAY_SIZE: hb_face_get_table_tags( self._hb_face, start_offset, &tag_count, tags_array) for i in range(tag_count): hb_tag_to_string(tags_array[i], cstr) cstr[4] = b'\0' packed = cstr tags.append(packed.decode()) start_offset += tag_count return tags @property def unicodes (self) -> Set[int]: s = Set() hb_face_collect_unicodes(self._hb_face, s._hb_set) return s @property def variation_selectors(self) -> Set[int]: s = Set() hb_face_collect_variation_selectors(self._hb_face, s._hb_set) return s def variation_unicodes(self, variation_selector: int) -> Set[int]: s = Set() hb_face_collect_variation_unicodes(self._hb_face, variation_selector, s._hb_set) return s # variations @property def has_var_data(self) -> bool: return hb_ot_var_has_data(self._hb_face) @property def axis_infos(self) -> List[OTVarAxisInfo]: cdef unsigned int axis_count = STATIC_ARRAY_SIZE cdef hb_ot_var_axis_info_t axis_array[STATIC_ARRAY_SIZE] cdef list infos = [] cdef char cstr[5] cdef bytes packed cdef unsigned int i cdef unsigned int start_offset = 0 while axis_count == STATIC_ARRAY_SIZE: hb_ot_var_get_axis_infos( self._hb_face, start_offset, &axis_count, axis_array) for i in range(axis_count): hb_tag_to_string(axis_array[i].tag, cstr) cstr[4] = b'\0' packed = cstr infos.append( OTVarAxisInfo( axis_index=axis_array[i].axis_index, tag=packed.decode(), name_id=axis_array[i].name_id, flags=axis_array[i].flags, min_value=axis_array[i].min_value, default_value=axis_array[i].default_value, max_value=axis_array[i].max_value ) ) start_offset += axis_count return infos @property def named_instances(self) -> List[OTVarNamedInstance]: instances = [] cdef hb_face_t* face = self._hb_face cdef unsigned int instance_count = hb_ot_var_get_named_instance_count(face) cdef unsigned int axis_count = hb_ot_var_get_axis_count(face) cdef hb_ot_name_id_t subfamily_name_id cdef hb_ot_name_id_t postscript_name_id cdef float* coords = malloc(axis_count * sizeof(float)) cdef unsigned int coord_length for i in range(instance_count): coord_length = axis_count hb_ot_var_named_instance_get_design_coords(face, i, &coord_length, coords) instances.append( OTVarNamedInstance( subfamily_name_id=hb_ot_var_named_instance_get_subfamily_name_id(face, i), postscript_name_id=hb_ot_var_named_instance_get_postscript_name_id(face, i), design_coords=[coords[j] for j in range(coord_length)], ) ) free(coords) return instances # math @property def has_math_data(self) -> bool: return hb_ot_math_has_data(self._hb_face) def is_glyph_extended_math_shape(self, glyph: int) -> bool: return hb_ot_math_is_glyph_extended_shape(self._hb_face, glyph) # color @property def has_color_layers(self) -> bool: return hb_ot_color_has_layers(self._hb_face) def get_glyph_color_layers(self, glyph: int) -> List[OTColorLayer]: cdef list ret = [] cdef unsigned int i cdef unsigned int start_offset = 0 cdef unsigned int layer_count = STATIC_ARRAY_SIZE cdef hb_ot_color_layer_t layers[STATIC_ARRAY_SIZE] while layer_count == STATIC_ARRAY_SIZE: hb_ot_color_glyph_get_layers(self._hb_face, glyph, start_offset, &layer_count, layers) for i in range(layer_count): ret.append(OTColorLayer(layers[i].glyph, layers[i].color_index)) start_offset += layer_count return ret @property def has_color_palettes(self) -> bool: return hb_ot_color_has_palettes(self._hb_face) def get_color_palette(self, palette_index: int) -> OTColorPalette: cdef hb_face_t* face = self._hb_face cdef list colors = [] cdef unsigned int i cdef unsigned int start_offset = 0 cdef unsigned int color_count = STATIC_ARRAY_SIZE cdef hb_color_t c_colors[STATIC_ARRAY_SIZE] while color_count == STATIC_ARRAY_SIZE: hb_ot_color_palette_get_colors(face, palette_index, start_offset, &color_count, c_colors) for i in range(color_count): colors.append(Color.from_int(c_colors[i])) return OTColorPalette( colors=colors, name_id=hb_ot_color_palette_get_name_id(face, palette_index), flags=OTColorPaletteFlags(hb_ot_color_palette_get_flags(face, palette_index)) ) @property def color_palettes(self) -> List[OTColorPalette]: cdef list palettes = [] cdef unsigned int palette_count = hb_ot_color_palette_get_count(self._hb_face) for i in range(palette_count): palettes.append(self.get_color_palette(i)) return palettes def color_palette_color_get_name_id(self, color_index: int) -> int | None: cdef hb_ot_name_id_t name_id name_id = hb_ot_color_palette_color_get_name_id(self._hb_face, color_index) if name_id == HB_OT_NAME_ID_INVALID: return None return name_id @property def has_color_paint(self) -> bool: return hb_ot_color_has_paint(self._hb_face) def glyph_has_color_paint(self, glyph: int) -> bool: return hb_ot_color_glyph_has_paint(self._hb_face, glyph) @property def has_color_svg(self) -> bool: return hb_ot_color_has_svg(self._hb_face) def get_glyph_color_svg(self, glyph: int) -> Blob: cdef hb_blob_t* blob blob = hb_ot_color_glyph_reference_svg(self._hb_face, glyph) return Blob.from_ptr(blob) @property def has_color_png(self) -> bool: return hb_ot_color_has_png(self._hb_face) # layout @property def has_layout_glyph_classes(self) -> bool: return hb_ot_layout_has_glyph_classes(self._hb_face) def get_layout_glyph_class(self, glyph: int) -> OTLayoutGlyphClass: return OTLayoutGlyphClass(hb_ot_layout_get_glyph_class(self._hb_face, glyph)) @property def has_layout_positioning(self) -> bool: return hb_ot_layout_has_positioning(self._hb_face) @property def has_layout_substitution(self) -> bool: return hb_ot_layout_has_substitution(self._hb_face) def get_lookup_glyph_alternates(self, lookup_index: int, glyph: int) -> List[int]: cdef list alternates = [] cdef unsigned int i cdef unsigned int start_offset = 0 cdef unsigned int alternate_count = STATIC_ARRAY_SIZE cdef hb_codepoint_t c_alternates[STATIC_ARRAY_SIZE] while alternate_count == STATIC_ARRAY_SIZE: hb_ot_layout_lookup_get_glyph_alternates(self._hb_face, lookup_index, glyph, start_offset, &alternate_count, c_alternates) for i in range(alternate_count): alternates.append(c_alternates[i]) start_offset += alternate_count return alternates def get_language_feature_tags(self, tag: str, script_index: int = 0, language_index: int = 0xFFFF) -> List[str]: cdef bytes packed = tag.encode() cdef hb_tag_t hb_tag = hb_tag_from_string(packed, -1) cdef unsigned int feature_count = STATIC_ARRAY_SIZE cdef hb_tag_t c_tags[STATIC_ARRAY_SIZE] cdef list tags = [] cdef char cstr[5] cdef unsigned int i cdef unsigned int start_offset = 0 while feature_count == STATIC_ARRAY_SIZE: hb_ot_layout_language_get_feature_tags( self._hb_face, hb_tag, script_index, language_index, start_offset, &feature_count, c_tags) for i in range(feature_count): hb_tag_to_string(c_tags[i], cstr) cstr[4] = b'\0' packed = cstr tags.append(packed.decode()) start_offset += feature_count return tags def get_script_language_tags(self, tag: str, script_index: int = 0) -> List[str]: cdef bytes packed = tag.encode() cdef hb_tag_t hb_tag = hb_tag_from_string(packed, -1) cdef unsigned int language_count = STATIC_ARRAY_SIZE cdef hb_tag_t c_tags[STATIC_ARRAY_SIZE] cdef list tags = [] cdef char cstr[5] cdef unsigned int i cdef unsigned int start_offset = 0 while language_count == STATIC_ARRAY_SIZE: hb_ot_layout_script_get_language_tags( self._hb_face, hb_tag, script_index, start_offset, &language_count, c_tags) for i in range(language_count): hb_tag_to_string(c_tags[i], cstr) cstr[4] = b'\0' packed = cstr tags.append(packed.decode()) start_offset += language_count return tags def get_table_script_tags(self, tag: str) -> List[str]: cdef bytes packed = tag.encode() cdef hb_tag_t hb_tag = hb_tag_from_string(packed, -1) cdef unsigned int script_count = STATIC_ARRAY_SIZE cdef hb_tag_t c_tags[STATIC_ARRAY_SIZE] cdef list tags = [] cdef char cstr[5] cdef unsigned int i cdef unsigned int start_offset = 0 while script_count == STATIC_ARRAY_SIZE: hb_ot_layout_table_get_script_tags( self._hb_face, hb_tag, start_offset, &script_count, c_tags) for i in range(script_count): hb_tag_to_string(c_tags[i], cstr) cstr[4] = b'\0' packed = cstr tags.append(packed.decode()) start_offset += script_count return tags def list_names(self) -> List[OTNameEntry]: cdef list ret = [] cdef unsigned int num_entries cdef const hb_ot_name_entry_t* entries cdef unsigned int i cdef const_char *cstr cdef bytes packed entries = hb_ot_name_list_names(self._hb_face, &num_entries) for i in range(num_entries): cstr = hb_language_to_string(entries[i].language) if cstr is NULL: language = None else: packed = cstr language = packed.decode() if entries[i].name_id in iter(OTNameIdPredefined): name_id = OTNameIdPredefined(entries[i].name_id) else: name_id = entries[i].name_id ret.append(OTNameEntry(name_id=name_id, language=language)) return ret def get_name(self, name_id: OTNameIdPredefined | int, language: str | None = None) -> str | None: cdef bytes packed cdef hb_language_t lang cdef char *text cdef unsigned int length if language is None: lang = 0 # HB_LANGUAGE_INVALID else: packed = language.encode() lang = hb_language_from_string(packed, -1) length = hb_ot_name_get_utf8(self._hb_face, name_id, lang, NULL, NULL) if length: length += 1 # for the null terminator text = malloc(length * sizeof(char)) if text == NULL: raise MemoryError() try: hb_ot_name_get_utf8(self._hb_face, name_id, lang, &length, text) result = text[:length].decode("utf-8") return result finally: free(text) return None class GlyphExtents(NamedTuple): x_bearing: int y_bearing: int width: int height: int class FontExtents(NamedTuple): ascender: int descender: int line_gap: int class OTMathConstant(IntEnum): SCRIPT_PERCENT_SCALE_DOWN = HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN SCRIPT_SCRIPT_PERCENT_SCALE_DOWN = HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN DELIMITED_SUB_FORMULA_MIN_HEIGHT = HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT DISPLAY_OPERATOR_MIN_HEIGHT = HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT MATH_LEADING = HB_OT_MATH_CONSTANT_MATH_LEADING AXIS_HEIGHT = HB_OT_MATH_CONSTANT_AXIS_HEIGHT ACCENT_BASE_HEIGHT = HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT FLATTENED_ACCENT_BASE_HEIGHT = HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT SUBSCRIPT_SHIFT_DOWN = HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN SUBSCRIPT_TOP_MAX = HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX SUBSCRIPT_BASELINE_DROP_MIN = HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN SUPERSCRIPT_SHIFT_UP = HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP SUPERSCRIPT_SHIFT_UP_CRAMPED = HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED SUPERSCRIPT_BOTTOM_MIN = HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN SUPERSCRIPT_BASELINE_DROP_MAX = HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX SUB_SUPERSCRIPT_GAP_MIN = HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT = HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT SPACE_AFTER_SCRIPT = HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT UPPER_LIMIT_GAP_MIN = HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN UPPER_LIMIT_BASELINE_RISE_MIN = HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN LOWER_LIMIT_GAP_MIN = HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN LOWER_LIMIT_BASELINE_DROP_MIN = HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN STACK_TOP_SHIFT_UP = HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP STACK_TOP_DISPLAY_STYLE_SHIFT_UP = HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP STACK_BOTTOM_SHIFT_DOWN = HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN = HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN STACK_GAP_MIN = HB_OT_MATH_CONSTANT_STACK_GAP_MIN STACK_DISPLAY_STYLE_GAP_MIN = HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN STRETCH_STACK_TOP_SHIFT_UP = HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP STRETCH_STACK_BOTTOM_SHIFT_DOWN = HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN STRETCH_STACK_GAP_ABOVE_MIN = HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN STRETCH_STACK_GAP_BELOW_MIN = HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN FRACTION_NUMERATOR_SHIFT_UP = HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP = HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP FRACTION_DENOMINATOR_SHIFT_DOWN = HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN = HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN FRACTION_NUMERATOR_GAP_MIN = HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN FRACTION_NUM_DISPLAY_STYLE_GAP_MIN = HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN FRACTION_RULE_THICKNESS = HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS FRACTION_DENOMINATOR_GAP_MIN = HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN = HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN SKEWED_FRACTION_HORIZONTAL_GAP = HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP SKEWED_FRACTION_VERTICAL_GAP = HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP OVERBAR_VERTICAL_GAP = HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP OVERBAR_RULE_THICKNESS = HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS OVERBAR_EXTRA_ASCENDER = HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER UNDERBAR_VERTICAL_GAP = HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP UNDERBAR_RULE_THICKNESS = HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS UNDERBAR_EXTRA_DESCENDER = HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER RADICAL_VERTICAL_GAP = HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP RADICAL_DISPLAY_STYLE_VERTICAL_GAP = HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP RADICAL_RULE_THICKNESS = HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS RADICAL_EXTRA_ASCENDER = HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER RADICAL_KERN_BEFORE_DEGREE = HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE RADICAL_KERN_AFTER_DEGREE = HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE RADICAL_DEGREE_BOTTOM_RAISE_PERCENT = HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT class OTMathKernEntry(NamedTuple): max_correction_height: int kern_value: int class OTMathKern(IntEnum): TOP_RIGHT = HB_OT_MATH_KERN_TOP_RIGHT TOP_LEFT = HB_OT_MATH_KERN_TOP_LEFT BOTTOM_RIGHT = HB_OT_MATH_KERN_BOTTOM_RIGHT BOTTOM_LEFT = HB_OT_MATH_KERN_BOTTOM_LEFT class OTMathGlyphVariant(NamedTuple): glyph: int advance: int class OTMathGlyphPartFlags(IntFlag): EXTENDER = HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER class OTMathGlyphPart(NamedTuple): glyph: int start_connector_length: int end_connector_length: int full_advance: int flags: OTMathGlyphPartFlags class OTMetricsTag(IntEnum): HORIZONTAL_ASCENDER = HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER HORIZONTAL_DESCENDER = HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER HORIZONTAL_LINE_GAP = HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP HORIZONTAL_CLIPPING_ASCENT = HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT HORIZONTAL_CLIPPING_DESCENT = HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT VERTICAL_ASCENDER = HB_OT_METRICS_TAG_VERTICAL_ASCENDER VERTICAL_DESCENDER = HB_OT_METRICS_TAG_VERTICAL_DESCENDER VERTICAL_LINE_GAP = HB_OT_METRICS_TAG_VERTICAL_LINE_GAP HORIZONTAL_CARET_RISE = HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE HORIZONTAL_CARET_RUN = HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN HORIZONTAL_CARET_OFFSET = HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET VERTICAL_CARET_RISE = HB_OT_METRICS_TAG_VERTICAL_CARET_RISE VERTICAL_CARET_RUN = HB_OT_METRICS_TAG_VERTICAL_CARET_RUN VERTICAL_CARET_OFFSET = HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET X_HEIGHT = HB_OT_METRICS_TAG_X_HEIGHT CAP_HEIGHT = HB_OT_METRICS_TAG_CAP_HEIGHT SUBSCRIPT_EM_X_SIZE = HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE SUBSCRIPT_EM_Y_SIZE = HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE SUBSCRIPT_EM_X_OFFSET = HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET SUBSCRIPT_EM_Y_OFFSET = HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET SUPERSCRIPT_EM_X_SIZE = HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE SUPERSCRIPT_EM_Y_SIZE = HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE SUPERSCRIPT_EM_X_OFFSET = HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET SUPERSCRIPT_EM_Y_OFFSET = HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET STRIKEOUT_SIZE = HB_OT_METRICS_TAG_STRIKEOUT_SIZE STRIKEOUT_OFFSET = HB_OT_METRICS_TAG_STRIKEOUT_OFFSET UNDERLINE_SIZE = HB_OT_METRICS_TAG_UNDERLINE_SIZE UNDERLINE_OFFSET = HB_OT_METRICS_TAG_UNDERLINE_OFFSET class StyleTag(IntEnum): ITALIC = HB_STYLE_TAG_ITALIC OPTICAL_SIZE = HB_STYLE_TAG_OPTICAL_SIZE SLANT_ANGLE = HB_STYLE_TAG_SLANT_ANGLE SLANT_RATIO = HB_STYLE_TAG_SLANT_RATIO WIDTH = HB_STYLE_TAG_WIDTH WEIGHT = HB_STYLE_TAG_WEIGHT cdef class Font: cdef hb_font_t* _hb_font # GC bookkeeping cdef Face _face cdef FontFuncs _ffuncs def __cinit__(self, face_or_font: Union[Face, Font] = None): if face_or_font is not None: if isinstance(face_or_font, Font): self.__create_sub_font(face_or_font) return self.__create(face_or_font) else: self._hb_font = hb_font_get_empty() self._face = Face() cdef __create(self, Face face): self._hb_font = hb_font_create(face._hb_face) self._face = face cdef __create_sub_font(self, Font font): self._hb_font = hb_font_create_sub_font(font._hb_font) self._face = font._face def __dealloc__(self): hb_font_destroy(self._hb_font) self._face = self._ffuncs = None @staticmethod cdef Font from_ptr(hb_font_t* hb_font): """Create Font from a pointer taking ownership of a it.""" cdef Font wrapper = Font.__new__(Font) wrapper._hb_font = hb_font wrapper._face = Face.from_ptr(hb_face_reference(hb_font_get_face(hb_font))) return wrapper # DEPRECATED: use the normal constructor @classmethod def create(cls, face: Face) -> Font: cdef Font inst = cls(face) return inst @property def face(self) -> Face: return self._face @property def funcs(self) -> FontFuncs: return self._ffuncs @funcs.setter def funcs(self, ffuncs: FontFuncs): hb_font_set_funcs( self._hb_font, ffuncs._hb_ffuncs, self, NULL) self._ffuncs = ffuncs @property def scale(self) -> Tuple[int, int]: cdef int x, y hb_font_get_scale(self._hb_font, &x, &y) return (x, y) @scale.setter def scale(self, value: Tuple[int, int]): x, y = value hb_font_set_scale(self._hb_font, x, y) @property def ppem(self) -> Tuple[int, int]: cdef unsigned int x, y hb_font_get_ppem(self._hb_font, &x, &y) return (x, y) @ppem.setter def ppem(self, value: Tuple[int, int]): x, y = value hb_font_set_ppem(self._hb_font, x, y) @property def ptem(self) -> float: return hb_font_get_ptem(self._hb_font) @ptem.setter def ptem(self, value: float): hb_font_set_ptem(self._hb_font, value) @property def synthetic_slant(self) -> float: return hb_font_get_synthetic_slant(self._hb_font) @synthetic_slant.setter def synthetic_slant(self, value: float): hb_font_set_synthetic_slant(self._hb_font, value) @property def synthetic_bold(self) -> Tuple[float, float, bool]: cdef float x_embolden cdef float y_embolden cdef hb_bool_t in_place hb_font_get_synthetic_bold(self._hb_font, &x_embolden, &y_embolden, &in_place) return (x_embolden, y_embolden, bool(in_place)) @synthetic_bold.setter def synthetic_bold(self, value: float|tuple[float]|tuple[float,float]|tuple[float,float,bool]): cdef float x_embolden cdef float y_embolden cdef hb_bool_t in_place = False if isinstance(value, tuple): if len(value) == 1: x_embolden = y_embolden = value[0] elif len(value) == 2: x_embolden, y_embolden = value else: x_embolden, y_embolden, in_place = value else: x_embolden = y_embolden = value hb_font_set_synthetic_bold(self._hb_font, x_embolden, y_embolden, in_place) @property def var_named_instance(self) -> int: return hb_font_get_var_named_instance(self._hb_font) @var_named_instance.setter def var_named_instance(self, value: int): hb_font_set_var_named_instance(self._hb_font, value) def set_variations(self, variations: Dict[str, float]): cdef unsigned int size cdef hb_variation_t* hb_variations cdef bytes packed cdef hb_variation_t variation size = len(variations) hb_variations = malloc(size * sizeof(hb_variation_t)) if not hb_variations: raise MemoryError() try: for i, (name, value) in enumerate(variations.items()): packed = name.encode() variation.tag = hb_tag_from_string(packed, -1) variation.value = value hb_variations[i] = variation hb_font_set_variations(self._hb_font, hb_variations, size) finally: free(hb_variations) def set_variation(self, name: str, value: float): packed = name.encode() cdef hb_tag_t tag = hb_tag_from_string(packed, -1) hb_font_set_variation(self._hb_font, tag, value) def get_glyph_name(self, gid: int) -> str | None: cdef char name[64] cdef bytes packed success = hb_font_get_glyph_name(self._hb_font, gid, name, 64) if success: packed = name return packed.decode() else: return None def get_glyph_from_name(self, name: str) -> int | None: cdef hb_codepoint_t gid cdef bytes packed packed = name.encode() success = hb_font_get_glyph_from_name(self._hb_font, packed, len(packed), &gid) return gid if success else None def get_glyph_extents(self, gid: int) -> GlyphExtents: cdef hb_glyph_extents_t extents success = hb_font_get_glyph_extents(self._hb_font, gid, &extents) if success: return GlyphExtents( extents.x_bearing, extents.y_bearing, extents.width, extents.height, ) else: return None def get_glyph_h_advance(self, gid: int) -> int: return hb_font_get_glyph_h_advance(self._hb_font, gid) def get_glyph_v_advance(self, gid: int) -> int: return hb_font_get_glyph_v_advance(self._hb_font, gid) def get_glyph_h_origin(self, gid: int) -> Tuple[int, int] | None: cdef hb_position_t x, y success = hb_font_get_glyph_h_origin(self._hb_font, gid, &x, &y) return (x, y) if success else None def get_glyph_v_origin(self, gid: int) -> Tuple[int, int] | None: cdef hb_position_t x, y success = hb_font_get_glyph_v_origin(self._hb_font, gid, &x, &y) return (x, y) if success else None def get_font_extents(self, direction: str) -> FontExtents: cdef hb_font_extents_t extents cdef hb_direction_t hb_direction cdef bytes packed packed = direction.encode() hb_direction = hb_direction_from_string(packed, -1) hb_font_get_extents_for_direction( self._hb_font, hb_direction, &extents ) return FontExtents( extents.ascender, extents.descender, extents.line_gap ) def get_variation_glyph(self, unicode: int, variation_selector: int) -> int | None: cdef hb_codepoint_t gid success = hb_font_get_variation_glyph(self._hb_font, unicode, variation_selector, &gid) return gid if success else None def get_nominal_glyph(self, unicode: int) -> int: cdef hb_codepoint_t gid success = hb_font_get_nominal_glyph(self._hb_font, unicode, &gid) return gid if success else None def get_var_coords_normalized(self) -> List[float]: cdef unsigned int length cdef const int *coords coords = hb_font_get_var_coords_normalized(self._hb_font, &length) # Convert from 2.14 fixed to float: divide by 1 << 14 return [coords[i] / 0x4000 for i in range(length)] def set_var_coords_normalized(self, coords: List[float]): cdef unsigned int length cdef int *coords_2dot14 length = len(coords) coords_2dot14 = malloc(length * sizeof(int)) if coords_2dot14 is NULL: raise MemoryError() try: for i in range(length): # Convert from float to 2.14 fixed: multiply by 1 << 14 coords_2dot14[i] = round(coords[i] * 0x4000) hb_font_set_var_coords_normalized(self._hb_font, coords_2dot14, length) finally: free(coords_2dot14) def get_var_coords_design(self): cdef unsigned int length cdef const float *coords coords = hb_font_get_var_coords_design(self._hb_font, &length) return [coords[i] for i in range(length)] def set_var_coords_design(self, coords: List[float]): cdef unsigned int length cdef cython.float *c_coords length = len(coords) c_coords = malloc(length * sizeof(cython.float)) if c_coords is NULL: raise MemoryError() try: for i in range(length): c_coords[i] = coords[i] hb_font_set_var_coords_design(self._hb_font, c_coords, length) finally: free(c_coords) def glyph_to_string(self, gid: int) -> str: cdef char name[64] cdef bytes packed hb_font_glyph_to_string(self._hb_font, gid, name, 64) packed = name return packed.decode() def glyph_from_string(self, string: str) -> int: cdef hb_codepoint_t gid cdef bytes packed packed = string.encode() success = hb_font_glyph_from_string(self._hb_font, packed, len(packed), &gid) return gid if success else None def draw_glyph(self, gid: int, draw_funcs: DrawFuncs, draw_state: object = None): cdef void *draw_state_p = draw_state if PyCapsule_IsValid(draw_state, NULL): draw_state_p = PyCapsule_GetPointer(draw_state, NULL) hb_font_draw_glyph(self._hb_font, gid, draw_funcs._hb_drawfuncs, draw_state_p); def paint_glyph(self, gid: int, paint_funcs: PaintFuncs, paint_state: object = None, palette_index: int = 0, foreground: Color | None = None): cdef void *paint_state_p = paint_state cdef hb_color_t c_foreground = 0x000000FF if foreground is not None: c_foreground = foreground.to_int() hb_font_paint_glyph(self._hb_font, gid, paint_funcs._hb_paintfuncs, paint_state_p, palette_index, c_foreground) def draw_glyph_with_pen(self, gid: int, pen): global drawfuncs if drawfuncs == NULL: drawfuncs = hb_draw_funcs_create() hb_draw_funcs_set_move_to_func(drawfuncs, _pen_move_to_func, NULL, NULL) hb_draw_funcs_set_line_to_func(drawfuncs, _pen_line_to_func, NULL, NULL) hb_draw_funcs_set_cubic_to_func(drawfuncs, _pen_cubic_to_func, NULL, NULL) hb_draw_funcs_set_quadratic_to_func(drawfuncs, _pen_quadratic_to_func, NULL, NULL) hb_draw_funcs_set_close_path_func(drawfuncs, _pen_close_path_func, NULL, NULL) # Keep local copy so they are not GC'ed before the call completes moveTo = pen.moveTo lineTo = pen.lineTo curveTo = pen.curveTo qCurveTo = pen.qCurveTo closePath = pen.closePath cdef _pen_methods methods methods.moveTo = moveTo methods.lineTo = lineTo methods.curveTo = curveTo methods.qCurveTo = qCurveTo methods.closePath = closePath hb_font_draw_glyph(self._hb_font, gid, drawfuncs, &methods) # math def get_math_constant(self, constant: OTMathConstant) -> int: if constant >= len(OTMathConstant): raise ValueError("invalid constant") return hb_ot_math_get_constant(self._hb_font, constant) def get_math_glyph_italics_correction(self, glyph: int) -> int: return hb_ot_math_get_glyph_italics_correction(self._hb_font, glyph) def get_math_glyph_top_accent_attachment(self, glyph: int) -> int: return hb_ot_math_get_glyph_top_accent_attachment(self._hb_font, glyph) def get_math_min_connector_overlap(self, direction: str) -> int: cdef bytes packed = direction.encode() cdef char* cstr = packed cdef hb_direction_t hb_direction = hb_direction_from_string(cstr, -1) return hb_ot_math_get_min_connector_overlap(self._hb_font, hb_direction) def get_math_glyph_kerning(self, glyph: int, kern: OTMathKern, correction_height: int) -> int: if kern >= len(OTMathKern): raise ValueError("invalid kern") return hb_ot_math_get_glyph_kerning(self._hb_font, glyph, kern, correction_height) def get_math_glyph_kernings(self, glyph: int, kern: OTMathKern) -> List[OTMathKernEntry]: if kern >= len(OTMathKern): raise ValueError("invalid kern") cdef unsigned int count = STATIC_ARRAY_SIZE cdef hb_ot_math_kern_entry_t kerns_array[STATIC_ARRAY_SIZE] cdef list kerns = [] cdef unsigned int i cdef unsigned int start_offset = 0 while count == STATIC_ARRAY_SIZE: hb_ot_math_get_glyph_kernings(self._hb_font, glyph, kern, start_offset, &count, kerns_array) for i in range(count): kerns.append(OTMathKernEntry(kerns_array[i].max_correction_height, kerns_array[i].kern_value)) start_offset += count return kerns def get_math_glyph_variants(self, glyph: int, direction: str) -> List[OTMathGlyphVariant]: cdef bytes packed = direction.encode() cdef char* cstr = packed cdef hb_direction_t hb_direction = hb_direction_from_string(cstr, -1) cdef unsigned int count = STATIC_ARRAY_SIZE cdef hb_ot_math_glyph_variant_t variants_array[STATIC_ARRAY_SIZE] cdef list variants = [] cdef unsigned int i cdef unsigned int start_offset = 0 while count == STATIC_ARRAY_SIZE: hb_ot_math_get_glyph_variants(self._hb_font, glyph, hb_direction, start_offset, &count, variants_array) for i in range(count): variants.append(OTMathGlyphVariant(variants_array[i].glyph, variants_array[i].advance)) start_offset += count return variants def get_math_glyph_assembly(self, glyph: int, direction: str) -> Tuple[List[OTMathGlyphPart], int]: cdef bytes packed = direction.encode() cdef char* cstr = packed cdef hb_direction_t hb_direction = hb_direction_from_string(cstr, -1) cdef unsigned int count = STATIC_ARRAY_SIZE cdef hb_ot_math_glyph_part_t assembly_array[STATIC_ARRAY_SIZE] cdef list assembly = [] cdef unsigned int i cdef unsigned int start_offset = 0 cdef hb_position_t italics_correction = 0 while count == STATIC_ARRAY_SIZE: hb_ot_math_get_glyph_assembly(self._hb_font, glyph, hb_direction, start_offset, &count, assembly_array, &italics_correction) for i in range(count): assembly.append( OTMathGlyphPart(assembly_array[i].glyph, assembly_array[i].start_connector_length, assembly_array[i].end_connector_length, assembly_array[i].full_advance, OTMathGlyphPartFlags(assembly_array[i].flags))) start_offset += count return assembly, italics_correction # metrics def get_metric_position(self, tag: OTMetricsTag) -> int: cdef hb_position_t position if hb_ot_metrics_get_position(self._hb_font, tag, &position): return position return None def get_metric_position_with_fallback(font, tag: OTMetricsTag) -> int: cdef hb_position_t position hb_ot_metrics_get_position_with_fallback(font._hb_font, tag, &position) return position def get_metric_variation(self, tag: OTMetricsTag) -> float: return hb_ot_metrics_get_variation(self._hb_font, tag) def get_metric_x_variation(self, tag: OTMetricsTag) -> int: return hb_ot_metrics_get_x_variation(self._hb_font, tag) def get_metric_y_variation(self, tag: OTMetricsTag) -> int: return hb_ot_metrics_get_y_variation(self._hb_font, tag) # color def get_glyph_color_png(self, glyph: int) -> Blob: cdef hb_blob_t* blob blob = hb_ot_color_glyph_reference_png(self._hb_font, glyph) return Blob.from_ptr(blob) #layout def get_layout_baseline(self, baseline_tag: str, direction: str, script_tag: str, language_tag: str) -> int: cdef hb_ot_layout_baseline_tag_t hb_baseline_tag cdef hb_direction_t hb_direction cdef hb_tag_t hb_script_tag cdef hb_tag_t hb_language_tag cdef hb_position_t hb_position cdef hb_bool_t success cdef bytes packed if baseline_tag == "romn": hb_baseline_tag = HB_OT_LAYOUT_BASELINE_TAG_ROMAN elif baseline_tag == "hang": hb_baseline_tag = HB_OT_LAYOUT_BASELINE_TAG_HANGING elif baseline_tag == "icfb": hb_baseline_tag = HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT elif baseline_tag == "icft": hb_baseline_tag = HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT elif baseline_tag == "ideo": hb_baseline_tag = HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT elif baseline_tag == "idtp": hb_baseline_tag = HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT elif baseline_tag == "math": hb_baseline_tag = HB_OT_LAYOUT_BASELINE_TAG_MATH else: raise ValueError(f"invalid baseline tag '{baseline_tag}'") packed = direction.encode() hb_direction = hb_direction_from_string(packed, -1) packed = script_tag.encode() hb_script_tag = hb_tag_from_string(packed, -1) packed = language_tag.encode() hb_language_tag = hb_tag_from_string(packed, -1) success = hb_ot_layout_get_baseline(self._hb_font, hb_baseline_tag, hb_direction, hb_script_tag, hb_language_tag, &hb_position) if success: return hb_position else: return None # style def get_style_value(self, tag: StyleTag) -> float: return hb_style_get_value(self._hb_font, tag) cdef struct _pen_methods: void *moveTo void *lineTo void *curveTo void *qCurveTo void *closePath cdef hb_draw_funcs_t* drawfuncs = NULL cdef void _pen_move_to_func(hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, float to_x, float to_y, void *user_data) noexcept: (((<_pen_methods*>draw_data).moveTo))((to_x, to_y)) cdef void _pen_line_to_func(hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, float to_x, float to_y, void *user_data) noexcept: (((<_pen_methods*>draw_data).lineTo))((to_x, to_y)) cdef void _pen_close_path_func(hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, void *user_data) noexcept: (((<_pen_methods*>draw_data).closePath))() cdef void _pen_quadratic_to_func(hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, float c1_x, float c1_y, float to_x, float to_y, void *user_data) noexcept: (((<_pen_methods*>draw_data).qCurveTo))((c1_x, c1_y), (to_x, to_y)) cdef void _pen_cubic_to_func(hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, float c1_x, float c1_y, float c2_x, float c2_y, float to_x, float to_y, void *user_data) noexcept: (((<_pen_methods*>draw_data).curveTo))((c1_x, c1_y), (c2_x, c2_y), (to_x, to_y)) cdef hb_position_t _glyph_h_advance_func(hb_font_t* font, void* font_data, hb_codepoint_t glyph, void* user_data) noexcept: cdef Font py_font = font_data return (py_font.funcs)._glyph_h_advance_func( py_font, glyph, user_data) cdef hb_position_t _glyph_v_advance_func(hb_font_t* font, void* font_data, hb_codepoint_t glyph, void* user_data) noexcept: cdef Font py_font = font_data return (py_font.funcs)._glyph_v_advance_func( py_font, glyph, user_data) cdef hb_bool_t _glyph_v_origin_func(hb_font_t* font, void* font_data, hb_codepoint_t glyph, hb_position_t* x, hb_position_t* y, void* user_data) noexcept: cdef Font py_font = font_data cdef hb_bool_t success cdef hb_position_t px cdef hb_position_t py success, px, py = (py_font.funcs)._glyph_v_origin_func( py_font, glyph, user_data) x[0] = px y[0] = py return success cdef hb_bool_t _glyph_name_func(hb_font_t *font, void *font_data, hb_codepoint_t glyph, char *name, unsigned int size, void *user_data) noexcept: cdef Font py_font = font_data cdef bytes ret = (py_font.funcs)._glyph_name_func( py_font, glyph, user_data).encode() name[0] = ret return 1 cdef hb_bool_t _nominal_glyph_func(hb_font_t* font, void* font_data, hb_codepoint_t unicode, hb_codepoint_t* glyph, void* user_data) noexcept: cdef Font py_font = font_data glyph[0] = (py_font.funcs)._nominal_glyph_func( py_font, unicode, user_data) # If the glyph is .notdef, return false, else return true return int(glyph[0] != 0) cdef hb_bool_t _variation_glyph_func(hb_font_t* font, void* font_data, hb_codepoint_t unicode, hb_codepoint_t variation_selector, hb_codepoint_t* glyph, void* user_data) noexcept: cdef Font py_font = font_data glyph[0] = (py_font.funcs)._variation_glyph_func( py_font, unicode, variation_selector, user_data) # If the glyph is .notdef, return false, else return true return int(glyph[0] != 0) cdef hb_bool_t _font_h_extents_func(hb_font_t* font, void* font_data, hb_font_extents_t *extents, void* user_data) noexcept: cdef Font py_font = font_data font_extents = (py_font.funcs)._font_h_extents_func( py_font, user_data) if font_extents is not None: if font_extents.ascender is not None: extents.ascender = font_extents.ascender if font_extents.descender is not None: extents.descender = font_extents.descender if font_extents.line_gap is not None: extents.line_gap = font_extents.line_gap return 1 return 0 cdef hb_bool_t _font_v_extents_func(hb_font_t* font, void* font_data, hb_font_extents_t *extents, void* user_data) noexcept: cdef Font py_font = font_data font_extents = (py_font.funcs)._font_v_extents_func( py_font, user_data) if font_extents is not None: if font_extents.ascender is not None: extents.ascender = font_extents.ascender if font_extents.descender is not None: extents.descender = font_extents.descender if font_extents.line_gap is not None: extents.line_gap = font_extents.line_gap return 1 return 0 cdef class FontFuncs: cdef hb_font_funcs_t* _hb_ffuncs cdef object _glyph_h_advance_func cdef object _glyph_v_advance_func cdef object _glyph_v_origin_func cdef object _glyph_name_func cdef object _nominal_glyph_func cdef object _variation_glyph_func cdef object _font_h_extents_func cdef object _font_v_extents_func def __cinit__(self): self._hb_ffuncs = hb_font_funcs_create() def __dealloc__(self): hb_font_funcs_destroy(self._hb_ffuncs) # DEPRECATED: use the normal constructor @classmethod def create(cls) -> FontFuncs: cdef FontFuncs inst = cls() return inst def set_glyph_h_advance_func(self, func: Callable[[ Font, int, # gid object, # user_data ], int], # h_advance user_data: object = None): hb_font_funcs_set_glyph_h_advance_func( self._hb_ffuncs, _glyph_h_advance_func, user_data, NULL) self._glyph_h_advance_func = func def set_glyph_v_advance_func(self, func: Callable[[ Font, int, # gid object, # user_data ], int], # v_advance user_data: object = None): hb_font_funcs_set_glyph_v_advance_func( self._hb_ffuncs, _glyph_v_advance_func, user_data, NULL) self._glyph_v_advance_func = func def set_glyph_v_origin_func(self, func: Callable[[ Font, int, # gid object, # user_data ], (int, int, int)], # success, v_origin_x, v_origin_y user_data: object = None): hb_font_funcs_set_glyph_v_origin_func( self._hb_ffuncs, _glyph_v_origin_func, user_data, NULL) self._glyph_v_origin_func = func def set_glyph_name_func(self, func: Callable[[ Font, int, # gid object, # user_data ], str], # name user_data: object = None): hb_font_funcs_set_glyph_name_func( self._hb_ffuncs, _glyph_name_func, user_data, NULL) self._glyph_name_func = func def set_nominal_glyph_func(self, func: Callable[[ Font, int, # unicode object, # user_data ], int], # gid user_data: object = None): hb_font_funcs_set_nominal_glyph_func( self._hb_ffuncs, _nominal_glyph_func, user_data, NULL) self._nominal_glyph_func = func def set_variation_glyph_func(self, func: Callable[[ Font, int, # unicode int, # variation_selector object, # user_data ], int], # gid user_data: object = None): hb_font_funcs_set_variation_glyph_func( self._hb_ffuncs, _variation_glyph_func, user_data, NULL) self._variation_glyph_func = func def set_font_h_extents_func(self, func: Callable[[ Font, object, # user_data ], FontExtents], # extents user_data: object = None): hb_font_funcs_set_font_h_extents_func( self._hb_ffuncs, _font_h_extents_func, user_data, NULL) self._font_h_extents_func = func def set_font_v_extents_func(self, func: Callable[[ Font, object, # user_data ], FontExtents], # extents user_data: object = None): hb_font_funcs_set_font_v_extents_func( self._hb_ffuncs, _font_v_extents_func, user_data, NULL) self._font_v_extents_func = func def shape(font: Font, buffer: Buffer, features: Dict[str,Union[int,bool,Sequence[Tuple[int,int,Union[int,bool]]]]] | None = None, shapers: List[str] | None = None): cdef unsigned int size cdef hb_feature_t* hb_features cdef bytes packed cdef hb_feature_t feat cdef const char* c_shapers[10] size = 0 hb_features = NULL try: if features: for value in features.values(): if isinstance(value, int): size += 1 else: size += len(value) hb_features = malloc(size * sizeof(hb_feature_t)) i = 0 for name, value in features.items(): assert i < size, "index out of range for feature array capacity" packed = name.encode() if isinstance(value, int): hb_feature_from_string(packed, len(packed), &feat) feat.value = value hb_features[i] = feat i += 1 else: feat.tag = hb_tag_from_string(packed, -1) for start, end, value in value: feat.value = value feat.start = start feat.end = end hb_features[i] = feat i += 1 if shapers: for i, shaper in enumerate(shapers[:9]): packed = shaper.encode() c_shapers[i] = packed c_shapers[i + 1] = NULL ret = hb_shape_full(font._hb_font, buffer._hb_buffer, hb_features, size, c_shapers) if not ret: raise RuntimeError("All shapers failed") else: hb_shape(font._hb_font, buffer._hb_buffer, hb_features, size) if not hb_buffer_allocation_successful(buffer._hb_buffer): raise MemoryError() finally: if hb_features is not NULL: free(hb_features) def ot_tag_to_script(tag: str) -> str: cdef bytes packed = tag.encode() cdef hb_tag_t hb_tag = hb_tag_from_string(packed, -1) cdef hb_script_t hb_script = hb_ot_tag_to_script(hb_tag) cdef char cstr[5] hb_tag_to_string(hb_script, cstr) cstr[4] = b'\0' packed = cstr return packed.decode() def ot_tag_to_language(tag: str) -> str: cdef bytes packed = tag.encode() cdef hb_tag_t hb_tag = hb_tag_from_string(packed, -1) cdef hb_language_t hb_language = hb_ot_tag_to_language(hb_tag) cdef const_char* cstr = hb_language_to_string(hb_language) if cstr is NULL: return None packed = cstr return packed.decode() @deprecated("Face.get_lookup_glyph_alternates()") def ot_layout_lookup_get_glyph_alternates( face: Face, lookup_index : int, glyph : hb_codepoint_t) -> List[int]: return face.get_lookup_glyph_alternates(lookup_index, glyph) @deprecated("Face.get_language_feature_tags()") def ot_layout_language_get_feature_tags( face: Face, tag: str, script_index: int = 0, language_index: int = 0xFFFF) -> List[str]: return face.get_language_feature_tags(tag, script_index, language_index) @deprecated("Face.get_script_language_tags()") def ot_layout_script_get_language_tags( face: Face, tag: str, script_index: int = 0) -> List[str]: return face.get_script_language_tags(tag, script_index) @deprecated("Face.get_table_script_tags()") def ot_layout_table_get_script_tags(face: Face, tag: str) -> List[str]: return face.get_table_script_tags(tag) @deprecated("Face.get_layout_baseline()") def ot_layout_get_baseline(font: Font, baseline_tag: str, direction: str, script_tag: str, language_tag: str) -> int: return font.get_layout_baseline(baseline_tag, direction, script_tag, language_tag) @deprecated("Face.face.has_layout_glyph_classes") def ot_layout_has_glyph_classes(face: Face) -> bool: return face.has_layout_glyph_classes @deprecated("Face.has_layout_positioning") def ot_layout_has_positioning(face: Face) -> bool: return face.has_layout_positioning @deprecated("Face.has_layout_substitution") def ot_layout_has_substitution(face: Face) -> bool: return face.has_layout_substitution @deprecated("Face.get_layout_glyph_class()") def ot_layout_get_glyph_class(face: Face, glyph: int) -> OTLayoutGlyphClass: return face.get_layout_glyph_class(glyph) @deprecated("Face.has_color_palettes") def ot_color_has_palettes(face: Face) -> bool: return face.has_color_palettes @deprecated("Face.color_palettes") def ot_color_palette_get_count(face: Face) -> int: return hb_ot_color_palette_get_count(face._hb_face) @deprecated("Face.get_color_palette()") def ot_color_palette_get_flags(face: Face, palette_index: int) -> OTColorPaletteFlags: return OTColorPaletteFlags(hb_ot_color_palette_get_flags(face._hb_face, palette_index)) @deprecated("Face.get_color_palette()") def ot_color_palette_get_colors(face: Face, palette_index: int) -> List[Color]: cdef list ret = [] cdef unsigned int i cdef unsigned int start_offset = 0 cdef unsigned int color_count = STATIC_ARRAY_SIZE cdef hb_color_t colors[STATIC_ARRAY_SIZE] while color_count == STATIC_ARRAY_SIZE: hb_ot_color_palette_get_colors(face._hb_face, palette_index, start_offset, &color_count, colors) for i in range(color_count): ret.append(Color.from_int(colors[i])) return ret @deprecated("Face.get_color_palette()") def ot_color_palette_get_name_id(face: Face, palette_index: int) -> int | None: cdef hb_ot_name_id_t name_id name_id = hb_ot_color_palette_get_name_id(face._hb_face, palette_index) if name_id == HB_OT_NAME_ID_INVALID: return None return name_id @deprecated("Face.color_palette_color_get_name_id()") def ot_color_palette_color_get_name_id(face: Face, color_index: int) -> int | None: return face.color_palette_color_get_name_id(color_index) @deprecated("Face.has_color_layers") def ot_color_has_layers(face: Face) -> bool: return face.has_color_layers @deprecated("Face.get_glyph_color_layers()") def ot_color_glyph_get_layers(face: Face, glyph: int) -> List[OTColorLayer]: return face.get_glyph_color_layers(glyph) @deprecated("Face.has_color_paint") def ot_color_has_paint(face: Face) -> bool: return face.has_color_paint @deprecated("Face.glyph_has_color_paint()") def ot_color_glyph_has_paint(face: Face, glyph: int) -> bool: return face.glyph_has_color_paint(glyph) @deprecated("Face.has_color_svg") def ot_color_has_svg(face: Face) -> bool: return face.has_color_svg @deprecated("Face.get_glyph_color_svg()") def ot_color_glyph_get_svg(face: Face, glyph: int) -> Blob: return face.get_glyph_color_svg(glyph) @deprecated("Face.has_color_png") def ot_color_has_png(face: Face) -> bool: return face.has_color_png @deprecated("Font.get_glyph_color_png()") def ot_color_glyph_get_png(font: Font, glyph: int) -> Blob: return font.get_glyph_color_png(glyph) @deprecated("Face.has_math_data") def ot_math_has_data(face: Face) -> bool: return face.has_math_data @deprecated("Font.get_math_constant()") def ot_math_get_constant(font: Font, constant: OTMathConstant) -> int: return font.get_math_constant(constant) @deprecated("Font.get_math_glyph_italics_correction()") def ot_math_get_glyph_italics_correction(font: Font, glyph: int) -> int: return font.get_math_glyph_italics_correction(glyph) @deprecated("Font.get_math_glyph_top_accent_attachment()") def ot_math_get_glyph_top_accent_attachment(font: Font, glyph: int) -> int: return font.get_math_glyph_top_accent_attachment(glyph) @deprecated("Face.is_glyph_extended_math_shape()") def ot_math_is_glyph_extended_shape(face: Face, glyph: int) -> bool: return face.is_glyph_extended_math_shape(glyph) @deprecated("Font.get_math_min_connector_overlap()") def ot_math_get_min_connector_overlap(font: Font, direction: str) -> int: return font.get_math_min_connector_overlap(direction) @deprecated("Font.get_math_glyph_kerning()") def ot_math_get_glyph_kerning(font: Font, glyph: int, kern: OTMathKern, int correction_height) -> int: return font.get_math_glyph_kerning(glyph, kern, correction_height) @deprecated("Font.get_math_glyph_kernings()") def ot_math_get_glyph_kernings(font: Font, glyph: int, kern: OTMathKern) -> List[OTMathKernEntry]: return font.get_math_glyph_kernings(glyph, kern) @deprecated("Font.get_math_glyph_variants()") def ot_math_get_glyph_variants(font: Font, glyph: int, direction: str) -> List[OTMathGlyphVariant]: return font.get_math_glyph_variants(glyph, direction) @deprecated("Font.get_math_glyph_assembly()") def ot_math_get_glyph_assembly(font: Font, glyph: int, direction: str) -> Tuple[List[OTMathGlyphPart], int]: return font.get_math_glyph_assembly(glyph, direction) def ot_font_set_funcs(font: Font): hb_ot_font_set_funcs(font._hb_font) class PaintCompositeMode(IntEnum): CLEAR = HB_PAINT_COMPOSITE_MODE_CLEAR SRC = HB_PAINT_COMPOSITE_MODE_SRC DEST = HB_PAINT_COMPOSITE_MODE_DEST SRC_OVER = HB_PAINT_COMPOSITE_MODE_SRC_OVER DEST_OVER = HB_PAINT_COMPOSITE_MODE_DEST_OVER SRC_IN = HB_PAINT_COMPOSITE_MODE_SRC_IN DEST_IN = HB_PAINT_COMPOSITE_MODE_DEST_IN SRC_OUT = HB_PAINT_COMPOSITE_MODE_SRC_OUT DEST_OUT = HB_PAINT_COMPOSITE_MODE_DEST_OUT SRC_ATOP = HB_PAINT_COMPOSITE_MODE_SRC_ATOP DEST_ATOP = HB_PAINT_COMPOSITE_MODE_DEST_ATOP XOR = HB_PAINT_COMPOSITE_MODE_XOR PLUS = HB_PAINT_COMPOSITE_MODE_PLUS SCREEN = HB_PAINT_COMPOSITE_MODE_SCREEN OVERLAY = HB_PAINT_COMPOSITE_MODE_OVERLAY DARKEN = HB_PAINT_COMPOSITE_MODE_DARKEN LIGHTEN = HB_PAINT_COMPOSITE_MODE_LIGHTEN COLOR_DODGE = HB_PAINT_COMPOSITE_MODE_COLOR_DODGE COLOR_BURN = HB_PAINT_COMPOSITE_MODE_COLOR_BURN HARD_LIGHT = HB_PAINT_COMPOSITE_MODE_HARD_LIGHT SOFT_LIGHT = HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT DIFFERENCE = HB_PAINT_COMPOSITE_MODE_DIFFERENCE EXCLUSION = HB_PAINT_COMPOSITE_MODE_EXCLUSION MULTIPLY = HB_PAINT_COMPOSITE_MODE_MULTIPLY HSL_HUE = HB_PAINT_COMPOSITE_MODE_HSL_HUE HSL_SATURATION = HB_PAINT_COMPOSITE_MODE_HSL_SATURATION HSL_COLOR = HB_PAINT_COMPOSITE_MODE_HSL_COLOR HSL_LUMINOSITY = HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY class ColorStop(NamedTuple): offset: float is_foreground: bool color: Color class PaintExtend(IntEnum): PAD = HB_PAINT_EXTEND_PAD REPEAT = HB_PAINT_EXTEND_REPEAT REFLECT = HB_PAINT_EXTEND_REFLECT cdef class ColorLine: cdef hb_color_line_t* _color_line def __cinit__(self): self._color_line = NULL @staticmethod cdef ColorLine from_ptr(hb_color_line_t* color_line): cdef ColorLine wrapper = ColorLine() wrapper._color_line = color_line return wrapper @property def color_stops(self) -> Sequence[ColorStop]: if self._color_line is NULL: return [] cdef unsigned int stop_count = STATIC_ARRAY_SIZE cdef hb_color_stop_t stops_array[STATIC_ARRAY_SIZE] cdef list stops = [] cdef unsigned int i cdef unsigned int start_offset = 0 while stop_count == STATIC_ARRAY_SIZE: hb_color_line_get_color_stops( self._color_line, start_offset, &stop_count, stops_array) for i in range(stop_count): c_stop = stops_array[i] py_color = Color.from_int(c_stop.color) stop = ColorStop(c_stop.offset, c_stop.is_foreground, py_color) stops.append(stop) start_offset += stop_count return stops @property def extend(self) -> PaintExtend: if self._color_line is NULL: return None return PaintExtend(hb_color_line_get_extend(self._color_line)) cdef void _paint_push_transform_func( hb_paint_funcs_t *funcs, void *paint_data, float xx, float yx, float xy, float yy, float dx, float dy, void *user_data) noexcept: py_funcs = user_data py_funcs._push_transform_func(xx, yx, xy, yy, dx, dy, paint_data) cdef void _paint_pop_transform_func( hb_paint_funcs_t *funcs, void *paint_data, void *user_data) noexcept: py_funcs = user_data py_funcs._pop_transform_func(paint_data) cdef hb_bool_t _paint_color_glyph_func( hb_paint_funcs_t *funcs, void *paint_data, hb_codepoint_t glyph, hb_font_t *font, void *user_data) noexcept: py_funcs = user_data if py_funcs._color_glyph_func(glyph, paint_data): return 1 return 0 cdef void _paint_push_clip_glyph_func( hb_paint_funcs_t *funcs, void *paint_data, hb_codepoint_t glyph, hb_font_t *font, void *user_data) noexcept: py_funcs = user_data py_funcs._push_clip_glyph_func(glyph, paint_data) cdef void _paint_push_clip_rectangle_func( hb_paint_funcs_t *funcs, void *paint_data, float xmin, float ymin, float xmax, float ymax, void *user_data) noexcept: py_funcs = user_data py_funcs._push_clip_rectangle_func(xmin, ymin, xmax, ymax, paint_data) cdef void _paint_pop_clip_func( hb_paint_funcs_t *funcs, void *paint_data, void *user_data) noexcept: py_funcs = user_data py_funcs._pop_clip_func(paint_data) cdef void _paint_color_func( hb_paint_funcs_t *funcs, void *paint_data, hb_bool_t is_foreground, hb_color_t color, void *user_data) noexcept: py_funcs = user_data py_color: Color = Color.from_int(color) py_funcs._color_func(py_color, is_foreground, paint_data) cdef hb_bool_t _paint_image_func( hb_paint_funcs_t *funcs, void *paint_data, hb_blob_t *image, unsigned int width, unsigned int height, hb_tag_t format, float slant, hb_glyph_extents_t *extents, void *user_data) noexcept: py_funcs = user_data py_image = Blob.from_ptr(hb_blob_reference(image)) py_format = hb_tag_to_string(format, NULL) py_extents = GlyphExtents(extents.x_bearing, extents.y_bearing, extents.width, extents.height) if py_funcs._image_func(py_image, width, height, py_format, slant, py_extents, paint_data): return 1 return 0 cdef void _paint_linear_gradient_func( hb_paint_funcs_t *funcs, void *paint_data, hb_color_line_t *color_line, float x0, float y0, float x1, float y1, float x2, float y2, void *user_data) noexcept: py_funcs = user_data py_color_line = ColorLine.from_ptr(color_line) py_funcs._linear_gradient_func(py_color_line, x0, y0, x1, y1, x2, y2, paint_data) cdef void _paint_radial_gradient_func( hb_paint_funcs_t *funcs, void *paint_data, hb_color_line_t *color_line, float x0, float y0, float r0, float x1, float y1, float r1, void *user_data) noexcept: py_funcs = user_data py_color_line = ColorLine.from_ptr(color_line) py_funcs._radial_gradient_func(py_color_line, x0, y0, r0, x1, y1, r1, paint_data) cdef void _paint_sweep_gradient_func( hb_paint_funcs_t *funcs, void *paint_data, hb_color_line_t *color_line, float x0, float y0, float start_angle, float end_angle, void *user_data) noexcept: py_funcs = user_data py_color_line = ColorLine.from_ptr(color_line) py_funcs._sweep_gradient_func(py_color_line, x0, y0, start_angle, end_angle, paint_data) cdef void _paint_push_group_func( hb_paint_funcs_t *funcs, void *paint_data, void *user_data) noexcept: py_funcs = user_data py_funcs._push_group_func(paint_data) cdef void _paint_pop_group_func( hb_paint_funcs_t *funcs, void *paint_data, hb_paint_composite_mode_t mode, void *user_data) noexcept: py_funcs = user_data py_mode = PaintCompositeMode(mode) py_funcs._pop_group_func(py_mode, paint_data) cdef hb_bool_t _paint_custom_palette_color_func( hb_paint_funcs_t *funcs, void *paint_data, unsigned int color_index, hb_color_t *color, void *user_data) noexcept: py_funcs = user_data py_color: Color = py_funcs._custom_palette_color_func(color_index, paint_data) if py_color is not None: color[0] = py_color.to_int() return 1 return 0 cdef class PaintFuncs: cdef hb_paint_funcs_t* _hb_paintfuncs cdef object _push_transform_func cdef object _pop_transform_func cdef object _color_glyph_func cdef object _push_clip_glyph_func cdef object _push_clip_rectangle_func cdef object _pop_clip_func cdef object _color_func cdef object _image_func cdef object _linear_gradient_func cdef object _radial_gradient_func cdef object _sweep_gradient_func cdef object _push_group_func cdef object _pop_group_func cdef object _custom_palette_color_func def __cinit__(self): self._hb_paintfuncs = hb_paint_funcs_create() def __dealloc__(self): hb_paint_funcs_destroy(self._hb_paintfuncs) def set_push_transform_func(self, func: Callable[[ float, # xx float, # yx float, # xy float, # yy float, # dx float, # dy object, # paint_data ], None]): self._push_transform_func = func hb_paint_funcs_set_push_transform_func( self._hb_paintfuncs, _paint_push_transform_func, self, NULL) def set_pop_transform_func(self, func: Callable[[ object, # paint_data ], None]): self._pop_transform_func = func hb_paint_funcs_set_pop_transform_func( self._hb_paintfuncs, _paint_pop_transform_func, self, NULL) def set_color_glyph_func(self, func: Callable[[ int, # gid object, # paint_data ], bool]): self._color_glyph_func = func hb_paint_funcs_set_color_glyph_func( self._hb_paintfuncs, _paint_color_glyph_func, self, NULL) def set_push_clip_glyph_func(self, func: Callable[[ int, # gid object, # paint_data ], None]): self._push_clip_glyph_func = func hb_paint_funcs_set_push_clip_glyph_func( self._hb_paintfuncs, _paint_push_clip_glyph_func, self, NULL) def set_push_clip_rectangle_func(self, func: Callable[[ float, # xmin float, # ymin float, # xmax float, # ymax object, # paint_data ], None]): self._push_clip_rectangle_func = func hb_paint_funcs_set_push_clip_rectangle_func( self._hb_paintfuncs, _paint_push_clip_rectangle_func, self, NULL) def set_pop_clip_func(self, func: Callable[[ object, # paint_data ], None]): self._pop_clip_func = func hb_paint_funcs_set_pop_clip_func( self._hb_paintfuncs, _paint_pop_clip_func, self, NULL) def set_color_func(self, func: Callable[[ Color, # color bool, # is_foreground object, # paint_data ], None]): self._color_func = func hb_paint_funcs_set_color_func( self._hb_paintfuncs, _paint_color_func, self, NULL) def set_image_func(self, func: Callable[[ Blob, # image int, # width int, # height str, # format float, # slant GlyphExtents, # extents object, # paint_data ], bool]): self._image_func = func hb_paint_funcs_set_image_func( self._hb_paintfuncs, _paint_image_func, self, NULL) def set_linear_gradient_func(self, func: Callable[[ ColorLine, # color_line float, # x0 float, # y0 float, # x1 float, # y1 float, # x2 float, # y2 object, # paint_data ], None]): self._linear_gradient_func = func hb_paint_funcs_set_linear_gradient_func( self._hb_paintfuncs, _paint_linear_gradient_func, self, NULL) def set_radial_gradient_func(self, func: Callable[[ ColorLine, # color_line float, # x0 float, # y0 float, # r0 float, # x1 float, # y1 float, # r1 object, # paint_data ], None]): self._radial_gradient_func = func hb_paint_funcs_set_radial_gradient_func( self._hb_paintfuncs, _paint_radial_gradient_func, self, NULL) def set_sweep_gradient_func(self, func: Callable[[ ColorLine, # color_line float, # x0 float, # y0 float, # start_angle float, # end_angle object, # paint_data ], None]): self._sweep_gradient_func = func hb_paint_funcs_set_sweep_gradient_func( self._hb_paintfuncs, _paint_sweep_gradient_func, self, NULL) def set_push_group_func(self, func: Callable[[ object, # paint_data ], None]): self._push_group_func = func hb_paint_funcs_set_push_group_func( self._hb_paintfuncs, _paint_push_group_func, self, NULL) def set_pop_group_func(self, func: Callable[[ PaintCompositeMode, # mode object, # paint_data ], None]): self._pop_group_func = func hb_paint_funcs_set_pop_group_func( self._hb_paintfuncs, _paint_pop_group_func, self, NULL) def set_custom_palette_color_func(self, func: Callable[[ int, # color_index object, # paint_data ], Color]): self._custom_palette_color_func = func hb_paint_funcs_set_custom_palette_color_func( self._hb_paintfuncs, _paint_custom_palette_color_func, self, NULL) cdef void _move_to_func(hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, float to_x, float to_y, void *user_data) noexcept: m = user_data m(to_x, to_y, draw_data) cdef void _line_to_func(hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, float to_x, float to_y, void *user_data) noexcept: l = user_data l(to_x, to_y, draw_data) cdef void _close_path_func(hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, void *user_data) noexcept: cl = user_data cl(draw_data) cdef void _quadratic_to_func(hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, float c1_x, float c1_y, float to_x, float to_y, void *user_data) noexcept: q = user_data q(c1_x, c1_y, to_x, to_y, draw_data) cdef void _cubic_to_func(hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, float c1_x, float c1_y, float c2_x, float c2_y, float to_x, float to_y, void *user_data) noexcept: c = user_data c(c1_x, c1_y, c2_x, c2_y, to_x, to_y, draw_data) cdef class DrawFuncs: cdef hb_draw_funcs_t* _hb_drawfuncs cdef object _move_to_func cdef object _line_to_func cdef object _cubic_to_func cdef object _quadratic_to_func cdef object _close_path_func def __cinit__(self): self._hb_drawfuncs = hb_draw_funcs_create() def __dealloc__(self): hb_draw_funcs_destroy(self._hb_drawfuncs) @deprecated("Font.draw_glyph()") def get_glyph_shape(self, font: Font, gid: int): font.draw_glyph(gid, self) @deprecated("Font.draw_glyph()") def draw_glyph(self, font: Font, gid: int, draw_data: object = None): font.draw_glyph(gid, self, draw_data) def set_move_to_func(self, func: Callable[[ float, float, object, # draw_data ], None], user_data: object = None): cdef hb_draw_move_to_func_t func_p cdef void *user_data_p if PyCapsule_IsValid(func, NULL): self._move_to_func = None func_p = PyCapsule_GetPointer(func, NULL) if PyCapsule_IsValid(user_data, NULL): user_data_p = PyCapsule_GetPointer(user_data, NULL) else: user_data_p = user_data else: self._move_to_func = func func_p = _move_to_func assert user_data is None, "Pass draw_state to Font.draw_glyph" user_data_p = func hb_draw_funcs_set_move_to_func( self._hb_drawfuncs, func_p, user_data_p, NULL) def set_line_to_func(self, func: Callable[[ float, float, object, # draw_data ], None], user_data: object = None): cdef hb_draw_line_to_func_t func_p cdef void *user_data_p if PyCapsule_IsValid(func, NULL): self._line_to_func = None func_p = PyCapsule_GetPointer(func, NULL) if PyCapsule_IsValid(user_data, NULL): user_data_p = PyCapsule_GetPointer(user_data, NULL) else: user_data_p = user_data else: self._line_to_func = func func_p = _line_to_func assert user_data is None, "Pass draw_state to Font.draw_glyph" user_data_p = func hb_draw_funcs_set_line_to_func( self._hb_drawfuncs, func_p, user_data_p, NULL) def set_cubic_to_func(self, func: Callable[[ float, float, float, float, float, float, object, # draw_data ], None], user_data: object = None): cdef hb_draw_cubic_to_func_t func_p cdef void *user_data_p if PyCapsule_IsValid(func, NULL): self._cubic_to_func = None func_p = PyCapsule_GetPointer(func, NULL) if PyCapsule_IsValid(user_data, NULL): user_data_p = PyCapsule_GetPointer(user_data, NULL) else: user_data_p = user_data else: self._cubic_to_func = func func_p = _cubic_to_func assert user_data is None, "Pass draw_state to Font.draw_glyph" user_data_p = func hb_draw_funcs_set_cubic_to_func( self._hb_drawfuncs, func_p, user_data_p, NULL) def set_quadratic_to_func(self, func: Callable[[ float, float, float, float, object, # draw_data ], None], user_data: object = None): cdef hb_draw_quadratic_to_func_t func_p cdef void *user_data_p if PyCapsule_IsValid(func, NULL): self._quadratic_to_func = None func_p = PyCapsule_GetPointer(func, NULL) if PyCapsule_IsValid(user_data, NULL): user_data_p = PyCapsule_GetPointer(user_data, NULL) else: user_data_p = user_data else: self._quadratic_to_func = func func_p = _quadratic_to_func assert user_data is None, "Pass draw_state to Font.draw_glyph" user_data_p = func hb_draw_funcs_set_quadratic_to_func( self._hb_drawfuncs, func_p, user_data_p, NULL) def set_close_path_func(self, func: Callable[[ object ], None], user_data: object = None): cdef hb_draw_close_path_func_t func_p cdef void *user_data_p if PyCapsule_IsValid(func, NULL): self._close_path_func = None func_p = PyCapsule_GetPointer(func, NULL) if PyCapsule_IsValid(user_data, NULL): user_data_p = PyCapsule_GetPointer(user_data, NULL) else: user_data_p = user_data else: self._close_path_func = func func_p = _close_path_func assert user_data is None, "Pass draw_state to Font.draw_glyph" user_data_p = func hb_draw_funcs_set_close_path_func( self._hb_drawfuncs, func_p, user_data_p, NULL) cdef class HBObject: cdef hb_subset_serialize_object_t* _hb_obj_list cdef unsigned int _num def __cinit__(self, num_nodes): self._hb_obj_list = calloc(num_nodes, sizeof(hb_subset_serialize_object_t)) if self._hb_obj_list == NULL: raise MemoryError() self._num = num_nodes def __dealloc__(self): if self._hb_obj_list != NULL: for i in range(self._num): if self._hb_obj_list[i].real_links != NULL: free(self._hb_obj_list[i].real_links) if self._hb_obj_list[i].virtual_links != NULL: free(self._hb_obj_list[i].virtual_links) free(self._hb_obj_list) cdef update_obj_length(self, unsigned int idx, char* head, char* tail): self._hb_obj_list[idx].head = head self._hb_obj_list[idx].tail = tail cdef hb_subset_serialize_link_t* create_links(self, unsigned int idx, unsigned int link_num, bint is_real_link): if link_num == 0: return NULL cdef hb_subset_serialize_link_t* p = calloc(link_num, sizeof(hb_subset_serialize_link_t)) if p == NULL: raise MemoryError() if is_real_link: self._hb_obj_list[idx].num_real_links = link_num self._hb_obj_list[idx].real_links = p else: self._hb_obj_list[idx].num_virtual_links = link_num self._hb_obj_list[idx].virtual_links = p return p cdef update_links(self, unsigned int idx, bint is_real_link, links: List[Tuple[int, int, int]]): cdef unsigned int num_links = len(links) cdef hb_subset_serialize_link_t* l = NULL if is_real_link: l = self._hb_obj_list[idx].real_links else: l = self._hb_obj_list[idx].virtual_links for i in range(num_links): l[i].position = links[i][0] l[i].width = links[i][1] l[i].objidx = links[i][2] class SerializerError(Exception): pass class RepackerError(SerializerError): pass @deprecated("serialize()") def repack(subtables, graphnodes): return serialize(subtables, graphnodes) @deprecated("serialize_with_tag()") def repack_with_tag(tag, subtables, graphnodes): return serialize_with_tag(tag, subtables, graphnodes) def serialize(subtables: List[bytes], graphnodes: List[Tuple[List[Tuple[int, int, int]], List[Tuple[int, int, int]] ]]) -> bytes: return serialize_with_tag("", subtables, graphnodes) def serialize_with_tag(tag: str, subtables: List[bytes], graphnodes: List[Tuple[List[Tuple[int, int, int]], List[Tuple[int, int, int]] ]]) -> bytes: """The whole table is represented as a Graph and the input graphnodes is a flat list of subtables with each node(subtable) represented by a tuple of 2 list: real_link list and virtual_link list. A link(egde) is an offset link between parent table and child table. It's represented in the format of a tuple: (posiiton: int, width: int, objidx: int): - position: means relative position of the offset field in bytes from the beginning of the subtable's C struct. e.g: a GSUB header struct in C looks like below: uint16 majorVersion uint16 minorVersion offset16 scriptListOffset offset16 featureListOffset offset16 lookupListOffset And the position for scriptListOffset is 4 which is calculated from (16+16)/8 - width: size of the offset: e.g 2 for offset16 and 4 for offset32 - objidx: objidx is the index of the subtable in graph/tree generated by postorder traversal There're 2 types of links: - real_link represents an real offset field in the parent table - virtual_link is not real offset link, it specifies an ordering constraint that harfbuzz packing must follow. A virtual link would have 0 width, 0 position, and a real objidx. e.g: if Node A has a virtual link with objidx b(corresponding Node is B), then that means Node B is always packed after Node A in the final serialized order """ if len(subtables) != len(graphnodes): raise ValueError( f"Input num of subtables({len(subtables)}) != num of graph nodes({len(graphnodes)})" ) cdef: unsigned int num_nodes = len(subtables) bytes table_bytes = b''.join(subtables) char* table_data = table_bytes unsigned int head = 0, tail = 0 hb_subset_serialize_link_t* p = NULL HBObject obj_list = HBObject(num_nodes) for i in range(num_nodes): tail += len(subtables[i]) obj_list.update_obj_length(i, table_data + head, table_data + tail) head = tail node = graphnodes[i] # real_links p = obj_list.create_links(i, len(node[0]), True) if p != NULL: obj_list.update_links(i, True, node[0]) # virtual_links p = obj_list.create_links(i, len(node[1]), False) if p != NULL: obj_list.update_links(i, False, node[1]) cdef bytes tag_packed = tag.encode() cdef char* cstr = tag_packed cdef hb_blob_t* packed_blob = hb_subset_serialize_or_fail(hb_tag_from_string(cstr, -1), obj_list._hb_obj_list, num_nodes) if packed_blob == NULL: raise RepackerError() cdef unsigned int blob_length cdef const_char* blob_data = hb_blob_get_data(packed_blob, &blob_length) cdef bytes packed = blob_data[:blob_length] hb_blob_destroy(packed_blob) return packed def subset_preprocess(face: Face) -> Face: new_face = hb_subset_preprocess(face._hb_face) return Face.from_ptr(new_face) def subset(face: Face, input: SubsetInput) -> Face: new_face = hb_subset_or_fail(face._hb_face, input._hb_input) if new_face == NULL: raise RuntimeError("Subsetting failed") return Face.from_ptr(new_face) class SubsetInputSets(IntEnum): GLYPH_INDEX = HB_SUBSET_SETS_GLYPH_INDEX UNICODE = HB_SUBSET_SETS_UNICODE NO_SUBSET_TABLE_TAG = HB_SUBSET_SETS_NO_SUBSET_TABLE_TAG DROP_TABLE_TAG = HB_SUBSET_SETS_DROP_TABLE_TAG NAME_ID = HB_SUBSET_SETS_NAME_ID NAME_LANG_ID = HB_SUBSET_SETS_NAME_LANG_ID LAYOUT_FEATURE_TAG = HB_SUBSET_SETS_LAYOUT_FEATURE_TAG LAYOUT_SCRIPT_TAG = HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG class SubsetFlags(IntFlag): DEFAULT = HB_SUBSET_FLAGS_DEFAULT NO_HINTING = HB_SUBSET_FLAGS_NO_HINTING RETAIN_GIDS = HB_SUBSET_FLAGS_RETAIN_GIDS DESUBROUTINIZE = HB_SUBSET_FLAGS_DESUBROUTINIZE NAME_LEGACY = HB_SUBSET_FLAGS_NAME_LEGACY SET_OVERLAPS_FLAG = HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG PASSTHROUGH_UNRECOGNIZED = HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED NOTDEF_OUTLINE = HB_SUBSET_FLAGS_NOTDEF_OUTLINE GLYPH_NAMES = HB_SUBSET_FLAGS_GLYPH_NAMES NO_PRUNE_UNICODE_RANGES = HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES NO_LAYOUT_CLOSURE = HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE cdef class SubsetInput: cdef hb_subset_input_t* _hb_input def __cinit__(self): self._hb_input = hb_subset_input_create_or_fail() if self._hb_input is NULL: raise MemoryError() def __dealloc__(self): if self._hb_input is not NULL: hb_subset_input_destroy(self._hb_input) def subset(self, source: Face) -> Face: return subset(source, self) def keep_everything(self): hb_subset_input_keep_everything(self._hb_input) def pin_all_axes_to_default(self, face: Face) -> bool: return hb_subset_input_pin_all_axes_to_default(self._hb_input, face._hb_face) def pin_axis_to_default(self, face: Face, tag: str) -> bool: hb_tag = hb_tag_from_string(tag.encode("ascii"), -1) return hb_subset_input_pin_axis_to_default( self._hb_input, face._hb_face, hb_tag ) def pin_axis_location(self, face: Face, tag: str, value: float) -> bool: hb_tag = hb_tag_from_string(tag.encode("ascii"), -1) return hb_subset_input_pin_axis_location( self._hb_input, face._hb_face, hb_tag, value ) def set_axis_range(self, face: Face, tag: str, min_value: float | None = None, max_value: float | None = None, def_value: float | None = None) -> bool: cdef hb_tag_t hb_tag = hb_tag_from_string(tag.encode("ascii"), -1) min_value = NAN if min_value is None else min_value max_value = NAN if max_value is None else max_value def_value = NAN if def_value is None else def_value return hb_subset_input_set_axis_range( self._hb_input, face._hb_face, hb_tag, min_value, max_value, def_value ) def get_axis_range(self, tag: str) -> Tuple[float | None, float | None | float | None] | None: cdef hb_tag_t hb_tag = hb_tag_from_string(tag.encode("ascii"), -1) cdef float axis_min_value, axis_max_value, axis_def_value if hb_subset_input_get_axis_range(self._hb_input, hb_tag, &axis_min_value, &axis_max_value, &axis_def_value): min_value = None if isnan(axis_min_value) else axis_min_value max_value = None if isnan(axis_max_value) else axis_max_value def_value = None if isnan(axis_def_value) else axis_def_value return min_value, max_value, def_value return None @property def unicode_set(self) -> Set[int]: return Set.from_ptr(hb_set_reference (hb_subset_input_unicode_set(self._hb_input))) @property def glyph_set(self) -> Set[int]: return Set.from_ptr(hb_set_reference (hb_subset_input_glyph_set(self._hb_input))) def sets(self, set_type : SubsetInputSets) -> Set: return Set.from_ptr(hb_set_reference (hb_subset_input_set(self._hb_input, set_type))) @property def no_subset_table_tag_set(self) -> Set: return self.sets(SubsetInputSets.NO_SUBSET_TABLE_TAG) @property def drop_table_tag_set(self) -> Set: return self.sets(SubsetInputSets.DROP_TABLE_TAG) @property def name_id_set(self) -> Set[int]: return self.sets(SubsetInputSets.NAME_ID) @property def name_lang_id_set(self) -> Set[int]: return self.sets(SubsetInputSets.NAME_LANG_ID) @property def layout_feature_tag_set(self) -> Set: return self.sets(SubsetInputSets.LAYOUT_FEATURE_TAG) @property def layout_script_tag_set(self) -> Set: return self.sets(SubsetInputSets.LAYOUT_SCRIPT_TAG) @property def flags(self) -> SubsetFlags: cdef unsigned subset_flags = hb_subset_input_get_flags(self._hb_input) return SubsetFlags(subset_flags) @flags.setter def flags(self, flags: SubsetFlags): hb_subset_input_set_flags(self._hb_input, int(flags)) cdef class SubsetPlan: cdef hb_subset_plan_t* _hb_plan def __cinit__(self, face: Face, input: SubsetInput): self._hb_plan = hb_subset_plan_create_or_fail(face._hb_face, input._hb_input) if self._hb_plan is NULL: raise MemoryError() def __dealloc__(self): if self._hb_plan is not NULL: hb_subset_plan_destroy(self._hb_plan) def execute(self) -> Face: new_face = hb_subset_plan_execute_or_fail(self._hb_plan) if new_face == NULL: raise RuntimeError("Subsetting failed") return Face.from_ptr(new_face) @property def old_to_new_glyph_mapping(self) -> Map: return Map.from_ptr(hb_map_reference (hb_subset_plan_old_to_new_glyph_mapping(self._hb_plan))) @property def new_to_old_glyph_mapping(self) -> Map: return Map.from_ptr(hb_map_reference (hb_subset_plan_new_to_old_glyph_mapping(self._hb_plan))) @property def unicode_to_old_glyph_mapping(self) -> Map: return Map.from_ptr(hb_map_reference (hb_subset_plan_unicode_to_old_glyph_mapping(self._hb_plan))) cdef class Set: cdef hb_set_t* _hb_set INVALID_VALUE = HB_SET_VALUE_INVALID def __cinit__(self, init = set()): self._hb_set = hb_set_create() if not hb_set_allocation_successful(self._hb_set): raise MemoryError() self.set(init) def __dealloc__(self): hb_set_destroy(self._hb_set) @staticmethod cdef Set from_ptr(hb_set_t* hb_set): """Create Set from a pointer taking ownership of a it.""" cdef Set wrapper = Set.__new__(Set) wrapper._hb_set = hb_set return wrapper def copy(self) -> Set: c = Set() c._hb_set = hb_set_copy(self._hb_set) return c def __copy__(self) -> Set: return self.copy() def clear(self): hb_set_clear(self._hb_set) def __bool__(self) -> bool: return not hb_set_is_empty(self._hb_set) def invert(self): hb_set_invert(self._hb_set) def is_inverted(self) -> bool: return hb_set_is_inverted(self._hb_set) def __contains__(self, c) -> bool: if type(c) != int: return False if c < 0 or c >= self.INVALID_VALUE: return False return hb_set_has(self._hb_set, c) def add(self, c: int): hb_set_add(self._hb_set, c) if not hb_set_allocation_successful(self._hb_set): raise MemoryError() def add_range(self, first: int, last: int): hb_set_add_range(self._hb_set, first, last) if not hb_set_allocation_successful(self._hb_set): raise MemoryError() def remove(self, c: int): if not c in self: raise KeyError, c hb_set_del(self._hb_set, c) if not hb_set_allocation_successful(self._hb_set): raise MemoryError() def discard(self, c: int): hb_set_del(self._hb_set, c) if not hb_set_allocation_successful(self._hb_set): raise MemoryError() def del_range(self, first: int, last: int): hb_set_del_range(self._hb_set, first, last) if not hb_set_allocation_successful(self._hb_set): raise MemoryError() def _is_equal(self, other: Set) -> bool: return hb_set_is_equal(self._hb_set, other._hb_set) def __eq__(self, other): if type(other) != Set: return NotImplemented return self._is_equal(other) def issubset(self, larger_set: Set) -> bool: return hb_set_is_subset(self._hb_set, larger_set._hb_set) def issuperset(self, smaller_set: Set) -> bool: return hb_set_is_subset(smaller_set._hb_set, self._hb_set) def _set(self, other: Set): hb_set_set(self._hb_set, other._hb_set) def set(self, other): if type(other) == Set: self._set(other) else: for c in other: hb_set_add(self._hb_set, c) if not hb_set_allocation_successful(self._hb_set): raise MemoryError() def _update(self, other: Set): hb_set_union(self._hb_set, other._hb_set) def update(self, other): if type(other) == Set: self._update(other) else: for c in other: hb_set_add(self._hb_set, c) if not hb_set_allocation_successful(self._hb_set): raise MemoryError() def __ior__(self, other): self.update(other) return self def intersection_update(self, other: Set): hb_set_intersect(self._hb_set, other._hb_set) if not hb_set_allocation_successful(self._hb_set): raise MemoryError() def __iand__(self, other: Set): self.intersection_update(other) return self def difference_update(self, other: Set): hb_set_subtract(self._hb_set, other._hb_set) if not hb_set_allocation_successful(self._hb_set): raise MemoryError() def __isub__(self, other: Set): self.difference_update(other) return self def symmetric_difference_update(self, other: Set): hb_set_symmetric_difference(self._hb_set, other._hb_set) if not hb_set_allocation_successful(self._hb_set): raise MemoryError() def __ixor__(self, other: Set): self.symmetric_difference_update(other) return self def __len__(self) -> int: return hb_set_get_population(self._hb_set) @property def min(self) -> int: return hb_set_get_min(self._hb_set) @property def max(self) -> int: return hb_set_get_max(self._hb_set) def __iter__(self): return SetIter(self) def __repr__(self): if self.is_inverted(): return "Set({...})" s = ', '.join(repr(v) for v in self) return ("Set({%s})" % s) cdef class SetIter: cdef Set s cdef hb_set_t *_hb_set cdef hb_codepoint_t _c def __cinit__(self, s: Set): self.s = s self._hb_set = s._hb_set self._c = s.INVALID_VALUE def __iter__(self): return self def __next__(self) -> int: ret = hb_set_next(self._hb_set, &self._c) if not ret: raise StopIteration return self._c cdef class Map: cdef hb_map_t* _hb_map INVALID_VALUE = HB_MAP_VALUE_INVALID def __cinit__(self, init = dict()): self._hb_map = hb_map_create() if not hb_map_allocation_successful(self._hb_map): raise MemoryError() self.update(init) def __dealloc__(self): hb_map_destroy(self._hb_map) @staticmethod cdef Map from_ptr(hb_map_t* hb_map): """Create Map from a pointer taking ownership of a it.""" cdef Map wrapper = Map.__new__(Map) wrapper._hb_map = hb_map return wrapper def copy(self) -> Map: c = Map() c._hb_map = hb_map_copy(self._hb_map) return c def __copy__(self) -> Map: return self.copy() def _update(self, other : Map): hb_map_update(self._hb_map, other._hb_map) def update(self, other): if type(other) == Map: self._update(other) else: for k,v in other.items(): hb_map_set(self._hb_map, k, v) if not hb_map_allocation_successful(self._hb_map): raise MemoryError() def clear(self): hb_map_clear(self._hb_map) def __bool__(self) -> bool: return not hb_map_is_empty(self._hb_map) def __len__(self) -> int: return hb_map_get_population(self._hb_map) def _is_equal(self, other: Map) -> bool: return hb_map_is_equal(self._hb_map, other._hb_map) def __eq__(self, other): if type(other) != Map: return NotImplemented return self._is_equal(other) def __setitem__(self, k: int, v: int): hb_map_set(self._hb_map, k, v) if not hb_map_allocation_successful(self._hb_map): raise MemoryError() def get(self, k: int): if k < 0 or k >= self.INVALID_VALUE: return None v = hb_map_get(self._hb_map, k) if v == self.INVALID_VALUE: v = None return v def __getitem__(self, k: int) -> int: v = self.get(k) if v is None: raise KeyError, v return v def __contains__(self, k) -> bool: if type(k) != int: return False if k < 0 or k >= self.INVALID_VALUE: return False return hb_map_has(self._hb_map, k) def __delitem__(self, c: int): if not c in self: raise KeyError, c hb_map_del(self._hb_map, c) def items(self): return MapIter(self) def keys(self): return (k for k,v in self.items()) def values(self): return (v for k,v in self.items()) def __iter__(self): return self.keys() def __repr__(self): s = ', '.join("%s: %s" % (repr(k), repr(v)) for k,v in sorted(self.items())) return ("Map({%s})" % s) cdef class MapIter: cdef Map m cdef hb_map_t *_hb_map cdef int _i def __cinit__(self, m: Map): self.m = m self._hb_map = m._hb_map self._i = -1 def __iter__(self): return self def __next__(self) -> Tuple[int, int]: cdef hb_codepoint_t k cdef hb_codepoint_t v ret = hb_map_next(self._hb_map, &self._i, &k, &v) if not ret: raise StopIteration return (k, v) uharfbuzz-0.53.3/src/uharfbuzz/_harfbuzz_test.pyx000066400000000000000000000000331513514046200222210ustar00rootroot00000000000000#cython: language_level=3 uharfbuzz-0.53.3/src/uharfbuzz/charfbuzz.pxd000066400000000000000000001516601513514046200211560ustar00rootroot00000000000000from libc.stdint cimport uint8_t, uint16_t, uint32_t cdef extern from "hb.h": # hb-common.h ctypedef void (*hb_destroy_func_t) (void* user_data) ctypedef int hb_bool_t ctypedef unsigned long hb_codepoint_t ctypedef long hb_position_t ctypedef unsigned long hb_mask_t ctypedef unsigned long hb_tag_t ctypedef uint32_t hb_color_t ctypedef enum hb_direction_t: HB_DIRECTION_LTR HB_DIRECTION_RTL HB_DIRECTION_TTB HB_DIRECTION_BTT ctypedef enum hb_script_t: pass ctypedef struct hb_language_t: pass ctypedef struct hb_feature_t: hb_tag_t tag unsigned long value unsigned int start unsigned int end ctypedef struct hb_glyph_extents_t: hb_position_t x_bearing hb_position_t y_bearing hb_position_t width hb_position_t height hb_direction_t hb_direction_from_string(const char* str, int len) const char* hb_direction_to_string(hb_direction_t direction) hb_bool_t hb_feature_from_string( const char* str, int len, hb_feature_t* feature) void hb_feature_to_string( hb_feature_t* feature, char* buf, unsigned int size) hb_language_t hb_language_from_string(const char* str, int len) const char* hb_language_to_string(hb_language_t language) hb_script_t hb_script_from_string(const char* str, int len) hb_tag_t hb_tag_from_string(const char* str, int len) void hb_tag_to_string(hb_tag_t tag, char* buf) hb_language_t hb_ot_tag_to_language(hb_tag_t tag) hb_script_t hb_ot_tag_to_script(hb_tag_t tag) const char* hb_version_string() uint8_t hb_color_get_alpha(hb_color_t color) uint8_t hb_color_get_red(hb_color_t color) uint8_t hb_color_get_green(hb_color_t color) uint8_t hb_color_get_blue(hb_color_t color) hb_color_t HB_COLOR(uint8_t b, uint8_t g, uint8_t r, uint8_t a) ctypedef struct hb_user_data_key_t: pass ctypedef union hb_var_int_t: unsigned long u32 long i32 unsigned int u16[2] int i16[2] unsigned short u8[4] short i8[4] ctypedef union hb_var_num_t: float f unsigned long u32 long i32 unsigned int u16[2] int i16[2] unsigned short u8[4] short i8[4] # hb-blob.h ctypedef struct hb_blob_t: pass ctypedef enum hb_memory_mode_t: HB_MEMORY_MODE_DUPLICATE HB_MEMORY_MODE_READONLY HB_MEMORY_MODE_WRITABLE HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE hb_blob_t* hb_blob_create( const char* data, unsigned int length, hb_memory_mode_t mode, void* user_data, hb_destroy_func_t destroy) hb_blob_t* hb_blob_create_from_file( const char *file_name) hb_blob_t* hb_blob_create_from_file_or_fail( const char *file_name) hb_blob_t* hb_blob_reference(hb_blob_t* blob) void hb_blob_destroy(hb_blob_t* blob) const char* hb_blob_get_data( hb_blob_t *blob, unsigned int *length) unsigned int hb_blob_get_length( hb_blob_t *blob) hb_blob_t* hb_blob_get_empty() # hb-buffer.h ctypedef struct hb_buffer_t: pass cdef hb_codepoint_t HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT ctypedef enum hb_glyph_flags_t: HB_GLYPH_FLAG_UNSAFE_TO_BREAK HB_GLYPH_FLAG_UNSAFE_TO_CONCAT HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL HB_GLYPH_FLAG_DEFINED ctypedef struct hb_glyph_info_t: hb_codepoint_t codepoint hb_mask_t mask unsigned long cluster ctypedef struct hb_glyph_position_t: hb_position_t x_advance hb_position_t y_advance hb_position_t x_offset hb_position_t y_offset hb_var_int_t var ctypedef enum hb_buffer_content_type_t: HB_BUFFER_CONTENT_TYPE_INVALID HB_BUFFER_CONTENT_TYPE_UNICODE HB_BUFFER_CONTENT_TYPE_GLYPHS ctypedef enum hb_buffer_cluster_level_t: HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS HB_BUFFER_CLUSTER_LEVEL_CHARACTERS HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES HB_BUFFER_CLUSTER_LEVEL_DEFAULT ctypedef enum hb_buffer_flags_t: HB_BUFFER_FLAG_DEFAULT HB_BUFFER_FLAG_BOT HB_BUFFER_FLAG_EOT HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE HB_BUFFER_FLAG_VERIFY HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL HB_BUFFER_FLAG_DEFINED ctypedef enum hb_buffer_serialize_format_t: HB_BUFFER_SERIALIZE_FORMAT_TEXT HB_BUFFER_SERIALIZE_FORMAT_JSON HB_BUFFER_SERIALIZE_FORMAT_INVALID ctypedef enum hb_buffer_serialize_flags_t: HB_BUFFER_SERIALIZE_FLAG_DEFAULT HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES HB_BUFFER_SERIALIZE_FLAG_DEFINED hb_buffer_t* hb_buffer_create() hb_bool_t hb_buffer_allocation_successful(hb_buffer_t* buffer) void hb_buffer_reset(hb_buffer_t *buffer) void hb_buffer_clear_contents(hb_buffer_t *buffer) void hb_buffer_add_codepoints( hb_buffer_t* buffer, const hb_codepoint_t* text, int text_length, unsigned int item_offset, int item_length) void hb_buffer_add_latin1( hb_buffer_t* buffer, const uint8_t* text, int text_length, unsigned int item_offset, int item_length) void hb_buffer_add_utf8( hb_buffer_t* buffer, const char* text, int text_length, unsigned int item_offset, int item_length) void hb_buffer_add_utf16( hb_buffer_t* buffer, const uint16_t* text, int text_length, unsigned int item_offset, int item_length) void hb_buffer_add_utf32( hb_buffer_t* buffer, const uint32_t* text, int text_length, unsigned int item_offset, int item_length) void hb_buffer_guess_segment_properties(hb_buffer_t* buffer) hb_direction_t hb_buffer_get_direction(hb_buffer_t* buffer) void hb_buffer_set_direction(hb_buffer_t* buffer, hb_direction_t direction) unsigned int hb_buffer_get_length(const hb_buffer_t *buffer) hb_glyph_info_t* hb_buffer_get_glyph_infos( hb_buffer_t* buffer, unsigned int* length) hb_glyph_position_t* hb_buffer_get_glyph_positions( hb_buffer_t* buffer, unsigned int* length) hb_script_t hb_buffer_get_script(hb_buffer_t* buffer) void hb_buffer_set_script(hb_buffer_t* buffer, hb_script_t script) hb_language_t hb_buffer_get_language(hb_buffer_t* buffer) void hb_buffer_set_language(hb_buffer_t* buffer, hb_language_t language) void hb_buffer_set_cluster_level(hb_buffer_t *buffer, hb_buffer_cluster_level_t cluster_level) hb_buffer_cluster_level_t hb_buffer_get_cluster_level(hb_buffer_t *buffer) void hb_buffer_destroy(hb_buffer_t* buffer) ctypedef hb_bool_t (*hb_buffer_message_func_t) ( hb_buffer_t *buffer, hb_font_t *font, const char *message, void *user_data) void hb_buffer_set_message_func( hb_buffer_t *buffer, hb_buffer_message_func_t func, void *user_data, void* destroy) void hb_buffer_set_flags(hb_buffer_t *buffer, hb_buffer_flags_t flags) hb_buffer_flags_t hb_buffer_get_flags(const hb_buffer_t *buffer) void hb_buffer_set_content_type(hb_buffer_t *buffer, hb_buffer_content_type_t content_type) hb_buffer_content_type_t hb_buffer_get_content_type(const hb_buffer_t *buffer) void hb_buffer_set_replacement_codepoint(hb_buffer_t *buffer, hb_codepoint_t replacement) hb_codepoint_t hb_buffer_get_replacement_codepoint(const hb_buffer_t *buffer) void hb_buffer_set_invisible_glyph(hb_buffer_t *buffer, hb_codepoint_t invisible) hb_codepoint_t hb_buffer_get_invisible_glyph(const hb_buffer_t *buffer) void hb_buffer_set_not_found_glyph(hb_buffer_t *buffer, hb_codepoint_t not_found) hb_codepoint_t hb_buffer_get_not_found_glyph(const hb_buffer_t *buffer) unsigned int hb_buffer_serialize(hb_buffer_t *buffer, unsigned int start, unsigned int end, char *buf, unsigned int buf_size, unsigned int *buf_consumed, hb_font_t *font, hb_buffer_serialize_format_t format, hb_buffer_serialize_flags_t flags) # hb-face.h ctypedef struct hb_face_t: pass ctypedef hb_blob_t* (*hb_reference_table_func_t) ( hb_face_t* face, hb_tag_t tag, void* user_data) hb_face_t* hb_face_create(hb_blob_t* blob, unsigned int index) hb_face_t* hb_face_create_for_tables( hb_reference_table_func_t reference_table_func, void* user_data, hb_destroy_func_t destroy) unsigned int hb_face_count(hb_blob_t* blob) unsigned int hb_face_get_index(const hb_face_t* face) void hb_face_set_index(hb_face_t* face, unsigned int index) unsigned int hb_face_get_upem(hb_face_t* face) void hb_face_set_upem(hb_face_t* face, unsigned int upem) unsigned int hb_face_get_glyph_count(hb_face_t* face) void hb_face_set_glyph_count(hb_face_t* face, unsigned int glyph_count) void* hb_face_get_user_data(hb_face_t* face, hb_user_data_key_t* key) hb_bool_t hb_face_set_user_data( hb_face_t* face, hb_user_data_key_t* key, void* data, hb_destroy_func_t destroy, hb_bool_t replace) void hb_face_destroy(hb_face_t* face) hb_blob_t* hb_face_reference_blob(hb_face_t *face) hb_blob_t* hb_face_reference_table(hb_face_t *face,hb_tag_t tag) hb_face_t* hb_face_reference(hb_face_t *face) hb_face_t* hb_face_get_empty() unsigned int hb_face_get_table_tags( const hb_face_t *face, unsigned int start_offset, unsigned int *table_count, hb_tag_t *table_tags) void hb_face_collect_unicodes(hb_face_t *face, hb_set_t *out) void hb_face_collect_variation_selectors(hb_face_t *face, hb_set_t *out) void hb_face_collect_variation_unicodes(hb_face_t *face, hb_codepoint_t variation_selector, hb_set_t *out) # hb-font.h ctypedef struct hb_font_funcs_t: pass ctypedef struct hb_font_t: pass ctypedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) ( hb_font_t* font, void* font_data, hb_codepoint_t unicode, hb_codepoint_t* glyph, void* user_data) ctypedef hb_bool_t (*hb_font_get_variation_glyph_func_t) ( hb_font_t *font, void *font_data, hb_codepoint_t unicode, hb_codepoint_t variation_selector, hb_codepoint_t *glyph, void *user_data) ctypedef hb_position_t (*hb_font_get_glyph_advance_func_t) ( hb_font_t* font, void* font_data, hb_codepoint_t glyph, void* user_data) ctypedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t ctypedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t ctypedef hb_bool_t (*hb_font_get_glyph_origin_func_t) ( hb_font_t* font, void* font_data, hb_codepoint_t glyph, hb_position_t* x, hb_position_t* y, void* user_data) ctypedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t ctypedef hb_bool_t (*hb_font_get_glyph_name_func_t) ( hb_font_t *font, void *font_data, hb_codepoint_t glyph, char *name, unsigned int size, void *user_data) ctypedef hb_bool_t (*hb_font_get_font_extents_func_t) ( hb_font_t *font, void *font_data, hb_font_extents_t *extents, void *user_data) ctypedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t ctypedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t ctypedef struct hb_variation_t: hb_tag_t tag float value ctypedef struct hb_font_extents_t: hb_position_t ascender hb_position_t descender hb_position_t line_gap hb_position_t reserved9 hb_position_t reserved8 hb_position_t reserved7 hb_position_t reserved6 hb_position_t reserved5 hb_position_t reserved4 hb_position_t reserved3 hb_position_t reserved2 hb_position_t reserved1 hb_font_t* hb_font_create(hb_face_t* face) hb_font_t* hb_font_create_sub_font(hb_font_t* parent) hb_font_t* hb_font_get_empty() hb_font_t* hb_font_reference(hb_font_t *font) void hb_font_destroy(hb_font_t* font) hb_face_t *hb_font_get_face(hb_font_t *font) hb_font_funcs_t* hb_font_funcs_create() void hb_font_funcs_set_glyph_h_advance_func( hb_font_funcs_t* ffuncs, hb_font_get_glyph_h_advance_func_t func, void* user_data, hb_destroy_func_t destroy) void hb_font_funcs_set_glyph_v_advance_func( hb_font_funcs_t* ffuncs, hb_font_get_glyph_v_advance_func_t func, void* user_data, hb_destroy_func_t destroy) void hb_font_funcs_set_glyph_v_origin_func( hb_font_funcs_t* ffuncs, hb_font_get_glyph_v_origin_func_t func, void* user_data, hb_destroy_func_t destroy) void hb_font_funcs_set_glyph_name_func( hb_font_funcs_t* ffuncs, hb_font_get_glyph_name_func_t func, void* user_data, hb_destroy_func_t destroy) void hb_font_funcs_set_nominal_glyph_func( hb_font_funcs_t* ffuncs, hb_font_get_nominal_glyph_func_t func, void* user_data, hb_destroy_func_t destroy) void hb_font_funcs_set_variation_glyph_func( hb_font_funcs_t *ffuncs, hb_font_get_variation_glyph_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_font_funcs_set_font_h_extents_func( hb_font_funcs_t *ffuncs, hb_font_get_font_h_extents_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_font_funcs_set_font_v_extents_func( hb_font_funcs_t *ffuncs, hb_font_get_font_v_extents_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_font_funcs_destroy(hb_font_funcs_t* ffuncs) void hb_font_set_funcs( hb_font_t* font, hb_font_funcs_t* klass, void* font_data, hb_destroy_func_t destroy) void hb_font_get_scale(hb_font_t* font, int* x_scale, int* y_scale) void hb_font_set_scale(hb_font_t* font, int x_scale, int y_scale) void hb_font_get_ppem(hb_font_t* font, unsigned int* x_ppem, unsigned int* y_ppem) void hb_font_set_ppem(hb_font_t* font, unsigned int x_ppem, unsigned int y_ppem) float hb_font_get_ptem(hb_font_t* font) void hb_font_set_ptem(hb_font_t* font, float ptem) void hb_font_get_synthetic_bold(hb_font_t *font, float *x_embolden, float *y_embolden, hb_bool_t *in_place) void hb_font_set_synthetic_bold(hb_font_t *font, float x_embolden, float y_embolden, hb_bool_t in_place) float hb_font_get_synthetic_slant(hb_font_t *font) void hb_font_set_synthetic_slant(hb_font_t *font, float slant) void hb_font_set_variations( hb_font_t* font, const hb_variation_t* variations, unsigned int variations_length) void hb_font_set_variation( hb_font_t *font, hb_tag_t tag, float value) void hb_font_set_var_named_instance(hb_font_t *font, unsigned int instance_index) unsigned int hb_font_get_var_named_instance(hb_font_t *font) void hb_font_set_var_coords_design( hb_font_t *font, const float *coords, unsigned int coords_length) const float * hb_font_get_var_coords_design( hb_font_t *font, unsigned int *length) hb_bool_t hb_font_get_glyph_name( hb_font_t* font, hb_codepoint_t glyph, char* name, unsigned int size) hb_bool_t hb_font_get_glyph_from_name( hb_font_t *font, const char *name, int len, hb_codepoint_t *glyph) hb_bool_t hb_font_get_glyph_extents( hb_font_t* font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) void hb_font_get_extents_for_direction(hb_font_t *font, hb_direction_t direction, hb_font_extents_t *extents) hb_bool_t hb_font_get_h_extents(hb_font_t *font, hb_font_extents_t *extents) hb_bool_t hb_font_get_v_extents(hb_font_t *font, hb_font_extents_t *extents) hb_position_t hb_font_get_glyph_h_advance( hb_font_t *font, hb_codepoint_t glyph) hb_position_t hb_font_get_glyph_v_advance( hb_font_t *font, hb_codepoint_t glyph) hb_bool_t hb_font_get_glyph_h_origin( hb_font_t *font, hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y) hb_bool_t hb_font_get_glyph_v_origin( hb_font_t *font, hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y) hb_bool_t hb_font_get_nominal_glyph( hb_font_t *font, hb_codepoint_t unicode, hb_codepoint_t *glyph) hb_bool_t hb_font_get_variation_glyph( hb_font_t *font, hb_codepoint_t unicode, hb_codepoint_t variation_selector, hb_codepoint_t *glyph) const int * hb_font_get_var_coords_normalized( hb_font_t *font, unsigned int *length) void hb_font_set_var_coords_normalized( hb_font_t *font, const int *coords, unsigned int coords_length) void hb_font_glyph_to_string( hb_font_t* font, hb_codepoint_t glyph, char* name, unsigned int size) hb_bool_t hb_font_glyph_from_string( hb_font_t *font, const char *s, int len, hb_codepoint_t *glyph) void hb_font_draw_glyph( hb_font_t *font, hb_codepoint_t glyph, const hb_draw_funcs_t *dfuncs, void *draw_data) void hb_font_paint_glyph( hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *pfuncs, void *paint_data, unsigned int palette_index, hb_color_t foreground) # hb-draw.h ctypedef struct hb_draw_state_t: hb_bool_t path_open float path_start_x float path_start_y float current_x float current_y float slant_xy hb_var_num_t reserved1 hb_var_num_t reserved2 hb_var_num_t reserved3 hb_var_num_t reserved4 hb_var_num_t reserved5 hb_var_num_t reserved6 ctypedef struct hb_draw_funcs_t: pass ctypedef void (*hb_draw_move_to_func_t) ( hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, float to_x, float to_y, void *user_data) ctypedef void (*hb_draw_line_to_func_t) ( hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, float to_x, float to_y, void *user_data) ctypedef void (*hb_draw_quadratic_to_func_t) ( hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, float control_x, float control_y, float to_x, float to_y, void *user_data) ctypedef void (*hb_draw_cubic_to_func_t) ( hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, float control1_x, float control1_y, float control2_x, float control2_y, float to_x, float to_y, void *user_data) ctypedef void (*hb_draw_close_path_func_t) ( hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, void *user_data) void hb_draw_funcs_set_move_to_func( hb_draw_funcs_t* dfuncs, hb_draw_move_to_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_draw_funcs_set_line_to_func( hb_draw_funcs_t* dfuncs, hb_draw_line_to_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_draw_funcs_set_quadratic_to_func( hb_draw_funcs_t* dfuncs, hb_draw_quadratic_to_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_draw_funcs_set_cubic_to_func( hb_draw_funcs_t* dfuncs, hb_draw_cubic_to_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_draw_funcs_set_close_path_func( hb_draw_funcs_t* dfuncs, hb_draw_close_path_func_t func, void *user_data, hb_destroy_func_t destroy) hb_draw_funcs_t* hb_draw_funcs_create() void hb_draw_funcs_destroy(hb_draw_funcs_t* funcs) # hb-paint.h ctypedef struct hb_paint_funcs_t: pass ctypedef struct hb_color_stop_t: float offset hb_bool_t is_foreground hb_color_t color ctypedef enum hb_paint_extend_t: HB_PAINT_EXTEND_PAD HB_PAINT_EXTEND_REPEAT HB_PAINT_EXTEND_REFLECT ctypedef struct hb_color_line_t: pass ctypedef enum hb_paint_composite_mode_t: HB_PAINT_COMPOSITE_MODE_CLEAR HB_PAINT_COMPOSITE_MODE_SRC HB_PAINT_COMPOSITE_MODE_DEST HB_PAINT_COMPOSITE_MODE_SRC_OVER HB_PAINT_COMPOSITE_MODE_DEST_OVER HB_PAINT_COMPOSITE_MODE_SRC_IN HB_PAINT_COMPOSITE_MODE_DEST_IN HB_PAINT_COMPOSITE_MODE_SRC_OUT HB_PAINT_COMPOSITE_MODE_DEST_OUT HB_PAINT_COMPOSITE_MODE_SRC_ATOP HB_PAINT_COMPOSITE_MODE_DEST_ATOP HB_PAINT_COMPOSITE_MODE_XOR HB_PAINT_COMPOSITE_MODE_PLUS HB_PAINT_COMPOSITE_MODE_SCREEN HB_PAINT_COMPOSITE_MODE_OVERLAY HB_PAINT_COMPOSITE_MODE_DARKEN HB_PAINT_COMPOSITE_MODE_LIGHTEN HB_PAINT_COMPOSITE_MODE_COLOR_DODGE HB_PAINT_COMPOSITE_MODE_COLOR_BURN HB_PAINT_COMPOSITE_MODE_HARD_LIGHT HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT HB_PAINT_COMPOSITE_MODE_DIFFERENCE HB_PAINT_COMPOSITE_MODE_EXCLUSION HB_PAINT_COMPOSITE_MODE_MULTIPLY HB_PAINT_COMPOSITE_MODE_HSL_HUE HB_PAINT_COMPOSITE_MODE_HSL_SATURATION HB_PAINT_COMPOSITE_MODE_HSL_COLOR HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY hb_paint_funcs_t *hb_paint_funcs_create() hb_paint_funcs_t *hb_paint_funcs_get_empty() hb_paint_funcs_t *hb_paint_funcs_reference(hb_paint_funcs_t *funcs) void hb_paint_funcs_destroy(hb_paint_funcs_t *funcs) hb_bool_t hb_paint_funcs_set_user_data( hb_paint_funcs_t *funcs, hb_user_data_key_t *key, void *data, hb_destroy_func_t destroy, hb_bool_t replace) void *hb_paint_funcs_get_user_data( const hb_paint_funcs_t *funcs, hb_user_data_key_t *key) void hb_paint_funcs_make_immutable(hb_paint_funcs_t *funcs) hb_bool_t hb_paint_funcs_is_immutable(hb_paint_funcs_t *funcs) unsigned int hb_color_line_get_color_stops( hb_color_line_t *color_line, unsigned int start, unsigned int *count, hb_color_stop_t *color_stops) hb_paint_extend_t hb_color_line_get_extend(hb_color_line_t *color_line) ctypedef void (*hb_paint_push_transform_func_t) ( hb_paint_funcs_t *funcs, void *paint_data, float xx, float yx, float xy, float yy, float dx, float dy, void *user_data) ctypedef void (*hb_paint_pop_transform_func_t) ( hb_paint_funcs_t *funcs, void *paint_data, void *user_data) ctypedef hb_bool_t (*hb_paint_color_glyph_func_t) ( hb_paint_funcs_t *funcs, void *paint_data, hb_codepoint_t glyph, hb_font_t *font, void *user_data) ctypedef void (*hb_paint_push_clip_glyph_func_t) ( hb_paint_funcs_t *funcs, void *paint_data, hb_codepoint_t glyph, hb_font_t *font, void *user_data) ctypedef void (*hb_paint_push_clip_rectangle_func_t) ( hb_paint_funcs_t *funcs, void *paint_data, float xmin, float ymin, float xmax, float ymax, void *user_data) ctypedef void (*hb_paint_pop_clip_func_t) ( hb_paint_funcs_t *funcs, void *paint_data, void *user_data) ctypedef void (*hb_paint_color_func_t) ( hb_paint_funcs_t *funcs, void *paint_data, hb_bool_t is_foreground, hb_color_t color, void *user_data) ctypedef hb_bool_t (*hb_paint_image_func_t) ( hb_paint_funcs_t *funcs, void *paint_data, hb_blob_t *image, unsigned int width, unsigned int height, hb_tag_t format, float slant, hb_glyph_extents_t *extents, void *user_data) ctypedef unsigned int (*hb_color_line_get_color_stops_func_t) ( hb_color_line_t *color_line, void *color_line_data, unsigned int start, unsigned int *count, hb_color_stop_t *color_stops, void *user_data) ctypedef hb_paint_extend_t (*hb_color_line_get_extend_func_t) ( hb_color_line_t *color_line, void *color_line_data, void *user_data) ctypedef struct hb_color_line_t: void *data hb_color_line_get_color_stops_func_t get_color_stops void *get_color_stops_user_data hb_color_line_get_extend_func_t get_extend void *get_extend_user_data void *reserved0 void *reserved1 void *reserved2 void *reserved3 void *reserved5 void *reserved6 void *reserved7 void *reserved8 ctypedef void (*hb_paint_linear_gradient_func_t) ( hb_paint_funcs_t *funcs, void *paint_data, hb_color_line_t *color_line, float x0, float y0, float x1, float y1, float x2, float y2, void *user_data) ctypedef void (*hb_paint_radial_gradient_func_t) ( hb_paint_funcs_t *funcs, void *paint_data, hb_color_line_t *color_line, float x0, float y0, float r0, float x1, float y1, float r1, void *user_data) ctypedef void (*hb_paint_sweep_gradient_func_t) ( hb_paint_funcs_t *funcs, void *paint_data, hb_color_line_t *color_line, float x0, float y0, float start_angle, float end_angle, void *user_data) ctypedef void (*hb_paint_push_group_func_t) ( hb_paint_funcs_t *funcs, void *paint_data, void *user_data) ctypedef void (*hb_paint_pop_group_func_t) ( hb_paint_funcs_t *funcs, void *paint_data, hb_paint_composite_mode_t mode, void *user_data) ctypedef hb_bool_t (*hb_paint_custom_palette_color_func_t) ( hb_paint_funcs_t *funcs, void *paint_data, unsigned int color_index, hb_color_t *color, void *user_data) void hb_paint_funcs_set_push_transform_func( hb_paint_funcs_t *funcs, hb_paint_push_transform_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_paint_funcs_set_pop_transform_func( hb_paint_funcs_t *funcs, hb_paint_pop_transform_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_paint_funcs_set_color_glyph_func( hb_paint_funcs_t *funcs, hb_paint_color_glyph_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_paint_funcs_set_push_clip_glyph_func( hb_paint_funcs_t *funcs, hb_paint_push_clip_glyph_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_paint_funcs_set_push_clip_rectangle_func( hb_paint_funcs_t *funcs, hb_paint_push_clip_rectangle_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_paint_funcs_set_pop_clip_func( hb_paint_funcs_t *funcs, hb_paint_pop_clip_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_paint_funcs_set_color_func( hb_paint_funcs_t *funcs, hb_paint_color_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_paint_funcs_set_image_func( hb_paint_funcs_t *funcs, hb_paint_image_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_paint_funcs_set_linear_gradient_func ( hb_paint_funcs_t *funcs, hb_paint_linear_gradient_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_paint_funcs_set_radial_gradient_func( hb_paint_funcs_t *funcs, hb_paint_radial_gradient_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_paint_funcs_set_sweep_gradient_func( hb_paint_funcs_t *funcs, hb_paint_sweep_gradient_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_paint_funcs_set_push_group_func( hb_paint_funcs_t *funcs, hb_paint_push_group_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_paint_funcs_set_pop_group_func( hb_paint_funcs_t *funcs, hb_paint_pop_group_func_t func, void *user_data, hb_destroy_func_t destroy) void hb_paint_funcs_set_custom_palette_color_func( hb_paint_funcs_t *funcs, hb_paint_custom_palette_color_func_t func, void *user_data, hb_destroy_func_t destroy) # hb-shape.h void hb_shape( hb_font_t* font, hb_buffer_t* buffer, const hb_feature_t* features, unsigned int num_features) hb_bool_t hb_shape_full( hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features, unsigned int num_features, char ** shaper_list) # hb-map.h ctypedef struct hb_map_t: pass cdef hb_codepoint_t HB_MAP_VALUE_INVALID hb_map_t* hb_map_create() hb_map_t* hb_map_get_empty() hb_map_t* hb_map_reference(hb_map_t* map) void hb_map_destroy(hb_map_t* map) hb_bool_t hb_map_set_user_data(hb_map_t* map, hb_user_data_key_t* key, void* data, hb_destroy_func_t destroy, hb_bool_t replace) void* hb_map_get_user_data(const hb_map_t* map, hb_user_data_key_t* key) hb_bool_t hb_map_allocation_successful(const hb_map_t* map) hb_map_t* hb_map_copy(const hb_map_t* map) void hb_map_clear(hb_map_t* map) hb_bool_t hb_map_is_empty(const hb_map_t* map) unsigned int hb_map_get_population(const hb_map_t* map) hb_bool_t hb_map_is_equal(const hb_map_t* map, const hb_map_t* other) unsigned int hb_map_hash(const hb_map_t* map) void hb_map_set(hb_map_t* map, hb_codepoint_t key, hb_codepoint_t value) hb_codepoint_t hb_map_get(const hb_map_t* map, hb_codepoint_t key) void hb_map_del(hb_map_t* map, hb_codepoint_t key) hb_bool_t hb_map_has(const hb_map_t* map, hb_codepoint_t key) void hb_map_update(hb_map_t* map, const hb_map_t* other) hb_bool_t hb_map_next(const hb_map_t* map, int *idx, hb_codepoint_t *key, hb_codepoint_t *value) # hb-set.h ctypedef struct hb_set_t: pass cdef hb_codepoint_t HB_SET_VALUE_INVALID hb_set_t* hb_set_create() hb_set_t* hb_set_get_empty() hb_set_t* hb_set_reference(hb_set_t* set) void hb_set_destroy(hb_set_t* set) hb_bool_t hb_set_set_user_data(hb_set_t* set, hb_user_data_key_t* key, void* data, hb_destroy_func_t destroy, hb_bool_t replace) void* hb_set_get_user_data(const hb_set_t* set, hb_user_data_key_t* key) hb_bool_t hb_set_allocation_successful(const hb_set_t* set) hb_set_t* hb_set_copy(const hb_set_t* set) void hb_set_clear(hb_set_t* set) hb_bool_t hb_set_is_empty(const hb_set_t* set) void hb_set_invert(hb_set_t* set) hb_bool_t hb_set_is_inverted(const hb_set_t* set) hb_bool_t hb_set_has(const hb_set_t* set, hb_codepoint_t codepoint) void hb_set_add(hb_set_t* set, hb_codepoint_t codepoint) void hb_set_add_range(hb_set_t* set, hb_codepoint_t first, hb_codepoint_t last) void hb_set_add_sorted_array(hb_set_t* set, const hb_codepoint_t* sorted_codepoints, unsigned int num_codepoints) void hb_set_del(hb_set_t* set, hb_codepoint_t codepoint) void hb_set_del_range(hb_set_t* set, hb_codepoint_t first, hb_codepoint_t last) hb_bool_t hb_set_is_equal(const hb_set_t* set, const hb_set_t* other) unsigned int hb_set_hash(const hb_set_t* set) hb_bool_t hb_set_is_subset(const hb_set_t* set, const hb_set_t* larger_set) void hb_set_set(hb_set_t* set, const hb_set_t* other) void hb_set_union(hb_set_t* set, const hb_set_t* other) void hb_set_intersect(hb_set_t* set, const hb_set_t* other) void hb_set_subtract(hb_set_t* set, const hb_set_t* other) void hb_set_symmetric_difference(hb_set_t* set, const hb_set_t* other) unsigned int hb_set_get_population(const hb_set_t* set) hb_codepoint_t hb_set_get_min(const hb_set_t* set) hb_codepoint_t hb_set_get_max(const hb_set_t* set) hb_bool_t hb_set_next(const hb_set_t* set, hb_codepoint_t* codepoint) hb_bool_t hb_set_previous(const hb_set_t* set, hb_codepoint_t* codepoint) hb_bool_t hb_set_next_range(const hb_set_t* set, hb_codepoint_t* first, hb_codepoint_t* last) hb_bool_t hb_set_previous_range(const hb_set_t* set, hb_codepoint_t* first, hb_codepoint_t* last) unsigned int hb_set_next_many(const hb_set_t* set, hb_codepoint_t codepoint, hb_codepoint_t* out, unsigned int size) # hb-style.h ctypedef enum hb_style_tag_t: HB_STYLE_TAG_ITALIC HB_STYLE_TAG_OPTICAL_SIZE HB_STYLE_TAG_SLANT_ANGLE HB_STYLE_TAG_SLANT_RATIO HB_STYLE_TAG_WIDTH HB_STYLE_TAG_WEIGHT float hb_style_get_value(hb_font_t *font, hb_style_tag_t style_tag) cdef extern from "hb-ot.h": # hb-ot-layout.h unsigned int hb_ot_layout_lookup_get_glyph_alternates( hb_face_t* face, unsigned lookup_index, hb_codepoint_t glyph, unsigned start_offset, unsigned * alternate_count, hb_codepoint_t *alternate_glyphs) unsigned int hb_ot_layout_language_get_feature_tags( hb_face_t* face, hb_tag_t table_tag, unsigned int script_index, unsigned int language_index, unsigned int start_offset, unsigned int* feature_count, # in/out hb_tag_t* feature_tags) # out unsigned int hb_ot_layout_script_get_language_tags( hb_face_t* face, hb_tag_t table_tag, unsigned int script_index, unsigned int start_offset, unsigned int* language_count, # in/out hb_tag_t* language_tags) # out unsigned int hb_ot_layout_table_get_script_tags( hb_face_t* face, hb_tag_t table_tag, unsigned int start_offset, unsigned int* script_count, # in/out hb_tag_t* script_tags) # out ctypedef enum hb_ot_layout_baseline_tag_t: HB_OT_LAYOUT_BASELINE_TAG_ROMAN HB_OT_LAYOUT_BASELINE_TAG_HANGING HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT HB_OT_LAYOUT_BASELINE_TAG_MATH hb_bool_t hb_ot_layout_get_baseline( hb_font_t* font, hb_ot_layout_baseline_tag_t baseline_tag, hb_direction_t direction, hb_tag_t script_tag, hb_tag_t language_tag, hb_position_t* coord) # out hb_bool_t hb_ot_layout_has_glyph_classes(hb_face_t *face) hb_bool_t hb_ot_layout_has_positioning(hb_face_t *face) hb_bool_t hb_ot_layout_has_substitution(hb_face_t *face) ctypedef enum hb_ot_layout_glyph_class_t: HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE HB_OT_LAYOUT_GLYPH_CLASS_MARK HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT hb_ot_layout_glyph_class_t hb_ot_layout_get_glyph_class(hb_face_t *face, hb_codepoint_t glyph) # hb-ot-font.h void hb_ot_font_set_funcs(hb_font_t* font) # hb-ot-name.h ctypedef unsigned int hb_ot_name_id_t ctypedef enum hb_ot_name_id_predefined_t: HB_OT_NAME_ID_COPYRIGHT HB_OT_NAME_ID_FONT_FAMILY HB_OT_NAME_ID_FONT_SUBFAMILY HB_OT_NAME_ID_UNIQUE_ID HB_OT_NAME_ID_FULL_NAME HB_OT_NAME_ID_VERSION_STRING HB_OT_NAME_ID_POSTSCRIPT_NAME HB_OT_NAME_ID_TRADEMARK HB_OT_NAME_ID_MANUFACTURER HB_OT_NAME_ID_DESIGNER HB_OT_NAME_ID_DESCRIPTION HB_OT_NAME_ID_VENDOR_URL HB_OT_NAME_ID_DESIGNER_URL HB_OT_NAME_ID_LICENSE HB_OT_NAME_ID_LICENSE_URL HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY HB_OT_NAME_ID_MAC_FULL_NAME HB_OT_NAME_ID_SAMPLE_TEXT HB_OT_NAME_ID_CID_FINDFONT_NAME HB_OT_NAME_ID_WWS_FAMILY HB_OT_NAME_ID_WWS_SUBFAMILY HB_OT_NAME_ID_LIGHT_BACKGROUND HB_OT_NAME_ID_DARK_BACKGROUND HB_OT_NAME_ID_VARIATIONS_PS_PREFIX HB_OT_NAME_ID_INVALID ctypedef struct hb_ot_name_entry_t: hb_ot_name_id_t name_id hb_language_t language const hb_ot_name_entry_t *hb_ot_name_list_names( hb_face_t *face, unsigned int *num_entries) # OUT. May be NULL. unsigned int hb_ot_name_get_utf16( hb_face_t *face, hb_ot_name_id_t name_id, hb_language_t language, unsigned int *text_size, # IN/OUT. May be NULL. uint16_t *text) # OUT. unsigned int hb_ot_name_get_utf32( hb_face_t *face, hb_ot_name_id_t name_id, hb_language_t language, unsigned int *text_size, # IN/OUT. May be NULL. uint32_t *text) # OUT. unsigned int hb_ot_name_get_utf8( hb_face_t *face, hb_ot_name_id_t name_id, hb_language_t language, unsigned int *text_size, # IN/OUT. May be NULL. char *text) # OUT. # hb-ot-color.h hb_bool_t hb_ot_color_has_palettes(hb_face_t *face) unsigned int hb_ot_color_palette_get_count(hb_face_t *face) hb_ot_name_id_t hb_ot_color_palette_get_name_id(hb_face_t *face, unsigned int palette_index) hb_ot_name_id_t hb_ot_color_palette_color_get_name_id(hb_face_t *face, unsigned int color_index) ctypedef enum hb_ot_color_palette_flags_t: HB_OT_COLOR_PALETTE_FLAG_DEFAULT HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND hb_ot_color_palette_flags_t hb_ot_color_palette_get_flags(hb_face_t *face, unsigned int palette_index) unsigned int hb_ot_color_palette_get_colors( hb_face_t *face, unsigned int palette_index, unsigned int start_offset, unsigned int *color_count, # IN/OUT. May be NULL. hb_color_t *colors) # OUT. May be NULL. hb_bool_t hb_ot_color_has_layers(hb_face_t *face) ctypedef struct hb_ot_color_layer_t: hb_codepoint_t glyph unsigned int color_index unsigned int hb_ot_color_glyph_get_layers( hb_face_t *face, hb_codepoint_t glyph, unsigned int start_offset, unsigned int *layer_count, # IN/OUT. May be NULL. hb_ot_color_layer_t *layers) # OUT. May be NULL. hb_bool_t hb_ot_color_has_paint(hb_face_t *face) hb_bool_t hb_ot_color_glyph_has_paint(hb_face_t *face, hb_codepoint_t glyph) hb_bool_t hb_ot_color_has_svg(hb_face_t *face) hb_blob_t *hb_ot_color_glyph_reference_svg(hb_face_t *face, hb_codepoint_t glyph) hb_bool_t hb_ot_color_has_png(hb_face_t *face) hb_blob_t *hb_ot_color_glyph_reference_png(hb_font_t *font, hb_codepoint_t glyph) # hb-ot-math.h ctypedef enum hb_ot_math_constant_t: HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT HB_OT_MATH_CONSTANT_MATH_LEADING HB_OT_MATH_CONSTANT_AXIS_HEIGHT HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN HB_OT_MATH_CONSTANT_STACK_GAP_MIN HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT ctypedef enum hb_ot_math_kern_t: HB_OT_MATH_KERN_TOP_RIGHT HB_OT_MATH_KERN_TOP_LEFT HB_OT_MATH_KERN_BOTTOM_RIGHT HB_OT_MATH_KERN_BOTTOM_LEFT ctypedef enum hb_ot_math_glyph_part_flags_t: HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER ctypedef struct hb_ot_math_kern_entry_t: hb_position_t max_correction_height hb_position_t kern_value ctypedef struct hb_ot_math_glyph_variant_t: hb_codepoint_t glyph hb_position_t advance ctypedef struct hb_ot_math_glyph_part_t: hb_codepoint_t glyph hb_position_t start_connector_length hb_position_t end_connector_length hb_position_t full_advance hb_ot_math_glyph_part_flags_t flags hb_bool_t hb_ot_math_has_data(hb_face_t *face) hb_position_t hb_ot_math_get_constant( hb_font_t *font, hb_ot_math_constant_t constant) hb_position_t hb_ot_math_get_glyph_italics_correction( hb_font_t *font, hb_codepoint_t glyph) hb_position_t hb_ot_math_get_glyph_top_accent_attachment( hb_font_t *font, hb_codepoint_t glyph) hb_bool_t hb_ot_math_is_glyph_extended_shape( hb_face_t *face, hb_codepoint_t glyph) hb_position_t hb_ot_math_get_glyph_kerning( hb_font_t *font, hb_codepoint_t glyph, hb_ot_math_kern_t kern, hb_position_t correction_height) unsigned int hb_ot_math_get_glyph_kernings( hb_font_t *font, hb_codepoint_t glyph, hb_ot_math_kern_t kern, unsigned int start_offset, unsigned int *entries_count, # in/out hb_ot_math_kern_entry_t *kern_entries) # out unsigned int hb_ot_math_get_glyph_variants( hb_font_t *font, hb_codepoint_t glyph, hb_direction_t direction, unsigned int start_offset, unsigned int *variants_count, # in/out hb_ot_math_glyph_variant_t *variants) # out hb_position_t hb_ot_math_get_min_connector_overlap( hb_font_t *font, hb_direction_t direction) unsigned int hb_ot_math_get_glyph_assembly( hb_font_t *font, hb_codepoint_t glyph, hb_direction_t direction, unsigned int start_offset, unsigned int *parts_count, # in/out hb_ot_math_glyph_part_t *parts, # out hb_position_t *italics_correction) # out # hb-ot-metrics.h ctypedef enum hb_ot_metrics_tag_t: HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT HB_OT_METRICS_TAG_VERTICAL_ASCENDER HB_OT_METRICS_TAG_VERTICAL_DESCENDER HB_OT_METRICS_TAG_VERTICAL_LINE_GAP HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET HB_OT_METRICS_TAG_VERTICAL_CARET_RISE HB_OT_METRICS_TAG_VERTICAL_CARET_RUN HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET HB_OT_METRICS_TAG_X_HEIGHT HB_OT_METRICS_TAG_CAP_HEIGHT HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET HB_OT_METRICS_TAG_STRIKEOUT_SIZE HB_OT_METRICS_TAG_STRIKEOUT_OFFSET HB_OT_METRICS_TAG_UNDERLINE_SIZE HB_OT_METRICS_TAG_UNDERLINE_OFFSET hb_bool_t hb_ot_metrics_get_position( hb_font_t *font, hb_ot_metrics_tag_t metrics_tag, hb_position_t *position) void hb_ot_metrics_get_position_with_fallback( hb_font_t *font, hb_ot_metrics_tag_t metrics_tag, hb_position_t *position) float hb_ot_metrics_get_variation( hb_font_t *font, hb_ot_metrics_tag_t metrics_tag) hb_position_t hb_ot_metrics_get_x_variation( hb_font_t *font, hb_ot_metrics_tag_t metrics_tag) hb_position_t hb_ot_metrics_get_y_variation( hb_font_t *font, hb_ot_metrics_tag_t metrics_tag) # hb-ot-var.h ctypedef enum hb_ot_var_axis_flags_t: HB_OT_VAR_AXIS_FLAG_HIDDEN _HB_OT_VAR_AXIS_FLAG_MAX_VALUE ctypedef struct hb_ot_var_axis_info_t: unsigned int axis_index hb_tag_t tag hb_ot_name_id_t name_id hb_ot_var_axis_flags_t flags float min_value float default_value float max_value unsigned int reserved hb_bool_t hb_ot_var_has_data(hb_face_t *face) unsigned int hb_ot_var_get_axis_count(hb_face_t *face) unsigned int hb_ot_var_get_axis_infos( hb_face_t *face, unsigned int start_offset, unsigned int *axes_count, # IN/OUT hb_ot_var_axis_info_t *axes_array) # OUT hb_bool_t hb_ot_var_find_axis_info( hb_face_t *face, hb_tag_t tag, hb_ot_var_axis_info_t *axis_info) unsigned int hb_ot_var_get_named_instance_count(hb_face_t *face) hb_ot_name_id_t hb_ot_var_named_instance_get_subfamily_name_id( hb_face_t *face, unsigned int instance_index) hb_ot_name_id_t hb_ot_var_named_instance_get_postscript_name_id( hb_face_t *face, unsigned int instance_index) unsigned int hb_ot_var_named_instance_get_design_coords( hb_face_t *face, unsigned int instance_index, unsigned int *coords_length, # IN/OUT float *coords) # OUT void hb_ot_var_normalize_variations( hb_face_t *face, const hb_variation_t *variations, # IN unsigned int variations_length, int *coords, # OUT unsigned int coords_length) void hb_ot_var_normalize_coords( hb_face_t *face, unsigned int coords_length, const float *design_coords, # IN int *normalized_coords) # OUT cdef extern from "hb-subset-serialize.h": ctypedef struct hb_subset_serialize_link_t: unsigned int width unsigned int position unsigned int objidx ctypedef struct hb_subset_serialize_object_t: char *head char *tail unsigned int num_real_links hb_subset_serialize_link_t *real_links unsigned int num_virtual_links hb_subset_serialize_link_t *virtual_links hb_blob_t* hb_subset_serialize_or_fail( hb_tag_t table_tag, hb_subset_serialize_object_t* hb_objects, unsigned int num_hb_objs) cdef extern from "hb-subset.h": ctypedef struct hb_subset_input_t: pass ctypedef struct hb_subset_plan_t: pass ctypedef enum hb_subset_flags_t: HB_SUBSET_FLAGS_DEFAULT HB_SUBSET_FLAGS_NO_HINTING HB_SUBSET_FLAGS_RETAIN_GIDS HB_SUBSET_FLAGS_DESUBROUTINIZE HB_SUBSET_FLAGS_NAME_LEGACY HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED HB_SUBSET_FLAGS_NOTDEF_OUTLINE HB_SUBSET_FLAGS_GLYPH_NAMES HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE ctypedef enum hb_subset_sets_t: HB_SUBSET_SETS_GLYPH_INDEX HB_SUBSET_SETS_UNICODE HB_SUBSET_SETS_NO_SUBSET_TABLE_TAG HB_SUBSET_SETS_DROP_TABLE_TAG HB_SUBSET_SETS_NAME_ID HB_SUBSET_SETS_NAME_LANG_ID HB_SUBSET_SETS_LAYOUT_FEATURE_TAG HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG hb_subset_input_t* hb_subset_input_create_or_fail() hb_subset_input_t* hb_subset_input_reference(hb_subset_input_t* input) void hb_subset_input_destroy(hb_subset_input_t* input) hb_bool_t hb_subset_input_set_user_data(hb_subset_input_t* input, hb_user_data_key_t* key, void* data, hb_destroy_func_t destroy, hb_bool_t replace) void* hb_subset_input_get_user_data(const hb_subset_input_t* input, hb_user_data_key_t* key) void hb_subset_input_keep_everything(hb_subset_input_t* input) hb_set_t* hb_subset_input_unicode_set(hb_subset_input_t* input) hb_set_t* hb_subset_input_glyph_set(hb_subset_input_t* input) hb_set_t* hb_subset_input_set(hb_subset_input_t* input, hb_subset_sets_t set_type) hb_subset_flags_t hb_subset_input_get_flags(hb_subset_input_t* input) void hb_subset_input_set_flags(hb_subset_input_t* input, unsigned value) hb_bool_t hb_subset_input_pin_all_axes_to_default( hb_subset_input_t *input, hb_face_t *face) hb_bool_t hb_subset_input_pin_axis_to_default(hb_subset_input_t* input, hb_face_t* face, hb_tag_t axis_tag) hb_bool_t hb_subset_input_pin_axis_location(hb_subset_input_t* input, hb_face_t* face, hb_tag_t axis_tag, float axis_value) hb_bool_t hb_subset_input_get_axis_range( hb_subset_input_t *input, hb_tag_t axis_tag, float *axis_min_value, float *axis_max_value, float *axis_def_value) hb_bool_t hb_subset_input_set_axis_range( hb_subset_input_t *input, hb_face_t *face, hb_tag_t axis_tag, float axis_min_value, float axis_max_value, float axis_def_value) hb_face_t* hb_subset_preprocess(hb_face_t* source) hb_face_t* hb_subset_or_fail(hb_face_t* source, const hb_subset_input_t* input) hb_face_t* hb_subset_plan_execute_or_fail(hb_subset_plan_t* plan) hb_subset_plan_t* hb_subset_plan_create_or_fail(hb_face_t* face, const hb_subset_input_t* input) void hb_subset_plan_destroy(hb_subset_plan_t* plan) const hb_map_t* hb_subset_plan_old_to_new_glyph_mapping(const hb_subset_plan_t* plan) const hb_map_t* hb_subset_plan_new_to_old_glyph_mapping(const hb_subset_plan_t* plan) const hb_map_t* hb_subset_plan_unicode_to_old_glyph_mapping(const hb_subset_plan_t* plan) hb_subset_plan_t* hb_subset_plan_reference(hb_subset_plan_t* plan) hb_bool_t hb_subset_plan_set_user_data(hb_subset_plan_t* plan, hb_user_data_key_t* key, void* data, hb_destroy_func_t destroy, hb_bool_t replace) void* hb_subset_plan_get_user_data(const hb_subset_plan_t* plan, hb_user_data_key_t* key) uharfbuzz-0.53.3/tests/000077500000000000000000000000001513514046200147655ustar00rootroot00000000000000uharfbuzz-0.53.3/tests/data/000077500000000000000000000000001513514046200156765ustar00rootroot00000000000000uharfbuzz-0.53.3/tests/data/AUTHORS_StixTwoMath.txt000066400000000000000000000010151513514046200220740ustar00rootroot00000000000000# This is the official list of project authors for copyright purposes. # This file is distinct from the CONTRIBUTORS.txt file. # See the latter for an explanation. # # Names should be added to this file as: # Name or Organization The STI Pub Companies # The STI Pub Companies is a consortium consisting of AIP Publishing, # American Chemical Society, American Mathematical Society, American # Physical Society, Elsevier, Inc., and The Institute of Electrical # and Electronic Engineers, Inc. uharfbuzz-0.53.3/tests/data/AdobeBlank.fea000066400000000000000000000001251513514046200203330ustar00rootroot00000000000000feature calt { sub e d c' b a by a; } calt; feature kern { pos b a 100; } kern; uharfbuzz-0.53.3/tests/data/AdobeBlank.subset.ttf000066400000000000000000000035441513514046200217110ustar00rootroot00000000000000BASElgGPOSwPGSUB׹N~OS/2S`cmap~cvt fpgm*Zhgasp glyf 4head c6hhearsT$hmtx|loca maxpx name"icfbicftideoromnkanalatn0 3y 2x ,DFLTkern d ,DFLTcalt>>$*uharfbuzz-0.53.3/tests/data/LICENSE_AdobeBlank.txt000066400000000000000000000103151513514046200215630ustar00rootroot00000000000000This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL ----------------------------------------------------------- SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ----------------------------------------------------------- PREAMBLE The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. DEFINITIONS "Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. "Reserved Font Name" refers to any names specified as such after the copyright statement(s). "Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s). "Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. "Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. PERMISSION & CONDITIONS Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: 1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. 2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. 3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. 5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. TERMINATION This license becomes null and void if any of the above conditions are not met. DISCLAIMER THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. uharfbuzz-0.53.3/tests/data/LICENSE_ChromaCheck_colr.txt000066400000000000000000000021571513514046200227740ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2018 Roel Nieskens, https://pixelambacht.nl Copyright (c) 2018 Google LLC 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. uharfbuzz-0.53.3/tests/data/LICENSE_MutatorSans.txt000066400000000000000000000020621513514046200220610ustar00rootroot00000000000000MIT License Copyright (c) 2017 Erik van Blokland 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. uharfbuzz-0.53.3/tests/data/LICENSE_OpenSans.txt000066400000000000000000000217121513514046200213320ustar00rootroot00000000000000Copyright Digitized data copyright © 2010-2011, Google Corporation. License Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.uharfbuzz-0.53.3/tests/data/LICENSE_STIXTwoMath.txt000066400000000000000000000114221513514046200216740ustar00rootroot00000000000000Copyright 2001-2021 The STIX Fonts Project Authors (https://github.com/stipub/stixfonts) STIX Fonts™ is a trademark of The Institute of Electrical and Electronics Engineers, Inc. Portions copyright © 1998–2003 by MicroPress, Inc. (www.micropress-inc.com), with Reserved Font Name TM Math. To obtain additional mathematical fonts, please contact MicroPress, Inc., 68-30 Harrow Street, Forest Hills, NY 11375, USA Phone: (718) 575-1816. Portions copyright © 1990 by Elsevier, Inc. Portions copyright © 2010, 2012, 2014 Adobe Systems Incorporated. This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL ----------------------------------------------------------- SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ----------------------------------------------------------- PREAMBLE The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. DEFINITIONS "Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. "Reserved Font Name" refers to any names specified as such after the copyright statement(s). "Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s). "Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. "Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. PERMISSION & CONDITIONS Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: 1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. 2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. 3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. 5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. TERMINATION This license becomes null and void if any of the above conditions are not met. DISCLAIMER THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. uharfbuzz-0.53.3/tests/data/MutatorSans-VF.subset.ttf000066400000000000000000000100501513514046200225060ustar00rootroot00000000000000 GDEF=61XGPOS0r?, TjGSUBDvLu HVARt]H MVARйC bOS/2cX`STAT $cmapy[X    &  & 4$ LX 2  >License same as MutatorMath. BSD 3-clause. [test-token: C]Regular1.002;LTTR;MutatorMathTest-LightCondensedMutatorMathTest LightCondensedVersion 1.002MutatorMathTest-LightCondensedWidthWeightLightCondensedBoldCondensedMutatorMathTest-BoldCondensedLightWideMutatorMathTest-LightWideBoldWideMutatorMathTest-BoldWideMedium_Narrow_IMutatorMathTest-Medium_Narrow_ITwoMutatorMathTest-TwoOneMutatorMathTest-Onewidth_794.52_weight_775.61MutatorSans-width_794.52_weight_775.61width_93.05_weight_658.60Medium_Wide_I2$%& 4@@@@@@@@<- ,DFLTkernD$ DFLTTZr@@,@,@@@@@@@@X $C V$cphthaschlgp 4@@@@@@@@dwdthwght wdthwght  G  9 ] PH ,Vb@@@@2 : / K%l|6< C#:fDbXdd@ddd@k?G> CC@ ă(d ,@@,@}<0009YyVrE"""Bk@ʁ HHcccH#HHHB2!424/" BaC)DuH555BnX333% >1)))))S!!!N@@ ddfffFĦddd\E.IFHA/#CmPPPnnHnnRWgrtttiacOMV```[USVnnF@V  l{jGttMssE@$     fEa`4hhE5`aflNk@Cr\D,39PddddK" ǖ3{FC=A5pAp5H<@b*fff*DbA@ %. uharfbuzz-0.53.3/tests/data/OpenSans.subset.ttf000066400000000000000000000065401513514046200214540ustar00rootroot00000000000000GDEF GPOS 4GSUBlt DOS/2} (`cmap t,cvt M tfpgm~agasp# glyf)u~headv6hhea $hmtx loca?maxp  name # postif prepC h 9@ IY ?3?9/9+9933910!!#3&'`B?e!#)/DjV}`s;V/\?'_< 51LL b  { 33f 1ASC@AAX H   AA@G[ZYXUTSRQPONMLKJIHGFEDCBA@?>=<;:9876510/.-,('&%$#"! , `E% Fa#E#aH-, EhD-,E#F` a F`&#HH-,E#F#a ` &a a&#HH-,E#F`@a f`&#HH-,E#F#a@` &a@a&#HH-, <<-, E# D# ZQX# D#Y QX# MD#Y &QX# D#Y!!-, EhD ` EFvhE`D-, C#Ce -, C#C -,(#p(>(#p(E: -, E%EadPQXED!!Y-,I#D-, EC`D-,CCe -, i@a ,b`+ d#da\XaY-,E+)#D)z-,Ee,#DE+#D-,KRXED!!Y-,KQXED!!Y-,%# `#-,%# a#-,%-,CRX!!!!!F#F`F# F`ab# # pE` PXaFY`h:Y-, E%FRKQ[X%F ha%%?#!8!Y-, E%FPX%F ha%%?#!8!Y-,CC -,!! d#d@b-,!QX d#d b@/+Y`-,!QX d#dUb/+Y`-, d#d@b`#!-,KSX%Id#Ei@ab aj#D#!# 9/Y-,KSX %Idi &%Id#ab aj#D&#D#D& 9# 9//Y-,E#E`#E`#E`#vhb -,H+-, ETX@D E@aD!!Y-,E0/E#Ea``iD-,KQX/#p#B!!Y-,KQX %EiSXD!!Y!!Y-,EC`c`iD-,/ED-,E# E`D-,E#E`D-,K#QX34 34YDD-,CX&EXdf`d `f X!@YaY#XeY)#D#)!!!!!Y-,CTXKS#KQZX8!!Y!!!!Y-,CX%Ed `f X!@Ya#XeY)#D%% XY%% F%#B<%%%% F%`#B< XY%%)) EeD%%)%% XY%%CH%%%%`CH!Y!!!!!!!-,% F%#B%%EH!!!!-,% %%CH!!!-,E# E P X#e#Y#h @PX!@Y#XeY`D-,KS#KQZX E`D!!Y-,KTX E`D!!Y-,KS#KQZX8!!Y-,!KTX8!!Y-,CTXF+!!!!Y-,CTXG+!!!Y-,CTXH+!!!!Y-,CTXI+!!!Y-, #KSKQZX#8!!Y-,%ISX @8!Y-,F#F`#Fa#  Fab@@pE`h:-, #Id#SX<!Y-,KRX}zY-,KKTB-,B#Q@SZX TXC`BY$QX @TXC`B$TX C`BKKRXC`BY@TXC`BY@cTXC`BY@cTXC`BY&QX@cTX@C`BY@cTXC`BYYYYYYCTX@ @@ @  CTX@   CRX@ @@ @Y@U@cUZX  YYYBBBBB-,Eh#KQX# E d@PX|Yh`YD-,%%#>#> #eB #B#?#? #eB#B-,CPCT[X!# Y-,Y+-,-@ !H U UHU?MK&LK3KF%&4U%3$UJI3IF%3UU3U?GFF#3"U3U3UU3UOU3UoTS++KRK P[%S@QZUZ[XYBK2SX YKdSXBYss++^stu+++++t+st+++++++++++++st+++^NuHN   <   \ tOpen SansRegularAscender - Open Sans Build 100Version 1.10OpenSansff    latnuharfbuzz-0.53.3/tests/data/STIXTwoMath-Regular.ttf000066400000000000000000003127101513514046200221130ustar00rootroot00000000000000@MATHQ*khead% L6maxp%!< postO*!HÚk_<Yᰠ. Ch q^D3h$%&'()*+,-./0123456789:;<=b     cd !"e#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[f\]^_`abcdefgghijklmnopqrstuvwxyz{|}~hDEFGHIJKLMNOPQRSTUVWXYZ[\]jikmlnoqprsutvw      !"#$%&'x()*+,-zy{./012}34|56789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a~bcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()C*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"?_ >@^`  AaB# !      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~                           ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~        !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|uni00A0uni1EA6uni1EA4uni1EAAuni1EA8uni1EACuni01DEAmacronAbreveuni1EB0uni1EAEuni1EB4uni1EB2uni1EB6 Aringacuteuni1EA2uni1E00uni1EA0AogonekAEacuteuni1E02uni1E06uni1E04 Ccircumflex Cdotaccentuni1E08Dcaronuni1E0Auni1E12uni1E0Euni1E0Cuni1E10Dcroatuni1EC0uni1EBEuni1EC4uni1EC2uni1EC6Ecaronuni1EBCEmacronuni1E14uni1E16Ebreve Edotaccentuni1EBAuni1E18uni1E1Auni1EB8uni0228uni1E1CEogonekuni1E1E Gcircumflexuni1E20 Gdotaccent Gcommaaccent Hcircumflexuni1E26uni1E22uni1E2Auni1E24uni1E28HbarItildeuni1E2EImacronIbreveuni1EC8uni1E2Cuni1ECAIogonek Jcircumflexuni1E30uni1E34uni1E32 KcommaaccentLacuteLcaronuni1E38uni1E3Cuni1E3Auni1E36 LcommaaccentLdotuni1E3Euni1E40uni1E42NacuteNcaronuni1E44uni1E4Auni1E48uni1E46 Ncommaaccentuni1ED2uni1ED0uni1ED6uni1ED4uni1ED8uni1E4Cuni1E4EOmacronuni1E50uni1E52Obreveuni1ECE Ohungarumlautuni1ECCOhornuni1EDCuni1EDAuni1EE0uni1EDEuni1EE2 Oslashacuteuni1E54uni1E56RacuteRcaronuni1E5Cuni1E58uni1E5Euni1E5A RcommaaccentSacuteuni1E64 Scircumflexuni1E66uni1E60uni1E68uni1E62uni0218uni015Euni1E9ETcaronuni1E6Auni1E70uni1E6Euni1E6Cuni021Auni0162TbarUtildeuni1E78Umacronuni1E7AUbreveUringuni1EE6 Uhungarumlautuni1E76uni1E74uni1E72uni1EE4UogonekUhornuni1EEAuni1EE8uni1EEEuni1EECuni1EF0uni1E7Cuni1E7EWgraveWacute Wcircumflex Wdieresisuni1E86uni1E88uni1E8Cuni1E8AYgrave Ycircumflexuni1EF8uni1E8Euni1EF6uni1EF4Zacuteuni1E90 Zdotaccentuni1E94uni1E92uni01B5uni0190uni2132EngIJi.TRKuni1EA7uni1EA5uni1EABuni1EA9uni1EADuni01DFamacronabreveuni1EB1uni1EAFuni1EB5uni1EB3uni1EB7 aringacuteuni1EA3uni1E9Auni1E01uni1EA1aogonekaeacuteuni1E03uni1E07uni1E05uni0253 ccircumflex cdotaccentuni1E09uni0188dcaronuni1E0Buni1E13uni1E0Funi1E0Duni1E11uni0257uni0256uni1EC1uni1EBFuni1EC5uni1EC3uni1EC7ecaronuni1EBDemacronuni1E15uni1E17ebreve edotaccentuni1EBBuni1E19uni1E1Buni1EB9uni0229uni1E1Deogonekuni1E1Funi0192 gcircumflexuni1E21 gdotaccent gcommaaccentuni0260 hcircumflexuni1E27uni1E23uni1E96uni1E2Buni1E25uni1E29hbar i.dotlessitildeuni1E2Fimacronibreveuni1EC9uni1E2Duni1ECBiogonekuni0268 j.dotless jcircumflexuni01F0uni0237uni1E31uni1E35uni1E33 kcommaaccentuni0199 kgreenlandiclacutelcaronuni1E39uni1E3Duni1E3Buni1E37 lcommaaccentldotuni019Auni026Buni1E3Funi1E41uni1E43nacutencaronuni1E45uni1E4Buni1E49uni1E47 ncommaaccent napostropheuni1ED3uni1ED1uni1ED7uni1ED5uni1ED9uni1E4Duni1E4Fomacronuni1E51uni1E53obreve ohungarumlautuni1ECFuni1ECDohornuni1EDDuni1EDBuni1EE1uni1EDFuni1EE3 oslashacuteuni0275uni1E55uni1E57uni01A5racutercaronuni1E5Duni1E59uni1E5Funi1E5B rcommaaccentsacuteuni1E65 scircumflexuni1E67uni1E61uni1E69uni1E63uni0219uni015Ftcaronuni1E97uni1E6Buni1E71uni1E6Funi1E6Duni021Buni0163uni01ADuni0288tbarutildeuni1E79umacronuni1E7Bubreveuringuni1EE7 uhungarumlautuni1E77uni1E75uni1E73uni1EE5uogonekuhornuni1EEBuni1EE9uni1EEFuni1EEDuni1EF1uni0289uni1E7Duni1E7Funi028Bwgravewacute wcircumflex wdieresisuni1E98uni1E87uni1E89uni1E8Duni1E8Bygrave ycircumflexuni1EF9uni1E99uni1E8Funi1EF7uni1EF5zacuteuni1E91 zdotaccentuni1E95uni1E93uni0250uni0251uni0252uni1D00uni0180uni0299uni0255uni0297uni0221uni1D81uni1E9Funi0258uni0259uni025Auni025Buni025Cuni025Duni029Auni025Euni1D07uni0261uni0262uni029Buni0263uniA727uni0267uni0266uni0265uni02AEuni02AFuni029Cuni0195uni026Auni029Duni025Funi0269uni1D84uni029Euni026Cuni0234uni1D85uni026Duni029Funi019B uni019B.varuni0271uni026Funi0270uni0235uni0272uni0273uni019Eenguni0274uni0254uni0276uni02A0uni027Duni027Cuni0279uni027Buni027Auni027Euni027Funi0280uni0281uni0282uni1D8Alongsuni1E9Buni1E9Cuni1E9Duni01ABuni0236uni0287uni1D1Cuni028Duni1D8Duni028Euni028Funi0291uni0290uni1D8Euni0292uni0293uni01BAuni0283uni0284uni0286uni01AAuni0285uni1D98uni028Auni028Cuni0294uni02A1uni0295uni02A2uni0296uni01BEuni0264 uni0264.varuni01BBuni0278uni0277uni01C2uni01C0uni01C1uni01C3uni0298uni02ACuni02ADuni02A4uni02A3uni02A5uni02A9ijuni02AAuni02ABuni026Euni02A8uni02A6uni02A7f_ff_f_if_f_lf_if_luni2071 nsuperioruni02B0uni02B1uni02B2uni02E1uni02B3uni02B4uni02B5uni02B6uni02E2uni02B7uni02E3uni02B8uni02E4uni02B9uni02BAuni02BBuni02BCuni02BDuni02BEuni02BFuni02C0uni02C1uni02C2uni02C3uni02C4uni02C5uni02CBuni02CAuni02C9uni02C8uni02CCuni02CDuni02CEuni02CFuni02D0uni02D1uni02D2uni02D3uni02D4uni02D5uni02D6uni02D7uni02DEuni02DFuni02E0uni1DA3uni02E5uni02E6uni02E7uni02E8uni02E9uni02ECuni02EDuni02F7uni0300 uni0300.capuni0301 uni0301.capuni0302 uni0302.cap uni03020300uni03020300.cap uni03020301uni03020301.cap uni03020303uni03020303.cap uni03020309uni03020309.capuni0303 uni0303.capuni0304 uni0304.capuni0305 uni0305.capuni0306 uni0306.cap uni03060300uni03060300.cap uni03060301uni03060301.cap uni03060303uni03060303.cap uni03060309uni03060309.capuni0307 uni0307.capuni0308 uni0308.capuni0309 uni0309.capuni030A uni030A.capuni030B uni030B.capuni030C uni030C.capuni030D uni030D.capuni030E uni030E.capuni030F uni030F.capuni0310 uni0310.capuni0311 uni0311.capuni0312 uni0312.capuni0313 uni0313.capuni0314 uni0314.capuni0315 uni0315.capuni031A uni031A.capuni031B uni031B.capuni033F uni033F.capuni0346 uni0346.capuni034C uni034C.capuni0360 uni0360.capuni0361 uni0361.capuni0316uni0317uni0318uni0319uni031Cuni031Duni031Euni031Funi0320uni0321uni0322uni0323uni0324uni0325uni0326uni0327uni0328uni0329uni032Auni032Buni032Cuni032Duni032Euni032Funi0330uni0331uni0332uni0333uni0339uni033Auni033Buni033Cuni033Duni033Euni0347uni0359uni035Cuni0362uni0334uni0335uni0336uni0337uni0338AlphaBetaGammaEpsilonZetaEtaThetaIotaKappaLambdaMuNuXiOmicronPiRhoSigmaTauUpsilonPhiChiPsiuni03DCuni03F4uni03D8uni03D2uni03DEuni03E0uni03DA Alphatonos EpsilontonosEtatonos Iotatonos Iotadieresis Omicrontonos UpsilontonosUpsilondieresis Omegatonosalphabetagammadeltaepsilonzetaetathetaiotakappalambdanuxiomicronrhosigmauni03C2tauupsilonphichipsiomegauni03DDuni03D9uni03DFuni03E1uni03DBuni03D0uni03F5uni03F6uni03D1uni03F0uni03D6uni03F1uni03D5 alphatonos epsilontonosetatonos iotatonos iotadieresisiotadieresistonos omicrontonos upsilontonosupsilondieresisupsilondieresistonos omegatonostonosdieresis.Greek dieresistonos anoteleiaanoteleia.caseuni037Euni0410uni0411uni0412uni0413uni0414uni0415uni0416uni0417uni0418uni0419uni041Auni041Buni041Cuni041Duni041Euni041Funi0420uni0421uni0422uni0423uni0424uni0425uni0426uni0427uni0428uni0429uni042Auni042Buni042Cuni042Duni042Euni042Funi0462uni0472uni0474uni046Auni0403uni0490uni0400uni0402uni0401uni0404uni0405uni040Funi040Duni0406uni0407uni0408uni040Cuni0409uni040Auni040Buni040Euni0430uni0431uni0432uni0433uni0434uni0435uni0436uni0437uni0438uni0439uni043Auni043Buni043Cuni043Duni043Euni043Funi0440uni0441uni0442uni0443uni0444uni0445uni0446uni0447uni0448uni0449uni044Auni044Buni044Cuni044Duni044Euni044Funi0463uni0473uni0475uni046Buni0453uni0491uni0450uni0452uni0451uni0454uni0455uni045Funi045Duni0456uni0457uni0458uni045Cuni0459uni045Auni045Buni045Ebrevecomb.Cyrillicbrevecomb.Cyrillic.capuni204F exclamdbluni2047uni2016uni204Euni2051uni2010uni00ADuni2011 figuredashuni2015 quotereverseduni201Funi204Buni203Buni204Cuni204Duni2043twodotenleaderuni2038 underscoredbluni203Euni2040uni2050uni2117 estimatedEurouni20A3uni20A4uni20A7uni20BDuni20BAuni20B9uni20ABuni2116 zerosuperior foursuperior fivesuperior sixsuperior sevensuperior eightsuperior ninesuperioruni207Auni207Buni207Cparenleftsuperiorparenrightsuperior zeroinferior oneinferior twoinferior threeinferior fourinferior fiveinferior sixinferior seveninferior eightinferior nineinferioruni208Auni208Buni208Cparenleftinferiorparenrightinferior oneeighthuni2159uni2155onethird threeeighthsuni2156uni2157 fiveeighths twothirdsuni2158uni215A seveneighthsuni2031uni2212uni2052minuteseconduni2034uni2057uni2035uni2036uni2037uni00B5uni2102uni2105uni2107 uni210A.ss01uni210Buni210Cuni210Duni210Euni210Funi2110uni2111uni2112uni2113uni2115uni2118uni2119uni211Auni211Buni211Cuni211Duni211Euni2124uni2125uni2126uni2127uni2128uni2129uni212Buni212Cuni212D uni212F.ss01uni2130uni2131uni2133 uni2134.ss01uni2135uni2136uni2137uni2138uni213Cuni213Duni213Euni213Funi2140uni2141uni2142uni2143uni2144uni2145uni2146uni2147uni2148uni2149uni214Auni214BuniA792uni20D0uni20D1uni20D2uni20D6uni20D7uni20DBuni20DCuni20DDuni20DEuni20DFuni20E1uni20E4uni20E5uni20E6uni20E7uni20E8uni20E9uni20EAuni20EBuni20ECuni20EDuni20EEuni20EFuni20F0uni205Funi25CC hyphen.cap uni210F.var parenleft.s1 parenleft.s2 parenleft.s3 parenleft.s4 parenleft.s5 parenleft.s6 parenleft.s7 parenleft.s8 parenleft.s9 parenleft.s10 parenleft.s11 parenleft.s12 parenright.s1 parenright.s2 parenright.s3 parenright.s4 parenright.s5 parenright.s6 parenright.s7 parenright.s8 parenright.s9parenright.s10parenright.s11parenright.s12bracketleft.s1bracketleft.s2bracketleft.s3bracketleft.s4bracketleft.s5bracketleft.s6bracketleft.s7bracketleft.s8bracketleft.s9bracketleft.s10bracketleft.s11bracketleft.s12bracketright.s1bracketright.s2bracketright.s3bracketright.s4bracketright.s5bracketright.s6bracketright.s7bracketright.s8bracketright.s9bracketright.s10bracketright.s11bracketright.s12 braceleft.s1 braceleft.s2 braceleft.s3 braceleft.s4 braceleft.s5 braceleft.s6 braceleft.s7 braceleft.s8 braceleft.s9 braceleft.s10 braceleft.s11 braceleft.s12 braceright.s1 braceright.s2 braceright.s3 braceright.s4 braceright.s5 braceright.s6 braceright.s7 braceright.s8 braceright.s9braceright.s10braceright.s11braceright.s12braceleft.s1.oldbraceleft.s2.oldbraceleft.s3.oldbraceleft.s4.oldbraceright.s1.oldbraceright.s2.oldbraceright.s3.oldbraceright.s4.oldslash.s1slash.s2slash.s3slash.s4 backslash.s1 backslash.s2 backslash.s3 backslash.s4bar.var underscore.s1 underscore.s2 underscore.s3 underscore.s4 underscore.s5 circumflex.s1 circumflex.s2 circumflex.s3 circumflex.s4 circumflex.s5caron.s1caron.s2caron.s3caron.s4caron.s5tilde.s1tilde.s2tilde.s3tilde.s4tilde.s5 tildelow.s1 tildelow.s2 tildelow.s3 tildelow.s4 tildelow.s5circumflexcomb.s1circumflexcomb.s2circumflexcomb.s3circumflexcomb.s4circumflexcomb.s5 tildecomb.s1 tildecomb.s2 tildecomb.s3 tildecomb.s4 tildecomb.s5overlinecomb.s1overlinecomb.s2overlinecomb.s3overlinecomb.s4overlinecomb.s5 caroncomb.s1 caroncomb.s2 caroncomb.s3 caroncomb.s4 caroncomb.s5tildebelowcomb.s1tildebelowcomb.s2tildebelowcomb.s3tildebelowcomb.s4tildebelowcomb.s5lowlinecomb.s1lowlinecomb.s2lowlinecomb.s3lowlinecomb.s4lowlinecomb.s5slashlongcomb.s1slashlongcomb.s2slashlongcomb.s3slashlongcomb.s4slashlongcomb.s5 minute.var second.varprimetriple.var primequad.varprimereversed.varprimedblreversed.varprimetriplereversed.var overline.s1 overline.s2 overline.s3 overline.s4 overline.s5 uni20D0.s1 uni20D0.s2 uni20D0.s3 uni20D0.s4 uni20D0.s5 uni20D1.s1 uni20D1.s2 uni20D1.s3 uni20D1.s4 uni20D1.s5 uni20D6.s1 uni20D6.s2 uni20D6.s3 uni20D6.s4 uni20D6.s5 uni20D6.x uni20D7.s1 uni20D7.s2 uni20D7.s3 uni20D7.s4 uni20D7.s5 uni20EC.s1 uni20EC.s2 uni20EC.s3 uni20EC.s4 uni20EC.s5 uni20ED.s1 uni20ED.s2 uni20ED.s3 uni20ED.s4 uni20ED.s5 uni20EE.s1 uni20EE.s2 uni20EE.s3 uni20EE.s4 uni20EE.s5 uni20EE.x uni20EF.s1 uni20EF.s2 uni20EF.s3 uni20EF.s4 uni20EF.s5 uni2140.s1 uni2140.varuni2190 uni2190.varuni2191 uni2191.varuni2192 uni2192.varuni2193 uni2193.varuni2194uni2195uni2196uni2197uni2198uni2199uni219Auni219Buni219Cuni219Duni219Euni219Funi21A0uni21A1uni21A2uni21A3uni21A4uni21A5uni21A6uni21A7uni21A8uni21A9uni21AAuni21ABuni21ACuni21ADuni21AEuni21AFuni21B0uni21B1uni21B2uni21B3uni21B4uni21B5uni21B6uni21B7uni21B8uni21B9uni21BAuni21BBuni21BCuni21BDuni21BEuni21BFuni21C0uni21C1uni21C2uni21C3uni21C4uni21C5uni21C6uni21C7uni21C8uni21C9uni21CAuni21CBuni21CCuni21CDuni21CEuni21CFuni21D0 uni21D0.xuni21D1 uni21D1.var uni21D1.xuni21D2uni21D3 uni21D3.varuni21D4uni21D5uni21D6uni21D7uni21D8uni21D9uni21DA uni21DA.xuni21DBuni21DCuni21DDuni21DEuni21DFuni21E0 uni21E0.varuni21E1uni21E2 uni21E2.varuni21E3uni21E4uni21E5uni21E6uni21E7uni21E8uni21E9uni21EAuni21F4uni21F5uni21F6uni21F7uni21F8uni21F9uni21FAuni21FBuni21FCuni21FDuni21FEuni21FFuni2200uni2201uni2203uni2204uni2205 uni2205.varuni2206uni2207uni2208 uni2208.varuni2209 uni2209.varuni220Auni220B uni220B.varuni220C uni220C.varuni220Duni220Euni220F uni220F.s1 uni220F.varuni2210 uni2210.s1 uni2210.varuni2211 uni2211.s1 uni2211.varuni2213uni2214uni2215uni2216 uni2216.varuni2217uni2218uni2219uni221A uni221A.s1 uni221A.s2 uni221A.s3 uni221A.s4 uni221A.t uni221A.var uni221A.xuni221B uni221B.s1 uni221B.s2 uni221B.s3 uni221B.s4 uni221B.varuni221C uni221C.s1 uni221C.s2 uni221C.s3 uni221C.s4 uni221C.varuni221D uni221D.varuni221Euni221Funi2220uni2221uni2222uni2223 uni2223.varuni2224 uni2224.varuni2225 uni2225.varuni2226 uni2226.varuni2227uni2228uni2229 uni2229.varuni222A uni222A.varuni222B uni222B.dsp uni222B.sm uni222B.up uni222B.updsp uni222B.upsmuni222C uni222C.dsp uni222C.sm uni222C.up uni222C.updsp uni222C.upsmuni222D uni222D.dsp uni222D.sm uni222D.up uni222D.updsp uni222D.upsmuni222E uni222E.dsp uni222E.sm uni222E.up uni222E.updsp uni222E.upsmuni222F uni222F.dsp uni222F.sm uni222F.up uni222F.updsp uni222F.upsmuni2230 uni2230.dsp uni2230.sm uni2230.up uni2230.updsp uni2230.upsmuni2231 uni2231.dsp uni2231.sm uni2231.up uni2231.updsp uni2231.upsmuni2232 uni2232.dsp uni2232.sm uni2232.up uni2232.updsp uni2232.upsmuni2233 uni2233.dsp uni2233.sm uni2233.up uni2233.updsp uni2233.upsmuni2234uni2235uni2236uni2237uni2238uni2239uni223Auni223Buni223C uni223C.varuni223Duni223E uni223E.varuni223F uni223F.varuni2240uni2241 uni2241.varuni2242uni2243uni2244 uni2244.varuni2245uni2246 uni2246.varuni2247 uni2247.varuni2248uni2249 uni2249.varuni224Auni224Buni224C uni224C.varuni224Duni224Euni224Funi2250uni2251uni2252uni2253uni2254uni2255uni2256uni2257uni2258uni2259uni225Auni225Buni225Cuni225Duni225Euni225Funi2260 uni2260.varuni2261uni2262 uni2262.varuni2263uni2264uni2265uni2266uni2267uni2268 uni2268.varuni2269 uni2269.varuni226Auni226Buni226Cuni226D uni226D.varuni226E uni226E.varuni226F uni226F.varuni2270 uni2270.varuni2271 uni2271.varuni2272 uni2272.varuni2273 uni2273.varuni2274 uni2274.varuni2275 uni2275.varuni2276uni2277uni2278 uni2278.varuni2279 uni2279.varuni227Auni227Buni227Cuni227Duni227Euni227Funi2280 uni2280.varuni2281 uni2281.varuni2282uni2283uni2284 uni2284.varuni2285 uni2285.varuni2286uni2287uni2288 uni2288.varuni2289 uni2289.varuni228A uni228A.varuni228B uni228B.varuni228Cuni228Duni228Euni228Funi2290uni2291uni2292uni2293 uni2293.varuni2294 uni2294.varuni2295 uni2295.varuni2296uni2297 uni2297.varuni2298uni2299uni229Auni229Buni229C uni229C.varuni229Duni229Euni229Funi22A0uni22A1uni22A2uni22A3uni22A4uni22A5uni22A6uni22A7uni22A8uni22A9uni22AAuni22ABuni22ACuni22ADuni22AEuni22AFuni22B0uni22B1uni22B2uni22B3uni22B4uni22B5uni22B6uni22B7uni22B8uni22B9uni22BAuni22BBuni22BCuni22BDuni22BEuni22BFuni22C0 uni22C0.s1uni22C1 uni22C1.s1uni22C2 uni22C2.s1uni22C3 uni22C3.s1uni22C4uni22C5uni22C6uni22C7uni22C8uni22C9uni22CAuni22CBuni22CCuni22CDuni22CEuni22CFuni22D0uni22D1uni22D2uni22D3uni22D4uni22D5uni22D6uni22D7uni22D8uni22D9uni22DA uni22DA.varuni22DB uni22DB.varuni22DCuni22DDuni22DEuni22DFuni22E0 uni22E0.varuni22E1 uni22E1.varuni22E2uni22E3uni22E4uni22E5uni22E6uni22E7uni22E8uni22E9uni22EAuni22EBuni22EC uni22EC.varuni22ED uni22ED.varuni22EEuni22EFuni22F0uni22F1uni22F2uni22F3uni22F4uni22F5uni22F6uni22F7uni22F8uni22F9uni22FAuni22FBuni22FCuni22FDuni22FEuni22FFuni2300uni2302uni2305uni2306uni2308 uni2308.s1 uni2308.s2 uni2308.s3 uni2308.s4uni2309 uni2309.s1 uni2309.s2 uni2309.s3 uni2309.s4uni230A uni230A.s1 uni230A.s2 uni230A.s3 uni230A.s4uni230B uni230B.s1 uni230B.s2 uni230B.s3 uni230B.s4uni230Cuni230Duni230Euni230Funi2310uni2311uni2312uni2313uni2315uni2316uni2317uni2318uni2319uni231Auni231Cuni231Duni231Euni231Funi2322 uni2322.varuni2323 uni2323.varuni2329uni232Auni232Cuni232Duni232Euni2332uni2336uni233Duni233Funi2340uni2353uni2370uni237Cuni2393uni2394uni23AFuni23B4 uni23B4.l uni23B4.r uni23B4.s1 uni23B4.s2 uni23B4.s3 uni23B4.s4 uni23B4.s5 uni23B4.xuni23B5 uni23B5.l uni23B5.r uni23B5.s1 uni23B5.s2 uni23B5.s3 uni23B5.s4 uni23B5.s5 uni23B5.xuni23B6 uni23B7.s1 uni23B8.s1 uni23B9.s1uni23CEuni23D0uni23DC uni23DC.l uni23DC.r uni23DC.s1 uni23DC.s2 uni23DC.s3 uni23DC.s4 uni23DC.s5uni23DD uni23DD.l uni23DD.r uni23DD.s1 uni23DD.s2 uni23DD.s3 uni23DD.s4 uni23DD.s5uni23DE uni23DE.l uni23DE.m uni23DE.r uni23DE.s1 uni23DE.s2 uni23DE.s3 uni23DE.s4 uni23DE.s5uni23DF uni23DF.l uni23DF.m uni23DF.r uni23DF.s1 uni23DF.s2 uni23DF.s3 uni23DF.s4 uni23DF.s5uni23E0 uni23E0.s1 uni23E0.s2 uni23E0.s3 uni23E0.s4 uni23E0.s5uni23E1 uni23E1.s1 uni23E1.s2 uni23E1.s3 uni23E1.s4 uni23E1.s5uni23E2uni23E3uni23E4uni23E5uni23E6uni23E7uni2423 uni2423.varuni2460uni2461uni2462uni2463uni2464uni2465uni2466uni2467uni2468uni24B6uni24B7uni24B8uni24B9uni24BAuni24BBuni24BCuni24BDuni24BEuni24BFuni24C0uni24C1uni24C2uni24C3uni24C4uni24C5uni24C6uni24C7uni24C8uni24C9uni24CAuni24CBuni24CCuni24CDuni24CEuni24CFuni24D0uni24D1uni24D2uni24D3uni24D4uni24D5uni24D6uni24D7uni24D8uni24D9uni24DAuni24DBuni24DCuni24DDuni24DEuni24DFuni24E0uni24E1uni24E2uni24E3uni24E4uni24E5uni24E6uni24E7uni24E8uni24E9uni24EAuni2500uni2502uni2506uni2508uni250Auni250Cuni2510uni2514uni2518uni251Cuni2524uni252Cuni2534uni253Cuni2550uni2551uni2552uni2553uni2554uni2555uni2556uni2557uni2558uni2559uni255Auni255Buni255Cuni255Duni255Euni255Funi2560uni2561uni2562uni2563uni2564uni2565uni2566uni2567uni2568uni2569uni256Auni256Buni256Cuni2571uni2572uni2580uni2584uni2588uni258Cuni2590uni2591uni2592uni2593uni25A0uni25A1uni25A2uni25A3uni25A4uni25A5uni25A6uni25A7uni25A8uni25A9 uni25A9.varuni25AAuni25ABuni25ACuni25ADuni25AEuni25AFuni25B0uni25B1uni25B2uni25B3uni25B4uni25B5uni25B6uni25B7uni25B8uni25B9uni25BAuni25BBuni25BCuni25BDuni25BEuni25BFuni25C0uni25C1uni25C2uni25C3uni25C4uni25C5uni25C6uni25C7uni25C8uni25C9uni25CAuni25CBuni25CDuni25CEuni25CFuni25D0uni25D1uni25D2uni25D3uni25D4uni25D5uni25D6uni25D7uni25D8uni25D9uni25DAuni25DBuni25DCuni25DDuni25DEuni25DFuni25E0uni25E1uni25E2uni25E3uni25E4uni25E5uni25E6uni25E7uni25E8uni25E9uni25EAuni25EBuni25ECuni25EDuni25EEuni25EFuni25F0uni25F1uni25F2uni25F3uni25F4uni25F5uni25F6uni25F7uni25F8uni25F9uni25FAuni25FBuni25FCuni25FDuni25FEuni25FFuni2605uni2606uni2609uni260Cuni260Euni2612uni2621uni2639uni263Auni263Buni263Cuni263Duni263Euni263Funi2640uni2641uni2642uni2643uni2644uni2646uni2647uni2648uni2649uni2660uni2661uni2662uni2663uni2664uni2665uni2666uni2667uni2669uni266Auni266Buni266Duni266Euni266Funi267Euni2680uni2681uni2682uni2683uni2684uni2685uni2686uni2687uni2688uni2689uni26A0uni26A5uni26AAuni26ABuni26ACuni26B2uni26E2uni2702uni2709uni2713uni2720uni272Auni2736uni273Duni2772 uni2772.s1 uni2772.s2 uni2772.s3 uni2772.s4uni2773 uni2773.s1 uni2773.s2 uni2773.s3 uni2773.s4uni2780uni2781uni2782uni2783uni2784uni2785uni2786uni2787uni2788uni2789uni278Auni278Buni278Cuni278Duni278Euni278Funi2790uni2791uni2792uni2793uni279Buni27C0uni27C1uni27C2uni27C3uni27C4uni27C5uni27C6uni27C7uni27C8uni27C9uni27CBuni27CCuni27CDuni27D0uni27D1uni27D2uni27D3uni27D4uni27D5uni27D6uni27D7uni27D8uni27D9uni27DAuni27DBuni27DCuni27DDuni27DEuni27DFuni27E0uni27E1uni27E2uni27E3uni27E4uni27E5uni27E6 uni27E6.s1 uni27E6.s2 uni27E6.s3 uni27E6.s4uni27E7 uni27E7.s1 uni27E7.s2 uni27E7.s3 uni27E7.s4uni27E8 uni27E8.s1 uni27E8.s2 uni27E8.s3 uni27E8.s4uni27E9 uni27E9.s1 uni27E9.s2 uni27E9.s3 uni27E9.s4uni27EA uni27EA.s1 uni27EA.s2 uni27EA.s3 uni27EA.s4uni27EB uni27EB.s1 uni27EB.s2 uni27EB.s3 uni27EB.s4uni27ECuni27EDuni27EEuni27EFuni27F0 uni27F0.xuni27F1uni27F2uni27F3uni27F4uni27F5uni27F6uni27F7uni27F8uni27F9uni27FAuni27FBuni27FCuni27FDuni27FEuni27FFuni2900uni2901uni2902uni2903uni2904uni2905uni2906uni2907uni2908uni2909uni290A uni290A.xuni290Buni290Cuni290Duni290Euni290Funi2910uni2911uni2912uni2913uni2914uni2915uni2916uni2917uni2918uni2919uni291Auni291Buni291Cuni291Duni291Euni291Funi2920uni2921uni2922uni2923uni2924uni2925uni2926uni2927uni2928uni2929uni292Auni292Buni292Cuni292Duni292Euni292Funi2930uni2931uni2932uni2933uni2934uni2935uni2936uni2937uni2938uni2939uni293Auni293Buni293Cuni293Duni293Euni293Funi2940uni2941uni2942uni2943uni2944uni2945uni2946uni2947uni2948uni2949uni294Auni294Buni294Cuni294Duni294Euni294Funi2950uni2951uni2952uni2953uni2954uni2955uni2956uni2957uni2958uni2959uni295Auni295Buni295Cuni295Duni295Euni295Funi2960uni2961uni2962uni2963uni2964uni2965uni2966uni2967uni2968uni2969uni296Auni296Buni296Cuni296Duni296Euni296Funi2970uni2971uni2972uni2973uni2974uni2975uni2976uni2977uni2978uni2979uni297Auni297Buni297Cuni297Duni297Euni297Funi2980uni2981uni2982uni2983 uni2983.s1 uni2983.s2 uni2983.s3 uni2983.s4uni2984 uni2984.s1 uni2984.s2 uni2984.s3 uni2984.s4uni2985 uni2985.s1 uni2985.s2 uni2985.s3 uni2985.s4uni2986 uni2986.s1 uni2986.s2 uni2986.s3 uni2986.s4uni2987uni2988uni2989uni298Auni298Buni298Cuni298Duni298Euni298Funi2990uni2991uni2992uni2993uni2994uni2995uni2996uni2997uni2998uni2999uni299Auni299Buni299Cuni299Duni299Euni299Funi29A0uni29A1uni29A2uni29A3uni29A4uni29A5uni29A6uni29A7uni29A8uni29A9uni29AAuni29ABuni29ACuni29ADuni29AEuni29AFuni29B0uni29B1uni29B2uni29B3uni29B4uni29B5uni29B6uni29B7uni29B8uni29B9uni29BAuni29BBuni29BCuni29BDuni29BEuni29BFuni29C0uni29C1uni29C2uni29C3uni29C4uni29C5uni29C6uni29C7uni29C8uni29C9uni29CAuni29CBuni29CCuni29CDuni29CEuni29CFuni29D0uni29D1uni29D2uni29D3uni29D4uni29D5uni29D6uni29D7uni29D8uni29D9uni29DAuni29DBuni29DCuni29DDuni29DEuni29DFuni29E0uni29E1uni29E2uni29E3uni29E4uni29E5uni29E6uni29E7uni29E8uni29E9uni29EAuni29EBuni29ECuni29EDuni29EEuni29EFuni29F0uni29F1uni29F2uni29F3uni29F4uni29F5uni29F6uni29F7uni29F8 uni29F8.s1uni29F9 uni29F9.s1uni29FAuni29FBuni29FCuni29FDuni29FEuni29FFuni2A00 uni2A00.s1uni2A01 uni2A01.s1uni2A02 uni2A02.s1uni2A03 uni2A03.s1uni2A04 uni2A04.s1uni2A05 uni2A05.s1uni2A06 uni2A06.s1uni2A07 uni2A07.s1uni2A08 uni2A08.s1uni2A09 uni2A09.s1uni2A0A uni2A0A.s1uni2A0B uni2A0B.dsp uni2A0B.sm uni2A0B.up uni2A0B.updsp uni2A0B.upsmuni2A0C uni2A0C.dsp uni2A0C.sm uni2A0C.up uni2A0C.updsp uni2A0C.upsmuni2A0D uni2A0D.dsp uni2A0D.sm uni2A0D.up uni2A0D.updsp uni2A0D.upsmuni2A0E uni2A0E.dsp uni2A0E.sm uni2A0E.up uni2A0E.updsp uni2A0E.upsmuni2A0F uni2A0F.dsp uni2A0F.sm uni2A0F.up uni2A0F.updsp uni2A0F.upsmuni2A10 uni2A10.dsp uni2A10.sm uni2A10.up uni2A10.updsp uni2A10.upsmuni2A11 uni2A11.dsp uni2A11.sm uni2A11.up uni2A11.updsp uni2A11.upsmuni2A12 uni2A12.dsp uni2A12.sm uni2A12.up uni2A12.updsp uni2A12.upsmuni2A13 uni2A13.dsp uni2A13.sm uni2A13.up uni2A13.updsp uni2A13.upsmuni2A14 uni2A14.dsp uni2A14.sm uni2A14.up uni2A14.updsp uni2A14.upsmuni2A15 uni2A15.dsp uni2A15.sm uni2A15.up uni2A15.updsp uni2A15.upsmuni2A16 uni2A16.dsp uni2A16.sm uni2A16.up uni2A16.updsp uni2A16.upsmuni2A17 uni2A17.dsp uni2A17.sm uni2A17.up uni2A17.updsp uni2A17.upsmuni2A18 uni2A18.dsp uni2A18.sm uni2A18.up uni2A18.updsp uni2A18.upsmuni2A19 uni2A19.dsp uni2A19.sm uni2A19.up uni2A19.updsp uni2A19.upsmuni2A1A uni2A1A.dsp uni2A1A.sm uni2A1A.up uni2A1A.updsp uni2A1A.upsmuni2A1B uni2A1B.dsp uni2A1B.sm uni2A1B.up uni2A1B.updsp uni2A1B.upsmuni2A1C uni2A1C.dsp uni2A1C.sm uni2A1C.up uni2A1C.updsp uni2A1C.upsmuni2A1Duni2A1Euni2A1Funi2A20uni2A21uni2A22uni2A23uni2A24uni2A25uni2A26uni2A27uni2A28uni2A29uni2A2Auni2A2Buni2A2Cuni2A2Duni2A2Euni2A2Funi2A30uni2A31uni2A32uni2A33uni2A34uni2A35uni2A36uni2A37uni2A38uni2A39uni2A3Auni2A3Buni2A3C uni2A3C.varuni2A3D uni2A3D.varuni2A3Euni2A3Funi2A40uni2A41uni2A42uni2A43uni2A44uni2A45uni2A46uni2A47uni2A48uni2A49uni2A4Auni2A4Buni2A4Cuni2A4Duni2A4Euni2A4Funi2A50uni2A51uni2A52uni2A53uni2A54uni2A55uni2A56uni2A57uni2A58uni2A59uni2A5Auni2A5Buni2A5Cuni2A5Duni2A5Euni2A5Funi2A60uni2A61uni2A62uni2A63uni2A64uni2A65uni2A66uni2A67uni2A68uni2A69uni2A6Auni2A6Buni2A6Cuni2A6Duni2A6Euni2A6Funi2A70uni2A71uni2A72uni2A73uni2A74uni2A75uni2A76uni2A77uni2A78uni2A79uni2A7Auni2A7Buni2A7Cuni2A7Duni2A7Euni2A7Funi2A80uni2A81uni2A82uni2A83uni2A84uni2A85uni2A86uni2A87uni2A88uni2A89uni2A8Auni2A8Buni2A8Cuni2A8Duni2A8Euni2A8Funi2A90uni2A91uni2A92uni2A93uni2A94uni2A95uni2A96uni2A97uni2A98uni2A99uni2A9Auni2A9Buni2A9Cuni2A9D uni2A9D.varuni2A9E uni2A9E.varuni2A9Funi2AA0uni2AA1uni2AA2uni2AA3uni2AA4uni2AA5uni2AA6uni2AA7uni2AA8uni2AA9uni2AAAuni2AABuni2AAC uni2AAC.varuni2AAD uni2AAD.varuni2AAEuni2AAFuni2AB0uni2AB1uni2AB2uni2AB3uni2AB4uni2AB5uni2AB6uni2AB7uni2AB8uni2AB9uni2ABAuni2ABBuni2ABCuni2ABDuni2ABEuni2ABFuni2AC0uni2AC1uni2AC2uni2AC3uni2AC4uni2AC5uni2AC6uni2AC7uni2AC8uni2AC9uni2ACAuni2ACB uni2ACB.varuni2ACC uni2ACC.varuni2ACDuni2ACEuni2ACFuni2AD0uni2AD1uni2AD2uni2AD3uni2AD4uni2AD5uni2AD6uni2AD7uni2AD8uni2AD9uni2ADAuni2ADBuni2ADCuni2ADDuni2ADEuni2ADFuni2AE0uni2AE1uni2AE2uni2AE3uni2AE4uni2AE5uni2AE6uni2AE7uni2AE8uni2AE9uni2AEAuni2AEBuni2AECuni2AEDuni2AEE uni2AEE.varuni2AEFuni2AF0uni2AF1uni2AF2uni2AF3uni2AF4uni2AF5uni2AF6uni2AF7uni2AF8uni2AF9uni2AFAuni2AFBuni2AFC uni2AFC.s1 uni2AFC.s2uni2AFDuni2AFEuni2AFF uni2AFF.s1 uni2AFF.s2uni2B12uni2B13uni2B14uni2B15uni2B16uni2B17uni2B18uni2B19uni2B1Auni2B1Buni2B1Cuni2B1Duni2B1Euni2B1Funi2B20uni2B21uni2B22uni2B23uni2B24uni2B25uni2B26uni2B27uni2B28uni2B29uni2B2Auni2B2Buni2B2Cuni2B2Duni2B2Euni2B2Funi2B30uni2B31uni2B32uni2B33uni2B34uni2B35uni2B36uni2B37uni2B38uni2B39uni2B3Auni2B3Buni2B3Cuni2B3Duni2B3Euni2B3Funi2B40uni2B41uni2B42uni2B43uni2B44uni2B45 uni2B45.xuni2B46uni2B47uni2B48uni2B49uni2B4Auni2B4Buni2B4Cuni2B50uni2B51uni2B52uni2B53uni2B54uni3012uni3030uni306Eu1D400u1D401u1D402u1D403u1D404u1D405u1D406u1D407u1D408u1D409u1D40Au1D40Bu1D40Cu1D40Du1D40Eu1D40Fu1D410u1D411u1D412u1D413u1D414u1D415u1D416u1D417u1D418u1D419u1D41Au1D41Bu1D41Cu1D41Du1D41Eu1D41Fu1D420u1D421u1D422u1D422.dotlessu1D423u1D423.dotlessu1D424u1D425u1D426u1D427u1D428u1D429u1D42Au1D42Bu1D42Cu1D42Du1D42Eu1D42Fu1D430u1D431u1D432u1D433u1D434u1D435u1D436u1D437u1D438u1D439u1D43Au1D43Bu1D43Cu1D43Du1D43Eu1D43Fu1D440u1D441u1D442u1D443u1D444u1D445u1D446u1D447u1D448u1D449u1D44Au1D44Bu1D44Cu1D44Du1D44Eu1D44Fu1D450u1D451u1D452u1D453u1D454 u1D454.altu1D456u1D456.dotlessu1D457u1D457.dotlessu1D458u1D459u1D45Au1D45Bu1D45Cu1D45Du1D45Eu1D45Fu1D460u1D461u1D462 u1D462.altu1D463 u1D463.altu1D464 u1D464.altu1D465u1D466u1D467 u1D467.altu1D468u1D469u1D46Au1D46Bu1D46Cu1D46Du1D46Eu1D46Fu1D470u1D471u1D472u1D473u1D474u1D475u1D476u1D477u1D478u1D479u1D47Au1D47Bu1D47Cu1D47Du1D47Eu1D47Fu1D480u1D481u1D482u1D483u1D484u1D485u1D486u1D487u1D488u1D489u1D48Au1D48A.dotlessu1D48Bu1D48B.dotlessu1D48Cu1D48Du1D48Eu1D48Fu1D490u1D491u1D492u1D493u1D494u1D495u1D496u1D497u1D498u1D499u1D49Au1D49Bu1D49Cu1D49Eu1D49Fu1D4A2u1D4A5u1D4A6u1D4A9u1D4AAu1D4ABu1D4ACu1D4AEu1D4AFu1D4B0u1D4B1u1D4B2u1D4B3u1D4B4u1D4B5 u1D4B6.ss01 u1D4B7.ss01 u1D4B8.ss01 u1D4B9.ss01 u1D4BB.ss01 u1D4BD.ss01 u1D4BE.ss01u1D4BE.dotless.ss01 u1D4BF.ss01u1D4BF.dotless.ss01 u1D4C0.ss01 u1D4C1.ss01 u1D4C2.ss01 u1D4C3.ss01 u1D4C5.ss01 u1D4C6.ss01 u1D4C7.ss01 u1D4C8.ss01 u1D4C9.ss01 u1D4CA.ss01 u1D4CB.ss01 u1D4CC.ss01 u1D4CD.ss01 u1D4CE.ss01 u1D4CF.ss01 u1D4D0.ss01 u1D4D1.ss01 u1D4D2.ss01 u1D4D3.ss01 u1D4D4.ss01 u1D4D5.ss01 u1D4D6.ss01 u1D4D7.ss01 u1D4D8.ss01 u1D4D9.ss01 u1D4DA.ss01 u1D4DB.ss01 u1D4DC.ss01 u1D4DD.ss01 u1D4DE.ss01 u1D4DF.ss01 u1D4E0.ss01 u1D4E1.ss01 u1D4E2.ss01 u1D4E3.ss01 u1D4E4.ss01 u1D4E5.ss01 u1D4E6.ss01 u1D4E7.ss01 u1D4E8.ss01 u1D4E9.ss01 u1D4EA.ss01 u1D4EB.ss01 u1D4EC.ss01 u1D4ED.ss01 u1D4EE.ss01 u1D4EF.ss01 u1D4F0.ss01 u1D4F1.ss01 u1D4F2.ss01u1D4F2.dotless.ss01 u1D4F3.ss01u1D4F3.dotless.ss01 u1D4F4.ss01 u1D4F5.ss01 u1D4F6.ss01 u1D4F7.ss01 u1D4F8.ss01 u1D4F9.ss01 u1D4FA.ss01 u1D4FB.ss01 u1D4FC.ss01 u1D4FD.ss01 u1D4FE.ss01 u1D4FF.ss01 u1D500.ss01 u1D501.ss01 u1D502.ss01 u1D503.ss01u1D504u1D505u1D507u1D508u1D509u1D50Au1D50Du1D50Eu1D50Fu1D510u1D511u1D512u1D513u1D514u1D516u1D517u1D518u1D519u1D51Au1D51Bu1D51Cu1D51Eu1D51Fu1D520u1D521u1D522u1D523u1D524u1D525u1D526u1D526.dotlessu1D527u1D527.dotlessu1D528u1D529u1D52Au1D52Bu1D52Cu1D52Du1D52Eu1D52Fu1D530u1D531u1D532u1D533u1D534u1D535u1D536u1D537u1D56Cu1D56Du1D56Eu1D56Fu1D570u1D571u1D572u1D573u1D574u1D575u1D576u1D577u1D578u1D579u1D57Au1D57Bu1D57Cu1D57Du1D57Eu1D57Fu1D580u1D581u1D582u1D583u1D584u1D585u1D586u1D587u1D588u1D589u1D58Au1D58Bu1D58Cu1D58Du1D58Eu1D58E.dotlessu1D58Fu1D58F.dotlessu1D590u1D591u1D592u1D593u1D594u1D595u1D596u1D597u1D598u1D599u1D59Au1D59Bu1D59Cu1D59Du1D59Eu1D59Fu1D538u1D539u1D53Bu1D53Cu1D53Du1D53Eu1D540u1D541u1D542u1D543u1D544u1D546u1D54Au1D54Bu1D54Cu1D54Du1D54Eu1D54Fu1D550u1D552u1D553u1D554u1D555u1D556u1D557u1D558u1D559u1D55Au1D55A.dotlessu1D55Bu1D55B.dotlessu1D55Cu1D55Du1D55Eu1D55Fu1D560u1D561u1D562u1D563u1D564u1D565u1D566u1D567u1D568u1D569u1D56Au1D56Bu1D5A0u1D5A1u1D5A2u1D5A3u1D5A4u1D5A5u1D5A6u1D5A7u1D5A8u1D5A9u1D5AAu1D5ABu1D5ACu1D5ADu1D5AEu1D5AFu1D5B0u1D5B1u1D5B2u1D5B3u1D5B4u1D5B5u1D5B6u1D5B7u1D5B8u1D5B9u1D5BAu1D5BBu1D5BCu1D5BDu1D5BEu1D5BFu1D5C0u1D5C1u1D5C2u1D5C2.dotlessu1D5C3u1D5C3.dotlessu1D5C4u1D5C5u1D5C6u1D5C7u1D5C8u1D5C9u1D5CAu1D5CBu1D5CCu1D5CDu1D5CEu1D5CFu1D5D0u1D5D1u1D5D2u1D5D3u1D5D4u1D5D5u1D5D6u1D5D7u1D5D8u1D5D9u1D5DAu1D5DBu1D5DCu1D5DDu1D5DEu1D5DFu1D5E0u1D5E1u1D5E2u1D5E3u1D5E4u1D5E5u1D5E6u1D5E7u1D5E8u1D5E9u1D5EAu1D5EBu1D5ECu1D5EDu1D5EEu1D5EFu1D5F0u1D5F1u1D5F2u1D5F3u1D5F4u1D5F5u1D5F6u1D5F6.dotlessu1D5F7u1D5F7.dotlessu1D5F8u1D5F9u1D5FAu1D5FBu1D5FCu1D5FDu1D5FEu1D5FFu1D600u1D601u1D602u1D603u1D604u1D605u1D606u1D607u1D608u1D609u1D60Au1D60Bu1D60Cu1D60Du1D60Eu1D60Fu1D610u1D611u1D612u1D613u1D614u1D615u1D616u1D617u1D618u1D619u1D61Au1D61Bu1D61Cu1D61Du1D61Eu1D61Fu1D620u1D621u1D622u1D623u1D624u1D625u1D626u1D627u1D628u1D629u1D62Au1D62A.dotlessu1D62Bu1D62B.dotlessu1D62Cu1D62Du1D62Eu1D62Fu1D630u1D631u1D632u1D633u1D634u1D635u1D636u1D637u1D638u1D639u1D63Au1D63Bu1D63Cu1D63Du1D63Eu1D63Fu1D640u1D641u1D642u1D643u1D644u1D645u1D646u1D647u1D648u1D649u1D64Au1D64Bu1D64Cu1D64Du1D64Eu1D64Fu1D650u1D651u1D652u1D653u1D654u1D655u1D656u1D657u1D658u1D659u1D65Au1D65Bu1D65Cu1D65Du1D65Eu1D65E.dotlessu1D65Fu1D65F.dotlessu1D660u1D661u1D662u1D663u1D664u1D665u1D666u1D667u1D668u1D669u1D66Au1D66Bu1D66Cu1D66Du1D66Eu1D66Fu1D670u1D671u1D672u1D673u1D674u1D675u1D676u1D677u1D678u1D679u1D67Au1D67Bu1D67Cu1D67Du1D67Eu1D67Fu1D680u1D681u1D682u1D683u1D684u1D685u1D686u1D687u1D688u1D689u1D68Au1D68Bu1D68Cu1D68Du1D68Eu1D68Fu1D690u1D691u1D692u1D692.dotlessu1D693u1D693.dotlessu1D694u1D695u1D696u1D697u1D698u1D699u1D69Au1D69Bu1D69Cu1D69Du1D69Eu1D69Fu1D6A0u1D6A1u1D6A2u1D6A3u1D6A4u1D6A5u1D6A8u1D6A9u1D6AAu1D6ABu1D6ACu1D6ADu1D6AEu1D6AFu1D6B0u1D6B1u1D6B2u1D6B3u1D6B4u1D6B5u1D6B6u1D6B7u1D6B8u1D6B9u1D6BAu1D6BBu1D6BCu1D6BDu1D6BEu1D6BFu1D6C0u1D6C1u1D6C2u1D6C3u1D6C4u1D6C5u1D6C6u1D6C7u1D6C8u1D6C9u1D6CAu1D6CBu1D6CCu1D6CDu1D6CEu1D6CFu1D6D0u1D6D1u1D6D2u1D6D3u1D6D4u1D6D5u1D6D6u1D6D7u1D6D8u1D6D9u1D6DAu1D6DBu1D6DCu1D6DDu1D6DEu1D6DFu1D6E0u1D6E1u1D6E2u1D6E3u1D6E4u1D6E5u1D6E6u1D6E7u1D6E8u1D6E9u1D6EAu1D6EBu1D6ECu1D6EDu1D6EEu1D6EFu1D6F0u1D6F1u1D6F2u1D6F3u1D6F4u1D6F5u1D6F6u1D6F7u1D6F8u1D6F9u1D6FAu1D6FBu1D6FCu1D6FDu1D6FEu1D6FFu1D700u1D701u1D702u1D703u1D704u1D705u1D706u1D707u1D708u1D709u1D70Au1D70Bu1D70Cu1D70Du1D70Eu1D70Fu1D710u1D711u1D712u1D713u1D714u1D715u1D716u1D717u1D718u1D719u1D71Au1D71Bu1D71Cu1D71Du1D71Eu1D71Fu1D720u1D721u1D722u1D723u1D724u1D725u1D726u1D727u1D728u1D729u1D72Au1D72Bu1D72Cu1D72Du1D72Eu1D72Fu1D730u1D731u1D732u1D733u1D734u1D735u1D736u1D737u1D738u1D739u1D73Au1D73Bu1D73Cu1D73Du1D73Eu1D73Fu1D740u1D741u1D742u1D743u1D744u1D745u1D746u1D747u1D748u1D749u1D74Au1D74Bu1D74Cu1D74Du1D74Eu1D74Fu1D750u1D751u1D752u1D753u1D754u1D755u1D756u1D757u1D758u1D759u1D75Au1D75Bu1D75Cu1D75Du1D75Eu1D75Fu1D760u1D761u1D762u1D763u1D764u1D765u1D766u1D767u1D768u1D769u1D76Au1D76Bu1D76Cu1D76Du1D76Eu1D76Fu1D770u1D771u1D772u1D773u1D774u1D775u1D776u1D777u1D778u1D779u1D77Au1D77Bu1D77Cu1D77Du1D77Eu1D77Fu1D780u1D782u1D781u1D783u1D784u1D785u1D786u1D787u1D788u1D789u1D78Au1D78Bu1D78Cu1D78Du1D78Eu1D78Fu1D790u1D791u1D792u1D793u1D794u1D795u1D796u1D797u1D798u1D799u1D79Au1D79Bu1D79Cu1D79Du1D79Eu1D79Fu1D7A0u1D7A1u1D7A2u1D7A3u1D7A4u1D7A5u1D7A6u1D7A7u1D7A8u1D7A9u1D7AAu1D7ABu1D7ACu1D7ADu1D7AEu1D7AFu1D7B0u1D7B1u1D7B2u1D7B3u1D7B4u1D7B5u1D7B6u1D7B7u1D7B8u1D7B9u1D7BAu1D7BCu1D7BBu1D7BDu1D7BEu1D7BFu1D7C0u1D7C1u1D7C2u1D7C3u1D7C4u1D7C5u1D7C6u1D7C7u1D7C8u1D7C9u1D7CAu1D7CBu1D7CEu1D7CFu1D7D0u1D7D1u1D7D2u1D7D3u1D7D4u1D7D5u1D7D6u1D7D7u1D7D8u1D7D9u1D7DAu1D7DBu1D7DCu1D7DDu1D7DEu1D7DFu1D7E0u1D7E1u1D7E2u1D7E3u1D7E4u1D7E5u1D7E6u1D7E7u1D7E8u1D7E9u1D7EAu1D7EBu1D7ECu1D7EDu1D7EEu1D7EFu1D7F0u1D7F1u1D7F2u1D7F3u1D7F4u1D7F5u1D7F6u1D7F7u1D7F8u1D7F9u1D7FAu1D7FBu1D7FCu1D7FDu1D7FEu1D7FF zero.sstyone.sstytwo.ssty three.ssty four.ssty five.sstysix.ssty seven.ssty eight.ssty nine.ssty plus.ssty minus.ssty equal.sstyparenleft.sstyparenright.ssty tackdown.ssty tackup.sstyA.sstyB.sstyC.sstyD.sstyE.sstyF.sstyG.sstyH.sstyI.sstyJ.sstyK.sstyL.sstyM.sstyN.sstyO.sstyP.sstyQ.sstyR.sstyS.sstyT.sstyU.sstyV.sstyW.sstyX.sstyY.sstyZ.sstya.sstyb.sstyc.sstyd.sstye.sstyf.sstyg.sstyh.sstyi.sstyi.dotless.ssty dotlessi.sstyj.sstyj.dotless.ssty uni0237.sstyk.sstyl.sstym.sstyn.sstyo.sstyp.sstyq.sstyr.sstys.sstyt.sstyu.sstyv.sstyw.sstyx.sstyy.sstyz.ssty Alpha.ssty Beta.ssty Gamma.ssty Delta.ssty Epsilon.ssty Zeta.sstyEta.ssty Theta.ssty Iota.ssty Kappa.ssty Lambda.sstyMu.sstyNu.sstyXi.ssty Omicron.sstyPi.sstyRho.ssty Sigma.sstyTau.ssty Upsilon.sstyPhi.sstyChi.sstyPsi.ssty Omega.ssty alpha.ssty beta.ssty gamma.ssty delta.ssty epsilon.ssty zeta.sstyeta.ssty theta.ssty iota.ssty kappa.ssty lambda.sstymu.sstynu.sstyxi.ssty omicron.sstypi.sstyrho.ssty sigma.sstysigmafinal.sstytau.ssty upsilon.sstyphi.sstychi.sstypsi.ssty omega.ssty u1D434.ssty u1D435.ssty u1D436.ssty u1D437.ssty u1D438.ssty u1D439.ssty u1D43A.ssty u1D43B.ssty u1D43C.ssty u1D43D.ssty u1D43E.ssty u1D43F.ssty u1D440.ssty u1D441.ssty u1D442.ssty u1D443.ssty u1D444.ssty u1D445.ssty u1D446.ssty u1D447.ssty u1D448.ssty u1D449.ssty u1D44A.ssty u1D44B.ssty u1D44C.ssty u1D44D.ssty u1D44E.ssty u1D44F.ssty u1D450.ssty u1D451.ssty u1D452.ssty u1D453.ssty u1D454.sstyu1D454.alt.ssty uni210E.ssty u1D456.sstyu1D456.dotless.ssty u1D457.sstyu1D457.dotless.ssty u1D458.ssty u1D459.ssty u1D45A.ssty u1D45B.ssty u1D45C.ssty u1D45D.ssty u1D45E.ssty u1D45F.ssty u1D460.ssty u1D461.ssty u1D46.sstyu1D46.alt.ssty u1D463.sstyu1D463.alt.ssty u1D464.sstyu1D464.alt.ssty u1D465.ssty u1D466.ssty u1D467.sstyu1D467.alt.ssty u1D6E2.ssty u1D6E3.ssty u1D6E4.ssty u1D6E5.ssty u1D6E6.ssty u1D6E7.ssty u1D6E8.ssty u1D6E9.ssty u1D6EA.ssty u1D6EB.ssty u1D6EC.ssty u1D6ED.ssty u1D6EE.ssty u1D6EF.ssty u1D6F0.ssty u1D6F1.ssty u1D6F2.ssty u1D6F3.ssty u1D6F4.ssty u1D6F5.ssty u1D6F6.ssty u1D6F7.ssty u1D6F8.ssty u1D6F9.ssty u1D6FA.ssty u1D6FB.ssty u1D6FC.ssty u1D6FD.ssty u1D6FE.ssty u1D6FF.ssty u1D700.ssty u1D701.ssty u1D702.ssty u1D703.ssty u1D704.ssty u1D705.ssty u1D706.ssty u1D707.ssty u1D708.ssty u1D709.ssty u1D70A.ssty u1D70B.ssty u1D70C.ssty u1D70D.ssty u1D70E.ssty u1D70F.ssty u1D710.ssty u1D711.ssty u1D712.ssty u1D713.ssty u1D714.ssty u1D715.ssty u1D716.ssty u1D717.ssty u1D718.ssty u1D719.ssty u1D71A.ssty u1D71B.ssty comma.ssty period.ssty hyphen.ssty minute.ssty second.ssty uni2057.ssty uni2034.ssty uni2035.ssty uni2036.ssty uni2037.ssty zero.ssty2 one.ssty2 two.ssty2 three.ssty2 four.ssty2 five.ssty2 six.ssty2 seven.ssty2 eight.ssty2 nine.ssty2 plus.ssty2 minus.ssty2 equal.ssty2parenleft.ssty2parenright.ssty2tackdown.ssty2 tackup.ssty2A.ssty2B.ssty2C.ssty2D.ssty2E.ssty2F.ssty2G.ssty2H.ssty2I.ssty2J.ssty2K.ssty2L.ssty2M.ssty2N.ssty2O.ssty2P.ssty2Q.ssty2R.ssty2S.ssty2T.ssty2U.ssty2V.ssty2W.ssty2X.ssty2Y.ssty2Z.ssty2a.ssty2b.ssty2c.ssty2d.ssty2e.ssty2f.ssty2g.ssty2h.ssty2i.ssty2i.dotless.ssty2dotlessi.ssty2j.ssty2j.dotless.ssty2 uni0237.ssty2k.ssty2l.ssty2m.ssty2n.ssty2o.ssty2p.ssty2q.ssty2r.ssty2s.ssty2t.ssty2u.ssty2v.ssty2w.ssty2x.ssty2y.ssty2z.ssty2 Alpha.ssty2 Beta.ssty2 Gamma.ssty2 Delta.ssty2 Epsilon.ssty2 Zeta.ssty2 Eta.ssty2 Theta.ssty2 Iota.ssty2 Kappa.ssty2 Lambda.ssty2Mu.ssty2Nu.ssty2Xi.ssty2 Omicron.ssty2Pi.ssty2 Rho.ssty2 Sigma.ssty2 Tau.ssty2 Upsilon.ssty2 Phi.ssty2 Chi.ssty2 Psi.ssty2 Omega.ssty2 alpha.ssty2 beta.ssty2 gamma.ssty2 delta.ssty2 epsilon.ssty2 zeta.ssty2 eta.ssty2 theta.ssty2 iota.ssty2 kappa.ssty2 lambda.ssty2mu.ssty2nu.ssty2xi.ssty2 omicron.ssty2pi.ssty2 rho.ssty2 sigma.ssty2sigmafinal.ssty2 tau.ssty2 upsilon.ssty2 phi.ssty2 chi.ssty2 psi.ssty2 omega.ssty2 u1D434.ssty2 u1D435.ssty2 u1D436.ssty2 u1D437.ssty2 u1D438.ssty2 u1D439.ssty2 u1D43A.ssty2 u1D43B.ssty2 u1D43C.ssty2 u1D43D.ssty2 u1D43E.ssty2 u1D43F.ssty2 u1D440.ssty2 u1D441.ssty2 u1D442.ssty2 u1D443.ssty2 u1D444.ssty2 u1D445.ssty2 u1D446.ssty2 u1D447.ssty2 u1D448.ssty2 u1D449.ssty2 u1D44A.ssty2 u1D44B.ssty2 u1D44C.ssty2 u1D44D.ssty2 u1D44E.ssty2 u1D44F.ssty2 u1D450.ssty2 u1D451.ssty2 u1D452.ssty2 u1D453.ssty2 u1D454.ssty2u1D454.alt.ssty2 uni210E.ssty2 u1D456.ssty2u1D456.dotless.ssty2 u1D457.ssty2u1D457.dotless.ssty2 u1D458.ssty2 u1D459.ssty2 u1D45A.ssty2 u1D45B.ssty2 u1D45C.ssty2 u1D45D.ssty2 u1D45E.ssty2 u1D45F.ssty2 u1D460.ssty2 u1D461.ssty2 u1D462.ssty2u1D462.alt.ssty2 u1D463.ssty2u1D463.alt.ssty2 u1D464.ssty2u1D464.alt.ssty2 u1D465.ssty2 u1D466.ssty2 u1D467.ssty2u1D467.alt.ssty2 u1D6E2.ssty2 u1D6E3.ssty2 u1D6E4.ssty2 u1D6E5.ssty2 u1D6E6.ssty2 u1D6E7.ssty2 u1D6E8.ssty2 u1D6E9.ssty2 u1D6EA.ssty2 u1D6EB.ssty2 u1D6EC.ssty2 u1D6ED.ssty2 u1D6EE.ssty2 u1D6EF.ssty2 u1D6F0.ssty2 u1D6F1.ssty2 u1D6F2.ssty2 u1D6F3.ssty2 u1D6F4.ssty2 u1D6F5.ssty2 u1D6F6.ssty2 u1D6F7.ssty2 u1D6F8.ssty2 u1D6F9.ssty2 u1D6FA.ssty2 u1D6FB.ssty2 u1D6FC.ssty2 u1D6FD.ssty2 u1D6FE.ssty2 u1D6FF.ssty2 u1D700.ssty2 u1D701.ssty2 u1D702.ssty2 u1D703.ssty2 u1D704.ssty2 u1D705.ssty2 u1D706.ssty2 u1D707.ssty2 u1D708.ssty2 u1D709.ssty2 u1D70A.ssty2 u1D70B.ssty2 u1D70C.ssty2 u1D70D.ssty2 u1D70E.ssty2 u1D70F.ssty2 u1D710.ssty2 u1D711.ssty2 u1D712.ssty2 u1D713.ssty2 u1D714.ssty2 u1D715.ssty2 u1D716.ssty2 u1D717.ssty2 u1D718.ssty2 u1D719.ssty2 u1D71A.ssty2 u1D71B.ssty2 comma.ssty2 period.ssty2 hyphen.ssty2 minute.ssty2 second.ssty2 uni2057.ssty2 uni2034.ssty2 uni2035.ssty2 uni2036.ssty2 uni2037.ssty2 u1D49C.ss01 uni212C.ss01 u1D49E.ss01 u1D49F.ss01 uni2130.ss01 uni2131.ss01 u1D4A2.ss01 uni210B.ss01 uni2110.ss01 u1D4A5.ss01 u1D4A6.ss01 uni2112.ss01 uni2133.ss01 u1D4A9.ss01 u1D4AA.ss01 u1D4AB.ss01 u1D4AC.ss01 uni211B.ss01 u1D4AE.ss01 u1D4AF.ss01 u1D4B0.ss01 u1D4B1.ss01 u1D4B2.ss01 u1D4B3.ss01 u1D4B4.ss01 u1D4B5.ss01uni1D9Buni0300.mathcapuni0301.mathcapuni0302.mathcapuni030C.mathcapuni0303.mathcapuni0308.mathcapuni0304.mathcapuni0306.mathcap uni0306.s1 uni0306.s2 uni0306.s3 uni0306.s4 uni0306.s5uni030A.mathcapuni0307.mathcapuni034D horizontal.x integral.xuni20D3uni20D4uni20D5uni20D8uni20D9uni20DA uni2191.x uni21BC.r0 uni21BD.r0 uni21C0.l0 uni21C1.l0 uni21D0.endl uni21D0.endr uni2308.x uni2309.x uni21A4.endr uni21A6.endl uni21A9.endr uni21AA.endluni2320uni2321uni2337uni2339uni2349uni234Buni234Euni2352uni2355uni2359uni235Duni235Euni235Funi2363uni2368uni236Auni236Buni236Cuni2371uni2372uni2373uni2374uni2375uni2377uni237Auni239Buni239Cuni239Duni239Euni239Funi23A0uni23A1uni23A2uni23A3uni23A4uni23A5uni23A6uni23A7uni23A8uni23A9uni23AAuni23ABuni23ACuni23ADuni23AEuni23B0uni23B1uni23B2uni23B3 uni23DC.x uni23DD.x uni27E8.s6 uni27E9.s6 uni29FC.s1 uni29FC.s2 uni29FC.s3 uni29FD.s1 uni29FD.s2 uni29FD.s3 uniE000.nu uniE001.nu uniE002.nu uniE003.nu uniE004.nu uniE005.nu uniE00A.nu uniE00B.nu uniE00E.nu uniE00F.nu uniE010.nu uniE011.nu uniE016.nu uniE018.nu uniE01E.nu uniE023.nu uniE025.nu uniE026.nu uniE027.nu uniE028.nu uniE029.nu uniE02A.nu uniE02B.nu uniE02F.nu uniE035.nu uniE037.nu uniE038.nu uniE039.nu uniE03A.nu uniE03B.nu uniE03C.nu uniE03D.nu uniE040.nu uniE041.nu uniE042.nu uniE043.nu uniE044.nu uniE045.nu uniE046.nu uniE04B.nu uniE04C.nu uniE04D.nu uniE04E.nu uniE04F.nu uniE050.nu uniE051.nu uniE052.nu uniE053.nu uniE054.nu uniE055.nu uniE056.nu uniE057.nu uniE059.nu uniE05A.nu uniE05B.nu uniE05C.nu uniE05D.nu uniE05E.nu uniE060.nu uniE061.nu uniE062.nu uniE063.nu uniE064.nu uniE065.nu uniE066.nu uniE067.nu uniE068.nu uniE06B.nu uniE06C.nu uniE06D.nu uniE06E.nu uniE06F.nu uniE070.nu uniE075.nu uniE076.nu uniE077.nu uniE07C.nu uniE07D.nu uniE07E.nu uniE07F.nu uniE080.nu uniE081.nu uniE082.nu uniE083.nu uniE084.nu uniE085.nu uniE086.nu uniE087.nu uniE088.nu uniE089.nu uniE092.nu uniE093.nu uniE094.nu uniE095.nu uniE096.nu uniE097.nu uniE098.nu uniE099.nu uniE09A.nu uniE09B.nu uniE09F.nu uniE0A0.nu uniE0A1.nu uniE0A2.nu uniE0A4.nu uniE0A5.nu uniE0A6.nu uniE0A7.nu uniE0A8.nu uniE0A9.nu uniE0AA.nu uniE0AB.nu uniE0AC.nu uniE0AD.nu uniE0AE.nu uniE0AF.nu uniE0B0.nu uniE0B1.nu uniE0B2.nu uniE0B3.nu uniE0B4.nu uniE0B5.nu uniE0B6.nu uniE0B7.nu uniE0B8.nu uniE0B9.nu uniE0BB.nu uniE0BC.nu uniE0BD.nu uniE0BE.nu uniE0BF.nu uniE0C0.nu uniE0C1.nu uniE0C2.nu uniE0C3.nu uniE0C4.nu uniE0C5.nu uniE0C6.nu uniE0C7.nu uniE0C8.nu uniE0C9.nu uniE0CA.nu uniE0CB.nu uniE0CC.nu uniE0CD.nu uniE0CE.nu uniE0CF.nu uniE0D0.nu uniE0D1.nu uniE0D2.nu uniE0D3.nu uniE0D4.nu uniE0D5.nu uniE0D6.nu uniE0D7.nu uniE0D8.nu uniE0D9.nu uniE0DA.nu uniE0DB.nu uniE0DC.nu uniE0DD.nu uniE0DE.nu uniE0DF.nu uniE0E0.nu uniE0E1.nu uniE0E2.nu uniE0E3.nu uniE0E4.nu uniE0E5.nu uniE0E6.nu uniE0E7.nu uniE0E8.nu uniE0E9.nu uniE0EA.nu uniE0EB.nu uniE0EC.nu uniE0ED.nu uniE0EE.nu uniE0EF.nu uniE0F1.nu uniE0F2.nu uniE0F3.nu uniE0F4.nu uniE0F5.nu uniE0F6.nu uniE0F7.nu uniE0F8.nu uniE0F9.nu uniE0FA.nu uniE0FB.nu uniE0FC.nu uniE0FD.nu uniE0FE.nu uniE0FF.nu uniE100.nu uniE101.nu uniE102.nu uniE103.nu uniE104.nu uniE105.nu uniE106.nu uniE107.nu uniE108.nu uniE109.nu uniE10A.nu uniE10C.nu uniE10D.nu uniE110.nu uniE111.nu uniE112.nu uniE113.nu uniE114.nu uniE115.nu uniE116.nu uniE117.nu uniE118.nu uniE119.nu uniE11A.nu uniE11B.nu uniE11C.nu uniE11D.nu uniE11E.nu uniE11F.nu uniE120.nu uniE121.nu uniE122.nu uniE123.nu uniE124.nu uniE125.nu uniE126.nu uniE127.nu uniE128.nu uniE129.nu uniE12A.nu uniE12B.nu uniE12C.nu uniE12D.nu uniE12E.nu uniE12F.nu uniE130.nu uniE131.nu uniE132.nu uniE133.nu uniE13A.nu uniE13F.nu uniE14C.nu uniE14D.nu uniE14E.nu uniE14F.nu uniE150.nu uniE151.nu uniE152.nu uniE153.nu uniE17C.nu uniE17D.nu uniE17E.nu uniE17F.nu uniE180.nu uniE181.nu uniE182.nu uniE183.nu uniE184.nu uniE185.nu uniE186.nu uniE187.nu uniE188.nu uniE189.nu uniE18A.nu uniE18B.nu uniE18C.nu uniE18D.nu uniE18E.nu uniE18F.nu uniE190.nu uniE191.nu uniE192.nu uniE193.nu uniE194.nu uniE195.nu uniE196.nu uniE197.nu uniE198.nu uniE199.nu uniE19A.nu uniE19B.nu uniE19C.nu uniE19D.nu uniE19E.nu uniE19F.nu uniE1A0.nu uniE1A1.nu uniE1A2.nu uniE1A3.nu uniE1A4.nu uniE1A5.nu uniE1A6.nu uniE1A7.nu uniE1A8.nu uniE1A9.nu uniE1AA.nu uniE1AB.nu uniE1AC.nu uniE1AD.nu uniE1AE.nu uniE1AF.nu uniE1B0.nu uniE1B1.nu uniE1B2.nu uniE1B3.nu uniE28C.nu uniE28D.nu uniE28E.nu uniE28F.nu uniE290.nu uniE291.nu uniE292.nu uniE293.nu Alpha_uni0338 Beta_uni0338 Gamma_uni0338 Delta_uni0338Epsilon_uni0338 Zeta_uni0338 Eta_uni0338 Theta_uni0338 Iota_uni0338 Kappa_uni0338Lambda_uni0338 Mu_uni0338 Nu_uni0338 Xi_uni0338Omicron_uni0338 Pi_uni0338 Rho_uni0338 Sigma_uni0338 Tau_uni0338Upsilon_uni0338 Phi_uni0338 Chi_uni0338 Psi_uni0338 Omega_uni0338uni03DA_uni0338uni03DC_uni0338uni03DE_uni0338uni03E0_uni0338 uniE3C2.nu uniE3C3.nu uniE3C4.nu uniE3C7.nu uniE3C8.nuS_Szeroinferior.peruni200BuniFFFDacutecomb.Greekdieresiscomb.Greekdieresistonoscomb uni1D488.alt uni1D628.alt uni1D65C.altuni2148.dotlessuni2149.dotlessuni2061 uni2061.edituni2062 uni2062.edituni249Cuni249Duni249Euni249Funi24A0uni24A1uni24A2uni24A3uni24A4uni24A5uni24A6uni24A7uni24A8uni24A9uni24AAuni24ABuni24ACuni24ADuni24AEuni24AFuni24B0uni24B1uni24B2uni24B3uni24B4uni24B5uni2469uni246Auni246Buni246Cuni246Duni246Euni246Funi2470uni2471uni2472uni2473uni24FFuni2776uni2777uni2778uni2779uni277Auni277Buni277Cuni277Duni277Euni277Funi24EBuni24ECuni24EDuni24EEuni24EFuni24F0uni24F1uni24F2uni24F3uni24F4uni24F5uni24F6uni24F7uni24F8uni24F9uni24FAuni24FBuni24FCuni24FDuni24FEuni2474uni2475uni2476uni2477uni2478uni2479uni247Auni247Buni247Cuni247Duni247Euni247Funi2480uni2481uni2482uni2483uni2484uni2485uni2486uni2487uni2488uni2489uni248Auni248Buni248Cuni248Duni248Euni248Funi2490uni2491uni2492uni2493uni2494uni2495uni2496uni2497uni2498uni2499uni249Auni249B uni2202.ssty uni2202.ssty2zero.VS1 zero.VS1.sstyzero.VS1.ssty2 uni2308.s5 uni2308.s6 uni2308.s7 uni2308.s8 uni2308.s9 uni2308.s10 uni2308.s11 uni2308.s12 uni2309.s5 uni2309.s6 uni2309.s7 uni2309.s8 uni2309.s9 uni2309.s10 uni2309.s11 uni2309.s12 uni230A.s5 uni230A.s6 uni230A.s7 uni230A.s8 uni230A.s9 uni230A.s10 uni230A.s11 uni230A.s12 uni230B.s5 uni230B.s6 uni230B.s7 uni230B.s8 uni230B.s9 uni230B.s10 uni230B.s11 uni230B.s12 uni2772.s5 uni2772.s6 uni2772.s7 uni2772.s8 uni2772.s9 uni2772.s10 uni2772.s11 uni2772.s12 uni2773.s5 uni2773.s6 uni2773.s7 uni2773.s8 uni2773.s9 uni2773.s10 uni2773.s11 uni2773.s12 uni27E6.s5 uni27E6.s6 uni27E6.s7 uni27E6.s8 uni27E6.s9 uni27E6.s10 uni27E6.s11 uni27E6.s12 uni27E7.s5 uni27E7.s6 uni27E7.s7 uni27E7.s8 uni27E7.s9 uni27E7.s10 uni27E7.s11 uni27E7.s12 uni27E8.s5 uni27E8.s7 uni27E8.s8 uni27E8.s9 uni27E8.s10 uni27E8.s11 uni27E8.s12 uni27E9.s5 uni27E9.s7 uni27E9.s8 uni27E9.s9 uni27E9.s10 uni27E9.s11 uni27E9.s12 uni27EA.s5 uni27EA.s6 uni27EA.s7 uni27EA.s8 uni27EA.s9 uni27EA.s10 uni27EA.s11 uni27EA.s12 uni27EB.s5 uni27EB.s6 uni27EB.s7 uni27EB.s8 uni27EB.s9 uni27EB.s10 uni27EB.s11 uni27EB.s12 uni2983.s5 uni2983.s6 uni2983.s7 uni2983.s8 uni2983.s9 uni2983.s10 uni2983.s11 uni2983.s12 uni2984.s5 uni2984.s6 uni2984.s7 uni2984.s8 uni2984.s9 uni2984.s10 uni2984.s11 uni2984.s12 uni2985.s5 uni2985.s6 uni2985.s7 uni2985.s8 uni2985.s9 uni2985.s10 uni2985.s11 uni2985.s12 uni2986.s5 uni2986.s6 uni2986.s7 uni2986.s8 uni2986.s9 uni2986.s10 uni2986.s11 uni2986.s12 uni29FC.s4 uni29FC.s5 uni29FC.s6 uni29FC.s7 uni29FC.s8 uni29FC.s9 uni29FC.s10 uni29FC.s11 uni29FC.s12 uni29FD.s4 uni29FD.s5 uni29FD.s6 uni29FD.s7 uni29FD.s8 uni29FD.s9 uni29FD.s10 uni29FD.s11 uni29FD.s12uni2338uni233Auni233Euni2341uni2342uni2347uni2348uni2350uni2357uni2360uni2364uni2365uni2366uni236Duni2378uni2395uni23B7uni23B8uni23B9uni2422u1EEF0u1EEF1uni2063 uni2063.edituni2064 uni2064.edituni2100uni2101uni2103uni2104uni2106uni2108uni2109uni2114uni211Funi2120uni2121uni2123uni212Auni2139uni213Auni213Buni214Cuni214Duni214Euni214Funi2301uni2303uni2304uni2307uni2314uni231Buni2324uni2325uni2326uni2327uni2328uni232Buni232Funi2330uni2331uni2333uni2334uni2335uni233Buni233Cuni2343uni2344uni2345uni2346uni234Auni234Cuni234Duni234Funi2351uni2354uni2356uni2358uni235Auni235Buni235Cuni2361uni2362uni2367uni2369uni236Euni236Funi2376uni2379uni237Buni237Duni237Euni237Funi2380uni2381uni2382uni2383uni2384uni2385uni2386uni2387uni2388uni2389uni238Auni238Buni238Cuni238Duni238Euni238Funi2390uni2391uni2392uni2396uni2397uni2398uni2399uni239Auni23BAuni23BBuni23BCuni23BDuni23BEuni23BFuni23C0uni23C1uni23C2uni23C3uni23C4uni23C5uni23C6uni23C7uni23C8uni23C9uni23CAuni23CBuni23CCuni23CDuni23CFuni23D1uni23D2uni23D3uni23D4uni23D5uni23D6uni23D7uni23D8uni23D9uni23DAuni23DBuni23E8uni23E9uni23EAuni23EBuni23ECuni23EDuni23EEuni23EFuni23F0uni23F1uni23F2uni23F3uni23F4uni23F5uni23F6uni23F7uni23F8uni23F9uni23FAuni23FBuni23FCuni23FDuni23FEuni23FFuni2600uni2601uni2602uni2603uni2604uni2607uni2608uni260Auni260Buni260Duni260Funi2610uni2611uni2613uni2614uni2615uni2616uni2617uni2618uni2619uni261Auni261Buni261Cuni261Duni261Euni261Funi2620uni2622uni2623uni2624uni2625uni2626uni2627uni2628uni2629uni262Auni262Buni262Cuni262Duni262Euni262Funi2630uni2631uni2632uni2633uni2634uni2635uni2636uni2637uni2638uni2645uni264Auni264Buni264Cuni264Duni264Euni264Funi2650uni2651uni2652uni2653uni2654uni2655uni2656uni2657uni2658uni2659uni265Auni265Buni265Cuni265Duni265Euni265Funi2668uni266Cuni2670uni2671uni2672recyclingtype1plasticsrecyclingtype2plasticsrecyclingtype3plasticsrecyclingtype4plasticsrecyclingtype5plasticsrecyclingtype6plasticsrecyclingtype7plasticsuni267Auni267Buni267Cuni267Dcaruni268Auni268Buni268Cuni268Duni268Euni268Funi2690uni2691uni2692uni2693uni2694uni2695uni2696uni2697uni2698uni2699uni269Auni269Buni269Cuni269Duni269Euni269Funi26A1uni26A2uni26A3uni26A4uni26A6uni26A7uni26A8uni26A9uni26ADuni26AEuni26AFuni26B0uni26B1uni26B3uni26B4uni26B5uni26B6uni26B7uni26B8uni26B9uni26BAuni26BBuni26BCuni26BDuni26BEkeyuni26C0uni26C1uni26C2uni26C3uni26C4uni26C5uni26C6uni26C7uni26C8uni26C9uni26CAuni26CBuni26CCuni26CDuni26CEuni26CFuni26D0uni26D1uni26D2uni26D3uni26D4uni26D5uni26D6uni26D7uni26D8uni26D9uni26DAuni26DBuni26DCuni26DDuni26DEuni26DFuni26E0uni26E1uni26E3uni26E4uni26E5uni26E6uni26E7uni26E8uni26E9uni26EAuni26EBuni26ECuni26EDuni26EEuni26EFuni26F0uni26F1uni26F2uni26F3uni26F4uni26F5uni26F6uni26F7uni26F8uni26F9uni26FAuni26FBuni26FCuni26FDuni26FEuni26FF uniE1BE.nu uniE1BF.nu uniE1C0.nu uniE1C1.nu uniE1C2.nu uniE1C3.nu uniE1C4.nu uniE1C5.nu uniE1C6.nu uniE1C7.nu uniE1C8.nu uniE1C9.nu uniE1CA.nu uniE1CB.nu uniE1CC.nu uniE1CD.nu uniE1CE.nu uniE1CF.nu uniE1D0.nu uniE1D1.nu uniE1D2.nu uniE1D3.nu uniE1D4.nu uniE1D5.nu uniE1D6.nu uniE1D7.nu uniE1BB.nu uniE1D8.nu uniE1D9.nu uniE1DA.nu uniE1DB.nu uniE1DC.nu uniE1DD.nu uniE1DE.nu uniE1DF.nu uniE1E0.nu uniE1E1.nu uniE1E2.nu uniE1E3.nu uniE1E4.nu uniE1E5.nu uniE1E6.nu uniE1E7.nu uniE1E8.nu uniE1E9.nu uniE1EA.nu uniE1EB.nu uniE1EC.nu uniE1ED.nu uniE1EE.nu uniE1EF.nu uniE1F0.nu uniE1F1.nu uniE1F2.nu uniE1F3.nu uniE1F4.nu uniE1F5.nu uniE154.nu uniE155.nu uniE1B4.nu uniE156.nu uniE157.nu uniE158.nu uniE1B5.nu uniE159.nu uniE15A.nu uniE15B.nu uniE15C.nu uniE15D.nu uniE1B6.nu uniE15E.nu uniE1B7.nu uniE1B8.nu uniE1B9.nu uniE15F.nu uniE160.nu uniE161.nu uniE162.nu uniE163.nu uniE164.nu uniE165.nu uniE1BA.nu uniE166.nu uniE167.nu uniE168.nu uniE169.nu uniE16A.nu uniE16B.nu uniE16C.nu uniE16D.nu uniE16E.nu uniE16F.nu uniE170.nu uniE171.nu uniE172.nu uniE173.nu uniE174.nu uniE175.nu uniE176.nu uniE177.nu uniE178.nu uniE179.nu uniE17A.nu uniE17B.nuu1D4B6u1D4B7u1D4B8u1D4B9uni212Fu1D4BBuni210Au1D4BDu1D4BEu1D4BE.dotlessu1D4BFu1D4BF.dotlessu1D4C0u1D4C1u1D4C2u1D4C3uni2134u1D4C5u1D4C6u1D4C7u1D4C8u1D4C9u1D4CAu1D4CBu1D4CCu1D4CDu1D4CEu1D4CFu1D4D0u1D4D1u1D4D2u1D4D3u1D4D4u1D4D5u1D4D6u1D4D7u1D4D8u1D4D9u1D4DAu1D4DBu1D4DCu1D4DDu1D4DEu1D4DFu1D4E0u1D4E1u1D4E2u1D4E3u1D4E4u1D4E5u1D4E6u1D4E7u1D4E8u1D4E9u1D4EAu1D4EBu1D4ECu1D4EDu1D4EEu1D4EFu1D4F0u1D4F1u1D4F2u1D4F2.dotlessu1D4F3u1D4F3.dotlessu1D4F4u1D4F5u1D4F6u1D4F7u1D4F8u1D4F9u1D4FAu1D4FBu1D4FCu1D4FDu1D4FEu1D4FFu1D500u1D501u1D502u1D503 colon.sstysemicolon.ssty ellipsis.ssty exclam.ssty slash.sstybackslash.sstybar.sstybracketleft.sstybracketright.sstybraceleft.sstybraceright.ssty uni27E8.ssty uni27E9.sstyquoteright.sstyquotedblright.ssty dagger.ssty uni20D7.ssty uni2190.ssty uni2191.ssty uni2192.ssty uni2193.sstynumbersign.sstyplusminus.ssty uni2213.ssty multiply.ssty uni2260.ssty less.ssty greater.ssty uni2264.ssty uni2265.ssty uni2A7D.ssty uni2A7E.ssty uni2295.ssty uni2297.ssty uni2205.ssty uni2216.ssty uni2217.ssty uni2208.ssty uni220B.ssty uni2227.ssty uni2228.ssty uni2229.sstyuni2229.var.ssty uni222A.sstyuni222A.var.ssty uni2282.ssty uni2283.ssty uni2211.ssty uni221A.ssty uni221E.ssty uni222B.ssty uni2218.ssty uni2219.ssty uni223C.ssty uni22A4.ssty uni22A5.ssty uni22C5.ssty uni22C6.ssty uni22EF.ssty uni266E.ssty uni266F.ssty uni210F.ssty uni2113.ssty u1D400.ssty u1D401.ssty u1D402.ssty u1D403.ssty u1D404.ssty u1D405.ssty u1D406.ssty u1D407.ssty u1D408.ssty u1D409.ssty u1D40A.ssty u1D40B.ssty u1D40C.ssty u1D40D.ssty u1D40E.ssty u1D40F.ssty u1D410.ssty u1D411.ssty u1D412.ssty u1D413.ssty u1D414.ssty u1D415.ssty u1D416.ssty u1D417.ssty u1D418.ssty u1D419.ssty u1D41A.ssty u1D41B.ssty u1D41C.ssty u1D41D.ssty u1D41E.ssty u1D41F.ssty u1D420.ssty u1D421.ssty u1D422.sstyu1D422.dotless.ssty u1D423.sstyu1D423.dotless.ssty u1D424.ssty u1D425.ssty u1D426.ssty u1D427.ssty u1D428.ssty u1D429.ssty u1D42A.ssty u1D42B.ssty u1D42C.ssty u1D42D.ssty u1D42E.ssty u1D42F.ssty u1D430.ssty u1D431.ssty u1D432.ssty u1D433.ssty u1D49C.ssty uni212C.ssty u1D49E.ssty u1D49F.ssty uni2130.ssty uni2131.ssty u1D4A2.ssty uni210B.ssty uni2110.ssty u1D4A5.ssty u1D4A6.ssty uni2112.ssty uni2133.ssty u1D4A9.ssty u1D4AA.ssty u1D4AB.ssty u1D4AC.ssty uni211B.ssty u1D4AE.ssty u1D4AF.ssty u1D4B0.ssty u1D4B1.ssty u1D4B2.ssty u1D4B3.ssty u1D4B4.ssty u1D4B5.ssty u1D4B6.ssty u1D4B7.ssty u1D4B8.ssty u1D4B9.ssty uni212F.ssty u1D4BB.ssty uni210A.ssty u1D4BD.ssty u1D4BE.sstyu1D4BE.dotless.ssty u1D4BF.sstyu1D4BF.dotless.ssty u1D4C0.ssty u1D4C1.ssty u1D4C2.ssty u1D4C3.ssty uni2134.ssty u1D4C5.ssty u1D4C6.ssty u1D4C7.ssty u1D4C8.ssty u1D4C9.ssty u1D4CA.ssty u1D4CB.ssty u1D4CC.ssty u1D4CD.ssty u1D4CE.ssty u1D4CF.sstyu1D49C.ssty.ss01uni212C.ssty.ss01u1D49E.ssty.ss01u1D49F.ssty.ss01uni2130.ssty.ss01uni2131.ssty.ss01u1D4A2.ssty.ss01uni210B.ssty.ss01uni2110.ssty.ss01u1D4A5.ssty.ss01u1D4A6.ssty.ss01uni2112.ssty.ss01uni2133.ssty.ss01u1D4A9.ssty.ss01u1D4AA.ssty.ss01u1D4AB.ssty.ss01u1D4AC.ssty.ss01uni211B.ssty.ss01u1D4AE.ssty.ss01u1D4AF.ssty.ss01u1D4B0.ssty.ss01u1D4B1.ssty.ss01u1D4B2.ssty.ss01u1D4B3.ssty.ss01u1D4B4.ssty.ss01u1D4B5.ssty.ss01u1D4B6.ssty.ss01u1D4B7.ssty.ss01u1D4B8.ssty.ss01u1D4B9.ssty.ss01uni212F.ssty.ss01u1D4BB.ssty.ss01uni210A.ssty.ss01u1D4BD.ssty.ss01u1D4BE.ssty.ss01u1D4BE.dotless.ssty.ss01u1D4BF.ssty.ss01u1D4BF.dotless.ssty.ss01u1D4C0.ssty.ss01u1D4C1.ssty.ss01u1D4C2.ssty.ss01u1D4C3.ssty.ss01uni2134.ssty.ss01u1D4C5.ssty.ss01u1D4C6.ssty.ss01u1D4C7.ssty.ss01u1D4C8.ssty.ss01u1D4C9.ssty.ss01u1D4CA.ssty.ss01u1D4CB.ssty.ss01u1D4CC.ssty.ss01u1D4CD.ssty.ss01u1D4CE.ssty.ss01u1D4CF.ssty.ss01 u1D504.ssty u1D505.ssty uni212D.ssty u1D507.ssty u1D508.ssty u1D509.ssty u1D50A.ssty uni210C.ssty uni2111.ssty u1D50D.ssty u1D50E.ssty u1D50F.ssty u1D510.ssty u1D511.ssty u1D512.ssty u1D513.ssty u1D514.ssty uni211C.ssty u1D516.ssty u1D517.ssty u1D518.ssty u1D519.ssty u1D51A.ssty u1D51B.ssty u1D51C.ssty uni2128.ssty u1D51E.ssty u1D51F.ssty u1D520.ssty u1D521.ssty u1D522.ssty u1D523.ssty u1D524.ssty u1D525.ssty u1D526.sstyu1D526.dotless.ssty u1D527.sstyu1D527.dotless.ssty u1D528.ssty u1D529.ssty u1D52A.ssty u1D52B.ssty u1D52C.ssty u1D52D.ssty u1D52E.ssty u1D52F.ssty u1D530.ssty u1D531.ssty u1D532.ssty u1D533.ssty u1D534.ssty u1D535.ssty u1D536.ssty u1D537.ssty u1D538.ssty u1D539.ssty uni2102.ssty u1D53B.ssty u1D53C.ssty u1D53D.ssty u1D53E.ssty uni210D.ssty u1D540.ssty u1D541.ssty u1D542.ssty u1D543.ssty u1D544.ssty uni2115.ssty u1D546.ssty uni2119.ssty uni211A.ssty uni211D.ssty u1D54A.ssty u1D54B.ssty u1D54C.ssty u1D54D.ssty u1D54E.ssty u1D54F.ssty u1D550.ssty uni2124.ssty u1D552.ssty u1D553.ssty u1D554.ssty u1D555.ssty u1D556.ssty u1D557.ssty u1D558.ssty u1D559.ssty u1D55A.sstyu1D55A.dotless.ssty u1D55B.sstyu1D55B.dotless.ssty u1D55C.ssty u1D55D.ssty u1D55E.ssty u1D55F.ssty u1D560.ssty u1D561.ssty u1D562.ssty u1D563.ssty u1D564.ssty u1D565.ssty u1D566.ssty u1D567.ssty u1D568.ssty u1D569.ssty u1D56A.ssty u1D56B.ssty colon.ssty2semicolon.ssty2ellipsis.ssty2 exclam.ssty2 slash.ssty2backslash.ssty2 bar.ssty2bracketleft.ssty2bracketright.ssty2braceleft.ssty2braceright.ssty2 uni27E8.ssty2 uni27E9.ssty2quoteright.ssty2quotedblright.ssty2 dagger.ssty2 uni20D7.ssty2 uni2190.ssty2 uni2191.ssty2 uni2192.ssty2 uni2193.ssty2numbersign.ssty2plusminus.ssty2 uni2213.ssty2multiply.ssty2 uni2260.ssty2 less.ssty2 greater.ssty2 uni2264.ssty2 uni2265.ssty2 uni2A7D.ssty2 uni2A7E.ssty2 uni2295.ssty2 uni2297.ssty2 uni2205.ssty2 uni2216.ssty2 uni2217.ssty2 uni2208.ssty2 uni220B.ssty2 uni2227.ssty2 uni2228.ssty2 uni2229.ssty2uni2229.var.ssty2 uni222A.ssty2uni222A.var.ssty2 uni2282.ssty2 uni2283.ssty2 uni2211.ssty2 uni221A.ssty2 uni221E.ssty2 uni222B.ssty2 uni2218.ssty2 uni2219.ssty2 uni223C.ssty2 uni22A4.ssty2 uni22A5.ssty2 uni22C5.ssty2 uni22C6.ssty2 uni22EF.ssty2 uni266E.ssty2 uni266F.ssty2 uni210F.ssty2 uni2113.ssty2 u1D400.ssty2 u1D401.ssty2 u1D402.ssty2 u1D403.ssty2 u1D404.ssty2 u1D405.ssty2 u1D406.ssty2 u1D407.ssty2 u1D408.ssty2 u1D409.ssty2 u1D40A.ssty2 u1D40B.ssty2 u1D40C.ssty2 u1D40D.ssty2 u1D40E.ssty2 u1D40F.ssty2 u1D410.ssty2 u1D411.ssty2 u1D412.ssty2 u1D413.ssty2 u1D414.ssty2 u1D415.ssty2 u1D416.ssty2 u1D417.ssty2 u1D418.ssty2 u1D419.ssty2 u1D41A.ssty2 u1D41B.ssty2 u1D41C.ssty2 u1D41D.ssty2 u1D41E.ssty2 u1D41F.ssty2 u1D420.ssty2 u1D421.ssty2 u1D422.ssty2u1D422.dotless.ssty2 u1D423.ssty2u1D423.dotless.ssty2 u1D424.ssty2 u1D425.ssty2 u1D426.ssty2 u1D427.ssty2 u1D428.ssty2 u1D429.ssty2 u1D42A.ssty2 u1D42B.ssty2 u1D42C.ssty2 u1D42D.ssty2 u1D42E.ssty2 u1D42F.ssty2 u1D430.ssty2 u1D431.ssty2 u1D432.ssty2 u1D433.ssty2 u1D49C.ssty2 uni212C.ssty2 u1D49E.ssty2 u1D49F.ssty2 uni2130.ssty2 uni2131.ssty2 u1D4A2.ssty2 uni210B.ssty2 uni2110.ssty2 u1D4A5.ssty2 u1D4A6.ssty2 uni2112.ssty2 uni2133.ssty2 u1D4A9.ssty2 u1D4AA.ssty2 u1D4AB.ssty2 u1D4AC.ssty2 uni211B.ssty2 u1D4AE.ssty2 u1D4AF.ssty2 u1D4B0.ssty2 u1D4B1.ssty2 u1D4B2.ssty2 u1D4B3.ssty2 u1D4B4.ssty2 u1D4B5.ssty2 u1D4B6.ssty2 u1D4B7.ssty2 u1D4B8.ssty2 u1D4B9.ssty2 uni212F.ssty2 u1D4BB.ssty2 uni210A.ssty2 u1D4BD.ssty2 u1D4BE.ssty2u1D4BE.dotless.ssty2 u1D4BF.ssty2u1D4BF.dotless.ssty2 u1D4C0.ssty2 u1D4C1.ssty2 u1D4C2.ssty2 u1D4C3.ssty2 uni2134.ssty2 u1D4C5.ssty2 u1D4C6.ssty2 u1D4C7.ssty2 u1D4C8.ssty2 u1D4C9.ssty2 u1D4CA.ssty2 u1D4CB.ssty2 u1D4CC.ssty2 u1D4CD.ssty2 u1D4CE.ssty2 u1D4CF.ssty2u1D49C.ssty2.ss01uni212C.ssty2.ss01u1D49E.ssty2.ss01u1D49F.ssty2.ss01uni2130.ssty2.ss01uni2131.ssty2.ss01u1D4A2.ssty2.ss01uni210B.ssty2.ss01uni2110.ssty2.ss01u1D4A5.ssty2.ss01u1D4A6.ssty2.ss01uni2112.ssty2.ss01uni2133.ssty2.ss01u1D4A9.ssty2.ss01u1D4AA.ssty2.ss01u1D4AB.ssty2.ss01u1D4AC.ssty2.ss01uni211B.ssty2.ss01u1D4AE.ssty2.ss01u1D4AF.ssty2.ss01u1D4B0.ssty2.ss01u1D4B1.ssty2.ss01u1D4B2.ssty2.ss01u1D4B3.ssty2.ss01u1D4B4.ssty2.ss01u1D4B5.ssty2.ss01u1D4B6.ssty2.ss01u1D4B7.ssty2.ss01u1D4B8.ssty2.ss01u1D4B9.ssty2.ss01uni212F.ssty2.ss01u1D4BB.ssty2.ss01uni210A.ssty2.ss01u1D4BD.ssty2.ss01u1D4BE.ssty2.ss01u1D4BE.dotless.ssty2.ss01u1D4BF.ssty2.ss01u1D4BF.dotless.ssty2.ss01u1D4C0.ssty2.ss01u1D4C1.ssty2.ss01u1D4C2.ssty2.ss01u1D4C3.ssty2.ss01uni2134.ssty2.ss01u1D4C5.ssty2.ss01u1D4C6.ssty2.ss01u1D4C7.ssty2.ss01u1D4C8.ssty2.ss01u1D4C9.ssty2.ss01u1D4CA.ssty2.ss01u1D4CB.ssty2.ss01u1D4CC.ssty2.ss01u1D4CD.ssty2.ss01u1D4CE.ssty2.ss01u1D4CF.ssty2.ss01 u1D504.ssty2 u1D505.ssty2 uni212D.ssty2 u1D507.ssty2 u1D508.ssty2 u1D509.ssty2 u1D50A.ssty2 uni210C.ssty2 uni2111.ssty2 u1D50D.ssty2 u1D50E.ssty2 u1D50F.ssty2 u1D510.ssty2 u1D511.ssty2 u1D512.ssty2 u1D513.ssty2 u1D514.ssty2 uni211C.ssty2 u1D516.ssty2 u1D517.ssty2 u1D518.ssty2 u1D519.ssty2 u1D51A.ssty2 u1D51B.ssty2 u1D51C.ssty2 uni2128.ssty2 u1D51E.ssty2 u1D51F.ssty2 u1D520.ssty2 u1D521.ssty2 u1D522.ssty2 u1D523.ssty2 u1D524.ssty2 u1D525.ssty2 u1D526.ssty2u1D526.dotless.ssty2 u1D527.ssty2u1D527.dotless.ssty2 u1D528.ssty2 u1D529.ssty2 u1D52A.ssty2 u1D52B.ssty2 u1D52C.ssty2 u1D52D.ssty2 u1D52E.ssty2 u1D52F.ssty2 u1D530.ssty2 u1D531.ssty2 u1D532.ssty2 u1D533.ssty2 u1D534.ssty2 u1D535.ssty2 u1D536.ssty2 u1D537.ssty2 u1D538.ssty2 u1D539.ssty2 uni2102.ssty2 u1D53B.ssty2 u1D53C.ssty2 u1D53D.ssty2 u1D53E.ssty2 uni210D.ssty2 u1D540.ssty2 u1D541.ssty2 u1D542.ssty2 u1D543.ssty2 u1D544.ssty2 uni2115.ssty2 u1D546.ssty2 uni2119.ssty2 uni211A.ssty2 uni211D.ssty2 u1D54A.ssty2 u1D54B.ssty2 u1D54C.ssty2 u1D54D.ssty2 u1D54E.ssty2 u1D54F.ssty2 u1D550.ssty2 uni2124.ssty2 u1D552.ssty2 u1D553.ssty2 u1D554.ssty2 u1D555.ssty2 u1D556.ssty2 u1D557.ssty2 u1D558.ssty2 u1D559.ssty2 u1D55A.ssty2u1D55A.dotless.ssty2 u1D55B.ssty2u1D55B.dotless.ssty2 u1D55C.ssty2 u1D55D.ssty2 u1D55E.ssty2 u1D55F.ssty2 u1D560.ssty2 u1D561.ssty2 u1D562.ssty2 u1D563.ssty2 u1D564.ssty2 u1D565.ssty2 u1D566.ssty2 u1D567.ssty2 u1D568.ssty2 u1D569.ssty2 u1D56A.ssty2 u1D56B.ssty2uni2000uni2001uni2002uni2003uni2004uni2005uni2006uni2007uni2008uni2009uni200Auni202Funi200Cuni200Duni2216.var.sstyuni2216.var.ssty2uniE1F6 S\F7-phx|(, , NDDIIDDD^DDDDDUDNA7=B> y( 7  <(###dPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPPdPPP2A--<A-A#AKddPn#  2A--<A-A#AKddPn# F  ((2(7A-FF(2 <(22<(PP<d( P P2ddF<<( (F 2 PZF<Z#n##( (< ( PZF<Z#-x---(##( P##--A-A#7#APPPP P#--A-A#7#AZPPP(F#2 F(#  2  PZ<<UZ_2A--<A-A#KKndPn# 2   P#--A-A#7#KnPZP (<2K#77FK7K-(UUnxZx-2(Z(-77K7K-A-(UxZZZ(###<2<(PP<d( P P2ddF< F(#  2  PZ<<UZ_(2P2(Z(dPFd-x#-#-nnP2(((F2<22 <A A6KK(2 nnP2(((F((<2(2K U(FF(2 nnP2((<2<(PP<d( P P2ddF<<(2((P22F<(<U(((_7PP2<xxZ<22F<F2ZZFn2Z((Z<nnPFF2    yE              ( * 7 9 9 ; ; = = ? @ B B D E M M O e g g i l n n p q   , - . / 1 24MNOPQRTUV[t  u  vwyz|}"~YZDEGLN\^^``bbddjjvvxx,57DHHJJNNPPSSYY[[^eghjo q !"#$%%.&0=0AA>CC?GG@IIALLBTTCW^D`aLchNjxTzzc||d~~efghijk !!##%%++88=EGTXX\\fgiillnnpprsuuwx~~2<>KMM OO QQ ST VVXY__aacdh012345@NOPQSTVWXZtuvwx@)t \h6|^JO|r|r,r6,r^^6"|88h6JTJ6rm^|Jr|,;1^hhhTr;@hE'JO"6JT"Eh@6@rJ^r|,|1Tr^w1 66h,rh"|11@Y,'^"rw"O"|@vhrm@|J'T||h^0YJ)@,6h^@;wJ|h^TrwJw^J!rrJ ,",,6",,,6|O*D"|*R|w&T*Z^"|,,Th@^T,T  OO@,YJ66,r,:qr|66&6m@^";|ch6XN0h6h:|hr| h|RlH0R>44v0&J|&&|NhT|rJrr&r|J,@|J|D|',@,^h,,T,@J@J@@|^|T1^h^^,, 66""""6"T"""^O,wOT"T""J"xx^",^,""hY@T^,^,'T' ",|rhhhh@|ThhhhTYJhT^116,^J'^@;6J6|rrrrTTrrrrrwcm^h66T6hh6h@@@T  @''''"",",6,,,66,,,,,,,,,,6,,""@"E|TO|TJw@wTw6Jhr,J","J"@hh6; ||J;|T|JTc;w6rJ,;|c^6'NYr"^rrO6h1T1@|m,hw&,,,J,,T^@T"^T,^ '|hE6" @mhhc|rrrh|rrhmcw|h|6"^@r6J"J;hJT6","rEhYET'," ^J@", ,1,,",,,@@,,","ThrrTT,Yh,"6"@@T6,6@6@6Th|hhhTTYJJT@T6^@6",|T@"6r@ &@JX0lr@@T|^&Y||6,||r;hh &@X|O'r|rc^r@JhJwI,,,6"|,!||@r0,@@T@6,^^hYT^^ThT,|||!|rr^^rOrJr"^J,@|h"6JT:::IOO0&&NrrN^|XY@'m5&:I!^&?0D:|O|Tr!T|I Nl&l X40"""6""JT,rOTO"TrhY",OOTJrh6,TJ6rr^|Jr|,;,^h^hEOhr@J6J",Jrhrwhh|hhhchJYhTr"^@w,@ J@^O,@"6^TJvTEr^||^T^h,;T,;66h@|m^||c^|^&:bX&|6J|h|h|||6||'cNw",'@'@,@@^6JJTJ@T":DXv0D+006^"||r fpXz >&fp0> NX&^&S|Xl,"6@6|,T6"6h,@|hrrr6r|c0EE'Y'Y;;;1EY1J:;wl1;6O6O;OOm@YY^YOc1X bv&0NbIN!SD0D^6JDXN 4HfN&N f4l:v:D|D:{ @6JTJ &@hJ,J|ET"r|||@|mDTT6h6,hJJJ@Th,@",,,"~578>FIkRuuqz ( )6!#R%[v\x} <GV L ' ?  ME @G$$&-\ elQYZ(([,,\hi]kl_noay|cglqrs p y 4 4 6 6 @ A D E i i n |            ! # $ & &! ) )" , -# / 0% 2 3' 5 6) 8 9+ ; <- > ?/ A B1 D E3 G H5 J K7 M N9 P Q; S T= V W? Y ZA \ ]C _ `E b cG e fI h iK k lM n oO q rQ t uS w xU b cW g iY\^L   $r $ * 8 F T b p       . z D Z p v   " 0 > L Z p ~    $ 2 @ z N z d z r " 8 N d r  r$rr:rHVdrx0FTbpn &<BnXnt*0>Tbx~"0>Lbp4J`v:   MM*OP+WW-]]._`/rr1tz29: ; < = ? @ A C D H I  l m  x  y  z ) )} 1 1~ 3 4 6 6 T T X X Z Z \ \ _ _ a d t t +KMNPPR\^^``bd` ~ ,~!8,@j$(s  (0~~$~?8~P<8 hRk30$$\M<[\NaAQXT !)-!#dZT|(d pHhb dlh;##-x|^:VQL<815,5`h$(Lhl$%#8#L9rt"FL,+!$9l q%0) Z@ ( <T`\~Nd~3ud@`/E+'?)me< ;ogg7K o+}9-j95Z)15 9)  9Z\~ p~0dldTDv/v.jv*Vbnz"Dfr&2>JVbnz 6  J * b " Z    & 2 > J V b n z  ".:FR^jv*6`p6Rn V&\~$P|0\ L t0\v$%&'()*+,-(,/hkny p u i n s x           # & ) , / 2 5 8 ; > A D G J M P S V Y \ _ b e h k n q t w b g/:<WY  &+.46)19BKQ 4 6 @ A D E$efbg h M%ijbk l M&&  &  ''  'dd8 (sa Q A 1    8 )!"#$s%a& Q' A( 1) * + ,8 *-./0s1b2 R3 B4 25 6 7 88 +9:;<s=b> R? B@ 2A B C D8 ,EFGHtIbJ RK BL 2M N O P    8 -QRSTtUbV RW BX 2Y Z [ \    GXXYGGXGXXYGXXYG(G*,,8(G,G,G*,,8/,G*,,8(Ghi3kl3no.yz?{ C| L}q~&? C LX~&? C LX~& +  +P hXX ^ + + + + + + + + + + + + + + + +!"8 o^ O ? 0   8 o^ O ? 0    8 o ^ O ? 0   8 o^ O ? 0    p q r s to^ O ? 0! " # $ u v w x yo%^& O' ?( 0) * + ,     o-^. O/ ?0 01 2 3 4     o5^6 O7 ?8 09 : ; <     s=c S> C? 3@ A B C     sDc SE CF 3G H I J     sKcL SM CN 3O P Q R     sScT SU CV 3W X Y Z G 8 G G G 8 G 8 G G G 8 i j k l ms[b\ R] B^ 2_ ` a b n o p q rscbd Re Bf 2g h i j s t u v wskbl Rm Bn 2o p q r x y z { |ssbt Ru Bv 2w x y z       "  "             . r D r D   +   +   +   +  ! + # $ + & ' + ) * + , - + / 0 + 2 3 + 5 6 + 8 9 + ; < + > ? + A B + D E + G H + J K + M N + P Q + S T + V W + Y Z + \ ] + _ ` + b c + e f + h i + k l + n4 o  q3 r  t3 u  w2 x  b c d| b b g h i}    s>tuvw QB}>~ Q  > Q:B> Q<  WWWWWYYY}; }; }< }}< }}} }<  }< }< }}< }UUUU<=UUUUUUU&x&x'C+w'C+w.&x'C+w4i4i5C6h5C6hw )XXw ! )"XX)y,-./0 )*XX+1y45678 )2"XX39w=>?@A ):,XX;,,XX<,BwFGHIJ )C,"XXD,,"XXE,KwLMNOP )QwRSTUV ) 4U 6U @U< A=U DU< E=Uuharfbuzz-0.53.3/tests/data/SparseFont.ttf000066400000000000000000000006241513514046200205030ustar00rootroot00000000000000@GPOSDPcmap*Xhead\6maxp  postJ 7%5_<ƚ D  CJT2 AIT2 $%&,-7IJ ,DFLTkern uharfbuzz-0.53.3/tests/data/chromacheck-colr.ttf000066400000000000000000000012141513514046200216170ustar00rootroot00000000000000 @COLR%`CPALxOS/2'JH`cmap 3,glyf "$head 6hhea$hmtxloca maxp( name >post@ #]m_<ҠQ 3      !!    ChromaCheck COLRuharfbuzz-0.53.3/tests/data/expected/000077500000000000000000000000001513514046200174775ustar00rootroot00000000000000uharfbuzz-0.53.3/tests/data/expected/hand-10000066400000000000000000000050741513514046200205600ustar00rootroot00000000000000start clip rectangle 64 -224 1.22e+03 928 start transform 1 0 0 1 0 0 start transform 1 0 0 1 0 0 start clip glyph 13 start transform 1 0 0 1 0 0 start transform 1 0 0 0.977 0 0 radial gradient p0 280 440 radius 0 p1 280 440 radius 467 colors 0 0 186 141 104 255 0.449 183 138 103 255 0.809 173 130 100 255 1 164 123 98 255 end transform end transform end clip end transform start transform 1 0 0 1 0 0 start clip glyph 14 start transform 1 0 0 1 0 0 linear gradient p0 231 -27 p1 1.02e+03 -27 p2 231 -815 colors 0 0 164 123 98 255 1 164 123 98 255 end transform end clip end transform start transform 1 0 0 1 0 0 start clip glyph 15 start transform 1 0 0 1 0 0 solid 145 103 77 255 end transform end clip end transform start transform 1 0 0 1 0 0 start clip glyph 16 start transform 1 0 0 1 0 0 solid 30 136 229 255 end transform end clip end transform start transform 1 0 0 1 0 0 start clip glyph 21 start transform 1 0 0 1 0 0 solid 145 103 77 255 end transform end clip end transform start transform 1 0 0 1 0 0 start clip glyph 16 start transform 1 0 0 1 0 0 linear gradient p0 669 776 p1 180 -106 p2 -212 1.26e+03 colors 0 0 100 181 246 255 1 33 150 243 255 end transform end clip end transform start transform 1 0 0 1 0 0 start clip glyph 18 start transform 1 0 0 1 0 0 solid 66 66 66 51 end transform end clip end transform start transform 1 0 0 1 0 0 start clip glyph 19 start transform 1 0 0 1 0 0 start transform 1 0 0 0.969 0 0 radial gradient p0 588 198 radius 0 p1 588 198 radius 342 colors 0 0 186 141 104 255 0.449 183 138 103 255 0.809 173 130 100 255 1 164 123 98 255 end transform end transform end clip end transform start transform 1 0 0 1 0 0 start clip glyph 20 start transform 1 0 0 1 0 0 solid 145 103 77 255 end transform end clip end transform end transform end clip uharfbuzz-0.53.3/tests/data/expected/test-10000066400000000000000000000006371513514046200206250ustar00rootroot00000000000000start clip rectangle 100 250 900 950 start transform 1 0 0 1 0 0 start transform 1 0 0 1 0 0 start clip glyph 10 start transform 1 0 0 1 0 0 linear gradient p0 100 250 p1 900 250 p2 100 300 colors 1 0 255 0 0 255 1.5 0 0 255 255 end transform end clip end transform end transform end clip uharfbuzz-0.53.3/tests/data/expected/test-106000066400000000000000000000010511513514046200207020ustar00rootroot00000000000000start transform 1 0 0 1 0 0 push group start transform 1 0 0 1 0 0 start clip glyph 3 start transform 1 0 0 1 0 0 solid 0 0 255 127 end transform end clip end transform push group start transform 1 0.268 0 1 0 -134 start transform 1 0 0 1 0 0 start clip glyph 3 start transform 1 0 0 1 0 0 solid 255 165 0 178 end transform end clip end transform end transform pop group mode 4 pop group mode 3 end transform uharfbuzz-0.53.3/tests/data/expected/test-116000066400000000000000000000010441513514046200207050ustar00rootroot00000000000000start transform 1 0 0 1 0 0 push group start transform 1 0 0 1 0 0 start clip glyph 3 start transform 1 0 0 1 0 0 solid 0 0 255 127 end transform end clip end transform push group start transform 1 0 0 1 100 0 start transform 1 0 0 1 0 0 start clip glyph 3 start transform 1 0 0 1 0 0 solid 255 165 0 178 end transform end clip end transform end transform pop group mode 4 pop group mode 3 end transform uharfbuzz-0.53.3/tests/data/expected/test-123000066400000000000000000000016021513514046200207030ustar00rootroot00000000000000start clip rectangle 0 0 1e+03 1e+03 start transform 1 0 0 1 0 0 start transform 1 0 0 1 0 0 start clip glyph 3 start transform 1 0 0 1 0 0 solid 0 0 0 255 end transform end clip end transform push group start transform 0.5 0 0 0.5 166 334 start transform 1 0 0 1 0 0 start clip glyph 2 start transform 1 0 0 1 0 0 solid 255 220 1 255 end transform end clip end transform end transform push group start transform 0.5 0 0 0.5 334 166 start transform 1 0 0 1 0 0 start clip glyph 2 start transform 1 0 0 1 0 0 solid 104 199 232 255 end transform end clip end transform end transform pop group mode 3 pop group mode 3 end transform end clip uharfbuzz-0.53.3/tests/data/expected/test-154000066400000000000000000000004141513514046200207070ustar00rootroot00000000000000start clip rectangle 100 250 900 950 start transform 1 0 0 1 0 0 start transform 1 0 0 1 0 0 start clip glyph 154 start transform 1 0 0 1 0 0 solid 0 0 0 255 end transform end clip end transform end transform end clip uharfbuzz-0.53.3/tests/data/expected/test-165000066400000000000000000000000601513514046200207060ustar00rootroot00000000000000start clip glyph 165 solid 0 0 0 255 end clip uharfbuzz-0.53.3/tests/data/expected/test-175000066400000000000000000000000601513514046200207070ustar00rootroot00000000000000start clip glyph 175 solid 0 0 0 255 end clip uharfbuzz-0.53.3/tests/data/expected/test-6000066400000000000000000000000561513514046200205450ustar00rootroot00000000000000start clip glyph 6 solid 0 0 0 255 end clip uharfbuzz-0.53.3/tests/data/expected/test-92000066400000000000000000000007041513514046200206320ustar00rootroot00000000000000start clip rectangle 0 0 1e+03 1e+03 start transform 1 0 0 1 0 0 start transform 1 0 0 1 0 0 start clip glyph 2 start transform 1 0 0 1 0 0 linear gradient p0 0 1.02e+03 p1 307 1.02e+03 p2 0 717 colors 2 0 0 128 0 255 0.5 255 255 255 255 1 255 0 0 255 end transform end clip end transform end transform end clip uharfbuzz-0.53.3/tests/data/noto_handwriting-cff2_colr_1.otf000066400000000000000000000101141513514046200240370ustar00rootroot00000000000000OTTO @CFF21b DCOLR* PCPAL atDGSUB'/vOS/2P`30`cmapNhead o6hheaT$hmtx>maxpP(name"8oPpost3 =j_<::33JPfMff33NONE  3WKXKXe$L$ L( ' '  4 ' ' N 8 8 ^F H  Hnoto_handwriting-cff2_colr_1Regular1.000;NONE;noto_handwriting-cff2_colr_1-Regularnoto_handwriting-cff2_colr_1 RegularVersion 1.000noto_handwriting-cff2_colr_1-Regular3eoeo  $|l~..tntQ|j;$ nCg!qv{~w" y]}Vg'% j<;jYxɏDžO0L\W[z[z]{Xn-|o$6!}dcg15 }M]tx ! |# J\ +( ~}~^M5  z91IX^g8 C>hfbxfŎ̳jkPtu)2$^frk{x|HY7TQ|~uuRw|cerKCNj_cMf=QPmk8 ktz! |# J%apnmsst[zmnz~qx}}xxwy͏yBezvsYjrpoxvro;lrtn ̐!rv{}w" z]|Vgvtunzo|piNJtn{oq||:$ rTe^% ۓw&?z=e}oVmppnzxvs`?7nlkqrr[zqs|~oג:gnpi`{|>|E|E|C"n(. 4 : @ F   "*2!&1^i!2=!Ch2n!2:Ec!2!,28e  @>u   @ o i ,@@@  @>zzV@1@ @  @>_ @@@ Q K @>//V@@&@7$@@@ @  XX @@@ p hAhA&f@@@ E @>==V@I@/@@@ @  @>_  @@ @ K E @>LLV@@3@@ @  @  @>_   qq!@=@ K E @>FF5 @ @1 @?@ @  @>p   @@@ P @ ? @>zzVf@0@ @ @   !BBB'/J7@\dJSp4S8WMg=`Bib{Cldghcz~( $2DFLTlatnccmp2 $    uharfbuzz-0.53.3/tests/data/test_glyphs-glyf_colr_1.ttf000066400000000000000000000521001513514046200231560ustar00rootroot00000000000000 @COLR=:CPALSlOS/2EM`H`cmapvh4glyfhead(.6hhea $hmtx. locaci?maxp( nametXXpost'K f_<yy ???? Xdddddddddddddd^, 4 G TZcgm  q  x       !2\j !-9EQ]iu)5AMYeq} %1=IUamy !-9EQ]iu)5AMYeq} %1=IUamy !-9EQ]iu #/Qs  I U a m y  ! - 9 E Q ] i u    ) 5 A M Y1! 533##5#522 22(#557(%Kj%(e! #"&554632'4&#"3265e1+*22**2%vG99G-G77G1))190,,0 7,, 1!!!!5!!!! d7!d Dd7!d Dd7!d Dd7!d D1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!! 1! !! ! 7! 1!d7!dLD1!1!&& #5#35#46334&#&222X2222X #5#35#46334&#X;)d;)d;)d;)X);d);d);d);d^ #5#35#466334&&#(E)(E)(E)(E)X)E()E()E()E(,  #5#35#466334&&#6[76[76[76[7X7[67[67[67[6^R #5#35#466334&&#CrECrECrECrEXErCErCErCErC,  #!3!4>3!4.# /Rm>/Rm>/Rm>,/Rm>X>mR/,>mR/,>mR/>mR/R #!3!4>3!4.#R6aH6aH6aH^6aHXHa6^Ha6^Ha6Ha61!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1!1! 4 !Tu 2  h BU 4 <COLRv1 Static Test GlyphsRegularCOLRv1 Static Test Glyphs 2024-05-27T11:29:29.707270COLRv1 Static Test Glyphs Regular2024-05-27T11:29:29.707270COLRv1StaticTestGlyphs-RegularCOLRv1 Static Test GlyphsRegularCOLRv1 Static Test Glyphs 2024-05-27T11:29:29.707270COLRv1 Static Test Glyphs Regular2024-05-27T11:29:29.707270COLRv1StaticTestGlyphs-Regular      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~upem_box_glyph cross_glyphtrianglenegative_crosslinear_repeat_0_1linear_repeat_0.2_0.8linear_repeat_0_1.5linear_repeat_0.5_1.5sweep_0_360_pad_narrowsweep_60_300_pad_narrowsweep_0_90_pad_narrowsweep_90_0_pad_narrowsweep_45_90_pad_narrowsweep_90_45_pad_narrowsweep_247.5_292.5_pad_narrowsweep_-45_45_pad_narrowsweep_45_-45_pad_narrowsweep_270_440_pad_narrowsweep_440_270_pad_narrowsweep_-180_540_pad_narrowsweep_0_360_reflect_narrowsweep_60_300_reflect_narrowsweep_0_90_reflect_narrowsweep_90_0_reflect_narrowsweep_45_90_reflect_narrowsweep_90_45_reflect_narrow sweep_247.5_292.5_reflect_narrowsweep_-45_45_reflect_narrowsweep_45_-45_reflect_narrowsweep_270_440_reflect_narrowsweep_440_270_reflect_narrowsweep_-180_540_reflect_narrowsweep_0_360_repeat_narrowsweep_60_300_repeat_narrowsweep_0_90_repeat_narrowsweep_90_0_repeat_narrowsweep_45_90_repeat_narrowsweep_90_45_repeat_narrowsweep_247.5_292.5_repeat_narrowsweep_-45_45_repeat_narrowsweep_45_-45_repeat_narrowsweep_270_440_repeat_narrowsweep_440_270_repeat_narrowsweep_-180_540_repeat_narrowsweep_0_360_pad_widesweep_60_300_pad_widesweep_0_90_pad_widesweep_90_0_pad_widesweep_45_90_pad_widesweep_90_45_pad_widesweep_247.5_292.5_pad_widesweep_-45_45_pad_widesweep_45_-45_pad_widesweep_270_440_pad_widesweep_440_270_pad_widesweep_-180_540_pad_widesweep_0_360_reflect_widesweep_60_300_reflect_widesweep_0_90_reflect_widesweep_90_0_reflect_widesweep_45_90_reflect_widesweep_90_45_reflect_widesweep_247.5_292.5_reflect_widesweep_-45_45_reflect_widesweep_45_-45_reflect_widesweep_270_440_reflect_widesweep_440_270_reflect_widesweep_-180_540_reflect_widesweep_0_360_repeat_widesweep_60_300_repeat_widesweep_0_90_repeat_widesweep_90_0_repeat_widesweep_45_90_repeat_widesweep_90_45_repeat_widesweep_247.5_292.5_repeat_widesweep_-45_45_repeat_widesweep_45_-45_repeat_widesweep_270_440_repeat_widesweep_440_270_repeat_widesweep_-180_540_repeat_wide scale_0.5_1.5_center_500.0_500.0 scale_1.5_1.5_center_500.0_500.0scale_0.5_1.5_center_0_0scale_1.5_1.5_center_0_0scale_0.5_1.5_center_1000_1000scale_1.5_1.5_center_1000_1000linear_gradient_extend_mode_pad"linear_gradient_extend_mode_repeat#linear_gradient_extend_mode_reflect)radial_contained_gradient_extend_mode_pad,radial_contained_gradient_extend_mode_repeat-radial_contained_gradient_extend_mode_reflect*radial_horizontal_gradient_extend_mode_pad-radial_horizontal_gradient_extend_mode_repeat.radial_horizontal_gradient_extend_mode_reflectrotate_10_center_0_0rotate_-10_center_1000_1000rotate_25_center_500.0_500.0rotate_-15_center_500.0_500.0skew_25_0_center_0_0skew_25_0_center_500.0_500.0skew_0_15_center_0_0skew_0_15_center_500.0_500.0skew_-10_20_center_500.0_500.0skew_-10_20_center_1000_1000 transform_matrix_1_0_0_1_125_125 transform_matrix_1.5_0_0_1.5_0_01transform_matrix_0.9659_0.2588_-0.2588_0.9659_0_0+transform_matrix_1.0_0.0_0.6_1.0_-300.0_0.0 translate_0_0translate_0_100translate_0_-100translate_100_0translate_-100_0translate_200_200translate_-200_-200composite_CLEAR composite_SRCcomposite_DESTcomposite_SRC_OVERcomposite_DEST_OVERcomposite_SRC_INcomposite_DEST_INcomposite_SRC_OUTcomposite_DEST_OUTcomposite_SRC_ATOPcomposite_DEST_ATOP composite_XORcomposite_PLUScomposite_SCREENcomposite_OVERLAYcomposite_DARKENcomposite_LIGHTENcomposite_COLOR_DODGEcomposite_COLOR_BURNcomposite_HARD_LIGHTcomposite_SOFT_LIGHTcomposite_DIFFERENCEcomposite_EXCLUSIONcomposite_MULTIPLYcomposite_HSL_HUEcomposite_HSL_SATURATIONcomposite_HSL_COLORcomposite_HSL_LUMINOSITYforeground_color_linear_alpha_1!foreground_color_linear_alpha_0.3foreground_color_radial_alpha_1!foreground_color_radial_alpha_0.3foreground_color_sweep_alpha_1 foreground_color_sweep_alpha_0.3foreground_color_solid_alpha_1 foreground_color_solid_alpha_0.3clip_box_top_leftclip_box_bottom_leftclip_box_bottom_rightclip_box_top_rightclip_box_centerclip_shade_top_leftclip_shade_bottom_leftclip_shade_bottom_rightclip_shade_top_rightclip_shade_centerinset_clipped_radial_reflectgradient_p2_skewedcolored_circles_v0colored_circles_v1 circle_r50 circle_r100 circle_r150 circle_r200 circle_r250 circle_r300 circle_r350solid_colorline_alphapaintcolrglyph_cycle_firstpaintcolrglyph_cycle_secondno_cycle_multi_colrglyph,sweep_coincident_angles_forward_blue_red_pad0sweep_coincident_angles_forward_blue_red_reflect/sweep_coincident_angles_forward_blue_red_repeat.sweep_coincident_angles_forward_linen_gray_pad2sweep_coincident_angles_forward_linen_gray_reflect1sweep_coincident_angles_forward_linen_gray_repeat,sweep_coincident_angles_reverse_blue_red_pad0sweep_coincident_angles_reverse_blue_red_reflect/sweep_coincident_angles_reverse_blue_red_repeat.sweep_coincident_angles_reverse_linen_gray_pad2sweep_coincident_angles_reverse_linen_gray_reflect1sweep_coincident_angles_reverse_linen_gray_repeat+sweep_coincident_stops_forward_blue_red_pad/sweep_coincident_stops_forward_blue_red_reflect.sweep_coincident_stops_forward_blue_red_repeat-sweep_coincident_stops_forward_linen_gray_pad1sweep_coincident_stops_forward_linen_gray_reflect0sweep_coincident_stops_forward_linen_gray_repeat+sweep_coincident_stops_reverse_blue_red_pad/sweep_coincident_stops_reverse_blue_red_reflect.sweep_coincident_stops_reverse_blue_red_repeat-sweep_coincident_stops_reverse_linen_gray_pad1sweep_coincident_stops_reverse_linen_gray_reflect0sweep_coincident_stops_reverse_linen_gray_repeat$paint_glyph_nested_identity_identity%paint_glyph_nested_identity_translate)paint_glyph_nested_identity_rotate_origin)paint_glyph_nested_identity_rotate_center%paint_glyph_nested_translate_identity&paint_glyph_nested_translate_translate*paint_glyph_nested_translate_rotate_origin*paint_glyph_nested_translate_rotate_center)paint_glyph_nested_rotate_origin_identity*paint_glyph_nested_rotate_origin_translate.paint_glyph_nested_rotate_origin_rotate_origin.paint_glyph_nested_rotate_origin_rotate_center)paint_glyph_nested_rotate_center_identity*paint_glyph_nested_rotate_center_translate.paint_glyph_nested_rotate_center_rotate_origin.paint_glyph_nested_rotate_center_rotate_center"(H     9 K]o,>Pbt !"#$%1&C'U(g)y*+,-./01$263H4Z5l6~789:;< = > )? ;@ MA _B qC D E F G H I J K .L @M RN dO vP Q R S T U V W !X /Y CZ U[ k\ ] ^ _ ` a b /c Zd he zf g h i j k l m n 5o \p q r s t u v w x0y6z<{B|H}N~TZ`flrx~0W~"(U (U 6cDq%R`n|.J tdd,  dd, @33@  dd,@`@  dd, @`@ X@ XU* X X X xX fX( TX BX 0X \r X\r  X@@%U@0@ X@ XU* X X X xX fX( TX BX 0X \r X\r  X@@%U@0@ X@ XU* X X X xX fX( TX BX 0X \r X\r  X@@%U@0@ X@ XU* X X X xX fX( TX BX 0X \r X\r  X@ @@@P@ X@ XU* X X X xX fX( TX BX 0X \r X\r  X@ @@@P@ X@ XU* X X X xX fX( TX BX 0X \r X\r  X@ @@@P@ :' ` &`  ` `  ` ` 3 3 3 R g | d@ @@@ d@ @@@ d@ @@@  r   t wd cPU S@U ?,r +r  }}    EBAE   {h kXd [H K8d ;( + 88 ,     "$&(*,.0246 ddd, udd, 8X2X IX2X  X @ @@@  X @ 3@@ @ 3 K > = 0 / " !     _ d@ @@@8@ B  X@U@*@@@  X@U@*@@@  X@U@*@@@  X@U@*@@@  X@U@*@@@  X@U@*@@@  X @ @ @ @  X @ @ @ @  X @ @ @ @  X @ @ @ @  X @ @ @ @  X @ @ @ @  X @ @ @ @  X @ @ @ @  X @ @ @ @  X @ @ @ @  X @ @ @ @  X @ @ @ @     rxx xx xx xx : L ^ n  U b  U Dxx  U &  U  U G (08@HPX`hpx0;FQWbmx         ~ v n f{ ^s Vk Nc F[ >S 6K .C &; 3 +   M  @ M  @ @ @ @ @ @ @ @  @ @j X@@@F@@X$4{4{X.((X qqX X X @X   ` SZbx`ir{dddd*KOO/hJ)*cA$c}šq uharfbuzz-0.53.3/tests/test_uharfbuzz.py000066400000000000000000002056771513514046200204370ustar00rootroot00000000000000import uharfbuzz as hb from pathlib import Path import sys import platform import pytest TESTDATA = Path(__file__).parent / "data" ADOBE_BLANK_TTF_PATH = TESTDATA / "AdobeBlank.subset.ttf" OPEN_SANS_TTF_PATH = TESTDATA / "OpenSans.subset.ttf" MUTATOR_SANS_TTF_PATH = TESTDATA / "MutatorSans-VF.subset.ttf" SPARSE_FONT_TTF_PATH = TESTDATA / "SparseFont.ttf" MATH_FONT_TTF_PATH = TESTDATA / "STIXTwoMath-Regular.ttf" COLORv0_FONT_TTF_PATH = TESTDATA / "chromacheck-colr.ttf" COLORv1_FONT_TTF_PATH = TESTDATA / "test_glyphs-glyf_colr_1.ttf" @pytest.fixture def blankfont(): """Return a subset of AdobeBlank.ttf containing the following glyphs/characters: [ {gid=0, name=".notdef"}, {gid=1, name="a", code=0x61}, {gid=2, name="b", code=0x62}, {gid=3, name="c", code=0x63}, {gid=4, name="d", code=0x64}, {gid=5, name="e", code=0x65}, {gid=6, name="ccedilla", code=0x62}, {gid=7, name="uni0431", code=0x0431}, # CYRILLIC SMALL LETTER BE {gid=8, name="u1F4A9", code=0x1F4A9}, # PILE OF POO ] """ blob = hb.Blob.from_file_path(ADOBE_BLANK_TTF_PATH) face = hb.Face(blob) font = hb.Font(face) return font @pytest.fixture def opensans(): """Return a subset of OpenSans.ttf containing the following glyphs/characters: [ {gid=0, name=".notdef"}, {gid=1, name="A", code=0x41}, ] """ blob = hb.Blob(OPEN_SANS_TTF_PATH.read_bytes()) face = hb.Face(blob) font = hb.Font(face) return font @pytest.fixture def mutatorsans(): """Return a subset of MutatorSans-VF with a wdth and wght axis.""" face = hb.Face(MUTATOR_SANS_TTF_PATH.read_bytes()) font = hb.Font(face) return font @pytest.fixture def sparsefont(): """Return a font that only has a few tables: GPOS, cmap, head, maxp and post""" face = hb.Face(SPARSE_FONT_TTF_PATH.read_bytes()) font = hb.Font(face) return font @pytest.fixture def mathfont(): """Return a subset of STIX Two Math font with only MATH, post, head, and maxp tables""" face = hb.Face(MATH_FONT_TTF_PATH.read_bytes()) font = hb.Font(face) return font @pytest.fixture def colorv0font(): blob = hb.Blob.from_file_path(COLORv0_FONT_TTF_PATH) face = hb.Face(blob) font = hb.Font(face) return font @pytest.fixture def colorv1font(): blob = hb.Blob.from_file_path(COLORv1_FONT_TTF_PATH) face = hb.Face(blob) font = hb.Font(face) return font class TestBuffer: def test_init(self): buf = hb.Buffer() def test_create(self): buf = hb.Buffer.create() @pytest.mark.parametrize( "string, expected", [ ("abcde", [(0x61, 0), (0x62, 1), (0x63, 2), (0x64, 3), (0x65, 4)]), ("abçde", [(0x61, 0), (0x62, 1), (0xE7, 2), (0x64, 3), (0x65, 4)]), ("aбcde", [(0x61, 0), (0x431, 1), (0x63, 2), (0x64, 3), (0x65, 4)]), ("abc💩e", [(0x61, 0), (0x62, 1), (0x63, 2), (0x1F4A9, 3), (0x65, 4)]), ], ids=["ascii", "latin1", "ucs2", "ucs4"], ) def test_add_str(self, string, expected): buf = hb.Buffer() buf.add_str(string) infos = [(g.codepoint, g.cluster) for g in buf.glyph_infos] flags = [(g.flags) for g in buf.glyph_infos] assert all(0 == f for f in flags) assert infos == expected def test_add_utf8(self): buf = hb.Buffer() buf.add_utf8("aбç💩e".encode("utf-8")) infos = [(g.codepoint, g.cluster) for g in buf.glyph_infos] assert infos == [(0x61, 0), (0x431, 1), (0xE7, 3), (0x1F4A9, 5), (0x65, 9)] def test_add_codepoints(self): buf = hb.Buffer() buf.add_codepoints([0x61, 0x431, 0xE7, 0x1F4A9, 0x65]) infos = [(g.codepoint, g.cluster) for g in buf.glyph_infos] assert infos == [(0x61, 0), (0x431, 1), (0xE7, 2), (0x1F4A9, 3), (0x65, 4)] def test_guess_set_segment_properties(self): buf = hb.Buffer() buf.add_str("הארץ") buf.guess_segment_properties() assert buf.direction == "rtl" assert buf.script == "Hebr" # the guessed language seems to be locale specific # assert buf.language == "en-us" assert buf.language buf.direction = "ltr" assert buf.direction == "ltr" buf.script = "Latn" assert buf.script == "Latn" buf.language = "he-il" assert buf.language == "he-il" buf.set_script_from_ot_tag("mym2") assert buf.script == "Mymr" buf.set_language_from_ot_tag("BGR") assert buf.language == "bg" def test_empty_buffer_props(self): buf = hb.Buffer() assert buf.script == None assert buf.language == None assert buf.direction == "invalid" def test_cluster_level(self): buf = hb.Buffer() assert buf.cluster_level == hb.BufferClusterLevel.DEFAULT buf.cluster_level = hb.BufferClusterLevel.MONOTONE_CHARACTERS assert buf.cluster_level == hb.BufferClusterLevel.MONOTONE_CHARACTERS buf.cluster_level = hb.BufferClusterLevel.MONOTONE_GRAPHEMES assert buf.cluster_level == hb.BufferClusterLevel.MONOTONE_GRAPHEMES buf.cluster_level = hb.BufferClusterLevel.CHARACTERS assert buf.cluster_level == hb.BufferClusterLevel.CHARACTERS buf.cluster_level = hb.BufferClusterLevel.DEFAULT assert buf.cluster_level == hb.BufferClusterLevel.DEFAULT def test_cluster_level_int(self): buf = hb.Buffer() assert buf.cluster_level == 0 buf.cluster_level = 1 assert buf.cluster_level == 1 with pytest.raises(ValueError): # 5 is not a valid BufferClusterLevel buf.cluster_level = 5 assert buf.cluster_level == 1 def test_properties(self): buf = hb.Buffer() assert len(buf) == 0 assert buf.flags == hb.BufferFlags.DEFAULT buf.flags = hb.BufferFlags.BOT | hb.BufferFlags.EOT assert buf.flags == hb.BufferFlags.BOT | hb.BufferFlags.EOT assert buf.content_type == hb.BufferContentType.INVALID buf.content_type = hb.BufferContentType.UNICODE assert buf.content_type == hb.BufferContentType.UNICODE assert buf.cluster_level == hb.BufferClusterLevel.DEFAULT buf.cluster_level = hb.BufferClusterLevel.CHARACTERS assert buf.cluster_level == hb.BufferClusterLevel.CHARACTERS assert buf.replacement_codepoint == hb.Buffer.DEFAULT_REPLACEMENT_CODEPOINT buf.replacement_codepoint = 0 assert buf.replacement_codepoint == 0 buf.add_str("ABC") assert len(buf) == 3 buf.clear_contents() assert len(buf) == 0 assert buf.flags == hb.BufferFlags.BOT | hb.BufferFlags.EOT buf.reset() assert buf.flags == hb.BufferFlags.DEFAULT @pytest.mark.parametrize( "glyphs,format,flags,expected", [ ( False, hb.BufferSerializeFormat.TEXT, hb.BufferSerializeFlags.DEFAULT, "", ), ( False, hb.BufferSerializeFormat.TEXT, hb.BufferSerializeFlags.NO_CLUSTERS, "", ), ( True, hb.BufferSerializeFormat.TEXT, hb.BufferSerializeFlags.DEFAULT, "[a=0+0|b=1+0|c=2+0|d=3+0|e=4+0]", ), ( True, hb.BufferSerializeFormat.TEXT, hb.BufferSerializeFlags.DEFAULT | hb.BufferSerializeFlags.NO_CLUSTERS | hb.BufferSerializeFlags.NO_POSITIONS, "[a|b|c|d|e]", ), ( False, hb.BufferSerializeFormat.JSON, hb.BufferSerializeFlags.DEFAULT, '[{"u":97,"cl":0},{"u":98,"cl":1},{"u":99,"cl":2},' '{"u":100,"cl":3},{"u":101,"cl":4}]', ), ( False, hb.BufferSerializeFormat.JSON, hb.BufferSerializeFlags.NO_CLUSTERS, '[{"u":97},{"u":98},{"u":99},{"u":100},{"u":101}]', ), ( True, hb.BufferSerializeFormat.JSON, hb.BufferSerializeFlags.DEFAULT, '[{"g":"a","cl":0,"dx":0,"dy":0,"ax":0,"ay":0},' '{"g":"b","cl":1,"dx":0,"dy":0,"ax":0,"ay":0},' '{"g":"c","cl":2,"dx":0,"dy":0,"ax":0,"ay":0},' '{"g":"d","cl":3,"dx":0,"dy":0,"ax":0,"ay":0},' '{"g":"e","cl":4,"dx":0,"dy":0,"ax":0,"ay":0}]', ), ( True, hb.BufferSerializeFormat.JSON, hb.BufferSerializeFlags.DEFAULT | hb.BufferSerializeFlags.NO_CLUSTERS | hb.BufferSerializeFlags.NO_POSITIONS, '[{"g":"a"},{"g":"b"},{"g":"c"},{"g":"d"},{"g":"e"}]', ), ], ) def test_serialize(self, glyphs, format, flags, expected): font = hb.Font(hb.Face(ADOBE_BLANK_TTF_PATH.read_bytes())) buf = hb.Buffer() buf.add_str("abcde") buf.guess_segment_properties() if glyphs: hb.shape(font, buf) assert buf.serialize(font, format=format, flags=flags) == expected class TestBlob: def test_from_file_path_fail(self): with pytest.raises(hb.HarfBuzzError, match="Failed to open: DOES-NOT-EXIST"): blob = hb.Blob.from_file_path("DOES-NOT-EXIST") class TestFace: def test_properties(self, blankfont): face = blankfont.face assert face.count > 0 assert face.index == 0 assert face.upem == 1000 assert face.glyph_count == 9 assert face.table_tags == [ "BASE", "GPOS", "GSUB", "OS/2", "cmap", "cvt ", "fpgm", "gasp", "glyf", "head", "hhea", "hmtx", "loca", "maxp", "name", "post", "prep", ] assert face.unicodes == hb.Set( {0x61, 0x62, 0x63, 0x64, 0x65, 0xE7, 0x431, 0x1F4A9} ) assert face.variation_selectors == hb.Set() assert face.variation_unicodes(1) == hb.Set() def test_has_var_data(self, blankfont, mutatorsans): assert blankfont.face.has_var_data == False assert mutatorsans.face.has_var_data == True def test_axis_infos(self, mutatorsans): face = mutatorsans.face assert face.axis_infos == [ (0, "wdth", 256, 0, 0.0, 0.0, 1000.0), (1, "wght", 257, 0, 0.0, 0.0, 1000.0), ] def test_named_instances(self, mutatorsans): face = mutatorsans.face named_instances = face.named_instances assert named_instances == [ (258, 259, [0.0, 0.0]), (260, 261, [0.0, 1000.0]), (262, 263, [1000.0, 0.0]), (264, 265, [1000.0, 1000.0]), (266, 267, [327.0, 500.0]), (268, 269, [569.0780029296875, 1000.0]), (270, 271, [1000.0, 500.0]), (272, 273, [794.52197265625, 775.6090087890625]), (274, 65535, [93.052001953125, 658.5969848632812]), (275, 276, [328.0, 500.0]), ] assert face.get_name(named_instances[0].subfamily_name_id) == "LightCondensed" assert ( face.get_name(named_instances[0].postscript_name_id) == "MutatorMathTest-LightCondensed" ) assert face.get_name(named_instances[-1].subfamily_name_id) == "Medium_Wide_I" assert ( face.get_name(named_instances[-1].postscript_name_id) == "MutatorMathTest-Medium_Narrow_I" ) def test_has_math_data(self, blankfont, mathfont): assert blankfont.face.has_math_data == False assert mathfont.face.has_math_data == True @pytest.mark.parametrize( "constant, expected", [ (hb.OTMathConstant.SCRIPT_PERCENT_SCALE_DOWN, 70), (hb.OTMathConstant.SCRIPT_SCRIPT_PERCENT_SCALE_DOWN, 55), (hb.OTMathConstant.RADICAL_KERN_BEFORE_DEGREE, 65), (hb.OTMathConstant.RADICAL_KERN_AFTER_DEGREE, -335), (hb.OTMathConstant.RADICAL_DEGREE_BOTTOM_RAISE_PERCENT, 55), ], ) def test_get_math_constant(self, mathfont, constant, expected): assert mathfont.get_math_constant(constant) == expected def test_get_math_constant_invalid(self, mathfont): with pytest.raises(ValueError): mathfont.get_math_constant(1000) @pytest.mark.parametrize( "glyph, expected", [ ("uni222B", 230), ("uni210B", 40), ("uni222B.dsp", 540), ("u1D435", 30), ("A", 0), ], ) def test_get_math_glyph_italics_correction(self, mathfont, glyph, expected): gid = mathfont.get_glyph_from_name(glyph) assert mathfont.get_math_glyph_italics_correction(gid) == expected @pytest.mark.parametrize( "glyph, expected", [ ("u1D435", 380), ("A", 360), ("parenleft", 250), ], ) def test_get_math_glyph_top_accent_attachment(self, mathfont, glyph, expected): gid = mathfont.get_glyph_from_name(glyph) assert mathfont.get_math_glyph_top_accent_attachment(gid) == expected @pytest.mark.parametrize( "glyph, expected", [ ("A", False), ("parenleft", True), ("parenright", True), ("bar", True), ("uni221A", True), ], ) def test_ot_math_is_glyph_extended_shape(self, mathfont, glyph, expected): gid = mathfont.get_glyph_from_name(glyph) assert mathfont.face.is_glyph_extended_math_shape(gid) == expected @pytest.mark.parametrize( "direction, expected", [ ("LTR", 100), ("RTL", 100), ("TTB", 100), ("BTT", 100), ], ) def test_get_math_min_connector_overlap(self, mathfont, direction, expected): assert mathfont.get_math_min_connector_overlap(direction) == expected @pytest.mark.parametrize( "glyph, kern, height, expected", [ ("A", hb.OTMathKern.TOP_RIGHT, 250, 0), ("A", hb.OTMathKern.TOP_RIGHT, 300, -18), ("A", hb.OTMathKern.TOP_RIGHT, 400, -66), ("F", hb.OTMathKern.BOTTOM_RIGHT, 0, -200), ("F", hb.OTMathKern.BOTTOM_RIGHT, 150, -44), ("F", hb.OTMathKern.BOTTOM_RIGHT, 300, 44), ("J", hb.OTMathKern.TOP_LEFT, 250, 64), ("J", hb.OTMathKern.TOP_LEFT, 300, -28), ("J", hb.OTMathKern.TOP_LEFT, 400, -28), ("M", hb.OTMathKern.BOTTOM_LEFT, 0, 40), ("M", hb.OTMathKern.BOTTOM_LEFT, 150, 40), ("M", hb.OTMathKern.BOTTOM_LEFT, 300, 40), ], ) def test_get_math_glyph_kerning(self, mathfont, glyph, kern, height, expected): gid = mathfont.get_glyph_from_name(glyph) assert mathfont.get_math_glyph_kerning(gid, kern, height) == expected def test_get_math_glyph_kerning_invalid(self, mathfont): gid = mathfont.get_glyph_from_name("A") with pytest.raises(ValueError): mathfont.get_math_glyph_kerning(gid, 1000, 100) @pytest.mark.parametrize( "glyph, kern, expected", [ ( "u1D434", hb.OTMathKern.TOP_RIGHT, [(213, 58), (350, -58), (0x7FFFFFFF, -70)], ), ( "u1D435", hb.OTMathKern.BOTTOM_RIGHT, [(160, -50), (283, -12), (0x7FFFFFFF, 20)], ), ( "u1D435", hb.OTMathKern.TOP_LEFT, [(176, 81), (0x7FFFFFFF, -50)], ), ( "U", hb.OTMathKern.BOTTOM_LEFT, [(126, -80), (256, -60), (0x7FFFFFFF, 36)], ), ], ) def test_get_math_glyph_kernings(self, mathfont, glyph, kern, expected): gid = mathfont.get_glyph_from_name(glyph) assert mathfont.get_math_glyph_kernings(gid, kern) == expected def test_get_math_glyph_kernings_invalid(self, mathfont): gid = mathfont.get_glyph_from_name("A") with pytest.raises(ValueError): mathfont.get_math_glyph_kernings(gid, 1000) @pytest.mark.parametrize( "glyph, direction, expected", [ ( "parenleft", "TTB", [ ("parenleft", 933), ("parenleft.s1", 1187), ("parenleft.s2", 1427), ("parenleft.s3", 1667), ("parenleft.s4", 1907), ("parenleft.s5", 2145), ("parenleft.s6", 2385), ("parenleft.s7", 2625), ("parenleft.s8", 2865), ("parenleft.s9", 3101), ("parenleft.s10", 3341), ("parenleft.s11", 3581), ("parenleft.s12", 3821), ], ), ("parenleft", "LTR", []), ("uni2211", "TTB", [("uni2211", 1031), ("uni2211.s1", 1326)]), ( "uni0302", "LTR", [ ("uni0302", 283), ("circumflex.s1", 574), ("circumflex.s2", 1003), ("circumflex.s3", 1496), ("circumflex.s4", 1932), ("circumflex.s5", 2385), ], ), ("uni0302", "TTB", []), ], ) def test_get_math_glyph_variants(self, mathfont, glyph, direction, expected): gid = mathfont.get_glyph_from_name(glyph) variants = mathfont.get_math_glyph_variants(gid, direction) result = [(mathfont.get_glyph_name(v.glyph), v.advance) for v in variants] assert result == expected @pytest.mark.parametrize( "glyph, direction, expected", [ ( "parenleft", "TTB", ( [ ("uni239D", 0, 250, 1273, 0), ("uni239C", 1000, 1000, 1252, hb.OTMathGlyphPartFlags.EXTENDER), ("uni239B", 250, 0, 1273, 0), ], 0, ), ), ("parenleft", "LTR", ([], 0)), ( "uni222B", "TTB", ( [ ("uni2321", 0, 800, 1896, 0), ( "integral.x", 600, 600, 1251, hb.OTMathGlyphPartFlags.EXTENDER, ), ("uni2320", 800, 0, 1630, 0), ], 80, ), ), ( "uni23DE", "LTR", ( [ ("uni23DE.l", 0, 300, 957, 0), ("uni23B4.x", 600, 600, 751, hb.OTMathGlyphPartFlags.EXTENDER), ("uni23DE.m", 300, 300, 943, 0), ("uni23B4.x", 600, 600, 751, hb.OTMathGlyphPartFlags.EXTENDER), ("uni23DE.r", 300, 0, 957, 0), ], 0, ), ), ("uni0302", "TTB", ([], 0)), ], ) def test_get_math_glyph_assembly(self, mathfont, glyph, direction, expected): gid = mathfont.get_glyph_from_name(glyph) assembly, italics_correction = mathfont.get_math_glyph_assembly(gid, direction) result = [ ( mathfont.get_glyph_name(v.glyph), v.start_connector_length, v.end_connector_length, v.full_advance, v.flags, ) for v in assembly ] assert (result, italics_correction) == expected def test_get_metric_position(self, opensans): assert opensans.get_metric_position(hb.OTMetricsTag.HORIZONTAL_ASCENDER) == 2189 assert opensans.get_metric_position(hb.OTMetricsTag.CAP_HEIGHT) == 1462 assert opensans.get_metric_position(hb.OTMetricsTag.VERTICAL_CARET_RISE) is None def test_get_metric_position_with_fallback(self, opensans): assert ( opensans.get_metric_position_with_fallback( hb.OTMetricsTag.VERTICAL_CARET_RISE ) == 1 ) def test_get_metric_variation(self, mutatorsans): assert mutatorsans.get_metric_variation(hb.OTMetricsTag.CAP_HEIGHT) == 0 mutatorsans.set_variations({"wdth": 250, "wght": 250}) assert mutatorsans.get_metric_variation(hb.OTMetricsTag.CAP_HEIGHT) == 25 def test_get_metric_x_variation(self, mutatorsans): mutatorsans.set_variations({"wdth": 250, "wght": 250}) assert mutatorsans.get_metric_x_variation(hb.OTMetricsTag.CAP_HEIGHT) == 25 def test_ot_get_metric_y_variation(self, mutatorsans): mutatorsans.set_variations({"wdth": 250, "wght": 250}) assert mutatorsans.get_metric_y_variation(hb.OTMetricsTag.CAP_HEIGHT) == 25 def test_has_color_palettes(self, colorv0font): assert colorv0font.face.has_color_palettes def test_has_no_color_palettes(self, blankfont): assert blankfont.face.has_color_palettes == False def test_color_palettes(self, colorv0font, colorv1font): palettes1 = colorv0font.face.color_palettes palettes2 = colorv1font.face.color_palettes assert len(palettes1) == 1 assert len(palettes2) == 3 assert palettes1[0].colors == [(200, 0, 0, 255)] assert palettes2[0].colors == [ (255, 0, 0, 255), (255, 165, 0, 255), (255, 255, 0, 255), (0, 128, 0, 255), (0, 0, 255, 255), (75, 0, 130, 255), (238, 130, 238, 255), (250, 240, 230, 255), (47, 79, 79, 255), (255, 255, 255, 255), (0, 0, 0, 255), (104, 199, 232, 255), (255, 220, 1, 255), (128, 128, 128, 255), ] assert palettes2[0].flags == hb.OTColorPaletteFlags.DEFAULT assert palettes2[1].flags == hb.OTColorPaletteFlags.USABLE_WITH_DARK_BACKGROUND assert palettes2[2].flags == hb.OTColorPaletteFlags.USABLE_WITH_LIGHT_BACKGROUND def test_no_color_palettes(self, blankfont): assert blankfont.face.color_palettes == [] def test_color_palette_color_get_name_id(self, colorv1font): assert colorv1font.face.color_palette_color_get_name_id(0) is None assert colorv1font.face.color_palette_color_get_name_id(1) is None assert colorv1font.face.color_palette_color_get_name_id(2) is None def test_color_palette_color_get_name_id_no_palettes(self, blankfont): assert blankfont.face.color_palette_color_get_name_id(0) is None def test_has_color_layers(self, colorv0font): assert colorv0font.face.has_color_layers def test_has_no_color_layers(self, blankfont): assert blankfont.face.has_color_layers == False def test_get_glyph_color_layers(self, colorv0font): assert colorv0font.face.get_glyph_color_layers(1) == [(1, 0)] assert colorv0font.face.get_glyph_color_layers(0) == [] def test_get_glyph_color_layers_no_layers(self, blankfont): assert blankfont.face.get_glyph_color_layers(1) == [] def test_has_color_paint(self, colorv1font): assert colorv1font.face.has_color_paint def test_has_no_color_paint(self, blankfont): assert blankfont.face.has_color_paint == False def test_glyph_has_color_paint(self, colorv1font): assert colorv1font.face.glyph_has_color_paint(1) == False assert colorv1font.face.glyph_has_color_paint(9) == True def test_glyph_has_no_color_paint(self, blankfont): assert blankfont.face.glyph_has_color_paint(1) == False def test_has_color_svg(self, blankfont): assert blankfont.face.has_color_svg == False blob = blankfont.face.get_glyph_color_svg(1) assert len(blob) == 0 def test_has_color_png(self, blankfont): assert blankfont.face.has_color_png == False def test_get_language_feature_tags(self, blankfont): assert blankfont.face.get_language_feature_tags("GPOS") == ["kern"] assert blankfont.face.get_language_feature_tags("GSUB") == ["calt"] def test_get_table_script_tags(self, blankfont): assert blankfont.face.get_table_script_tags("GPOS") == ["DFLT"] def test_script_get_language_tags(self, blankfont): assert blankfont.face.get_script_language_tags("GPOS", 0) == [] def test_lookup_get_glyph_alternates(self, blankfont): gid = blankfont.get_nominal_glyph(ord("c")) assert blankfont.face.get_lookup_glyph_alternates(1, gid) == [1] def test_has_layout_glyph_classes(self, opensans): assert opensans.face.has_layout_glyph_classes def test_has_no_layout_glyph_classes(self, blankfont): assert blankfont.face.has_layout_glyph_classes == False def test_get_layout_glyph_class(self, opensans): glyph_class = opensans.face.get_layout_glyph_class(1) assert glyph_class == hb.OTLayoutGlyphClass.BASE_GLYPH def test_has_layout_positioning(self, opensans): assert opensans.face.has_layout_positioning def test_has_no_positioning(self, mathfont): assert mathfont.face.has_layout_positioning == False def test_has_layout_substitution(self, opensans): assert opensans.face.has_layout_substitution def test_has_no_layout_substitution(self, mathfont): assert mathfont.face.has_layout_substitution == False @pytest.mark.parametrize( "name_id, language, expected", [ (hb.OTNameIdPredefined.FULL_NAME, None, "Adobe Blank"), (hb.OTNameIdPredefined.FULL_NAME, "ar", None), (hb.OTNameIdPredefined.INVALID, "en", None), (hb.OTNameIdPredefined.INVALID, None, None), (hb.OTNameIdPredefined.DESCRIPTION, None, None), ], ) def test_get_name(self, blankfont, name_id, language, expected): assert blankfont.face.get_name(name_id, language) == expected def test_list_names(self, blankfont): face = blankfont.face names = face.list_names() assert names == [ (hb.OTNameIdPredefined.COPYRIGHT, "en"), (hb.OTNameIdPredefined.FONT_FAMILY, "en"), (hb.OTNameIdPredefined.FONT_SUBFAMILY, "en"), (hb.OTNameIdPredefined.UNIQUE_ID, "en"), (hb.OTNameIdPredefined.FULL_NAME, "en"), (hb.OTNameIdPredefined.VERSION_STRING, "en"), (hb.OTNameIdPredefined.POSTSCRIPT_NAME, "en"), ] assert [face.get_name(*name) for name in names] == [ "Copyright © 2013, 2015 Adobe Systems Incorporated " "(http://www.adobe.com/).", "Adobe Blank", "Regular", "1.045;ADBO;AdobeBlank;ADOBE", "Adobe Blank", "Version 1.045;PS 1.045;hotconv 1.0.82;makeotf.lib2.5.63406", "AdobeBlank", ] def test_list_names_with_user_names(self, mutatorsans): face = mutatorsans.face names = face.list_names() assert names == [ (hb.OTNameIdPredefined.COPYRIGHT, "en"), (hb.OTNameIdPredefined.FONT_SUBFAMILY, "en"), (hb.OTNameIdPredefined.UNIQUE_ID, "en"), (hb.OTNameIdPredefined.FULL_NAME, "en"), (hb.OTNameIdPredefined.VERSION_STRING, "en"), (hb.OTNameIdPredefined.POSTSCRIPT_NAME, "en"), (256, "en"), (257, "en"), (258, "en"), (259, "en"), (260, "en"), (261, "en"), (262, "en"), (263, "en"), (264, "en"), (265, "en"), (266, "en"), (267, "en"), (268, "en"), (269, "en"), (270, "en"), (271, "en"), (272, "en"), (273, "en"), (274, "en"), (275, "en"), (276, "en"), ] assert [face.get_name(*name) for name in names] == [ "License same as MutatorMath. BSD 3-clause. [test-token: C]", "Regular", "1.002;LTTR;MutatorMathTest-LightCondensed", "MutatorMathTest LightCondensed", "Version 1.002", "MutatorMathTest-LightCondensed", "Width", "Weight", "LightCondensed", "MutatorMathTest-LightCondensed", "BoldCondensed", "MutatorMathTest-BoldCondensed", "LightWide", "MutatorMathTest-LightWide", "BoldWide", "MutatorMathTest-BoldWide", "Medium_Narrow_I", "MutatorMathTest-Medium_Narrow_I", "Two", "MutatorMathTest-Two", "One", "MutatorMathTest-One", "width_794.52_weight_775.61", "MutatorSans-width_794.52_weight_775.61", "width_93.05_weight_658.60", "Medium_Wide_I", "MutatorMathTest-Medium_Narrow_I", ] def test_reference_table(self, blankfont): face = blankfont.face if "OS/2" in face.table_tags: blob = face.reference_table("OS/2") assert len(blob.data) == 96 if "head" in face.table_tags: blob = face.reference_table("head") assert len(blob.data) == 54 class TestFont: def test_get_glyph_extents(self, opensans): # extents = opensans.get_glyph_extents(1) assert (0, 1468, 1296, -1468) == extents assert 0 == extents.x_bearing assert 1468 == extents.y_bearing assert 1296 == extents.width assert -1468 == extents.height assert opensans.get_glyph_extents(1000) is None def test_get_font_extents(self, blankfont): extents = blankfont.get_font_extents("ltr") assert (880, -120, 0) == extents assert 880 == extents.ascender assert -120 == extents.descender assert 0 == extents.line_gap extents = blankfont.get_font_extents("ttb") assert (500, -500, 0) == extents assert 500 == extents.ascender assert -500 == extents.descender assert 0 == extents.line_gap def test_get_glyph_name(self, blankfont): glyph_name = blankfont.get_glyph_name(1) assert glyph_name == "a" glyph_name = blankfont.get_glyph_name(1000) assert glyph_name is None def test_get_nominal_glyph(self, blankfont): gid = blankfont.get_nominal_glyph(ord("a")) assert gid == 1 gid = blankfont.get_nominal_glyph(ord("å")) assert gid is None def test_get_var_coords_normalized(self, mutatorsans): coords = mutatorsans.get_var_coords_normalized() assert coords == [0, 0] mutatorsans.set_variations({"wght": 500}) coords = mutatorsans.get_var_coords_normalized() assert coords == [0, 0.5] mutatorsans.set_variations({"wdth": 1000}) coords = mutatorsans.get_var_coords_normalized() assert coords == [1.0, 0] mutatorsans.set_variations({"wdth": 250, "wght": 250}) coords = mutatorsans.get_var_coords_normalized() assert coords == [0.25, 0.25] def test_set_var_coords_normalized(self, mutatorsans): expected_coords = [0.5, 0.25] mutatorsans.set_var_coords_normalized(expected_coords) coords = mutatorsans.get_var_coords_normalized() assert expected_coords == coords mutatorsans.set_var_coords_normalized([0.5]) coords = mutatorsans.get_var_coords_normalized() assert [0.5, 0] == coords with pytest.raises(TypeError): mutatorsans.set_var_coords_normalized(["a"]) def test_properties(self, blankfont): assert blankfont.scale == (1000, 1000) blankfont.scale = (1024, 1024) assert blankfont.scale == (1024, 1024) assert blankfont.ppem == (0, 0) blankfont.ppem = (16, 24) assert blankfont.ppem == (16, 24) assert blankfont.ptem == 0 blankfont.ptem = 12.0 assert blankfont.ptem == 12.0 assert blankfont.synthetic_slant == 0 blankfont.synthetic_slant = 0.2 assert blankfont.synthetic_slant == pytest.approx(0.2) def test_get_glyph_color_png(self, blankfont): blob = blankfont.get_glyph_color_png(1) assert len(blob) == 0 # The test font contains a BASE table with some test values def test_get_layout_baseline_invalid_tag(self, blankfont): with pytest.raises(ValueError): # invalid baseline tag baseline = blankfont.get_layout_baseline("xxxx", "LTR", "", "") @pytest.mark.parametrize( "baseline_tag, script_tag, direction, expected_value", [ ("icfb", "grek", "LTR", None), # BASE table doesn't contain grek script ("icfb", "latn", "LTR", -70), ("icft", "latn", "LTR", 830), ("romn", "latn", "LTR", 0), ("ideo", "latn", "LTR", -120), ("icfb", "kana", "LTR", -71), ("icft", "kana", "LTR", 831), ("romn", "kana", "LTR", 1), ("ideo", "kana", "LTR", -121), ("icfb", "latn", "TTB", 50), ("icft", "latn", "TTB", 950), ("romn", "latn", "TTB", 120), ("ideo", "latn", "TTB", 0), ("icfb", "kana", "TTB", 51), ("icft", "kana", "TTB", 951), ("romn", "kana", "TTB", 121), ("ideo", "kana", "TTB", 1), ], ) def test_get_layout_baseline( self, blankfont, baseline_tag, script_tag, direction, expected_value ): value = blankfont.get_layout_baseline(baseline_tag, direction, script_tag, "") assert value == expected_value def test_get_style_value(self, blankfont): assert blankfont.get_style_value(hb.StyleTag.ITALIC) == 0.0 assert blankfont.get_style_value(hb.StyleTag.OPTICAL_SIZE) == 12.0 assert blankfont.get_style_value(hb.StyleTag.SLANT_ANGLE) == 0.0 assert blankfont.get_style_value(hb.StyleTag.SLANT_RATIO) == -0.0 assert blankfont.get_style_value(hb.StyleTag.WIDTH) == 100.0 assert blankfont.get_style_value(hb.StyleTag.WEIGHT) == 400.0 class TestShape: @pytest.mark.parametrize( "string, expected", [ ("abcde", [(1, 0), (2, 1), (3, 2), (4, 3), (5, 4)]), ("abçde", [(1, 0), (2, 1), (6, 2), (4, 3), (5, 4)]), ("aбcde", [(1, 0), (7, 1), (3, 2), (4, 3), (5, 4)]), ("abc💩e", [(1, 0), (2, 1), (3, 2), (8, 3), (5, 4)]), ], ids=["ascii", "latin1", "ucs2", "ucs4"], ) def test_gid_and_cluster_no_features(self, blankfont, string, expected): buf = hb.Buffer() buf.add_str(string) buf.guess_segment_properties() hb.shape(blankfont, buf) infos = [(g.codepoint, g.cluster) for g in buf.glyph_infos] assert infos == expected def test_shape_set_shaper(self, blankfont): string = "abcde" buf = hb.Buffer() buf.add_str(string) buf.guess_segment_properties() hb.shape(blankfont, buf, shapers=["fallback"]) pos = [g.position for g in buf.glyph_positions] expected = [ (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), ] assert pos == expected @pytest.mark.skipif(sys.platform != "win32", reason="requires Windows") def test_shape_set_shaper_directwrite(self, blankfont): string = "abcde" buf = hb.Buffer() buf.add_str(string) buf.guess_segment_properties() hb.shape(blankfont, buf, shapers=["directwrite"]) pos = [g.position for g in buf.glyph_positions] expected = [ (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), ] assert pos == expected @pytest.mark.xfail @pytest.mark.skipif(sys.platform != "win32", reason="requires Windows") def test_shape_set_shaper_uniscribe(self, blankfont): string = "abcde" buf = hb.Buffer() buf.add_str(string) buf.guess_segment_properties() hb.shape(blankfont, buf, shapers=["uniscribe"]) pos = [g.position for g in buf.glyph_positions] expected = [ (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), ] assert pos == expected @pytest.mark.skipif(sys.platform != "darwin", reason="requires macOS") def test_shape_set_shaper_coretext(self, blankfont): string = "abcde" buf = hb.Buffer() buf.add_str(string) buf.guess_segment_properties() hb.shape(blankfont, buf, shapers=["coretext"]) pos = [g.position for g in buf.glyph_positions] expected = [ (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), ] assert pos == expected @pytest.mark.parametrize( "string, expected", [ ("abcde", ["a", "b", "c", "d", "e"]), ("abçde", ["a", "b", "ccedilla", "d", "e"]), ("aбcde", ["a", "uni0431", "c", "d", "e"]), ("abc💩e", ["a", "b", "c", "u1F4A9", "e"]), ], ids=["ascii", "latin1", "ucs2", "ucs4"], ) def test_glyh_name_no_features(self, blankfont, string, expected): buf = hb.Buffer() buf.add_str(string) buf.guess_segment_properties() hb.shape(blankfont, buf) # font.get_glyph_name() returns None if the font does not contain glyph names # or if the glyph ID does not exist. glyph_names = [blankfont.get_glyph_name(g.codepoint) for g in buf.glyph_infos] assert glyph_names == expected assert blankfont.get_glyph_name(1000) is None # font.glyph_to_string() return "gidN" if the font does not contain glyph names # or if the glyph ID does not exist. glyph_names = [blankfont.glyph_to_string(g.codepoint) for g in buf.glyph_infos] assert glyph_names == expected assert blankfont.glyph_to_string(1000) == "gid1000" @pytest.mark.parametrize( "string, features, expected", [ # The calt feature replaces c by a in the context e, d, c', b, a. ("edcbaedcba", {}, ["e", "d", "a", "b", "a", "e", "d", "a", "b", "a"]), ( "edcbaedcba", {"calt[2]": False}, ["e", "d", "c", "b", "a", "e", "d", "a", "b", "a"], ), ( "edcbaedcba", {"calt": [(7, 8, False)]}, ["e", "d", "a", "b", "a", "e", "d", "c", "b", "a"], ), ( "edcbaedcba", {"calt": [(0, 10, False), (7, 8, True)]}, ["e", "d", "c", "b", "a", "e", "d", "a", "b", "a"], ), ], ) def test_features_slice(self, blankfont, string, features, expected): buf = hb.Buffer() buf.add_str(string) buf.guess_segment_properties() hb.shape(blankfont, buf, features) glyph_names = [blankfont.glyph_to_string(g.codepoint) for g in buf.glyph_infos] assert glyph_names == expected class TestCallbacks: def test_nominal_glyph_func(self, blankfont): string = "abcde" expected = [97, 98, 99, 100, 101] buf = hb.Buffer() buf.add_str(string) buf.guess_segment_properties() def nominal_glyph_func(font, code_point, data): return code_point funcs = hb.FontFuncs.create() funcs.set_nominal_glyph_func(nominal_glyph_func) blankfont.funcs = funcs hb.shape(blankfont, buf) infos = [g.codepoint for g in buf.glyph_infos] assert infos == expected def test_variation_glyph_func(self, blankfont): string = "a\ufe00" expected = [ord("a") + 0xFE00] buf = hb.Buffer() buf.add_str(string) buf.guess_segment_properties() def variation_glyph_func(font, unicode, variation_selector, data): return unicode + variation_selector funcs = hb.FontFuncs.create() funcs.set_variation_glyph_func(variation_glyph_func) blankfont.funcs = funcs hb.shape(blankfont, buf) infos = [g.codepoint for g in buf.glyph_infos] assert infos == expected def test_glyph_h_advance_func(self, blankfont): string = "abcde" expected = [456, 456, 456, 456, 456] buf = hb.Buffer() buf.add_str(string) buf.guess_segment_properties() def h_advance_func(font, gid, data): return 456 funcs = hb.FontFuncs.create() funcs.set_glyph_h_advance_func(h_advance_func) blankfont.funcs = funcs hb.shape(blankfont, buf) infos = [pos.x_advance for pos in buf.glyph_positions] assert infos == expected def test_glyph_v_metrics_funcs(self, blankfont): string = "abcde" expected = [(456, -345, -567)] * 5 buf = hb.Buffer() buf.add_str(string) buf.guess_segment_properties() buf.direction = "TTB" def v_advance_func(font, gid, data): return 456 def v_origin_func(font, gid, data): return (True, 345, 567) funcs = hb.FontFuncs.create() funcs.set_glyph_v_advance_func(v_advance_func) funcs.set_glyph_v_origin_func(v_origin_func) blankfont.funcs = funcs hb.shape(blankfont, buf) infos = [ (pos.y_advance, pos.x_offset, pos.y_offset) for pos in buf.glyph_positions ] assert infos == expected def test_font_extents_funcs(self, blankfont): def font_h_extents_func(font, data): return hb.FontExtents(123, -456, 789) def font_v_extents_func(font, data): return hb.FontExtents(987, -654, 321) funcs = hb.FontFuncs.create() funcs.set_font_h_extents_func(font_h_extents_func) funcs.set_font_v_extents_func(font_v_extents_func) blankfont.funcs = funcs assert (123, -456, 789) == blankfont.get_font_extents("ltr") assert (987, -654, 321) == blankfont.get_font_extents("ttb") def test_message_func(self, blankfont): # Glyph IDs 1, 2, 3, 4, 5 map to glyphs a, b, c, d, e. # The calt feature replaces c by a in the context e, d, c', b, a. # The kern feature kerns b, a by +100. string = "edcba" buf = hb.Buffer() buf.add_str(string) buf.guess_segment_properties() messages = [] infos_trace = [] positions_trace = [] def message(msg): messages.append(msg) infos_trace.append(buf.glyph_infos) positions_trace.append(buf.glyph_positions) buf.set_message_func(message) hb.shape(blankfont, buf) gids = [g.codepoint for g in buf.glyph_infos] assert gids == [5, 4, 1, 2, 1] pos = [g.x_advance for g in buf.glyph_positions] assert pos == [0, 0, 0, 100, 0] expected_messages = [ "start table GSUB script tag 'DFLT'", "start lookup 0 feature 'calt'", "end lookup 0 feature 'calt'", "end table GSUB script tag 'DFLT'", "start table GPOS script tag 'DFLT'", "start lookup 0 feature 'kern'", "end lookup 0 feature 'kern'", "end table GPOS script tag 'DFLT'", ] assert messages == expected_messages gids_trace = [[g.codepoint for g in infos] for infos in infos_trace] assert gids_trace == [ [5, 4, 3, 2, 1], [5, 4, 3, 2, 1], [5, 4, 1, 2, 1], [5, 4, 1, 2, 1], [5, 4, 1, 2, 1], [5, 4, 1, 2, 1], [5, 4, 1, 2, 1], [5, 4, 1, 2, 1], ] advances_trace = [[g.x_advance for g in pos] for pos in positions_trace if pos] assert advances_trace == [ [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 100, 0], [0, 0, 0, 100, 0], ] def test_message_func_return_false(self, blankfont): # Glyph IDs 1, 2, 3, 4, 5 map to glyphs a, b, c, d, e. # The calt feature replaces c by a in the context e, d, c', b, a. # The kern feature kerns b, a by +100. string = "edcba" buf = hb.Buffer() buf.add_str(string) buf.guess_segment_properties() messages = [] infos_trace = [] positions_trace = [] def message(msg): messages.append(msg) infos_trace.append(buf.glyph_infos) positions_trace.append(buf.glyph_positions) return False buf.set_message_func(message) hb.shape(blankfont, buf) gids = [g.codepoint for g in buf.glyph_infos] assert gids == [5, 4, 3, 2, 1] pos = [g.x_advance for g in buf.glyph_positions] assert pos == [0, 0, 0, 0, 0] expected_messages = [ "start table GSUB script tag 'DFLT'", "start table GPOS script tag 'DFLT'", ] assert messages == expected_messages gids_trace = [[g.codepoint for g in infos] for infos in infos_trace] assert gids_trace == [[5, 4, 3, 2, 1], [5, 4, 3, 2, 1]] advances_trace = [[g.x_advance for g in pos] for pos in positions_trace if pos] assert advances_trace == [[0, 0, 0, 0, 0]] def test_message_func_crash(self, blankfont): string = "edcba" buf = hb.Buffer() buf.add_str(string) buf.guess_segment_properties() message_collector = MessageCollector() buf.set_message_func(message_collector.message) hb.shape(blankfont, buf) def test_draw_funcs(self, opensans): funcs = hb.DrawFuncs() container = [] def move_to(x, y, c): c.append(f"M{x:g},{y:g}") def line_to(x, y, c): c.append(f"L{x:g},{y:g}") def cubic_to(c1x, c1y, c2x, c2y, x, y, c): c.append(f"C{c1x:g},{c1y:g} {c2x:g},{c2y:g} {x:g},{y:g}") def quadratic_to(c1x, c1y, x, y, c): c.append(f"Q{c1x:g},{c1y:g} {x:g},{y:g}") def close_path(c): c.append("Z") funcs.set_move_to_func(move_to) funcs.set_line_to_func(line_to) funcs.set_cubic_to_func(cubic_to) funcs.set_quadratic_to_func(quadratic_to) funcs.set_close_path_func(close_path) opensans.draw_glyph(1, funcs, container) assert ( "".join(container) == "M1120,0L938,465L352,465L172,0L0,0L578,1468L721,1468L1296,0L1120,0ZM885,618L715,1071Q682,1157 647,1282Q625,1186 584,1071L412,618L885,618Z" ) @pytest.mark.xfail( platform.python_implementation() == "PyPy", reason="PyPy's ctypes has no 'pythonapi' attribute", ) def test_draw_funcs_pycapsule(self, opensans): import ctypes import uharfbuzz._harfbuzz_test funcs = hb.DrawFuncs() PyCapsule_New = ctypes.pythonapi.PyCapsule_New PyCapsule_New.restype = ctypes.py_object PyCapsule_New.argtypes = (ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p) def cap(x): return PyCapsule_New(x, None, None) lib = ctypes.cdll.LoadLibrary(uharfbuzz._harfbuzz_test.__file__) container = ctypes.create_string_buffer(1000) container_cap = cap(container) funcs.set_move_to_func(cap(lib._test_move_to)) funcs.set_line_to_func(cap(lib._test_line_to)) funcs.set_cubic_to_func(cap(lib._test_cubic_to)) funcs.set_quadratic_to_func(cap(lib._test_quadratic_to)) funcs.set_close_path_func(cap(lib._test_close_path)) opensans.draw_glyph(1, funcs, container_cap) assert ( container.value == b"M1120,0L938,465L352,465L172,0L0,0L578,1468L721,1468L1296,0L1120,0ZM885,618L715,1071Q682,1157 647,1282Q625,1186 584,1071L412,618L885,618Z" ) def test_draw_pen(self, opensans): class TestPen: def __init__(self): self.value = [] def moveTo(self, p0): self.value.append(("moveTo", (p0,))) def lineTo(self, p1): self.value.append(("lineTo", (p1,))) def qCurveTo(self, *points): self.value.append(("qCurveTo", points)) def curveTo(self, *points): self.value.append(("curveTo", points)) def closePath(self): self.value.append(("closePath", ())) pen = TestPen() opensans.draw_glyph_with_pen(1, pen) assert pen.value == [ ("moveTo", ((1120, 0),)), ("lineTo", ((938, 465),)), ("lineTo", ((352, 465),)), ("lineTo", ((172, 0),)), ("lineTo", ((0, 0),)), ("lineTo", ((578, 1468),)), ("lineTo", ((721, 1468),)), ("lineTo", ((1296, 0),)), ("lineTo", ((1120, 0),)), ("closePath", ()), ("moveTo", ((885, 618),)), ("lineTo", ((715, 1071),)), ("qCurveTo", ((682, 1157), (647, 1282))), ("qCurveTo", ((625, 1186), (584, 1071))), ("lineTo", ((412, 618),)), ("lineTo", ((885, 618),)), ("closePath", ()), ] class TestPaintFuncs: @staticmethod def setup_funcs(): def push_transform_func(xx, xy, yx, yy, dx, dy, conainer): conainer.append( f"start transform " f"{xx:.3g} {xy:.3g} {yx:.3g} {yy:.3g} {dx:.3g} {dy:.3g}" ) conainer.level += 1 def pop_transform_func(conainer): conainer.level -= 1 conainer.append(f"end transform") def color_glyph_func(gid, conainer): conainer.append(f"paint color glyph {gid}; acting as failed") return False def push_clip_glyph_func(gid, conainer): conainer.append(f"start clip glyph {gid}") conainer.level += 1 return True def push_clip_rectangle_func(xmin, ymin, xmax, ymax, conainer): conainer.append( f"start clip rectangle {xmin:.3g} {ymin:.3g} {xmax:.3g} {ymax:.3g}" ) conainer.level += 1 def pop_clip_func(conainer): conainer.level -= 1 conainer.append(f"end clip") def color_func(color, is_foreground, conainer): r, g, b, a = color conainer.append(f"solid {r} {g} {b} {a}") def image_func(image, width, height, format, slant, extents, conainer): conainer.append( f"image type {format} " f"size {width} {height} " f"slant {slant:.3g} " f"extents {extents.x_bearing} {extents.y_bearing} {extents.width} {extents.height}" ) return True def linear_gradient_func(color_line, x0, y0, x1, y1, x2, y2, conainer): conainer.append(f"linear gradient") conainer.level += 1 conainer.append(f"p0 {x0:.3g} {y0:.3g}") conainer.append(f"p1 {x1:.3g} {y1:.3g}") conainer.append(f"p2 {x2:.3g} {y2:.3g}") conainer.append_color_line(color_line) conainer.level -= 1 def radial_gradient_func(color_line, x0, y0, r0, x1, y1, r1, conainer): conainer.append(f"radial gradient") conainer.level += 1 conainer.append(f"p0 {x0:.3g} {y0:.3g} radius {r0:.3g}") conainer.append(f"p1 {x1:.3g} {y1:.3g} radius {r1:.3g}") conainer.append_color_line(color_line) conainer.level -= 1 def sweep_gradient_func(color_line, cx, cy, start_angle, end_angle, conainer): conainer.append(f"sweep gradient") conainer.level += 1 conainer.append(f"center {cx:.3g} {cy:.3g}") conainer.append(f"angles {start_angle:.3g} {end_angle:.3g}") conainer.append_color_line(color_line) conainer.level -= 1 def push_group_func(conainer): conainer.append(f"push group") conainer.level += 1 def pop_group_func(mode, conainer): conainer.level -= 1 conainer.append(f"pop group mode {int(mode)}") def custom_palette_color_func(color_index, conainer): return None funcs = hb.PaintFuncs() funcs.set_push_transform_func(push_transform_func) funcs.set_pop_transform_func(pop_transform_func) funcs.set_color_glyph_func(color_glyph_func) funcs.set_push_clip_glyph_func(push_clip_glyph_func) funcs.set_push_clip_rectangle_func(push_clip_rectangle_func) funcs.set_pop_clip_func(pop_clip_func) funcs.set_color_func(color_func) funcs.set_image_func(image_func) funcs.set_linear_gradient_func(linear_gradient_func) funcs.set_radial_gradient_func(radial_gradient_func) funcs.set_sweep_gradient_func(sweep_gradient_func) funcs.set_push_group_func(push_group_func) funcs.set_pop_group_func(pop_group_func) funcs.set_custom_palette_color_func(custom_palette_color_func) class Container: def __init__(self): self.level = 0 self.lines = [] def append(self, line): indent = " " * self.level * 2 self.lines.append(indent + line) def append_color_line(self, color_line): self.append(f"colors {int(color_line.extend)}") self.level += 1 for stop in color_line.color_stops: r, g, b, a = stop.color self.append(f"{stop.offset:.3g} {r} {g} {b} {a}") self.level -= 1 def value(self): return "\n".join(self.lines) return funcs, Container() @pytest.mark.parametrize( "fontpath, glyph, expectedpath", [ ("noto_handwriting-cff2_colr_1.otf", 10, "hand-10"), ("test_glyphs-glyf_colr_1.ttf", 6, "test-6"), ("test_glyphs-glyf_colr_1.ttf", 10, "test-10"), ("test_glyphs-glyf_colr_1.ttf", 92, "test-92"), ("test_glyphs-glyf_colr_1.ttf", 106, "test-106"), ("test_glyphs-glyf_colr_1.ttf", 116, "test-116"), ("test_glyphs-glyf_colr_1.ttf", 123, "test-123"), ("test_glyphs-glyf_colr_1.ttf", 154, "test-154"), ("test_glyphs-glyf_colr_1.ttf", 165, "test-165"), ("test_glyphs-glyf_colr_1.ttf", 175, "test-175"), ], ) def test_paint(self, fontpath, glyph, expectedpath): blob = hb.Blob.from_file_path(TESTDATA / fontpath) face = hb.Face(blob) font = hb.Font(face) funcs, container = self.setup_funcs() font.paint_glyph(glyph, funcs, container) result = container.value() with open(TESTDATA / "expected" / expectedpath) as f: expected = "".join(line for line in f.readlines() if line[0] != "#") assert result.strip() == expected.strip() class MessageCollector: def message(self, message): pass class TestOTLayout: def test_ot_tag_to_script(self): assert hb.ot_tag_to_script("mym2") == "Mymr" def test_ot_tag_to_language(self): assert hb.ot_tag_to_language("BGR") == "bg" class TestOTColor: def test_ot_color_palette_get_count(self, colorv0font, colorv1font): with pytest.deprecated_call(): assert hb.ot_color_palette_get_count(colorv0font.face) == 1 assert hb.ot_color_palette_get_count(colorv1font.face) == 3 def test_ot_color_palette_get_colors(self, colorv0font, colorv1font, blankfont): with pytest.deprecated_call(): palette = hb.ot_color_palette_get_colors(colorv0font.face, 0) assert palette == [(200, 0, 0, 255)] palette = hb.ot_color_palette_get_colors(colorv1font.face, 0) assert palette == [ (255, 0, 0, 255), (255, 165, 0, 255), (255, 255, 0, 255), (0, 128, 0, 255), (0, 0, 255, 255), (75, 0, 130, 255), (238, 130, 238, 255), (250, 240, 230, 255), (47, 79, 79, 255), (255, 255, 255, 255), (0, 0, 0, 255), (104, 199, 232, 255), (255, 220, 1, 255), (128, 128, 128, 255), ] assert hb.ot_color_palette_get_colors(blankfont.face, 0) == [] def test_ot_color_palette_get_flags(self, colorv1font, colorv0font): with pytest.deprecated_call(): flags = hb.ot_color_palette_get_flags(colorv1font.face, 0) assert flags == hb.OTColorPaletteFlags.DEFAULT flags = hb.ot_color_palette_get_flags(colorv1font.face, 1) assert flags == hb.OTColorPaletteFlags.USABLE_WITH_DARK_BACKGROUND flags = hb.ot_color_palette_get_flags(colorv1font.face, 2) assert flags == hb.OTColorPaletteFlags.USABLE_WITH_LIGHT_BACKGROUND flags = hb.ot_color_palette_get_flags(colorv0font.face, 0) assert flags == hb.OTColorPaletteFlags.DEFAULT def test_ot_color_palette_get_name_id(self, colorv1font, blankfont): with pytest.deprecated_call(): assert hb.ot_color_palette_get_name_id(colorv1font.face, 0) is None assert hb.ot_color_palette_get_name_id(colorv1font.face, 1) is None assert hb.ot_color_palette_get_name_id(colorv1font.face, 2) is None assert hb.ot_color_palette_get_name_id(blankfont.face, 0) is None class TestSubsetInput: @pytest.mark.parametrize( "use_subset_plan", [False, True], ) def test_subset(self, blankfont, use_subset_plan): assert blankfont.get_nominal_glyph(ord("a")) == 1 assert blankfont.get_nominal_glyph(ord("b")) == 2 assert blankfont.get_nominal_glyph(ord("c")) == 3 assert blankfont.get_nominal_glyph(ord("d")) == 4 assert blankfont.get_nominal_glyph(ord("e")) == 5 inp = hb.SubsetInput() inp.sets(hb.SubsetInputSets.UNICODE).set({ord("b")}) s = inp.sets(hb.SubsetInputSets.LAYOUT_FEATURE_TAG) s.clear() s.invert() inp.layout_script_tag_set.invert() inp.unicode_set.update(ord(c) for c in "cd") inp.unicode_set.add(ord("e")) if not use_subset_plan: face = hb.subset(blankfont.face, inp) else: plan = hb.SubsetPlan(blankfont.face, inp) face = plan.execute() assert face is not None font = hb.Font(face) assert font.get_nominal_glyph(ord("a")) is None assert font.get_nominal_glyph(ord("b")) == 1 assert font.get_nominal_glyph(ord("c")) == 2 assert font.get_nominal_glyph(ord("d")) == 3 assert font.get_nominal_glyph(ord("e")) == 4 blob = face.blob assert blob assert len(blob) > 100 face = hb.Face(blob) font = hb.Font(face) assert font.get_nominal_glyph(ord("a")) is None assert font.get_nominal_glyph(ord("b")) == 1 assert font.get_nominal_glyph(ord("c")) == 2 assert font.get_nominal_glyph(ord("d")) == 3 assert font.get_nominal_glyph(ord("e")) == 4 if use_subset_plan: mapping = plan.old_to_new_glyph_mapping reverse = plan.new_to_old_glyph_mapping assert 1 not in mapping assert mapping[2] == 1 assert mapping[3] == 2 assert reverse[mapping[2]] == 2 assert reverse[mapping[3]] == 3 assert len(reverse) == 5 cmap = plan.unicode_to_old_glyph_mapping assert cmap[ord("b")] == 2 @pytest.mark.parametrize( "axes", [ ["wght"], ["wdth"], ["wght", "wdth"], ], ) def test_pin_axis_to_default(self, mutatorsans, axes): inp = hb.SubsetInput() inp.keep_everything() for axis in axes: inp.pin_axis_to_default(mutatorsans.face, axis) face = hb.subset(mutatorsans.face, inp) assert face is not None tags = {a.tag for a in face.axis_infos} assert tags.isdisjoint(set(axes)) @pytest.mark.parametrize( "axis,value", [ ["wght", 100], ["wdth", 1000], ], ) def test_pin_axis_location(self, mutatorsans, axis, value): inp = hb.SubsetInput() inp.keep_everything() inp.pin_axis_location(mutatorsans.face, axis, value) face = hb.subset(mutatorsans.face, inp) assert face is not None tags = [a.tag for a in face.axis_infos] assert axis not in tags def test_pin_all_axes_to_default(self, mutatorsans): inp = hb.SubsetInput() inp.keep_everything() inp.pin_all_axes_to_default(mutatorsans.face) face = hb.subset(mutatorsans.face, inp) assert face is not None assert not face.axis_infos @pytest.mark.parametrize( "axis,min_value,max_value,def_value", [ ["wght", None, None, None], ["wght", 100.0, 400.0, 200.0], ["wght", None, 300.0, 100], ["wght", None, None, 300], ["wght", 10.0, None, 50.0], ["wght", None, None, 50.0], ["wght", 10.0, None, None], ["wght", 50.0, 500.0, None], ["wght", None, 600.0, None], ], ) def test_set_axis_range(self, mutatorsans, axis, min_value, max_value, def_value): inp = hb.SubsetInput() inp.keep_everything() if any([min_value, max_value, def_value]): inp.set_axis_range(mutatorsans.face, axis, min_value, max_value, def_value) else: inp.set_axis_range(mutatorsans.face, axis) face = hb.subset(mutatorsans.face, inp) assert face is not None assert face.axis_infos axis_infos = [a for a in mutatorsans.face.axis_infos if a.tag == axis] assert len(axis_infos) == 1 info = axis_infos[0] expected_min = info.min_value if min_value is None else min_value expected_max = info.max_value if max_value is None else max_value new_axis_infos = [a for a in face.axis_infos if a.tag == axis] assert len(new_axis_infos) == 1 new_info = new_axis_infos[0] assert new_info.min_value == expected_min assert new_info.max_value == expected_max if def_value is not None: assert new_info.default_value == def_value assert (expected_min, expected_max, def_value) == inp.get_axis_range(axis) def test_harfbuzz_version(): v = hb.version_string() assert isinstance(v, str) def test_uharfbuzz_version(): v = hb.__version__ assert isinstance(v, str) assert "unknown" not in v def test_create_sub_font(): blob = hb.Blob.from_file_path(ADOBE_BLANK_TTF_PATH) face = hb.Face(blob) font = hb.Font(face) font2 = hb.Font(font) assert font is not font2 assert font.face is font2.face def test_harfbuzz_repacker(): table_data = [ bytes(b"\x00\x00\xff\xff\x00\x01\x00\x00"), bytes(b"\x00\x00\x00\x00"), bytes(b"\x00\x01latn\x00\x00"), bytes(b"\x00\x00\x00\x01\x00\x01"), bytes(b"\x00\x01test\x00\x00"), bytes(b"\x00\x01\x00\x01\x00\x02"), bytes(b"\x00\x01\x00\x00\x00\x01"), bytes(b"\x00\x01\x00\x00\x00\x01\x00\x00"), bytes(b"\x00\x01\x00\x01\x00\x01"), bytes(b"\x00\x02\x00\x01\x00\x02\x00\x01\x00\x00"), bytes(b"\x00\x01\x00\x00"), bytes(b"\x00\x01\x00\x00\x00\x01\x00\x00"), bytes(b"\x00\x05\x00\x00\x00\x01\x00\x00"), bytes(b"\x00\x02\x00\x00\x00\x00"), bytes(b"\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"), ] obj_list = [ ([], []), ([(0, 2, 1)], []), ([(6, 2, 2)], []), ([], []), ([(6, 2, 4)], []), ([], []), ([(2, 2, 6)], []), ([(6, 2, 7)], []), ([], []), ([], []), ([(2, 2, 10)], []), ([(2, 2, 9), (6, 2, 11)], []), ([(6, 2, 12)], []), ([(2, 2, 8), (4, 2, 13)], []), ([(4, 2, 3), (6, 2, 5), (8, 2, 14)], []), ] expected_data = bytes( b'\x00\x01\x00\x00\x00\x10\x00\x18\x00\n\x00\x02\x00\x1a\x00"\x00\x01latn\x00\x10\x00\x01test\x00\x1c\x00\x1a\x00\x00\x00\x01\x00\x00\x00\x01\x00\x1e\x00\x05\x00\x00\x00\x01\x00\x1c\x00\x00\x00\x01\x00\x01\x00\x00\xff\xff\x00\x01\x00\x00\x00\x01\x00\x0e\x00\x01\x00\x01\x00\x12\x00\x01\x00\x0e\x00\x01\x00\x01\x00\x02\x00\x01\x00\n\x00\x01\x00\x01\x00\x01\x00\x02\x00\x01\x00\x02\x00\x01\x00\x00' ) packed_data = hb.serialize(table_data, obj_list) assert expected_data == packed_data @pytest.mark.skipif(sys.platform != "darwin", reason="requires macOS") def test_sparsefont_coretext(sparsefont): buf = hb.Buffer() buf.add_str("ABC") buf.guess_segment_properties() with pytest.raises(RuntimeError): hb.shape(sparsefont, buf, shapers=["coretext"]) def test_set(): s1 = hb.Set() s2 = hb.Set({1, 3, 4}) s3 = hb.Set([1, 3, 4]) assert s1 != None assert s1 != False assert not s1 assert s2 assert s1 != s2 assert not s1 == s2 assert not s2 != s3 assert s2 == s3 s1.add(1) s1.add_range(3, 4) assert s1 == s2 assert -1 not in s1 assert 1 in s1 s1.remove(1) assert 1 not in s1 assert list(s1) == [3, 4] s1 &= hb.Set({3, 4, 5}) assert list(s1) == [3, 4] s1 -= hb.Set({3}) assert list(s1) == [4] s1 ^= hb.Set({5}) assert list(s1) == [4, 5] s1 |= {8} # Update accepts set() as well assert list(s1) == [4, 5, 8] assert len(s1) == 3 assert s1.min == 4 assert s1.max == 8 assert repr(s1) == "Set({4, 5, 8})" s1.invert() assert repr(s1) == "Set({...})" iter(iter(hb.Set({}))) def test_map(): m1 = hb.Map() m2 = hb.Map({1: 2, 3: 4}) m3 = hb.Map({1: 2, 3: 4}) assert m1 != None assert m1 != False assert not m1 assert m2 assert m1 != m2 assert not m1 == m2 assert not m2 != m3 assert m2 == m3 m1[1] = 2 assert m1[1] == 2 assert m1 != m2 m1[3] = 4 assert m1 == m2 assert -1 not in m2 assert 1 in m1 del m1[1] assert 1 not in m1 assert len(m1) == 1 assert set(m2.items()) == {(1, 2), (3, 4)} assert set(m2.keys()) == {1, 3} assert set(m2) == {1, 3} assert set(m2.values()) == {2, 4} m4 = hb.Map(m3) m5 = hb.Map() m5.update(m4) assert len(m4) == len(m5) == 2 m5.update({10: 11}) assert len(m5) == 3 assert repr(m5) == "Map({1: 2, 3: 4, 10: 11})" iter(iter(hb.Map({}))) def test_deprecated(): with pytest.deprecated_call(): hb.ot_color_glyph_get_layers(hb.Face(), 0) uharfbuzz-0.53.3/tox.ini000066400000000000000000000033771513514046200151500ustar00rootroot00000000000000[tox] project_name = uharfbuzz envlist = py3,py3-cov,coverage skip_missing_interpreters = true [testenv] skip_install = cov: true !cov: false deps = pytest cov: -rrequirements-dev.txt changedir= {toxinidir} setenv = cov: PYTHONPATH=src/uharfbuzz cov: CYTHON_ANNOTATE=1 cov: CYTHON_LINETRACE=1 commands = !cov: pytest {posargs} cov: python setup.py develop cov: coverage run --parallel -m pytest {posargs} [testenv:coverage] skip_install = true deps = cython coverage diff_cover setenv = PYTHONPATH=src passenv = DIFF_AGAINST changedir = {toxinidir} commands = coverage erase coverage combine coverage report coverage xml -o {toxworkdir}/coverage.xml coverage html diff-cover --compare-branch {env:DIFF_AGAINST:origin/main} {toxworkdir}/coverage.xml [testenv:codecov] skip_install = true deps = {[testenv:coverage]deps} codecov setenv = {[testenv:coverage]setenv} passenv = TOXENV CI TRAVIS TRAVIS_* APPVEYOR APPVEYOR_* CODECOV_* changedir = {toxinidir} commands = coverage combine codecov --env TOXENV [testenv:wheel] description = build wheel package for upload to PyPI skip_install = true deps = setuptools >= 36.4.0 pip >= 18.0 wheel >= 0.31.0 changedir = {toxinidir} commands = python -c 'import os, glob; whl = glob.glob(".tox/dist/*.whl"); whl and os.remove(whl[0])' pip wheel --pre --no-deps --no-cache-dir --wheel-dir {distdir} --find-links {distdir} --no-binary {[tox]project_name} {[tox]project_name} [testenv:docs] description = build Sphinx docs, including API reference deps = -r{toxinidir}/docs/requirements.txt changedir = {toxinidir} commands = sphinx-build -j auto docs/source/ docs/build/ [pytest] testpaths = tests/ addopts = -v -r a