OpenType GSUB Substitution Engine

سطح قدرات استبدال صور الحروف (v2.119.43 - v2.119.50)

 

Arabic Shaping  CFF / OpenType Subsetting

يتيح محرك OpenType GSUB (استبدال صور الحروف) داخل HotPDF للمستدعين الاستعلام عن وتشغيل ودمج كل نوع من استبدال صور الحروف الذي يعلنه خط OpenType - مثل الروابط، والبدائل الأسلوبية، والمتغيرات السياقية، وأشكال التشكيل العربية / الهندية، والأشكال البديلة CJK، وما إلى ذلك؛ ويتم تنفيذ كل نوع من أنواع LookupType 1 إلى 8 لـ OpenType GSUB وكشفه كسطح استعلام للقدرات فقط؛ ويقوم المستدعي بتوجيه إصدار النص ويقرر أي صورة حرف بديلة يكتبها إلى تدفق محتوى الصفحة

 

Public API

type

  TGSUBStringArray = array of AnsiString;

 

// LookupType 1 - Single Substitution (one glyph -> one glyph)

function GetSingleSubstituteGlyph(InputGID: Word; const FeatureTag: AnsiString): Word;

 

// LookupType 2 - Multiple Substitution (one glyph -> sequence of glyphs)

function GetMultipleSubstituteGlyphs(InputGID: Word; const FeatureTag: AnsiString;

  var OutGIDs: array of Word): Boolean;

 

// LookupType 3 - Alternate Substitution (one glyph -> one of N alternates)

function GetAlternateGlyphCount(InputGID: Word; const FeatureTag: AnsiString): Integer;

