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()
|
||||