pax_global_header00006660000000000000000000000064152667006750014530gustar00rootroot0000000000000052 comment=9d3a16202b83c25cc6f815520794bae29e374f5c harfbuzz-uharfbuzz-7a648c4/000077500000000000000000000000001526670067500157435ustar00rootroot00000000000000harfbuzz-uharfbuzz-7a648c4/.coveragerc000066400000000000000000000016151526670067500200670ustar00rootroot00000000000000[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 harfbuzz-uharfbuzz-7a648c4/.github/000077500000000000000000000000001526670067500173035ustar00rootroot00000000000000harfbuzz-uharfbuzz-7a648c4/.github/workflows/000077500000000000000000000000001526670067500213405ustar00rootroot00000000000000harfbuzz-uharfbuzz-7a648c4/.github/workflows/ci.yml000066400000000000000000000115551526670067500224650ustar00rootroot00000000000000name: 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 build-pyodide: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set up Python uses: actions/setup-python@v5 with: # Host Python must match cibuildwheel's default stable Pyodide ABI # (Pyodide 0.28/0.29.x -> pyemscripten_2025_0 -> CPython 3.13). If a # future cibuildwheel bumps its default stable Pyodide to a newer # CPython, bump this in lockstep (or pin pyodide-version) or the # cross-build will fail. python-version: "3.13" - name: Install cibuildwheel # cibuildwheel >= 4.0 tags Pyodide wheels with the PEP 783 pyemscripten_* # platform, which PyPI accepts. Older versions emit pyodide_2024_0, which # PyPI rejects. run: pip install "cibuildwheel>=4.0" - name: Build and test Pyodide wheel run: python -m cibuildwheel --platform pyodide --output-dir wheelhouse - uses: actions/upload-artifact@v4 with: name: uharfbuzz-pyodide path: wheelhouse/*.whl deploy: name: Create and populate release needs: [build, build-pyodide] 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_name }} \ --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 harfbuzz-uharfbuzz-7a648c4/.gitignore000066400000000000000000000007501526670067500177350ustar00rootroot00000000000000# 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 # generated by setup.py src/uharfbuzz/_generated_docs.pxi harfbuzz-uharfbuzz-7a648c4/.gitmodules000066400000000000000000000001241526670067500201150ustar00rootroot00000000000000[submodule "harfbuzz"] path = harfbuzz url = https://github.com/harfbuzz/harfbuzz harfbuzz-uharfbuzz-7a648c4/.readthedocs.yml000066400000000000000000000015531526670067500210350ustar00rootroot00000000000000# 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 harfbuzz-uharfbuzz-7a648c4/LICENSE000066400000000000000000000261351526670067500167570ustar00rootroot00000000000000 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. harfbuzz-uharfbuzz-7a648c4/MANIFEST.in000066400000000000000000000002241526670067500174770ustar00rootroot00000000000000recursive-include harfbuzz/src/ *.cc recursive-include harfbuzz/src/ *.h recursive-include harfbuzz/src/ *.hh recursive-include src/uharfbuzz *.pxi harfbuzz-uharfbuzz-7a648c4/README.md000066400000000000000000000057311526670067500172300ustar00rootroot00000000000000## 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 y_advance = pos.y_advance x_offset = pos.x_offset y_offset = pos.y_offset print( f"{glyph_name=} {gid=} {cluster=} " f"{x_advance=} {y_advance=} " f"{x_offset=} {y_offset=}" ) ``` ### 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 harfbuzz-uharfbuzz-7a648c4/docs/000077500000000000000000000000001526670067500166735ustar00rootroot00000000000000harfbuzz-uharfbuzz-7a648c4/docs/.gitignore000066400000000000000000000000071526670067500206600ustar00rootroot00000000000000/build/harfbuzz-uharfbuzz-7a648c4/docs/requirements.in000066400000000000000000000000761526670067500217510ustar00rootroot00000000000000Sphinx >= 7.4.7 sphinx-rtd-theme >= 2.0.0 myst-parser >= 4.0.0harfbuzz-uharfbuzz-7a648c4/docs/requirements.txt000066400000000000000000000027111526670067500221600ustar00rootroot00000000000000# # 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.15 # 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.20.0 # via sphinx pyyaml==6.0.2 # via myst-parser requests==2.33.0 # 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.7.0 # via requests harfbuzz-uharfbuzz-7a648c4/docs/source/000077500000000000000000000000001526670067500201735ustar00rootroot00000000000000harfbuzz-uharfbuzz-7a648c4/docs/source/conf.py000066400000000000000000000030451526670067500214740ustar00rootroot00000000000000# 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", ] # Cython emits parameter annotations as string forward references (e.g. # `font: 'Font'`). Sphinx renders these as `~uharfbuzz._harfbuzz.Font` with # the `~` displayed literally. Strip the qualifier ourselves. import re as _re _QUALIFIED_TYPE_RE = _re.compile(r"~?uharfbuzz(?:\._harfbuzz)?\.") def _strip_module_prefix(app, what, name, obj, options, signature, return_annotation): if signature: signature = _QUALIFIED_TYPE_RE.sub("", signature) if return_annotation: return_annotation = _QUALIFIED_TYPE_RE.sub("", return_annotation) return signature, return_annotation def setup(app): app.connect("autodoc-process-signature", _strip_module_prefix) # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output html_theme = "sphinx_rtd_theme" harfbuzz-uharfbuzz-7a648c4/docs/source/index.rst000066400000000000000000000002611526670067500220330ustar00rootroot00000000000000uharfbuzz documentation ======================= .. include:: ../../README.md :parser: myst_parser.sphinx_ .. toctree:: :maxdepth: 1 :caption: Contents: reference harfbuzz-uharfbuzz-7a648c4/docs/source/reference.rst000066400000000000000000000054271526670067500226730ustar00rootroot00000000000000API Reference ============= .. automodule:: uharfbuzz :members: :undoc-members: :show-inheritance: :exclude-members: DEFAULT_REPLACEMENT_CODEPOINT, INVALID_VALUE, UNSAFE_TO_BREAK, UNSAFE_TO_CONCAT, SAFE_TO_INSERT_TATWEEL, DEFAULT, BOT, EOT, PRESERVE_DEFAULT_IGNORABLES, REMOVE_DEFAULT_IGNORABLES, DO_NOT_INSERT_DOTTED_CIRCLE, VERIFY, PRODUCE_UNSAFE_TO_CONCAT, PRODUCE_SAFE_TO_INSERT_TATWEEL, MONOTONE_GRAPHEMES, MONOTONE_CHARACTERS, CHARACTERS, GRAPHEMES, INVALID, UNICODE, GLYPHS, TEXT, JSON, NO_CLUSTERS, NO_POSITIONS, NO_GLYPH_NAMES, GLYPH_EXTENTS, GLYPH_FLAGS, NO_ADVANCES, DEFINED, HIDDEN, USABLE_WITH_LIGHT_BACKGROUND, USABLE_WITH_DARK_BACKGROUND, UNCLASSIFIED, BASE_GLYPH, LIGATURE, MARK, COMPONENT, CLEAR, SRC, DEST, SRC_OVER, DEST_OVER, SRC_IN, DEST_IN, SRC_OUT, DEST_OUT, SRC_ATOP, DEST_ATOP, XOR, PLUS, SCREEN, OVERLAY, DARKEN, LIGHTEN, COLOR_DODGE, COLOR_BURN, HARD_LIGHT, SOFT_LIGHT, DIFFERENCE, EXCLUSION, MULTIPLY, HSL_HUE, HSL_SATURATION, HSL_COLOR, HSL_LUMINOSITY, PAD, REPEAT, REFLECT, A8, BGRA32, GLYPH_INDEX, NO_SUBSET_TABLE_TAG, DROP_TABLE_TAG, NAME_LANG_ID, LAYOUT_FEATURE_TAG, LAYOUT_SCRIPT_TAG, NO_HINTING, RETAIN_GIDS, DESUBROUTINIZE, NAME_LEGACY, SET_OVERLAPS_FLAG, PASSTHROUGH_UNRECOGNIZED, NOTDEF_OUTLINE, GLYPH_NAMES, NO_PRUNE_UNICODE_RANGES, NO_LAYOUT_CLOSURE, OPTIMIZE_IUP_DELTAS, NO_BIDI_CLOSURE, DOWNGRADE_CFF2, CFF_IDENTITY_CHARSET, COPYRIGHT, FONT_FAMILY, FONT_SUBFAMILY, UNIQUE_ID, FULL_NAME, VERSION_STRING, POSTSCRIPT_NAME, TRADEMARK, MANUFACTURER, DESIGNER, DESCRIPTION, VENDOR_URL, DESIGNER_URL, LICENSE, LICENSE_URL, TYPOGRAPHIC_FAMILY, TYPOGRAPHIC_SUBFAMILY, MAC_FULL_NAME, SAMPLE_TEXT, CID_FINDFONT_NAME, WWS_FAMILY, WWS_SUBFAMILY, LIGHT_BACKGROUND, DARK_BACKGROUND, VARIATIONS_PS_PREFIX, TOP_RIGHT, TOP_LEFT, BOTTOM_RIGHT, BOTTOM_LEFT, EXTENDER, ITALIC, OPTICAL_SIZE, SLANT_ANGLE, SLANT_RATIO, WIDTH, WEIGHT, HORIZONTAL_ASCENDER, HORIZONTAL_DESCENDER, HORIZONTAL_LINE_GAP, HORIZONTAL_CLIPPING_ASCENT, HORIZONTAL_CLIPPING_DESCENT, VERTICAL_ASCENDER, VERTICAL_DESCENDER, VERTICAL_LINE_GAP, HORIZONTAL_CARET_RISE, HORIZONTAL_CARET_RUN, HORIZONTAL_CARET_OFFSET, VERTICAL_CARET_RISE, VERTICAL_CARET_RUN, VERTICAL_CARET_OFFSET, X_HEIGHT, CAP_HEIGHT, SUBSCRIPT_EM_X_SIZE, SUBSCRIPT_EM_Y_SIZE, SUBSCRIPT_EM_X_OFFSET, SUBSCRIPT_EM_Y_OFFSET, SUPERSCRIPT_EM_X_SIZE, SUPERSCRIPT_EM_Y_SIZE, SUPERSCRIPT_EM_X_OFFSET, SUPERSCRIPT_EM_Y_OFFSET, STRIKEOUT_SIZE, STRIKEOUT_OFFSET, UNDERLINE_SIZE, UNDERLINE_OFFSETharfbuzz-uharfbuzz-7a648c4/harfbuzz/000077500000000000000000000000001526670067500175765ustar00rootroot00000000000000harfbuzz-uharfbuzz-7a648c4/logo.png000066400000000000000000003037501526670067500174210ustar00rootroot00000000000000‰PNG  IHDR  Ûph pHYs.#.#x¥?vtEXtSoftwarewww.inkscape.org›î< IDATxœìÝy|œUÕðß¹3I›¤­,²U�MDe){Âb!3“iAƒ"B B[vED°7D¶¶´PðeTÚÉ,PQ´ @±-¢¢ø²¤IšÌÌ=ï­¯µÜ's'y’fù}?ÿ™sžûœJ—9¹›¨*ˆˆˆˆˆˆ‚ÙÜÑÈÁ„ˆˆˆˆˆ """""0l@ˆˆˆˆˆhÀ°!""""¢Ã„ˆˆˆˆˆ """""0l@ˆˆˆˆˆhÀ°!""""¢Ã„ˆˆˆˆˆ """""0l@ˆˆˆˆˆhÀ°!""""¢Ã„ˆˆˆˆˆ """""0l@ˆˆˆˆˆhÀ°!""""¢Ã„ˆˆˆˆˆ """""0l@ˆˆˆˆˆhÀ°!""""¢Ã„ˆˆˆˆˆ """""0l@ˆˆˆˆˆhÀ°!""""¢Ã„ˆˆˆˆˆ """""0l@ˆˆˆˆˆhÀ°!""""¢Ã„ˆˆˆˆˆ """""0l@ˆˆˆˆˆhÀ°!""""¢Ã„ˆˆˆˆˆ """""0l@ˆˆˆˆˆhÀ°!""""¢Ã„ˆˆˆˆˆ """""0l@ˆˆˆˆˆhÀ°!""""¢Ã„ˆˆˆˆˆLts@4’477›ƒ:è}ÐÑÑÑÞÔÔÔ½¹k""""H¢ª›»¢a+—Ëí Ø€cý°*v‘Ñ¥tú`VªÚ奒f’Éä뛫^"""¢þÆ„(|’˵$ó%@�¨ðY `¹ª½¥££ëœ!!""¢á† QˆòùôDUs€�†0ÜKªökO>ùô�sçε!ŒGDDD´Ù±! A>ŸØkTõ|„¸Ãï¬Å%‰DbYÈã 86 D}”Ïç·±¶ô LìÏ÷ˆ`IwwéÂiÓ¦½ÔŸï!"""êOl@ˆú`éÒ¥;UUE°Û½r­ªmîè躮©©©4@ï$""" ¢^ÊçóÛ¨[Ùkà߮ϑ3b±Ø3ÿn"""¢ÞcBÔ ©Tªº®®æ!‡nÆ2ºTõuuc¯­¯¯/nÆ:ˆˆˆˆ¼ñ&t¢^¨««ù>6oó£Dä›k“N§?¶™k!"""ò¢ åréã“«ð1 àAU}Ð?è°¥1‘½Tõ¡o?èð­í¶{õê fú0Q¿bBT�t:=65¿ðAßgD°DÕ\‹Åþ”“Ï/Ù]5z€Ùª{[Ÿ*žŽDìgŽ?>ù|oÇ """êOl@ˆ*�ÏgnRÅÏônçÅb‰[}ÇÏf³»£WY«'‰ˆô®J¬UµçÇãÉÛ{ù<Q¿aBä)“ÉÔ‹è¯|UTqB"‘¨t© —KOQ57‰`ïÞ<¿Á�Ñhõ9S§NmïÃDDDD¡â&t"™L¦V üg%ôœÞ6‹%îè蟥Z|Ê÷¶sUû™x<ùSWì¼;ߺ ]-€¾ÑÇ…èÕXW{û¼YÊŸ›Ëå> Ø[LòûlJnno︠©©©Ô»ç‰ˆˆˆú†{@ˆzd¯ðm>, j>š[[£íNmÒ|À®PY€QëÚÎZ¼br¹Äb±?>ñD[=€Ïèð¬k#zv]]ͽ˖-««üY"""¢¾ã Q€|>}€ªù-€¨Gú[‘H÷¾ÇwâWpÖí+¾"Ыˌ¡üØvW}iÁ™‡¾^î…Ùlv/½@onA"©j8î¸ãþÙ‹g‰ˆˆˆz� ‘Ckkk´£cíoè÷„ž‹5.vEÎY´bÏRDŸ0Úóõo«àëo׬¹áž2K¥Z[[Gwt¬½FUϯôÞU¬ŽF»?Ô4õ.Á"rèèX{)ü›�ûƒš�æf˜RTÁ¿ù€-DqÝ–�;<ýí>”IDDDTg@ˆ6RWWs<›<�'oqÆQSµ!4Æ›)•Úf-^Þã‡ñxü­µk;ã"pÖÕƒ�UWGó©T*”z‰ˆˆˆ‚p„hƒL&³‡1x~ýu‹vÿd2霑˜³xÅuÎŒô™àκšÈìï7ÞÙSZ6›¾�¯W²9]ùºº1Óê=.G$"""ê ΀hnn6Æ`ξ㱨è·B-pcŠSÛ;ìŠsn[¾[Oiñxò"2ëoA÷"‚†ŽŽµßís�DDDDØ€˜0á€sLñLÿmgg烂VK lJa�ô€’‘§fݱü„ž²b±Ä­ªö³*™Ñ¸ —k ÜXODDDÔ\‚E#^.—Û°Ïë‘Þ%RšÐÐ0mµ+8çöå§)p{¸öHòÕù3&ö8ã’˵|�Ÿ¨ö·[U>�Çé{‰DDDDÿÁ"”n�_óUýFPóqîâÖíøA¨¥•'½zöíËoèé¨ÞX¬ñçÖâd=^l¸‘j@Sétz»pÊ$"""Z� �hÙlËç9Î3ýwÛo¿æ;AÁ¢‰Þ`«p*«Ø¹¯î²üç¥ ÜÃ’H$îô,õœöÁ¶‘ˆY ¢Ö‰ˆˆˆz„F¬t:=^DŠ�©¢˜Ó'L˜UpÅçܱâSPœn…›¾¶£”›=ÿ�÷%l¸±ý ßEÐ�ËeÎ £8""""€ �`Ñhä&øoÿv,{Ƙ}wëûUõúð*ë=ê1zôC³ïn}PN<Þx5€Å¾cªêw²Ùì^aÔGDDDÄ„F¤\®åd@“žé«Œ‰\Ôîèõ¶ §²(öCwôWçÝñøÖA)"‘³yÔg8-¢7b-ÅJ§ÓÛe³ÙÝ–,YÒϧ•Ѧx �8ù|~ÕâJ@¶ñH/¥I±Ø´ßº‚³n_‘èÒ�K …mÕѪ£¯?åйâ¹\n{ ô8 ;zùÙX,qWˆ%ˆÖÖÖh{{û1"8Ðý|À¸�R¬*þj VXk6¦êg Îÿψˆˆ¨ï؀Ј“ÏgîVŧ|rEä{ ñ/¹b³ç?ð>Œ½€ïøÍáÁ·j·:þž¦½»]Á–––##y@¤Ü@ªXcLd¯¡òå|É’%[ŒUõ%U= @à’´M©j; w‹˜«b±Øßú±D""¢‰K°hDÉd2Ó}›Z»¶ãk�ÑÑ£¿�ÁÝ|ÀQ[vþóæ `ccãC"òmŸ�D°ƒjé«á•Ö?š››M.×ò…ªªÈŸUõ+¨ ù©Á™€]�Ëeæ¦R)ß»SˆˆˆÈg@hÄÈf³[ºR;x¤[À‹%vϺíá£�1`è싸pÞŒIÎ�òmmó«^}ür{ŒÓQ,ÚÝ“Éäëá–ŽeËîݶX¬ºÀÇÃU�DºšŽ;îÄ5á�IDD4rq„F ýžgó·5§Ý¹¬Î³C§ù€ï͹ýá)®Àú£…Ílø]RX�š/†[Z8î»/½g±}¡6 G”JU¿Íç—ìî¸DDD#²ÙìqfúeëߊEû• hm©öZ»…RØÀ‰*ÌÝA'cm8bøFŸ�TõìeËî<§~hiiÙÇZó`ê+$;ªFXºtéNý3>ÑÈÁ„†½t:=VDçù䪪Z+³“Éä»®ø¬;9Rg‡[á€_Ðî[ƒ‚ÕÕ�s¼Vn©+•ª/ µ²>X¶ìÞm#Éؾß$;WUE~ÖÖ6¿ªßCDD4¼±¡a/�\àƒ>¹"æ¶D"±Ì›=¿­V¬ µ¥W›š>çöå§¹ÇÛô޵öjŸATõŒÁðE¼µµ5Z,VÝ` f&~ã�|c€ÞEDD4,±¡a-—KOt¶gú«ÝÝ…‹ƒ‚ZÝù {„SÙæ£Ðï-Å3fÜ­^ñf»5kÆO ·²Êut¬½€soK±V¿pß}é=ò�DDDà ¶R©T `Àó÷¹ª=gúôéo»b³ï\~¨Ͳ£¾‘­‹¶ûJW¤¾¾~�µÖëXÞHg†[WeÒéô‡\Qác¯«âFŸU-MUµÓ\ àO¾ˆ ÊZñš)"""¢÷â1¼4lår™kÎhlâîX,qŠ+pÁ�ò£ºÆ�} ÀÞ¡·ù•¬±]pê”ç6 ´¶¶ŽîèXûç,ÉF,`vß\—õårÙ»ý´O®* "øF{{ç÷ššš:7�§R©HMͨ³EäZ]~SŸéììüa/^¡€Þà“(¢úk'""؀а‘J¥"@äVÕ>ùªöâd2ùª+6ëöû@ô«¡88m§£;�sT%ã3@$‚‰á–Ô#qÏÚlÊZùFSSSÉ;ïŽÇ·žuÇò ϸí‘mžý9€�bò©…ˆˆˆþƒ  uu58Ø3ý—ñxò6Wà¤T*"ª Œ ­¸ÁL1Ýõq"‘ø€?{Œ0`³DÙìÒcDPöU¼ØÙÙ™vÅλãñ­ Ú½\×UYäÊI$~íQÒ�9DDD´6 4,d2™=|Ý3}­1ÅÙœgPoÙ±Ãç!84¬Ú;Ž—àÛÝUîyUÐÜÜ< —ˆD¼f?D0?hö£ …y> Ä‚fATõ7åÞ£ª;úÔCDDDÿÁ„†¼ææfc ¨ñÉ·Ö^vüñÓ_tÅæ,~xß±¼¡à³?¼¯+ ªO{¹ªº.±gÎ�;׺â¯îºâ@½™áF Î}Ƙ•ª(”{^ãïê?ÚÚæWY«gúäZ‹›]ŸŸ¾¸u U|fÓÏ ô•€‘¼–W�ݹÖ'�ˆˆˆÖcBCš1¸ÀXÏôæã�O>ï œ¹ðÑ�¡zux• -ªîÓœºD°¦ÜóƘíïê?Ö¬¢vðHý]"‘xÌe¢gxïñ½FþäÊ7Æìæñ¾·�=¶Ék¦„ˆˆˆÖcBCV.×2Àñ~ÙúÌöÛ¯ù¾+"€˜¨]ÿFfÒ}z؈þšÇóýÚ€ƒ³=Sot}ØÜ £ªÎ1´³ÓÙ€¨êîïó9%Œˆˆˆ6„†¤\.·½*¾ë“«Š‚µrú„ ³œK‰fÝñÈçéÊUŸ±hEÐ^†²3 ª^³½ÒÒÒ²üöø¼�Vßí ¼²ëŠãqm”}Þ¬cƒf0|f@þâ‘CDDDaBC”½AD¶òLþv"‘ø�+ð¹E+ÆCåÚ ²Ì¨BÀiNò�ÇkC-f#ƈ×Ñ»î˜:uj»+ Š ï�³”�‘| #""¢ÿ`BCN&“ù$€}rU±Ú˜ÈUAñhDo°eXµ eQ[½…;¢ÎûR6áÜØßW©TjŒN-—§ªj-nqÅÎ\øè΀º—ê þèúøþûïß ¿/Tõ¯årˆˆˆè¿±¡!åÞ{ïÝÚüÈ3½dŒžÙÐÐÐå κ}Å)€û𑨈¢óâ>‘òO¨öORSSs2€qåòDä×nn�h´t€ˆóAëÞ€^*uù,¿‚ªå Q…¢›»¢JŒUõ}Ûy¦_ßÐÐè¼ÍzöÝ­ïD�›ÒGªRQÞt}®*&àÒøÿ'R&¡—ŒÁY>yªÖyôîE©Çj8=ð9±Ðñ! Ú’ÿ_y† ÈÈ$™Læ=ÚÙ Ànªºõ†PÀ+^ìƒÖš‡‰DÇf¬•ˆhÐaBCF&“‰S~9¨âU\˜PˆÞ`Û°jìÚ1¯ýÓÒ²§ƒ‰À9{ÒÙlv‚œÇo╺ºqiW`m{édÙ:èAQu.Á༜p]mmm/' �Tr¹Ü΀^ØO#;²ÑEWÇj¾d ºr¹Ì£ªögªæv6#DDl@hˆÈçóãŒq_0·)UU@g%Iç?ôs¯8‚¦p+êô­{šš‚šˆz àqToeDüf?,¬¯¯/ŒÑÓñ½Šî:ç †ˆq�˜µéã ºÔ’†—t:=>�\¥ªŸAUð‰ÕN£%bŽÁ•ù|v^¡PúQ2™|½ŸÊ%"ô¸„†ˆÒ5vòÉ1 âñ䃮ؙ ÛJE�wEŒlòlPDµ|b-þ7ÌjÒéôX@OöH- ¥…®À¬Å� ô8ƒòò¼YœMªªÏ ˆéé-&r¹–™Ñ¨Y èŒõÍGŸl­ª—E£æ�™Lú+©Tª&”"‰ˆ†6 4èe2™zku¶_¶¾\]ÝqIP4RUº@¿^š7D=áúð�Rït›ò�ëËa‰ÈÉð»2?mÚ´—\cl¹” åWñi@—oÑ0�J¥ªs¹Ì"@8!®×Æc®ª­­Y•ͦã!�MD4象A-“ÉÔƒù">[‚U=ûØc›œËÍY¼"õÛC2Òˆ¨³)FOðûÿÞü-Üzü–_Y‹®ÏÏMµŽQŧ{zV¡ÎŒ GðîùÿçUy ú0•ÏçÇ�Ss?€™ýùì"bZòùÌ=étz|¾‹ˆh0aBƒZ$‚+x¬Çü8Of]� ~òÛq*ê¼'‚ ¥HÉyZ˜ªâ3@4Ú¸„«R¹\ú @&”ÏÔ—;;;s®H±³ê”™A1â>‚×Úî{” Uá È0´~YTi©*ލwªâ“‘ˆ<ŸÍ¶\’J¥ÜGF #l@hÐÊå–ªŠ }rUñFWWá Añ®bá;ðÜC2â(_pJ}ЪC=xù¸ãN\^A‘3ýòdaSÐÆyÕYåž¶K°üö‘H„3 Ã�ÔÕÕÜ5�ÍÇÿ¿X¤ND¾UWW³"—Ëí?Ðï'"Hl@hPÊçó£€È­º@n"zÁ 'œðWlö+޼OTqTäg®Ï×ÿ7ÀÑåž‘'êeÙ²eu€ö¸tjƒ¢HĹù|Î�+p`¹¢E÷  »{¼¿£¡¡á�<B²Ù–ËLÛÌeØÇóùÌw×ÿy "~؀Р¤Zú €}|rE°$k¼Ç›=¿­ª Pá¹™#IÔê/\Ÿ«¦Àc#x©d�ûGz£Xìj‚ÇÍç€äœ³6jÕ§Ù,½9vË¿:ŸW¯%B¹ÛiHÉç[‘¯Wúœ*Þ�p½ˆ\ àNU<ßÇr¢ª¸¨XìjËd2^Ë ‰ˆ†ÞBƒN:�‰È—=÷�¿eL÷¹AA©î¼ZŸŸh�H ¬¸éôIqG�× {"‘e!–xkùÆTKÎÍçŸ[´bl4Ÿã{_¼§iïnW@¤üïUpùÕ0’J¥ªëêjæÃsÆTñ¼ˆ^ÙѱîçMMMïù½”ËåvV-Í‘³l×»ÊäÃÆ`y.—¹ª¶vÌUA÷Ý 5œ¡A'5_‘Ñ>¹Öââ ýsîxôpœnuË(~èú¼­m~•ÏR(U¬‰ÇãO…QK&“ÙC“õZ~Qw²dÉ’-àqo©¤l@†‰t:ý1U|¥‚G>‹%>___¿Î'¹¾¾~]"‘¼¶ªª°§îPÕ^ýyÁaª¥¶\®Åkf’ˆh0cBƒJ4¹Øsöc­ª™�€/¿]ãÆ^ `ïP‹fDð£y³&Ü1ãµÊZ¤Ã¨%•JETíiåòÖy“Ů؜EË÷SÀãø^p7ÕÕÆëÈçH„ ÈpÐÚÚ�Fea7œ_‹%®ïÍ»¦N=á�††ÄL@�íí%–"²•*–ær™oµ¶¶r 5 Yl@hÐXÿª=Å'WU¿‹Åœ—ßm8é¢P‹~Þ6QÌwòù%»ðù)ë›���÷‡QLmmí±€ìX.ODŠÇãÎ=+jp¶ÿ�³�ðÜ€ŽRI¸dèèX{±ß�3ëg\Ÿx¢íʾ¾3O>(Ý@3€®JŸß0KxI{ûÚû6\šID4ä°¡A£½ý�zŸe?ªxaûí×8/<)µºZ-�,ôH×Üô™Io¹bªÑ à·t-pý{¥ŒÑ™>yÖb±ëó‹R�Õ@ð)ß÷Yt‹yù#xUu][[[н)4Dd2™�¨ê×|rUµ]ÕÌž;w® LZ}Ôö]˜üa ü2†††®X,ÑlŒÝ@«wÑÁÑ¥Rá±L&ó‘Þw/¼[]]ýsW ££Ô` ÏWÚÑï¼ëœ=)߀ˆà¯=~¥A¯¹¹Ùˆ`�ïa. šqÅê}« +'ßRÐâ+¦„ç «&½YX5ù†Îg�*;£wüñÉçc±Ä1€žàí ~ ÿ¶‡1x4“ÉLíųDD› 4¬ÕÃ<ÒÞÜn»5?qÎY´bOHE›IG$šçÍšÐኃ/ã1̱X2” Eô3ž_ï™:uj»+ ÀLÿâ¥ëÏoXú¢G6ó¬¡n„ÎÁDÏôåO>ùÔ�AÁ‚n¹‚ÙøÏ¿§[87)þ¹{õ¤«ÐvPm™ñ5k\\(”öð+Ïš6¶…1Èd³é½x–ˆh³`Bƒ†ˆÏ¦qÉÍ~”"¸@uÈe 7Ïî°sq‘+°lÙ½Ûªªç±Åz]ˆ5y}q±‹]ŸŸuçû¨÷}™ôÐ@¨ŠÇîÿʲÙìn"òMÏôNÀœ4ãUX5åL ðÞ™Q¢rYatÍêîÕSÊÎðM›6í¥X,1Ð/ªª× [‰²(›M±Â爈6 6 4(¤R©�ýî[·?·hÅx@}. É, fÍ ¸Ì¬X¬úªˆÔyŒóRmíØTårK? à ò™údž†ä£®HÄFf¢‚›îUÝû?–-[Vèö#pdè�çùûÖÚæX,æ<±ªãùIãýŽÇ0;‹ê’îU“[Ö={ä®er5kü�1:¨ì²Kó�\.s5*øó@D´9°¡A¡¦¦fKxm|Vçæßh÷{~D»yÞ©“~ë d³Ù}ßS¤ôºðndŽÌôɲVo‡ãÈåæf­p鉻�X·nÝî>÷�– È•ÉdÎpŒgú��]ß FK2þûŽ @"µ«Š+§| ©“zü»ª¡!ùtuuçÁ~á;þF.Íå2×�M bl@hP¨®®îôÉS5θÅâÕp+v^­º,8¬×Áïä°×¬•yaÔÖ6¿J>Ç.—s‡+ðÊ®Ë�†¢¢Û¡p6‘ˆß¼Åbe?™¦Á!ŸÏï(‚k=Ó»�Ò™A^VN>UñŠ‹PԨ赅½Ö,ïzvÒž=¥{lÓ;±X¢ÉZ\ ÀYGÎÏç3>³3DD›6l.öø©ºÝÃõé-3'þ*_@H·r7*8ïúSý—+–Éd>)‚£}ƱÖ~;‘H87°KS· IDATWjÍšñql[.OˉÄ+®˜xŸØµñ€g"b<6 £ø�¼æ> ‰5ÕÒÍ"xŸgú·b±i¿wFžž² gF¼3Qyº¸jò%€ôôï°&‰ï‹hRïTò U\”Ïg¯êS�DDý„  ª({·‚1&›7sâu€9�C-lˆàžù§Mº×K¥R5Æx­c /�3.”Ù0F<÷ì¸7ŸŸ¾¸u (N¨ô½%´‡Ãçü-è¼²Ùôgï‹gÛÛ;¿,VÛ›¡å÷«•¥¨QàšÂª‰¿ì\yäN=¥644æ�)MTuÏÞ¾Bõ+¹\æò¾JD>6 4hˆàq�´)---çÍ8bºFo£òe ÃÑ›bÌùAÁººš/ⵄÉZùJ}}}¥§ó8¥Óé±€–½m]UÿiLUÚ…ªO¨©ðÕo,¾§¬††i«�‰ ¢ã¯Uµ9“ɜ֧‰ˆBÆ„ Uý�O^$"7¦R©ÀãvçÍšÐ1æ¤K�؃y:¼ ‡9ïæS�xÃËç—î àRŸqT±"‘HÜV]‘¦Á£y0ÆÜÕÐླÊV¾üªÇ¬´ìUîÿjªªÌ�lí™þ½ÀûmþpèÖ¢p^àÙwºµ*rÝ«&_ÓÓ’¬†††¿‹öUüÚwdc0?›MN­DD}Ç„ Uùüf-ª­­¹eNy¹ù´)O¿U»åa®òw¸YrËiÿÇH¥RÕÈ"£<Ʊª¸!î¯1Ÿö˴ΦgÎm�ì-À!•¿Ù8�|>? �—Á¬Ç#x‡’\®åªø¤O®*ž¯­Ó/GýÀv¡÷^"À%…U‰g'î�J&“âçŒ]-b~ÞÒÒ²Ouõ4‰ÄÿÈûäŠàÌ\.» §™¸§iïîy3&]®ÖNAÀéGÓþ='(ZWWs¼¿ÀË­‰Dâ©� C&“y¿*>î‘ú—††Fç±ÁV¤wKJÔÝ@”J¥]áñ÷¡ð@Êw#>Q¿aBƒŒ½É?WϨ««yÈç§zóOŸò(ºj>àú>7TXsê¼ÏN^ã Þw_zOU üIï&Þ1W„X|RUå’Dä§p̺ÈúU%Ÿê͋Ÿ/!4¦üò« y\‚5D”J…ÀÆâ†††ä g¤íãïSÁÍ¡æggË‹+'N J¨¯¯/n»í«§XZÁ¸*jô¹:"¢>bBƒJ,–¼@®‚G�D¤-—ËÌ]¿Œ&ؼY:æÍ˜t¡ˆNðfŸ ÄòÍù§MtÎ$577k# Ed´ÏXªúõ†††¿‡YŸ1ðZ~e-~êú|ÎâåGºKoÞmKú÷»Êo@`kjÞç|ž—L&pªgú_£Ñê¯ 5ë¾§ÀŽáTV‘1*¦¥{Õ”À?/&Ì*´·w~ ü�©ŠOær™ B©�ˆ¨—؀Р#R¼PU+9m©À\ÕÒ³¹\ºìÒž[N›¼ÔF‹(àþ‰çÐö«Ö¾zeP𠃼Ð#<Çz¬£c]3RååóùLòHý}<_é X‘^/…‰D£ÎŒH$âÓ€¼Ö)`Ôòùü8cüf,TU­Å¬ ÷½Gqõ‘GCqF¸V¤Z wWNùRPBSSS·µ8 ÀŒ{m&“9°ïåõt¦¿ ðèØì˜ûs¹ÌK–,Ù¢§Ä§Ô¿ü��‹õP4°½*tðy©`õä{noÎd2‡âu1™ª®³Ÿ º º·¬-~ïXk�³ü(? P¯MÅkƒNóœáþ�!@Õ^ Àã@ÀÜšH$~å ®>jŒÂÞŠ2‡] QÑk»WM¼›$‘Ht‹6 ௞cV£·¶¶¶FÃ)‘ˆ¨2l@hPŠÇèíOß?[]ý]&“9¦§¤¹õõÅy3'}ªŸðv/ß5Xt iÑé“�Ë¥òùü6Æèÿøì½Ö/½J$·D@e÷n¨ªªŠ³é;. Çæ²�û7DÀ#x‡�|¾åhU{–_¶¾\UµîËAÑ‚–¾Å®aÕÖW\ZX59ðöd2ùºª$¼å9âþk×þ+pf…ˆ¨?±¡A«½½óBwöòñ�DtY.—¹®µµµÇýófN^˜ƒ¬êå»67+*Ÿ�wê$ç‰QÍÍÍ(Ý ˆï:öÇ;;»¿èôV.—û0 Êå‰Èo�?ÉUÓ—“ˆÄ9ƒÑÚÚUÅ.åŸç XƒÙ²eËêTe¾ˆøÎXœsì±Mï¸ÅÕ“&Á§ÈmFu¯š¸Ä2�?è Uõ:2[D®Xÿç’ˆh`±¡A«©©©ôÄm§Ò«h6|¹ £ãÝGËý#;oÆ/Dk‹‡XÒ›wmV*_¼eæÄ_…>xª‘Édzüéù�MõkçϘtâ†}!¡]º×¿äófN¼.(šÉd¦ð>FWU¿ÑØØØ_3A>{7J¥’Þã »õ“ð»8ÑM­sVÅ¿µ"Ëd�Êf—¡ª¾ûÆ^ïê*|!(ØÝ½ö›ö §²þ¢?è~nÊô hMMÝå–û�%Çåó-G‡T‘6 4$Äã�óUå@Õ^Ÿ\5ÖܙϷÌëé¸^tý¾ù,€A~â‘ü|ü‹/ŠÞw_zO½ þÎ[;:Ö};œÚþ[:�ÞNU÷öHýu2™|Ýôþô+P1/„¼Öùwu¹Ú¼Z[[G‹Dn…çïskqþ 'œðW¬°zÊ! lN ED¬þ¸û¹‰ûºÂõõõE‘âé:¼†S¹›³=� l@hȈÇãÏ=ùdÛ‘XBÖ¿z3†ªœeméÁt:=¾§¼y3'Þƒz¯õæ=à�n-|vî\÷ ^ù|~›RÉdDd+ŸÁT±0ŸéŸ¥W@4*“|ÖæÝýqîmïÁä>ÕPt/ÁÌ.�¿=}úô¡~PÁ°ÔÙÙ~€�øäªâç‰DÂ}{øê}«au!‘0ëëGubÍ/ðÌQÎC¦¿ ª_÷ë \®¥)¼ÒˆˆzÆ„†”õK²7‹vow÷f ‰˜'²Ù¥=Þ‡1ïÔI¿59ÀS½yO¿<­-žpÛL÷�©TªFµ´D>GË@ÑZýL,ëÇfËL,—¡ªZ(Ò®XQ"§ o_i§)üÍ)¿]ÕûxS@™Læ@Uõ:ÉIUÿ)b—iuëV—CàœQÄö(V;:ÖýÀ“~CÉåà, 6 4$%“ÉWc±Ä)€&8—ìôD;ˆD~�ͶÌê)ïæÓ¥X’z@²½­5\úĨHUÃ�Mõk]Ñææf3fLÍí¯`Я566>N}AÔãòAy.hiŒˆNëck‚6õ8jU„ È`ÓÖ6¿Ê,àu—…ª\Ôdw¯œò1�^j�D'VMq=ÜÔÔTR-}Þs¨}³Ù¥=]ND6 4¤Åb�‘ÈÇžÕƒj¹%—ËÞ’J¥ªƒ’ž1ñÝ·j_�¦Š~ÙáO~_%£®?åÐÀåg<á[ª^›½ÿ-‹%úõוJ¥ÆØ¿\žq}>{~[­}½µ9`ù âÓ€�Aæµ×vø €ý|rU‘O$w8ƒ­GEzàwGÎà¤ßïZ}„ó.›x|Ú£€Þë3ŠHÄ·Y!"ê6 4ä544ü=K|ÒZ|NUÛ+AgÕÖÖü*—Ëm”qOSSiþÌI—ŠÊÙŠ}(··þ` Ñ�ßpÚ!ÎÈf[> ’‹Åþª*§¡ŸOüª«u8<~J­j� تöÃ6ˆ~äE×§îˆ üïþo¥Rɹ|‹6�–––}Dä2Ïô‹¥9AÁâû‹—@úÜànncŒFn ªšËáñ÷–ª6Üw_zÏP+#"r`BÃF"‘¸ 0‡XYé³"˜”Ïd2=~¹eæÄ[TЀ�½9ý�Å’³àÌC—še2™³x_¨ŠwTeZ<÷¼5¹/Êïÿ‘¨sÄDLŸ6Ÿ€Ì€¬[÷¯�áñ÷ 1î†^*•ŠD"²ÞM©^2mÚ´—\‘îßñ\by›Ó1Ý«';7’o¸ ðÊ "b­ù\ø¥ý76 4¬Äãñç¬ÅaVþ´ì(¢e2™zÊšÚ¤J‘ÈÁ<ßË2ý)~kŒ™¼ðŒ‰¯¥d2™SŒÁ;7@«¢ bOŠÇã7j½äÓ@¼‹Åܳ Ú·Ó¯ÀÜb­ß¼¥÷€ µµ£¿àÏôc±ÆùÎH꤈D¢‹Œ«¶ÍMßËGüzÔ÷ÂÁ“ÀÍèDÔÏØ€Ð°“H$:b±ÄY€ÎÐYɳ"R'¢?Ëå2s{Ê»õ³‡ÿ¹ ÕEä×}*¶ ü¬®.rÔͧñFPN&“™n nC–Uqa,–üe(E–ÑÖ6¿ À¡åòT÷T8¬Ï…DÜ „Ït5jÔ‹}®�ú,—Ë}XDš=Ó;ŠE;K ‹û¬¹ª•Ö0ìTX[:݈ŒOÂïrÂf2™¾ÿ™#"ê¶b±Æ;­Å±ëï¸ð·a&an>ŸYÜÓ¥…7œvÈ?vø`á¸~Øœ^‚¢ù/NúÔ÷›l òù–cðSxž"ru"‘\+¶7ÞØa€Úò™îýftÇêúZ‡ÀÜ‚ٹܳªxcêÔ©½Ø[Dajnn6€� Æ'_U/O&“vÅÖ={䮪ðmd†ÑK±z߀åizƒÏÆï!¢~Å„†µD"ñX©dVÅo*}V§©–~™Ïç· Ê™[__œ?sÒ¥ª: @wŸŠ]ï kíÔy3'}=è’AÈfÓIkñsT´9[~Úп"„½©Š×RuþdÖªôyù€î·F¿úŠ+ ª»”{˜Gð<álSü²åÑ'Ÿ|êú€˜D"v€1aÕ6È|°[·:Ñho_×Ày„÷³=.C%"ê+6 4ì%“ÉW�‰¥Š[{ñø$ÕÒoZZZöé)iþÌÉ ÔڣЇ›Óøe±$,8}J�˺2™Ìé"æg"â½v]ÕÖÖ��~>ñÊa‚GÎ[O<ñÌ*wHBX"£ÿ{Oð ïK°xïæ–ËåvpµO®ª®SÅYsçÎu6ð…U“ÎPbyƒ‘sVSSS'€–ò�ËÎ÷Ý·d—pK""ú6 4"444tÅã‰Yªö\T>S±k$"+²Ùt¼§¤ù§OyFäé ÇïpÞ‚“Žëi³9d2é/‹è­¨`Ù€ß 6Y_ネ¯éAå2DðDЗE@}7WÐsáÑ€è‹}­�úDDì<c}’UõëO}z¯u«'À5a7 ôØÎ•GîäŠY‹”ÏÖF˜}$"rbB#J<ž¼YU>àÍ 'b–d³-÷”4ïÔ‰ÿÛ­…#ù±Ï d¬±ûÌ›1éFíav"•JUçr™›�1×øžvµž>£*±d2ù®ÿ3áÈçóãñ¸S@žt}zîâÖí8¿DUBà^B•N§Çx¹çUÙ€lNÙlútULõLj̘qß Å|x62Cœ‰Jé®@ggçðº$”å�DDNl@hĉÇã�¨ÊaªX]᣹6—Ë,êisúm3ë×ÍŸ1ñ4—î} ¬°ÖsËŒI� N�ÒãŸeËîݶ®nô/Ì®¬\}.-?0w}¼W©T:Ç”Jêl@ RÕçÙ€ºg@¢Ñòû?@•w€l.étz¼ˆù®O®* ÖâsõõõÎ/×…•“Ïà¸p+¼¦ÁõySSÓZO•{^“B/Šˆh6 4"Åãñ¿ŒÕ9À}½x|¦µ¥–-»wÛ tÞŒIWAõÿ¹…[^ÅMVt¿ù3&M*·×2™Ì�ÅbÕã@Å?�ü‹µ2uêÔ�ðío"å—_@$q6 Âò+t¯xÁ‹€êÑhä&[øä#×$‰ß9ƒÏMÙ¯Ff¸è‘X}”s£½ˆ8�½ÞÄ©Tª‚C.ˆˆüU²ŽœhX9öئwR©Tc]]Í÷œ_ɳ"˜X,F›Éd¦~é0oæä%–TZ[*•ŠÔÖŽ¾ØiFE']^2¦xl,6ÝyòÓ@1F&hù-ï¯544¼ì (pH·¡ Ü—Š˜]<·‘HäC(ƒ*”˵œ HÒ3}`7©­½�-C*m¨U„=$ ¼çÖ–)ûóÇH]]Ý.þØÅÑÈÆÑšššJ±Xâ ›ÓË®‹þo²³1x¤ÜÍé•Êç—ì^[[Ó*"ßBåÍǬÅäã�Ÿþb˜5õ†µð™ ˜ý€¼ž/«+ðsÙ¥üÓújCCCWu�¿ G__ç™^²Ÿ úïÔ½jòÉ ™^uCˆºg!­•ç})ínADDë±!¿7§—bÞ®ðÑ1ݜާØçóùQÙlËŪѧE0±Cícìá€V´äàß7§çr™Ô†“•*%ÙlºIµ´JD®E¯.HÓû£Ñêc‰D¥§{õ‹B¡p�Ïi]Öâ ççQ{pH¥¼ØCl—ò�sú@ËåZ¦úiÏô?µ·wÎ  ÅÜ«5ì öw}¼á>�²K4#‘ÈŽ¡×DD6 Dÿåøã“Ï«šÃy �Ÿ‰˜Ç³Ù¬Ïå{€|¾åè\.ûˆˆù>32¿½}Ý´©S§¶÷îùðƒý|òª« Î%Xª^z�¿õä È “Íf·T•›<Ó-`ÏÚðeú=ºVMnàÛÈ O‚ízˆ®)÷¸µZb5DDÿ�›Ð‰6�Çßjmm�µ·¯ý�έäYì èc¹\v�µº0‘H<�Mî÷Èd23§²_o/'WE°Ÿ�Ç“7÷j€þµ¯GÎK�§t©зm뉪³¹÷Þ{·5ªj\¹ç­EO …Ìý®*vðÉUÅÍñxòag°íãï‹Ôàf�C†7Å8@  ®åVå7µýP"— w œŸÉdV‰à‡"¨ªàñ( gƒ³³Ù–ŠÈŸyÐ-ìnL{ôïÖâ¤ÆÆäC}«_|Ì#çYׇÈ,ñz¾,wR]]½‹gãÇ�’Íf�t¦ß=›ú·RI/ ŠFwýŠ„XÞP%x¦~öïÞ6Ut–û¿ZUjú«0"Ù¸‹¨‰DâÀà½y^D¶p( Çbý©Na4�‘CeóÑÖ6¿ ÀGÊ剈³9ó·wA8Ð!bœ ˆª×tcØ€ €t:=VÄÞâ³oHUÕZ™�L&ßuÅ‹«'èŒð«¢L·ó$=8—®m‚3 DÔ/Ø€•�',íá€>·™KépÉOssQ¯åS¥’{ –ë<¹§7LÔ:cÌË=+‚—šššJaÕBn¹\z €9žé¯vu¿,tW@Ùÿ¶#ÈÛ¨0è~£­Ë=¬*AÍ QŸ°!ò”L&ß}üñ¶DäjÕÛÞú®ª^ÞÞÞyh,6í÷ôξòÙ€Þ5~üçqÇ¢Ö H×ø&¿î ¨z}IÝì÷© w©Tª0 àýo‘ž;}útç]=Å•“ë¡:;Äò† \:ªŠ­Ê?¯l@ˆ¨_p:Q6Ì>\žÉd~+‚Åi¯‚ƒðÀ\�Ç^ë§wô—²3 ªX=a¬‚3„Ô€èKsç]¶V~ z¾C„B0fLÍ7T±‡gúݱXãRg¤í Z]»ÐÎN>TÔyãy*•ŠÔÕÕ”½ãC• õ΀õB"‘hÌ�½¼/¤GªÈ«Êþ±XbF,6äšøh¹8÷œwÇã[a�^Ôã œÙÌr¹¥‡ªâB¿lý»HäóAÑÂèÚ«ýPXµ î‹>kjjvƒÇ>-@¹Šˆúg@ˆziÃFðã2™ÌLc0}X{®Š‚1XZ,êw�_†‚l6»¥vòHu6 Ýè> ´a‹{z>Ÿ`‹r�«êKa•Bÿ-ŸÏ�"·ˆøä«ê…±XÃß]±Âs“ƒÈù½¼NgXèãÎÏÅîåóóÇR «C/Šˆœ!ê+M$·µ·wîn-€Þ«ª^7’«ê:¿²Ö~¡ªª°SCC⤡Ü|€H©ì쨺�àõ»AÝïî;@T»½N[ÜØ) ö2ûx&/�Ç“?uF^XþhÕ1cÆr VÈš››ÍÁO˜/‚*Ÿ|kqqÐï•Âê‰û Là‘¼#ž"åú8•JÕÔÕÕZöq…sùQ¸‹ˆB¤>K°œ³ÍÍ0ñ§Ù‘R©w€Èëüéoø:èÀ9Ê~ù]OïO$‹�¡Ö£¢°f!à×ÈŒ@Z2¥_¸cÆŒ®‡×E¡x(좈ˆþ� …Eàu–{ÿÇK»?¶€º�j)Ù¸žw€pùUÈî¿ÿ;r•gú»@d¦ÓŠÛ–.ƒÀgÃHõØè½VÌʉ>cØ€Q¿aBD¡Èç—ì`L¹=zôðºØT� HDeŸ0ë)ElÀ †øÌ€ü+�¿f=#™*<ölèßÇŒ³ØY÷ÜÄ�!ð=¾w“«ñ¡ßüË©ªŠœ `¬Ç �74$Ÿ·."¢÷bBD}&"^ŠØç\Ÿ«hh@õh°‰\vòxœË¯B¤j÷+—#‚%A?F¬\�ã�G¸ªF�qžvÿý÷o%"ù ¢j�ûGˆˆÂÆ„ˆúLÄú4ŵk»ÿ쌨Ù;ÄrÞº±©~­;äsˆ{ùU.�N�‘²—KZ«�º>ï|ö¨™~e˨=Ê9—¯Y[¼À–åÆPÅšººqw…^‘" �Ù³\†*^hjj 8TÃk@¤Ç§á HHDÄgó9ÐôEM©aî žîŠî»b™+�Édöð=�LÕþ0hŠˆ(ll@ˆ¨ÏDÊ7ÆÀ¹üjöü¶* üvïZAwxˆªîXîyk-g@Bb­õ:MIÕ¨ësáÒ«rÞªÒBàòªHßP]nU¼3zt×¼P+#"ê"ê“ææfȇËgг±5í‚Ç—$o'`Ýÿ/¶‘Ñå—žgP¨Ñh4`)ܱÎÓšFn IDATË!£&r3€Ö0k^äËØ÷7¯»"¹\zŠ*¦{�"øÞ±Ç6½nmDDÁØ€QŸxà�;Ãã–kUë¼`N¬„¹ÿ q΀X[Å;@Ø“O>ùŽª¶—ˉâ ìýàÚª•b¹€s–dÄR‰FñŸ¼R î$Ü èPq/Áò½Ü„š¹sçZYU>S?�J¥Ü— þhgÕÞŸ-�É€û÷ÐÔnaçêlÊjkGŸÈŸ�¬•ˉDG¸åõŒ õI©Tþ^]Ïùå1ì#x5` –ç Ýmmmk¬g¤SųiÛ×ÕÕ\ÖSBtŸ‡WTÕEPE3€€Ã FŒKFí»âW —Ëí,"WzŽóT[[Û�C¬‹ˆÈ "ê‘ò3 "òr2™|×Bm@¢(8g@DÊߢЗæÎ�kìg¤Ñ´gê¥ÙlúÄ3vyp]õ¾�|bð»>7©>\µÏò›ƒì ðܼ¯j¿ÄßïD´9°!¢¾*Û@ˆ¸OÀjn†à±�Ý›µÝc_q|–`qzøÚÛ×-SÕz¤FDÌ]¹\Ë©å«ö^ñLÕ¨±‡ªèwŒ¤/Ð69Pç¯9“É| @Üo(IÇãÉC¬�ˆÈ"êŸ� °^ÝåÑ]á±�½kæÍšPpTÕãta²¦¦¦nYà™^ Èíù|˼L&Óóï‹庪÷^þe±vçr¤aGqþ¨½ú“+”N§·3F¯÷Fu _·8""l@ˆ¨×–-»w[[—Ë+•ôy×ç¢6Ô è‚À;@ �%Xø<õžª\ à­ òÏA[>ŸžX.7úÑ�U­=‚;ûTä`'XXµï#‹‚¢Ñ¨YÈ6^C‰\‹ÅþbuDDaBD½ÖÕõÚ¿¡ªÎ�°7 #à«L&S«ªe%@_¹�Çß²_­äì©jÊç³?X¶lY]�É~ùNÕÞ�œ¦*§({ìïôlUgçAÁl6=@Ìs¬Uíí�׆SQï°!¢^)D£ÑÕÎçaÂ=+`$µ;‰ˆ”{^D¹«Ÿ$‰[,­ð1£ª‹ÝÏf2™cÊ%Wïûð�Õ–‚be杖޶jOÄ„'�Gå¦Ó鉘o{ŽeE윦¦¦‘~Šmfl@ˆ¨×Œñºä w,t@î)•|öª΀ô#U9èUs°«ˆ.Ëå²7¦Óé±=%VôÑ?T™èáPùIïªT¬�tän>Ÿ�š»àyê€[’+Â+�ˆ¨wØ€Q¯ùm@wŸ€%€dÏ�KrÎ`ü{w&Euîüûžêž™žf‘¸ ˆ:î²HÔWÀqz™Ô1‹[ŒcÖ{“_’›M2¹É½71˽I¼‰æj—l�ÌTwƒ1adQ£@4j¢÷}A`€é®óþþ˜!!pªëô6=ÀûyžÇ§ëTÕaºÞ:ç}_fÇ*QJÉ H %‰· = À“¥žÛ¿‚Å×…Bôg×u§bw©TêÅBAO°¦¼+ÐáJá®ÛõùÎÎ΢ßaáI+~D s¼RÞ½êˆèG¡ Ë¿íw8›íþ€k-¯æt¥üýB €!Ê’N§‡1ó¸ qDætUh¨êö+ Ÿ2º6M¥ÈàI¥R¯47› Àªl¬AH)õõ)SZ—d³Ùƒ‹œ¸leÁ �Âê2ï5èpÃëþ˜ßñ®®®ÉýÀözDôÍD"±¼:³BˆÊI"„(KSSÓx»Änó ¸ºù¶ÿèò3�¹&@p Ä ÉÿDmmmÛâñä¿Ü�Jôîâ<@?”ÍvM/6(2yéóa„Ú¸«Ìû "z¨Ák~/:~홎.X°`ÿPHÝËþ9ÌøÓæÍ½�U�¢BTH!DYÇ*ÿDžqU/ÁËÏ1ÀÆ#l³bÞ¾%j+oÿ­Ö˜ À-ó‡êžL¦û‹E·dMXº94qÅÅÌôŸeÞg0¬ ‡�8&/1–Îår���áß8Òòz[•ò.—ªWBˆ¡F!DYˆ”MÒûÇ?>bÞ…àü‘ç㻅ʦ ¡ô©Ÿd2ùB<žL1ë+˜ùÍ2."¢Ÿ2¥uÑ=÷¤‹ä17LZö½À¶rç[ôd>Ä3pìÒ×ýhíÝ èjÏΘù±Ølc l!„¨' @„ea»-T�ÏŸ?_ϯr¢Ù@d2™QŠ–n˜Ñ3Õœ�(]"‘ºÃóx"~Sî%úú"f2™¢·&.û%±:À«eÞ§Úžóç‚æãV¼è7 “q;‰ð~Û ñ�‰ö[ª3=!„¨. @„eaÞ‚åWëÚ_ôà€j·È@xžgÙDV@†‚T*õJ,–¼Dk¼`Ÿœž¢Ž!╹\w¬Ø Ð¤{ïÓgÀ§Lô z•µ7£éø¥ü¸®{¾dI^‰ ÿdæ&„5!ˆ¢détº�G�óK@W}Nµû€µ¹ ¡ãØl¿<Ï|¾¨�d2ù«B�'tO§ïÇL]™L÷çøJh à0‹ÓšI¤~R(ô=�ͺ_r]תQY™Ž ÀŒ§Šô¨ö¬·¿wéiï˜Ùüù± {€3æ¾úàƒ«ã[²ŒÕÕŠ8ÐË2™®T±AÎøYMj j“œþË0…¦«vÕÝÝ=‘Y-°_ ×½ëÁW¶òé !Äà�Dˆ!"“əͺ.‘ZàÔ .u€¯amP% r1 ~ è—¤ÓœÀ^ÿ&‚Ì6IèÒ„pO1þ|�H¤þ�Y_`S‰§#Rwe2Ýÿ¯Ø Æñ÷þ5ܘ?�€îògúO ü[xâò÷aÂÒÍ~ƒ²Ù®S‡–¢´ qj�+üÊ] !ÄP$ˆC€ëºs‰x €xµ®I„­áær™¯§ûú«†(8ðWÓ‡£ziÐXÍù0æ tÆ>$èd)Á»çI$R]žÇg0nó+BÑ7³Y÷ÇétºÁwÔѼZ?f.€ïT2OOAñ´ÐÄåß(6¨»»ûl@݃’‚þ ‘ÓžL&{+œ£B * @„¨³lÖý ÿÀˆj_›ˆˆ™??lXäE¶J0ÐØoÿ qÌlÎÿ`®~ ^hã Æ”)S‚E°Ã,+ {¢öööuŽ>ÀïÊ8ýêaÃ"K,Xàÿw¹ã×^xâòO3ð~¶–|Âí៿â�bòÙî¤ãP%ý àçgf,+§WŠBÔ• BÔQ6ëþ€ë‰ª^êŸ0ãâh4ò«j¬„0³Íê”2¿™fÒU@ˆÌIä¶M᳂"†¾™3g¾¹eËÖ8€ï–z.3Înh?�Ë-šPl\ÃÄå¿pæ*Z»û‹RœOX~Ž[Qt›˜ëv}  »PBµ+¯(ÅÄãqcóM!„ê$¢N2™î/ø·A¼åìaÚ¿U…ëX }}Ú¸‹«Ÿ€ò Ç*�ŽãÈ È¬££Ã‹Ç“ŸfÖ×ð+|`D„£´vVf³]³Š� OXþG¯àMð ÿŰ‘˜>¦·NpƯÈ»^:�nÈdÜ›•RßCi)ß¼³f¥ž(á!„R$¢\×�Qç`ß—™?éºîœJ®¡޶Ö;{ölc^�ª¾¢}V@ìÐQؼy³í›m1„%©[=�gx£”óˆ0PÝ®ÛõÉbã"ï¾ï…p4t6˜îÜåÐà \Fh\hÒ²0amÑ ¨««kt4¹‡×”2Oï:�Ï~´Äó„bH‘DˆA¶hÑ¢C‰ø6”ñï�y€Ÿð8€·Ë¹?~´dÉ’w•sîÀlV@žà×ý¯9 æ&„JÑ8‹Ó_ìèè(µË¶¢ÚÛÛï-ô€¹ [ŽR껹\÷MEó¥Z–n OZvM$¢ó ^èÐðÄå'…',¿¹X…«²Ù®Y¡�Z `j)“cÆF"�ˆÇS«J9O!†" @„d¡�ó"*%ÐÌø-3Å”rFÄãíGÄãÉ ñxò]Ì4À×¼e{1"¤uáó%Oüç—]ëŠÛïŽSî½}è�M¼`:À ›Dò?ö2©Têɾ¾Â™ÝSê¹Ìô¡h4²´«««hÇõ† ËÖ‡&,û}dòR« jétzX6›ù3ePb7wf¼ª”>7K­,å;Ký©sBˆ¡@!Igg§"âoÚŽ'ÂÂP¨áôd2éŸô: ™L¾‹%/P´×À?®MM…B¨Ôýçp]÷£,†>e¼¯ª~þÆÕ�~€;_ìÉÚÚÚ ±Xò#ÌüI…O?à{2™î�—{ÿ\.7.›uïT pd©ç3ã ­1]Î…{ @„$S¦´¾À –Ã3ôâ{f̘±¥”{ÄãÉϸÃn´ºª”k°ª€åyl®€Å5Éÿ0���Š9x»—ÖZ�½\"Ñþ}fjgÆÆRÎ#B˜ˆþ'›u–N§­Ëäær¹s¹Ì ÌÞãÞWf™ífLK&“²EP±×‘DˆA0Ðc¾åð¿64l½¬µu^¾œ{9CÑU�ãÐ’Éd&•xy«„Ù'¡”àeóªÓO?a4ÂÁW00bï’H$–TNçt¸<�Üïºnþ[)—ë>=›uÈì=ÅÌŸÐ\ætÿwôèg&“É×Ë<_!†´Rj� !Ê�6Í�ÅÃ;3³Ö˜wþù%½©ÝY,{'“éú"ucÐX"}€µ¶×&²ÊÿØœJ¥Œem©°”9€ð¼Ð!Vç³’�}D"‘xlÁ‚g46†ÓÚJ<}²Rp³ÙîçZʬŸ¨O)5ŠYÓÜÐè §ØÇÌŸH$Úo®ð:B1¤I"Ä `¦±Ù„A¤~ÕÞž¸×ïøµ?]ù~À¡`^”g|üÖ«¦½¶ë¸ÞÞí·G£‘øVMžÕN£Ža¿âºÇOÂP‚—šg¹‚R ÖxÑô¹Öjœ²[ã•�}ÈܹsßX½ú景¾:æÌô¡Ò¯@ã\NÔÿ—‹™Q¥º /0Óû‰äòj\L!†2Ù‚%D�¹®{*βZè+~çýlåÿñ�èˆoÑ{Š~eÛÑѱÀ²à[òD‹yýc´UeÜ~õáÛî `x)÷³¡ |mS‚W�ó¢4!ÜÇ´¶ÎËÇbí×j�� ÄÎéµÁw2ÓäD"!Á‡bŸ ˆ5æ8|µÍ8"Ü�Çÿb:öáŸ-?�`¬ uμÛVøåU<|W>Ðfn; Ü‚Ed.Á íU}õÀæ$r¥T`¯f¼Rn®�Øó%“Éi�sP·U0~ àŽx¼ýòD"aÝËG!öt€QC®ë6kM—�ëÏý o™Ž]õÓž&†ú?øìó fãƒ=3¿|_Ú/hÌ]]]£Œçyl,ÁËDGÙÞ«œßî÷ðhS‚Wò?öqÉdò~@MxPWˆ°°PàÉñxûoó¾B1H"DmÍ%ÂÈ AD”M$�™Ž5�ó €[üÎe¢í¦Ï‰l6¦³<¦Ÿã8V¬GWq]‹dóMóÎ÷Kط؂Å€Äãñ—››‡ŸË>:ú+À©X,ya*• |I „{# @„¨!¥p…Í8fú�éóko^èÅÎ%"ã?‘: è¾DdÝg„™m*`!Ÿ7—9e"«óKT,€¬‚Eä—?"ö5mmm…x<ùyf}3—ÔÇÒ‹>>zô‹“âñv·×Bˆ=† BԈ뺇8/x$?ßÛÛ{�ñPö�Þ6öog™a“`¾[-?Žc@¼ã÷V—¸ôNÐAˆÈXk@`ÂÌÅÎû D"u‡çñI¥èJ¯ÇŒ Ìü©-[¶�'o”œ#!„�2¼BÔ _P`�O¤nïèèðÙ ÅEW?<>¾ù!‰™'—þeã¶/Ÿ±Iäæ„À@Õ·`i6o¡Z²dÉ»`ÑŽYË,±›T*õ$€÷är‹&0‡>ÃÌsl¶Rîd@@ÿ|Õª5ÙùóçWÈ!ÄÞD!j„ˆ¬¶_y·™>ÿðí+Oá´¢ç‚×™>w]·Y)to­y½Í�ÊJð~ì¶÷`�ðnKùt1÷¼m‡ŽÍ%d –ð‹Í^àªÕ«ož÷Ê+·êfC„c f0€—‰è9fýßßÜ<âÁ¶¶¶m�·×ï7 „C” BÔ€ëº'+eóÀN÷Íš•zÂtD3®ZÀÐPÆ„ˆÆl±úãù¦¡Ì|4,©ø•àõ°ý¨*5kû'šÈ¸‚¡µs¨MBÏÃsÕž“Øû l›úÝÀ/!„’!jÀqèB›qÌÚ¸úqI:ís`ù^żÖ|]»ƒJi«ÄuݱD Ç¬Í è\›¼~+ DlÓ„Û·û–ðB!D�H"D hÍY ÛÚØ¸ÍØÉ|¿mŸ`tЛW0”Âx‹û÷>øà#O[Œ³®€¥5Ô ÿàSÅŠˆÆ�ÊÌovttl­þ¤„BQŒ BTY6»è"<’Ÿ~‡±‡1]jq«ÞÑÏNÝàsl’Åý³MŽ%"« ù|Þ§H�š’¹ :@‡�KD²ýJ!„¨ @„¨:Çjû•Öt—éóko^Ý Æ‹K¬÷¯€\‚—ˆló? lV@Þš;wîÆù ú%xÞj|ùUó!X‚’€.„BÔ… BTŸÍö«>"Êšpco Àð  Șÿ‘N§‡|xÐùž§­+` Tý â[‚àZ¬€¼ôkßòÅd‘bN`B!DmI"De³Ùcaµý ÷$‰·Ì‡È&€�†9ÿ£©©i<•« •R‚×"€0÷¹ê§=Ms2JEÅW0Æ_�_ªÚd„BaM!ªHë‚UðÀ¬�Û¯>ñý\# ›køUÀr«èð<뼂{ŠæôFvŽD ~Ö0È€ôôô4eq Ù‚%„BÔ� BT‘RÊ&w£À¬ºLú†Ÿ`„ͽö+¡K‚Îeæ-kÖ¬yÆæ>¹\î@ 4]+Fk˜+jQmÐáS‚wË–-«€Öx±ºóB!„ @„¨’%KîÃ̧X ]šL&_7`X•ï€wþ÷ªéÆËôõ¶°˜û¬ȉÈ€p�*`ù JyVÛ½”R€!„u ˆUây ›Ü ­±Àôùµ7¯ƒ¨Ýîn¼Ž6!²Ú‚e½ýŠ™,¶_J)Ÿ]›„•1ó<|(ÂAãüz€PÍz€à•"Çlþ_;_!„5$ˆ²\ý@Æü�kn¹ïp“­ïçÓýž{Ò#t¾Öö°=@P“Dû¬€¼þúØT#’!„¢^$¢®ëàÝÁ#iq,Ûn<ÂVÌÎ'fÇ*aŸã­(x„gΜù¦ñüA^ñ¼¦ÑVçK"„BÔ� BT@)»àAkΘ>¿öæ{F˜VÊ=)äÇ ®€ÅŒ�~}H|Îh±ô·"ÇjÒ„˜}ˆÂ�vW𤠡BQ'€QËíW€¬é74Æ4”pËWnz_ÛëÆkqp¬·_(¿ÈÇn{p€G–v?;š”1a†Õ H>¯üš !„¢Æ$¢Létz3ζz2™4 *¡ú X,‹D—€Xå€W@¶s_K‰÷²¦à·`1«ƒ,NßšJ¥6UyJB!„°$ˆejnnœ‹&{Ì~Û¯V‡ ˜UÊ=‰ÍÈ’%KÞEÜÿBk"ŽS°®€¥5UÔ„ìØË±í¦yçoô™�Mº B!DI"DN9åÄÓ‰ø¶�ˆŒ«ÀTJ÷ó~yÒÆ`†HY”æ×fμ°„|Á èÌ̽½½|Îo±¿WIÌù4€à-cR‚W!„¨/ @„(ƒR¡„Í8¿ò»ºmùdX6ùÛÉó?ù@ÛÛæCl±‹þ\Ê͈¨ÅbÌK[}æT«Ÿ?€�Ì\,€B!D­I"D˜9pû36Žóâ2Ó1‡K®~€1}šN§“,.Pb 1›ó?^Êýlð–ï1‚Mº B!DI"D‰²Ùìá°xàW ‹[[çåMÇ4Jì~ cÒÜÜ|,€HÐéZ›Ï÷½7$2—à½îöû-å~¶Øg$�N;ÌÁ}G˜Ùص]!„ƒC!JÄìY­^h­�Û¯®¾uåX¦”|_2DÚª–ãèGK¼eKÐ"Ú`<À^à¹åbŸ�#FŒ´©ÚEä¿…K!„µ'ˆ%"RVÝÏûú¼œé@(„v�ʻߘö™�M¬6Wã2p]÷#‚Æ1kã,†ªYòYÑz«UIcYB!êK!J�ËåF<=hVÌ�;÷ ãA.cû°å�§§>i¼³E,<‹Å¶ÛÞŒÙ.�Üóür@jV‚`ó ³² @”’!„¢ž$¢Zçgh§]ÓçWÜ~wàóJ¿3ÿyþ|hŸc6HIùŽcW¡Ë¯ˆæÚ ¤ðŽÏ!«„Hû&± !„¢öBõž€{¥T‚9x³2æ4{Ñ™LÜTÆ��Û¯2™Ì("t¶ÖÚº!0ãˆàl ômݺõÓµ”r¿R0Ø€h­F*‹W*Û¶É ˆBˆ=[.—‘Ïçrg$8Ž·™9¼¡”Ýõ$ˆ–Òé´�F»Ÿøk2™|Üt€¡Så¤À']k=Ùq‚¯§T©%x©ª@ÀG IDATÅbسžÏ1›óËBP›|Ù¬€èGyä�9sæTsJB!DMÝsOzä¶m‘K”ÂyÎph(¤ô¿ÕZðt6ëþ À½Zc‰ã8ÝC5 ‘DKÆ5žnÓèŽÆîç—¤ÓÎ(cÕÀpW~%t•‚M:§PÒ,"a±ÒcÜ~EÍ+å~¥ÐðÛ‚¥GYì*Ý8þ|Ÿ­lB!Äвxñ­CבK”BsÀpàhG+…«™½7r¹Ì-Û¶õÝà›—Z'€a‰Y%mÆyŒùïê}#8€1РѼq Y üÚÌ™¾TÊ ™mr@ÌùóîX~0@A?$Ëæ°6 ŽãŒäà¨I¶_ !D ¤Óéa‘Hä(GñQJÑ‘Ì< ý`@†êŠü@ÞÐF"¼ÆŒg™ùyfzN)µ¡¹¹ùommm…Áþ=ÕS:�ŽD£‘Ï¡ÏÀ¢×—�ý™ù³ ák3™îë‰ö`Ç’I�I"„%f´[äE¼5lذÆó¡Êè~€ð×;Ú6ûµ@¨¤íW[Í,º˜óãÝ´ÓÂ~ùòUP ·`Ù4!D‘.êB!ì¤Ói'‰LRŠOè4§777G´c�1¡ÿ}ÐŽ/Íb_ž4jç1;Þ#ú¿s5z{7÷e³îcæõ¯‡½‡f̘ûj•kCB&³èüh4ò¿è_ͨFô?¹œ›Ø¶-éPX ‘D ¹Ü£ˆB,†..ò–¦œò»€6÷ÿ;²“OþˆŸH$r,*}lì‚Κ�('ÍÅVH{~U°†�K>Á‹Bˆâººº†+¥f*…ö�|Èýw,,úÀV¢À Nè¿¡PPÈf»ŸÔƒÌz –&‰u"oøËáºîJÑ €ºe%ŒÇŒ��¡e‹-š5{öìçª}ýRH"„­›ÕlÜ~õáŸ,ŸEÇ–so&e "‘È1°X–Õº´èý=@‚³¾=@”n×î‹(ï5" Ú�Å,ˆBØJ§Ó ÑhÓ€> ©s4Ö{NÿŒøp"êÙl÷kDt¯ÖܨʼnDÂø¢l(Êdº.Sо àÀÚs4>v~¿`Á‚3ê¹"ˆ”¢ÙIÙfµØt€I¥Ê~)C0®€(Å“m¢Ð ö!PK-_?½3b¤q;sð  ˆBÉåź¦¹9r€ƒê={t 3.&¢‹û÷q"dµö÷öö-ëèèè«÷ wåºî©JῈTÛ ÞöèÆÆpº§§gF½rk$"@ÿ’(¦Z ]‘H$Œ9D<»Ü‡r¯`ÞBE¤&%]3#¯=VÚÉ"ÿ›’Éä릚ÑRÃw7[Ý1Áï Ä"! @„ÂG6»èfçz¢Ð\ª¶»ªÅñÌ8žÈùT4ٔɸw3#«µÎ¦R©Wê9±îîÍ'â‹€ºüI·mÞüΧ|³÷–Dˆ Jq 'x$Ëï^wû}1pj™·í–žõ¢ñnÌ� èDx¢Œà6Èß{Ö°|KðZ’!„Ø]&“™¤_8×3ßC 'ÂED¸H)¥³Yw—Hgb±ÔäܑLfÑ™D¡Ï*…vfP�sgŠRJ]¿xñÂ_Ïš5gÃ`ß[!Ñl›Qž‡…¦Ï5{)€Êú�Î0o¿`S‚·¤íWZ,ÆU¬Òét4�nÐZV@„û.×u?¬¾»k¶6XED÷kíýpÖF£Ñg+­®äºn3€cï84àñZã$"U•Y— ¿‘Ú3 €�v¬õ6MËÁÏ0óÇâñT¦”³’Édw&Óõ@Ýx¦$bhèéé œ ÉÏÄb©?™Ž©Ù\þŠÀvÚÞôÓ¥ÔÉózmæÌ _*冎ãØ$ Ckó,ÖêPíV@l\illŒZ�OÚ¯£¼Bìµ,X°SSøÇJaN•.ùW‹<�3Û¶m[ÑÑÑáU麗L&{<2ðëï,X°c£3…™N%¢iÎ@uª¡Âèû[¶l½¾£££¬ï®ÞÞíÿ�F®E`GužžN§�Züô#ˆ>6oÞ¼–õ<Ê€44èˆÖÁóVжV}RB1„¹®{rccx3­ðRoág€wk,6{}U&W†�æy‹~!�N7477Ÿèsˆè\gb¾eƘñÙd2±¦’ëtttx™L÷-DôŸÅÆQtøðÆ£¼$�vFaL¥KüE1ic¢µŽØ­€(YBìÕªþ�H]SÎùÌØÀŒO'“É…¨Fàñç³ʇ0–ï4�ô©�LÀ‘Zà¨f0À €hGLCkÐ ùë¦@xÌOøAýÄÎBk#“—>_Æï韤R©üÀ�{zzš¶nÝt bZó¹D˜Péõ-­p»çéÛR©Ô+Ög=o,lÛüi¥ð%‘ÝŽ+E_QE²Z�D³‹,Æl°Äx„ ©ÊJññS7Í;£ñ#p„e¬~€˜qX¹=@H{-µn¤ËÌ}æÏUÄfQ]ë @„{¥\.×È|ȯ.cõ�W3«+âñÄcöç�*¶M@÷<.¹/�?¼4˜µq 4QÄbj0~N*0p€|~˜¬€!ö*���jÊ”“oE‰Á3^UŠß‹%ÿ`3¾°núLÍø„"5 €™Ü!€§˜BŒÉ3€uÓfB†ˆÝðø•îØäUŽ�’ù#ÿdõê›Ã­­ó ¨Qr~~Ý´wøË56o×°¢{Œ×Êç'ØäH*¥7”2ÇJI"Ä.ˆ‚·_1# 5ó?4{)€‚Ÿä‹P¤�ˆm:3—¼¢µÓbóCŠÙ1wA':¼‚¦‹vˆ�å™9bQØDÇb1c‰B쩦Liý.€KK<íQÇ)̶É,²Ùî‹|µ”s˜ñ½½½×uttùyH”_;íÃñ7^á4‡Š0€ó:Ïñ ßͯ›ú'"µPk,l˜´ÌXq²¦ÖOj(èýÎf¢‹¼ÀˆJ^à1`Ü~ÕŸ7Êçm+'¢Ê¿{y$b'Dt¡Å0ÏqcþG¡s‰`ÌS(A… èeUÀ› ÆíW�==!pè�2ïkOy~ËÞ6[ÞÊÞ ,„CI.×u3ý´´¦zô߉DâÓ(ò‚jÛúi‡9|ÖO@lñÖ|OF'õ7%Dg~Ý´§üž™–{ {#“î­ÍJÀúsîÓù³‰h6hT„‘Õº´bsEÎ|~Ûy69’ž§WVk.¶$b@6›=œ™O úyÎŒ{ãñ˜¹Y’â‹À•íCbæU¦ÏmеFÉд!còüsêP5(?O”q –Rd“¤'+ Bˆ=^¹Xµ�ÑNûz<žør±…G§Ÿí8Ht`…SÜÓà("ž#¿nꀖáë õDÓäeÏØ'´“Úºvú!aæ#ÙÑ'@«Ó¡øL0ŽøûóE5w ^ ­³ÜT»“ȉÛÜŒÈÉVqFV$bsáb"›Âú·¦O¯úiÏ~ :¿ò™8>°pŠM’x(T00·`1{ÆD±ÓR£b »Lo?f8ï%BìÑú+^µÞàPÛs˜qc"‘,|ä×Oý}\•¾{8jв#ßÒq4òë¦ö‚¦=ÍoÑFfzÄ[€€Qˆ¸D‡€§¶„H72`ˆkýõØ…Ž_›¾ß`›ÊhÏ&‰µÕžT @„@¤l¶_éP¨`Ü~ՠ³Á\éö«ÞCZúŒ?”R'�ÌÌoΚ5Ç\&·ˆ ìߨÜëˬŒ×f­/i'@¹X¿nüØ"„Y¶` !ölS¦´^à<û3øÎU«Ö|2‘ؽpH?RùuS¿ÐG«1¿½X3'€ú¸Ó?" ÆŽ ”÷p»R`ãKQ×uOR �[£‰ÈXѳÖ$€ëº‡(eÓ»ƒWΜy¡¹Ñ³M÷ô kæ·µ|Ž D´eü ‡Ã6ù`fs ^E‡Ê^RÆÆ�6û ‰öì$�N;‘Hd’RÜÂŒð;ÌêM/X“L&Í�1…{¼\®û\€¾XÂ)ÙÑ£_ú oá�ô%N~âÔ›|°*ƒ�°ÑÁÛ¿7"�°k!¢sUž• @„@Ä6yd|Ópõ­+‡‡\Pé<˜‡t:Âaó,°Ýù5´W&¡ß}÷ÝÑ|~û{º0�œ`@;U‡ßù¿QÈf݇dˆœ[b±Øóu˜²¢r¹Ü�ZÓíDV?ë`m¡ ßçÛ¯âÉxcaâ¦_€±g–Øý4¹˜´Ö˜I¤âA§3ó–ææáK«?±`€€ˆ,š2+2–ßu¤Xuã¸KEÐËM@WŠ[,º¿ššö3>ÔÑálÑ ¤Vˆl‚Çò;â6×uP _p%�°<-à§0{_Êf]×óøKíííëj7S!Äàðn$»±üšçav*•2÷ùH_â&lº�!ÁÇžŽ¡�Ï$K–Ü5h˜t>‘úý@Ç÷AgÕÞ]ˆ½YEœ<’þè÷VY¡*Û¯ C!cy-; ‘M~¡Íg{³¶é!R3̼WTÁêììT™L×uDü8€�° >v嘭­ÉfÝo ¬  !ö@®ë¾‡ÛŒeFàŽöövß®Öù‰/}‡QqÃ\Qo„­ :êS~·a6,žñ™õ W¿ÚA±ÏÓºp1¬¶ð˜«_}4Ý3Œ�YU˜Ê›·\vÆS¦DÁùÌüfyЀ-¶P™KðvvBd]‘¥lr@˜©~K4ººº†O™Òº�HÝHDïªÆ5‰ð™B¡ïþl6[ïmrBˆuuu�V ß·O„/Åã©e~ÇûÖMíãÕ™�¨'bú&/16-V*xuk`W‡ BÔ‹Rê’ 1ÌÌŽc@ò[œ$€H¦ò _±>›èå& ÷_Ÿ[,†�g]y0€Ærî[-Ì:p{U {§�뺇…Bj¿R5•šè²ÙE…„C…ã¨8Àrx6O~Ëï`ßú©—èúêÌLÔ˜>Ïd2£˜Ñt>­ªg®  bŸ¶hÑ¢C™9pû­ž5kΟƒUÙ~2ç”�€^nBøvœˆ6˜>‡‚Ï­5føUÛÙ� @2™Ì(¥°À 5¾ÕhÀÉår‹&Ôø>Bˆ*p]7NÛï—´Æàó*¿þ¬‰éæªMNÔÁ ‡×xˆtr`õ»(­µ±¥À`‘DìÓB!ºÄfû€´éÃko^ÝL@¬s!MÆdûöí§Àâá™Y—€är¹F�ÓZ?kþÜ«{¢” @˜‡^Ñ�t:Ý@Ä¿�]€Y ûií¸]]]£é~Bˆ2ôôô4álÆ233{W%“IcŸ$<~Úþ€º @s5ç(ꈱ Ç.5ÿÿæØ]DWP‹ bŸFd·ý P¿6žßÔP•_±1Ýqè ›óµ¦²: 3÷YÚÜ]Õ`‹rH4ù&€sóžDh …ÔmƒyO!Diz{7ŽGÙŒUŠnJ$fßc>J*ï5ü Œ#ª9?QgŒE¦�]×mh¦ÅK&“�W{Z¥�Dì³r¹…G°)Sw<7wç*m¿ž»é²iƇD° @^)Võ¤8eÙ„Ð1÷Ñ´ XLÚ§Ó+]Dõ]ý$û0­�÷Ø�dãêÇU?íi�¨ÎlÈØ€1Û |_¹wÖÚ*];ŽcÞ‚¥¬Î¯ Åæ^+ÌÚÜlëŸGÕ5Q~gÙlö`¥ð–Ûÿð3ÌüåBAŸøÐC«›‰ö‰öáZãPf}3(eDôí… îWêÜ…µEÄÿAD�}¥ú·^ék:::6›Žçןu"­ú3uÅXÓ4ù^ã G›êWÀìÕ5ÿ�F„bFD�Û¯xŽÓgÌÿ«P ŒáÕ™‹9}ñâ®cX…÷—{o¥lz€àåX,¶Ýt€˜mDkßjcæ†[;!¢¦t:ÝÐÑÑaì;¸ô7a‘w3ÀðµææáߨÑ0*•Jýý`2™|ÀÏü,“麌HÝØü½¤Ãaç¾Us„ƒ+—ë>�6ï&ˆèÎx¼ÝÜÅzÃ9M€º €Ïª±ØS‘2ç¤ær¹Ff´[üÕy6O•Õ3¬š$û¤þJ@Îd‹¡Ëfμм5ŠéÂ2«Þî~-�?š>/Ô™Êb�R).;鯀øû0o¿ê7˜M}V@ÔF›µ„aÆ�ðZ•çT’îî¥–‹€;âñvã~ß]%©;\×}T)Ü`ÿ ñDøh:�þnGGÇ�oÒ¸/H§Ó £C¡P;¨J¶jÚæyÞk¾Ý­ÅÞ€˜Õ·ˆØ¢¯6)ß­WùÍ…¯�j^YOÔ�§uÚôðÎ\¸€ˆFZ\b!ªõðR @Ä>*ô›Ìü+ÓçŸø~®#F´Wi2yÝ1nÁr>�ƒ¿‹¶G"#*x›a³…ÊÜ„ð#?_1 åwë.‘yD)½ÑfGi>Ÿ¯{â8ô_¬¢fýÉD"e|ì�L&q]w.~\Š‘�D"qÝ¥ÜCT&�Nknn> ЭDt€ã™1®¹¹éàþmyÿü³‰Ù#RÈdº·ô2'¢uÌü‘~ ?‹ÅÞ©ÏïHTC&Ó5—H�i3–Y9‘H¾l:Ö·vúd"i6¸w¢‡'­46,ÔEvÏ5dìi6Ø$ûœÎÎN5eJë•A㘑g¦»LǶ�~1Û¼iÆXsÓ¼Ö^óÈæËhÍŽ­9e²èbÎLŸúÔáD�=«†ˆŒˆÖj£ÍJ‘ã8ÕùV¦L¦+A¤l›Þ‘H¤~XÎ}’ÉäŠ\.ó]fö}CºƒR4 €Ô\&“9Ð)"J47G¦qxç8´AÌjÛM€-Ì< ˜ÏËfÝÕ–2SO4½·ÂŸ b |/}Årø£[·n÷ùÙ@Š0õ& ¸„Øó™_ЦÓé†h4’2Û3^ZµjÕÊD¢Jé«�Dìs¦L9iì¶ Ýã[W�ÑQ­ùñrÓç™LfÆŸ_~þGÿžQ´ˆ™�ÝR•ò·X¡©·`…B…�Zÿ8SJ×5!R_°úä–-[?RÙÝÔÞuÌáó+»�ð“N§"‘H>J„Ów¥”(�àT§ñç¶lÙ¼1›Í,d.Ü™HÌþ=†À– ᯵µµÀ$›±ÌôY¿m“ùuÓ> âÓ«:91Tp�ôoLßtÍÍ�À.¯ð®ùóçÞ[Ã"$û"õA¶ø*f†ïö+1<ðMƒ-Md¬`¥”>�™ßë3W’ÿ±}QÈb¿1=çóù ÷QƪMÛ¶áí‹TKf:¸Ú3²ÕÝÝ=Ŷ§ 3}ܯ²ÍÕ·®røkf�ñ’"þ⯜¶r×q±Xì�lÖ½@P sŒëº‡ $³‹*èêê ©OE£‘¨KÓG"ŒøJ"çÊlÖ]«5¾ë8ÎÏýŠIˆúI§ÓNssäË6c‰pw<žXb:ÖûÄÔ±aÐW«;;1d–5�_iÜM¤Þos f ‰íW€”áû˜\.w 3l‚‡M ƨÛF K¨VùRvHíöðØOY½Årœ|Ù%x=/d±ý PJù Ü„Ù8ß9sæ¼mÓƒyðJïÊq”åŠu%æŒ+n¿;Rü;Ÿp,gkÐ’ÝÙ3Îx%âŒÕ‰Ž´››(¦³³Se2ÝW‡Bê óQ§àÃ`’R¸Ekïo®ÛõÙt:íWMNÔA4Út &X õ˜½Ïø ðuê731”0øÇ¦ÏÓéô0³-.ñÊÖ­[�;.êA±Oa.\‹²„DüË3fhèÒ*Né¯?¼üÌWM˜Ù&ÿãi¿*]–¬*Xùõ!Ü.š¯bN”ß™Rƒ0 H§ÓØõ}Mü IDATÅA㘙úŠßñ&Ýü? ìšCUž3Ï4>Þfœic#ìe2™ÖSNi}ˆˆ~  n+mÅaŒRê¿¢ÑÈcÙ¬û~XCµFŸ¶Ç¿ŒÇg?j:’_Ö‰]QÍY‰!å톭یͣѦ¹°h>à·C©â¡ bC´Ŭo5}þ‘Ÿ¯Å@¼zÓÁ ÓÇétÚv{ÐÜM%ý?€È¼¢ðÏ÷à-3gÎ|Óçè >С؃r`Ò_rxðE"‘ ‰(4Žˆ²ñxüaÓ±ën[~*æ¿¿LSMŸ~ÇFfl ž!IR�lÖý(¯ ÂIõž‹¥Ãܑͺ÷»®kµ-PÔ†ëºmN¶êοûÕêÈ3ÝÞ‹ùv´®2«!²{)Êìý¼º“ªŒüeûŒ�/Ú‰Cׯã³Í}9úøbUë¨MlÎÿˆD"ï†ÅRz% èýç?xÁ¸ú1Àj WÕ0Æ^Ҝ톈6ž^§-XJÑe6ã´Æ÷}�1}þo¬}W²ˆ‚fØuYì.—Ë�Èf3¿ð}Tñç :U),Ïå27ôôôÈß�:pü«Í8"Ü�Çÿb:¶}ýÔƒ]Lb€¿�ð(«AX àqž`|Pe+h¥¿g:°dÉ]c˜qžÅ5žN$fWô¼Pm’„.öJù¼=Þ ÿÄïUwû”g^Ðfs>‘.;ÿc@`AdN@ïï…2ü  ï_ªðþ[Ç `·„ifýlps?:¼§§'ÔÖÖV¨Íôv—ËåÆ|nÐ8flH&“¿3›wûò³ TÖ3š‚þXˆ””k-ÑÝw/8ˆ9|,+ aŠ™?ÝÛ»)îºîUÉdÒØ“HTßâÅ]Ç1+›z¨^>¯¿f>DJaªÏ±ª(€è!f^ÐÃPÞÚ†Þíó{ÿw«/ÙÙ~ˆÆ0ó!DËŒ#œ„þ3ðZ£;'Ü÷¤éH¡º†Æ—r»ø9†X%< @Ä>a *Í%Cû´¦ÛM>ò“GBaz§õÒÿ~ð¬'Lg[TêÚ‰Œ0î.�Å,�í#FŽô ï!/h}( ÀÏXlioìíÝ8@¥nÖ´.\J\ÍL)º>_ŠÕõ\ü»#ïw€(ø‹ž™%)AWW×èP(|ìVTƒ¼ ` =âyüœRü¼çᥔvo³ç9À™÷S £™õ@GD»Ò›h¼RX‘ÉtmÕª5_*¥:÷fÌê“°Ú‰Bw¥R)ãhßÚ³.¦jw<'x̸Äw64ºqô¥7¸lýÝÆ`#€õ»ë9'Ô·¿OJŸð‰ :ŒÓ A‰IŸ¦‚1Àìéé чl.ÂLCjû ˆØG8}�ý€%“ cï­øšjVðg Çôù@IÆéAwbÆŠJßä3ã0‹ß‘±+o ~üà�Ý>'^gs¾ÖÎIÄ„(xû3³Ö¸ÃtìC·/;B±:'à}þ×F$øïIb)›Í Ñï�à=>43zvÕ•H$þVÉ|\×= @›Rhp€C*¸\ˆˆ¾rê©­­¹\îré¬^;®ë ¬’Ɖôw�Ò—84�æWmR„­`ÜêÔ·›&ßûtÕ®»«¶¥…†þŸÁ�¸ °ú”æBSó4Ïáp•ƒª=ã³�Í«›7o~�RVù{k‰ÄcUžYÅ${½�úOØŒe†1ù¼³§'ÄvO/ óRÓÇÑhãIæ1ë{+¹}.—Ñß+ 8­}r@´W�]RdübjnùØ–-›¶ tŠö¥ÎÀŽ/½Ëd2­DÁoɉè�D"ùWÓ1G;`ïöH>{®Óé´�F;"é­AcDÿ¿@ß P9ÁÇnõ<þQ{{{Õî’Éä³èÿû|[gg§:ùä“§9]ÍŒ÷•× ›íÌÞ]×�›L&¯Ö\Å?(…êrÝ‹%w{á}_z±UùÞà»TèSMÇ/ÝP—ê­«zCÀôÿ›>&¯ùÅÁÜ»*O{fà††I+Œ¹���jÊ”“¿`SÈŽ™�Ï5õ&Ièb¯‰DRD8Êb賫V­2îÁá™pÀØjÎK�{|޽íÞ1Îç|;…BÁ*�œÈ3nÁ"èJÞ´–�4O6}ÞÖÖV ¢?_�-ÿ|+GÄVo8™µqõ£³Љ_ßT�9ÒjK³ä€I§ÓŽÖÞ/PzÎÇv"ú&‘sT<žü\5ƒ�]ÍŸ?_···ß�'¯PÊ9 À ÊZÅ ÂqJá�l¶kVug)r¹\#‚„ðYý)®¯x2„�L¸$4aù…MÇ/ÝPñõªeü²——ߞ°ì½a¯ù &\Ê€‹"«½{‘W‰o˜¸üsýqÈîN9å¤Ë-_„lò<6n+¯7 @Ä^O)»*#Ì|«ß¾g‚¾ºº³Â ?úÀtãog[œÿΰaÃÖT2�Pȶˆ9 ƒ]kN&ß×>æªb»Œ96›ÍÖ¼oï«-ÛC¡Æ_™¼pÄŠsaÕìQm2}êyžÕ[C¥$$H4Ú|b%ž¶Œ™&Æb‰ìíL±Xìùx<ù9­q43ndöÏ*b f³Ý6ùsÂ’çyîWÌÓ[¶l[h:зnÚ\0Ž«h"„ÕZëÖ† ËÓ]§Ö&/ÙÒ0aùÏ&.oçC£\9Œ Z1‘ÁÃȇø¤Ð„å‹ýFtuu�%Rß±ºã¶T*eü~¨7Ù‚%öj™Ì¢3‰c�„�1ó¶p¸ð#Ó±kn¹ïp'DÕëý ãö«žžž€ÀùX^iþ‡Ö8Ô&£¥Pðë‚®%ªKQ�?tÛŠcpÅTCIJ}/@ÿ| =€qi»Z¢Ñ¦Ka±•@Æ¯Ï 1]iµÍ�اÔnß�°(�ây’_PCE&Óõ^"eñ÷ª3³Rê¿"‘èüÁ¬¸f’L&_ðq×uoðí2‚¨€îÌfÝñxòÿj0Å}ŽmEF­õ÷üÇáӕ퀥ÿãÍÏaÒZë…Å‹»ŽÓšN%RG3ã€ÇhúÐxè_�íèMÏ2ó‹Dx–ˆß¼yûã•m÷hñâ®ãˆÔM¶ãûWø²X,aÿVùþ3#…‘N+ƒNÿöÎ<>ªòêã¿óÜ™¬€`­Ôí[Û ¨U*«¡Upfn‚ˆ±­ŠâÂæ^—Zk-FkµÖ}\XܧJ˜Ü™Ü" ¢BÔ*Dí«Ûº·®$!3sŸóþè‹ðÜ™g&7a2¹ßÏçý|ÞÞg¹Ç�Ü{ÏsÎù|Ÿˆ÷f‰þ ”`¾`à ¾€Ä߉åßF~ £^Ðþ˜Û\ËŠÅê§3ÓM:õ_[a0ó=ÑhýÀP¨êú,ÖylC<^÷f£2³d8¾”R]“˜j7Œ\H2Àø‡7Þ¬3yó!Þ4fL"C€¿•´íÇ·ÿ÷–ÿNfByy©ŒF­÷ˆøu€Ö0Ë—lks=¡/Öøµ]•zsìOYâtÇ ·©iuöNù¥oX£²ÿØš›çù[[w€Giîü`WE.ºÏñ(Xb±¥‡FÆüåÎÓJ©|Ïš×\†byšN¡W6©.@g•z:[B¹>ˆh¯L§ëN¼ÀHÛ•¼›¡ñ¶ë× …¾ˆÅ¬ÕÈE’’ÇG"‘}�¤-»J}}ý†AÊZ•møp·Ý>Œª !§™»§w Yb€Hi›HàC½ûô-âñx1³x Z z�Ο V?‘qò;‡H&ü¿`¦©4À˜†Ëß#3¾õÈá­ÿ˜’�ĺqo0QL�íÿ¼–ÊM0Xµ`éÒ¥Ïó™1Qg Pç—äu±˜•ÍnvÞ ÿ©DéE%6s¯ã‡9ÓÅ9 €¤œîÞ”Q„#«7úõ– —ôEg=&ýÀ"Ÿ2« §™ígÊËwjª¬¬Ì2%”¥o(žð4ZFÆ4� ð¾®XÝ�=æo/ž…ЧÒ6ŒíTMÛý¡,œ[J\ゅ݆ç€x0ÆåzóhY 0y{­rTÜ~ƒ¾ã¦Um¸óÔ1ÊS "­„_¶µµ½ÖU+˜9c –SôãÃ-Eƒ€ïvÕ†\aðÑ+ÞÂR¢Nˆô‘ß/Îð›î°Ï0´÷�_Q1S�›O¤­ºÆJ„»k|8lÌ×á�ü=G$ OÊè|ümÂ.Édò·€ÿt(÷<?‡ø_ž\?î5"<è+JÎÏÔ·aòäÉÿˆFë/'¢ß#»zÐ-Ëú�išåjx†˜åÉ™´˜™‰ eº[Çëc, 2s¸÷&&úEѰ•KÓMêŒÐøîH÷C·«€*T—´µml�Ç­Ff^âó¥–8e&82ì…ÏýÀ-Ý–hWEÌçC³±oÓÐyþa+3¦5Æãõ‡ A�!»ºËMS­¬˜/xEèIgôZuÌø³êúæÜs\5¬ó†ËU—››çù“i9�ò‚³�(÷.èßiýtwìØçÇ÷f>Ðx°j€™—0gnã(%Ϫ««è¶aÑh´ I™æ1#™JÉùª±3î{ao‚~ÓKvˆ€aèº*Ó·ú:Ñh´‚™/Ö�/¥¼<ªN“vE”\7~N2™ú@¿�1Õ2KbÆõÉÿ{©uã‹·ÇfŠÚp(Tu%ÀÇ0#íéë6"ÜoY–Ëuq…O}}ý�ÔW!he0TÔ¸dÐiÈöÙK°YÐ/39Ñhýé̾×íSöî ´32Gw¥Rþb1ëYËŠœ‰Dg· Ë¢a+—ú‡7N‰CÐÙ <_šk¾Î,Fø‡gv>b1ë\fj@Î3ZÊÊú¹×¦›ð�E\§9q¥iš ª�Y V�½äfF´Buý£�v _¦õÌNò½ÙÁÌe…mÛV7!$¡¥ Õ��“U׫ªªÞ#¢Œ52DØ©¨Èwžëv_ª3O,­®®V¦>†<Y<ŸSœz×Á–Ý4–{È6„Ãá""¾úYšfµsºCóQ;¥Ö�}ÄwµÎåŽìÌÄW'Sâ½äúñ¿Bøø´õPÁ`•E$ �ŽH¿x<]:ºËÖö! ƒªuæ9ömh˜à0-ë3Î+ºR©¦t~ÅãÖ}D4@iÖûw€J!Ä­>Ÿøg,fEb±ú©›eŒµñ{þUÿðÆ™é`&(S^{�;ýå¾Ã2¥LF"‘þ±˜õ(€›e±ŠHNÏ>�­çñ�‚#� Ð8�¹Râ*§1Öü�Ì’T’ϪˆôúSuÝyúéðND™ë ˆÔµÌƬÿØløD§1)qŸæ6/[V7Ä‹þy;Fg®m«‹àϽ-^ ¬,nûéÓ+¿T H©#áK^ýÇ6”——þÐîļNJÌv}}̮ɒM Lz¿îÁßøÆä°�V%ZƧmV×yÚ.ÆÐè£ó_ʈŒ',ËÚ!ý€z)ÊC“møFJR¦ñٻؓÐ9Tø/ \çÞx‡Óx</þôÓÝÿÂŒS³Ùwà`–2õA,fÝnYÖ¡ÙlP´ÿÊ׋†5šD<ŒuÝd§ÂWÌ8Ö?¼ñ, y.­s�F+|>±@.ò×—ƒÕks3²gñ�‚¢óäRh^1c•išÏ¨Ææ,l=9ܬ`à%§�E"úYÆõÌŸ¿üò«íªeZM™…ÃéøŽiB¸ ?˜½xÕÕ@¿~ýž`†Nîp™”Æ]µµµ]~vîaÜ�ç*ž7M³I5–ÐÿçÐë`À1Ï—H§O+£\}•X,v3t62ÓÏ�”âðÎá’B<à × ÌžÃˆù•TËØKÓEC‚ÁàÇÌ4�Ê®Û �‡ÃálNhû$ñxÝ Q§eN¿OL<=ËÛ>Z4¼É±Ͳ¬2À^ÊŒª,÷Ý¡ÑÎÎìl”Y¿>­¿$GØ7¬©Ñ_Òˆ”ÒûÝ@‹8´hÿÆ%é&ÕÖÖŠX̺˜ˆWøa÷¹-4•)åùˆç€xåå%gAó—Ù9ú!!º#ú€•éWáp¸€ŒõBÐJ§f‰YY¡‘~DêÓqb‡4!Ü–j=ýÎð3kêŸÓ¤‘#+~ÝU[FŒ8x:­9ÛvV'ɶîH€”ÈŠKv…Fº�”ÎL_#Ìò>"øuæ3óE¡PH�J>ÞHtø¹ŸÆ™ÅÌôÇİ�cxm‚cÝS(ú¢­­}"dÂU^^–·½ò)�Œua�°ºN£eôÎŒ¬…·üvÙN�´W¬XQnˆf£„–ŸÐP"ºF¼�[w†Ãa½²}cdÛÕÀº 1êü>>¼x¿FeMÏ–/r·‘#+âþ„ìR®:ïCtËš5ÍZM—óÏñ(–.]º@WhNÆ4M¥30sÁ Ü-–ÌByÏÒÒÒ Ðxè0gõaàH§ô’²˜×¶ùNÿÑÜèªX¬~j®V,_þänD¤+y¸ÆéwoÖâUc(£:Ž¿¥ºœLiuI&"åú¾HYYñL"(Å < U)E 9ôÛÈ(Þ“xbÒo¯I¬;b¨Óœššš�DÆ1^Ñß™çD£mÕ¶¾ e¬—aF2‘HÅTc ˆÝÚ‡�8.ou2&™L,`Æšûmc'oð èfbæ+Ðùñ|xà¿èÈå9àcÆì²²Ò¿@K7Ÿˆ…èÞhãßþMSñ㦴*ƒÑh$dÛþ×�[ñ¿Í,/B¿rãp²'ñdx= ¿ßwÀ:zýŽê6‚äUìvã�N>ÿªüÃ5ª"½S(!¤RA+[4åYÛŽ<²F©ŽÃŒÝ»å'”=ý;RÉéP4¬®®þ&­¿šˆnÔØÇèA˲¦iÖgc@86ÊËK„¦,1³¼ÒiŒ$_’­(+3+s™‰X˱m;íÉ\_¡®®n`Q‘¯VsúF!R3àÐŒ!¹nìl¹¯ ç ¼/¿�Z?þ¾á+•Ï“@ ðõŠK‚©”¿še"qç²e‘�>ºúmWÍ-ˆxL¦× šŽ9æuŠ.S6‘Š ýÞÕi0³®$B¶.’Kº·­­}¥nGóp8lïcÆŒá†!FJ‰Ãˆ²«eÑ…˲&›¦éXt‰ucjˆ2gä ×íßô[§ðßwÇý6ÇN+Ÿñ‰Á`µ²®4ßñ" Açé5k)Œaa0Töј³¨ñPBîZ·åÆxæqù\"èȶnpëån†ÎÃß¹8¹›^9rѹ·©UQÊËûß°nÏ”b!ð¤eEÎÎææýú•ý€–€3â¡PµR…eöâU#rùÝóIv*þ‘Æò/ª««?Éöž…HQ‘ïr»hN¿ôè£�Ù H´Œ¢|OIÈàHâÍñŽ…ñ'NùTˆÔ$¤{|›R)Åýáp8­êV_äé§Ã;1CG9p¥ú2kžŽaIº¢óXÌ:�™«³×˜ñ*3 ™5¡Ph¹®ó555vuuõ;¡PuÄ4«¯ ÌcC!s�dÒÞ›Yž¼9Z⪆adHU{'XL‚®uóž[C„+І7^šÎùˆÇãß-//‹¸Œ(çƒS)YTõJçð�À²¬]˜I«3/3·Ú6~ï4n3ý Ýý€SýÇæâÄŒ[‰àJô˜uäYYY€N�?Ÿ]ݲÅöJ è¯Lÿ¨¬¬LáLº}S !Ä­ñ¸õø’%KÒ6 \¾|ùαXôfÖlx‰„aÈ œYÊ«‘õï}uç©ã�ŠÈ÷Ë´šÞi5€eË"?f†–ãI„ç׬i¾K9Ø0ÁGŒJ\4¯»("æ¿$Ö�û¥Ó„£�>fƒ”8úi4£ÊÊJzUzO�L– ÕûÈ”/©®&Ö�;@Sýê>‘˜á4‹-=Àül>x™qG[[û¨P(Ô¬»F‡É“'ÿ3ª~00§ƒæžÌt ”ò2d•ú§†9}4:Õ±ñ<0öéê}ÔÐí¾a�i#©ñxýáÌöZ€�Ìv÷Î&•tCYYÿŸ9ɸ÷¼,�^Mmm­9ò�ÅižÈóu¦Y¥lÚ6ká ©;;¦’ºþCJc’Ö«Iºç€ÈX„îT€>çá¦�vž}`1ðû³Â ßQS¹qÛ±@ êÅh´þ "rØn?ÆqÅÅþ#c1k1ÀO1‹w¥”›|>Y*%(„8ŠS‘]3¹[œ"X�ªkY¥Xl±ô U7øÍü$Ój"òRŠëu Ï™yS*Å3œr­S»Ú¿óH÷-ì& ëÇ'І¯TJ¿š¦ùr4Zé+]iY–eš¦W[´fÝ46¿2�R@NäÌg€<û½¤¬{[±bE9 Ev}>~ ™Èb~΄B¡uÖ¸¦¾¾~!0•'”ƒ‚9÷´ùÛ„]Ý"±€ø‡7�›nF,f�ÐíÈ¡ÐÀ—Ìtz J«¦Õ[ð" ½š#¾L§ë4ÐÙ´­­ãOª±ãÃaàëݵî[¼yÏ´1ÿP ¡×5Û0 C­œ1‚ÁLʈìÐjn×Óì‘jó9ÊM®]ûÊ5€º}8 ¯7 z—ÙXG$Þ¬™Ÿ�óñ^*%_ä6(Ç—¼:½Ì²¬] Ñ9WJ;m3¬¾@4�ÍÔ7!Ä�ÕÕÕÊ�›ä›ãaæß¹j\Ïà'ð#öºñŽ?ƒP¨j@êæxÛ@D%Bà/kkHGV{c PŽAd.`ñEþá«”5†�J%nÈQ|`[˜ù×Á`Ï8ÛRUUõ^(Tu}0XuH*%h^Ë%‘½Øi0™´ç¢óÙî.„çý›6ÍL—v‹YsÌCnÎG“”8È4Í‚p>ÏñèÅD£K�$ŽéTÛ ™1»¦¦&¡Ô¾û€u�å€úã71g® Âê@ ðµ{öPÆ‚i)íÏT×m°v�ŠæÂ3ï_¥,¼ž;w®d'x£‡m€„”øeuuµR eö¢Æãr�¼1Ó˪ëBH-%'!àX¨Ú‡Ã‘ÞÁ3>Ú¸±M�7Þ<›zò½yˆ_?šlãxÚ\VV~6ôÓc+++9ÝÓz?D¬1í#8D39SŠ.ãqÿ°¦Û�†c±úi¦kØÐ¹ã¡PUwÈiS]]ý:´kNº'¨V>×-c‡œM“W]þéOÉãQ±6édT,½ÀÜöN¨mmmŸ`š¦ò³·â9 ½’h4ú}"㺧ló�¿�qßê�Áò ׌S@,žR]/++ _¦õÌêú‘\hnžçgæŒ'@B¥b¡ó2Ý”Hƒïpò …¾0ŒÄÑÌx·gÍâKMÓT: ³æ5—1(ç½ô«•×¥ž”,‘_·@¿ )--=Àp�¹D|YMMÍv)~�,);;Oú}t…~Ä¢¾íí±ÊôÌÊÊÊM¶Í§@³„ˆjãñx6QÂFG�‘”ÏÛÎåiëýߨÓ�-ËÚ Ç¢ôínÅx"2sùPî,ËÅÌšŠrü/"ç^ÄtÜ?$èó±8p•cãÛxP9# `àðAíß»Äi|Ò¤c?"GÜS©GKƒÁª›�©¸íw`ì�ãÞŸßwÒ(¥3%„¡‘7Íÿ Î=Nsó<¿΂Û°vÍšWÔMËÖ>ÄyóÁÖØÓŸ¤z¼>©\5^UUµ€®Tñ`fÛñ¹Û· �z[VFç;—;Öm4ù7•TaÔ ÊA8.�Bã� èT»òû‹¦Ã¹®¬G‰ÇãÅD˜ýoÕ3�2ëÇÿšj…Ù@L—û÷oZë4�Gk™ù¼¬÷%Ô%öÁ�@õª®Y˜¿xˆG¯¢¶¶V”——, ›.eñÉNý,æ,j< N&ô!FÃ=3+ÚÔ£¬SÿñéÚµk]K•Bhö«PG@4ó™wLWÎ\Ôä¨. ßgc<×Í–¬L$R§Âáe~æý«~Ì  »°ÿËNèÌœ1BD}:ýê“Ov; À÷3ÍëT�‘ŽM¾’ð_ÆN®¸£ ’2Ú8 —•õ»€2¢·-Ì|þ²euC\²¬7ÓµzÆ&ÅÕ‡ý_ÛQñ”òÝee¥·8Pó._Û¶üùĉ�šö8Ìö¥D¦9ý‘`°ÊRŽ´Lè'4S-³¤Ñ·ã Nƒ–e�˜…JâRRÊßæT§ž0…‚ç€xô*=tÄ MÉbI­“Nöñá–"Éâ^tõå�¤|(Æb±ï1ë(ñSnv8%²µ)¥Òa ¿À Æ#g>Ðäøq …¾hmmáF®w�%Â݃x”Ó dÖ¼f¿-x!rˆHQ� IDAT+Fì„¡”쬫«H”YÖ™¹ïÖ444”¸Lg.‘xÌé2Ù2þP ®8Ç%×�WʹVVV¦˜éTh¤bQ‰”þ?ºn`¯ƒ¾È4ƒÙYÚœ�­Ó‡[tœxã‰N‘°,ë"œ¡k¡”˜å$°°#°,ëfèªUý›È8ßi0�äï™±‡K¦má)1`åûò¬Ÿ�{²Üóc)1Ñ4«¯CžD¡ºÏñè5XVä×Y†2—­YÓìøòØöŸßtoáy'B&•ˆ”r¢¦»kõ@dhõð(+ëpJÏÉG¬mÙż|ƽ/9Ö«ÔÔÔ$ó""žàŸîÜ–ß—¿ Ì3+*f:$%íW‚pX—î$H选ááTK‰>[ÿÑÖöÍ€öÌ4�If8([‘óm(Ø÷(ßÔñúX¥¨C(z“ˆnÑÚ…åÏ#‘ˆî)|A"¥T«[m†ÄãꆪE šFG±´‡ú‡7íï$™¼˲¦�ëô-¤y¦i>¦?¿{éLãÅ:ÒØÀ,/pJ'M¬;b(19:'¹CÐøwÕH4$žP–ņ«S)9Â4ÍWÌëèƒÓ£ÐˆF#'Ñ5ºó™±AJœì9˜µ`åʪlnÐwM¯Ü ÁL«™™S)÷ Ð@J©épJ[#h)ºä´¯ð'—Íz¤!mwë@ êY"ã)åoä¨2Â︤¬¬ÿÐL/ò™ š¦�áX§¢{Ã"ø•i0DÆ(� ¤”Zi4…F8îÇLZ?"Ü …”ÉõcOp¨«ÆååBÐÃhÙ_¥óûÛ®a†cá툈|>ºØ}ózìÔ,tkʤ”•Ê‘ƒW~æÚøtÑ/¼•Næ¢Ñ¥£…Àbèß½ÑÚÚ–WÍ#ûõ+û“®d03â¡PõƒêQ""ézá9¢þá+ç;� Á÷@#½óÿ¡Hkkû‘½½±`¶xˆGÞcYÖD@ܧ۽•™[™1Å4Í«Æ/¯.‰‡(O›Ü„ •Ñ�Íò»ýKèµêêêOÜ´I‘öƒ¼NWœÜ�ûns¾•s­N~_›fõueeýöíìüLw1£%Í’kˆèv@VƒUßÍ?WVVªrµÿËìMGá^dÝñ|;Þ¹ýäC• Ǥä1™3cC_{Ùm¡¬¬ä<"çt—-0ó&"ãjå`ËþE \á¶myá�*{AtPHÍ‚túy}}}7užî Õ™EÄŽ]ÌuˆÅ"Gm,Ñ=yß(%~^SS“…Ìm÷‹EŽ–Rž¥9ýf8Öp&[ÆNð3W ûþ]Ÿcj[,f�ÁŒãt7cÆÃ­­mSóéß §ð�¼&�V�°~(–™™N5MÓñ�ßÚfÿèÉL›EDu½¼¼ø¢Ì…«BÐ2·m""�‚Y¥ó¶™Þ&­9T²ýœE+3fWVV¦LÓ¬ Cg…Bæþ>_Q¢Ô™í±D|$3�$Jýpðàƒæa�@èÜ`°z%4òug-hªaÂRt¥î㿨ӯ|DZ§ò/t݆ÞG$é@ë´—HÜ”'×I4#ƒ4jÁ@  ëÆ+S¨ÊḚ̈^cŸt�»–õB¡Ð›:òßÌ<¥óÀ-kȲ¬ %"¥‚™ )qv>u¬_±bÉ®Ìú‡�RÊË{c´LøŽâ9Ct1†=÷±j(‹ýˆ™oÊb·¥ååý¦¢Ä®žâ‘·Äãu? b €††z'Dt•išqŸ½ © À™nاÁg_•èЙV˜:Ø6«U=º3;I:n)ûPçɽö .�øÉ¢i悦iÙ,š8qbk pÌ»¡Ðä�ªgC¡Ps pÌ»ië;¶¡¶bÖ‚U—ƒð\q>buúÔÆ�„–ä&÷IDÌ!¢�3ÍcæVŸ/¡n:¸zt)‘vqlï‡aIåGUgAºÔ,æÇi+V,Ѫ?+Dˆ¨^c �‡b±¥Úµ‰–eí‹YO �ëhÈýþ÷nóLÓTKKïÂá°‘Jù"Ò®1\ÙÜüê�Nƒ)NÝ`�;Öm†hµXãB§Q@ÎÓwù5)qbeeeÊ5ûzžâ‘—Ô××ïÃì{YÔaQ0h:¦ÌX¼r&~]Oѳ}ÜádƒU™Ö3ãÓææfåIw×à’ÌsH™JtÚý«ú¡÷>7ʈ°hö‚¦e³¬üaOÜp΂†! iZâ+á¢Ú µQæô«ÎyFŸs@: […VôCqëĉS”õ ©�ŒóºAQ'Ï¡Ÿ&Ö�Ÿª …ªë¬ÓؤԶ‹tSk »Nsâw£1�Ìq*JGgÄcT,}X¼Ž,û[aÅàÁh6÷ëÊÊJçB3]Š_â§ÏDËøã8ÖU ¶ÏsªÁ‰Åêg¯³3nÛ˜jš¦ƒ<ß oÙãg¨¯¯ßÇ0ð,€ÿÑ_ÅËwÝõ£pH…9+ÜÐOH_=X¿ ê?"‘È�>Ÿ’i=YnÊïnµsÆ;å£jG£ò&Lij®ºÓÇÉëî˜^© §w…³Â ýR­þ_�|¿¡ì”Pth•›Ê”ºDb”F6Ø7­­­o¸lSÞSVVrô4¾”êžÍGíÄ%è“Õ¾ Í#â¨X»íG3ËëˆDÆÓtf>-_ÙSN‚Áꕱ˜µÀH�éˆÄÌöb1ë9"zKJùÍæôÙ1c”Ø-G¥Ö7ãøl¢¸ÝM<^ Ò…!âsƒÁàûÊÁæ£v¥|s7hØÞí¾J™Ñ‰Dv7 q­Nâ3³˜ U½ç¶�½ ÏñÈ+–-«bƳeÑš›[[7Õ8=P  Ym¾ûÐCu›IضPªWeŒ~€”î§_m&c„Y)úÈ—C1À¿J‘oö¬…�÷1ÄÝóN£“Ëž–9‹Vï!¥=ä;ÄS}r�MwϬpøxàÑ[¼Ø×>ÃápQyyéEšÓo …Bʾ ‰’MÐ-ÿ®½€½R¥%çù€íÔËË<ÚÚºñJ" ɰÇååÅGp½¶­7ÀL¿'âxK8–™±uY„^…„’“IÛœ<ÙTv ß,[V7„Ù·ú‘õǃÁªÅNƒÉ’M·Âí%á3¿í$Ç øýâvÖlFJD7f6¿KoM¥ð(@b±ØÞ¶íËÊù`Æ»©›555Êš˜¹ i.Ç»c¥¦]Àó÷�6æÕe¬ÿ`æMEEEO¹o çˆmdãö J:›Àëf-hzqö¢¦ f.\5<› f,^¹Ïì…M3g-l\.Ù~„¹èÆ�T5¨®Çãñ=¡5ìséWee%Óì¥1õkfºU9ò· »Ð ýzÌt>V�Þîù±¹äF½]Ät—Íê5„B¡åDØ!ý6˜ñ‘mó¤É“'»Ôó¨ëD"‘þRú–B?3áÃð;Öp&ZÆÕ8Ùã¶Fò¥8 Qy(‹ÕOeÆ1zñkDFÈÿ÷¼ˆG^‹Åöä³'h[ÁŸÙ6ÒÉÔÎ\Ð4�¿wÁĬÌÊ‚ÃX,ö=h„à‰èÙ‰'¶ºnX'9G@¤@JtCRX^@8Œ‡ø†Y ›>ð::~þÁÌ_¨‚ÊHÊ´†t€€›7è $РºnÛö¡q¤$%V»lR^‡�òòÒ_kN¿Ë1ú‘JþŠ@þÍ®ÉÆ©~@Qü+îgÆUê~“—/_¾ó¤I“>ï ó!ügÙvr$²êÑeþÐĪ*SÙÓfGP[[+=´âAfèܧy¢ÓïMû_Gïáów»hâÖú÷_õ€jàé§Ã;1—Þª—z…d§Bg Ãm{+^Äc‡³lYÝ@> èËZ2s«mì®®~ÇiÎŒ«Æa>zêËp+lÃ)}JšÐø»“Ý•~ ³ Ô5 6çMÞp7³;€£\à"z„ÇÁ¼€‰n%Â%ªÒÃvm‰’fÕ€Ði@h†ñ¢Ë6å5åå%ÇÐhO¥äÍÊ‘7Æ "¦³]5¬÷r!ÂÇo'¨`šfÕX_œLvœÐ võ &Mšôy*%� tt݇ž&2F95ÔÜQŒYq�ŽË¤”¿Û,y®€„Ï'ÁýÈ3ƒè,€ÕÅî‰ÒËtU»„ ëÓµè‹xˆÇ%�•ÒX‰ìœ�MD|lUU•ƒÄ-0kÁêýqz Ù ‚׿OïP`¦•~Å2J6æiD@X1ÈîqgÎã[4ÞãXÿ�±ë×�¼Éÿî ßhν×)šš œ‡Þ×ÿ¦»ø~bè‡ÊFkDì$Qú-„YÉaÕÕÕ¯3ÓDt¯’bÆZ[Û�@ ]cÙ'�œd#æ@Ó¬þ³Óhjݸ ú© ¦}FØ?l¥Rò<‰ì à\Í�þVZZ~•‹–žâ±Ã¨¯¯IÄÏ´§îšÎc1%¬v¬�8ë�•{AØË°ƒŠEô¸êz8.øÈLë‰ðŠiš¸oÙtú€@逨ÒKÛܱpƒêêòåËwð“Ìë©OÕÄbõÕ€VŠG"™´•¯ˆt?4úDâBÕõ@ êEf´dZÏÌ#"‘Èîî[Ö{…BÍRâpf(íºÈj)122Ÿo‚–e�%Ù¤J½ÇŒSá ù•|sü!Lüw¬ûöÖÒé ϯƒF_'ffÛÆ¬ÊÊJå;µ/ã9 ;„h42Á0èi»è®Ùù…BË�æÌ¸÷¥Á)C<Æ+–öÙxRu½´´ôHhI²R7¦_]‰€áó�³ñœêz*ÕQ �>#Röµ„ÚÒž‹�ŠsS%›Î�Û Íz=<2Ñ2V)Ö@„ŒQ�Ά{"ä¾]½ Ó4ÿ·¼¼ß"ú#7zB¼Â,OX³¦y\>¦ûÄbKK¡Ÿ™Ð&%jœê²ðÚ„��ü8\jðº ó‹‡>ÿ¿ª�x¼þ§º…çDb~UUÕóîšVxˆG�‹ÕO(ŠìzJt�©Á`µ£|ã¬Gvþä3`ü¸ëVæÌkwž6æmÕ€a°V÷s"qפíШ!‡> ¶ßmc<´ùf�! ‡ÓR¡Ûˆ¬Á-cò˲&B¯ç‚�JÉ?)G^ŸTÎ^ôÃú¥êªa$�QªBêóTVVn B¿ľþ ð¿²ÜâKf<,%Ž Í¡Põ£ÝÓ?ªkÔ××ïqh:óÌÌÌòTÓ4_QÏ J¥îð÷¬ü/ýäS¦L…Ãaƒ™nÐÜç“¢¢¶K\´« ð�¥3÷“ÂD™Oá·¢CJL ªµ³Ï}è¥Høâ²’Puâ°êrmm­�2sý€Õ¯¹lÕ¶dt"˜¥º§ y)X;Z9·²2¥!­Âouoj_~a¸TsêãNb)£íl0¾ë¢Y1NRu¤˜4éØ�˜¡Ì›ßfù³†††lÞM0ü84/Y³æ•!Dr€K<` €w| à¬%ÂcÌ|)9xð‡ƒC!ó$Ó4ŸÙ�æ§eÅŠ%»-C§¸‡Dte(T­|Ÿ@ªeì%̘âŠ�ÛÀŒ0ì9eƒÚÒÒÒÓ •î ¸üÈ#k¾rϲÂÂû˜ðè1¢ÑÈ…]‡ìT©:˜åq¦Ysš0k^sŠSõFtÙÈ®"}Êô«#FŒ!b µ ²�c{Û,P~Än ³:�G2|^úŽ‚•éW–eí!ö˸š‘·(ncYÖX!pD¦y�‚b»Æz€æe\Rz�ëÆ{§ZÆŒõ CãöCèðt‹‰¨¼½ý› ¼¦l[±9z±jóÿõzâñø)ýq"-%º-< šW: ¦Ö�«dB÷u>+*N*{ÚX–UF„+ô6â×Z[7)å{=:ñ" ÝN86b1ë"ñg¢¬z¸¶K‰©¡PuÔiÂñá–"·ÿàñ.˜ÚU^»gú¨·TD¬T�Ù~žìæú)' ïÐbáÔÿCÖRaƳ®”Ç­Ú!hi(Z§K–”Ͱ««†,éDÕu"Ãñ™ý­õì¥a2áp¸³!ÂÁY,[ÛÚÚîXtÞþú„=¹Sî¹›ÞEtö}ÑA)Pž§+»+%]�où†ç€xt+–e••——þÀ9Ù¬cÆW€ ˜¦éù¨mhð jûü1�®ÚéQ]¬­­¦j¬ÿðõÀG"ë8 Ê4-É^ÔtÇ@_}Uö‘CjžÐq@l"uõB#�V ³‡KFR)VG?6L(!ðEnÚUˆ�€2­4 þ€NÇí|88òè¢Ñè ²²ÒÈîßøƒTJSSS£®AÜ0¡ÄgØOì†�ÛAxÏ_Ôožjhùòå; !t¥ƒŸ4M³Á=à Ïñè6V¬X²«xÀälÖ1ãSfü̹éPgäãÃ÷ý�zJ=O¨.�yðXhå¾r} Ðý]R™)£"¥T;ÌÞ3c‡À+wÓ =ßPJOÇb±Ø+Ób"êéWñx݈ô%£Í#ü`ò¢š¡ŽÀI)ŸÖYnÛv·}Pzô<‘Hä@Û.z ƒ²XÖÆlW9¥C@jÝø‹Át’ &:±¾hXÓ£ª˲ö`f­,"º=8æ]wM+L<ÄÃuâñÈ@®"ÊZï­dÒwôÑÕJ[8yñŠr·G ™bÑc0Ò¨_i9J_—•õwìoâ2ˆP÷”ÔíB)?ÍœÒQ¿‚msŸp@˜}çB£ €&'mþdiÉiÀŽë#ÔÛ R7We/i®Ïö�Ê#O±,ëŸO¬„ơȘ‘$âšPh²c�"{Ýø ‡—`¢+VÊ A—CC¾ž_mÚ”¸ÖmÛ Ïñp•X¬þ—RÒS¾“ÝJn&2Žpjg>Ü4¨D–= hIŽö$lÆcª�ŠŠŠñšEk‘žë”š9ŠáX„.=dðÖ=§ŒVž¨ ¡Õÿ£@“»&åÑht€Su楉~€¼ô‰,`à§¿�Ó×)ùœ¹§‘8´{,óè)âñxq,fÝLÄOÈ&¥N2ã´tûÉ7Ç"‰…ƒ2£+Þ(Ö¨T°´,뇟¦·_?eÊ”ÿ¸iZ!ã9 nA±˜5—fÙãž!òý,|æ4aÎâvµSxŽ€<|YQã½'�Rö  :;0ËI¿ê¼Wæ8(ŒØl÷�“äñÿ�òå\[[+˜‘Ñ!‹¦iºÑe9¯a¶gè—y^uúàI—Nc×�+l&‡p€j€ˆ^̼܋€ôfâñúÙí—œ›¥Ê%˜ùW¦i>ä4¾éÍ1{³d ×]�A—;E?ˆ0zŠ[ûýÅ7»kYaã9 ]¦¡¡¡$µ˜›íˆ‹Z[ÛC�@ÀAö˜õ`ãnRÊgÁÚÍz/P]�ÇãÅDÈXÿÁŒ¯„ð÷Tú•V ÀÊ®ÏKÁêqˆÕ}FŽ2u^ŽRJ�fp½à ÝÈÅNÍ¥€×÷£k슖 ßS !cO"/õ-ßhhhðE£õ§3Ûo¸]è>ÎŒ·1&]sa¼,N—>Î@U®÷É’U¾ý›žR Äb‘ñ̘¨³‰”˜;wî\e»Gz¼,m|­­oBœ•íZf¼*„1Ù4ieg.j:�7¢8Ç ù;&8Ót­=˜z:ý @æN¹L¯üjæÂ¦$ ®ñp"zþþSÇ*•áˆDHc )„?æ²Yy…eY?BëƒÅ&JݪH¬;b(2F+=Ò“âäP Šv¼`lºµÌì9 yB86ÊËKNèr"ráß…²m>³ºÚT¦*š�Ú)Y²©„q]¿ŸÄø�ó¨øƒæ6kMÓ¬sÅ >HÞäyäO?Þ©½}£E„¬�€"mmíGÎÎ4kѪëˆq3zÇï%û$=¨ˆD"áp�-Þ …BÍn–ñ®lgt@˜¡LÁÚìpeŒ xt ~Bu=‰ôgfe÷émx)�´u!@„s¡õ¼àˆSwbòBè�x¤E²P¦Ë2³FWhú~mmmoxî2�FjÊËKßh!º(ÈÀÌ­Ì<#¬šV]]íì|´ŒÞ9Y²i9Ðs΀g|û76¨b±ÈÑÈà0o�™.‡ŽÊ‚‡/â‘‘x¼îÌ%C³]KD7¼üòÚKÒ…(/¯.�Õf?ÄÀ”.Ú³2�̽v˜¹ Ó¯–/_¾3ÀÓõŠÏ…ZŸÝáƒA~-±�ô¹TfzG#“¾¸¢¢bOÿpÛ.�ÌD£ÑqD|‘p«'KÔ0ìsŽ>ú˜ é&µ¯;b/+ìçÒ}µ Ð\Ç!ÐUšÛ¬ …B=&Ÿ_ˆxˆGZ:L¾'�e=3’Ì8Û4Cóçl‘3î[½³á³—BóÄ!_ ¦›T×ÃápiyyéI[ØÌ´Øe³´BdŒ`Q‰eYeÊvŒ{çÅÝ «ï;ṁêQšª³‘¬wÓ¦|#™ì˜%„Б] …U *:‹ÀÙ6NõPÀ„ݕיÿ®ã$ !w…ç€ô(–eí'®!Âd—¶ü'³¼(ªgš˜xcô~>a,ð?.Ý[ þâ¾r•j,�L!:‚[¢]Às@<‰Åê§ÑÝŠ²\ú3Ž7M3­ºÓŒÅ+÷1ü"Æ�s·r@x{· c–©†JKKk ¡ÂŒ¦iî�—-Á¬åA ‚J²Wà?^й{„'U×W¬XQàèLë™ñn(4ù × ËÂápQyyé™:s™¥ò°Í#ʨ¤tŽ«†õe˜•ˆaŸZ5º¹ª+ydI$éïó‰Ë‰p\¨çcƧ_[^ÞÿîÊÊÊM™æ§ZÆMÂx@Æ>Y.³)eø.V}øvÖ¾”ÖêmÃËC!Sy¨á¡�ç€xlGmm­9²âj€.Éaù;R¢Ú4Í·ÒMš¹à…‘‚„`×ܬÜq°äæÎU¿Q…ÀZ{0îu×*}˜å瀑qžöÎ>Ø~ü»Ìòøl‚ñ˜j •êT–i"(›c åå%?‡žD÷?ÊË(Éâ²SÎs¥½^„C„ˆ¾P �n7Ós@z€X¬þ—>Ÿ¸À¹µòø_2ó mm›né”\ΉT˘K¸3Í)óKÈe˜øÆ’ýžÛ +++>ÀðŒ{03{Ñð�o±bÅŠòC­XÌŒc²]K„ç7mJ7eÊ”´R­³5GD dü�ÊC>ëWîs,>÷ùDÆT2f|´ÛnZ‡”ÆçB£Ü“Hì `ûSt¦�¼H÷ÁÏÜuò¨í?€˜ªWó(•ì…3�¯óñÄÌ·WVV¦¶!û+÷-ëË�R†7|8;D- IDAT‹Y)dþÞð�n¤³q0Ý Ð„®îÅÌ­Dt3ý92uTÑööØÝý©±‹ü¬«÷Ï>ôÃ�j̲¬2!„VôƒuÁ`õZw­ë›xˆÇ‰Çã{Ji/%ÂÁÙ®%Â7¶ÏI× ´Séªé×ÌôGô¥«íaÜycͨvÕ�ß/ÎÓ9é‚ìÈæpíííÿÒéN,%Q]'!ßÓLáòȆX¤º‡û•••5Ú¼ V÷¸ºZOÑY—¦õŒú¦¸xÓ|Õ@bݘcˆðC—MëÓ0Ø©‡|‰Œu„^¤;ˆÇãû÷BÐ9èzºU€yDÆ5Á`0cƒÉNˆ’ëÇNóƒnÀìíÅŒß`øsÊ(�¸zUÉ,œ Ø=²Äs@<õõõ#… :"µ’I$€KóÏé&�º ¡d&ùç3 S �¯tø�º[5‰Dû|â„L033Ó}OMMM{,f}@yb¹!Œ½U×¥Í'á9 ÝÄFYRÙ|°´´ôX"è]?�–†$âSõæÑýGYó•ÃØ…îZåA@ºbþ/�á㓈zº à‰Å¬˜ñg"ìÖ•t+f$…à¶MWgS»Øñæ?rÌÝtdûB³x“²ûŠKvüëmÄ�„Bæ:7MëËxˆ¢ÑH�aˆJ³\ºàiÁ`•òƒi ³lÜÍO¾:€ÍÙȼ€ß1½Ryêãó‰9Ðê|.ž CJùÞž„ˆÒ; Ì?½‡íÝÞ§ßQSépJG'éùvÁ¦_…Ãá~åå¥ÇiLµS)©l<˜|c\F»lšGú÷‡Fï éE@\béÒ¥{ùýÆ�B]¬ó°zÀU�€©ÿÞZwøà$|— ¢Ye+bã6L¶<`eÝf*U4àþû$ˆì+Ü5­oã9 }˜ÚÚZ1bDÅ]†ìqý“ƒÁàké&ÍXØT!@KI/¼™ÏH)ìU %ÏÑùJÉ·¹nYÑ€35K¢º8ï¤qÏ\ØÔ†ÞYÓ׆2ý*�ï dn>ÈŒ ¡Ðä—Ý·,?(++>@¿Lóˆ°¤ªªê=å àÙ^ßÁn¡ ¶OD%ÂW™ÒS¥$�èžGzȲ¬Y~¿q-€]Ü+ÆL¿ …Bú'þoö�„ô_@ä?§=ÓþV­V E£Ñ¡D *»¶7á’@ êYí%-£wNHã\Eçc§®ÝßEí6ño� _ˆøè}¹iSâ.Zæ�ÞZìÑ%"‘Ⱦ†!Vw:Yóxkkû„tÎ4{QÓ%zà|°™}ʇO86˜¡•OÎŒ[Óu„ïYøýL3ˆ°ëæ¾Û�;<�¬à`šç$ï Ð4�-ˆ„R¡­°,k@+uê½—_~¥A5�LÑÉtÒ-ŸxYJ23 !þ„®@šÖ «Kg¶Ù÷3ð‹.šš7hñÝÓG)ûš”––žH”¹‘"3î÷/tߺÜ`Hã}ßÑÑ1ÀúíÖ-ò!”S(tƒîW Ô××�4 ÊmbÆ‹¡Pðoî›–ÁGZQ EŽŽ>aVáÆ‡òa+ f/ç­;ˆF£ƒˆø."q|¶±ÜÃ,.…B_„BU™W¼=¶*Eg2ŒßPÏ7Ôå]_¹ïzÕÀæF¦7èmÃï÷ë7@YOæÑ5<¤�°¹¹à倸YF¾˜y�„N7oÖƒ�»±Muôòbóo±)•¢+T >"h5$"¢y'NluÕ².`ö)3ÿ†Cå€0¿ªu¨é¡áñ»¦�þT5db–^Vlô£:*ÓŒÎ&aÆÕX²eÜa`àºYÿOëEÏ`smH¦Õžk˜ÑèÒÑDÆ#öÊ}z�È>'¨~Ukú† %©�ö9Lt)ò¼o‹`œ�!Ï)»²———žèÉp3óå:ÝÝ=²ÇKÁêÄãñïŽY0Ùÿ›ÂL? Í´ÎÇìû›~›^,0ç¾éÞÓG+Ó•Z[¿9…?È´3’Râ÷­ËfÿfdìEB$T^‡/­ø€GvÄ]ªëuuuÖ‰&&‰”²{z�@2: Døk0tJ/Ì(“íÑU¾È¹¿‘ç€hB–e]Ï!G烟|Z0§ç|%ZÆÕ$ÛR-L|òÜù  ÞØ¿QÙì7‹}Àeš[­Y»öÕ´ß>¹ã9 N4ºt4sª/ooâpÓ4• [˜¹°q*Xàr22ùŒ;:þ¤‡ÃE›ÕÃ2BD‹MÓtèl½cDP¦•m 3¤º¾ûû£þ@)ë‘%„¿Þ}òhåßXQ‘ïdhÕQq´�s”£Ñè~ÐPÒ#+”áã ft%MÅC‡ÒM¯s©ÔÕÕ ŒÅ¬'…ÀõD95”Dt{2™Ú/¬Z�¨SêÍqG&×�i&Æã`ì“Ã={š[ǺL"y54˜™¥ÄùùS·Yxx)X… ÅbõçƵȡû)ê’IyJuµù�ã€f-lºŒ@W¢u-‰{ÏÌ#•�ÌJKKO#R«DmMgôC^íºmîðW cJÊOTçÎ…œµ�ßh”ûfõ-X²ctŒ3õ2ÝXÙñ»P`æu~¶ÍO©®§†}|$eh¼éáÃÖ;8 ™;™½"ôtX–µ_Q‘/`ßÜvà7™åŒ`pò :³ëÆŸ ˜Ø›^ï þSñÐçÿW5�×ÎL§èìCD…Bé_=º†)@êêêÆãÖÝ�í)I§\"jsjuuµ£óqîmñ♋š2pzÓÓIÆK»¿7NY\WW7�WèlCD8ö#ØÁ0Ë¿jLÛ#�;H / «ë|үܧ¬Ý¨¯¯?‚HKêøïkÖ¼ª>ù/ôŠðy“aMÊ1â÷­òøÛ©Ù�nšSHX–5Q¼€œf$‰è�D¾CB! çãµ “-ãn!âfOÌÅÞo(úZ^«©­­Ìt+ô¾{7J‰KݵÍc[¼H�‹EFùãÜB¥ž V=™nÒ¬wCÿþKÀ8,G3ó�IÌr’D-.öÏeæ]5öé�’ÿè²m.Â:¤LüÀÓÛ �|Åˬè ºåÆšQíª1Ÿ�ÎÒéŒÀÌó =M€™‡gšCDoåG,1&yÇëÝLúš2�¦xüµk¶–9[q#rû^{  i�@¨9óT¢d˸SàçkÁœÃ½v8,į0ªIù<­¨¨8À­}˜¯5ͪ¼J›.D¼HaY‘³Ñää|ü°Ç„BÕi��9‹V ›^¬ó®½û´±Ê�óh4º?3Ÿ¥µã^Ó4•äù³¡ÁÊ:’ü¼›öôA¾NrRY|nYÖ™1Ec�¿?õ€ËvåÌÈè€0o¯Ö‰–±ÃØÓ}«<¾Á1bÎý!˜¥ãú> ÅãÑ›„·"K烙™w´¶¶W„B™��d˘ƒ’ëÇ6‚ù w: !âSƒÁªeg¶Lè—”É?Bˆ3èжOy¼fXB5�Fj ù1#„¸5ß”¯Љ‚Œ¯­­U?+$7¸jMߡÖ¤ln‰Dvg¦“õ¶‘÷¸iT>‡Ë¡áôáå€Ä�ܶÉC‰2…ª³_i¼7¼,‡Ã¥mmŸDnÎGƒa$ «3:©–±ã’œzDç€{µó"\ãTx‹Å"ÂlÍ­–ƒUK]4Í# žÒ‹‰Åê§ �—ì—Ãò�¥ÄQ¦Y} ÒHñ�º aàŒE�3®E�ÿ¾0á‚{¦�C5fYÖ.DâÍ­>L&í|U¾Ú–UsUTT(Ó°ôŒËöô  î;ṁª!ŸOœ Xc“ׂÁê•.[–w `ô×™'%)£ID4ÄM{<QF@:::4ê?)©ÏG@"‘HÿòòÒ83Ë¥ÀÕ­­íGMštìGig¾sø€äúq÷0ÓóÐlÆ—ç¼é+꟦ð\Þ½èNç»kšG:¼¬^H86úõ+»še¯@E„ç…Hœ ¦P�yÿª¾%` ÍÝÚ^ãóN{§Ó |@Z2žÌò7éÄò "n`½BòJ¯l{Ñ–ôŒÏðÊ{³d“�ÕÒÌuuu‹Š|Z§uÌ|�»få'Ì>­XÃPŸ K&ƒ<…×n‡II$;†Ö3¦OG@,Ë*óùD=€ñÙ¬cÆWBð �@U<ÓÜÔúñ“þy(œž]’3±oL)>1bÄÁ³ˆ0Fs¯›‚Áàß\´Í#}¢]ˆX–µKyyé2fþ5‘^‡€-03Ñ5¥¥ý2ž’Ì^°êXÛà5@Ÿp>Öµ‹¶3œ£ÑÈi郫B¡ê‡Ü3­{)-í¿'—[c8Buý¾ÓÆ|ÂÛ®VÐÐ]wœ:þŸª¿ß8 @Æf¼ÛÖÖvÝ´<$™$-�ÊXAR©Šãá.Äj‚Hïß�¹ï¦`ÅãñbÃÀ“ÈÞùx Ñ��Õ£K“-ãîdð2Žó0æû†5*¥·-ËÚƒH\£¹Ó­­í½%k¡`ð�^„eYûa5€Ÿå°üßBÀ B—UVV:5‹úo½‡¡ñ!T|l§„¹hÚÄVÕ`4ý>‘¸Is/[y.4ºËæ •••)f(à[ÃŒqápØ!ŒM·í*`6 ¡'‡Ã¥�£³ 3n¨©©±Ý5-?1 ©õž’Ò§ü»cˆ�îZä¡„ð™ò2É�u–†Ñ'S°š›çù™åcÌȪçžO$’‡‡B¡7ÓÍK´Œ–ÜÉx Œ9]³4¿ àCGÉ%NãBàvhÉ?Ìòâššï9ÑÃxH/!¯ÿ©X¥§³-ôB2iWd:%9÷¡—ÌX°jI_¨÷ØL;޹÷ôÑï«;‹'±šŽæÕ¯ºjaÀ,uät–––ŽS®—Ô'Nâ]�qÃ]ÓF+U«ÊËKÏ&‚N™�ûõë·À]Ãò!ÔµÛÂÌ•×Iö1ˆ^�?V^'±›ÎzÃ0þí®E½úøãݸ:ËunÜØ>iÊ”)ÿI7)¹~ÜÉÄü2tÁÆ|„Ið T<¥tZc±ú©&ëlD„çC¡êÇ\µÎC‹¾ð‘Ùë‰Å¬3¤¤8€AÙ¬ÛÜÕüúÁƒ?˜0yòdeÊÇμÕ�;RɉXë�¶h%pÕ=ÓÆ¾ä4¡½}ã­�ÖÜߺd[�ÂLÏéÌǨ®Ï›>z €w]5ª0ùw±ß¯Ô—¯««ÈÌŽ§yÛpk_’‰ÂþBsªòùHiŸ}îÀ’>Q^g™ÑaæMÿÇÞ™‡GY]ü{î;3$Ü�¶j[¬p©�ª$A¨ ÌÌ›´Q+ XÔºÔÝZ-M­Ö}©à¾/£“wf©ˆ…¨UˆûÒZAlëJ2Ë=¿?ûSx'sgòN2™ÜÏóøGçÜå4!ó¾çÞs¾g„ ª¿ç¢!‹\I„²œvÛš5M3jkkmÕtš7�y@qÊææÃVDíLߥö ƒ6Ä¥¤³Ñ‡²Š ]„^ÀÔÕÕ‰Q£*þ à¢ìª=_1ÓÉ�€9?ÓÀÓXQÃ= dnUЗ,Sþ¹'�Y•nD4j�(K÷If9còäÉJ'µ…Æ–-[^.++ùŒˆ2¥JLp쿬Ÿp±ãÎWþeê!¶yî�ëbSU˜ñå€m¶Í ‹•]vù÷ç›6 É8.]ªÞÒoùGÀ>ÂÜq–"Úˆ~ö‰ÔŸBDÙZÕùýf�ߟ^$«ýõê ᮸¼{,︓e¥3`\Ë ¥[7f\Ö9çš&ô H� …<£F�|@Ú?´t0£Yyˆiv|ÔÕAÌz`åULXp? >ð�$9f^—ÁGx"€U$¢›� Ò-B!R[[›"õ CP__?ÒÎ �§v«ØX�öRÛÀ!pŽÊ"D¸ëÈ#kûU®|EÅÌ…ülaÛïÃ5 Ù„™RM‘l…M˜9sôêZ:¶ÈˆFÃG”VuѾÀï7뺑\?¦R¼ XƒIħà€E¶5›–e!%Ò Ê|f¼åõ¼ÚY÷4Ù �$‹ ðzKŸÎ­¹ …Z[Û�81Ø¥2Ñ9�¾´ýÇ{­|Ä—!S‹Ú¢�– !½{ZõkéFÔ××ÄPï û .wÆ¿ÞD.Pår Û4¬»§W5A§a¥ƒYð¯çάHØ].ã÷ÊÖùšÈPD(6>PSaûéÐÕ_xÓQo4Û�Œ'mo@€Ì§ÑDlÛ§‰D"?b¦Ç‰àV�ÓÑ0¸¦Ë¿ýĺªSü TGÖ'aðŸ\å+íl‘Hd'!ø~uÐEP9«?¥²":)0,Ë*R ‘}#¢$³¼ÈïŸIÍaæƒ+‡·'kûQ½GÀUCöJ‘®b±…å†AÏAQ9@;�:ÉçóÙj�÷%ZZ¶,ffÛS¥oÃÌǧëŠN„»�÷¬ <>ï¤jÛBÿçž ï ð¯T–aæ}>Ÿ­ÒPñCÛô Ùfáà´FFÆ šn/}ûû¶Eè@æfûÛ“bò¬2"~F!Ýõ0ãO� ƒÓ@os=ˆîàqÀÍB¥ÁÓ<ä�éŒBð�}_e!"qwhâZè褀…B…€•­3¾d Þˆ y´§?°¢†:º_CTÞ—L?Ÿ;½êòÙ]È[–õ3fc€ï©.,¥¼ÈïŸdÛ9½¯Q[[ÛÐs CXQQ1ÎÎ \˜ ÕYÏú<›Œ´µ1ÌâJ¨ÕâmjmÝb[ÀÞ`–ƒ¢Ñè^v2„–ŠÎ/ÿ@íSid¡I%¿_  mq ú º%0ŸÖ:ÖH4WÝMÌvß»‚f“[Ð éþ�E"á™qœÊBÌØ�'.uÖ=M.è¤@X²$´ƒ×[ö::NgÃB¤*ýþàó] ê‡õ 7¢½tÿ»gTÚ^Ù~C,VïKì’ÅúsM3x{·<,0ˆ�Q° sÜÉvŸßyBÕç´œá·`PÝ]Ó³•��Å•Rò1*ëH)¯êß:õ²Ies*`÷¹kØòFï8ê’æpšôËp8¼”kÊ¢@,+|@SUÇáé5kÖ¦,Bljò�÷�qŠ#.’XNðå¶ÿF:ÄmY,wv_Œ)6tR„B¡�ñxésYH¾~Ë.Wâ0ŸoRsWƒú]½cXVÌ�^uáÜ™]žÈ[–u>3… Ìb‡¿´A©h¸/‘LÊz•4,"LY°`�}Ϫò‡Åã¥/Ê6Øæm744¸˜Åí*ùÊÞokkŸç°w} ·»ôï/ÒÑöŸ3s¿þæ"û!Ä�Tæ3‹¢@¢ÑèABˆë³˜òâæÍmÓgÏžm/žÐ<“¾1`š#0 \í±r±�­#X>H¤¬àùl |ÖA÷4Ý@ ½L(òx½eÏ8$»™ôDYÙÀ#Æ�Ÿ’¶¦N¿¿±¼Õ{|@DÇÏ�Q5vîŒ1]¦F544”D£Ö}BਜෙéØNež¢" ~M¤ÔT°Ôå'ÚæÍý*iÆúíLtÊSiº•oÞüÕ¯¡žŠñû.5ÿûãÇ�oaÆêLãˆ0¶¾¾þ‡v6WIr^ºnÝšîA’ßOcÚOq ‘�>ÉâÅ‹½€| ÀÅ)ï“;ÒbmhéŽË�ç3cŠcN(Ìõ _1;�}Ô¨Š‹ŒQ\î)•¥õ5=€@z‘ºº:áõ–>ð‘YN½ÁïLͤà0ó¡& ± Å_ïño"\:૯‡Í™V™1(‰ kmݼÀŒl6aæÏ¤¤š@ P´ ³˜é~•qBˆsÒ£ƒ¯sÖ«>óó¦W®·3-ZôìBˆ.å4¿µÐ«kÖ4=á¤k}f©"- ƒì_2†®þ rÖ+ H�m ï«0½}àÀ�E€$“‰[¡ˆ1sK2)�N/6A”()»›ˆýºX¨¼íIS¶½ŠÅ•ÌPúíP½âSLÓü�³.jºƒ@z‘Ÿýl䵎Íf]é÷›£‹bóº:ˆÓ\YGŒp‘×{lóÅh/Ý{δªkÿrvf5ªhÔ:•ˆ×8 ˽Z™é¦iuy XðÛ C‡VTTØÞªÍ™V½��.k’ŠVîý$mÁx*å¾ÊJk|YÚ4Œ~‡˜Ï™:Úu0+]Š û?®;¼ä¬_6„m37"Ê€0ã½±]„ôe,Ëš¢ªrD˜ ÓÊÄÇ›«®xº3Þ4_3ñÑ8h©m­Æ¢EÏî!¥xJUÊXq‡ÏW£•ð €ôÑhý f¾ ›9Ì|¹ÏH{ §Ü·r»�{¯xšÁ¿GÑÖ{ЇLø ÚK4wFõõ™ê<`áÂ…?ˆF- À<¨õ\ø6_H‰‰¦i6äâmƒz@e ÎO¿Š¸J9ûEÇf‘¢éR¯,Ë: ÕÔ‰ˆßTQ&똦ùV( ݾ³³ü¶Œ]š”)ž­Öæ$­†-·½aÎ|òOTœ=Zb±ØnD°m>š†›ýþšÇÓÍU³ˆñ;\+t¤¦zÊWØÞ 75Ís§Rž'‰”»�7oÞÜz‰³.jœ@ ½@,®Hù‹‰™YJ\ÔtÙµsÖÃ+÷tü"£8sC hbæ_~^¶aè¼iU·ªuuu"©Ÿév¯ÈåÚú)1Î4M•Ÿ¢ÀåJÜÇÌ4¡2«ÿ¹�mތѯá>ç½+ltÊ�¿ª´m‹Åv‚U‹ôÛ˜é\]+”RœûÜs ö¶3 8`Å[Ì8º;ºS¬K“&CÛv§ÿÎ ¢¢ @€ÔDjM™±zР i¥a“oT ÐÎùV¸ó%†7¦M·Ü´iÈ ª—‹ !OJ[O£éUtÒÃÄb±Ý˜Å“P,HëÈ]¤sLÓì²À¬–ïÉ+ wÂÏ"Bˆ GÍ™^5rÞŒê'Ò�.oM,Vè¨Q«ˆhÔ› ~›w“I9Æ4Í¿ç0·ÏÒ!l@�¨Œe¦«�æ¦�H\ЗŽ:WÐÐÍó¦W>•Î*eêN€vSY‰™¯ é {û-D®Ç›Ö•Ji¤=äñŒhœ¢ß Cß$�[Á˲~@DÞLÓ™¥mÀÞ—‰DÂÇ3ãŠÃ¿�’§¦6i7˜%g#–ÒGa¾Í5bÅ éÌ‘HøDg«/dz}¾à+Žø¦q€ô uuu‚9ù€Œ�a¿�ˆ.õûÍ.O>f=¸j_;5ÿi‚eYieJÝåËoC‡EQÖô¶5 BH•t¤RÅ•‚‰DvÄ-ê3øôššš4Eø$H>`�#Î0 »ßr^:»eY‰9Y,Ù°víËÙHkz€ô ’q4!‹)×ûýf—@³Z9�š=õÚA#øyÙÆ}æM¯üó}'W+Ëf.^<÷X,r³Ûm¼ à$Å Û@D·—• ôM˜0á³\æ>ߤf"R*Ú#ŸššæÙù°úVºlYldƒ�›;³Âö3‰ ¶ý@¶¦3ÝrV&…»þ ‘q'3º”ÿÿ±¸5[ðãtv÷ðÆ‡ˆP£åys‡Ûž03“Òm¼Ëå*ª"üY5õŠ÷ûý5ioM“ëª/ã(ç¼+XVº¼Æqé:�ÏŸ?!ð Ôë77â-àQØè¤‡ˆF£©JÆ3óûÍ´9¡0óÁÆßƒù~@M ¢P!`51��ö-ƒæN«:vÎŒªzÕ4+°,kÏhÔº.™t¿ËÌçB]o}k63Ë“}¾À9Ūʒ DòÏjãP¾qã`Û“«Ù³!âd_;ê\Á@_ ’�•¢‡² IDAT¹'VÛ¦544”ñcP|p‰9ýDì g|>ßWÿQe,v`6B¡P¨4ÝWyãs ƒb@«ädOÜõ¥\kg B…Âü ¿Ïâ Y8àS‡ÿÓínK+ä‘\?¦’‰ûà òknJ±÷RÛC—†††�ǽ€RSKqæÔ±~¿ÿç\Ôä€ô]�彪’qþÖÚÚvºÈOžõÀÊ«T‡¾«tÕ F±üÉœéU‡Í™Q9gîÌ#³ªˆD"Ѩõ(Þp!²ëfþ˜ñŠrT |0×5Š Ÿ/¸€¥2–ˆ®ˆF£{ÙÙæNýƒTÊ}‰6B*x×´1isŒ[[[î‚rÃAþG2™êòÐAÓ�×»Ý<À¾ö`[è ¯·ìÞt}k lß<ÃýL4 BH»ì+µ)¯â°U¶¾Ì4Ra~ZÉÙ¾FSÓ<7‘qÞ«˜™™S§yd­ý3¯yôÎ ~ €Ëa7 �fwJ…òU¶Ùuuu¢µµåA"Tª.ÈÌç“t3Ü>€@z€––¯/!ÂO‡oH&åÑ]©6Ìz`åU ¾Ì!÷z’�ü‚ªçN¯>wFÕæÌ“U_�ºº:aYVM,f-íìçñË,;;$€›…0FOœ,ªT'�W@A-ˆˆ¼D2­ÂSgq¶ªT_ ÁDÇÌ™>fyº‘HýÙªšýõ6<3 éM‘³Œ;6)%Nƒ²Ô3?jÔÈ´Å­ßà)_¾ÐÝË~J×úý¦ò÷gâõê ˜ÆŒZ‚Zß�¬!ü Xò“ž�®Ø¶©(Dñæêcˆù&˜ÐŽõ”7†¶þܲ¬#„PiFÊSüþš…ùð­'é|ίƒZªåÇDÆðt©g‰uÕç€p«³ï%“©ÃK\õqº‘Hýoˆ¨KõÏoÃŒWZ[Ûª´änߡد÷zf÷ù«Ö$Ôu|ÌzpÅ õ…—”ÿ0°P0žÞcïä’Ù�õó²_‡,Ëú¹aàT!0À'2Θ‘‚n(-õ^©‹}3C$~Çœš¤&©É7[–µÂ4Ím”mf�›<çÑ—ŽmO%–ƒUÓ’ ŽbürÎôÊ´:õ–eí#„x:‹àãe"£/Þhö:©Ï‚ý SœrI4jm×ÒÒvn­B�™{ÿÆ&Mý&Ñ<ú@b1AUŒBîÊDÿ!ð2&±Œ)µÔ3lÕz «“@fO9žÆkbq£õ .@�<»S‰”íá�j}¤¤¢¸‘Òu뼤Äy¦i|Ä×>ŒÅ®€÷vŠpTWÁ‡eYÓˆp£ê‚Ìü™”ø…>úú$�,YÚ!/ýjµ Ë׬iúy:Õ†Y¬¼¤VxÙK| ð|�xöóÒ Ë³)"ß˲¾ÈiDâWDH«`“¼HJ:ÏîY“Ë _,„¸FelG=�1ÚçóµÛÙuãnnA/ᨓùçT3ç¤Ê´/MÑht0 W@½`r3 Fúýþ·�q±ÿQ__?\¬V �ÿ^dž©ÝQºÛÒ\½§‹iƒ‡4„=˜yâŽà€‰$‘ü’6øˆˆÞLŠÔ›%ÃVþ#×= ±¾r 2wÏ3Íîá�¶JW‘ˆµ„¶MJ¿Å¿ßü~üêQ¢ÑúIÍWî÷›¦½‰Db}U#€ÑNùVxð+îOì*íªóç‚z��d¦š@ °È5=…@òˆeY§ �¹ C[“IyPºž3XqD᜿¢g¥Ä³÷̨|)×ô*…B¥¥¥¥GNbÆ€ãM—Þ‘š¦™öäZ“ž¦¦yîM›†4A1h ÂC>Ÿy2Òü›øõ ƒ“äz^u½à )dàî“Æ¤ÑëÂáðv.—X à`ÕE¥Ä Ó4rÄÃ~L4Z@Ù H| %¦›¦¹"/Nå“G—&v0®ãlôÞsá&÷ðÆmnäC¡�Çë-ý nˆð¤Ïgþ2oÞõ�ÿ_ת0¼Uˆäˆ‰'hgL4�9ÌÅT'·5�î-%5¨x>­ØŒeYGq=•¨.*%Î4M3›þ šA¡ç!P£2NJü>]ð1ëþƃ‰0…|HþÂ(…ƒæN¯:wZåÅwϨ\�KðQWW'"‘Hu4jÝíõ–n3c<œ >>øŒAƒ6ŒÐÁGîTTÌLÉ3›‚Ó"‘ú´¹öwÌûIœ“Õ`¤M9,xÊp£²«à#‹mïr‰²>ܦƒgðûk�±È|+~(–Æb‘ëÃápßê£tت6wy㹂©À½á±´=q.+óŒ„B:3ú^à·^oé¹P >ÀÌW¦ >¶¼Q¹˜¯rÒ·B‚ ÷W© ™‚!°0›àƒˆ®ÓÁGßE߀ä‰Î“‘Ϥ՟f|ØÚÚ¶�]>ò)÷­ÜÎeð+€ÓiHYño/–1ò$ÍýåØÿtwA˲~f8–™�(_WðŸH‰ÚÚÚîÒy¡Î‘MÑo§²Óñ�@p›"Õo8ç¶Ø€øÛÝÆŒÓœóÒ1¾`ÐYó¦W>ÚÕ  ìèñ¸bÉbíåƒm8ª¢b¦móBMNP4j=àÄæ~"%fï±Ç†úÚï¤ý�Ã÷RÎ ÔøÏmî/S»ØIðF"Ö‰pyæERúý“ Xá«k/ž¿{"á~‹;( }Р #ÓýÛŠ¯¯~ŽÐçÅ9ÒÀ÷¸·l9kÓþ]E" �$2"ÃûÒ·é¼A;}G²Z³QÈVŒx½ž}¡ôÇÄ÷¤+†tò÷ êéà#ÆZÄ86øƒêµ³gg–aÍ„eYËÌÇ �uĽy¹Ôyà›‰\�›¦} ‚&w6oný�×[: 'ý�èéa˲¶¤»}úËÙ¾v3g>Ð¸Šˆþ  N¢‰è#•šqÇÉc>êjÜâÅów÷x\@©éÚ7|är%Žík/º}4hÃ)›6 Ù€?˹ƒ…ÀÜM›ö¸Ì²Â7†û¡¾Ò oÀ°eïàÝCG'Ú]óÊTwáÌhH×ÿƒ“2ÏçÏÖ®}u½ßŸqhÁ’J¹®T >$sêŒtï‰õÕÓŠ2ø ¤Àt‘{xãÍ] ‹FÃG �Eð ¡´t`Ú_Mß@߀t�eYûñÑDâ@€‡3wýa30£™ Ì©eÌÆ*Ó4[¿5wªx8ó.ö§@§?°|&±ùïržx-3-'âF´·¯È¶!`:,ËÚOà8ä±`’™Yz>•ÂM¦i>ý¥”Wž{.¼o*Ek³(ú�K‰ÚL)p§Þ»j/Ã%ïpd÷½ÌÂ[�¸bÞŒª§3¥F£ ÷g6aï,vø cý~oô˜è„B!OYYé£D8&×5˜¹…ˆB€|jРOþÚ'‚Ŧ‘e‰ÒÒ(‡ç3:Í=|ù6rÛõõõ?4 z/ãlÂÓ>Ÿyl~|Ë?Ñhô @®�Rº0=è÷N¶5½=n×D2Ù ÆnÎzØëlf¢=åË»”XŽDÂG‰G¡Ö¦ n"rÑW4éÑÈV444¸ZZ¾žN$N85Š/ü¥½=qÛ”)Sþ‰Ô_HD™äôZ[ZÚv°»™õàŠÛü:ßÙÌÀZZÈå­¢mõC'�oqjñH$ò#æÔqBˆc¡Ü:gÚ‰ð˜”ts X—ç½4ß"­ŸÐ}YL‰3Ë�à³™žþÀŠ&ÜŒžM=üWî±Wò¾od£»Â²¬!ð²»±‰3§Ìô È4N … ¯·ìÕF�ø À*«¤Ä ûöaSAñî¡Û'¶¸—‚²ªEÊ–¤ÛíÚ?YºM:®e…ÏBtyâ ô}ñ…hÔzÀX…¡›“I¹_0Ü`gL¬«~„>ˆÙBø€%MöŒXÞe—ûH¤þ"šƒìj>ß$2÷ù|ÿîž“šB@ ߢ³êt/—v33n‚ fÎÔðê}¿ß´-`›õàŠ� é†�ðM 4QÓç%;ýí©Úòx7×ýuuu¢¢¢âà “™pjíôðRÒ½2M³Û5)šÜˆF­œ—Å àr¿ßÌ(ç{l¨Ù³sëgS¸ù•}ÄwÅeê‘ûgdî ÓÐÐàjmÝ<Ào‘…ˆ333M3M³Ëz�£�e…/B\g…-’Ìø> ‡Rò?þ7µ1s ³ø’(%‰ˆ˜±c眕1óŽBˆR"*í°q3J‰h€½{:]oAdzä€ß&2©J5·7�*Øø;ûRd ƒ{†/·MŠF­¿—a‰d{{b�)S¦ü×yïò�eYS„À3*c™ùŠ@ Æ¶¸<ùFõ‘,Uš5ö¹¶”œÖU±9Ð!ëNDîHÓU柉DªzÒ¤I]¦Åjú:ÐÐÐPÒÚºùN3œZ“ …Fdïøýæ¾v†Y®xÀ³Ø2 `@k ¼†%¯E¢ìõ¹3+OˆÅbÛ§R©ñBP�~€zâú¸ ÀÓÌtO hì�ý4è8e.� �®}Z&2f¦ëòmêê 6üpå០Æ$Ûçäìwù€ÀϰÄãsO®~YuR,¶àÇÌ®G�]±yg1>.jnÉÖQM÷‰FÃñ0€]zÛ—n º§¥¥õœÚÚÚŒHñõÕ×pI~\±O¿ŠD";ñ&d¨-%Â2ŸÏ̤$ßy%¯©5¾ä´´l)·AiçJì–|=)�OmŸç._ÑeÛ�Žœ–[>#» ø_D©q>ßäŒé}š¾C¿@¢Ñè`fù,í…í7¯YÓ´£]óÁ3ï_ñ£”Àå|oeÞDDë%°^0¯K1½¶�Wüý¦ÚÃò¦ö‹-,—RŒ'~€Çðäk¯­X#¥|˜Èx4|ÞC{j …B½ÞÒFd�nǯ2‹iÙ¤ÎuÜŠü·Z2EÀ¡ Œ�©Ex @#72‰åsOªüg6žÖÕÕ‰‘#:‹H\ƒ,‹ä;n>ø\Ó ÞžÍ<�³t6ˆœ‡ìƒå‚‚s|>óÌLãâ¯�Þ�„ñF\H¸�øØï¥mn/T{±töcº)¾å�H$ü+"±Mðeï÷ׄ[�ô­if!�ó [Ùåwy§Zà“ŽÊny|+ý:±,ë{Dh̲ˆÔQ¤ÄHÓ4»<…=ãáU»ƒ“ßãµs¢ìù3+òž‡ !ŽG ã ã{ùÞó[| à¢ÔÃ>ߤæÜW“–e}O,…¢þ·hgæ+Ö®}ù&» <Й÷/ÿ~Ò0†BbìL`YÐG©8}d¤lèÎ-`,V(3n(•«o�Râ Ó4ïÎu�³tÖ.ýÀ Þö%GdgM�mߨÿ‡Db}U÷úbBÄSÞhÄE£V ^2)’ÙÿÂ#‹ `N½`O…á+ü~ópØ Y¼=n×D"ù6€�v±§ÙB„k\ží®ÁÐh—·Ùápx¨Ë%ÂÈ:�VÅL¿ @:¯‹—¡÷;1ÏõûÍ,¯#�§£‹3*ñsG1óYægv—¯3‹GZ[[—¤“&Ö&ÝBÀŒÕ̸À4ÍóàZNÄb ~ ¸®�’OÊåï #“Oíl�§) –, í�H”]ÎÌg£çnrƒ™Ojæu9èÝC·O´»Q3üÎÞ„©žòÆÇ¶þ¼óyº™žëý~s§ýê ¢ÑúóºQa¨d¦C�@“�1±®z³v¯g!,c)ÎðŒX–ñ–Ͳ¬ÉBà>àõPŠð?ˆRGêà£xé—Hgîú_Œém_$‰xŒÏW³º'7µ,kWUB @5€ŸÂÙBMÚˆI¥ðT[[[D7 ìÛt/a‚žI$äe½y:jYÖ>†�ß1ãäØ'‰™?¸6.uØ=�ƒ,\¸ð�ë"f>Ùõ èeø¿¿¦K¥©Îæ„JEëYÐâN• ‹¶QMÌ"5é*¿ß¼Âa¿òNǽ«Xïø°ßoÚª¯%ÖWB¸ÇŸµN±‰‰/ð”¯È(¦ÑÔ4Ïýé§ß»ZJy~¶‡8Ìh˜èóùþ•»«šB§_6",++¹…|€‹™ž�D"ãó%% …Œ²²²a@êgDÆÏ®$âò¾áø†8¥RxJJƒ_÷‚š<`šæÇ–e�1dy³Ø©ô —KL‰D¬Dò6¿?¸ü7444¸6oÞ<À!P�Åž ôn‡é$À•’ž"¢º˜¼¸é8-�tgf¼ÈǤ¤gkjj>pÈ=AyiiéaB †'a–�ÄãÉ“&Ožü…kiz˜NIñq†�c˜1X'ÂŒæÖÖ¶3¥¨&ÖWÝÐ '÷ŒcD£µõç±Xl7æÔÇÈp ÉŒæ@Àìí”笱,kW!ðÔž¡·ùýæ¹v†xsu-1úZö3nö´—ÜœIZ÷¢ÑúÌt³b—ø­ %--­G×ÖÖnÎ~®¦¯Ñ�úeU«Œef&¢G¤Äe¦i~¼µ½³(íTf¾&‹®Ð™v} ¹‰Dj~Wz×Ê<#÷R#˜1\1@9€a(Œ¼æ€F)ñ”aÏèÆAý‹P(d Xz-3Îwb=f¼B„(À/¹^ÊößS(2JJJö‚Gâ("L€C²¬Ì¼À%�@ÍíÈÐ=]Ó7è PG²Ú0D%3ªÐ³BÛÐQW$+ýþàÚ.¾8º4±½ñO»:·;ý×½¥uT¬ÝFÐÁ²¬Ó…À�™V`æ?5tΧžAµß3·¤R<4 nÚÆØ4Ò�()]`Ÿ<¸˜>eÐ\%oAùªÏT&„ÃáA.—1·ó`6îmiiûµŠÌ´¦8èWˆeY~!°Í Ž/<3>’il,¶°œÙˆøA·�ü.Ü ÐFf$‰h"Þ�ƒÐ¡Ä‘—FSÝà ",’RFâñT¬¯6šÒ8‡eY' �[ tr]f¼G„÷úà�þ„ùÿ_þ‰àhtœbÿÀANûÐÉëÌ45_铚¡¾¾þ‡Dt ïMD{ø:þm FG I¦ïã8€_CMIé;0ËÙ�@ðÊLãëªNÑ]Ù®Ÿ�;ÜÃϲ3D£ÖrU™B›81ø–Ã~啎T"~“ˆJ†§­oI¬sˆ3i½c5ƒîð” eR¶ú�ÖOè:äô¦˜å¥�@P¥À_SDô«$±šˆðS…¡I)qŒišõªkwöÉXND;wÞÈ;D¨8ºûî+*f:ÞøPÓ·‰ÅüXJ×D¨ìm_¤�×{½¯;6suMÿ`É’Ðñ¸·4™L²aÿ;Éõz½_�;6iYÖ®Dx�¾lÖeÆJ¯wัcÇ&»Ø<“à�לµD—�8Ø]¾ì•­?ŽF£?aN½‘¹ž�_õûkvÔ§ µîpJ¦qÌüÙ€[~|䑵ۦ)½6Á7Zߥmûy [~Œ;Ü#Vt}»¶Ñhô fy[7¾Û¿xªß_£t0¬).úMz,V(©øÓ¬Q>Àç›ÔlYÖ©Dx6ÿú ̼…ˆ™åb"W½ßïwZiESdø|“ß …BcËÊJ.$¢?ÐÛ>ufÄR)y®.4×lMç ¨m®|,®‚èûY.û¾Û�8&cð É;^â|ð�&»àˆx ReL}­öá)n[5«­aæëlƒI£å|\ðÁÀ'Lºø/eû®Ø�ÍÜùóçï2`€û÷Î$Ê­¨žoT˜úö¸ŸÒofÊxŠÑIÚ5/ßê÷×d½‡iš ¢Që)Çf=¹@鬃y Àó€|¾µµ}…–ËÕdKgÑìµõõõ–t]¶'À›ÿ6¨YØÛŽhúdYá‹„B–Ï\fl$þñã§|šilû‡ï#@—åìe:$Ýk÷q‡œ}É4 cü!…H>á¸_yFJ×%DJ¿¯ mmí·ÙZÞ·+ƒ.tÖ³nÂx™‰®÷li}kÙŒÆb±í™Sç à>Àö¹º@„'“I9S«`öoúEÒÐÐPµ @âü´*T ã\ÉAr´‹ëÒf%Çì:}ûgû@/HÉK¤ä%Á`ͶEuMÔÔÔ¬ˆDI$®è Þö)Ìh&â«Ö¬yùÉî(Ôiú .ü�ÛmÜ#„8*Û¹ÌØÈŒ#…[榑e¢¤ô)*µ êÚÜ ãq;“×;à(•Ûf4Lœ8ùCGýÊ3�¿·ij£ùÊt‡r‰DêwèÆ‹º£š$ø�†¯¬²Ë½_¼x±7ßòk!ÄEèžxG\Jy¡ioïÆš"¡/¿$+³yóæ1Bd–ÐcÆü@Àÿª�­õ­ª!îÝé9H쟀ñ9šÇLt—/ÿÛÖã|¾ÉïE£ÖNtÀõ¡ã*�DÜ(Dª±¯=,4}�@`Ò’ººº‘£FUà7òÑ· »¬øÆµk_~zöìÙ2—[QMÿ%­Ÿár7¹È‘âf˜¦i¾£28QRz:„œæi´ÔVVšHLW{�•8êQÐÙ Rårà�Aƒ6ÞggØò渽 ð»– ŒË�á+"Ù–eíit&3Ÿ&„Ø©›~¼™Jñôššàšn®£)úE"MTQÇ$’óÒX„;Y°ç;�ù)4��ò¥ÛèU§R|›aPA �5¯ÑßR)^)¥l´• ÔhòLçmÂc‹ÅÂ•ÌÆ9OAï~/}à‘dRÞ _xh²!�&’sªÉ­Õ+7¶·'�VUŒ¯óG~™ËN™H×Ý|Ñ¢E;KÉ“šÌ}Å,úT]d4 °RÊ6³¼2�ðŠ‘Jý½[ïö)@—»›߇ڧºì³5‘ÈÂÑDÆ9Bàhfîî÷±pkKKÛå:}[ómúEð8…A¯YóÊ_ýþm%¬ãÍUÇ0z«�÷JrêLpÝÖãkjjÖD£Ö;Ȭù�ð€ZäዪC7o´–Y®!â¿ üÉßµR•¦Ððù‚+¬ ‡ÃC„ÀÑBˆ)Æ=Ò5ø¿K‰ðÀ�jU+MŽP$>™H\Ëœkš ?Jä:uÊ”% ÔdsÕo d+ý꯹†-[n»o²ýd"‘1Ý‹ˆŸ4ÍšVç]Ë'ò|tÈ*gâ]¯w{ÛÚ–Žzžê¬_Ê$˜ø�'ù' ]ý†«MêH³ŠŸ ŸAd8u›öA*Å¿ª©©YæÐzš"¢è�ήÌ»¯2#–.¿›@gÙÝ 0ø,€nØnÞcfgØÖ%%n÷x&ÆIDh4²éJxàuÌ´žë‰hýàÁ¿¥ƒ M_" np;€Û;$Ky’TÍ̇ô‡¶ieÆ+BÐr ݼ¹}u¦ÎÒMWD"‘aD|‘“ã©ÎF}WC±™er]Õ…LtuŽû)@¶…ÕuuubÔ¨ŠY*+H)tÖ§üÒÙõüt•±Ì|m:e2!ååè�÷«× èdϰƗU'X–µ§8ÀÉB`GQ�Œ0#!ý%‘HýQškÒQôˆâgPx¡gÆ_í>�7W '¦ÃÒLûA²yÌXW9^ØÚ�JqÔ0(S!ðóñã§\àF7.X°`G·›F2ÓÁBˆ=‰ðfúßi ÁŒ >‘x£­­í }µ©)6LÓü€{;ÿÃüùówq»Ý‡ñþ}Ÿ{Øà=r¡ãûl; £+1mð >èãTŠ_"µ¶¥%Þ¬�„B¡Ò²²ÒßábÙ }›O˜åÔ@ ¸Tm8‰ÄúªëAt~Žû©ìñ_÷WÉGí,£Fýt<€ŒR¿Ìx+˜´Êq×òH狸JÃÒ¶¶nyØÎÐqû�œõ,# f\íio»Ê®[½‘Hd„|!~ Àí”#DX–JñY�€¹Þ©55ÅI?@0Jqè‹¶Ÿr×µÌ\l€lÙ²åe¯·ô ;fØw€k¾ù“'OþÀ’Îÿ4M'�9ñÑÎÿ4š^% ½ÞÒ ð2žf¼@$N ÌO”&|8®$ÙRõ:ÒvóƒïÁa«lµˆÄŠÅç¶õ#…JÇáŸë,•ºf¾®¶¶6ngë…Û�Bðqža+V« ŽÅÂ?Ä6™3·�Ì‚ .öùÌÇ¡x‹§é߈Þv PÉF U3 IDATeüØ4ÍÚ¨#@èþ¹Ý§�'¬*y�•MMó;}Ðh4MþˆFî�F‰È=øHøckkۿ߯|´½6îû‰ÍÉ¥œçà„”4\sìLÑht/føVis¹Üï°gyÅãq�E”Y±Œ½Þíl•¯Ú›GEÞ~0`¹�øÁn…à#[ðãhÔz”Y¬aF�ƒ¡Ç\"%~â÷›�AEŠþàƒ2å4Á^îµ ^88ÃûcÝ¡ƒ0bõ6JRRÊ!Ĥ óË>ýtð¶�f5�FÓûÄb±Ý€T`œpÎâÌx‹(5ÃïŸô’êœäºÊñ.C< `×\÷U…˜”ì·ôC[ñLæÌ)ÍDxb„ ¶½² ‘P(4Ðë-=We,3nL'T!ظ=ó^ÅÌø£gÄŠºLÒº–e• �+˜]ç9—jà+77û|¾¯\WÓO(ê¤óKE%WõïvŸ']m‡‚3þÁRœ<ã<jVßAJ, wLRÒ(èD£Ñh ކ††’––¯Ï"¢Ë�9¥¶+$@immý�rÍ^Ã8W|×äå$ÄåPxñw¸ÁîóÎÙÓ”Ö`y—³^寷ä4(5Øã{<æÚYÚß8|A˜ÚçÿíÌtªgÄòG2 ŒDÂ"q€½�ºï`ƧD¸«½=q»ªT´FcGQ eež ”fƶÍÁ¬Ô�:Ò°¶ @ÚÛÛ×»\¥›‘¡¨MT¨ì£Ñh4šž¡¡¡ÁÕÒòõt"Ì&ÊÜñ;ïòW~ÐVÖÖŽöæÑCÅ®ÆÃD8´“ZÒ¥óñ €Tn`ÖøýÁµÎº•?B¡�Çë-U*è—’o?~|‹�MÈÔeå7H$|I)šäÞy—éÝ�ꟷ‰îþš”¸Õ0ŒÇ|>Ÿ’L´FÓE€BQËÚ° @˜xXåØÀ>P©­­ME£õ¯TÝålV.”×h4M~¡h´þh€®$¢ýº¹V’ˆn5 ÷Ò½¸Ú‘X_=MÀ¸¤¤ÈäºÆîóP(d”••ž§¶ ÷±Û�Òi¾§0ôsÃpßagh{mÜ÷]å·öƒð%€ ®ý—w™ºgYÖa.—xÀ�Ø5 LÄwú|5Ûˆíh4Ý¡¨!p ‚ZÇç~¿ß¶Lû‡t@åhé¶“¿#¢5ÌÈ€ÐðP(Tª¥t5�¦÷°,k¼ø#@?s`¹—¤Ä馰MñµeÝ¡ƒ’äš P¦ÚÁ|ðw×ðÆÅv†ÒÒÒ)Dø±ÂÿmiÙò¤Ã~å�P(dx½¥)¿-]­ƒËH]€Üe˜Uø )ŒwïߨÔÕ hÔ:Gt¤Ðu÷Ýî"ºwû|¾us-�Æ–¢@˜IåäUØ©64Œsa7¨ž~ ˆ{¼ûy€×·6H)×u�F·×ë9€rQ¢F£Ñhœ!«÷IIW�CXî f¾|íÚ—ç¤knkG¼¹º–È}'z ÐÜ]“® Y\ ¸Ìœ¾t�æõ–`ŸL㘹%OÚ6fDóè�ãT§}û„6’¢Æµÿ²´ÁG,À,ïð«nî¶à¶<–NfX£qŠ¢ @\̼¿‚ÒœmúU|W¹%ªûɃ`€¤RXëRø)3‹ èD£ÑhzŒÎ"Ý+úYw‹t™™‰èÈ_:aÂÑ�µ‰Íã'‘¼“SºçA·xßóoãi;C$©&Â!™`æ-©ßî¼kyƒ˜é•ß;‘¸;]Áu\çPþRå$K>Ñ=bYÚ†Ž‘Hd'€ÃD¨Ì}Z%%_kš¦-£«é!Š6Ù¼yóP!(c!¥½ÏòÏð@ÛtF ƒïE£VƆ„D"“ܯF£ÑhºI]]�¨¨¨ �ˈ„’Ј/2Óy�€ù7õ)D‰õÕ§|=º§®åôgŒ]š´µ+¥( �‡�à6rô…J4ž@$~ª04N$n²µ¼6ÁK�•¯wv"\ä¾âÙtöE‹žÝƒÈó€ýsÜb�”ø�iêsœ¯ÑäLÑ ë7Ò ,÷ÏÔ?d+Ló93ãe"Ø6,üÖ0§„�F£ÙŠP(ä)+pâ¨QÊéµ™øàKýþš'�Å[hüõÃ÷'QuÀÝ8µvŒ÷Ü[Z´3X–u02 $Û¿¤,âRµqôHº:ˆ„Ñ6`ùÞœxÈUÞ˜ögZ__ÿCÃð<�ŠÍ™ù3fúmSSÓ½Ù¤ j4NR´ˆ®0,iÆ›¶óA#²:Ó ŒH¼Í3š€L†/YÚáÈ#k¿Ìf[�F£Ñ¤'og4«³ÑœŠÚ‘ ›™ùfºÁ4kZ•g5�,‹(½˜~‹ü-«Ã¨³P!p ”œV?qbð-‡=˱X¸c†J€®³µ4�t£¤ô7ÎzÖ Ñ‹nÏÀ™éÌápxˆË%r ><,„ëBŸÏ÷oÓ4s÷Q£é&E€T®p õn:=kV¿Aù†ãëªGxF൭ Râe…†„Æ–-¥cè«P�F£é&–eíit¦Ë%f¹§8€9.Wâêñã§|šÕÄõcŽ¡’Ò›ØÓ!_œàM÷{ØÖ*—”¶¨ :®»åtWf½¹F£Ñô:o;ާ �1ö­ór£³—G˜™®ôùLÛÓïôÅ×WOØéO œŠƒ{’¥ÆˆFËÎ�†G2Ó1*·̲O=«\.qÔ¢ÔMÓl°3$›ÇàgNú€‰ÄLT¬µ4ˆDŽ&2®Éb½8³<)ÚÞpi4…@Q DBå£Ýëõ¾ck‘b8(·§š!ä86ˆ±�@—åèDâÌÅ‹ß4~üø–œÐh4š"IJ¬ƒ ƒN’Rž$9z³Ðx`‘q¥ßï·mNÛÉæ1G0ª®% ÂI¿ò„„  ӛş‰”^Ò×Á¨c^å™Xla9`üBe,§M+c°ó·„û\åË^°3…B¡�^oé€rZxœˆ§øýÁ˜cþi4y H W8{;]N$‘,Ïõ*Ÿ€÷mý¹ßïÿ$µVÈ$ý7(•J\àw99 Ñh4EB,û¾”É©Dt¢ÎÌP«KPƒ "zLJ¾¡¦¦Æ¶&°+ë+G1Ä•LpÌ©|CxÔ=l¹ííŽeYã…À*Ë0Ë?¡uÍ–Ò¸Œ¨ëÀNÖú|5¶/ï‰uU#At”‰®HgôzËnx¨âZ)€§¦ó_£)$Š2aVªá°/(l7 ½rÞ›0M#Ëì®R¥ÄBd @ÀÌE" #�À¤U¹ú¡Ñh4}‘E‹íœH$&a*Æ‘ÊKc¶lpw2™ºeÒ¤Ie;9þFå!Åïñ rªð¤gØ’.·+�¬««#GVüYef¼ûŒbc4ý ŽSÛXÙB„K�ޏ¸ Ö۪SE"áq�¦t3óé�@Í3Ž:¨Ñ䉢 @B¡P©×[š1ÿ–™m Ð2±_7�ØÊÚKJ�`#§ÛÖÖöˆ×[z€�2¬á"2ž©¯¯]SSc“Î¥Ñh4ŃeY» �ÉÃL?"³ˆH.0ãS@Þár ¸c„ Ÿe;?Þ\5\0ý� Žá¾x¸¥¤¼ÑVädÔ¨ƒ�ðSµ•äïчn?þ-”R˜øÕt�UüõÑû‘0¦8êáK�ˆ_ogjjšç†Ü¦˜€n Ì{�tO£É'E€x½ž¡Pø¢a&ûëv¢òîú €`€ÔÖÖnŽF­¹Tš 2 ¼‡� ƒïv×'�F£)$"‘È�˜S~!Ä$!0€�Zßí¬áW¥¤ÛøøØ±c·d;;ñƘƒ‘âKˆèœ¡Ž¯P!`ƒÛÅWÛÙB¡�Çë-U-(_#º–W"‘È�ˆxªÊXfN›VF¸ÿî tö{é¿v¶M›†ü†ªï#-+ó^ì kMÞ)º„™öQy€¹\ò ÛùÀpž¿ØÒ\}‰ÝI3]OħØ5ó2´—a`µeYÓLÓì3Å~�F³5MMóÜŸ~ºG5 |Ì Â~ùÉ®úIf,$’·ùýÁå9-°¾jœ„¸”ÀãûÞ}Çw‘À…ØwÅ×v¶²²gC¡³v‡<±ÒZÁ@„Ë ö®³níÚWÁm ñ×GïG†qœÃw>ÿqòf;âE‹v†zè“I9]÷ùÐô5Š.¨Ë^�$wÛí“÷ÓØº}À%@gئSj ø<­¿ %mn"Ú™áHĺºµµ­®¶¶6M×Z�F£),¢Ñè`æ¤>¢!GØ>ÿ™;üo€î“wåÖS‰Dûúª€ ú-@‡Q_Ê4Jórψ•OØ™Âáð ׫,CDó}>sµ³Îå�H$2‚ˆ§«Œ•WÍž=Û¶/ ㊛§… sÓ„R&ϰ½Ò:,Ï ƒœôM£é Š.!û(<à>¬¨˜™°�ïLŸ†w½CWµµÍﯙ�ÖOHU9Eáò²²Ò@,>Çç ®tÂG�F£q’††W[ÛW‡ÆxfégÆÁD"ïwÌÌ-eÆÝmm[æ×ÖÖÆ³^¤y„'��¦‚«.À~p²ÁHï’`!Î@šÿC.—ø€ÖIJ ¥@¥P âk VûñFSÓË!Ó4·±äéö#™’b®�¡³êl•Eˆð´ß¯{}hú&E€rŸLµ�̰ïÿñ®{9òEÃØ!Ñîží.°µÂ8™Y6aÕ%‰ðS)iy4j=šLÊKõ©‡F£émb±…åÌÆ‘D8‚c±]Ç!P¾ê9þf|*= %î5MÓþ{=¯Mð&Dë© �.ðg=ì}¸ÙS¾ÜVt%‰Tád•uˆø~Ó¬yÓYïò‡eYG¿ÊX)éêž¼ý `Aéˆe¶êkBà,Û),³9OÙ½_h4}‚" @2§` AoÛ}�5”˜œü¢9'þúáxö_öúÖ¿ßÿI$ 2Ë"òª.ØÑ-'º\âèHĺ ›�@ºt2�F£q”E‹žÝ#•rIDG0ãHÀ¤;_Ï q"D¥”�´¶¶[9Ýv@ó¸ÁqNœA�ÀÑÆ†…ÿr“+]q9|  «™¹%™ä:g½Ë±Xl€ü5¡2~»­m‹mzZžn?Æv75Ís39M%p—Rþ9 i�¦P(ª$‹m`p¦qÌl¯*%é'ºHÈ»ª¶{<�¦h4\ Ð3J³\»Œ¿xV4yš(u½Ï|Å·5�¦˲vPÕ©TuàôhÀñ /2ó£ñxòÉ)S¦Ø*©�x½º3L#P‰ƒþRÐÙ¶t³�-µ~I„JÅ¥®éK7îÌ©K¦6–¯HW[™�Ûë]#V,³3lÜ8äh!2gE0ãS�§ä/û¥Ñô(E€H)•°i{"ˆöaç +“ÍUç¹Êq“�Ñï>‹Õ×0ÓsXßðñÌâøhÔZÃÌâñ@ ðy÷ÜÖh4ý˲¾'�DÀcˆ¸œœl?žë<#%Ë9Å èH³rµNãLèœ{ Ñ“žaËØ™,X°£Ûíº^ñ·ú�×»Ý�Žú–Gž{.¼/ ””º˜±:>mgËßíÝ‘.|g¨-"¯?~|‹“ni4=MQ Dò'*W®BHÛ+Ô�ä3®M®¯zÅ5|ÅR;»ÏWóB}}ýa†A!ûuc«QD4ŠYÞ‹Y ~h÷Ý7.IWp¯Ñh4±Ø‚§R®1B šÕBàÇ߃ïH={ð«Ìx†™ž1M³[5‰7Æ ‰“að‰`ì蔇…ý×�L�“Îêv»®S¯?ä‹sé�Ò45ÍsK9äTÆ3ãb¤ïû1;·[ÜIãq;C4ºpÀ£°ÆnwɇýÒhzœ¢ @˜‘ñ„™·¼ôÒßÿ9qâd#œNÁúC„¶¼vø¨’–Ùv6¯©©Y‡q¹Œ{®íÎfDTÂŒã:nÓ¦!ŸG£–%%XdšfkwÖÖh4}—P(TZZZZAćá0f:”ȵ‡è¬è¥{Ž$V¦R2&%žívãÕWÇí˜ð$�…Ä,vÈÇ>3~ƒV~jg³,k,Ÿ¢xضÔï¯yÆYïòǦMCê¢2–Ϙ¦¹ÂÎo®N cu®ƒù8hév"ã µ´Fz@ß~hŠ�¢ @ˆ�±�ˆÞK§vÁDûäïùË»/ÀÛãŽÀO–þÇnD0üÀq‘Hý‹®&r$?y'' �“´F£ÖsR"`±iš;°¾F£)Pêëëht:^Ê-++=ˆîo^>{+±ŠŸQ �±x<µxòäɶ/eÊ4Œs¥vMM`’'³›jÀðôõÆ�¹Â@Ì3bù#v¶P(Têõ–ÎUüͧ€Ôov/otª^©vÿZã¼tFº2ï‰åvŸÇb±í™qb¦ùÌÌDBß~hŠ‚¢ @T°ˆÒHð¾Uµ�”%qsä€D"ùW÷+cŽÄO—ÿ;Ý @ æ–H$øF“Ü¿ ÀÑBàhˆD¬f"Z,%/ñx<Ëô©ŠFÓw‰Åb»1'*˜©‚ˆF8Ä0è;¢½p0Q€¨”ˆ655­Mw¤‰dse%3�ÝQ ÆnùH¡íc|! §§3z½¥W™ê:™ë÷OÚFÁ±‰F£{ �G 40óå~¿ï_v¶N‘›‰nó‘kĪ%öþ¤Ž…B ¨ô¼Ïç·­aÕhúE€¨|±ÚKð&RÆP ›ÏC5H¸ù÷k•G¤»"€NiÝ)‘HdÀ·a_§!B9ÀåBà7Éd¼=µVI)—‹×®]ûJ÷_4M>X¼xþîÿÇÞ�ÇGU�ÿÿ<çÎL2 ‹ˆ€(­`m•PY\ A°Ì’€ÚX»¨èµ­U[«Õ.Ö¢ý~kµZ«Ö­»ß¢c’;3šªD¸F’VWPA²ÎÌ=Ïï�™ Â�™;“’™œ÷ëÅ«uιç`ÈÌsÏ9ÏcŽD°�‰Ì˜à›€èµ coÌü¹ôœa ,„öz½[»ÚÌ ¾Ymš6gÊÎ``TüfÝŸo>`æ KWšV…BǸÜÚ8ØÐÕ¶N®‡�ÅÅîåFX¼ä•¶¶Ž;Ì›ˆ ÊnAD²Lxà$Ÿ©´ÀÊ›˜™ï´wVŠÒ{ˆó¤ÚëÒ¥K‡8“®*ìá¯×ïÞ/FËN#¢ý¹×õ§;KëßL×1¸Üî‚ ˆÄeDÝóSlhÀ«˜iUqqñ›3f̈í§{+ŠGÁ`p `C$ÆáhfLB,˜ÇÌD´ À³€|æÕW×¼nÏC ¢hã´I,p*±8à#º?f^ºÇYZ�YC8.`6^¬fãª\8û±hÑ"1eÊä'®´Ò?þ•Ç'[Ù‰6–ŸÂ?í�eüÖRˆ# Æ>¿Ï ]×�¦…"÷â½ÖÖŽ#’¥ V”\“7+ .—k´•'†Á¦[°pø~žà¥hsùÏœ%õ÷§ê˜(´u{]]Ý]mm-g¸–?H²vPâ0|£­­¥% ¾ð*@®ŽÅðRâÌŠ¢(6 (ÇŒ£1�™'aví,écÏ‹$€7ˆèfãÙ¶¶Î•UUUí]�^¯¥ï„ægh±Ò-'J†ŸP~:ˆ� ÔRGRÍÎŽöç5ä"X>–æBð€Ž;nâ�ÌÖ‚ ¢+’n+kžz „v}½ÅVš i´Àʃ`fܯ‚%ŸäM‡YÙþ©iÚf³×™h´½ó±¤Œû¢MÓ':;ڮĤ×Rf¨J¬@ü€…BÕs˜ÅÅD˜ Øž*ÐÌ€g˜80B!ýM«˜å‹†�×*++ß�ú† ()% û`¬¦Ñw˜y,€£Š‹Ý£™»~ˆqŸÙJõu¼ ˜ås‘ˆñ\w îcóÌÂÎÖØ)‚q*JPÆAñ?õ#%%B;âÌdŸ¡Põt@XÚzàËXŒ/¶qv=&Öod¦ó3¸d¹×ëO²õ ˆB»!~ލ00{¹®®Î!%Ÿeáߺ$Ò´{ZŠÒ›ò&a£-ü#Ž™f~bàðÞû¼çŸGÝn5—ÿÌQRÿ”• ¼Þʧ</†³˜qNOœIA0ÀD"q±Ãƒú"¬°†Y®‚_oi‰lTOm”þfÑ¢EbòäÉ£™ù("9Vú3�p”8¨«_ß+^ Ð ×;±úÙ³OMzn-맦±˜CŒY ÌÀ@u޲¯ …ô?áÊ .ic§&]­k/¯Ÿ>2*¹/.;ïdÐß]’ÿ†ñõ_d;H0œð<"Ì0 =P`ÉFÛ4ñFfÚ$%6ؤiÚ&�Çc%Ë™¢X¸ÝîQDÆ(fmŒ¦Ñañ࣌ppêrFŒëˆð"À/KI/ùý~óšHÝµáø¡é:™‰3c8¼GîÓ¿µ²'&Ûz …c6ˆè@+ƒ1óO|¾ŠÅöNÑ> ‹�Ÿ|rÈÝdr³¼Æç«¼.Y{´±üRnéîüRx×Yºò³ôÁ`Í/ˆèæôCÐ�^¯ï¢ž˜œ¢ô¦~µ°é H,fŒ†è“ßÉøê¨À/ÐTþ/H,vޝOò$'9ŸÏ× ÀâéŠße¦Y‰ìi·®íg˜ÎLÓìþka6 黀x@Ð&€7K‰MRÊ÷ �­vïOWrW pà<Ä0#‰ä(€BÊ,&¢QÌÁÌß(.vǯÐ@ÔçÏdXÆŒÍ~MJ¼TPPðZ�m˜\+rO•³ˆ0 ì:–úöCŽœÇ …É‚�@ à*.v/±|Ðûrð?ÇrHÀ)^úOŸ¯òOÉcÍeå º¡{³K�ˆL–»ŽÈÚö+Ã0¯ž®(¹./�gž ܤëÇ,M 4I¡F}zå\� ¢Íå ;áø?”¬hÉt Ä>ØÇ¿ðÔSÕGÆb8EÓÄ)̘ ÕX{Ñ@â¿â_BBÄb¡�° Þ à#)åV@|$„Übô13o4hÐvUÓ$wƒÁ!D4ˆ’R,eæ¡ BÄŒƒÊŒƒˆ0Àˆâb÷ æ®¶+…- Ý_rd›TZ]~4å¶ IDATÁ³| Ñh´ÁÖìT{[;§8æh;Œi̘…Bw9$ èÛxòýÕUòÂ’díÅÅîoq´Ïb1Î$“Ô~U]]}ˆÃ!‚È0í<kiiÿ ’¼#Éžà²ašÉ°að#f_²B¡êÉ€˜`aŒÆŠŠŠW힘¢ôy€tt¸G[YÀ‚6›¾N|hÎ<øŒ!»;ŠØ_ÑTö1=ê·ò…äVS›;·r#€�n�/s|" f˜ àÄ¿ôç €o¼{UGì~c|uþ¤­­¥+c×g¶õ‹¶ü¹”ØF$·ÚN ¶‹»„à]†áÜñÚk¯íPâ¿. ‰D"Âår –Rº……BÈÁÌìbÆ@"*f† À€]D¢À@f¸ˆh02“àÁˆÿPÄ 7Óîo¶Z"  ÝÁÞ+yO¤b0ãm"ZË,ßD37ôø¹©·OdDe†¤“ˆ1&ƒŸùÿgÞ׬p}ªý%æ�Á`u‘¸$ƒñ.¨¬¬üÄ–™Ù, ŽK™ÝÔ‡ÿøl�çóì‹kçkšX`xwç˜Æsãëß5o ¬ ¥yú^EÉy€IK5@Ãt 3�ÊÁGwZÈ„…±¦²%M_B0u–¬z#Û'Mº à…Ä/mÀ€‚ RR™4•eµiþ½*‘±k0€=ª*µª?Å¿ô€”cÊ”I…ô6»â¿x@;2ˆ¸…™¢·!B;3wèˆWàE„­_Í�$³Ü±×¼v1sÆ«3B§”¼÷êU@E{¾ÀLˆØ  €ˆÜñß( N4Šÿ†Ù P!À€&®;€ ñ Á‰ÄjPPàÀÐ4À`&Ä…Ý¿¯®ßáž¿×Dßøÿî­©| `-­5 ^àM�~¿?e­ ;´¯�9JÓŒ2b9 iΣÁÐPGïúÀiÈ31c…éÏ]׿-„¸'ƒñþéõV,·in¶ «g‰H»³a/¡¢¢g$>ËLÅ´²Ó½¦ÇL˜½^WWWàé¯GÔåŠ>b÷¼¥¯È‹Äb–'ÙÒýÀôj𨜠?öÀÀ(b¾—G›Ê×Ñf^î,­³;ã&êw¬Iüº ˆn”R– ASž yó>²¬(ñkÄWßÈöþ"Í_ÛùÛõÄ~ßlIûÎÙ|ñf¶¶¥ˆL¿Eš½û»^3Ÿ·b›/™±�ˆš¥4ÞÄz‡#¶nîÜù›÷ËÝëf:¢#Œ `Ló‰ÊZâ‰s×_z.ÿpÌm`>-Yzö@ à..v?ŽøC„´˜ñŽaÈ êhì?¡�~ nFü!G&–·¶¶ßëõG’uˆ6—Ýà{Ýš 5;]�mOš5´¶îœO$†¤@Õ¹F%ŸåÅG!è°ô[¨øãªª*ÓLÌ•GOöÆ2ó"‹¢Íå›À¼Œ¤XîØpðJT=Þí‚€‰bHïxèúàsM`¦‰€8–ŒCÏî­U”œÁÌL„÷‰h#@ë ƒ7É�†�æý½ý¥ýÍ©‡jNÇd€§ã Ãñ�}úÜ—HfüØ5nåkÉ:»ï‚ÅsÌÜÁLßïkµ˜êêê ÛÚZïpNæ<(0bÄG?N¾òDËÿH„L¶§uÇcÉ*Ó‰}3qš0 ¨ÚJ^Ë‹DJ–î3%­"J„œ^IŠ1 _²à_FK¶lCS™ÎŒ§\Žè38êe[©VUUµx9ñ @¾Ž°ÑQúüjÓ&’çÀZÎÿ‡U¦F%ßåEPÚƒÑÉ2`µˆƒœ8i܈Č)ÌòwÑB÷.jš¾Ä/0¨Þù©öz²ƒŽÙJdŽJÔð@h϶P(t0‘Q"%Žh¬ø63Æ ^ÛEmåRö§í6uÌüžØ$¥Ø\\\¼iÆŒ½=Á®4¸Ì<,&Cðdâ;à=c nä:žvmsü„ò¥˜ƒÒÓ:ãµaÄG̼…Ø*%>&2>G£ôA_Û�7f+�˜� �4“á@ @±:$ž�ë\®è˜Qoú ¨¶vép‡Ã±ë61s«òŒ^Ù hbÙ²e¸\Žû‰h^¦×2óçD|šß_ùBª~ÑæéüwìÏhœ`D£ÆÃf_¬‚ÁêDâp £¼èóùÖÛ=5Eékr>)((¤_Á`¦-f¯KÆpU²wÀ8…Á§@ÑAZMåo‚ð*@¯0ä«®’Uë³­=bUbÕäƒÄ¯}>lÂápÐ9Ê0#…àC¤ä‘BˆC `À#úúvqE%{_ü@Û‰°�Ûl“Rn‚>%Â'ÌòC"×V�ÇóYoO6¥ÀZçø-ß"‰£-<N ă ¨`£x?&…ÏyÄK;ÍÃáp�”ÎÁJöÇþ©Ç3¯Ù® vG(T=Ùår<`L¦×Æ‹n Ÿ×›ú z¬iú¯þK¶sÌ3jÝG¯þȬ�HÕþP”=å|"„8ØJ?McÓD0W9FÓr˜ Æd€J D›Êvå ¼æ°\ëÚ0ê¿vdÚ²Êãñtx'ñ+©ÚÚÚâH$ò uUÑ&C #ÂPfJ¼†¡_UÔVo ›uhx'@‘Äÿ¶ÔÁÌ;ˆhW¼† "Ìüe×kñZ)ü…”b‡ÓÉ;¥tì(**Ú–›{¤‰:6Ì8ÌÉÑ6D) > LãQÂ¥Âø*IC<ÎPoÁ~èSiðl÷„çMSÆ/Z´HLž<éŸD˜f}HºÅç«ìõ$t½úçBˆd~5ן‘:sQ¤©|�¯Îz’ÝÁü€ÙËÏ< ¸O·0B›¦i)·•)J¾Èù„HŽ´²–Y3 @H`¸J “•�f0Diˆ–niGSyÀo€ÄZ2°Öahoâ˜_öæDÛ6drͲeË((( ¥È̉ŒAÌÚBðf 0�ˆ"^(ËÐ fD4`øàkü#þF%d^\Ë1Ä‹'€�(€È;]ÁÀ±x É/™wD‘R¶Å (ò^×£ àN"úàNfG«Óiik£Èüùó{õï¿W4Lvv�†”Gi@ Ç.”ec5ÄŠå×¶O©@ Â@Ì-˜ðüÆd]Ž;nòMÌüà F}ªµµí f×-ápx³¼GQ•ÍõDtûðáÿ*Uš]4�sE¹|1�-�³èŸ» ™vìì,ü>‘¥,�ÿöx<¦+_Š’oò #Óõaf‚¶š¶�FØ?«~Šá0 É` *b@Sùš4ð®4C¢©`üÊMè£9A_š÷Ëg]׋ˆh÷AfÖˆ(iA1‡Ãñe,KúçVPÐ&gͪڑ¬]±Ñºò!1 ¥ ”0ãp΄ÃQè.R*¼P, ´‰JÇØç×$ë ÖüŽˆ.µ>(¯w¹:~àõöRf¶]×' �%ŽÈâòv)ñS¿ß÷PÊ^ËFxÈãž›Õ$í@xG„:“4.°2„”ªö‡Òä|’8ˆœ²mOl×1Ã{b^Ê× 0 À4Fb½JѦ²�@ù¿ÅŒw x—ˆÞ‰hünÑ‘+M“ä#¿ßß`ï¢UÛzc.Ê^6?4u�f�Æ)G3ÑfMÄc�‚®c÷ q(™‰ IUڸ瓪…j.$¢ë¬ÈÌŸ3Óü^~Aº^}‰âzd·åêC)é{~¿ÿ•T½:ÖO;L“"H@i–ó´â^³×u]?Jœ`aˆM~¿ÿy›§¥(}VÎ ¥Í€…x†¥dTÒ{8LÇu…�Ì€3Fˆ6•wx—�w‰ð.ïIÉ hF¥xß½qØ–ýyÞDÉCoŸ0(q�ÒÅD# ø&“8„™GðM£× €˜Á‰D*ÂPlB0˜qŽ6î…`².¡PÍéÝnuHfD®òû+þkÏ$3W[»tx,æ|@‘íŠÄ³RÒü~Ê1±¦éÓĈ'é=Œ—\ãŸ_gÖ$γ8ÊýP�/”~$ç"šîß,3>M>†«ò}R!€J�Ø*OD`H84‰hÉ–5•oeà}}æ�ˆð‘”ô©Ðx«„ÜêŠâSLX•üï^É/Íã\è[çÈ"(ˆo—×»ÝÅפK2m*ÿ€¿Qߨu�Ù‹ ‹�À!VªÔËhÔxÐæ9)JŸ–ó€´ÕS‰h{ÒFµ+W9`T×1æøÓi–A ªh*�áS¶2°•˜?Óv¼�Ylc–Û‹íÒalwAÛþ|;J#½ú;ë�6Ï,Ä®˜»BD„�ƒ ¦ˆi0&¦Á’x00D‚x0€Á &Âà!n¸-ñ^ˆÝuʈ¨ŒwJcÉ?v�[™4ã‘®ë' AK‘Ùö¥¿õV¥ó@ à*.v_GÄ—gùm;3�ãñøB){½8Õä¸@o6ßÛN§,2ý{üä“‘^iÏ™á™yóæ™f>S”|•óH"}jJDœ$!*;H­€ä5'3phb @s|Ç>�‰AR 0h*ßàK0v€°“�ϵ“�/ñfÚÉL;@h‚w@R;Kî�À†‹;Š"ÔŽñ+wôt­”ý¢n¦CcQàÐ:;cƒ@’‹€RÒ` b æ""¸%0„˜‹@ph°àa ƒp3PŒ® a¢+Ÿƒ™âÿ?±Ý‰é«• @{ü£¥®%7Dô׸ú'ë .Ÿ*„B<Û Eü諯¾~…×ë·aŠ™ …Bß).v?`r–Ì_ŒF�3Ó} ïX?í0m ö$À³šhO ú?Lx:I�Gq®•N†¡Ÿ+ýOÎ D<,}¾|2/B¶¦|(\lyi[é7Â7€¯¿»]ÁËWgâ!£ë ´ˆ¢@S€ò€VÚèH Ó J:—ˆh&ÄD"U.IìNu 0ðE×ÿÄ;ÀôõÀ†XH¦Á_ý'awf-„¯Ú$S1�]‰ß� ÄMÜ (dÀ�øÖ†bt�²ŠÆ º2t­.È®?—=RÊRW�€ÝBwÿw×@Å J¿‘ÄU%õÕÉ:ƒË§i!I3á틞immÿ‰â­û•®ëg �Û‘EÁWff"º­µµý×UUU)WžcMÓçhÐñЬ'ÛÈ|ûUuuõMžtñ3>`À@Óô½Š’Ïr>(í#Ã0>7{=R ‡«-J�rpq<ØWº¾}ïñöûZ¡ë½²ïù.e³÷,Ó×ÃpúzØÄ_kÚë«êÿTÅ‚é{ÎÒú¤ÎÃáêi‰à#ƒ•¼ìp8OM÷ÞnµµK‡†ó!P‘å;™i¡Ïç"u7±æ²«ø¬ýÚŸ α/¼nÖäpˆ³/â›z¢Gg̘ё®Ÿ¢ä›œ@t]/îtý„ ÓD@ÁÈý2Š¢(JŸö%Iš¯�!išÕ`0XN$‚Èl%¡IÓœ¾D±ÕýF×õS…pÜÀJJ´ ùýÞ÷RvÛpüЈQö0žìîÓã'y�^�~w %Ôás¥_Êé{?UNBJóCè’y¸ZÿPEQz [ˆ¤×1~ÕÉú„BÕÓ‰„ŽŒ‚~OJšëõÎ1}ÀÖª««:Úßâ©e³úô4˜ñçâââkÓf¹Z?}"Øõc²›m�kqº¢KÌt]?I›~~Ãï¯0]AQ”|—ÓˆÃ!H™~EVÓ¤i1&b¡rn*Š¢(=d½$Ì-,Yõ~²¡Põ)Ìô$Š­ÊŒO‰´9~¿÷#{¦™^0,w8Ägð‡†�³***ÒÛ‹6•Ÿ Â]‰si}/Á/í4k?±6=`ã„%§ät"¥µ}²†!ZÌ^g`ˆŠ?EQ”°ÊIF¥³duÒŠPHÿ! î#²^Ë"^׊fy½Þ·ì™fjuuu…íí­×ñ/‘ýŒå��±…§žzjò”øÐ0¹(ZXt€súüa4"ÓÊçO?ýäHfש’�uvvFµ}^Š’#r<„…‡D´Ëüu”å2²¢(Š¢˜"ÂRÇãG8qu{²>Á`õ¯º�2Ë[û‰”<«¢ÂßdÃ4Ó ƒ“~�%Ù\ÏÌ.÷ù*îH×·³yê¢ÐýÀGgs¯ýl­³¤þe³†X̱�(ýásO¦ È%�åt"°@8�Ó êóOYEQ”\Á ü�³då5)jQ8¬ßH$.ËpìOˆŒïVTÌkîî$ÓihXìüä“C~ à·¿L›ygù|¾Æt#Íå?Ðî@¼&PßÇ|§ÙËuuu":ßÚt—½“R”Ü’Ó,¦*ܱ#fº‰�jDQE±A �ë*y!iZÙ@ à**rßG„f8ö'†Á³öGð//a>䓳©)ØUÛƒH»Òëõt¦ìüö ƒ¢�Î ¸ «ÉöŽÏ�²øa³†––– !hTº˜Ñìóùêퟚ¢äŽœ@¤$+[°bUUU¦ËàL¤âEQ¥›>€Ä©®ñ/4$ë»07ñÁGEOo»¢`°æ|"ífEYŽñ>3-ðùüué:F×—�é|À·²¼W¯`â»’U>·~ø\þÃÎ9)J.Ê鄈 -lÁJº—2ª4«(Š¢({a~Á)¹ V}š¬ËòåË¿QTä^àØ GÿXù]¯·rc÷&™Z0<œˆ ¢²lÇ ÂC€v‰ßï1Í µ[ÝLGä ØïIÐïhÙÞ¯—D�˜Ótû•®ëß&âYŽôì2 TEQá3>G+YNÕ-ÒâvdþYó: ü••þ­ÙO25]×‚ï‚ætc˜�¦EΟ3ç´-é:F›ÊÏÐþ�ì�ÞGÆßÍ^ÂÖšÅÔásEAŽ B¤_¾e†‘¢9Û슢(J¿ÄÏE5œUtäÊ�“õ¨««s´µµ\àÊŒGg<'„všÇ“f+S7ƒÕUDt'@f9Ä.f¾Â竸H³–ñÆÌ¢ÎØ~�å½úæœãV½jÖäv»Ï$‚…?K®÷zç­³{jŠ’‹r:±²‹H­€(Š¢(ÝcÆÿ¸Æ­ºÖ™<Å.t]?H<`f¦7`ÆÿµµµŸWUUéÖL“¨­]:<sÞA$NëÆ0uBÄΛ;wþætcÍ'� §|@ÚÌP}kâoÉÚ„À…ÖF¡»íš�¢äºl«šöV¶`%]!ÊíLQEÙ/Þ‚àr׸ú?¦¨ï�Phùx!ð2²>ÜúÚk g÷Tð VWÅbŽu² >˜¹ƒ™óê« ³Ò›gF›Ênf–ÿá<>¼ëj<¸Æ¬!\>Àqé‡àψ´´çd¥¿Èõ/àÝˢ˪ ˆ¢(Š’”èVçÎØoSU5]×$„v'2<ãÀÌÌLWøýþ›½^·&k&c–·‰ªn ó 3-ðûý|¾Š”£ëÊ'Aà!€²ªžÞ'1nEÕã¦3…Ð~ÁÔ‰{=ž4uQ¥ÉõÄÊ?æÂd jK·}UQEé�x3ç9JëW¤êU[[[‹En 2¾sÀçùýK²žf ¡PÍéÌô" Ïrˆ3_W\<ð/3fÌH•Q¨›éˆ ‹ý ×"¿¶7ïtFï7k¨©©£itª…1 ¢è=6ÏKQrZ® mú¤HµËV®WEQúp�“œ¿BÉŠ–Tu]?Zü ÀQYÜç#)qZEE¥éÁæîXºtéЂ×m�™M5ó„u€8Çç󾑮cgã´o‰aâAÓ²¾[_ŸG¼dš@ÓÄÅ§Ý N„�•33ŠÒŸätÂLíé~¸2s!â[µö]ê j…•µSEQ¥?ø/�/t”®L¹êº®Ÿ-î@võ¤^Ô´È÷¼Þôék3¥ëº· À¹àC²B¸�H»2ý–!¢hcÙ%Bˆ?ƒáÎò~}Á04Çífé2Ãáð €Ï³2Œ”ò›g¦(9/§!¸5Ý1"¢ÚÚÚ¢Ù³g·îÓÈjDQEA”�›\;�kÓ�õxúé§4ŒÈ=BXÚz³"Üh?›3ç4[Ï$æõw!èGÝæ¿Rb�ßï1]ÇŽõÓÓdÙý ÌÌÛ�Ì’––¬ØlÚ$cÑ tC0c�ÏW™6 U”þ&§)©]XÈã‰DÜö @ÔÊyû“SQEI�^ø|Wiý›ézêº~\|Ë�ÉâF3ÿÞë­øKצ×x˜i1@‡fs=33‘¸§µµíòªªª”ÛÎ Ú<}�q €ÁÙÜ/GĤˆýѬ!Ñ¥Ö†‘IÓ÷*J–Ó‘l±’IXq €m{¿ÎÌ[T,EQ”~© ?8›Nšá¨K p»¯W"‹ÏMfþ�gú|óžÉz¶&‚Áà!øoÌtv¶c0c³XèñøžKÛyí´á1!îa~¶÷Ë!÷”¬~Û¬�ÙXÀJ°÷Q[[çãöNKQòCN Bð'ÖÒߣ¼µïëØ¤Ö?EQút)äÏ Ç®z¥©û†BÕ“‹‹Ý÷—åí…0Nõxæ¿“åõ¦t]÷ �ÅÌÈê¬G|Õƒ†üµÏW¹+]c}™×ÐĽŒÌæ~9¦#Æâº$g? üÚâ8ÿ詺.Š’ër:\¦¨3¸›a�i!$Ix—T¢(ŠÒ_ü——8KêŸJ×1þESþW ëÏJZÜÚÚö˪ªª”çJ2ñÌ3�ÁѨûf!pn7†yŸˆÏ÷z+þ“¶çÛ' Šv:oè‚þ³a€îr�{þ³æØ€¾‘nfn„ª|®(Iätâñxv†BúN)‚±iB’7¡9 EQ”œÐÆŒ]…ÿŒ#Biëº~î#BVÅô˜±�ø|•�l®O&ªž .F–ÕÅ™™ú§Úå�ß4µìžbÍåeÌÎ|+›ûå¨V'G®7khhXìF^ee!Ä]�ï {§¦(ù#§`Ƈé>$ˆ„é^M§�ïFÓ§ðVEQrƒðH,æø­{ŠÓu®««+lkk¹F\ Û‡—¥äVTTnÊòú}TWWt:é¯Ì´�(Û§fü!_àõV¤]ýÁ‹SÝÑÁÚõ`\Œt©&ó 3þŠq/}bÖöÉ'‡œà0 ô3ÓMöÎLQòKÎ BàCætO©Ø¼HTÉêϹ©|+÷ÀÔEQ”Þ³�—9KV½j¶—oápÍ Ìø'@c³¼ŸpãˆÿaÒ¤ ¢YŽa6¯“5MÜËŒÑÙ†D¸ßéì¸lÖ¬ªéúF›§‡Aڃଊ+æºw\» Ó,e�@À]\ìþ½•Aˆh±ÇãÝjïÔ%¿ä|ÂŒ´O™˜ùèdmXÍÀiöÎJQEé%ø½³tåðPi6^?#ú?�+iÍ}"%ÎñûýµY^¿]׋4�®—e½ ñ1³¼Ðë­ ¦íÙ0Ù+t_à:Vb¶¼#˜.MV¦¨¨ðßL73wÄbòFÛ'§(y&Û¶}³\›®¨ëºùÂ*Û'¥(Š¢ìoŸó΂�ßv–Ö?”.øX´h‘Ðuý|Ènp!²ü<$Bm,&�±3~Ò:V IDATø‡«§ �7˜ùçÙn¹"ÂCÌ4ÞçK|DוOЏ_gàzôÓàD�iã^0ý³Òuý €¬žý¸·²²òc{'§(ù'V@Ä×C Š¢(9¬•�Û]QÇõ8fÅ—V.¨©©™2eʤÛLéÆ}w1Ë«¼ÞÊ»{*ÚÖÕÕ¶··^Ç,~‰,"flaÆOü~MÚÎ]«×pes¿¼@øÌ3.IÖ¬i¸–ÙRÑÅN@Ü`ãÌ%oå|ÒÞÞ¾®¸Ø-‘懵¦ÑI–íýº_¬‰Ò�v0Ü=5GEQÅv� ÜåŒÉÿÅ„UŸZ¹`éÒ¥C \ÿ£i´ÝÚ@Ͻ`îÜù›³ãëâUÖùþnœAÀ�:®KçÌ™óyºžÑ擎E¡û²¿_~`¢ ’½‡t]?Q\`e"ºÇãñ¤Mv (J UUU-¡�þ�úÀ3ŸlÚPÒá¦òç ˜ÛóSEQlø!ƒèºÂ’ú}VµÍ,Z´HL™2ñü‚çŸÚ�{ïøJ¯×¿6­z|½Ê:eû™ü‰”ø©ß_±ÏC¶}4LvF Ü¿#ÂoÑ_·[í‰è.רLÿÜ;…8ä.X Vwâ:{'§(ù+çÏ€$<Ÿ®3�«­]:ܬ�ˆ³JŠ¢(Š�" <,É(u–®<ßjð .Ÿ:eʤ—º@ÖÁj¥Ä¯·ânØ|„B¡cŠ‹Ý¯ø²| H„ǤÄx¿ßŸ6øˆ¬Ÿ6.êv¿H„k ‚XëÜ»,YãÖ­# `¼•�¤”ñx<ŸÙ63EÉs9¿Ç+º0U"¢HÄ9ÀC{·9Û –F ;îPÐS3TEQ²@h‡ä{cÒyƒ•Z]‚ÁàX!øˆ´ùÝœÁN—{<þ¾³ŽÖÖ�¿Ä¶1Ë‹¼^ Åëf:bâ¿!ˆß£?Ÿõøº/$§'Ëz 'ô‹c}ÐÞÞy‹�sS”¼—ˆÃ«‹Fœ.[ˆ¦át˜ ˜ôŸÔXfBw?¨EQ{|ÉÀbÑ-W¿Åê·t]×%Â5DXÀÜíϸ§¢QãÂyóæ}ÐÍqv«©©)Õ4ºŸHLÎv ",‹FåO+++M æí)²~Ú8.Ó¤lï—‡bÄüý‚ÒÕo›5ÖÖÖüˆõà�¯¨ªª2 dE1Gœ>MzN…ô7�þ0]'‘6ÂãñìÜ»!ÒXö}"ZÒ3³SEQ,z [œy/Ž\¹ËêEË–-;  Ày3_  ¨{Sà\îõV<Þ½q¾4·»àWBˆEÈ~µý fy©ÏWùHÚžu3±ƒŒ_3ñºq¿üD|±³dåíÉšƒA}1Z-äõúý6ÍLQú�¼X"ZÎÌé�æØ<ïÝà*´,Ö¹ëcé™*Š¢(I1^g�›\Ÿ:ÇŒ1«—…ÃáÃ0.r¹¿aîÖsˆø›ÃQð§Ù³g·vs¬ÝÂáeß*.v?àÄlÇ`F˜øý•¥ëiž^BÃðÀÝI3œ—ø‹+Eð¡ëú¹BX >˜¹UÓŒŸÛ7;Eé?ò&aŽ=hW[èº&Žu¢¹üf0þjûäEQ3–C`±clý3€k.Z´HLš4éÇBð"!è0æò!ä%sçVn´a¬Ý‚Áê3‰w”å;\îóùïMß•D´±ìb"üjÕÃ=è*­ÿM²Ö`08‰ˆÿË…çù�v¦bV”þ$o¶`@0¨¯'‘éú1ÓŸÏ׸OCóÌQ޽àÀž˜Ÿ¢(Šá#0ßí ç=(Y±5“k�€V\\x@¿0Άé| %~å÷ûŸ°a¬ÝâÍ[þF„‹º1̳€XèõzßK×1²nêQDÚý œÐ�ûå/âGœM‡,@Õã†YsmíÒ᱘ãeÀZ0K„ç_y¥á»×\s�´w¢ŠÒ?äÍ HBÀïÓu"âŸØwÙ´dE 7•ÝNÖ3_(Š¢(ֽƄœŸ:–f²Í ˆ×dزå�^ Ðwl˜K„ˆnÒ4çÿÚ¹Ý žy&08)\BDs²¹ž™[‰è*¯×ÒeÞ œ¡ÅJ·ü‚„ö'…ÙÜ/ï1îw–®Zˆ6 t]/ÂY ÀêJÚ—‘ˆq¶ >%{yµR]]}„¦ÑÆtÙ°´H‰Ãý~ÿ¶}Z6?4jlìf±*EQå+Ï’Àõ»·Ye ®®®°µuç¹Dôk«O§-x ¿ðz½oÙ4Þnápx³Q àè,‡XI;×ã™ÿNºŽ�Ê¿# Ü`j–÷ÊDw9Kê/̃�øŠšû ó¬)%~à÷ûUý0Eé†|)D¨¬¬|[ú�…®4�~iÚrÔËÛÁòJ{g¦(ŠÒïH",ÑñÎÒúY™µµµÅº®_ÖÖÖò6‘ø‡=Á70³½^¿·'‚�§Ÿ~r¤”Æ d|´K‰Ë_}µaFúàƒD´©ìBâ ¨à#•›�%õ?K| ââ¢[‘AðÁŒ{Uð¡(Ý—W+  ëú|!𤅮»:;£‡Ÿzê©Û÷m"Š6•= `¦ÝóSEÉs»ü‹YÜâ÷üúL/~æ™ÀàÎ΋ˆp)@Ãì˜3ÞäÕ>_åc°©˜àÞ‚Áà"¹ ±Y\þŠ”Xà÷û7¤ëرö¤1š&ï0#‹ûô üÅUZUª>¡�þWd0ì«EENš1cFG÷f§(J¾�Á€ô¶¶–|#M×�……®+˜ü€bf*»˜˜^‡ª«(ŠbÅ;`Üæ,ŒÞ�#^Ú§ÖR:¡Pè`fù3"÷ωp€bƧÌòO#Gn½{Ò¤ ¢vŒi&ñÒ,‚�3_[\<ð†3f¤9C"Ú\~‘¦ñõèv�“ì{àÓà¦ÖÖö›ªªªZl3©PHÀY™\ÃŒfÃ�?¬¬¬\›®oçºòÃ…†ûÀ8)ëIöÛHàé¶ûƒÕW‰EVeFTöx<ÏuŠŠ¢y¸RÒÝBà §éꌿð˜6Ž[ym¤±| {mŸ¤¢(JŽb`+€¥!î.œðü¦L¯�§¨Ýy* .!Â4ÛæÅˆXlòO•••ŸØ5n*Á`õyD"£àÀÌøyeee[ênDÑæ²ó…ÀM` Èz’ý¯1 íôÂÒ”ïG ‡ƒ&¿ÎhdÆOTð¡(öÊËÐuý2!¬ä*¯·âߦMÍSŒ²ö*€Ãí›�¢(JΑ Ô‚±ØµÍQ“i]xúé§ŒF; !~à›6Î-`I,&¯­¬¬|ÛÆqS ‡——0k¯Àú–()¥ü­ß_yCºŽfŽÖŒè?:¹{³Ì{ ;œÅÚ½"éö¨E‹‰)S&Ý àgŽ­×ëÿc·f¨(Ê>ò9)7hG{½^Ó‚X‘Æéˆx5€b{g©(ŠÒÇ6²Ä)Ń٬v@0›Øfuì=¿ð0Qìz+ikmF¡P°`«Y¨bRâ\¿ßÿhºŽ‘æò*bÜ `H÷¦˜÷Þ!ðùŽÒ•+Ru î¢"÷CD8=³áéA¯×wz(q�¢ôgy€@(¤/°ØJ_f„}>¿I~ÐDÖOŸO’à´qŠŠ¢(}Ñ ,𠳤þålX´h‘˜<ùX�âb)ù õ™2ÑNDÿ4 þ«ßï߯q- …jtŸÅî³ü¡ÏWHÙkÍôa1'/fÂünO0¿Å˜éF×íÚT«°téÒ¡®åŠ]ž,*pfú䊢d#¯�Ä’ëjÇY¼ä^¯ÿÖd�‘¦é§ø_PAˆ¢(ù†ÐNŒ -q ÐqD¨3›aB¡Ða€\à\Ø»Í ˆ.¿ 7'[±Þª««jšø/†[éÏÌ?÷ù*îHÕÇh,÷K½°´jßo1–I)~g%ų®ëG �€#2¼O¨µµý´ªªªHvÓT%�¼@ ¦¦fŠ¦Ñ‹°PtÑJ¦ „(Š’7$V€ð°³ º,›ô¹@< -sl�ÇŒY°¿Èí—Dt[GGäVóÚMûW0Xs9¥=Ç‘p›×ë¿4U‡hcù¥ ÜŒ<+l³ÕD|•£de½•ΉàÎð>϶¶¶WVUUµg ÀPç˜ÀŸ1ãïÿ˜5«j‡ýãg.lï8$}on r”y<óÕ¤ÀZ´dë-ÿÜÞYæ•g‰ðWGIýSV:×ÖÖFäÌ8;Ó1#ÜÖÖþ=|(JÏëH8Äl¬0Æâ%¤Ät¿ß¿-Yµ¢(Jé P-C>é$YÓ� £ººz âL!p€ãmœãx½”t›ËåzxöìÙ­=s�ìX=û_Q7Žõxæ5›vØ<³0Öû—:ïaªàGXj·ºÆ?¿ÎêE¡Põ)€¸ Ö?ëwcÆ¿ÛÚÚ¤¶])ÊþÑ/‡«§1‹:š•þÌXÐ,ŸÏ÷E²>‰ƒé�AUKW¥ïÙ¢ƒÿí‚#Œ’Ý)ÈGápõT@œÇŒ*ÀþšÌÌ=Э>Ÿ¯}4óP(¤? à ]oôzýWš¶ÎÐbc·<¡‚�}4áa‡Ãq/¾³"éÀ½ƒÁ!Bð_¥äÙ%; [[ÛVUU™_«(J6úMÁ ~-~ŸÁ%¯i³=OÒ}ѱæ“Nf–ÿp@÷g¨(ŠÒ-o$A!‡s`}¶É»„BËÇ9Îdæ3‘ÅSe‹Z<$„¼mîÜÊ�=t[ÔÖ.‹9?Dúí·;#‘ØèùóçiÖm.ÿ;—Ø?ÃÜCÀ‡’h 1?â,­3“k�€V\ì>ÀµH_xØüþDÿëñø®F x%_õ«¤¡a±ó“Oy@™Õk˜±ÊétÍMµ Ò\VJL!ØŸñEQ%•êˆ($¥*·ªÛµ0Âáeß’R;“ˆÎPjÃM1c3ÀwD£Æ½É¾¨÷5¡PÍ…Ý™®Ýàñø®2k‹4–�FDæ…oû Â:?% tŒ¯¯Xf:D8\ãa¦¿—å,b‰ìd–Rõ+Šb¯~€@8&¥ñ2F[½†Ï;�íóS‚\;mxT£©ªµŠ¢ô°÷@ ‰�ÖÙþ&½ÖÖÝ«««Ñ4:#tXM[ž%®pkkkDz\Ûò éøqº~D±o›Fl8ep¤°c=#{b~}Ø6V0㩘a<í>zõGÙלÌL¿03Û1˜ùs!p–ÇSÎv EQº§ß @|[ ­00ƒËÖJ ŸßïOþƒ3p†»õ:"¾ €�E·Eé¿¢VSH r•¬l²cЧŸ~úÀh4zº8ÀIèÙ°-“wúýþ×{ð>=*Ò›•¦Û«^¯ßôp~¤©l�þ`ÿÌú”kAx Œ—¤/UÿV7Ǥ`°ºWá„nŽõ ¾ïõzßëæ8Š¢tC¿ @ ªñ´¥'¼Odx“f5Iˆ­/Ÿ‰ûÕ½Y*ŠÒO½ ðsLâiW{Á0é?¶¤ ]¶lÙ‡Ã'¾`6z>�Æ‹Ì|_[[ÇcUUUÝ9ßëéw[‘>P»ÖëõÿqŸW›Ç¹¢<ä#õÀôz[ˆÑ¢FM²ÑÙÖ±ÖŽU9 ~¸œˆÏøB€ÆÚ0äm­­íW¨LWŠÒûúmº®Ÿ-îCOþuBæûýþ•);¾1ó€¨Ã¸Ä?êî<EÉo|Ì„g¬0H>W8v•mOgu]ÿ& +…Ð*™ù$¢žNΟÑÀq_º‡5¹¤ººú‡C|˜¾'ŸêõV,ßûÕXÓô9 ¶TË¢Ú`€f07’@“²©;éœS ]×§i&2®eZHÐÌ6)ñ3¿ßÿ„ c)Šbƒ~]HÏï÷?¤ëº&î�Å „ˆ$ÂsÁ`ÍÕ>_Å_’vrs8ØR¡EÃÀǦ „ãs ÏÒšÀh‚àF‚Öìèäu8ö…ÏzúÆ555¥šFßð#!p„}ÏF)àpD.ž=ûÔOíQQ”îë×øýþûu½º˜ˆþžAþpý9ÔÇ;�® SeÈr”¾ð4^œ:>2H\E ËÙ3sEQrØð*+%óJ;²UíI×õ"Mã“áa–šF‡}ÕÚsQG"“Õ±˜¼Þ¼yôØ�ú"rXùR¬i²Ãìuh÷œºa'€õ¯D3±lŒ8ÑTtäJóà©44,v~úéÈòø{–+5�¾mó->b–ù|•Õ6�«(Š úõ¬=ƒ5—Ñ Y\Ú$%ªü~ÿ†tÛ×ÎåТ×t6zöÀ§¢(½§ÀëL´š!ë ÎÕ™U³*¾ÊÁs‰Älf.'¢B»ï‘D€å€|àÕW×<{Í5×dœB5UWWápˆ´‡©‰d¹ÇS¹jï×£Me¿èo=3»¤Ú@X¦Fb4‘��Qâf;·øe" ŽŒ€8™§Ô·é$¢Û�ζ?¥Ì\©(J¯RÈt½úR!ÄMÈ<8Øð¯½ÞŠÅ°PÌ(Ò8}‚üGḟʖ¥(¹LXÆ+½ /;ÛÚÖaÒkQ»o ‡0ów‰0›s|Ãî{¤P `Ikk{u®(ÏF¢áÖtý˜åBŸ¯ò¾}ÖO•¼=ô¥ÀzÍDÜhM�ÜT0nõ¦ljlØaÙ²e8�âXfq¬8ñLk#zê~ÌÌDâ1Ã�¿«¨¨ØÔS÷QÅ*ÙK0X]E$P�ÅåÏ ;îÜù›­tŽ4NŸ ˆ¯fà4¨Eɼ™@¯xàW¼†#Wîê‰;éº^àD"œDD'|<2ËÚ×]3ž'ÂMs>9gΜž8pœK(Ò¿@úâŸ^¯ÿ|³£¹Ì#™гœCÀ[`4q£„hf�×lu¼‹+bYŽÙ-uuuŽÖÖÖoÆ8"Q ðx€Ž0f?NãY)ñ;¿ßÿÊ~¼§¢(Ý 555'i-p@—·0Ë+}¾Ê»`a5:›§!Øq)Àç"û&EQìB0Àئ5$x Ö8 ¹ãë¿è©[÷€…'â$fž‰xAÀžN“kæe)å§3öøœ9§mé…û÷Y¡�^`zšnÛ‰´Q�§Ó¬±£¹ü›šÄo!p&ƒMº|`ˆ¶Ë�%D3X6B ÉÕÞñVO¬®YD555£‰hœ(eÆ8"”‹^xŸÆW<¨0®÷zç½¼¿ï¯(J÷¨$‰`08ŽH†Ê¶–ÇJfú¥Ïçk°|źò!QA @|.ã³¼¯¢(™Ù F3kÁô4¹ÆÎZÉÔÕÕ¶´´œ NB¼ªóñÈnåÕ�̼K|>ß»½4‡>/ÒoðËtý˜ùRŸ¯â¶´¾1ó€N-v`�æhƒëĆ‘;Qõx¯W‡…B3GÇb@%D˜ À€ÞžâÛÍ7 ¾¡¢¢Â–¢œŠ¢ì*IA×õC‰°„Ó²Bôp,fü®²²2£ì"‘æ²R0�E„óÀ–åýEùJÀ h’Œf4Üì*Yµ~ì“�©‹MBLeƉ&¡wV8ÌØ(ý[J,ñù|�½5�\’X_a¡ë€˜Ø×«m' SŽûÿíÝ{|œe™ÿñïõ̤iÓ •S9ÊqE¥(»È’™¦âÅu­¸B[<àWÔŸk­®'WQ b)º®Æµ4�É@5Òr räLO[Û&i›™ûúý‘¢Ug’'Éd’L>ï׋0÷õÜÏ/Zò�ç¹ï;Šüxw{ù‰Æ«%ÅÚr¸Âž�t­YbI}}ý�o `h@úÐÞ¾¸fýú¿*ùG:‡»wH~™{ty:�îß·ªO4ÔîܹµQÁηÈÏ–Wôp`4ê”ü1É5³Gƒü…èÁq£Ç+õž|sss¢¶¶öøDB§™E§H:UÒᕸw/‚d¿¡Ð’Ljù9ç4>Ö÷%ØÝ¢E‹¢“Nšþœ™è»Ú»cGþŸÎ=÷Ü—†¾³Þ577O¨««;n×:�ãÔ2ŽWe72è7wï0‹V¸ç¯O¥æü\1_k0ò@bÚµ8ý:I“:‡»6¸‡o„ «û¿põÁ7î×­dÚdiïÙÂ�õ"³\ZgÒ#2{LÁ5…Gò =6þØ;ž•*ûÛÊ•Ëöݹ³æ¤(ÒëÍtŠ»Þ¨¡Ùí¨¿ºÌtkÞRS“_Áalƒ×Úšù²¤Kc–?‚þ9�N?>”=½¬½}qÍš5•Hh× ?^²W«'üŽ–�Nv˜)BøIMÍø½�³`ô"€ôÃÍ7·Bôipë3Üý�’®�¢o§R©�-j}úÇç»ò3Ü5[=Ûù¾r0=#Ô&™ž4דAzÒLOšôp²küï4ýÿ†e�ÿžíEí$³ÄI’^þcýúóç%»%e%­ì÷SWô*“ɼ"ŠôÅÿ2jKaá¬ûîôéóʵ€Ü²ÙìaRáÜu|%^-ùq’ŽÑ0¾Ö7PîÚ`f9)äÆ�Û~ çwÕ�ÒO¹\®V ÿáîŸÐàO’ß"éw»f° ?»>íµ ÁütëyÝc$|û ôe§¤gdzZ®§Lö‡àá 3ûCM¡î �p˰~ûÙÜÜ��øû§¦' y=YûèÏŒ„]$iùòå'“v‚d¯1‹^#…×Hv¤Fæ«+�šÙ-RXY(دxÊQYÍÍÍ&Nœp·zÖQ ÄFI¿“ô¼d]fÁ$ÛKÒ>!h3í+éåêwX/é7’î*¼mòäÉwÍœ9sûp7`ø@¡¹¹yܤIuÿ/ÿ¤™jÊ3«?ã®kÝíétúÙòÌ)íøÝé‡G‘fÈôF¹NPOpâ) £[Ò:IÏÊõ‚Ì_�ô¬›½…è…né¹ £µÃu@Z)=¿nk�w·×HÑ î~‚ä¯5³½‡»·^¬‘ü—’ýJŠþo¤ï®4¬X±âøDÂîÒ(~1òîú½™=ä�ü·…‚~Óß] T?H´´´œ�HDß0Ó™åšs×!K·»ûÿDQ²y(¶ì|lÆ´DÞ¦'¤ãÜt¼\Óe:š�¶ i§K/™i�¹žtÓZs­ ¦'#im¡ 5µ/%ŸiábwmmmÉmÛ¶&é¤pLÙq’�à®cÊ÷…ÁÐp×Z3µ¹û¯Ìm ¿îžð÷²Ù–óÌ¢UÙê‡Ý®ÿ?=m¦%{ÐÝ Auuu=ÒÔÔ´s¸û0ò@Ê(›mi4³Ëv½Ÿ[NyI·Jþ³dvH÷@àì‰ÝÉ®ã]áU‘¢#Üu¸äG¸t„)ÎÖ“ᶪç©Å‹&Ñ¥]¶Î¤µAz.²èùš°c�þá×뇻Ѹš››ÇÕÕÕ%ŽÝµÅè±êYŒ;š䮓¬M ¿ Á~•N§î†Ï®²Tƒ_8"í êç°Ê‡Ýíw]]]755mîÞŒ^�2ë97ä€JöI{ Á-‚¤{Ü=gæ­ �íªÔÞèwž:aÇ^‰ƒyMsé`‹ü ÷hšI¯t÷}eš*iIS*Ò¤ž3/6H¶Þ{BÅF—­�L<èÅ(ò�Á¢õùîĆ u^Ô‘­;†»á�Êårû …#ÍÂQQ”x•»ã®ãÍt„FÑîî’="é3¿#ŠüNÎäÝ2™Ì[¢HK52N ¨M’2Óƒ!øƒ!è¡|>ÿàH8Ç@õ!€ ‘eË–M?~ÜGÝýƒÚµë$݂ڒÉümçœó–§‡ð^ñ4¿=¡£_˜º3JN�¢05ȦZð©&›¢°�ɦšûT—MUω»“vûcD¿3D\ÒfI›äÚ,óÍ&Ûì¦Írm6ùf·h³‚oŽd ‘o,XX7¾sÇ‹š~oU->^¶lÙÔÚÚèHw{•Yt¤¤WIzùÏ£2Øö¦f÷HºÝ=üZJÜ1àí·1be2™c¢H?Vy6&J�’Ö®'Rô»(Šª¯¯~¸0v@†XÏ™‰‹%]\¡E®ÏIú•»¯v·ÛFß«éw3öìç;m|”´)–/Ô*M M–Y­™ï¡  f¤)&¯•l÷C÷°ÝÞɲ=Íý/;™í)Ûíï]S$ýe[UÓd¹v?(2/Ûíï]¹¶ìêv«\ywm“©[ò—íŒÌ:å¾ÃÍ;$ëpi[|³,êt+t„B´¥¶6¹E[·vV[ˆèÍ®ƒÒ2³CÌÂ!fÑ¡’)ّ IDATþª¾<®§Ìt·»î”Âuu{üvæÌ™#v­ ʧ­­m|gç¶�»û¥f6¬ź«ÛL�Jö�{xÐÝ!<ø›ßüæI¶¼0Ü ÒÒÒ29‘°÷KöÑ][,VÊKfjw×}!è>woŸ={öS¼?Æ�\.W[(^iV8DЉ¢è•î~¨ä‡Jvˆ¤U] v_�t¯¤vw»gçÎ�÷òÊ r¹ÜAî…�K:_C¿Û`p×SQ¤ß¹ë¡ô ™=´ÿþ/2¬\¹râŽ;öM&µŸ»^!é!ø¾‰D´oÏ_k3ßW²—O[ž0¼«NIšùýîö@º?‘H¿å!L‰¢èå'RuÚõÃ}…šÂn¯ÍÙŸÏ|1³‰îçîÌl¼™íÙs�M”|ò®¿ÞõêE¨Ýumí®ù÷Pu-Ò®¨ž�ü 3{(=*…‡Í’�šÙ#õõõ£ö ª d”Èår…�oˆ";Ç]gid¬†Ë6ÉŸ�¢G%8=ºkçŸ'Øù€‘�2 år¹Z÷î3̳Üý I¯Ó(: ˆ©SÒîzÜLO¸û!è w¼±±qÍp7†RzÎIœjæ3$½IÒëÅ:Œ[$=Óó4ÞAO˜…'¢¨æqNf :@ªP[[Ûø®®-ÓÝ£éf:Ñ]'J:V¬-@…¹û%{&ŠôŒdÏ …§¥è™D"<BâiΞ`ì!€Œ»ïAE‰×J~¼»Ž+g;`HtIzAòµîöœ™Ö„ž�"{Ú=zºP(<ÓØØ¸u¸›# dŒËd2šŽ•¢c£ÈŽu×1’Žªî­Ñ‡à®õf¾ÆÌÖ¸Ûóî…uföœ{´6„ðü¸qãÖž}öÙîFÀèCAQ¹\®Ö¬ûÐB!q¨»E:DÒa’u×ÁfÚOR4Ìm"¾­’ÖKzQ²%m4ÓºÂFÉ7ši£”\BxqÒ¤IëgΜ™æ~@•"€`@š››µµµû%“šBt€¤£Hû¹ë@3í/ÙÞî>ÕLS{þÌÓ”Árw7³Íê97e³»6«ç¼”Íf¶ÙÝÿBØÜó÷Úh¦õRÍ‹’^ä 0R@PË–-›Z[[;Õ¬°w>Õ,ÚSòÉîšEÑdwŸl¦I’&ï:á{ÉÇí:°Oîšd¦I5g ¼ܵÝL]’o‘lGÏ!‹Þ!i‡d›%ß.©+„°EŠv˜ù63Û&yG¡Ð,¢(ÚÏNY -€!•Íf�5óû$ÕÆ©7³ËêëSŸ’ԯߜvhx…¤Ц$É]·»ë¼t:ýÂ@ç½c,CfÑ¢E‘™_§øáã;õõ©OªŸáC’o««›tRú¸»wô÷úžûë43µg³ËÏÈõ oCæõ¯?ñÃ’N‰Y~Û„ ?6˜ûÍœ93ŸN§¿‚N�4 ®Ì´¯Y"—Í®ø´¤¡:¡€1‹W° ‰\î¦#Ü“÷Kª‹QÞe–?áo›V6Ûò³èë’¦pŠutt]ÐÔÔÔUξË †‚µ¶f~.ifÌúKÒ_+:‘dónXõï’]")éæ¿–G7øôi?]¸P¡¯‰W®\¶o>?î›’Ÿ¿ý¿rw"±óܳÏ~ëÚ^vCPv™LfAé»1Ëïîèè:­©©©PlpÞÒÛ¯0÷zÈMYÿÒ¯wD‘Þ^_?;ןëÀ_° €²Éd2ïUü§ ì¿ÿº¯”´�É+/|HÒD™îÕùÇ{.Zºê }Ôz*5û›îvš¤§bÎßÓ“ÙDw[ÖÚºbN®ÁeqË-?; P÷ ¤½b”çCÐÓéô}Å,Y=ÛM-l%ï®ËÇoݺðŠÕïè­pÙ²eSkkknTÿ_ÉÚ‚šÒéôŠöÀ˜Åe¸+/|È̾V*|¼wIÛ7]5ˆV’fºtÇ“ï�ÿýU'öVxî¹ç¾ÔÑÑ5ÛÌ.ïç=ÆE‘š[[W¤Ñ'cO@ Z6ÛržYôßqjÝõØÄ‰“^7sæÌíÅÆçݰú“æ–©µ�2_4í•…ËΜ™ï­°µ5ó/î~�™�ïÏü!(•N§>È>3 %“ɼ"Šü¡˜ÛÛ†tz:�¾³Øà¼¥·×›{k™[”d·)λæ_Oïõ,�+V¼)Šì&3íÙ�É7¹Û›Jíäþ¯`”(ҷ⟭aW” ÿð®=Ìýšröö~† öÛ7¬zsoU³gÏþ•»fJZ×�É÷2 ­¹\î AµÀA0`ÙlK£¤wÆ©u×Bðϔߑïþš¤ƒËÕ[ûºìæKW_j’•*J§Ó÷»Û wý!þÔv�{!³råʉåh€jÆ+XäÖ[›÷ܹsƒ’ì«ÖÝ] g§RsŠžZ~á÷o;3Š¢[ÕK0(+ÓÏ’òï¹²iæ¶R%¹\î ÷Â/$Ù�™ÖÐ�n’Äo¬”ÀÒÝ=áŠ>$É,ººTø˜¿¸½.Š¢ÅªTø�$×[ �ɶ‹n¼£ä9#õõõÏ›%Îìß“½5›]qI: j@ô[&“™‚Ÿ³üY³èS%Gk»¾,éˆrôÕ.M!üzÁ’Û^Uª¦¾¾þù|¾p¦¤çâÎkf_Îf³§—¥Iª¯`è—•+WNÌçwÞ/éðxW„†††Æ›‹�,XzÇ)îa•¤Dù:ì·õAJ]ûží¥ r¹åÇ…Ýff{Çœó©|>¼¶±±qk™z jð@¿äóÝ—)vøÐ’Ráã½KÚÆ»‡ë5¼áC’ö‹¤_Î[ºú¬Rõõs6 )I�1ç<,‘ˆú{¸!c@l+V¬x“äóãÔºk­»•\Q£äç$SžÎm²¹²óoX•*UÐÐ0ç®ô>�ùØØLd2™†òµ@uà,±d2™º(ÒosW(÷ð¶TªñgÅÆ.ZzÛë‚GwIª)g�eÐBH_ûÞ3~Qª µ5óUIÿs¾'ëê&ýC©Sß‹x –DBŸWÌða¦— ‹ÚÚ’ÁßÓÈ ’4!Š¢óo\}r©‚ŽŽ®OKVtG¯"ïèØ7¬0&@ô©µuùÉîúpÌò�‰DwÉÚ5O'?#ùëÊÔÚP¨Sв‹–´Zl°©©©`½Ë]âLf}òæ›o*:c@¯r¹\­÷<±ˆ¹XÜ?Rj0™ìþ¸¤Í1æIDѨxòÀ�#€(ª½}qMù÷Íâ.—Ô××?_läý×ß~´»>WÆö*Ⱦ:oɯ/62kÖ¹Ü=îëUÿšÍf㞟@Õ"€(jýúi—JöÚ8µfZ™J5~¿ØØ¢EŠ ¿NÒø²6X95fá†�5ß9¡Øàþû¯½RòGbÌ“ìǺªÀßÉd2Ǹû§ãÔº{Gö~IEzá°Õ’4£œý ƒc;;óÿQl`úôyÝîþ…˜óÌmkk­A €² €ø+‹-ŠÌt­™ÅýAùÒT*õd±�‹–´j®ÿ,c{ÃÆe—¼ÿúÛ�.6vソù‰¤cL3µ³së¹åí €Ñ…௼þõ'~ØL§Å,¿íÞ{ﻺ؀IæQÍ÷$ÝÊvWHøX¸paA_�7�]PΦm̽è[Æ ›o¾éÐ’(^hè A¯K§Ó�\°äön~Uy;~‘|ÆUï9ýö¿ý¼½}qͺuÓž6Ó}L¤è †††uCÔ"#O@¼Ì …äuŠùÄÂ=,,>.Zzç�nþå²v7BEE·Ó�>}^·™–Ƙ"r/¤ÊÜ£€$)“É\`¦3c–ßÝٹ㛥ƒ®•4¥<��4Þ0Ém¯.6’χïyŒÇÊfÑìò÷Àè@ \.w�™.‹Y¾³Pð÷555Š Î[²ê|Iõåêm2Yâ½ÅŸ0³{ûžÂÏjnn.º­/ÕŽ@î…o›iÏxµá‹³gÏ~¨ØØ–´íof——·»‘(Ì}{óÃãJ ®ˆ1AÝĉµE7 Ú@€1.“ɼKÒœ˜åtvî(¹ÛSÁ’ß•´wYÑlêÞ›Î*6’χ–xsD'—³#F 0†­\¹lß(RÑ­e‹ÈKႦ¦¦�Å,½ý.�™3.ÜBÑ×Ì�ÔçWîzCÙ›` €cX¡Pó-I¯ˆSkfßhhh,º¾áƒKïžêîß*ks#žõ¶“Õ]}^mÎÀ˜DƨÖÖiw½#^µÿ~Û¶ÎE¥FwúÎoKÚ¯L­�‡]ð½;)6àî÷ô}¹ÔÒÒ2¹ÜM0Ò@€1覛nš"YÑÌ‹îÑ…MMM]Åç-]�6é�eloÔˆ’…“Š}îg',)‘H 0T30ÕÖ&/—4-N­™}7•J­*66ñ­{š«êN;�+’¦—z*Þ `Ì!€cL.·âÌüüxÕþLwwáÿ•?þ’*Kc£�— ]]]ÏH }Ï`À˜CÆ�æææI!Øuff}Õº»‡`ó·_pê7ËUô@¾±ÃІ¯];…õ¹VEcmÝ `,™4©îKf:4NmÙ’t:½²ØØÜWNtÙbI}™*7¥—±?Ƹ¾¶\�0Z@€1"“Éœâîï�Y¾.ûx©Á aâ×$^žÎFµ^N�÷}]ìîãËÙ £ÚÚÚÆG‘¾§˜¿æCÐR©Ô¦bcón\õ&Éç—µÁÑ«ÎJ<r·í}]læÊß#:;·}VÒ11Ë’N§—˜¿¸½Î‚®¿w¼l“K^lÀL5}]ìn1ªP]ø!¨r­­­¯u×%1Ë_ÊçÇK ú¸®/Hvd™Z«{Û«¯‹Í,Î:ª ¨bíí‹k¤Âõq¾�—$÷ðÑÆÆÆõÅÆæß¸úd3• 'c“¿TrÄ{[òr�Ýa €jFªØúõÓ.•ìµ1˳©T㊠\üí\­‚®—”(_wÕÀž)öi&“©3Ó+úº:m.OŒl Je2™cÜýÓ1Ë·twJî�µcòŸ•t\y:«&~w±O£(:J1~M$¼h€ š@€*ÔÜÜœ0Óõfs›W¿tΜ9ÏYpýê×ÈüßËÙ_µÝ[ôóŽŽu}ˆ+oGŒ|  Mœ8þb3½1fy[CÃìÅÅæ/n¯ñ„–HñÖ�Œ1…q»Sl ‘Ðëc\¿£³³“' €1‡T™l6{¸»>³¼Ó,¡Jl%ëµ�Ÿ’w ɘâÒª+›fn+:æ:-Æ�555ÊÜ#¨.&ùb3›§8}¶¾þ-(6vá�·k²O•·½êaÒO‹}¾råʉî:1Æ ¿.wOŒ Šd³+.4Ó™1ËïêêêúV±�E‹E]')æ’1'ä Vô°ÆîîígÇÛö8Ü^î¦  @•hii™&ÙWc–ï(ü‚R¯½pèí“ëÔ2¶Welõ÷þí´5ÅF¢(jŒ3ƒ{DŒI JÔÔDŸ1ëûð»]¾8{ö쇊 Ì[ºú(“Ç]C2&¹‡«Š}ÞÜÜ<.Oǘâ©T*õd™Û`T €U —Ëíã®÷Ä,`¿ýÖ}R²h‘"s»VÒ„òuWuÖØÎºÿ-6PWW;ÇÌöîk3}} €±€T�º(^hÈ»Ûû¦OŸ×]lpí!«> ùåí®Ê˜_yͼéEÿýIÑùq¦Èç}E;`T!€£\.—«5‹Jžbþ7¾žJ¥Ú‹ \´¤íP7ûR[«F�ª)=3¥µµõ3Íêkwmؾ}ûêò·Àè@F½ü™’öë«Ê]¨«›Ttm‡I,q�¤Iå¸}óšwÎÜX|0\,)Ñ×fú!çÆ20ʹ[*N�™}æÌ™Û‹�]¸dÕ’õùíý·©Pˆ./6�Ëåö�ô¾8“äóᆲvÀ(CF¿1j6vtl_Zlࢥwh}­Ì=U÷/_÷¾SþX|¨p±¤=bÌrwccãåm €Ñ…ŒbÍÍÍã$Ów¥5755u ^ø¬äq·ï«ž�81ù�b7ÝtÓI�3IúnY»`"€£Øäɵ‡I×weøE±O?ðýÛ–t~Y›ªBf~ñ7šN)àjkk>*i¯Ó¼ÐÕÕõ?åí €Ñ‡Œbù|ëÉE¡ G‹^ÙÛ+ÀŒ]&-»zîéË‹�-_¾ü`w¿$Î<îþ�¦¦¦�åí€Ñ‡Œn“ã%“É?‰^UÎfªÐÖB2q©ÁššäW%ÕŘgSmíö«Ëףި°-N]¡P˜Zìó¾-iCY›ª.Ÿ¹ö]3Ÿ/6�ÍfOwïˆ9Ï�uVS‰ÀØBF±în­‰Sgæ'ûüÚwŸñˆ<ñ&I•µ±j`ºcÚÓ3Š.í™gJú°¤Žrô7Ú¸t÷¦‰ë¾Qj¼P¨ùŽâm»+÷ècÓ§Ïë.[sTs÷áîÀ d³ÙÃÍüQIÉåOtwÞ')?¨&G ·O– Ë–-›j]s¦ù|áãeì €ªAª@¡.“Š/˜þ{v�”øUkkfa[[ÛøÞ*Μ™¿fîŒEîÑ©2=V†VG,w[¾øüÓJîVU[[ó IûŜ(OgTP�TtËØÆIZØÙ¹íþL&óæ¾ŠŸê=]Ö9]¦ÜäÈöûñ5ɹ.}'5›m9OÒ»cÎõDúÏòµ@ua P%ÚÚÚÆwtl»×LÇõÿjkN&w~hÖ¬sû<”pÁ «çºt•â�>t¹G§.>ÿÔßÌf³‡KÞn¦=ûšÈÝÝÝf¥Ó韗¿MªO@€*1sæÌíîz—¤-ý¿Ú›º»“g2™wõUyõ{f,µ‚N•ôxÿï3ò¸k~©ðÑÞ¾¸ÆÌ'|H’™-&|Ð;PEÒéôýîá\I;û{­™íEº±µ5ûã[n¹eïÞj¯þ·÷×&kN’ìÜìH`úÊâóg”|­lÆ¿ ©Ïû»¬Ù¹3ÿ©ò4@õâ,  e³-�fÑ�$Màφ óÓét[oE&Ùü¥«?á®/i´}¡áþãiÏœþ/¥N;ÏåVÔ»Û ÅþçòƆ†Ù™2v@U"€U*—k9ÍÝ~&Ù>œ"HúBGG×655z+\°tÕÛÜm‰¤‰¼W…Ùmµ[¶ÌºâCõ;Š�Þ|sËÑ!DwJšsÂï54¤/,_T¯Ñõ�%€ØêëoÁN”tÛ§ˆ$-œ8qÂÍ---½n?{õÜÓÌO•ìéÞ«’NÔø[J…�›nºiJ¡ݤØáÃI&Ç}¤ŒýPÕ @K§Ó/ÜsOû™!„‹Ýõ§Nóæd2jomm9£·¢kçžþ@èN¾Qò;xŸJxV‘Õ÷_fl*6ØÜÜœ7.ñ#3g2wßžÏû;gÍšÕQÞ6¨^¼‚Œ---Ó’ÉÄIÞ4�ëÝÕm¦�54¤¯ì­îâoçjwì9ùZyìs3*eƒ<ñ¦kÎ?åÑR­­™Ë%}´s~¨¯à¯@€1¦µµå÷èÛf:b ×»ëºÎή655•Üik.NßEÑ?^õîS,U�É´|0Š¢+âNh¦›êëÓÿ¬‡€âFÂ*¨¡¡ñæÎή$»Êð „™.¨«›ðóÖÖÖýKÕ¸äWÏ�ñU3‡¤ÎA5ÝÛy!ï»þöÉ5 ÿo—Òo3¶Í2{ë5sOûe©‚ÖÖÖ£¤Âªþœ“Bød:ÝxYyZ`l"€ø³l6{º™ÿ·¤pùÍf‰óêëë·”*x{ssbJÇ—™écï²OϺ¬añ{N{¨TA&“yUùÏ%;¨óþ ¡!=· ý0¦@ü••+—í›Ï×üDR¯ç~”pww¡qΜ9ÏõV4éíï‘û5ŠÿêS\«•ð·_󯧯-U�Édމ"ݪþ­{¹­®nÒ93gÎÜ>øÛ þN{ûâš ¦}Ë] pùºô–>§Õ‰Šì&I¬Ë¿³xSÝÞúIÓq%·Îå–瞸Uý[ÿÀ¸q]o:묦�ävCPR6»bž™]!i\?/Ý‚.H§Ó?ì­è¢¥w<¿L²×¼Km2óyWÏ=ý§½e³Ùc%¿ÕLôc�3Î>û­%Ÿ¨€þa,%¥R³»Û?¹kC?/­5ó¥ÙlËH²REWÍ=å…Ú-ÛN—û éÏÌ~’ùb„�éf¡­?áÃ]BÐ9„Ê‹' ú”Éd^Eú™¤ûµÿ°®nò…}­Ÿ˜êOHö%I‰“n6÷ÏðÌéW.\¨Ð[a&“™mæÿmfûÑôVw;3•Jµ÷ã@,™L¦.Šì:ÉÏÀåwçóá­���kz+Z°dõ9nú‘¤)%J‚L? ;kþýÚ N^ßwÏ-Ž¢èëŠj^Öiæ�õõ³Ñ�k@Lýñòy!_Tÿ_á\#þ¹¡aÎ]½Í_rç1²B‹¤WíöñfÉ—¸ÙU‹çÎø}_7jkkßÙÙñÉÿ­Ÿ=>bý–ÉdÞEº^Ò„þ\çîÛ%Ÿ—J5þ ·ºù‹oÝÓj'¼Í=ì-ÓÃÚQ÷ËkæMïŒs�›on9:„èÇ’NèOoêyí*�J¥Võó:ÐÒÚºüd)±LýÛÒöeWttt]ÒÛÉé`ÙìŠ %]ÞÏõ’´-5¦Óé¶2öŠ €°]‹Ó—KzÍ.o7®ë]å8_£çds}WÒ›û{­»þdV8§¯WÃ@y@ Jssó¤I“&üÐ]³pù£!hN:�~| ÷^¹råÄB¡ûSî~‰pªº»6˜…tCCã½¹?è?€AknnNLš4á«îúØ.߂ޙN§Wƽ ½}qͺu¼×LŸ‘ì ÜS’?R((={öì§v=€²Éd2ïÝõ*T¿žF¸»›Ùw’Éî/ΚunÉC[ZZ¦%“Ñ»$-�tØ Zý¥»½-•JmÄ` Ê*›]~ªYâ§Øâô.É–»ÚÍ¢µî¡Û=š�HØÑ’Ÿê®êß™EØ7÷Ûï…K§OŸ×=¸yÀ@@”].—;È=¿L²éÃÝËËܽCò S©Æÿî^Ëú{�ô©¾¾þùŽŽígH6B~Ø÷v)zá€áÇCi0'§—C^Òå] ›ššvÃýÀß €r™Lfvé’&Wð¶÷Ia[ì0²ð €!—N§WH…îzº·{Iò‹î¹§ý „Fž€¨˜eË–M­­­¹RÒÛË=·»o�¢èšíÛwþç¹çžûR¹çåAPqÙlËyfvÙÀü‹]ÁãºîîÂW×”£?0t †E{ûâšµk§½ÓLŸ0ÓqýŸÁÛCðHÑÓéôÆòw†À°Z´hQ4}úô“£HgKš.éXõbX·[ÙIOHzXòÛÝ£ÿK¥ROC»`� F¤æææ uuuãS©Ô¦áî”@Ű /€Š!€¨€Š!€¨€Š!€¨€Š!€¨€Š!€¨€Š!€¨€Š!€¨€Š!€¨€Š!€¨€Š!€¨€Š!€¨€Š!€¨€Š!€¨€Š!€¨€Š!€¨€Š!€¨€Š!€¨€Š!€¨€Š!€¨€ŠùÿªŽaöCbeIEND®B`‚harfbuzz-uharfbuzz-7a648c4/pyproject.toml000066400000000000000000000031051526670067500206560ustar00rootroot00000000000000[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. # Pyodide 3.15 wheel fails to import. # Minimum supported CPython/PyPy is 3.11 (see setup.py). skip = [ "cp38-*", "cp39-*", "cp310-*", "pp310-*", "cp3??t-*", "cp*-macosx_x86_64", "cp*-macosx_arm64", "cp315-pyodide_wasm32", ] 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" harfbuzz-uharfbuzz-7a648c4/requirements-dev.txt000066400000000000000000000001511526670067500220000ustar00rootroot00000000000000cython>=3.1 # we need wheel >= 0.31.0 to support Markdown long_description wheel>=0.31 pytest coverage harfbuzz-uharfbuzz-7a648c4/setup.cfg000066400000000000000000000000421526670067500175600ustar00rootroot00000000000000[metadata] license_file = LICENSE harfbuzz-uharfbuzz-7a648c4/setup.py000077500000000000000000000202011526670067500174530ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import platform import sys from io import open from typing import List from Cython.Build import cythonize from setuptools import Extension, setup def is_emscripten_build() -> bool: """Detect if we're building for Emscripten/Pyodide.""" return sys.platform == "emscripten" or os.environ.get( "_PYTHON_HOST_PLATFORM", "" ).startswith("emscripten") 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.11' below limited_api_min_version = "0x030B0000" def _configure_extensions_with_system_libs() -> List[Extension]: import pkgconfig include_dirs = [] define_macros = [] libraries = [] library_dirs = [] harfbuzz_components = ["harfbuzz-subset", "harfbuzz-raster"] 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]: define_macros = [ ("HB_NO_MT", "1"), ("HB_HAS_SUBSET", "1"), ("HB_HAS_RASTER", "1"), ] extra_compile_args = [] extra_link_args = [] libraries = [] sources = ["harfbuzz/src/harfbuzz-world.cc", "src/uharfbuzz/_harfbuzz.pyx"] emscripten = is_emscripten_build() if use_cython_linetrace: define_macros.append(("CYTHON_TRACE_NOGIL", "1")) limited_api = use_py_limited_api if limited_api: define_macros.append(("Py_LIMITED_API", limited_api_min_version)) if platform.system() == "Windows" and not emscripten: define_macros.append(("HB_HAS_DIRECTWRITE", "1")) define_macros.append(("HB_HAS_UNISCRIBE", "1")) libraries += ["usp10", "gdi32", "user32", "rpcrt4", "dwrite"] else: 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")) if platform.system() == "Darwin" and not emscripten: define_macros.append(("HB_HAS_CORETEXT", "1")) extra_link_args.extend(["-framework", "ApplicationServices"]) extension = Extension( "uharfbuzz._harfbuzz", define_macros=define_macros, include_dirs=["harfbuzz/src"], sources=sources, language="c++", libraries=libraries, extra_compile_args=extra_compile_args, extra_link_args=extra_link_args, py_limited_api=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=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() def _generate_field_docs() -> None: import ast import re import textwrap pkg_dir = os.path.join(here, "src", "uharfbuzz") output_name = "_generated_docs.pxi" output = os.path.join(pkg_dir, output_name) # Locate `class Foo(... NamedTuple ...):` headers; the body is parsed as # AST so it tolerates any consistent indentation. class_re = re.compile( r"^class\s+(\w+)[^:]*\bNamedTuple\b[^:]*:[^\n]*\n" r"((?:[ \t]+.*\n|\s*\n)*)", re.MULTILINE, ) assignments: List[str] = [] for fname in sorted(os.listdir(pkg_dir)): if not fname.endswith(".pxi") or fname == output_name: continue with open(os.path.join(pkg_dir, fname), encoding="utf-8") as f: source = f.read() for cls_match in class_re.finditer(source): cls_name = cls_match.group(1) body_nodes = ast.parse(textwrap.dedent(cls_match.group(2))).body for i, node in enumerate(body_nodes): if ( isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name) and i + 1 < len(body_nodes) and isinstance(body_nodes[i + 1], ast.Expr) and isinstance(body_nodes[i + 1].value, ast.Constant) and isinstance(body_nodes[i + 1].value.value, str) ): doc = " ".join(body_nodes[i + 1].value.value.split()) assignments.append( f"{cls_name}.{node.target.id}.__doc__ = {doc!r}" ) content = "# Generated by setup.py; do not edit.\n" + "\n".join(assignments) + "\n" # Only rewrite if changed, so Cython doesn't rebuild needlessly. try: with open(output, encoding="utf-8") as f: if f.read() == content: return except FileNotFoundError: pass with open(output, "w", encoding="utf-8") as f: f.write(content) _generate_field_docs() 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.11", ext_modules=cythonize( configure_extensions(), annotate=use_cython_annotate, compiler_directives={"linetrace": use_cython_linetrace}, ), options={"bdist_wheel": {"py_limited_api": "cp311"}} if use_py_limited_api else {}, ) harfbuzz-uharfbuzz-7a648c4/src/000077500000000000000000000000001526670067500165325ustar00rootroot00000000000000harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/000077500000000000000000000000001526670067500205525ustar00rootroot00000000000000harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/__init__.py000066400000000000000000000051321526670067500226640ustar00rootroot00000000000000try: from ._version import version as __version__ except ImportError: __version__ = "0.0.0+unknown" from ._harfbuzz import * __all__ = [ "Blob", "Buffer", "BufferClusterLevel", "BufferContentType", "BufferFlags", "BufferSerializeFlags", "BufferSerializeFormat", "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", "OTNameEntry", "OTNameIdPredefined", "OTVarAxisFlags", "OTVarAxisInfo", "OTVarNamedInstance", "PaintCompositeMode", "PaintExtend", "PaintFuncs", "RasterDraw", "RasterExtents", "RasterFormat", "RasterImage", "RasterPaint", "RepackerError", "SerializerError", "Set", "SetIter", "StyleTag", "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", "serialize", "serialize_with_tag", "shape", "subset", "subset_preprocess", "version_string", ] harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/_blob.pxi000066400000000000000000000052451526670067500223570ustar00rootroot00000000000000cdef class Blob: """Binary data containers. Blobs wrap a chunk of binary data to handle lifecycle management of data while it is passed between client and HarfBuzz. Blobs are primarily used to create font faces, but also to access font face tables, as well as pass around other binary data. :param data: The binary data to wrap. If ``None`` or empty, the empty blob is returned. Wraps `hb_blob_t `_. """ 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 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: """Creates a new blob containing the data from the specified file. The filename is passed directly to the system on all platforms, except on Windows, where the filename is interpreted as UTF-8. Only if the filename is not valid UTF-8, it will be interpreted according to the system codepage. :param filename: A filename. :returns: A new :class:`Blob` with the content of the file. :raises HarfBuzzError: If the file cannot be opened or read. Wraps `hb_blob_create_from_file_or_fail() `_. """ 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: """Fetches the data from a blob. :type: bytes Wraps `hb_blob_get_data() `_. """ 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] harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/_buffer.pxi000066400000000000000000001116351526670067500227130ustar00rootroot00000000000000class GlyphFlags(IntFlag): """Flags for :class:`GlyphInfo`. .. attribute:: UNSAFE_TO_BREAK :value: 0x01 Indicates that if input text is broken at the beginning of the cluster this glyph is part of, then both sides need to be re-shaped, as the result might be different. On the flip side, it means that when this flag is not present, then it is safe to break the glyph-run at the beginning of this cluster, and the two sides will represent the exact same result one would get if breaking input text at the beginning of this cluster and shaping the two sides separately. This can be used to optimize paragraph layout, by avoiding re-shaping of each line after line-breaking. .. attribute:: UNSAFE_TO_CONCAT :value: 0x02 Indicates that if input text is changed on one side of the beginning of the cluster this glyph is part of, then the shaping results for the other side might change. Note that the absence of this flag will NOT by itself mean that it IS safe to concat text. Only two pieces of text both of which clear of this flag can be concatenated safely. This can be used to optimize paragraph layout, by avoiding re-shaping of each line after line-breaking, by limiting the reshaping to a small piece around the breaking position only, even if the breaking position carries the :attr:`UNSAFE_TO_BREAK` or when hyphenation or other text transformation happens at line-break position, in the following way: 1. Iterate back from the line-break position until the first cluster start position that is NOT unsafe-to-concat, 2. shape the segment from there till the end of line, 3. check whether the resulting glyph-run also is clear of the unsafe-to-concat at its start-of-text position; if it is, just splice it into place and the line is shaped; If not, move on to a position further back that is clear of unsafe-to-concat and retry from there, and repeat. At the start of next line a similar algorithm can be implemented. That is: 1. Iterate forward from the line-break position until the first cluster start position that is NOT unsafe-to-concat, 2. shape the segment from beginning of the line to that position, 3. check whether the resulting glyph-run also is clear of the unsafe-to-concat at its end-of-text position; if it is, just splice it into place and the beginning is shaped; If not, move on to a position further forward that is clear of unsafe-to-concat and retry up to there, and repeat. A slight complication will arise in the implementation of the algorithm above, because while our buffer API has a way to return flags for position corresponding to start-of-text, there is currently no position corresponding to end-of-text. This limitation can be alleviated by shaping more text than needed and looking for unsafe-to-concat flag within text clusters. The :attr:`UNSAFE_TO_BREAK` flag will always imply this flag. To use this flag, you must enable the buffer flag :attr:`BufferFlags.PRODUCE_UNSAFE_TO_CONCAT` during shaping, otherwise the buffer flag will not be reliably produced. .. attribute:: SAFE_TO_INSERT_TATWEEL :value: 0x04 In scripts that use elongation (Arabic, Mongolian, Syriac, etc.), this flag signifies that it is safe to insert a U+0640 TATWEEL character before this cluster for elongation. This flag does not determine the script-specific elongation places, but only when it is safe to do the elongation without interrupting text shaping. Wraps `hb_glyph_flags_t `_. """ 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: """The structure that holds information about the glyphs and their relation to input text. Wraps `hb_glyph_info_t `_. """ 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: """Either a Unicode code point (before shaping) or a glyph index (after shaping). """ return self._hb_glyph_info.codepoint @property def cluster(self) -> int: """The index of the character in the original text that corresponds to this :class:`GlyphInfo`, or whatever the client passes to :meth:`Buffer.add_codepoints`. More than one :class:`GlyphInfo` can have the same ``cluster`` value, if they resulted from the same character (e.g. one to many glyph substitution), and when more than one character gets merged in the same glyph (e.g. many to one glyph substitution) the :class:`GlyphInfo` will have the smallest cluster value of them. By default some characters are merged into the same cluster (e.g. combining marks have the same cluster as their bases) even if they are separate glyphs, :attr:`Buffer.cluster_level` allows selecting more fine-grained cluster handling. """ return self._hb_glyph_info.cluster @property def flags(self) -> GlyphFlags: """Glyph flags encoded within a :class:`GlyphInfo`. :type: GlyphFlags Wraps `hb_glyph_info_get_glyph_flags() `_. """ return GlyphFlags(self._hb_glyph_info.mask & HB_GLYPH_FLAG_DEFINED) cdef class GlyphPosition: """The structure that holds the positions of the glyph in both horizontal and vertical directions. All positions in :class:`GlyphPosition` are relative to the current point. Wraps `hb_glyph_position_t `_. """ 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]: """A tuple of (:attr:`x_offset`, :attr:`y_offset`, :attr:`x_advance`, :attr:`y_advance`). """ 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: """How much the line advances after drawing this glyph when setting text in horizontal direction. """ return self._hb_glyph_position.x_advance @property def y_advance(self) -> int: """How much the line advances after drawing this glyph when setting text in vertical direction. """ return self._hb_glyph_position.y_advance @property def x_offset(self) -> int: """How much the glyph moves on the X-axis before drawing it, this should not affect how much the line advances. """ return self._hb_glyph_position.x_offset @property def y_offset(self) -> int: """How much the glyph moves on the Y-axis before drawing it, this should not affect how much the line advances. """ return self._hb_glyph_position.y_offset class BufferFlags(IntFlag): """Flags for :class:`Buffer`. .. attribute:: DEFAULT :value: 0x00 The default buffer flag. .. attribute:: BOT :value: 0x01 Flag indicating that special handling of the beginning of text paragraph can be applied to this buffer. Should usually be set, unless you are passing to the buffer only part of the text without the full context. .. attribute:: EOT :value: 0x02 Flag indicating that special handling of the end of text paragraph can be applied to this buffer, similar to :attr:`BOT`. .. attribute:: PRESERVE_DEFAULT_IGNORABLES :value: 0x04 Flag indication that character with Default_Ignorable Unicode property should use the corresponding glyph from the font, instead of hiding them (done by replacing them with the space glyph and zeroing the advance width.) This flag takes precedence over :attr:`REMOVE_DEFAULT_IGNORABLES`. .. attribute:: REMOVE_DEFAULT_IGNORABLES :value: 0x08 Flag indication that character with Default_Ignorable Unicode property should be removed from glyph string instead of hiding them (done by replacing them with the space glyph and zeroing the advance width.) :attr:`PRESERVE_DEFAULT_IGNORABLES` takes precedence over this flag. .. attribute:: DO_NOT_INSERT_DOTTED_CIRCLE :value: 0x10 Flag indicating that a dotted circle should not be inserted in the rendering of incorrect character sequences (such at <0905 093E>). .. attribute:: VERIFY :value: 0x20 Flag indicating that the :func:`shape` call and its variants should perform various verification processes on the results of the shaping operation on the buffer. If the verification fails, then either a buffer message is sent, if a message handler is installed on the buffer, or a message is written to standard error. In either case, the shaping result might be modified to show the failed output. .. attribute:: PRODUCE_UNSAFE_TO_CONCAT :value: 0x40 Flag indicating that the :attr:`GlyphFlags.UNSAFE_TO_CONCAT` glyph-flag should be produced by the shaper. By default it will not be produced since it incurs a cost. .. attribute:: PRODUCE_SAFE_TO_INSERT_TATWEEL :value: 0x80 Flag indicating that the :attr:`GlyphFlags.SAFE_TO_INSERT_TATWEEL` glyph-flag should be produced by the shaper. By default it will not be produced. Wraps `hb_buffer_flags_t `_. """ 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): """Data type for holding HarfBuzz's clustering behavior options. The cluster level dictates one aspect of how HarfBuzz will treat non-base characters during shaping. :attr:`MONOTONE_GRAPHEMES` is the default, because it maintains backward compatibility with older versions of HarfBuzz. New client programs that do not need to maintain such backward compatibility are recommended to use :attr:`MONOTONE_CHARACTERS` instead of the default. .. attribute:: MONOTONE_GRAPHEMES :value: 0 Return cluster values grouped by graphemes into monotone order. Non-base characters are merged into the cluster of the base character that precedes them. There is also cluster merging every time the clusters will otherwise become non-monotone. .. attribute:: MONOTONE_CHARACTERS :value: 1 Return cluster values grouped into monotone order. Non-base characters are initially assigned their own cluster values, which are not merged into preceding base clusters. This allows HarfBuzz to perform additional operations like reorder sequences of adjacent marks. The output is still monotone, but the cluster values are more granular. .. attribute:: CHARACTERS :value: 2 Don't group cluster values. Non-base characters are assigned their own cluster values, which are not merged into preceding base clusters. Moreover, the cluster values are not merged into monotone order. This is the most granular cluster level, and it is useful for clients that need to know the exact cluster values of each character, but is harder to use for clients, since clusters might appear in any order. .. attribute:: GRAPHEMES :value: 3 Only group clusters, but don't enforce monotone order. Non-base characters are merged into the cluster of the base character that precedes them. This is similar to the Unicode Grapheme Cluster algorithm, but it is not exactly the same. The output is not forced to be monotone. This is useful for clients that want to use HarfBuzz as a cheap implementation of the Unicode Grapheme Cluster algorithm. .. attribute:: DEFAULT :value: MONOTONE_GRAPHEMES Default cluster level, equal to :attr:`MONOTONE_GRAPHEMES`. Wraps `hb_buffer_cluster_level_t `_. """ 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): """The type of :class:`Buffer` contents. .. attribute:: INVALID :value: 0 Initial value for new buffer. .. attribute:: UNICODE :value: 1 The buffer contains input characters (before shaping). .. attribute:: GLYPHS :value: 2 The buffer contains output glyphs (after shaping). Wraps `hb_buffer_content_type_t `_. """ INVALID = HB_BUFFER_CONTENT_TYPE_INVALID UNICODE = HB_BUFFER_CONTENT_TYPE_UNICODE GLYPHS = HB_BUFFER_CONTENT_TYPE_GLYPHS class BufferSerializeFormat(IntEnum): """The buffer serialization and de-serialization format used in :meth:`Buffer.serialize`. .. attribute:: TEXT A human-readable, plain text format. .. attribute:: JSON A machine-readable JSON format. .. attribute:: INVALID Invalid format. Wraps `hb_buffer_serialize_format_t `_. """ TEXT = HB_BUFFER_SERIALIZE_FORMAT_TEXT JSON = HB_BUFFER_SERIALIZE_FORMAT_JSON INVALID = HB_BUFFER_SERIALIZE_FORMAT_INVALID class BufferSerializeFlags(IntFlag): """Flags that control what glyph information are serialized in :meth:`Buffer.serialize`. .. attribute:: DEFAULT :value: 0x00 Serialize glyph names, clusters and positions. .. attribute:: NO_CLUSTERS :value: 0x01 Do not serialize glyph cluster. .. attribute:: NO_POSITIONS :value: 0x02 Do not serialize glyph position information. .. attribute:: NO_GLYPH_NAMES :value: 0x04 Do not serialize glyph name. .. attribute:: GLYPH_EXTENTS :value: 0x08 Serialize glyph extents. .. attribute:: GLYPH_FLAGS :value: 0x10 Serialize glyph flags. .. attribute:: NO_ADVANCES :value: 0x20 Do not serialize glyph advances, glyph offsets will reflect absolute glyph positions. Note: when this flag is used with a partial range of the buffer (i.e. ``start`` is not 0), calculating the absolute positions has a cost proportional to ``start``. If the buffer is serialized in many small chunks, this can lead to quadratic behavior. It is recommended to use a larger ``buf_size`` to minimize this cost. Wraps `hb_buffer_serialize_flags_t `_. """ 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: """Input and output buffers. Buffers serve a dual role in HarfBuzz; before shaping, they hold the input characters that are passed to :func:`shape`, and after shaping they hold the output glyphs. The input buffer is a sequence of Unicode codepoints, with associated attributes such as direction and script. The output buffer is a sequence of glyphs, with associated attributes such as position and cluster. .. attribute:: DEFAULT_REPLACEMENT_CODEPOINT :value: 0xFFFD The default code point for replacing invalid characters in a given encoding. Set to U+FFFD REPLACEMENT CHARACTER. Wraps `HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT `_. Wraps `hb_buffer_t `_. """ 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) @classmethod @deprecated("Buffer()", since="0.10.0") 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): """Resets the buffer to its initial status, as if it was just newly created. Wraps `hb_buffer_reset() `_. """ hb_buffer_reset (self._hb_buffer) def clear_contents(self): """Similar to :meth:`reset`, but does not clear the Unicode functions and the replacement code point. Wraps `hb_buffer_clear_contents() `_. """ hb_buffer_clear_contents(self._hb_buffer) @property def direction(self) -> str: """The text flow direction of the buffer. No shaping can happen without setting buffer direction, and it controls the visual direction for the output glyphs; for RTL direction the glyphs will be reversed. Many layout features depend on the proper setting of the direction, for example, reversing RTL text before shaping, then shaping with LTR direction is not the same as keeping the text in logical order and shaping with RTL direction. Wraps `hb_buffer_get_direction() `_ / `hb_buffer_set_direction() `_. """ 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]: """The buffer glyph information array. The value is valid as long as the buffer has not been modified. :type: list[GlyphInfo] Wraps `hb_buffer_get_glyph_infos() `_. """ 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]: """The buffer glyph position array. The value is valid as long as the buffer has not been modified. If the buffer did not have positions before, the positions will be initialized to zeros, unless this property is accessed from within a buffer message callback (see :meth:`set_message_func`), in which case ``None`` is returned. :type: list[GlyphPosition] | None Wraps `hb_buffer_get_glyph_positions() `_. """ 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: """The language of the buffer, as a BCP 47 language tag. Languages are crucial for selecting which OpenType feature to apply to the buffer which can result in applying language-specific behaviour. Languages are orthogonal to the scripts, and though they are related, they are different concepts and should not be confused with each other. Wraps `hb_buffer_get_language() `_ / `hb_buffer_set_language() `_. """ 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: """The script of the buffer, as an ISO 15924 script tag. Script is crucial for choosing the proper shaping behaviour for scripts that require it (e.g. Arabic) and the which OpenType features defined in the font to be applied. Wraps `hb_buffer_get_script() `_ / `hb_buffer_set_script() `_. """ 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: """The :class:`BufferFlags` of the buffer. :type: BufferFlags Wraps `hb_buffer_get_flags() `_ / `hb_buffer_set_flags() `_. """ 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: """The cluster level of the buffer. The :class:`BufferClusterLevel` dictates one aspect of how HarfBuzz will treat non-base characters during shaping. :type: BufferClusterLevel Wraps `hb_buffer_get_cluster_level() `_ / `hb_buffer_set_cluster_level() `_. """ 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: """The type of buffer contents. Buffers are either empty, contain characters (before shaping), or contain glyphs (the result of shaping). :type: BufferContentType Wraps `hb_buffer_get_content_type() `_ / `hb_buffer_set_content_type() `_. """ 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: """The codepoint that replaces invalid entries for a given encoding when adding text to the buffer. Default is :attr:`DEFAULT_REPLACEMENT_CODEPOINT`. Wraps `hb_buffer_get_replacement_codepoint() `_ / `hb_buffer_set_replacement_codepoint() `_. """ 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: """The codepoint that replaces invisible characters in the shaping result. If set to zero (default), the glyph for the U+0020 SPACE character is used. Otherwise, this value is used verbatim. Wraps `hb_buffer_get_invisible_glyph() `_ / `hb_buffer_set_invisible_glyph() `_. """ 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: """The codepoint that replaces characters not found in the font during shaping. The not-found glyph defaults to zero, sometimes known as the ``.notdef`` glyph. This API allows for differentiating the two. Wraps `hb_buffer_get_not_found_glyph() `_ / `hb_buffer_set_not_found_glyph() `_. """ 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): """Sets the language of the buffer from an OpenType language tag. Wraps `hb_ot_tag_to_language() `_ + `hb_buffer_set_language() `_. """ 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): """Sets the script of the buffer from an OpenType script tag. Wraps `hb_ot_tag_to_script() `_ + `hb_buffer_set_script() `_. """ 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): """Appends characters from ``codepoints`` to the buffer. The ``item_offset`` is the position of the first character from ``codepoints`` that will be appended, and ``item_length`` is the number of characters. When shaping part of a larger text (e.g. a run of text from a paragraph), instead of passing just the substring corresponding to the run, it is preferable to pass the whole paragraph and specify the run start and length as ``item_offset`` and ``item_length``, respectively, to give HarfBuzz the full context to be able, for example, to do cross-run Arabic shaping or properly handle combining marks at start of run. This method does not check the validity of ``codepoints``, it is up to the caller to ensure it contains valid Unicode scalar values. In contrast, :meth:`add_utf8` and :meth:`add_str` perform sanity-check on the input. :param codepoints: A sequence of Unicode code points to append. :param item_offset: The offset of the first code point to add to the buffer. :param item_length: The number of code points to add to the buffer, or ``-1`` to add the rest of ``codepoints``. :raises MemoryError: If memory allocation fails. Wraps `hb_buffer_add_codepoints() `_. """ 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): """Appends UTF-8 ``text`` to the buffer. Replaces invalid UTF-8 characters with the buffer replacement code point, see :attr:`replacement_codepoint`. :param text: UTF-8 encoded text to append. :param item_offset: The offset of the first character to add to the buffer. :param item_length: The number of characters to add to the buffer, or ``-1`` to add the rest of ``text``. :raises MemoryError: If memory allocation fails. Wraps `hb_buffer_add_utf8() `_. """ 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): """Appends ``text`` to the buffer. Replaces invalid characters with the buffer replacement code point, see :attr:`replacement_codepoint`. :param text: Text to append. :param item_offset: The offset of the first character to add to the buffer. :param item_length: The number of characters to add to the buffer, or ``-1`` to add the rest of ``text``. :raises MemoryError: If memory allocation fails. Wraps `hb_buffer_add_utf32() `_. """ 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): """Sets unset buffer segment properties based on buffer Unicode contents. If the buffer is not empty, it must have content type :attr:`BufferContentType.UNICODE`. If the buffer script is not set, it will be set to the Unicode script of the first character in the buffer that has a script other than ``COMMON``, ``INHERITED``, and ``UNKNOWN``. Next, if the buffer direction is not set, it will be set to the natural horizontal direction of the buffer script. Finally, if the buffer language is not set, it will be set to the process's default language. Wraps `hb_buffer_guess_segment_properties() `_. """ hb_buffer_guess_segment_properties(self._hb_buffer) def set_message_func(self, callback: Callable[str]): """Sets the implementation function for the buffer's message callback. The callback is called with a message describing what step of the shaping process will be performed. Returning ``False`` from this callback will skip this shaping step and move to the next one. Wraps `hb_buffer_set_message_func() `_. """ 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: """Serializes the buffer into a textual representation of its content, whether Unicode codepoints or glyph identifiers and positioning information. This is useful for showing the contents of the buffer, for example during debugging. :param font: The :class:`Font` used to shape this buffer, needed to read glyph names and extents. :param format: The :class:`BufferSerializeFormat` to use for formatting the output. :param flags: The :class:`BufferSerializeFlags` that control what glyph properties to serialize. :returns: The serialized buffer contents. Wraps `hb_buffer_serialize() `_. """ 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() harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/_draw.pxi000066400000000000000000000171741526670067500224020ustar00rootroot00000000000000cdef 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()", since="0.34.0") def get_glyph_shape(self, font: Font, gid: int): font.draw_glyph(gid, self) @deprecated("Font.draw_glyph()", since="0.34.0") 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) harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/_draw_test_funcs.cc000066400000000000000000000031521526670067500244130ustar00rootroot00000000000000#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); } } harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/_face.pxi000066400000000000000000001204771526670067500223440ustar00rootroot00000000000000class OTVarAxisFlags(IntFlag): """Flags for :class:`OTVarAxisInfo`. .. attribute:: HIDDEN :value: 0x01 The axis should not be exposed directly in user interfaces. Wraps `hb_ot_var_axis_flags_t `_. """ HIDDEN = HB_OT_VAR_AXIS_FLAG_HIDDEN class OTVarAxisInfo(NamedTuple): """Data type for holding variation-axis values. Wraps `hb_ot_var_axis_info_t `_. """ axis_index: int """Index of the axis in the variation-axis array.""" tag: str """The tag identifying the design variation of the axis.""" name_id: int """The ``name`` table Name ID that provides display names for the axis.""" flags: OTVarAxisFlags """The :class:`OTVarAxisFlags` flags for the axis.""" min_value: float """The minimum value on the variation axis that the font covers.""" default_value: float """The position on the variation axis corresponding to the font's defaults.""" max_value: float """The maximum value on the variation axis that the font covers.""" class OTVarNamedInstance(NamedTuple): """A named instance defined in the font's ``fvar`` table.""" subfamily_name_id: int """The ``name`` table Name ID that provides display names for the "Subfamily name" defined for the given named instance.""" postscript_name_id: int """The ``name`` table Name ID that provides display names for the "PostScript name" defined for the given named instance.""" design_coords: List[float] """The design-space coordinates corresponding to the named instance.""" class Color(NamedTuple): """A color value. Colors are eight bits per channel RGB plus alpha transparency. Wraps `hb_color_t `_. """ red: int """Red channel value.""" green: int """Green channel value.""" blue: int """Blue channel value.""" alpha: int """Alpha channel value.""" def to_int(self) -> int: """Returns an :class:`int` representation of this :class:`Color`.""" return HB_COLOR(self.blue, self.green, self.red, self.alpha) @staticmethod def from_int(value: int) -> Color: """Construct a :class:`Color` from an integer representation.""" 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): """A :class:`Color` from a font's color palette, together with its name ID.""" name_id: int | None class OTColorPaletteFlags(IntFlag): """Flags that describe the properties of a color palette. .. attribute:: DEFAULT :value: 0x00 Default indicating that there is nothing special to note about a color palette. .. attribute:: USABLE_WITH_LIGHT_BACKGROUND :value: 0x01 Flag indicating that the color palette is appropriate to use when displaying the font on a light background such as white. .. attribute:: USABLE_WITH_DARK_BACKGROUND :value: 0x02 Flag indicating that the color palette is appropriate to use when displaying the font on a dark background such as black. Wraps `hb_ot_color_palette_flags_t `_. """ 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): """A color palette from a font's ``CPAL`` table.""" colors: List[OTColor] """The colors that make up the palette.""" name_id: int | None """The ``name`` table Name ID that provides display names for the palette, or ``None`` if no name is associated.""" flags: OTColorPaletteFlags """The :class:`OTColorPaletteFlags` flags for the palette.""" class OTColorLayer(NamedTuple): """A pair of glyph and color index. A color index of ``0xFFFF`` does not refer to a palette color, but indicates that the foreground color should be used. Wraps `hb_ot_color_layer_t `_. """ glyph: int """The glyph ID of the layer.""" color_index: int """The palette color index of the layer.""" class OTLayoutGlyphClass(IntEnum): """The GDEF classes defined for glyphs. .. attribute:: UNCLASSIFIED :value: 0 Glyphs not matching the other classifications. .. attribute:: BASE_GLYPH :value: 1 Spacing, single characters, capable of accepting marks. .. attribute:: LIGATURE :value: 2 Glyphs that represent ligation of multiple characters. .. attribute:: MARK :value: 3 Non-spacing, combining glyphs that represent marks. .. attribute:: COMPONENT :value: 4 Spacing glyphs that represent part of a single character. Wraps `hb_ot_layout_glyph_class_t `_. """ 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) cdef unsigned int _get_table_tags_func( const hb_face_t* face, unsigned int start_offset, unsigned int* table_count, hb_tag_t* table_tags, void* user_data) noexcept: cdef Face py_face = (hb_face_get_user_data(face, &k)) cdef list tags = py_face._get_table_tags_func(py_face, user_data) cdef unsigned int population = len(tags) cdef unsigned int end_offset cdef unsigned int i cdef bytes packed if table_count is NULL: return population if start_offset >= population: table_count[0] = 0 return population end_offset = start_offset + table_count[0] if end_offset < start_offset: table_count[0] = 0 return population if end_offset > population: end_offset = population table_count[0] = end_offset - start_offset for i in range(start_offset, end_offset): packed = tags[i].encode() table_tags[i - start_offset] = hb_tag_from_string(packed, -1) return population class OTNameIdPredefined(IntEnum): """Predefined values for the OpenType ``name`` table Name ID. .. attribute:: COPYRIGHT Copyright notice. .. attribute:: FONT_FAMILY Font Family name. .. attribute:: FONT_SUBFAMILY Font Subfamily name. .. attribute:: UNIQUE_ID Unique font identifier. .. attribute:: FULL_NAME Full font name that reflects all family and relevant subfamily descriptors. .. attribute:: VERSION_STRING Version string. .. attribute:: POSTSCRIPT_NAME PostScript name for the font. .. attribute:: TRADEMARK Trademark. .. attribute:: MANUFACTURER Manufacturer name. .. attribute:: DESIGNER Designer. .. attribute:: DESCRIPTION Description. .. attribute:: VENDOR_URL URL of font vendor. .. attribute:: DESIGNER_URL URL of typeface designer. .. attribute:: LICENSE License description. .. attribute:: LICENSE_URL License information URL. .. attribute:: TYPOGRAPHIC_FAMILY Typographic family name. .. attribute:: TYPOGRAPHIC_SUBFAMILY Typographic subfamily name. .. attribute:: MAC_FULL_NAME Compatible full name (Macintosh only). .. attribute:: SAMPLE_TEXT Sample text. .. attribute:: CID_FINDFONT_NAME PostScript CID findfont name. .. attribute:: WWS_FAMILY WWS family name. .. attribute:: WWS_SUBFAMILY WWS subfamily name. .. attribute:: LIGHT_BACKGROUND Light background palette. .. attribute:: DARK_BACKGROUND Dark background palette. .. attribute:: VARIATIONS_PS_PREFIX Variations PostScript name prefix. .. attribute:: INVALID Value to represent a nonexistent name ID. Wraps `hb_ot_name_id_predefined_t `_. """ 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): """Structure representing a name ID in a particular language. Wraps `hb_ot_name_entry_t `_. """ name_id: OTNameIdPredefined | int """The name ID, as an :class:`OTNameIdPredefined` value or a raw :class:`int` if it does not match any of the predefined ones.""" language: str | None """The BCP 47 language tag, or ``None`` if the language cannot be determined.""" cdef class Face: """Font face objects. A font face is an object that represents a single face from within a font family. More precisely, a font face represents a single face in a binary font file. Font faces are typically built from a binary blob and a face index. Font faces are used to create fonts. The face index is used for blobs of file formats such as TTC and DFont that can contain more than one face. Face indices within such collections are zero-based. :param blob: A :class:`Blob` or :class:`bytes` containing the font data. If ``None``, the empty face is returned. :param index: The index of the face within the blob. Wraps `hb_face_t `_. """ cdef hb_face_t* _hb_face cdef object _reference_table_func cdef object _get_table_tags_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 it.""" cdef Face wrapper = Face.__new__(Face) wrapper._hb_face = hb_face return wrapper @classmethod @deprecated("Face()", since="0.10.0") 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: """Variant of the normal constructor, built for those cases where it is more convenient to provide data for individual tables instead of the whole font data. With the caveat that :attr:`table_tags` would not work with faces created this way. You can address that by calling the :meth:`set_get_table_tags_func` method and setting the appropriate callback. Creates a new face object from the specified ``user_data`` and ``func``. :param func: A callback that takes the :class:`Face`, a table tag, and the ``user_data`` and returns the table data as :class:`bytes`. :param user_data: User data passed to ``func`` on each call. Wraps `hb_face_create_for_tables() `_. """ 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: """The number of faces in the blob. Wraps `hb_face_count() `_. """ return hb_face_count(self._blob._hb_blob) @property def index(self) -> int: """The face-index of this face. Face indices within a collection are zero-based. Changing the index has no effect on the face itself, only on the value returned by this property. Wraps `hb_face_get_index() `_ / `hb_face_set_index() `_. """ 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: """The units-per-em (UPEM) value of the face. Typical UPEM values for fonts are 1000, or 2048, but any value in between 16 and 16,384 is allowed for OpenType fonts. Wraps `hb_face_get_upem() `_ / `hb_face_set_upem() `_. """ 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: """The glyph-count value of the face. Wraps `hb_face_get_glyph_count() `_ / `hb_face_set_glyph_count() `_. """ 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: """A :class:`Blob` containing the binary data of the face. If referencing the face data is not possible, this property creates a blob out of individual table blobs if :attr:`table_tags` works with this face, otherwise it returns an empty blob. :type: Blob Wraps `hb_face_reference_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: """Fetches a reference to the specified table within the face. :param tag: The four-character tag of the table to query. :returns: A :class:`Blob` with the table data, or an empty blob if referencing table data is not possible. Wraps `hb_face_reference_table() `_. """ 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) def set_get_table_tags_func(self, func: Callable[[Face, object], List[str]], user_data: object = None): """Sets the implementation function for retrieving the table tags of the face. :param func: A callback that takes the :class:`Face` and the ``user_data`` and returns the list of table tags as :class:`str`. :param user_data: User data passed to ``func`` on each call. Wraps `hb_face_set_get_table_tags_func() `_. """ self._get_table_tags_func = func hb_face_set_get_table_tags_func( self._hb_face, _get_table_tags_func, user_data, NULL) @property def table_tags(self) -> List[str]: """A list of all table tags for the face, if possible. :type: list[str] Wraps `hb_face_get_table_tags() `_. """ 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]: """All Unicode characters covered by the face. :type: Set Wraps `hb_face_collect_unicodes() `_. """ s = Set() hb_face_collect_unicodes(self._hb_face, s._hb_set) return s @property def variation_selectors(self) -> Set[int]: """All Unicode "Variation Selector" characters covered by the face. :type: Set Wraps `hb_face_collect_variation_selectors() `_. """ s = Set() hb_face_collect_variation_selectors(self._hb_face, s._hb_set) return s def variation_unicodes(self, variation_selector: int) -> Set[int]: """All Unicode characters for ``variation_selector`` covered by the face. :param variation_selector: The Variation Selector to query. :returns: The :class:`Set` of Unicode characters. Wraps `hb_face_collect_variation_unicodes() `_. """ 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: """Whether the face includes any OpenType variation data in the ``fvar`` table. Wraps `hb_ot_var_has_data() `_. """ return hb_ot_var_has_data(self._hb_face) @property def axis_infos(self) -> List[OTVarAxisInfo]: """A list of all variation axes in the face. :type: list[OTVarAxisInfo] Wraps `hb_ot_var_get_axis_infos() `_. """ 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]: """The named instances defined in the face's ``fvar`` table. :type: list[OTVarNamedInstance] Wraps `hb_ot_var_get_named_instance_count() `_, `hb_ot_var_named_instance_get_subfamily_name_id() `_, `hb_ot_var_named_instance_get_postscript_name_id() `_, and `hb_ot_var_named_instance_get_design_coords() `_. """ 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: """Whether the face has a ``MATH`` table. Wraps `hb_ot_math_has_data() `_. """ return hb_ot_math_has_data(self._hb_face) def is_glyph_extended_math_shape(self, glyph: int) -> bool: """Tests whether the given glyph index is an extended shape in the face. :param glyph: The glyph index to test. :returns: ``True`` if the glyph is an extended shape, ``False`` otherwise. Wraps `hb_ot_math_is_glyph_extended_shape() `_. """ return hb_ot_math_is_glyph_extended_shape(self._hb_face, glyph) # color @property def has_color_layers(self) -> bool: """Whether the face includes a ``COLR`` table with data according to COLRv0. Wraps `hb_ot_color_has_layers() `_. """ return hb_ot_color_has_layers(self._hb_face) def get_glyph_color_layers(self, glyph: int) -> List[OTColorLayer]: """Fetches a list of all color layers for the specified glyph index in the face. :param glyph: The glyph index to query. :returns: The array of layers found. Wraps `hb_ot_color_glyph_get_layers() `_. """ 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: """Whether the face includes a ``CPAL`` color-palette table. Wraps `hb_ot_color_has_palettes() `_. """ return hb_ot_color_has_palettes(self._hb_face) def get_color_palette(self, palette_index: int) -> OTColorPalette: """Fetches the color palette at the specified index. :param palette_index: The index of the color palette. :returns: An :class:`OTColorPalette` with the colors, name ID, and flags of the palette. Wraps `hb_ot_color_palette_get_colors() `_, `hb_ot_color_palette_get_name_id() `_, and `hb_ot_color_palette_get_flags() `_. """ 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]: """The face's color palettes. :type: list[OTColorPalette] Wraps `hb_ot_color_palette_get_count() `_. """ 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: """Fetches the ``name`` table Name ID that provides display names for the specified color in the face's ``CPAL`` color palette. :param color_index: The index of the color. :returns: The Name ID, or ``None`` if the color is not named. Wraps `hb_ot_color_palette_color_get_name_id() `_. """ 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: """Whether the face includes a ``COLR`` table with data according to COLRv1. Wraps `hb_ot_color_has_paint() `_. """ return hb_ot_color_has_paint(self._hb_face) def glyph_has_color_paint(self, glyph: int) -> bool: """Tests whether the face includes COLRv1 paint data for ``glyph``. :param glyph: The glyph index to query. :returns: ``True`` if data is found, ``False`` otherwise. Wraps `hb_ot_color_glyph_has_paint() `_. """ return hb_ot_color_glyph_has_paint(self._hb_face, glyph) @property def has_color_svg(self) -> bool: """Whether the face includes any ``SVG`` glyph images. Wraps `hb_ot_color_has_svg() `_. """ return hb_ot_color_has_svg(self._hb_face) def get_glyph_color_svg(self, glyph: int) -> Blob: """Fetches the SVG document for a glyph. The blob may be either plain text or gzip-encoded. If the glyph has no SVG document, the singleton empty blob is returned. :param glyph: An SVG glyph index. :returns: A :class:`Blob` with the content of the SVG document. Wraps `hb_ot_color_glyph_reference_svg() `_. """ 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: """Whether the face has PNG glyph images (either in ``CBDT`` or ``sbix`` tables). Wraps `hb_ot_color_has_png() `_. """ return hb_ot_color_has_png(self._hb_face) # layout @property def has_layout_glyph_classes(self) -> bool: """Whether the face has any glyph classes defined in its GDEF table. Wraps `hb_ot_layout_has_glyph_classes() `_. """ return hb_ot_layout_has_glyph_classes(self._hb_face) def get_layout_glyph_class(self, glyph: int) -> OTLayoutGlyphClass: """Fetches the GDEF class of the requested glyph. :param glyph: The glyph code point to query. :returns: The :class:`OTLayoutGlyphClass` glyph class of the given code point in the GDEF table of the face. Wraps `hb_ot_layout_get_glyph_class() `_. """ return OTLayoutGlyphClass(hb_ot_layout_get_glyph_class(self._hb_face, glyph)) @property def has_layout_positioning(self) -> bool: """Whether the face includes any GPOS positioning. Wraps `hb_ot_layout_has_positioning() `_. """ return hb_ot_layout_has_positioning(self._hb_face) @property def has_layout_substitution(self) -> bool: """Whether the face includes any GSUB substitutions. Wraps `hb_ot_layout_has_substitution() `_. """ return hb_ot_layout_has_substitution(self._hb_face) def get_lookup_glyph_alternates(self, lookup_index: int, glyph: int) -> List[int]: """Fetches alternates of a glyph from a given GSUB lookup index. :param lookup_index: Index of the feature lookup to query. :param glyph: A glyph id. :returns: Alternate glyphs associated with the glyph id. Wraps `hb_ot_layout_lookup_get_glyph_alternates() `_. """ 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]: """Fetches a list of all features in the face's GSUB or GPOS table. :param tag: ``"GSUB"`` or ``"GPOS"``. :param script_index: The index of the requested script tag. :param language_index: The index of the requested language tag. :returns: The array of feature tags found for the query. Wraps `hb_ot_layout_language_get_feature_tags() `_. """ 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]: """Fetches a list of language tags in the face's GSUB or GPOS table, underneath the specified script index. :param tag: ``"GSUB"`` or ``"GPOS"``. :param script_index: The index of the requested script tag. :returns: Array of language tags found in the table. Wraps `hb_ot_layout_script_get_language_tags() `_. """ 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]: """Fetches a list of all scripts enumerated in the specified face's GSUB or GPOS table. :param tag: ``"GSUB"`` or ``"GPOS"``. :returns: The array of script tags found for the query. Wraps `hb_ot_layout_table_get_script_tags() `_. """ 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]: """Enumerates all available name IDs and language combinations. :returns: Array of available name entries. Wraps `hb_ot_name_list_names() `_. """ 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: """Fetches a font name from the OpenType ``name`` table. :param name_id: The OpenType name identifier to fetch. :param language: The BCP 47 language tag to fetch the name for. If ``None``, English (``"en"``) is assumed. :returns: The name as a :class:`str`, or ``None`` if not found. Wraps `hb_ot_name_get_utf8() `_. """ 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 harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/_font.pxi000066400000000000000000001760361526670067500224160ustar00rootroot00000000000000class GlyphExtents(NamedTuple): """Glyph extent values, measured in font units. Note that ``height`` is negative, in coordinate systems that grow up. Wraps `hb_glyph_extents_t `_. """ x_bearing: int """Distance from the x-origin to the left extremum of the glyph.""" y_bearing: int """Distance from the top extremum of the glyph to the y-origin.""" width: int """Distance from the left extremum of the glyph to the right extremum.""" height: int """Distance from the top extremum of the glyph to the bottom extremum.""" class FontExtents(NamedTuple): """Font-wide extent values, measured in scaled units. Note that typically ``ascender`` is positive and ``descender`` negative, in coordinate systems that grow up. Wraps `hb_font_extents_t `_. """ ascender: int """The height of typographic ascenders.""" descender: int """The depth of typographic descenders.""" line_gap: int """The suggested line-spacing gap.""" class OTMathConstant(IntEnum): """Math constants from the OpenType ``MATH`` table. Wraps `hb_ot_math_constant_t `_. """ 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): """Math kerning (cut-in) information for a glyph. Wraps `hb_ot_math_kern_entry_t `_. """ max_correction_height: int """The maximum height at which this entry should be used.""" kern_value: int """The kern value of the entry.""" class OTMathKern(IntEnum): """The math kerning-table types defined for the four corners of a glyph. .. attribute:: TOP_RIGHT :value: 0 The top right corner of the glyph. .. attribute:: TOP_LEFT :value: 1 The top left corner of the glyph. .. attribute:: BOTTOM_RIGHT :value: 2 The bottom right corner of the glyph. .. attribute:: BOTTOM_LEFT :value: 3 The bottom left corner of the glyph. Wraps `hb_ot_math_kern_t `_. """ 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): """Math-variant information for a glyph. Wraps `hb_ot_math_glyph_variant_t `_. """ glyph: int """The glyph index of the variant.""" advance: int """The advance width of the variant.""" class OTMathGlyphPartFlags(IntFlag): """Flags for math glyph parts. .. attribute:: EXTENDER :value: 0x01 This is an extender glyph part that can be repeated to reach the desired length. Wraps `hb_ot_math_glyph_part_flags_t `_. """ EXTENDER = HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER class OTMathGlyphPart(NamedTuple): """Information for a "part" component of a math-variant glyph. Large variants for stretchable math glyphs (such as parentheses) can be constructed on the fly from parts. Wraps `hb_ot_math_glyph_part_t `_. """ glyph: int """The glyph index of the variant part.""" start_connector_length: int """The length of the connector on the starting side of the variant part.""" end_connector_length: int """The length of the connector on the ending side of the variant part.""" full_advance: int """The total advance of the part.""" flags: OTMathGlyphPartFlags """:class:`OTMathGlyphPartFlags` flags for the part.""" class OTMetricsTag(IntEnum): """Metric tags corresponding to `MVAR Value Tags `_. Wraps `hb_ot_metrics_tag_t `_. """ 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): """Style tags defined by `OpenType Design-Variation Axis Tag Registry `_. .. attribute:: ITALIC Used to vary between non-italic and italic. A value of 0 can be interpreted as "Roman" (non-italic); a value of 1 can be interpreted as (fully) italic. .. attribute:: OPTICAL_SIZE Used to vary design to suit different text sizes. Non-zero. Values can be interpreted as text size, in points. .. attribute:: SLANT_ANGLE Used to vary between upright and slanted text. Values must be greater than -90 and less than +90. Values can be interpreted as the angle, in counter-clockwise degrees, of oblique slant from whatever the designer considers to be upright for that font design. Typical right-leaning Italic fonts have a negative slant angle (typically around -12). .. attribute:: SLANT_RATIO Same as :attr:`SLANT_ANGLE` expressed as a ratio. Typical right-leaning Italic fonts have a positive slant ratio (typically around 0.2). .. attribute:: WIDTH Used to vary width of text from narrower to wider. Non-zero. Values can be interpreted as a percentage of whatever the font designer considers "normal width" for that font design. .. attribute:: WEIGHT Used to vary stroke thicknesses or other design details to give variation from lighter to blacker. Values can be interpreted in direct comparison to values for usWeightClass in the OS/2 table, or the CSS font-weight property. Wraps `hb_style_tag_t `_. """ 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: """Font objects. A font object represents a font face at a specific size and with certain other parameters (pixels-per-em, points-per-em, variation settings) specified. Font objects are created from font face objects, and are used as input to :func:`shape`, among other things. Client programs can optionally pass in their own functions that implement the basic, lower-level queries of font objects. This set of font functions is defined by the virtual methods in :class:`FontFuncs`. :param face_or_font: A :class:`Face` to create a font from, or another :class:`Font` to create a sub-font from. If ``None``, the empty font is returned. Wraps `hb_font_t `_. """ 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 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 @classmethod @deprecated("Font()", since="0.10.0") def create(cls, face: Face) -> Font: cdef Font inst = cls(face) return inst @property def face(self) -> Face: """The :class:`Face` associated with this font. :type: Face Wraps `hb_font_get_face() `_. """ return self._face @property def funcs(self) -> FontFuncs: """The font-functions structure attached to this font. Assigning to this property replaces the font-functions structure attached to the font. :type: FontFuncs Wraps `hb_font_set_funcs() `_. """ 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]: """The horizontal and vertical scale of the font, as a ``(x_scale, y_scale)`` tuple. The font scale is a number related to, but not the same as, font size. Typically the client establishes a scale factor to be used between the two. For example, 64, or 256, which would be the fractional-precision part of the font scale. This is necessary because position values are integer types and you need to leave room for fractional values in there. For example, to set the font size to 20, with 64 levels of fractional precision you would call ``font.scale = (20 * 64, 20 * 64)``. In the example above, even what font size 20 means is up to you. It might be 20 pixels, or 20 points, or 20 millimeters. HarfBuzz does not care about that. You can set the point size of the font using :attr:`ptem`, and the pixel size using :attr:`ppem`. The choice of scale is yours but needs to be consistent between what you set here, and what you expect out of position values as well has draw / paint API output values. Fonts default to a scale equal to the UPEM value of their face. A font with this setting is sometimes called an "unscaled" font. Wraps `hb_font_get_scale() `_ / `hb_font_set_scale() `_. """ 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]: """The horizontal and vertical pixels-per-em (PPEM) of the font, as a ``(x_ppem, y_ppem)`` tuple. These values are used for pixel-size-specific adjustment to shaping and draw results, though for the most part they are unused and can be left unset. Wraps `hb_font_get_ppem() `_ / `hb_font_set_ppem() `_. """ 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: """The "point size" of the font. Set to zero to unset. Used in CoreText to implement optical sizing. Note: there are 72 points in an inch. Wraps `hb_font_get_ptem() `_ / `hb_font_set_ptem() `_. """ 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: """The "synthetic slant" of the font. By default is zero. Synthetic slant is the graphical skew applied to the font at rendering time. HarfBuzz needs to know this value to adjust shaping results, metrics, and style values to match the slanted rendering. The slant value is a ratio. For example, a 20% slant would be represented as a 0.2 value. Wraps `hb_font_get_synthetic_slant() `_ / `hb_font_set_synthetic_slant() `_. """ 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]: """The "synthetic boldness" of the font, as a tuple ``(x_embolden, y_embolden, in_place)``. Positive values for ``x_embolden`` / ``y_embolden`` make a font bolder, negative values thinner. Typical values are in the 0.01 to 0.05 range. The default value is zero. If ``in_place`` is ``False``, then glyph advance-widths are also adjusted, otherwise they are not. The in-place mode is useful for simulating font grading. The setter accepts a :class:`float` (applied to both axes, ``in_place=False``), a 1-tuple, a 2-tuple, or a 3-tuple. Wraps `hb_font_get_synthetic_bold() `_ / `hb_font_set_synthetic_bold() `_. """ 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: """The currently-set named-instance index of the font. Wraps `hb_font_get_var_named_instance() `_ / `hb_font_set_var_named_instance() `_. """ 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]): """Applies a list of font-variation settings to the font. Note that this overrides all existing variations set on the font. Axes not included in ``variations`` will be effectively set to their default values. :param variations: A mapping of axis-tag string to value. Wraps `hb_font_set_variations() `_. """ 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): """Change the value of one variation axis on the font. Note: this method is expensive to be called repeatedly. If you want to set multiple variation axes at the same time, use :meth:`set_variations` instead. :param name: The axis tag. :param value: The value of the variation axis. Wraps `hb_font_set_variation() `_. """ 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: """Fetches the glyph-name string for a glyph ID in the font. According to the OpenType specification, glyph names are limited to 63 characters and can only contain (a subset of) ASCII. :param gid: The glyph ID to query. :returns: Name string retrieved for the glyph ID, or ``None`` if not found. Wraps `hb_font_get_glyph_name() `_. """ 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: """Fetches the glyph ID that corresponds to a name string in the font. :param name: The name to query. :returns: The glyph ID retrieved, or ``None`` if not found. Wraps `hb_font_get_glyph_from_name() `_. """ 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: """Fetches the :class:`GlyphExtents` data for a glyph ID. :param gid: The glyph ID to query. :returns: The :class:`GlyphExtents` retrieved, or ``None`` if not found. Wraps `hb_font_get_glyph_extents() `_. """ 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: """Fetches the advance for a glyph ID, for horizontal text segments. Wraps `hb_font_get_glyph_h_advance() `_. """ return hb_font_get_glyph_h_advance(self._hb_font, gid) def get_glyph_v_advance(self, gid: int) -> int: """Fetches the advance for a glyph ID, for vertical text segments. Wraps `hb_font_get_glyph_v_advance() `_. """ return hb_font_get_glyph_v_advance(self._hb_font, gid) def get_glyph_h_origin(self, gid: int) -> Tuple[int, int] | None: """Fetches the (X, Y) coordinates of the origin for a glyph ID, for horizontal text segments. :returns: The (X, Y) coordinates of the origin, or ``None`` if not found. Wraps `hb_font_get_glyph_h_origin() `_. """ 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: """Fetches the (X, Y) coordinates of the origin for a glyph ID, for vertical text segments. :returns: The (X, Y) coordinates of the origin, or ``None`` if not found. Wraps `hb_font_get_glyph_v_origin() `_. """ 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: """Fetches the extents for a font in a text segment of the specified direction. Calls the appropriate direction-specific variant (horizontal or vertical) depending on the value of ``direction``. :param direction: The direction of the text segment. :returns: The :class:`FontExtents` retrieved. Wraps `hb_font_get_extents_for_direction() `_. """ 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: """Fetches the glyph ID for a Unicode code point when followed by the specified variation-selector code point. :returns: The glyph ID retrieved, or ``None`` if not found. Wraps `hb_font_get_variation_glyph() `_. """ 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 | None: """Fetches the nominal glyph ID for a Unicode code point. :returns: The glyph ID retrieved, or ``None`` if not found. Wraps `hb_font_get_nominal_glyph() `_. """ 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]: """Fetches the list of normalized variation coordinates currently set on the font. :returns: The coordinates array. Wraps `hb_font_get_var_coords_normalized() `_. """ 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]): """Applies a list of variation coordinates (in normalized units) to the font. Note that this overrides all existing variations set on the font. Axes not included in ``coords`` will be effectively set to their default values. Wraps `hb_font_set_var_coords_normalized() `_. """ 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): """Fetches the list of variation coordinates (in design-space units) currently set on the font. Wraps `hb_font_get_var_coords_design() `_. """ 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]): """Applies a list of variation coordinates (in design-space units) to the font. Note that this overrides all existing variations set on the font. Axes not included in ``coords`` will be effectively set to their default values. Wraps `hb_font_set_var_coords_design() `_. """ 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: """Fetches the name of the specified glyph ID. If the glyph ID has no name, a string of the form ``gidDDD`` is generated, with ``DDD`` being the glyph ID. Wraps `hb_font_glyph_to_string() `_. """ 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: """Fetches the glyph ID that matches the specified string. Strings of the format ``gidDDD`` or ``uniUUUU`` are parsed automatically. :returns: The glyph ID corresponding to the string requested, or ``None`` if not found. Wraps `hb_font_glyph_from_string() `_. """ 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): """Draws the outline that corresponds to a glyph in the font. The outline is returned by way of calls to the callbacks of the ``draw_funcs`` object, with ``draw_state`` passed to them. :param gid: The glyph ID. :param draw_funcs: The :class:`DrawFuncs` to draw to. :param draw_state: User data to pass to the draw callbacks. Wraps `hb_font_draw_glyph() `_. """ 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): """Paints the glyph. If painting a color glyph failed, it will fall back to painting an outline monochrome glyph. The painting instructions are returned by way of calls to the callbacks of the ``paint_funcs`` object, with ``paint_state`` passed to them. :param gid: The glyph ID. :param paint_funcs: The :class:`PaintFuncs` to paint with. :param paint_state: User data to pass to the paint callbacks. :param palette_index: The index of the font's color palette to use. :param foreground: The foreground color, unpremultiplied. Wraps `hb_font_paint_glyph() `_. """ 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): """Draws the outline of a glyph using a fontTools-style pen. :param gid: The glyph ID. :param pen: An object with ``moveTo``, ``lineTo``, ``curveTo``, ``qCurveTo``, and ``closePath`` methods. """ 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: """Fetches the specified math constant. For most constants, the value returned is a position. However, if the requested constant is :attr:`OTMathConstant.SCRIPT_PERCENT_SCALE_DOWN`, :attr:`OTMathConstant.SCRIPT_SCRIPT_PERCENT_SCALE_DOWN` or :attr:`OTMathConstant.RADICAL_DEGREE_BOTTOM_RAISE_PERCENT`, then the return value is an integer between 0 and 100 representing that percentage. :raises ValueError: If ``constant`` is not a valid :class:`OTMathConstant`. Wraps `hb_ot_math_get_constant() `_. """ 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: """Fetches an italics-correction value (if one exists) for the specified glyph index. Wraps `hb_ot_math_get_glyph_italics_correction() `_. """ return hb_ot_math_get_glyph_italics_correction(self._hb_font, glyph) def get_math_glyph_top_accent_attachment(self, glyph: int) -> int: """Fetches a top-accent-attachment value (if one exists) for the specified glyph index. Wraps `hb_ot_math_get_glyph_top_accent_attachment() `_. """ return hb_ot_math_get_glyph_top_accent_attachment(self._hb_font, glyph) def get_math_min_connector_overlap(self, direction: str) -> int: """Fetches the MathVariants table for the font and returns the minimum overlap of connecting glyphs that are required to draw a glyph assembly in the specified direction. Wraps `hb_ot_math_get_min_connector_overlap() `_. """ 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: """Fetches the math kerning (cut-ins) value for the specified font, glyph index, and ``kern``. :raises ValueError: If ``kern`` is not a valid :class:`OTMathKern`. Wraps `hb_ot_math_get_glyph_kerning() `_. """ 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]: """Fetches the raw MathKern (cut-in) data for the specified font, glyph index, and ``kern``. :raises ValueError: If ``kern`` is not a valid :class:`OTMathKern`. Wraps `hb_ot_math_get_glyph_kernings() `_. """ 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]: """Fetches the MathGlyphConstruction for the specified font, glyph index, and direction. Wraps `hb_ot_math_get_glyph_variants() `_. """ 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]: """Fetches the GlyphAssembly for the specified font, glyph index, and direction. :returns: A tuple ``(parts, italics_correction)`` of the glyph parts returned and the italics correction of the glyph assembly. Wraps `hb_ot_math_get_glyph_assembly() `_. """ 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 | None: """Fetches metrics value corresponding to ``tag`` from the font. :returns: The metrics value from the font, or ``None`` if not found. Wraps `hb_ot_metrics_get_position() `_. """ 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(self, tag: OTMetricsTag) -> int: """Fetches metrics value corresponding to ``tag`` from the font, and synthesizes a value if the value is missing in the font. Wraps `hb_ot_metrics_get_position_with_fallback() `_. """ cdef hb_position_t position hb_ot_metrics_get_position_with_fallback(self._hb_font, tag, &position) return position def get_metric_variation(self, tag: OTMetricsTag) -> float: """Fetches metrics value corresponding to ``tag`` from the font with the current font variation settings applied. Wraps `hb_ot_metrics_get_variation() `_. """ return hb_ot_metrics_get_variation(self._hb_font, tag) def get_metric_x_variation(self, tag: OTMetricsTag) -> int: """Fetches horizontal metrics value corresponding to ``tag`` from the font with the current font variation settings applied. Wraps `hb_ot_metrics_get_x_variation() `_. """ return hb_ot_metrics_get_x_variation(self._hb_font, tag) def get_metric_y_variation(self, tag: OTMetricsTag) -> int: """Fetches vertical metrics value corresponding to ``tag`` from the font with the current font variation settings applied. Wraps `hb_ot_metrics_get_y_variation() `_. """ return hb_ot_metrics_get_y_variation(self._hb_font, tag) # color def get_glyph_color_png(self, glyph: int) -> Blob: """Fetches the PNG image for a glyph. This function takes a font object, not a face object, as input. To get an optimally sized PNG blob, the PPEM values must be set on the font object. If PPEM is unset, the blob returned will be the largest PNG available. If the glyph has no PNG image, the singleton empty blob is returned. Wraps `hb_ot_color_glyph_reference_png() `_. """ 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: """Fetches a baseline value from the font. :param baseline_tag: A baseline tag. :param direction: Text direction. :param script_tag: Script tag. :param language_tag: Language tag, currently unused. :returns: The baseline value if found, or ``None`` otherwise. :raises ValueError: If ``baseline_tag`` is not recognized. Wraps `hb_ot_layout_get_baseline() `_. """ 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: """Searches variation axes of the font for a specific axis first; if not set, first tries to get default style values in the ``STAT`` table, then tries to polyfill from different tables of the font. :returns: Corresponding axis or default value to a style tag. Wraps `hb_style_get_value() `_. """ 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: """The virtual methods that define the font functions used by a :class:`Font` for the basic, lower-level queries against a font object. Wraps `hb_font_funcs_t `_. """ 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) @classmethod @deprecated("FontFuncs()", since="0.10.0") 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): """Sets the implementation function for the horizontal-glyph-advance callback. Wraps `hb_font_funcs_set_glyph_h_advance_func() `_. """ 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): """Sets the implementation function for the vertical-glyph-advance callback. Wraps `hb_font_funcs_set_glyph_v_advance_func() `_. """ 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): """Sets the implementation function for the vertical-glyph-origin callback. The callback must return a ``(success, x, y)`` tuple. Wraps `hb_font_funcs_set_glyph_v_origin_func() `_. """ 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): """Sets the implementation function for the glyph-name callback. Wraps `hb_font_funcs_set_glyph_name_func() `_. """ 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): """Sets the implementation function for the nominal-glyph callback. Wraps `hb_font_funcs_set_nominal_glyph_func() `_. """ 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): """Sets the implementation function for the variation-glyph callback. Wraps `hb_font_funcs_set_variation_glyph_func() `_. """ 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): """Sets the implementation function for the horizontal-font-extents callback. Wraps `hb_font_funcs_set_font_h_extents_func() `_. """ 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): """Sets the implementation function for the vertical-font-extents callback. Wraps `hb_font_funcs_set_font_v_extents_func() `_. """ hb_font_funcs_set_font_v_extents_func( self._hb_ffuncs, _font_v_extents_func, user_data, NULL) self._font_v_extents_func = func harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/_harfbuzz.pyx000066400000000000000000000346111526670067500233130ustar00rootroot00000000000000#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: """Returns library version as a string with three components. :returns: Library version string. Wraps `hb_version_string() `_. """ cdef const char* cstr = hb_version_string() cdef bytes packed = cstr return packed.decode() WARNED = set() def deprecated(replacement=None, since=""): """Decorator to raise a warning when a deprecated function is called. Also prepends a Sphinx ``.. deprecated::`` directive to the wrapped function's docstring. """ 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) notice = f".. deprecated:: {since}".rstrip() if replacement: # Put the replacement note as a separate paragraph so it doesn’t # get stripped away if there is no existing docstring. notice += f"\n\nUse :obj:`{replacement}` instead." existing = wrapper.__doc__ or "" wrapper.__doc__ = f"{notice}\n\n{existing}" if existing else notice return wrapper return decorator class HarfBuzzError(Exception): pass include "_set.pxi" include "_map.pxi" include "_blob.pxi" include "_buffer.pxi" include "_face.pxi" include "_draw.pxi" include "_paint.pxi" include "_font.pxi" include "_raster.pxi" include "_serialize.pxi" include "_subset.pxi" # Generated by setup.py include "_generated_docs.pxi" 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): """Shapes ``buffer`` using ``font`` turning its Unicode characters content to positioned glyphs. If ``features`` is not ``None``, it will be used to control the features applied during shaping. If two features have the same tag but overlapping ranges the value of the feature with the higher index takes precedence. If ``shapers`` is not ``None``, the specified shapers will be used in the given order, otherwise the default shapers list will be used. :param font: A :class:`Font` to use for shaping. :param buffer: A :class:`Buffer` to shape. :param features: A mapping whose keys are feature tags (or feature strings as accepted by ``hb_feature_from_string`` when the value is an ``int``/``bool``), and whose values are either an ``int``/``bool`` applied globally, or a sequence of ``(start, end, value)`` triples applying the feature to a specific cluster range. :param shapers: Ordered list of shaper names to try, or ``None`` for the default list. :raises RuntimeError: If all shapers failed (only when ``shapers`` is provided). :raises MemoryError: If memory allocation fails. Wraps `hb_shape() `_ or `hb_shape_full() `_ when ``shapers`` is given. """ 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: """Converts a script tag to a script. :param tag: A script tag. :returns: The script corresponding to ``tag``. Wraps `hb_ot_tag_to_script() `_. """ 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: """Converts a language tag to a language. :param tag: A language tag. :returns: The language corresponding to ``tag``, or ``None``. Wraps `hb_ot_tag_to_language() `_. """ 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()", since="0.40.0") 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()", since="0.40.0") 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()", since="0.40.0") 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()", since="0.40.0") 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()", since="0.40.0") 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", since="0.40.0") def ot_layout_has_glyph_classes(face: Face) -> bool: return face.has_layout_glyph_classes @deprecated("Face.has_layout_positioning", since="0.40.0") def ot_layout_has_positioning(face: Face) -> bool: return face.has_layout_positioning @deprecated("Face.has_layout_substitution", since="0.40.0") def ot_layout_has_substitution(face: Face) -> bool: return face.has_layout_substitution @deprecated("Face.get_layout_glyph_class()", since="0.40.0") def ot_layout_get_glyph_class(face: Face, glyph: int) -> OTLayoutGlyphClass: return face.get_layout_glyph_class(glyph) @deprecated("Face.has_color_palettes", since="0.40.0") def ot_color_has_palettes(face: Face) -> bool: return face.has_color_palettes @deprecated("Face.color_palettes", since="0.40.0") def ot_color_palette_get_count(face: Face) -> int: return hb_ot_color_palette_get_count(face._hb_face) @deprecated("Face.get_color_palette()", since="0.40.0") 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()", since="0.40.0") 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()", since="0.40.0") 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()", since="0.40.0") 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", since="0.40.0") def ot_color_has_layers(face: Face) -> bool: return face.has_color_layers @deprecated("Face.get_glyph_color_layers()", since="0.40.0") def ot_color_glyph_get_layers(face: Face, glyph: int) -> List[OTColorLayer]: return face.get_glyph_color_layers(glyph) @deprecated("Face.has_color_paint", since="0.40.0") def ot_color_has_paint(face: Face) -> bool: return face.has_color_paint @deprecated("Face.glyph_has_color_paint()", since="0.40.0") def ot_color_glyph_has_paint(face: Face, glyph: int) -> bool: return face.glyph_has_color_paint(glyph) @deprecated("Face.has_color_svg", since="0.40.0") def ot_color_has_svg(face: Face) -> bool: return face.has_color_svg @deprecated("Face.get_glyph_color_svg()", since="0.40.0") def ot_color_glyph_get_svg(face: Face, glyph: int) -> Blob: return face.get_glyph_color_svg(glyph) @deprecated("Face.has_color_png", since="0.40.0") def ot_color_has_png(face: Face) -> bool: return face.has_color_png @deprecated("Font.get_glyph_color_png()", since="0.40.0") def ot_color_glyph_get_png(font: Font, glyph: int) -> Blob: return font.get_glyph_color_png(glyph) @deprecated("Face.has_math_data", since="0.40.0") def ot_math_has_data(face: Face) -> bool: return face.has_math_data @deprecated("Font.get_math_constant()", since="0.40.0") def ot_math_get_constant(font: Font, constant: OTMathConstant) -> int: return font.get_math_constant(constant) @deprecated("Font.get_math_glyph_italics_correction()", since="0.40.0") 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()", since="0.40.0") 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()", since="0.40.0") 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()", since="0.40.0") 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()", since="0.40.0") 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()", since="0.40.0") 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()", since="0.40.0") 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()", since="0.40.0") 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): """Sets the font functions to use when working with ``font`` to the HarfBuzz's native implementation. This is the default for fonts newly created. Wraps `hb_ot_font_set_funcs() `_. """ hb_ot_font_set_funcs(font._hb_font) harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/_harfbuzz_test.pyx000066400000000000000000000000331526670067500243410ustar00rootroot00000000000000#cython: language_level=3 harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/_map.pxi000066400000000000000000000121331526670067500222100ustar00rootroot00000000000000cdef class Map: """Data type for holding integer-to-integer hash maps. .. attribute:: INVALID_VALUE Unset map value. Wraps `HB_MAP_VALUE_INVALID `_. Wraps `hb_map_t `_. """ cdef hb_map_t* _hb_map INVALID_VALUE = HB_MAP_VALUE_INVALID def __cinit__(self, *args, **kwargs): self._hb_map = NULL def __init__(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 it.""" cdef Map wrapper = Map.__new__(Map) wrapper._hb_map = hb_map return wrapper def copy(self) -> Map: """Allocate a copy of this map. :returns: Newly-allocated map. Wraps `hb_map_copy() `_. """ 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): """Add the contents of ``other`` to this map. :param other: Another :class:`Map`, or any mapping of integer keys to integer values. Wraps `hb_map_update() `_. """ 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): """Clears out the contents of this map. Wraps `hb_map_clear() `_. """ 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): """Fetches the value stored for ``k`` in this map. :param k: The key to query. :returns: The value stored for ``k``, or ``None`` if ``k`` is not in the map. Wraps `hb_map_get() `_. """ 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): """Returns an iterator over ``(key, value)`` pairs in this map. The order in which the pairs are returned is undefined. """ return MapIter(self) def keys(self): """Returns an iterator over the keys in this map. The order in which the keys are returned is undefined. """ return (k for k,v in self.items()) def values(self): """Returns an iterator over the values in this map. The order in which the values are returned is undefined. """ 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: """Iterator over ``(key, value)`` pairs in a :class:`Map`. Wraps `hb_map_next() `_. """ 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) harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/_paint.pxi000066400000000000000000000765541526670067500225670ustar00rootroot00000000000000class PaintCompositeMode(IntEnum): """The values of this enumeration describe the compositing modes that can be used when combining temporary redirected drawing with the backdrop. See the OpenType spec `COLR `_ section for details. .. attribute:: CLEAR Clear destination layer (bounded). .. attribute:: SRC Replace destination layer (bounded). .. attribute:: DEST Ignore the source. .. attribute:: SRC_OVER Draw source layer on top of destination layer (bounded). .. attribute:: DEST_OVER Draw destination on top of source. .. attribute:: SRC_IN Draw source where there was destination content (unbounded). .. attribute:: DEST_IN Leave destination only where there was source content (unbounded). .. attribute:: SRC_OUT Draw source where there was no destination content (unbounded). .. attribute:: DEST_OUT Leave destination only where there was no source content. .. attribute:: SRC_ATOP Draw source on top of destination content and only there. .. attribute:: DEST_ATOP Leave destination on top of source content and only there (unbounded). .. attribute:: XOR Source and destination are shown where there is only one of them. .. attribute:: PLUS Source and destination layers are accumulated. .. attribute:: SCREEN Source and destination are complemented and multiplied. This causes the result to be at least as light as the lighter inputs. .. attribute:: OVERLAY Multiplies or screens, depending on the lightness of the destination color. .. attribute:: DARKEN Replaces the destination with the source if it is darker, otherwise keeps the source. .. attribute:: LIGHTEN Replaces the destination with the source if it is lighter, otherwise keeps the source. .. attribute:: COLOR_DODGE Brightens the destination color to reflect the source color. .. attribute:: COLOR_BURN Darkens the destination color to reflect the source color. .. attribute:: HARD_LIGHT Multiplies or screens, dependent on source color. .. attribute:: SOFT_LIGHT Darkens or lightens, dependent on source color. .. attribute:: DIFFERENCE Takes the difference of the source and destination color. .. attribute:: EXCLUSION Produces an effect similar to difference, but with lower contrast. .. attribute:: MULTIPLY Source and destination layers are multiplied. This causes the result to be at least as dark as the darker inputs. .. attribute:: HSL_HUE Creates a color with the hue of the source and the saturation and luminosity of the target. .. attribute:: HSL_SATURATION Creates a color with the saturation of the source and the hue and luminosity of the target. Painting with this mode onto a gray area produces no change. .. attribute:: HSL_COLOR Creates a color with the hue and saturation of the source and the luminosity of the target. This preserves the gray levels of the target and is useful for coloring monochrome images or tinting color images. .. attribute:: HSL_LUMINOSITY Creates a color with the luminosity of the source and the hue and saturation of the target. This produces an inverse effect to :attr:`HSL_COLOR`. Wraps `hb_paint_composite_mode_t `_. """ 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): """Information about a color stop on a color line. Color lines typically have offsets ranging between 0 and 1, but that is not required. The ``is_foreground`` and ``color`` fields have the same semantics as in the color callback set by :meth:`PaintFuncs.set_color_func`. Note: despite ``color`` being unpremultiplied here, interpolation in gradients shall happen in premultiplied space. See the OpenType spec `COLR `_ section for details. Wraps `hb_color_stop_t `_. """ offset: float """The offset of the color stop.""" is_foreground: bool """Whether the color is the foreground.""" color: Color """The color, unpremultiplied.""" class PaintExtend(IntEnum): """The values of this enumeration determine how color values outside the minimum and maximum defined offset on a :class:`ColorLine` are determined. See the OpenType spec `COLR `_ section for details. .. attribute:: PAD Outside the defined interval, the color of the closest color stop is used. .. attribute:: REPEAT The color line is repeated over repeated multiples of the defined interval. .. attribute:: REFLECT The color line is repeated over repeated intervals, as for the repeat mode. However, in each repeated interval, the ordering of color stops is the reverse of the adjacent interval. Wraps `hb_paint_extend_t `_. """ PAD = HB_PAINT_EXTEND_PAD REPEAT = HB_PAINT_EXTEND_REPEAT REFLECT = HB_PAINT_EXTEND_REFLECT cdef class ColorLine: """A struct containing color information for a gradient. Wraps `hb_color_line_t `_. """ 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]: """Fetches a list of color stops from this color line. Note that due to variations being applied, the returned color stops may be out of order. It is the caller's responsibility to ensure that color stops are sorted by their offset before they are used. :type: Sequence[ColorStop] Wraps `hb_color_line_get_color_stops() `_. """ 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: """Fetches the extend mode of this color line. :type: PaintExtend Wraps `hb_color_line_get_extend() `_. """ 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_fill_glyph_func( hb_paint_funcs_t *funcs, void *paint_data, hb_codepoint_t glyph, hb_font_t *font, 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._fill_glyph_func(glyph, py_color, is_foreground, paint_data) 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: """Glyph paint callbacks. The callbacks assume that the caller maintains a stack of current transforms, clips and intermediate surfaces, as evidenced by the pairs of push/pop callbacks. The push/pop calls will be properly nested, so it is fine to store the different kinds of object on a single stack. Not all callbacks are required for all kinds of glyphs. For rendering COLRv0 or non-color outline glyphs, the gradient callbacks are not needed, and the composite callback only needs to handle simple alpha compositing (:attr:`PaintCompositeMode.SRC_OVER`). The paint-image callback is only needed for glyphs with image blobs in the ``CBDT``, ``sbix`` or ``SVG`` tables. The custom-palette-color callback is only necessary if you want to override colors from the font palette with custom colors. Wraps `hb_paint_funcs_t `_. """ cdef hb_paint_funcs_t* _hb_paintfuncs cdef object _push_transform_func cdef object _pop_transform_func cdef object _color_glyph_func cdef object _fill_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]): """Sets the push-transform callback on this :class:`PaintFuncs`. The callback applies a transform to subsequent paint calls. This transform is applied after the current transform, and remains in effect until a matching call to the pop-transform callback. Wraps `hb_paint_funcs_set_push_transform_func() `_. """ 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]): """Sets the pop-transform callback on this :class:`PaintFuncs`. The callback undoes the effect of a prior call to the push-transform callback. Wraps `hb_paint_funcs_set_pop_transform_func() `_. """ 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]): """Sets the color-glyph callback on this :class:`PaintFuncs`. The callback renders a color glyph by glyph index. It should return ``True`` if the glyph was painted, ``False`` otherwise. Wraps `hb_paint_funcs_set_color_glyph_func() `_. """ self._color_glyph_func = func hb_paint_funcs_set_color_glyph_func( self._hb_paintfuncs, _paint_color_glyph_func, self, NULL) def set_fill_glyph_func(self, func: Callable[[ int, # gid Color, # color bool, # is_foreground object, # paint_data ], None]): """Sets the fill-glyph callback on this :class:`PaintFuncs`. The callback fills a glyph's shape with a solid color. ``is_foreground`` indicates whether the color is the foreground. ``color`` is the color to use, unpremultiplied. If not set, a sequence of push-clip-glyph, color and pop-clip paint operations, in that order, will be emitted instead. Wraps `hb_paint_funcs_set_fill_glyph_func() `_. """ self._fill_glyph_func = func hb_paint_funcs_set_fill_glyph_func( self._hb_paintfuncs, _paint_fill_glyph_func, self, NULL) def set_push_clip_glyph_func(self, func: Callable[[ int, # gid object, # paint_data ], None]): """Sets the push-clip-glyph callback on this :class:`PaintFuncs`. The callback clips subsequent paint calls to the outline of a glyph. This clip is applied in addition to the current clip, and remains in effect until a matching call to the pop-clip callback. Wraps `hb_paint_funcs_set_push_clip_glyph_func() `_. """ 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]): """Sets the push-clip-rectangle callback on this :class:`PaintFuncs`. The callback clips subsequent paint calls to a rectangle. The coordinates of the rectangle are interpreted according to the current transform. This clip is applied in addition to the current clip, and remains in effect until a matching call to the pop-clip callback. Wraps `hb_paint_funcs_set_push_clip_rectangle_func() `_. """ 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]): """Sets the pop-clip callback on this :class:`PaintFuncs`. The callback undoes the effect of a prior call to the push-clip-glyph or push-clip-rectangle callback. Wraps `hb_paint_funcs_set_pop_clip_func() `_. """ 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]): """Sets the color callback on this :class:`PaintFuncs`. The callback paints a color everywhere within the current clip. ``is_foreground`` indicates whether the color is the foreground. ``color`` is the color to use, unpremultiplied. When ``is_foreground`` is true, this color originates from the foreground-color sentinel in the font's color data. The ``color`` parameter still carries a fully resolved RGBA value (with any paint-tree alpha already applied), so backends that do not need to distinguish the foreground can simply use ``color`` directly. Backends that defer foreground resolution (e.g. to honor a CSS ``currentColor`` or a runtime uniform) should substitute their own foreground RGB when ``is_foreground`` is true, but must combine the alpha from ``color`` with their foreground alpha, since it encodes additional modulation from the paint tree. For this mode to work correctly, the caller should pass a fully-opaque foreground color to :meth:`Font.paint_glyph`, so that the alpha in ``color`` reflects only the paint-tree contribution. Wraps `hb_paint_funcs_set_color_func() `_. """ 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]): """Sets the paint-image callback on this :class:`PaintFuncs`. The callback paints a glyph image. It is called for glyphs with image blobs in the ``CBDT``, ``sbix`` or ``SVG`` tables. The ``format`` argument identifies the kind of data that is contained in ``image``. The image dimensions and glyph extents are provided if available, and should be used to size and position the image. The callback should return whether the operation was successful. Wraps `hb_paint_funcs_set_image_func() `_. """ 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]): """Sets the linear-gradient callback on this :class:`PaintFuncs`. The callback paints a linear gradient everywhere within the current clip. The ``color_line`` object contains information about the colors of the gradient; it is only valid for the duration of the callback, you cannot keep it around. The coordinates of the points are interpreted according to the current transform. Wraps `hb_paint_funcs_set_linear_gradient_func() `_. """ 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]): """Sets the radial-gradient callback on this :class:`PaintFuncs`. The callback paints a radial gradient everywhere within the current clip. The ``color_line`` object contains information about the colors of the gradient; it is only valid for the duration of the callback, you cannot keep it around. The coordinates of the points are interpreted according to the current transform. Wraps `hb_paint_funcs_set_radial_gradient_func() `_. """ 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]): """Sets the sweep-gradient callback on this :class:`PaintFuncs`. The callback paints a sweep gradient everywhere within the current clip. The ``color_line`` object contains information about the colors of the gradient; it is only valid for the duration of the callback, you cannot keep it around. The coordinates of the points are interpreted according to the current transform. Wraps `hb_paint_funcs_set_sweep_gradient_func() `_. """ 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]): """Sets the push-group callback on this :class:`PaintFuncs`. The callback uses an intermediate surface for subsequent paint calls. The drawing will be redirected to an intermediate surface until a matching call to the pop-group callback. Wraps `hb_paint_funcs_set_push_group_func() `_. """ 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]): """Sets the pop-group callback on this :class:`PaintFuncs`. The callback undoes the effect of a prior call to the push-group callback. It stops the redirection to the intermediate surface, and then composites it on the previous surface, using the compositing mode passed to the callback. Wraps `hb_paint_funcs_set_pop_group_func() `_. """ 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]): """Sets the custom-palette-color callback on this :class:`PaintFuncs`. The callback fetches a custom palette override color for ``color_index``. Custom palette colors override colors from the font's selected color palette. It is not necessary to override all palette entries; return ``None`` for entries that should be taken from the font palette. Wraps `hb_paint_funcs_set_custom_palette_color_func() `_. """ self._custom_palette_color_func = func hb_paint_funcs_set_custom_palette_color_func( self._hb_paintfuncs, _paint_custom_palette_color_func, self, NULL) harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/_raster.pxi000066400000000000000000000554651526670067500227520ustar00rootroot00000000000000class RasterFormat(IntEnum): """Pixel format for raster images. .. attribute:: A8 8-bit alpha-only coverage. .. attribute:: BGRA32 32-bit BGRA color. Wraps `hb_raster_format_t `_. """ A8 = HB_RASTER_FORMAT_A8 BGRA32 = HB_RASTER_FORMAT_BGRA32 class RasterExtents(NamedTuple): """Pixel-buffer extents for raster operations. Wraps `hb_raster_extents_t `_. """ x_origin: int = 0 """X coordinate of the left edge of the image in glyph space.""" y_origin: int = 0 """Y coordinate of the bottom edge of the image in glyph space.""" width: int = 0 """Width in pixels.""" height: int = 0 """Height in pixels.""" stride: int = 0 """Bytes per row; 0 means auto-calculate on input, filled on output.""" cdef class RasterImage: """An opaque raster image object holding a pixel buffer produced by :meth:`RasterDraw.render`. Use :attr:`buffer` and :attr:`extents` to access the pixels. Wraps `hb_raster_image_t `_. """ cdef hb_raster_image_t* _hb_raster_image def __cinit__(self): self._hb_raster_image = NULL def __init__(self): self._hb_raster_image = hb_raster_image_create_or_fail() if self._hb_raster_image is NULL: raise MemoryError() def __dealloc__(self): hb_raster_image_destroy(self._hb_raster_image) @staticmethod cdef RasterImage from_ptr(hb_raster_image_t* hb_img): """Create RasterImage from a pointer, taking ownership of it.""" cdef RasterImage wrapper = RasterImage.__new__(RasterImage) wrapper._hb_raster_image = hb_img return wrapper def configure(self, format: RasterFormat, extents: RasterExtents | None = None) -> bool: """Configures this image's format and extents together, resizing backing storage at most once. This function does not clear pixel contents. Passing ``None`` for ``extents`` clears extents and releases the backing allocation. :returns: ``True`` if configuration succeeds, ``False`` on allocation failure. Wraps `hb_raster_image_configure() `_. """ cdef hb_raster_extents_t c_extents cdef hb_raster_extents_t* c_extents_ptr = NULL if extents is not None: c_extents.x_origin = extents.x_origin c_extents.y_origin = extents.y_origin c_extents.width = extents.width c_extents.height = extents.height c_extents.stride = extents.stride c_extents_ptr = &c_extents return hb_raster_image_configure(self._hb_raster_image, format, c_extents_ptr) def clear(self): """Clears this image's pixels to zero while keeping current extents and format. Wraps `hb_raster_image_clear() `_. """ hb_raster_image_clear(self._hb_raster_image) @property def format(self) -> RasterFormat: """Fetches the pixel format of this image. :type: RasterFormat Wraps `hb_raster_image_get_format() `_. """ return RasterFormat(hb_raster_image_get_format(self._hb_raster_image)) @property def extents(self) -> RasterExtents: """Fetches the pixel-buffer extents of this image. :type: RasterExtents Wraps `hb_raster_image_get_extents() `_. """ cdef hb_raster_extents_t c_extents hb_raster_image_get_extents(self._hb_raster_image, &c_extents) return RasterExtents( x_origin=c_extents.x_origin, y_origin=c_extents.y_origin, width=c_extents.width, height=c_extents.height, stride=c_extents.stride, ) @property def buffer(self) -> bytes: """Fetches the raw pixel buffer of this image. The buffer layout is described by :attr:`extents` and :attr:`format`. Rows are stored bottom-to-top. :type: bytes Wraps `hb_raster_image_get_buffer() `_. """ cdef hb_raster_extents_t c_extents hb_raster_image_get_extents(self._hb_raster_image, &c_extents) cdef const uint8_t* buf = hb_raster_image_get_buffer(self._hb_raster_image) if buf is NULL: return b"" cdef Py_ssize_t size = c_extents.height * c_extents.stride return buf[:size] cdef class RasterDraw: """An opaque outline rasterizer object. Accumulates glyph outlines via :class:`DrawFuncs` callbacks, then produces a :class:`RasterImage` with :meth:`render`. Wraps `hb_raster_draw_t `_. """ cdef hb_raster_draw_t* _hb_raster_draw def __cinit__(self): self._hb_raster_draw = hb_raster_draw_create_or_fail() if self._hb_raster_draw is NULL: raise MemoryError() def __dealloc__(self): hb_raster_draw_destroy(self._hb_raster_draw) @property def transform(self) -> Tuple[float, float, float, float, float, float]: """A 2×3 affine transform applied to all incoming draw coordinates before rasterization. The default is the identity. :type: tuple of (xx, yx, xy, yy, dx, dy) Wraps `hb_raster_draw_get_transform() `_ and `hb_raster_draw_set_transform() `_. """ cdef float xx, yx, xy, yy, dx, dy hb_raster_draw_get_transform(self._hb_raster_draw, &xx, &yx, &xy, &yy, &dx, &dy) return (xx, yx, xy, yy, dx, dy) @transform.setter def transform(self, value: Tuple[float, float, float, float, float, float]): xx, yx, xy, yy, dx, dy = value hb_raster_draw_set_transform(self._hb_raster_draw, xx, yx, xy, yy, dx, dy) @property def scale_factor(self) -> Tuple[float, float]: """Post-transform minification factors applied during rasterization. Factors larger than 1 shrink the output in pixels. The default is 1. :type: tuple of (x_scale_factor, y_scale_factor) Wraps `hb_raster_draw_get_scale_factor() `_ and `hb_raster_draw_set_scale_factor() `_. """ cdef float x, y hb_raster_draw_get_scale_factor(self._hb_raster_draw, &x, &y) return (x, y) @scale_factor.setter def scale_factor(self, value: Tuple[float, float]): x, y = value hb_raster_draw_set_scale_factor(self._hb_raster_draw, x, y) @property def extents(self) -> RasterExtents | None: """The output image extents. When set, :meth:`render` uses the given extents instead of auto-computing them from the accumulated geometry. ``None`` if no extents are configured. :type: RasterExtents | None Wraps `hb_raster_draw_get_extents() `_ and `hb_raster_draw_set_extents() `_. """ cdef hb_raster_extents_t c_extents if not hb_raster_draw_get_extents(self._hb_raster_draw, &c_extents): return None return RasterExtents( x_origin=c_extents.x_origin, y_origin=c_extents.y_origin, width=c_extents.width, height=c_extents.height, stride=c_extents.stride, ) @extents.setter def extents(self, value: RasterExtents): cdef hb_raster_extents_t c_extents c_extents.x_origin = value.x_origin c_extents.y_origin = value.y_origin c_extents.width = value.width c_extents.height = value.height c_extents.stride = value.stride hb_raster_draw_set_extents(self._hb_raster_draw, &c_extents) def set_glyph_extents(self, extents: GlyphExtents) -> bool: """Transforms ``extents`` with the rasterizer's current transform and sets the resulting pixel extents for the next render. This is equivalent to computing a transformed bounding box in pixel space and assigning it to :attr:`extents`. :returns: ``True`` if transformed extents are non-empty and set; ``False`` otherwise. Wraps `hb_raster_draw_set_glyph_extents() `_. """ cdef hb_glyph_extents_t c_extents c_extents.x_bearing = extents.x_bearing c_extents.y_bearing = extents.y_bearing c_extents.width = extents.width c_extents.height = extents.height return hb_raster_draw_set_glyph_extents(self._hb_raster_draw, &c_extents) def draw_glyph(self, font: Font, glyph: int): """Draws one glyph into this rasterizer using the current transform. Equivalent to :meth:`draw_glyph_or_fail` with the return value ignored. Wraps `hb_raster_draw_glyph() `_. """ hb_raster_draw_glyph(self._hb_raster_draw, font._hb_font, glyph) def draw_glyph_or_fail(self, font: Font, glyph: int) -> bool: """Convenience to draw one glyph. :returns: ``True`` if the glyph was drawn, ``False`` if the font has no outlines for ``glyph``. Wraps `hb_raster_draw_glyph_or_fail() `_. """ return hb_raster_draw_glyph_or_fail(self._hb_raster_draw, font._hb_font, glyph) def render(self) -> RasterImage | None: """Rasterizes the accumulated outline geometry into a new :class:`RasterImage`. After rendering, the accumulated edges are cleared so the rasterizer can be reused. Output format is always :attr:`RasterFormat.A8`. :returns: A rendered :class:`RasterImage`. Returns ``None`` on allocation/configuration failure. If no geometry was accumulated, returns an empty image. Wraps `hb_raster_draw_render() `_. """ cdef hb_raster_image_t* img = hb_raster_draw_render(self._hb_raster_draw) if img is NULL: return None return RasterImage.from_ptr(img) def clear(self): """Discards accumulated geometry and extents so this rasterizer can be reused for another render. User configuration (transform, scale factors) is preserved. Call :meth:`reset` to also reset user configuration to defaults. Wraps `hb_raster_draw_clear() `_. """ hb_raster_draw_clear(self._hb_raster_draw) def reset(self): """Resets this rasterizer to its initial state, clearing all accumulated geometry, the transform, and fixed extents. The object can then be reused for a new glyph. Wraps `hb_raster_draw_reset() `_. """ hb_raster_draw_reset(self._hb_raster_draw) cdef class RasterPaint: """An opaque color-glyph paint context. Implements :class:`PaintFuncs` callbacks that render COLRv0/v1 color glyphs into a :attr:`RasterFormat.BGRA32` :class:`RasterImage`. Wraps `hb_raster_paint_t `_. """ cdef hb_raster_paint_t* _hb_raster_paint def __cinit__(self): self._hb_raster_paint = hb_raster_paint_create_or_fail() if self._hb_raster_paint is NULL: raise MemoryError() def __dealloc__(self): hb_raster_paint_destroy(self._hb_raster_paint) @property def transform(self) -> Tuple[float, float, float, float, float, float]: """The base 2×3 affine transform that maps from glyph-space coordinates to pixel-space coordinates. :type: tuple of (xx, yx, xy, yy, dx, dy) Wraps `hb_raster_paint_get_transform() `_ and `hb_raster_paint_set_transform() `_. """ cdef float xx, yx, xy, yy, dx, dy hb_raster_paint_get_transform(self._hb_raster_paint, &xx, &yx, &xy, &yy, &dx, &dy) return (xx, yx, xy, yy, dx, dy) @transform.setter def transform(self, value: Tuple[float, float, float, float, float, float]): xx, yx, xy, yy, dx, dy = value hb_raster_paint_set_transform(self._hb_raster_paint, xx, yx, xy, yy, dx, dy) @property def scale_factor(self) -> Tuple[float, float]: """Post-transform minification factors applied during painting. Factors larger than 1 shrink the output in pixels. The default is 1. :type: tuple of (x_scale_factor, y_scale_factor) Wraps `hb_raster_paint_get_scale_factor() `_ and `hb_raster_paint_set_scale_factor() `_. """ cdef float x, y hb_raster_paint_get_scale_factor(self._hb_raster_paint, &x, &y) return (x, y) @scale_factor.setter def scale_factor(self, value: Tuple[float, float]): x, y = value hb_raster_paint_set_scale_factor(self._hb_raster_paint, x, y) @property def extents(self) -> RasterExtents | None: """The output image extents (pixel rectangle). Must be set before painting; otherwise :meth:`render` returns ``None``. ``None`` if no extents are configured. :type: RasterExtents | None Wraps `hb_raster_paint_get_extents() `_ and `hb_raster_paint_set_extents() `_. """ cdef hb_raster_extents_t c_extents if not hb_raster_paint_get_extents(self._hb_raster_paint, &c_extents): return None return RasterExtents( x_origin=c_extents.x_origin, y_origin=c_extents.y_origin, width=c_extents.width, height=c_extents.height, stride=c_extents.stride, ) @extents.setter def extents(self, value: RasterExtents): cdef hb_raster_extents_t c_extents c_extents.x_origin = value.x_origin c_extents.y_origin = value.y_origin c_extents.width = value.width c_extents.height = value.height c_extents.stride = value.stride hb_raster_paint_set_extents(self._hb_raster_paint, &c_extents) def set_glyph_extents(self, extents: GlyphExtents) -> bool: """Transforms ``extents`` with the paint context's base transform and sets the resulting output image extents. This is equivalent to computing a transformed bounding box in pixel space and assigning it to :attr:`extents`. :returns: ``True`` if transformed extents are non-empty and set; ``False`` otherwise. Wraps `hb_raster_paint_set_glyph_extents() `_. """ cdef hb_glyph_extents_t c_extents c_extents.x_bearing = extents.x_bearing c_extents.y_bearing = extents.y_bearing c_extents.width = extents.width c_extents.height = extents.height return hb_raster_paint_set_glyph_extents(self._hb_raster_paint, &c_extents) @property def foreground(self) -> Color: """The foreground color used when paint callbacks request it (e.g. ``is_foreground`` in color stops or solid fills). Defaults to opaque black if none was set. :type: Color Wraps `hb_raster_paint_get_foreground() `_ and `hb_raster_paint_set_foreground() `_. """ return Color.from_int(hb_raster_paint_get_foreground(self._hb_raster_paint)) @foreground.setter def foreground(self, value: Color): hb_raster_paint_set_foreground(self._hb_raster_paint, value.to_int()) @property def background(self) -> Color: """The background color. If set to a non-transparent value, the rendered image is pre-filled with this color before glyph content is composited on top. Default is transparent. :type: Color Wraps `hb_raster_paint_get_background() `_ and `hb_raster_paint_set_background() `_. """ return Color.from_int(hb_raster_paint_get_background(self._hb_raster_paint)) @background.setter def background(self, value: Color): hb_raster_paint_set_background(self._hb_raster_paint, value.to_int()) @property def palette(self) -> int: """Selects which font palette is used when paint callbacks look up indexed colors. Default is palette 0. :type: int Wraps `hb_raster_paint_get_palette() `_ and `hb_raster_paint_set_palette() `_. """ return hb_raster_paint_get_palette(self._hb_raster_paint) @palette.setter def palette(self, value: int): hb_raster_paint_set_palette(self._hb_raster_paint, value) def set_custom_palette_color(self, color_index: int, color: Color) -> bool: """Overrides one font palette color entry for subsequent paint operations. Overrides are keyed by ``color_index`` and persist on this paint context until cleared (or replaced for the same index). These overrides are consulted by paint operations that resolve ``CPAL`` entries. :returns: ``True`` if the override was set; ``False`` on allocation failure. Wraps `hb_raster_paint_set_custom_palette_color() `_. """ return hb_raster_paint_set_custom_palette_color( self._hb_raster_paint, color_index, color.to_int()) def clear_custom_palette_colors(self): """Clears all custom palette color overrides previously set on this paint context. After this call, palette lookups use the selected font palette without custom override entries. Wraps `hb_raster_paint_clear_custom_palette_colors() `_. """ hb_raster_paint_clear_custom_palette_colors(self._hb_raster_paint) def paint_glyph(self, font: Font, glyph: int): """Paints one glyph into this paint context. Unlike :meth:`paint_glyph_or_fail`, glyphs with no color paint data fall back to a synthesized foreground-colored outline, so any glyph with an outline or bitmap image produces output. Wraps `hb_raster_paint_glyph() `_. """ hb_raster_paint_glyph(self._hb_raster_paint, font._hb_font, glyph) def paint_glyph_or_fail(self, font: Font, glyph: int) -> bool: """Convenience to paint one color glyph. :returns: ``True`` if painting succeeded, ``False`` otherwise. Wraps `hb_raster_paint_glyph_or_fail() `_. """ return hb_raster_paint_glyph_or_fail(self._hb_raster_paint, font._hb_font, glyph) def render(self) -> RasterImage | None: """Extracts the rendered image after painting has completed. The paint context's surface stack is consumed and the result returned as a new :class:`RasterImage`. Output format is always :attr:`RasterFormat.BGRA32`. :attr:`extents` or :meth:`set_glyph_extents` must be called before painting; otherwise this function returns ``None``. Internal drawing state is cleared here so the same object can be reused without client-side clearing. :returns: A rendered :class:`RasterImage`. Returns ``None`` if extents were not set or if allocation/configuration fails. If extents were set but nothing was painted, returns an empty image. Wraps `hb_raster_paint_render() `_. """ cdef hb_raster_image_t* img = hb_raster_paint_render(self._hb_raster_paint) if img is NULL: return None return RasterImage.from_ptr(img) def clear(self): """Discards accumulated paint output so this paint context can be reused for another render. User configuration (base transform, scale factors, foreground, custom palette colors) is preserved. Call :meth:`reset` to also reset user configuration to defaults. Wraps `hb_raster_paint_clear() `_. """ hb_raster_paint_clear(self._hb_raster_paint) def reset(self): """Resets this paint context to its initial state, clearing all configuration while preserving internal image caches. Wraps `hb_raster_paint_reset() `_. """ hb_raster_paint_reset(self._hb_raster_paint) harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/_serialize.pxi000066400000000000000000000162331526670067500234270ustar00rootroot00000000000000cdef class HBObject: """Represents an array of objects in the object graph to be serialized. Used internally by :func:`serialize` and :func:`serialize_with_tag`. Wraps `hb_subset_serialize_object_t `_. """ 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()", since="0.45.0") def repack(subtables, graphnodes): return serialize(subtables, graphnodes) @deprecated("serialize_with_tag()", since="0.45.0") 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: """Same as :func:`serialize_with_tag` with an empty ``tag``, which disables table specific optimizations. """ 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: """Given the input object graph info, repack a table to eliminate offset overflows and serialize it into a continuous array of bytes. Table specific optimizations (e.g. extension promotion in ``GSUB`` and ``GPOS``) may be performed. Passing an empty ``tag`` will disable table specific optimizations. 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 :param tag: Tag of the table being packed, needed to allow table specific optimizations. :param subtables: List of subtable byte buffers, one per object in the object graph. :param graphnodes: List of ``(real_links, virtual_links)`` tuples, one per object. :returns: The serialized table as bytes. :raises RepackerError: If serialization fails. Wraps `hb_subset_serialize_or_fail() `_. """ 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 harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/_set.pxi000066400000000000000000000233471526670067500222370ustar00rootroot00000000000000cdef class Set: """Data type for holding a set of integers. :class:`Set` is used to gather and contain glyph IDs, Unicode code points, and various other collections of discrete values. .. attribute:: INVALID_VALUE Unset set value. Wraps `HB_SET_VALUE_INVALID `_. Wraps `hb_set_t `_. """ cdef hb_set_t* _hb_set INVALID_VALUE = HB_SET_VALUE_INVALID def __cinit__(self, *args, **kwargs): self._hb_set = NULL def __init__(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 it.""" cdef Set wrapper = Set.__new__(Set) wrapper._hb_set = hb_set return wrapper def copy(self) -> Set: """Allocate a copy of this set. :returns: Newly-allocated set. Wraps `hb_set_copy() `_. """ c = Set() c._hb_set = hb_set_copy(self._hb_set) return c def __copy__(self) -> Set: return self.copy() def clear(self): """Clears out the contents of this set. Wraps `hb_set_clear() `_. """ hb_set_clear(self._hb_set) def __bool__(self) -> bool: return not hb_set_is_empty(self._hb_set) def invert(self): """Inverts the contents of this set. Wraps `hb_set_invert() `_. """ hb_set_invert(self._hb_set) def is_inverted(self) -> bool: """Returns whether the set is inverted. :returns: ``True`` if the set is inverted, ``False`` otherwise. Wraps `hb_set_is_inverted() `_. """ 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): """Adds ``c`` to this set. Wraps `hb_set_add() `_. """ 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): """Adds all of the elements from ``first`` to ``last`` (inclusive) to this set. Wraps `hb_set_add_range() `_. """ 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): """Removes ``c`` from this set, raising :class:`KeyError` if ``c`` is not in the set. Wraps `hb_set_del() `_. """ 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): """Removes ``c`` from this set if it is present. Wraps `hb_set_del() `_. """ 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): """Removes all of the elements from ``first`` to ``last`` (inclusive) from this set. If ``last`` is :attr:`INVALID_VALUE`, then all values greater than or equal to ``first`` are removed. Wraps `hb_set_del_range() `_. """ 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: """Tests whether this set is a subset of ``larger_set``. :returns: ``True`` if this set is a subset of (or equal to) ``larger_set``, ``False`` otherwise. Wraps `hb_set_is_subset() `_. """ return hb_set_is_subset(self._hb_set, larger_set._hb_set) def issuperset(self, smaller_set: Set) -> bool: """Tests whether ``smaller_set`` is a subset of this set. :returns: ``True`` if ``smaller_set`` is a subset of (or equal to) this set, ``False`` otherwise. Wraps `hb_set_is_subset() `_. """ 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): """Makes the contents of this set equal to the contents of ``other``. :param other: Another :class:`Set`, or any iterable of integers. Wraps `hb_set_set() `_. """ 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): """Makes this set the union of itself and ``other``. :param other: Another :class:`Set`, or any iterable of integers. Wraps `hb_set_union() `_. """ 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): """Makes this set the intersection of itself and ``other``. Wraps `hb_set_intersect() `_. """ 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): """Subtracts the contents of ``other`` from this set. Wraps `hb_set_subtract() `_. """ 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): """Makes this set the symmetric difference of itself and ``other``. Wraps `hb_set_symmetric_difference() `_. """ 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: """The smallest element in the set, or :attr:`INVALID_VALUE` if the set is empty. :type: int Wraps `hb_set_get_min() `_. """ return hb_set_get_min(self._hb_set) @property def max(self) -> int: """The largest element in the set, or :attr:`INVALID_VALUE` if the set is empty. :type: int Wraps `hb_set_get_max() `_. """ 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: """Iterator over the elements of a :class:`Set` in increasing order. Wraps `hb_set_next() `_. """ 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 harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/_subset.pxi000066400000000000000000000440361526670067500227470ustar00rootroot00000000000000def subset_preprocess(face: Face) -> Face: """Preprocesses the face and attaches data that will be needed by the subsetter. Future subsetting operations can then use the precomputed data to speed up the subsetting operation. See `subset-preprocessing `_ for more information. Note: the preprocessed face may contain sub-blobs that reference the memory backing the source :class:`Face`. Therefore in the case that this memory is not owned by the source face you will need to ensure that memory lives as long as the returned :class:`Face`. :returns: a new :class:`Face`. Wraps `hb_subset_preprocess() `_. """ new_face = hb_subset_preprocess(face._hb_face) return Face.from_ptr(new_face) def subset(face: Face, input: SubsetInput) -> Face: """Subsets a font according to provided input. :raises RuntimeError: If the subset operation fails or the face has no glyphs. Wraps `hb_subset_or_fail() `_. """ 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): """List of sets that can be configured on the subset input. .. attribute:: GLYPH_INDEX The set of glyph indexes to retain in the subset. .. attribute:: UNICODE The set of unicode codepoints to retain in the subset. .. attribute:: NO_SUBSET_TABLE_TAG The set of table tags which specifies tables that should not be subsetted. .. attribute:: DROP_TABLE_TAG The set of table tags which specifies tables which will be dropped in the subset. .. attribute:: NAME_ID The set of name ids that will be retained. .. attribute:: NAME_LANG_ID The set of name lang ids that will be retained. .. attribute:: LAYOUT_FEATURE_TAG The set of layout feature tags that will be retained in the subset. .. attribute:: LAYOUT_SCRIPT_TAG The set of layout script tags that will be retained in the subset. Defaults to all tags. Wraps `hb_subset_sets_t `_. """ 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): """List of boolean properties that can be configured on the subset input. .. attribute:: DEFAULT All flags at their default value of false. .. attribute:: NO_HINTING If set hinting instructions will be dropped in the produced subset. Otherwise hinting instructions will be retained. .. attribute:: RETAIN_GIDS If set glyph indices will not be modified in the produced subset. If glyphs are dropped their indices will be retained as an empty glyph. .. attribute:: DESUBROUTINIZE If set and subsetting a CFF font the subsetter will attempt to remove subroutines from the CFF glyphs. .. attribute:: NAME_LEGACY If set non-unicode name records will be retained in the subset. .. attribute:: SET_OVERLAPS_FLAG If set the subsetter will set the ``OVERLAP_SIMPLE`` flag on each simple glyph. .. attribute:: PASSTHROUGH_UNRECOGNIZED If set the subsetter will not drop unrecognized tables and instead pass them through untouched. .. attribute:: NOTDEF_OUTLINE If set the notdef glyph outline will be retained in the final subset. .. attribute:: GLYPH_NAMES If set the PS glyph names will be retained in the final subset. .. attribute:: NO_PRUNE_UNICODE_RANGES If set then the unicode ranges in ``OS/2`` will not be recalculated. .. attribute:: NO_LAYOUT_CLOSURE If set do not perform glyph closure on layout substitution rules (``GSUB``). .. attribute:: OPTIMIZE_IUP_DELTAS If set perform IUP delta optimization on the remaining ``gvar`` table's deltas. .. attribute:: NO_BIDI_CLOSURE If set do not pull mirrored versions of input codepoints into the subset. .. attribute:: DOWNGRADE_CFF2 If set and instantiating a variable font with all axes pinned, convert the output ``CFF2`` table to ``CFF ``. This enables compatibility with older renderers that don't support ``CFF2``. .. attribute:: CFF_IDENTITY_CHARSET If set and subsetting a CID-keyed CFF font, the output CFF charset will use sequential identity CIDs (CID = new GID) rather than preserving the original CIDs. Wraps `hb_subset_flags_t `_. """ 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 OPTIMIZE_IUP_DELTAS = HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS NO_BIDI_CLOSURE = HB_SUBSET_FLAGS_NO_BIDI_CLOSURE DOWNGRADE_CFF2 = HB_SUBSET_FLAGS_DOWNGRADE_CFF2 CFF_IDENTITY_CHARSET = HB_SUBSET_FLAGS_CFF_IDENTITY_CHARSET cdef class SubsetInput: """Things that change based on the input. Characters to keep, etc. Wraps `hb_subset_input_t `_. """ 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: """Subsets ``source`` according to this input. Equivalent to calling :func:`subset` with ``source`` and this input. """ return subset(source, self) def keep_everything(self): """Configure input object to keep everything in the font face. That is, all Unicodes, glyphs, names, layout items, glyph names, etc. The input can be tailored afterwards by the caller. Wraps `hb_subset_input_keep_everything() `_. """ hb_subset_input_keep_everything(self._hb_input) def pin_all_axes_to_default(self, face: Face) -> bool: """Pin all axes to default locations in this subset input object. All axes in a font must be pinned. Additionally, ``CFF2`` table, if present, will be de-subroutinized. :returns: ``True`` if success, ``False`` otherwise. Wraps `hb_subset_input_pin_all_axes_to_default() `_. """ 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: """Pin an axis to its default location in this subset input object. All axes in a font must be pinned. Additionally, ``CFF2`` table, if present, will be de-subroutinized. :param tag: Tag of the axis to be pinned. :returns: ``True`` if success, ``False`` otherwise. Wraps `hb_subset_input_pin_axis_to_default() `_. """ 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: """Pin an axis to a fixed location in this subset input object. All axes in a font must be pinned. Additionally, ``CFF2`` table, if present, will be de-subroutinized. :param tag: Tag of the axis to be pinned. :param value: Location on the axis to be pinned at. :returns: ``True`` if success, ``False`` otherwise. Wraps `hb_subset_input_pin_axis_location() `_. """ 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: """Restricting the range of variation on an axis in this subset input object. New min/default/max values will be clamped if they're not within the ``fvar`` axis range. If the ``fvar`` axis default value is not within the new range, the new default value will be changed to the new min or max value, whichever is closer to the ``fvar`` axis default. Note: input min value can not be bigger than input max value. If the input default value is not within the new min/max range, it'll be clamped. :param tag: Tag of the axis. :param min_value: Minimum value of the axis variation range to set, if ``None`` the existing min will be used. :param max_value: Maximum value of the axis variation range to set, if ``None`` the existing max will be used. :param def_value: Default value of the axis variation range to set, if ``None`` the existing default will be used. :returns: ``True`` if success, ``False`` otherwise. Wraps `hb_subset_input_set_axis_range() `_. """ 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: """Gets the axis range assigned by previous calls to :meth:`set_axis_range`. :param tag: Tag of the axis. :returns: ``(min, max, default)`` triple if a range has been set for this axis tag, ``None`` otherwise. Each component is ``None`` only if it was previously set to ``None`` (NaN) via :meth:`set_axis_range`. Wraps `hb_subset_input_get_axis_range() `_. """ 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]: """The set of Unicode code points to retain. The caller should modify the set as needed. :type: Set Wraps `hb_subset_input_unicode_set() `_. """ return Set.from_ptr(hb_set_reference (hb_subset_input_unicode_set(self._hb_input))) @property def glyph_set(self) -> Set[int]: """The set of glyph IDs to retain. The caller should modify the set as needed. :type: Set Wraps `hb_subset_input_glyph_set() `_. """ return Set.from_ptr(hb_set_reference (hb_subset_input_glyph_set(self._hb_input))) def sets(self, set_type : SubsetInputSets) -> Set: """Gets the set of the specified type. Wraps `hb_subset_input_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: """Shortcut for ``sets(SubsetInputSets.NO_SUBSET_TABLE_TAG)``. :type: Set """ return self.sets(SubsetInputSets.NO_SUBSET_TABLE_TAG) @property def drop_table_tag_set(self) -> Set: """Shortcut for ``sets(SubsetInputSets.DROP_TABLE_TAG)``. :type: Set """ return self.sets(SubsetInputSets.DROP_TABLE_TAG) @property def name_id_set(self) -> Set[int]: """Shortcut for ``sets(SubsetInputSets.NAME_ID)``. :type: Set """ return self.sets(SubsetInputSets.NAME_ID) @property def name_lang_id_set(self) -> Set[int]: """Shortcut for ``sets(SubsetInputSets.NAME_LANG_ID)``. :type: Set """ return self.sets(SubsetInputSets.NAME_LANG_ID) @property def layout_feature_tag_set(self) -> Set: """Shortcut for ``sets(SubsetInputSets.LAYOUT_FEATURE_TAG)``. :type: Set """ return self.sets(SubsetInputSets.LAYOUT_FEATURE_TAG) @property def layout_script_tag_set(self) -> Set: """Shortcut for ``sets(SubsetInputSets.LAYOUT_SCRIPT_TAG)``. :type: Set """ return self.sets(SubsetInputSets.LAYOUT_SCRIPT_TAG) @property def flags(self) -> SubsetFlags: """All of the subsetting flags in the input object. :type: SubsetFlags Wraps `hb_subset_input_get_flags() `_ and `hb_subset_input_set_flags() `_. """ 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: """Contains information about how the subset operation will be executed. Such as mappings from the old glyph ids to the new ones in the subset. Constructing a :class:`SubsetPlan` computes a plan for subsetting the supplied ``face`` according to the provided ``input``. The plan describes which tables and glyphs should be retained. Wraps `hb_subset_plan_t `_. """ 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: """Executes this subsetting plan. :returns: A new :class:`Face` containing the generated font subset. :raises RuntimeError: If the subsetting operation fails. Wraps `hb_subset_plan_execute_or_fail() `_. """ 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: """The mapping between glyphs in the original font to glyphs in the subset that will be produced by this plan. :type: Map Wraps `hb_subset_plan_old_to_new_glyph_mapping() `_. """ 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: """The mapping between glyphs in the subset that will be produced by this plan and the glyph in the original font. :type: Map Wraps `hb_subset_plan_new_to_old_glyph_mapping() `_. """ 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: """The mapping between codepoints in the original font and the associated glyph id in the original font. :type: Map Wraps `hb_subset_plan_unicode_to_old_glyph_mapping() `_. """ return Map.from_ptr(hb_map_reference (hb_subset_plan_unicode_to_old_glyph_mapping(self._hb_plan))) harfbuzz-uharfbuzz-7a648c4/src/uharfbuzz/charfbuzz.pxd000066400000000000000000001663011526670067500232740ustar00rootroot00000000000000from 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) ctypedef unsigned int (*hb_get_table_tags_func_t) ( const hb_face_t *face, unsigned int start_offset, unsigned int *table_count, hb_tag_t *table_tags, void *user_data) void hb_face_set_get_table_tags_func( hb_face_t *face, hb_get_table_tags_func_t func, void *user_data, hb_destroy_func_t destroy) 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_fill_glyph_func_t) ( hb_paint_funcs_t *funcs, void *paint_data, hb_codepoint_t glyph, hb_font_t *font, hb_bool_t is_foreground, hb_color_t color, 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_fill_glyph_func( hb_paint_funcs_t *funcs, hb_paint_fill_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 HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS HB_SUBSET_FLAGS_NO_BIDI_CLOSURE HB_SUBSET_FLAGS_DOWNGRADE_CFF2 HB_SUBSET_FLAGS_CFF_IDENTITY_CHARSET 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) cdef extern from "hb-raster.h": ctypedef enum hb_raster_format_t: HB_RASTER_FORMAT_A8 HB_RASTER_FORMAT_BGRA32 ctypedef struct hb_raster_extents_t: int x_origin int y_origin unsigned int width unsigned int height unsigned int stride ctypedef struct hb_raster_image_t: pass ctypedef struct hb_raster_draw_t: pass ctypedef struct hb_raster_paint_t: pass # Image hb_raster_image_t* hb_raster_image_create_or_fail() hb_raster_image_t* hb_raster_image_reference(hb_raster_image_t* image) void hb_raster_image_destroy(hb_raster_image_t* image) hb_bool_t hb_raster_image_configure( hb_raster_image_t* image, hb_raster_format_t format, const hb_raster_extents_t* extents) void hb_raster_image_clear(hb_raster_image_t* image) const uint8_t* hb_raster_image_get_buffer(const hb_raster_image_t* image) void hb_raster_image_get_extents( const hb_raster_image_t* image, hb_raster_extents_t* extents) hb_raster_format_t hb_raster_image_get_format(const hb_raster_image_t* image) hb_bool_t hb_raster_image_deserialize_from_png_or_fail( hb_raster_image_t* image, hb_blob_t* png) hb_blob_t* hb_raster_image_serialize_to_png_or_fail(const hb_raster_image_t* image) # Draw hb_raster_draw_t* hb_raster_draw_create_or_fail() hb_raster_draw_t* hb_raster_draw_reference(hb_raster_draw_t* draw) void hb_raster_draw_destroy(hb_raster_draw_t* draw) void hb_raster_draw_set_transform( hb_raster_draw_t* draw, float xx, float yx, float xy, float yy, float dx, float dy) void hb_raster_draw_get_transform( const hb_raster_draw_t* draw, float* xx, float* yx, float* xy, float* yy, float* dx, float* dy) void hb_raster_draw_set_scale_factor( hb_raster_draw_t* draw, float x_scale_factor, float y_scale_factor) void hb_raster_draw_get_scale_factor( const hb_raster_draw_t* draw, float* x_scale_factor, float* y_scale_factor) void hb_raster_draw_set_extents( hb_raster_draw_t* draw, const hb_raster_extents_t* extents) hb_bool_t hb_raster_draw_get_extents( const hb_raster_draw_t* draw, hb_raster_extents_t* extents) hb_bool_t hb_raster_draw_set_glyph_extents( hb_raster_draw_t* draw, const hb_glyph_extents_t* glyph_extents) hb_draw_funcs_t* hb_raster_draw_get_funcs(const hb_raster_draw_t* draw) void hb_raster_draw_glyph( hb_raster_draw_t* draw, hb_font_t* font, hb_codepoint_t glyph) hb_bool_t hb_raster_draw_glyph_or_fail( hb_raster_draw_t* draw, hb_font_t* font, hb_codepoint_t glyph) hb_raster_image_t* hb_raster_draw_render(hb_raster_draw_t* draw) void hb_raster_draw_clear(hb_raster_draw_t* draw) void hb_raster_draw_reset(hb_raster_draw_t* draw) void hb_raster_draw_recycle_image( hb_raster_draw_t* draw, hb_raster_image_t* image) # Paint hb_raster_paint_t* hb_raster_paint_create_or_fail() hb_raster_paint_t* hb_raster_paint_reference(hb_raster_paint_t* paint) void hb_raster_paint_destroy(hb_raster_paint_t* paint) void hb_raster_paint_set_transform( hb_raster_paint_t* paint, float xx, float yx, float xy, float yy, float dx, float dy) void hb_raster_paint_get_transform( const hb_raster_paint_t* paint, float* xx, float* yx, float* xy, float* yy, float* dx, float* dy) void hb_raster_paint_set_scale_factor( hb_raster_paint_t* paint, float x_scale_factor, float y_scale_factor) void hb_raster_paint_get_scale_factor( const hb_raster_paint_t* paint, float* x_scale_factor, float* y_scale_factor) void hb_raster_paint_set_extents( hb_raster_paint_t* paint, const hb_raster_extents_t* extents) hb_bool_t hb_raster_paint_get_extents( const hb_raster_paint_t* paint, hb_raster_extents_t* extents) hb_bool_t hb_raster_paint_set_glyph_extents( hb_raster_paint_t* paint, const hb_glyph_extents_t* glyph_extents) void hb_raster_paint_set_foreground( hb_raster_paint_t* paint, hb_color_t foreground) hb_color_t hb_raster_paint_get_foreground(const hb_raster_paint_t* paint) void hb_raster_paint_set_background( hb_raster_paint_t* paint, hb_color_t background) hb_color_t hb_raster_paint_get_background(const hb_raster_paint_t* paint) void hb_raster_paint_set_palette( hb_raster_paint_t* paint, unsigned int palette) unsigned int hb_raster_paint_get_palette(const hb_raster_paint_t* paint) void hb_raster_paint_clear_custom_palette_colors(hb_raster_paint_t* paint) hb_bool_t hb_raster_paint_set_custom_palette_color( hb_raster_paint_t* paint, unsigned int color_index, hb_color_t color) hb_paint_funcs_t* hb_raster_paint_get_funcs(const hb_raster_paint_t* paint) void hb_raster_paint_glyph( hb_raster_paint_t* paint, hb_font_t* font, hb_codepoint_t glyph) hb_bool_t hb_raster_paint_glyph_or_fail( hb_raster_paint_t* paint, hb_font_t* font, hb_codepoint_t glyph) hb_raster_image_t* hb_raster_paint_render(hb_raster_paint_t* paint) void hb_raster_paint_clear(hb_raster_paint_t* paint) void hb_raster_paint_reset(hb_raster_paint_t* paint) void hb_raster_paint_recycle_image( hb_raster_paint_t* paint, hb_raster_image_t* image) harfbuzz-uharfbuzz-7a648c4/tests/000077500000000000000000000000001526670067500171055ustar00rootroot00000000000000harfbuzz-uharfbuzz-7a648c4/tests/data/000077500000000000000000000000001526670067500200165ustar00rootroot00000000000000harfbuzz-uharfbuzz-7a648c4/tests/data/AUTHORS_StixTwoMath.txt000066400000000000000000000010151526670067500242140ustar00rootroot00000000000000# 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. harfbuzz-uharfbuzz-7a648c4/tests/data/AdobeBlank.fea000066400000000000000000000001251526670067500224530ustar00rootroot00000000000000feature calt { sub e d c' b a by a; } calt; feature kern { pos b a 100; } kern; harfbuzz-uharfbuzz-7a648c4/tests/data/AdobeBlank.subset.ttf000066400000000000000000000035441526670067500240310ustar00rootroot00000000000000BASElâg¿Ô¾GPOS°¿w”PGSUB¨×¹Nä~OS/2S„¯à˜`cmapú~”cvt ÿfpgm™*¯Z¤hgaspÈ glyf ˆ4€head c›6hhearsT$hmtxè|øloca€  maxpx name"‘ÿˆicfbicftideoromnkanalatn0 3·y 2¶x ,DFLTÿÿkern d ,DFLTÿÿcalt>>$*ÿþharfbuzz-uharfbuzz-7a648c4/tests/data/LICENSE_AdobeBlank.txt000066400000000000000000000103151526670067500237030ustar00rootroot00000000000000This 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. harfbuzz-uharfbuzz-7a648c4/tests/data/LICENSE_ChromaCheck_colr.txt000066400000000000000000000021571526670067500251140ustar00rootroot00000000000000The 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. harfbuzz-uharfbuzz-7a648c4/tests/data/LICENSE_MutatorSans.txt000066400000000000000000000020621526670067500242010ustar00rootroot00000000000000MIT 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. harfbuzz-uharfbuzz-7a648c4/tests/data/LICENSE_OpenSans.txt000066400000000000000000000217121526670067500234520ustar00rootroot00000000000000Copyright 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.harfbuzz-uharfbuzz-7a648c4/tests/data/LICENSE_STIXTwoMath.txt000066400000000000000000000114221526670067500240140ustar00rootroot00000000000000Copyright 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. harfbuzz-uharfbuzz-7a648c4/tests/data/MutatorSans-VF.subset.ttf000066400000000000000000000100501526670067500246260ustar00rootroot00000000000000 GDEF=6Å1üXGPOS0r?, TjGSUBDvLu À HVARt]¶H à¥MVARйC® ˆbOS/2c�X¯ø`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_Iÿµ2$%& 4@@@@@@@@Øì<çì- ,DFLTÿÿkernD$€€ DFLTÿÿœTZr@@,Í@,Í@@@@@@@@Xÿ $CÿÚÊ ÿV$cphthaschlgp 4@@@@@@@@œdwdthwght wdthèwghtèèèèè  Gô  9øè èô…¢›ç] P’˜ÕÿÿHô ,Vb@@@@€2 : / K•œ%ªló|…ü‹Žƒ6<„ âÃC†¾#ÿ:fDbüX€dd@‚Ôddd‡€@ÿk–?ººGþüþüþ§ÿ>ÿ·ÿ ÿCÿCÖÖ@ÿ �ƒÄÔÔăý�ýƒ€(d „À,Í@Š@,Í@}<0009YyV���·×æææÜÔØîåßßßßßÕ¹���rE"""Bk@Ê�€ HHôcccH#þÙÀÀÀHHHB2!424/" ‚B‘‘‘aC)ôôƒââDððÈÈ›uH555BnX›ÈÈÍò333% >1)))))õÎÈÈ‘S!!!N@‡€@ �€ ddfffFðĦ¦¦ddd\E.IFHA/#‚CÊÊÊ�mPƒââPPnnHþæþêþïþòþòþòþõþñþænnRÿWÿgÿrÿtÿtÿtÿiÿaÿcÿOÿMÿVÿ`ÿ`ÿ`ÿ[ÿUÿSÿVnnFþÛþàþèþèþèþåþå€@ÿV�€ ö Šÿþ�þþÿ…ûú÷ööƒ€l{jGùœ§€ttM€§›÷öš§€ssE€§›÷€@$�  ƒ ö÷ƒøñôõòøƒøö ƒ ƒfEa`4æ±£hâââhE£±ç5`aflNƒž©¬¿ãúúú㿬©�‚k@C�r\Dƒ,39PddddK" òÇ–€€€€�ê3{FÇääääÏœƒCþ…ÿÿÿ=‰½Aÿ5ÿpÇöööÇAÿpÿ5½ˆHÿ<ÿÿþ†þ�þÍÿ@ÿ‘ÿb¶*fff*¶Dÿbÿ‘ÿAþÍþŒ€@ÿ�ãÒÚðƒøö ƒ%.ƒ öøƒöêƒharfbuzz-uharfbuzz-7a648c4/tests/data/OpenSans.subset.ttf000066400000000000000000000065401526670067500235740ustar00rootroot00000000000000GDEF GPOS 4GSUBlŒt… DOS/2}ì (`cmap tˆ,cvt M¤ t¢fpgm~a¶´´gasp# glyf)�ëu~head÷vâ¦Ä6hhea ÌÒ$hmtx ÝÁüloca?¼maxp› œ name #ä Òpostÿif ì prepC·–¤ h ¼9@ IY ?3?9/9+9933910!!#3&'`¶ý¶´¬B�?þeª!#)¬Ñþ/¼úDjÅV}`sþ;ŠV/\ø?š'šä_<õ É51‹ÉèLLûšýÕ ¢b ÍÁ�ý¨ ¬ûšþ{ ¢¶�š3š3Ñfñ 1ASC@AAþ„�X ŸH¶   AÿÿAÿÿÿÀ@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 °` E°FvhŠE`D-,± C#Ce -,± C#C -,°(#p±(>°(#p±(E:± -, E°%Ead°PQXED!!Y-,I°#D-, E°C`D-,°C°Ce -, i°@a°‹ ±,ÀŠŒ¸b`+ d#da\X°aY-,ŠEŠŠ‡°+°)#D°)zä-,Ee°,#DE°+#D-,KRXED!!Y-,KQXED!!Y-,°%# Šõ°`#íì-,°%# Šõ°a#íì-,°%õíì-,°C°RX!!!!!F#F`ŠŠF# FŠ`Ša¸ÿ€b# #б ŠpE` °PX°a¸ÿº‹°FŒY°`h:Y-, E°%FRK°Q[X°%F ha°%°%?#!8!Y-, E°%FPX°%F ha°%°%?#!8!Y-,°C°C -,!! d#d‹¸@b-,!°€QX d#d‹¸ b²@/+Y°`-,!°ÀQX d#d‹¸Ub²€/+Y°`-, d#d‹¸@b`#!-,KSXа%Id#Ei°@‹a°€b° aj°#D#°ö!#Š 9/Y-,KSX °%Idi °&°%Id#a°€b° aj°#D°&°öа#D°ö°#D°íа& 9# 9//Y-,E#E`#E`#E`#vh°€b -,°H+-, E°TX°@D E°@aD!!Y-,E±0/E#Ea`°`iD-,KQX°/#p°#B!!Y-,KQX °%EiSXD!!Y!!Y-,E°C°`c°`iD-,°/ED-,E# EŠ`D-,E#E`D-,K#QX¹3ÿà±4 ³34YDD-,°CX°&EŠXdf°`d° `f X!°@Y°aY#XeY°)#D#°)à!!!!!Y-,°CTXKS#KQZX8!!Y!!!!Y-,°CX°%Ed° `f X!°@Y°a#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-,°CTX°F+!!!!Y-,°CTX°G+!!!Y-,°CTX°H+!!!!Y-,°CTX°I+!!!Y-, Š#KSŠKQZX#8!!Y-,°%I°SX °@8!Y-,F#F`#Fa#  FŠa¸ÿ€bб@@ŠpE`h:-, Š#IdŠ#SX<!Y-,KRX}zY-,°KKTB-,±B±#ˆQ±@ˆSZX¹ ˆTX²C`BY±$ˆQX¹ @ˆTX²C`B±$ˆTX² C`BKKRX²C`BY¹@€ˆTX²C`BY¹@€c¸ˆTX²C`BY¹@c¸ˆTX²C`BY±&ˆQX¹@c¸ˆTX²@C`BY¹@c¸ˆTX²€C`BYYYYYY±CTX@ @@ @  ±CTX²@º ³  ±€CRX²@¸€± @²@º€ @Y¹@€ˆU¹@c¸ˆUZX³ ³ YYYBBBBB-,Eh#KQX# E d°@PX|YhŠ`YD-,°°%°%°#>°#>± ° #eB° #B°#?°#?± °#eB°#B°-,°€°CP°°CT[X!#° ÉŠíY-,°Y+-,Šå-@™ !H U UHU?¯MK&LK3KF%&4U%3$UÿÿÿJI3IF%3UU3U?¯GFëF#3"U3U3UU3UOÏÿU3Uo¯ï€¸�±TS++K¸ÿRK° P[°ˆ°%S°ˆ°@QZ°ˆ°UZ[X±ŽY…��BK°2SX° YK°dSX°±BYss++^stu+++++t+st+++++++++++++st+++^N¶u¶ÍH‘ÿìÿìÿìþÿì¶ü”ÿíþ…ÿêþ©ÿìþ¼‹�ݘ�Ž™ˆ�ŠN   <   \ tOpen SansRegularAscender - Open Sans Build 100Version 1.10OpenSansÿff ÿÿ   latnharfbuzz-uharfbuzz-7a648c4/tests/data/STIXTwoMath-Regular.ttf000066400000000000000000003127101526670067500242330ustar00rootroot00000000000000@MATHšQÌæ*¸khead%Í L6maxp%§!<„ postÈO‰À¤*!HÚÂk_<õèÛÿÆYá° ¬ü.ù— Ch Œáq„^�DÞÿ²3h$%&'()*+,-./0123456789:;<=­ÉÇ®b     c�ýÿd !"ËeÈ#$%&'()Ê*+,-./012345678ø9:;<=>?@AÏÌÍBÎCDEúFGHIJKLMNOPQRSTUVâWXYZ[f\]^_`ÓÐÑabcde¯fgghijklmnopqrst‘u°vwxyz{|}~€�䂃„…†‡ˆ‰Š‹Œ�Ž��ÖÔÕ‘’h“”•–—˜™š›œ�žŸ ¡¢£¤¥¦§¨©ª«¬­®ë¯°»±²³´µæ¶·¸¹º»¼éí½DEFGHIJKL¾MNOPQRSTUVWXYZ[\]jik¿ÀÁÂÃmlÄÅÆÇÈÉÊËnÌÍÎÏÐÑ ÒÓÔÕÖþרoÙÚÛÜÝÞßàáâqprãäåæçèésêëìíîïðñòóôõö÷øùùúûüýþÿutvw     × ã!"#$%&'x()*+,-zy{./012}34|56789:;<=>?@A¡BC±DEFGHIJKLMNOPåQRSTUV‰WXYZ[\]^_`a~€bc�defghijklmnopqrstuvwxyz{|}~€�‚샄º…†‡ˆ‰Šç‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêîêëìíîïðñòóôõö÷øùúûüýþÿ      !"#$%&'()C*�+ØáÙŽÚ,ÛÝÜßàÞ-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€�‚ƒ„…†‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¨¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏПÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë—ìíî›ïðñòóôõö÷øùúûüýþÿ      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€�‚«£"¢ƒ„?_… >@^`  †‡ˆ‰Š‹²³Œ¶�·´޵Äž¿©ª‚ˆ�†�Ç‘’“”•AaèB–—˜™#‹šŒŠ›½œ„…–�žŸ ¡¢£¤¥ñò󦧨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿¼ÀÁÂõÃÄÅôÆÇÈöÉÊËÆÌÍΓð¸ !¤�žƒÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€�‚ƒ„…†‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijk˜lmnopqrstuvwxyz{|}~€�‚ƒ„…†‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ      !"#$%&'()*+,-./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-–à�Òp hüxæ–|(‡,‡žÖ �²–, NDDI€I€D–DD–^D¯DD¯DDUªDNAþ±7Ü=B>ð èy( 7  <(###ædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPPædPPP2A--<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#APÌPPP 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 ¥ ¦2¸Ð4ÒÒMÔÔNÖÖOÙÙPÛÛQÝÞRääTææUèìVî[t  u  vwyz|}"~YZƒ–—…™ž‡ ¢�¤¥�§®’°°š²²›´´œ¶¶�¸¸ž¼¼ŸÈÈ ÊÊ¡ÐÑ¢ÓØ¤Úèªêê¹ììºîî»ðð¼òò½öö¾ÿÿ¿ÀÁDEÂGLÄN\Ê^^Ù``ÚbbÛddÜjjÝvvÞxxß,5à7DêHHøJJùNNúPPûSSüYYý[[þ^eÿghjo q��ƒƒ…… ‡‡!‰‰"��#™™$››%%.&0=0AA>CC?GG@IIALLBTTCW^D`aLchNjxTzzc||d~~e€€f‚‚g††h’’i””j£¼k… ‡�œ!!�##ž%%Ÿ++ 88¡=E¢GT«XX¹\\ºfg»ii½ll¾nn¿ppÀrsÁuuÃwxÄ~~Æ€€Ç‚ƒÈ‡ Ê¢¢ä¤¤å¦¦æ¨©ç««é­®ê´´ì¶¶í¸¹îïïð2<ñ>KüMM OO QQ ST VVXY__aacdh�……0‡‡1ŠŠ2ŒŒ3��4‰5‹˜@ššNœœOžžP ¡Q££S¥¦T¬¬V®®W°±XµÎZÒÒtÔÔu××vÙÙwÜÜx@)t \h6|^JO|�¹ðr¾¸|r,r6,�rÖ^^6æúðúú‘‘ŒŒ®"Üͯ|úðŒ‚‚ÿÿÿÿÿÿÿÿÿÿÿ8ÿ8ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿh6JTJ6†r¹m^½|Jr|,;1^hhh†Tr;@hE'Júæ‚úðúúO"ëæð6úJTæúܾ"æ´¸úEh@6@rJÖ††^†¸†r|,|1Tr^w1 6¾6ôh,rh½æð"ð|Í11@Y,'ðæ^ú"ÿš•ær–áw"æOúðõð"úõ|@Ìv¸h††�ràÂm@|¤J'T||h¾^š¤0€¸YJ)@,6hÂ^@š®;úú†ÿÿÿÿÿÿÿÿwJ|h^Tr¤Í�ÍêšwJw^J³†!rrJú ,",  ––,–Â6",æÒ´,,Â6ÿà|चšààO*DÂ"ÌÂ|Â*R|w•à¸&®¤�T*Z^"|,Ö,TÜ´h@^ÜàT,šT  æOO@,¸®YJ66à¤ï¸³³åþ,rà,:ïê¤ê¤†¸þåqÂdzr|6�6&6¤ÒÂ��úþm@¤^";õ|cêh¤6€½©¸XNàþ½�ôôà€®¸ÌÖ¸0êêh6šhê†:½àÌ|hr³| h³|äRÆl¼€H€0Rø>Æþ4å4ž¼¶vÚàêÂ0¤ôà&�JÂ|&®€þ¸&à®|†à®N�à‹¤®¤hT|ršJ®†¤†¤rr¸&r|úÒÍȹ¹ÈÈ×ÈÂJ,úÈ@†Ü𮆜�|†¤��¤J®š¤š®•|Ÿ®D�®|'ú,ðÜ@,ÒÒæææÜà^h,,ÈT,Â@ðJ@J@@| ^ ®|T1^h^^,, 66"ŒŒ‡‡"–®""6ë´ú†"T"""^O‡ð,wOT"T""J•ú"úúÿ×ÿ‚x‚x‚�ÒÒªæ^ÜæÜ",^,""hY–@†T^,^,'T¤' ",挂Œ‚‘¤æá¾ÿ|úÿðrhšhhh¤šÜ@|TÇš¤h¤hhhšTàYJhT^1�16,^Ü´J'^æ¸@;6Jÿú6†|r¤rrr¤©õT�TÖ¤¤r¤rrr¤rôwcm^h6†6T6há¹h6hõÂ@@@T  @'š'''"",",6,,,66È,,,,,,,,,,6,,""@"´E|TO|TJ¤�͆wô¤@w�Tw6Jh†r¤š†,Já"–,ð"úJ"ëæ@hhæ6; Âà|šÖš�à̸ÑÛ�ÂÛ|†•šÌ¸ÌêšJ¤;‹|T|¾JTc;w6‹rJ,;|³½�c�^Ÿ6स峳þê'ÖàNê®àô¤àš³¸å®¤Y®r‹"®^†Òr�rO•6¤h1T1@|Çê¤m,�h®w&,,,J,,T^–@†T"^T,^ �'|hE6"úúŒÜú @úúðmhhcš|rr�rh¤¤úš|Ö¤r¤¤r¤hmcàw̸|h|6‹"^@r¾6J"J;hJT6",š"©•rEhY¸EÌTë'æðæ,"¾ú ^J@"úæðë,ð ÿðð,1ú,,",,,@@,,"ðúú,"�T®hrr®¸Òšæþ®ŸTŸT,Y¤��h,"6"@ª  ª––@ êT6,6úæÈ@6Ì@6�Th|hh¸¤Òš‹þ®hŸ³TTY���Ÿ³J†JT@T6›^@6",|T@"6r@¤� ½ÂÖÌ&@šôJX¸¸�½0êlôêÑr†@�@T|¤õÒ‹^�õ&†Y||6,||r;þå†�hh ½ÑÛÖÌ&þ@þXÌþÂþ®½êôþþÌ|ÑO¸'�r‹Ü|r®c©^¤r@Jh¸þôѤJÇšÖwI,,,6"¤|Ö���ÌÖð,Âð!ÌÇ|Ç|@rà¸0®®†,@@T@6,^¾´´¹¯¯^´hYT^á^TôhT,¤||•�|ÖÇæÂš!̆ÇÑ|rr®©®¸Ö^¤^rOrJªr"^J,@š|h"6JšT̳:Ö:àôù:IO©OŠ0&Ì&Ì®ÛN”þššr¸rN^�ÌÒ¤|¸X©†®šY@'¤¤šm5&Ÿš��:àêôþI!^&?Š0ïDàÌÛ:å©þ|ïO†¸ššÂ�Ì|ï•Tr†Â!¸TÛ½Ñ|I” ¨NŠl&ô¼ÚlÌÇ àX”Ú40¨ôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"""6""JT‡,rOTO"TõrhYú"ðú‚¾ðð,ðæðOðOTÿúJÿrh6,TJ6�r¹r^¸|Jr|,;,^h^h†EOhr@JÈÈ6Jú",Jrhrwhhš¤Ü|hÇšh¤Ÿh¤chJÑY¸©hTr‹"^@w¾,ú@ J@^O,@"‹‹�6^šT¤¤šàššåÂJ¸ÂàŸàŸ¤š¸¸v¸®®T†Er^||ê^T^h,;T,¤;66®¸þhêÂþð@þ•ô†¸|Âm^||cô^|^ŠÖ&®:³”¸ÂbàŠXô½&šêнÂ̸Â|þÌ6J©®Ì†Ì|h†¤|‹šh�à¤|¤�||®Ñá6¸ë¤|¤|'cà®N�‹w",'@'@,@´´ª @¥^6JJðÒTJô@T"²:ïDÌXѼ¸à€¨v0åD¸+0²0ÖàêÌÖ†à6^"³¤Öšà‹|šš�|šrø„ f²îÐpŠXz >Ð&fþp0¼ø>ÞŠ NôàXÂô&�^Â�&®Šåàô¤�šÛ¤S�ï¤Öà�Öš†®ê¤¤Ì|Xà¸Ö¸ÖÖ¤¤êl®®š,"ú6õð@6×׿æÿð|,T6"6ëh,Ì@|h®rrr®š¾6�¾ÖŸ®r®|†c�š0��†EE'Y'Y;¥¥››;¥å;1EYÒ1ŸÂš®ššÌåõJÖõ:บ¸š;wþÂl®¤‹1;6O6O;Où¹¥O´m@YYÿÜ^YOc1ÐX bêvïÚÖþž&Д0NbÖIN!ÚSôþôþD®0D^6†JDÛXÌþ³¤ÂÌ®N¤Ìš ¬4ŽÚø˜²€¢HføNŽ&˜Nä f²4l:þvà:D®|à¤D̲þ:®¸ùÂ{® Âôþ®ô¸¤Ì®Âôš”þÖôÖôôŠÌÌ®@6JÿúTJææõð ú&�@hJ,Jõ|EàT"�r¸|||¸¤È@šÈ꩸|¸†�mš¤Dšš�TT6h6,hJ´´››J´ôJ@Th,á@"¸,,,"ÿ~5‚‚7ØÝ8æí>öFIkRušu¬Ï›á¿qzãÀÁíÃÖïØÛÝõøÿ ( ®º)Ÿ6ª³»˜£¼ü¾ÅËÍÑÒ!ÔÕ#R%[v\ƒ‡xøü}¼‚ú <GV L 'ðÃÿÀ ? À ME @G$$&-\ elQääYèèZ(([,,\hi]kl_noay|c�…g‡‹l””q˜˜r¢×s‰‰©‹‹ª��«��¬×ê­ 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:rHVdrx†œª°¶ÄÒàö0FTbp†œª°¶ÌÒèŠîn &<BnXntŠ�¦¼Òèþ*0>Tbx~Œ°¢°ÆÔÚ°ð"0>Lbp†”¢°¶Ìâððö4J`v:   ÿMM*OP+WW-]]._`/rr1tz2ÈÈ9áá: ® ®; ° °< ² ³= · ·? ¹ ¹@ ¼ ½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‹ „ „Œ ’ ’� ” •ޝÎ�+K°MNÑPPÓR\Ô^^ß``àbdᨨ䲲嶶渹çü`ÿîÿ¾ü ~ ,~!ÿ8ÿÔ,ü@ÿäüÿðüÿj$–ÿÙ(ÿs ü ÿÛÿ¦(ÿ¦0~ÿ¶ÿÕ~ÿ°ÿÄ$~ÿ?ÿ‰8~ÿPÿ <ÿ�8 hÿøüRkÿî3 ÿžÿË0‡ÿ¦ÿã$‰ÿ¦ÿî$š\MÿÓÿš<ÿ[ü\ÿçÿ¿ÑNÿçÿ²öÿaÿÇ”ÿ¹AÑÿªQüÿÎüXÿì‘ÿñüÿì˜ÿñT ÿñ–ÿö!ÿß‘)ÿ…ÿ¿- ÿö!‘ÿâ”ÿ#ÿ¬d´Zÿàÿ´�T|ÿèÿž(‹ÿ¤ÿîdü ÿpÝÿìHÿ hb ÿßÿØdÿàl‡ÿhÿ ;‘ÿžÿÀ##-ÿºxÿÌ|Õ^:ÿÆÿºV°QÿΠÿÎÿôL<ÿà81ÿÕ¦5ÿÜÿè,¢5ÿ`ÿÈhªÿÓ$(²Lÿ¬ÿåhÛÿþÿ“´ÿºÿÓl ÿâ$ÿ%ÿº‹#ÿÕ8¤ÿö#L9ÿœr¢ÿ ÿÌtœÿ"ÿŠÊFÿõ ÿLÿ¾òÿ•êšÿñšÿö,+!–ÿö$œÿ9ÿl”ÿô ÿq%ÿð0ÿô)ÿø ¢ÿZÿž@ ÿå –ÿç(–ÿç –ÿÓ<ÿúüÿ¶Tÿ`\~ÿÿNd~ÿ3ÿudÿ@`ÿÎ/‚ÿ­ÿÍE+‚ÿ'ÿ?)‚mþäÿe‚<þÀÿ ÿì‚ÿ;ÿ§oÿö‚ÿgÿ¿g‚ÿÂÿï7ÿñ‚ÿ×ÿÿKÿç� þòÿo¦þºþÜ’+þ}þÌ’9þ‡þОÿç-–ÿjÿÁ9–ÿãÿý5ÿòZÿ«)šÿÑüÿ¬˜ÿ«1ÿùáÿÏÿð˜ÿõ–ÿÑ–ÿçÿÅ5 ‘ÿ¡ÿÃ9–ÿ—ÿ¾–ÿù–ÿå˜ÿ¸ÿéšÿá ÿñœÿÙ–ÿðšÿÁÿò)˜ÿå –ÿì–ÿå –ÿ©ÿÍ9üZÿåÿÃ\ÿƒÿ°Ëÿéÿ¶êÿåÿÕÿé~ ÿpÿ°~ÿ0ÿdœ�ÿ¨ÿà‘ÿlÿܤ‹ÿœÿø¤dTDv/¦¾ÖøvÒ.Šújv˜ºæ*Vbnz²ê"Dfr¢®ºÆÒÞêö&2>JVbnz†’ä 6 ˆ Ú  J ‚ º ò * b š ¼ Þ " Z ’ Ê    & 2 > J V b n z † ’ ž ª ¶ Â Î Ú æ ò þ ".:FR^jv‚Žš¦²¾ÊÖâîú*6`pœÈä6Rn¤Æè VŒ¸Ôð&\~ Ìø$P|žÀâ0\ˆªÌ LŒÌ t�¬Ø0\ˆ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$eìfbg Øh M%iìjbk Øl M&Ÿ&  Ÿ&  Ÿ'Ÿ'  Ÿ'ddŸ8 (¥£“ƒsa Q A 1   ý íþúùýèèäüúù8 )¥!£"“#ƒ$s%a& Q' A( 1) * + ý,íúùèèäÿúù8 *¥-£.“/ƒ0s1b2 R3 B4 25 6 7 þ8î°ûèèé°û8 +¥9£:“;ƒ<s=b> R? B@ 2A B C þDî°ûèèé°û8 ,¦E¤F”G„HtIbJ RK BL 2M N O þPî ôû èèé ôô› èèéôû8 -¦Q¤R”S„TtUbV RW BX 2Y Z [ þ\îôû èèé ôô› èèé ôûìàÎäGÖXXYä¼GèGèXGÖXXYëÒè¼GÖXXYä¼G(G*,,8(ôG,G,ôG*,,8/Ò,ôG*,,8(ôGhi3kl3no.y¤z?{ C| L}ÈÈq€ŠŠ‹~&‚�³‚?ƒ C„ L…ÈX™€ŠŠ‹~&‚‡°ˆ?‰ CŠ L‹ÈX—€ŠŠ‹~&‚”…”„„…”„„…˜…˜„„…˜„„…¢º£ + ¥º¦ +Pä hÏXXãã ^¨º© +«º¬ +®º¯ +±º² +´ºµ +·º¸ +ºº» +½º¾ +ÀºÁ +ÃºÄ +ÆºÇ +ÉºÊ +ÌºÍ +ϺР+ÒºÓ +ÕºÖ +‰ŠÏ‹ŒÏ�!ŽÙ�"�Ù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>tëuØvŒw QæB}>~ëØ€Œ� Qê‘‘Ã’Ž“•” • ‘èèÑèèÖ>—ë˜Ø™Œš Q:B›>œë�ØžŒŸ Q< ¡¢£ ¤ WôôWôôWWôôWôôYYôôYôôù¸¶}·;¸û¹¹º ú¸»}¼;½û¾¹¿ ü´À}Á<ÂûÃ¹Ä Àȼ}ÅÈÈý´Æ}Ç<ÈûÉ¹Ê ÅÈÈÆ¼È}îÀȼ}ÅÈÈÆ¼È} ¸Ë}Ì<ÍûÎ¹Ï  ¸Ð}Ñ<ÒûÓ¹Ô ´Õ}Ö<×ûع٠Õȼ}ÚÈÈ´Û}Ü<ÝûÞ¹ß ÚÈÈÛ¼È}â´ãÈúÎúúUæ´ÎúúUçÈùê´ãÈúÎúúUçÈùú´ãÈúÎúúUß�<ü´à�=ÎúúUçÈùÿ´ãÈúÎúúUáú‘´âú’ÎúúUçÈùÒ×›ÎúúUÒØÂ›ÎúúUÒÎúúUÙ›ÒÎúúUÚ›&x&Èôx'––CÜ––+wÛ––€'––C+ôÈw.´&Èôx'––C+ôÈw4i4Èôi5––C6h5––C6ôÈhwéÝë… )ôïXXïôïwéÝë …! )ôï"XXïôï)y,é-Ý.ë/…0 )*�½XXï+�½1y4é5Ý6ë7…8 )2�½"XXï3�½9w=é>Ý?ë@…A ):,½XXï;,,¯XXï<,½BwFéGÝHëI…J )C,½"XXïD,,¯"XXïE,½KwLéMÝNëO…P )QwRéSÝTëU…V ) 4´×›ÎúúUÙ› 6´ØÂ›ÎúúUÚ› @´×›ÎúúUß�< A´à�=ÎúúUÙ› D´ØÂ›ÎúúUß�< E´à�=ÎúúUÚ›harfbuzz-uharfbuzz-7a648c4/tests/data/SparseFont.ttf000066400000000000000000000006241526670067500226230ustar00rootroot00000000000000@GPOS°¿DPcmap*´Xhead£¯§\6maxp ” post×J� 7%�5€_<õèÜÆšÜÆÔÄ D  CJT2ÿÿ AIT2ÿÿÿèÿÀÿ³þÓ $%&,-7IJ ,DFLTÿÿkern ÿìharfbuzz-uharfbuzz-7a648c4/tests/data/chromacheck-colr.ttf000066400000000000000000000012141526670067500237370ustar00rootroot00000000000000 €@COLR%`CPALÉxOS/2ñ'JH`cmap é3°,glyf "$ähead Á˜ÛÌ6hhea$hmtx¨loca Ümaxp( nameç >post@ #]m_<õÒ ×óQÎ �™Ì�™Ìë3  Àéé   éÿÿéÿÿ !!üü    ChromaCheck COLRÈÿharfbuzz-uharfbuzz-7a648c4/tests/data/expected/000077500000000000000000000000001526670067500216175ustar00rootroot00000000000000harfbuzz-uharfbuzz-7a648c4/tests/data/expected/hand-10000066400000000000000000000041771526670067500227030ustar00rootroot00000000000000start transform 1 0 0 1 0 0 start clip rectangle 64 -224 1.22e+03 928 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 fill glyph 15 solid 145 103 77 255 end transform start transform 1 0 0 1 0 0 fill glyph 16 solid 30 136 229 255 end transform start transform 1 0 0 1 0 0 fill glyph 21 solid 145 103 77 255 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 fill glyph 18 solid 66 66 66 51 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 fill glyph 20 solid 145 103 77 255 end transform end clip end transform harfbuzz-uharfbuzz-7a648c4/tests/data/expected/test-10000066400000000000000000000006371526670067500227450ustar00rootroot00000000000000start transform 1 0 0 1 0 0 start clip rectangle 100 250 900 950 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 clip end transform harfbuzz-uharfbuzz-7a648c4/tests/data/expected/test-106000066400000000000000000000005471526670067500230330ustar00rootroot00000000000000start transform 1 0 0 1 0 0 push group start transform 1 0 0 1 0 0 fill glyph 3 solid 0 0 255 128 end transform push group start transform 1 0.268 0 1 0 -134 start transform 1 0 0 1 0 0 fill glyph 3 solid 255 165 0 179 end transform end transform pop group mode 4 pop group mode 3 end transform harfbuzz-uharfbuzz-7a648c4/tests/data/expected/test-116000066400000000000000000000005421526670067500230270ustar00rootroot00000000000000start transform 1 0 0 1 0 0 push group start transform 1 0 0 1 0 0 fill glyph 3 solid 0 0 255 128 end transform push group start transform 1 0 0 1 100 0 start transform 1 0 0 1 0 0 fill glyph 3 solid 255 165 0 179 end transform end transform pop group mode 4 pop group mode 3 end transform harfbuzz-uharfbuzz-7a648c4/tests/data/expected/test-123000066400000000000000000000011171526670067500230240ustar00rootroot00000000000000start transform 1 0 0 1 0 0 start clip rectangle 0 0 1e+03 1e+03 start transform 1 0 0 1 0 0 fill glyph 3 solid 0 0 0 255 end transform push group start transform 0.5 0 0 0.5 166 334 start transform 1 0 0 1 0 0 fill glyph 2 solid 255 220 1 255 end transform end transform push group start transform 0.5 0 0 0.5 334 166 start transform 1 0 0 1 0 0 fill glyph 2 solid 104 199 232 255 end transform end transform pop group mode 3 pop group mode 3 end clip end transform harfbuzz-uharfbuzz-7a648c4/tests/data/expected/test-154000066400000000000000000000002631526670067500230310ustar00rootroot00000000000000start transform 1 0 0 1 0 0 start clip rectangle 100 250 900 950 start transform 1 0 0 1 0 0 fill glyph 154 solid 0 0 0 255 end transform end clip end transform harfbuzz-uharfbuzz-7a648c4/tests/data/expected/test-165000066400000000000000000000000371526670067500230320ustar00rootroot00000000000000fill glyph 165 solid 0 0 0 255 harfbuzz-uharfbuzz-7a648c4/tests/data/expected/test-175000066400000000000000000000000371526670067500230330ustar00rootroot00000000000000fill glyph 175 solid 0 0 0 255 harfbuzz-uharfbuzz-7a648c4/tests/data/expected/test-6000066400000000000000000000000351526670067500226620ustar00rootroot00000000000000fill glyph 6 solid 0 0 0 255 harfbuzz-uharfbuzz-7a648c4/tests/data/expected/test-92000066400000000000000000000007041526670067500227520ustar00rootroot00000000000000start transform 1 0 0 1 0 0 start clip rectangle 0 0 1e+03 1e+03 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 clip end transform harfbuzz-uharfbuzz-7a648c4/tests/data/noto_handwriting-cff2_colr_1.otf000066400000000000000000000101141526670067500261570ustar00rootroot00000000000000OTTO €@CFF21b§ DCOLRü¤Õ* PóCPAL îatDŽGSUB'/ÀÔvOS/2ßP`30`cmapNòЀhead o’âÌ6hheaœT$hmtx¢«�>maxpP(name"¢8oPœpostÿ¶3ì =ƒèj_<õÞ:§•Þ:§–3ÿ°¶¶ÿû3J±Pû�šfMšff33€NONEÀ ÿÿ¶ÿ¶úÍ û3ûûWç¢KXKÏÏXe$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-Regularÿ³3 —eo‹‹ —eo‹‹ ú¨ $¬|¦¸ð‚Àl~¿¾ûŽø.°ü.¾ûƒúÞ÷ÈþÞ°÷¢¨t¢nŒtŒQ|j›;$ n›C¢g‚ûž!q…v{~w" y]‹}Vµg±…°„¼¢™Áª÷'% èˆjû<‹÷;ûj÷YáxÜÁÉ�§�Ç…¥ƒ¨ƒ¨ ¨÷ÖùðûOŒ0­L¦\ W�[z[z]{Xšn±-÷ù¨�‹|ûoû$Žø6÷ ÷!÷}ŠdŠc¥g²÷—1û5û ‚}”Ž™¸÷MŒ����Žøªú–ž¢’��Ý]œ��t€xüªþ ‰†‡††ˆ! ˆ‰‹Œˆ|�# ˜�”›· ùJúŒŒ‹ŒÝ\‹�ЉŒŠ‹‡ˆ†ü©þ Š‰ŠŠ‰‰û+®÷(ŒŒ�ŒŒøªú �Ž��ލ~}ƒ~ƒüªþˆˆŠ‡Š†^ûM�‰’„”ŽŽŒ�Ž÷5÷ �Ž��Ž�ø©ú –ž†¢z•9¹ކ…�…ù›÷îû·1„IX^gû8û C>hf«b©xÆfÅŽ÷ØÌ³´jºk‹ÓPËtÊu÷)­½×ÂÞ2÷$û€åù÷ï^frk�ƒ{x|HYû7TQ„ƒŠ…Œ‡Œ€—|›�~Ÿž†Ÿ°»ž¶Ò𤢒£µ«uuª‘‡ŒŠŒ‹ŒŠ‹ÐRÅwމ‘Š’Š£|¤ƒ¨Šcƒe‹r”K¢CÇ‹ˆŒ‰�‰Œ_©c§Mfû=QˆP°mžk´®°ÓØ÷8÷ ¸¯š–œ•œ’•¤§�©¡£ˆ…¥•‰–ˆ–ˆkˆt†z†Œ€€Œ�! ˆ‰‹ˆ|Ž# —�”›¸ ùðû JŒ%µa�—pn‘mss‡ƒt[zˆ€�‰mn™£z~›�ˆ‡�‡Š‹‹Šˆˆ‹ˆqx•¡�‚�Šž‘�Ž‘ˆ’†�Œˆ‰Œˆˆ‡‰‰ˆ}}xƒx‡ˆ‹ŒˆwŽy—�š‚™‰›�œ�‘œ¸™Í�¡�¢�¡’­“·�’‹‹ŒŒ—��˜¡‘Œ÷�õŒ��‹‘®Ày¢�‰÷ÞûBÛe…—›‰ž››Œ�™Œ•“Œ’� ŠœzvûÖƒˆ„…………ƒˆƒˆˆŒŒˆ’sY‘j†‡ŠˆrŠp‚o‚…‰‰Š‰ŠŠŠxvr�oüÿ÷ŠŠˆŠˆŠ‰‰…�„‘‡Š�ŽŠŽŽ�ŒŽŽ’“”‘•‘÷׎��ŽŒ�ŸðŒ�Š�ˆŽŽˆ‡�‡Š;ƒl‡rt…n�ú³�òñú ˜Ì�¢�¡�¡‘«’²�”Œ‹‹‹–›š–��Œ�ŒŒ÷›ôŒ��‹�§„„ŠŠ†ûž!r…v{}w" z]‹|Vµg±…Š��‹� ¢“��„v‹t–un™¥€§Ž�‹�˜zoŸ­|­—˜��—»œ“¡¡Ž¢¦¦†¥ÊpæiÇŠŽ­§˜Ÿ ¨”§•¤ŒŽ�Œ�ª¼…„¢Š��Š�£ Ÿ£÷Ö¨t¢nŒ‹Š‹Š{o†q||Œ‘€:$ ˜rTžeû�ü^ŒŽ‹ŽŒŽ·÷% Û“w&û?€…�ƒƒƒø‹ø²«½z¢™„÷Ôû=Üe…™œˆ œ›Œ�™Œ””Œ‘Œ™Š–�}ûÖ‚‚„ƒ‰‰ŒŠ“oV‘m†‡‹Š‡pŠp‚n�…‰‡Šˆ‰ˆˆzxvƒsˆ`Œ?¡7°˜nl‘kqr‡‚r[zˆ‚‚Š�qs—Ÿ|~œ’†‚�ƒŠŠ‹Šˆˆ‹‰o�˜–†„™Šš‘š�‘‹‘‰‘‘Œ‘Ž��‘’“‘“�Œ‹Œ‹÷×’��’�’ŸðŒ”‰”…’‘†ƒŽƒŠŠ‹‹:ƒŠg†npƒi`ûЋЋ‰Š‰Š‰‰…‹„�†…Š…ˆ‡‡€{„|�€�>|E|E|•ƒ—…•‰—ޱûá÷C‹�£Ÿž¤Ž"nÞ(. 4 : @ F   "*2Ìêõ!û&1^i‡¬!²2¸÷=!Ch2n§²Ðõ!û2:Ecˆ!Ž2”ÍØö!,28e  @>„u î îÓ @ o i �´ÿ–ÿ,ñ@@@  Í @>z z Vœ@1@ @  @>„_‡‡Ó çÿåûÿåçüÑ@@@ Q K @>/Á/ÁV@ì@&¥@7$@@@ @  „Xß°ßXü  çÿåûÿåçüÑ@@@ p hAhA¢&f@@@ E @>=Ð=ÐV@I@/‘@@@ @  @>„_¸¸Ó çÿåûÿåçüÑ @@ @ K E @>LÆLÆV@¹@3À@@ @  @  @>_ ñ ñÓ qÿåqÿå!@=@ K E @>F½F½5 @¨ @1â @?ñ@ @  @>„p î îÓ çÿåûÿåçüÑ@@@ P @ ? @>z z Vf@0¤@ @ @ÿ À   åˆÿó–!ÿBBBÿ'/Jÿ7@\ÿöµdÿJSpÿ4S‡ÿ8W�ÿMg‘ÿ=`˜ÿBi¢ÿb{¤ÿCl¥ÿd‚­ÿgŠ·ÿh�ºÿc�ºÿz¤Ìÿˆ°Öÿ’¸Þÿ•»àÿ~·æÿ¦íÿ‘ÃíÿžËðÿ¯ÕõÿºÛøÿ½Ýùÿªÿÿ³ÿÿ(Êÿÿ $2DFLTlatnÿÿccmp2 $    harfbuzz-uharfbuzz-7a648c4/tests/data/test_glyphs-glyf_colr_1.ttf000066400000000000000000000521001526670067500252760ustar00rootroot00000000000000 €@COLR=á�Ã:à‰CPALÔÐûˆSlÒOS/2E£M`H`cmapvh´4glyf÷¹ô̤²head(¸.šÌ6hhea •ž$hmtx“.¨ locac�i?è¼maxpâ( nametXÃÉX�postë'�K øåfó‹²_<õèâyôéâyôé°è¶ÿâþ Ü©Ýç�????€ÿÿÿÿ¶¶ú Xèèúè¸è­èÈèèdèdèdèdèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèdèdèdèdèdèdèdèdèèèôèôèúèèèôèôèúèdâdèÂ�^,úÈ– 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 Yèè1!èèüúúîî 533##5#5Û2áá2á áá2áá2¸ú(#557(%KjþÛ÷%(­öe! #"&554632'4&#"3265e1+*22**2%vG99G-G77G1))190,,0Èú 7È,,úýøèè 1!!!!5!!!!ïþùïþïþþïþïþï ïþïdú„¶7!d ú¼ýDdú„¶7!d ú¼ýDdú„¶7!d ú¼ýDdú„¶7!d ú¼ýDèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè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!èèüdú°¶7!dLú¼ýDèè1!èèüèè1!èèüÂ&&Š #5#35#46334&#&222X2222�ôX¼ #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[7È6[7È6[7È6[7X7[6È7[6È7[6È7[6Èú^îR #5#35#466334&&#îCrEúCrEúCrEúCrEXErCúErCúErCúErCúÈ, „ #!3!4>3!4.# /Rm>þÔ/Rm>þÔ/Rm>,/Rm>X>mR/,>mR/,>mR/þÔ>mR/þÔ–úR¶ #!3!4>3!4.#R6aHþ¢6aHþ¢6aH^6aHXHa6^Ha6^Ha6þ¢Ha6þ¢èè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè1!èèüèè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~7�8¢9´:Æ;Ø< = > )? ;@ 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€`�f‚lƒr„x…~†„‡Šˆ�‰–Šœ‹¢Œ¨�®Ž´�º�À‘ƒ̓Ҕؕ˜0™Wš~›‰œ”�¢ž°Ÿ¾ ̦â§å©±²³´"µ(¶U·‚¸¯¹ܺ »(¼U½‚¾¯¿ÜÀ Á6ÂcÃ�ĽÅêÆÇDÈqÉžÊËËøÌ%ÍRÎ`ÏnÐ|ÑŠÒ˜Ó¦Ô´ÕÂÖÎ×ÚØæÙòÚÛ.ÜJ tdú„úd,  dú„úd, Í@33@  dú„úd,@`@  dú„úd, @`@ °ÒôXÀ@ °ÀôXÕU*« °®ôXÀà °œôXàÀ °ŠôXÐà °xôXàÐ °fôX( °TôX°Ð °BôXа °0ôX \r °ôX\r ° ôX€ÿ@«@%U@0@ °ÒôXÀ@ °ÀôXÕU*« °®ôXÀà °œôXàÀ °ŠôXÐà °xôXàÐ °fôX( °TôX°Ð °BôXа °0ôX \r °ôX\r ° ôX€ÿ@«@%U@0@ °ÒôXÀ@ °ÀôXÕU*« °®ôXÀà °œôXàÀ °ŠôXÐà °xôXàÐ °fôX( °TôX°Ð °BôXа °0ôX \r °ôX\r ° ôX€ÿ@«@%U@0@ °ÒôXÀ@ °ÀôXÕU*« °®ôXÀà °œôXàÀ °ŠôXÐà °xôXàÐ °fôX( °TôX°Ð °BôXа °0ôX \r °ôX\r ° ôX€ÿð@ @@@P@ °ÒôXÀ@ °ÀôXÕU*« °®ôXÀà °œôXàÀ °ŠôXÐà °xôXàÐ °fôX( °TôX°Ð °BôXа °0ôX \r °ôX\r ° ôX€ÿð@ @@@P@ °ÒôXÀ@ °ÀôXÕU*« °®ôXÀà °œôXàÀ °ŠôXÐà °xôXàÐ °fôX( °TôX°Ð °BôXа °0ôX \r °ôX\r ° ôX€ÿð@ @@@P@ :' `ôô &`ôô  ` ñ` öã `èè âÏ`èè ”3Í ©3Í ¾3Í R¦¦ g¦¦ |¦¦ �ôd¼ôÈ@ @@@ �ôd¼ôÈ@ @@@ �ôd¼ôÈ@ @@@ Ë¸Ž ½ªürèè «˜äôô ™†ú«ôô ‡tä wdäôô cPU S@Uôô ?,ürôô +ürèè  }} ð Ý€€ É ¶÷EBAÿÿ½¿÷E ¢ �™šþÔ {h kXd [Hÿœ K8d ;(ÿœ +ÈÈ ÿ8ÿ8 ,Í     "$&(*,.0246 ”ddú„úd, •udú„úd, –8ôX2ôX —IôX2ôX ˜ ô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ø ø(ø0ø8ø@øHøPøXø`øhøpøxø€øˆø�ø˜ø ø¨ø°ø¸øÀøÈøÐøØøàøèøðøþ0;FQWbmxƒ–ÃÏÛçý æû Þó Öë Îã ÆÛ ¾Ó ¶Ë ®à ¦» ž ³ – « Ž £ † › ~ “ v‹ nƒ f{ ^s Vk Nc F[ >S 6K .C &; 3 + †  ›M  @ M›  @ °@ ¯@ ®@ @­ ¬@ «@ ª@  @– °@ÿj °ôúô¶Xú@@@F@@ôX$4{4{ôX.(ö(öôX qqôX ÀôX ììôX @ôX ±  ` S¨Zb¨x“¨”›`œœi��ržž{ŸŸ„  �¦¦–§§Ÿ±Ü¨dú„¶ôôèôôôèôôôèèúúîîdd„„dú°¶èè*Æÿÿ¥ÿÿÿÿÿ€ÿÿÿ‚Kÿî‚îÿæðúÿOO/ÿÿÿÿÿÿèÇhÿÜÿÿ€€€ÿJ)*ÿcA$ÿˆcÿ£}ÿšÿè¾ÿÿÔÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿqüÿ�ûÿ•úÿ ¨úÿ ¾ùÿÓøÿçøÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿharfbuzz-uharfbuzz-7a648c4/tests/test_raster.py000066400000000000000000000103361526670067500220210ustar00rootroot00000000000000from pathlib import Path import pytest import uharfbuzz as hb TESTDATA = Path(__file__).parent / "data" OPENSANS_TTF = TESTDATA / "OpenSans.subset.ttf" COLORV1_TTF = TESTDATA / "test_glyphs-glyf_colr_1.ttf" @pytest.fixture def font(): blob = hb.Blob(OPENSANS_TTF.read_bytes()) return hb.Font(hb.Face(blob)) @pytest.fixture def colorv1font(): blob = hb.Blob(COLORV1_TTF.read_bytes()) return hb.Font(hb.Face(blob)) class TestRasterImage: def test_configure(self): img = hb.RasterImage() ok = img.configure( hb.RasterFormat.A8, hb.RasterExtents(width=16, height=16), ) assert ok assert img.format is hb.RasterFormat.A8 assert img.extents.width == 16 assert img.extents.height == 16 assert img.extents.stride >= 16 assert len(img.buffer) == img.extents.height * img.extents.stride class TestRasterDraw: def test_render_a8(self, font): gid = 1 draw = hb.RasterDraw() draw.scale_factor = (1.0, 1.0) assert draw.set_glyph_extents(font.get_glyph_extents(gid)) draw.draw_glyph(font, gid) image = draw.render() assert image.format is hb.RasterFormat.A8 assert image.extents.width > 0 assert image.extents.height > 0 assert len(image.buffer) == image.extents.height * image.extents.stride assert any(b != 0 for b in image.buffer) def test_transform_roundtrip(self): draw = hb.RasterDraw() draw.transform = (2.0, 0.0, 0.0, 2.0, 10.0, 20.0) assert draw.transform == (2.0, 0.0, 0.0, 2.0, 10.0, 20.0) def test_scale_factor_roundtrip(self): draw = hb.RasterDraw() draw.scale_factor = (1.5, 2.5) assert draw.scale_factor == (1.5, 2.5) def test_extents_roundtrip(self): draw = hb.RasterDraw() assert draw.extents is None draw.extents = hb.RasterExtents(0, 0, 32, 32, 0) assert draw.extents is not None assert draw.extents.width == 32 assert draw.extents.height == 32 def test_clear_and_reset(self, font): gid = 1 draw = hb.RasterDraw() draw.scale_factor = (1.0, 1.0) draw.set_glyph_extents(font.get_glyph_extents(gid)) draw.draw_glyph(font, gid) draw.clear() draw.reset() image = draw.render() assert isinstance(image, hb.RasterImage) class TestRasterPaint: def test_render_bgra32(self, colorv1font): gid = 10 paint = hb.RasterPaint() paint.scale_factor = (1.0, 1.0) paint.set_glyph_extents(colorv1font.get_glyph_extents(gid)) paint.paint_glyph(colorv1font, gid) image = paint.render() assert image.format is hb.RasterFormat.BGRA32 assert image.extents.width > 0 assert image.extents.height > 0 assert len(image.buffer) == image.extents.height * image.extents.stride def test_foreground_roundtrip(self): paint = hb.RasterPaint() paint.foreground = hb.Color(red=10, green=20, blue=30, alpha=40) color = paint.foreground assert (color.red, color.green, color.blue, color.alpha) == (10, 20, 30, 40) def test_background_roundtrip(self): paint = hb.RasterPaint() paint.background = hb.Color(red=0, green=0, blue=0, alpha=255) color = paint.background assert color.alpha == 255 def test_palette_roundtrip(self): paint = hb.RasterPaint() paint.palette = 2 assert paint.palette == 2 def test_custom_palette_color(self): paint = hb.RasterPaint() assert paint.set_custom_palette_color(0, hb.Color(255, 0, 0, 255)) paint.clear_custom_palette_colors() def test_paint_glyph_or_fail(self, font): # OpenSans glyphs are monochrome gid = 1 paint = hb.RasterPaint() paint.scale_factor = (1.0, 1.0) paint.set_glyph_extents(font.get_glyph_extents(gid)) # _or_fail variant signals "no color paint data" via False assert not paint.paint_glyph_or_fail(font, gid) # plain variant falls back to outline drawing paint.paint_glyph(font, gid) image = paint.render() assert image is not None assert image.format is hb.RasterFormat.BGRA32 harfbuzz-uharfbuzz-7a648c4/tests/test_uharfbuzz.py000066400000000000000000002123051526670067500225410ustar00rootroot00000000000000import 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_deprecated(self): with pytest.deprecated_call(): 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_create_deprecated(self, blankfont): with pytest.deprecated_call(): hb.Face.create(blankfont.face.blob.data) def test_set_get_table_tags_func(self): expected = ["head", "GSUB", "GPOS"] def reference_table(face, tag, user_data): return None def get_table_tags(face, user_data): return expected face = hb.Face.create_for_tables(reference_table, None) face.set_get_table_tags_func(get_table_tags) assert face.table_tags == expected 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_create_deprecated(self, blankfont): with pytest.deprecated_call(): hb.Font.create(blankfont.face) 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 TestFontFuncs: def test_create_deprecated(self): with pytest.deprecated_call(): hb.FontFuncs.create() 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() 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() 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() 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() 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() 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 decompose", "end decompose", "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 == [ [101, 100, 99, 98, 97], [101, 100, 99, 98, 97], [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 if "decompose" not in msg else True 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 decompose", "end decompose", "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 == [ [101, 100, 99, 98, 97], [101, 100, 99, 98, 97], [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 fill_glyph_func(gid, color, is_foreground, conainer): r, g, b, a = color conainer.append(f"fill glyph {gid} solid {r} {g} {b} {a}") 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_fill_glyph_func(fill_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() def test_fill_glyph_fallback(self): blob = hb.Blob.from_file_path(TESTDATA / "test_glyphs-glyf_colr_1.ttf") face = hb.Face(blob) font = hb.Font(face) def push_clip_glyph_func(gid, lines): lines.append(f"start clip glyph {gid}") def color_func(color, is_foreground, lines): r, g, b, a = color lines.append(f"solid {r} {g} {b} {a}") def pop_clip_func(lines): lines.append("end clip") # Without a fill-glyph callback, the operation is decomposed into # push-clip-glyph, color and pop-clip. funcs = hb.PaintFuncs() funcs.set_push_clip_glyph_func(push_clip_glyph_func) funcs.set_color_func(color_func) funcs.set_pop_clip_func(pop_clip_func) lines = [] font.paint_glyph(6, funcs, lines) assert lines == ["start clip glyph 6", "solid 0 0 0 255", "end clip"] 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.0], ["wght", None, None, 300.0], ["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) harfbuzz-uharfbuzz-7a648c4/tox.ini000066400000000000000000000056441526670067500172670ustar00rootroot00000000000000[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/ [testenv:pyodide] description = build and test Pyodide wheel # Emscripten SDK is cached globally by pyodide-build: # Linux: ~/.pyodide-xbuildenv-{version}/{pyodide-version}/emsdk # macOS: ~/Library/Caches/.pyodide-xbuildenv-{version}/{pyodide-version}/emsdk skip_install = true allowlist_externals = bash {envtmpdir}/.pyodide-venv/bin/pip {envtmpdir}/.pyodide-venv/bin/python deps = pyodide-build passenv = HOME changedir = {toxinidir} commands = # avoid re-downloading emsdk if already cached bash -c '\ find_emsdk() { \ for p in "$HOME/.pyodide-xbuildenv"-*/*/emsdk "$HOME/Library/Caches/.pyodide-xbuildenv"-*/*/emsdk; do \ [ -d "$p" ] && echo "$p" && return; \ done; \ }; \ EMSDK=$(find_emsdk); \ [ -z "$EMSDK" ] && pyodide xbuildenv install-emscripten && EMSDK=$(find_emsdk); \ source "$EMSDK/emsdk_env.sh" 2>/dev/null && \ pyodide build --outdir {envtmpdir}/dist' pyodide venv {envtmpdir}/.pyodide-venv bash -c '{envtmpdir}/.pyodide-venv/bin/pip install pytest {envtmpdir}/dist/uharfbuzz*.whl' {envtmpdir}/.pyodide-venv/bin/python -m pytest {posargs} [pytest] testpaths = tests/ addopts = -v -r a