Unterschneidung

Informationen über Unterschneidung finden sich beim Schriftfeaturesystem in einem „GPOS“ Block. Dieser Block kann noch andere Informationen zur Zeichenplatzierung enthalten. Die Strukturen sind darum allgemeiner ausgerichtet, als dies im „kern“ Block der Fall ist.

der Blockheader

Der „GPOS“ Block beginnt immer mit folgenden Angaben:

PositionGrösseTyp Inhalt
04 Byteuint32Version
42 Byteuint16Position Schrift/Sprachtabelle
62 Byteuint16Position Featuretabelle
82 Byteuint16Position Lookuptabelle

Damit lassen sich mit dem unter Das Schriftfeaturesystem erwähnten Verfahren die Position des Unterblocks bzw. der Unterblöcke ermitteln. Die gesuchte Feature-ID ist dabei „kern“.

Der Inhalt der Unterblocks hängt von der Typnummer im Lookupeintrag ab. Für „kern“ sind die Nummern 2, 8 und 9 erlaubt.

2 steht für normale Unterschneidung.

8 steht für kontextabhängige Unterschneidung. Das ist eine recht komplexe und selten gebrauchte Art der Unterschneidung, bei der die Buchstaben vor und nach dem Buchstabenpaar eine Rolle spielen. Ich gehe hier nicht darauf ein.

9 ist ein Spezialfall. Dieser Unterblock wird verwendet, wenn der uint16 im Lookupeintrag nicht ausreicht, um die eigentliche Position des Unterblocks abzubilden (bei grossen „GPOS“ Blöcken).

Typ 9

Dieser Unterblock verweist lediglich auf den eigentlichen Unterblock. Er ist folgendermassen aufgebaut:

PositionGrösseTyp Inhalt
02 Byteuint16Version
22 Byteuint16Typ
44 Byteuint32Position

Die Position ist ab dem Anfang des Unterblocks gerechnet.

Typ 2

Dieser Unterblock enthält die Unterschneidungsinformationen. Dabei ist er flexibler als der „kern“ Block (zumindest flexibler als der allgemein unterstützte Minimalstandard des „kern“ Blocks).

Zum einen unterstützt er neben der normalen Unterschneidung auf Basis von Zeichenpaaren auch solche auf Basis von Zeichenklassenpaaren. Dabei werden die Zeichen in Zeichenklassen eingeteilt, und dann Unterschneidungswerte festgelegt für Kombinationen von bestimmten Zeichenklassen. Dieser Wert gilt dann für alle Kombinationen eines Zeichens aus der linken Klasse mit einem Zeichen aus der rechten Klasse. Auf diese Weise lässt sich Unterschneidung für grosse Zeichensätze definieren, wo die Kombinationsm??glichkeiten sonst schnell in die Milliarden gehen würden.

Zum anderen ist es möglich, mehrere Unterblocks zu definieren. Die Werte der Unterblocks wirken dabei kumulativ. Das heisst, falls sich für ein Zeichenpaar in mehreren Unterblocks Unterschneidungswerte ergeben, so müssen diese addiert werden. Dies wird vor allem in Zusammenhang mit Zeichenklassen verwendet.

Je nachdem, ob die Unterschneidung auf Zeichenpaaren oder Zeichenklassenpaaren basiert, wird mit einem anderen Format gearbeitet. Die Formatnummer ist in einem uint16 am Anfang des Unterblocks festgehalten.

Format 1

Dieses Format kommt für einfache Unterschneidung auf Basis von Zeichenpaaren zur Anwendung. Der Unterblock beginnt folgendermassen:

PositionGrösseTyp Inhalt
02 Byteuint16Format (immer 1)
22 Byteuint16Position Zeichenliste
42 Byteuint16Werteformat 1
62 Byteuint16Werteformat 2
82 Byteuint16Anzahl Paarlisten

Die Zeichenliste enthält eine Liste der möglichen Zeichen links. Die Position ist ab dem Beginn des Unterblocks gerechnet.

Die beiden Einträge für das Werteformat bestimmen, wie die Werteeinträge aufgebaut sind. Für klassische Unterschneidung muss das Werteformat 1 auf 4 oder 68 stehen, das Werteformat 2 auf 0. Steht etwas anderes, haben wir es wahrscheinlich mit komplexer Unterschneidung zu tun, welche Vertikalversatz enthält. Ähnlich wie bei kontextabhängiger Unterschneidung ist auch dies selten gebraucht und mühsam umzusetzen, weshalb ich nicht darauf eingehe.

Nun kommen wir zu den Paarlisten. Für jedes mögliche Zeichen links gibt es eine Paarliste, welche die dazu passenden möglichen Zeichen rechts und den jeweiligen Unterschneidungswert enthält. Das heisst, die Anzahl Paarlisten sollte identisch sein mit der Anzahl Zeichen in der Zeichenliste.

Auf die erwähnten Angaben folgt zunächst für jeder Paarliste folgender Eintrag:

PositionGrösseTyp Inhalt
02 Byteuint16Position Paarliste

Die Position ist jeweils ab dem Anfang des Unterblocks gerechnet. An der Position findet sich dann die eigentliche Liste. Sie beginnt folgendermassen:

PositionGrösseTyp Inhalt
02 Byteuint16Anzahl Einträge

Daraufhin folgen die Einträge. Ist das Werteformat 1 auf 4 gesetzt, sehen sie folgendermassen aus:

PositionGrösseTyp Inhalt
02 Byteuint16GID rechts
22 Byteint16 Unterschneidung

Ist das Werteformat 1 auf 68 gesetzt, sehen die Einträge so aus:

PositionGrösseTyp Inhalt
02 Byteuint16GID rechts
22 Byteint16 Unterschneidung
42 Byteuint16Position Hintingtabelle

Die Unterschneidung muss, wie im „kern“ Block, in Promille der Schriftgrösse umgerechnet, und negiert werden, damit die Zahl für den Einsatz in PDF brauchbar ist.

Die Hintingtabelle ist für dein Einsatz in PDF uninteressant. Wir müssen den Eintrag aber natürlich überlesen.

Wie man sieht, ist die GID links nicht explizit aufgeführt. Sie ergibt sich aus der Zeichenliste. Die erste Paarliste deckt das erste Zeichen der Zeichenliste ab, die zweite Paarliste das zweite Zeichen der Zeichenliste, und so weiter.

Format 2

Dieses Format kommt für Unterschneidung auf der Basis von Zeichenklassen zur Anwendung. Es ist folglich ein klein wenig komplexer. Der Unterblock beginnt folgendermassen:

PositionGrösseTyp Inhalt
02 Byteuint16Format (immer 2)
22 Byteuint16Position Zeichenliste
42 Byteuint16Werteformat 1
62 Byteuint16Werteformat 2
82 Byteuint16Position Klassendefinition links
102 Byteuint16Position Klassendefinition rechts
122 Byteuint16Anzahl Klassen links
142 Byteuint16Anzahl Klassen rechts

Für die Zeichenliste und die Werteformate gilt hier grundsätzlich das gleiche, wie im Format 1. Allerdings benötigen wir die Zeichenliste nicht, da die Einträge hier nicht danach geordnet sind.

Die Positionen der Klassendefinitionen sind ab dem Beginn des Unterblocks gerechnet. Ähnlich wie bei den Zeichenlisten gibt es auch bei der Klassendefinition zwei Formate, die sich anhand eines uint16 am Anfang unterscheiden lassen:

Klassendefinition Format 1

Dieses Format beginnt folgendermassen:

PositionGrösseTyp Inhalt
02 Byteuint16Format (immer 1)
22 Byteuint16erste GID
42 Byteuint16Anzahl GIDs

Danach folgt für jede GID ein Eintrag:

PositionGrösseTyp Inhalt
02 Byteuint16Klassennummer

Der erste Eintrag steht dabei für die „erste GID“, der nächste für die erste GID plus 1, und so weiter. Alle nicht aufgeführten GIDs sind in der Klasse 0.

Klassendefinition Format 2

Dieses Format beginnt folgendermassen:

PositionGrösseTyp Inhalt
02 Byteuint16Format (immer 2)
22 Byteuint16Anzahl GID-Bereiche

Danach folgt für jeden GID-Bereich ein Eintrag:

PositionGrösseTyp Inhalt
02 Byteuint16erste GID
22 Byteuint16letzte GID
42 Byteuint16Klassennummer

Alle GIDs von der ersten bis und mit der letzten GID werden dabei der jeweiligen Klassennummer zugeteilt. Die Bereiche dürfen sich dabei nicht überschneiden (ein Zeichen ist immer in genau einer Klasse). Alle GIDs, die in keinem der aufgeführten Bereiche sind, werden der Klasse 0 zugeteilt.

die Unterschneidungstabelle

Nachdem wir nun wissen, welche Zeichen in welcher Klasse sind, können wir die Klassenpaare auslesen. Die „Anzahl Klassen links“ und „Anzahl Klassen rechts“ vom Anfang des Blocks sollte dabei mit der jeweiligen Anzahl definierter Klassen übereinstimmen (einschliesslich der Klasse 0).

Die Tabelle beginnt direkt nach den Angaben am Beginn des Unterblocks (also an Position 16 des Unterblocks). Dabei hat es nacheinander einen Eintrag für jede mögliche Kombination der Klassen links und rechts in folgender Reihenfolge: Zunächst je ein Eintrag für die Kombination der Klasse 0 links mit jeder der Klassen rechts von 0 an aufsteigend. Dann je ein Eintrag für die Klasse 1 links mit jeder der Klassen rechts, und so weiter.

Die Einträge sind wiederum vom Werteformat 1 abhängig. Bei Format 4 sehen sie folgendermassen aus:

PositionGrösseTyp Inhalt
02 Byteint16Unterschneidung

Bei Format 68 folgendermassen:

PositionGrösseTyp Inhalt
02 Byteint16 Unterschneidung
22 Byteuint16Position Hintingtabelle

Auch hier muss die Unterschneidung in Promille der Schriftgrösse umgerechnet sowie negiert werden, und auch hier können wir die Hintingtabelle ignorieren.