From 764c120b0f946e526591b2c2f0cd839ad3d5912e Mon Sep 17 00:00:00 2001 From: "P. Baudin" Date: Sat, 19 Mar 2022 18:49:15 +0100 Subject: [PATCH] first public issue of fontforge-of-ocaml library under license LGPL 2.1 --- .gitignore | 1 + CHANGES.md | 3 + LICENSE.md | 15 + Makefile | 77 ++ README.md | 67 ++ dune | 21 + dune-project | 42 + fontforge-of-ocaml.opam | 45 + fontforge-of-ocaml.opam.template | 17 + headers/headache_config.txt | 39 + headers/license.txt | 17 + images/author.png | Bin 0 -> 23013 bytes images/fontforge-of-ocaml.png | Bin 0 -> 9868 bytes licenses/LGPLv2.1 | 458 ++++++++ src/Core.ml | 620 +++++++++++ src/Core.mli | 1176 ++++++++++++++++++++ src/FontForge.ml | 22 + src/FontForge.mli | 1740 ++++++++++++++++++++++++++++++ src/LookupTables.ml | 721 +++++++++++++ src/LookupTables.mli | 631 +++++++++++ src/Util.ml | 231 ++++ src/Util.mli | 119 ++ src/dune | 32 + tests/FreeMono.ttf | Bin 0 -> 361228 bytes tests/FreeMonoBold.ttf | Bin 0 -> 184480 bytes tests/Makefile | 43 + tests/dune | 38 + tests/test_FontForgeLib.log | 97 ++ tests/test_FontForgeLib.ml | 328 ++++++ 29 files changed, 6600 insertions(+) create mode 100644 .gitignore create mode 100644 CHANGES.md create mode 100644 LICENSE.md create mode 100644 Makefile create mode 100644 README.md create mode 100644 dune create mode 100644 dune-project create mode 100644 fontforge-of-ocaml.opam create mode 100644 fontforge-of-ocaml.opam.template create mode 100644 headers/headache_config.txt create mode 100644 headers/license.txt create mode 100644 images/author.png create mode 100644 images/fontforge-of-ocaml.png create mode 100644 licenses/LGPLv2.1 create mode 100644 src/Core.ml create mode 100644 src/Core.mli create mode 100644 src/FontForge.ml create mode 100644 src/FontForge.mli create mode 100644 src/LookupTables.ml create mode 100644 src/LookupTables.mli create mode 100644 src/Util.ml create mode 100644 src/Util.mli create mode 100644 src/dune create mode 100644 tests/FreeMono.ttf create mode 100644 tests/FreeMonoBold.ttf create mode 100644 tests/Makefile create mode 100644 tests/dune create mode 100644 tests/test_FontForgeLib.log create mode 100644 tests/test_FontForgeLib.ml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba65b13 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/_build/ diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..ce7ebd2 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,3 @@ +## v1.1.0 + +### First public release diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..e505653 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,15 @@ +# License of fontforge-of-ocaml library # + +The [fontforge-of-ocaml](https://github.com/pbaudin/[fontforge-of-ocaml) library is published under the license [LGPL v2.1](https://spdx.org/licenses/LGPL-2.1-only.html). + +About this library, +you can redistribute it and/or modify it under the terms of the GNU +Lesser General Public License as published by the Free Software +Foundation, version 2.1. + +It is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU Lesser General Public License version 2.1 +for more details (enclosed in the file [licenses/LGPLv2.1](licenses/LGPLv2.1)) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6f6762c --- /dev/null +++ b/Makefile @@ -0,0 +1,77 @@ +############################################################################## +# # +# This file is part of fontforge-of-ocaml library # +# # +# Copyright (C) 2017-2022, Patrick BAUDIN # +# (https://github.com/pbaudin/fontforge-of-ocaml) # +# # +# you can redistribute it and/or modify it under the terms of the GNU # +# Lesser General Public License as published by the Free Software # +# Foundation, version 2.1. # +# # +# It is distributed in the hope that it will be useful, but WITHOUT ANY # +# WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. # +# # +# See the GNU Lesser General Public License version 2.1 # +# for more details (enclosed in the file licenses/LGPLv2.1) # +# # +############################################################################## + +.PHONY: all build clean + +PACKAGE=fontforge-of-ocaml + +all: $(PACKAGE).opam build + +build: + dune build @install + +$(PACKAGE).opam: $(PACKAGE).opam.template dune-project + rm -f $@ + dune build $@ + +PHONY: clean +clean: + rm -fr _build + +############################################################################## + +.PHONY: tests +tests: + dune build @runtest + +############################################################################## + +.PHONY: install uninstall + +FFOO_INSTALLDIR?="" + +install: +ifeq ($(FFOO_INSTALLDIR),"") + dune install +else + dune install --prefix ${FFOO_INSTALLDIR} +endif + +uninstall: +ifeq ($(FFOO_INSTALLDIR),"") + dune uninstall +else + dune uninstall --prefix ${FFOO_INSTALLDIR} +endif + +############################################################################## + +.PHONY: headers + +HEADER_FILES:=dune dune-project headers/headache_config.txt Makefile +HEADER_FILES+=src/dune $(wildcard src/*.ml) $(wildcard src/*.mli) +HEADER_FILES+=tests/dune tests/Makefile $(wildcard tests/*.ml) $(wildcard tests/*.mli) + +HEADACHE=headache -c headers/headache_config.txt -h headers/license.txt + +headers: + $(HEADACHE) $(HEADER_FILES) + +############################################################################## diff --git a/README.md b/README.md new file mode 100644 index 0000000..0838b75 --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +

+ +

