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 เป็นคู่ตรงข้ามของ backend Uniscribe ใน FPdfTextShaping สำหรับเป้าหมายที่ไม่มี usp10.dll อินเทอร์เฟซถูกคอมไพล์ภายใต้ Free Pascal เท่านั้น เพราะ Delphi รันบน Windows ซึ่งใช้ backend Uniscribe
สอง backend แบ่งงานกันไม่เหมือนกัน Uniscribe แยกชิ้น จัดรูป วางตำแหน่ง และจัดลำดับใหม่ในรอบเดียว ส่วน HarfBuzz จัดรูป run เดียวที่ทิศทางและสคริปต์รู้แล้ว ยูนิตนี้จัดหาส่วนที่เหลือ: FPdfBidi หา embedding level, สคริปต์ Unicode ของอักขระแต่ละตัวแบ่งข้อความเป็น run และ run ทั้งหมดถูกวางตามลำดับการแสดงผลที่กฎ L2 ของ UAX #9 กำหนด อักขระสคริปต์แบบ Common, inherited และไม่รู้จักจะรวมอยู่กับ run ที่ตนอยู่ ตัวเลขหรือช่องว่างจึงไม่ตัดคำ
libharfbuzz ถูกผูกตอนรันไทม์ผ่าน DynLibs จึงไม่ใช่ build dependency และเมื่อหายไปจะรายงานแทนที่จะพัง HarfBuzzAvailable รายงานว่าเจอไลบรารีและหา entry point ที่จำเป็นครบหรือไม่ และ HarfBuzzVersionString คืนเวอร์ชันของไลบรารีที่โหลด
ตัว shaper ไม่ค้นหาฟอนต์เอง Uniscribe อ่านไบนารีฟอนต์ออกจาก GDI device context ซึ่งไม่มีสิ่งที่เทียบเท่าแบบพกพาได้ โฮสต์จึงส่ง TPdfFontDataResolver ให้ Create เพื่อแมปชื่อฟอนต์ไปยังไบต์ TrueType หรือ OpenType วิธีนี้ทำให้การสำรวจฟอนต์ - fontconfig, CoreText หรือโฟลเดอร์ฟอนต์ของแอปเอง - อยู่นอกยูนิตที่ไม่ควรมีสิทธิ์กำหนดนโยบายนี้
| Function | Description |
|---|---|
HarfBuzzAvailable | เป็น True เมื่อเจอ libharfbuzz และหา entry point ที่จำเป็นได้ครบ การเรียกครั้งแรกจะทำการผูก |
HarfBuzzVersionString | เวอร์ชันของไลบรารีที่โหลดในรูป "major.minor.micro" หรือสตริงว่างเมื่อไม่มีไลบรารี |
| Type | Description |
|---|---|
TPdfFontDataResolver | method reference ที่แมป FontName ไปยังไบต์ไฟล์ฟอนต์ใน FontData การคืน False ทำให้ shaper ล้มเหลวคำขอนั้นเหมือนกับที่ฟอนต์ GDI ที่อ่านไม่ได้ทำบน Windows |
EPdfHarfBuzzError | ข้อยกเว้นที่เกิดเมื่อไม่ได้ตั้ง resolver, libharfbuzz ไม่พร้อมใช้ หรือสร้าง blob, face, font หรือบัฟเฟอร์ของ HarfBuzz ไม่สำเร็จ |
TPdfHarfBuzzTextShaper | การ implement TPdfTextShaper ที่อยู่บนพื้นฐาน HarfBuzz พร้อม Create, Destroy และ Shape |
| Member | Description |
|---|---|
Create(Resolver) | สร้าง shaper และเก็บ TPdfFontDataResolver ที่จะใช้ค้นฟอนต์ทุกครั้ง |
Destroy | ปล่อย face และ blob ของ HarfBuzz ที่ cache ไว้ แล้วตามด้วย destructor ที่สืบทอดมา |
Shape(Text, FontName, FontSize, Options, Shaped) | หา embedding level แบ่งข้อความตามระดับและสคริปต์ จัดรูปแต่ละ run ผ่าน HarfBuzz แล้วคืน run เรียงตามลำดับการแสดงผลใน Shaped คืน False เมื่อข้อความไม่ให้ glyph ใด |
HarfBuzzAvailable ครั้งแรกจะลอง libharfbuzz-0.dll และ harfbuzz.dll บน Windows, libharfbuzz.0.dylib และ libharfbuzz.dylib บน macOS และ libharfbuzz.so.0 กับ libharfbuzz.so บนแพลตฟอร์มอื่นShape raise EPdfTextShapingError เมื่อข้อความว่าง ชื่อฟอนต์ว่าง ขนาดฟอนต์ไม่เป็นบวก ค่าจำกัดของ Options ไม่ถูกต้อง ข้อความเกิน MaxCharacters, glyph เกิน MaxGlyphs หรือข้อมูลฟอนต์ที่ resolver หาให้ไม่ได้Shape raise EPdfHarfBuzzError เมื่อไม่ได้ตั้ง TPdfFontDataResolver, libharfbuzz ไม่พร้อมใช้ หรือสร้างวัตถุ HarfBuzz ไม่สำเร็จOptions.MaxRuns และ Options.Direction แมป ptdLeftToRight กับ ptdRightToLeft เป็นทิศทางย่อหน้าคงที่ นอกนั้นหาค่าอัตโนมัติShaped.FontData เก็บไบต์ที่ resolver คืนมา ซึ่ง TPdf.AddShapedText ต้องใช้สร้างฟอนต์ CID