function GetAlternateGlyph(InputGID: Word; const FeatureTag: AnsiString;

// LookupType 4 - Ligature Substitution (N glyphs -> one ligature)

 

// LookupType 4 - Ligature Substitution (N glyphs -> one ligature)

function ApplyLigatureSubstitution(const InputGIDs: array of Word;

  StartIndex: Integer; const FeatureTag: AnsiString;

  out OutGID: Word; out ConsumedCount: Integer): Boolean;

 

// LookupType 5 + 6 - Contextual / Chained Contextual Substitution

function ApplyContextualSubst(const InputGIDs: array of Word;

  StartIndex: Integer; const FeatureTag: AnsiString;

  var OutGIDs: array of Word;

  out ConsumedLen: Integer): Boolean;

 

// LookupType 8 - Reverse Chained Contextual Single Substitution

function ApplyReverseChainedContextualSubst(const InputGIDs: array of Word;

  StartIndex: Integer; const FeatureTag: AnsiString;

  out OutGID: Word): Boolean;

 

// Script / LangSys selection (Phase 7)

procedure SetGSUBScript(const ScriptTag: AnsiString);

procedure SetGSUBLanguage(const LangTag: AnsiString);

function GetGSUBScripts: TGSUBStringArray;

function GetGSUBLanguages(const ScriptTag: AnsiString): TGSUBStringArray;

function GetGSUBFeatures(const ScriptTag, LangTag: AnsiString): TGSUBStringArray;

 

// TTF subsetter closure (Phase 9)

procedure MarkUnicodeGlyphUsed(GID: Word);

 

الوصف

ينشط المحرك بعد أن يقوم RegisterUnicodeTTF بتحليل خط وتخزين جداول GSUB / GDEF / cmap tables الخاصة به مؤقتًا؛ وتتتبع كل عملية استعلام استبدال سلسلة ScriptList / LangSysList / FeatureList / LookupList الخاصة بالخط وتوجهها إلى معالج LookupType المناسب؛ والأساليب الـ 12 المذكورة أعلاه هي السطح العام الكامل؛ وكل شيء آخر (تتبع cmap، وتحليل ScriptList، والبحث في جدول التغطية، وحل ClassDef، واحترام LookupFlag، وفك غلاف الملحق، والتوجيه المتداخل لـ SequenceLookupRecord) يعيش خلف هذا السطح

 

عقد دفاعي متكامل: الخطوط التي لا تحتوي على جدول GSUB، وعلامات الميزات غير المكونة من 4 بايتات، والميزات التي لا يعلن عنها النص / اللغة المحددة، ومعرفات GIDs التي لا يغطيها أي جدول فرعي، وصور الحروف المدخلة المتجاهلة بواسطة LookupFlag ترجع جميعها عملية فارغة آمنة (False / OutGID = InputGID / و OutGIDs فارغة / و ConsumedCount = 1) بحيث لا يرى المستدعون أبدًا استثناءات لحالات "لا يوجد استبدال ينطبق" الروتينية

 

مصفوفة LookupType

LookupType 1 (استبدال فردي) - صورة حرف واحدة تعين إلى بديل واحد؛ الميزات القياسية: salt، و ss01-ss20، و smcp، و onum، و liga عندما يتم ربط LookupType 1، بالإضافة إلى الأشكال الموضعية العربية init / medi / fina / isol في الخطوط التي تقودها عبر GSUB؛ واستخدم GetSingleSubstituteGlyph

LookupType 2 (استبدال متعدد) - تنقسم صورة حرف واحدة إلى متسلسلة من صور الحروف البديلة؛ المستخدم القياسي: ccmp لتركيب / تفكيك صور الحروف (تنقسم أحرف اللاتينية المشددة المركبة مسبقًا إلى علامات أساسية + علامات دمج لموضع العلامة اللاحق)؛ واستخدم GetMultipleSubstituteGlyphs

LookupType 3 (استبدال بديل) - تعين صورة حرف واحدة إلى واحد من بدائل N؛ الميزات القياسية: aalt (الوصول إلى جميع البدائل)، و salt عند ربطها كـ Type 3، و titl (بدائل العناوين)، ومجموعات الأسلوب ss01-ss20 stylistic sets عندما يقدم مصمم الخط أكثر من بديل واحد لكل فتحة؛ واستخدم GetAlternateGlyphCount + GetAlternateGlyph

LookupType 4 (استبدال الروابط) - تطوى N من صور الحروف المدخلة إلى رابط واحد؛ الميزات القياسية: liga (الروابط القياسية: fi / fl / ffi / ffl)، و clig (الروابط السياقية)، و dlig (الروابط التقديرية)، و hlig (الروابط التاريخية)، و rlig (الروابط المطلوبة - لام ألف العربية وما شابه)، وروابط النصوص الهندية (akhn، و pres، و blws، و psts)؛ واستخدم ApplyLigatureSubstitution

LookupType 5 (استبدال سياقي) + LookupType 6 (استبدال سياقي متسلسل) - يطابق متسلسلة صور حروف مدخلة ويوجه عمليات البحث المتداخلة عند مواضع محددة داخل التطابق؛ ويتم تنفيذ جميع متغيرات التنسيق الثلاثة (1 متسلسلة حرفية، 2 متسلسلة ClassDef، 3 متسلسلة تغطية)؛ ويعيد موجه SequenceLookupRecord الدخول إلى LookupList ويتعامل مع عمليات البحث المتداخلة Single / Multiple / Alternate (الأولى) / Ligature مع تتبع MatchPositions المباشر؛ الميزات القياسية: rclt (البدائل السياقية المطلوبة - الأشكال العربية init/medi/fina/isol عندما تقودها GSUB)، و clig، و calt، وتشكيل Indic pres / blws / psts / half / pstf / cjct؛ واستخدم ApplyContextualSubst (تغطي نقطة دخول واحدة كلاً من LookupType 5 و 6)

LookupType 7 (استبدال ممتد) - طبقة غير مباشرة بحتة يحددها مواصفات OpenType للخطوط التي تعيش جداول استبدالها الفرعية خارج نطاق 16 بت لـ LookupList؛ وتتبع كل واجهة برمجة تطبيقات عامة بشفافية الإشارة غير المباشرة Offset32 ذات الـ 32 بت إلى جدول LookupType 1 / 2 / 3 / 4 / 5 / 6 / 8 الفرعي الحقيقي؛ ويفك العوائق لخطوط CJK / الهندية الثقيلة (Noto Sans CJK، و Noto Sans Devanagari) التي يتجاوز GSUB الخاص بها 64 كيلوبايت؛ ولا توجد واجهة برمجة تطبيقات منفصلة - حيث يتم فك الغلاف تلقائيًا

LookupType 8 (استبدال فردي سياقي متسلسل عكسي) - استبدال 1:1 مدرك للسياق، ميزته المميزة هي أنه يجب على المستدعين تطبيقه بترتيب فحص عكسي على تشغيل متعدد صور الحروف (من النهاية إلى البداية) لأن كل بديل قد يعتمد على سياق تطلع مستقبلي يجب ألا يتم استبداله بعد؛ الاستخدام القياسي: البدائل السياقية العربية / السريانية / إنكو / الهندية التي يعتمد شكلها النهائي على صورة الحرف التالية؛ واستخدم ApplyReverseChainedContextualSubst؛ حيث يقود المستدعي حلقة الفحص العكسي

 

تحديد Script / LangSys

افتراضيًا، يفضل المحرك نص DFLT (أو النص الأول الذي يعلنه الخط) و LangSys الافتراضي؛ واستدعي SetGSUBScript('latn' / 'arab' / 'cyrl' / 'hani' / 'kana' / 'deva' / 'beng' / 'taml' / إلخ) و SetGSUBLanguage('ENG ' / 'TUR ' / 'AZE ' / 'JAN ' / 'KOR ' / 'ARA ' / إلخ، مع استكمال المسافات الزائدة إلى 4 بايتات) لتثبيت الاستعلامات إلى زوج نص / لغة محدد؛ وترجع السلسلة الفارغة خط الأساس للمسار الافتراضي؛ وتستمر التحديدات عبر الاستعلامات ويتم مسحها عند RegisterUnicodeTTF('', nil)

 

دلالات صارمة مقابل احتياطية: يؤدي ScriptTag غير المعروف إلى جعل الاستعلامات اللاحقة ترجع نتائج فارغة بلا عملية (بحيث يمكن للمستدعين الكشف عن أن نصهم المختار غير متاح)؛ و LangTag غير المعروف يتراجع إلى LangSys الافتراضي للنص وفقًا لاتفاقية OpenType؛ وتقوم GetGSUBScripts / GetGSUBLanguages / GetGSUBFeatures بسرد ما يعلنه الخط المحمل بالفعل

 

احترام LookupFlag و GDEF

يقرأ كل query قيمة LookupFlag في كل Lookup table، إضافة إلى markFilteringSet uint16 اللاحق الاختياري عند ضبط useMarkFilteringSet، ويتجاوز glyphs التي تشير flags إلى تجاهلها. تحترم bits المعرفة في المواصفة، وتقرأ ClassDef Format 1 و2، وتقبل رؤوس GDEF v1.0 / v1.1 / v1.2. الخطوط التي لا تحتوي جدول GDEF تعود إلى سلوك لا يتجاهل أي glyph حتى يبقى الإخراج مطابقًا للمستدعين الذين يستخدمون خطوطًا بلا GDEF

 

إغلاق مخصص مخرجات TTF (MarkUnicodeGlyphUsed)

يشتق مخصص مخرجات TTF للإصدار v2.84.0 لـ HotPDF مجموعة صور الحروف المستخدمة من FUnicodeUsedCps من خلال cmap؛ وعادةً لا تحتوي صور حروف بدائل GSUB (البدائل الأسلوبية، والروابط، والمتغيرات السياقية - كل ما ترجعه واجهات برمجة تطبيقات الاستعلام السبعة المذكورة أعلاه) على نقطة ترميز تصل إليها عبر cmap، لذا كانت غير مرئية سابقًا لمخصص المخرجات وكان القارئ المستهلك يقدم .notdef في مكانها

 

بعد إصدار أي معرف GID ترجعه GetSingleSubstituteGlyph / GetMultipleSubstituteGlyphs / GetAlternateGlyph / ApplyLigatureSubstitution / ApplyContextualSubst / ApplyReverseChainedContextualSubst في تدفق نص PDF، استدعي MarkUnicodeGlyphUsed(GID) مرة واحدة لكل GID تم إصداره لسحبه إلى المجموعة الفرعية المدمجة؛ والمساعد متطابق القيمة، ودفاعي (يتم إسقاط معرفات GIDs الخارجة عن النطاق بصمت)، ويتكامل مع ممر إغلاق صور الحروف المركبة للإصدار v2.84.0: يحتاج المستدعون فقط إلى وضع علامة على معرف GID البديل للمستوى الأعلى - ويتم سحب المكونات المركبة تلقائيًا

 

سير العمل النموذجي (الحروف اللاتينية الصغيرة)

 

PDF.RegisterUnicodeTTF('myFont', 'C:\\Windows\\Fonts\\arial.ttf');

PDF.SetGSUBScript('latn');

PDF.SetGSUBLanguage('');  // default LangSys

SmallCapGID := PDF.GetSingleSubstituteGlyph(InputGID, 'smcp');

// emit SmallCapGID into the page content stream...

begin

  // emit SmallCapGID into the page content stream...

  PDF.MarkUnicodeGlyphUsed(SmallCapGID);  // pull into subset

end;

 

سير العمل النموذجي (رابطة لام ألف العربية)

 

PDF.SetGSUBScript('arab');

// post-cmap GIDs// post-cmap GIDs

if PDF.ApplyLigatureSubstitution(Run, 0, 'rlig', LigGID, ConsumedCount) then

begin

  // emit LigGID + advance by ConsumedCount

  PDF.MarkUnicodeGlyphUsed(LigGID);

end;

 

النطاق والقيود

المحرك سطح query للقدرات فقط: يجيب عما يمكن أن يفعله GSUB هنا، لكنه لا يشغل pipeline shaping تلقائيًا مثل Harfbuzz. يتحمل المستدعون قيادة scan loop، واختيار البديل المطلوب، واستدعاء MarkUnicodeGlyphUsed لكل substitute GID صادر، وتطبيق أي GPOS أو mark positioning يتطلبه الخط

 

يتم تنفيذ تشكيل العربية / الفارسية / الأردية على جانب المنتج (رابطة لام ألف الإلزامية + أشكال عرض العربية-A) كخط معالجة مدمج منفصل يعمل تلقائيًا أثناء إصدار النص - انظر التشكيل العربي / الفارسي / الأردي

 

تتبع الإصدارات

v2.119.43 استبدال فردي + المرحلة 1؛ v2.119.44 متعدد + بديل (المرحلة 2)؛ v2.119.45 رابطة (المرحلة 3)؛ v2.119.46 امتداد + GDEF + احترام LookupFlag (المرحلة 4)؛ v2.119.47 سياقي + سياقي متسلسل + موجه SequenceLookupRecord (المرحلة 5)؛ v2.119.48 سياقي متسلسل عكسي - إغلاق مصفوفة LookupType 1-8 (المرحلة 6)؛ v2.119.49 واجهة برمجة تطبيقات تحديد Script / LangSys (المرحلة 7)؛ v2.119.50 إغلاق مخصص مخرجات TTF عبر MarkUnicodeGlyphUsed (المرحلة 9؛ وكانت المرحلة 8 عبارة عن زيادة في تكامل التشكيل على جانب المنتج وانقسمت إلى 8a-8f للمراجعات المستقبلية)

 

انظر أيضًا: Arabic / Persian / Urdu Shaping، CFF / OpenType Font Subsetting Functions، THotPDF.EnableFontSubsetting