The font for this test case is a
variation font with a single axis. While the ‘gvar’ table
does a regular interpolation without any special quirks, the
font’s ‘avar’ table defines a mapping that modifies the
variation axis.
A correct implementation should
produce the test glyph in its maximally thin shape at axis value
100. The resulting glyph should become bolder until 250,
then stay at the exact same weight until 650, then become
bolder up to the maximum at 900.
100
150
200
250
300
350
400
450
500
550
600
650
700
750
800
850
900
Curve
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
CFF–1: Hexing the Last Byte
The font for this test case is FDArray Test 257, a test
font by Adobe. The font has been engineered by Ken Lunde to use a CFF font dictionary array for mapping Unicode codepoints to glyphs.
If your implementation is correct, each rendered glyph should show a hexadecimal
number with the least significant byte of the Unicode codepoint being rendered.
For a more detailed explanation of this test, please refer to Adobe’s
description.
A
U+0041
ℝ
U+211D
⓪
U+24EA
①
U+2460
②
U+2461
仿
U+4EFF
A
U+FF21
𐄳
U+10133
𝓐
U+1D4D0
🌺
U+1F33A
🌻
U+1F33B
💧
U+1F4A7
🥝
U+1F95D
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
CFF–2: Hexing the Second Last Byte
The font for this test case is Adobe’s FDArray Test 65535,
which complements test case CFF-1.
If your implementation is correct, each rendered glyph should show a hexadecimal
number with the second least significant byte of the Unicode codepoint
being rendered. For a more detailed explanation of this test, please refer to Adobe’s
description.
If the implementation under test works correctly, you should see
the glyphs À and Ü.
Expected
Observed
Conformance
✖
✖
CFF2–1: Variations
The font for this test
case is a subset
of Adobe’s Variable Font Prototype, a variable font in the
Compact
Font Format (CFF) Version 2. If your implementation is correct,
the dollar sign should change its weight in the rendering below. For
most weights, the dollar glyph should be fully stroked. But for the
boldest weights, you should see a glyph variant where the stroke is
only partial.
100
200
300
400
500
600
700
800
900
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
✓
✓
✓
CMAP–1: Ideographic Variation Sequences
The Unicode
Ideographic Variation Database defines glyph variants for Han
ideographs. For example, Unicode supports two slightly different
variants when rendering U+82A6 in Japanese; the font for this test
case contains a type 14 ‘cmap’ table that implements them.
With a conforming implementation, you should see four
glyphs below. In the third glyph (U+82A6 U+E0101), the top stroke
below the radical should be attached and slanting up.
But in the first, second, and fourth glyph, that stroke should be
detached and horizontal. If all four glyphs look the
same, or if you see any black boxes in the renderings, it’s a sign
that your implementation is broken.
82A6 —
82A6 E0100
82A6 E0101
82A6 E0102
Expected
Observed
Conformance
✓
✓
✓
✓
CMAP–2: Unicode Variation Selectors
Unicode defines Standardized Variants of certain characters, including some
Mathematical
Symbols. The font for
this test case contains a type 14 ‘cmap’ table that
implements both the regular symbol ≩ U+2269 GREATER-THAN BUT NOT
EQUAL TO, and its variant U+2269 U+FE00 GREATER-THAN BUT NOT EQUAL
TO WITH VERTICAL STROKE. With a correct implementation, the two
glyphs should look different. If the two glyphs look the same, or if
you see any black boxes in the renderings, it’s a sign that your
implementation is broken.
2269 —
2269 FE00
Expected
Observed
Conformance
✓
✓
CMAP–3: MacOS Turkish Encoding
The font for this test
case contains a ‘cmap’ table of format 0, platform 1,
encoding 0, language 18. Platform 1 means the classic Macintosh up
to MacOS 9; the
combination of encoding 0 and language 18 indicates
the MacOS
Turkish character encoding. (The QuickDraw graphics system of
the classic Macintosh had used code 17 for the Turkish language; as described
by section ”The ‘cmap’ table and language codes” in the
Apple TrueType specification, Macintosh language codes in
the ‘cmap’ table are 1 higher than the QuickDraw language code).
Although Apple has deprecated the
Macintosh encodings in favor of Unicode in 2002, present-day
renderers may still encounter such fonts. For example, users
sometimes want to open electronic documents that were created a long
time ago, and certain file formats contain embedded fonts.
A correct implementation should be able to render Turkish
text with this test font, using Unicode’s
conversion table. If you see boxes, missing characters, or
glyphs from a different (fallback) font in the rendering below, it’s
a sign that your implementation cannot handle legacy fonts
that were built for MacOS.
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
CMAP–4: Many-to-one range mappings
The font for
this test case contains a format 13 ‘cmap’ table that
defines many-to-one range mapping for Latin, Cherokee,
Cuneiform, and Chess Symbols. The font is a subset of the
Last Resort Font.
U U+0055
Ꮿ U+13EF
𒀼 U+1203C
🨀 U+1FA00
Expected
Observed
Conformance
✓
✓
✓
✓
CVAR–1: Sharing Points
The font for this test case
uses shared point numbers in its ‘cvar’ table.
Some versions of the FreeType rasterizer had a bug which made the
glyphs look as if the font had a reverse-contrast design; see
FontTools
bug 1113 and
FreeType bug 52532.
Note: The OpenType specification
explicitly requires that weight values can be interpreted in direct comparison
to values for usWeightClass
in the ‘OS/2’ table, or the CSS font-weight property. Our test font uses a
numeric range from 28 to 194. Therefore, applications will typically display
the rendered letters in a much thinner weight than the font designer probably expected.
However, the font’s weight axis is still within the permitted bounds (from 1 to 1000),
so this font is technically valid. In any case, an implementation should not distort
the glyphs to appear in reverse contrast.
28
94
194
Expected
Observed
Conformance
✓
✓
✓
CVAR–2: Not Sharing Points
Other than CVAR–1, the font for this test case
does not use shared point numbers in its ‘cvar’ table.
28
94
194
Expected
Observed
Conformance
✓
✓
✓
GLYF–1: Composite Glyphs
The font for this test case
has a ‘glyf’ table whose entry for U+0123 LATIN SMALL
LETTER G WITH CEDILLA is a composite glyph. It has two
components: one for the base glyph, and another one for the
accent. A correct implementation must place the accent on top of the
g.
Expected
Observed
Conformance
✓
GPOS–1: Pair Adjustment Positioning
The font for this test case
contains a ‘GPOS’ table whose ‘kern’ feature enables
a lookup of type 2
for Pair
Adjustment Positioning. The lookup contains two subtables:
First, a PairPos format 1 subtable that adjusts the
spacing between pairs of individual letters.
For example, when Ą and J
stand next to each other, their shapes would overlap. From
a typographic perspective, this would look rather terrible,
so this subtable puts them further apart.
Second, a PairPos format 2 subtable that adjusts the
spacing betwen glyph classes. For example, when
they appear on the left-hand side of a letter pair, this subtable
categorizes the letters A Á Ą into one particular class,
G Ģ into another, and V into yet another class.
The same happens for the right-hand side: a á ą are put
into one glyph class, f fi fl into another, and so on.
Finally, the subtable contains a table how to change the spacing
for each combination of classes. Compared to format 1, this
encoding can be more compact.
If you see touching or overlapping glyph pairs in the rendering,
it’s a sign that your implementation fails to handle
‘GPOS’ tables with type 2 lookups for Pair Adjustment
Positioning.
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
GPOS–2: Coverage in Pair Adjustment Positioning
This test case exercises the handling of the Coverage field
in Pair
Adjustment Positioning
subtables. The font contains
a ‘GPOS’ table whose ‘kern’ feature enables a
single lookup of type 2. This lookup contains three PairPos
format 1 subtables. All three subtables specify ◯ U+25EF LARGE
CIRCLE as their Coverage, but no other glyphs.
The first subtable contains a single PairSet for kerning ◯ U+25EF
LARGE CIRCLE and U+0020 SPACE. When rendering the string ◯☼, an
OpenType implementation should decode this subtable because the
first glyph ◯ is in its Coverage. However, because there’s no
match for the second glyph ☼, a correct implementation
should proceed to the second subtable.
The second subtable has two PairSets, both kerning
◯ U+25EF LARGE CIRCLE and ☼ U+263C WHITE SUN WITH RAYS. The first
PairSet applies kerning so that the two symbols will exactly
overlap. If the second PairSet was applied, it would add spacing
to move the two symbols away from each other. But a correct text
rendering engine should walk the PairSets in the order given by
the font, and stop processing after finding the first
match.
The third subtable has yet another PairSet for kerning ◯ U+25EF
LARGE CIRCLE and ☼ U+263C WHITE SUN WITH RAYS. A correct
implementation should have found a matching PairSet in the second
subtable and then stopped processing. Therefore, the implementation
should ignore the pair adjustment positioning data in
the third subtable.
If your implementation is correct, the two symbols ◯ and ☼ should
exactly overlap when drawn next to each other. If you see two
separate symbols in the rightmost column below, your text rendering engine
fails to correctly handle Coverage inside GPOS pair
adjustment positioning subtables.
◯
☼
◯☼
Expected
Observed
Conformance
✓
✓
✓
GPOS–3: Mark-to-Base Attachment for Ethiopic Diacritics
The font for this test case
defines
a Mark Positioning feature in
its Glyph
Positioning table. The feature uses
a MarkToBase Attachment Positioning Subtable for placing Ethiopic
diacritics on top of a base glyph. If your text rendering engine is
correct, the dots (which indicate “long vowel”, “long
consonant”, and “long consonant plus long vowel”)
should be placed on top of the base glyph (the
syllable “la”). If the dots appear to the right of the base
glyph, or if they are missing entirely, it’s a sign that your text
rendering system is broken.
U+1308 —
U+1308 U+135E
U+1308 U+135F
U+1308 U+135D
Expected
Observed
Conformance
✓
✓
✓
✓
GPOS–4: Mark-to-Mark Attachment for Stacked Accents
The font for this test case
uses a MarkToMark Attachment Positioning Subtable for stacking
accents. If your text rendering engine is correct, the accents
should be positioned on top each other. If the accents appear to
the right of the base glyph, or if they are missing entirely, it’s a
sign that your text rendering system is broken.
Expected
Observed
Conformance
✓
✓
✓
✓
GPOS–5: Glyph Positioning for Variable Fonts
The font for this test case
uses
a Glyph positioning table with font variations. If your text
rendering engine is correct, the Sukun mark should be centered on
the dots of the Shin letter, no matter the weight. If the placement
is off for some weights, your text rendering system fails to
handle Item Variation Stores inside GPOS tables.
100
300
500
700
900
Expected
Observed
Conformance
✓
✓
✓
✓
✓
GSUB–1: Space Isn’t Nothing
The font for this test case
has a contextual alternates feature in its GSUB table that
substitutes a by a.alt if followed by a
space. Some versions of Adobe InDesign had a bug where space was
treated like an empty substitution context. If your implementation
is correct, you should see two different glyphs in the rendering:
the first letter should have an overbar, the second letter should
not.
Expected
Observed
Conformance
✓
GSUB–2: Chaining Contextual Substitution for Ethiopic Numerals
The font for this test case
supports the “joining style”
of Ethiopic
numerals. It contains distinct glyphs for the the initial,
medial, and final form of every digit, plus
an isolated form which gets used when a digit stands
alone. In
its Glyph
Substitution table, the test font uses
a Glyph Composition/Decomposition feature to select the correct
shape depending on its context. To achieve this effect, the feature
invokes lookups for
Chaining
Contextual Substitution. In the test rendering, you
should see continuous strokes; only the the first and the last digit
of each number should have side strokes. If you can see small side
strokes also at interior digits, it’s a sign that your text
rendering engine is broken.
20
3
40
5
23
45
100
2300
2323
2345
4523
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
GSUB-3: Substituting a Billion Laughs
The font for this test case
is an OpenType version of the Billion
laughs attack. Its GSUB table contains a sequence of
nine identical lookups. Each lookup replaces the glyph o by
the string olololololololololo, provided that the
o is surrounded (both preceded and followed) by an
l. The first lookup thus expands one single laugh
(lol) into ten. The second lookup gives 100 laughs; the
third 1000; the fourth 10,000; the fifth 100,000; and so forth.
After executing the ninth lookup, the final result would be a
billion laughs, but this takes a very long time (and large amounts
of memory) to compute. If your implementation is immune to this
attack, it should neither crash nor hang when rendering lol
with this font. Instead, your implementation should stop executing
once its internal buffer has reached a size limit. See also fontkit
bug 221.
Expected
Shouldn’t crash
Conformance
✖
GVAR–1: Sharing All Points
The font for this test case
uses shared point numbers in its ‘gvar’ table. In
its shared points set, the font sets the number of points
to zero. A correct implementation should interpret such an empty set
as a compact encoding of “all points.” If the glyphs in the
rendering below have all the same weight, of if some glyphs are
missing entirely, it’s a sign that your implementation is broken.
300
350
400
450
500
550
600
650
700
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
✓
✓
✓
GVAR–2: Sharing Enumerated Points
Like in test case GVAR–1,
the font for this test
uses shared point numbers in its ‘gvar’
table. However, this font does not simply state an empty set for
indicating that “all points” should be affected by the variation
record. Instead, it gives an explicit enumeration of point numbers
in its shared points set. A correct implementation should
render the glyphs in the exact same way as
in GVAR–1, although the font uses a less
compact encoding.
300
350
400
450
500
550
600
650
700
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
✓
✓
✓
GVAR–3: Sharing No Points
Other than the fonts for test cases GVAR–1
and GVAR–2, the font for this test does not use any shared point numbers
in its ‘gvar’ table. A correct implementation should still
render the glyphs in the exact same way, no matter what encoding
has been used.
300
350
400
450
500
550
600
650
700
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
✓
✓
✓
GVAR–4: Crawling Lizard
The font for this test case
is Zycon, designed in 1993, by David Berlow at Font Bureau
Inc. The font was developed for illustrating the capabilities of
TrueType GX. The glyph ids and the font have been updated to
OpenType 1.8. The new version supports a small number of Emoji such
as 🦎 U+1F98E LIZARD. If your implementation is correct, the lizard
should crawl. Variation axis M₁ moves its legs while
axis T₁ bobs the head.
–1.0 +0.0
–0.8 +0.1
–0.6 +0.2
–0.4 +0.3
–0.2 +0.4
±0.0 +0.5
+0.2 +0.6
+0.4 +0.7
+0.6 +0.8
+0.8 +0.9
+1.0 +1.0
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
GVAR–5: Lunar Phases
The font for this test case
is the same Zycon as in
GVAR–4. If your implementation is
correct, 🌝 U+1F31D FULL MOON WITH FACE should wax and wane in sync
with to variation axis M₁.
–1.0
–0.8
–0.6
–0.4
–0.2
±0.0
+0.2
+0.4
+0.6
+0.8
+1.0
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
GVAR–6: Timid Turtle
The font for this test case is
again the same Zycon as in GVAR–4.
Here, axis T₁ controls the timidity of 🐢 U+1F422 TURTLE. If
your implementation is correct, the turtle should fully stick its
head, legs and tail out of the shell at T₁ = 0.0. As the axis
value goes up, the turtle should become increasingly
timid. At T₁ = 1.0, it should be fully hidden inside the
shell.
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
GVAR–7: Stemming Digits
With one particular OpenType implementation,
the font for this test case
triggered an etched look where the glyphs were distorted. If your
implementation is correct, you see normal-looking glyphs whose
weight is smoothly increasing. All the “I” letters should have
visible stems, and there should not be anything unusual about the
“O” letters either.
150
200
250
300
350
400
450
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
✓
GVAR–8: Inferring Variation Deltas for Unreferenced Points
The font for this test case
has a single glyph (‘H’) which displays examples of a boundary IUP
issue which was treated differently in existing implementations. The
top of the top serifs and bottom of the bottom serifs all have
multiple points at the same Y location in the default. If you examine
the bottom left serif, you will see points 149 through 157 all share
the same Y coordinate of 0. When moving from the default 0.0 to –1.0
in the Hooves axis, point 153 moves by (0,50). This now leaves
6 untouched points that need to be interpolated. The handling of these
intermediate points (150–152 and 154–156) was different between
Apple’s, FreeType’s and Monotype’s implementations.
±0.0
–0.2
–0.4
–0.6
–0.8
–1.0
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
GVAR–9: IUP, again
The font for this test case
has one axis, TEST, that runs from –1.0 to 1.0 with default 0.0. It
has one glyph, A, which contains 4 square contours, all identical
apart from their x position. The top edge of each contour contains 5
points, with 3 extra points spaced evenly between the top-left and
top-right points. It has one gvar variation tuple, value 1 on axis
TEST. This tuple only moves points that lie on the top of each
contour. Note that in each contour moved by the gvar tuple, there are
TWO runs of interpolated points. Thus: contour #0 has points 0–6;
contour #1 has points 7–13; contour #2 has points 14–20; contour #3
has points 21–27.
If your implementation is correct, you should see four square contours
for values of TEST ≤ 0. As the value increases towards +1.0,
the first, third and fourth contour should look increasingly distorted.
The font for this test case contains
a Horizontal Metrics Variation Table
whose offsetToAdvanceWidthMapping field is zero. The font,
which was kindly contributed by Adobe Systems, had triggered a bug
in an unreleased version of
the FreeType library;
see FreeType
bug 50170. If your implementation is correct, the advance
width should grow as the weight increases. In particular, the
letters A and B should not overlap, not even in the boldest weights.
If you see any overlapping glyphs, your implementation
fails to compute advance widths for fonts whose HVAR table
contains no advance width mapping.
0
200
400
600
800
1000
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
HVAR–2: Last entry
The font for this test case
contains an
HVAR
table with fewer entries than glyphs in the font. According to
the OpenType HVAR specification, “if a given glyph ID is greater
than
mapCount – 1, then the last entry is used.” If your
implementation is correct, the two glyphs should not crisscross. If
they overlap, your implementation is faulty. See also
FreeType
bug 50678.
0
200
400
600
800
1000
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
KERN–1
The font for this test case
contains a ‘kern’ table of format 0, which in turns
contains a single format 0 subtable. Without kerning, the glyphs
for T, u and the dotless ı will look like
normal letters. However, if your implementation correctly applies
the font’s kerning data, the shapes will join to form a geometric
pattern. If you can still discern the original
letters ıTuTuTı in the rendering, it’s a sign that your
implementation fails to correctly handle kerning.
See also HarfBuzz
bug 1255.
Expected
Observed
Conformance
✓
KERN–2
Although kerning is typically reducing space between
letter pairs, it’s entirely valid for a font to increase it.
This test verifies that an implementation can handle
such kerning tables. If your implementation works correctly,
you should see four groups separated by whitespace.
Expected
Observed
Conformance
✓
MORX–1: Non-Contextual Glyph Substitution
The font for this test case contains
an AAT Extended Glyph Metamorphosis Table
with a single Non-Contextual Glyph Substitution Subtable,
replacing the glyphs A and C by alternate forms.
If your renderer supports
Apple
Advanced Typography,
the letters A and C should be white on black whereas the letter B
should appear inside a stroked circle.
Expected
Observed
Conformance
✓
MORX–2: Rearrangement
The font for this test case contains
an AAT Extended Glyph Metamorphosis Table
with a single Rearrangement Subtable. Its finite-state table
contains one single state, but a set of interesting transitions.
For glyph A, the transition carries the
markFirst bit, so it starts the marked range.
For glyphs B to D and X to Z,
the transitions carry the markLast bit. Therefore,
these glyphs extend the marked range.
For glyph O, the transition carries no special flags,
and it does not execute any action.
For glyphs ⓿ to ⓯, the transition executes
the corresponding rearrangement action on the range that
has been marked earlier.
In the font for this test
case, the transitions for glyphs ⓿ to ⓯ execute the corresponding
rearrangement actions. However, the font’s state machine is unusual
because it does not contain any transitions for changing the marked
glyph range. Therefore, the rearrangements get invoked without a
marked range. If your rendering engine is correctly implemented, it
should leave the input sequence unchanged.
Expected
Observed
Conformance
✓
✓
✓
✖
Expected
Observed
Conformance
✖
✖
✖
✖
Expected
Observed
Conformance
✖
✖
✖
✖
Expected
Observed
Conformance
✖
✖
✖
✖
MORX–4: Empty Rearrangement
The font for this test case
contains
an AAT Extended Glyph Metamorphosis Table with a
single Rearrangement Subtable. Its finite-state table
contains one single state and the following transitions:
For glyph A, the transition carries both the
markFirst and markLast bits, so it starts and
ends the marked range.
For glyphs B to F, the transitions carry
the markLast bit, so they extend the marked range.
For glyphs P to Z, the transitions carry no
special flags, and they do not execute any actions.
For glyphs ⓿ to ⓯, the transitions execute
the corresponding rearrangement actions on the range that
has been marked earlier.
The test strings are crafted to trigger rearrangements on sequences
whose variable-length part is empty (x = ε). If your
rendering engine implements Apple Advanced Typography, the
output should should match the expectations. See also
Apple
Radar bug 36384131.
0: No change
1: Aε ⇒ εA
2: εA ⇒ Aε
3: AεD ⇒ DεA
Expected
—
Observed
—
Conformance
—
✓
✓
✓
4: ABε ⇒ εAB
5: ABε ⇒ εBA
6: εAB ⇒ ABε
7: εAB ⇒ BAε
Expected
Observed
Conformance
✓
✓
✓
✓
8: AεCD ⇒ CDεA
9: AεCD ⇒ DCεA
10: ABεD ⇒ DεAB
11: ABεD ⇒ DεBA
Expected
Observed
Conformance
✓
✓
✓
✓
12: ABεCD ⇒ CDεAB
13: ABεCD ⇒ CDεBA
14: ABεCD ⇒ DCεAB
15: ABεCD ⇒ DCεBA
Expected
Observed
Conformance
✓
✓
✓
✓
MORX–5: Rearrangement underflow
The font for this test case
is the same as in MORX-4. The test strings
are crafted to trigger rearrangements on sequences that are shorter
than the operands of the executed action. For example, rearrangement
action 3 swaps the first and last glyph of the marked sequence;
so we test what happens when the marked sequence contains just one
glyph. If your rendering engine is correctly implemented, it should
not perform rearrangements when there are not enough arguments.
See also fontkit
bug 143.
3: AxD ⇒ DxA only 1 of 2+ glyphs
4: ABx ⇒ xAB only 1 of 2+ glyphs
5: ABx ⇒ xBA only 1 of 2+ glyphs
6: xCD ⇒ CDx only 1 of 2+ glyphs
Expected
Observed
Conformance
✖
✖
✖
✖
7: xCD ⇒ DCx only 1 of 2+ glyphs
8: AxCD ⇒ CDxA only 1 of 3+ glyphs
8: AxCD ⇒ CDxA only 2 of 3+ glyphs
9: AxCD ⇒ DCxA only 1 of 3+ glyph
Expected
Observed
Conformance
✖
✖
✖
✖
9: AxCD ⇒ DCxA only 2 of 3+ glyphs
10: ABxD ⇒ DxAB only 1 of 3+ glyph
10: ABxD ⇒ DxAB only 2 of 3+ glyphs
11: ABxD ⇒ DxBA only 1 of 3+ glyphs
Expected
Observed
Conformance
✖
✖
✖
✖
11: ABxD ⇒ DxBA only 2 of 3+ glyphs
12: ABxCD ⇒ CDxAB only 1 of 4+ glyphs
12: ABxCD ⇒ CDxAB only 2 of 4+ glyphs
12: ABxCD ⇒ CDxAB only 3 of 4+ glyphs
Expected
Observed
Conformance
✖
✖
✖
✖
13: ABxCD ⇒ CDxBA only 1 of 4+ glyphs
13: ABxCD ⇒ CDxBA only 2 of 4+ glyphs
13: ABxCD ⇒ CDxBA only 3 of 4+ glyphs
14: ABxCD ⇒ DCxAB only 1 of 4+ glyphs
Expected
Observed
Conformance
✖
✖
✖
✖
14: ABxCD ⇒ DCxAB only 2 of 4+ glyphs
14: ABxCD ⇒ DCxAB only 3 of 4+ glyphs
15: ABxCD ⇒ DCxBA only 1 of 4+ glyphs
15: ABxCD ⇒ DCxBA only 2 of 4+ glyphs
Expected
Observed
Conformance
✖
✖
✖
✖
15: ABxCD ⇒ DCxBA only 3 of 4+ glyphs
Expected
Observed
Conformance
✖
MORX–6: Re-Re-Re-Rearrangements
The font for this test case
is the same as in MORX-4. When rendering the
test string OOOABCDEFGOOO3141, the following should happen:
Upon processing the three initial O glyphs, the
finite-state automaton performs no special actions beyond
consuming the input symbols.
Upon processing the A glyph, the rendering engine
remembers the position of the current glyph as start and end of the marked
glyph sequence. Afterwards, the marked glyph sequence is A.
Upon processing the B, C, D, E, F, and G glyphs,
the rendering engine sets the current position as end of the marked
glyph sequence. After processing G, the marked glyph sequence
is ABCDEFG.
When processing the three following O glyphs, the
finite-state automaton again performs no special actions, apart from
consuming the input symbols.
When processing the 3 glyph, the finite-state automaton
executes Rearrangement action 3. This action exchanges the
first and last glyph of the marked sequence. Afterwards, the marked
glyph sequence is GBCDEFA.
When processing the 1 glyph, the finite-state automaton
executes Rearrangement action 1. This action moves the
first glyph of the marked sequence (G) to the
end. Afterwards, the marked sequence is BCDEFAG.
When processing the 4 glyph, the finite-state automaton
executes Rearrangement action 4. This action moves the
first two marked glyphs (BC) to the end. Afterwards, the
marked sequence is DEFAGBC.
When processing the 1 glyph, the finite-state automaton
executes Rearrangement action 1. This action moves the
first glyph of the marked sequence (D) to the
end. Afterwards, the marked sequence is EFAGBCD.
If your implementation supports
Apple
Advanced Typography, the text should get rearranged as expected.
If the resulting string is ordered as ABCDEFG, your
implementation does not implement AAT at all. If the result is
ordered as GBCDEFA, your implementation incorrectly clears
the marked glyph sequence after executing actions.
Expected
Observed
Conformance
✓
MORX–7: Unstarted Rearrangement
The font for this test case
is the same as in MORX–2. When rendering the
string OBCD1, we set the end of the marked glyph sequence
to B; then we change it to C; finally, to D.
However, we never set the start of the marked glyph sequence.
If your rendering engine is correctly implemented, it should implicitly
start the marked glyph range at the beginning of the string,
and move the O after the D when executing the
rearrangement for 1.
Expected
Observed
Conformance
✓
MORX–8: Rearrangement State Machine
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Rearrangement Subtable. Its finite-state machine
contains three states (0, 1, 2) and the following transitions:
For glyph 0, the machine enters state 0.
For glyph 1, the machine enters state 1.
For glyph 2, the machine enters state 2.
For glyph A, the machine remains in its current
state. As a side effect, it sets both start
and end of the marked glyph sequence to the current
position.
For glyph B, the machine remains in its current
state. As a side effect, it changes the end of the
marked glyph sequence to the current position.
For glyph C, the machine remains in its current
state. As a side effect, the machine changes the end of
the marked glyph sequence to the current position. In
addition, it executes one of the following rearrangement
actions:
In state 0, a rearrangement of type 0. This is a no-op, so
the marked glyph sequence remains unchanged.
In state 1, a rearrangement of type 1. This moves the first
marked glyph to the back, so “ABC” gets rewritten to “BCA”.
In state 2, a rearrangement of type 2. This moves the last
marked glyph to the front, so “ABC” gets rewritten to “CAB”.
If your rendering system correctly implements Apple Advanced
Typography, the string “0ABC” should get rendered in the
original ordering, whereas “1ABC” and “2ABC” should get re-arranged
in a state-dependent way.
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Rearrangement Subtable. Its finite-state machine
contains one single state with the following transitions:
For glyph A, the machine sets both start
and end of the marked glyph sequence to the current
glyph position.
For glyph B, the machine changes the end of the
marked glyph sequence to the current position.
For any other glyph (“out of bounds”), the machine executes a
rearrangement action.
If your rendering system correctly implements Apple Advanced
Typography, it should swap the first two letters in ABXAB.
Expected
Observed
Conformance
✓
MORX–10: “End of Text” Rearrangement
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Rearrangement Subtable. Its finite-state machine
contains one single state with the following transitions:
For glyph A, the machine sets both start
and end of the marked glyph sequence to the current
glyph position.
For glyph B, the machine changes the end of the
marked glyph sequence to the current position.
For “end of text”, the machine executes a rearrangement action.
If your rendering system correctly implements Apple Advanced
Typography, it should swap the last two letters in ABABAB
when taking the final end-of-text transition. See also
fontkit
bug 144.
Expected
Observed
Conformance
✖
MORX–11: “End of Text” Rearrangement with MarkLast Flag
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Rearrangement Subtable. Its finite-state machine
contains one single state with the following transitions:
For glyph A, the machine sets both start
and end of the marked glyph sequence to the current
glyph position.
For “end of text”, the machine changes the end of the
marked glyph sequence to the current position and
executes a rearrangement action of type 2, which moves the
last marked glyph to the front of the marked sequence.
For any other glyphs, the machine performs no action.
The input string for this test case is BABBAABX. If your
rendering system correctly implements Apple Advanced
Typography, the finite-state machine should have marked the
last A (the third-last glyph in the input string) before
taking the final end-of-text transition. When processing
end-of-text, your implementation should first extend the marked
glyph sequence to the trailing ABX, and then perform a
rearrangement for moving X to the front of the marked
sequence. See also fontkit bug 145.
Expected
Observed
Conformance
✖
MORX–12: Rearrangement with DontAdvance Flag
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Rearrangement Subtable. Its finite-state machine
contains two states (0 and 1) with the following transitions:
For glyph A, the machine stays in its current
state. As a side effect, it sets both start
and end of the marked glyph sequence to the
current glyph position.
For glyphs B and C, the machine stays
in its current state. As a side effect, it sets both start
and end of the marked glyph sequence to the
current glyph position.
For glyph ➊:
from state 0, the machine makes a transition to state 1.
This transition carries the DontAdvance flag.
No rearrangement action is performed.
from state 1, the machine stays in state 1. This transition
carries no flags. However, it peforms a rearrangement of type 2
which moves the last marked glyph to the front of the marked
glyph sequence. This changes the marked sequence
from ABC to CAB.
For glyph ➋:
from state 0, the machine makes a transition to state 1.
This transition carries the DontAdvance flag, and
it performs a rearrangement of type 2. This rewrites the
marked glyph sequence from ABC to CAB.
from state 1, the machine stays in state 1. This transition
carries no flags and performs no actions.
For glyph ➌:
from state 0, the machine makes a transition to state 1.
This transition carries the DontAdvance flag, and
it performs a rearrangement of type 2. This rewrites the
marked glyph sequence from ABC to CAB.
from state 1, the machine stays in state 1. This transition
carries no flags. However, it peforms another rearrangement of
type 2. This second rewrite changes the
marked glyph sequence from CAB to BCA.
For any other glyphs and “end of text”, the machine performs
no action.
The input string for this test case is XABCX followed by
➊, ➋, or ➌. If your rendering system correctly implements Apple
Advanced Typography, the finite-state machine should follow the
DontAdvance transitions to state 1 and produce the expected
outputs.
XABCX➊
XABCX➋
XABCX➌
Expected
Observed
Conformance
✓
✓
✓
MORX-13: Rearrangement with DontAdvance and MarkLast
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Rearrangement Subtable. Its finite-state machine
contains two states (0 and 1) with the following transitions:
For glyph A, the machine stays in its current
state. As a side effect, it sets both start
and end of the marked glyph sequence to the
current glyph position.
For glyphs B, C, and D, the machine stays
in its current state. As a side effect, it sets both start
and end of the marked glyph sequence to the
current glyph position.
For glyph E,
from state 0, the machine makes a transition to state 1.
This transition carries both the DontAdvance and
MarkLast flags. No rearrangement action is performed.
from state 1, the machine stays in state 1. The transition
carries no flags. However, it peforms a rearrangement of type 1
which moves the first marked glyph to the end of the marked
glyph sequence.
For any other glyphs and “end of text”, the machine performs
no action.
The input string for this test case is ABCDE. If your
rendering system correctly implements Apple Advanced
Typography, the finite-state machine should extend
the marked glyph range to include E when the state
changes from 0 to 1, even though the current position is not
advancing. As a result, the final string after rearrangement should
be BCDEA. If your implementation produces BCDAE
or another order, it fails to handle state transitions that carry
both the DontAdvance and MarkLast flags.
Expected
Observed
Conformance
✓
MORX-14: Rearrangement Loop
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Rearrangement Subtable. Its finite-state machine
contains two states (0 and 1) with the following transitions:
For glyph A:
in state 0, the machine loops back to state 0.
This transition carries both the MarkFirst and
MarkLast flags. No rearrangement action is performed.
in state 1, the machine loops back to state 1.
This transition carries no flags.
No rearrangement action is performed.
For glyphs B, C, and D:
in state 0, the machine loops back to state 0.
This transition carries the MarkLast flag.
No rearrangement action is performed.
in state 1, the machine loops back to state 1.
This transition carries the DontAdvance flag,
and executes a rearrangement of type 2 (xD ⇒ Dx).
For glyph E:
in state 0, the machine makes a transition to state 1.
This transition carries both the DontAdvance and
MarkLast flags. No rearrangement action is performed.
in state 1, the machine loops back to state 1.
This transition carries the DontAdvance flag,
and it executes a rearrangement of type 2 (xD ⇒ Dx).
For any other glyphs and “end of text”, the machine performs
no action.
If your rendering system correctly implements Apple Advanced
Typography, the finite-state machine should loop multiple times
through state 1, repeatedly rearranging the marked glyphs in every
iteration.
For the input string ABCDE, your implementation should
change the marked glyph sequence as follows: A → AB
→ ABC → ABCD → ABCDE → EABCD
→ DEABC → CDEAB → BCDEA.
For the input string ABBBCCCDDDBCDCE, your
implementation should change the marked glyph changes as
follows: A → AB → ABB → [...]
→ ABBBCCCDDDBCDCE → EABBBCCCDDDBCDC
→ CEABBBCCCDDDBCD → DCEABBBCCCDDDBC
→ CDCEABBBCCCDDDB → BCDCEABBBCCCDDD
→ DBCDCEABBBCCCDD → [...] → BCCCDDDBCDCEABB
→ BBCCCDDDBCDCEAB → BBBCCCDDDBCDCEA.
However, since this is a rather degenerated corner case,
we only expect that the implementation does not crash or hang.
ABCDE
ABBBCCCDDDBCDCE
Expected
Shouldn’t crash or hang
Observed
Conformance
✓
✓
MORX-16: Rearrangement with DontAdvance and MarkFirst
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Rearrangement Subtable. Its finite-state machine
contains two states (0 and 1) with the following transitions:
For glyph A:
in state 0, the machine moves to state 1.
This transition carries both the DontAdvance and
MarkFirst flags. No rearrangement action is performed.
in state 1, the machine moves to state 0.
This transition carries no flags.
No rearrangement action is performed.
For glyphs B, C, and D, the machine stays
in its current state. As a side effect, it sets the end
of the marked glyph sequence to the current glyph position.
For glyph E, the machine stays in its current state.
As a side effect, it sets the end
of the marked glyph sequence to the current glyph position,
and executes a rearrangement action of type 1 (Ax ⇒ xA).
For any other glyphs and “end of text”, the machine performs
no action.
The input string for this test case is ABCDE.
If your rendering system correctly implements Apple Advanced
Typography, the A glyph should be rearranged to the
end of the rendered string, resulting in BCDEA.
ABCDE
Expected
Observed
Conformance
✓
MORX-17: Rearrangement with DontAdvance at End of Text
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Rearrangement Subtable. Its finite-state machine
contains a single state with the following transitions:
For glyph A, the transition carries the
MarkFirst flag. No rearrangement action is performed.
For glyph B, the transition carries the
MarkLast flag. No rearrangement action is performed.
For End of text, the transition carries the
DontAdvance flag and performs a rearrangement action
of type 1 (Ax ⇒ xA).
For any other glyphs, the machine performs no action.
The input string for this test case is AB.
If your rendering system correctly implements Apple Advanced
Typography, the A glyph should be rearranged to the
end of the rendered string when your implementation executes the
rearrangement for the End-of-text transition. Despite the presence
of the DontAdvance flag, the result should be BA.
See also fontkit
bug 147.
AB
Expected
Observed
Conformance
✖
MORX-18: Contextual Glyph Substitution
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Contextual Glyph Substitution Subtable.
Its finite-state machine
contains a single state with the following transitions:
For glyph B, the transition carries the SetMark flag.
For glyph D, the transition sets MarkIndex to 0,
and CurrentIndex to 1.
The glyph substitution table has two entries. Index 0 replaces
letters A to E by circled black-on-white forms;
index 1 replaces A to E by circled white-on-black
forms.
If your rendering system correctly implements Apple Advanced
Typography, the renderings should look as expected.
Expected
Observed
Conformance
✓
✓
✓
✓
MORX-19: Contextual Glyph Substitution without Marking
The font for this test
case is the same as with MORX–18. In this
test, we do not render the B letter, so there are no marked
glyphs. If your rendering system correctly implements Apple
Advanced Typography, it should implicitly mark the first letter
of the rendered string, so the output should look as expected.
See also Fontkit bug 150.
Expected
Observed
⁓
⁓
Conformance
✖
✖
MORX-20: Contextual Glyph Substitution at End of Text
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Contextual Glyph Substitution Subtable. Its finite-state machine
contains a single state with the following transitions:
For glyph A, B, and C,
the transition carries the SetMark flag.
For End of Text, the transition sets MarkIndex to 0,
and CurrentIndex to 1.
The glyph substitution table has two entries. Index 0 replaces
letters A to E by circled black-on-white forms;
index 1 replaces A to E by circled white-on-black
forms.
If your rendering system correctly implements Apple Advanced
Typography, the renderings should look as expected.
See also Fontkit bug 151.
ABCDE
ABC
ABE
AE
EE
A
E
Expected
Observed
Conformance
✖
✖
✖
✖
✓
✖
✓
MORX-21: Contextual Glyph Substitution with SetMark
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Contextual Glyph Substitution Subtable. Its finite-state machine
contains a single state with the following transitions:
For glyph B, the transition carries the
SetMark flag.
For glyph D, the transition carries the
SetMark flag. Also, it replaces the marked glyph
with a circled form.
The input string for this test is ABCDE. If your rendering
system correctly implements Apple Advanced Typography, it
should do the following when processing the transition
for D: first, it should replace the marked glyph B
by a circled form. Second, it should reset the marked glyph index
to D. Therefore, only the B letter should
be encircled in the rendered result. If the D is encircled,
your implementation should be fixed to reset the marked glyph index
after performing the replacement.
ABCDE
Expected
Observed
Conformance
✓
MORX-22: Contextual Glyph Substitution with MarkIndex and CurrentIndex
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Contextual Glyph Substitution Subtable. Its finite-state machine
contains two states (0 and 1) with the following transitions:
For glyph A:
In state 0, the machine moves to state 1 using a transition
that carries both the SetMark and DontAdvance flags.
In state 1, the machine moves back to state 0 using a transition
that executes glyph substitution #0 on the marked glyph, and
also glyph substitution #1 on the current glyph.
The input string for this test is A. If your rendering
system implements Apple Advanced Typography,
both MarkIndex and CurrentIndex will affect the
same glyph. If your implementation is correct, it should
first execute the glyph substitution for MarkIndex
to replace A by B. Then, it should
execute the glyph substitution for CurrentIndex,
which replaces B (the result of the previous substitution)
by C. Therefore, the final result should be C.
A
Expected
Observed
Conformance
✓
MORX-23: Contextual Glyph Substitution with CurrentIndex and DontAdvance
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Contextual Glyph Substitution Subtable.
Its finite-state machine contains one state. For glyphs
glyphs A, B, C, and D,
the machine executes the per-glyph substitution #0
on CurrentIndex on a transition that is also marked
with the DontAdvance flag. The glyph substitution
replaces A by B, B by C,
C by D, and D by E.
The input string for this test is ABCDE. If your rendering
system correctly implements Apple Advanced Typography, the
finite-state machine should loop for each glyph in state 0 until it
gets rewritten to E. The final result should be EEEEE.
ABCDE
Expected
Observed
Conformance
✓
MORX-24: Contextual Glyph Subsitution Forever
The font for this
test case attempts to run a denial-of-service attack on the
rendering engine under test. The font’s finite-state transducer
substitutes glyph A by B, B by C,
C by D, D by E,
and E by A. These transitions are all marked with
the DontAdvance flag, so the machine never makes progress.
If your rendering system is immune to this attack, it will detect
getting stuck (for example, by imposing an upper limit on the number
of transitions taken by the finite-state machine), and give up quickly.
See fontkit
bug 175.
Expected
Shouldn’t crash
Conformance
✖
MORX-25: State Machine for Contextual Glyph Substitution
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Contextual Glyph Substitution Subtable. Its finite-state machine
contains two states (0 and 1). In state 0, glyph A moves to
state 1 with a transition carrying the SetMark flag; other glyphs
have no effect. In state 1, glyphs B, C, D, E replace both
the current and the marked glyph by an encircled form; other glyphs
have no effect.
ABCDE
EBCDA
CBABC
ABC
CBA
AB
BA
A
B
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
✓
✓
✓
MORX-26: Another State Machine for Contextual Glyph Substitution
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Contextual Glyph Substitution Subtable. Its
finite-state machine contains two states (0 and 1). In state 0,
glyph A moves to state 1; glyphs B, C, D, E get
replaced by an encircled form. In state 1, no substitution happens.
If your implementation is correct, the input string AB
should not get any substitutions, but a stand-alone B
should get rendered inside a circle.
MORX-28: Ligature Substitution with Unmarked Glyphs
The font for this
test case has
an AAT Extended Glyph Metamorphosis Table with a
single Ligature Subtable to substitute AED by a ligature.
The glyphs x and y do not change the current
state of the finite-state machine, and their transitions also
do not carry the SetMark flag. If your implementation
is correct, it should form the ligature in spite of the presence
of x and y.
AED
AxED
AEyD
AxEyD
AxxxEyyyyD
Expected
Observed
Conformance
✓
✓
✓
✓
✓
MORX-29: Insertion
The font for this
test case has
an AAT Extended Glyph Metamorphosis Table with a
single Glyph Insertion Subtable. The glyph
M has the SetMark bit set. The glyph
A inserts the string INS before the last marked
glyph because its MarkedInsertBefore bit is set;
whereas B inserts the same after the marked
sequence because its MarkedInsertBefore bit is clear.
Glyphs C and D perform the same insertion
before/after the current glyph. The glyphs P, Q, R, X, Y,Z
perform no actions.
MORX-30: Multiple Insertions Without Resetting Mark
The font for this
test case is the same as in MORX-29; we
test the behavior when multiple insertions get performed without
re-setting the mark. See also
fontkit bug 172.
Expected
Observed
Conformance
✖
Expected
Observed
Conformance
✖
Expected
Observed
Conformance
✖
Expected
Observed
Conformance
✖
MORX-31: Insertion With SetMark On Same Transition
The font for this
test case has
an AAT Extended Glyph Metamorphosis Table
with a single Glyph Insertion Subtable. Its finite-state machine
contains the following transitions:
For glyph M, the transition carries the SetMark
flag, but it does not insert anything.
For glyph A, the transition carries the SetMark
and MarkedInsertBefore flags, and it executes an action to insert
the string INS.
For glyph B, the transition carries
the SetMark flag, and it executes an action to insert
the string INS.
For any other glyphs and “end of text”, the transition carries
no flags and performs no insertions.
See also Apple
Radar bug 44861764. Contextual and insertion subtables should
mark the first glyph (according to process order) before doing
anything else.
XXAYYAZZ
XXAYYBZZ
Expected
Observed
Conformance
✖
✖
XXBYYAZZ
XXBYYBZZ
Expected
Observed
Conformance
✖
✖
MPQRAXYZA
MPQRAXYZB
Expected
Observed
Conformance
✖
✖
MPQRBXYZA
MPQRBXYZB
Expected
Observed
Conformance
✖
✖
MORX-32: Insertion At Mark Without SetMark
The font for this
test case has
an AAT Extended Glyph Metamorphosis Table
with a single Glyph Insertion Subtable. Its finite-state machine
contains the following transitions:
For glyph A, the transition inserts the string INS
before the currently marked glyph.
For glyph B, the transition inserts the string INS
after the currently marked glyph.
For any other glyphs and “end of text”, the transition carries
no flags and performs no insertions.
The test cases check what happens when inserting glyphs without
setting the mark. We expect that implementations match the buggy
behavior of Apple’s CoreText, since the existing fonts have been
developed for that platform. See
also HarfBuzz bug 1195.
A
XAY
B
XBY
Expected
Observed
Conformance
✖
✖
✖
✖
MORX-33: Twice the Fun
The font for this
test case has
an AAT Extended Glyph Metamorphosis Table
with a single Glyph Insertion Subtable. When consuming
glyph ‘h’ in state 0, its finite-state machine transitions
to state 1. When consuming
glyph ‘a’ in state 1, its finite-state machine transitions
back to state 0 while also inserting the string “ha”.
If your implementation is correct, every ha in the input
should get rendered twice.
The font for this
test case is an AAT version of the
Billion
laughs attack. It contains
an AAT Extended Glyph Metamorphosis Table with nine
identical Glyph Insertion Subtables whose embedded
finite-state machine inserts the
string hahahahahahahahahaha for every a in the
input string. If the input is “ha” (one single laugh), the first
subtable rewrites it to 10 laughs. The second subtable rewrites 10
to 100 laughs; the third goes from 100 to 1000; the fourth from 1000
to 10,000. After executing the ninth subtable, the final result
will be a billion laughs, but this will take a very long time (and
large amounts of memory) to compute. Your implementation should
neither crash nor hang under attack. See also
fontkit bug 174.
Expected
Shouldn’t crash
Conformance
✖
MORX-35: Insertion with DontAdvance
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Glyph Insertion Subtable. Its finite-state machine
contains two states (0 and 1) with the following transitions:
For glyph A
in state 0, the machine moves to state 1 while inserting
C after the current position.
This transition carries the DontAdvance flag.
in state 1, the machine moves to state 0 while inserting
B after the current position.
This transition carries no flags.
For glyphs B and C, the machine stays
in its current state while inserting E to the right of
the current position. This transition carries no flags.
For any other glyphs and “end of text”, the machine performs
no action.
The font for this test case has
an AAT Extended Glyph Metamorphosis Table
with a single Glyph Insertion Subtable. Its finite-state machine
contains three states (0, 1 and 2) with the following transitions:
In state 0, the machine moves to state 1 for any glyph in
{A, B, C, D} while inserting B after
the current position. This transition carries the
DontAdvance flag.
In state 1, the machine moves to state 2 for any glyph in
{A, B, C, D} while inserting C after
the current position. This transition carries the
DontAdvance flag.
In state 2, the machine moves to state 0 for any glyph in
{A, B, C, D} while inserting D after
the current position. This transition carries the
DontAdvance flag.
Otherwise, the machine performs no action.
The input string for this test case is A.
Your implementation should not hang (run without time limit)
nor crash while rendering this input, even though the font is
trying to trick the rendering engine into an infinite loop.
Expected
Shouldn’t crash
Conformance
✖
MORX-37: Processing in Layout/Physical Order
The font for this test case
has
an AAT Extended Glyph Metamorphosis Table
with a single Contextual Glyph Substitution Subtable.
Bits 28 and 30 of that subtable’s Coverage Flags
request processing in Layout (= physical) order,
which is always left-to-right. The subtable’s finite-state machine
contains two states (0 and 1) with the following transitions:
For glyphs A and א:
in state 0, the machine moves to state 1 while marking
the current glyph using the transitions’s SetMark flag;
in state 1, the machine moves to state 0 without further
action.
For glyphs B and ב:
in state 0, the machine stays in state 0 without further action;
in state 1, the machine replaces both the marked and the current
glyph by circled forms; then, it moves back to state 0.
For any other glyphs and “end of text”, the machine
performs no action.
Thus, if the tested rendering engine first processes A or
א, the result will be displayed in circled letters. If the tested
rendering engine first processes B or ב, the result will be
displayed in normal letters. If your rendering is correctly implemented,
the observed output should look as expected.
AB
BA
אב
בא
Expected
Observed
Conformance
✓
✓
✓
✓
MORX-38: Processing in Logical Order
The font for this test case
is similar to MORX-37, but
bits 28 and 30 of the subtable’s Coverage Flags
request processing in Logical Order.
AB
BA
אב
בא
Expected
Observed
Conformance
✓
✓
✖
✖
MORX-39: Processing in Reverse Layout/Physical Order
The font for this test case
is similar to MORX-37, but
bits 28 and 30 of the subtable’s Coverage Flags
request processing in Reverse Layout/Physical Order.
AB
BA
אב
בא
Expected
Observed
Conformance
✓
✓
✓
✓
MORX-40: Processing in Reverse Logical Order
The font for this test case
is similar to MORX-37, but
bits 28 and 30 of the subtable’s Coverage Flags
request processing in Reverse Logical Order.
AB
BA
אב
בא
Expected
Observed
Conformance
✓
✓
✖
✖
MORX-41: Ligature Substitution Under-/Overflow
The font for this test
case has
an AAT Extended Glyph Metamorphosis Table with a
single Ligature Subtable whose finite-state machine has one
single state. For glyphs a and b, the transition
marks the current glyph. For glyph c, the transition also
marks the current glyph, and then it executes an action to substitue
the marked glyphs by a ligature. When rendering the
strings ac and bc, the implementation finds two
glyphs on its glyph stack, which should get replaced by the
corresponding ligature. When rendering the string cc,
the implementation is asked to pop two glyphs from a stack
that contains just one. When rendering abcc,
the stack will contain three glyphs when handling the
first c.
ac
bc
cc
abcc
Expected
No crash
No crash
Observed
⁓
⁓
Conformance
✓
✓
✖
✖
SFNT–1: OpenType with PostScript Outlines
The font for this test case,
contributed by Simon
Cozens, contains glyphs outlines in both CFF
and glyf format. Because
the Offset Table uses an sfntVersion of
0x4F54544F (‘OTTO’), your rendering engine should take the glyph
outlines from the CFF table. If you see CFF below
the characters A and B, your rendering engine
makes correct use of the sfntVersion field.
See also fontkit bug 214 and OpenType.js bug 419.
Expected
Observed
Conformance
✖
✖
SFNT–2: OpenType with TrueType Outlines
The font for this test case,
contributed by Simon
Cozens, contains glyphs outlines in both CFF
and glyf format. Because
the Offset Table uses an sfntVersion of 0x00010000, your
rendering engine should take the glyph outlines from
the glyf table. If you see glyf below the
characters A and B, your rendering engine makes
correct use of the sfntVersion field.
Expected
Observed
Conformance
✓
✓
SHARAN–1: Nasta‘līq
The font for this test case supports
the Nasta‘līq
script with letterforms for
the Urdu language.
Other than Naskh,
Nasta‘līq requires that letters get arranged both in the
horizontal and in the vertical direction. For text
rendering systems, this is difficult to implement. If your
implementation is correct, you should see the sample Urdu words
arranged along a slightly diagonal baseline.
A correct implementation should call
the Kannada
Shaping Engine when rendering Kannada text. The test cases are taken
from Noto bugs
760,
770,
and 793.
Some of these test cases have also been reported to Unicode, for
example in text rendering bugs
18,
21 and
22.
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
✓
✓
✓
✓
Expected
Observed
Conformance
✓
✓
✓
✓
✓
✓
SHKNDA–3: Kannada
Some versions of Apple’s CoreText library had a bug which caused
incorrect renderings of certain Kannada text. In Apple’s “Radar”
system, this has been reported as bugs 29311179, 30862517, and
30948070. See also
here and here.
These vowel combinations are taken from Revised proposal for
encoding the Lanna script in the BMP of the
UCS,ISO/IEC JTC1/SC2/WG2/N3207R, L2/07-007R (Everson, Hosken &
Constable). Changes have been rung on the initial consonants to
check for silly omissions. A hyphen in the pronunciation indicates a
syllable-final consonant that would be specifed by a subscript
consonant or following orthographic syllable.
Like in SHLANA-1 and SHLANA-2,
the following
Tai
Tham words have been taken from Revised proposal for
encoding the Lanna script in the BMP of the
UCS,ISO/IEC JTC1/SC2/WG2/N3207R, L2/07-007R (Everson, Hosken &
Constable). However, unlike above, L2/07-007R does not indicate a particular
sequence of Unicode codepoints for these words. As before, the
test font has been
contributed by
Richard Wordingham, whose
browser test page for Tai Tham rendering gives more
background for each test case.
The Tai
Tham codepoint U+1A58 TAI THAM SIGN MAI LANG KAI is challenging
due to its wide range of behaviours. It can behave as a spacing
final character (as in modern Tai Khün fonts) to a repha-like
character, the old-fashioned behaviour seen in Tai Khün, Thailand
and Laos. The MFL dictionary shows an intermediate behaviour, where
marks above the following base consonant cause it to be positioned
within the previous syllable. This is the style employed by the
test font, which has
been contributed by
Richard Wordingham and
whose
browser test page for Tai Tham rendering gives more
background.
These examples are taken from
ภาษาเมืองล้านนา,
ISBN 974-85472-0-5, pages 151 to 156. Some of these renderings are
unusual compared with the native tradition, and are included for
that reason. The position of RA HAAM is particularly noteworthy.
The pronuciations given are guesswork where Siamese practice and Lanna script orthography conflict.
Like above, the test font
and the test cases have been contributed by
Richard Wordingham
whose
browser test page for Tai Tham rendering discusses each case.
‘gas’ /kɛs/
‘tractor’ /tʰɛːk tʰɤː/
‘note’ /noːt/
‘protein’ /pʰoː tiːn/
‘fuse’ /fiu/
‘postage stamp’ /sa tɛːm/
‘to serve’ /sɤːp/
Expected
Observed
Conformance
✖
✖
✖
✖
✖
✓
✖
SHLANA–7: Tai Lü
The following
Tai Lü
words are taken from Veomany Khotsimeuang, A Lost Tradition:
The Lue of Sipsongpanna and the Written Language Reform, Hours
Thesis in Asian Studies (Chinese), Australian National University,
2001; chapter “Graphic Blends”, section “Complex Orthographic Rules”
(available
online). The test
font and the encoded test strings have been contributed by
Richard Wordingham
whose
browser test page for Tai Tham rendering gives more background.
‘all’ /taŋ laːi/
‘spell’ (magic) /kʰan tʰaː/
‘okay’ /kɔː diː/
‘to not come’ /bau maː/
‘to not come’ /bau ma:/
‘to not have’ /bau da:i/
‘How big an area?’ /tsak va:/
‘deceased’ /se: lɛu/
‘Really, is that true?’ /tɛː nɔː/
‘to look this way’ /lɛ maː/
Expected
Observed
Conformance
✖
✓
✖
✖
✓
✖
✖
✖
✖
✓
‘hair’ /keː saː/
‘to come and go’ /pai maː/
‘if’ /seː vaː/
‘time’ /veː laː/
‘physical body’ /tʰaː tuʔ/
‘in conclusion’ /tsălɛː/
‘because’ /pɔi vaː/
‘world’ /suŋ saːn/
Expected
Observed
Conformance
✖
✖
✖
✖
✖
✓
✖
✖
SHLANA–8: More Tai Lü
The following
Tai Lü
words are taken from from the MA thesis Development of Tai Lue
Scripts and Orthography by Apiradee Techasiriwan (อภิรดี
เตชะศิริวรรณ), which is
available online. The pronunciations given are Tai Lü.
As with the other Lanna tests, the font
and the encoded strings have been contributed by
Richard Wordingham
whose
browser test page for Tai Tham rendering gives more background.
The word typically meaning ‘and ... not’ or ‘and
... then’ may be written with a chained syllable, and this may
present challenges to renderers. The form of the letter representing
/b/ in a chained syllable presented an encoding challenge.
N3207R
proposed using the sequence ‹SAKOT, BA› for it, and using ‹SAKOT,
HIGH PA› for the subscript form corresponding to both BA (common)
and HIGH PA (extremely rare) in its rôle as a final (Thai sakot)
consonant. During the ISO process, a new character was introduced
instead for the special form, SIGN BA, and it is widely assumed that
‹SAKOT, BA› represents the usual subscript form corresponding to BA,
both as a sakot consonant and in the Pali /mp/ and /pp/ intervocalic
clusters.
When syllables are chained, shared vowel symbols are not
repeated. This leads to ambiguity as to which symbol is dropped.
All the spellings in the table below represent the same careful
pronuciation in Northern Thai, namely /kɔː bɔː/. The Tai Lü forms
are written with different marks and pronounced with different
vowels, but use the same two consonant forms in the stack.