Initial commit
This commit is contained in:
commit
ca93f7224c
35
Makefile
Normal file
35
Makefile
Normal file
@ -0,0 +1,35 @@
|
||||
# TEXLIVE_SRC must be a precompiled TEXLIVE build with dynamic libraries
|
||||
TEXLIVE_SRC = $(HOME)/texlive-source
|
||||
# We expect to find a precompiled static library compiled with -fpic here
|
||||
LUA_DIR = $(HOME)/lua/
|
||||
# HarfBuzz also should be compiled static, position independent in a build_meson subdirectory
|
||||
HARFBUZZ_DIR = $(HOME)/harfbuzz
|
||||
# Graphite also should be compiled static, position independent in a build_meson subdirectory
|
||||
GRAPHITE_DIR = $(HOME)/graphite
|
||||
|
||||
HB_INCLUDE_DIRS = $(HARFBUZZ_DIR)/src
|
||||
TL_INCLUDE_DIRS = $(TEXLIVE_SRC)/Work/texk $(TEXLIVE_SRC)/texk
|
||||
LUA_INCLUDE_DIRS = $(LUA_DIR)
|
||||
LINK.so = $(LINK.o) -shared
|
||||
|
||||
LUAHARFBUZZ_SRCS = $(wildcard luaharfbuzz/src/luaharfbuzz/*.c)
|
||||
LUAHARFBUZZ_OBJS = $(patsubst %.c,%.o,$(LUAHARFBUZZ_SRCS))
|
||||
|
||||
override CFLAGS += -fpic -DHAVE_DECL_ISASCII=1 $(patsubst %,-I%,$(INCLUDE_DIRS))
|
||||
override LDFLAGS += -Wl,linkscript.ld
|
||||
# For Windows instead:
|
||||
# override LDFLAGS += -Wl,-version-script=versionscript
|
||||
|
||||
luaharfbuzz/src/luaharfbuzz/%.o: INCLUDE_DIRS = $(HB_INCLUDE_DIRS) $(LUA_INCLUDE_DIRS)
|
||||
luametalatex-kpse/lkpselib.o: INCLUDE_DIRS = $(TL_INCLUDE_DIRS) $(LUA_INCLUDE_DIRS)
|
||||
|
||||
luametalatex.so: luametalatex-kpse/lkpselib.o $(LUAHARFBUZZ_OBJS) $(TEXLIVE_SRC)/Work/texk/kpathsea/.libs/libkpathsea.a $(HARFBUZZ_DIR)/build_meson/src/libharfbuzz.a $(GRAPHITE_DIR)/build/src/libgraphite2.a $(LUA_DIR)/liblua.a
|
||||
|
||||
%.so:
|
||||
$(LINK.so) $^ $(LOADLIBES) $(LDLIBS) -o $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm $(LUAHARFBUZZ_OBJS) luametalatex-kpse/lkpselib.o luametalatex.so
|
||||
|
||||
# lkpselib.o: lkpselib.c
|
1
libs.lua
Normal file
1
libs.lua
Normal file
@ -0,0 +1 @@
|
||||
print(require'luametalatex.kpse', require'luametalatex.harfbuzz')
|
9
linkscript.ld
Normal file
9
linkscript.ld
Normal file
@ -0,0 +1,9 @@
|
||||
luaopen_luametalatex_kpse = luaopen_kpse;
|
||||
luaopen_luametalatex_harfbuzz = luaopen_luaharfbuzz;
|
||||
|
||||
VERSION {
|
||||
{
|
||||
global: luaopen_luametalatex_*;
|
||||
local: *;
|
||||
};
|
||||
}
|
13
luaharfbuzz/.busted
Normal file
13
luaharfbuzz/.busted
Normal file
@ -0,0 +1,13 @@
|
||||
return {
|
||||
_all = {
|
||||
coverage = true,
|
||||
verbose = true,
|
||||
ROOT = { "spec" }
|
||||
},
|
||||
default = {
|
||||
["exclude-tags"] = "mac"
|
||||
},
|
||||
mac = {
|
||||
tags = "mac"
|
||||
}
|
||||
}
|
11
luaharfbuzz/.gitignore
vendored
Normal file
11
luaharfbuzz/.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
*.la
|
||||
*.lo
|
||||
*.o
|
||||
*.so
|
||||
.libs/*
|
||||
build/*
|
||||
luacov.report.out
|
||||
luacov.stats.out
|
||||
.luacheckcache
|
||||
api
|
||||
*.src.rock
|
13
luaharfbuzz/.luacheckrc
Normal file
13
luaharfbuzz/.luacheckrc
Normal file
@ -0,0 +1,13 @@
|
||||
cache = true
|
||||
files["spec/"].std = "+busted"
|
||||
files["examples/luatex/"].globals = {
|
||||
"texio",
|
||||
"fontloader",
|
||||
"callback",
|
||||
"tex",
|
||||
"node",
|
||||
"read_font",
|
||||
"unicode",
|
||||
"font"
|
||||
}
|
||||
|
22
luaharfbuzz/LICENSE
Normal file
22
luaharfbuzz/LICENSE
Normal file
@ -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.
|
||||
|
15
luaharfbuzz/Makefile
Normal file
15
luaharfbuzz/Makefile
Normal file
@ -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
|
165
luaharfbuzz/README.md
Normal file
165
luaharfbuzz/README.md
Normal file
@ -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>.
|
2
luaharfbuzz/THANKS
Normal file
2
luaharfbuzz/THANKS
Normal file
@ -0,0 +1,2 @@
|
||||
Simon Cozens
|
||||
Michal Hoftich
|
9
luaharfbuzz/config.ld
Normal file
9
luaharfbuzz/config.ld
Normal file
@ -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'
|
108
luaharfbuzz/docs/examples/core_types.lua.html
Normal file
108
luaharfbuzz/docs/examples/core_types.lua.html
Normal file
@ -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>
|
2829
luaharfbuzz/docs/index.html
Normal file
2829
luaharfbuzz/docs/index.html
Normal file
File diff suppressed because it is too large
Load Diff
303
luaharfbuzz/docs/ldoc.css
Normal file
303
luaharfbuzz/docs/ldoc.css
Normal file
@ -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; }
|
||||
|
52
luaharfbuzz/examples/core_types.lua
Normal file
52
luaharfbuzz/examples/core_types.lua
Normal file
@ -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}))
|
||||
|
1
luaharfbuzz/fixtures/AppleGothic_korean_issue_22.json
Normal file
1
luaharfbuzz/fixtures/AppleGothic_korean_issue_22.json
Normal file
@ -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}]
|
1
luaharfbuzz/fixtures/amiri-regular_123.json
Normal file
1
luaharfbuzz/fixtures/amiri-regular_123.json
Normal file
@ -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}]
|
1
luaharfbuzz/fixtures/amiri-regular_123_numr.json
Normal file
1
luaharfbuzz/fixtures/amiri-regular_123_numr.json
Normal file
@ -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}]
|
1
luaharfbuzz/fixtures/notonastaliq_U06CC_U06C1.json
Normal file
1
luaharfbuzz/fixtures/notonastaliq_U06CC_U06C1.json
Normal file
@ -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}]
|
BIN
luaharfbuzz/fonts/Rajdhani-Regular.ttf
Executable file
BIN
luaharfbuzz/fonts/Rajdhani-Regular.ttf
Executable file
Binary file not shown.
BIN
luaharfbuzz/fonts/TwitterColorEmoji-SVGinOT.ttf
Normal file
BIN
luaharfbuzz/fonts/TwitterColorEmoji-SVGinOT.ttf
Normal file
Binary file not shown.
BIN
luaharfbuzz/fonts/amiri-regular.ttf
Normal file
BIN
luaharfbuzz/fonts/amiri-regular.ttf
Normal file
Binary file not shown.
BIN
luaharfbuzz/fonts/amiriquran-colored.ttf
Normal file
BIN
luaharfbuzz/fonts/amiriquran-colored.ttf
Normal file
Binary file not shown.
BIN
luaharfbuzz/fonts/notocoloremoji-subset.ttf
Normal file
BIN
luaharfbuzz/fonts/notocoloremoji-subset.ttf
Normal file
Binary file not shown.
BIN
luaharfbuzz/fonts/notonastaliq.ttf
Normal file
BIN
luaharfbuzz/fonts/notonastaliq.ttf
Normal file
Binary file not shown.
334
luaharfbuzz/inspect.lua
Normal file
334
luaharfbuzz/inspect.lua
Normal file
@ -0,0 +1,334 @@
|
||||
local inspect ={
|
||||
_VERSION = 'inspect.lua 3.1.0',
|
||||
_URL = 'http://github.com/kikito/inspect.lua',
|
||||
_DESCRIPTION = 'human-readable representations of tables',
|
||||
_LICENSE = [[
|
||||
MIT LICENSE
|
||||
|
||||
Copyright (c) 2013 Enrique García Cota
|
||||
|
||||
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.
|
||||
]]
|
||||
}
|
||||
|
||||
local tostring = tostring
|
||||
|
||||
inspect.KEY = setmetatable({}, {__tostring = function() return 'inspect.KEY' end})
|
||||
inspect.METATABLE = setmetatable({}, {__tostring = function() return 'inspect.METATABLE' end})
|
||||
|
||||
local function rawpairs(t)
|
||||
return next, t, nil
|
||||
end
|
||||
|
||||
-- Apostrophizes the string if it has quotes, but not aphostrophes
|
||||
-- Otherwise, it returns a regular quoted string
|
||||
local function smartQuote(str)
|
||||
if str:match('"') and not str:match("'") then
|
||||
return "'" .. str .. "'"
|
||||
end
|
||||
return '"' .. str:gsub('"', '\\"') .. '"'
|
||||
end
|
||||
|
||||
-- \a => '\\a', \0 => '\\0', 31 => '\31'
|
||||
local shortControlCharEscapes = {
|
||||
["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n",
|
||||
["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v"
|
||||
}
|
||||
local longControlCharEscapes = {} -- \a => nil, \0 => \000, 31 => \031
|
||||
for i=0, 31 do
|
||||
local ch = string.char(i)
|
||||
if not shortControlCharEscapes[ch] then
|
||||
shortControlCharEscapes[ch] = "\\"..i
|
||||
longControlCharEscapes[ch] = string.format("\\%03d", i)
|
||||
end
|
||||
end
|
||||
|
||||
local function escape(str)
|
||||
return (str:gsub("\\", "\\\\")
|
||||
:gsub("(%c)%f[0-9]", longControlCharEscapes)
|
||||
:gsub("%c", shortControlCharEscapes))
|
||||
end
|
||||
|
||||
local function isIdentifier(str)
|
||||
return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" )
|
||||
end
|
||||
|
||||
local function isSequenceKey(k, sequenceLength)
|
||||
return type(k) == 'number'
|
||||
and 1 <= k
|
||||
and k <= sequenceLength
|
||||
and math.floor(k) == k
|
||||
end
|
||||
|
||||
local defaultTypeOrders = {
|
||||
['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4,
|
||||
['function'] = 5, ['userdata'] = 6, ['thread'] = 7
|
||||
}
|
||||
|
||||
local function sortKeys(a, b)
|
||||
local ta, tb = type(a), type(b)
|
||||
|
||||
-- strings and numbers are sorted numerically/alphabetically
|
||||
if ta == tb and (ta == 'string' or ta == 'number') then return a < b end
|
||||
|
||||
local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb]
|
||||
-- Two default types are compared according to the defaultTypeOrders table
|
||||
if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb]
|
||||
elseif dta then return true -- default types before custom ones
|
||||
elseif dtb then return false -- custom types after default ones
|
||||
end
|
||||
|
||||
-- custom types are sorted out alphabetically
|
||||
return ta < tb
|
||||
end
|
||||
|
||||
-- For implementation reasons, the behavior of rawlen & # is "undefined" when
|
||||
-- tables aren't pure sequences. So we implement our own # operator.
|
||||
local function getSequenceLength(t)
|
||||
local len = 1
|
||||
local v = rawget(t,len)
|
||||
while v ~= nil do
|
||||
len = len + 1
|
||||
v = rawget(t,len)
|
||||
end
|
||||
return len - 1
|
||||
end
|
||||
|
||||
local function getNonSequentialKeys(t)
|
||||
local keys, keysLength = {}, 0
|
||||
local sequenceLength = getSequenceLength(t)
|
||||
for k,_ in rawpairs(t) do
|
||||
if not isSequenceKey(k, sequenceLength) then
|
||||
keysLength = keysLength + 1
|
||||
keys[keysLength] = k
|
||||
end
|
||||
end
|
||||
table.sort(keys, sortKeys)
|
||||
return keys, keysLength, sequenceLength
|
||||
end
|
||||
|
||||
local function countTableAppearances(t, tableAppearances)
|
||||
tableAppearances = tableAppearances or {}
|
||||
|
||||
if type(t) == 'table' then
|
||||
if not tableAppearances[t] then
|
||||
tableAppearances[t] = 1
|
||||
for k,v in rawpairs(t) do
|
||||
countTableAppearances(k, tableAppearances)
|
||||
countTableAppearances(v, tableAppearances)
|
||||
end
|
||||
countTableAppearances(getmetatable(t), tableAppearances)
|
||||
else
|
||||
tableAppearances[t] = tableAppearances[t] + 1
|
||||
end
|
||||
end
|
||||
|
||||
return tableAppearances
|
||||
end
|
||||
|
||||
local copySequence = function(s)
|
||||
local copy, len = {}, #s
|
||||
for i=1, len do copy[i] = s[i] end
|
||||
return copy, len
|
||||
end
|
||||
|
||||
local function makePath(path, ...)
|
||||
local keys = {...}
|
||||
local newPath, len = copySequence(path)
|
||||
for i=1, #keys do
|
||||
newPath[len + i] = keys[i]
|
||||
end
|
||||
return newPath
|
||||
end
|
||||
|
||||
local function processRecursive(process, item, path, visited)
|
||||
if item == nil then return nil end
|
||||
if visited[item] then return visited[item] end
|
||||
|
||||
local processed = process(item, path)
|
||||
if type(processed) == 'table' then
|
||||
local processedCopy = {}
|
||||
visited[item] = processedCopy
|
||||
local processedKey
|
||||
|
||||
for k,v in rawpairs(processed) do
|
||||
processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited)
|
||||
if processedKey ~= nil then
|
||||
processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited)
|
||||
end
|
||||
end
|
||||
|
||||
local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited)
|
||||
if type(mt) ~= 'table' then mt = nil end -- ignore not nil/table __metatable field
|
||||
setmetatable(processedCopy, mt)
|
||||
processed = processedCopy
|
||||
end
|
||||
return processed
|
||||
end
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
local Inspector = {}
|
||||
local Inspector_mt = {__index = Inspector}
|
||||
|
||||
function Inspector:puts(...)
|
||||
local args = {...}
|
||||
local buffer = self.buffer
|
||||
local len = #buffer
|
||||
for i=1, #args do
|
||||
len = len + 1
|
||||
buffer[len] = args[i]
|
||||
end
|
||||
end
|
||||
|
||||
function Inspector:down(f)
|
||||
self.level = self.level + 1
|
||||
f()
|
||||
self.level = self.level - 1
|
||||
end
|
||||
|
||||
function Inspector:tabify()
|
||||
self:puts(self.newline, string.rep(self.indent, self.level))
|
||||
end
|
||||
|
||||
function Inspector:alreadyVisited(v)
|
||||
return self.ids[v] ~= nil
|
||||
end
|
||||
|
||||
function Inspector:getId(v)
|
||||
local id = self.ids[v]
|
||||
if not id then
|
||||
local tv = type(v)
|
||||
id = (self.maxIds[tv] or 0) + 1
|
||||
self.maxIds[tv] = id
|
||||
self.ids[v] = id
|
||||
end
|
||||
return tostring(id)
|
||||
end
|
||||
|
||||
function Inspector:putKey(k)
|
||||
if isIdentifier(k) then return self:puts(k) end
|
||||
self:puts("[")
|
||||
self:putValue(k)
|
||||
self:puts("]")
|
||||
end
|
||||
|
||||
function Inspector:putTable(t)
|
||||
if t == inspect.KEY or t == inspect.METATABLE then
|
||||
self:puts(tostring(t))
|
||||
elseif self:alreadyVisited(t) then
|
||||
self:puts('<table ', self:getId(t), '>')
|
||||
elseif self.level >= self.depth then
|
||||
self:puts('{...}')
|
||||
else
|
||||
if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end
|
||||
|
||||
local nonSequentialKeys, nonSequentialKeysLength, sequenceLength = getNonSequentialKeys(t)
|
||||
local mt = getmetatable(t)
|
||||
|
||||
self:puts('{')
|
||||
self:down(function()
|
||||
local count = 0
|
||||
for i=1, sequenceLength do
|
||||
if count > 0 then self:puts(',') end
|
||||
self:puts(' ')
|
||||
self:putValue(t[i])
|
||||
count = count + 1
|
||||
end
|
||||
|
||||
for i=1, nonSequentialKeysLength do
|
||||
local k = nonSequentialKeys[i]
|
||||
if count > 0 then self:puts(',') end
|
||||
self:tabify()
|
||||
self:putKey(k)
|
||||
self:puts(' = ')
|
||||
self:putValue(t[k])
|
||||
count = count + 1
|
||||
end
|
||||
|
||||
if type(mt) == 'table' then
|
||||
if count > 0 then self:puts(',') end
|
||||
self:tabify()
|
||||
self:puts('<metatable> = ')
|
||||
self:putValue(mt)
|
||||
end
|
||||
end)
|
||||
|
||||
if nonSequentialKeysLength > 0 or type(mt) == 'table' then -- result is multi-lined. Justify closing }
|
||||
self:tabify()
|
||||
elseif sequenceLength > 0 then -- array tables have one extra space before closing }
|
||||
self:puts(' ')
|
||||
end
|
||||
|
||||
self:puts('}')
|
||||
end
|
||||
end
|
||||
|
||||
function Inspector:putValue(v)
|
||||
local tv = type(v)
|
||||
|
||||
if tv == 'string' then
|
||||
self:puts(smartQuote(escape(v)))
|
||||
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
|
||||
tv == 'cdata' or tv == 'ctype' then
|
||||
self:puts(tostring(v))
|
||||
elseif tv == 'table' then
|
||||
self:putTable(v)
|
||||
else
|
||||
self:puts('<', tv, ' ', self:getId(v), '>')
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
function inspect.inspect(root, options)
|
||||
options = options or {}
|
||||
|
||||
local depth = options.depth or math.huge
|
||||
local newline = options.newline or '\n'
|
||||
local indent = options.indent or ' '
|
||||
local process = options.process
|
||||
|
||||
if process then
|
||||
root = processRecursive(process, root, {}, {})
|
||||
end
|
||||
|
||||
local inspector = setmetatable({
|
||||
depth = depth,
|
||||
level = 0,
|
||||
buffer = {},
|
||||
ids = {},
|
||||
maxIds = {},
|
||||
newline = newline,
|
||||
indent = indent,
|
||||
tableAppearances = countTableAppearances(root)
|
||||
}, Inspector_mt)
|
||||
|
||||
inspector:putValue(root)
|
||||
|
||||
return table.concat(inspector.buffer)
|
||||
end
|
||||
|
||||
setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end })
|
||||
|
||||
return inspect
|
||||
|
46
luaharfbuzz/luaharfbuzz-1.1.0-1.rockspec
Normal file
46
luaharfbuzz/luaharfbuzz-1.1.0-1.rockspec
Normal file
@ -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"
|
||||
}
|
||||
}
|
48
luaharfbuzz/luaharfbuzz-scm-1.rockspec
Normal file
48
luaharfbuzz/luaharfbuzz-scm-1.rockspec
Normal file
@ -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"
|
||||
}
|
||||
}
|
2
luaharfbuzz/scripts/generate_harfbuzz_api_list.sh
Executable file
2
luaharfbuzz/scripts/generate_harfbuzz_api_list.sh
Executable file
@ -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
|
11
luaharfbuzz/scripts/generate_hb_shape_json.sh
Executable file
11
luaharfbuzz/scripts/generate_hb_shape_json.sh
Executable file
@ -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
|
236
luaharfbuzz/spec/buffer_spec.lua
Normal file
236
luaharfbuzz/spec/buffer_spec.lua
Normal file
@ -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)
|
||||
|
||||
|
541
luaharfbuzz/spec/harfbuzz_spec.lua
Normal file
541
luaharfbuzz/spec/harfbuzz_spec.lua
Normal file
@ -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)
|
||||
|
157
luaharfbuzz/spec/shaping_spec.lua
Normal file
157
luaharfbuzz/spec/shaping_spec.lua
Normal file
@ -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)
|
84
luaharfbuzz/src/harfbuzz.lua
Normal file
84
luaharfbuzz/src/harfbuzz.lua
Normal file
@ -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
|
535
luaharfbuzz/src/harfbuzz.luadoc
Normal file
535
luaharfbuzz/src/harfbuzz.luadoc
Normal file
@ -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 `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
|
60
luaharfbuzz/src/luaharfbuzz/blob.c
Normal file
60
luaharfbuzz/src/luaharfbuzz/blob.c
Normal file
@ -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);
|
||||
}
|
338
luaharfbuzz/src/luaharfbuzz/buffer.c
Normal file
338
luaharfbuzz/src/luaharfbuzz/buffer.c
Normal file
@ -0,0 +1,338 @@
|
||||
#include "luaharfbuzz.h"
|
||||
|
||||
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;
|
||||
|
||||
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 (unsigned int 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);
|
||||
}
|
25
luaharfbuzz/src/luaharfbuzz/class_utils.c
Normal file
25
luaharfbuzz/src/luaharfbuzz/class_utils.c
Normal file
@ -0,0 +1,25 @@
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
luaL_setfuncs(L, methods, 0);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_newtable(L);
|
||||
luaL_setfuncs(L, functions, 0);
|
||||
luaL_getmetatable(L, name);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
84
luaharfbuzz/src/luaharfbuzz/direction.c
Normal file
84
luaharfbuzz/src/luaharfbuzz/direction.c
Normal file
@ -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);
|
||||
}
|
466
luaharfbuzz/src/luaharfbuzz/face.c
Normal file
466
luaharfbuzz/src/luaharfbuzz/face.c
Normal file
@ -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);
|
||||
}
|
110
luaharfbuzz/src/luaharfbuzz/feature.c
Normal file
110
luaharfbuzz/src/luaharfbuzz/feature.c
Normal file
@ -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);
|
||||
}
|
218
luaharfbuzz/src/luaharfbuzz/font.c
Normal file
218
luaharfbuzz/src/luaharfbuzz/font.c
Normal file
@ -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);
|
||||
}
|
49
luaharfbuzz/src/luaharfbuzz/language.c
Normal file
49
luaharfbuzz/src/luaharfbuzz/language.c
Normal file
@ -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);
|
||||
}
|
102
luaharfbuzz/src/luaharfbuzz/luaharfbuzz.c
Normal file
102
luaharfbuzz/src/luaharfbuzz/luaharfbuzz.c
Normal file
@ -0,0 +1,102 @@
|
||||
#include "luaharfbuzz.h"
|
||||
|
||||
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");
|
||||
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 (unsigned int 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 (unsigned int 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");
|
||||
|
||||
luaL_setfuncs(L, lib_table, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
39
luaharfbuzz/src/luaharfbuzz/luaharfbuzz.h
Normal file
39
luaharfbuzz/src/luaharfbuzz/luaharfbuzz.h
Normal file
@ -0,0 +1,39 @@
|
||||
#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);
|
47
luaharfbuzz/src/luaharfbuzz/ot.c
Normal file
47
luaharfbuzz/src/luaharfbuzz/ot.c
Normal file
@ -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);
|
||||
}
|
71
luaharfbuzz/src/luaharfbuzz/script.c
Normal file
71
luaharfbuzz/src/luaharfbuzz/script.c
Normal file
@ -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);
|
||||
}
|
50
luaharfbuzz/src/luaharfbuzz/tag.c
Normal file
50
luaharfbuzz/src/luaharfbuzz/tag.c
Normal file
@ -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);
|
||||
}
|
33
luaharfbuzz/src/luaharfbuzz/texput.log
Normal file
33
luaharfbuzz/src/luaharfbuzz/texput.log
Normal file
@ -0,0 +1,33 @@
|
||||
This is LuaHBTeX, Version 1.11.2 (TeX Live 2020/dev) (format=luahbtex 2019.12.5) 11 DEC 2019 21:17
|
||||
restricted system commands enabled.
|
||||
**\relax
|
||||
|
||||
*\directlua{print(luaharfbuzz.Tag.new"ab ")}
|
||||
|
||||
*\directlua{print(luaharfbuzz.Tag.new"ab " .. 'c')}
|
||||
[\directlua]:1: attempt to concatenate a harfbuzz.Tag value
|
||||
stack traceback:
|
||||
[\directlua]:1: in main chunk.
|
||||
<*> ...ctlua{print(luaharfbuzz.Tag.new"ab " .. 'c')}
|
||||
|
||||
? \directlua{print(tostring(luaharfbuzz.Tag.new"ab ") .. 'c')}
|
||||
Type <return> to proceed, S to scroll future error messages,
|
||||
R to run without stopping, Q to run quietly,
|
||||
I to insert something,
|
||||
1 or ... or 9 to ignore the next 1 to 9 tokens of input,
|
||||
H for help, X to quit.
|
||||
?
|
||||
|
||||
*\directlua{print(tostring(luaharfbuzz.Tag.new"ab ") .. 'c')}
|
||||
|
||||
*directlua{print(tostring(luaharfbuzz.Tag.new"ab") .. 'c')}
|
||||
|
||||
*\directlua{print(tostring(luaharfbuzz.Tag.new"ab") .. 'c')}
|
||||
|
||||
*
|
||||
! Emergency stop.
|
||||
<*> ...int(tostring(luaharfbuzz.Tag.new"ab") .. 'c')}
|
||||
|
||||
End of file on the terminal!
|
||||
|
||||
! ==> Fatal error occurred, no output PDF file produced!
|
22
luaharfbuzz/src/luaharfbuzz/unicode.c
Normal file
22
luaharfbuzz/src/luaharfbuzz/unicode.c
Normal file
@ -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;
|
||||
}
|
42
luaharfbuzz/status/done.txt
Normal file
42
luaharfbuzz/status/done.txt
Normal file
@ -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
|
||||
|
429
luaharfbuzz/status/full_api.txt
Normal file
429
luaharfbuzz/status/full_api.txt
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user