Skip to content

Commit

Permalink
Removed WIP tutorial sections for now
Browse files Browse the repository at this point in the history
  • Loading branch information
n7s committed Aug 28, 2024
1 parent e68213d commit a224eb9
Showing 1 changed file with 4 additions and 271 deletions.
275 changes: 4 additions & 271 deletions docs/smith/tutorial.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -120,286 +120,19 @@ We also added extra text files at the root of the project folder: `README.txt, R

=== font4 - Internal processing ===

Before our example gains smart font support and grows in complexity, there is
one area of control that is worth examining. For the most part, when creating a
`wscript` one fills in the various 'forms' that create the objects, and smith
knows what needs to happen to make things turn out right. But while this makes
for pretty tutorials, real world projects have unique quirks that require the
ability to add commands into the processing or to create things dynamically. In
this exercise we will add a process to the source font:

[source,python,linenums]
----
include::./tutorial/font4/wscript[]
----

The interest lies in line 6. Here we use a `process()` function to tell smith
that we want it to run a command over the source font before converting it to a
`.ttf`. A `process()` function takes a file which already exists (either in the
source tree or one that is generated by another process) and then runs the list
of `cmd()` function results over it in order.

In this case, the command is to run
a simple script that removes glyphs from the background layer in a UFO. The command
string takes some study. The program takes two command line parameters, an input
font file and an output font file. We represent these in the command string by
`${DEP}` (the dependent file) as the input and `${TGT}` as the output file.
smith will fill these in appropriately when it comes to run the command.

The rest of the new lines in this exercise are simply extra variables being used
to make the file easier to read, otherwise some of the lines would become
excessively long and confusing. Notice that all the magic variables in a
`wscript` that smith considers are all caps. That is if you use a variable name
with a lowercase letter in it, you are sure to be safe from smith assuming some
special meaning to that variable.

For the most part, we are not very interested in precisely what smith is doing to
get the results we want, but sometimes it helps to know, and all that cryptic
output streaming by isn't much help. But there is a way to get something more
helpful. First we need to get back to a completely pristine source tree:

----
smith distclean
----

Now we can configure and run in a way that has smith tell us what it is doing:

----
smith configure
smith build -j1 -v
----

Thankfully, on a modern terminal, the colourising helps makes more sense of the
voluminous information. But it is helpful once you learn to read it. The
timestamped `runner` lines give the precise command-lines that are run at each
stage of the build.

Clearly, the key to getting this output is in the command-line options to `smith build`.
The `-v` says to output the extra information, (v stands for verbosity). But since smith tries to use multiple processors if you have them, to speed up the build (for example without the
`-j1`, my build runs in 0.479s), it means the output can get interleaved. It is
therefore wise to restrict smith to a single process (j stands for job) while outputting this
information, and this is done using `-j1`.
The part of the tutorial is being rewritten

=== font5 - Smarts and Basic Tests ===

In this exercise we grow our description to add OpenType and Graphite tables and
also add some tests.

[source,python,linenums]
----
include::./tutorial/font5/wscript[]
----

Line 12 tells smith how the OpenType tables will be generated for this font. It
is possible to compile in VOLT tables, or, as here to use the internal
description already in the font. The `internal()` does very little, but it does
indicate to smith that the font has OpenType tables and that they should be
tested.

Line 13 tells smith how the Graphite tables are to be added. There is currently
only one form for Graphite source, and that is GDL. The `gdl()` object tells
smith how to generate and bring together the various files that typically make
up a Graphite description. A typical Graphite project has an autogenerated
component (which is the first parameter to the gdl() (`variable.gdl`) and a
common core `.gdl` file that is hand authored (the `master` parameter). Smith then
does the work to generate the files and compile them into the font.

Line 15 talks about an attachment point database. This file holds information
about glyphs in the font that cannot be held by TTF. Most importantly this file
holds the positions of anchor points on the glyphs, and these positions are used
when autogenerating smart code, either for `volt()` or `gdl()` or whatever.
Depending on the source file format, the file may be autogenerated or be
required as part of the source files.

These three lines are all it takes to add a sophisticated smart font build
system to the font creation step. The rest of this section will look at basic font
testing.

The basic principle of font testing in smith is that there is a directory
containing test data, by default `tests`. This data is then applied to the various fonts and results
are generated in the build tree. Test data can be of various formats, but the
easiest to work with is simple `.txt` files that are treated as one paragraph
per line files.

Line 4 gives the directory where the test files may be found. Since it is
outside the project tree rooted in the directory containing the wscript, we have
to specify where in the buildtree we want the test results to be put. Line 8
specifies that subdirectory.

Smith allows for user defined tests, but there are some defaults built-in, which
we will examine here.

----
smith pdfs
----

This tells smith to generate pdfs of each test file for each font for each smart
font technology. That's quite a few for each, but it means that you can look
at any particular font and its smart rendering technology for each test. The
files end up in `results/tests` based on the value of `TESTRESULTSDIR`.

So for example, the test file `Short.txt` will generate 4 pdf files:
for the regular font: Short_Example_ot.pdf, Short_Example_gr.pdf and
for the bold font: Short_Example-bold_ot.pdf and
Short_Example-bold_gr.pdf. The `_ot` extension is used for OpenType
rendered texts and `_gr` for the Graphite rendered texts. The texts are rendered
using XeTeX.

The other file in the tests directory is `tests.htxt`. The `h` in htxt
tells smith to preprocess the file to convert strings of the form \uxxxx into
the corresponding Unicode character before rendering. This makes it easier to
create test files.

Line 16 is an important line for OpenType testing since it specifies which
script to use when running the OpenType shaping engine.

Another aspect of testing is regression testing. Can we find out what has
changed between this font and a known good version? The way this works is that
we store known good versions of the fonts and then have smith run tests against
both fonts and compare the results. The default directory to keep the font files
in is `references/`.

----
smith test
----

The results end up in the `TESTRESULTSDIR/tests` directory as `.html` files. If
there are no differences, the files are 0 length.

A further target that is useful is the ability to create font reports that show
all the glyphs in a font. We set this as a font product rather than a kind of
test, in line 17. The default target filename is the same as the `target` .ttf
file but with a .pdf extension instead. The file is built as part of `smith
build`.

There are two other targets that this wscript enables:

----
smith waterfall
smith xfont
----

Line 9 specifies a string that will be used in creating the waterfall files and also the cross font
summary files. `smith waterfall` creates one file per font and technology and stores it in
the `waterfall` sub directory of the `TESTRESULTSDIR`, prefixing each font and technology with
`waterfall`. `smith xfont` creates one file per technology in the `TESTRESULTSDIR` called `Crossfont_ot.pdf`
or `Crossfont_gr.pdf` that contains the test string output with the font name, one per line.

Another feature of smith is its ability to integrate with `graide`. Graide is a
graphically based IDE for developing GDL Graphite source code. It also
incorporates a Graphite debugger to help font developers see how their code
executes.

----
smith graide
graide -p graide/Example.cfg
----

Running `smith graide` causes smith to create graide configuration files in a
`graide/` subdirectory. This is one of the few commands that creates files
outside of the results/ tree. The user can then run graide referencing one
of these configuration files. One file is made per font.

A word of advice. Since, most often, smith does not generate .gdx files when it
runs grcompiler (.gdx files are grcompiler debug files), it is best to recompile
the font on loading into graide.

The configuration is designed to restrict graide to just editing GDL. If you
want to use graide to adjust attachment points or add them, then you will need
to enable writing to the AP.xml, in the graide configuration, and you are then
responsible for propagating those changes back from the AP.xml to your source
font.
The part of the tutorial is being rewritten

=== font6 - Metadata ===

So far we have concerned ourselves with the mechanics of font creation. But in
order to release a font package we also need to concern ourselves with the
metadata that is involved in producing a font release.

[source,python,linenums]
----
include::./tutorial/font6/wscript[]
----

We have used an existing font: Andika Mtihani as our base font. The
font has been released under the https://openfontlicense.org[OFL (Open Font License)] and so we are free to modify and develop our own derivative under that license. To avoid any confusion it is better to change the name to something different for our derivative, for example: `Foobar`. We do this in a number of places in the wscript: Line 19 changes both the
name of the font file generated (and all derived products), but it also
processes that font file to change the internal name to "Foobar", using a
`process()` and a `name()` function that acts like a `cmd()` that is suited to font
renaming.

We also set the internal version of the font using a `version` parameter.

The Web Open Font Format (WOFF) is designed particularly for distribution of webfonts
and smith can generate such files from the target .ttf font file. The default
parameters for this object, take the font target filename as the basis of the
woff filename, which is sufficient for our needs. Both in v1 and v2 of the format.

The part of the tutorial is being rewritten

=== font7 - More Tests ===

This section is for those interested in doing more advanced types of testing.
For most projects there is no need to go to this level of complexity and many
users never need to use these capabilities. So this exercise has been placed
after the exercise that pretty much completes font creation. We also try to
introduce as many advanced techniques as we can, even if the results end up
being a little contrived.

Font testing is not limited to just the inbuilt test types. Smith supports the
integration of other test programs as you the user desires, so long as they are
command line based, non-interactive and report generators.

[source,python,linenums]
----
include::./tutorial/font7/wscript[]
----

The interesting section is in lines 17-21. These lines create a fonttest object
that is then referenced within the font at line 34. A fonttest object adds new
smith commands. This example adds the three smith commands: pdfs, test and
report. Notice that the `smith pdfs` command is actually implemented using a
fonttest() object. The `targets` parameter to fonttest uses a python data
structure called a dictionary. This is indicated by the `{` at the start (and
`}` at the end). Dictionary elements consist of a string before a `:` and a
value after it. The value before the `:` is known as the key and the value after
as the value. So a dictionary is set of key, value pairs. In our case, the keys
here indicate smith commands and the values are the test objects that get
executed for the command.

The first two commands use default test objects appropriate to the type of
command. The `pdfs` command executes a `tex()` object that does all the xetex
processing of test files. Likewise the `test` command executes a default
`tests()` object which implements the regression testing.

Our new command `report` also uses a `tests()` object. But in this, we give
another dictionary of key, value pairs. The key is a subdirectory under the
TESTRESULTSDIR and the value is a `cmd()` object that gives the command to
execute. In this case, we are running the uforeport script. The reference to
'${SRC[0]}` says to use the first element from the inputs. The inputs has 3
elements: the font, the text file to test and the corresponding `references/`
font file. We only need the first of these and list indices all start from 0 in
python. In addition, we use the parameter `coverage` to say that we only want to
run tests one per font, and not one per test file per shaper per font. The `>
${TGT}` says that the output that the program produces, which would normally be
printed on the screen is to be sent to the target log file instead.

Another thing we have changed is that rather than hardwiring various of the
specialist programs into our wscript, we now will get smith to go and search for
them. We introduce another new Python concept: the function. Each
smith command will search for a function in your wscript with the same name as
the command and will execute it. For more information of what to do then you
should read the manual for the underlying framework that smith is built on,
which is waf. The variable passed to us is a waf context that can be used to do
various things like add commands to the build process, etc. In our case we want
to have smith search for various programs. `find_program()` is the key that
tells smith to search for the programs. In the case of `ufobackgroundclean`, that is
necessary for the build, so if it is missing we want the configuration to fail.
But in the case of the test script, we only lose the ability of that one test
type if the script is missing, so we don't want to fail the configuration. This
is a marginal call, but we do at least get to see the pattern for achieving
this. In each case `find_program()` takes a list of paths to search,
and it only searches those directories, not directories below those, unless
explicitly listed.
The part of the tutorial is being rewritten

=== font8 - Designspace ===

Expand Down

0 comments on commit a224eb9

Please sign in to comment.