+ +Copyright (C) 2017-2022, P. Baudin (https://github.com/pbaudin/fontforge-of-ocaml) + +

+
+ +
+ +# OCaml binding to FontForge # + +## Library usage ## + +The `fontforge-of-ocaml` library is published under the [LGPL v2.1](LICENSE.md) license and its API is documented in the file [src/FontForge.mli](src/FontForge.mli). + +### Example of use ### + +Look at the included test file [tests/test_FontForgeLib.ml](tests/test_FontForgeLib.ml). + +### Notice ### + +The binding is incomplete, but don't forget that the library is able to load `.fea` ([OpenType Feature](https://opentypecookbook.com/putting-it-together)) files to design complex fonts. + +### Installation ### + +The library can easily be installed from source-based package manager [Opam](https://opam.ocaml.org/) +from a [pin](https://opam.ocaml.org/doc/Manual.html#Pinning) to this GitHub repository: +```bash +$ opam pin https://github.com/pbaudin/fontforge-of-ocaml +``` + +On Ubuntu, the library relies on `python3-fontforge` package that contains the `python3` binding to `FontForge`: +```bash +$ sudo apt-get install -y python3-fontforge +``` + +## Contributing ## + +Since the library meets my needs, I won't complete the binding from myself. +Nevertheless, if you want to contribute you are welcome. +Don't hesitate to open an issue for that and why not propose a pull request. + +## The story ## + +### Preamble ### + +This library was developed in 2017 and used for the design of several [Advanced Cross-Stitch Fonts](https://github.com/pbaudin/ACSF). +Five years later, it time to publish the `fontforge-of-ocaml` library even if the binding is incomplete. + +### Development ### + +The first version of that library was written in [`OCaml`](https://ocaml.org/) and +used the [`Lymp`](https://github.com/dbousque/lymp) library allowing you to use `Python` functions and objects of `FontForge` API from `OCaml` world. + +The `FontForge` API imposes type constraints between the arguments of the functions managing the contextual font tables. +In order to offer an `OCaml` API as close as the `FontForge` API, the use of [Generalized Algebraic Data Type](https://caml.inria.fr/pub/docs/manual-ocaml/gadts.html) of `OCaml` was seen as an opportunity. +That has not been so much used due to some bugs in the `Lymp` library raised by the hudge number of calls from `OCaml` to `Python`. +A work around has been found in generating an intermediate file (specifying the [`OpenType Feature Data`](https://opentypecookbook.com/putting-it-together/) to use in a `.fea` file) to build the final fonts from `FontForge Python` API and the `OCaml` binding. That explains why the development of the `FontForge` binding was stopped earlier that expected. + +In the meantime, `Fontforge` API migrated to `Python 3` and the `Lymp` library was no more able to perform the binding with newer versions of `OCaml` compiler and various libraries. +Nevertheless, with few effort the `Lymp` library was easily replaced by the [`PyMl`](https://github.com/thierry-martinez/pyml) library. + +

+ +

diff --git a/dune b/dune new file mode 100644 index 0000000..b4ed2f1 --- /dev/null +++ b/dune @@ -0,0 +1,21 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; This file is part of fontforge-of-ocaml library ;; +;; ;; +;; Copyright (C) 2017-2022, Patrick BAUDIN ;; +;; (https://github.com/pbaudin/fontforge-of-ocaml) ;; +;; ;; +;; you can redistribute it and/or modify it under the terms of the GNU ;; +;; Lesser General Public License as published by the Free Software ;; +;; Foundation, version 2.1. ;; +;; ;; +;; It is distributed in the hope that it will be useful, but WITHOUT ANY ;; +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or ;; +;; FITNESS FOR A PARTICULAR PURPOSE. ;; +;; ;; +;; See the GNU Lesser General Public License version 2.1 ;; +;; for more details (enclosed in the file licenses/LGPLv2.1) ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(dirs src tests) diff --git a/dune-project b/dune-project new file mode 100644 index 0000000..237f676 --- /dev/null +++ b/dune-project @@ -0,0 +1,42 @@ +(lang dune 2.8) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; This file is part of fontforge-of-ocaml library ;; +;; ;; +;; Copyright (C) 2017-2022, Patrick BAUDIN ;; +;; (https://github.com/pbaudin/fontforge-of-ocaml) ;; +;; ;; +;; you can redistribute it and/or modify it under the terms of the GNU ;; +;; Lesser General Public License as published by the Free Software ;; +;; Foundation, version 2.1. ;; +;; ;; +;; It is distributed in the hope that it will be useful, but WITHOUT ANY ;; +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or ;; +;; FITNESS FOR A PARTICULAR PURPOSE. ;; +;; ;; +;; See the GNU Lesser General Public License version 2.1 ;; +;; for more details (enclosed in the file licenses/LGPLv2.1) ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(generate_opam_files true) + +(name fontforge-of-ocaml) +(maintainers "https://github.com/pbaudin/fontforge-of-ocaml") + +(package + (name fontforge-of-ocaml) + (depends + (ocaml (>= 4.09.0)) + (base (>= v0.12.2)) + (fmt (>= 0.8.9 )) + (pyml (>= 20200518 )) + (ppx_python (>= v0.12.0)) + ) + (depopts + (headache (>= 1.05)) + ) + ; (conflict ...) + (tags ("font" "fontforge" "binding") + ) +) diff --git a/fontforge-of-ocaml.opam b/fontforge-of-ocaml.opam new file mode 100644 index 0000000..647aa8c --- /dev/null +++ b/fontforge-of-ocaml.opam @@ -0,0 +1,45 @@ +# This file is generated by dune, edit dune-project instead +tags: ["font" "fontforge" "binding"] +depends: [ + "dune" {>= "2.8"} + "ocaml" {>= "4.09.0"} + "base" {>= "v0.12.2"} + "fmt" {>= "0.8.9"} + "pyml" {>= "20200518"} + "ppx_python" {>= "v0.12.0"} + "odoc" {with-doc} +] +depopts: [ + "headache" {>= "1.05"} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +opam-version: "2.0" +name: "fontforge-of-ocaml" +version: "1.1.0" +synopsis: "OCaml binding of FontForge" +description: """ +Library providing OCaml binding of FontForge Python API +""" +maintainer: "http://github.com/pbaudin" +authors: [ + "Patrick Baudin" +] +license: "LGPL-2.1-only" +homepage: "http://github.com/pbaudin/fontforge-of-ocaml" +bug-reports: "https://github.com/pbaudin/fontforge-of-ocaml" +messages: [ +] +dev-repo: "git+https://github.com/pbaudin/fontforge-of-ocaml" diff --git a/fontforge-of-ocaml.opam.template b/fontforge-of-ocaml.opam.template new file mode 100644 index 0000000..e0dfb98 --- /dev/null +++ b/fontforge-of-ocaml.opam.template @@ -0,0 +1,17 @@ +opam-version: "2.0" +name: "fontforge-of-ocaml" +version: "1.1.0" +synopsis: "OCaml binding of FontForge" +description: """ +Library providing OCaml binding of FontForge Python API +""" +maintainer: "http://github.com/pbaudin" +authors: [ + "Patrick Baudin" +] +license: "LGPL-2.1-only" +homepage: "http://github.com/pbaudin/fontforge-of-ocaml" +bug-reports: "https://github.com/pbaudin/fontforge-of-ocaml" +messages: [ +] +dev-repo: "git+https://github.com/pbaudin/fontforge-of-ocaml" diff --git a/headers/headache_config.txt b/headers/headache_config.txt new file mode 100644 index 0000000..9b910ed --- /dev/null +++ b/headers/headache_config.txt @@ -0,0 +1,39 @@ +############################################################################## +# # +# This file is part of fontforge-of-ocaml library # +# # +# Copyright (C) 2017-2022, Patrick BAUDIN # +# (https://github.com/pbaudin/fontforge-of-ocaml) # +# # +# you can redistribute it and/or modify it under the terms of the GNU # +# Lesser General Public License as published by the Free Software # +# Foundation, version 2.1. # +# # +# It is distributed in the hope that it will be useful, but WITHOUT ANY # +# WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. # +# # +# See the GNU Lesser General Public License version 2.1 # +# for more details (enclosed in the file licenses/LGPLv2.1) # +# # +############################################################################## + +## Usage +# headache -c headache_config.txt -h license.txt ... + +## Dune ## +# note: the skip directive requires a filename starting by ".*" +# since the skip directive looks at the full path-name +| "dune-project" -> frame open:";;" line:";" close:";;" +| ".*dune-project" -> skip match:"(lang.*" +| "dune" -> frame open:";;" line:";" close:";;" + +## Makefile ## +| "Make.*" -> frame open:"#" line:"#" close:"#" + +## Shell scripts ## +| ".*\.sh" -> frame open:"#" line:"#" close:"#" +| ".*\.sh" -> skip match:"#!.*" + +## Headache config ## +| "headache_config.txt" -> frame open:"#" line:"#" close:"#" diff --git a/headers/license.txt b/headers/license.txt new file mode 100644 index 0000000..a721609 --- /dev/null +++ b/headers/license.txt @@ -0,0 +1,17 @@ + +This file is part of fontforge-of-ocaml library + +Copyright (C) 2017-2022, Patrick BAUDIN + (https://github.com/pbaudin/fontforge-of-ocaml) + +you can redistribute it and/or modify it under the terms of the GNU +Lesser General Public License as published by the Free Software +Foundation, version 2.1. + +It is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU Lesser General Public License version 2.1 +for more details (enclosed in the file licenses/LGPLv2.1) + diff --git a/images/author.png b/images/author.png new file mode 100644 index 0000000000000000000000000000000000000000..311f3a0361b9ca97a12a51aaf29252b97cec7a72 GIT binary patch literal 23013 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 tail | Some x -> (f x)::tail +(***********************************************************) +module type Attr = sig + type t + type attr + val name: string + val get: t -> attr + val set: t -> attr -> unit +end +(**************) +module Member(V:sig type attr val typ:attr Value.obj end)(O:sig type t end)(X:sig val attr:string end) = struct + type t = O.t Object.t + type attr = V.attr + let name = X.attr + let get : t -> attr = API.get ~typ:V.typ ~m:X.attr + let set : t -> attr -> unit = fun o v -> API.set ~typ:V.typ ~m:X.attr o v +end +(*******) +module BoolAttr = Member(struct type attr = bool let typ = Value.Bool end) +module IntAttr = Member(struct type attr = int let typ = Value.Int end) +module FloatAttr = Member(struct type attr = float let typ = Value.Float end) +module StringAttr = Member(struct type attr = string let typ = Value.String end) +module SelectionAttr = Member(struct type attr = Object.selection Object.t let typ = Value.Object Object.Selection end) +(***********************************************************) +module PsMat = struct + type t = Object.matrix Object.t + let api = matrix_api (API.call_function Import.psMat) + (*** FUNCTIONS ********) + let compose ~mat1 mat2 = api ~m:"compose" [v_matrix mat1;v_matrix mat2] + let identity () = api ~m:"identify" [] + let inverse mat = api ~m:"inverse" [v_matrix mat] + let rotate theta = api ~m:"rotate" [v_float theta] + let scale ?y x = api ~m:"scale" ((v_float x)::(a_opt v_float y)) + let skew theta = api ~m:"skew" [v_float theta] + let translate ~x ~y = api ~m:"translate" [v_float x;v_float y] +end +(***********************************************************) +module Point = struct + type t = Object.point Object.t + (****************************) + module BoolAttr = BoolAttr(struct type t = Object.point end) + module FloatAttr = FloatAttr(struct type t = Object.point end) + (* ATTRIBUTE TYPES ********) + module type BoolAttr = Attr with type t = t and type attr = bool + module type FloatAttr = Attr with type t = t and type attr = float + (* ATTRIBUTES ********) + module X = FloatAttr(struct let attr = "x" end) + module Y = FloatAttr(struct let attr = "y" end) + module On_curve = BoolAttr(struct let attr = "on_curve" end) + module Selected = BoolAttr(struct let attr = "selected" end) + (*** METHODS ********) + let dup = point_api API.call_method ~m:"dup" [] + let transform ~matrix = unit_api API.call_method ~m:"transform" [v_matrix matrix] + (* let reduce *) +end +(***********************************************************) +module Contour = struct + type t = Object.contour Object.t + (****************************) + module BoolAttr = BoolAttr(struct type t = Object.contour end) + module StringAttr = StringAttr(struct type t = Object.contour end) + (* ATTRIBUTE TYPES ********) + module type BoolAttr = Attr with type t = t and type attr = bool + module type StringAttr = Attr with type t = t and type attr = string + (* ATTRIBUTES ********) + module Is_quadratic = BoolAttr(struct let attr = "is_quadratic" end) + module Closed = BoolAttr(struct let attr = "closed" end) + module Name = StringAttr(struct let attr = "name" end) + (* ITERATORS ********) + let iterator o = Py.Object.get_iter Object.(python_of o) + let iter ~f o = Py.Iter.iter (fun pypt -> f (Object.of_python ~typ:(Object.Point) pypt)) (iterator o) + let iteri ~f o = let i = ref 0 in let f pt = f !i pt in iter ~f o + let to_list o = Py.Iter.to_list_map (Object.of_python ~typ:(Object.Point)) (iterator o) + let map ~f o = Py.Iter.to_list_map (fun pypt -> f (Object.of_python ~typ:(Object.Point) pypt)) (iterator o) + let mapi ~f o = let i = ref 0 in let f pt = f !i pt in map ~f o + let fold ~init ~f o = Py.Iter.fold_left (fun acc pypt -> f acc (Object.of_python ~typ:(Object.Point) pypt)) init (iterator o) + (* BUILT-IN METHODS ********) + (* let len = API.size *) + let len = int_api API.call_method ~m:"__len__" [] + exception Index_out_of_bounds + let nth i o = + if not (0 <= i && i < len o) then raise Index_out_of_bounds; + point_api API.call_method ~m:"__getitem__" [v_int i] o + let set_nth i pt o = + if not (0 <= i && i < len o) then raise Index_out_of_bounds; + unit_api API.call_method ~m:"__setitem__" [v_int i;v_point pt]o + let add_contour c = contour_api API.call_method ~m:"__add__" [v_contour c] + let add_point pt = contour_api API.call_method ~m:"__add__" [v_point pt] + let append_contour c = unit_api API.call_method ~m:"__iadd__" [v_contour c] + let append_point pt = unit_api API.call_method ~m:"__iadd__" [v_point pt] + let contains_point pt = bool_api API.call_method ~m:"__contains__" [v_point pt] + let contains_coord xy = bool_api API.call_method ~m:"__contains__" [v_coord xy] + let extract ~min ~max o = + let contour = contour_api (API.call_function Import.fontforge) ~m:"contour" [] in + (let exception Stop in + try + iteri ~f:(fun i pt -> if min <= i && i < max && min <= max then append_point pt contour + else if max <= i then raise Stop) o ; + with Stop -> ()); + contour + (* METHODS ********) + let dup = contour_api API.call_method ~m:"dup" [] + let isEmpty = bool_api API.call_method ~m:"isEmpty" [] + let moveTo x y = unit_api API.call_method ~m:"moveTo" ((v_float x)::[v_float y]) + let moveToCoord (x,y) = moveTo x y + let moveTo ~x ~y = moveTo (Float.of_int x) (Float.of_int y) + let lineTo x y ?nth = unit_api API.call_method ~m:"lineTo" ((v_float x)::(v_float y)::(a_opt v_int nth)) + let lineToCoord (x,y) ?nth= lineTo x y ?nth + let lineTo ~x ~y ?nth = lineTo (Float.of_int x) (Float.of_int y) ?nth + let cubicToCoord ~cp1 ~cp2 ~pt ?nth = unit_api API.call_method ~m:"cubicTo" ((v_coord cp1)::(v_coord cp2)::(v_coord pt)::(a_opt v_int nth)) + let cubicTo ~cpx1 ~cpy1 ~cpx2 ~cpy2 ~x ~y ?nth = cubicToCoord ~cp1:Float.((of_int cpx1),(of_int cpy1)) ~cp2:Float.((of_int cpx2),(of_int cpy2)) ~pt:Float.((of_int x),(of_int y)) ?nth + let quadraticToCoord ~cp:(x1,y1) ~pt:(x,y) ?nth = unit_api API.call_method ~m:"quadraticTo" ((v_float x1)::(v_float y1)::(v_float x)::(v_float y)::(a_opt v_int nth)) + let quadraticTo ~cpx ~cpy ~x ~y ?nth = quadraticToCoord ~cp:Float.((of_int cpx),(of_int cpy)) ~pt:Float.((of_int x),(of_int y)) ?nth + let insertPt x y ?(onCurve=false) ?nth = unit_api API.call_method ~m:"insertPoint" ((v_float x)::(v_float y)::(v_bool onCurve)::(a_opt v_int nth)) + let insertPtCoord ~pt:(x,y) ?onCurve ?nth = insertPt x y ?onCurve ?nth + let insertPt ~x ~y ?onCurve ?nth = insertPt (Float.of_int x) (Float.of_int y) ?onCurve ?nth + let insertPoint ~pt ?nth = unit_api API.call_method ~m:"insertPoint" ((v_point pt)::(a_opt v_int nth)) + let makeFirst x = unit_api API.call_method ~m:"makeFirst" [v_int x] + let isClockwise = int_api API.call_method ~m:"isClockwise" [] + let reverseDirection = unit_api API.call_method ~m:"reverseDirection" [] + (* similar *) + (* xBoundsAtY *) + (* yBoundsAtX *) + (* addExtrema *) + (* cluster *) + let merge x = unit_api API.call_method ~m:"merge" (List.map ~f:v_int x) + let round ?factor = unit_api API.call_method ~m:"round" (a_opt v_float factor) + (* simplify *) + let selfIntersects = bool_api API.call_method ~m:"selfIntersects" [] + let transform ~matrix = unit_api API.call_method ~m:"transform" [v_matrix matrix] + (* boundingBox *) + (* getSplineAfterPoint *) + let draw x = unit_api API.call_method ~m:"draw" [v_glyphPen x] +end +(***********************************************************) +module Layer = struct + type t = Object.layer Object.t +end +(***********************************************************) +module GlyphPen = struct + type t = Object.glyphPen Object.t + (* METHODS ********) + let addComponent ~glyphname ~transform = unit_api API.call_method ~m:"addComponent" [v_string glyphname;v_matrix transform] + let closePath = unit_api API.call_method ~m:"closePath" [] + let curveTo ~cp1 ?cp2 ~pt = unit_api API.call_method ~m:"curveTo" ((v_coord cp1)::(a_opt ~tail:[v_coord pt] v_coord cp2)) + let endPath = unit_api API.call_method ~m:"endPath" [] + let lineTo x y = unit_api API.call_method ~m:"lineTo" [v_float x;v_float y] + let lineToCoord (x,y) = lineTo x y + let lineTo ~x ~y = lineTo (Float.of_int x) (Float.of_int y) + let moveTo x y = unit_api API.call_method ~m:"moveTo" [v_float x;v_float y] + let moveToCoord (x,y) = moveTo x y + let moveTo ~x ~y = moveTo (Float.of_int x) (Float.of_int y) + let qcurveTo ~cps ?pt = unit_api API.call_method ~m:"qcurveTo" (List.append (List.map ~f:v_coord cps) (a_opt v_coord pt)) + (* METHODS implemented via extFontForge ********) + let finalize _o = () (* unit_api (API.call_function Import.extFontForge) ~m:"finalize" [v_glyphPen _o] *) +end +(***********************************************************) +module Glyph = struct + type t = Object.glyph Object.t + (****************************) + module BoolAttr = BoolAttr(struct type t = Object.glyph end) + module IntAttr = IntAttr(struct type t = Object.glyph end) + module StringAttr = StringAttr(struct type t = Object.glyph end) + (* ATTRIBUTE TYPES ********) + module type BoolAttr = Attr with type t = t and type attr = bool + module type IntAttr = Attr with type t = t and type attr = int + module type StringAttr = Attr with type t = t and type attr = string + (* ATTRIBUTES ********) + module ActiveLayer = IntAttr(struct let attr = "activeLayer" end) + (* module Altuni *) + (* module AnchorPoints *) + (* module AnchorPointsWithSel *) + (* module Background *) + module Changed = BoolAttr(struct let attr = "changed" end) + module Color = IntAttr(struct let attr = "color" end) + (* module Comment *) + (* module Dhints *) + (* module Foreground *) + module Glyphclass = StringAttr(struct let attr = "glyphclass" end) + module Glyphname = StringAttr(struct let attr = "glyphname" end) + (* module Hhints *) + (* module HorizontalComponents *) + (* module HorizontalComponentsItalicCorrection *) + (* module HorizontalVariants *) + module IsExtendedShape = BoolAttr(struct let attr = "isExtendedShape" end) + module ItalicCorrection = IntAttr(struct let attr = "italicCorrection" end) + (* module Layers *) + (* module Layerrefs *) + (* module Lcarets *) + module Left_side_bearing = IntAttr(struct let attr = "left_side_bearing" end) + (* module ManualHints *) + (* module MathKern *) + module Right_side_bearing = IntAttr(struct let attr = "right_side_bearing" end) + (* module Temporary *) + module Texheight = IntAttr(struct let attr = "texheight" end) + module Texdepth = IntAttr(struct let attr = "textdepth" end) + module Topaccent = IntAttr(struct let attr = "topaccent" end) + (* module Ttinstrs *) + module Unicode = IntAttr(struct let attr = "unicode" end) + module UnlinkRmOvrlpSave = IntAttr(struct let attr = "unlinkRmOvrlpSave" end) + (* module Userdata *) + (* module VerticalComponents *) + (* module VerticalComponentsItalicCorrection *) + (* module VerticalVariants *) + (* module Vhints *) + module Vwidth = IntAttr(struct let attr = "vwidth" end) + module Width = IntAttr(struct let attr = "width" end) + (* READ ONLY ATTRIBUTES ********) + let encoding = int_api API.get ~m:"encoding" + let font = font_api API.get ~m:"font" + let originalgid = int_api API.get ~m:"originalgid" + (* READ ONLY ATTRIBUTES OR METHODS ?? ********) + let layer_cnt = int_api API.call_method ~m:"layer_cnt" [] + let script = string_api API.call_method ~m:"script" [] + let validation_state = int_api API.call_method ~m:"validation_state" [] + (* METHODS ********) + (* let addAnchorPoint *) + let addExtrema ?(flags="only_good") ?emsize = unit_api API.call_method ~m:"addExtrema" ((v_string flags)::(a_opt v_int emsize)) + let addReference ~glyphname ?transform = unit_api API.call_method ~m:"addReference" ((v_string glyphname)::(a_opt v_matrix transform)) + let addHint ~is_vertical ~start ~width = unit_api API.call_method ~m:"addHint" [v_bool is_vertical;v_float start;v_float width] + let addPosSub subtable args = unit_api API.call_method ~m:"addPosSub" + LookupTables.Table.((v_string (get_subtable_name subtable))::(values (get_lookup_type (get_lookup_table subtable)) args)) + (* let appendAccent *) + let autoHint = unit_api API.call_method ~m:"autoHint" [] + let autoInstr = unit_api API.call_method ~m:"autoInstr" [] + let autoTrace = unit_api API.call_method ~m:"autoTrace" [] + let build = unit_api API.call_method ~m:"build" [] + let canonicalContours = unit_api API.call_method ~m:"canonicalContours" [] + let canonicalStart = unit_api API.call_method ~m:"canonicalStart" [] + (* let changeWeight *) + let condenseExtend ~c_factor ~c_add ?(sb_factor=c_factor) ?(sb_add=c_add) ?correct = unit_api API.call_method ~m:"condenseExtend" + ((v_float c_factor)::(v_float c_add)::(v_float sb_factor)::(v_float sb_add)::(a_opt v_bool correct)) + let clear = unit_api API.call_method ~m:"clear" [] + let cluster ?(within=0.1) ?max = unit_api API.call_method ~m:"cluster" ((v_float within)::(a_opt v_float max)) + let correctDirection = unit_api API.call_method ~m:"correctDirection" [] + let exclude layer = unit_api API.call_method ~m:"exclude" [v_layer layer] + (* let export *) + (* let getPosSub: string -> t -> ?? *) + let importOutlines ~filename ?(flags=[]) = unit_api API.call_method ~m:"importOutlines" ((v_string filename)::(List.map ~f:v_string flags)) + let intersect = unit_api API.call_method ~m:"intersect" [] + let isWorthOutputting = bool_api API.call_method ~m:"isWorthOutputting" [] + let preserveLayerAsUndo ?layer_dohints = match layer_dohints with + | None -> unit_api API.call_method ~m:"preserveLayerAsUndo" [] + | Some (layer,dohints) -> unit_api API.call_method ~m:"preserveLayerAsUndo" [v_int layer;v_bool dohints] + let removeOverlap = unit_api API.call_method ~m:"removeOverlap" [] + let removePosSub ~name = unit_api API.call_method ~m:"removePosSub" [v_string name] + let round ?factor = unit_api API.call_method ~m:"round" (a_opt v_int factor) + let selfIntersects = bool_api API.call_method ~m:"selfIntersects" [] + (* let simplify *) + (* let stroke *) + let transform ~matrix ?(flags=[]) = unit_api API.call_method ~m:"transform" ((v_matrix matrix)::(List.map ~f:v_string flags)) + let nltransform ~xexpr ~yexpr = unit_api API.call_method ~m:"nltransform" [v_string xexpr; v_string yexpr] + let unlinkRef ?refname = unit_api API.call_method ~m:"unlinkRef" (a_opt v_string refname) + let unlinkThisGlyph = unit_api API.call_method ~m:"unlinkThisGlyph" [] + let useRefsMetrics ~name ?flag = unit_api API.call_method ~m:"useRefsMetrics" ((v_string name)::(a_opt v_bool flag)) + let validate ?force = int_api API.call_method ~m:"validate" (a_opt v_bool force) + let draw pen = unit_api API.call_method ~m:"draw" [v_glyphPen pen] + let glyphPen ?(replace=false) = glyphPen_api API.call_method ~m:"glyphPen" (if replace then [v_string "replace"] else []) +end +(***********************************************************) +module Selection = struct + type t = Object.selection Object.t + (* MISC ********) + type request_t = + | Sint of int + | Sstr of string + | Sglyph of Glyph.t + let code i = Sint i + let glyphname s = Sstr s + let glyph x = Sglyph x + let v_flag flag = string_comb_api Value.value [flag] + let v_flag_encoding = v_flag "encoding" + (* METHODS ********) + let select_from_encoding ~encoding = unit_api API.call_method ~m:"select" [v_flag_encoding;v_int encoding] + let select_from_unicode ~unicode = unit_api API.call_method ~m:"select" [v_int unicode] + let select_from_glyphname ~name = unit_api API.call_method ~m:"select" [v_string name] + let select ?(encoding=false) ?less ?(ranges=false) ~request = + let flags = [] in + let flags = match less with | None -> flags | Some x -> ((if x then "less" else "more")::flags) in + let flags = if ranges then "ranges"::flags else flags in + let flags = if encoding then "encoding":: flags else flags in + let flags = match flags with + | [] -> [] + | [f1] -> [v_flag f1] + | [f1;f2] -> [v_string_list [ f1 ; f2]] + | [f1;f2;f3] -> [v_string_list [ f1 ; f2 ; f3] ] + | _ -> assert false + in + let encode a = function + | Sint x -> (v_int x)::a + | Sstr x -> (v_string x)::a + | Sglyph x -> (v_glyph x)::a + in + let args = List.rev (List.fold ~f:encode ~init:flags request) in + unit_api API.call_method ~m:"select" args + + let all = unit_api API.call_method ~m:"all" [] + let none = unit_api API.call_method ~m:"none" [] + let changed = unit_api API.call_method ~m:"changed" [] + let invert = unit_api API.call_method ~m:"invert" [] + (* ATTRIBUTES **) + let byGlyphs = selection_api API.get ~m:"byGlyphs" + (* ITERATORS ********) + let iterator o = Py.Object.get_iter Object.(python_of o) + let is_slot = Py.Int.check + exception UnspecifiedSlotIteration + exception UnspecifiedGlyphIteration + let iter ?(slot=fun _ -> raise UnspecifiedSlotIteration) ?(glyph = fun _ -> raise UnspecifiedGlyphIteration) o = + Py.Iter.iter (fun x -> if is_slot x then slot (Py.Int.to_int x) else glyph (Object.of_python ~typ:(Object.Glyph) x) + + ) (iterator o) +end +(***********************************************************) +module Font = struct + type t = Object.font Object.t + + (* METHODS implemented via extFontForge ********) + + let glyph_from_name ~glyphname o = glyph_api API.call_method ~m:"__getitem__" [v_string glyphname] o + let glyph_from_code ~unicode o = glyph_api API.call_method ~m:"__getitem__" [v_int unicode] o + (* METHODS ********) + let contains_glyphname ~glyphname = bool_api API.call_method ~m:"__contains__" [v_string glyphname] + let contains_unicode ~unicode = bool_api API.call_method ~m:"__contains__" [v_int unicode] + let addAnchorClass ~subtable ~anchorclass = unit_api API.call_method ~m:"addAnchorClass" [v_string subtable;v_string anchorclass] + (* let addKerningClass *) + type lookup_script_t = LookupTables.Script.t + let lookupScript ~script ~languages = LookupTables.Script.mk ~languages script + type lookup_feature_t = LookupTables.Feature.lookup_feature_t + let lookupFeature ~feature ~scripts = ((feature, scripts):lookup_feature_t) + let addLookup lookuptable lookuptype ~flags feature ?(others=[]) ?after_lookupname = unit_api API.call_method ~m:"addLookup" + ((v_string (LookupTables.Table.get_lookup_name lookuptable)):: + (v_string (LookupTables.Table.get_lookup_typename lookuptype)):: + (v_string_list flags):: + (LookupTables.TypedFeature.value (feature::others)):: + (a_opt v_string after_lookupname)) + let addLookupSubtable subtable ?after_subtable = unit_api API.call_method ~m:"addLookupSubtable" + LookupTables.Table.((v_string (get_lookup_name (get_lookup_table subtable))):: + (v_string (get_subtable_name subtable)):: + (a_opt v_string after_subtable)) + + (* addContextualSubtable *) + (* addSmallCaps *) + (* alterKerningClass *) + (* autoKern *) + (* appendSFNTName *) + let buildOrReplaceAALTFeatures = unit_api API.call_method ~m:"buildOrReplaceAALTFeatures" [] + let cidConvertByCMap ~filename = unit_api API.call_method ~m:"cidConvertByCMap" [v_string filename] + let cidFlattenByCMap ~filename = unit_api API.call_method ~m:"cidFlattenByCMap" [v_string filename] + (* cidConvertTo *) + let cidFlatten = unit_api API.call_method ~m:"cidFlatten" [] + let cidInsertBlankSubFont = unit_api API.call_method ~m:"cidInsertBlankSubFont" [] + let cidRemoveSubFont = unit_api API.call_method ~m:"cidRemoveSubFont" [] + let close = unit_api API.call_method ~m:"close" [] + (* let compareFonts *) + let createChar ~unicode ?name = glyph_api API.call_method ~m:"createChar" ((v_int unicode)::(a_opt v_string name)) + (* let createInterpolatedGlyph *) + (* let createMappedChar *) + (* let find *) + (* let findEncodingSlot *) + (* let glyphs *) + (* TODO: optional args for [generate] *) + let generate ~filename = unit_api API.call_method ~m:"generate" [v_string filename] + (* let generateTtc *) + (* let generateFeatureFile *) + (* let genericGlyphChange *) + (* let getKerningClass *) + (* let getLookupInfo *) + (* let getLookupSubtables *) + (* let getLookupSubtableAnchorClasses *) + (* let getLookupOfSubtable *) + (* let getSubtableOfAnchor *) + (* let importBitmaps *) + (* let importLookups *) + (* let interpolateFonts *) + (* let isKerningClass *) + (* let isVerticalKerning *) + (* let italicize *) + (*TODO: use the same as for addLookup *) + let lookupSetFeatureList ~lookupname ~features = unit_api API.call_method ~m:"lookupSetFeatureList" [v_string lookupname; v_feature_list features] + let lookupSetFlags ~lookupname ~flags = unit_api API.call_method ~m:"lookupSetFlags" (List.map ~f:v_string (lookupname::flags)) + let lookupSetStoreLigatureInAfm ~lookupname ~store = unit_api API.call_method ~m:"lookupSetStoreLigatureInAfm" [v_string lookupname;v_bool store] + let mergeFonts ~filename ?preserveCrossFontKerning = unit_api API.call_method ~m:"mergeFonts" ((v_string filename)::(a_opt v_bool preserveCrossFontKerning)) + let mergeFeature ~filename = unit_api API.call_method ~m:"mergeFeature" [v_string filename] + let mergeKern ~filename = unit_api API.call_method ~m:"mergeKern" [v_string filename] + let mergeLookups ~lookupname1 ~lookupname2 = unit_api API.call_method ~m:"mergeLookup" [v_string lookupname1;v_string lookupname2] + let mergeLookupSubtables ~subtable1 ~subtable2 = unit_api API.call_method ~m:"mergeLookupSubtables" [v_string subtable1;v_string subtable2] + (* let printSample *) + (* Returns a random text sample using the letter frequencies of the specified script (and optionally language). + Both script and language should be expressed as strings containing OpenType Script and Language tags. + "dflt" is a reasonable language tag. + If the language is not specified, one will be chosen at random. + If FontForge has no frequency information for the script/language specified it will use the letters in the script with equal frequencies. *) + let randomText ~script ?lang = string_api API.call_method ~m:"randomText" ((v_string script)::(a_opt v_string lang)) + let regenBitmaps ~sizes = unit_api API.call_method ~m:"regenBitmaps" (List.map ~f:v_int sizes) + let removeAnchorClass ~anchorclass = unit_api API.call_method ~m:"removeAnchorClass" [v_string anchorclass] + let removeLookup ~lookup = unit_api API.call_method ~m:"removeLookup" [v_string lookup] + let removeLookupSubtable ~subtable = unit_api API.call_method ~m:"removeLookupSubtable" [v_string subtable] + let removeGlyph_from_unicode ~unicode = unit_api API.call_method ~m:"removeGlyph" [v_int unicode] + let removeGlyph_from_glyphname ~glyphname = unit_api API.call_method ~m:"removeGlyph" [v_string glyphname] + let removeGlyph_from_glyph ~glyph = unit_api API.call_method ~m:"removeGlyph" [v_glyph glyph] + let removeGlyph = function + | Selection.Sint unicode -> removeGlyph_from_unicode ~unicode + | Selection.Sstr glyphname -> removeGlyph_from_glyphname ~glyphname + | Selection.Sglyph glyph -> removeGlyph_from_glyph ~glyph + + type replace_spec_t = Value.t list + let from_Layer ~srch ~rpl = List.map ~f:v_layer [srch; rpl] + let from_Contour ~srch ~rpl = List.map ~f:v_contour [srch; rpl] + let replaceAll ~spec ?error_bound = unit_api API.call_method ~m:"replaceAll" (List.append spec (a_opt v_float error_bound)) + let replaceAll_from_Layer ~srch ~rpl = replaceAll ~spec:(from_Layer ~srch ~rpl) + let replaceAll_from_Contour ~srch ~rpl = replaceAll ~spec:(from_Contour ~srch ~rpl) + let revert = unit_api API.call_method ~m:"revert" [] + let revertFromBackup = unit_api API.call_method ~m:"revertFromBackup" [] + let save ~filename = unit_api API.call_method ~m:"saveName" [v_string filename] + let saveNamelist ~filename = unit_api API.call_method ~m:"saveNamelist" [v_string filename] + let getTableData ~tablename = string_api API.call_method ~m:"getTableData" [v_string tablename] + (* let setTableData *) + let validate ?force = int_api API.call_method ~m:"validate" (a_opt v_bool force) + + let addExtrema = unit_api API.call_method ~m:"addExtrema" [] + let addSmallCaps = unit_api API.call_method ~m:"addSmallCaps" [] + let autoHint = unit_api API.call_method ~m:"autoHint" [] + let autoInstr = unit_api API.call_method ~m:"autoInstr" [] + let autoTrace = unit_api API.call_method ~m:"autoTrace" [] + let build = unit_api API.call_method ~m:"build" [] + let canonicalContours = unit_api API.call_method ~m:"canonicalContours" [] + let canonicalStart = unit_api API.call_method ~m:"canonicalStart" [] + let clear = unit_api API.call_method ~m:"clear" [] + let copy = unit_api API.call_method ~m:"copy" [] + let copyReference = unit_api API.call_method ~m:"copyReference" [] + let correctDirection = unit_api API.call_method ~m:"correctDirection" [] + let correctReferences = unit_api API.call_method ~m:"correctReferences" [] + let cut = unit_api API.call_method ~m:"cut" [] + let paste = unit_api API.call_method ~m:"paste" [] + let intersect = unit_api API.call_method ~m:"intersect" [] + let pasteInto = unit_api API.call_method ~m:"pasteInto" [] + let removeOverlap = unit_api API.call_method ~m:"removeOverlap" [] + let replaceWithReference ?fudge = unit_api API.call_method ~m:"replaceWithReference" (a_opt v_float fudge) + let round ?factor = unit_api API.call_method ~m:"round" (a_opt v_float factor) + (* let simplify *) + (* let stroke *) + let transform ~matrix = unit_api API.call_method ~m:"transform" [v_matrix matrix] + let nltransform ~xexpr ~yexpr = unit_api API.call_method ~m:"nltransform" [v_string xexpr; v_string yexpr] + let unlinkReferences = unit_api API.call_method ~m:"unlinkReferences" [] + (****************************) + module IntAttr = IntAttr(struct type t = Object.font end) + module StringAttr = StringAttr(struct type t = Object.font end) + module SelectionAttr = SelectionAttr(struct type t = Object.font end) + (* ATTRIBUTE TYPES ********) + module type IntAttr = Attr with type t = t and type attr = int + module type StringAttr = Attr with type t = t and type attr = string + module type SelectionAttr = Attr with type t = t and type attr = Selection.t + (* ATTRIBUTES ********) + module Ascent = IntAttr(struct let attr = "ascent" end) + module Descent = IntAttr(struct let attr = "descent" end) + module Em = IntAttr(struct let attr = "em" end) + module Encoding = StringAttr(struct let attr = "encoding" end) + module Familyname = StringAttr(struct let attr = "familyname" end) + module Fontname = StringAttr(struct let attr = "fontname" end) + module Fullname = StringAttr(struct let attr = "fullname" end) + module Version = StringAttr(struct let attr = "version" end) + module Weight = StringAttr(struct let attr = "weight" end) + module Selection = SelectionAttr(struct let attr = "selection" end) + (* added *) + module Copyright = StringAttr(struct let attr = "copyright" end) +end +(***********************************************************) +module FontForge = struct + let get : type a . typ:a Value.obj -> m:string -> Value.t list -> a = + fun ~typ ~m o -> API.call_function Import.fontforge ~typ ~m o + (* PYTHON INITIATLISATION ********) + let initialize = Util.Import.init + let finalize = Py.finalize + (* FUNCTIONS ********) + let activeFont () = font_opt_api get ~m:"activeFont" [] + (* activeFontInUI *) + let activeGlyph () = glyph_opt_api get ~m:"activeGlyph" [] + let activeLayer () = int_api get ~m:"activeGlyph" [] + (* ask *) + (* askChoices *) + (* askString *) + let defaultOtherSubrs () = unit_api get ~m:"defaultOtherSubrs" [] + let fonts () = font_list_api get ~m:"fonts" [] + let fontsInFile ~filename = string_list_api get ~m:"fontsInFile" [v_string filename] + (* getPrefs ~name:_ = assert false *) + let hasSpiro () = bool_api get ~m:"hasSpiro" [] + (* hasUserInterface *) + (* IsFraction *) + (* IsLigature *) + (* IsOtherFraction *) + (* IsVulgarFraction *) + let loadEncodingFile ~filename = string_opt_api get ~m:"loadEncodingFile" [v_string filename] + let loadNamelist ~filename = unit_api get ~m:"loadNamelist" [v_string filename] + let loadNamelistDir ~dirname = unit_api get ~m:"loadNamelistDir" [v_string dirname] + let loadPlugin ~filename = unit_api get ~m:"loadPlugin" [v_string filename] + let loadPluginDir ~dirname = unit_api get ~m:"loadPluginDir" [v_string dirname] + let loadPrefs () = unit_api get ~m:"loadPrefs" [] + (* logWarning *) + let nameFromUnicode ?namelist unicode = string_api get ~m:"nameFromUnicode" ((v_int unicode)::(a_opt v_string namelist)) + (* onAppClosing *) + let openFont ~filename = font_api get ~m:"open" [v_string filename] + (* openFilename *) + let parseTTInstr arg = string_api get ~m:"parseTTInstr" [v_string arg] + (* postError *) + (* postNotice *) + let preloadCidmap ~filename ~registry ~order ~supplement = unit_api get ~m:"preloadCidmap" [v_string filename ; v_string registry ; v_string order ; v_int supplement] + (* printSetup *) + let readOtherSubrsFile ~filename = unit_api get ~m:"readOtherSubrsFile" [v_string filename] + (* registerGlyphSeparationHook *) + (* registerImportExport *) + (* registerMenuItem *) + (* runInitScripts *) + (* saveFilename *) + let savePrefs () = unit_api get ~m:"savePrefs" [] + (* scriptPath *) + (* setPrefs ~name:_ ~value:_ *) + (* SpiroVersion *) + (* ucFracChartGetCnt *) + (* ucLigChart... *) + (* ucOFracChart... *) + (* ucVulChart... *) + (* Unicode... *) + let unicodeFromName ~glyphname = int_api get ~m:"unicodeFromName" [v_string glyphname] + (* unitShape *) + let unParseTTInstr arg = string_api get ~m:"unParseTTInstr" [v_string arg] + let version () = string_api get ~m:"version" [] + (* CLASSES ********) + (* awcontext *) + (* awglyph *) + let contour () = contour_api get ~m:"contour" [] + (* cvt *) + let font () = font_api get ~m:"font" [] + let layer () = layer_api get ~m:"layer" [] + (* layer_array *) + (* layerinfo *) + (* layerinfo_array *) + (* math *) + (* mathKern *) + let point ?oncurve ?(y=0.0) x = point_api get ~m:"point" ((v_float x)::(v_float y)::(a_opt v_bool oncurve)) + let pointCoord ?oncurve (x,y) = point_api get ~m:"point" ((v_float x)::(v_float y)::(a_opt v_bool oncurve)) + (* private *) + (* references *) + (* selection *) +end +(***********************************************************) diff --git a/src/Core.mli b/src/Core.mli new file mode 100644 index 0000000..084605b --- /dev/null +++ b/src/Core.mli @@ -0,0 +1,1176 @@ +(******************************************************************************) +(* *) +(* This file is part of fontforge-of-ocaml library *) +(* *) +(* Copyright (C) 2017-2022, Patrick BAUDIN *) +(* (https://github.com/pbaudin/fontforge-of-ocaml) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, but WITHOUT ANY *) +(* WARRANTY; without even the implied warranty of MERCHANTABILITY or *) +(* FITNESS FOR A PARTICULAR PURPOSE. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1) *) +(* *) +(******************************************************************************) + +(** {1 Fontforge} *) +(***********************************************************) +type coord = float * float +(***********************************************************) +(** {2 Attributes} *) +(***********************************************************) +module type Attr = sig + type t + type attr + val name: string + val get: t -> attr + val set: t -> attr -> unit +end +(***********************************************************) +(** {2 Tranformation Matrix} *) +(***********************************************************) +(** [PsMat] which provides quick access to some useful transformations expressed as PostScript matrices. + API: complete (compared to the Python API) except that the type [PsMat.t] become abstract. *) +module PsMat: sig + type t + (** Abstract type for transform PostScript matrices *) + + val identity: unit -> t + (** Returns an identity matrix *) + val compose: mat1:t -> t -> t + (** Returns a matrix which is the composition of the two input transformations *) + val inverse: t -> t + (** Returns a matrix which is the inverse of the input transformation. (Note: There will not always be an inverse) *) + val rotate: float -> t + (** Returns a matrix which will rotate by theta. Theta is expressed in radians *) + val scale: ?y:float -> float -> t + (** Returns a matrix which will scale by [x] in the horizontal direction and y in the vertical. + If [y] is omitted, it will scale by the same amount [x] in both directions *) + val skew: float -> t + (** Returns a matrix which will skew by theta (to produce a oblique font). Theta is expressed in radians *) + val translate: x:float -> y:float -> t + (** Returns a matrix which will translate by x in the horizontal direction and y in the vertical *) +end +(***********************************************************) +(** {2 Point} *) +(***********************************************************) +(** [Point] + API: complete (compared to the Python API) except the Pickling Method [reduce]. *) +module Point: sig + type t + (** Abstract type for points *) + + (** {3 Methods} *) + + val dup: t -> t + (** Returns a copy of the current point. *) + val transform: matrix:PsMat.t -> t -> unit + (** Transforms the point by the transformation matrix. *) + +(** TODO + - val reduce: +*) + + (** {3 Attributes} *) + + (** Submodules giving read and write accesses to FontForge point attributes. *) + + module type BoolAttr = Attr with type t = t and type attr = bool + module type FloatAttr = Attr with type t = t and type attr = float + + module X: FloatAttr + (** The [x] location of the point. *) + module Y: FloatAttr + (** The [y] location of the point. *) + module On_curve: BoolAttr + (** Whether this is an on curve point or an off curve point (a control point). *) + module Selected: BoolAttr + (** Whether this point is selected in the UI. + If an off-curve point is selected in means the preceding (interpolated) on-curve point is selected. *) +end + +(***********************************************************) +(** {2 Layer} *) +(***********************************************************) +(** A [Layer] is a collection of Contours. + All the contours must be the same order (all quadratic or all cubic). Currently layers do not contain references. + Layers may be compared to see if their contours are similar. + API: TODO *) +module Layer: sig + type t + (** Abstract type for layers *) +end +(***********************************************************) +(* {2 Glyph Pen} *) +(***********************************************************) +(** [GlyphPen] Protocol to draw into a [Glyph] + You create a glyphPen with the [GlyphPen] function of a glyph. + You then draw into it with the functions below. + API: complete (compared to the Python API); a [finalize] function has been added. *) +module GlyphPen: sig + type t + (** Abstract type for glyph pens. *) + + (** {3 Python workarounds} *) + + val finalize: t -> unit + (** Finalize the pen (equivalent to [pen = None] at the Python side). + This tells FontForge that the drawing is done and causes it to refresh the display (if a UI is active). + Note: nothing is performed in the OCaml implementation + *) + + (** {3 Methods} *) + + val moveTo: x:int -> y:int -> t -> unit + (** With one exception this call begins every contour and creates an on curve point at (x,y) as the start point of that contour. + This should be the first call after a pen has been created and the call that follows a closePath, endPath. *) + val moveToCoord: coord -> t -> unit + (** Idem [moveTo] with float coords. *) + val lineTo: x:int -> y:int -> t -> unit + (** Draws a line from the last point to (x,y) and adds that to the contour. *) + val lineToCoord: coord -> t -> unit + (** Idem [lineTo] with float coords. *) + val curveTo: cp1:coord -> ?cp2:coord -> pt:coord -> t -> unit + (** This routine has slightly different arguments depending on the type of the font. + When drawing into a cubic font (PostScript) use the first set of arguments (with two control points -- off curve points -- between each on curve point). + When drawing into a quadratic font (TrueType) use the second format (when the optional [cp2] is specified) with one control point between adjacent on-curve points. + The standard appears to support super-bezier curves with more than two control points between on-curve points. + FontForge does not. Nor does FontForge allow you to draw a quadratic spline into a cubic font, nor vice versa. *) + val qcurveTo: cps:coord list -> ?pt:coord -> t -> unit + (** This routine may only be used in quadratic (TrueType) fonts and has two different formats. + It is used to express the TrueType idiom where an on-curve point mid-way between its control points may be omitted, leading to a run of off-curve points (with implied but unspecified on-curve points between them). + The first format (when the optional [pt] is specified) allows an arbetary number of off-curve points followed by one on-curve point. + It is possible to have a contour which consists solely of off-curve points. + When this happens the contour is NOT started with a moveTo, instead the entire contour, all the off curve points, are listed in one call, and the argument list is terminated by a None to indicate there are no on-curve points. *) + val closePath: t -> unit + (** Closes the contour (connects the last point to the first point to make a loop) and ends it. *) + val endPath: t -> unit + (** Ends the contour without closing it. + This is only relevant if you are stroking contours. *) + val addComponent: glyphname:string -> transform:PsMat.t -> t -> unit + (** Adds a reference (a component) to the glyph. + The PostScript transformation matrix is a 6 element tuple. *) +end +(***********************************************************) +(* {2 Contour} *) +(***********************************************************) +(** A [Contour] is a collection of points. A contour may be either based on cubic or quadratic splines. + + If based on cubic splines there should be either 0 or 2 off-curve points between every two on-curve points. + If there are no off-curve points then we have a line between those two points. If there are 2 off-curve points we have a cubic bezier curve between the two end points. + + If based on quadratic splines things are more complex. + Again, two adjacent on-curve points yield a line between those points. + Two on-curve points with an off-curve point between them yields a quadratic bezier curve. + However if there are two adjacent off-curve points then an on-curve point will be interpolated between them. + (This should be familiar to anyone who has read the truetype 'glyf' table docs). + + For examples of what these splines can look like see the section on bezier curves. + + A contour may be open in which case it is just a long wiggly line, or closed when it is more like a circle with an inside and an outside. + Unless you are making stroked fonts all your contours should eventually be closed. + + Contours may also be expressed in terms of Raph Levien's spiro points. + This is an alternate representation for the contour, and is not always available (Only if fontforge.hasSpiro() is True. + If available the spiro member will return a tuple of spiro control points, while assigning to this member will change the shape of the contour to match the new spiros. + + Two contours may be compared to see if they describe similar paths. + + API: uncomplete (compared to the Python API) *) +module Contour: sig + type t + (** Abstract type for contours *) + + (** {3 Python workarounds} *) + + exception Index_out_of_bounds + val nth: int -> t -> Point.t + (** Related to the python expression: [c[i]]. The ith point on the contour. You may assign to this using [set_nth]. + @raises [Index_out_of_bounds]. *) + val set_nth: int -> Point.t -> t -> unit + (** Related to the python assignement: [c[i] = pt]. + @raises [Index_out_of_bounds]. *) + val len: t -> int + (** The number of points in the contour. *) + + val extract: min:int -> max:int -> t -> t + (** Related to the python expression: [c[min:max]]. The contour containing points between i and j excluded. *) + val add_contour: t -> t -> t + (** Related to the python expression: [c+d]. A contour concatenating c and d (another contour). *) + val add_point: Point.t -> t -> t + (** Related to the python expression: [c+d]. A contour concatenating c and d (a point). *) + val append_contour: t -> t -> unit + (** Related to the python assignement: [c+=d]. Appends d (another contour) to c. *) + val append_point: Point.t -> t -> unit + (** Related to the python assignement: [c+=d]. Appends d (a point) to c. *) + + val to_list: t -> Point.t list + (** Returns the point list of the contour. *) + + (** {4 Iterators} *) + + val iter: f:(Point.t -> unit) -> t -> unit + (** Iterates on the contour points. *) + val iteri: f:(int -> Point.t -> unit) -> t -> unit + val map: f:(Point.t -> 'a) -> t -> 'a list + val mapi: f:(int -> Point.t -> 'a) -> t -> 'a list + val fold: init:'a -> f:('a -> Point.t -> 'a) -> t -> 'a + + (** {3 Methods} *) + + val contains_point: Point.t -> t -> bool + (* Related to the python expression: p in c. + Returns whether the point p is in the contour c. *) + val contains_coord: coord -> t -> bool + (* Related to the python expression: p in c. + Returns whether the point (x,y) is in the contour c. *) + + val dup: t -> t + (** Returns a deep copy of the contour. That is, it copies the points that make up the contour. *) + val isEmpty: t -> bool + (* Returns whether the contour is empty (contains no points). *) + val moveTo: x:int -> y:int -> t -> unit + (** Adds an initial, on-curve point at (x,y) to the contour. *) + val moveToCoord: coord -> t -> unit + (** Idem [moveTo] with float coords. *) + val lineTo: x:int -> y:int -> ?nth:int -> t -> unit + (** Adds an line to the contour. + If the optional third argument is given, the line will be added after the pos'th point, otherwise it will be at the end of the contour. *) + val lineToCoord: coord -> ?nth:int -> t -> unit + (** Idem [LineTo] with float coords. *) + val cubicToCoord: cp1:coord -> cp2:coord -> pt:coord -> ?nth:int -> t -> unit + (** Adds a cubic curve to the contour (requires Is_quadratic set to false). + If the optional fourth argument is give, the line will be added after the pos'th point, otherwise it will be at the end of the contour.*) + val cubicTo: cpx1:int -> cpy1:int -> cpx2:int -> cpy2:int -> x:int -> y:int -> ?nth:int -> t -> unit + (** Idem [cubicToCoord] with int coords. *) + val quadraticToCoord: cp:coord -> pt:coord -> ?nth:int -> t -> unit + (** Adds a quadratic curve to the contour (requires Is_quadratic set to true). + If the optional third argument is give, the line will be added after the pos'th point, otherwise it will be at the end of the contour. *) + val quadraticTo: cpx:int -> cpy:int -> x:int -> y:int -> ?nth:int -> t -> unit + (** Idem [quadraticToCoord] with int coords. *) + val insertPtCoord: pt:coord -> ?onCurve:bool -> ?nth:int -> t -> unit + (** Adds point to the contour. + If the optional third argument is give, the line will be added after the pos'th point, otherwise it will be at the end of the contour. + The point may be either a point or a tuple with three members (x,y,on_curve) *) + val insertPt: x:int -> y:int -> ?onCurve:bool -> ?nth:int -> t -> unit + (** Idem [insertPtCoord] with int coords. *) + val insertPoint: pt:Point.t -> ?nth:int -> t -> unit + (** Idem [insertPt]. *) + + val makeFirst: int -> t -> unit + (** Rotate the point list so that the pos'th point becomes the first point. *) + val isClockwise: t -> int + (** Returns whether the contour is drawn in a clockwise direction. + A return value of -1 indicates that no consistant direction could be found (the contour self-intersects). *) + val reverseDirection: t -> unit + (** Reverse the order in which the contour is drawn (turns a clockwise contour into a counter-clockwise one). + See also layer.correctDirection. *) + +(** TODO + - val similar + - val xBoundsAtY + - val yBoundsAtX + - val addExtrema + - val cluster +*) + + val merge: int list -> t -> unit + (** Removes the on-curve point a the given position and rearranges the other points to make the curve as similar to the original as possible. + All of the listed position will be removed. + See Also simplify. *) + + val round: ?factor:float -> t -> unit + (** Rounds the x and y coordinates. + If factor is specified then new-coord = round(factor*old-coord)/factor. + See Also cluster *) + + val selfIntersects: t -> bool + (** Returns whether this contour intersects itself. *) + +(** TODO + - val simplify + *) + + val transform: matrix:PsMat.t -> t -> unit + (* Transforms the point by the transformation matrix. *) + +(** TODO + - boundingBox + - getSplineAfterPoint +*) + + val draw: GlyphPen.t -> t -> unit + (* Draw the contour to the pen argument. *) + +(** TODO + - val reduce + *) + + (** {3 Attributes} *) + + (** Submodules giving read and write access to FontForge contour attributes. *) + + module type BoolAttr = Attr with type t = t and type attr = bool + module type StringAttr = Attr with type t = t and type attr = string + + module Is_quadratic: BoolAttr + (** Whether the contour should be interpretted as a set of quadratic or cubic splines. + Setting this value has the side effect of converting the point list to the appropriate format. *) + module Closed: BoolAttr + (** Whether the contour is open or closed. *) + module Name: StringAttr + (** The contour name (generally there is no name). *) + +(** TODO + module Spiro +*) + +end +(***********************************************************) +(** {2 Glyph} *) +(***********************************************************) +(** [Glyph] refers to a fontforge Glyph object. + It has no independent life of its own, it always lives within a font. + It has all the things you expect to be associated with a glyph: a glyph name, a unicode encoding, a drawing layer, GPOS/GSUB features... + This type may not be pickled. + This type may not be created directly -- all glyphs are bound to a font and must be created through the font. + See [Font.createChar] function. + API: partialy implemented (compared to the Python API) but all members and functions are listed. *) +module rec Glyph: sig + type t + (* Abstract type for glyphs. *) + + (** {3 Methods} *) + +(** TODO + - val addAnchorPoint +*) + + val addExtrema: ?flags:string -> ?emsize:int -> t -> unit + (** Extrema should be marked by on-curve points. + If a curve lacks a point at an extrema this command will add one. + Flags may be one of the following strings: + - all - Add all missing extrema + - only_good - Only add extrema on longer splines (with respect to the em-size). Default flag. + - only_good_rm - As above but also merge away on-curve points which are very close to, but not on, an added extremum. *) + val addReference: glyphname:string -> ?transform:PsMat.t -> t -> unit + (** Adds a reference to the specified glyph into the current glyph. + Optionally specifying a transformation matrix *) + val addHint: is_vertical:bool -> start:float -> width:float -> t -> unit + (** Adds a postscript hint. Takes a boolean flag indicating whether the hint is horizontal or vertical, a start location and the hint's width. *) + val addPosSub: ((LookupTables.Table.lookup_pos_sub_t * 'b) * 'b LookupTables.Table.args_t) LookupTables.Table.lookup_subtable_t -> 'b LookupTables.Table.args_t -> t -> unit + (** Adds position/substitution data to the glyph. + The number and type of the arguments vary acording to the type of the lookup containing the subtable. + The first argument should always be a lookup subtable name. + If the lookup is for single substitutions then the second argument should be a string containing a single glyph name. + For multiple and alternated substitutions a tuple of glyph names. For ligatures, a tuple of the ligature components (glyph names). + For single positionings the second through fifth arguments should be small integers representing the adjustment along the appropriate axis. + For pairwise positionings (kerning) the second argument should be the name of the other glyph being kerned with, and the third through tenth should be small integers – or, if there are exactly three arguments then the third specifies traditional, one-axis, kerning. + If there is a previously existing entry, this will replace it (except for ligatures). + *) + +(** TODO + - val appendAccent +*) + + val autoHint: t -> unit + (** Generates PostScript hints for this glyph. *) + val autoInstr: t -> unit + (** Generates TrueType instructions for this glyph. *) + val autoTrace: t -> unit + (** Auto traces any background images. *) + val build: t -> unit + (** If the character is a composite character, then clears it and inserts references to its components. *) + val canonicalContours: t -> unit + (** Orders the contours in the current glyph by the x coordinate of their leftmost point. + This can reduce the size of the charstring needed to describe the glyph(s). *) + val canonicalStart: t -> unit + (** Sets the start point of all the contours of the current glyph to be the leftmost point on the contour. + If there are several points with that value then use the one which is closest to the baseline. + This can reduce the size of the charstring needed to describe the glyph(s). + By regularizing things it can also make more things available to be put in subroutines. *) + +(** TODO + - val changeWeight +*) + + val condenseExtend: c_factor:float -> c_add:float -> ?sb_factor:float -> ?sb_add:float -> ?correct:bool -> t -> unit + (** Condenses or extends the size of the counters and side-bearings of the glyph. + The first two arguments provide information on shrinking/growing the counters, the second two the sidebearings. + If the last two are omitted they default to the same values as the first two. + A counter's width will become: + new_width = c_factor * old_width + c_add + + If present the correct argument allows you to specify whether you want to correct for the italic angle before condensing the glyph. (it defaults to True). *) + val clear: t -> unit + (** Clears the contents of the glyph (and marks it as not worth outputting). *) + val cluster: ?within:float -> ?max:float -> t -> unit + (** Moves clustered coordinates to a standard central value. + See also round. *) + val correctDirection: t -> unit + (** Orients all contours so that external ones are clockwise and internal counter-clockwise. *) + val exclude: Layer.t -> t -> unit + (** Removes the excluded area from the current glyph. Takes an argument which is a layer. + See also removeOverlap and intersect. *) + +(** TODO + - val export + - val getPosSub: string -> t -> ?? +*) + + val importOutlines: filename:string -> ?flags:string list -> t -> unit + (** Uses the file's extension to determine behavior. + Imports outline descriptions (eps, svg, glif files) into the forground layer. + Imports image descriptions (bmp, png, xbm, etc.) into the background layer. + Optionally, flags can be used to control PostScript import, it'll be ignored for other file types. + Flags is a list of strings ? *) + val intersect: t -> unit + (** Leaves only areas in the intersection of contours. See also removeOverlap and exclude. *) + val isWorthOutputting: t -> bool + (** Returns whether the glyph is worth outputting into a font file. + Basically a glyph is worth outputting if it contains any contours, or references or has had its width set. *) + val preserveLayerAsUndo: ?layer_dohints:(int * bool) -> t -> unit + (** Normally undo handling is turned off during python scripting. + If you wish you may tell fontforge to preserve the current state of a layer so that whatever you do later can be undone by the user. + You may omit the layer parameter (in which case the currently active layer will be used). + You may also request that hints be preserved (they are not, by default).*) + val removeOverlap: t -> unit + (** Removes overlapping areas. See also intersect and exclude. *) + val removePosSub: name:string -> t -> unit + (** Removes all data from the glyph corresponding to the given lookup-subtable. If the name is "*" then all data will be removed. *) + val round: ?factor:int -> t -> unit + (** Rounds the x and y coordinates of each point in the glyph. + If factor is specified then new-coord = round(factor*old-coord)/factor. + See also cluster. *) + val selfIntersects: t -> bool + (** Returns whether any of the contours in this glyph intersects any other contour in the glyph (including itself). *) + val transform: matrix:PsMat.t -> ?flags:string list -> t -> unit + (** Transforms the glyph by the matrix. + The optional flags argument should be a tuple containing any of the following strings: + - partialRefs - Don't transform any references in the glyph, but do transform their offsets. + This is useful if the refered glyph will be (or has been) transformed. + - round - Round to int after the transformation is done.*) + val nltransform: xexpr:string -> yexpr:string -> t -> unit + (** xexpr and yexpr are strings specifying non-linear transformations that will be applied to all points in the current layer (with xexpr being applied to x values, and yexpr to y values, of course). + The syntax for the expressions is explained in the non-linear transform dialog. *) + val unlinkRef: ?refname:string -> t -> unit + (** Unlinks the reference to the glyph named ref-name. + If ref-name is omitted, unlinks all references. *) + val unlinkThisGlyph: t -> unit + (** Unlinks all the references to the current glyph within any other glyph in the font. *) + val useRefsMetrics: name:string -> ?flag:bool -> t -> unit + (** Finds a reference with the given name and sets the "use_my_metrics" flag on it (so this glyph will have the same advance width as the glyph the reference points to). + If the optional flag argument is False, then the glyph will no longer have its metrics bound to the reference.*) + val validate: ?force:bool -> t -> int + (** Validates the glyph and returns the validation_state of the glyph (except bit 0x1 will always be clear). + If the glyph passed the validation then the return value will be 0 (not 0x1). + Otherwise the return value will be the set of errors found. + If force is specified true this will always be validated, if force is unspecified (or specified as false) then it will return the cached value if it is known, otherwise will validate it. *) + val draw: GlyphPen.t -> t -> unit + (** Draw the glyph's outline to the pen argument. *) + val glyphPen: ?replace:bool -> t -> GlyphPen.t + (** Creates a new glyphPen which will draw into the current glyph. + By default the pen will replace any existing contours and references, but setting the optional keyword argument, replace to false will retain the old contents.*) + + (** {3 Attributes} *) + + (** Submodules giving read and write access to FontForge glyph attributes. + Readonly attributes are implemented as functions. *) + + module type BoolAttr = Attr with type t = t and type attr = bool + module type IntAttr = Attr with type t = t and type attr = int + module type StringAttr = Attr with type t = t and type attr = string + + module ActiveLayer: IntAttr + (** Returns currently active layer in the glyph (as an integer). + May be set to an integer or a layer name to change the active layer. + Not implemented: set the attribute from a layer name *) + +(** TODO + - module Atuni: ???Attr + - module AnchorPoints: ???Attr + - module AnchorPointsWithSel: ???Attr + - module Background: ???Attr +*) + + module Changed: BoolAttr + (* Whether this glyph has been modified. + This is (should be) maintained automatically, but you may set it if you wish. *) + module Color: IntAttr + (* The color of the glyph in the fontview. + A 6 hex-digit RGB number or -1 for default. + 0xffffff is white, 0x0000ff is blue, etc. *) + +(** TODO + - module Comments: UTF8Attr + - module Dhints: FloatTuple2Tuple3ListAttr +*) + + val encoding: t -> int + (** Returns the glyph's encoding in the font's encoding. (readonly) + If the glyph has multiple encodings, one will be picked at random. + If the glyph is not in the font's encoding then a number will be returned beyond the encoding size (or in some cases -1 will be returned). + Note: an Ocaml [IntAttr] module is not used there since the Python attribute [font] is read only. *) + val font: t -> Font.t + (** The font containing this glyph. + Note: an Ocaml [FontAttr] module is not used there since the Python attribute [font] is read only. *) + +(** TODO + - module Foreground: ??Attr +*) + + module Glyphclass: StringAttr + (* An opentype glyphclass, one of automatic, noclass, baseglyph, baseligature, mark, component. *) + module Glyphname: StringAttr + (* The name of the glyph. *) + +(** TODO + - module Hhints: FloatTuple2ListAttr + - module HorizontalComponents: ??Attr + - module HorizontalComponentItalicCorrection : ??Attr +*) + + (* module HorizontalVariants: ??Attr *) + (* A boolean containing the MATH "is extended shape" field. *) + module IsExtendedShape: BoolAttr + (* The glyph's italic correction field. Used by both TeX and MATH. + The special value of -32768 (0x8000) means the value is unspecified. + An unspecified value will not go into the output tables, a value of 0 will. *) + module ItalicCorrection: IntAttr + + val layer_cnt: t -> int + (** The number of layers in this glyph. + Cannot be set. + Note: an Ocaml [IntAttr] module is not used there since the Python attribute [font] is read only. *) + +(** TODO seems to be readonly + - module Layers: ??Attr + - module Layerrefs: ??Attr + - module Lcarets: ??Attr +*) + + module Left_side_bearing: IntAttr + (* The left side bearing of the glyph. *) + +(** TODO + - module ManualHints: ??Attr + - module MathKern: ??Attr + - module Persistant: ??Attr + - module References: ??Attr +*) + + module Right_side_bearing: IntAttr + (* The right side bearing of the glyph. *) + +(** TODO + - module Temporary: ??Attr +*) + + module Texheight: IntAttr + (** The Tex height. + The special value of -32768 (0x8000) means the field is unspecified. + An unspecified value will not go into the output tables, a value of 0 will. *) + module Texdepth: IntAttr + (** The Tex depth. + The special value of -32768 (0x8000) means the field is unspecified. + An unspecified value will not go into the output tables, a value of 0 will. *) + module Topaccent: IntAttr + (** The glyph's top accent position field. Used by MATH. + The special value of -32768 (0x8000) means the field is unspecified. + An unspecified value will not go into the output tables, a value of 0 will. *) + +(** TODO + - module Ttinstrs: ??Attr +*) + + module Unicode: IntAttr + (** The glyph's unicode code point, or -1 *) + module UnlinkRmOvrlpSave: IntAttr + (** A flag that indicates the glyph's references should be unlinked and remove overlap run on it before the font is saved (and then the original references replaced after the save finishes). *) + +(** TODO + - module VerticalComponents: ??Attr + - module VerticalComponentsItalicCorrection: ??Attr + - module VerticalVariants: ??Attr + - module Vhints: ??Attr +*) + + (* The vertical advance width of the glyph. See also width. *) + module Vwidth: IntAttr + (* The advance width of the glyph. See also vwidth. *) + module Width: IntAttr + (* The GID of this glyph in the font it was read from. (readonly) *) + + val originalgid: t -> int + + val script: t -> string + (** A string containing the OpenType 4 letter tag for the script associated with this glyph (readonly). *) + + val validation_state: t -> int + (** A (readonly) bit mask indicating some problems this glyph might have. + 0x1 If set then this glyph has been validated. + If unset then other bits are meaningless. + 0x2 Glyph has an open contour. + 0x4 Glyph intersects itself somewhere. + 0x8 At least one contour is drawn in the wrong direction + 0x10 At least one reference in the glyph has been flipped + (and so is drawn in the wrong direction) + 0x20 Missing extrema + 0x40 A glyph name referred to from this glyph, in an opentype table, + is not present in the font. + 0x80 PostScript has a limit of 1500 points in a glyph. + 0x100 PostScript has a limit of 96 hints in a glyph. + 0x200 Invalid glyph name. + TrueType only, errors in original file + 0x400 More points in a glyph than allowed in 'maxp' + 0x800 More paths in a glyph than allowed in 'maxp' + 0x1000 More points in a composite glyph than allowed in 'maxp' + 0x2000 More paths in a composite glyph than allowed in 'maxp' + 0x4000 Instructions longer than allowed in 'maxp' + 0x8000 More references in a glyph than allowed in 'maxp' + 0x10000 References nested more deeply than allowed in 'maxp' + 0x40000 Points too far apart. TrueType and Type2 fonts are limited to 16 bit numbers, + and so adjacent points must be within 32767 em-units of each other. + 0x80000 Points non-integral. TrueType points and control points must be integer aligned. + (FontForge will round them if they aren't) + 0x100000 Missing anchor. According to the opentype spec, if a glyph contains an anchor + point for one anchor class in a subtable, it must contain anchor points for all + anchor classes in the subtable. + Even it, logically, they do not apply and are unnecessary. + 0x200000 Duplicate glyph name. Two (or more) glyphs in this font have the same name. + When outputting a PostScript font only one of them will ever be seen. + It's a little hard to detect this in normal use, but if you change the encoding + to "Glyph Order", and then use Edit->Select->Wildcard and enter the glyph name, + both of them should be selected. + 0x400000 Duplicate unicode code point. Two (or more) glyphs in this font have the code point. + When outputting an sfnt (TrueType/OpenType) font only one of them will ever be seen. + It's a little hard to detect this in normal use, but if you change the encoding + to "Glyph Order", and then use Edit->Select->Wildcard and enter the code point, + both of them should be selected. + 0x800000 Overlapped hints. Either the glyph has no hint masks and there are overlapped + hints, or a hint mask specifies two overlapping hints. *) + + +end +(***********************************************************) +(** {2 Selection} *) +(***********************************************************) +(** [Selection] of glyphs. + API: complete with some specificities about the selection requests and the iterations (compared to the Python API). *) +and Selection: sig + type t + (* Abstract type for contours *) + + (** {3 Python workarounds} *) + + val byGlyphs: t -> t + (* Returns another selection, just the same as this one except that its iterator function + will return glyphs (rather than encoding slots) and will only return those entries for which glyphs exist. + Note: an Ocaml [FFmember] module is not used there since the Python attribute [byGlyphs] is read only. *) + + exception UnspecifiedSlotIteration + exception UnspecifiedGlyphIteration + val iter: ?slot:(int -> unit) -> ?glyph:(Glyph.t -> unit) -> t -> unit + (* Iterates on selected item using one of the two function depending on the current iteration mode (see [byGlyphs]). + Raises [UnspecifiedSlotIteration] when the iteration is over encoding slots and the [slot] function is unspecified. + Raises [UnspecifiedGlyphIteration] when the iteration is over glyphs and the [glyph] function is unspecified. + Related to efficiency, [max] specifies the maximal number of items returned from the Python side in one call to [next_items]. *) + + type request_t + (* Abstract type for beeing able to build selection requests. *) + val glyphname: string -> request_t + (* Build a selection request from a glyph [name]. *) + val glyph: Glyph.t -> request_t + (* Build a selection request from a fontforge [glyph]. *) + val code: int -> request_t + (* Build a selection request from the [code] either an encoding index or (default) a unicode code point depending on the flags. *) + + val select: ?encoding:bool -> ?less:bool -> ?ranges:bool -> request:request_t list -> t -> unit + (* Select specified items depending on specified flags: + - ?encoding=false (default) -> "unicode" - Interpret specified code items as unicode code points + - ?encoding=true -> "encoding"- Interpret specified code items as encoding indeces. + + - ?less=unspecified (default) -> "None" - Would produce a selection from scratch using specified items + - ?less=false -> "more" - Would add specified items to the current selection + - ?less=true -> "less" - Would remove specified items from the current selection + + - ?ranges=false (default) -> "singletons" - Specified items should be interpreted individually and mean the obvious. + - ?ranges=true -> "ranges"- Specified items should be interpreted in pairs and represent all encoding slots between the start and end points specified by the pair. + *) + + val select_from_encoding: encoding:int -> t -> unit + (* Shortcut: Select from an unicode. *) + val select_from_unicode: unicode:int -> t -> unit + (* Shortcut: Select from an unicode. *) + val select_from_glyphname: name:string -> t -> unit + (* Shortcut: Select from a glyph name. *) + + val all: t -> unit + (** Select everything. *) + val none: t -> unit + (** Deselect everything. *) + val changed: t -> unit + (** Select all glyphs which have changed. *) + val invert: t -> unit + (** Invert the selection. *) + +end +(***********************************************************) +(* {2 Font} *) +(***********************************************************) +(** FontForge [Font] object. + It generally contains a list of glyphs, an encoding to order those glyphs, a fontname, a list of GPOS/GSUB lookups and many other things. + API: almost complete (all listed even the unimplemented ones) compared to the Python API. +*) +and Font: sig + type t + (** Abstract type for fonts *) + + (** {3 Python workarounds} *) + + val contains_glyphname: glyphname:string -> t -> bool + (** Equivalent to the Python expression: [glyphname in font]. + Returns whether the font contains a glyph with the given name. *) + val contains_unicode: unicode:int -> t -> bool + (** Equivalent to the Python expression: unicode in font. + Returns whether the font contains a glyph with that encoding. *) + + val glyph_from_name: glyphname:string -> t -> Glyph.t + (** Equivalent to the Python access [font[glyphname]] from a string. + Returns the glyph with that name.*) + val glyph_from_code: unicode:int -> t -> Glyph.t + (** Equivalent to the Python access [font[unicode]] from an integer. + Returns the glyph at that encoding. *) + + (** {3 Methods} *) + + val addAnchorClass: subtable:string -> anchorclass:string -> t -> unit + (** Adds an anchor class to the specified (anchor) subtable. *) + +(** TODO + - gpos_pair + - val addKerningClass +*) + + type lookup_script_t + (** Abstract type for script languages of lookup features *) + val lookupScript: script:string -> languages:string list -> lookup_script_t + (** i.e. [let script = lookupScript ~script:"latn" ~languages:["dflt"]] *) + type lookup_feature_t + (** Abstract type for lookup features *) + val lookupFeature: feature:string -> scripts:lookup_script_t list -> lookup_feature_t + (** i.e. [let feature = lookupFeature feature:"liga" scripts:[script]] *) + val addLookup: 'a LookupTables.Table.lookup_table_t -> 'a LookupTables.Table.t -> + flags:string list -> 'a LookupTables.TypedFeature.t -> ?others:'a LookupTables.TypedFeature.t list -> ?after_lookupname:string -> t -> unit + (** Creates a new lookup with the given name, type and flags. It will tag it with any indicated features. The type of one of + - gsub_single + - gsub_multiple + - gsub_alternate + - gsub_ligature + - gsub_context + - gsub_contextchain + - gsub_revesechain + - morx_indic + - morx_context + - morx_insert + - gpos_single + - gpos_pair + - gpos_cursive + - gpos_mark2base + - gpos_mark2ligature + - gpos_mark2mark + - gpos_context + - gpos_contextchain + - kern_statemachine + + The flags argument is a tuple of strings. At most one of these strings may be the name of a mark class. + The others are: + - right_to_left + - ignore_bases + - ignore_ligatures + - ignore_marks + + A feature-script-lang tuple is a tuple with one entry for each feature (there may be no entries if there are no features). + Each entry is itself a two element tuple, the first entry is a string containing a 4 letter feature tag, and the second entry is another tuple (potentially empty) with an entry for each script for which the feature is active. + Each entry here is itself a two element tuple. + The first element is a 4 letter script tag and the second is a tuple of languages. Each entry in the language tuple is a four letter language. + - Example: (("liga",(("latn",("dflt")),)),) + The optional final argument allows you to specify the ordering of the lookup. If not specified the lookup will be come the first lookup in its table. *) + val addLookupSubtable: 'a LookupTables.Table.lookup_subtable_t -> ?after_subtable:string -> t -> unit + (** Creates a new subtable within the specified lookup. + The lookup name should be a string specifying an existing lookup. + The subtable name should also be a string and should not match any currently existing subtable in the lookup. + The optional final argument allows you to specify the ordering within the lookup. + If not specified this subtable will be first in the lookup. + If you want to create a subtable in a contextual lookup, then use addContextualSubtable below. + If you want to create a kerning class subtable, then use addKerningClass above. *) + +(** TODO + - val addContextualSubtable: lookupname:string -> subtable:string -> subtabletype:string -> rule: ?? + -> ?afterSubtable:string -> ?bclasses:string -> mclasses: string -> ?fclasses:string -> ?bclassnames:string -> ?mclassnames:string -> ?fclassnames:string + -> t -> unit + - addSmallCaps + - alterKerningClass + - autoKern + - appendSFNTName +*) + + val buildOrReplaceAALTFeatures: t -> unit + (** Removes any existing AALT features (and any lookups solely controled by such features) and creates new ones containing all possible single and alternate substutions available for each glyph. *) + val cidConvertByCMap: filename:string -> t -> unit + (** Converts a normal font into a CID-keyed font with one subfont using + the CMAP to determine the mapping. *) + +(** TODO + - cidConvertTo +*) + + val cidFlatten: t -> unit + (** Converts a CID font into a normal font (glyphs will be in CID order). *) + val cidInsertBlankSubFont: t -> unit + (** Adds a new (blank) sub-font into a cid-keyed font and changes the current sub-font to be it. *) + val cidFlattenByCMap: filename:string -> t -> unit + (** Converts a CID font into a normal font (glyphs will be in CID order). *) + val cidRemoveSubFont: t -> unit + (** Removes the current subfont from a cid-keyed font. *) + val close: t -> unit + (** Frees memory for the current font. + Warning: Any python pointers to it will become invalid. *) + +(** TODO + - compareFonts +*) + + val createChar: unicode:int -> ?name:string -> t -> Glyph.t + (** Create (and return) a character at the specified [unicode] codepoint in this font and optionally [name] it. + If you wish to create an glyph with no unicode codepoint set the first argument to -1 and specify a name. + If there is already a character there, return it (it will not be renamed). *) + +(** TODO + - createInterpolatedGlyph + - createMappedChar + - find + - indEncodingSlot + - glyphs +*) + + val generate: filename:string -> t -> unit + (** TODO: adds optional args for [generate] *) + +(** TODO + - generateTtc + - generateFeatureFile + - genericGlyphChange + - getKerningClass + - getLookupInfo + - getLookupSubtables + - getLookupSubtableAnchorClasses + - getLookupOfSubtable + - getSubtableOfAnchor + - importBitmaps + - importLookups + - interpolateFonts + - isKerningClass + - isVerticalKerning + - italicize +*) + + val lookupSetFeatureList: lookupname:string -> features:lookup_feature_t list -> t -> unit + (** Sets the feature list of indicated lookup. + The feature-script-lang tuple is described at [addLookup] function. *) + val lookupSetFlags: lookupname:string -> flags:string list -> t -> unit + (** Sets the lookup flags for the named lookup. + At most one of these strings may be the name of a mark class. + The others are: + - right_to_left + - ignore_bases + - ignore_ligatures + - ignore_marks *) + val lookupSetStoreLigatureInAfm: lookupname:string -> store:bool -> t -> unit + (** Sets whether this ligature lookup contains data to store in the afm. *) + val mergeFonts: filename:string -> ?preserveCrossFontKerning:bool -> t -> unit + (** Merges the font in the file into the current font. *) + val mergeFeature: filename:string -> t -> unit + (** Merge feature and lookup information from an adobe feature file, or metrics information from the (afm,tfm,etc) file into the current font. *) + val mergeKern: filename:string -> t -> unit + (** Deprecated name for mergeFeature above *) + val mergeLookups: lookupname1:string -> lookupname2:string -> t -> unit + (** The lookups must be of the same type. + All subtables from [lookupname2] will be moved to [lookupname1], the features list of [lookupname2] will be merged with that of [lookupname1], and [lookupname2] will be removed. *) + val mergeLookupSubtables: subtable1:string -> subtable2:string -> t -> unit + (** The subtables must be in the same lookup. + Not all lookup types allow their subtables to be merged (contextual subtables may not be merged, kerning classes may not be (kerning pairs may be)). + Any information bound to subtable2 will be bound to subtable1 and subtable2 will be removed. *) + +(** TODO + - printSample +*) + + val randomText: script:string -> ?lang:string -> t -> string + (** Returns a random text sample using the letter frequencies of the specified script (and optionally language). + Both script and language should be expressed as strings containing OpenType Script and Language tags. "dflt" is a reasonable language tag. + If the language is not specified, one will be chosen at random. + If FontForge has no frequency information for the script/language specified it will use the letters in the script with equal frequencies. *) + val regenBitmaps: sizes:int list -> t -> unit + (** A tuple with an entry for each bitmap strike to be regenerated (rerasterized). + Each strike is identified by pixelsize (if the strike is a grey scale font it will be indicated by (bitmap-depth<<16)|pixelsize. *) + + val removeAnchorClass: anchorclass:string -> t -> unit + (** Removes the named AnchorClass (and all associated points) from the font. *) + val removeLookup: lookup:string -> t -> unit + (** Remove the lookup (and any subtables within it). *) + val removeLookupSubtable: subtable:string -> t -> unit + (** Remove the subtable (and all data associated with it). *) + val removeGlyph: Selection.request_t -> t -> unit + (** You may either pass in a FontForge glyph object (from this font) or identify a glyph in the font by unicode code point or name. + In any case the glyph will be removed from the font. + WARNING: This frees fontforge's storage to this glyph. + If you have any python pointers (also [FFglyph.t] value) to that storage they will be looking at garbage. + This does not go through the usual python reference mechanism. *) + val removeGlyph_from_unicode: unicode:int -> t -> unit + (** Shortcut using [removeGlyph]. *) + val removeGlyph_from_glyphname: glyphname:string -> t -> unit + (** Shortcut using [removeGlyph]. *) + val removeGlyph_from_glyph: glyph:Glyph.t -> t -> unit + (** Shortcut using [removeGlyph]. *) + + type replace_spec_t + (** Abstract type for [replaceAll] function. *) + val from_Layer: srch:Layer.t -> rpl:Layer.t -> replace_spec_t + (** For replacing a [FFlayer] by another one. *) + val from_Contour: srch:Contour.t -> rpl:Contour.t -> replace_spec_t + (** For replacing a [FFcontour] by another one. *) + val replaceAll: spec:replace_spec_t -> ?error_bound:float -> t -> unit + (** Searches the font for all occurences of the srch contour (or layer) and replaces them with the replace contour (or layer). *) + val replaceAll_from_Layer: srch:Layer.t -> rpl:Layer.t -> ?error_bound:float -> t -> unit + (** Idem [replaceAll] from a layer *) + val replaceAll_from_Contour: srch:Contour.t -> rpl:Contour.t -> ?error_bound:float -> t -> unit + (** Idem [replaceAll] from a contour *) + + val revert: t -> unit + (** Reloads the font from the disk. + Caveat: if you have any pointers to glyphs which live in the font those pointers will no longer be valid, and using them will cause crashes. + This is very un-python-like. *) + val revertFromBackup: t -> unit + (** Reloads the font from the backup file on the disk. + Caveat: if you have any pointers to glyphs which live in the font those pointers will no longer be valid, and using them will cause crashes. + This is very un-python-like. *) + val save: filename:string -> t -> unit + (** Saves the font to an sfd file. + See also generate() *) + val saveNamelist: filename:string -> t -> unit + (** Saves the font's namelist to a file. *) + val getTableData: tablename:string -> t -> string + (** Gets binary data from any saved table. + FontForge will save 'fpgm', 'prep', 'cvt ' and 'maxp'. + FontForge may also save tables which you explicitly request. + Do not expect to get binary data for tables like 'GPOS' or 'glyf' which FontForge will generate when it creates a font... that information is not currently available. + Returns a binary string. *) + +(** TODO + - setTableData: tablename:string -> ?? -> t -> unit +*) + + val validate: ?force:bool -> t -> int + (** Validates the font and returns a bit mask of all errors from all glyphs (as defined in the validation_state of a glyph -- except bit 0x1 is clear). + If the font passed the validation then the return value will be 0 (not 0x1). + Otherwise the return value will be the set of errors found. + Note: The set of errors is slightly different for TrueType and PostScript output. + The returned mask contains the list of potential errors. You must figure out which apply to you. + + Normally each glyph will cache its validation_state and it will not be recalculated. + If you pass a non-zero argument to the routine then it will force recalculation of each glyph -- this can be slow.s *) + + val addExtrema: t -> unit + (** Extrema should be marked by on-curve points. If a curve in any selected glyph lacks a point at a significant extremum this command will add one. *) + val addSmallCaps: t -> unit + (** For all selected upper or lower case letters in the latin, greek and cyrillic scripts this will try to create a small caps version of that glyph in a new glyph slot. + So if you select "A" (or "a") then a glyph "a.sc" will be created (if "a.sc" already exists, it will be reused, and its current contents cleared). + The contents of "a.sc" will be based on the upper case variant of this glyph (and that variant must be present for the command to work). + FontForge will also create two lookups (unless appropriate ones already exist) one, bound to the feature 'c2sc' will map upper case letters to small caps, the other, bound to feature 'smcp' will map lower case letters to small caps. *) + val autoHint: t -> unit + (** Generates PostScript hints for all selected glyphs. *) + val autoInstr: t -> unit + (** Generates TrueType instructions for all selected glyphs. *) + val autoTrace: t -> unit + (** Auto traces any background images in all selected glyphs. *) + val build: t -> unit + (** If any of the selected characters is a composite character, then this command will clear it and insert references to its components (this command can create new glyphs). *) + val canonicalContours: t -> unit + (** Orders the contours in the selected glyphs by the x coordinate of their leftmost point. + This can reduce the size of the charstring needed to describe the glyph(s). *) + val canonicalStart: t -> unit + (** Sets the start point of all the contours of the selected glyphs to be the leftmost point on the contour. + If there are several points with that value then use the one which is closest to the baseline. + This can reduce the size of the charstring needed to describe the glyph(s). + By regularizing things it can also make more things available to be put in subroutines. *) + val clear: t -> unit + (** Clears the contents of all selected glyphs. *) + val copy: t -> unit + (** Copies all selected glyphs into (fontforge's internal) clipboard. *) + val copyReference: t -> unit + (** Copies all selected glyphs (as references) into (fontforge's internal) clipboard. *) + val correctDirection: t -> unit + (** Orients all contours so that external ones are clockwise and internal counter-clockwise in all selected glyphs. *) + val correctReferences: t -> unit + (** Checks a font for glyphs with mixed contours and references (or references with transformation matrices which cannot be represented truetype (ie. scaling by 2 or more)). + If a mixed case is discovered fontforge will take the contours out of the glyph, put them in a new glyph, and make a reference to the new glyph. *) + val cut: t -> unit + (** Copies all selected glyphs into (fontforge's internal) clipboard. And then clears them. *) + val paste: t -> unit + (** Pastes the contents of (fontforge's internal) clipboard into the selected glyphs -- and removes what was there before. *) + val intersect: t -> unit + (** Leaves only areas in the intersection of contours in all selected glyphs. See also removeOverlap. *) + val pasteInto: t -> unit + (** Pastes the contents of (fontforge's internal) clipboard into the selected glyphs -- and retains what was there before. *) + val removeOverlap: t -> unit + (** Removes overlapping areas in all selected glyphs. See also intersect. *) + val replaceWithReference: ?fudge:float -> t -> unit + (** Finds any glyph which contains an inline copy of one of the selected glyphs, and converts that copy into a reference to the appropriate glyph. + Selection is changed to the set of glyphs which the command alters. + If specified the fudge argument specifies the error allowed for coordinate differences. *) + val round: ?factor:float -> t -> unit + (** Rounds the x and y coordinates of each point in all selected glyphs. + If factor is specified then new-coord = round(factor*old-coord)/factor. + See also cluster.*) + +(** TODO + - simplify + - stroke +*) + + val transform: matrix:PsMat.t -> t -> unit + (** Transforms all selected glyphs by the matrix. *) + val nltransform: xexpr:string -> yexpr:string -> t -> unit + (** xexpr and yexpr are strings specifying non-linear transformations that will be applied to all points in the selected glyphs of the font (with xexpr being applied to x values, and yexpr to y values, of course). + The syntax for the expressions is explained in the non-linear transform dialog. *) + val unlinkReferences: t -> unit + (** Unlinks all references in all selected glyphs and replaces them with splines. *) + + (** {3 Attributes} *) + + (** Submodules giving read and write access to FontForge contour attributes. *) + + module type IntAttr = Attr with type t = t and type attr = int + module type StringAttr = Attr with type t = t and type attr = string + module type SelectionAttr = Attr with type t = t and type attr = Selection.t + + module Ascent : IntAttr + module Descent : IntAttr + module Em : IntAttr + + module Encoding : StringAttr + module Familyname: StringAttr + module Fontname : StringAttr + module Fullname : StringAttr + module Version : StringAttr + module Weight : StringAttr + + module Selection : SelectionAttr + + module Copyright : StringAttr + +end +(***********************************************************) +module FontForge: sig + (***********************************************************) +(** TODO + - getPrefs: ~name:string -> ?? + - setPrefs: ~name:string -> ~value:?? -> unit +*) + + val savePrefs: unit -> unit + (** Saves the current preference settings. *) + val loadPrefs: unit -> unit + (** Loads the user's default preference settings. + Not done automatically in a script. *) + + val hasSpiro: unit -> bool + (** Returns a boolean, True if Raph Levien's spiro package is available for use in FontForge. *) + val defaultOtherSubrs: unit -> unit + (** Sets the type1 PostScript OtherSubrs to the default value. *) + val readOtherSubrsFile: filename:string -> unit + (** Sets the type1 PostScript OtherSubrs to the stuff found in the file. *) + + val loadEncodingFile: filename:string -> string option + (** Loads an encoding file, returns the name of the encoding or None. *) + val loadNamelist: filename:string -> unit + (** Loads a namelist. *) + val loadNamelistDir: dirname:string -> unit + (** Loads all namelist files in the directory. *) + val loadPlugin: filename:string -> unit + (** Loads a fontforge plugin. *) + val loadPluginDir: dirname:string -> unit + (** Loads all fontforge plugins in the directory. *) + val preloadCidmap: filename:string -> registry:string -> order:string -> supplement:int -> unit + (** Loads a fontforge cidmap file. *) + +(** TODO: From fontforge/python.c file, it seems that the second argument is not used for pdf-file and ps-file! + [print method = { "lp", "lpr", "ghostview", "ps-file", "command", "pdf-file", 5 }]. + - printSetup: ?? -> unit +*) + + val nameFromUnicode: ?namelist:string -> int -> string + (** Finds the glyph name associated with a given unicode codepoint. + If a namelist is specified the name will be taken from that. *) + val unicodeFromName: glyphname:string -> int + (** Looks up glyph name in its dictionary and if it is associated with a unicode code point returns that number. + Otherwise it returns -1. *) + val version: unit -> string + (** Returns fontforge's version number as a string. + This will be a large number like 20070406. *) + val fonts: unit -> Font.t list + (** Returns a list of all fonts currently loaded into fontforge for editing. *) + val activeFont: unit -> Font.t option + (** If the script were invoked from the File->Execute Script... dialog, or invoked by a menu item in the font view, this returns the font that was active at the time. + Otherwise it returns None. *) + val activeGlyph: unit -> Glyph.t option + (** If the script were invoked from the File->Execute Script... dialog or a menu item from an outline glyph window or a glyph import/export command this returns the glyph that was active at the time. + Otherwise it returns None. *) + val activeLayer: unit -> int + (** This returns the currently active layer as an integer between 0 (inclusive) and the font/glyph's layer count (exclusive). + It may also be set to -1 if the current glyph window is displaying the font's guidline layer. *) + val fontsInFile: filename:string -> string list + (** Returns the list of all fontnames found in the specified file. + The list may be empty if fontforge couldn't find any. *) + val openFont: filename:string -> Font.t + (** Opens a filename and returns the font it contains. If it does. + If the flags argument is 4, then FontForge will load all glyphs in the 'glyf' table of a ttc file (rather than just the glyphs used in the font picked). + This will not load all 'glyf' tables though. + Not implemented: flags argument (So, the defaut Python value is used.). + Note the original Python name is [open], but it is an Ocaml keyword. *) + val parseTTInstr: string -> string + (** Returns a binary string each byte of which corresponds to a truetype instruction. + The input string should contain a set of instruction names as "SRP0\nMIRP[min,rnd,black]". *) + val unParseTTInstr: string -> string + (** Reverse of the above. + Converts a binary string into a human (sort of) readable string. *) + +(** TODO + - unitShape: int -> ?? + - registerGlyphSeparationHook +*) + +(** TODO - User Interface Methods *) + + val contour: unit -> Contour.t + (** Creates a new contour. *) + val font: unit -> Font.t + (** Creates a new font. *) + val layer: unit -> Layer.t + (** Creates a new layer. *) + val point: ?oncurve:bool -> ?y:float -> float -> Point.t + (** Creates a new point. + Optionally specifying its location. *) + val pointCoord: ?oncurve:bool -> coord -> Point.t + (** Idem [point] with float coords. *) + + val initialize: unit -> unit + val finalize: unit -> unit +end +(***********************************************************) diff --git a/src/FontForge.ml b/src/FontForge.ml new file mode 100644 index 0000000..90f52f1 --- /dev/null +++ b/src/FontForge.ml @@ -0,0 +1,22 @@ +(******************************************************************************) +(* *) +(* This file is part of fontforge-of-ocaml library *) +(* *) +(* Copyright (C) 2017-2022, Patrick BAUDIN *) +(* (https://github.com/pbaudin/fontforge-of-ocaml) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, but WITHOUT ANY *) +(* WARRANTY; without even the implied warranty of MERCHANTABILITY or *) +(* FITNESS FOR A PARTICULAR PURPOSE. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1) *) +(* *) +(******************************************************************************) + +include LookupTables +include Core diff --git a/src/FontForge.mli b/src/FontForge.mli new file mode 100644 index 0000000..6651d0a --- /dev/null +++ b/src/FontForge.mli @@ -0,0 +1,1740 @@ +(******************************************************************************) +(* *) +(* This file is part of fontforge-of-ocaml library *) +(* *) +(* Copyright (C) 2017-2022, Patrick BAUDIN *) +(* (https://github.com/pbaudin/fontforge-of-ocaml) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, but WITHOUT ANY *) +(* WARRANTY; without even the implied warranty of MERCHANTABILITY or *) +(* FITNESS FOR A PARTICULAR PURPOSE. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1) *) +(* *) +(******************************************************************************) + +(** {1 Lookup Tables} *) + +(***********************************************************) +(** Languages within Script *) +module Script: sig + type t + (** Abstract type *) + + + val mk: ?languages:string list -> string -> t + (** Constructor *) + + val get_scriptname: t -> string + val get_languages: t -> string list + +end + +(** Typography Table *) +module Table: sig + + (** Defines types: one for each group of lookup type. + Each of them have a specific function for adding data into the tables of that group. *) + + type unspecified_table_t + type contextual_table_t + type lookup_pos_sub_t + + (** Defines types: one for each FontForge lookup type. *) + + type ff_gpos_context_t + type ff_gpos_contextchain_t + type ff_gpos_cursive_t + type ff_gpos_mark2base_t + type ff_gpos_mark2ligature_t + type ff_gpos_mark2mark_t + type ff_gpos_pair_t + type ff_gpos_single_t + type ff_gsub_alternate_t + type ff_gsub_context_t + type ff_gsub_contextchain_t + type ff_gsub_ligature_t + type ff_gsub_multiple_t + type ff_gsub_reversecchain_t + type ff_gsub_single_t + type ff_kern_statemachine_t + type ff_morx_indic_t + type ff_morx_insert_t + type ff_morx_context_t + + (** Defines types: one for each style. *) + + type unspecified_args_t + + type args_glyph_kern_t + type args_pos_t + type args_glyph_pos2_t + + type _ args_t = + ARGS_gpos_pair_kern: args_glyph_kern_t -> ff_gpos_pair_t args_t + | ARGS_gpos_pair_full: args_glyph_pos2_t -> ff_gpos_pair_t args_t + | ARGS_gpos_single: args_pos_t -> ff_gpos_single_t args_t + | ARGS_gsub_single: string -> ff_gsub_single_t args_t + | ARGS_gsub_ligature: string list -> ff_gsub_ligature_t args_t + (** Defines GADT: one constructor for each sub-styles. *) + + val args_gpos_pair_kern: glyphname:string -> kerning:int -> ff_gpos_pair_t args_t + val args_gpos_pair_pos2: glyphname:string -> + xoff1:int -> yoff1:int -> xadv1:int -> yadv1:int -> + xoff2:int -> yoff2:int -> xadv2:int -> yadv2:int -> ff_gpos_pair_t args_t + val args_gpos_single: xoff:int -> yoff:int -> xadv:int -> yadv:int -> ff_gpos_single_t args_t + val args_gsub_single: glyphname:string -> ff_gsub_single_t args_t + val args_gsub_ligature: glyphname1:string -> glyphname2:string -> others:string list -> ff_gsub_ligature_t args_t + + (** Defines types: one for each lookup style. *) + + type gpos_context_t = (contextual_table_t * ff_gpos_context_t) * unspecified_args_t + type gpos_contextchain_t = (contextual_table_t * ff_gpos_contextchain_t) * unspecified_args_t + type gpos_cursive_t = (lookup_pos_sub_t * ff_gpos_cursive_t) * unspecified_args_t + type gpos_mark2base_t = (lookup_pos_sub_t * ff_gpos_mark2base_t) * unspecified_args_t + type gpos_mark2ligature_t = (lookup_pos_sub_t * ff_gpos_mark2ligature_t) * unspecified_args_t + type gpos_mark2mark_t = (lookup_pos_sub_t * ff_gpos_mark2mark_t) * unspecified_args_t + type gpos_pair_t = (lookup_pos_sub_t * ff_gpos_pair_t) * ff_gpos_pair_t args_t + type gpos_single_t = (lookup_pos_sub_t * ff_gpos_single_t) * ff_gpos_single_t args_t + type gsub_alternate_t = (lookup_pos_sub_t * ff_gsub_alternate_t) * unspecified_args_t + type gsub_context_t = (contextual_table_t * ff_gsub_context_t) * unspecified_args_t + type gsub_contextchain_t = (contextual_table_t * ff_gsub_contextchain_t) * unspecified_args_t + type gsub_ligature_t = (lookup_pos_sub_t * ff_gsub_ligature_t) * ff_gsub_ligature_t args_t + type gsub_multiple_t = (lookup_pos_sub_t * ff_gsub_multiple_t) * unspecified_args_t + type gsub_reversecchain_t = (contextual_table_t * ff_gsub_reversecchain_t) * unspecified_args_t + type gsub_single_t = (lookup_pos_sub_t * ff_gsub_single_t) * ff_gsub_single_t args_t + type kern_statemachine_t = (unspecified_table_t * ff_kern_statemachine_t) * unspecified_args_t + type morx_indic_t = (unspecified_table_t * ff_morx_indic_t) * unspecified_args_t + type morx_insert_t = (unspecified_table_t * ff_morx_insert_t) * unspecified_args_t + type morx_context_t = (unspecified_table_t * ff_morx_context_t) * unspecified_args_t + + (** Classified lookup type. *) + + type _ t = + GPOS_context: gpos_context_t t + | GPOS_contextchain: gpos_contextchain_t t + | GPOS_cursive: gpos_cursive_t t + | GPOS_mark2base: gpos_mark2base_t t + | GPOS_mark2ligature: gpos_mark2ligature_t t + | GPOS_mark2mark: gpos_mark2mark_t t + | GPOS_pair: gpos_pair_t t + | GPOS_single: gpos_single_t t + | GSUB_alternate: gsub_alternate_t t + | GSUB_context: gsub_context_t t + | GSUB_contextchain: gsub_contextchain_t t + | GSUB_ligature: gsub_ligature_t t + | GSUB_multiple: gsub_multiple_t t + | GSUB_reversecchain: gsub_reversecchain_t t + | GSUB_single: gsub_single_t t + | KERN_statemachine: kern_statemachine_t t + | MORX_indic: morx_indic_t t + | MORX_insert: morx_insert_t t + | MORX_context: morx_context_t t + (** Defines GADT: one constructor by lookup type with constraints on their style. *) + + (** {3 Lookup tables} *) + + type 'a lookup_table_t + (** Lookup tables are named *) + + val mk_lookup_table: 'a t -> name:string -> 'a lookup_table_t + (** Constructor *) + + val get_lookup_name: 'a lookup_table_t -> string + val get_lookup_type: 'a lookup_table_t -> 'a t + val get_lookup_typename: 'a t -> string + + + (** {3 Lookup sub-tables} *) + + type 'a lookup_subtable_t + (** Lookup sub-tables are named *) + + val mk_lookup_subtable: 'a lookup_table_t -> name:string -> 'a lookup_subtable_t + (** Constructor *) + + val get_subtable_name: 'a lookup_subtable_t -> string + val get_lookup_table: 'a lookup_subtable_t -> 'a lookup_table_t + +end +(***********************************************************) +(** Feature classification *) +module Feature: sig + + (** {3 Types} *) + + type _ t + + (** Defines types: one for each combined group of lookup types. + Features of a same group accept a lookup type among the same set of lookup types. *) + + type in_all_t + type in_gpos_mark2base_or_gpos_mark2ligature_t + type in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t + type in_gsub_context_or_gsub_contextchain_or_morx_context_t + type in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t + type in_gsub_multiple_or_gsub_ligature_t + type in_gsub_single_or_gpos_single_t + type in_gsub_single_or_gsub_alternate_t + type in_gsub_single_or_gsub_ligature_t + + type 'a name_t + (** Features are named. *) + + (** {3 Untyped Feature} *) + + val mk: ?scripts:Script.t list -> 'a name_t -> 'a t + (** Feature constructor linking a named script with a language list to an untyped feature. *) + val get_featurename: 'a t -> string + val get_script_languages: 'a t -> Script.t list + +end +(***********************************************************) +(** Typed Feature *) +module TypedFeature: sig + + type _ t + (** Typed feature. *) + + val select_gpos_mark2base_in_gpos_mark2base_or_gpos_mark2ligature: + Feature.in_gpos_mark2base_or_gpos_mark2ligature_t Feature.t -> Table.gpos_mark2base_t t + val select_gpos_mark2ligature_in_gpos_mark2base_or_gpos_mark2ligature: + Feature.in_gpos_mark2base_or_gpos_mark2ligature_t Feature.t -> Table.gpos_mark2ligature_t t + + val select_gsub_multiple_in_gsub_multiple_or_gsub_ligature: + Feature.in_gsub_multiple_or_gsub_ligature_t Feature.t -> Table.gsub_multiple_t t + val select_gsub_ligature_in_gsub_multiple_or_gsub_ligature: + Feature.in_gsub_multiple_or_gsub_ligature_t Feature.t -> Table.gsub_ligature_t t + + val select_gsub_single_in_gsub_single_or_gpos_single: + Feature.in_gsub_single_or_gpos_single_t Feature.t -> Table.gsub_single_t t + val select_gpos_single_in_gsub_single_or_gpos_single: + Feature.in_gsub_single_or_gpos_single_t Feature.t -> Table.gpos_single_t t + + val select_gsub_single_in_gsub_single_or_gsub_alternate: + Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> Table.gsub_single_t t + val select_gsub_alternate_in_gsub_single_or_gsub_alternate: + Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> Table.gsub_alternate_t t + + val select_gsub_single_in_gsub_single_or_gsub_ligature: + Feature.in_gsub_single_or_gsub_ligature_t Feature.t -> Table.gsub_single_t t + val select_gsub_ligature_in_gsub_single_or_gsub_ligature: + Feature.in_gsub_single_or_gsub_ligature_t Feature.t -> Table.gsub_ligature_t t + + val select_gsub_context_in_gsub_context_or_gsub_contextchain_or_morx_context: + Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> Table.gsub_context_t t + val select_gsub_contextchain_in_gsub_context_or_gsub_contextchain_or_morx_context: + Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> Table.gsub_contextchain_t t + val select_morx_context_in_gsub_context_or_gsub_contextchain_or_morx_context: + Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> Table.morx_context_t t + + val select_gpos_pair_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine: + Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t -> Table.gpos_pair_t t + val select_gpos_context_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine: + Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t -> Table.gpos_context_t t + val select_gpos_contextchain_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine: + Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t -> Table.gpos_contextchain_t t + val select_kern_statemachine_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine: + Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t -> Table.kern_statemachine_t t + + val select_gsub_ligature_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context: + Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> Table.gsub_ligature_t t + val select_gsub_context_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context: + Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> Table.gsub_context_t t + val select_gsub_contextchain_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context: + Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> Table.gsub_contextchain_t t + val select_morx_context_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context: + Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> Table.morx_context_t t + + val get_lookup_type: 'a t -> 'a Table.t + +end +(***********************************************************) +(** Predefined Features *) +module PredefinedFeature: sig + + val dflt: ?scripts:Script.t list -> 'a Table.t -> 'a TypedFeature.t + (** Default. *) + + val aalt: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Access All Alternates. *) + val abvf: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Above Base Forms. *) + val abvm: ?scripts:Script.t list -> (Feature.in_gpos_mark2base_or_gpos_mark2ligature_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Above Base Mark. *) + val abvs: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Above Base Substitutions. *) + val afrc: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Vertical Fractions. *) + val akhn: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Akhand. *) + val alig: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Ancient Ligatures. *) + + val blwf: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Below Base Forms. *) + val blwm: ?scripts:Script.t list -> (Feature.in_gpos_mark2base_or_gpos_mark2ligature_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Below Base Mark. *) + val blws: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Below Base Substitutions. *) + + val c2pc: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Capitals to Petite Capitals. *) + val c2sc: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Capitals to Small Capitals. *) + val calt: ?scripts:Script.t list -> (Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Contextual Alternates. *) + val case: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gpos_single_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Case-Sensitive Forms. *) + val ccmp: ?scripts:Script.t list -> (Feature.in_gsub_multiple_or_gsub_ligature_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Glyph Composition/Decomposition. *) + val cfar: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Conjunct Form After Ro. *) + val cjct: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Conjunct Forms. *) + val clig: ?scripts:Script.t list -> unit -> Table.gsub_reversecchain_t TypedFeature.t + (** Contextual Ligatures. *) + val cpct: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Centered CJK Punctuation. *) + val cpsp: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Capital Spacing. *) + val cswh: ?scripts:Script.t list -> unit -> Table.gsub_reversecchain_t TypedFeature.t + (** Contextual Swash. *) + val curs: ?scripts:Script.t list -> unit -> Table.gpos_cursive_t TypedFeature.t + (** Cursive Attachment. *) + val cv00: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 00. *) + val cv01: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 01. *) + val cv02: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 02. *) + val cv03: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 03. *) + val cv04: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 04. *) + val cv05: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 05. *) + val cv06: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 06. *) + val cv07: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 07. *) + val cv08: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 08. *) + val cv09: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 09. *) + val cv10: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 10. *) + val cv99: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 99. *) + + val dcap: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Drop Caps. *) + val dist: ?scripts:Script.t list -> unit -> Table.gpos_pair_t TypedFeature.t + (** Distance. *) + val dlig: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Discretionary Ligatures. *) + val dnom: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Denominators. *) + val dpng: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Dipthongs (Obsolete). *) + val dtls: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Dotless Forms. *) + + (** Expert Forms. *) + val expt: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + + val falt: ?scripts:Script.t list -> unit -> Table.gsub_alternate_t TypedFeature.t + (** Final Glyph On Line. *) + val fin2: ?scripts:Script.t list -> (Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Terminal Forms #2. *) + val fin3: ?scripts:Script.t list -> (Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Terminal Forms #3. *) + val fina: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Terminal Forms. *) + val flac: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_ligature_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Flattened Accents over Capitals. *) + val frac: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_ligature_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Diagonal Fractions. *) + val fwid: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gpos_single_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Full Widths. *) + + val half: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Half Forms. *) + val haln: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Halant Forms. *) + val halt: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Alternative Half Widths. *) + val hist: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Historical Forms. *) + val hkna: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Horizontal Kana Alternatives. *) + val hlig: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Historic Ligatures. *) + val hngl: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Hanja to Hangul. *) + val hojo: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Hojo (JIS X 0212-1990) Kanji Forms. *) + val hwid: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gpos_single_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Half Widths. *) + + val init: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Initial Forms. *) + val isol: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Isolated Forms. *) + val ital: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Italics. *) + + val jalt: ?scripts:Script.t list -> unit -> Table.gsub_alternate_t TypedFeature.t + (** Justification Alternatives. *) + val jajp: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Japanese Forms (Obsolete). *) + val jp04: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** JIS2004 Forms. *) + val jp78: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** JIS78 Forms. *) + val jp83: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** JIS83 Forms. *) + val jp90: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** JIS90 Forms. *) + + val kern: ?scripts:Script.t list -> (Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Horizontal Kerning. *) + + val lfbd: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Left Bounds. *) + val liga: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Standard Ligatures. *) + val ljmo: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Leading Jamo Forms. *) + val lnum: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Lining Figures. *) + val locl: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Localized Forms. *) + + val mark: ?scripts:Script.t list -> (Feature.in_gpos_mark2base_or_gpos_mark2ligature_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Mark Positioning. *) + val med2: ?scripts:Script.t list -> (Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Medial Forms 2. *) + val medi: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Medial Forms. *) + val mgrk: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Mathematical Greek. *) + val mkmk: ?scripts:Script.t list -> unit -> Table.gpos_mark2mark_t TypedFeature.t + (** Mark to Mark. *) + val mset: ?scripts:Script.t list -> (Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Mark Positioning via Substitution. *) + + val nalt: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Alternate Annotation Forms. *) + val nlck: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** NLC Kanji Forms. *) + val nukt: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Nukta Forms. *) + val numr: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Numerators. *) + + val onum: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Oldstyle Figures. *) + val opbd: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Optical Bounds. *) + val ordn: ?scripts:Script.t list -> (Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Ordinals. *) + val ornm: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Ornaments. *) + + val palt: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Proportional Alternate Metrics. *) + val pcap: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Lowercase to Petite Capitals. *) + val pkna: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Proportional Kana. *) + val pnum: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Proportional Numbers. *) + val pref: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Pre Base Forms. *) + val pres: ?scripts:Script.t list -> (Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Pre Base Substitutions. *) + val pstf: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Post Base Forms. *) + val psts: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Post Base Substitutions. *) + val pwid: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Proportional Width. *) + + val qwid: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gpos_single_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Quarter Widths. *) + + val rand: ?scripts:Script.t list -> unit -> Table.gsub_alternate_t TypedFeature.t + (** Randomize. *) + val rkrf: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Rakar Forms. *) + val rlig: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Required Ligatures. *) + val rphf: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Reph Form. *) + val rtbd: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Right Bounds. *) + val rtla: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Right to Left Alternates. *) + val rtlm: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Right to Left mirrored forms. *) + val ruby: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Ruby Notational Forms. *) + + val salt: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Stylistic Alternatives. *) + val sinf: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Scientific Inferiors. *) + val smcp: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Lowercase to Small Capitals. *) + val smpl: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Simplified Forms. *) + val ss01: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 1. *) + val ss02: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 2. *) + val ss03: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 3. *) + val ss04: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 4. *) + val ss05: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 5. *) + val ss06: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 6. *) + val ss07: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 7. *) + val ss08: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 8. *) + val ss09: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 9. *) + val ss10: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 10. *) + val ss11: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 11. *) + val ss12: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 12. *) + val ss13: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 13. *) + val ss14: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 14. *) + val ss15: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 15. *) + val ss16: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 16. *) + val ss17: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 17. *) + val ss18: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 18. *) + val ss19: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 19. *) + val ss20: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 20. *) + val ssty: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Script Style. *) + val subs: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Subscript. *) + val sups: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Superscript. *) + val swsh: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Swash. *) + + val titl: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Titling. *) + val tjmo: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Trailing Jamo Forms. *) + val tnam: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Traditional Name Forms. *) + val tnum: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Tabular Numbers. *) + val trad: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Traditional Forms. *) + val twid: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gpos_single_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Third Widths. *) + + val unic: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Unicase. *) + + val valt: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Alternate Vertical Metrics. *) + val vatu: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Vattu Variants. *) + val vert: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Vertical Alternates (obs). *) + val vhal: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Alternate Vertical Half Metrics. *) + val vjmo: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Vowel Jamo Forms. *) + val vkna: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Vertical Kana Alternates. *) + val vkrn: ?scripts:Script.t list -> (Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Vertical Kerning. *) + val vpal: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Proportional Alternate Vertical Metrics. *) + val vrt2: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Vertical Rotation & Alternates. *) + + val zero: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Slashed Zero. *) +end +(******************************************************************************) + +(** {1 Fontforge} *) + +(***********************************************************) +type coord = float * float + +(***********************************************************) +(** {2 Attributes} *) +module type Attr = sig + type t + type attr + val name: string + val get: t -> attr + val set: t -> attr -> unit +end +(***********************************************************) +(** {2 Tranformation Matrix} *) + +(** [PsMat] which provides quick access to some useful transformations expressed as PostScript matrices. + API: complete (compared to the Python API) except that the type [PsMat.t] become abstract. *) +module PsMat: sig + type t + (** Abstract type for transform PostScript matrices *) + + val identity: unit -> t + (** Returns an identity matrix *) + val compose: mat1:t -> t -> t + (** Returns a matrix which is the composition of the two input transformations *) + val inverse: t -> t + (** Returns a matrix which is the inverse of the input transformation. (Note: There will not always be an inverse) *) + val rotate: float -> t + (** Returns a matrix which will rotate by theta. Theta is expressed in radians *) + val scale: ?y:float -> float -> t + (** Returns a matrix which will scale by [x] in the horizontal direction and y in the vertical. + If [y] is omitted, it will scale by the same amount [x] in both directions *) + val skew: float -> t + (** Returns a matrix which will skew by theta (to produce a oblique font). Theta is expressed in radians *) + val translate: x:float -> y:float -> t + (** Returns a matrix which will translate by x in the horizontal direction and y in the vertical *) +end +(***********************************************************) +(** {2 Point} *) + +(** [Point] + API: complete (compared to the Python API) except the Pickling Method [reduce]. *) +module Point: sig + type t + (** Abstract type for points *) + + (** {3 Methods} *) + + val dup: t -> t + (** Returns a copy of the current point. *) + val transform: matrix:PsMat.t -> t -> unit + (** Transforms the point by the transformation matrix. *) + +(** TODO + - val reduce: +*) + + (** {3 Attributes} *) + + (** Submodules giving read and write accesses to FontForge point attributes. *) + + module type BoolAttr = Attr with type t = t and type attr = bool + module type FloatAttr = Attr with type t = t and type attr = float + + module X: FloatAttr + (** The [x] location of the point. *) + module Y: FloatAttr + (** The [y] location of the point. *) + module On_curve: BoolAttr + (** Whether this is an on curve point or an off curve point (a control point). *) + module Selected: BoolAttr + (** Whether this point is selected in the UI. + If an off-curve point is selected in means the preceding (interpolated) on-curve point is selected. *) +end + +(***********************************************************) +(** {2 Layer} *) + +(** A [Layer] is a collection of Contours. + All the contours must be the same order (all quadratic or all cubic). Currently layers do not contain references. + Layers may be compared to see if their contours are similar. + API: TODO *) +module Layer: sig + type t + (** Abstract type for layers *) +end +(***********************************************************) +(* {2 Glyph Pen} *) + +(** [GlyphPen] Protocol to draw into a [Glyph] + You create a glyphPen with the [GlyphPen] function of a glyph. + You then draw into it with the functions below. + API: complete (compared to the Python API); a [finalize] function has been added. *) +module GlyphPen: sig + type t + (** Abstract type for glyph pens. *) + + (** {3 Python workarounds} *) + + val finalize: t -> unit + (** Finalize the pen (equivalent to [pen = None] at the Python side). + This tells FontForge that the drawing is done and causes it to refresh the display (if a UI is active). + Note: nothing is performed in the OCaml implementation + *) + + (** {3 Methods} *) + + val moveTo: x:int -> y:int -> t -> unit + (** With one exception this call begins every contour and creates an on curve point at (x,y) as the start point of that contour. + This should be the first call after a pen has been created and the call that follows a closePath, endPath. *) + val moveToCoord: coord -> t -> unit + (** Idem [moveTo] with float coords. *) + val lineTo: x:int -> y:int -> t -> unit + (** Draws a line from the last point to (x,y) and adds that to the contour. *) + val lineToCoord: coord -> t -> unit + (** Idem [lineTo] with float coords. *) + val curveTo: cp1:coord -> ?cp2:coord -> pt:coord -> t -> unit + (** This routine has slightly different arguments depending on the type of the font. + When drawing into a cubic font (PostScript) use the first set of arguments (with two control points -- off curve points -- between each on curve point). + When drawing into a quadratic font (TrueType) use the second format (when the optional [cp2] is specified) with one control point between adjacent on-curve points. + The standard appears to support super-bezier curves with more than two control points between on-curve points. + FontForge does not. Nor does FontForge allow you to draw a quadratic spline into a cubic font, nor vice versa. *) + val qcurveTo: cps:coord list -> ?pt:coord -> t -> unit + (** This routine may only be used in quadratic (TrueType) fonts and has two different formats. + It is used to express the TrueType idiom where an on-curve point mid-way between its control points may be omitted, leading to a run of off-curve points (with implied but unspecified on-curve points between them). + The first format (when the optional [pt] is specified) allows an arbetary number of off-curve points followed by one on-curve point. + It is possible to have a contour which consists solely of off-curve points. + When this happens the contour is NOT started with a moveTo, instead the entire contour, all the off curve points, are listed in one call, and the argument list is terminated by a None to indicate there are no on-curve points. *) + val closePath: t -> unit + (** Closes the contour (connects the last point to the first point to make a loop) and ends it. *) + val endPath: t -> unit + (** Ends the contour without closing it. + This is only relevant if you are stroking contours. *) + val addComponent: glyphname:string -> transform:PsMat.t -> t -> unit + (** Adds a reference (a component) to the glyph. + The PostScript transformation matrix is a 6 element tuple. *) +end +(***********************************************************) +(* {2 Contour} *) + +(** A [Contour] is a collection of points. A contour may be either based on cubic or quadratic splines. + + If based on cubic splines there should be either 0 or 2 off-curve points between every two on-curve points. + If there are no off-curve points then we have a line between those two points. If there are 2 off-curve points we have a cubic bezier curve between the two end points. + + If based on quadratic splines things are more complex. + Again, two adjacent on-curve points yield a line between those points. + Two on-curve points with an off-curve point between them yields a quadratic bezier curve. + However if there are two adjacent off-curve points then an on-curve point will be interpolated between them. + (This should be familiar to anyone who has read the truetype 'glyf' table docs). + + For examples of what these splines can look like see the section on bezier curves. + + A contour may be open in which case it is just a long wiggly line, or closed when it is more like a circle with an inside and an outside. + Unless you are making stroked fonts all your contours should eventually be closed. + + Contours may also be expressed in terms of Raph Levien's spiro points. + This is an alternate representation for the contour, and is not always available (Only if fontforge.hasSpiro() is True. + If available the spiro member will return a tuple of spiro control points, while assigning to this member will change the shape of the contour to match the new spiros. + + Two contours may be compared to see if they describe similar paths. + + API: uncomplete (compared to the Python API) *) +module Contour: sig + type t + (** Abstract type for contours *) + + (** {3 Python workarounds} *) + + exception Index_out_of_bounds + val nth: int -> t -> Point.t + (** Related to the python expression: [c[i]]. The ith point on the contour. You may assign to this using [set_nth]. + @raises [Index_out_of_bounds]. *) + val set_nth: int -> Point.t -> t -> unit + (** Related to the python assignement: [c[i] = pt]. + @raises [Index_out_of_bounds]. *) + val len: t -> int + (** The number of points in the contour. *) + + val extract: min:int -> max:int -> t -> t + (** Related to the python expression: [c[min:max]]. The contour containing points between i and j excluded. *) + val add_contour: t -> t -> t + (** Related to the python expression: [c+d]. A contour concatenating c and d (another contour). *) + val add_point: Point.t -> t -> t + (** Related to the python expression: [c+d]. A contour concatenating c and d (a point). *) + val append_contour: t -> t -> unit + (** Related to the python assignement: [c+=d]. Appends d (another contour) to c. *) + val append_point: Point.t -> t -> unit + (** Related to the python assignement: [c+=d]. Appends d (a point) to c. *) + + val to_list: t -> Point.t list + (** Returns the point list of the contour. *) + + (** {4 Iterators} *) + + val iter: f:(Point.t -> unit) -> t -> unit + (** Iterates on the contour points. *) + val iteri: f:(int -> Point.t -> unit) -> t -> unit + val map: f:(Point.t -> 'a) -> t -> 'a list + val mapi: f:(int -> Point.t -> 'a) -> t -> 'a list + val fold: init:'a -> f:('a -> Point.t -> 'a) -> t -> 'a + + (** {3 Methods} *) + + val contains_point: Point.t -> t -> bool + (* Related to the python expression: p in c. + Returns whether the point p is in the contour c. *) + val contains_coord: coord -> t -> bool + (* Related to the python expression: p in c. + Returns whether the point (x,y) is in the contour c. *) + + val dup: t -> t + (** Returns a deep copy of the contour. That is, it copies the points that make up the contour. *) + val isEmpty: t -> bool + (* Returns whether the contour is empty (contains no points). *) + val moveTo: x:int -> y:int -> t -> unit + (** Adds an initial, on-curve point at (x,y) to the contour. *) + val moveToCoord: coord -> t -> unit + (** Idem [moveTo] with float coords. *) + val lineTo: x:int -> y:int -> ?nth:int -> t -> unit + (** Adds an line to the contour. + If the optional third argument is given, the line will be added after the pos'th point, otherwise it will be at the end of the contour. *) + val lineToCoord: coord -> ?nth:int -> t -> unit + (** Idem [LineTo] with float coords. *) + val cubicToCoord: cp1:coord -> cp2:coord -> pt:coord -> ?nth:int -> t -> unit + (** Adds a cubic curve to the contour (requires Is_quadratic set to false). + If the optional fourth argument is give, the line will be added after the pos'th point, otherwise it will be at the end of the contour.*) + val cubicTo: cpx1:int -> cpy1:int -> cpx2:int -> cpy2:int -> x:int -> y:int -> ?nth:int -> t -> unit + (** Idem [cubicToCoord] with int coords. *) + val quadraticToCoord: cp:coord -> pt:coord -> ?nth:int -> t -> unit + (** Adds a quadratic curve to the contour (requires Is_quadratic set to true). + If the optional third argument is give, the line will be added after the pos'th point, otherwise it will be at the end of the contour. *) + val quadraticTo: cpx:int -> cpy:int -> x:int -> y:int -> ?nth:int -> t -> unit + (** Idem [quadraticToCoord] with int coords. *) + val insertPtCoord: pt:coord -> ?onCurve:bool -> ?nth:int -> t -> unit + (** Adds point to the contour. + If the optional third argument is give, the line will be added after the pos'th point, otherwise it will be at the end of the contour. + The point may be either a point or a tuple with three members (x,y,on_curve) *) + val insertPt: x:int -> y:int -> ?onCurve:bool -> ?nth:int -> t -> unit + (** Idem [insertPtCoord] with int coords. *) + val insertPoint: pt:Point.t -> ?nth:int -> t -> unit + (** Idem [insertPt]. *) + + val makeFirst: int -> t -> unit + (** Rotate the point list so that the pos'th point becomes the first point. *) + val isClockwise: t -> int + (** Returns whether the contour is drawn in a clockwise direction. + A return value of -1 indicates that no consistant direction could be found (the contour self-intersects). *) + val reverseDirection: t -> unit + (** Reverse the order in which the contour is drawn (turns a clockwise contour into a counter-clockwise one). + See also layer.correctDirection. *) + +(** TODO + - val similar + - val xBoundsAtY + - val yBoundsAtX + - val addExtrema + - val cluster +*) + + val merge: int list -> t -> unit + (** Removes the on-curve point a the given position and rearranges the other points to make the curve as similar to the original as possible. + All of the listed position will be removed. + See Also simplify. *) + + val round: ?factor:float -> t -> unit + (** Rounds the x and y coordinates. + If factor is specified then new-coord = round(factor*old-coord)/factor. + See Also cluster *) + + val selfIntersects: t -> bool + (** Returns whether this contour intersects itself. *) + +(** TODO + - val simplify + *) + + val transform: matrix:PsMat.t -> t -> unit + (* Transforms the point by the transformation matrix. *) + +(** TODO + - boundingBox + - getSplineAfterPoint +*) + + val draw: GlyphPen.t -> t -> unit + (* Draw the contour to the pen argument. *) + +(** TODO + - val reduce + *) + + (** {3 Attributes} *) + + (** Submodules giving read and write access to FontForge contour attributes. *) + + module type BoolAttr = Attr with type t = t and type attr = bool + module type StringAttr = Attr with type t = t and type attr = string + + module Is_quadratic: BoolAttr + (** Whether the contour should be interpretted as a set of quadratic or cubic splines. + Setting this value has the side effect of converting the point list to the appropriate format. *) + module Closed: BoolAttr + (** Whether the contour is open or closed. *) + module Name: StringAttr + (** The contour name (generally there is no name). *) + +(** TODO + module Spiro +*) +end +(***********************************************************) +(** {2 Glyph} *) + +(** [Glyph] refers to a fontforge Glyph object. + It has no independent life of its own, it always lives within a font. + It has all the things you expect to be associated with a glyph: a glyph name, a unicode encoding, a drawing layer, GPOS/GSUB features... + This type may not be pickled. + This type may not be created directly -- all glyphs are bound to a font and must be created through the font. + See [Font.createChar] function. + API: partialy implemented (compared to the Python API) but all members and functions are listed. *) +module rec Glyph: sig + type t + (* Abstract type for glyphs. *) + + (** {3 Methods} *) + +(** TODO + - val addAnchorPoint +*) + + val addExtrema: ?flags:string -> ?emsize:int -> t -> unit + (** Extrema should be marked by on-curve points. + If a curve lacks a point at an extrema this command will add one. + Flags may be one of the following strings: + - all - Add all missing extrema + - only_good - Only add extrema on longer splines (with respect to the em-size). Default flag. + - only_good_rm - As above but also merge away on-curve points which are very close to, but not on, an added extremum. *) + val addReference: glyphname:string -> ?transform:PsMat.t -> t -> unit + (** Adds a reference to the specified glyph into the current glyph. + Optionally specifying a transformation matrix *) + val addHint: is_vertical:bool -> start:float -> width:float -> t -> unit + (** Adds a postscript hint. Takes a boolean flag indicating whether the hint is horizontal or vertical, a start location and the hint's width. *) + val addPosSub: ((Table.lookup_pos_sub_t * 'b) * 'b Table.args_t) Table.lookup_subtable_t -> 'b Table.args_t -> t -> unit + (** Adds position/substitution data to the glyph. + The number and type of the arguments vary acording to the type of the lookup containing the subtable. + The first argument should always be a lookup subtable name. + If the lookup is for single substitutions then the second argument should be a string containing a single glyph name. + For multiple and alternated substitutions a tuple of glyph names. For ligatures, a tuple of the ligature components (glyph names). + For single positionings the second through fifth arguments should be small integers representing the adjustment along the appropriate axis. + For pairwise positionings (kerning) the second argument should be the name of the other glyph being kerned with, and the third through tenth should be small integers – or, if there are exactly three arguments then the third specifies traditional, one-axis, kerning. + If there is a previously existing entry, this will replace it (except for ligatures). + *) + +(** TODO + - val appendAccent +*) + + val autoHint: t -> unit + (** Generates PostScript hints for this glyph. *) + val autoInstr: t -> unit + (** Generates TrueType instructions for this glyph. *) + val autoTrace: t -> unit + (** Auto traces any background images. *) + val build: t -> unit + (** If the character is a composite character, then clears it and inserts references to its components. *) + val canonicalContours: t -> unit + (** Orders the contours in the current glyph by the x coordinate of their leftmost point. + This can reduce the size of the charstring needed to describe the glyph(s). *) + val canonicalStart: t -> unit + (** Sets the start point of all the contours of the current glyph to be the leftmost point on the contour. + If there are several points with that value then use the one which is closest to the baseline. + This can reduce the size of the charstring needed to describe the glyph(s). + By regularizing things it can also make more things available to be put in subroutines. *) + +(** TODO + - val changeWeight +*) + + val condenseExtend: c_factor:float -> c_add:float -> ?sb_factor:float -> ?sb_add:float -> ?correct:bool -> t -> unit + (** Condenses or extends the size of the counters and side-bearings of the glyph. + The first two arguments provide information on shrinking/growing the counters, the second two the sidebearings. + If the last two are omitted they default to the same values as the first two. + A counter's width will become: + new_width = c_factor * old_width + c_add + + If present the correct argument allows you to specify whether you want to correct for the italic angle before condensing the glyph. (it defaults to True). *) + val clear: t -> unit + (** Clears the contents of the glyph (and marks it as not worth outputting). *) + val cluster: ?within:float -> ?max:float -> t -> unit + (** Moves clustered coordinates to a standard central value. + See also round. *) + val correctDirection: t -> unit + (** Orients all contours so that external ones are clockwise and internal counter-clockwise. *) + val exclude: Layer.t -> t -> unit + (** Removes the excluded area from the current glyph. Takes an argument which is a layer. + See also removeOverlap and intersect. *) + +(** TODO + - val export + - val getPosSub: string -> t -> ?? +*) + + val importOutlines: filename:string -> ?flags:string list -> t -> unit + (** Uses the file's extension to determine behavior. + Imports outline descriptions (eps, svg, glif files) into the forground layer. + Imports image descriptions (bmp, png, xbm, etc.) into the background layer. + Optionally, flags can be used to control PostScript import, it'll be ignored for other file types. + Flags is a list of strings? *) + val intersect: t -> unit + (** Leaves only areas in the intersection of contours. See also removeOverlap and exclude. *) + val isWorthOutputting: t -> bool + (** Returns whether the glyph is worth outputting into a font file. + Basically a glyph is worth outputting if it contains any contours, or references or has had its width set. *) + val preserveLayerAsUndo: ?layer_dohints:(int * bool) -> t -> unit + (** Normally undo handling is turned off during python scripting. + If you wish you may tell fontforge to preserve the current state of a layer so that whatever you do later can be undone by the user. + You may omit the layer parameter (in which case the currently active layer will be used). + You may also request that hints be preserved (they are not, by default).*) + val removeOverlap: t -> unit + (** Removes overlapping areas. See also intersect and exclude. *) + val removePosSub: name:string -> t -> unit + (** Removes all data from the glyph corresponding to the given lookup-subtable. If the name is "*" then all data will be removed. *) + val round: ?factor:int -> t -> unit + (** Rounds the x and y coordinates of each point in the glyph. + If factor is specified then new-coord = round(factor*old-coord)/factor. + See also cluster. *) + val selfIntersects: t -> bool + (** Returns whether any of the contours in this glyph intersects any other contour in the glyph (including itself). *) + val transform: matrix:PsMat.t -> ?flags:string list -> t -> unit + (** Transforms the glyph by the matrix. + The optional flags argument should be a tuple containing any of the following strings: + - partialRefs - Don't transform any references in the glyph, but do transform their offsets. + This is useful if the refered glyph will be (or has been) transformed. + - round - Round to int after the transformation is done.*) + val nltransform: xexpr:string -> yexpr:string -> t -> unit + (** xexpr and yexpr are strings specifying non-linear transformations that will be applied to all points in the current layer (with xexpr being applied to x values, and yexpr to y values, of course). + The syntax for the expressions is explained in the non-linear transform dialog. *) + val unlinkRef: ?refname:string -> t -> unit + (** Unlinks the reference to the glyph named ref-name. + If ref-name is omitted, unlinks all references. *) + val unlinkThisGlyph: t -> unit + (** Unlinks all the references to the current glyph within any other glyph in the font. *) + val useRefsMetrics: name:string -> ?flag:bool -> t -> unit + (** Finds a reference with the given name and sets the "use_my_metrics" flag on it (so this glyph will have the same advance width as the glyph the reference points to). + If the optional flag argument is False, then the glyph will no longer have its metrics bound to the reference.*) + val validate: ?force:bool -> t -> int + (** Validates the glyph and returns the validation_state of the glyph (except bit 0x1 will always be clear). + If the glyph passed the validation then the return value will be 0 (not 0x1). + Otherwise the return value will be the set of errors found. + If force is specified true this will always be validated, if force is unspecified (or specified as false) then it will return the cached value if it is known, otherwise will validate it. *) + val draw: GlyphPen.t -> t -> unit + (** Draw the glyph's outline to the pen argument. *) + val glyphPen: ?replace:bool -> t -> GlyphPen.t + (** Creates a new glyphPen which will draw into the current glyph. + By default the pen will replace any existing contours and references, but setting the optional keyword argument, replace to false will retain the old contents.*) + + (** {3 Attributes} *) + + (** Submodules giving read and write access to FontForge glyph attributes. + Readonly attributes are implemented as functions. *) + + module type BoolAttr = Attr with type t = t and type attr = bool + module type IntAttr = Attr with type t = t and type attr = int + module type StringAttr = Attr with type t = t and type attr = string + + module ActiveLayer: IntAttr + (** Returns currently active layer in the glyph (as an integer). + May be set to an integer or a layer name to change the active layer. + Not implemented: set the attribute from a layer name *) + +(** TODO + - module Atuni: ???Attr + - module AnchorPoints: ???Attr + - module AnchorPointsWithSel: ???Attr + - module Background: ???Attr +*) + + module Changed: BoolAttr + (* Whether this glyph has been modified. + This is (should be) maintained automatically, but you may set it if you wish. *) + module Color: IntAttr + (* The color of the glyph in the fontview. + A 6 hex-digit RGB number or -1 for default. + 0xffffff is white, 0x0000ff is blue, etc. *) + +(** TODO + - module Comments: UTF8Attr + - module Dhints: FloatTuple2Tuple3ListAttr +*) + + val encoding: t -> int + (** Returns the glyph's encoding in the font's encoding. (readonly) + If the glyph has multiple encodings, one will be picked at random. + If the glyph is not in the font's encoding then a number will be returned beyond the encoding size (or in some cases -1 will be returned). + Note: an Ocaml [IntAttr] module is not used there since the Python attribute [font] is read only. *) + val font: t -> Font.t + (** The font containing this glyph. + Note: an Ocaml [FontAttr] module is not used there since the Python attribute [font] is read only. *) + +(** TODO + - module Foreground: ??Attr +*) + + module Glyphclass: StringAttr + (* An opentype glyphclass, one of automatic, noclass, baseglyph, baseligature, mark, component. *) + module Glyphname: StringAttr + (* The name of the glyph. *) + +(** TODO + - module Hhints: FloatTuple2ListAttr + - module HorizontalComponents: ??Attr + - module HorizontalComponentItalicCorrection : ??Attr +*) + + (* module HorizontalVariants: ??Attr *) + (* A boolean containing the MATH "is extended shape" field. *) + module IsExtendedShape: BoolAttr + (* The glyph's italic correction field. Used by both TeX and MATH. + The special value of -32768 (0x8000) means the value is unspecified. + An unspecified value will not go into the output tables, a value of 0 will. *) + module ItalicCorrection: IntAttr + + val layer_cnt: t -> int + (** The number of layers in this glyph. + Cannot be set. + Note: an Ocaml [IntAttr] module is not used there since the Python attribute [font] is read only. *) + +(** TODO seems to be readonly + - module Layers: ??Attr + - module Layerrefs: ??Attr + - module Lcarets: ??Attr +*) + + module Left_side_bearing: IntAttr + (* The left side bearing of the glyph. *) + +(** TODO + - module ManualHints: ??Attr + - module MathKern: ??Attr + - module Persistant: ??Attr + - module References: ??Attr +*) + + module Right_side_bearing: IntAttr + (* The right side bearing of the glyph. *) + +(** TODO + - module Temporary: ??Attr +*) + + module Texheight: IntAttr + (** The Tex height. + The special value of -32768 (0x8000) means the field is unspecified. + An unspecified value will not go into the output tables, a value of 0 will. *) + module Texdepth: IntAttr + (** The Tex depth. + The special value of -32768 (0x8000) means the field is unspecified. + An unspecified value will not go into the output tables, a value of 0 will. *) + module Topaccent: IntAttr + (** The glyph's top accent position field. Used by MATH. + The special value of -32768 (0x8000) means the field is unspecified. + An unspecified value will not go into the output tables, a value of 0 will. *) + +(** TODO + - module Ttinstrs: ??Attr +*) + + module Unicode: IntAttr + (** The glyph's unicode code point, or -1 *) + module UnlinkRmOvrlpSave: IntAttr + (** A flag that indicates the glyph's references should be unlinked and remove overlap run on it before the font is saved (and then the original references replaced after the save finishes). *) + +(** TODO + - module VerticalComponents: ??Attr + - module VerticalComponentsItalicCorrection: ??Attr + - module VerticalVariants: ??Attr + - module Vhints: ??Attr +*) + + (* The vertical advance width of the glyph. See also width. *) + module Vwidth: IntAttr + (* The advance width of the glyph. See also vwidth. *) + module Width: IntAttr + (* The GID of this glyph in the font it was read from. (readonly) *) + + val originalgid: t -> int + + val script: t -> string + (** A string containing the OpenType 4 letter tag for the script associated with this glyph (readonly). *) + + val validation_state: t -> int + (** A (readonly) bit mask indicating some problems this glyph might have. + 0x1 If set then this glyph has been validated. + If unset then other bits are meaningless. + 0x2 Glyph has an open contour. + 0x4 Glyph intersects itself somewhere. + 0x8 At least one contour is drawn in the wrong direction + 0x10 At least one reference in the glyph has been flipped + (and so is drawn in the wrong direction) + 0x20 Missing extrema + 0x40 A glyph name referred to from this glyph, in an opentype table, + is not present in the font. + 0x80 PostScript has a limit of 1500 points in a glyph. + 0x100 PostScript has a limit of 96 hints in a glyph. + 0x200 Invalid glyph name. + TrueType only, errors in original file + 0x400 More points in a glyph than allowed in 'maxp' + 0x800 More paths in a glyph than allowed in 'maxp' + 0x1000 More points in a composite glyph than allowed in 'maxp' + 0x2000 More paths in a composite glyph than allowed in 'maxp' + 0x4000 Instructions longer than allowed in 'maxp' + 0x8000 More references in a glyph than allowed in 'maxp' + 0x10000 References nested more deeply than allowed in 'maxp' + 0x40000 Points too far apart. TrueType and Type2 fonts are limited to 16 bit numbers, + and so adjacent points must be within 32767 em-units of each other. + 0x80000 Points non-integral. TrueType points and control points must be integer aligned. + (FontForge will round them if they aren't) + 0x100000 Missing anchor. According to the opentype spec, if a glyph contains an anchor + point for one anchor class in a subtable, it must contain anchor points for all + anchor classes in the subtable. + Even it, logically, they do not apply and are unnecessary. + 0x200000 Duplicate glyph name. Two (or more) glyphs in this font have the same name. + When outputting a PostScript font only one of them will ever be seen. + It's a little hard to detect this in normal use, but if you change the encoding + to "Glyph Order", and then use Edit->Select->Wildcard and enter the glyph name, + both of them should be selected. + 0x400000 Duplicate unicode code point. Two (or more) glyphs in this font have the code point. + When outputting an sfnt (TrueType/OpenType) font only one of them will ever be seen. + It's a little hard to detect this in normal use, but if you change the encoding + to "Glyph Order", and then use Edit->Select->Wildcard and enter the code point, + both of them should be selected. + 0x800000 Overlapped hints. Either the glyph has no hint masks and there are overlapped + hints, or a hint mask specifies two overlapping hints. *) +end +(***********************************************************) +(** {2 Selection} *) + +(** [Selection] of glyphs. + API: complete with some specificities about the selection requests and the iterations (compared to the Python API). *) +and Selection: sig + type t + (* Abstract type for contours *) + + (** {3 Python workarounds} *) + + val byGlyphs: t -> t + (* Returns another selection, just the same as this one except that its iterator function + will return glyphs (rather than encoding slots) and will only return those entries for which glyphs exist. + Note: an Ocaml [FFmember] module is not used there since the Python attribute [byGlyphs] is read only. *) + + exception UnspecifiedSlotIteration + exception UnspecifiedGlyphIteration + val iter: ?slot:(int -> unit) -> ?glyph:(Glyph.t -> unit) -> t -> unit + (* Iterates on selected item using one of the two function depending on the current iteration mode (see [byGlyphs]). + Raises [UnspecifiedSlotIteration] when the iteration is over encoding slots and the [slot] function is unspecified. + Raises [UnspecifiedGlyphIteration] when the iteration is over glyphs and the [glyph] function is unspecified. + Related to efficiency, [max] specifies the maximal number of items returned from the Python side in one call to [next_items]. *) + + type request_t + (* Abstract type for beeing able to build selection requests. *) + val glyphname: string -> request_t + (* Build a selection request from a glyph [name]. *) + val glyph: Glyph.t -> request_t + (* Build a selection request from a fontforge [glyph]. *) + val code: int -> request_t + (* Build a selection request from the [code] either an encoding index or (default) a unicode code point depending on the flags. *) + + val select: ?encoding:bool -> ?less:bool -> ?ranges:bool -> request:request_t list -> t -> unit + (* Select specified items depending on specified flags: + - ?encoding=false (default) -> "unicode" - Interpret specified code items as unicode code points + - ?encoding=true -> "encoding"- Interpret specified code items as encoding indeces. + + - ?less=unspecified (default) -> "None" - Would produce a selection from scratch using specified items + - ?less=false -> "more" - Would add specified items to the current selection + - ?less=true -> "less" - Would remove specified items from the current selection + + - ?ranges=false (default) -> "singletons" - Specified items should be interpreted individually and mean the obvious. + - ?ranges=true -> "ranges"- Specified items should be interpreted in pairs and represent all encoding slots between the start and end points specified by the pair. + *) + + val select_from_encoding: encoding:int -> t -> unit + (* Shortcut: Select from an unicode. *) + val select_from_unicode: unicode:int -> t -> unit + (* Shortcut: Select from an unicode. *) + val select_from_glyphname: name:string -> t -> unit + (* Shortcut: Select from a glyph name. *) + + val all: t -> unit + (** Select everything. *) + val none: t -> unit + (** Deselect everything. *) + val changed: t -> unit + (** Select all glyphs which have changed. *) + val invert: t -> unit + (** Invert the selection. *) + +end +(***********************************************************) +(* {2 Font} *) + +(** FontForge [Font] object. + It generally contains a list of glyphs, an encoding to order those glyphs, a fontname, a list of GPOS/GSUB lookups and many other things. + API: almost complete (all listed even the unimplemented ones) compared to the Python API. +*) +and Font: sig + type t + (** Abstract type for fonts *) + + (** {3 Python workarounds} *) + + val contains_glyphname: glyphname:string -> t -> bool + (** Equivalent to the Python expression: [glyphname in font]. + Returns whether the font contains a glyph with the given name. *) + val contains_unicode: unicode:int -> t -> bool + (** Equivalent to the Python expression: unicode in font. + Returns whether the font contains a glyph with that encoding. *) + + val glyph_from_name: glyphname:string -> t -> Glyph.t + (** Equivalent to the Python access [font[glyphname]] from a string. + Returns the glyph with that name.*) + val glyph_from_code: unicode:int -> t -> Glyph.t + (** Equivalent to the Python access [font[unicode]] from an integer. + Returns the glyph at that encoding. *) + + (** {3 Methods} *) + + val addAnchorClass: subtable:string -> anchorclass:string -> t -> unit + (** Adds an anchor class to the specified (anchor) subtable. *) + +(** TODO + - gpos_pair + - val addKerningClass +*) + + type lookup_script_t + (** Abstract type for script languages of lookup features *) + val lookupScript: script:string -> languages:string list -> lookup_script_t + (** i.e. [let script = lookupScript ~script:"latn" ~languages:["dflt"]] *) + type lookup_feature_t + (** Abstract type for lookup features *) + val lookupFeature: feature:string -> scripts:lookup_script_t list -> lookup_feature_t + (** i.e. [let feature = lookupFeature feature:"liga" scripts:[script]] *) + val addLookup: 'a Table.lookup_table_t -> 'a Table.t -> + flags:string list -> 'a TypedFeature.t -> ?others:'a TypedFeature.t list -> ?after_lookupname:string -> t -> unit + (** Creates a new lookup with the given name, type and flags. It will tag it with any indicated features. The type of one of + - gsub_single + - gsub_multiple + - gsub_alternate + - gsub_ligature + - gsub_context + - gsub_contextchain + - gsub_revesechain + - morx_indic + - morx_context + - morx_insert + - gpos_single + - gpos_pair + - gpos_cursive + - gpos_mark2base + - gpos_mark2ligature + - gpos_mark2mark + - gpos_context + - gpos_contextchain + - kern_statemachine + + The flags argument is a tuple of strings. At most one of these strings may be the name of a mark class. + The others are: + - right_to_left + - ignore_bases + - ignore_ligatures + - ignore_marks + + A feature-script-lang tuple is a tuple with one entry for each feature (there may be no entries if there are no features). + Each entry is itself a two element tuple, the first entry is a string containing a 4 letter feature tag, and the second entry is another tuple (potentially empty) with an entry for each script for which the feature is active. + Each entry here is itself a two element tuple. + The first element is a 4 letter script tag and the second is a tuple of languages. Each entry in the language tuple is a four letter language. + - Example: (("liga",(("latn",("dflt")),)),) + The optional final argument allows you to specify the ordering of the lookup. If not specified the lookup will be come the first lookup in its table. *) + val addLookupSubtable: 'a Table.lookup_subtable_t -> ?after_subtable:string -> t -> unit + (** Creates a new subtable within the specified lookup. + The lookup name should be a string specifying an existing lookup. + The subtable name should also be a string and should not match any currently existing subtable in the lookup. + The optional final argument allows you to specify the ordering within the lookup. + If not specified this subtable will be first in the lookup. + If you want to create a subtable in a contextual lookup, then use addContextualSubtable below. + If you want to create a kerning class subtable, then use addKerningClass above. *) + +(** TODO + - val addContextualSubtable: lookupname:string -> subtable:string -> subtabletype:string -> rule: ?? + -> ?afterSubtable:string -> ?bclasses:string -> mclasses: string -> ?fclasses:string -> ?bclassnames:string -> ?mclassnames:string -> ?fclassnames:string + -> t -> unit + - addSmallCaps + - alterKerningClass + - autoKern + - appendSFNTName +*) + + val buildOrReplaceAALTFeatures: t -> unit + (** Removes any existing AALT features (and any lookups solely controled by such features) and creates new ones containing all possible single and alternate substutions available for each glyph. *) + val cidConvertByCMap: filename:string -> t -> unit + (** Converts a normal font into a CID-keyed font with one subfont using + the CMAP to determine the mapping. *) + +(** TODO + - cidConvertTo +*) + + val cidFlatten: t -> unit + (** Converts a CID font into a normal font (glyphs will be in CID order). *) + val cidInsertBlankSubFont: t -> unit + (** Adds a new (blank) sub-font into a cid-keyed font and changes the current sub-font to be it. *) + val cidFlattenByCMap: filename:string -> t -> unit + (** Converts a CID font into a normal font (glyphs will be in CID order). *) + val cidRemoveSubFont: t -> unit + (** Removes the current subfont from a cid-keyed font. *) + val close: t -> unit + (** Frees memory for the current font. + Warning: Any python pointers to it will become invalid. *) + +(** TODO + - compareFonts +*) + + val createChar: unicode:int -> ?name:string -> t -> Glyph.t + (** Create (and return) a character at the specified [unicode] codepoint in this font and optionally [name] it. + If you wish to create an glyph with no unicode codepoint set the first argument to -1 and specify a name. + If there is already a character there, return it (it will not be renamed). *) + +(** TODO + - createInterpolatedGlyph + - createMappedChar + - find + - indEncodingSlot + - glyphs +*) + + val generate: filename:string -> t -> unit + (** TODO: adds optional args for [generate] *) + +(** TODO + - generateTtc + - generateFeatureFile + - genericGlyphChange + - getKerningClass + - getLookupInfo + - getLookupSubtables + - getLookupSubtableAnchorClasses + - getLookupOfSubtable + - getSubtableOfAnchor + - importBitmaps + - importLookups + - interpolateFonts + - isKerningClass + - isVerticalKerning + - italicize +*) + + val lookupSetFeatureList: lookupname:string -> features:lookup_feature_t list -> t -> unit + (** Sets the feature list of indicated lookup. + The feature-script-lang tuple is described at [addLookup] function. *) + val lookupSetFlags: lookupname:string -> flags:string list -> t -> unit + (** Sets the lookup flags for the named lookup. + At most one of these strings may be the name of a mark class. + The others are: + - right_to_left + - ignore_bases + - ignore_ligatures + - ignore_marks *) + val lookupSetStoreLigatureInAfm: lookupname:string -> store:bool -> t -> unit + (** Sets whether this ligature lookup contains data to store in the afm. *) + val mergeFonts: filename:string -> ?preserveCrossFontKerning:bool -> t -> unit + (** Merges the font in the file into the current font. *) + val mergeFeature: filename:string -> t -> unit + (** Merge feature and lookup information from an adobe feature file, or metrics information from the (afm,tfm,etc) file into the current font. *) + val mergeKern: filename:string -> t -> unit + (** Deprecated name for mergeFeature above *) + val mergeLookups: lookupname1:string -> lookupname2:string -> t -> unit + (** The lookups must be of the same type. + All subtables from [lookupname2] will be moved to [lookupname1], the features list of [lookupname2] will be merged with that of [lookupname1], and [lookupname2] will be removed. *) + val mergeLookupSubtables: subtable1:string -> subtable2:string -> t -> unit + (** The subtables must be in the same lookup. + Not all lookup types allow their subtables to be merged (contextual subtables may not be merged, kerning classes may not be (kerning pairs may be)). + Any information bound to subtable2 will be bound to subtable1 and subtable2 will be removed. *) + +(** TODO + - printSample +*) + + val randomText: script:string -> ?lang:string -> t -> string + (** Returns a random text sample using the letter frequencies of the specified script (and optionally language). + Both script and language should be expressed as strings containing OpenType Script and Language tags. "dflt" is a reasonable language tag. + If the language is not specified, one will be chosen at random. + If FontForge has no frequency information for the script/language specified it will use the letters in the script with equal frequencies. *) + val regenBitmaps: sizes:int list -> t -> unit + (** A tuple with an entry for each bitmap strike to be regenerated (rerasterized). + Each strike is identified by pixelsize (if the strike is a grey scale font it will be indicated by (bitmap-depth<<16)|pixelsize. *) + + val removeAnchorClass: anchorclass:string -> t -> unit + (** Removes the named AnchorClass (and all associated points) from the font. *) + val removeLookup: lookup:string -> t -> unit + (** Remove the lookup (and any subtables within it). *) + val removeLookupSubtable: subtable:string -> t -> unit + (** Remove the subtable (and all data associated with it). *) + val removeGlyph: Selection.request_t -> t -> unit + (** You may either pass in a FontForge glyph object (from this font) or identify a glyph in the font by unicode code point or name. + In any case the glyph will be removed from the font. + WARNING: This frees fontforge's storage to this glyph. + If you have any python pointers (also [FFglyph.t] value) to that storage they will be looking at garbage. + This does not go through the usual python reference mechanism. *) + val removeGlyph_from_unicode: unicode:int -> t -> unit + (** Shortcut using [removeGlyph]. *) + val removeGlyph_from_glyphname: glyphname:string -> t -> unit + (** Shortcut using [removeGlyph]. *) + val removeGlyph_from_glyph: glyph:Glyph.t -> t -> unit + (** Shortcut using [removeGlyph]. *) + + type replace_spec_t + (** Abstract type for [replaceAll] function. *) + val from_Layer: srch:Layer.t -> rpl:Layer.t -> replace_spec_t + (** For replacing a [FFlayer] by another one. *) + val from_Contour: srch:Contour.t -> rpl:Contour.t -> replace_spec_t + (** For replacing a [FFcontour] by another one. *) + val replaceAll: spec:replace_spec_t -> ?error_bound:float -> t -> unit + (** Searches the font for all occurences of the srch contour (or layer) and replaces them with the replace contour (or layer). *) + val replaceAll_from_Layer: srch:Layer.t -> rpl:Layer.t -> ?error_bound:float -> t -> unit + (** Idem [replaceAll] from a layer *) + val replaceAll_from_Contour: srch:Contour.t -> rpl:Contour.t -> ?error_bound:float -> t -> unit + (** Idem [replaceAll] from a contour *) + + val revert: t -> unit + (** Reloads the font from the disk. + Caveat: if you have any pointers to glyphs which live in the font those pointers will no longer be valid, and using them will cause crashes. + This is very un-python-like. *) + val revertFromBackup: t -> unit + (** Reloads the font from the backup file on the disk. + Caveat: if you have any pointers to glyphs which live in the font those pointers will no longer be valid, and using them will cause crashes. + This is very un-python-like. *) + val save: filename:string -> t -> unit + (** Saves the font to an sfd file. + See also generate() *) + val saveNamelist: filename:string -> t -> unit + (** Saves the font's namelist to a file. *) + val getTableData: tablename:string -> t -> string + (** Gets binary data from any saved table. + FontForge will save 'fpgm', 'prep', 'cvt ' and 'maxp'. + FontForge may also save tables which you explicitly request. + Do not expect to get binary data for tables like 'GPOS' or 'glyf' which FontForge will generate when it creates a font... that information is not currently available. + Returns a binary string. *) + +(** TODO + - setTableData: tablename:string -> ?? -> t -> unit +*) + + val validate: ?force:bool -> t -> int + (** Validates the font and returns a bit mask of all errors from all glyphs (as defined in the validation_state of a glyph -- except bit 0x1 is clear). + If the font passed the validation then the return value will be 0 (not 0x1). + Otherwise the return value will be the set of errors found. + Note: The set of errors is slightly different for TrueType and PostScript output. + The returned mask contains the list of potential errors. You must figure out which apply to you. + + Normally each glyph will cache its validation_state and it will not be recalculated. + If you pass a non-zero argument to the routine then it will force recalculation of each glyph -- this can be slow.s *) + + val addExtrema: t -> unit + (** Extrema should be marked by on-curve points. If a curve in any selected glyph lacks a point at a significant extremum this command will add one. *) + val addSmallCaps: t -> unit + (** For all selected upper or lower case letters in the latin, greek and cyrillic scripts this will try to create a small caps version of that glyph in a new glyph slot. + So if you select "A" (or "a") then a glyph "a.sc" will be created (if "a.sc" already exists, it will be reused, and its current contents cleared). + The contents of "a.sc" will be based on the upper case variant of this glyph (and that variant must be present for the command to work). + FontForge will also create two lookups (unless appropriate ones already exist) one, bound to the feature 'c2sc' will map upper case letters to small caps, the other, bound to feature 'smcp' will map lower case letters to small caps. *) + val autoHint: t -> unit + (** Generates PostScript hints for all selected glyphs. *) + val autoInstr: t -> unit + (** Generates TrueType instructions for all selected glyphs. *) + val autoTrace: t -> unit + (** Auto traces any background images in all selected glyphs. *) + val build: t -> unit + (** If any of the selected characters is a composite character, then this command will clear it and insert references to its components (this command can create new glyphs). *) + val canonicalContours: t -> unit + (** Orders the contours in the selected glyphs by the x coordinate of their leftmost point. + This can reduce the size of the charstring needed to describe the glyph(s). *) + val canonicalStart: t -> unit + (** Sets the start point of all the contours of the selected glyphs to be the leftmost point on the contour. + If there are several points with that value then use the one which is closest to the baseline. + This can reduce the size of the charstring needed to describe the glyph(s). + By regularizing things it can also make more things available to be put in subroutines. *) + val clear: t -> unit + (** Clears the contents of all selected glyphs. *) + val copy: t -> unit + (** Copies all selected glyphs into (fontforge's internal) clipboard. *) + val copyReference: t -> unit + (** Copies all selected glyphs (as references) into (fontforge's internal) clipboard. *) + val correctDirection: t -> unit + (** Orients all contours so that external ones are clockwise and internal counter-clockwise in all selected glyphs. *) + val correctReferences: t -> unit + (** Checks a font for glyphs with mixed contours and references (or references with transformation matrices which cannot be represented truetype (ie. scaling by 2 or more)). + If a mixed case is discovered fontforge will take the contours out of the glyph, put them in a new glyph, and make a reference to the new glyph. *) + val cut: t -> unit + (** Copies all selected glyphs into (fontforge's internal) clipboard. And then clears them. *) + val paste: t -> unit + (** Pastes the contents of (fontforge's internal) clipboard into the selected glyphs -- and removes what was there before. *) + val intersect: t -> unit + (** Leaves only areas in the intersection of contours in all selected glyphs. See also removeOverlap. *) + val pasteInto: t -> unit + (** Pastes the contents of (fontforge's internal) clipboard into the selected glyphs -- and retains what was there before. *) + val removeOverlap: t -> unit + (** Removes overlapping areas in all selected glyphs. See also intersect. *) + val replaceWithReference: ?fudge:float -> t -> unit + (** Finds any glyph which contains an inline copy of one of the selected glyphs, and converts that copy into a reference to the appropriate glyph. + Selection is changed to the set of glyphs which the command alters. + If specified the fudge argument specifies the error allowed for coordinate differences. *) + val round: ?factor:float -> t -> unit + (** Rounds the x and y coordinates of each point in all selected glyphs. + If factor is specified then new-coord = round(factor*old-coord)/factor. + See also cluster.*) + +(** TODO + - simplify + - stroke +*) + + val transform: matrix:PsMat.t -> t -> unit + (** Transforms all selected glyphs by the matrix. *) + val nltransform: xexpr:string -> yexpr:string -> t -> unit + (** xexpr and yexpr are strings specifying non-linear transformations that will be applied to all points in the selected glyphs of the font (with xexpr being applied to x values, and yexpr to y values, of course). + The syntax for the expressions is explained in the non-linear transform dialog. *) + val unlinkReferences: t -> unit + (** Unlinks all references in all selected glyphs and replaces them with splines. *) + + (** {3 Attributes} *) + + (** Submodules giving read and write access to FontForge contour attributes. *) + + module type IntAttr = Attr with type t = t and type attr = int + module type StringAttr = Attr with type t = t and type attr = string + module type SelectionAttr = Attr with type t = t and type attr = Selection.t + + module Ascent : IntAttr + module Descent : IntAttr + module Em : IntAttr + + module Encoding : StringAttr + module Familyname: StringAttr + module Fontname : StringAttr + module Fullname : StringAttr + module Version : StringAttr + module Weight : StringAttr + + module Selection : SelectionAttr + + module Copyright : StringAttr + +end +(***********************************************************) +(** FontForge module *) +module FontForge: sig + +(** TODO + - getPrefs: ~name:string -> ?? + - setPrefs: ~name:string -> ~value:?? -> unit +*) + + val savePrefs: unit -> unit + (** Saves the current preference settings. *) + val loadPrefs: unit -> unit + (** Loads the user's default preference settings. + Not done automatically in a script. *) + + val hasSpiro: unit -> bool + (** Returns a boolean, True if Raph Levien's spiro package is available for use in FontForge. *) + val defaultOtherSubrs: unit -> unit + (** Sets the type1 PostScript OtherSubrs to the default value. *) + val readOtherSubrsFile: filename:string -> unit + (** Sets the type1 PostScript OtherSubrs to the stuff found in the file. *) + + val loadEncodingFile: filename:string -> string option + (** Loads an encoding file, returns the name of the encoding or None. *) + val loadNamelist: filename:string -> unit + (** Loads a namelist. *) + val loadNamelistDir: dirname:string -> unit + (** Loads all namelist files in the directory. *) + val loadPlugin: filename:string -> unit + (** Loads a fontforge plugin. *) + val loadPluginDir: dirname:string -> unit + (** Loads all fontforge plugins in the directory. *) + val preloadCidmap: filename:string -> registry:string -> order:string -> supplement:int -> unit + (** Loads a fontforge cidmap file. *) + +(** TODO: From fontforge/python.c file, it seems that the second argument is not used for pdf-file and ps-file! + [print method = { "lp", "lpr", "ghostview", "ps-file", "command", "pdf-file", 5 }]. + - printSetup: ?? -> unit +*) + + val nameFromUnicode: ?namelist:string -> int -> string + (** Finds the glyph name associated with a given unicode codepoint. + If a namelist is specified the name will be taken from that. *) + val unicodeFromName: glyphname:string -> int + (** Looks up glyph name in its dictionary and if it is associated with a unicode code point returns that number. + Otherwise it returns -1. *) + val version: unit -> string + (** Returns fontforge's version number as a string. + This will be a large number like 20070406. *) + val fonts: unit -> Font.t list + (** Returns a list of all fonts currently loaded into fontforge for editing. *) + val activeFont: unit -> Font.t option + (** If the script were invoked from the File->Execute Script... dialog, or invoked by a menu item in the font view, this returns the font that was active at the time. + Otherwise it returns None. *) + val activeGlyph: unit -> Glyph.t option + (** If the script were invoked from the File->Execute Script... dialog or a menu item from an outline glyph window or a glyph import/export command this returns the glyph that was active at the time. + Otherwise it returns None. *) + val activeLayer: unit -> int + (** This returns the currently active layer as an integer between 0 (inclusive) and the font/glyph's layer count (exclusive). + It may also be set to -1 if the current glyph window is displaying the font's guidline layer. *) + val fontsInFile: filename:string -> string list + (** Returns the list of all fontnames found in the specified file. + The list may be empty if fontforge couldn't find any. *) + val openFont: filename:string -> Font.t + (** Opens a filename and returns the font it contains. If it does. + If the flags argument is 4, then FontForge will load all glyphs in the 'glyf' table of a ttc file (rather than just the glyphs used in the font picked). + This will not load all 'glyf' tables though. + Not implemented: flags argument (So, the defaut Python value is used.). + Note the original Python name is [open], but it is an Ocaml keyword. *) + val parseTTInstr: string -> string + (** Returns a binary string each byte of which corresponds to a truetype instruction. + The input string should contain a set of instruction names as "SRP0\nMIRP[min,rnd,black]". *) + val unParseTTInstr: string -> string + (** Reverse of the above. + Converts a binary string into a human (sort of) readable string. *) + +(** TODO + - unitShape: int -> ?? + - registerGlyphSeparationHook +*) + +(** TODO - User Interface Methods *) + + val contour: unit -> Contour.t + (** Creates a new contour. *) + val font: unit -> Font.t + (** Creates a new font. *) + val layer: unit -> Layer.t + (** Creates a new layer. *) + val point: ?oncurve:bool -> ?y:float -> float -> Point.t + (** Creates a new point. + Optionally specifying its location. *) + val pointCoord: ?oncurve:bool -> coord -> Point.t + (** Idem [point] with float coords. *) + + val initialize: unit -> unit + val finalize: unit -> unit +end +(***********************************************************) diff --git a/src/LookupTables.ml b/src/LookupTables.ml new file mode 100644 index 0000000..94a50bc --- /dev/null +++ b/src/LookupTables.ml @@ -0,0 +1,721 @@ +(******************************************************************************) +(* *) +(* This file is part of fontforge-of-ocaml library *) +(* *) +(* Copyright (C) 2017-2022, Patrick BAUDIN *) +(* (https://github.com/pbaudin/fontforge-of-ocaml) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, but WITHOUT ANY *) +(* WARRANTY; without even the implied warranty of MERCHANTABILITY or *) +(* FITNESS FOR A PARTICULAR PURPOSE. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1) *) +(* *) +(******************************************************************************) + +(** {1 Lookup Tables} *) + +(***********************************************************) +(** {2 Convert} *) +(***********************************************************) +let int_api api = api ~typ:Util.Value.(Int) +let string_api api = api ~typ:Util.Value.(String) +let string_list_api api = api ~typ:Util.Value.(List String) + +let script_typ = Util.Value.(Pair (String, List String)) +let script_api api= api ~typ:script_typ +let feature_typ = Util.Value.(Pair (String, List script_typ)) +let feature_api api = api ~typ:feature_typ +let feature_list_api api= api ~typ:Util.Value.(List feature_typ) + +let v_int = int_api Util.Value.value +let v_string = string_api Util.Value.value +let v_string_list = string_list_api Util.Value.value +let v_script = script_api Util.Value.value +let v_feature = feature_api Util.Value.value +let v_feature_list = feature_list_api Util.Value.value +(***********************************************************) +(** {2 Script} *) +(***********************************************************) +module Script = struct + + type t = string * string list + (** Shortcut type: script_lang = (script name, language list) *) + + let consolitated_languages = function | [] -> ["dflt"] | languages -> languages + (** Fills the empty language list with the default language ("dflt"). *) + + let mk ?(languages=[]) scriptname = scriptname,(consolitated_languages languages) + let get_scriptname (x,_) = x + let get_languages (_,y) = y + + let value = v_script +end +(***********************************************************) +(** {2 Table} *) +(***********************************************************) +module Table = struct + + (** {3 Styles} *) + + (** lookup type classification. *) + + (** Defines types: one for each group of lookup type. + Each of them have a specific function for adding data into the tables of that group. *) + + type unspecified_table_t (* G0 *) + type contextual_table_t (* G1 *) + type lookup_pos_sub_t (* G2 *) + + (** Defines types: one for each FontForge lookup type. *) + + type ff_gpos_context_t (* T01 *) + type ff_gpos_contextchain_t (* T02 *) + type ff_gpos_cursive_t (* T03 *) + type ff_gpos_mark2base_t (* T04 *) + type ff_gpos_mark2ligature_t (* T05 *) + type ff_gpos_mark2mark_t (* T06 *) + type ff_gpos_pair_t (* T07 *) + type ff_gpos_single_t (* T08 *) + type ff_gsub_alternate_t (* T09 *) + type ff_gsub_context_t (* T10 *) + type ff_gsub_contextchain_t (* T11 *) + type ff_gsub_ligature_t (* T12 *) + type ff_gsub_multiple_t (* T13 *) + type ff_gsub_reversecchain_t (* T14 *) + type ff_gsub_single_t (* T15 *) + type ff_kern_statemachine_t (* T16 *) + type ff_morx_indic_t (* T17 *) + type ff_morx_insert_t (* T18 *) + type ff_morx_context_t (* T19 *) + + (** Defines types: one for each style. *) + + type unspecified_args_t (* S0 *) + + type args_glyph_kern_t = { kerning:int ; glyphname:string } + type args_pos_t = { xoff:int ; yoff:int ; xadv:int ; yadv:int } + type args_glyph_pos2_t = { pos1:args_pos_t ; pos2:args_pos_t ; glyphname:string ; } + type args_str_t = string + type args_str_list_t = string list + + let args_glyph_kern ~glyphname ~kerning = { kerning ; glyphname } + let args_pos ~xoff ~yoff ~xadv ~yadv = { xoff ; yoff ; xadv ; yadv } + let args_glyph_pos2 ~glyphname ~xoff1 ~yoff1 ~xadv1 ~yadv1 ~xoff2 ~yoff2 ~xadv2 ~yadv2 = + { pos1=args_pos ~xoff:xoff1 ~yoff:yoff1 ~xadv:xadv1 ~yadv:yadv1 ; + pos2=args_pos ~xoff:xoff2 ~yoff:yoff2 ~xadv:xadv2 ~yadv:yadv2 ; + glyphname } + + type _ args_t = + | ARGS_gpos_pair_kern : args_glyph_kern_t -> ff_gpos_pair_t args_t + | ARGS_gpos_pair_full : args_glyph_pos2_t -> ff_gpos_pair_t args_t + | ARGS_gpos_single : args_pos_t -> ff_gpos_single_t args_t + | ARGS_gsub_single : args_str_t -> ff_gsub_single_t args_t + | ARGS_gsub_ligature : args_str_list_t -> ff_gsub_ligature_t args_t + (** Defines GADT: one constructor for each sub-styles. *) + + let args_gpos_pair_kern ~glyphname ~kerning = ARGS_gpos_pair_kern (args_glyph_kern ~glyphname ~kerning) + let args_gpos_pair_pos2 ~glyphname ~xoff1 ~yoff1 ~xadv1 ~yadv1 ~xoff2 ~yoff2 ~xadv2 ~yadv2 = ARGS_gpos_pair_full (args_glyph_pos2 ~glyphname ~xoff1 ~yoff1 ~xadv1 ~yadv1 ~xoff2 ~yoff2 ~xadv2 ~yadv2) + let args_gpos_single ~xoff ~yoff ~xadv ~yadv = ARGS_gpos_single (args_pos ~xoff ~yoff ~xadv ~yadv) + let args_gsub_single ~glyphname = ARGS_gsub_single(glyphname) + let args_gsub_ligature ~glyphname1 ~glyphname2 ~others = ARGS_gsub_ligature(glyphname1::glyphname2::others) + + (** Defines types: one for each lookup style. *) + + type gpos_context_t = (contextual_table_t * ff_gpos_context_t ) * unspecified_args_t + type gpos_contextchain_t = (contextual_table_t * ff_gpos_contextchain_t ) * unspecified_args_t + type gpos_cursive_t = (lookup_pos_sub_t * ff_gpos_cursive_t ) * unspecified_args_t + type gpos_mark2base_t = (lookup_pos_sub_t * ff_gpos_mark2base_t ) * unspecified_args_t + type gpos_mark2ligature_t = (lookup_pos_sub_t * ff_gpos_mark2ligature_t ) * unspecified_args_t + type gpos_mark2mark_t = (lookup_pos_sub_t * ff_gpos_mark2mark_t ) * unspecified_args_t + type gpos_pair_t = (lookup_pos_sub_t * ff_gpos_pair_t ) * ff_gpos_pair_t args_t + type gpos_single_t = (lookup_pos_sub_t * ff_gpos_single_t ) * ff_gpos_single_t args_t + type gsub_alternate_t = (lookup_pos_sub_t * ff_gsub_alternate_t ) * unspecified_args_t + type gsub_context_t = (contextual_table_t * ff_gsub_context_t ) * unspecified_args_t + type gsub_contextchain_t = (contextual_table_t * ff_gsub_contextchain_t ) * unspecified_args_t + type gsub_ligature_t = (lookup_pos_sub_t * ff_gsub_ligature_t ) * ff_gsub_ligature_t args_t + type gsub_multiple_t = (lookup_pos_sub_t * ff_gsub_multiple_t ) * unspecified_args_t + type gsub_reversecchain_t = (contextual_table_t * ff_gsub_reversecchain_t ) * unspecified_args_t + type gsub_single_t = (lookup_pos_sub_t * ff_gsub_single_t ) * ff_gsub_single_t args_t + type kern_statemachine_t = (unspecified_table_t * ff_kern_statemachine_t ) * unspecified_args_t + type morx_indic_t = (unspecified_table_t * ff_morx_indic_t ) * unspecified_args_t + type morx_insert_t = (unspecified_table_t * ff_morx_insert_t ) * unspecified_args_t + type morx_context_t = (unspecified_table_t * ff_morx_context_t ) * unspecified_args_t + + (** Classified lookup type. *) + + type _ t = + | GPOS_context : gpos_context_t t + | GPOS_contextchain : gpos_contextchain_t t + | GPOS_cursive : gpos_cursive_t t + | GPOS_mark2base : gpos_mark2base_t t + | GPOS_mark2ligature : gpos_mark2ligature_t t + | GPOS_mark2mark : gpos_mark2mark_t t + | GPOS_pair : gpos_pair_t t + | GPOS_single : gpos_single_t t + | GSUB_alternate : gsub_alternate_t t + | GSUB_context : gsub_context_t t + | GSUB_contextchain : gsub_contextchain_t t + | GSUB_ligature : gsub_ligature_t t + | GSUB_multiple : gsub_multiple_t t + | GSUB_reversecchain : gsub_reversecchain_t t + | GSUB_single : gsub_single_t t + | KERN_statemachine : kern_statemachine_t t + | MORX_indic : morx_indic_t t + | MORX_insert : morx_insert_t t + | MORX_context : morx_context_t t + (** Defines GADT: one constructor by lookup type with constraints on their style. *) + + let values : type a b . ((a*b)*b args_t) t -> b args_t -> Util.Value.t list = + fun lookup_type args -> match lookup_type, args with + | GPOS_pair, ARGS_gpos_pair_kern { kerning ; glyphname } -> [ v_string glyphname ; v_int kerning ] + | GPOS_pair, ARGS_gpos_pair_full { pos1 ; pos2 ; glyphname } -> + (v_string glyphname)::(List.map v_int [ pos1.xoff ; pos1.yoff ; pos1.xadv ; pos1.yadv; pos2.xoff ; pos2.yoff ; pos2.xadv ; pos2.yadv ]) + | GPOS_single, ARGS_gpos_single { xoff ; yoff ; xadv ; yadv } -> List.map v_int [ xoff ; yoff ; xadv ; yadv ] + | GSUB_single, ARGS_gsub_single(glyphname) -> [ v_string glyphname ] + | GSUB_ligature, ARGS_gsub_ligature(glyphnames) -> [ v_string_list glyphnames ] + + let get_lookup_typename : type a . a t -> string = function + | GPOS_context -> "gpos_context" + | GPOS_contextchain -> "gpos_contextchain" + | GPOS_cursive -> "gpos_cursive" + | GPOS_mark2base -> "gpos_mark2base" + | GPOS_mark2ligature -> "gpos_mark2ligature" + | GPOS_mark2mark -> "gpos_mark2mark" + | GPOS_pair -> "gpos_pair" + | GPOS_single -> "gpos_single" + | GSUB_alternate -> "gsub_alternate" + | GSUB_context -> "gsub_context" + | GSUB_contextchain -> "gsub_contextchain" + | GSUB_ligature -> "gsub_ligature" + | GSUB_multiple -> "gsub_multiple" + | GSUB_reversecchain -> "gsub_reversecchain" + | GSUB_single -> "gsub_single" + | KERN_statemachine -> "kern_statemachine" + | MORX_indic -> "morx_indic" + | MORX_insert -> "morx_insert" + | MORX_context -> "morx_context" + + type 'a lookup_table_t = 'a t * string + (** Lookup sub-tables are named *) + + let mk_lookup_table typ ~name = (typ,name) + let get_lookup_name (_,name) = name + let get_lookup_type (typ,_) = typ + + type 'a lookup_subtable_t = 'a lookup_table_t * string + (** Lookup sub-tables are named *) + + let mk_lookup_subtable tbl ~name = (tbl,name) + let get_subtable_name (_,name) = name + let get_lookup_table (tbl,_) = tbl +end +(***********************************************************) +(** {2 Feature classification} *) +(***********************************************************) +module Feature = struct + + (** Defines types: one for each combined group of lookup types. + Features of a same group accept a lookup type among the same set of lookup types. *) + + type in_all_t = G_generic + type in_gpos_mark2base_or_gpos_mark2ligature_t = G_04_S05 + type in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t = G_07_S01_S02_S16 + type in_gsub_context_or_gsub_contextchain_or_morx_context_t = S10_S11_S19 + type in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t = G_12_S10_S11_S19 + type in_gsub_multiple_or_gsub_ligature_t = G_13_S12 + type in_gsub_single_or_gpos_single_t = G_15_S08 + type in_gsub_single_or_gsub_alternate_t = G_15_S09 + type in_gsub_single_or_gsub_ligature_t = G_15_S12 + + type _ in_type_t = + | GT_one_to_one : 'a Table.t -> 'a Table.t in_type_t + | GT_all_to_one : in_all_t in_type_t + | GT_04_05 : in_gpos_mark2base_or_gpos_mark2ligature_t in_type_t + | GT_07_01_02_16 : in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t in_type_t + | GT_10_11_19 : in_gsub_context_or_gsub_contextchain_or_morx_context_t in_type_t + | GT_12_10_11_19 : in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t in_type_t + | GT_13_12 : in_gsub_multiple_or_gsub_ligature_t in_type_t + | GT_15_08 : in_gsub_single_or_gpos_single_t in_type_t + | GT_15_09 : in_gsub_single_or_gsub_alternate_t in_type_t + | GT_15_12 : in_gsub_single_or_gsub_ligature_t in_type_t + + type 'a name_t = 'a in_type_t * string + (** Features are named. *) + + (** Constructors of feature groups related to accepted subtbl-types. *) + + let mk_in: type a . a in_type_t -> string -> a name_t = fun t n -> (t,n) + + let mk_in_one_to_one tt ~name = mk_in (GT_one_to_one(tt)) name + let mk_in_all ~name = mk_in GT_all_to_one name + + let mk_in_gpos_mark2base_or_gpos_mark2ligature ~name = mk_in GT_04_05 name + let mk_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine ~name = mk_in GT_07_01_02_16 name + let mk_in_gsub_context_or_gsub_contextchain_or_morx_context ~name = mk_in GT_10_11_19 name + let mk_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context ~name = mk_in GT_12_10_11_19 name + let mk_in_gsub_multiple_or_gsub_ligature ~name = mk_in GT_13_12 name + let mk_in_gsub_single_or_gpos_single ~name = mk_in GT_15_08 name + let mk_in_gsub_single_or_gsub_alternate ~name = mk_in GT_15_09 name + let mk_in_gsub_single_or_gsub_ligature ~name = mk_in GT_15_12 name + + type 'a t = 'a name_t * Script.t list + (** Shortcut type: feature = (named feature, (script, languages) list. *) + + let consolitated_scripts ~scripts = match scripts with [] -> [Script.mk "DFLT"] | _ -> scripts + (** Fills the empty language_script list with the default script ("DFLT"). *) + + let mk : type a . ?scripts:Script.t list -> a name_t -> a t = + fun ?(scripts=[]) feature -> feature,(consolitated_scripts ~scripts) + (** Feature constructor linking a named script with a language list to an untyped feature. *) + + let get_featurename ((_,name),_) = name + let get_script_languages (_,script) = script + + type lookup_feature_t = string * (Script.t list) + let value = v_feature +end +(***********************************************************) +module TypedFeature = struct + + (** Lookup type selection among types accepted by a feature. *) + + type (_,_) selector_t = + | ST_one_to_one : 'a Table.t -> ('a Table.t, 'a Table.t Feature.t) selector_t + | ST_all_to_one : 'a Table.t -> ('a Table.t, Feature.in_all_t Feature.t) selector_t + + | ST_04_IN_04_05 : (Table.gpos_mark2base_t Table.t, Feature.in_gpos_mark2base_or_gpos_mark2ligature_t Feature.t) selector_t + | ST_05_IN_04_05 : (Table.gpos_mark2ligature_t Table.t, Feature.in_gpos_mark2base_or_gpos_mark2ligature_t Feature.t) selector_t + + | ST_13_IN_13_12 : (Table.gsub_multiple_t Table.t, Feature.in_gsub_multiple_or_gsub_ligature_t Feature.t) selector_t + | ST_12_IN_13_12 : (Table.gsub_ligature_t Table.t, Feature.in_gsub_multiple_or_gsub_ligature_t Feature.t) selector_t + + | ST_15_IN_15_08 : (Table.gsub_single_t Table.t, Feature.in_gsub_single_or_gpos_single_t Feature.t) selector_t + | ST_08_IN_15_08 : (Table.gpos_single_t Table.t, Feature.in_gsub_single_or_gpos_single_t Feature.t) selector_t + + | ST_15_IN_15_09 : (Table.gsub_single_t Table.t, Feature.in_gsub_single_or_gsub_alternate_t Feature.t) selector_t + | ST_09_IN_15_09 : (Table.gsub_alternate_t Table.t, Feature.in_gsub_single_or_gsub_alternate_t Feature.t) selector_t + + | ST_15_IN_15_12 : (Table.gsub_single_t Table.t, Feature.in_gsub_single_or_gsub_ligature_t Feature.t) selector_t + | ST_12_IN_15_12 : (Table.gsub_ligature_t Table.t, Feature.in_gsub_single_or_gsub_ligature_t Feature.t) selector_t + + | ST_10_IN_10_11_19 : (Table.gsub_context_t Table.t, Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t) selector_t + | ST_11_IN_10_11_19 : (Table.gsub_contextchain_t Table.t, Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t) selector_t + | ST_19_IN_10_11_19 : (Table.morx_context_t Table.t, Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t) selector_t + + | ST_07_IN_07_01_02_16 : (Table.gpos_pair_t Table.t, Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t) selector_t + | ST_01_IN_07_01_02_16 : (Table.gpos_context_t Table.t, Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t) selector_t + | ST_02_IN_07_01_02_16 : (Table.gpos_contextchain_t Table.t, Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t) selector_t + | ST_16_IN_07_01_02_16 : (Table.kern_statemachine_t Table.t, Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t) selector_t + + | ST_12_IN_12_10_11_19 : (Table.gsub_ligature_t Table.t, Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t) selector_t + | ST_10_IN_12_10_11_19 : (Table.gsub_context_t Table.t, Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t) selector_t + | ST_11_IN_12_10_11_19 : (Table.gsub_contextchain_t Table.t, Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t) selector_t + | ST_19_IN_12_10_11_19 : (Table.morx_context_t Table.t, Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t) selector_t + (** Defines GADT. + These constructors are selectors allowing to choose one lookup type among ones accepted by the feature type. *) + + let get_selected_type : type a b . (a Table.t,b Feature.t) selector_t -> a Table.t = function + | ST_one_to_one(tt) -> tt + | ST_all_to_one(tt) -> tt + + | ST_04_IN_04_05 -> GPOS_mark2base + | ST_05_IN_04_05 -> GPOS_mark2ligature + + | ST_13_IN_13_12 -> GSUB_multiple + | ST_12_IN_13_12 -> GSUB_ligature + + | ST_15_IN_15_08 -> GSUB_single + | ST_08_IN_15_08 -> GPOS_single + + | ST_15_IN_15_09 -> GSUB_single + | ST_09_IN_15_09 -> GSUB_alternate + + | ST_15_IN_15_12 -> GSUB_single + | ST_12_IN_15_12 -> GSUB_ligature + + | ST_10_IN_10_11_19 -> GSUB_context + | ST_11_IN_10_11_19 -> GSUB_contextchain + | ST_19_IN_10_11_19 -> MORX_context + + | ST_07_IN_07_01_02_16 -> GPOS_pair + | ST_01_IN_07_01_02_16 -> GPOS_context + | ST_02_IN_07_01_02_16 -> GPOS_contextchain + | ST_16_IN_07_01_02_16 -> KERN_statemachine + + | ST_12_IN_12_10_11_19 -> GSUB_ligature + | ST_10_IN_12_10_11_19 -> GSUB_context + | ST_11_IN_12_10_11_19 -> GSUB_contextchain + | ST_19_IN_12_10_11_19 -> MORX_context + (** For debuging since the info is in the GATD: for each constructor, there is only one possible mapping. *) + + type _ t = + | TF: ('a Table.t,'b Feature.t) selector_t * 'b Feature.t -> 'a t + (** Shortcut type: typed feature = (type selector, feature). *) + + let typeX_in_XY : type a b . select:(a Table.t,b Feature.t) selector_t -> b Feature.t -> a t = + fun ~select feature -> TF (select, feature) + (** Builds a typed feature from a type selector and a feature. *) + + let select_T_in_one : type a . a Table.t Feature.t -> a t = + function ((GT_one_to_one(tt),_),_) as feature -> typeX_in_XY ~select:(ST_one_to_one(tt)) feature + + let select_T_in_all : type a . a Table.t -> Feature.in_all_t Feature.t -> a t = + fun select feature -> typeX_in_XY ~select:(ST_all_to_one(select)) feature + + (** Constructors of features related to accepted tbl-types. *) + + let select_gpos_mark2base_in_gpos_mark2base_or_gpos_mark2ligature feature = typeX_in_XY ~select:ST_04_IN_04_05 feature + let select_gpos_mark2ligature_in_gpos_mark2base_or_gpos_mark2ligature feature = typeX_in_XY ~select:ST_05_IN_04_05 feature + + let select_gsub_multiple_in_gsub_multiple_or_gsub_ligature feature = typeX_in_XY ~select:ST_13_IN_13_12 feature + let select_gsub_ligature_in_gsub_multiple_or_gsub_ligature feature = typeX_in_XY ~select:ST_12_IN_13_12 feature + + let select_gsub_single_in_gsub_single_or_gpos_single feature = typeX_in_XY ~select:ST_15_IN_15_08 feature + let select_gpos_single_in_gsub_single_or_gpos_single feature = typeX_in_XY ~select:ST_08_IN_15_08 feature + + let select_gsub_single_in_gsub_single_or_gsub_alternate feature = typeX_in_XY ~select:ST_15_IN_15_09 feature + let select_gsub_alternate_in_gsub_single_or_gsub_alternate feature = typeX_in_XY ~select:ST_09_IN_15_09 feature + + let select_gsub_single_in_gsub_single_or_gsub_ligature feature = typeX_in_XY ~select:ST_15_IN_15_12 feature + let select_gsub_ligature_in_gsub_single_or_gsub_ligature feature = typeX_in_XY ~select:ST_12_IN_15_12 feature + + let select_gsub_context_in_gsub_context_or_gsub_contextchain_or_morx_context feature = typeX_in_XY ~select:ST_10_IN_10_11_19 feature + let select_gsub_contextchain_in_gsub_context_or_gsub_contextchain_or_morx_context feature = typeX_in_XY ~select:ST_11_IN_10_11_19 feature + let select_morx_context_in_gsub_context_or_gsub_contextchain_or_morx_context feature = typeX_in_XY ~select:ST_19_IN_10_11_19 feature + + let select_gpos_pair_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine feature = typeX_in_XY ~select:ST_07_IN_07_01_02_16 feature + let select_gpos_context_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine feature = typeX_in_XY ~select:ST_01_IN_07_01_02_16 feature + let select_gpos_contextchain_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine feature = typeX_in_XY ~select:ST_02_IN_07_01_02_16 feature + let select_kern_statemachine_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine feature = typeX_in_XY ~select:ST_16_IN_07_01_02_16 feature + + let select_gsub_ligature_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context feature = typeX_in_XY ~select:ST_12_IN_12_10_11_19 feature + let select_gsub_context_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context feature = typeX_in_XY ~select:ST_10_IN_12_10_11_19 feature + let select_gsub_contextchain_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context feature = typeX_in_XY ~select:ST_11_IN_12_10_11_19 feature + let select_morx_context_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context feature = typeX_in_XY ~select:ST_19_IN_12_10_11_19 feature + + let get_lookup_type = function + | TF (selector,_) -> get_selected_type selector + + let get_feature_scripts = function + | TF (_,((_,feature),scripts)) -> (feature,scripts) + + let value x = v_feature_list (Base.List.map ~f:(get_feature_scripts) x) +end +(***********************************************************) +(* {2 Predefined Features} *) +(***********************************************************) +module PredefinedFeature = struct + open Table + open Feature + open TypedFeature + + let dflt ?scripts lookup_type = select_T_in_all lookup_type (mk ?scripts (mk_in_all ~name:"DFLT")) + (** Default. *) + + let aalt ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gsub_alternate ~name:"aalt")) + (** Access All Alternates. *) + let abvf ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"abvf")) + (** Above Base Forms. *) + let abvm ?scripts select = select (mk ?scripts (mk_in_gpos_mark2base_or_gpos_mark2ligature ~name:"abvm")) + (** Above Base Mark. *) + let abvs ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"abvs")) + (** Above Base Substitutions. *) + let afrc ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"afrc")) + (** Vertical Fractions. *) + let akhn ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"akhn")) + (** Akhand. *) + let alig ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"alig")) + (** Ancient Ligatures. *) + let blwf ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"blwf")) + (** Below Base Forms. *) + let blwm ?scripts select = select (mk ?scripts (mk_in_gpos_mark2base_or_gpos_mark2ligature ~name:"blwm")) + (** Below Base Mark. *) + let blws ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"blws")) + (** Below Base Substitutions. *) + let c2pc ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"c2pc")) + (** Capitals to Petite Capitals. *) + let c2sc ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"c2sc")) + (** Capitals to Small Capitals. *) + let calt ?scripts select = select (mk ?scripts (mk_in_gsub_context_or_gsub_contextchain_or_morx_context ~name:"calt")) + (** Contextual Alternates. *) + let case ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gpos_single ~name:"case")) + (** Case-Sensitive Forms. *) + let ccmp ?scripts select = select (mk ?scripts (mk_in_gsub_multiple_or_gsub_ligature ~name:"ccmp")) + (** Glyph Composition/Decomposition. *) + let cfar ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"cfar")) + (** Conjunct Form After Ro. *) + let cjct ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"cjct")) + (** Conjunct Forms. *) + let clig ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_reversecchain ~name:"clig")) + (** Contextual Ligatures. *) + let cpct ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GPOS_single ~name:"cpct")) + (** Centered CJK Punctuation. *) + let cpsp ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GPOS_single ~name:"cpsp")) + (** Capital Spacing. *) + let cswh ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_reversecchain ~name:"cswh")) + (** Contextual Swash. *) + let curs ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GPOS_cursive ~name:"curs")) + (** Cursive Attachment. *) + let cv00 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"cv00")) + (** Character Variants 00. *) + let cv01 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"cv01")) + (** Character Variants 01. *) + let cv02 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"cv02")) + (** Character Variants 02. *) + let cv03 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"cv03")) + (** Character Variants 03. *) + let cv04 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"cv04")) + (** Character Variants 04. *) + let cv05 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"cv05")) + (** Character Variants 05. *) + let cv06 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"cv06")) + (** Character Variants 06. *) + let cv07 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"cv07")) + (** Character Variants 07. *) + let cv08 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"cv08")) + (** Character Variants 08. *) + let cv09 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"cv09")) + (** Character Variants 09. *) + let cv10 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"cv10")) + (** Character Variants 10. *) + let cv99 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"cv99")) + (** Character Variants 99. *) + let dcap ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"dcap")) + (** Drop Caps. *) + let dist ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GPOS_pair ~name:"dist")) + (** Distance. *) + let dlig ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"dlig")) + (** Discretionary Ligatures. *) + let dnom ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"dnom")) + (** Denominators. *) + let dpng ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"dpng")) + (** Dipthongs (Obsolete). *) + let dtls ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"dtls")) + (** Dotless Forms. *) + let expt ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"expt")) + (** Expert Forms. *) + let falt ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_alternate ~name:"falt")) + (** Final Glyph On Line. *) + let fin2 ?scripts select = select (mk ?scripts (mk_in_gsub_context_or_gsub_contextchain_or_morx_context ~name:"fin2")) + (** Terminal Forms #2. *) + let fin3 ?scripts select = select (mk ?scripts (mk_in_gsub_context_or_gsub_contextchain_or_morx_context ~name:"fin3")) + (** Terminal Forms #3. *) + let fina ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"fina")) + (** Terminal Forms. *) + let flac ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gsub_ligature ~name:"flac")) + (** Flattened Accents over Capitals. *) + let frac ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gsub_ligature ~name:"frac")) + (** Diagonal Fractions. *) + let fwid ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gpos_single ~name:"fwid")) + (** Full Widths. *) + let half ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"half")) + (** Half Forms. *) + let haln ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"haln")) + (** Halant Forms. *) + let halt ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GPOS_single ~name:"halt")) + (** Alternative Half Widths. *) + let hist ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"hist")) + (** Historical Forms. *) + let hkna ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"hkna")) + (** Horizontal Kana Alternatives. *) + let hlig ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"hlig")) + (** Historic Ligatures. *) + let hngl ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gsub_alternate ~name:"hngl")) + (** Hanja to Hangul. *) + let hojo ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"hojo")) + (** Hojo (JIS X 0212-1990) Kanji Forms. *) + let hwid ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gpos_single ~name:"hwid")) + (** Half Widths. *) + let init ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"init")) + (** Initial Forms. *) + let isol ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"isol")) + (** Isolated Forms. *) + let ital ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ital")) + (** Italics. *) + let jalt ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_alternate ~name:"jalt")) + (** Justification Alternatives. *) + let jajp ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gsub_alternate ~name:"jajp")) + (** Japanese Forms (Obsolete). *) + let jp04 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"jp04")) + (** JIS2004 Forms. *) + let jp78 ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gsub_alternate ~name:"jp78")) + (** JIS78 Forms. *) + let jp83 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"jp83")) + (** JIS83 Forms. *) + let jp90 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"jp90")) + (** JIS90 Forms. *) + let kern ?scripts select = select (mk ?scripts (mk_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine ~name:"kern")) + (** Horizontal Kerning. *) + let lfbd ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GPOS_single ~name:"lfbd")) + (** Left Bounds. *) + let liga ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"liga")) + (** Standard Ligatures. *) + let ljmo ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"ljmo")) + (** Leading Jamo Forms. *) + let lnum ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"lnum")) + (** Lining Figures. *) + let locl ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"locl")) + (** Localized Forms. *) + let mark ?scripts select = select (mk ?scripts (mk_in_gpos_mark2base_or_gpos_mark2ligature ~name:"mark")) + (** Mark Positioning. *) + let med2 ?scripts select = select (mk ?scripts (mk_in_gsub_context_or_gsub_contextchain_or_morx_context ~name:"med2")) + (** Medial Forms 2. *) + let medi ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"medi")) + (** Medial Forms. *) + let mgrk ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"mgrk")) + (** Mathematical Greek. *) + let mkmk ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GPOS_mark2mark ~name:"mkmk")) + (** Mark to Mark. *) + let mset ?scripts select = select (mk ?scripts (mk_in_gsub_context_or_gsub_contextchain_or_morx_context ~name:"mset")) + (** Mark Positioning via Substitution. *) + let nalt ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gsub_alternate ~name:"nalt")) + (** Alternate Annotation Forms. *) + let nlck ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"nlck")) + (** NLC Kanji Forms. *) + let nukt ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"nukt")) + (** Nukta Forms. *) + let numr ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"numr")) + (** Numerators. *) + let onum ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"onum")) + (** Oldstyle Figures. *) + let opbd ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GPOS_single ~name:"opbd")) + (** Optical Bounds. *) + let ordn ?scripts select = select (mk ?scripts (mk_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context ~name:"ordn")) + (** Ordinals. *) + let ornm ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gsub_alternate ~name:"ornm")) + (** Ornaments. *) + let palt ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GPOS_single ~name:"palt")) + (** Proportional Alternate Metrics. *) + let pcap ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"pcap")) + (** Lowercase to Petite Capitals. *) + let pkna ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GPOS_single ~name:"pkna")) + (** Proportional Kana. *) + let pnum ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"pnum")) + (** Proportional Numbers. *) + let pref ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"pref")) + (** Pre Base Forms. *) + let pres ?scripts select = select (mk ?scripts (mk_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context ~name:"pres")) + (** Pre Base Substitutions. *) + let pstf ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"pstf")) + (** Post Base Forms. *) + let psts ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"psts")) + (** Post Base Substitutions. *) + let pwid ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"pwid")) + (** Proportional Width. *) + let qwid ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gpos_single ~name:"qwid")) + (** Quarter Widths. *) + let rand ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_alternate ~name:"rand")) + (** Randomize. *) + let rkrf ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"rkrf")) + (** Rakar Forms. *) + let rlig ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"rlig")) + (** Required Ligatures. *) + let rphf ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"rphf")) + (** Reph Form. *) + let rtbd ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GPOS_single ~name:"rtbd")) + (** Right Bounds. *) + let rtla ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"rtla")) + (** Right to Left Alternates. *) + let rtlm ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"rtlm")) + (** Right to Left mirrored forms. *) + let ruby ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ruby")) + (** Ruby Notational Forms. *) + let salt ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gsub_alternate ~name:"salt")) + (** Stylistic Alternatives. *) + let sinf ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"sinf")) + (** Scientific Inferiors. *) + let smcp ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"smcp")) + (** Lowercase to Small Capitals. *) + let smpl ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"smpl")) + (** Simplified Forms. *) + let ss01 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss01")) + (** Style Set 1. *) + let ss02 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss02")) + (** Style Set 2. *) + let ss03 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss03")) + (** Style Set 3. *) + let ss04 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss04")) + (** Style Set 4. *) + let ss05 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss05")) + (** Style Set 5. *) + let ss06 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss06")) + (** Style Set 6. *) + let ss07 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss07")) + (** Style Set 7. *) + let ss08 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss08")) + (** Style Set 8. *) + let ss09 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss09")) + (** Style Set 9. *) + let ss10 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss10")) + (** Style Set 10. *) + let ss11 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss11")) + (** Style Set 11. *) + let ss12 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss12")) + (** Style Set 12. *) + let ss13 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss13")) + (** Style Set 13. *) + let ss14 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss14")) + (** Style Set 14. *) + let ss15 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss15")) + (** Style Set 15. *) + let ss16 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss16")) + (** Style Set 16. *) + let ss17 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss17")) + (** Style Set 17. *) + let ss18 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss18")) + (** Style Set 18. *) + let ss19 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss19")) + (** Style Set 19. *) + let ss20 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"ss20")) + (** Style Set 20. *) + let ssty ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gsub_alternate ~name:"ssty")) + (** Script Style. *) + let subs ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"subs")) + (** Subscript. *) + let sups ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"sups")) + (** Superscript. *) + let swsh ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gsub_alternate ~name:"swsh")) + (** Swash. *) + let titl ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"titl")) + (** Titling. *) + let tjmo ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"tjmo")) + (** Trailing Jamo Forms. *) + let tnam ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"tnam")) + (** Traditional Name Forms. *) + let tnum ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"tnum")) + (** Tabular Numbers. *) + let trad ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gsub_alternate ~name:"trad")) + (** Traditional Forms. *) + let twid ?scripts select = select (mk ?scripts (mk_in_gsub_single_or_gpos_single ~name:"twid")) + (** Third Widths. *) + let unic ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"unic")) + (** Unicase. *) + let valt ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GPOS_single ~name:"valt")) + (** Alternate Vertical Metrics. *) + let vatu ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"vatu")) + (** Vattu Variants. *) + let vert ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"vert")) + (** Vertical Alternates (obs). *) + let vhal ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GPOS_single ~name:"vhal")) + (** Alternate Vertical Half Metrics. *) + let vjmo ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_ligature ~name:"vjmo")) + (** Vowel Jamo Forms. *) + let vkna ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"vkna")) + (** Vertical Kana Alternates. *) + let vkrn ?scripts select = select (mk ?scripts (mk_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine ~name:"vkrn")) + (** Vertical Kerning. *) + let vpal ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GPOS_single ~name:"vpal")) + (** Proportional Alternate Vertical Metrics. *) + let vrt2 ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"vrt2")) + (** Vertical Rotation & Alternates. *) + let zero ?scripts () = select_T_in_one (mk ?scripts (mk_in_one_to_one GSUB_single ~name:"zero")) + (** Slashed Zero. *) + +end +(***********************************************************) diff --git a/src/LookupTables.mli b/src/LookupTables.mli new file mode 100644 index 0000000..2f9412a --- /dev/null +++ b/src/LookupTables.mli @@ -0,0 +1,631 @@ +(******************************************************************************) +(* *) +(* This file is part of fontforge-of-ocaml library *) +(* *) +(* Copyright (C) 2017-2022, Patrick BAUDIN *) +(* (https://github.com/pbaudin/fontforge-of-ocaml) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, but WITHOUT ANY *) +(* WARRANTY; without even the implied warranty of MERCHANTABILITY or *) +(* FITNESS FOR A PARTICULAR PURPOSE. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1) *) +(* *) +(******************************************************************************) + +(** {1 Lookup Tables} *) +(***********************************************************) +(** {2 Script} *) +(***********************************************************) +module Script: sig + type t = string * string list + + val mk: ?languages:string list -> string -> t + (** Constructor *) + + val get_scriptname: t -> string + val get_languages: t -> string list + + val value: t -> Util.Value.t + (** convert *) +end +(***********************************************************) +(** {2 Table} *) +(***********************************************************) +module Table: sig + + (** Defines types: one for each group of lookup type. + Each of them have a specific function for adding data into the tables of that group. *) + + type unspecified_table_t + type contextual_table_t + type lookup_pos_sub_t + + (** Defines types: one for each FontForge lookup type. *) + + type ff_gpos_context_t + type ff_gpos_contextchain_t + type ff_gpos_cursive_t + type ff_gpos_mark2base_t + type ff_gpos_mark2ligature_t + type ff_gpos_mark2mark_t + type ff_gpos_pair_t + type ff_gpos_single_t + type ff_gsub_alternate_t + type ff_gsub_context_t + type ff_gsub_contextchain_t + type ff_gsub_ligature_t + type ff_gsub_multiple_t + type ff_gsub_reversecchain_t + type ff_gsub_single_t + type ff_kern_statemachine_t + type ff_morx_indic_t + type ff_morx_insert_t + type ff_morx_context_t + + (** Defines types: one for each style. *) + + type unspecified_args_t + + type args_glyph_kern_t + type args_pos_t + type args_glyph_pos2_t + + type _ args_t = + ARGS_gpos_pair_kern: args_glyph_kern_t -> ff_gpos_pair_t args_t + | ARGS_gpos_pair_full: args_glyph_pos2_t -> ff_gpos_pair_t args_t + | ARGS_gpos_single: args_pos_t -> ff_gpos_single_t args_t + | ARGS_gsub_single: string -> ff_gsub_single_t args_t + | ARGS_gsub_ligature: string list -> ff_gsub_ligature_t args_t + (** Defines GADT: one constructor for each sub-styles. *) + + val args_gpos_pair_kern: glyphname:string -> kerning:int -> ff_gpos_pair_t args_t + val args_gpos_pair_pos2: glyphname:string -> + xoff1:int -> yoff1:int -> xadv1:int -> yadv1:int -> + xoff2:int -> yoff2:int -> xadv2:int -> yadv2:int -> ff_gpos_pair_t args_t + val args_gpos_single: xoff:int -> yoff:int -> xadv:int -> yadv:int -> ff_gpos_single_t args_t + val args_gsub_single: glyphname:string -> ff_gsub_single_t args_t + val args_gsub_ligature: glyphname1:string -> glyphname2:string -> others:string list -> ff_gsub_ligature_t args_t + + (** Defines types: one for each lookup style. *) + + type gpos_context_t = (contextual_table_t * ff_gpos_context_t) * unspecified_args_t + type gpos_contextchain_t = (contextual_table_t * ff_gpos_contextchain_t) * unspecified_args_t + type gpos_cursive_t = (lookup_pos_sub_t * ff_gpos_cursive_t) * unspecified_args_t + type gpos_mark2base_t = (lookup_pos_sub_t * ff_gpos_mark2base_t) * unspecified_args_t + type gpos_mark2ligature_t = (lookup_pos_sub_t * ff_gpos_mark2ligature_t) * unspecified_args_t + type gpos_mark2mark_t = (lookup_pos_sub_t * ff_gpos_mark2mark_t) * unspecified_args_t + type gpos_pair_t = (lookup_pos_sub_t * ff_gpos_pair_t) * ff_gpos_pair_t args_t + type gpos_single_t = (lookup_pos_sub_t * ff_gpos_single_t) * ff_gpos_single_t args_t + type gsub_alternate_t = (lookup_pos_sub_t * ff_gsub_alternate_t) * unspecified_args_t + type gsub_context_t = (contextual_table_t * ff_gsub_context_t) * unspecified_args_t + type gsub_contextchain_t = (contextual_table_t * ff_gsub_contextchain_t) * unspecified_args_t + type gsub_ligature_t = (lookup_pos_sub_t * ff_gsub_ligature_t) * ff_gsub_ligature_t args_t + type gsub_multiple_t = (lookup_pos_sub_t * ff_gsub_multiple_t) * unspecified_args_t + type gsub_reversecchain_t = (contextual_table_t * ff_gsub_reversecchain_t) * unspecified_args_t + type gsub_single_t = (lookup_pos_sub_t * ff_gsub_single_t) * ff_gsub_single_t args_t + type kern_statemachine_t = (unspecified_table_t * ff_kern_statemachine_t) * unspecified_args_t + type morx_indic_t = (unspecified_table_t * ff_morx_indic_t) * unspecified_args_t + type morx_insert_t = (unspecified_table_t * ff_morx_insert_t) * unspecified_args_t + type morx_context_t = (unspecified_table_t * ff_morx_context_t) * unspecified_args_t + + (** Classified lookup type. *) + + type _ t = + GPOS_context: gpos_context_t t + | GPOS_contextchain: gpos_contextchain_t t + | GPOS_cursive: gpos_cursive_t t + | GPOS_mark2base: gpos_mark2base_t t + | GPOS_mark2ligature: gpos_mark2ligature_t t + | GPOS_mark2mark: gpos_mark2mark_t t + | GPOS_pair: gpos_pair_t t + | GPOS_single: gpos_single_t t + | GSUB_alternate: gsub_alternate_t t + | GSUB_context: gsub_context_t t + | GSUB_contextchain: gsub_contextchain_t t + | GSUB_ligature: gsub_ligature_t t + | GSUB_multiple: gsub_multiple_t t + | GSUB_reversecchain: gsub_reversecchain_t t + | GSUB_single: gsub_single_t t + | KERN_statemachine: kern_statemachine_t t + | MORX_indic: morx_indic_t t + | MORX_insert: morx_insert_t t + | MORX_context: morx_context_t t + (** Defines GADT: one constructor by lookup type with constraints on their style. *) + + val values: (('a * 'b) * 'b args_t) t -> 'b args_t -> Util.Value.t list + (** Convert *) + + (** {3 Lookup tables} *) + + type 'a lookup_table_t + (** Lookup tables are named *) + + val mk_lookup_table: 'a t -> name:string -> 'a lookup_table_t + val get_lookup_name: 'a lookup_table_t -> string + val get_lookup_type: 'a lookup_table_t -> 'a t + val get_lookup_typename: 'a t -> string + + + (** {3 Lookup sub-tables} *) + + type 'a lookup_subtable_t + (** Lookup sub-tables are named *) + + val mk_lookup_subtable: 'a lookup_table_t -> name:string -> 'a lookup_subtable_t + val get_subtable_name: 'a lookup_subtable_t -> string + val get_lookup_table: 'a lookup_subtable_t -> 'a lookup_table_t + +end +(***********************************************************) +(** {2 Feature classification} *) +(***********************************************************) +module Feature: sig + + (** {3 Types} *) + + (** Defines types: one for each combined group of lookup types. + Features of a same group accept a lookup type among the same set of lookup types. *) + + type in_all_t + type in_gpos_mark2base_or_gpos_mark2ligature_t + type in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t + type in_gsub_context_or_gsub_contextchain_or_morx_context_t + type in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t + type in_gsub_multiple_or_gsub_ligature_t + type in_gsub_single_or_gpos_single_t + type in_gsub_single_or_gsub_alternate_t + type in_gsub_single_or_gsub_ligature_t + + type _ in_type_t = + GT_one_to_one: 'a Table.t -> 'a Table.t in_type_t + | GT_all_to_one: in_all_t in_type_t + | GT_04_05: in_gpos_mark2base_or_gpos_mark2ligature_t in_type_t + | GT_07_01_02_16: in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t in_type_t + | GT_10_11_19: in_gsub_context_or_gsub_contextchain_or_morx_context_t in_type_t + | GT_12_10_11_19: in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t in_type_t + | GT_13_12: in_gsub_multiple_or_gsub_ligature_t in_type_t + | GT_15_08: in_gsub_single_or_gpos_single_t in_type_t + | GT_15_09: in_gsub_single_or_gsub_alternate_t in_type_t + | GT_15_12: in_gsub_single_or_gsub_ligature_t in_type_t + + type 'a name_t + (** Features are named. *) + + (** {3 Constructors of features related to a group accepted lookup types} *) + + val mk_in_one_to_one: 'a Table.t -> name:string -> 'a Table.t name_t + (** For features accepting only one lookup type. *) + val mk_in_all: name:string -> in_all_t name_t + (** For features accepting all possible lookup types. *) + val mk_in_gpos_mark2base_or_gpos_mark2ligature: name:string -> in_gpos_mark2base_or_gpos_mark2ligature_t name_t + (** For features accepting: GPOS_mark2base, GPOS_mark2ligature. *) + val mk_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine: name:string -> in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t name_t + (** For features accepting: GPOS_pair, GPOS_context, GPOS_contextchain, KERN_statemachine. *) + val mk_in_gsub_context_or_gsub_contextchain_or_morx_context: name:string -> in_gsub_context_or_gsub_contextchain_or_morx_context_t name_t + (** For features accepting: GSUB_context, GSUB_contextchain, MORX_context. *) + val mk_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context: name:string -> in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t name_t + (** For features accepting: GSUB_ligature, GSUB_context, GSUB_contextchain, MORX_context. *) + val mk_in_gsub_multiple_or_gsub_ligature: name:string -> in_gsub_multiple_or_gsub_ligature_t name_t + (** For features accepting: GSUB_multiple, GSUB_ligature. *) + val mk_in_gsub_single_or_gpos_single: name:string -> in_gsub_single_or_gpos_single_t name_t + (** For features accepting: GSUB_single, GPOS_single. *) + val mk_in_gsub_single_or_gsub_alternate: name:string -> in_gsub_single_or_gsub_alternate_t name_t + (** For features accepting: GSUB_single, GSUB_alternate. *) + val mk_in_gsub_single_or_gsub_ligature: name:string -> in_gsub_single_or_gsub_ligature_t name_t + (** For features accepting: GSUB_single, GSUB_ligature. *) + + (** {3 Untyped Feature} *) + + type 'a t + val mk: ?scripts:Script.t list -> 'a name_t -> 'a t + (** Feature constructor linking a named script with a language list to an untyped feature. *) + val get_featurename: 'a t -> string + val get_script_languages: 'a t -> Script.t list + + type lookup_feature_t = string * (Script.t list) + val value: lookup_feature_t -> Util.Value.t +end +(***********************************************************) +module TypedFeature: sig + + type (_,_) selector_t + (** selector of a lookup type among the acceptable type of a feature. *) + + type _ t + (** Typed feature. *) + + val typeX_in_XY: select:('a Table.t, 'b Feature.t) selector_t -> 'b Feature.t -> 'a t + (** Builds a typed feature from a type selector and a feature. *) + + val select_T_in_one: 'a Table.t Feature.t -> 'a t + val select_T_in_all: 'a Table.t -> Feature.in_all_t Feature.t -> 'a t + + val select_gpos_mark2base_in_gpos_mark2base_or_gpos_mark2ligature: + Feature.in_gpos_mark2base_or_gpos_mark2ligature_t Feature.t -> Table.gpos_mark2base_t t + val select_gpos_mark2ligature_in_gpos_mark2base_or_gpos_mark2ligature: + Feature.in_gpos_mark2base_or_gpos_mark2ligature_t Feature.t -> Table.gpos_mark2ligature_t t + + val select_gsub_multiple_in_gsub_multiple_or_gsub_ligature: + Feature.in_gsub_multiple_or_gsub_ligature_t Feature.t -> Table.gsub_multiple_t t + val select_gsub_ligature_in_gsub_multiple_or_gsub_ligature: + Feature.in_gsub_multiple_or_gsub_ligature_t Feature.t -> Table.gsub_ligature_t t + + val select_gsub_single_in_gsub_single_or_gpos_single: + Feature.in_gsub_single_or_gpos_single_t Feature.t -> Table.gsub_single_t t + val select_gpos_single_in_gsub_single_or_gpos_single: + Feature.in_gsub_single_or_gpos_single_t Feature.t -> Table.gpos_single_t t + + val select_gsub_single_in_gsub_single_or_gsub_alternate: + Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> Table.gsub_single_t t + val select_gsub_alternate_in_gsub_single_or_gsub_alternate: + Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> Table.gsub_alternate_t t + + val select_gsub_single_in_gsub_single_or_gsub_ligature: + Feature.in_gsub_single_or_gsub_ligature_t Feature.t -> Table.gsub_single_t t + val select_gsub_ligature_in_gsub_single_or_gsub_ligature: + Feature.in_gsub_single_or_gsub_ligature_t Feature.t -> Table.gsub_ligature_t t + + val select_gsub_context_in_gsub_context_or_gsub_contextchain_or_morx_context: + Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> Table.gsub_context_t t + val select_gsub_contextchain_in_gsub_context_or_gsub_contextchain_or_morx_context: + Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> Table.gsub_contextchain_t t + val select_morx_context_in_gsub_context_or_gsub_contextchain_or_morx_context: + Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> Table.morx_context_t t + + val select_gpos_pair_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine: + Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t -> Table.gpos_pair_t t + val select_gpos_context_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine: + Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t -> Table.gpos_context_t t + val select_gpos_contextchain_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine: + Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t -> Table.gpos_contextchain_t t + val select_kern_statemachine_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine: + Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t -> Table.kern_statemachine_t t + + val select_gsub_ligature_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context: + Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> Table.gsub_ligature_t t + val select_gsub_context_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context: + Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> Table.gsub_context_t t + val select_gsub_contextchain_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context: + Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> Table.gsub_contextchain_t t + val select_morx_context_in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context: + Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> Table.morx_context_t t + + val get_lookup_type: 'a t -> 'a Table.t + val get_feature_scripts: 'a t -> Feature.lookup_feature_t + val value: _ t list -> Util.Value.t + +end +(***********************************************************) +(* {2 Predefined Features} *) +(***********************************************************) +module PredefinedFeature: sig + + val dflt: ?scripts:Script.t list -> 'a Table.t -> 'a TypedFeature.t + (** Default. *) + + val aalt: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Access All Alternates. *) + val abvf: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Above Base Forms. *) + val abvm: ?scripts:Script.t list -> (Feature.in_gpos_mark2base_or_gpos_mark2ligature_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Above Base Mark. *) + val abvs: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Above Base Substitutions. *) + val afrc: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Vertical Fractions. *) + val akhn: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Akhand. *) + val alig: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Ancient Ligatures. *) + + val blwf: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Below Base Forms. *) + val blwm: ?scripts:Script.t list -> (Feature.in_gpos_mark2base_or_gpos_mark2ligature_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Below Base Mark. *) + val blws: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Below Base Substitutions. *) + + val c2pc: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Capitals to Petite Capitals. *) + val c2sc: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Capitals to Small Capitals. *) + val calt: ?scripts:Script.t list -> (Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Contextual Alternates. *) + val case: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gpos_single_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Case-Sensitive Forms. *) + val ccmp: ?scripts:Script.t list -> (Feature.in_gsub_multiple_or_gsub_ligature_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Glyph Composition/Decomposition. *) + val cfar: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Conjunct Form After Ro. *) + val cjct: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Conjunct Forms. *) + val clig: ?scripts:Script.t list -> unit -> Table.gsub_reversecchain_t TypedFeature.t + (** Contextual Ligatures. *) + val cpct: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Centered CJK Punctuation. *) + val cpsp: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Capital Spacing. *) + val cswh: ?scripts:Script.t list -> unit -> Table.gsub_reversecchain_t TypedFeature.t + (** Contextual Swash. *) + val curs: ?scripts:Script.t list -> unit -> Table.gpos_cursive_t TypedFeature.t + (** Cursive Attachment. *) + val cv00: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 00. *) + val cv01: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 01. *) + val cv02: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 02. *) + val cv03: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 03. *) + val cv04: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 04. *) + val cv05: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 05. *) + val cv06: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 06. *) + val cv07: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 07. *) + val cv08: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 08. *) + val cv09: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 09. *) + val cv10: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 10. *) + val cv99: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Character Variants 99. *) + + val dcap: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Drop Caps. *) + val dist: ?scripts:Script.t list -> unit -> Table.gpos_pair_t TypedFeature.t + (** Distance. *) + val dlig: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Discretionary Ligatures. *) + val dnom: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Denominators. *) + val dpng: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Dipthongs (Obsolete). *) + val dtls: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Dotless Forms. *) + + (** Expert Forms. *) + val expt: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + + val falt: ?scripts:Script.t list -> unit -> Table.gsub_alternate_t TypedFeature.t + (** Final Glyph On Line. *) + val fin2: ?scripts:Script.t list -> (Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Terminal Forms #2. *) + val fin3: ?scripts:Script.t list -> (Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Terminal Forms #3. *) + val fina: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Terminal Forms. *) + val flac: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_ligature_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Flattened Accents over Capitals. *) + val frac: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_ligature_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Diagonal Fractions. *) + val fwid: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gpos_single_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Full Widths. *) + + val half: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Half Forms. *) + val haln: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Halant Forms. *) + val halt: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Alternative Half Widths. *) + val hist: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Historical Forms. *) + val hkna: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Horizontal Kana Alternatives. *) + val hlig: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Historic Ligatures. *) + val hngl: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Hanja to Hangul. *) + val hojo: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Hojo (JIS X 0212-1990) Kanji Forms. *) + val hwid: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gpos_single_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Half Widths. *) + + val init: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Initial Forms. *) + val isol: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Isolated Forms. *) + val ital: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Italics. *) + + val jalt: ?scripts:Script.t list -> unit -> Table.gsub_alternate_t TypedFeature.t + (** Justification Alternatives. *) + val jajp: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Japanese Forms (Obsolete). *) + val jp04: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** JIS2004 Forms. *) + val jp78: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** JIS78 Forms. *) + val jp83: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** JIS83 Forms. *) + val jp90: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** JIS90 Forms. *) + + val kern: ?scripts:Script.t list -> (Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Horizontal Kerning. *) + + val lfbd: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Left Bounds. *) + val liga: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Standard Ligatures. *) + val ljmo: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Leading Jamo Forms. *) + val lnum: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Lining Figures. *) + val locl: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Localized Forms. *) + + val mark: ?scripts:Script.t list -> (Feature.in_gpos_mark2base_or_gpos_mark2ligature_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Mark Positioning. *) + val med2: ?scripts:Script.t list -> (Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Medial Forms 2. *) + val medi: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Medial Forms. *) + val mgrk: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Mathematical Greek. *) + val mkmk: ?scripts:Script.t list -> unit -> Table.gpos_mark2mark_t TypedFeature.t + (** Mark to Mark. *) + val mset: ?scripts:Script.t list -> (Feature.in_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Mark Positioning via Substitution. *) + + val nalt: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Alternate Annotation Forms. *) + val nlck: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** NLC Kanji Forms. *) + val nukt: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Nukta Forms. *) + val numr: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Numerators. *) + + val onum: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Oldstyle Figures. *) + val opbd: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Optical Bounds. *) + val ordn: ?scripts:Script.t list -> (Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Ordinals. *) + val ornm: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Ornaments. *) + + val palt: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Proportional Alternate Metrics. *) + val pcap: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Lowercase to Petite Capitals. *) + val pkna: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Proportional Kana. *) + val pnum: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Proportional Numbers. *) + val pref: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Pre Base Forms. *) + val pres: ?scripts:Script.t list -> (Feature.in_gsub_ligature_or_gsub_context_or_gsub_contextchain_or_morx_context_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Pre Base Substitutions. *) + val pstf: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Post Base Forms. *) + val psts: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Post Base Substitutions. *) + val pwid: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Proportional Width. *) + + val qwid: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gpos_single_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Quarter Widths. *) + + val rand: ?scripts:Script.t list -> unit -> Table.gsub_alternate_t TypedFeature.t + (** Randomize. *) + val rkrf: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Rakar Forms. *) + val rlig: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Required Ligatures. *) + val rphf: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Reph Form. *) + val rtbd: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Right Bounds. *) + val rtla: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Right to Left Alternates. *) + val rtlm: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Right to Left mirrored forms. *) + val ruby: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Ruby Notational Forms. *) + + val salt: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Stylistic Alternatives. *) + val sinf: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Scientific Inferiors. *) + val smcp: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Lowercase to Small Capitals. *) + val smpl: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Simplified Forms. *) + val ss01: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 1. *) + val ss02: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 2. *) + val ss03: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 3. *) + val ss04: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 4. *) + val ss05: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 5. *) + val ss06: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 6. *) + val ss07: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 7. *) + val ss08: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 8. *) + val ss09: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 9. *) + val ss10: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 10. *) + val ss11: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 11. *) + val ss12: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 12. *) + val ss13: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 13. *) + val ss14: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 14. *) + val ss15: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 15. *) + val ss16: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 16. *) + val ss17: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 17. *) + val ss18: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 18. *) + val ss19: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 19. *) + val ss20: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Style Set 20. *) + val ssty: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Script Style. *) + val subs: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Subscript. *) + val sups: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Superscript. *) + val swsh: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Swash. *) + + val titl: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Titling. *) + val tjmo: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Trailing Jamo Forms. *) + val tnam: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Traditional Name Forms. *) + val tnum: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Tabular Numbers. *) + val trad: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gsub_alternate_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Traditional Forms. *) + val twid: ?scripts:Script.t list -> (Feature.in_gsub_single_or_gpos_single_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Third Widths. *) + + val unic: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Unicase. *) + + val valt: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Alternate Vertical Metrics. *) + val vatu: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Vattu Variants. *) + val vert: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Vertical Alternates (obs). *) + val vhal: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Alternate Vertical Half Metrics. *) + val vjmo: ?scripts:Script.t list -> unit -> Table.gsub_ligature_t TypedFeature.t + (** Vowel Jamo Forms. *) + val vkna: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Vertical Kana Alternates. *) + val vkrn: ?scripts:Script.t list -> (Feature.in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine_t Feature.t -> 'a TypedFeature.t) -> 'a TypedFeature.t + (** Vertical Kerning. *) + val vpal: ?scripts:Script.t list -> unit -> Table.gpos_single_t TypedFeature.t + (** Proportional Alternate Vertical Metrics. *) + val vrt2: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Vertical Rotation & Alternates. *) + + val zero: ?scripts:Script.t list -> unit -> Table.gsub_single_t TypedFeature.t + (** Slashed Zero. *) +end diff --git a/src/Util.ml b/src/Util.ml new file mode 100644 index 0000000..bf0f248 --- /dev/null +++ b/src/Util.ml @@ -0,0 +1,231 @@ +(******************************************************************************) +(* *) +(* This file is part of fontforge-of-ocaml library *) +(* *) +(* Copyright (C) 2017-2022, Patrick BAUDIN *) +(* (https://github.com/pbaudin/fontforge-of-ocaml) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, but WITHOUT ANY *) +(* WARRANTY; without even the implied warranty of MERCHANTABILITY or *) +(* FITNESS FOR A PARTICULAR PURPOSE. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1) *) +(* *) +(******************************************************************************) + +module Import = struct + type fontforge + type psMat + type extFontForge + type _ obj = + | Fontforge : fontforge obj + | PsMat : psMat obj +(* | ExtFontForge : extFontForge obj *) + + let typename : type a . a obj -> string = function + | Fontforge -> "fontforge" + | PsMat -> "psMat" +(* | ExtFontForge -> "extFontForge" *) + + type pyobject = Pytypes.pyobject + type 'a t ='a obj * pyobject + + let pp_type : type a . Format.formatter -> a obj -> unit = + fun fmt typ -> Fmt.string fmt (typename typ) + + let pretty_type : type a . Format.formatter -> a t -> unit = + fun fmt (typ,_) -> pp_type fmt typ + + type 'a lazy_object = unit -> 'a t + + let call_once ~f memo = match !memo with + | Some r -> r + | None -> let r = f () in memo := Some r ; r + + let init = let memo = ref None in + fun () -> call_once memo ~f:(fun () -> if not (Py.is_initialized ()) + then (Fmt.pr "Init Python...@."; + Py.initialize ~version:3 ()) else ()) + + let import memo typ = call_once memo ~f:(fun () -> init (); typ, (Py.import (typename typ))) + + let fontforge = let memo = ref None in fun () -> import memo Fontforge + let psMat = let memo = ref None in fun () -> import memo PsMat +(* let extFontForge = let memo = ref None in fun () -> import memo ExtFontForge *) + + let python_of : type a . a lazy_object -> Pytypes.pyobject = + fun import -> snd (import ()) +end +(***********************************************************) +module Object = struct + type contour + type font + type glyph + type glyphPen + type layer + type matrix + type point + type selection + + type _ obj = + | Contour : contour obj + | Font : font obj + | Glyph : glyph obj + | GlyphPen : glyphPen obj + | Layer : layer obj + | Matrix : matrix obj + | Point : point obj + | Selection : selection obj + + type pyobject = Pytypes.pyobject + type 'a t = 'a obj * pyobject + + let pp_type : type a . Format.formatter -> a obj -> unit = + fun fmt -> function + | Contour -> Fmt.string fmt "contour" + | Font -> Fmt.string fmt "font" + | Glyph -> Fmt.string fmt "glyp" + | GlyphPen -> Fmt.string fmt "glypPen" + | Layer -> Fmt.string fmt "layer" + | Matrix -> Fmt.string fmt "matrix" + | Point -> Fmt.string fmt "point" + | Selection -> Fmt.string fmt "selection" + let pretty_type : type a . Format.formatter -> a t -> unit = + fun fmt (typ,_) -> pp_type fmt typ + + let python_of (x:'a t) = snd x + let of_python : type a . typ:a obj -> pyobject -> a t = fun ~typ pyobject -> (typ,pyobject) + + let pretty : type a . Format.formatter -> a t -> unit = + fun fmt x -> Py.Object.format_repr fmt (python_of x) + +end +(***********************************************************) +module Value = struct + open Ppx_python_runtime + + type _ obj = + | Object : 'a Object.obj -> 'a Object.t obj + | Unit : unit obj + | Bool : bool obj + | Float : float obj + | Int : int obj + | String : string obj + | Comb : 'a obj -> 'a list obj + | List : 'a obj -> 'a list obj + | Array : 'a obj -> 'a list obj + | Nullable: 'a obj -> 'a option obj + | Option : 'a obj -> 'a option obj + | Pair : 'a obj * 'b obj -> ('a*'b) obj + | Coord : (float*float) obj + + let rec pp_type : type a . Format.formatter -> a obj -> unit = + fun fmt -> function + | Object typ -> Fmt.pf fmt "(Object %a)" Object.pp_type typ + | Unit -> Fmt.string fmt "Unit" + | Bool -> Fmt.string fmt "Bool" + | Float -> Fmt.string fmt "Float" + | Int -> Fmt.string fmt "Int" + | String -> Fmt.string fmt "String" + | Comb typ -> Fmt.pf fmt "(Comb %a)" pp_type typ + | List typ -> Fmt.pf fmt "(List %a)" pp_type typ + | Array typ -> Fmt.pf fmt "(Array %a)" pp_type typ + | Nullable typ -> Fmt.pf fmt "(Nullable %a)" pp_type typ + | Option typ -> Fmt.pf fmt "(Option %a)" pp_type typ + | Pair(ty1,ty2) -> Fmt.pf fmt "(Pair %a * %a)" pp_type ty1 pp_type ty2 + | Coord -> Fmt.string fmt "Coord" + + let rec python_of : type a . (a obj * a) -> Pytypes.pyobject = function + | Object _, v -> Object.python_of v + | Unit, _ -> Py.null + | Bool, v -> [%python_of: bool] v + | Float, v -> [%python_of: float] v + | Int, v -> [%python_of: int] v + | String, v -> [%python_of: string] v + | Comb t, v -> Base.List.fold (List.rev v) ~init:Py.none + ~f:(fun acc v-> Py.Tuple.of_list [ python_of (t,v) ; acc ]) + | List t, v -> Py.List.of_list_map (fun v -> python_of (t,v)) v + | Array t, v -> Py.List.of_array_map (fun v -> python_of (t,v)) (Array.of_list v) + | Nullable t, v -> (match v with None -> Py.null | Some v -> python_of (t,v)) + | Option t, v -> (match v with None -> Py.none | Some v -> python_of (t,v)) + | Pair(t1,t2), (v1,v2) -> Py.Tuple.of_list [ python_of(t1,v1) ; python_of (t2,v2) ] + | Coord, (v1,v2) -> Py.Tuple.of_list [ [%python_of: float] v1 ; [%python_of: float] v2 ] + + let rec of_python : type a . typ:a obj -> Pytypes.pyobject -> a = + fun ~typ v -> match typ with + | Object typ -> Object.of_python ~typ v + | Unit -> () + | Bool -> if Py.Int.check v + then 0 <> [%of_python: int] v + else [%of_python: bool] v + | Float -> [%of_python: float] v + | Int -> [%of_python: int] v + | String -> if Py.is_none v || Py.is_null v then "" else [%of_python: string] v + | List typ -> Py.List.to_list_map (of_python ~typ) v + | Array typ -> Array.to_list (Py.List.to_array_map (of_python ~typ) v) + | Comb t1 -> (* [v1,[v2,...[vn,None]...]] *) + let v1,v2 = Py.Tuple.to_pair v in + (of_python ~typ:t1 v1)::(if Py.is_null v2 then [] else of_python ~typ v2) + | Nullable typ -> if Py.is_null v then None else Some (of_python ~typ v) + | Option typ -> if Py.is_none v then None else Some (of_python~typ v) + | Pair(ty1,ty2) -> + let v1,v2 = Py.Tuple.to_pair v in + (of_python ~typ:ty1 v1), (of_python ~typ:ty2 v2) + | Coord -> let v1,v2 = Py.Tuple.to_pair v in + ([%of_python: float] v1), ([%of_python: float] v2) + + type t = Value: 'a obj * 'a -> t + let value : type a . typ:a obj -> a -> t = fun ~typ v -> Value (typ,v) + + let pretty_type : Format.formatter -> t -> unit = + fun fmt (Value (typ,_)) -> pp_type fmt typ + + let rec pretty : type a . Format.formatter -> (a obj * a) -> unit = + fun fmt -> function + | Object _, v -> Object.pretty fmt v + | Unit, _ -> Fmt.string fmt "()" + | Bool, v -> Fmt.bool fmt v + | Float, v -> Fmt.float fmt v + | Int, v -> Fmt.int fmt v + | String, v -> Fmt.string fmt v + | List t, v -> Fmt.pf fmt "[%a]" (Fmt.list ~sep:(fun fmt () -> Fmt.string fmt "; ") (fun fmt v -> pretty fmt (t,v))) v + | Array t, v -> Fmt.pf fmt "[%a]" (Fmt.list ~sep:(fun fmt () -> Fmt.string fmt "; ") (fun fmt v -> pretty fmt (t,v))) v + | Comb _, [] -> Fmt.string fmt "None" + | ((Comb t) as typ), (v::vs) -> Fmt.pf fmt "[%a,%a]" pretty (t,v) pretty (typ,vs) + | Nullable t, v -> (match v with None -> Fmt.string fmt "Null" | Some v -> pretty fmt (t,v)) + | Option t, v -> (match v with None -> Fmt.string fmt "None" | Some v -> pretty fmt (t,v)) + | Pair(t1,t2), (v1,v2) -> Fmt.pf fmt "(%a,%a)" pretty (t1,v1) pretty (t2,v2) + | Coord, (v1,v2) -> Fmt.pf fmt "(%f,%f)" v1 v2 + let pretty fmt (Value (typ, v)) = pretty fmt (typ,v) + + let python_of = function Value (typ,v) -> python_of (typ,v) +end +(***********************************************************) +module API = struct + let params : Value.t list -> Pytypes.pyobject array = + fun args -> Array.of_list (Base.List.map args ~f:Value.python_of) + + let size : type a . a Object.t -> int = fun x -> Py.Object.size (Object.python_of x) + + let get : type a b . typ:b Value.obj -> m:string -> a Object.t -> b = + fun ~typ ~m o -> + Value.of_python ~typ Pyops.((Object.python_of o).@$(m)) + + let set : type a b . typ:b Value.obj -> m:string -> a Object.t -> b-> unit = + fun ~typ ~m o v -> + Pyops.((Object.python_of o).@$(m) <- Value.(python_of (value ~typ v))) + + let call_function : type a b . b Import.lazy_object -> typ:a Value.obj -> m:string -> Value.t list -> a = + fun o ~typ ~m args -> + Value.of_python ~typ (Py.Module.get_function (Import.python_of o) m (params args)) + + let call_method : type a b . typ:a Value.obj -> m:string -> Value.t list -> b Object.t -> a = + fun ~typ ~m args o -> + Value.of_python ~typ (Py.Object.call_method (Object.python_of o) m (params args)) +end +(***********************************************************) diff --git a/src/Util.mli b/src/Util.mli new file mode 100644 index 0000000..926135f --- /dev/null +++ b/src/Util.mli @@ -0,0 +1,119 @@ +(******************************************************************************) +(* *) +(* This file is part of fontforge-of-ocaml library *) +(* *) +(* Copyright (C) 2017-2022, Patrick BAUDIN *) +(* (https://github.com/pbaudin/fontforge-of-ocaml) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, but WITHOUT ANY *) +(* WARRANTY; without even the implied warranty of MERCHANTABILITY or *) +(* FITNESS FOR A PARTICULAR PURPOSE. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1) *) +(* *) +(******************************************************************************) + +module Import: sig + type fontforge + type psMat + type extFontForge + type pyobject + type _ obj = + Fontforge: fontforge obj + | PsMat: psMat obj +(* | ExtFontForge: extFontForge obj + (* if some code has to be written in python *) +*) + + type 'a t = 'a obj * pyobject + type 'a lazy_object = unit -> 'a t + + val fontforge: fontforge lazy_object + val psMat: psMat lazy_object +(* val extFontForge: extFontForge lazy_object + (* if some code has to be written in python *) + *) + + val python_of: 'a lazy_object -> pyobject + val pp_type: Format.formatter -> 'a obj -> unit + val pretty_type: Format.formatter -> 'a t -> unit + + val init: unit -> unit +end +(***********************************************************) +module Object:sig + type contour + type font + type glyph + type glyphPen + type layer + type matrix + type point + type selection + + type _ obj = + | Contour: contour obj + | Font: font obj + | Glyph: glyph obj + | GlyphPen: glyphPen obj + | Layer: layer obj + | Matrix: matrix obj + | Point: point obj + | Selection: selection obj + type pyobject + type 'a t = 'a obj * pyobject + val pretty_type: Format.formatter -> 'a t -> unit + val pretty: Format.formatter -> 'a t -> unit + + val python_of: 'a t -> Pytypes.pyobject + val of_python: typ:'a obj -> Pytypes.pyobject -> 'a t + val pp_type: Format.formatter -> 'a obj -> unit +end +(***********************************************************) +module Value: sig + type _ obj = + | Object: 'a Object.obj -> 'a Object.t obj + | Unit: unit obj + | Bool: bool obj + | Float: float obj + | Int: int obj + | String: string obj + | Comb: 'a obj -> 'a list obj + | List: 'a obj -> 'a list obj + | Array: 'a obj -> 'a list obj + | Nullable: 'a obj -> 'a option obj + | Option: 'a obj -> 'a option obj + | Pair: 'a obj * 'b obj -> ('a * 'b) obj + | Coord: (float*float) obj + type t + val pp_type: Format.formatter -> 'a obj -> unit + val pretty_type: Format.formatter -> t -> unit + val pretty: Format.formatter -> t -> unit + + val value: typ:'a obj -> 'a -> t + val python_of: t -> Pytypes.pyobject + val of_python: typ:'a obj -> Pytypes.pyobject -> 'a +end +(***********************************************************) +module API: sig + val size: 'a Object.t -> int + + val get: typ:'b Value.obj -> m:string -> 'a Object.t -> 'b + (** get an attribute *) + val set: typ:'b Value.obj -> m:string -> 'a Object.t -> 'b -> unit + (** set an attribute *) + + val call_method: + typ:'a Value.obj -> m:string -> Value.t list -> 'b Object.t -> 'a + (** method call of an object *) + + val call_function: + 'b Import.lazy_object -> typ:'a Value.obj -> m:string -> Value.t list -> 'a + (** function call of an imported module *) +end +(***********************************************************) diff --git a/src/dune b/src/dune new file mode 100644 index 0000000..75cab73 --- /dev/null +++ b/src/dune @@ -0,0 +1,32 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; This file is part of fontforge-of-ocaml library ;; +;; ;; +;; Copyright (C) 2017-2022, Patrick BAUDIN ;; +;; (https://github.com/pbaudin/fontforge-of-ocaml) ;; +;; ;; +;; you can redistribute it and/or modify it under the terms of the GNU ;; +;; Lesser General Public License as published by the Free Software ;; +;; Foundation, version 2.1. ;; +;; ;; +;; It is distributed in the hope that it will be useful, but WITHOUT ANY ;; +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or ;; +;; FITNESS FOR A PARTICULAR PURPOSE. ;; +;; ;; +;; See the GNU Lesser General Public License version 2.1 ;; +;; for more details (enclosed in the file licenses/LGPLv2.1) ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(env + (dev + (flags (:standard -w -37+50)))) + +(library + (name FontForge) + (public_name fontforge-of-ocaml) + (modules FontForge Core LookupTables Util) + (private_modules Core LookupTables Util) + (libraries base fmt pyml ppx_python) + (preprocess (pps ppx_python)) +) diff --git a/tests/FreeMono.ttf b/tests/FreeMono.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3842c7615a9866bc3287a4b0a535cf9abf764ac4 GIT binary patch literal 361228 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 D#4!+( literal 0 HcmV?d00001 diff --git a/tests/FreeMonoBold.ttf b/tests/FreeMonoBold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b86828707146e06516ec44a96bcf10912727ad06 GIT binary patch literal 184480 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

--QH!SEGIWOK&pGa5r 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


30SdtLdvPEwh@dW6cY? z5Pd!7^fb?EY3WtuF;LUgV|81TZaZ#aR*YJQ&E6Vnn-O%@*VjcYcD>u9C|avUhf5Ot z=GGw?PraYMu{xbjXr9-_s;|DfI;MM`c^v6<^$mN8*NGtGatHRFMx`AXwJywD#2Qt! z$j4JLN+yj>m>5p^mJ4cH@zZOu7^Pv1Wi&>%YAVK*<5FX|@E1fY3u1%bdN$`^;^ZoXA-A}}fJw{@K})j*MeZ&360s*4H@GJ7 zr4E?g{^@I;e?#lM;rY$Jf8uAy&}hewg{@n!9%awE`L&_jzCYf3)8d&utG~aE3~@$x zWbgdmt)sVWm=7)@oogR-u736vr$y5w-_IU8Olf3qq1bOS?W&QF0)ErEZCUyd&r?Td zk#JT@FU>a+Ja&iWS%9}lb@He@kC%b-1#|}-Zb*X_4=|k9M_^ZDmpD&b=FxlwD9oDF^o9?uv&cN?h!w( z`OIgQ{Y*`Nf=16SD!t`PDf+sEK2p?A9*N-`$`o|&dguk?hbb)xdUv3I9a0P8CZm7B zyJ{NukbuJ6f%%@41ECRsW*~P0v|iNyi#}M>uzK(7!$+>x%QPcv*;P|Ci(ie8!-*vC ze=q8w^Dho*kZh>D-qHMD*$Fv?G?P4E_EK8@<@}rSd73CR|7yHFT(b#J-7J~U;YqLi z-alG^?|LBkCi^n+Bg?Tb|Cq~5_#I8id!fV5rxQtO%pU5@AUJ{s8|ejL10?VUkdi=R z1HUy;c1q3~T>rxcHdc`wys&C#ml#Z@c&H(ntWA3CW>3r;_Cx2f*gSJvx&{zgNgn#h z9_5GOhK3I}Ha1jaDs(#(_E_#+2OQ+hOzXtgY=glN3`elihDUGM<@H)^RxGib2V32^ z3Rq4IUeay%$o;t|6L1Q7&8qcA9JcC!Brd8}|0M|<->LVGVmdm}g%Fo^_i z;fDtqZBkX?QrnpbmaMiHy+#fr+`U5;JEx?CXl%DKt<^P)cP<*-d7&Ch}x#>ta zW^_5=+jhUUv1x5hOO3}K^u&@?{wN*r_AGAina?RPf7QSoWoz!A4*0>Dna+-r0Z^PqpOPE&b{5H@_>u^)p&jax~AY3Zk+fRFXiGe=+}ic|Y2p zh8=Se_(5>y`?$(b@aFgLW_ie~lpJaljL7O#!J#IX>uYHEkH*HnR<(D3QPI0>o6TGD zxA8gbs=p0$pT0w>KSg^Y(0;J0Jzan5&Zwh?ZR*5<^mg_7`Q5<(#pBQ6KZ;s&1b-&^2C|8pUpi3My)wBdT8@6 zaeD0L{$evI+LS`>VyEyK`#0Oi{67E%Pac!jAYSGry~-(`{cfUfzyTfoV-gG^8L3n-R)jfrR<8-+h+?yqb`r`!yneAUG8ePBT=J3w?8CV*w^G* z=ZEx5B?XbtuqqrPjhEIbqMnD~E4CE6emh@7dplASLEw5;MgM*c@fQGJNmt?r*bw^VI%f;Pv)c~i>;X!Z zr2U*HUj$FyOeYffS?LltMx{J;aUY8T!xukW;69$GL+-~pAj*?~;De_hwHgMc z>&X44FPbzMf0J;4UtMV(XwO=3-t@oaD&RLMEt3Z-`1NwUtK;w1N%N<@i%P!-ez?C# zzYe$`<^2+cEu>$18EKP9J4|V;5oJ6t%8+g4eTDY##k)pPw``vFE-L9kn_13`ei-({;&rtc&y=p!1fkr(B$qPT3c9gprD}1~!AIm)7e3Z5s<<31!@J7Hd6Y%oV z{M#kI#Ji~E1HGOC9z>h_fQKFw$Bq?$hZQsXPrM^qzQy0Iqw`$oQ-_qsyYG>=0{WEC zQ9cfCCSi!loDz^b>Q)wZ8`a~y#iPfBF~ z)qR!3_*&)9pC|EWq>?6;zX*pl`7N9_90!IY$vrNmSa-2%kMU&i&{EmkK9#FN@LhHlKBoHny
GKIqPW68CUDDNc>>o%kBE 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 d|5F$Wbnx%hQ!;1k@X, +- 6 - Copyright (modified): COPYRIGHT (c) this-year, my-self +- 6 - create a new font = SIMPLE +At least one anchor point was lost when pasting from one font to another because no matching anchor class could be found in the new font. +At least one anchor point was lost when pasting from one font to another because no matching anchor class could be found in the new font. +At least one anchor point was lost when pasting from one font to another because no matching anchor class could be found in the new font. +At least one anchor point was lost when pasting from one font to another because no matching anchor class could be found in the new font. +At least one anchor point was lost when pasting from one font to another because no matching anchor class could be found in the new font. +At least one anchor point was lost when pasting from one font to another because no matching anchor class could be found in the new font. +- 6 - paste the glyphs from A to F into SIMPLE +- 6 - select all by glyphs +- 6 - iter on selected ghyphs from fontname = "SIMPLE" +("zero",48) ; ("one",49) ; ("two",50) ; ("three",51) ; ("four",52) ; ("five",53) ; ("six",54) ; ("seven",55) ; ("eight",56) ; ("nine",57) ; ("A",65) ; ("B",66) ; ("C",67) ; ("D",68) ; ("E",69) ; ("F",70) ; +- 6 - nb of iterations = 16 +- 6 - exist A in the font = true +- 6 - exist 65 (A) in the font = true +- 6 - exist G in the font = false +- 6 - exist 71 (F) in the font = false +- 7 - kern features... +- 7 - GPOS_pair lookup table... +- 7 - kerningSubtable lookup subtable... +- 7 - create a kerningLookUp table and kerningSubtable subtable +- 7 - kerning A and F with delta = -300 +- 8 - ligature features... +- 8 - create a LigatureLookUp table and LigatureSubtable subtable +- 8 - translate x=300.000000 +- 8 - create a ligature glyph for AE = liga_A_E +- 9 - fina features... +- 9 - GSUB_single lookup table... +- 9 - FinalSubtable lookup subtable... +- 9 - create a FinalLookUp table and FinalSubtable subtable +- 9 - create a substitution glyph for final E = E.fina +- 10 - points... +- 10 - point (0,1,curve=true, sel=false) +- 11 - contours... +- 11 - empty contour: name="" len=0 is_quadratic=false is_closed=false +- 11 - no c[0] +- 11 - cannot set c[0] +- 11 - line contour c1: name="1" len=3 is_quadratic=false is_closed=true points=[(0,1,curve=true, sel=false), (4,5,curve=true, sel=false), (8,9,curve=true, sel=false)] +- 11 - c1[0]=(0,1,curve=true, sel=false) +- 11 - extracted contour c: name="" len=3 is_quadratic=false is_closed=false points=[(0,1,curve=true, sel=false), (4,5,curve=true, sel=false), (8,9,curve=true, sel=false)] +- 11 - c0=c+pt1: name="" len=4 is_quadratic=false is_closed=false points=[(0,1,curve=true, sel=false), (4,5,curve=true, sel=false), (8,9,curve=true, sel=false), (1,1,curve=true, sel=false)] +- 11 - c2=c+c: name="" len=6 is_quadratic=false is_closed=false points=[(0,1,curve=true, sel=false), (4,5,curve=true, sel=false), (8,9,curve=true, sel=false), (0,1,curve=true, sel=false), (4,5,curve=true, sel=false), (8,9,curve=true, sel=false)] +- 11 - c contains coord: (4.000000,5.000000)=true +- 11 - c contains coord: (0.0,0.0)=false +- 11 - c contains point pt0: true +- 11 - c contains point pt1: false +- 11 - set c[1]=pt1 +- 11 - c contains point pt1: true +- 11 - quadratic contour c2: name="2" len=5 is_quadratic=true is_closed=true points=[(1,2,curve=true, sel=false), (0,2,curve=false, sel=false), (2,4,curve=true, sel=false), (1,4,curve=false, sel=false), (3,6,curve=true, sel=false)] +- 11 - cubic contour c3: name="3" len=7 is_quadratic=false is_closed=true points=[(3,2,curve=true, sel=false), (8,6,curve=false, sel=false), (4,2,curve=false, sel=false), (6,4,curve=true, sel=false), (11,8,curve=false, sel=false), (7,4,curve=false, sel=false), (9,6,curve=true, sel=false)] +- 11 - c1+=c3 : name="1" len=10 is_quadratic=false is_closed=true points=[(0,1,curve=true, sel=false), (4,5,curve=true, sel=false), (8,9,curve=true, sel=false), (3,2,curve=true, sel=false), (8,6,curve=false, sel=false), (4,2,curve=false, sel=false), (6,4,curve=true, sel=false), (11,8,curve=false, sel=false), (7,4,curve=false, sel=false), (9,6,curve=true, sel=false)] +- 11 - c1+= pt1: name="1" len=11 is_quadratic=false is_closed=true points=[(0,1,curve=true, sel=false), (4,5,curve=true, sel=false), (8,9,curve=true, sel=false), (3,2,curve=true, sel=false), (8,6,curve=false, sel=false), (4,2,curve=false, sel=false), (6,4,curve=true, sel=false), (11,8,curve=false, sel=false), (7,4,curve=false, sel=false), (9,6,curve=true, sel=false), (1,1,curve=true, sel=false)] +- Z - ends... +- Z - Font file generated = ./test_FontForgeLib.ttf diff --git a/tests/test_FontForgeLib.ml b/tests/test_FontForgeLib.ml new file mode 100644 index 0000000..e28ade8 --- /dev/null +++ b/tests/test_FontForgeLib.ml @@ -0,0 +1,328 @@ +(******************************************************************************) +(* *) +(* This file is part of fontforge-of-ocaml library *) +(* *) +(* Copyright (C) 2017-2022, Patrick BAUDIN *) +(* (https://github.com/pbaudin/fontforge-of-ocaml) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, but WITHOUT ANY *) +(* WARRANTY; without even the implied warranty of MERCHANTABILITY or *) +(* FITNESS FOR A PARTICULAR PURPOSE. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1) *) +(* *) +(******************************************************************************) + +open FontForge +module FF = FontForge + +let coords ~nb ~kx ~dx ~ky ~dy = Base.Array.init nb + ~f:(fun i -> (Float.of_int (kx*i+dx)),(Float.of_int (ky*i+dy))) + +let mk_contour ~is_quadratic ~name ~mk coords = let open Contour in + let c = FF.contour () in + Is_quadratic.set c is_quadratic; + Name.set c name; + Base.Array.iteri coords ~f:(fun i xy -> if i = 0 + then moveToCoord xy c + else mk xy c); + lineToCoord (Array.get coords 0) c; + Closed.set c true; + c + +let pretty_point fmt pt = let open Point in + Fmt.pf fmt "(%d,%d,curve=%b, sel=%b)" + (Float.to_int (X.get pt)) (Float.to_int (Y.get pt)) (On_curve.get pt) (Selected.get pt) + +let pretty_contour fmt c = let open Contour in + Fmt.pf fmt "name=%S len=%d is_quadratic=%b is_closed=%b points=[%a]" + (Name.get c) (len c) (Is_quadratic.get c) (Closed.get c) + (Fmt.list ~sep:(fun fmt () -> Fmt.string fmt ", ") pretty_point) (to_list c) + +let _ = + let version = FF.version () in + Fmt.pr "- 0 - fontforge version = %S@." version; + let font = FF.openFont ~filename:"./FreeMonoBold.ttf" in + Fmt.pr "- 1 - font loaded@."; + let fontname = Font.Fontname.get font in + Fmt.pr "- 1 - fontname = %s@." fontname; + let fonts = FF.fonts() in + Fmt.pr "- 1 - number of fonts loaded = %d@." (List.length fonts); + let font = match fonts with | [x] -> x | _ -> assert false in + let fontname = Font.Fontname.get font in + Fmt.pr "- 1 - fontname = %s@." fontname; + + let font = FF.openFont ~filename:"./FreeMono.ttf" in + Fmt.pr "- 2 - another font loaded@."; + let fonts = FF.fonts() in + Fmt.pr "- 2 - number of fonts loaded = %d@." (List.length fonts); + List.iter (fun font -> + let fontname = Font.Fontname.get font in + Fmt.pr "- 2 - fontname = %s@." fontname) fonts; + + let fontname = Font.Fontname.get font in + Fmt.pr "- 3 - fontname = %s@." fontname; + let em = Font.Em.get font in + let ascent = Font.Ascent.get font in + let descent = Font.Descent.get font in + Fmt.pr "- 3 - em = %d ; ascent = %d ; descent = %d@." em ascent descent; + + let selection = Font.Selection.get font in + Fmt.pr "- 4 - selection@."; + Selection.all selection ; + Fmt.pr "- 4 - select all by slots@."; + if true then begin + let n = ref 0 in + Selection.iter ~slot:(fun _ -> incr n) selection ; + Fmt.pr "- 4 - nb of iterations = %d@." !n; + end; + let selection = Selection.byGlyphs selection in + Fmt.pr "- 4 - select all by glyphs@."; + let n = ref 0 in + Selection.iter ~glyph:(fun _ -> incr n) selection ; + Fmt.pr "- 4 - nb of iterations = %d@." !n; + + let selection = Font.Selection.get font in + Fmt.pr "- 5 - selection@."; + let ranges = [ Selection.glyphname "1" ; Selection.glyphname "8" ] in + Selection.select ~ranges:true ~request:ranges selection; + Fmt.pr "- 5 - selection set from 1-8@."; + let ranges = [ Selection.glyphname "B" ; Selection.glyphname "J" ] in + Selection.select ~ranges:true ~less:false ~request:ranges selection; + Fmt.pr "- 5 - selection added from B-J@."; + let ranges = [ Selection.glyphname "F" ; Selection.glyphname "Z" ] in + Selection.select ~ranges:true ~less:true ~request:ranges selection; + Fmt.pr "- 5 - selection removed from F-Z@."; + let singletons = [ Selection.glyphname "9" ; Selection.glyphname "F" ] in + Selection.select ~less:false ~request:singletons selection; + Fmt.pr "- 5 - selection added 9 and F@."; + let singletons = [ Selection.code 48 ; Selection.code 65 ] in + Selection.select ~encoding:true ~less:false ~request:singletons selection; + Fmt.pr "- 5 - selection added encoding 48 and 65 (0 and A)@."; + let selection = Selection.byGlyphs selection in + Fmt.pr "- 5 - select them by glyphs@."; + let n = ref 0 in + Selection.iter + ~glyph:(fun x -> incr n; + if !n = 1 then Fmt.pr "- 5 - iter on selected ghyphs from fontname = %S@." + (Font.Fontname.get (Glyph.font x)); + Fmt.pr "(%S,%d) ; " + (Glyph.Glyphname.get x) + (Glyph.Unicode.get x) ) + selection ; + Fmt.pr "@.- 5 - nb of iterations = %d@." !n; + Fmt.pr "- 5 - exist A in the font = %b@." + (Font.contains_glyphname ~glyphname:"A" font); + Fmt.pr "- 5 - exist 65 (A) in the font = %b@." + (Font.contains_unicode ~unicode:65 font); + Fmt.pr "- 5 - exist G in the font = %b@." + (Font.contains_glyphname ~glyphname:"G" font); + Fmt.pr "- 5 - exist 71 (F) in the font = %b@." + (Font.contains_unicode ~unicode:71 font); + + Font.copy font; + Fmt.pr "- 6 - copy selected glyphs into the clip board@."; + + let font = FF.font () in + Font.Fontname.set font "MY-FONT" ; + Font.Em.set font em ; + Font.Ascent.set font ascent; + Font.Descent.set font descent; + Font.Encoding.set font "UnicodeFull"; + Font.Version.set font "1.0"; + Font.Weight.set font "Regular"; + Font.Familyname.set font "SIMPLE"; + Font.Fontname.set font "SIMPLE" ; + Font.Fullname.set font "SIMPLE"; + + let copyright = Font.Copyright.get font in + (* extract the year and the $USER *) + let copyright = String.sub copyright 0 14 in + Fmt.pr "- 6 - Copyright (from fontforge): %s, @." + copyright; + Font.Copyright.set font "COPYRIGHT (c) this-year, my-self"; + Fmt.pr "- 6 - Copyright (modified): %s@." + (Font.Copyright.get font); + + Fmt.pr "- 6 - create a new font = %s@." + (Font.Fontname.get font); + + let selection = Font.Selection.get font in + let ranges = [ Selection.glyphname "0" ; Selection.glyphname "9" ] in + Selection.select ~ranges:true ~request:ranges selection; + let ranges = [ Selection.glyphname "A" ; Selection.glyphname "F" ] in + Selection.select ~ranges:true ~less:false ~request:ranges selection; + Font.paste font; + Fmt.pr "- 6 - paste the glyphs from A to F into %s@." + (Font.Fontname.get font); + + Selection.all selection; + let selection = Selection.byGlyphs selection in + Fmt.pr "- 6 - select all by glyphs@."; + let n = ref 0 in + Selection.iter + ~glyph:(fun x -> incr n; + if !n = 1 then Fmt.pr "- 6 - iter on selected ghyphs from fontname = %S@." + (Font.Fontname.get (Glyph.font x)); + Fmt.pr "(%S,%d) ; " + (Glyph.Glyphname.get x) + (Glyph.Unicode.get x) ) + selection ; + Fmt.pr "@.- 6 - nb of iterations = %d@." !n; + Fmt.pr "- 6 - exist A in the font = %b@." + (Font.contains_glyphname ~glyphname:"A" font); + Fmt.pr "- 6 - exist 65 (A) in the font = %b@." + (Font.contains_unicode ~unicode:65 font); + Fmt.pr "- 6 - exist G in the font = %b@." + (Font.contains_glyphname ~glyphname:"G" font); + Fmt.pr "- 6 - exist 71 (F) in the font = %b@." + (Font.contains_unicode ~unicode:71 font); + + Fmt.pr "- 7 - kern features...@." ; + let feature = + PredefinedFeature.kern ~scripts:[ Script.mk ~languages:["dflt"] "latn" ] + TypedFeature.select_gpos_pair_in_gpos_pair_or_gpos_context_or_gpos_contextchain_or_kern_statemachine in + Fmt.pr "- 7 - GPOS_pair lookup table...@." ; + let lookuptable = Table.(mk_lookup_table GPOS_pair ~name:"kerningLookUp") in + Font.addLookup lookuptable Table.GPOS_pair ~flags:[] feature font; + Fmt.pr "- 7 - kerningSubtable lookup subtable...@." ; + let lookupsubtable = Table.mk_lookup_subtable lookuptable ~name:"kerningSubtable" in + Font.addLookupSubtable lookupsubtable font; + Fmt.pr "- 7 - create a %s table and %s subtable@." + (Table.get_lookup_name lookuptable) + (Table.get_subtable_name lookupsubtable); + let glyphA = Font.glyph_from_code ~unicode:65 font in + let glyphname = "F" in + let glyphF = Font.glyph_from_name ~glyphname font in + let kerning = -(Glyph.Width.get glyphF) / 2 in + let spec = Table.args_gpos_pair_kern ~glyphname ~kerning in + Glyph.addPosSub lookupsubtable spec glyphA; + Fmt.pr "- 7 - kerning %s and %s with delta = %d@." + (Glyph.Glyphname.get glyphA) glyphname kerning; + + Fmt.pr "- 8 - ligature features...@."; + let feature = PredefinedFeature.liga ~scripts:[ Script.mk ~languages:["dflt"] "latn" ] () in + let lookuptable = Table.(mk_lookup_table GSUB_ligature ~name:"LigatureLookUp") in + Font.addLookup lookuptable Table.GSUB_ligature ~flags:[] feature font; + let lookupsubtable = Table.mk_lookup_subtable lookuptable ~name:"LigatureSubtable" in + Font.addLookupSubtable lookupsubtable font; + Fmt.pr "- 8 - create a %s table and %s subtable@." + (Table.get_lookup_name lookuptable) + (Table.get_subtable_name lookupsubtable); + let ligaAE = "liga_A_E" in + let glyph_ligaAE = Font.createChar ~unicode:(-1) ~name:ligaAE font in + Selection.select_from_glyphname ~name:"E" selection; + Font.copy font; + Selection.select_from_glyphname ~name:ligaAE selection; + Font.paste font; + let x = Float.of_int ((Glyph.Width.get glyphA) / 2) in + Fmt.pr "- 8 - translate x=%f@." x; + let matrix = PsMat.translate ~x ~y:0.0 in + Glyph.transform ~matrix glyph_ligaAE; + Selection.select_from_glyphname ~name:"A" selection; + Font.copy font; + Selection.select_from_glyphname ~name:ligaAE selection; + Font.pasteInto font; + let spec = Table.args_gsub_ligature ~glyphname1:"A" ~glyphname2:"E" ~others:[] in + Glyph.addPosSub lookupsubtable spec glyph_ligaAE; + Fmt.pr "- 8 - create a ligature glyph for AE = %s@." ligaAE; + + Fmt.pr "- 9 - fina features...@." ; + let feature = PredefinedFeature.fina ~scripts:[ Script.mk ~languages:["dflt"] "DFLT" ] () in + Fmt.pr "- 9 - GSUB_single lookup table...@." ; + let lookuptable = Table.(mk_lookup_table GSUB_single ~name:"FinalLookUp") in + Font.addLookup lookuptable Table.GSUB_single ~flags:[] feature font; + Fmt.pr "- 9 - FinalSubtable lookup subtable...@." ; + let lookupsubtable = Table.mk_lookup_subtable lookuptable ~name:"FinalSubtable" in + Font.addLookupSubtable lookupsubtable font; + Fmt.pr "- 9 - create a %s table and %s subtable@." + (Table.get_lookup_name lookuptable) + (Table.get_subtable_name lookupsubtable); + let finaE = "E.fina" in + let glyph_finaE = Font.createChar ~unicode:(-1) ~name:finaE font in + Selection.select_from_glyphname ~name:"E" selection; + Font.copy font; + Selection.select_from_glyphname ~name:finaE selection; + Font.paste font; + let matrix = PsMat.translate ~x:0.0 ~y:(Float.of_int (ascent / 4)) in + Glyph.transform ~matrix glyph_finaE; + let _glyphE = Font.glyph_from_name ~glyphname:"E" font in + let spec = Table.args_gsub_single ~glyphname:"E" in + Glyph.addPosSub lookupsubtable spec glyph_finaE; + Fmt.pr "- 9 - create a substitution glyph for final E = %s@." finaE; + + Fmt.pr "- 10 - points...@."; + let nb_pts = 3 in + let coords1 = coords ~nb:nb_pts ~kx:4 ~dx:0 ~ky:4 ~dy:1 in + let pt1 = FF.pointCoord (1.0,1.0) in + let pt = FF.pointCoord (Array.get coords1 0) in + Fmt.pr "- 10 - point %a@." pretty_point pt; + + Fmt.pr "- 11 - contours...@."; + let c1 = FF.contour () in + Fmt.pr "- 11 - empty contour: name=%S len=%d is_quadratic=%b is_closed=%b@." + (Contour.Name.get c1) (Contour.len c1) + (Contour.Is_quadratic.get c1) (Contour.Closed.get c1); + (try ignore (Contour.nth 0 c1) + with | Contour.Index_out_of_bounds -> Fmt.pr "- 11 - no c[0]@."); + (try Contour.set_nth 0 pt1 c1; + with | Contour.Index_out_of_bounds -> Fmt.pr "- 11 - cannot set c[0]@."); + Contour.Name.set c1 "1"; + Base.Array.iteri coords1 ~f:(fun i xy -> if i = 0 + then Contour.moveToCoord xy c1 + else Contour.lineToCoord xy c1); + Contour.lineToCoord (Array.get coords1 0) c1; + Contour.Closed.set c1 true; + Fmt.pr "- 11 - line contour c1: %a@." pretty_contour c1; + (try Fmt.pr "- 11 - c1[0]=%a@." pretty_point (Contour.nth 0 c1) + with | Contour.Index_out_of_bounds -> Fmt.pr "- 11 - no c1[0]@."); + + let c = Contour.extract ~min:(0) ~max:nb_pts c1 in + let c0 = Contour.add_point pt1 c in + let c2 = Contour.add_contour c c in + Fmt.pr "- 11 - extracted contour c: %a@." pretty_contour c; + Fmt.pr "- 11 - c0=c+pt1: %a@." pretty_contour c0; + Fmt.pr "- 11 - c2=c+c: %a@." pretty_contour c2; + + let coord1 = Array.get coords1 1 in + Fmt.pr "- 11 - c contains coord: (%f,%f)=%b@." + (fst coord1) (snd coord1) (Contour.contains_coord coord1 c); + Fmt.pr "- 11 - c contains coord: (0.0,0.0)=%b@." (Contour.contains_coord (0.0,0.0) c); + Fmt.pr "- 11 - c contains point pt0: %b@." (Contour.contains_point pt c); + Fmt.pr "- 11 - c contains point pt1: %b@." (Contour.contains_point pt1 c); + (try Contour.set_nth 1 pt1 c; + Fmt.pr "- 11 - set c[1]=pt1@."; + Fmt.pr "- 11 - c contains point pt1: %b@." (Contour.contains_point pt1 c) + with | Contour.Index_out_of_bounds -> Fmt.pr "- 11 - cannot set c[1]=pt1@."); + + let coords2 = coords ~nb:3 ~kx:1 ~dx:1 ~ky:2 ~dy:2 in + let c2 = mk_contour ~is_quadratic:true ~name:"2" + ~mk:(fun ((x,y) as xy) c -> Contour.quadraticToCoord + ~cp:((x -. 2.0),(y -. 2.0)) ~pt:xy c) + coords2 in + Fmt.pr "- 11 - quadratic contour c2: %a@." pretty_contour c2; + + let coords3 = coords ~nb:3 ~kx:3 ~dx:3 ~ky:2 ~dy:2 in + let c3 = mk_contour ~is_quadratic:false ~name:"3" + ~mk:(fun ((x,y) as xy) c ->Contour.cubicToCoord + ~cp1:((x +. 2.0),(y +. 2.0)) + ~cp2:((x -. 2.0),(y -. 2.0)) + ~pt:xy c) + coords3 in + Fmt.pr "- 11 - cubic contour c3: %a@." pretty_contour c3; + + Contour.append_contour c3 c1 ; + Fmt.pr "- 11 - c1+=c3 : %a@." pretty_contour c1; + Contour.append_point pt1 c1 ; + Fmt.pr "- 11 - c1+= pt1: %a@." pretty_contour c1; + + Fmt.pr "- Z - ends...@." ; + let filename = "./test_FontForgeLib.ttf" in + Font.generate ~filename font; + Font.close font; + Fmt.pr "- Z - Font file generated = %s@." filename