summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/luatexdir/luaharfbuzz
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2021-02-25 19:22:25 +0000
committerKarl Berry <karl@freefriends.org>2021-02-25 19:22:25 +0000
commitad547a6b5986815fda458221149728d9d9ab1d87 (patch)
tree16296910eb3eca724371474ea9aea3994dc69614 /Build/source/texk/web2c/luatexdir/luaharfbuzz
parent947b43de3dd21d58ccc2ffadefc4441ea1c2a813 (diff)
restore Build,TODO from r57911
git-svn-id: svn://tug.org/texlive/trunk@57915 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/luaharfbuzz')
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/LICENSE22
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/Makefile15
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/README.md165
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/THANKS2
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/config.ld9
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/docs/examples/core_types.lua.html108
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/docs/index.html2829
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/docs/ldoc.css303
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/examples/core_types.lua52
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/AppleGothic_korean_issue_22.json1
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/amiri-regular_123.json1
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/amiri-regular_123_numr.json1
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/notonastaliq_U06CC_U06C1.json1
-rwxr-xr-xBuild/source/texk/web2c/luatexdir/luaharfbuzz/fonts/Rajdhani-Regular.ttfbin0 -> 378456 bytes
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/TwitterColorEmoji-SVGinOT.ttfbin0 -> 4232 bytes
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/amiri-regular.ttfbin0 -> 548016 bytes
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/amiriquran-colored.ttfbin0 -> 173108 bytes
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/notocoloremoji-subset.ttfbin0 -> 6124 bytes
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/notonastaliq.ttfbin0 -> 497204 bytes
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-1.1.0-1.rockspec46
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-scm-1.rockspec48
-rwxr-xr-xBuild/source/texk/web2c/luatexdir/luaharfbuzz/scripts/generate_harfbuzz_api_list.sh2
-rwxr-xr-xBuild/source/texk/web2c/luatexdir/luaharfbuzz/scripts/generate_hb_shape_json.sh11
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/buffer_spec.lua236
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/harfbuzz_spec.lua541
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/shaping_spec.lua157
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/harfbuzz.lua84
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/harfbuzz.luadoc535
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/blob.c60
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/buffer.c354
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/class_utils.c33
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/direction.c84
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/face.c466
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/feature.c110
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/font.c218
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/language.c49
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.c131
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.h42
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/ot.c47
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/script.c71
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/tag.c50
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/unicode.c22
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/status/done.txt42
-rw-r--r--Build/source/texk/web2c/luatexdir/luaharfbuzz/status/full_api.txt429
44 files changed, 7377 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/LICENSE b/Build/source/texk/web2c/luatexdir/luaharfbuzz/LICENSE
new file mode 100644
index 00000000000..157ffe59094
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-16 Deepak Jois
+
+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.
+
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/Makefile b/Build/source/texk/web2c/luatexdir/luaharfbuzz/Makefile
new file mode 100644
index 00000000000..71d1fd2712e
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/Makefile
@@ -0,0 +1,15 @@
+DOCS_DIR := docs
+
+spec:
+ busted .
+
+clean:
+ rm -rf build *.so
+
+lint:
+ luacheck src spec examples
+
+doc:
+ ldoc -d ${DOCS_DIR} .
+
+.PHONY: clean lint spec doc
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/README.md b/Build/source/texk/web2c/luatexdir/luaharfbuzz/README.md
new file mode 100644
index 00000000000..c5cee58f869
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/README.md
@@ -0,0 +1,165 @@
+# _luaharfbuzz_
+
+Lua bindings for [Harfbuzz].
+
+[Harfbuzz]:http://harfbuzz.org
+
+## Contents
+
+* [Overview](#overview)
+* [Installing Harfbuzz](#installing-harfbuzz)
+* [Installing _luaharfbuzz_](#installing-luaharfbuzz)
+* [Documentation](#documentation)
+* [Sample Code](#sample-code)
+* [Development](#development)
+* [Contact](#contact)
+
+## Overview
+HarfBuzz is an OpenType text shaping engine. It is used in software like Qt,
+Pango, Firefox, Chromium, XeTeX and LibreOffice.
+
+_luaharfbuzz_ provides bindings for the most common types in Harfbuzz. The
+initial motivation for building it was to use Harfbuzz with the [LuaTeX]
+typesetting system. However, the module isn’t tied to LuaTeX in any way. It
+can be used with any Lua codebase.
+
+luaharfbuzz is currently being used inside [HarfTeX], a TeX engine built
+on top of LuaTeX and designed to use Harfbuzz for shaping text. For more
+details read this TUGboat journal article titled [Bringing world scripts to LuaTeX: The
+HarfBuzz experiment][tugboat-article]
+
+[HarfTeX]: https://github.com/khaledhosny/harftex
+[tugboat-article]: https://tug.org/TUGboat/tb40-1/tb124hosny-harfbuzz.pdf
+[LuaTeX]:luatex.org
+
+## Installing Harfbuzz
+
+Make sure [Harfbuzz] libraries and headers are installed. before trying to
+install _luaharfbuzz_
+
+#### OS X
+
+Install via [Homebrew](http://brew.sh/)
+
+```
+brew install harfbuzz
+```
+#### Ubuntu Linux
+
+```
+apt-get install libharfbuzz0b libharfbuzz-dev
+```
+
+#### Other Platforms
+_Send a pull request if you want to include specific instructions to install
+Harfbuzz on your preferred platform._
+
+Before building the package, LuaRocks populates the `HARFBUZZ_INCDIR` and `HARFBUZZ_LIBDIR` to point to the correct locations. If you can populate these variables manually before running LuaRocks, you can install _luaharfbuzz_ on any system that supports Lua and Harfbuzz.
+
+## Installing _luaharfbuzz_
+
+#### Luarocks
+If [Luarocks] and Harfbuzz are installed, _luaharfbuzz_ can be installed like this:
+
+```
+luarocks install luaharfbuzz
+```
+
+[Luarocks]: https://luarocks.org
+
+## Documentation
+* [API Docs](http://ufytex.github.io/luaharfbuzz/)
+* [Wiki](http://github.com/ufytex/luaharfbuzz/wiki)
+
+## Sample Code
+
+Here is some sample code, showcasing the core types and methods in the API.
+
+```lua
+local harfbuzz = require('harfbuzz')
+local serpent = require('serpent') -- luarocks install serpent
+
+-- Harfbuzz API Version
+print("Harfbuzz API version", harfbuzz.version())
+
+-- Shapers available
+print("Shapers:", serpent.line({ harfbuzz.shapers() }, {comment = false}))
+
+-- harfbuzz.Face
+local face = harfbuzz.Face.new('../fonts/notonastaliq.ttf')
+print('\nFace upem = '..face:get_upem())
+
+-- harfbuzz.Font
+local font = harfbuzz.Font.new(face)
+local xs, xy = font:get_scale()
+print("\nDefault font scale = X: "..xs..", Y: "..xy)
+
+-- harfbuzz.Buffer
+local text = "یہ" -- U+06CC U+06C1
+local buf = harfbuzz.Buffer.new()
+buf:add_utf8(text)
+
+-- harfbuzz.shape (Shapes text)
+print("\nShaping '"..text.."' set with Noto Nastaliq Urdu")
+harfbuzz.shape(font, buf, { language = harfbuzz.Language.new("urd"), script = harfbuzz.Script.new("Arab"), direction = harfbuzz.Direction.RTL})
+
+local glyphs = buf:get_glyphs()
+print("No. of glyphs", #glyphs)
+print(serpent.line(glyphs, {comment = false}))
+
+local opts = { language = harfbuzz.Language.new("eng"), script = harfbuzz.Script.new("Latn"), direction = harfbuzz.Direction.LTR }
+local amiri_face = harfbuzz.Face.new('../fonts/amiri-regular.ttf')
+local amiri_font = harfbuzz.Font.new(amiri_face)
+
+-- shaping '123' w/o features
+print("\nShaping '123' set with Amiri Regular and no features")
+buf= harfbuzz.Buffer.new()
+buf:add_utf8("123")
+harfbuzz.shape(amiri_font, buf, opts)
+glyphs = buf:get_glyphs()
+print(serpent.line(glyphs, {comment = false}))
+
+-- shaping '123' with '+numr' (numerators)
+print("\nShaping '123' set with Amiri Regular with 'numr' feature turned on")
+buf= harfbuzz.Buffer.new()
+buf:add_utf8("123")
+opts.features = "+numr"
+harfbuzz.shape(amiri_font, buf, opts)
+glyphs = buf:get_glyphs()
+print(serpent.line(glyphs, {comment = false}))
+```
+
+## Development
+
+#### Building
+You can build the package for development purposes using LuaRocks as well. It is recommended that you build it to your local tree (using `--local`) to isolate it from your actual installation.
+
+```
+luarocks --local make
+```
+
+#### Testing and Linting
+In order to make changes to the code and run the tests, the following dependencies need to be installed:
+
+* [Busted](http://olivinelabs.com/busted/) – `luarocks install busted`
+* [luacheck](luacheck.readthedocs.org) – `luarocks install luacheck`
+* [luacov](https://keplerproject.github.io/luacov/) – `luarocks install luacov`
+* [ldoc](https://stevedonovan.github.io/ldoc/) – `luarocks install ldoc`
+
+Run the test suite:
+```
+make spec
+```
+
+Lint the codebase:
+```
+make lint
+```
+
+Generate documentation from sources:
+```
+make doc
+```
+
+## Contact
+Open a Github issue, or email me at <deepak.jois@gmail.com>.
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/THANKS b/Build/source/texk/web2c/luatexdir/luaharfbuzz/THANKS
new file mode 100644
index 00000000000..1d996820929
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/THANKS
@@ -0,0 +1,2 @@
+Simon Cozens
+Michal Hoftich
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/config.ld b/Build/source/texk/web2c/luatexdir/luaharfbuzz/config.ld
new file mode 100644
index 00000000000..d37be652ca9
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/config.ld
@@ -0,0 +1,9 @@
+project = 'luaharfbuzz'
+description = 'Lua bindings to Harfbuzz'
+full_description = 'The documentation is available on the @{https://github.com/ufytex/luaharfbuzz/wiki|wiki}'
+use_markdown_titles = true
+backtick_references = false
+title = 'luaharfbuzz Documentation'
+file = 'src/harfbuzz.luadoc'
+examples = 'examples'
+format = 'markdown'
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/docs/examples/core_types.lua.html b/Build/source/texk/web2c/luatexdir/luaharfbuzz/docs/examples/core_types.lua.html
new file mode 100644
index 00000000000..6345ea3c6fa
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/docs/examples/core_types.lua.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<head>
+ <title>luaharfbuzz Documentation</title>
+ <link rel="stylesheet" href="../ldoc.css" type="text/css" />
+</head>
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"></div>
+ <div id="product_name"><big><b></b></big></div>
+ <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+
+<div id="main">
+
+
+<!-- Menu -->
+
+<div id="navigation">
+<br/>
+<h1>luaharfbuzz</h1>
+
+
+
+
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><strong>core_types.lua</strong></li>
+</ul>
+<h2>Modules</h2>
+<ul class="nowrap">
+ <li><a href="../index.html">harfbuzz</a></li>
+</ul>
+
+</div>
+
+<div id="content">
+
+ <h2>core_types.lua</h2>
+<pre>
+<span class="keyword">local</span> harfbuzz = <span class="global">require</span>(<span class="string">'harfbuzz'</span>)
+<span class="keyword">local</span> serpent = <span class="global">require</span>(<span class="string">'serpent'</span>) <span class="comment">-- luarocks install serpent
+</span>
+<span class="comment">-- Harfbuzz API Version
+</span><span class="global">print</span>(<span class="string">"Harfbuzz API version"</span>, harfbuzz.version())
+
+<span class="comment">-- Shapers available
+</span><span class="global">print</span>(<span class="string">"Shapers:"</span>, serpent.line({ harfbuzz.shapers() }, {comment = <span class="keyword">false</span>}))
+
+<span class="comment">-- harfbuzz.Face
+</span><span class="keyword">local</span> face = harfbuzz.Face.new(<span class="string">'../fonts/notonastaliq.ttf'</span>)
+<span class="global">print</span>(<span class="string">'\nFace upem = '</span>..face:get_upem())
+
+<span class="comment">-- harfbuzz.Font
+</span><span class="keyword">local</span> font = harfbuzz.Font.new(face)
+<span class="keyword">local</span> xs, xy = font:get_scale()
+<span class="global">print</span>(<span class="string">"\nDefault font scale = X: "</span>..xs..<span class="string">", Y: "</span>..xy)
+
+<span class="comment">-- harfbuzz.Buffer
+</span><span class="keyword">local</span> text = <span class="string">"یہ"</span> <span class="comment">-- U+06CC U+06C1
+</span><span class="keyword">local</span> buf = harfbuzz.Buffer.new()
+buf:add_utf8(text)
+
+<span class="comment">-- harfbuzz.shape (Shapes text)
+</span><span class="global">print</span>(<span class="string">"\nShaping '"</span>..text..<span class="string">"' set with Noto Nastaliq Urdu"</span>)
+harfbuzz.shape(font, buf, { language = harfbuzz.Language.new(<span class="string">"urd"</span>), script = harfbuzz.Script.new(<span class="string">"Arab"</span>), direction = harfbuzz.Direction.RTL})
+
+<span class="keyword">local</span> glyphs = buf:get_glyphs()
+<span class="global">print</span>(<span class="string">"No. of glyphs"</span>, #glyphs)
+<span class="global">print</span>(serpent.line(glyphs, {comment = <span class="keyword">false</span>}))
+
+<span class="keyword">local</span> opts = { language = harfbuzz.Language.new(<span class="string">"eng"</span>), script = harfbuzz.Script.new(<span class="string">"Latn"</span>), direction = harfbuzz.Direction.LTR }
+<span class="keyword">local</span> amiri_face = harfbuzz.Face.new(<span class="string">'../fonts/amiri-regular.ttf'</span>)
+<span class="keyword">local</span> amiri_font = harfbuzz.Font.new(amiri_face)
+
+<span class="comment">-- shaping '123' w/o features
+</span><span class="global">print</span>(<span class="string">"\nShaping '123' set with Amiri Regular and no features"</span>)
+buf= harfbuzz.Buffer.new()
+buf:add_utf8(<span class="string">"123"</span>)
+harfbuzz.shape(amiri_font, buf, opts)
+glyphs = buf:get_glyphs()
+<span class="global">print</span>(serpent.line(glyphs, {comment = <span class="keyword">false</span>}))
+
+<span class="comment">-- shaping '123' with '+numr' (numerators)
+</span><span class="global">print</span>(<span class="string">"\nShaping '123' set with Amiri Regular with 'numr' feature turned on"</span>)
+buf= harfbuzz.Buffer.new()
+buf:add_utf8(<span class="string">"123"</span>)
+opts.features = <span class="string">"+numr"</span>
+harfbuzz.shape(amiri_font, buf, opts)
+glyphs = buf:get_glyphs()
+<span class="global">print</span>(serpent.line(glyphs, {comment = <span class="keyword">false</span>}))</pre>
+
+
+</div> <!-- id="content" -->
+</div> <!-- id="main" -->
+<div id="about">
+<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
+<i style="float:right;">Last updated 2019-07-31 18:39:39 </i>
+</div> <!-- id="about" -->
+</div> <!-- id="container" -->
+</body>
+</html>
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/docs/index.html b/Build/source/texk/web2c/luatexdir/luaharfbuzz/docs/index.html
new file mode 100644
index 00000000000..d1aaf74c0fa
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/docs/index.html
@@ -0,0 +1,2829 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<head>
+ <title>luaharfbuzz Documentation</title>
+ <link rel="stylesheet" href="ldoc.css" type="text/css" />
+</head>
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"></div>
+ <div id="product_name"><big><b></b></big></div>
+ <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+
+<div id="main">
+
+
+<!-- Menu -->
+
+<div id="navigation">
+<br/>
+<h1>luaharfbuzz</h1>
+
+
+<h2>Contents</h2>
+<ul>
+<li><a href="#Functions">Functions</a></li>
+<li><a href="#Class_Blob">Class Blob </a></li>
+<li><a href="#Class_Face">Class Face </a></li>
+<li><a href="#Class_Font">Class Font </a></li>
+<li><a href="#Class_Buffer">Class Buffer </a></li>
+<li><a href="#Cluster_Levels">Cluster Levels </a></li>
+<li><a href="#Class_Feature">Class Feature </a></li>
+<li><a href="#Class_Tag">Class Tag </a></li>
+<li><a href="#Class_Script">Class Script </a></li>
+<li><a href="#Predefined_Script_Codes">Predefined Script Codes </a></li>
+<li><a href="#Class_Direction">Class Direction </a></li>
+<li><a href="#Predefined_directions">Predefined directions </a></li>
+<li><a href="#Class_Language">Class Language </a></li>
+<li><a href="#Predefined_languages">Predefined languages </a></li>
+<li><a href="#Unicode_functions">Unicode functions </a></li>
+<li><a href="#Predefined_Name_IDs">Predefined Name IDs </a></li>
+</ul>
+
+
+<h2>Modules</h2>
+<ul class="nowrap">
+ <li><strong>harfbuzz</strong></li>
+</ul>
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="examples/core_types.lua.html">core_types.lua</a></li>
+</ul>
+
+</div>
+
+<div id="content">
+
+<h1>Module <code>harfbuzz</code></h1>
+<p>Lua bindings to Harfbuzz.</p>
+<p>
+
+<ul>
+ <li><a href="http://github.com/ufytex/luaharfbuzz/wiki">Wiki</a></li>
+ <li><a href="https://github.com/ufytex/luaharfbuzz">Source on Github</a></li>
+ <li><a href="https://github.com/ufytex/luaharfbuzz/blob/master/status/done.txt">API Coverage Status</a></li>
+</ul>
+</p>
+ <h3>Info:</h3>
+ <ul>
+ <li><strong>Copyright</strong>: 2016</li>
+ <li><strong>License</strong>: MIT</li>
+ <li><strong>Author</strong>: Deepak Jois <<a href="&#x6d;&#97;&#x69;&#108;&#x74;&#111;&#x3a;d&#101;&#x65;&#112;&#x61;&#107;&#x2e;&#106;&#x6f;i&#115;&#x40;&#103;&#x6d;&#97;&#x69;&#108;&#x2e;&#99;&#x6f;m">&#x64;&#101;&#x65;&#112;&#x61;&#107;&#x2e;j&#111;&#x69;&#115;&#x40;&#103;&#x6d;&#97;&#x69;l&#46;&#x63;&#111;&#x6d;</a>></li>
+ </ul>
+
+
+<h2><a href="#Functions">Functions</a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#version">version ()</a></td>
+ <td class="summary">Wraps <code>hb_version</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#shape">shape (font, buffer[, options])</a></td>
+ <td class="summary">Wraps <code>hb_shape</code>.</td>
+ </tr>
+</table>
+<h2><a href="#Class_Blob">Class Blob </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#Blob.new">Blob.new (data)</a></td>
+ <td class="summary">Wraps <code>hb_blob_create</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Blob.new_from_file">Blob.new_from_file (filename)</a></td>
+ <td class="summary">Wraps <code>hb_blob_create_from_file</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Blob:get_length">Blob:get_length ()</a></td>
+ <td class="summary">Wraps <code>hb_blob_get_length</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Blob:get_data">Blob:get_data ()</a></td>
+ <td class="summary">Wraps <code>hb_blob_get_data</code>.</td>
+ </tr>
+</table>
+<h2><a href="#Class_Face">Class Face </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#Face.new_from_blob">Face.new_from_blob (blob[, font_index=0])</a></td>
+ <td class="summary">Wraps <code>hb_face_create</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face.new">Face.new (file[, font_index=0])</a></td>
+ <td class="summary">Create a new <code>Face</code> from a file.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:collect_unicodes">Face:collect_unicodes ()</a></td>
+ <td class="summary">Wraps <code>hb_face_collect_unicodes</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:get_glyph_count">Face:get_glyph_count ()</a></td>
+ <td class="summary">Wraps <code>hb_face_get_glyph_count</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:get_table">Face:get_table (tag)</a></td>
+ <td class="summary">Wraps <code>hb_face_reference_table</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:get_table_tags">Face:get_table_tags ()</a></td>
+ <td class="summary">Wraps <code>hb_face_get_table_tags</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:get_upem">Face:get_upem ()</a></td>
+ <td class="summary">Wraps <code>hb_face_get_upem</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:ot_color_has_palettes">Face:ot_color_has_palettes ()</a></td>
+ <td class="summary">Wraps <code>hb_ot_color_has_palettes</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:ot_color_palette_get_count">Face:ot_color_palette_get_count ()</a></td>
+ <td class="summary">Wraps <code>hb_ot_color_palette_get_count</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:ot_color_palette_get_colors">Face:ot_color_palette_get_colors ()</a></td>
+ <td class="summary">Wraps <code>hb_ot_color_palette_get_colors</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:ot_color_has_layers">Face:ot_color_has_layers ()</a></td>
+ <td class="summary">Wraps <code>hb_ot_color_has_layers</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:ot_color_glyph_get_layers">Face:ot_color_glyph_get_layers ()</a></td>
+ <td class="summary">Wraps <code>hb_ot_color_glyph_get_layers</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:ot_color_has_png">Face:ot_color_has_png ()</a></td>
+ <td class="summary">Wraps <code>hb_ot_color_has_png</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:ot_layout_get_script_tags">Face:ot_layout_get_script_tags ()</a></td>
+ <td class="summary">Wraps <code>hb_ot_layout_table_get_script_tags</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:ot_layout_get_language_tags">Face:ot_layout_get_language_tags ()</a></td>
+ <td class="summary">Wraps <code>hb_ot_layout_script_get_language_tags</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:ot_layout_get_feature_tags">Face:ot_layout_get_feature_tags ()</a></td>
+ <td class="summary">Wraps <code>hb_ot_layout_language_get_feature_tags</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:ot_layout_find_script">Face:ot_layout_find_script ()</a></td>
+ <td class="summary">Wraps <code>hb_ot_layout_table_find_script</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:ot_layout_find_language">Face:ot_layout_find_language ()</a></td>
+ <td class="summary">Wraps <code>hb_ot_layout_script_find_language</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Face:ot_layout_find_feature">Face:ot_layout_find_feature ()</a></td>
+ <td class="summary">Wraps <code>hb_ot_layout_language_find_feature</code>.</td>
+ </tr>
+</table>
+<h2><a href="#Class_Font">Class Font </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#Font.new">Font.new (face)</a></td>
+ <td class="summary">Wraps <code>hb_font_create</code>, and sets up some defaults for scale and shaping functions.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Font:get_scale">Font:get_scale ()</a></td>
+ <td class="summary">Wraps <code>hb_font_get_scale</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Font:set_scale">Font:set_scale (x_scale, y_scale)</a></td>
+ <td class="summary">Wraps <code>hb_font_set_scale</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Font:get_h_extents">Font:get_h_extents ()</a></td>
+ <td class="summary">Wraps <code>hb_font_get_h_extents</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Font:get_v_extents">Font:get_v_extents ()</a></td>
+ <td class="summary">Wraps <code>hb_font_get_v_extents</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Font:get_glyph_extents">Font:get_glyph_extents (glyph)</a></td>
+ <td class="summary">Wraps <code>hb_font_get_glyph_extents</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Font:get_glyph_name">Font:get_glyph_name (glyph)</a></td>
+ <td class="summary">Wraps <code>hb_font_get_glyph_name</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Font:get_glyph_from_name">Font:get_glyph_from_name (name)</a></td>
+ <td class="summary">Wraps <code>hb_font_get_glyph_from_name</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Font:get_glyph_h_advance">Font:get_glyph_h_advance (glyph)</a></td>
+ <td class="summary">Wraps <code>hb_font_get_glyph_h_advance</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Font:get_glyph_v_advance">Font:get_glyph_v_advance (glyph)</a></td>
+ <td class="summary">Wraps <code>hb_font_get_glyph_v_advance</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Font:get_nominal_glyph">Font:get_nominal_glyph (codepoint.)</a></td>
+ <td class="summary">Wraps <code>hb_font_get_nominal_glyph</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Font:ot_color_glyph_get_png">Font:ot_color_glyph_get_png ()</a></td>
+ <td class="summary">Wraps <code>hb_ot_color_glyph_get_png</code>.</td>
+ </tr>
+</table>
+<h2><a href="#Class_Buffer">Class Buffer </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#Buffer.new">Buffer.new ()</a></td>
+ <td class="summary">Wraps <code>hb_buffer_create</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer:add_utf8">Buffer:add_utf8 (text[, item_offset=0[, item_length=-1]])</a></td>
+ <td class="summary">Wraps <code>hb_buffer_add_utf8</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer:add_codepoints">Buffer:add_codepoints (text[, item_offset=0[, item_length=-1]])</a></td>
+ <td class="summary">Wraps <code>hb_buffer_add_codepoints</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer:set_direction">Buffer:set_direction (dir)</a></td>
+ <td class="summary">Wraps <code>hb_buffer_set_direction</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer:get_direction">Buffer:get_direction ()</a></td>
+ <td class="summary">Wraps <code>hb_buffer_get_direction</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer:set_script">Buffer:set_script (script)</a></td>
+ <td class="summary">Wraps <code>hb_buffer_set_script</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer:get_script">Buffer:get_script ()</a></td>
+ <td class="summary">Wraps <code>hb_buffer_get_script</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer:set_language">Buffer:set_language (lang)</a></td>
+ <td class="summary">Wraps <code>hb_buffer_set_language</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer:get_language">Buffer:get_language ()</a></td>
+ <td class="summary">Wraps <code>hb_buffer_get_language</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer:reverse">Buffer:reverse ()</a></td>
+ <td class="summary">Wraps <code>hb_buffer_reverse</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer:get_length">Buffer:get_length ()</a></td>
+ <td class="summary">Wraps <code>hb_buffer_get_length</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer:get_cluster_level">Buffer:get_cluster_level ()</a></td>
+ <td class="summary">Wraps <code>hb_buffer_get_cluster_level</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer:set_cluster_level">Buffer:set_cluster_level (level)</a></td>
+ <td class="summary">Wraps <code>hb_buffer_set_cluster_level</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer:guess_segment_properties">Buffer:guess_segment_properties ()</a></td>
+ <td class="summary">Wraps <code>hb_buffer_guess_segment_properties</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer:get_glyphs">Buffer:get_glyphs ()</a></td>
+ <td class="summary">Helper method to get shaped glyph data.</td>
+ </tr>
+</table>
+<h2><a href="#Cluster_Levels">Cluster Levels </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#Buffer.CLUSTER_LEVEL_MONOTONE_GRAPHEMES">Buffer.CLUSTER_LEVEL_MONOTONE_GRAPHEMES</a></td>
+ <td class="summary">Wraps <code>HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer.CLUSTER_LEVEL_MONOTONE_CHARACTERS">Buffer.CLUSTER_LEVEL_MONOTONE_CHARACTERS</a></td>
+ <td class="summary">Wraps <code>HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer.CLUSTER_LEVEL_CHARACTERS">Buffer.CLUSTER_LEVEL_CHARACTERS</a></td>
+ <td class="summary">Wraps <code>HB_BUFFER_CLUSTER_LEVEL_CHARACTERS</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer.CLUSTER_LEVEL_DEFAULT">Buffer.CLUSTER_LEVEL_DEFAULT</a></td>
+ <td class="summary">Wraps <code>HB_BUFFER_CLUSTER_LEVEL_DEFAULT</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer.GLYPH_FLAG_UNSAFE_TO_BREAK">Buffer.GLYPH_FLAG_UNSAFE_TO_BREAK</a></td>
+ <td class="summary">Wraps <code>HB_GLYPH_FLAG_UNSAFE_TO_BREAK</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Buffer.GLYPH_FLAG_DEFINED">Buffer.GLYPH_FLAG_DEFINED</a></td>
+ <td class="summary">Wraps <code>HB_GLYPH_FLAG_DEFINED</code>.</td>
+ </tr>
+</table>
+<h2><a href="#Class_Feature">Class Feature </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#Feature.new">Feature.new (feature_string)</a></td>
+ <td class="summary">Wraps <code>hb_feature_from_string</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Feature:__tostring">Feature:__tostring ()</a></td>
+ <td class="summary">Wraps <code>hb_feature_to_string</code>.</td>
+ </tr>
+</table>
+<h2><a href="#Class_Tag">Class Tag </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#Tag.new">Tag.new (string)</a></td>
+ <td class="summary">Wraps <code>hb_tag_from_string</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Tag:__to_string">Tag:__to_string ()</a></td>
+ <td class="summary">Wraps <code>hb_tag_to_string</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Tag:__eq">Tag:__eq ()</a></td>
+ <td class="summary">Enables equality comparisions with <code>==</code> between two tags.</td>
+ </tr>
+</table>
+<h2><a href="#Class_Script">Class Script </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#Script.new">Script.new (script)</a></td>
+ <td class="summary">Wraps <code>hb_script_from_string</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Script.from_iso15924_tag">Script.from_iso15924_tag (tag)</a></td>
+ <td class="summary">Wraps <code>hb_script_from_iso15924_tag</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Script:to_iso15924_tag">Script:to_iso15924_tag ()</a></td>
+ <td class="summary">Wraps <code>hb_script_to_iso15924_tag</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Script:__to_string">Script:__to_string ()</a></td>
+ <td class="summary">Enable nice output with <code>tostring(…)</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Script:__eq">Script:__eq ()</a></td>
+ <td class="summary">Enables equality comparisions with <code>==</code> between two scripts.</td>
+ </tr>
+</table>
+<h2><a href="#Predefined_Script_Codes">Predefined Script Codes </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#Script.COMMON">Script.COMMON</a></td>
+ <td class="summary">Wraps <code>HB_SCRIPT_COMMON</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Script.INHERITED">Script.INHERITED</a></td>
+ <td class="summary">Wraps <code>HB_SCRIPT_INHERITED</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Script.UNKNOWN">Script.UNKNOWN</a></td>
+ <td class="summary">Wraps <code>HB_SCRIPT_UNKNOWN</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Script.INVALID">Script.INVALID</a></td>
+ <td class="summary">Wraps <code>HB_SCRIPT_INVALID</code>.</td>
+ </tr>
+</table>
+<h2><a href="#Class_Direction">Class Direction </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#Direction.new">Direction.new (dir)</a></td>
+ <td class="summary">Wraps <code>hb_direction_from_string</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Direction:__to_string">Direction:__to_string ()</a></td>
+ <td class="summary">Wraps <code>hb_direction_to_string</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Direction:__eq">Direction:__eq ()</a></td>
+ <td class="summary">Enables equality comparisions with <code>==</code> between two directions.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Direction:is_valid">Direction:is_valid ()</a></td>
+ <td class="summary">Wraps <code>HB_DIRECTION_IS_VALID</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Direction:is_horizontal">Direction:is_horizontal ()</a></td>
+ <td class="summary">Wraps <code>HB_DIRECTION_IS_HORIZONTAL</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Direction:is_vertical">Direction:is_vertical ()</a></td>
+ <td class="summary">Wraps <code>HB_DIRECTION_IS_VERTICAL</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Direction:is_forward">Direction:is_forward ()</a></td>
+ <td class="summary">Wraps <code>HB_DIRECTION_IS_FORWARD</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Direction:is_backward">Direction:is_backward ()</a></td>
+ <td class="summary">Wraps <code>HB_DIRECTION_IS_BACKWARD</code>.</td>
+ </tr>
+</table>
+<h2><a href="#Predefined_directions">Predefined directions </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#Direction.LTR">Direction.LTR</a></td>
+ <td class="summary">Wraps <code>HB_DIRECTION_LTR</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Direction.RTL">Direction.RTL</a></td>
+ <td class="summary">Wraps <code>HB_DIRECTION_RTL</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Direction.TTB">Direction.TTB</a></td>
+ <td class="summary">Wraps <code>HB_DIRECTION_TTB</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Direction.BTT">Direction.BTT</a></td>
+ <td class="summary">Wraps <code>HB_DIRECTION_LTR</code>.</td>
+ </tr>
+</table>
+<h2><a href="#Class_Language">Class Language </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#Language.new">Language.new (lang)</a></td>
+ <td class="summary">Wraps <code>hb_language_from_string</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Language:__to_string">Language:__to_string ()</a></td>
+ <td class="summary">Wraps <code>hb_language_to_string</code>.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#Language:__eq">Language:__eq ()</a></td>
+ <td class="summary">Enables equality comparisions with <code>==</code> between two languages.</td>
+ </tr>
+</table>
+<h2><a href="#Predefined_languages">Predefined languages </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#Language.INVALID">Language.INVALID</a></td>
+ <td class="summary">Wraps <code>HB_LANGUAGE_INVALID</code>.</td>
+ </tr>
+</table>
+<h2><a href="#Unicode_functions">Unicode functions </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#unicode.script">unicode.script (char)</a></td>
+ <td class="summary">Wraps <code>hb_unicode_script</code></td>
+ </tr>
+</table>
+<h2><a href="#Predefined_Name_IDs">Predefined Name IDs </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_COPYRIGHT">ot.NAME_ID_COPYRIGHT</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_COPYRIGHT</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_FONT_FAMILY">ot.NAME_ID_FONT_FAMILY</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_FONT_FAMILY</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_FONT_SUBFAMILY">ot.NAME_ID_FONT_SUBFAMILY</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_FONT_SUBFAMILY</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_UNIQUE_ID">ot.NAME_ID_UNIQUE_ID</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_UNIQUE_ID</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_FULL_NAME">ot.NAME_ID_FULL_NAME</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_FULL_NAME</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_VERSION_STRING">ot.NAME_ID_VERSION_STRING</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_VERSION_STRING</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_POSTSCRIPT_NAME">ot.NAME_ID_POSTSCRIPT_NAME</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_POSTSCRIPT_NAME</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_TRADEMARK">ot.NAME_ID_TRADEMARK</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_TRADEMARK</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_MANUFACTURER">ot.NAME_ID_MANUFACTURER</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_MANUFACTURER</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_DESIGNER">ot.NAME_ID_DESIGNER</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_DESIGNER</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_DESCRIPTION">ot.NAME_ID_DESCRIPTION</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_DESCRIPTION</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_VENDOR_URL">ot.NAME_ID_VENDOR_URL</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_VENDOR_URL</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_DESIGNER_URL">ot.NAME_ID_DESIGNER_URL</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_DESIGNER_URL</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_LICENSE">ot.NAME_ID_LICENSE</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_LICENSE</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_LICENSE_URL">ot.NAME_ID_LICENSE_URL</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_LICENSE_URL</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_TYPOGRAPHIC_FAMILY">ot.NAME_ID_TYPOGRAPHIC_FAMILY</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_TYPOGRAPHIC_SUBFAMILY">ot.NAME_ID_TYPOGRAPHIC_SUBFAMILY</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_MAC_FULL_NAME">ot.NAME_ID_MAC_FULL_NAME</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_MAC_FULL_NAME</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_SAMPLE_TEXT">ot.NAME_ID_SAMPLE_TEXT</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_SAMPLE_TEXT</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_CID_FINDFONT_NAME">ot.NAME_ID_CID_FINDFONT_NAME</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_CID_FINDFONT_NAME</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_WWS_FAMILY">ot.NAME_ID_WWS_FAMILY</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_WWS_FAMILY</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_WWS_SUBFAMILY">ot.NAME_ID_WWS_SUBFAMILY</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_WWS_SUBFAMILY</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_LIGHT_BACKGROUND">ot.NAME_ID_LIGHT_BACKGROUND</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_LIGHT_BACKGROUND</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_DARK_BACKGROUND">ot.NAME_ID_DARK_BACKGROUND</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_DARK_BACKGROUND</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_VARIATIONS_PS_PREFIX">ot.NAME_ID_VARIATIONS_PS_PREFIX</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_VARIATIONS_PS_PREFIX</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.NAME_ID_INVALID">ot.NAME_ID_INVALID</a></td>
+ <td class="summary">Wraps <code>HB_OT_NAME_ID_INVALID</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.LAYOUT_NO_SCRIPT_INDEX">ot.LAYOUT_NO_SCRIPT_INDEX</a></td>
+ <td class="summary">Wraps <code>HB_OT_LAYOUT_NO_SCRIPT_INDEX</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.LAYOUT_NO_FEATURE_INDEX">ot.LAYOUT_NO_FEATURE_INDEX</a></td>
+ <td class="summary">Wraps <code>HB_OT_LAYOUT_NO_FEATURE_INDEX</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.LAYOUT_DEFAULT_LANGUAGE_INDEX">ot.LAYOUT_DEFAULT_LANGUAGE_INDEX</a></td>
+ <td class="summary">Wraps <code>HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX</code></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#ot.LAYOUT_NO_VARIATIONS_INDEX">ot.LAYOUT_NO_VARIATIONS_INDEX</a></td>
+ <td class="summary">Wraps <code>HB_OT_LAYOUT_NO_VARIATIONS_INDEX</code></td>
+ </tr>
+</table>
+
+<br/>
+<br/>
+
+
+ <h2 class="section-header "><a name="Functions"></a>Functions</h2>
+
+ <dl class="function">
+ <dt>
+ <a name = "version"></a>
+ <strong>version ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_version</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "shape"></a>
+ <strong>shape (font, buffer[, options])</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_shape</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">font</span>
+ <code>Font</code> to use for shaping
+ </li>
+ <li><span class="parameter">buffer</span>
+ <code>Buffer</code> to shape
+ </li>
+ <li><span class="parameter">options</span>
+
+<p> table containing one or more supported options:</p>
+
+<ul>
+ <li><code>direction</code>: A <code>Direction</code> object representing the object.</li>
+ <li><code>script</code>: A <code>Script</code> object representing the script.</li>
+ <li><code>language</code>: A <code>Language</code> object representing the language.</li>
+ <li><code>features</code>: features to enable, specified as either of the following.
+ <ul>
+ <li>comma-separated list of features. See <a href="https://github.com/ufytex/luaharfbuzz/wiki/Feature-Strings">feature string syntax reference</a></li>
+ <li>table of <code>Feature</code> objects</li>
+ </ul></li>
+</ul>
+
+ (<em>optional</em>)
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header has-description"><a name="Class_Blob"></a>Class Blob </h2>
+
+ <div class="section-description">
+ Lua wrapper for <code>hb_blob_t</code> type
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "Blob.new"></a>
+ <strong>Blob.new (data)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_blob_create</code>.
+ Initializes a new <code>hb_blob_t</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">data</span>
+ lua string containing binary or character data.
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Blob.new_from_file"></a>
+ <strong>Blob.new_from_file (filename)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_blob_create_from_file</code>.
+ Initializes a new <code>hb_blob_t</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">filename</span>
+ lua string.
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Blob:get_length"></a>
+ <strong>Blob:get_length ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_blob_get_length</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Blob:get_data"></a>
+ <strong>Blob:get_data ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_blob_get_data</code>.
+
+
+
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header has-description"><a name="Class_Face"></a>Class Face </h2>
+
+ <div class="section-description">
+ Lua wrapper for <code>hb_face_t</code> type
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "Face.new_from_blob"></a>
+ <strong>Face.new_from_blob (blob[, font_index=0])</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_face_create</code>.
+ Initializes a new <code>hb_face_t</code> from a <code>Blob</code> object.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">blob</span>
+ <code>Blob</code> to read the font from.
+ </li>
+ <li><span class="parameter">font_index</span>
+ index of font to read.
+ (<em>default</em> 0)
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face.new"></a>
+ <strong>Face.new (file[, font_index=0])</strong>
+ </dt>
+ <dd>
+ Create a new <code>Face</code> from a file.
+ Makes a call to <code>Face:new_from_blob</code> after creating a <code>Blob</code> from the
+ file contents.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">file</span>
+ path to font file.
+ </li>
+ <li><span class="parameter">font_index</span>
+ index of font to read.
+ (<em>default</em> 0)
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:collect_unicodes"></a>
+ <strong>Face:collect_unicodes ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_face_collect_unicodes</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ table of codepoints supported by the face.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:get_glyph_count"></a>
+ <strong>Face:get_glyph_count ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_face_get_glyph_count</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:get_table"></a>
+ <strong>Face:get_table (tag)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_face_reference_table</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">tag</span>
+ <code>Tag</code> object of the table.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <code>Blob</code> object for the face table of <code>tag</code>.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:get_table_tags"></a>
+ <strong>Face:get_table_tags ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_face_get_table_tags</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ table of <code>Tag</code>s representing face table tags.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:get_upem"></a>
+ <strong>Face:get_upem ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_face_get_upem</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:ot_color_has_palettes"></a>
+ <strong>Face:ot_color_has_palettes ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_ot_color_has_palettes</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:ot_color_palette_get_count"></a>
+ <strong>Face:ot_color_palette_get_count ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_ot_color_palette_get_count</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:ot_color_palette_get_colors"></a>
+ <strong>Face:ot_color_palette_get_colors ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_ot_color_palette_get_colors</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:ot_color_has_layers"></a>
+ <strong>Face:ot_color_has_layers ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_ot_color_has_layers</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:ot_color_glyph_get_layers"></a>
+ <strong>Face:ot_color_glyph_get_layers ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_ot_color_glyph_get_layers</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:ot_color_has_png"></a>
+ <strong>Face:ot_color_has_png ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_ot_color_has_png</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:ot_layout_get_script_tags"></a>
+ <strong>Face:ot_layout_get_script_tags ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_ot_layout_table_get_script_tags</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:ot_layout_get_language_tags"></a>
+ <strong>Face:ot_layout_get_language_tags ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_ot_layout_script_get_language_tags</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:ot_layout_get_feature_tags"></a>
+ <strong>Face:ot_layout_get_feature_tags ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_ot_layout_language_get_feature_tags</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:ot_layout_find_script"></a>
+ <strong>Face:ot_layout_find_script ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_ot_layout_table_find_script</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:ot_layout_find_language"></a>
+ <strong>Face:ot_layout_find_language ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_ot_layout_script_find_language</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Face:ot_layout_find_feature"></a>
+ <strong>Face:ot_layout_find_feature ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_ot_layout_language_find_feature</code>.
+
+
+
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header has-description"><a name="Class_Font"></a>Class Font </h2>
+
+ <div class="section-description">
+ Lua wrapper for <code>hb_font_t</code> type
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "Font.new"></a>
+ <strong>Font.new (face)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_font_create</code>, and sets up some defaults for scale and shaping functions.
+ Initializes a new <code>hb_font_t</code> from a <code>Face</code> object. Sets the default scale
+ to the face’s upem value, and sets the font shaping functions by
+ calling <code>hb_ot_font_set_funcs</code> on it.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">face</span>
+ <code>Face</code> object.
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Font:get_scale"></a>
+ <strong>Font:get_scale ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_font_get_scale</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ two values for the x-scale and y-scale of the font.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Font:set_scale"></a>
+ <strong>Font:set_scale (x_scale, y_scale)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_font_set_scale</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">x_scale</span>
+ desired x-scale of font.
+ </li>
+ <li><span class="parameter">y_scale</span>
+ desired y-scale of font.
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Font:get_h_extents"></a>
+ <strong>Font:get_h_extents ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_font_get_h_extents</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+
+<p> font extents table for horizontal direction, contains the following
+ or <code>nil</code> if HarfBuzz fails to load font extents:</p>
+
+<ul>
+ <li><code>ascender</code>: typographic ascender.</li>
+ <li><code>descender</code>: typographic descender.</li>
+ <li><code>line_gap</code>: line spacing gap.</li>
+</ul>
+
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Font:get_v_extents"></a>
+ <strong>Font:get_v_extents ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_font_get_v_extents</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ font extents table for vertical direction, similar to
+ <code>Font:get_h_extents</code>, or <code>nil</code> if HarfBuzz fails to load font extents:
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Font:get_glyph_extents"></a>
+ <strong>Font:get_glyph_extents (glyph)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_font_get_glyph_extents</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">glyph</span>
+ index inside the font.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+
+<p> extents table contains the following or <code>nil</code> if HarfBuzz fails to
+ load glyph extents:</p>
+
+<ul>
+ <li><code>x_bearing</code>: left side of glyph from origin.</li>
+ <li><code>y_bearing</code>: top side of glyph from origin.</li>
+ <li><code>width</code>: distance from left to right side.</li>
+ <li><code>height</code>: distance from top to bottom side.</li>
+</ul>
+
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Font:get_glyph_name"></a>
+ <strong>Font:get_glyph_name (glyph)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_font_get_glyph_name</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">glyph</span>
+ index inside the font.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ name of the glyph or nil.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Font:get_glyph_from_name"></a>
+ <strong>Font:get_glyph_from_name (name)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_font_get_glyph_from_name</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">name</span>
+ of the glyph.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ glyph index inside the font or nil.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Font:get_glyph_h_advance"></a>
+ <strong>Font:get_glyph_h_advance (glyph)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_font_get_glyph_h_advance</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">glyph</span>
+ index inside the font.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ advance glyph advance of the glyph in horizontal direction.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Font:get_glyph_v_advance"></a>
+ <strong>Font:get_glyph_v_advance (glyph)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_font_get_glyph_v_advance</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">glyph</span>
+ index inside the font.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ advance glyph advance of the glyph in vertical direction.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Font:get_nominal_glyph"></a>
+ <strong>Font:get_nominal_glyph (codepoint.)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_font_get_nominal_glyph</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">codepoint.</span>
+
+
+
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ glyph index or <code>nil</code> if <code>codepoint</code> is not supported by the font.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Font:ot_color_glyph_get_png"></a>
+ <strong>Font:ot_color_glyph_get_png ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_ot_color_glyph_get_png</code>.
+
+
+
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header has-description"><a name="Class_Buffer"></a>Class Buffer </h2>
+
+ <div class="section-description">
+ Lua wrapper for <code>hb_buffer_t</code> type.
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "Buffer.new"></a>
+ <strong>Buffer.new ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_buffer_create</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer:add_utf8"></a>
+ <strong>Buffer:add_utf8 (text[, item_offset=0[, item_length=-1]])</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_buffer_add_utf8</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">text</span>
+ UTF8 encoded string.
+ </li>
+ <li><span class="parameter">item_offset</span>
+ 0-indexed offset in <code>text</code>, from where to start adding.
+ (<em>default</em> 0)
+ </li>
+ <li><span class="parameter">item_length</span>
+ length to add from <code>item_offset</code>. <code>-1</code> adds till end of <code>text</code>.
+ (<em>default</em> -1)
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer:add_codepoints"></a>
+ <strong>Buffer:add_codepoints (text[, item_offset=0[, item_length=-1]])</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_buffer_add_codepoints</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">text</span>
+ table with codepoints as lua numbers.
+ </li>
+ <li><span class="parameter">item_offset</span>
+ 0-indexed offset in <code>text</code>, from where to start adding.
+ (<em>default</em> 0)
+ </li>
+ <li><span class="parameter">item_length</span>
+ length to add from <code>item_offset</code>. <code>-1</code> adds till end of&nbsp;<code>text</code>.
+ (<em>default</em> -1)
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer:set_direction"></a>
+ <strong>Buffer:set_direction (dir)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_buffer_set_direction</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">dir</span>
+ A <code>Direction</code> object.
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer:get_direction"></a>
+ <strong>Buffer:get_direction ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_buffer_get_direction</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ A <code>Direction</code> object.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer:set_script"></a>
+ <strong>Buffer:set_script (script)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_buffer_set_script</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">script</span>
+ A <code>Script</code> object.
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer:get_script"></a>
+ <strong>Buffer:get_script ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_buffer_get_script</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ A <code>Script</code> object.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer:set_language"></a>
+ <strong>Buffer:set_language (lang)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_buffer_set_language</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">lang</span>
+ A <code>Language</code> object
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer:get_language"></a>
+ <strong>Buffer:get_language ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_buffer_get_language</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ A <code>Language</code> object
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer:reverse"></a>
+ <strong>Buffer:reverse ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_buffer_reverse</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer:get_length"></a>
+ <strong>Buffer:get_length ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_buffer_get_length</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer:get_cluster_level"></a>
+ <strong>Buffer:get_cluster_level ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_buffer_get_cluster_level</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ see <a href="#Cluster_Levels">Cluster Levels</a>
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer:set_cluster_level"></a>
+ <strong>Buffer:set_cluster_level (level)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_buffer_set_cluster_level</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">level</span>
+ see <a href="#Cluster_Levels">Cluster Levels</a>
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer:guess_segment_properties"></a>
+ <strong>Buffer:guess_segment_properties ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_buffer_guess_segment_properties</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer:get_glyphs"></a>
+ <strong>Buffer:get_glyphs ()</strong>
+ </dt>
+ <dd>
+ Helper method to get shaped glyph data.
+ Calls <code>hb_buffer_get_glyph_infos</code>, <code>hb_buffer_get_glyph_positions</code> and
+ <code>hb_glyph_info_get_glyph_flags</code>, and assembles the data into a Lua table.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+
+<p> table containing data for each glyph, in a nested table. Each nested
+ table contains the following:</p>
+
+<ul>
+ <li><code>x_advance</code>: horizontal advance.</li>
+ <li><code>y_advance</code>: vertical advance.</li>
+ <li><code>x_offset</code>: horizontal displacement.</li>
+ <li><code>y_offset</code>: vertical displacement.</li>
+ <li><code>cluster</code>: glyph cluster index within input.</li>
+ <li><code>codepoint</code>: glyph index inside the font <em>(this field name is a bit misleading, but that’s what Harfbuzz uses)</em>.</li>
+ <li><code>flags</code>: glyph flags</li>
+</ul>
+
+ </ol>
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header has-description"><a name="Cluster_Levels"></a>Cluster Levels </h2>
+
+ <div class="section-description">
+ See <a href="http://behdad.github.io/harfbuzz/clusters.html">Harfbuzz docs</a> for more details
+ about what each of these levels mean.
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "Buffer.CLUSTER_LEVEL_MONOTONE_GRAPHEMES"></a>
+ <strong>Buffer.CLUSTER_LEVEL_MONOTONE_GRAPHEMES</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer.CLUSTER_LEVEL_MONOTONE_CHARACTERS"></a>
+ <strong>Buffer.CLUSTER_LEVEL_MONOTONE_CHARACTERS</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer.CLUSTER_LEVEL_CHARACTERS"></a>
+ <strong>Buffer.CLUSTER_LEVEL_CHARACTERS</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_BUFFER_CLUSTER_LEVEL_CHARACTERS</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer.CLUSTER_LEVEL_DEFAULT"></a>
+ <strong>Buffer.CLUSTER_LEVEL_DEFAULT</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_BUFFER_CLUSTER_LEVEL_DEFAULT</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer.GLYPH_FLAG_UNSAFE_TO_BREAK"></a>
+ <strong>Buffer.GLYPH_FLAG_UNSAFE_TO_BREAK</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_GLYPH_FLAG_UNSAFE_TO_BREAK</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Buffer.GLYPH_FLAG_DEFINED"></a>
+ <strong>Buffer.GLYPH_FLAG_DEFINED</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_GLYPH_FLAG_DEFINED</code>.
+
+
+
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header has-description"><a name="Class_Feature"></a>Class Feature </h2>
+
+ <div class="section-description">
+ Lua wrapper for <code>hb_feature_t</code> type
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "Feature.new"></a>
+ <strong>Feature.new (feature_string)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_feature_from_string</code>
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">feature_string</span>
+ See <a href="https://github.com/ufytex/luaharfbuzz/wiki/Feature-Strings">feature string syntax reference</a>
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Feature:__tostring"></a>
+ <strong>Feature:__tostring ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_feature_to_string</code>.
+ Enables nice output with <code>tostring(…)</code>.
+
+
+
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header has-description"><a name="Class_Tag"></a>Class Tag </h2>
+
+ <div class="section-description">
+ Lua wrapper for <code>hb_tag_t</code> type.
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "Tag.new"></a>
+ <strong>Tag.new (string)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_tag_from_string</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">string</span>
+ to be converted to a <code>Tag</code> object.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ a <code>Tag</code> object.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Tag:__to_string"></a>
+ <strong>Tag:__to_string ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_tag_to_string</code>. Enable nice output with <code>tostring(…)</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ Returns a string representation for the tag object.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Tag:__eq"></a>
+ <strong>Tag:__eq ()</strong>
+ </dt>
+ <dd>
+ Enables equality comparisions with <code>==</code> between two tags.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <code>true</code> or <code>false</code> depending on whether the two tags are equal.
+ </ol>
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header has-description"><a name="Class_Script"></a>Class Script </h2>
+
+ <div class="section-description">
+ Lua wrapper for <code>hb_script_t</code> type.
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "Script.new"></a>
+ <strong>Script.new (script)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_script_from_string</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">script</span>
+ 4-letter script code according to the <a href="http://www.unicode.org/iso15924/iso15924-num.html">ISO 15924 standard</a>.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ a <code>Script</code> object.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Script.from_iso15924_tag"></a>
+ <strong>Script.from_iso15924_tag (tag)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_script_from_iso15924_tag</code>
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">tag</span>
+ a <code>Tag</code> object representing a <a href="http://www.unicode.org/iso15924/iso15924-num.html">ISO 15924 script</a>.
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Script:to_iso15924_tag"></a>
+ <strong>Script:to_iso15924_tag ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_script_to_iso15924_tag</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ a <code>Tag</code> object representing the script.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Script:__to_string"></a>
+ <strong>Script:__to_string ()</strong>
+ </dt>
+ <dd>
+ Enable nice output with <code>tostring(…)</code>
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ Returns a 4-letter <a href="http://www.unicode.org/iso15924/iso15924-num.html">ISO 15924 script code</a> for the script object.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Script:__eq"></a>
+ <strong>Script:__eq ()</strong>
+ </dt>
+ <dd>
+ Enables equality comparisions with <code>==</code> between two scripts.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <code>true</code> or <code>false</code> depending on whether the two scripts are equal.
+ </ol>
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header has-description"><a name="Predefined_Script_Codes"></a>Predefined Script Codes </h2>
+
+ <div class="section-description">
+ Predefined directions that correspond to their original definitions in Harfbuzz.
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "Script.COMMON"></a>
+ <strong>Script.COMMON</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_SCRIPT_COMMON</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Script.INHERITED"></a>
+ <strong>Script.INHERITED</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_SCRIPT_INHERITED</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Script.UNKNOWN"></a>
+ <strong>Script.UNKNOWN</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_SCRIPT_UNKNOWN</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Script.INVALID"></a>
+ <strong>Script.INVALID</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_SCRIPT_INVALID</code>.
+
+
+
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header has-description"><a name="Class_Direction"></a>Class Direction </h2>
+
+ <div class="section-description">
+ Lua wrapper for <code>hb_direction_t</code> type.
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "Direction.new"></a>
+ <strong>Direction.new (dir)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_direction_from_string</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">dir</span>
+ can be one of <code>ltr</code>, <code>rtl</code>, <code>ttb</code>, <code>btt</code> or <code>invalid</code>.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ a <code>Direction</code> object.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Direction:__to_string"></a>
+ <strong>Direction:__to_string ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_direction_to_string</code>. Enable nice output with <code>tostring(…)</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ Returns a string representation for direction.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Direction:__eq"></a>
+ <strong>Direction:__eq ()</strong>
+ </dt>
+ <dd>
+ Enables equality comparisions with <code>==</code> between two directions.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <code>true</code> or <code>false</code> depending on whether the two tags are equal.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Direction:is_valid"></a>
+ <strong>Direction:is_valid ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_DIRECTION_IS_VALID</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ a boolean value
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Direction:is_horizontal"></a>
+ <strong>Direction:is_horizontal ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_DIRECTION_IS_HORIZONTAL</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ a boolean value
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Direction:is_vertical"></a>
+ <strong>Direction:is_vertical ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_DIRECTION_IS_VERTICAL</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ a boolean value
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Direction:is_forward"></a>
+ <strong>Direction:is_forward ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_DIRECTION_IS_FORWARD</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ a boolean value
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Direction:is_backward"></a>
+ <strong>Direction:is_backward ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_DIRECTION_IS_BACKWARD</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ a boolean value
+ </ol>
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header has-description"><a name="Predefined_directions"></a>Predefined directions </h2>
+
+ <div class="section-description">
+ Predefined directions that correspond to their original definitions in Harfbuzz.
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "Direction.LTR"></a>
+ <strong>Direction.LTR</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_DIRECTION_LTR</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Direction.RTL"></a>
+ <strong>Direction.RTL</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_DIRECTION_RTL</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Direction.TTB"></a>
+ <strong>Direction.TTB</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_DIRECTION_TTB</code>.
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Direction.BTT"></a>
+ <strong>Direction.BTT</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_DIRECTION_LTR</code>.
+
+
+
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header has-description"><a name="Class_Language"></a>Class Language </h2>
+
+ <div class="section-description">
+ Lua wrapper for <code>hb_language_t</code> type.
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "Language.new"></a>
+ <strong>Language.new (lang)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_language_from_string</code>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">lang</span>
+ <a href="http://www.microsoft.com/typography/otspec/languagetags.htm">three-letter language tag</a> to be converted to a <code>Language</code> object.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ a <code>Language</code> object.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Language:__to_string"></a>
+ <strong>Language:__to_string ()</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_language_to_string</code>. Enable nice output with <code>tostring(…)</code>.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ Returns a string representation for the language object.
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "Language:__eq"></a>
+ <strong>Language:__eq ()</strong>
+ </dt>
+ <dd>
+ Enables equality comparisions with <code>==</code> between two languages.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <code>true</code> or <code>false</code> depending on whether the two languages are equal.
+ </ol>
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header has-description"><a name="Predefined_languages"></a>Predefined languages </h2>
+
+ <div class="section-description">
+ Predefined languages that correspond to their original definitions in Harfbuzz.
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "Language.INVALID"></a>
+ <strong>Language.INVALID</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_LANGUAGE_INVALID</code>.
+
+
+
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header "><a name="Unicode_functions"></a>Unicode functions </h2>
+
+ <dl class="function">
+ <dt>
+ <a name = "unicode.script"></a>
+ <strong>unicode.script (char)</strong>
+ </dt>
+ <dd>
+ Wraps <code>hb_unicode_script</code>
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">char</span>
+ Unicode codepoint
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ a <code>Script</code> object.
+ </ol>
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header has-description"><a name="Predefined_Name_IDs"></a>Predefined Name IDs </h2>
+
+ <div class="section-description">
+ Predefined OpenType 'name' table name identifier.
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "ot.NAME_ID_COPYRIGHT"></a>
+ <strong>ot.NAME_ID_COPYRIGHT</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_COPYRIGHT</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_FONT_FAMILY"></a>
+ <strong>ot.NAME_ID_FONT_FAMILY</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_FONT_FAMILY</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_FONT_SUBFAMILY"></a>
+ <strong>ot.NAME_ID_FONT_SUBFAMILY</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_FONT_SUBFAMILY</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_UNIQUE_ID"></a>
+ <strong>ot.NAME_ID_UNIQUE_ID</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_UNIQUE_ID</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_FULL_NAME"></a>
+ <strong>ot.NAME_ID_FULL_NAME</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_FULL_NAME</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_VERSION_STRING"></a>
+ <strong>ot.NAME_ID_VERSION_STRING</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_VERSION_STRING</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_POSTSCRIPT_NAME"></a>
+ <strong>ot.NAME_ID_POSTSCRIPT_NAME</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_POSTSCRIPT_NAME</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_TRADEMARK"></a>
+ <strong>ot.NAME_ID_TRADEMARK</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_TRADEMARK</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_MANUFACTURER"></a>
+ <strong>ot.NAME_ID_MANUFACTURER</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_MANUFACTURER</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_DESIGNER"></a>
+ <strong>ot.NAME_ID_DESIGNER</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_DESIGNER</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_DESCRIPTION"></a>
+ <strong>ot.NAME_ID_DESCRIPTION</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_DESCRIPTION</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_VENDOR_URL"></a>
+ <strong>ot.NAME_ID_VENDOR_URL</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_VENDOR_URL</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_DESIGNER_URL"></a>
+ <strong>ot.NAME_ID_DESIGNER_URL</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_DESIGNER_URL</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_LICENSE"></a>
+ <strong>ot.NAME_ID_LICENSE</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_LICENSE</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_LICENSE_URL"></a>
+ <strong>ot.NAME_ID_LICENSE_URL</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_LICENSE_URL</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_TYPOGRAPHIC_FAMILY"></a>
+ <strong>ot.NAME_ID_TYPOGRAPHIC_FAMILY</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_TYPOGRAPHIC_SUBFAMILY"></a>
+ <strong>ot.NAME_ID_TYPOGRAPHIC_SUBFAMILY</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_MAC_FULL_NAME"></a>
+ <strong>ot.NAME_ID_MAC_FULL_NAME</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_MAC_FULL_NAME</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_SAMPLE_TEXT"></a>
+ <strong>ot.NAME_ID_SAMPLE_TEXT</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_SAMPLE_TEXT</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_CID_FINDFONT_NAME"></a>
+ <strong>ot.NAME_ID_CID_FINDFONT_NAME</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_CID_FINDFONT_NAME</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_WWS_FAMILY"></a>
+ <strong>ot.NAME_ID_WWS_FAMILY</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_WWS_FAMILY</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_WWS_SUBFAMILY"></a>
+ <strong>ot.NAME_ID_WWS_SUBFAMILY</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_WWS_SUBFAMILY</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_LIGHT_BACKGROUND"></a>
+ <strong>ot.NAME_ID_LIGHT_BACKGROUND</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_LIGHT_BACKGROUND</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_DARK_BACKGROUND"></a>
+ <strong>ot.NAME_ID_DARK_BACKGROUND</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_DARK_BACKGROUND</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_VARIATIONS_PS_PREFIX"></a>
+ <strong>ot.NAME_ID_VARIATIONS_PS_PREFIX</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_VARIATIONS_PS_PREFIX</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.NAME_ID_INVALID"></a>
+ <strong>ot.NAME_ID_INVALID</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_NAME_ID_INVALID</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.LAYOUT_NO_SCRIPT_INDEX"></a>
+ <strong>ot.LAYOUT_NO_SCRIPT_INDEX</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_LAYOUT_NO_SCRIPT_INDEX</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.LAYOUT_NO_FEATURE_INDEX"></a>
+ <strong>ot.LAYOUT_NO_FEATURE_INDEX</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_LAYOUT_NO_FEATURE_INDEX</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.LAYOUT_DEFAULT_LANGUAGE_INDEX"></a>
+ <strong>ot.LAYOUT_DEFAULT_LANGUAGE_INDEX</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX</code>
+
+
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "ot.LAYOUT_NO_VARIATIONS_INDEX"></a>
+ <strong>ot.LAYOUT_NO_VARIATIONS_INDEX</strong>
+ </dt>
+ <dd>
+ Wraps <code>HB_OT_LAYOUT_NO_VARIATIONS_INDEX</code>
+
+
+
+
+
+
+
+</dd>
+</dl>
+
+
+</div> <!-- id="content" -->
+</div> <!-- id="main" -->
+<div id="about">
+<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
+<i style="float:right;">Last updated 2019-07-31 18:39:39 </i>
+</div> <!-- id="about" -->
+</div> <!-- id="container" -->
+</body>
+</html>
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/docs/ldoc.css b/Build/source/texk/web2c/luatexdir/luaharfbuzz/docs/ldoc.css
new file mode 100644
index 00000000000..52c4ad2bd8a
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/docs/ldoc.css
@@ -0,0 +1,303 @@
+/* BEGIN RESET
+
+Copyright (c) 2010, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.8.2r1
+*/
+html {
+ color: #000;
+ background: #FFF;
+}
+body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td {
+ margin: 0;
+ padding: 0;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+fieldset,img {
+ border: 0;
+}
+address,caption,cite,code,dfn,em,strong,th,var,optgroup {
+ font-style: inherit;
+ font-weight: inherit;
+}
+del,ins {
+ text-decoration: none;
+}
+li {
+ margin-left: 20px;
+}
+caption,th {
+ text-align: left;
+}
+h1,h2,h3,h4,h5,h6 {
+ font-size: 100%;
+ font-weight: bold;
+}
+q:before,q:after {
+ content: '';
+}
+abbr,acronym {
+ border: 0;
+ font-variant: normal;
+}
+sup {
+ vertical-align: baseline;
+}
+sub {
+ vertical-align: baseline;
+}
+legend {
+ color: #000;
+}
+input,button,textarea,select,optgroup,option {
+ font-family: inherit;
+ font-size: inherit;
+ font-style: inherit;
+ font-weight: inherit;
+}
+input,button,textarea,select {*font-size:100%;
+}
+/* END RESET */
+
+body {
+ margin-left: 1em;
+ margin-right: 1em;
+ font-family: arial, helvetica, geneva, sans-serif;
+ background-color: #ffffff; margin: 0px;
+}
+
+code, tt { font-family: monospace; font-size: 1.1em; }
+span.parameter { font-family:monospace; }
+span.parameter:after { content:":"; }
+span.types:before { content:"("; }
+span.types:after { content:")"; }
+.type { font-weight: bold; font-style:italic }
+
+body, p, td, th { font-size: .95em; line-height: 1.2em;}
+
+p, ul { margin: 10px 0 0 0px;}
+
+strong { font-weight: bold;}
+
+em { font-style: italic;}
+
+h1 {
+ font-size: 1.5em;
+ margin: 20px 0 20px 0;
+}
+h2, h3, h4 { margin: 15px 0 10px 0; }
+h2 { font-size: 1.25em; }
+h3 { font-size: 1.15em; }
+h4 { font-size: 1.06em; }
+
+a:link { font-weight: bold; color: #004080; text-decoration: none; }
+a:visited { font-weight: bold; color: #006699; text-decoration: none; }
+a:link:hover { text-decoration: underline; }
+
+hr {
+ color:#cccccc;
+ background: #00007f;
+ height: 1px;
+}
+
+blockquote { margin-left: 3em; }
+
+ul { list-style-type: disc; }
+
+p.name {
+ font-family: "Andale Mono", monospace;
+ padding-top: 1em;
+}
+
+pre {
+ background-color: rgb(245, 245, 245);
+ border: 1px solid #C0C0C0; /* silver */
+ padding: 10px;
+ margin: 10px 0 10px 0;
+ overflow: auto;
+ font-family: "Andale Mono", monospace;
+}
+
+pre.example {
+ font-size: .85em;
+}
+
+table.index { border: 1px #00007f; }
+table.index td { text-align: left; vertical-align: top; }
+
+#container {
+ margin-left: 1em;
+ margin-right: 1em;
+ background-color: #f0f0f0;
+}
+
+#product {
+ text-align: center;
+ border-bottom: 1px solid #cccccc;
+ background-color: #ffffff;
+}
+
+#product big {
+ font-size: 2em;
+}
+
+#main {
+ background-color: #f0f0f0;
+ border-left: 2px solid #cccccc;
+}
+
+#navigation {
+ float: left;
+ width: 14em;
+ vertical-align: top;
+ background-color: #f0f0f0;
+ overflow: visible;
+}
+
+#navigation h2 {
+ background-color:#e7e7e7;
+ font-size:1.1em;
+ color:#000000;
+ text-align: left;
+ padding:0.2em;
+ border-top:1px solid #dddddd;
+ border-bottom:1px solid #dddddd;
+}
+
+#navigation ul
+{
+ font-size:1em;
+ list-style-type: none;
+ margin: 1px 1px 10px 1px;
+}
+
+#navigation li {
+ text-indent: -1em;
+ display: block;
+ margin: 3px 0px 0px 22px;
+}
+
+#navigation li li a {
+ margin: 0px 3px 0px -1em;
+}
+
+#content {
+ margin-left: 14em;
+ padding: 1em;
+ width: 700px;
+ border-left: 2px solid #cccccc;
+ border-right: 2px solid #cccccc;
+ background-color: #ffffff;
+}
+
+#about {
+ clear: both;
+ padding: 5px;
+ border-top: 2px solid #cccccc;
+ background-color: #ffffff;
+}
+
+@media print {
+ body {
+ font: 12pt "Times New Roman", "TimeNR", Times, serif;
+ }
+ a { font-weight: bold; color: #004080; text-decoration: underline; }
+
+ #main {
+ background-color: #ffffff;
+ border-left: 0px;
+ }
+
+ #container {
+ margin-left: 2%;
+ margin-right: 2%;
+ background-color: #ffffff;
+ }
+
+ #content {
+ padding: 1em;
+ background-color: #ffffff;
+ }
+
+ #navigation {
+ display: none;
+ }
+ pre.example {
+ font-family: "Andale Mono", monospace;
+ font-size: 10pt;
+ page-break-inside: avoid;
+ }
+}
+
+table.module_list {
+ border-width: 1px;
+ border-style: solid;
+ border-color: #cccccc;
+ border-collapse: collapse;
+}
+table.module_list td {
+ border-width: 1px;
+ padding: 3px;
+ border-style: solid;
+ border-color: #cccccc;
+}
+table.module_list td.name { background-color: #f0f0f0; min-width: 200px; }
+table.module_list td.summary { width: 100%; }
+
+
+table.function_list {
+ border-width: 1px;
+ border-style: solid;
+ border-color: #cccccc;
+ border-collapse: collapse;
+}
+table.function_list td {
+ border-width: 1px;
+ padding: 3px;
+ border-style: solid;
+ border-color: #cccccc;
+}
+table.function_list td.name { background-color: #f0f0f0; min-width: 200px; }
+table.function_list td.summary { width: 100%; }
+
+ul.nowrap {
+ overflow:auto;
+ white-space:nowrap;
+}
+
+dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;}
+dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;}
+dl.table h3, dl.function h3 {font-size: .95em;}
+
+/* stop sublists from having initial vertical space */
+ul ul { margin-top: 0px; }
+ol ul { margin-top: 0px; }
+ol ol { margin-top: 0px; }
+ul ol { margin-top: 0px; }
+
+/* make the target distinct; helps when we're navigating to a function */
+a:target + * {
+ background-color: #FF9;
+}
+
+
+/* styles for prettification of source */
+pre .comment { color: #558817; }
+pre .constant { color: #a8660d; }
+pre .escape { color: #844631; }
+pre .keyword { color: #aa5050; font-weight: bold; }
+pre .library { color: #0e7c6b; }
+pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; }
+pre .string { color: #8080ff; }
+pre .number { color: #f8660d; }
+pre .operator { color: #2239a8; font-weight: bold; }
+pre .preprocessor, pre .prepro { color: #a33243; }
+pre .global { color: #800080; }
+pre .user-keyword { color: #800080; }
+pre .prompt { color: #558817; }
+pre .url { color: #272fc2; text-decoration: underline; }
+
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/examples/core_types.lua b/Build/source/texk/web2c/luatexdir/luaharfbuzz/examples/core_types.lua
new file mode 100644
index 00000000000..ec3d0d4388c
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/examples/core_types.lua
@@ -0,0 +1,52 @@
+local harfbuzz = require('harfbuzz')
+local serpent = require('serpent') -- luarocks install serpent
+
+-- Harfbuzz API Version
+print("Harfbuzz API version", harfbuzz.version())
+
+-- Shapers available
+print("Shapers:", serpent.line({ harfbuzz.shapers() }, {comment = false}))
+
+-- harfbuzz.Face
+local face = harfbuzz.Face.new('../fonts/notonastaliq.ttf')
+print('\nFace upem = '..face:get_upem())
+
+-- harfbuzz.Font
+local font = harfbuzz.Font.new(face)
+local xs, xy = font:get_scale()
+print("\nDefault font scale = X: "..xs..", Y: "..xy)
+
+-- harfbuzz.Buffer
+local text = "یہ" -- U+06CC U+06C1
+local buf = harfbuzz.Buffer.new()
+buf:add_utf8(text)
+
+-- harfbuzz.shape (Shapes text)
+print("\nShaping '"..text.."' set with Noto Nastaliq Urdu")
+harfbuzz.shape(font, buf, { language = harfbuzz.Language.new("urd"), script = harfbuzz.Script.new("Arab"), direction = harfbuzz.Direction.RTL})
+
+local glyphs = buf:get_glyphs()
+print("No. of glyphs", #glyphs)
+print(serpent.line(glyphs, {comment = false}))
+
+local opts = { language = harfbuzz.Language.new("eng"), script = harfbuzz.Script.new("Latn"), direction = harfbuzz.Direction.LTR }
+local amiri_face = harfbuzz.Face.new('../fonts/amiri-regular.ttf')
+local amiri_font = harfbuzz.Font.new(amiri_face)
+
+-- shaping '123' w/o features
+print("\nShaping '123' set with Amiri Regular and no features")
+buf= harfbuzz.Buffer.new()
+buf:add_utf8("123")
+harfbuzz.shape(amiri_font, buf, opts)
+glyphs = buf:get_glyphs()
+print(serpent.line(glyphs, {comment = false}))
+
+-- shaping '123' with '+numr' (numerators)
+print("\nShaping '123' set with Amiri Regular with 'numr' feature turned on")
+buf= harfbuzz.Buffer.new()
+buf:add_utf8("123")
+opts.features = "+numr"
+harfbuzz.shape(amiri_font, buf, opts)
+glyphs = buf:get_glyphs()
+print(serpent.line(glyphs, {comment = false}))
+
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/AppleGothic_korean_issue_22.json b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/AppleGothic_korean_issue_22.json
new file mode 100644
index 00000000000..2fa441bcd50
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/AppleGothic_korean_issue_22.json
@@ -0,0 +1 @@
+[{"g":2651,"cl":0,"dx":0,"dy":0,"ax":1000,"ay":0},{"g":2942,"cl":1,"dx":0,"dy":0,"ax":1000,"ay":0},{"g":3083,"cl":2,"dx":0,"dy":0,"ax":1000,"ay":0}]
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/amiri-regular_123.json b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/amiri-regular_123.json
new file mode 100644
index 00000000000..b4bc7fb19a2
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/amiri-regular_123.json
@@ -0,0 +1 @@
+[{"g":20,"cl":0,"dx":0,"dy":0,"ax":1090,"ay":0},{"g":21,"cl":1,"dx":0,"dy":0,"ax":1090,"ay":0},{"g":22,"cl":2,"dx":0,"dy":0,"ax":1090,"ay":0}]
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/amiri-regular_123_numr.json b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/amiri-regular_123_numr.json
new file mode 100644
index 00000000000..f5423328096
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/amiri-regular_123_numr.json
@@ -0,0 +1 @@
+[{"g":6673,"cl":0,"dx":0,"dy":0,"ax":600,"ay":0},{"g":6674,"cl":1,"dx":0,"dy":0,"ax":600,"ay":0},{"g":6675,"cl":2,"dx":0,"dy":0,"ax":600,"ay":0}]
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/notonastaliq_U06CC_U06C1.json b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/notonastaliq_U06CC_U06C1.json
new file mode 100644
index 00000000000..218dcb0376b
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fixtures/notonastaliq_U06CC_U06C1.json
@@ -0,0 +1 @@
+[{"g":277,"cl":2,"dx":0,"dy":0,"ax":472,"ay":0,"fl":1},{"g":19,"cl":0,"dx":310,"dy":-383,"ax":0,"ay":0},{"g":985,"cl":0,"dx":0,"dy":0,"ax":0,"ay":0},{"g":316,"cl":0,"dx":0,"dy":-68,"ax":731,"ay":0}]
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/Rajdhani-Regular.ttf b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/Rajdhani-Regular.ttf
new file mode 100755
index 00000000000..4b6ccefe34a
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/Rajdhani-Regular.ttf
Binary files differ
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/TwitterColorEmoji-SVGinOT.ttf b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/TwitterColorEmoji-SVGinOT.ttf
new file mode 100644
index 00000000000..a60d3ff3198
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/TwitterColorEmoji-SVGinOT.ttf
Binary files differ
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/amiri-regular.ttf b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/amiri-regular.ttf
new file mode 100644
index 00000000000..f898e3b2b7f
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/amiri-regular.ttf
Binary files differ
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/amiriquran-colored.ttf b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/amiriquran-colored.ttf
new file mode 100644
index 00000000000..5ebf488bee8
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/amiriquran-colored.ttf
Binary files differ
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/notocoloremoji-subset.ttf b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/notocoloremoji-subset.ttf
new file mode 100644
index 00000000000..875ca15b480
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/notocoloremoji-subset.ttf
Binary files differ
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/notonastaliq.ttf b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/notonastaliq.ttf
new file mode 100644
index 00000000000..891f633d802
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/fonts/notonastaliq.ttf
Binary files differ
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-1.1.0-1.rockspec b/Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-1.1.0-1.rockspec
new file mode 100644
index 00000000000..17a84532b73
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-1.1.0-1.rockspec
@@ -0,0 +1,46 @@
+package = "luaharfbuzz"
+version = "1.1.0-1"
+source = {
+ url = "git://github.com/ufytex/luaharfbuzz",
+ tag = "v1.1.0"
+}
+description = {
+ summary = "Lua bindings for the Harfbuzz text shaping library",
+ homepage = "https://github.com/ufytex/luaharfbuzz",
+ license = "MIT",
+ maintainer = "Deepak Jois <deepak.jois@gmail.com>"
+}
+dependencies = {
+ "lua >= 5.2"
+}
+build = {
+ type = "builtin",
+ modules = {
+ harfbuzz ="src/harfbuzz.lua",
+ luaharfbuzz= {
+ sources = {
+ "src/luaharfbuzz/luaharfbuzz.c",
+ "src/luaharfbuzz/blob.c",
+ "src/luaharfbuzz/face.c",
+ "src/luaharfbuzz/font.c",
+ "src/luaharfbuzz/buffer.c",
+ "src/luaharfbuzz/feature.c",
+ "src/luaharfbuzz/tag.c",
+ "src/luaharfbuzz/ot.c",
+ "src/luaharfbuzz/unicode.c",
+ "src/luaharfbuzz/script.c",
+ "src/luaharfbuzz/direction.c",
+ "src/luaharfbuzz/language.c",
+ "src/luaharfbuzz/class_utils.c"
+ },
+ libraries = {"harfbuzz"},
+ incdirs = {"$(HARFBUZZ_INCDIR)/harfbuzz"},
+ libdirs = {"$(HARFBUZZ_LIBDIR)"}
+ }
+ }
+}
+external_dependencies = {
+ HARFBUZZ = {
+ header = "harfbuzz/hb.h"
+ }
+}
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-scm-1.rockspec b/Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-scm-1.rockspec
new file mode 100644
index 00000000000..31ae2ab4fb7
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-scm-1.rockspec
@@ -0,0 +1,48 @@
+rockspec_format = "3.0"
+package = "luaharfbuzz"
+version = "scm-1"
+source = {
+ url = "git://github.com/ufytex/luaharfbuzz"
+}
+description = {
+ summary = "Lua bindings for the Harfbuzz text shaping library",
+ homepage = "https://github.com/ufytex/luaharfbuzz",
+ license = "MIT",
+ maintainer = "Deepak Jois <deepak.jois@gmail.com>",
+ issues_url = "https://github.com/ufytex/luaharfbuzz/issues",
+ labels = {"unicode", "fonts"}
+}
+dependencies = {
+ "lua >= 5.2"
+}
+build = {
+ type = "builtin",
+ modules = {
+ harfbuzz ="src/harfbuzz.lua",
+ luaharfbuzz= {
+ sources = {
+ "src/luaharfbuzz/luaharfbuzz.c",
+ "src/luaharfbuzz/blob.c",
+ "src/luaharfbuzz/face.c",
+ "src/luaharfbuzz/font.c",
+ "src/luaharfbuzz/buffer.c",
+ "src/luaharfbuzz/feature.c",
+ "src/luaharfbuzz/tag.c",
+ "src/luaharfbuzz/ot.c",
+ "src/luaharfbuzz/unicode.c",
+ "src/luaharfbuzz/script.c",
+ "src/luaharfbuzz/direction.c",
+ "src/luaharfbuzz/language.c",
+ "src/luaharfbuzz/class_utils.c"
+ },
+ libraries = {"harfbuzz"},
+ incdirs = {"$(HARFBUZZ_INCDIR)/harfbuzz"},
+ libdirs = {"$(HARFBUZZ_LIBDIR)"}
+ }
+ }
+}
+external_dependencies = {
+ HARFBUZZ = {
+ header = "harfbuzz/hb.h"
+ }
+}
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/scripts/generate_harfbuzz_api_list.sh b/Build/source/texk/web2c/luatexdir/luaharfbuzz/scripts/generate_harfbuzz_api_list.sh
new file mode 100755
index 00000000000..07d4770b0b6
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/scripts/generate_harfbuzz_api_list.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+grep -e "^hb_" /usr/local/include/harfbuzz/hb*.h | grep "(" | sed -e 's/ .*$//' | awk -F: '{print $2}' | sort > status/full_api.txt
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/scripts/generate_hb_shape_json.sh b/Build/source/texk/web2c/luatexdir/luaharfbuzz/scripts/generate_hb_shape_json.sh
new file mode 100755
index 00000000000..5389845f326
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/scripts/generate_hb_shape_json.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+SHAPER_OPTS="--font-funcs=ot --shapers=ot"
+CLUSTER_OPTS="--utf8-clusters"
+FORMAT_OPTS="--show-flags --no-glyph-names --output-format=json"
+STANDARD_OPTS="$SHAPER_OPTS $CLUSTER_OPTS $FORMAT_OPTS"
+
+hb-shape $STANDARD_OPTS fonts/notonastaliq.ttf "یہ" > fixtures/notonastaliq_U06CC_U06C1.json
+hb-shape $STANDARD_OPTS fonts/amiri-regular.ttf "123" > fixtures/amiri-regular_123.json
+hb-shape $STANDARD_OPTS --features="+numr" fonts/amiri-regular.ttf "123" > fixtures/amiri-regular_123_numr.json
+hb-shape $SHAPER_OPTS $FORMAT_OPTS /Library/Fonts/AppleGothic.ttf "가나다" > fixtures/AppleGothic_korean_issue_22.json
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/buffer_spec.lua b/Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/buffer_spec.lua
new file mode 100644
index 00000000000..503b902c9dc
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/buffer_spec.lua
@@ -0,0 +1,236 @@
+local harfbuzz = require("harfbuzz")
+
+describe("harfbuzz.Buffer", function()
+ it("can be created", function()
+ harfbuzz.Buffer.new()
+ end)
+
+ it("can add a single codepoints with explicit cluster value", function()
+ local b = harfbuzz.Buffer.new()
+ b:add(0x06CC, 42)
+ local glyphs = b:get_glyphs()
+ assert.are_equal(#glyphs, 1)
+ assert.are_equal(glyphs[1].cluster, 42)
+ assert.are_equal(glyphs[1].codepoint, 0x06CC)
+ end)
+
+ it("can add a UTF8 string", function()
+ local b = harfbuzz.Buffer.new()
+ local s = "Some String"
+ b:add_utf8(s)
+ assert.are_equal(string.len(s), b:get_length())
+ end)
+
+ it("can add a UTF 8 string with item_offset", function()
+ local b = harfbuzz.Buffer.new()
+ local s = "Some String"
+ local o = 5
+ b:add_utf8(s,o)
+ assert.are_equal(string.len(s) - o, b:get_length())
+ end)
+
+ it("can add a UTF 8 string with item_length", function()
+ local b = harfbuzz.Buffer.new()
+ local s = "Some String"
+ local o = 5
+ local l = 2
+ b:add_utf8(s,o,l)
+ assert.are_equal(l, b:get_length())
+ end)
+
+ it("can add codepoints", function()
+ local b = harfbuzz.Buffer.new()
+ local s = { 0x06CC, 0x06C1 }
+ b:add_codepoints(s)
+ assert.are_equal(#s, b:get_length())
+ end)
+
+ it("can add codepoints with item_offset", function()
+ local b = harfbuzz.Buffer.new()
+ local s = { 0x06CC, 0x06C1 }
+ local o = 1
+ b:add_codepoints(s,o)
+ assert.are_equal(#s - o, b:get_length())
+ end)
+
+ it("can add codepoints with item_length", function()
+ local b = harfbuzz.Buffer.new()
+ local s = { 0x06CC, 0x06C1 }
+ local o = 1
+ local l = 1
+ b:add_codepoints(s,o,l)
+ assert.are_equal(l, b:get_length())
+ end)
+
+ it("can call guess_segment_properties", function()
+ local b = harfbuzz.Buffer.new()
+ b:add_utf8("Some String")
+ b:guess_segment_properties()
+ end)
+
+ it("can get and set the direction of a buffer", function()
+ local b = harfbuzz.Buffer.new()
+ b:add_utf8("abc")
+ local dir = harfbuzz.Direction.RTL
+ b:set_direction(dir)
+ assert.are_equal(dir, b:get_direction())
+ end)
+
+ it("sets direction to INVALID if direction is invalid", function()
+ local b = harfbuzz.Buffer.new()
+ b:set_direction(harfbuzz.Direction.new("invalid"))
+ assert.are_equal(harfbuzz.Direction.INVALID, b:get_direction())
+ end)
+
+ it("can get the direction correctly", function()
+ local b = harfbuzz.Buffer.new()
+ b:add_utf8("یہ")
+ b:guess_segment_properties()
+ assert.are_equal(harfbuzz.Direction.RTL, b:get_direction())
+ end)
+
+ it("can get and set the language of a buffer", function()
+ local b = harfbuzz.Buffer.new()
+ b:add_utf8("یہ")
+ local urd = harfbuzz.Language.new("urd")
+ b:set_language(urd)
+ assert.are_equal(urd, b:get_language())
+ end)
+
+ it("Sets language to INVALID if language is invalid", function()
+ local b = harfbuzz.Buffer.new()
+ b:set_language(harfbuzz.Language.INVALID)
+ assert.are_equal(harfbuzz.Language.INVALID, b:get_language())
+ end)
+
+ it("can get the language correctly", function()
+ local b = harfbuzz.Buffer.new()
+ b:add_utf8("یہ")
+ b:guess_segment_properties()
+ assert.are_not_equal(harfbuzz.Language.INVALID, b:get_language())
+ end)
+
+ it("can get and set the script of a buffer", function()
+ local b = harfbuzz.Buffer.new()
+ b:add_utf8("abc")
+ b:set_script(harfbuzz.Script.new("latn"))
+ assert.are_equal("Latn", tostring(b:get_script()))
+ end)
+
+ it("returns script as UNKNOWN if script is invalid", function()
+ local b = harfbuzz.Buffer.new()
+ b:set_script(harfbuzz.Script.new("xxx"))
+ assert.are_equal(harfbuzz.Script.UNKNOWN, b:get_script())
+ end)
+
+ it("can get the script correctly", function()
+ local b = harfbuzz.Buffer.new()
+ b:add_utf8("یہ")
+ assert.are_equal(harfbuzz.Script.new(""), b:get_script())
+ b:guess_segment_properties()
+ assert.are_equal(harfbuzz.Script.new("Arab"), b:get_script())
+ end)
+
+ it("can reverse the buffer", function()
+ local face = harfbuzz.Face.new('fonts/notonastaliq.ttf')
+ local font = harfbuzz.Font.new(face)
+ local urdu_text = "یہ" -- U+06CC U+06C1
+ local options = { language = harfbuzz.Language.new("urd"), script = harfbuzz.Script.new("Arab"), direction = harfbuzz.Direction.RTL }
+
+ local buf= harfbuzz.Buffer.new()
+ buf:add_utf8(urdu_text)
+ harfbuzz.shape(font, buf, options)
+ local orig_glyphs = buf:get_glyphs()
+ buf:reverse()
+ local reversed_glyphs = buf:get_glyphs()
+
+ assert.are_equal(#orig_glyphs, #reversed_glyphs)
+
+ for c = 1, #orig_glyphs do
+ local g = orig_glyphs[#orig_glyphs - (c - 1)]
+ local r = reversed_glyphs[c]
+ assert.are_equal(g.codepoint, r.codepoint)
+ assert.are_equal(g.cluster, r.cluster)
+ assert.are_equal(g.x_advance, r.x_advance)
+ assert.are_equal(g.y_advance, r.y_advance)
+ assert.are_equal(g.x_offset, r.x_offset)
+ assert.are_equal(g.y_offset, r.y_offset)
+ end
+
+ end)
+
+ it("can get the length of the buffer", function()
+ local b = harfbuzz.Buffer.new()
+ local s = "some string"
+ b:add_utf8(s)
+ assert.are_equal(string.len(s), b:get_length())
+ end)
+
+ it("can get the cluster level of the buffer", function()
+ local b = harfbuzz.Buffer.new()
+ assert.are_equal(harfbuzz.Buffer.CLUSTER_LEVEL_DEFAULT, b:get_cluster_level())
+ end)
+
+ it("can set the cluster level of the buffer", function()
+ local b = harfbuzz.Buffer.new()
+ b:set_cluster_level(harfbuzz.Buffer.CLUSTER_LEVEL_CHARACTERS)
+ assert.are_equal(harfbuzz.Buffer.CLUSTER_LEVEL_CHARACTERS, b:get_cluster_level())
+ end)
+
+ it("can get the replacement glyph for invisible characters of the buffer", function()
+ local b = harfbuzz.Buffer.new()
+ assert.are_equal(0, b:get_invisible_glyph())
+ end)
+
+ it("can set the replacement glyph for invisible characters of the buffer", function()
+ local b = harfbuzz.Buffer.new()
+ b:set_invisible_glyph(3)
+ assert.are_equal(3, b:get_invisible_glyph())
+ end)
+
+ it("can get the replacement codepoint of the buffer", function()
+ local b = harfbuzz.Buffer.new()
+ assert.are_equal(0xFFFD, b:get_replacement_codepoint())
+ end)
+
+ it("can set the replacement codepoint of the buffer", function()
+ local b = harfbuzz.Buffer.new()
+ b:set_replacement_codepoint(0xFFFF)
+ assert.are_equal(0xFFFF, b:get_replacement_codepoint())
+ b:add_utf8("\xFF")
+ local glyphs = b:get_glyphs()
+ assert.are_equal(1, #glyphs)
+ assert.are_equal(0xFFFF, glyphs[1].codepoint)
+ end)
+
+ it("can get the flags of the buffer", function()
+ local b = harfbuzz.Buffer.new()
+ assert.are_equal(harfbuzz.Buffer.FLAG_DEFAULT, b:get_flags())
+ end)
+
+ it("can set the flags of the buffer", function()
+ local b = harfbuzz.Buffer.new()
+ b:set_flags(harfbuzz.Buffer.FLAG_DEFAULT | harfbuzz.Buffer.FLAG_BOT)
+ assert.are_equal(harfbuzz.Buffer.FLAG_DEFAULT | harfbuzz.Buffer.FLAG_BOT, b:get_flags())
+ end)
+
+ it("can clear the buffer", function()
+ local b = harfbuzz.Buffer.new()
+ b:add_utf8("abc")
+ b:set_flags(harfbuzz.Buffer.FLAG_DEFAULT | harfbuzz.Buffer.FLAG_BOT)
+ b:clear_contents()
+ assert.are_equal(0, b:get_length())
+ assert.are_equal(harfbuzz.Buffer.FLAG_DEFAULT | harfbuzz.Buffer.FLAG_BOT, b:get_flags())
+ end)
+
+ it("can reset the buffer", function()
+ local b = harfbuzz.Buffer.new()
+ b:add_utf8("abc")
+ b:set_flags(harfbuzz.Buffer.FLAG_DEFAULT | harfbuzz.Buffer.FLAG_BOT)
+ b:reset()
+ assert.are_equal(0, b:get_length())
+ assert.are_equal(harfbuzz.Buffer.FLAG_DEFAULT, b:get_flags())
+ end)
+end)
+
+
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/harfbuzz_spec.lua b/Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/harfbuzz_spec.lua
new file mode 100644
index 00000000000..dfae07d8e65
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/harfbuzz_spec.lua
@@ -0,0 +1,541 @@
+local harfbuzz = require("harfbuzz")
+
+describe("harfbuzz module", function()
+
+ it("returns a valid version string", function()
+ assert.are_equal("string", type(harfbuzz.version()))
+ end)
+
+ it("returns a valid list of shapers", function()
+ local shapers = { harfbuzz.shapers }
+ assert.is_not.True(#shapers == 0)
+ end)
+
+ describe("harfbuzz.Blob", function()
+ it("can be initialized with a string", function()
+ local s = "test string"
+ local blob = harfbuzz.Blob.new(s)
+ assert.are_equal(string.len(s), blob:get_length())
+ end)
+ end)
+
+ describe("harfbuzz.Face", function()
+ local face = harfbuzz.Face.new('fonts/notonastaliq.ttf')
+ it("can be initialized with a blob", function()
+ local fontfile = io.open('fonts/notonastaliq.ttf', "r")
+ local fontdata = fontfile:read("*all")
+ fontfile:close()
+
+ local blob = harfbuzz.Blob.new(fontdata)
+ harfbuzz.Face.new_from_blob(blob,0)
+ end)
+
+ it("can be initialized with a file and a font index", function()
+ harfbuzz.Face.new('fonts/notonastaliq.ttf',0)
+ end)
+
+ it("can be initialized with a file only", function()
+ harfbuzz.Face.new('fonts/notonastaliq.ttf')
+ end)
+
+ it("returns a valid upem value", function()
+ assert.are_equal(2048,face:get_upem())
+ end)
+
+ it("can return SFNT table", function()
+ local b = face:get_table(harfbuzz.Tag.new("OS/2"))
+ local d = b:get_data()
+ assert.are_equal(96,b:get_length())
+ assert.are_equal(96,#d)
+ assert.are_equal(4,string.unpack(">H", d, 1))
+ assert.are_equal(1155,string.unpack(">h", d, 3))
+ assert.are_equal(5,string.unpack(">H", d, -2))
+ end)
+
+ it("can return table tags", function()
+ local t = face:get_table_tags()
+ assert.are_equal(14,#t)
+ assert.are_equal("GDEF",tostring(t[1]))
+ assert.are_equal("post",tostring(t[#t]))
+ end)
+
+ it("can return glyph count", function()
+ assert.are_equal(1133,face:get_glyph_count())
+ end)
+
+ it("can return unicode characters supported by face", function()
+ local u = face:collect_unicodes()
+ assert.are_equal(267,#u)
+ assert.are_equal(0x0000,u[1])
+ assert.are_equal(0xFEFF,u[#u])
+ end)
+
+ it("can return face names", function()
+ assert.are_equal("Copyright 2014 Google Inc. All Rights Reserved.",face:get_name(harfbuzz.ot.NAME_ID_COPYRIGHT))
+ assert.are_equal("Noto Nastaliq Urdu",face:get_name(harfbuzz.ot.NAME_ID_FONT_FAMILY))
+ assert.are_equal("Regular",face:get_name(harfbuzz.ot.NAME_ID_FONT_SUBFAMILY))
+ assert.are_equal("Noto Nastaliq Urdu",face:get_name(harfbuzz.ot.NAME_ID_FULL_NAME))
+ assert.are_equal("NotoNastaliqUrdu",face:get_name(harfbuzz.ot.NAME_ID_POSTSCRIPT_NAME))
+ assert.are_equal("Noto is a trademark of Google Inc.",face:get_name(harfbuzz.ot.NAME_ID_TRADEMARK))
+ assert.are_equal(331,#face:get_name(harfbuzz.ot.NAME_ID_LICENSE))
+ assert.are_equal(nil,face:get_name(harfbuzz.ot.NAME_ID_INVALID))
+ end)
+
+ it("can return face names with language", function()
+ local f = harfbuzz.Face.new('fonts/amiri-regular.ttf')
+ local ar = harfbuzz.Language.new("ar")
+ local en = harfbuzz.Language.new("en")
+ assert.are_equal("حقوق النشر 2010-2015، خالد حسني <khaledhosny@eglug.org>.",f:get_name(harfbuzz.ot.NAME_ID_COPYRIGHT, ar))
+ assert.are_equal("Copyright (c) 2010-2015, Khaled Hosny <khaledhosny@eglug.org>.\nPortions copyright (c) 2010, Sebastian Kosch <sebastian@aldusleaf.org>.",f:get_name(harfbuzz.ot.NAME_ID_COPYRIGHT, en))
+ assert.are_equal("عادي",f:get_name(harfbuzz.ot.NAME_ID_FONT_SUBFAMILY, ar))
+ assert.are_equal("Regular",f:get_name(harfbuzz.ot.NAME_ID_FONT_SUBFAMILY, en))
+ assert.are_equal("إصدارة 000٫108",f:get_name(harfbuzz.ot.NAME_ID_VERSION_STRING, ar))
+ assert.are_equal("Version 000.108 ",f:get_name(harfbuzz.ot.NAME_ID_VERSION_STRING, en))
+ assert.are_equal("خالد حسني",f:get_name(harfbuzz.ot.NAME_ID_DESIGNER, ar))
+ assert.are_equal("Khaled Hosny",f:get_name(harfbuzz.ot.NAME_ID_DESIGNER, en))
+ assert.are_equal(512,#f:get_name(harfbuzz.ot.NAME_ID_DESCRIPTION, ar))
+ assert.are_equal(263,#f:get_name(harfbuzz.ot.NAME_ID_DESCRIPTION, en))
+ assert.are_equal("صِفْ خَلْقَ خَوْدٍ كَمِثْلِ ٱلشَّمْسِ إِذْ بَزَغَتْ يَحْظَىٰ ٱلضَّجِيعُ بِهَا نَجْلَاءَ مِعْطَارِ.",f:get_name(harfbuzz.ot.NAME_ID_SAMPLE_TEXT, ar))
+ assert.are_equal("صِفْ خَلْقَ خَوْدٍ كَمِثْلِ ٱلشَّمْسِ إِذْ بَزَغَتْ يَحْظَىٰ ٱلضَّجِيعُ بِهَا نَجْلَاءَ مِعْطَارِ.",f:get_name(harfbuzz.ot.NAME_ID_SAMPLE_TEXT, en))
+ end)
+
+ it("can check color palettes", function()
+ local f = harfbuzz.Face.new('fonts/amiriquran-colored.ttf')
+ assert.are_equal(false,face:ot_color_has_palettes())
+ assert.are_equal(true,f:ot_color_has_palettes())
+ end)
+
+ it("can return number of color palettes", function()
+ local f = harfbuzz.Face.new('fonts/amiriquran-colored.ttf')
+ assert.are_equal(0,face:ot_color_palette_get_count())
+ assert.are_equal(1,f:ot_color_palette_get_count())
+ end)
+
+ it("can return palette colors", function()
+ local f = harfbuzz.Face.new('fonts/amiriquran-colored.ttf')
+ assert.are_equal(nil,face:ot_color_palette_get_colors())
+ local colors = {
+ { alpha = 255, blue = 51, green = 51, red = 204, },
+ { alpha = 255, blue = 80, green = 165, red = 0, },
+ { alpha = 255, blue = 51, green = 153, red = 238, },
+ { alpha = 255, blue = 153, green = 102, red = 51, },
+ }
+ assert.are_same(colors,f:ot_color_palette_get_colors())
+ end)
+
+ it("can check color layers", function()
+ local f = harfbuzz.Face.new('fonts/amiriquran-colored.ttf')
+ assert.are_equal(false,face:ot_color_has_layers())
+ assert.are_equal(true,f:ot_color_has_layers())
+ end)
+
+ it("can return glyph color layers", function()
+ local f = harfbuzz.Face.new('fonts/amiriquran-colored.ttf')
+ assert.are_equal(nil,face:ot_color_glyph_get_layers(100))
+ assert.are_equal(nil,f:ot_color_glyph_get_layers(2))
+ local layers = {
+ { color_index = 65535, glyph = 1341 },
+ { color_index = 1, glyph = 1370 },
+ }
+ assert.are_same(layers,f:ot_color_glyph_get_layers(100))
+ end)
+
+ it("can check PNG glyph support", function()
+ local f = harfbuzz.Face.new('fonts/notocoloremoji-subset.ttf')
+ assert.are_equal(false,face:ot_color_has_png())
+ assert.are_equal(true,f:ot_color_has_png())
+ end)
+
+ it("can check SVG glyph support", function()
+ local f = harfbuzz.Face.new('fonts/TwitterColorEmoji-SVGinOT.ttf')
+ assert.are_equal(false,face:ot_color_has_svg())
+ assert.are_equal(true,f:ot_color_has_svg())
+ end)
+
+ it("can return glyph color png", function()
+ local f = harfbuzz.Face.new('fonts/TwitterColorEmoji-SVGinOT.ttf')
+
+ assert.are_equal(nil,face:ot_color_glyph_get_svg(100))
+ assert.are_equal(nil,f:ot_color_glyph_get_svg(0))
+ assert.are_same(751,f:ot_color_glyph_get_svg(5):get_length())
+ assert.are_same(804,f:ot_color_glyph_get_svg(6):get_length())
+ assert.are_same("<?xml version='1.0' encoding='UTF-8'?>",f:ot_color_glyph_get_svg(5):get_data():sub(1, 38))
+ end)
+
+ it("can return script tags", function()
+ local t
+ local tags = {
+ harfbuzz.Tag.new("arab"),
+ harfbuzz.Tag.new("dflt"),
+ harfbuzz.Tag.new("latn"),
+ }
+ t = face:ot_layout_get_script_tags(harfbuzz.Tag.new("GSUB"))
+ assert.are_same(tags, t)
+ t = face:ot_layout_get_script_tags(harfbuzz.Tag.new("GPOS"))
+ assert.are_same({ tags[1] }, t)
+ end)
+
+ it("can return language tags", function()
+ local t
+ local tags = {
+ harfbuzz.Tag.new("ARA "),
+ harfbuzz.Tag.new("FAR "),
+ harfbuzz.Tag.new("KSH "),
+ harfbuzz.Tag.new("SND "),
+ harfbuzz.Tag.new("URD "),
+ }
+ t = face:ot_layout_get_language_tags(harfbuzz.Tag.new("GSUB"), 0)
+ assert.are_same(tags, t)
+ t = face:ot_layout_get_language_tags(harfbuzz.Tag.new("GPOS"), 0)
+ assert.are_equal(nil, t)
+ end)
+
+ it("can return feature tags", function()
+ local t, tags
+ tags = {
+ harfbuzz.Tag.new("ccmp"),
+ harfbuzz.Tag.new("isol"),
+ harfbuzz.Tag.new("init"),
+ harfbuzz.Tag.new("medi"),
+ harfbuzz.Tag.new("fina"),
+ harfbuzz.Tag.new("rlig"),
+ }
+ t = face:ot_layout_get_feature_tags(harfbuzz.Tag.new("GSUB"), 0, 0)
+ assert.are_same(tags, t)
+ tags = {
+ harfbuzz.Tag.new("curs"),
+ harfbuzz.Tag.new("mark"),
+ harfbuzz.Tag.new("mkmk"),
+ }
+ t = face:ot_layout_get_feature_tags(harfbuzz.Tag.new("GPOS"), 0, harfbuzz.ot.LAYOUT_DEFAULT_LANGUAGE_INDEX)
+ assert.are_same(tags, t)
+ end)
+
+ it("can find scripts, languages and features", function()
+ local r, i
+ r, i = face:ot_layout_find_script(harfbuzz.Tag.new("GSUB"), harfbuzz.Tag.new("latn"))
+ assert.True(r)
+ assert.are_same(2, i)
+ r, i = face:ot_layout_find_language(harfbuzz.Tag.new("GSUB"), i, harfbuzz.Tag.new("ENG "))
+ assert.False(r)
+ assert.are_same(harfbuzz.ot.LAYOUT_DEFAULT_LANGUAGE_INDEX, i)
+ r, i = face:ot_layout_find_language(harfbuzz.Tag.new("GSUB"), 0, harfbuzz.Tag.new("ARA "))
+ assert.True(r)
+ assert.are_same(0, i)
+ r, i = face:ot_layout_find_feature(harfbuzz.Tag.new("GSUB"), 0, i, harfbuzz.Tag.new("rlig"))
+ assert.True(r)
+ assert.are_same(13, i)
+
+ r, i = face:ot_layout_find_feature(harfbuzz.Tag.new("GSUB"), 1, harfbuzz.ot.LAYOUT_DEFAULT_LANGUAGE_INDEX, harfbuzz.Tag.new("rlig"))
+ assert.True(r)
+ assert.are_same(13, i)
+ end)
+ end)
+
+ describe("harfbuzz.Font", function()
+ local face = harfbuzz.Face.new('fonts/notonastaliq.ttf')
+ it("can be initialized with a face", function()
+ harfbuzz.Font.new(face)
+ end)
+
+ it("has a default scale set to the fonts upem", function()
+ local font = harfbuzz.Font.new(face)
+ local upem = face:get_upem()
+ local xs, ys = font:get_scale()
+ assert.are_equal(upem, xs)
+ assert.are_equal(upem, ys)
+ end)
+
+ it("can set the scale of the font using set_scale", function()
+ local font = harfbuzz.Font.new(face)
+ font:set_scale(1024,2048)
+ local xs, ys = font:get_scale()
+ assert.are_equal(1024, xs)
+ assert.are_equal(2048, ys)
+ end)
+
+ it("can get glyph extents using get_glyph_extents", function()
+ local font = harfbuzz.Font.new(face)
+ local extents = font:get_glyph_extents(0)
+ assert.are_equal(145, extents.x_bearing)
+ assert.are_equal(2452, extents.y_bearing)
+ assert.are_equal(1553, extents.width)
+ assert.are_equal(-2452, extents.height)
+ extents = font:get_glyph_extents(1)
+ assert.are_equal(0, extents.x_bearing)
+ assert.are_equal(0, extents.y_bearing)
+ assert.are_equal(0, extents.width)
+ assert.are_equal(0, extents.height)
+ end)
+
+ it("can get font extents", function()
+ local font = harfbuzz.Font.new(face)
+ local extents = font:get_h_extents(0)
+ assert.are_equal(3900, extents.ascender)
+ assert.are_equal(-1220, extents.descender)
+ assert.are_equal(0, extents.line_gap)
+ extents = font:get_v_extents(1)
+ assert.are_equal(nil, extents)
+ end)
+
+ it("can get glyph name using get_glyph_name", function()
+ local font = harfbuzz.Font.new(face)
+ assert.are_equal(".notdef", font:get_glyph_name(0))
+ assert.are_equal("null", font:get_glyph_name(1))
+ end)
+
+ it("can get glyph using get_glyph_from_name", function()
+ local font = harfbuzz.Font.new(face)
+ assert.are_equal(0, font:get_glyph_from_name(".notdef"))
+ assert.are_equal(1, font:get_glyph_from_name("null"))
+ end)
+
+ it("can get glyph advance using get_glyph_h_advance", function()
+ local font = harfbuzz.Font.new(face)
+ assert.are_equal(1843, font:get_glyph_h_advance(0))
+ assert.are_equal(0, font:get_glyph_h_advance(1))
+ end)
+
+ it("can get glyph advance using get_glyph_v_advance", function()
+ local font = harfbuzz.Font.new(face)
+ assert.are_equal(-2048, font:get_glyph_v_advance(0))
+ assert.are_equal(-2048, font:get_glyph_v_advance(1))
+ end)
+
+ it("can get nominal glyph for codepoint", function()
+ local font = harfbuzz.Font.new(face)
+ assert.are_equal(nil, font:get_nominal_glyph(0x0041))
+ assert.are_equal(858, font:get_nominal_glyph(0x0627))
+ end)
+
+ it("can return glyph color png", function()
+ local font = harfbuzz.Font.new(face)
+ local f = harfbuzz.Font.new(harfbuzz.Face.new('fonts/notocoloremoji-subset.ttf'))
+
+ assert.are_equal(nil,font:ot_color_glyph_get_png(100))
+ assert.are_equal(nil,f:ot_color_glyph_get_png(0))
+ assert.are_same(2233,f:ot_color_glyph_get_png(1):get_length())
+ assert.are_same(2857,f:ot_color_glyph_get_png(2):get_length())
+ assert.are_same("\137PNG",f:ot_color_glyph_get_png(2):get_data():sub(1, 4))
+ end)
+ end)
+
+ describe("harfbuzz.Feature", function()
+ it("can be initialised with a valid feature string", function()
+ harfbuzz.Feature.new('kern')
+ harfbuzz.Feature.new('+kern')
+ end)
+
+ it("throws an error when trying to initialise a new Feature with an invalid string", function()
+ assert.are_equal(nil, harfbuzz.Feature.new(''))
+ assert.are_equal(nil, harfbuzz.Feature.new('#kern'))
+ end)
+
+ it("has a valid tostring value", function()
+ local fs = 'kern'
+ local f = harfbuzz.Feature.new(fs)
+ assert.are_equal(fs, tostring(f))
+ end)
+
+ it("has visible fields", function()
+ local f = harfbuzz.Feature.new('-kern')
+ print(getmetatable(f).__index)
+ assert.are_equal(tostring(f.tag), 'kern')
+ assert.are_equal(f.value, 0)
+ assert.are_equal(f.start, nil)
+ assert.are_equal(f._end, nil)
+
+ f = harfbuzz.Feature.new('aalt[3:5]=4')
+ assert.are_equal(tostring(f.tag), 'aalt')
+ assert.are_equal(f.value, 4)
+ assert.are_equal(f.start, 3)
+ assert.are_equal(f._end, 5)
+ end)
+
+ it("has editable fields", function()
+ local f = harfbuzz.Feature.new('-kern')
+ f.tag, f.value, f.start, f._end = harfbuzz.Tag.new"aalt", 4, 3, 5
+ assert.are_equal(tostring(f), "aalt[3:5]=4")
+
+ f.tag, f.value, f.start, f._end = harfbuzz.Tag.new"harf", 0, nil, nil
+ assert.are_equal(tostring(f), "-harf")
+ end)
+ end)
+
+ describe("harfbuzz.Tag", function()
+ it("can be initialised with a valid tag string", function()
+ harfbuzz.Tag.new('Zyyy')
+ end)
+
+ it("can be initialised to NONE with nil or empty argument", function()
+ local t = harfbuzz.Tag.new()
+ assert.are_equal(harfbuzz.Tag.NONE, t)
+ t = harfbuzz.Tag.new(nil)
+ assert.are_equal(harfbuzz.Tag.NONE, t)
+ end)
+
+ it("has a valid tostring value", function()
+ local ts = 'Arab'
+ local t = harfbuzz.Tag.new(ts)
+ assert.are_equal(ts, tostring(t))
+ end)
+
+ it("has a valid equality check functions", function()
+ local ts = 'Arab'
+ local t1 = harfbuzz.Tag.new(ts)
+ local t2 = harfbuzz.Tag.new(ts)
+ local t3 = harfbuzz.Tag.new("Latn")
+ assert.are_equal(t1, t2)
+ assert.are_not_equal(t1, t3)
+ end)
+
+ it("has a preset value for NONE", function()
+ local n = harfbuzz.Tag.NONE
+ assert.is_not_nil(n)
+ assert.are_equal("", tostring(n))
+ assert.are_equal(harfbuzz.Tag.NONE, harfbuzz.Tag.new(""))
+ end)
+ end)
+
+ describe("harfbuzz.Script", function()
+ it("can be initialised with a string", function()
+ harfbuzz.Script.new('Arab')
+ end)
+
+ it("can be initialised to INVALID with nil or empty argument", function()
+ local t = harfbuzz.Script.new()
+ assert.are_equal(harfbuzz.Script.INVALID, t)
+ t = harfbuzz.Script.new(nil)
+ assert.are_equal(harfbuzz.Script.INVALID, t)
+ end)
+
+ it("can be initialised with a tag", function()
+ local ts = "Arab"
+ local s = harfbuzz.Script.from_iso15924_tag(harfbuzz.Tag.new(ts))
+ assert.are_equal(ts, tostring(s))
+ end)
+
+ it("can be converted to a tag", function()
+ local s = 'Arab'
+ local sc = harfbuzz.Script.new(s)
+ assert.are_equal(s, tostring(sc:to_iso15924_tag()))
+ end)
+
+ it("has a valid tostring value", function()
+ local ts = 'Arab'
+ local t = harfbuzz.Script.new(ts)
+ assert.are_equal(ts, tostring(t))
+ end)
+
+ it("has a valid equality check functions", function()
+ local ts = 'Arab'
+ local t1 = harfbuzz.Script.new(ts)
+ local t2 = harfbuzz.Script.new(ts)
+ local t3 = harfbuzz.Script.new("Latn")
+ assert.are_equal(t1, t2)
+ assert.are_not_equal(t1, t3)
+ end)
+ end)
+
+ describe("harfbuzz.Direction", function()
+ it("can be initialised with a valid tag string", function()
+ harfbuzz.Direction.new('LTR')
+ end)
+
+ it("can be initialised with invalid strings", function()
+ local d1 = harfbuzz.Direction.new("i")
+ local d2 = harfbuzz.Direction.new("inv")
+
+ assert.are_equal(d1, d2)
+ assert.are_equal("invalid", tostring(d1))
+ end)
+
+ it("has a valid tostring value", function()
+ local ts = 'ltr'
+ local t = harfbuzz.Direction.new(ts)
+ assert.are_equal(ts, tostring(t))
+
+ t = harfbuzz.Direction.new("LTR")
+ assert.are_equal(ts, tostring(t))
+ end)
+
+ it("has a valid equality check functions", function()
+ local ts = 'ltr'
+ local t1 = harfbuzz.Direction.new(ts)
+ local t2 = harfbuzz.Direction.new(ts)
+ local t3 = harfbuzz.Direction.new("rtl")
+ assert.are_equal(t1, t2)
+ assert.are_not_equal(t1, t3)
+ end)
+
+ it("has a is_valid function", function()
+ assert.True(harfbuzz.Direction.LTR:is_valid())
+ assert.False(harfbuzz.Direction.INVALID:is_valid())
+ end)
+
+ it("has a is_horizontal function", function()
+ assert.True(harfbuzz.Direction.LTR:is_horizontal())
+ assert.False(harfbuzz.Direction.TTB:is_horizontal())
+ end)
+
+ it("has a is_vertical function", function()
+ assert.True(harfbuzz.Direction.TTB:is_vertical())
+ assert.False(harfbuzz.Direction.LTR:is_vertical())
+ end)
+
+ it("has a is_forward function", function()
+ assert.True(harfbuzz.Direction.LTR:is_forward())
+ assert.False(harfbuzz.Direction.RTL:is_forward())
+ end)
+
+ it("has a is_backward function", function()
+ assert.True(harfbuzz.Direction.RTL:is_backward())
+ assert.False(harfbuzz.Direction.LTR:is_backward())
+ end)
+ end)
+
+ describe("harfbuzz.Language", function()
+ it("can be initialised with a valid language string", function()
+ harfbuzz.Language.new('urd')
+ end)
+
+ it("can be initialised to INVALID with nil or empty argument", function()
+ local t = harfbuzz.Language.new()
+ assert.are_equal(harfbuzz.Language.INVALID, t)
+ t = harfbuzz.Language.new(nil)
+ assert.are_equal(harfbuzz.Language.INVALID, t)
+ end)
+
+ it("has a valid tostring value", function()
+ local ts = 'urd'
+ local t = harfbuzz.Language.new(ts)
+ assert.are_equal(ts, tostring(t))
+ end)
+
+ it("has a valid equality check functions", function()
+ local ts = 'urd'
+ local t1 = harfbuzz.Language.new(ts)
+ local t2 = harfbuzz.Language.new(ts)
+ local t3 = harfbuzz.Language.new("hin")
+ assert.are_equal(t1, t2)
+ assert.are_not_equal(t1, t3)
+ end)
+
+ it("has a preset value for INVALID", function()
+ local n = harfbuzz.Language.INVALID
+ assert.is_not_nil(n)
+ assert.are_equal(harfbuzz.Language.INVALID, harfbuzz.Language.new())
+ assert.are_equal("", tostring(n))
+ end)
+ end)
+
+ describe("harfbuzz.unicode", function()
+ describe("script function returns a valid script for a codepoint",function()
+ local s = harfbuzz.unicode.script(0x0020)
+ assert.are_equal(harfbuzz.Script.COMMON, s)
+ s = harfbuzz.unicode.script(0x0041)
+ assert.are_equal(harfbuzz.Script.new("Latn"), s)
+ end)
+ end)
+end)
+
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/shaping_spec.lua b/Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/shaping_spec.lua
new file mode 100644
index 00000000000..8ab810e3da4
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/shaping_spec.lua
@@ -0,0 +1,157 @@
+local harfbuzz = require("harfbuzz")
+
+local compare_glyphs_against_fixture = function(glyphs, fixture)
+ local json = require('dkjson')
+ local f = io.open("fixtures/"..fixture)
+ local s = f:read("*all")
+ f:close()
+ local hb_shape_glyphs = json.decode(s)
+ assert.are_equal(#hb_shape_glyphs, #glyphs)
+ for c = 1, #glyphs do
+ local g = glyphs[c]
+ local h = hb_shape_glyphs[c]
+ assert.are_equal(h.g, g.codepoint)
+ assert.are_equal(h.cl, g.cluster)
+ assert.are_equal(h.ax, g.x_advance)
+ assert.are_equal(h.ay, g.y_advance)
+ assert.are_equal(h.dx, g.x_offset)
+ assert.are_equal(h.dy, g.y_offset)
+ assert.are_equal(h.fl, g.flags)
+ end
+end
+
+
+describe("harfbuzz module shaping functions", function()
+ local face = harfbuzz.Face.new('fonts/notonastaliq.ttf')
+ local font = harfbuzz.Font.new(face)
+ local urdu_text = "یہ" -- U+06CC U+06C1
+
+ it("can take a buffer and font and shape it, with output matching hb-shape", function()
+ local buf = harfbuzz.Buffer.new()
+ buf:add_utf8(urdu_text)
+
+ harfbuzz.shape(font, buf)
+ local glyphs = buf:get_glyphs()
+ assert.True(#glyphs > 0)
+
+ -- Compare against output of hb-shape
+ compare_glyphs_against_fixture(glyphs, 'notonastaliq_U06CC_U06C1.json')
+ end)
+
+ it("can take a buffer, font and an options table with script, language and direction settings.", function()
+ local buf = harfbuzz.Buffer.new()
+ buf:add_utf8(urdu_text)
+
+ harfbuzz.shape(font, buf, { language = harfbuzz.Language.new("urd"), script = harfbuzz.Script.new("Arab"), direction = harfbuzz.Direction.HB_DIRECTION_RTL })
+ local glyphs = buf:get_glyphs()
+ assert.True(#glyphs > 0)
+
+ -- Compare against output of hb-shape
+ compare_glyphs_against_fixture(glyphs, 'notonastaliq_U06CC_U06C1.json')
+ end)
+
+ it("can take codepoints, font and an options table with script, language and direction settings. #mac", function()
+ local buf = harfbuzz.Buffer.new()
+ local korean_text = { 0xAC00, 0xB098, 0xB2E4 }
+ buf:add_codepoints(korean_text)
+
+ local face_korean = harfbuzz.Face.new('/Library/Fonts/AppleGothic.ttf')
+ local font_korean = harfbuzz.Font.new(face_korean)
+
+ harfbuzz.shape(font_korean, buf, { language = harfbuzz.Language.new("KOR"), script = harfbuzz.Script.new("hang"), direction = harfbuzz.Direction.HB_DIRECTION_LTR })
+ local glyphs = buf:get_glyphs()
+ assert.True(#glyphs > 0)
+
+ -- Compare against output of hb-shape
+ compare_glyphs_against_fixture(glyphs, 'AppleGothic_korean_issue_22.json')
+ end)
+
+ it("can take a string containing a comma-delimited list of valid features", function()
+ local buf = harfbuzz.Buffer.new()
+ buf:add_utf8(urdu_text)
+
+ harfbuzz.shape(font, buf, { language = harfbuzz.Language.new("urd"), script = harfbuzz.Script.new("Arab"), direction = harfbuzz.Direction.HB_DIRECTION_RTL, features = "+kern,smcp" })
+ local glyphs = buf:get_glyphs()
+ assert.True(#glyphs > 0)
+ end)
+
+ describe("features option", function()
+ local buf
+ local options
+
+ before_each(function()
+ buf= harfbuzz.Buffer.new()
+ buf:add_utf8(urdu_text)
+ options = { language = harfbuzz.Language.new("urd"), script = harfbuzz.Script.new("Arab"), direction = harfbuzz.Direction.HB_DIRECTION_RTL }
+ end)
+
+ it("can take a table containing a valid features", function()
+ options.features = {
+ harfbuzz.Feature.new('+kern'),
+ harfbuzz.Feature.new('smcp')
+ }
+
+ harfbuzz.shape(font, buf, options)
+ local glyphs = buf:get_glyphs()
+ assert.True(#glyphs > 0)
+ end)
+
+ it("throws an error if feature string is invalid", function()
+ options.features = "#kern"
+ assert.has_error(function()
+ harfbuzz.shape(font, buf, options)
+ end, "Invalid feature string: '#kern'")
+ end)
+
+ it("throws an error if feature option is not a table or string", function()
+ options.features = 25
+ assert.has_error(function()
+ harfbuzz.shape(font, buf, options)
+ end, "Invalid features option")
+ end)
+
+ it("throws an error if features table does not contain a feature", function()
+ options.features = {
+ harfbuzz.Feature.new('+kern'),
+ 25,
+ harfbuzz.Feature.new('smcp')
+ }
+ assert.has_error(function()
+ harfbuzz.shape(font, buf, options)
+ end, "bad argument #-1 to 'shape_full' (harfbuzz.Feature expected, got number)")
+ end)
+
+ it("shapes a string appropriately with the features turned on",function()
+ buf= harfbuzz.Buffer.new()
+ buf:add_utf8("123")
+ local opts = { language = harfbuzz.Language.new("eng"), script = harfbuzz.Script.new("Latn"), direction = harfbuzz.Direction.HB_DIRECTION_LTR }
+ local amiri_face = harfbuzz.Face.new('fonts/amiri-regular.ttf')
+ local amiri_font = harfbuzz.Font.new(amiri_face)
+
+ -- Check normal shaping w/o features
+ buf= harfbuzz.Buffer.new()
+ buf:add_utf8("123")
+
+ harfbuzz.shape(amiri_font, buf, opts)
+ local glyphs = buf:get_glyphs()
+ compare_glyphs_against_fixture(glyphs, "amiri-regular_123.json")
+
+ -- Check shaping with '+numr'
+ buf= harfbuzz.Buffer.new()
+ buf:add_utf8("123")
+ opts.features = "+numr"
+ harfbuzz.shape(amiri_font, buf, opts)
+ glyphs = buf:get_glyphs()
+ compare_glyphs_against_fixture(glyphs, "amiri-regular_123_numr.json")
+ end)
+
+ it("can set specefic shaper",function()
+ options.shapers = { "fallback"}
+ harfbuzz.shape(font, buf, options)
+ local glyphs = buf:get_glyphs()
+ assert.are_equal(2, #glyphs)
+ assert.are_equal(906, glyphs[1].codepoint)
+ assert.are_equal(909, glyphs[2].codepoint)
+ end)
+ end)
+end)
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/harfbuzz.lua b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/harfbuzz.lua
new file mode 100644
index 00000000000..b7b0d7ff88c
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/harfbuzz.lua
@@ -0,0 +1,84 @@
+local hb = require("luaharfbuzz")
+
+-- special tags
+hb.Tag.NONE = hb.Tag.new()
+
+-- special script codes (ISO 15924)
+hb.Script.COMMON = hb.Script.new("Zyyy")
+hb.Script.INHERITED = hb.Script.new("Zinh")
+hb.Script.UNKNOWN = hb.Script.new("Zzzz")
+hb.Script.INVALID = hb.Script.from_iso15924_tag(hb.Tag.NONE)
+
+-- directions
+hb.Direction.INVALID = hb.Direction.new("invalid")
+hb.Direction.LTR = hb.Direction.new("ltr")
+hb.Direction.RTL = hb.Direction.new("rtl")
+hb.Direction.TTB = hb.Direction.new("ttb")
+hb.Direction.BTT = hb.Direction.new("btt")
+
+-- special languages
+hb.Language.INVALID = hb.Language.new()
+
+hb.shape = function(font, buf, options)
+ options = options or { }
+
+ -- Apply options to buffer if they are set.
+ if options.language then buf:set_language(options.language) end
+ if options.script then buf:set_script(options.script) end
+ if options.direction then buf:set_direction(options.direction) end
+
+ -- Guess segment properties, in case all steps above have failed
+ -- to set the right properties.
+ buf:guess_segment_properties()
+
+ local features = {}
+
+ -- Parse features
+ if type(options.features) == "string" then
+ for fs in string.gmatch(options.features, '([^,]+)') do
+ local feature = hb.Feature.new(fs)
+ if feature then
+ table.insert(features, hb.Feature.new(fs))
+ else
+ error(string.format("Invalid feature string: '%s'", fs))
+ end
+ end
+ elseif type(options.features) == "table" then
+ features = options.features
+ elseif options.features then -- non-nil but not a string or table
+ error("Invalid features option")
+ end
+
+ return hb.shape_full(font,buf,features,options.shapers or {})
+end
+
+-- For backward compatibility
+hb.Buffer.HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES = hb.Buffer.CLUSTER_LEVEL_MONOTONE_GRAPHEMES
+hb.Buffer.HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS = hb.Buffer.CLUSTER_LEVEL_MONOTONE_CHARACTERS
+hb.Buffer.HB_BUFFER_CLUSTER_LEVEL_CHARACTERS = hb.Buffer.CLUSTER_LEVEL_CHARACTERS
+hb.Buffer.HB_BUFFER_CLUSTER_LEVEL_DEFAULT = hb.Buffer.CLUSTER_LEVEL_DEFAULT
+
+hb.Tag.HB_TAG_NONE = hb.Tag.NONE
+
+hb.Script.HB_SCRIPT_COMMON = hb.Script.COMMON
+hb.Script.HB_SCRIPT_INHERITED = hb.Script.INHERITED
+hb.Script.HB_SCRIPT_UNKNOWN = hb.Script.UNKNOWN
+hb.Script.HB_SCRIPT_INVALID = hb.Script.INVALID
+
+hb.Language.HB_LANGUAGE_INVALID = hb.Language.INVALID
+
+hb.Direction.HB_DIRECTION_INVALID = hb.Direction.INVALID
+hb.Direction.HB_DIRECTION_LTR = hb.Direction.LTR
+hb.Direction.HB_DIRECTION_RTL = hb.Direction.RTL
+hb.Direction.HB_DIRECTION_TTB = hb.Direction.TTB
+hb.Direction.HB_DIRECTION_BTT = hb.Direction.BTT
+
+hb.Direction.HB_DIRECTION_IS_VALID = hb.Direction.is_valid
+hb.Direction.HB_DIRECTION_IS_HORIZONTAL = hb.Direction.is_horizontal
+hb.Direction.HB_DIRECTION_IS_VERTICAL = hb.Direction.is_vertical
+hb.Direction.HB_DIRECTION_IS_FORWARD = hb.Direction.is_forward
+hb.Direction.HB_DIRECTION_IS_BACKWARD = hb.Direction.is_backward
+
+hb.Buffer.get_glyph_infos_and_positions = hb.Buffer.get_glyphs
+
+return hb
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/harfbuzz.luadoc b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/harfbuzz.luadoc
new file mode 100644
index 00000000000..3a30a03c904
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/harfbuzz.luadoc
@@ -0,0 +1,535 @@
+-----------
+-- Lua bindings to Harfbuzz.
+-- * [Wiki](http://github.com/ufytex/luaharfbuzz/wiki)
+-- * [Source on Github](https://github.com/ufytex/luaharfbuzz)
+-- * [API Coverage Status](https://github.com/ufytex/luaharfbuzz/blob/master/status/done.txt)
+--
+-- @author Deepak Jois <<deepak.jois@gmail.com>>
+-- @copyright 2016
+-- @license MIT
+-- @module harfbuzz
+
+--- Wraps `hb_version`
+-- @function version
+
+--- Wraps `hb_shape`.
+-- @param font `Font` to use for shaping
+--
+-- @param buffer `Buffer` to shape
+--
+-- @param[opt] options table containing one or more supported options:
+--
+-- * `direction`: A `Direction` object representing the object.
+-- * `script`: A `Script` object representing the script.
+-- * `language`: A `Language` object representing the language.
+-- * `features`: features to enable, specified as either of the following.
+-- - comma-separated list of features. See [feature string syntax reference](https://github.com/ufytex/luaharfbuzz/wiki/Feature-Strings)
+-- - table of `Feature` objects
+-- @function shape
+
+--- Lua wrapper for `hb_blob_t` type
+-- @type Blob
+
+--- Wraps `hb_blob_create`.
+-- Initializes a new `hb_blob_t`.
+-- @param data lua string containing binary or character data.
+-- @function Blob.new
+
+--- Wraps `hb_blob_create_from_file`.
+-- Initializes a new `hb_blob_t`.
+-- @param filename lua string.
+-- @function Blob.new_from_file
+
+--- Wraps `hb_blob_get_length`.
+-- @function Blob:get_length
+
+--- Wraps `hb_blob_get_data`.
+-- @function Blob:get_data
+
+--- Lua wrapper for `hb_face_t` type
+-- @type Face
+
+--- Wraps `hb_face_create`.
+-- Initializes a new `hb_face_t` from a `Blob` object.
+-- @param blob `Blob` to read the font from.
+-- @param[opt=0] font_index index of font to read.
+-- @function Face.new_from_blob
+
+--- Create a new `Face` from a file.
+-- Makes a call to `Face:new_from_blob` after creating a `Blob` from the
+-- file contents.
+-- @param file path to font file.
+-- @param[opt=0] font_index index of font to read.
+-- @function Face.new
+
+--- Wraps `hb_face_collect_unicodes`.
+-- @return table of codepoints supported by the face.
+-- @function Face:collect_unicodes
+
+--- Wraps `hb_face_get_glyph_count`.
+-- @function Face:get_glyph_count
+
+--- Wraps `hb_face_reference_table`.
+-- @param tag `Tag` object of the table.
+-- @return `Blob` object for the face table of `tag`.
+-- @function Face:get_table
+
+--- Wraps `hb_face_get_table_tags`.
+-- @return table of `Tag`s representing face table tags.
+-- @function Face:get_table_tags
+
+--- Wraps `hb_face_get_upem`.
+-- @function Face:get_upem
+
+--- Wraps `hb_ot_color_has_palettes`.
+-- @function Face:ot_color_has_palettes
+
+--- Wraps `hb_ot_color_palette_get_count`.
+-- @function Face:ot_color_palette_get_count
+
+--- Wraps `hb_ot_color_palette_get_colors`.
+-- @function Face:ot_color_palette_get_colors
+
+--- Wraps `hb_ot_color_has_layers`.
+-- @function Face:ot_color_has_layers
+
+--- Wraps `hb_ot_color_glyph_get_layers`.
+-- @function Face:ot_color_glyph_get_layers
+
+--- Wraps `hb_ot_color_has_png`.
+-- @function Face:ot_color_has_png
+
+--- Wraps `hb_ot_layout_table_get_script_tags`.
+-- @function Face:ot_layout_get_script_tags
+
+--- Wraps `hb_ot_layout_script_get_language_tags`.
+-- @function Face:ot_layout_get_language_tags
+
+--- Wraps `hb_ot_layout_language_get_feature_tags`.
+-- @function Face:ot_layout_get_feature_tags
+
+--- Wraps `hb_ot_layout_table_find_script`.
+-- @function Face:ot_layout_find_script
+
+--- Wraps `hb_ot_layout_script_find_language`.
+-- @function Face:ot_layout_find_language
+
+--- Wraps `hb_ot_layout_language_find_feature`.
+-- @function Face:ot_layout_find_feature
+
+
+--- Lua wrapper for `hb_font_t` type
+-- @type Font
+
+--- Wraps `hb_font_create`, and sets up some defaults for scale and shaping functions.
+-- Initializes a new `hb_font_t` from a `Face` object. Sets the default scale
+-- to the face’s upem value, and sets the font shaping functions by
+-- calling `hb_ot_font_set_funcs` on it.
+-- @param face `Face` object.
+-- @function Font.new
+
+--- Wraps `hb_font_get_scale`.
+-- @return two values for the x-scale and y-scale of the font.
+-- @function Font:get_scale
+
+--- Wraps `hb_font_set_scale`.
+-- @param x_scale desired x-scale of font.
+-- @param y_scale desired y-scale of font.
+-- @function Font:set_scale
+
+--- Wraps `hb_font_get_h_extents`.
+-- @return font extents table for horizontal direction, contains the following
+-- or `nil` if HarfBuzz fails to load font extents:
+--
+-- * `ascender`: typographic ascender.
+-- * `descender`: typographic descender.
+-- * `line_gap`: line spacing gap.
+-- @function Font:get_h_extents
+
+--- Wraps `hb_font_get_v_extents`.
+-- @return font extents table for vertical direction, similar to
+-- `Font:get_h_extents`, or `nil` if HarfBuzz fails to load font extents:
+-- @function Font:get_v_extents
+
+--- Wraps `hb_font_get_glyph_extents`.
+-- @param glyph index inside the font.
+-- @return extents table contains the following or `nil` if HarfBuzz fails to
+-- load glyph extents:
+--
+-- * `x_bearing`: left side of glyph from origin.
+-- * `y_bearing`: top side of glyph from origin.
+-- * `width`: distance from left to right side.
+-- * `height`: distance from top to bottom side.
+-- @function Font:get_glyph_extents
+
+--- Wraps `hb_font_get_glyph_name`.
+-- @param glyph index inside the font.
+-- @return name of the glyph or nil.
+-- @function Font:get_glyph_name
+
+--- Wraps `hb_font_get_glyph_from_name`.
+-- @param name of the glyph.
+-- @return glyph index inside the font or nil.
+-- @function Font:get_glyph_from_name
+
+--- Wraps `hb_font_get_glyph_h_advance`.
+-- @param glyph index inside the font.
+-- @return advance glyph advance of the glyph in horizontal direction.
+-- @function Font:get_glyph_h_advance
+
+--- Wraps `hb_font_get_glyph_v_advance`.
+-- @param glyph index inside the font.
+-- @return advance glyph advance of the glyph in vertical direction.
+-- @function Font:get_glyph_v_advance
+
+--- Wraps `hb_font_get_nominal_glyph`.
+-- @param codepoint.
+-- @return glyph index or `nil` if `codepoint` is not supported by the font.
+-- @function Font:get_nominal_glyph
+
+--- Wraps `hb_ot_color_glyph_get_png`.
+-- @function Font:ot_color_glyph_get_png
+
+--- Lua wrapper for `hb_buffer_t` type.
+-- @type Buffer
+
+--- Wraps `hb_buffer_create`.
+-- @function Buffer.new
+
+--- Wraps `hb_buffer_add_utf8`.
+-- @param text UTF8 encoded string.
+-- @param[opt=0] item_offset 0-indexed offset in `text`, from where to start adding.
+-- @param[opt=-1] item_length length to add from `item_offset`. `-1` adds till end of `text`.
+-- @function Buffer:add_utf8
+
+--- Wraps `hb_buffer_add_codepoints`.
+-- @param text table with codepoints as lua numbers.
+-- @param[opt=0] item_offset 0-indexed offset in `text`, from where to start adding.
+-- @param[opt=-1] item_length length to add from `item_offset`. `-1` adds till end of&nbsp;`text`.
+-- @function Buffer:add_codepoints
+
+--- Wraps `hb_buffer_set_direction`.
+-- @param dir A `Direction` object.
+-- @function Buffer:set_direction
+
+--- Wraps `hb_buffer_get_direction`.
+-- @return A `Direction` object.
+-- @function Buffer:get_direction
+
+--- Wraps `hb_buffer_set_script`.
+-- @param script A `Script` object.
+-- @function Buffer:set_script
+
+--- Wraps `hb_buffer_get_script`.
+-- @return A `Script` object.
+-- @function Buffer:get_script
+
+--- Wraps `hb_buffer_set_language`.
+-- @param lang A `Language` object
+-- @function Buffer:set_language
+
+--- Wraps `hb_buffer_get_language`.
+-- @return A `Language` object
+-- @function Buffer:get_language
+
+--- Wraps `hb_buffer_reverse`.
+-- @function Buffer:reverse
+
+--- Wraps `hb_buffer_get_length`.
+-- @function Buffer:get_length
+
+--- Wraps `hb_buffer_get_cluster_level`.
+-- @return see [Cluster Levels](#Cluster_Levels)
+-- @function Buffer:get_cluster_level
+
+--- Wraps `hb_buffer_set_cluster_level`.
+-- @param level see [Cluster Levels](#Cluster_Levels)
+-- @function Buffer:set_cluster_level
+
+--- Wraps `hb_buffer_guess_segment_properties`.
+-- @function Buffer:guess_segment_properties
+
+--- Helper method to get shaped glyph data.
+-- Calls `hb_buffer_get_glyph_infos`, `hb_buffer_get_glyph_positions` and
+-- `hb_glyph_info_get_glyph_flags`, and assembles the data into a Lua table.
+-- @return table containing data for each glyph, in a nested table. Each nested
+-- table contains the following:
+--
+-- * `x_advance`: horizontal advance.
+-- * `y_advance`: vertical advance.
+-- * `x_offset`: horizontal displacement.
+-- * `y_offset`: vertical displacement.
+-- * `cluster`: glyph cluster index within input.
+-- * `codepoint`: glyph index inside the font _(this field name is a bit misleading, but that’s what Harfbuzz uses)_.
+-- * `flags`: glyph flags
+-- @function Buffer:get_glyphs
+
+--- Cluster Levels.
+-- See [Harfbuzz docs](http://behdad.github.io/harfbuzz/clusters.html) for more details
+-- about what each of these levels mean.
+-- @section
+
+--- Wraps `HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES`.
+-- @field Buffer.CLUSTER_LEVEL_MONOTONE_GRAPHEMES
+
+--- Wraps `HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS`.
+-- @field Buffer.CLUSTER_LEVEL_MONOTONE_CHARACTERS
+
+--- Wraps `HB_BUFFER_CLUSTER_LEVEL_CHARACTERS`.
+-- @field Buffer.CLUSTER_LEVEL_CHARACTERS
+
+--- Wraps `HB_BUFFER_CLUSTER_LEVEL_DEFAULT`.
+-- @field Buffer.CLUSTER_LEVEL_DEFAULT
+
+--- Wraps `HB_GLYPH_FLAG_UNSAFE_TO_BREAK`.
+-- @field Buffer.GLYPH_FLAG_UNSAFE_TO_BREAK
+
+--- Wraps `HB_GLYPH_FLAG_DEFINED`.
+-- @field Buffer.GLYPH_FLAG_DEFINED
+
+--- Lua wrapper for `hb_feature_t` type
+-- @type Feature
+
+--- Wraps `hb_feature_from_string`
+-- @param feature_string See [feature string syntax reference](https://github.com/ufytex/luaharfbuzz/wiki/Feature-Strings)
+-- @function Feature.new
+
+--- Wraps `hb_feature_to_string`.
+-- Enables nice output with `tostring(…)`.
+-- @function Feature:__tostring
+
+--- Lua wrapper for `hb_tag_t` type.
+-- @type Tag
+
+--- Wraps `hb_tag_from_string`.
+-- @param string to be converted to a `Tag` object.
+-- @return a `Tag` object.
+-- @function Tag.new
+
+--- Wraps `hb_tag_to_string`. Enable nice output with `tostring(…)`.
+-- @return Returns a string representation for the tag object.
+-- @function Tag:__to_string
+
+--- Enables equality comparisions with `==` between two tags.
+-- @return `true` or `false` depending on whether the two tags are equal.
+-- @function Tag:__eq
+
+
+--- Lua wrapper for `hb_script_t` type.
+-- @type Script
+
+--- Wraps `hb_script_from_string`.
+-- @param script 4-letter script code according to the [ISO 15924 standard](http://www.unicode.org/iso15924/iso15924-num.html).
+-- @return a `Script` object.
+-- @function Script.new
+
+--- Wraps `hb_script_from_iso15924_tag`
+-- @param tag a `Tag` object representing a [ISO 15924 script](http://www.unicode.org/iso15924/iso15924-num.html).
+-- @function Script.from_iso15924_tag
+
+--- Wraps `hb_script_to_iso15924_tag`.
+-- @return a `Tag` object representing the script.
+-- @function Script:to_iso15924_tag
+
+--- Enable nice output with `tostring(…)`
+-- @return Returns a 4-letter [ISO 15924 script code](http://www.unicode.org/iso15924/iso15924-num.html) for the script object.
+-- @function Script:__to_string
+
+--- Enables equality comparisions with `==` between two scripts.
+-- @return `true` or `false` depending on whether the two scripts are equal.
+-- @function Script:__eq
+
+--- Predefined Script Codes.
+-- Predefined directions that correspond to their original definitions in Harfbuzz.
+-- @section
+
+--- Wraps `HB_SCRIPT_COMMON`.
+-- @field Script.COMMON
+
+--- Wraps `HB_SCRIPT_INHERITED`.
+-- @field Script.INHERITED
+
+--- Wraps `HB_SCRIPT_UNKNOWN`.
+-- @field Script.UNKNOWN
+
+--- Wraps `HB_SCRIPT_INVALID`.
+-- @field Script.INVALID
+
+--- Lua wrapper for `hb_direction_t` type.
+-- @type Direction
+
+--- Wraps `hb_direction_from_string`.
+-- @param dir can be one of `ltr`, `rtl`, `ttb`, `btt` or `invalid`.
+-- @return a `Direction` object.
+-- @function Direction.new
+
+--- Wraps `hb_direction_to_string`. Enable nice output with `tostring(…)`.
+-- @return Returns a string representation for direction.
+-- @function Direction:__to_string
+
+--- Enables equality comparisions with `==` between two directions.
+-- @return `true` or `false` depending on whether the two tags are equal.
+-- @function Direction:__eq
+
+--- Wraps `HB_DIRECTION_IS_VALID`.
+-- @return a boolean value
+-- @function Direction:is_valid
+
+--- Wraps `HB_DIRECTION_IS_HORIZONTAL`.
+-- @return a boolean value
+-- @function Direction:is_horizontal
+
+--- Wraps `HB_DIRECTION_IS_VERTICAL`.
+-- @return a boolean value
+-- @function Direction:is_vertical
+
+--- Wraps `HB_DIRECTION_IS_FORWARD`.
+-- @return a boolean value
+-- @function Direction:is_forward
+
+--- Wraps `HB_DIRECTION_IS_BACKWARD`.
+-- @return a boolean value
+-- @function Direction:is_backward
+
+--- Predefined directions.
+-- Predefined directions that correspond to their original definitions in Harfbuzz.
+-- @section
+
+--- Wraps `HB_DIRECTION_LTR`.
+-- @field Direction.LTR
+
+--- Wraps `HB_DIRECTION_RTL`.
+-- @field Direction.RTL
+
+--- Wraps `HB_DIRECTION_TTB`.
+-- @field Direction.TTB
+
+--- Wraps `HB_DIRECTION_LTR`.
+-- @field Direction.BTT
+
+--- Lua wrapper for `hb_language_t` type.
+-- @type Language
+
+--- Wraps `hb_language_from_string`.
+-- @param lang [three-letter language tag](http://www.microsoft.com/typography/otspec/languagetags.htm) to be converted to a `Language` object.
+-- @return a `Language` object.
+-- @function Language.new
+
+--- Wraps `hb_language_to_string`. Enable nice output with `tostring(…)`.
+-- @return Returns a string representation for the language object.
+-- @function Language:__to_string
+
+--- Enables equality comparisions with `==` between two languages.
+-- @return `true` or `false` depending on whether the two languages are equal.
+-- @function Language:__eq
+
+--- Predefined languages.
+-- Predefined languages that correspond to their original definitions in Harfbuzz.
+-- @section
+
+--- Wraps `HB_LANGUAGE_INVALID`.
+-- @field Language.INVALID
+
+
+--- Unicode functions.
+-- @section
+
+--- Wraps `hb_unicode_script`
+-- @param char Unicode codepoint
+-- @return a `Script` object.
+-- @function unicode.script
+
+
+--- Predefined Name IDs.
+-- Predefined OpenType 'name' table name identifier.
+-- @section
+
+--- Wraps `HB_OT_NAME_ID_COPYRIGHT`
+-- @field ot.NAME_ID_COPYRIGHT
+
+--- Wraps `HB_OT_NAME_ID_FONT_FAMILY`
+-- @field ot.NAME_ID_FONT_FAMILY
+
+--- Wraps `HB_OT_NAME_ID_FONT_SUBFAMILY`
+-- @field ot.NAME_ID_FONT_SUBFAMILY
+
+--- Wraps `HB_OT_NAME_ID_UNIQUE_ID`
+-- @field ot.NAME_ID_UNIQUE_ID
+
+--- Wraps `HB_OT_NAME_ID_FULL_NAME`
+-- @field ot.NAME_ID_FULL_NAME
+
+--- Wraps `HB_OT_NAME_ID_VERSION_STRING`
+-- @field ot.NAME_ID_VERSION_STRING
+
+--- Wraps `HB_OT_NAME_ID_POSTSCRIPT_NAME`
+-- @field ot.NAME_ID_POSTSCRIPT_NAME
+
+--- Wraps `HB_OT_NAME_ID_TRADEMARK`
+-- @field ot.NAME_ID_TRADEMARK
+
+--- Wraps `HB_OT_NAME_ID_MANUFACTURER`
+-- @field ot.NAME_ID_MANUFACTURER
+
+--- Wraps `HB_OT_NAME_ID_DESIGNER`
+-- @field ot.NAME_ID_DESIGNER
+
+--- Wraps `HB_OT_NAME_ID_DESCRIPTION`
+-- @field ot.NAME_ID_DESCRIPTION
+
+--- Wraps `HB_OT_NAME_ID_VENDOR_URL`
+-- @field ot.NAME_ID_VENDOR_URL
+
+--- Wraps `HB_OT_NAME_ID_DESIGNER_URL`
+-- @field ot.NAME_ID_DESIGNER_URL
+
+--- Wraps `HB_OT_NAME_ID_LICENSE`
+-- @field ot.NAME_ID_LICENSE
+
+--- Wraps `HB_OT_NAME_ID_LICENSE_URL`
+-- @field ot.NAME_ID_LICENSE_URL
+
+--- Wraps `HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY`
+-- @field ot.NAME_ID_TYPOGRAPHIC_FAMILY
+
+--- Wraps `HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY`
+-- @field ot.NAME_ID_TYPOGRAPHIC_SUBFAMILY
+
+--- Wraps `HB_OT_NAME_ID_MAC_FULL_NAME`
+-- @field ot.NAME_ID_MAC_FULL_NAME
+
+--- Wraps `HB_OT_NAME_ID_SAMPLE_TEXT`
+-- @field ot.NAME_ID_SAMPLE_TEXT
+
+--- Wraps `HB_OT_NAME_ID_CID_FINDFONT_NAME`
+-- @field ot.NAME_ID_CID_FINDFONT_NAME
+
+--- Wraps `HB_OT_NAME_ID_WWS_FAMILY`
+-- @field ot.NAME_ID_WWS_FAMILY
+
+--- Wraps `HB_OT_NAME_ID_WWS_SUBFAMILY`
+-- @field ot.NAME_ID_WWS_SUBFAMILY
+
+--- Wraps `HB_OT_NAME_ID_LIGHT_BACKGROUND`
+-- @field ot.NAME_ID_LIGHT_BACKGROUND
+
+--- Wraps `HB_OT_NAME_ID_DARK_BACKGROUND`
+-- @field ot.NAME_ID_DARK_BACKGROUND
+
+--- Wraps `HB_OT_NAME_ID_VARIATIONS_PS_PREFIX`
+-- @field ot.NAME_ID_VARIATIONS_PS_PREFIX
+
+--- Wraps `HB_OT_NAME_ID_INVALID`
+-- @field ot.NAME_ID_INVALID
+
+--- Wraps `HB_OT_LAYOUT_NO_SCRIPT_INDEX`
+-- @field ot.LAYOUT_NO_SCRIPT_INDEX
+
+--- Wraps `HB_OT_LAYOUT_NO_FEATURE_INDEX`
+-- @field ot.LAYOUT_NO_FEATURE_INDEX
+
+--- Wraps `HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX`
+-- @field ot.LAYOUT_DEFAULT_LANGUAGE_INDEX
+
+--- Wraps `HB_OT_LAYOUT_NO_VARIATIONS_INDEX`
+-- @field ot.LAYOUT_NO_VARIATIONS_INDEX
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/blob.c b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/blob.c
new file mode 100644
index 00000000000..889f5b19742
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/blob.c
@@ -0,0 +1,60 @@
+#include "luaharfbuzz.h"
+
+static int blob_new(lua_State *L) {
+ Blob *b;
+ size_t data_l;
+ const char *data = luaL_checklstring(L, 1, &data_l);
+
+ b = (Blob *)lua_newuserdata(L, sizeof(*b));
+ luaL_getmetatable(L, "harfbuzz.Blob");
+ lua_setmetatable(L, -2);
+
+ *b = hb_blob_create(data, data_l, HB_MEMORY_MODE_DUPLICATE, (void*)data, NULL);
+ return 1;
+}
+
+static int blob_new_from_file(lua_State *L) {
+ Blob *b;
+ const char *file_name = luaL_checkstring(L, 1);
+
+ b = (Blob *)lua_newuserdata(L, sizeof(*b));
+ luaL_getmetatable(L, "harfbuzz.Blob");
+ lua_setmetatable(L, -2);
+
+ *b = hb_blob_create_from_file(file_name);
+ return 1;
+}
+
+static int blob_get_length(lua_State *L) {
+ Blob *b = (Blob *)luaL_checkudata(L, 1, "harfbuzz.Blob");
+
+ lua_pushinteger(L, hb_blob_get_length(*b));
+ return 1;
+}
+
+static int blob_get_data(lua_State *L) {
+ Blob *b = (Blob *)luaL_checkudata(L, 1, "harfbuzz.Blob");
+ unsigned int l;
+ const char *d;
+
+ d = hb_blob_get_data(*b, &l);
+ lua_pushlstring(L, d, l);
+
+ return 1;
+}
+
+static const struct luaL_Reg blob_methods[] = {
+ { "get_length", blob_get_length },
+ { "get_data", blob_get_data },
+ { NULL, NULL }
+};
+
+static const struct luaL_Reg blob_functions[] = {
+ { "new", blob_new },
+ { "new_from_file", blob_new_from_file },
+ { NULL, NULL }
+};
+
+int register_blob(lua_State *L) {
+ return register_class(L, "harfbuzz.Blob", blob_methods, blob_functions, NULL);
+}
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/buffer.c b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/buffer.c
new file mode 100644
index 00000000000..67921ba293a
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/buffer.c
@@ -0,0 +1,354 @@
+#include "luaharfbuzz.h"
+
+#ifdef LuajitTeX
+
+static int lua_absindex (lua_State *L, int i) {
+ if (i < 0 && i > LUA_REGISTRYINDEX)
+ i += lua_gettop(L) + 1;
+ return i;
+}
+static int lua_geti (lua_State *L, int index, lua_Integer i) {
+ index = lua_absindex(L, index);
+ lua_pushinteger(L, i);
+ lua_gettable(L, index);
+ return lua_type(L, -1);
+}
+#endif
+
+static int buffer_new(lua_State *L) {
+ Buffer *b;
+
+ b = (Buffer *)lua_newuserdata(L, sizeof(*b));
+ luaL_getmetatable(L, "harfbuzz.Buffer");
+ lua_setmetatable(L, -2);
+
+ *b = hb_buffer_create();
+ return 1;
+}
+
+static int buffer_guess_segment_properties(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ hb_buffer_guess_segment_properties(*b);
+ return 0;
+}
+
+static int buffer_get_direction(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ Direction *dp = (Direction *)lua_newuserdata(L, sizeof(*dp));
+ luaL_getmetatable(L, "harfbuzz.Direction");
+ lua_setmetatable(L, -2);
+
+ *dp = hb_buffer_get_direction(*b);
+ return 1;
+}
+
+static int buffer_set_direction(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+ Direction* dir = (Direction *)luaL_checkudata(L, 2, "harfbuzz.Direction");
+
+ hb_buffer_set_direction(*b, *dir);
+ return 0;
+}
+
+static int buffer_get_flags(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ lua_pushinteger(L, hb_buffer_get_flags(*b));
+ return 1;
+}
+
+static int buffer_set_flags(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ unsigned int l = luaL_checkinteger(L, 2);
+
+ hb_buffer_set_flags(*b, l);
+ return 0;
+}
+
+static int buffer_get_language(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ Language *lp = (Language *)lua_newuserdata(L, sizeof(*lp));
+ luaL_getmetatable(L, "harfbuzz.Language");
+ lua_setmetatable(L, -2);
+
+ *lp = hb_buffer_get_language(*b);
+ return 1;
+}
+
+static int buffer_set_language(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+ Language *lang = (Language *)luaL_checkudata(L, 2, "harfbuzz.Language");
+
+ hb_buffer_set_language(*b, *lang);
+ return 0;
+}
+
+static int buffer_get_script(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ Script *sp = (Script *)lua_newuserdata(L, sizeof(*sp));
+ luaL_getmetatable(L, "harfbuzz.Script");
+ lua_setmetatable(L, -2);
+
+ *sp = hb_buffer_get_script(*b);
+ return 1;
+}
+
+static int buffer_set_script(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+ Script *script = (Script *)luaL_checkudata(L, 2, "harfbuzz.Script");
+
+ hb_buffer_set_script(*b, *script);
+ return 0;
+}
+
+static int buffer_get_invisible_glyph(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ lua_pushinteger(L, hb_buffer_get_invisible_glyph(*b));
+ return 1;
+}
+
+static int buffer_set_invisible_glyph(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ hb_codepoint_t cp = (hb_codepoint_t) luaL_checkinteger(L, 2);
+
+ hb_buffer_set_invisible_glyph(*b, cp);
+ return 0;
+}
+
+static int buffer_get_replacement_codepoint(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ lua_pushinteger(L, hb_buffer_get_replacement_codepoint(*b));
+ return 1;
+}
+
+static int buffer_set_replacement_codepoint(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ hb_codepoint_t cp = (hb_codepoint_t) luaL_checkinteger(L, 2);
+
+ hb_buffer_set_replacement_codepoint(*b, cp);
+ return 0;
+}
+
+static int buffer_add(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ hb_codepoint_t c = (hb_codepoint_t) luaL_checkinteger(L, 2);
+ unsigned int cluster = luaL_checkinteger(L, 3);
+
+ hb_buffer_add(*b, c, cluster);
+
+ return 0;
+}
+
+static int buffer_add_codepoints(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+ unsigned int item_offset;
+ int item_length;
+ int i;
+
+ luaL_checktype(L, 2, LUA_TTABLE);
+ item_offset = luaL_optinteger(L, 3, 0);
+ item_length = luaL_optinteger(L, 4, -1);
+
+ int n = lua_rawlen(L, 2);
+
+ hb_codepoint_t *text = (hb_codepoint_t *) malloc(n * sizeof(hb_codepoint_t));
+
+ for (i = 0; i != n; ++i) {
+ lua_geti(L, 2, i + 1);
+ hb_codepoint_t c = (hb_codepoint_t) luaL_checkinteger(L, -1);
+ text[i] = c;
+ lua_pop(L, 1);
+ }
+
+ hb_buffer_add_codepoints(*b, text, n, item_offset, item_length);
+
+ free(text);
+
+ return 0;
+}
+
+static int buffer_clear_contents(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ hb_buffer_clear_contents(*b);
+ return 0;
+}
+
+static int buffer_reset(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ hb_buffer_reset(*b);
+ return 0;
+}
+
+static int buffer_add_utf8(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+ const char *text;
+ unsigned int item_offset;
+ int item_length;
+
+ text = luaL_checkstring(L, 2);
+ item_offset = luaL_optinteger(L, 3, 0);
+ item_length = luaL_optinteger(L, 4, -1);
+
+ hb_buffer_add_utf8(*b, text, -1, item_offset, item_length);
+
+ return 0;
+}
+
+static int buffer_destroy(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ hb_buffer_destroy(*b);
+ return 0;
+}
+
+static int buffer_get_glyphs(lua_State *L) {
+ Buffer *buf = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ // Get glyph info and positions out of buffer
+ unsigned int len = hb_buffer_get_length(*buf);
+ hb_glyph_info_t *info = hb_buffer_get_glyph_infos(*buf, NULL);
+ hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(*buf, NULL);
+ hb_glyph_flags_t flags;
+ unsigned int i;
+
+ // Create Lua table and push glyph data onto it.
+ lua_createtable(L, len, 0); // parent table
+
+ for (i = 0; i < len; i++) {
+ lua_pushinteger(L, i+1); // 1-indexed key parent table
+ lua_createtable(L, 0, 7); // child table
+
+ lua_pushinteger(L, info[i].codepoint);
+ lua_setfield(L, -2, "codepoint");
+
+ lua_pushinteger(L, info[i].cluster);
+ lua_setfield(L, -2, "cluster");
+
+ lua_pushnumber(L, pos[i].x_advance);
+ lua_setfield(L, -2, "x_advance");
+
+ lua_pushnumber(L, pos[i].y_advance);
+ lua_setfield(L, -2, "y_advance");
+
+ lua_pushnumber(L, pos[i].x_offset);
+ lua_setfield(L, -2, "x_offset");
+
+ lua_pushnumber(L, pos[i].y_offset);
+ lua_setfield(L, -2, "y_offset");
+
+ flags = hb_glyph_info_get_glyph_flags(&(info[i]));
+ if (flags & HB_GLYPH_FLAG_DEFINED) {
+ lua_pushnumber(L, flags);
+ lua_setfield(L, -2, "flags");
+ }
+
+ lua_settable(L, -3); // Add child table at index i+1 to parent table
+ }
+
+ return 1;
+}
+
+static int buffer_reverse(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ hb_buffer_reverse(*b);
+ return 0;
+}
+
+static int buffer_get_length(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ lua_pushinteger(L, hb_buffer_get_length(*b));
+ return 1;
+}
+
+static int buffer_get_cluster_level(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ lua_pushinteger(L, hb_buffer_get_cluster_level(*b));
+ return 1;
+}
+
+static int buffer_set_cluster_level(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ unsigned int l = luaL_checkinteger(L, 2);
+
+ hb_buffer_set_cluster_level(*b, l);
+ return 0;
+}
+
+static int buffer_pre_allocate(lua_State *L) {
+ Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
+
+ unsigned int n = luaL_checkinteger(L, 2);
+
+ lua_pushboolean(L, hb_buffer_pre_allocate(*b, n));
+ return 1;
+}
+
+static const struct luaL_Reg buffer_methods[] = {
+ { "__gc", buffer_destroy },
+ { "add", buffer_add },
+ { "add_utf8", buffer_add_utf8 },
+ { "add_codepoints", buffer_add_codepoints },
+ { "clear_contents", buffer_clear_contents },
+ { "set_direction", buffer_set_direction },
+ { "get_direction", buffer_get_direction },
+ { "set_flags", buffer_set_flags },
+ { "get_flags", buffer_get_flags },
+ { "set_language", buffer_set_language },
+ { "get_language", buffer_get_language },
+ { "set_script", buffer_set_script },
+ { "get_script", buffer_get_script },
+ { "set_invisible_glyph", buffer_set_invisible_glyph },
+ { "get_invisible_glyph", buffer_get_invisible_glyph },
+ { "set_replacement_codepoint", buffer_set_replacement_codepoint },
+ { "get_replacement_codepoint", buffer_get_replacement_codepoint },
+ { "get_glyphs", buffer_get_glyphs },
+ { "guess_segment_properties", buffer_guess_segment_properties },
+ { "reset", buffer_reset },
+ { "reverse", buffer_reverse },
+ { "get_length", buffer_get_length },
+ { "get_cluster_level", buffer_get_cluster_level },
+ { "set_cluster_level", buffer_set_cluster_level },
+ { "pre_allocate", buffer_pre_allocate },
+ { NULL, NULL }
+};
+
+static const struct luaL_Reg buffer_functions[] = {
+ { "new", buffer_new },
+ { NULL, NULL }
+};
+
+static const struct luahb_constant_t buffer_constants[] = {
+ { "CLUSTER_LEVEL_MONOTONE_GRAPHEMES", HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES },
+ { "CLUSTER_LEVEL_MONOTONE_CHARACTERS", HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS },
+ { "CLUSTER_LEVEL_CHARACTERS", HB_BUFFER_CLUSTER_LEVEL_CHARACTERS },
+ { "CLUSTER_LEVEL_DEFAULT", HB_BUFFER_CLUSTER_LEVEL_DEFAULT },
+ { "FLAG_DEFAULT", HB_BUFFER_FLAG_DEFAULT },
+ { "FLAG_BOT", HB_BUFFER_FLAG_BOT },
+ { "FLAG_EOT", HB_BUFFER_FLAG_EOT },
+ { "FLAG_PRESERVE_DEFAULT_IGNORABLES", HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES },
+ { "FLAG_REMOVE_DEFAULT_IGNORABLES", HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES },
+ { "FLAG_DO_NOT_INSERT_DOTTED_CIRCLE", HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE },
+ { "GLYPH_FLAG_UNSAFE_TO_BREAK", HB_GLYPH_FLAG_UNSAFE_TO_BREAK },
+ { "GLYPH_FLAG_DEFINED", HB_GLYPH_FLAG_DEFINED },
+ { NULL, 0 }
+};
+
+int register_buffer(lua_State *L) {
+ return register_class(L, "harfbuzz.Buffer", buffer_methods, buffer_functions, buffer_constants);
+}
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/class_utils.c b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/class_utils.c
new file mode 100644
index 00000000000..89428526a7c
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/class_utils.c
@@ -0,0 +1,33 @@
+// Utility functions to create Lua classes.
+#include "luaharfbuzz.h"
+
+int register_class(lua_State *L, const char *name, const luaL_Reg *methods, const luaL_Reg *functions, const luahb_constant_t *constants) {
+ luaL_newmetatable(L, name);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+
+ if (constants) {
+ while (constants->name) {
+ lua_pushinteger(L, constants->value);
+ lua_setfield(L, -2, constants->name);
+ constants++;
+ }
+ }
+#ifdef LuajitTeX
+ luaL_register(L,NULL,methods);
+#else
+ luaL_setfuncs(L, methods, 0);
+#endif
+ lua_pop(L, 1);
+
+ lua_newtable(L);
+#ifdef LuajitTeX
+ luaL_register(L,NULL,functions);
+#else
+ luaL_setfuncs(L, functions, 0);
+#endif
+ luaL_getmetatable(L, name);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/direction.c b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/direction.c
new file mode 100644
index 00000000000..644b3af30a2
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/direction.c
@@ -0,0 +1,84 @@
+// harfbuzz.Feature
+#include "luaharfbuzz.h"
+
+static int direction_new(lua_State *L) {
+ Direction *d;
+ const char *dir = luaL_checkstring(L, 1);
+
+ d = (Direction *)lua_newuserdata(L, sizeof(*d));
+ luaL_getmetatable(L, "harfbuzz.Direction");
+ lua_setmetatable(L, -2);
+
+ *d = hb_direction_from_string(dir, -1);
+ return 1;
+}
+
+static int direction_to_string(lua_State *L) {
+ Direction* d = (Direction *)luaL_checkudata(L, 1, "harfbuzz.Direction");
+
+ lua_pushstring(L, hb_direction_to_string(*d));
+ return 1;
+}
+
+static int direction_equals(lua_State *L) {
+ Direction* lhs = (Direction *)luaL_checkudata(L, 1, "harfbuzz.Direction");
+ Direction* rhs = (Direction *)luaL_checkudata(L, 2, "harfbuzz.Direction");
+
+ lua_pushboolean(L, *lhs == *rhs);
+ return 1;
+}
+
+static int direction_is_valid(lua_State *L) {
+ Direction* d = (Direction *)luaL_checkudata(L, 1, "harfbuzz.Direction");
+
+ lua_pushboolean(L, HB_DIRECTION_IS_VALID(*d));
+ return 1;
+}
+
+static int direction_is_horizontal(lua_State *L) {
+ Direction* d = (Direction *)luaL_checkudata(L, 1, "harfbuzz.Direction");
+
+ lua_pushboolean(L, HB_DIRECTION_IS_HORIZONTAL(*d));
+ return 1;
+}
+
+static int direction_is_vertical(lua_State *L) {
+ Direction* d = (Direction *)luaL_checkudata(L, 1, "harfbuzz.Direction");
+
+ lua_pushboolean(L, HB_DIRECTION_IS_VERTICAL(*d));
+ return 1;
+}
+
+static int direction_is_forward(lua_State *L) {
+ Direction* d = (Direction *)luaL_checkudata(L, 1, "harfbuzz.Direction");
+
+ lua_pushboolean(L, HB_DIRECTION_IS_FORWARD(*d));
+ return 1;
+}
+
+static int direction_is_backward(lua_State *L) {
+ Direction* d = (Direction *)luaL_checkudata(L, 1, "harfbuzz.Direction");
+
+ lua_pushboolean(L, HB_DIRECTION_IS_BACKWARD(*d));
+ return 1;
+}
+
+static const struct luaL_Reg direction_methods[] = {
+ { "__tostring", direction_to_string },
+ { "__eq", direction_equals },
+ { "is_valid", direction_is_valid },
+ { "is_horizontal", direction_is_horizontal },
+ { "is_vertical", direction_is_vertical },
+ { "is_forward", direction_is_forward },
+ { "is_backward", direction_is_backward },
+ { NULL, NULL }
+};
+
+static const struct luaL_Reg direction_functions[] = {
+ { "new", direction_new },
+ { NULL, NULL }
+};
+
+int register_direction(lua_State *L) {
+ return register_class(L, "harfbuzz.Direction", direction_methods, direction_functions, NULL);
+}
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/face.c b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/face.c
new file mode 100644
index 00000000000..5538c704571
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/face.c
@@ -0,0 +1,466 @@
+#include "luaharfbuzz.h"
+
+/* Size of static arrays we use to avoid heap allocating memory when reading
+ * data from HarfBuzz. */
+#define STATIC_ARRAY_SIZE 128
+
+static int face_new(lua_State *L) {
+ Face *f;
+ hb_blob_t *blob;
+ hb_face_t *face;
+ const char *file_name = luaL_checkstring(L, 1);
+ unsigned int face_index = (unsigned int) luaL_optinteger(L, 2, 0);
+
+ blob = hb_blob_create_from_file(file_name);
+ face = hb_face_create(blob, face_index);
+
+ if (blob == hb_blob_get_empty() || face == hb_face_get_empty()) {
+ lua_pushnil(L);
+ } else {
+ f = (Face *)lua_newuserdata(L, sizeof(*f));
+ *f = face;
+ luaL_getmetatable(L, "harfbuzz.Face");
+ lua_setmetatable(L, -2);
+ }
+ return 1;
+}
+
+static int face_new_from_blob(lua_State *L) {
+ Face *f;
+ hb_face_t *face;
+ Blob *blob = luaL_checkudata(L, 1, "harfbuzz.Blob");
+ unsigned int face_index = (unsigned int) luaL_optinteger(L, 2, 0);
+
+ face = hb_face_create(*blob, face_index);
+
+ if (*blob == hb_blob_get_empty() || face == hb_face_get_empty()) {
+ lua_pushnil(L);
+ } else {
+ f = (Face *)lua_newuserdata(L, sizeof(*f));
+ *f = face;
+ luaL_getmetatable(L, "harfbuzz.Face");
+ lua_setmetatable(L, -2);
+ }
+ return 1;
+}
+
+static int face_get_glyph_count(lua_State *L) {
+ Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+
+ lua_pushinteger(L, hb_face_get_glyph_count(*f));
+ return 1;
+}
+
+static int face_get_name(lua_State *L) {
+ Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+ hb_ot_name_id_t name_id = (hb_ot_name_id_t) luaL_checkinteger(L, 2);
+ hb_language_t lang = HB_LANGUAGE_INVALID;
+ char name[STATIC_ARRAY_SIZE];
+ unsigned int text_size = STATIC_ARRAY_SIZE, len;
+
+ if (lua_gettop(L) > 2)
+ lang = *((Language*)luaL_checkudata(L, 3, "harfbuzz.Language"));
+
+ len = hb_ot_name_get_utf8(*f, name_id, lang, &text_size, name);
+ if (len) {
+ if (len < STATIC_ARRAY_SIZE) {
+ lua_pushstring(L, name);
+ } else {
+ char *name = malloc(len + 1);
+ text_size = len + 1;
+ hb_ot_name_get_utf8(*f, name_id, lang, &text_size, name);
+ lua_pushstring(L, name);
+ free(name);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int face_get_table(lua_State *L) {
+ Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+ Tag *t = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
+ Blob *b;
+
+ b = (Blob *)lua_newuserdata(L, sizeof(*b));
+ luaL_getmetatable(L, "harfbuzz.Blob");
+ lua_setmetatable(L, -2);
+
+ *b = hb_face_reference_table(*f, *t);
+
+ return 1;
+}
+
+static int face_get_table_tags(lua_State *L) {
+ Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+ hb_tag_t tags[STATIC_ARRAY_SIZE];
+ unsigned int count = hb_face_get_table_tags(*f, 0, NULL, NULL);
+
+ if (count) {
+ unsigned int i = 0, offset = 0;
+ lua_createtable(L, count, 0);
+ do {
+ count = STATIC_ARRAY_SIZE;
+ hb_face_get_table_tags(*f, offset, &count, tags);
+ for (i = 0; i < count; i++) {
+ lua_pushnumber(L, offset + i + 1);
+
+ Tag *tp = (Tag *)lua_newuserdata(L, sizeof(*tp));
+ luaL_getmetatable(L, "harfbuzz.Tag");
+ lua_setmetatable(L, -2);
+ *tp = tags[i];
+
+ lua_rawset(L, -3);
+ }
+ offset += count;
+ } while (count == STATIC_ARRAY_SIZE);
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int face_ot_layout_get_script_tags(lua_State *L) {
+ Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+ Tag *table = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
+
+ hb_tag_t tags[STATIC_ARRAY_SIZE];
+ unsigned int count = hb_ot_layout_table_get_script_tags(*face, *table, 0, NULL, NULL);
+
+ if (count) {
+ unsigned int i = 0, offset = 0;
+ lua_createtable(L, count, 0);
+ do {
+ count = STATIC_ARRAY_SIZE;
+ hb_ot_layout_table_get_script_tags(*face, *table, offset, &count, tags);
+ for (i = 0; i < count; i++) {
+ lua_pushnumber(L, offset + i + 1);
+
+ Tag *tp = (Tag *)lua_newuserdata(L, sizeof(*tp));
+ luaL_getmetatable(L, "harfbuzz.Tag");
+ lua_setmetatable(L, -2);
+ *tp = tags[i];
+
+ lua_rawset(L, -3);
+ }
+ offset += count;
+ } while (count == STATIC_ARRAY_SIZE);
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int face_ot_layout_get_language_tags(lua_State *L) {
+ Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+ Tag *table = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
+ unsigned int script_index = (unsigned int) luaL_checkinteger(L, 3);
+
+ hb_tag_t tags[STATIC_ARRAY_SIZE];
+ unsigned int count = hb_ot_layout_script_get_language_tags(*face, *table, script_index, 0, NULL, NULL);
+
+ if (count) {
+ unsigned int i = 0, offset = 0;
+ lua_createtable(L, count, 0);
+ do {
+ count = STATIC_ARRAY_SIZE;
+ hb_ot_layout_script_get_language_tags(*face, *table, script_index, offset, &count, tags);
+ for (i = 0; i < count; i++) {
+ lua_pushnumber(L, offset + i + 1);
+
+ Tag *tp = (Tag *)lua_newuserdata(L, sizeof(*tp));
+ luaL_getmetatable(L, "harfbuzz.Tag");
+ lua_setmetatable(L, -2);
+ *tp = tags[i];
+
+ lua_rawset(L, -3);
+ }
+ offset += count;
+ } while (count == STATIC_ARRAY_SIZE);
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int face_ot_layout_get_feature_tags(lua_State *L) {
+ Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+ Tag *table = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
+ unsigned int script_index = (unsigned int) luaL_checkinteger(L, 3);
+ unsigned int language_index = (unsigned int) luaL_checkinteger(L, 4);
+
+ hb_tag_t tags[STATIC_ARRAY_SIZE];
+ unsigned int count = hb_ot_layout_language_get_feature_tags(*face, *table, script_index, language_index, 0, NULL, NULL);
+
+ if (count) {
+ unsigned int i = 0, offset = 0;
+ lua_createtable(L, count, 0);
+ do {
+ count = STATIC_ARRAY_SIZE;
+ hb_ot_layout_language_get_feature_tags(*face, *table, script_index, language_index, offset, &count, tags);
+ for (i = 0; i < count; i++) {
+ lua_pushnumber(L, offset + i + 1);
+
+ Tag *tp = (Tag *)lua_newuserdata(L, sizeof(*tp));
+ luaL_getmetatable(L, "harfbuzz.Tag");
+ lua_setmetatable(L, -2);
+ *tp = tags[i];
+
+ lua_rawset(L, -3);
+ }
+ offset += count;
+ } while (count == STATIC_ARRAY_SIZE);
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int face_ot_layout_find_script(lua_State *L) {
+ Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+ Tag *table = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
+ Tag *script = (Tag *)luaL_checkudata(L, 3, "harfbuzz.Tag");
+ unsigned int index = 0;
+
+ int found = hb_ot_layout_table_find_script(*face, *table, *script, &index);
+ lua_pushboolean(L, found);
+ lua_pushinteger(L, index);
+ return 2;
+}
+
+static int face_ot_layout_find_language(lua_State *L) {
+ Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+ Tag *table = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
+ unsigned int script_index = (unsigned int) luaL_checkinteger(L, 3);
+ Tag *language = (Tag *)luaL_checkudata(L, 4, "harfbuzz.Tag");
+ unsigned int index = 0;
+
+ int found = hb_ot_layout_script_select_language(*face, *table, script_index, 1, &(*language), &index);
+ lua_pushboolean(L, found);
+ lua_pushinteger(L, index);
+ return 2;
+}
+
+static int face_ot_layout_find_feature(lua_State *L) {
+ Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+ Tag *table = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
+ unsigned int script_index = (unsigned int) luaL_checkinteger(L, 3);
+ unsigned int language_index = (unsigned int) luaL_checkinteger(L, 4);
+ Tag *feature = (Tag *)luaL_checkudata(L, 5, "harfbuzz.Tag");
+ unsigned int index = 0;
+
+ int found = hb_ot_layout_language_find_feature(*face, *table, script_index, language_index, *feature, &index);
+ lua_pushboolean(L, found);
+ lua_pushinteger(L, index);
+ return 2;
+}
+
+static int face_collect_unicodes(lua_State *L) {
+ Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+ hb_set_t *codes = hb_set_create();
+
+ hb_face_collect_unicodes (*f, codes);
+ lua_createtable(L, hb_set_get_population(codes), 0);
+ if (!hb_set_is_empty(codes)) {
+ unsigned int i = 0;
+ hb_codepoint_t c = HB_SET_VALUE_INVALID;
+
+ while (hb_set_next(codes, &c)) {
+ lua_pushnumber(L, ++i);
+ lua_pushnumber(L, c);
+ lua_rawset(L, -3);
+ }
+ }
+
+ hb_set_destroy(codes);
+
+ return 1;
+}
+
+static int face_get_upem(lua_State *L) {
+ Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+
+ lua_pushinteger(L, hb_face_get_upem(*f));
+ return 1;
+}
+
+static int face_ot_color_has_palettes(lua_State *L) {
+ Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+
+ lua_pushboolean(L, hb_ot_color_has_palettes(*f));
+ return 1;
+}
+
+static int face_ot_color_palette_get_count(lua_State *L) {
+ Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+
+ lua_pushinteger(L, hb_ot_color_palette_get_count(*f));
+ return 1;
+}
+
+static int face_ot_color_palette_get_colors(lua_State *L) {
+ Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+ unsigned int index = (unsigned int) luaL_optinteger(L, 2, 1) - 1;
+
+ hb_color_t colors[STATIC_ARRAY_SIZE];
+ unsigned int count = hb_ot_color_palette_get_colors(*f, index, 0, NULL, NULL);
+
+ if (count) {
+ unsigned int i = 0, offset = 0;
+ lua_createtable(L, count, 0); // parent table
+ do {
+ count = STATIC_ARRAY_SIZE;
+ hb_ot_color_palette_get_colors(*f, index, offset, &count, colors);
+ for (i = 0; i < count; i++) {
+ hb_color_t color = colors[i];
+
+ lua_pushnumber(L, offset + i + 1); // 1-indexed key parent table
+ lua_createtable(L, 0, 4); // child table
+
+ lua_pushinteger(L, hb_color_get_red(color));
+ lua_setfield(L, -2, "red");
+
+ lua_pushinteger(L, hb_color_get_green(color));
+ lua_setfield(L, -2, "green");
+
+ lua_pushinteger(L, hb_color_get_blue(color));
+ lua_setfield(L, -2, "blue");
+
+ lua_pushinteger(L, hb_color_get_alpha(color));
+ lua_setfield(L, -2, "alpha");
+
+ lua_settable(L, -3); // Add child table at index i+1 to parent table
+ }
+ offset += count;
+ } while (count == STATIC_ARRAY_SIZE);
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int face_ot_color_has_layers(lua_State *L) {
+ Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+
+ lua_pushboolean(L, hb_ot_color_has_layers(*f));
+ return 1;
+}
+
+static int face_ot_color_glyph_get_layers(lua_State *L) {
+ Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+ hb_codepoint_t gid = (hb_codepoint_t) luaL_checkinteger(L, 2);
+ hb_ot_color_layer_t layers[STATIC_ARRAY_SIZE];
+ unsigned int count = hb_ot_color_glyph_get_layers(*f, gid, 0, NULL, NULL);
+
+ if (count) {
+ unsigned int i = 0, offset = 0;
+ lua_createtable(L, count, 0); // parent table
+ do {
+ count = STATIC_ARRAY_SIZE;
+ hb_ot_color_glyph_get_layers(*f, gid, offset, &count, layers);
+ for (i = 0; i < count; i++) {
+ hb_ot_color_layer_t layer = layers[i];
+ unsigned int color_index = layer.color_index;
+ if (color_index != 0xFFFF)
+ color_index++; // make it 1-indexed
+
+ lua_pushnumber(L, offset + i + 1); // 1-indexed key parent table
+ lua_createtable(L, 0, 2); // child table
+
+ lua_pushinteger(L, layer.glyph);
+ lua_setfield(L, -2, "glyph");
+
+ lua_pushinteger(L, color_index);
+ lua_setfield(L, -2, "color_index");
+
+ lua_settable(L, -3); // Add child table at index i+1 to parent table
+ }
+ offset += count;
+ } while (count == STATIC_ARRAY_SIZE);
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int face_ot_color_has_png(lua_State *L) {
+ Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+
+ lua_pushboolean(L, hb_ot_color_has_png(*f));
+ return 1;
+}
+
+static int face_ot_color_has_svg(lua_State *L) {
+ Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+
+ lua_pushboolean(L, hb_ot_color_has_svg(*f));
+ return 1;
+}
+
+static int face_ot_color_glyph_get_svg(lua_State *L) {
+ Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+ hb_codepoint_t gid = (hb_codepoint_t) luaL_checkinteger(L, 2);
+ hb_blob_t* blob = hb_ot_color_glyph_reference_svg(*f, gid);
+
+ if (hb_blob_get_length(blob) != 0) {
+ Blob *b = (Blob *)lua_newuserdata(L, sizeof(*b));
+ luaL_getmetatable(L, "harfbuzz.Blob");
+ lua_setmetatable(L, -2);
+
+ *b = blob;
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int face_destroy(lua_State *L) {
+ Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+
+ hb_face_destroy(*f);
+ return 0;
+}
+
+static const struct luaL_Reg face_methods[] = {
+ { "__gc", face_destroy },
+ { "collect_unicodes", face_collect_unicodes },
+ { "get_glyph_count", face_get_glyph_count },
+ { "get_name", face_get_name },
+ { "get_table", face_get_table },
+ { "get_table_tags", face_get_table_tags },
+ { "get_upem", face_get_upem },
+ { "ot_color_has_palettes", face_ot_color_has_palettes },
+ { "ot_color_palette_get_count", face_ot_color_palette_get_count },
+ { "ot_color_palette_get_colors", face_ot_color_palette_get_colors },
+ { "ot_color_has_layers", face_ot_color_has_layers },
+ { "ot_color_glyph_get_layers", face_ot_color_glyph_get_layers },
+ { "ot_color_has_png", face_ot_color_has_png },
+ { "ot_color_has_svg", face_ot_color_has_svg },
+ { "ot_color_glyph_get_svg", face_ot_color_glyph_get_svg },
+ { "ot_layout_get_script_tags", face_ot_layout_get_script_tags },
+ { "ot_layout_get_language_tags", face_ot_layout_get_language_tags },
+ { "ot_layout_get_feature_tags", face_ot_layout_get_feature_tags },
+ { "ot_layout_find_script", face_ot_layout_find_script },
+ { "ot_layout_find_language", face_ot_layout_find_language },
+ { "ot_layout_find_feature", face_ot_layout_find_feature },
+ { NULL, NULL }
+};
+
+static const struct luaL_Reg face_functions[] = {
+ { "new", face_new },
+ { "new_from_blob", face_new_from_blob },
+ { NULL, NULL }
+};
+
+int register_face(lua_State *L) {
+ return register_class(L, "harfbuzz.Face", face_methods, face_functions, NULL);
+}
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/feature.c b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/feature.c
new file mode 100644
index 00000000000..d6cd1ec325b
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/feature.c
@@ -0,0 +1,110 @@
+// harfbuzz.Feature
+#include "luaharfbuzz.h"
+
+static int feature_new(lua_State *L) {
+ Feature f;
+ const char *feature = luaL_checkstring(L, 1);
+
+ if (hb_feature_from_string(feature, -1, &f)) {
+ Feature *fp = (Feature *)lua_newuserdata(L, sizeof(*fp));
+ luaL_getmetatable(L, "harfbuzz.Feature");
+ lua_setmetatable(L, -2);
+ *fp = f;
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int feature_to_string(lua_State *L) {
+ Feature* f = (Feature *)luaL_checkudata(L, 1, "harfbuzz.Feature");
+ char feature[128];
+
+ hb_feature_to_string(f, feature, 128);
+ lua_pushstring(L, feature);
+ return 1;
+}
+
+static const char *feature_tag_ptr;
+static const char *feature_value_ptr;
+static const char *feature_start_ptr;
+static const char *feature_end_ptr;
+
+static int feature_index(lua_State *L) {
+ Feature* f = (Feature *)luaL_checkudata(L, 1, "harfbuzz.Feature");
+ const char *key = lua_tostring(L, 2);
+
+ if (key == feature_tag_ptr) {
+ Tag *tag = (Tag *)lua_newuserdata(L, sizeof(*tag));
+ luaL_getmetatable(L, "harfbuzz.Tag");
+ lua_setmetatable(L, -2);
+ *tag = f->tag;
+ } else if (key == feature_value_ptr) {
+ lua_pushinteger(L, f->value);
+ } else if (key == feature_start_ptr) {
+ if (f->start == HB_FEATURE_GLOBAL_START)
+ lua_pushnil(L);
+ else
+ lua_pushinteger(L, f->start);
+ } else if (key == feature_end_ptr) {
+ if (f->end == HB_FEATURE_GLOBAL_END)
+ lua_pushnil(L);
+ else
+ lua_pushinteger(L, f->end);
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int feature_newindex(lua_State *L) {
+ Feature* f = (Feature *)luaL_checkudata(L, 1, "harfbuzz.Feature");
+ const char *key = lua_tostring(L, 2);
+
+ if (key == feature_tag_ptr) {
+ f->tag = *(Tag *)luaL_checkudata(L, 3, "harfbuzz.Tag");
+ } else if (key == feature_value_ptr) {
+ f->value = luaL_checkinteger(L, 3);
+ } else if (key == feature_start_ptr) {
+ if (lua_toboolean(L, 3))
+ f->start = luaL_checkinteger(L, 3);
+ else
+ f->start = HB_FEATURE_GLOBAL_START;
+ } else if (key == feature_end_ptr) {
+ if (lua_toboolean(L, 3))
+ f->end = luaL_checkinteger(L, 3);
+ else
+ f->end = HB_FEATURE_GLOBAL_END;
+ }
+ return 0;
+}
+
+static const struct luaL_Reg feature_methods[] = {
+ { "__index", feature_index },
+ { "__newindex", feature_newindex },
+ { "__tostring", feature_to_string },
+ { NULL, NULL },
+};
+
+static const struct luaL_Reg feature_functions[] = {
+ { "new", feature_new },
+ { NULL, NULL }
+};
+
+int register_feature(lua_State *L) {
+ lua_pushliteral(L, "tag");
+ feature_tag_ptr = lua_tostring(L, -1);
+ (void) luaL_ref (L, LUA_REGISTRYINDEX);
+ lua_pushliteral(L, "value");
+ feature_value_ptr = lua_tostring(L, -1);
+ (void) luaL_ref (L, LUA_REGISTRYINDEX);
+ lua_pushliteral(L, "start");
+ feature_start_ptr = lua_tostring(L, -1);
+ (void) luaL_ref (L, LUA_REGISTRYINDEX);
+ lua_pushliteral(L, "_end"); /* _end instead of end to avoid Lua keyword */
+ feature_end_ptr = lua_tostring(L, -1);
+ (void) luaL_ref (L, LUA_REGISTRYINDEX);
+
+ return register_class(L, "harfbuzz.Feature", feature_methods, feature_functions, NULL);
+}
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/font.c b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/font.c
new file mode 100644
index 00000000000..c601673647e
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/font.c
@@ -0,0 +1,218 @@
+#include "luaharfbuzz.h"
+
+static int font_new(lua_State *L) {
+ Font *f;
+ Face *face = luaL_checkudata(L, 1, "harfbuzz.Face");
+
+ f = (Font *)lua_newuserdata(L, sizeof(*f));
+ luaL_getmetatable(L, "harfbuzz.Font");
+ lua_setmetatable(L, -2);
+
+ *f = hb_font_create(*face);
+
+ // Set default scale to be the face's upem value
+ unsigned int upem = hb_face_get_upem(*face);
+ hb_font_set_scale(*f, upem, upem);
+
+ // Set shaping functions to OpenType functions
+ hb_ot_font_set_funcs(*f);
+ return 1;
+}
+
+static int font_set_scale(lua_State *L) {
+ Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+ int x_scale = luaL_checkinteger(L, 2);
+ int y_scale = luaL_checkinteger(L, 3);
+
+ hb_font_set_scale(*f, x_scale, y_scale);
+ return 0;
+}
+
+static int font_get_scale(lua_State *L) {
+ Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+ int x_scale, y_scale;
+
+ hb_font_get_scale(*f, &x_scale, &y_scale);
+
+ lua_pushinteger(L, x_scale);
+ lua_pushinteger(L, y_scale);
+ return 2;
+}
+
+static int font_get_h_extents(lua_State *L) {
+ Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+ hb_font_extents_t extents;
+
+ if (hb_font_get_h_extents(*f, &extents)) {
+ lua_createtable(L, 0, 3);
+
+ lua_pushnumber(L, extents.ascender);
+ lua_setfield(L, -2, "ascender");
+
+ lua_pushnumber(L, extents.descender);
+ lua_setfield(L, -2, "descender");
+
+ lua_pushnumber(L, extents.line_gap);
+ lua_setfield(L, -2, "line_gap");
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int font_get_v_extents(lua_State *L) {
+ Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+ hb_font_extents_t extents;
+
+ if (hb_font_get_v_extents(*f, &extents)) {
+ lua_createtable(L, 0, 3);
+
+ lua_pushnumber(L, extents.ascender);
+ lua_setfield(L, -2, "ascender");
+
+ lua_pushnumber(L, extents.descender);
+ lua_setfield(L, -2, "descender");
+
+ lua_pushnumber(L, extents.line_gap);
+ lua_setfield(L, -2, "line_gap");
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int font_get_glyph_extents(lua_State *L) {
+ Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+ hb_codepoint_t glyph = luaL_checkinteger(L, 2);
+ hb_glyph_extents_t extents;
+
+ if (hb_font_get_glyph_extents(*f, glyph, &extents)) {
+ lua_createtable(L, 0, 4);
+
+ lua_pushnumber(L, extents.x_bearing);
+ lua_setfield(L, -2, "x_bearing");
+
+ lua_pushnumber(L, extents.y_bearing);
+ lua_setfield(L, -2, "y_bearing");
+
+ lua_pushnumber(L, extents.width);
+ lua_setfield(L, -2, "width");
+
+ lua_pushnumber(L, extents.height);
+ lua_setfield(L, -2, "height");
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int font_get_glyph_name(lua_State *L) {
+ Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+ hb_codepoint_t glyph = luaL_checkinteger(L, 2);
+
+#define NAME_LEN 128
+ char name[NAME_LEN];
+ if (hb_font_get_glyph_name(*f, glyph, name, NAME_LEN))
+ lua_pushstring(L, name);
+ else
+ lua_pushnil(L);
+#undef NAME_LEN
+
+ return 1;
+}
+
+static int font_get_glyph_from_name(lua_State *L) {
+ Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+ const char *name = luaL_checkstring(L, 2);
+ hb_codepoint_t glyph;
+
+ if (hb_font_get_glyph_from_name(*f, name, -1, &glyph))
+ lua_pushinteger(L, glyph);
+ else
+ lua_pushnil(L);
+
+ return 1;
+}
+
+static int font_get_glyph_h_advance(lua_State *L) {
+ Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+ hb_codepoint_t glyph = luaL_checkinteger(L, 2);
+
+ lua_pushinteger(L, hb_font_get_glyph_h_advance(*f, glyph));
+ return 1;
+}
+
+static int font_get_glyph_v_advance(lua_State *L) {
+ Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+ hb_codepoint_t glyph = luaL_checkinteger(L, 2);
+
+ lua_pushinteger(L, hb_font_get_glyph_v_advance(*f, glyph));
+ return 1;
+}
+
+static int font_get_nominal_glyph(lua_State *L) {
+ Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+ hb_codepoint_t uni = luaL_checkinteger(L, 2);
+ hb_codepoint_t glyph;
+
+ if (hb_font_get_nominal_glyph(*f, uni, &glyph))
+ lua_pushinteger(L, glyph);
+ else
+ lua_pushnil(L);
+
+ return 1;
+}
+
+
+static int font_destroy(lua_State *L) {
+ Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+
+ hb_font_destroy(*f);
+ return 0;
+}
+
+static int font_ot_color_glyph_get_png(lua_State *L) {
+ Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+ hb_codepoint_t gid = (hb_codepoint_t) luaL_checkinteger(L, 2);
+ hb_blob_t* blob = hb_ot_color_glyph_reference_png(*f, gid);
+
+ if (hb_blob_get_length(blob) != 0) {
+ Blob *b = (Blob *)lua_newuserdata(L, sizeof(*b));
+ luaL_getmetatable(L, "harfbuzz.Blob");
+ lua_setmetatable(L, -2);
+
+ *b = blob;
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static const struct luaL_Reg font_methods[] = {
+ { "__gc", font_destroy },
+ { "set_scale", font_set_scale },
+ { "get_scale", font_get_scale },
+ { "get_h_extents", font_get_h_extents },
+ { "get_v_extents", font_get_v_extents },
+ { "get_glyph_extents", font_get_glyph_extents },
+ { "get_glyph_name", font_get_glyph_name },
+ { "get_glyph_from_name", font_get_glyph_from_name },
+ { "get_glyph_h_advance", font_get_glyph_h_advance },
+ { "get_glyph_v_advance", font_get_glyph_v_advance },
+ { "get_nominal_glyph", font_get_nominal_glyph },
+ { "ot_color_glyph_get_png", font_ot_color_glyph_get_png },
+ { NULL, NULL }
+};
+
+static const struct luaL_Reg font_functions[] = {
+ { "new", font_new },
+ { NULL, NULL }
+};
+
+int register_font(lua_State *L) {
+ return register_class(L, "harfbuzz.Font", font_methods, font_functions, NULL);
+}
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/language.c b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/language.c
new file mode 100644
index 00000000000..9f397e5272a
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/language.c
@@ -0,0 +1,49 @@
+// harfbuzz.Feature
+#include "luaharfbuzz.h"
+
+static int language_new(lua_State *L) {
+ Language *l;
+
+ l = (Language *)lua_newuserdata(L, sizeof(*l));
+ luaL_getmetatable(L, "harfbuzz.Language");
+ lua_setmetatable(L, -2);
+
+ if (lua_gettop(L) == 1 || lua_isnil(L, -2))
+ *l = HB_LANGUAGE_INVALID;
+ else
+ *l = hb_language_from_string(luaL_checkstring(L, -2), -1);
+
+ return 1;
+}
+
+static int language_to_string(lua_State *L) {
+ Language* l = (Language *)luaL_checkudata(L, 1, "harfbuzz.Language");
+ const char *s = hb_language_to_string(*l);
+
+ lua_pushstring(L, s ? s : "");
+ return 1;
+}
+
+static int language_equals(lua_State *L) {
+ Language* lhs = (Language *)luaL_checkudata(L, 1, "harfbuzz.Language");
+ Language* rhs = (Language *)luaL_checkudata(L, 2, "harfbuzz.Language");
+
+ lua_pushboolean(L, *lhs == *rhs);
+
+ return 1;
+}
+
+static const struct luaL_Reg language_methods[] = {
+ { "__tostring", language_to_string },
+ { "__eq", language_equals },
+ { NULL, NULL }
+};
+
+static const struct luaL_Reg language_functions[] = {
+ { "new", language_new },
+ { NULL, NULL }
+};
+
+int register_language(lua_State *L) {
+ return register_class(L, "harfbuzz.Language", language_methods, language_functions, NULL);
+}
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.c b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.c
new file mode 100644
index 00000000000..176c552aa59
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.c
@@ -0,0 +1,131 @@
+#include "luaharfbuzz.h"
+#ifdef LuajitTeX
+static int lua_absindex (lua_State *L, int i) {
+ if (i < 0 && i > LUA_REGISTRYINDEX)
+ i += lua_gettop(L) + 1;
+ return i;
+}
+static int lua_geti (lua_State *L, int index, lua_Integer i) {
+ index = lua_absindex(L, index);
+ lua_pushinteger(L, i);
+ lua_gettable(L, index);
+ return lua_type(L, -1);
+}
+#endif
+
+static int shape_full (lua_State *L) {
+ Font *font = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+ Buffer *buf = (Buffer *)luaL_checkudata(L, 2, "harfbuzz.Buffer");
+ unsigned int i;
+ luaL_checktype(L, 3, LUA_TTABLE);
+ luaL_checktype(L, 4, LUA_TTABLE);
+
+ unsigned int num_features = lua_rawlen(L, 3);
+ Feature *features = (Feature *) malloc (num_features * sizeof(hb_feature_t));
+
+ for (i = 0; i != num_features; ++i) {
+ lua_geti(L, 3, i + 1);
+ Feature* f = (Feature *)luaL_checkudata(L, -1, "harfbuzz.Feature");
+ features[i] = *f;
+ lua_pop(L, 1);
+ }
+
+ const char **shapers = NULL;
+ size_t num_shapers = lua_rawlen(L, 4);
+ if (num_shapers) {
+ shapers = (const char**) calloc (num_shapers + 1, sizeof(char*));
+ for (i = 0; i != num_shapers; ++i) {
+ lua_geti(L, 4, i + 1);
+ shapers[i] = luaL_checkstring(L, -1);
+ lua_pop(L, 1);
+ }
+ }
+
+ // Shape text
+ lua_pushboolean(L, hb_shape_full(*font, *buf, features, num_features, shapers));
+
+ free(features);
+ free(shapers);
+
+ return 1;
+}
+
+static int version (lua_State *L) {
+ lua_pushstring(L, hb_version_string());
+ return 1;
+}
+
+static int list_shapers (lua_State *L) {
+ const char **shaper_list = hb_shape_list_shapers ();
+ int i = 0;
+
+ for (; *shaper_list; shaper_list++) {
+ i++;
+ lua_pushstring(L, *shaper_list);
+ }
+ return i;
+}
+
+static const struct luaL_Reg lib_table [] = {
+ {"shape_full", shape_full},
+ {"version", version},
+ {"shapers", list_shapers},
+ {NULL, NULL}
+};
+
+int luaopen_luaharfbuzz (lua_State *L) {
+ lua_newtable(L);
+
+ register_blob(L);
+ lua_setfield(L, -2, "Blob");
+
+ register_face(L);
+ lua_setfield(L, -2, "Face");
+
+ register_font(L);
+ lua_setfield(L, -2, "Font");
+
+ register_buffer(L);
+ lua_setfield(L, -2, "Buffer");
+
+ register_feature(L);
+ lua_setfield(L, -2, "Feature");
+
+ register_tag(L);
+ lua_setfield(L, -2, "Tag");
+
+ register_script(L);
+ lua_setfield(L, -2, "Script");
+
+ register_direction(L);
+ lua_setfield(L, -2, "Direction");
+
+ register_language(L);
+ lua_setfield(L, -2, "Language");
+
+ register_ot(L);
+ lua_setfield(L, -2, "ot");
+
+ register_unicode(L);
+ lua_setfield(L, -2, "unicode");
+
+#ifdef LuajitTeX
+ luaL_register(L,NULL, lib_table);
+ /**/
+ lua_pushvalue(L, -1);
+ lua_setglobal(L,"luaharfbuzz");
+ /**/
+ lua_getglobal(L, "package");
+ lua_getfield(L, -1, "loaded");
+ lua_remove(L, -2);
+ lua_pushvalue(L, -2);
+ lua_setfield(L, -2, "luaharfbuzz");
+ /**/
+#else
+ luaL_setfuncs(L, lib_table, 0);
+#endif
+
+
+ return 1;
+}
+
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.h b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.h
new file mode 100644
index 00000000000..60f5db9c223
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.h
@@ -0,0 +1,42 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <hb.h>
+#include <hb-ot.h>
+#include <string.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+typedef hb_blob_t* Blob;
+typedef hb_face_t* Face;
+typedef hb_font_t* Font;
+typedef hb_buffer_t* Buffer;
+typedef hb_feature_t Feature;
+typedef hb_tag_t Tag;
+typedef hb_script_t Script;
+typedef hb_direction_t Direction;
+typedef hb_language_t Language;
+
+typedef struct luahb_constant_t {
+ const char *name;
+ int value;
+} luahb_constant_t;
+
+// Functions to create classes and push them onto the stack
+int register_class(lua_State *L, const char *name, const luaL_Reg * methods, const luaL_Reg *functions, const luahb_constant_t* constants);
+int register_blob(lua_State *L);
+int register_face(lua_State *L);
+int register_font(lua_State *L);
+int register_buffer(lua_State *L);
+int register_feature(lua_State *L);
+int register_tag(lua_State *L);
+int register_script(lua_State *L);
+int register_direction(lua_State *L);
+int register_language(lua_State *L);
+int register_ot(lua_State *L);
+int register_unicode(lua_State *L);
+
+// Missed declaration
+int luaopen_luaharfbuzz (lua_State *L);
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/ot.c b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/ot.c
new file mode 100644
index 00000000000..01041cfc9a3
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/ot.c
@@ -0,0 +1,47 @@
+#include "luaharfbuzz.h"
+
+static const struct luahb_constant_t ot_constants[] = {
+ { "NAME_ID_COPYRIGHT", HB_OT_NAME_ID_COPYRIGHT },
+ { "NAME_ID_FONT_FAMILY", HB_OT_NAME_ID_FONT_FAMILY },
+ { "NAME_ID_FONT_SUBFAMILY", HB_OT_NAME_ID_FONT_SUBFAMILY },
+ { "NAME_ID_UNIQUE_ID", HB_OT_NAME_ID_UNIQUE_ID },
+ { "NAME_ID_FULL_NAME", HB_OT_NAME_ID_FULL_NAME },
+ { "NAME_ID_VERSION_STRING", HB_OT_NAME_ID_VERSION_STRING },
+ { "NAME_ID_POSTSCRIPT_NAME", HB_OT_NAME_ID_POSTSCRIPT_NAME },
+ { "NAME_ID_TRADEMARK", HB_OT_NAME_ID_TRADEMARK },
+ { "NAME_ID_MANUFACTURER", HB_OT_NAME_ID_MANUFACTURER },
+ { "NAME_ID_DESIGNER", HB_OT_NAME_ID_DESIGNER },
+ { "NAME_ID_DESCRIPTION", HB_OT_NAME_ID_DESCRIPTION },
+ { "NAME_ID_VENDOR_URL", HB_OT_NAME_ID_VENDOR_URL },
+ { "NAME_ID_DESIGNER_URL", HB_OT_NAME_ID_DESIGNER_URL },
+ { "NAME_ID_LICENSE", HB_OT_NAME_ID_LICENSE },
+ { "NAME_ID_LICENSE_URL", HB_OT_NAME_ID_LICENSE_URL },
+ { "NAME_ID_TYPOGRAPHIC_FAMILY", HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY },
+ { "NAME_ID_TYPOGRAPHIC_SUBFAMILY", HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY },
+ { "NAME_ID_MAC_FULL_NAME", HB_OT_NAME_ID_MAC_FULL_NAME },
+ { "NAME_ID_SAMPLE_TEXT", HB_OT_NAME_ID_SAMPLE_TEXT },
+ { "NAME_ID_CID_FINDFONT_NAME", HB_OT_NAME_ID_CID_FINDFONT_NAME },
+ { "NAME_ID_WWS_FAMILY", HB_OT_NAME_ID_WWS_FAMILY },
+ { "NAME_ID_WWS_SUBFAMILY", HB_OT_NAME_ID_WWS_SUBFAMILY },
+ { "NAME_ID_LIGHT_BACKGROUND", HB_OT_NAME_ID_LIGHT_BACKGROUND },
+ { "NAME_ID_DARK_BACKGROUND", HB_OT_NAME_ID_DARK_BACKGROUND },
+ { "NAME_ID_VARIATIONS_PS_PREFIX", HB_OT_NAME_ID_VARIATIONS_PS_PREFIX },
+ { "NAME_ID_INVALID", HB_OT_NAME_ID_INVALID },
+ { "LAYOUT_NO_SCRIPT_INDEX", HB_OT_LAYOUT_NO_SCRIPT_INDEX },
+ { "LAYOUT_NO_FEATURE_INDEX", HB_OT_LAYOUT_NO_FEATURE_INDEX },
+ { "LAYOUT_DEFAULT_LANGUAGE_INDEX", HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX },
+ { "LAYOUT_NO_VARIATIONS_INDEX", HB_OT_LAYOUT_NO_VARIATIONS_INDEX },
+ { NULL, 0 }
+};
+
+static const struct luaL_Reg ot_methods[] = {
+ { NULL, NULL }
+};
+
+static const struct luaL_Reg ot_functions[] = {
+ { NULL, NULL }
+};
+
+int register_ot(lua_State *L) {
+ return register_class(L, "harfbuzz.ot", ot_methods, ot_functions, ot_constants);
+}
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/script.c b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/script.c
new file mode 100644
index 00000000000..133cc6a0ebb
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/script.c
@@ -0,0 +1,71 @@
+#include "luaharfbuzz.h"
+
+static int new_script_from_string(lua_State *L) {
+ Script *sp = (Script *)lua_newuserdata(L, sizeof(*sp));
+ luaL_getmetatable(L, "harfbuzz.Script");
+ lua_setmetatable(L, -2);
+
+ if (lua_gettop(L) == 1 || lua_isnil(L, -2))
+ *sp = HB_SCRIPT_INVALID;
+ else
+ *sp = hb_script_from_string(luaL_checkstring(L, -2), -1);
+
+ return 1;
+}
+
+static int new_script_from_tag(lua_State *L) {
+ Tag* tp = (Tag *)luaL_checkudata(L, 1, "harfbuzz.Tag");
+
+ Script *sp = (Script *)lua_newuserdata(L, sizeof(*sp));
+ luaL_getmetatable(L, "harfbuzz.Script");
+ lua_setmetatable(L, -2);
+
+ *sp = hb_script_from_iso15924_tag(*tp);
+ return 1;
+}
+
+static int script_to_string(lua_State *L) {
+ Script *script = (Script *)luaL_checkudata(L, 1, "harfbuzz.Script");
+ char s[5];
+
+ hb_tag_to_string(hb_script_to_iso15924_tag(*script), s);
+ s[4] = '\0';
+ lua_pushstring(L, s);
+ return 1;
+}
+
+static int script_to_tag(lua_State *L) {
+ Script *script = (Script *)luaL_checkudata(L, 1, "harfbuzz.Script");
+
+ Tag *tp = (Tag *)lua_newuserdata(L, sizeof(*tp));
+ luaL_getmetatable(L, "harfbuzz.Tag");
+ lua_setmetatable(L, -2);
+
+ *tp = hb_script_to_iso15924_tag(*script);
+ return 1;
+}
+
+static int script_equals(lua_State *L) {
+ Script* lhs = (Script *)luaL_checkudata(L, 1, "harfbuzz.Script");
+ Script* rhs = (Script *)luaL_checkudata(L, 2, "harfbuzz.Script");
+
+ lua_pushboolean(L, *lhs == *rhs);
+ return 1;
+}
+
+static const struct luaL_Reg script_methods[] = {
+ { "__tostring", script_to_string },
+ { "__eq", script_equals },
+ { "to_iso15924_tag", script_to_tag },
+ { NULL, NULL }
+};
+
+static const struct luaL_Reg script_functions[] = {
+ { "new", new_script_from_string },
+ { "from_iso15924_tag", new_script_from_tag },
+ { NULL, NULL }
+};
+
+int register_script(lua_State *L) {
+ return register_class(L, "harfbuzz.Script", script_methods, script_functions, NULL);
+}
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/tag.c b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/tag.c
new file mode 100644
index 00000000000..ec7e4b172e3
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/tag.c
@@ -0,0 +1,50 @@
+// harfbuzz.Feature
+#include "luaharfbuzz.h"
+
+static int tag_new(lua_State *L) {
+ Tag *t;
+
+ t = (Tag *)lua_newuserdata(L, sizeof(*t));
+ luaL_getmetatable(L, "harfbuzz.Tag");
+ lua_setmetatable(L, -2);
+
+ if (lua_gettop(L) == 1 || lua_isnil(L, -2))
+ *t = HB_TAG_NONE;
+ else
+ *t = hb_tag_from_string(luaL_checkstring(L, -2), -1);
+
+ return 1;
+}
+
+static int tag_to_string(lua_State *L) {
+ Tag* t = (Tag *)luaL_checkudata(L, 1, "harfbuzz.Tag");
+ char tag[5];
+
+ hb_tag_to_string(*t, tag);
+ tag[4] = '\0';
+ lua_pushstring(L, tag);
+ return 1;
+}
+
+static int tag_equals(lua_State *L) {
+ Tag* lhs = (Tag *)luaL_checkudata(L, 1, "harfbuzz.Tag");
+ Tag* rhs = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
+
+ lua_pushboolean(L, *lhs == *rhs);
+ return 1;
+}
+
+static const struct luaL_Reg tag_methods[] = {
+ { "__tostring", tag_to_string },
+ { "__eq", tag_equals },
+ { NULL, NULL }
+};
+
+static const struct luaL_Reg tag_functions[] = {
+ { "new", tag_new },
+ { NULL, NULL }
+};
+
+int register_tag(lua_State *L) {
+ return register_class(L, "harfbuzz.Tag", tag_methods, tag_functions, NULL);
+}
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/unicode.c b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/unicode.c
new file mode 100644
index 00000000000..4e887fcd61d
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/unicode.c
@@ -0,0 +1,22 @@
+#include "luaharfbuzz.h"
+
+static int script(lua_State *L) {
+ hb_codepoint_t c = (hb_codepoint_t) luaL_checkinteger(L, -1);
+
+ Script *sp = (Script *)lua_newuserdata(L, sizeof(*sp));
+ luaL_getmetatable(L, "harfbuzz.Script");
+ lua_setmetatable(L, -2);
+
+ *sp = hb_unicode_script(hb_unicode_funcs_get_default(), c);
+ return 1;
+}
+
+static const struct luaL_Reg unicode_functions[] = {
+ { "script", script },
+ { NULL, NULL }
+};
+
+int register_unicode(lua_State *L) {
+ luaL_newlib(L, unicode_functions);
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/status/done.txt b/Build/source/texk/web2c/luatexdir/luaharfbuzz/status/done.txt
new file mode 100644
index 00000000000..fff80d672fd
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/status/done.txt
@@ -0,0 +1,42 @@
+hb_blob_create
+hb_blob_destroy
+hb_blob_get_length
+hb_buffer_add_codepoints
+hb_buffer_add_utf8
+hb_buffer_create
+hb_buffer_destroy
+hb_buffer_get_cluster_level
+hb_buffer_get_direction
+hb_buffer_get_language
+hb_buffer_get_length
+hb_buffer_get_script
+hb_buffer_guess_segment_properties
+hb_buffer_reverse
+hb_buffer_set_cluster_level
+hb_buffer_set_direction
+hb_buffer_set_language
+hb_buffer_set_script
+hb_direction_from_string
+hb_direction_to_string
+hb_face_create
+hb_face_destroy
+hb_face_get_upem
+hb_feature_from_string
+hb_feature_to_string
+hb_font_create
+hb_font_destroy
+hb_font_get_scale
+hb_font_set_scale
+hb_language_from_string
+hb_language_to_string
+hb_script_from_iso15924_tag
+hb_script_from_string
+hb_script_to_iso15924_tag
+hb_shape
+hb_shape_full
+hb_shape_list_shapers
+hb_tag_from_string
+hb_tag_to_string
+hb_unicode_script
+hb_version
+
diff --git a/Build/source/texk/web2c/luatexdir/luaharfbuzz/status/full_api.txt b/Build/source/texk/web2c/luatexdir/luaharfbuzz/status/full_api.txt
new file mode 100644
index 00000000000..3b6728fcefb
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luaharfbuzz/status/full_api.txt
@@ -0,0 +1,429 @@
+hb_aat_layout_feature_type_get_name_id
+hb_aat_layout_feature_type_get_selector_infos
+hb_aat_layout_get_feature_types
+hb_aat_layout_has_positioning
+hb_aat_layout_has_substitution
+hb_aat_layout_has_tracking
+hb_blob_copy_writable_or_fail
+hb_blob_create
+hb_blob_create_from_file
+hb_blob_create_sub_blob
+hb_blob_destroy
+hb_blob_get_data
+hb_blob_get_data_writable
+hb_blob_get_empty
+hb_blob_get_length
+hb_blob_get_user_data
+hb_blob_is_immutable
+hb_blob_make_immutable
+hb_blob_reference
+hb_blob_set_user_data
+hb_buffer_add
+hb_buffer_add_codepoints
+hb_buffer_add_latin1
+hb_buffer_add_utf16
+hb_buffer_add_utf32
+hb_buffer_add_utf8
+hb_buffer_allocation_successful
+hb_buffer_append
+hb_buffer_clear_contents
+hb_buffer_create
+hb_buffer_deserialize_glyphs
+hb_buffer_destroy
+hb_buffer_diff
+hb_buffer_get_cluster_level
+hb_buffer_get_content_type
+hb_buffer_get_direction
+hb_buffer_get_empty
+hb_buffer_get_flags
+hb_buffer_get_glyph_infos
+hb_buffer_get_glyph_positions
+hb_buffer_get_invisible_glyph
+hb_buffer_get_language
+hb_buffer_get_length
+hb_buffer_get_replacement_codepoint
+hb_buffer_get_script
+hb_buffer_get_segment_properties
+hb_buffer_get_unicode_funcs
+hb_buffer_get_user_data
+hb_buffer_guess_segment_properties
+hb_buffer_normalize_glyphs
+hb_buffer_pre_allocate
+hb_buffer_reference
+hb_buffer_reset
+hb_buffer_reverse
+hb_buffer_reverse_clusters
+hb_buffer_reverse_range
+hb_buffer_serialize_format_from_string
+hb_buffer_serialize_format_to_string
+hb_buffer_serialize_glyphs
+hb_buffer_serialize_list_formats
+hb_buffer_set_cluster_level
+hb_buffer_set_content_type
+hb_buffer_set_direction
+hb_buffer_set_flags
+hb_buffer_set_invisible_glyph
+hb_buffer_set_language
+hb_buffer_set_length
+hb_buffer_set_message_func
+hb_buffer_set_replacement_codepoint
+hb_buffer_set_script
+hb_buffer_set_segment_properties
+hb_buffer_set_unicode_funcs
+hb_buffer_set_user_data
+hb_color_get_alpha
+hb_color_get_blue
+hb_color_get_green
+hb_color_get_red
+hb_direction_from_string
+hb_direction_to_string
+hb_face_builder_add_table
+hb_face_builder_create
+hb_face_collect_unicodes
+hb_face_collect_variation_selectors
+hb_face_collect_variation_unicodes
+hb_face_count
+hb_face_create
+hb_face_create_for_tables
+hb_face_destroy
+hb_face_get_empty
+hb_face_get_glyph_count
+hb_face_get_index
+hb_face_get_table_tags
+hb_face_get_upem
+hb_face_get_user_data
+hb_face_is_immutable
+hb_face_make_immutable
+hb_face_reference
+hb_face_reference_blob
+hb_face_reference_table
+hb_face_set_glyph_count
+hb_face_set_index
+hb_face_set_upem
+hb_face_set_user_data
+hb_feature_from_string
+hb_feature_to_string
+hb_font_add_glyph_origin_for_direction
+hb_font_create
+hb_font_create_sub_font
+hb_font_destroy
+hb_font_funcs_create
+hb_font_funcs_destroy
+hb_font_funcs_get_empty
+hb_font_funcs_get_user_data
+hb_font_funcs_is_immutable
+hb_font_funcs_make_immutable
+hb_font_funcs_reference
+hb_font_funcs_set_font_h_extents_func
+hb_font_funcs_set_font_v_extents_func
+hb_font_funcs_set_glyph_contour_point_func
+hb_font_funcs_set_glyph_extents_func
+hb_font_funcs_set_glyph_from_name_func
+hb_font_funcs_set_glyph_func
+hb_font_funcs_set_glyph_h_advance_func
+hb_font_funcs_set_glyph_h_advances_func
+hb_font_funcs_set_glyph_h_kerning_func
+hb_font_funcs_set_glyph_h_origin_func
+hb_font_funcs_set_glyph_name_func
+hb_font_funcs_set_glyph_v_advance_func
+hb_font_funcs_set_glyph_v_advances_func
+hb_font_funcs_set_glyph_v_kerning_func
+hb_font_funcs_set_glyph_v_origin_func
+hb_font_funcs_set_nominal_glyph_func
+hb_font_funcs_set_nominal_glyphs_func
+hb_font_funcs_set_user_data
+hb_font_funcs_set_variation_glyph_func
+hb_font_get_empty
+hb_font_get_extents_for_direction
+hb_font_get_face
+hb_font_get_glyph
+hb_font_get_glyph_advance_for_direction
+hb_font_get_glyph_advances_for_direction
+hb_font_get_glyph_contour_point
+hb_font_get_glyph_contour_point_for_origin
+hb_font_get_glyph_extents
+hb_font_get_glyph_extents_for_origin
+hb_font_get_glyph_from_name
+hb_font_get_glyph_h_advance
+hb_font_get_glyph_h_advances
+hb_font_get_glyph_h_kerning
+hb_font_get_glyph_h_origin
+hb_font_get_glyph_kerning_for_direction
+hb_font_get_glyph_name
+hb_font_get_glyph_origin_for_direction
+hb_font_get_glyph_v_advance
+hb_font_get_glyph_v_advances
+hb_font_get_glyph_v_kerning
+hb_font_get_glyph_v_origin
+hb_font_get_h_extents
+hb_font_get_nominal_glyph
+hb_font_get_parent
+hb_font_get_ppem
+hb_font_get_ptem
+hb_font_get_scale
+hb_font_get_user_data
+hb_font_get_var_coords_normalized
+hb_font_get_variation_glyph
+hb_font_get_v_extents
+hb_font_glyph_from_string
+hb_font_glyph_to_string
+hb_font_is_immutable
+hb_font_make_immutable
+hb_font_reference
+hb_font_set_face
+hb_font_set_funcs
+hb_font_set_funcs_data
+hb_font_set_parent
+hb_font_set_ppem
+hb_font_set_ptem
+hb_font_set_scale
+hb_font_set_user_data
+hb_font_set_var_coords_design
+hb_font_set_var_coords_normalized
+hb_font_set_variations
+hb_font_subtract_glyph_origin_for_direction
+hb_ft_face_create
+hb_ft_face_create_cached
+hb_ft_face_create_referenced
+hb_ft_font_changed
+hb_ft_font_create
+hb_ft_font_create_referenced
+hb_ft_font_get_face
+hb_ft_font_get_load_flags
+hb_ft_font_set_funcs
+hb_ft_font_set_load_flags
+hb_glib_blob_create
+hb_glib_get_unicode_funcs
+hb_glib_script_from_script
+hb_glib_script_to_script
+hb_glyph_info_get_glyph_flags
+hb_gobject_aat_layout_feature_selector_get_type
+hb_gobject_aat_layout_feature_type_get_type
+hb_gobject_blob_get_type
+hb_gobject_buffer_cluster_level_get_type
+hb_gobject_buffer_content_type_get_type
+hb_gobject_buffer_diff_flags_get_type
+hb_gobject_buffer_flags_get_type
+hb_gobject_buffer_get_type
+hb_gobject_buffer_serialize_flags_get_type
+hb_gobject_buffer_serialize_format_get_type
+hb_gobject_direction_get_type
+hb_gobject_face_get_type
+hb_gobject_feature_get_type
+hb_gobject_font_funcs_get_type
+hb_gobject_font_get_type
+hb_gobject_glyph_flags_get_type
+hb_gobject_glyph_info_get_type
+hb_gobject_glyph_position_get_type
+hb_gobject_map_get_type
+hb_gobject_memory_mode_get_type
+hb_gobject_ot_color_palette_flags_get_type
+hb_gobject_ot_layout_glyph_class_get_type
+hb_gobject_ot_math_constant_get_type
+hb_gobject_ot_math_glyph_part_flags_get_type
+hb_gobject_ot_math_glyph_part_get_type
+hb_gobject_ot_math_glyph_variant_get_type
+hb_gobject_ot_math_kern_get_type
+hb_gobject_ot_var_axis_flags_get_type
+hb_gobject_script_get_type
+hb_gobject_segment_properties_get_type
+hb_gobject_set_get_type
+hb_gobject_shape_plan_get_type
+hb_gobject_unicode_combining_class_get_type
+hb_gobject_unicode_funcs_get_type
+hb_gobject_unicode_general_category_get_type
+hb_gobject_user_data_key_get_type
+hb_graphite2_face_get_gr_face
+hb_graphite2_font_get_gr_font
+hb_language_from_string
+hb_language_get_default
+hb_language_to_string
+hb_map_allocation_successful
+hb_map_clear
+hb_map_create
+hb_map_del
+hb_map_destroy
+hb_map_get
+hb_map_get_empty
+hb_map_get_population
+hb_map_get_user_data
+hb_map_has
+hb_map_is_empty
+hb_map_reference
+hb_map_set
+hb_map_set_user_data
+hb_ot_color_glyph_get_layers
+hb_ot_color_glyph_reference_png
+hb_ot_color_glyph_reference_svg
+hb_ot_color_has_layers
+hb_ot_color_has_palettes
+hb_ot_color_has_png
+hb_ot_color_has_svg
+hb_ot_color_palette_color_get_name_id
+hb_ot_color_palette_get_colors
+hb_ot_color_palette_get_count
+hb_ot_color_palette_get_flags
+hb_ot_color_palette_get_name_id
+hb_ot_font_set_funcs
+hb_ot_layout_collect_features
+hb_ot_layout_collect_lookups
+hb_ot_layout_feature_get_characters
+hb_ot_layout_feature_get_lookups
+hb_ot_layout_feature_get_name_ids
+hb_ot_layout_feature_with_variations_get_lookups
+hb_ot_layout_get_attach_points
+hb_ot_layout_get_glyph_class
+hb_ot_layout_get_glyphs_in_class
+hb_ot_layout_get_ligature_carets
+hb_ot_layout_get_size_params
+hb_ot_layout_has_glyph_classes
+hb_ot_layout_has_positioning
+hb_ot_layout_has_substitution
+hb_ot_layout_language_find_feature
+hb_ot_layout_language_get_feature_indexes
+hb_ot_layout_language_get_feature_tags
+hb_ot_layout_language_get_required_feature
+hb_ot_layout_language_get_required_feature_index
+hb_ot_layout_lookup_collect_glyphs
+hb_ot_layout_lookups_substitute_closure
+hb_ot_layout_lookup_substitute_closure
+hb_ot_layout_lookup_would_substitute
+hb_ot_layout_script_find_language
+hb_ot_layout_script_get_language_tags
+hb_ot_layout_script_select_language
+hb_ot_layout_table_choose_script
+hb_ot_layout_table_find_feature_variations
+hb_ot_layout_table_find_script
+hb_ot_layout_table_get_feature_tags
+hb_ot_layout_table_get_lookup_count
+hb_ot_layout_table_get_script_tags
+hb_ot_layout_table_select_script
+hb_ot_math_get_constant
+hb_ot_math_get_glyph_assembly
+hb_ot_math_get_glyph_italics_correction
+hb_ot_math_get_glyph_kerning
+hb_ot_math_get_glyph_top_accent_attachment
+hb_ot_math_get_glyph_variants
+hb_ot_math_get_min_connector_overlap
+hb_ot_math_has_data
+hb_ot_math_is_glyph_extended_shape
+hb_ot_name_get_utf16
+hb_ot_name_get_utf32
+hb_ot_name_get_utf8
+hb_ot_name_list_names
+hb_ot_shape_glyphs_closure
+hb_ot_shape_plan_collect_lookups
+hb_ot_tag_from_language
+hb_ot_tags_from_script
+hb_ot_tags_from_script_and_language
+hb_ot_tags_to_script_and_language
+hb_ot_tag_to_language
+hb_ot_tag_to_script
+hb_ot_var_find_axis
+hb_ot_var_find_axis_info
+hb_ot_var_get_axes
+hb_ot_var_get_axis_count
+hb_ot_var_get_axis_infos
+hb_ot_var_get_named_instance_count
+hb_ot_var_has_data
+hb_ot_var_named_instance_get_design_coords
+hb_ot_var_named_instance_get_postscript_name_id
+hb_ot_var_named_instance_get_subfamily_name_id
+hb_ot_var_normalize_coords
+hb_ot_var_normalize_variations
+hb_script_from_iso15924_tag
+hb_script_from_string
+hb_script_get_horizontal_direction
+hb_script_to_iso15924_tag
+hb_segment_properties_equal
+hb_segment_properties_hash
+hb_set_add
+hb_set_add_range
+hb_set_allocation_successful
+hb_set_clear
+hb_set_create
+hb_set_del
+hb_set_del_range
+hb_set_destroy
+hb_set_get_empty
+hb_set_get_max
+hb_set_get_min
+hb_set_get_population
+hb_set_get_user_data
+hb_set_has
+hb_set_intersect
+hb_set_invert
+hb_set_is_empty
+hb_set_is_equal
+hb_set_is_subset
+hb_set_next
+hb_set_next_range
+hb_set_previous
+hb_set_previous_range
+hb_set_reference
+hb_set_set
+hb_set_set_user_data
+hb_set_subtract
+hb_set_symmetric_difference
+hb_set_union
+hb_shape
+hb_shape_full
+hb_shape_list_shapers
+hb_shape_plan_create
+hb_shape_plan_create2
+hb_shape_plan_create_cached
+hb_shape_plan_create_cached2
+hb_shape_plan_destroy
+hb_shape_plan_execute
+hb_shape_plan_get_empty
+hb_shape_plan_get_shaper
+hb_shape_plan_get_user_data
+hb_shape_plan_reference
+hb_shape_plan_set_user_data
+hb_subset
+hb_subset_input_create_or_fail
+hb_subset_input_destroy
+hb_subset_input_drop_tables_set
+hb_subset_input_get_desubroutinize
+hb_subset_input_get_drop_hints
+hb_subset_input_get_retain_gids
+hb_subset_input_glyph_set
+hb_subset_input_nameid_set
+hb_subset_input_reference
+hb_subset_input_set_desubroutinize
+hb_subset_input_set_drop_hints
+hb_subset_input_set_retain_gids
+hb_subset_input_unicode_set
+hb_tag_from_string
+hb_tag_to_string
+hb_unicode_combining_class
+hb_unicode_compose
+hb_unicode_decompose
+hb_unicode_decompose_compatibility
+hb_unicode_eastasian_width
+hb_unicode_funcs_create
+hb_unicode_funcs_destroy
+hb_unicode_funcs_get_default
+hb_unicode_funcs_get_empty
+hb_unicode_funcs_get_parent
+hb_unicode_funcs_get_user_data
+hb_unicode_funcs_is_immutable
+hb_unicode_funcs_make_immutable
+hb_unicode_funcs_reference
+hb_unicode_funcs_set_combining_class_func
+hb_unicode_funcs_set_compose_func
+hb_unicode_funcs_set_decompose_compatibility_func
+hb_unicode_funcs_set_decompose_func
+hb_unicode_funcs_set_eastasian_width_func
+hb_unicode_funcs_set_general_category_func
+hb_unicode_funcs_set_mirroring_func
+hb_unicode_funcs_set_script_func
+hb_unicode_funcs_set_user_data
+hb_unicode_general_category
+hb_unicode_mirroring
+hb_unicode_script
+hb_variation_from_string
+hb_variation_to_string
+hb_version
+hb_version_atleast
+hb_version_string