TPdfFontDataResolver = function(const FontName: WideString;
out FontData: TBytes): Boolean of object;
EPdfHarfBuzzError = class(Exception);
TPdfHarfBuzzTextShaper = class(TPdfTextShaper)
constructor Create(const Resolver: TPdfFontDataResolver);
destructor Destroy; override;
function Shape(const Text, FontName: WideString; FontSize: Single;
const Options: TPdfTextShapingOptions;
out Shaped: TPdfShapedText): Boolean; override;
end;
function HarfBuzzAvailable: Boolean;
function HarfBuzzVersionString: string;
FPdfTextShapingHb ist das Gegenstück zum Uniscribe-Backend in FPdfTextShaping für Ziele ohne usp10.dll. Die Schnittstelle wird nur unter Free Pascal kompiliert, denn Delphi zielt auf Windows ab, wo das Uniscribe-Backend gilt
Die beiden Backends teilen die Arbeit unterschiedlich auf. Uniscribe itemisiert, shaped, platziert und ordnet in einem Durchlauf, während HarfBuzz einen einzelnen Run shaped, dessen Richtung und Skript bereits bekannt sind. Diese Unit liefert den Rest: FPdfBidi löst die Einbettungsebenen auf, das Unicode-Skript jedes Zeichens segmentiert den Text in Runs, und die Runs werden in der visuellen Reihenfolge angeordnet, die UAX #9 Regel L2 vorgibt. Zeichen mit dem Skript Common, Inherited oder Unknown setzen den Run fort, in dem sie stehen, sodass eine Ziffer oder ein Leerzeichen kein Wort zerschneidet
libharfbuzz wird zur Laufzeit über DynLibs gebunden, ist also keine Build-Abhängigkeit, und sein Fehlen wird gemeldet, statt fatal zu enden. HarfBuzzAvailable meldet, ob die Bibliothek gefunden wurde und die erforderlichen Einstiegspunkte aufgelöst sind, und HarfBuzzVersionString gibt die Version der geladenen Bibliothek zurück
Der Shaper sucht selbst keine Schriften. Uniscribe liest die Schriftbinärdaten aus einem GDI-Device-Kontext, wofür es kein portables Äquivalent gibt, daher übergibt der Host Create einen TPdfFontDataResolver, der einen Schriftnamen auf die TrueType- oder OpenType-Bytes abbildet. So bleibt die Schriftenummerierung - fontconfig, CoreText oder ein eigener Schriftordner der Anwendung - außerhalb einer Unit, die diese Entscheidung nichts angeht
| Funktion | Beschreibung |
|---|---|
HarfBuzzAvailable | True, wenn libharfbuzz gefunden wurde und die erforderlichen Einstiegspunkte aufgelöst sind; der erste Aufruf führt die Bindung durch |
HarfBuzzVersionString | Version der geladenen Bibliothek als "major.minor.micro", oder ein leerer String, wenn die Bibliothek nicht verfügbar ist |
| Typ | Beschreibung |
|---|---|
TPdfFontDataResolver | Methodenreferenz, die FontName auf die Schriftdatei-Bytes in FontData abbildet; die Rückgabe False lässt den Shaper die Anforderung genauso scheitern wie eine unlesbare GDI-Schrift unter Windows |
EPdfHarfBuzzError | Exception, die ausgelöst wird, wenn kein Resolver konfiguriert ist, libharfbuzz nicht verfügbar ist oder ein HarfBuzz-Blob, Face, Font oder Buffer sich nicht anlegen lässt |
TPdfHarfBuzzTextShaper | TPdfTextShaper-Implementierung auf HarfBuzz-Basis, mit Create, Destroy und Shape |
| Member | Beschreibung |
|---|---|
Create(Resolver) | Erzeugt den Shaper und speichert den TPdfFontDataResolver, den er für jede Schriftsuche verwendet |
Destroy | Gibt das zwischengespeicherte HarfBuzz-Face und -Blob frei, danach den geerbten Destruktor |
Shape(Text, FontName, FontSize, Options, Shaped) | Löst die Einbettungsebenen auf, segmentiert den Text nach Ebene und Skript, shaped jeden Run durch HarfBuzz und liefert die Runs in visueller Reihenfolge in Shaped; False, wenn der Text keine Glyphen erzeugt |
HarfBuzzAvailable-Aufruf probiert unter Windows libharfbuzz-0.dll und harfbuzz.dll, unter macOS libharfbuzz.0.dylib und libharfbuzz.dylib und sonst libharfbuzz.so.0 und libharfbuzz.soShape löst EPdfTextShapingError aus bei leerem Text, leerem Schriftnamen, nicht positiver Schriftgröße, ungültigen Options-Grenzen, Text über MaxCharacters, Glyphen über MaxGlyphs oder Schriftdaten, die der Resolver nicht liefern konnteShape löst EPdfHarfBuzzError aus, wenn kein TPdfFontDataResolver konfiguriert ist, libharfbuzz nicht verfügbar ist oder sich ein HarfBuzz-Objekt nicht anlegen lässtOptions.MaxRuns begrenzt, und Options.Direction bildet ptdLeftToRight und ptdRightToLeft auf eine feste Absatzrichtung ab, alles andere wird automatisch aufgelöstShaped.FontData enthält die Bytes, die der Resolver geliefert hat - genau das, was TPdf.AddShapedText braucht, um einen CID-Font zu bauen