پشتیبانی شکل‌دهی عربی / فارسی / اردو

خط لولهٔ شکل‌دهی سمت تولیدکننده (v2.85.0 - v2.119.68)

 

موتور OpenType GSUB  CFF / زیرمجموعه‌سازی OpenType

HotPDF یک خط لوله شکل‌دهی سمت تولیدکننده اجرا می‌کند که runهای عربی، فارسی و اردو با ورودی Unicode را هنگام تولید متن PDF به Arabic Presentation Forms خودشان تبدیل می‌کند، تا readerهای مصرف‌کننده glyphهای موقعیتی / لیگاچری آماده رندر دریافت کنند و نیازی به shaper هم‌رده Harfbuzz نداشته باشند

 

آنچه این خط لوله انجام می‌دهد

شکل‌دهی موقعیتی (v2.85.0): هر حرف پایه عربی تا چهار form موقعیتی دارد - isolated (isol)، initial (init)، medial (medi) و final (fina). HotPDF کلاس اتصال هر نویسه عربی و کلاس اتصال همسایه‌های بلافصل آن را بررسی می‌کند، سپس codepoint ورودی را قبل از emission به glyph مناسب Arabic Presentation Forms-B (U+FE70 - U+FEFC) نگاشت می‌کند. نویسه‌های non-joining، joinerها، نویسه‌های transparent (combining markها) و Tatweel kashida همگی طبق Unicode Arabic Shaping algorithm مدیریت می‌شوند

 

لیگاتور اجباری LAM-ALEF (v2.119.32): مشخصات Arabic Unicode Shaping ایجاب می‌کند هر LAM (U+0644) که بلافاصله با یک ALEF دنبال شود (U+0627 ساده، U+0622 با madda بالا، U+0623 با hamza بالا، U+0625 با hamza پایین) به یک glyph لیگاچر واحد (U+FEFB - U+FEFC formهای isolated / final با variantهای مناسب hamza / madda) تبدیل شود. این یکی از معدود لیگاچرهای غیر‌اختیاری در تایپوگرافی عربی است و برای درستی خروجی لازم است؛ رندرکردن آن‌ها به صورت glyphهای جداگانه متنی تولید می‌کند که readerهای بومی بلافاصله آن را نادرست تشخیص می‌دهند. HotPDF این fold را هنگام emission انجام می‌دهد تا فراخواننده در مسیر خودش به shaper هم‌رده Harfbuzz نیاز نداشته باشد

 

9 حرف اصلی فارسی / اردو (v2.119.35): فارسی و اردو عربی را با نویسه‌هایی گسترش می‌دهند که در بلوک Arabic Presentation Forms-B (U+FE70 - U+FEFC) نیستند. 9 حرف پرکاربرد از این نوع - از جمله PEH (U+067E)، TCHEH (U+0686)، JEH (U+0698)، KEH (U+06A9 / U+06AF)، GAF (U+06AF)، NOON GHUNNA (U+06BA)، HEH DOACHASHMEE (U+06BE)، YEH BARREE (U+06D2) و HEH GOAL (U+06C1) - formهای نمایش در Arabic Presentation Forms-A (U+FB50 - U+FDFF) دارند. HotPDF اکنون این نویسه‌ها را هنگام شکل‌دهی موقعیتی به glyph مناسب Forms-A نگاشت می‌کند تا متن فارسی و اردو در هر reader مصرف‌کننده با formهای درست init / medi / fina / isol رندر شود

 

Arabic Extended-A + Supplement (v2.119.52, v2.119.56): جدول joining-class اکنون نویسه‌های باقی‌مانده Arabic Extended-A (ALEF WASLA / NOON GHUNNA / variantهای HEH)، Arabic Supplement U+0750-U+077F و بازه بالاتر Arabic Extended-A U+08A0-U+08FF را هم پوشش می‌دهد. نویسه‌هایی که encoding ایستا در Presentation Forms-A دارند از طریق shaper چهارموقعیتی موجود نگاشت می‌شوند؛ نویسه‌هایی که ندارند (بیشتر Extended-A) فقط طبقه‌بندی joining-class می‌گیرند تا همسایه‌ها درست شکل بگیرند، حتی وقتی خود نویسه بدون تغییر عبور کند. v2.119.56 دو نگاشت Forms-A اشتباه را که v2.119.52 معرفی کرده بود اصلاح کرد (U+06C2 / U+06C3)

 

پوشش کامل Form-B فارسی / اردو (v2.119.57): جدول joining-class به بازه کامل U+0672-U+06D5 گسترش یافت (حدود 80 نویسه شامل variantهای REH / DAL / SEEN / SAD / TAH / AIN / FEH / QAF / KAF / GAF / LAM / NOON / HEH / WAW / YEH)، و 26 نگاشت جدید Presentation Forms-A اضافه شد (15 مورد D-class چهارفرمی + 11 مورد R-class دورفرمی). به‌طور مشخص، HEH DOACHASHMEE استاندارد اردو 'h' (U+06BE → FBAA-FBAD) و YEH BARREE پایانیِ واژه در اردو (U+06D2 → FBAE-FBAF) اکنون درست به slotهای Forms-A نگاشت می‌شوند که وصله موقت v2.119.52 برای ALEF WASLA / NOON GHUNNA از آن‌ها به‌اشتباه استفاده کرده بود. پوشش ایستا Forms-A اکنون بیش از 40 نویسه منبع را در بر می‌گیرد

 

پس‌پردازش لیگاتور YEH-HAMZA + واکه (v2.119.58): یک post-pass که به _ApplyArabicShaping پس از شکل‌دهی موقعیتی افزوده شد، 8 جفت لیگاتور در بازهٔ Forms-A یعنی U+FBEA-U+FBFB را پوشش می‌دهد - YEH-HAMZA + ALEF / AE / WAW / U / OE / YU / E / ALEF MAKSURA. هر جفت form منفرد (FBEA / FBEC / FBEE / FBF0 / FBF2 / FBF4 / FBF6 / FBF9) را همراه با form نهایی base+1 صادر می‌کند. slotهای form آغازین / میانی FBF8 / FBFB از طریق opt-in sfArabicGSUB به موتور GSUB واگذار می‌شوند. این بخش بر همان اسکلت v2.119.32 مربوط به LAM-ALEF ساخته شده است

 

لیگاتور Allah (v2.119.60): دنبالهٔ چهارنویسه‌ای ALEF + LAM + LAM + HEH به U+FDF2 ARABIC LIGATURE ALLAH ISOLATED FORM fold می‌شود. این قابلیت به‌صورت یک post-pass ایستای سطح codepoint پس از v2.119.32 LAM-ALEF و v2.119.58 YEH-HAMZA در زنجیرهٔ _ApplyArabicShaping پیاده‌سازی شده است

 

لیگاتور عبارت Bismillah (v2.119.62): عبارت استاندارد 22 codepointی Bismillah یعنی "بسم الله الرحمن الرحيم" به یک glyph واحد U+FDFD ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM fold می‌شود. این بخش به‌عنوان نخستین pre-pass در _ApplyArabicShaping (پیش از LAM-ALEF) اجرا می‌شود، بنابراین glyphِ foldشدهٔ Bismillah به‌صورت یک codepoint وارد بقیهٔ خط لوله می‌شود و دیگر توسط substitutionهای بعدی دست‌کاری نمی‌شود

 

کمک‌رویه‌های پرس‌وجوی عمومی

GetArabicJoiningClass کلاس اتصال Unicode را که شکل‌دهندهٔ ایستای عربی استفاده می‌کند برمی‌گرداند. GetArabicPosition یک نویسه درون run را به موقعیت isolated، initial، medial یا final resolve می‌کند تا فراخواننده بتواند همان تصمیم‌های شکل‌دهی را پیش از صدور متن بررسی یا بازتاب کند

 

نحوهٔ فراخوانی

خط لولهٔ شکل‌دهی به‌طور خودکار داخل متدهای صدور متن Unicode اجرا می‌شود - نیازی به فراخوانی صریح «این را شکل بده» نیست. رشته‌های عربی / فارسی / اردو با ورودی Unicode را به THPDFPage.UnicodeTextOut یا THPDFPage.RtLTextOut بدهید تا HotPDF هر کدپوینت ورودی را پیش از نوشتن PDF text-showing operator به presentation form خودش نگاشت کند. بایت‌های اصلی Unicode نیز برای تولید ToUnicode CMap در FUnicodeUsedCps ثبت می‌شوند، بنابراین copy / paste و screen reader در سمت reader همچنان بار اصلی Unicode را می‌بینند

 

نیازمندی‌های فونت

فونتی که از طریق RegisterUnicodeTTF ثبت می‌شود باید glyphهای هم بلوک Arabic Presentation Forms-B (U+FE70 - U+FEFC) و هم، برای فارسی / اردو، بازهٔ مربوط به Arabic Presentation Forms-A (U+FB50 - U+FDFF) را داشته باشد. فونت‌های پیشنهادی که این مجموعه را کامل ارائه می‌کنند:

 

Noto Sans Arabic (Latin + Arabic; Forms-A + Forms-B + Arabic Extended-A)

Noto Naskh Arabic, Noto Naskh Arabic UI

Amiri (traditional Naskh, full Forms-A + Forms-B coverage)

Scheherazade New (SIL، طراحی‌شده برای زبان‌های جهان اسلام)

Microsoft Arabic Typesetting / Tahoma / Times New Roman (Windows-bundled, full Forms-B; some have Forms-A coverage)

 

وقتی فونت ثبت‌شده برای یک presentation form مشتق‌شده glyph نداشته باشد، HotPDF به کدپوینت پایهٔ Unicode برمی‌گردد و آن را بدون تغییر صادر می‌کند؛ در این حالت readerهای مصرف‌کننده ممکن است shaping خودشان را امتحان کنند (Acrobat، Foxit) یا .notdef را رندر کنند

 

Typical workflow

 

PDF.RegisterUnicodeTTF('NotoArab', 'NotoSansArabic-Regular.ttf');

PDF.BeginDoc;

PDF.CurrentPage.SetFont('NotoArab', [], 14);

PDF.CurrentPage.RtLTextOut(100, 700, 0,

  UnicodeString(#$0645#$0631#$062D#$0628#$0627));  // "marhaba" (hello)

PDF.EndDoc;

 

ادغام خط لولهٔ Phase 8 به‌صورت خودکار (v2.119.59 - v2.119.68)

v2.119.59 ویژگی اختیاری ShapingFeatures: THPDFShapingFeatures و enumِ THPDFShapingFeature را معرفی کرد و خط لولهٔ شکل‌دهی را از fold ایستای post-pass به substitution اختصاصی فونت و مبتنی بر GSUB ارتقا داد. با PDF.ShapingFeatures := [sfArabicGSUB]، lookupهای بومی عربیِ init، medi، fina، isol، rlig، calt و rclt فونت ثبت‌شده اعمال می‌شوند و GIDهای contextual حاصل صادر می‌گردند؛ با افزودن sfCursiveAttachment anchorهای ورودی / خروجی cursive GPOS روی همان run شکل‌گرفته اعمال می‌شوند؛ با افزودن sfStandardLigatures لیگاتورهای استاندارد لاتین (FB00-FB06 ff / fi / fl / ffi / ffl / ſt / st از طریق ApplyLatinLigatureRefinement نسخهٔ v2.119.65) فعال می‌شوند؛ و sfIndicShaping بازآرایی pre-pass دواناگری (v2.119.67) را روشن می‌کند. مقدار پیش‌فرض [] برای فراخواننده‌هایی که به خط لولهٔ ایستا وابسته‌اند، خروجی کاملاً همسانِ بایتی را حفظ می‌کند

 

وقتی sfArabicGSUB فعال است، شکل‌دهندهٔ ایستای Unicode Presentation Forms کنار گذاشته می‌شود و قوانین GSUB خود فونت جای آن را می‌گیرند. HotPDF وقتی آن glyphها از cmap فونت قابل دسترس نیستند، GIDهای contextual بومی را از طریق codepointهای مصنوعی صادر می‌کند، subset تعبیه‌شده را بسته نگه می‌دارد و برای copy / paste reverse mappingهای ToUnicode می‌نویسد. فراخواننده‌هایی که می‌خواهند شکل‌دهندهٔ ایستا برای codepointهایی بیرون از پوشش GSUB فونت همچنان فعال بماند، باید sfArabicGSUB را خاموش بگذارند و به زنجیرهٔ post-pass ایستا تکیه کنند

 

ToUnicode CMap ligature reverse mapping (v2.119.61, v2.119.62, v2.119.65)

ToUnicode CMapِ Adobe-Identity-UCS که توسط RegisterUnicodeTTF صادر می‌شود، برای هر codepoint لیگاتوری که زنجیرهٔ post-pass می‌تواند تولید کند، ورودی‌های reverse-mapping از نوع bfchar حمل می‌کند. v2.119.61 تعداد 27 ورودی اضافه کرد (8 مورد LAM-ALEF + 18 مورد از خانوادهٔ YEH-HAMZA + 1 مورد Allah)؛ v2.119.62 مورد Bismillah (U+FDFD) را افزود؛ و v2.119.65 هفت ورودی Latin Standard Ligature (FB00-FB06) را اضافه کرد. copy / paste در reader مصرف‌کننده هر glyph لیگاتوری را به دنبالهٔ codepoint مبدأ برمی‌گرداند، بنابراین PDF رندرشده از نظر دسترس‌پذیری دوستانه باقی می‌ماند

 

PUA synthetic codepoint emit (v2.119.68)

AssignSyntheticCodepointForGID(GID; out CP): Boolean + GetSyntheticCodepointForGID(GID): Word به کد تولیدکننده اجازه می‌دهد GIDهای جایگزین GSUB را که هیچ codepoint Unicode طبیعیِ قابل دسترسی از طریق cmap فونت ندارند صادر کند. تخصیص‌دهنده codepointها را در Private Use Area (U+E000 - U+F8FF، 6400 slot) توزیع می‌کند و این تخصیص را به FUnicodeCpToGid بازتاب می‌دهد (تا /CIDToGIDMap در reader مصرف‌کننده، CP مصنوعی را دوباره به GID هدف resolve کند)، به FAcroFormUnicodeAdvances (تا word-wrap نسخهٔ v2.65 em-fraction درست را پیدا کند) و به یک جدول reverse-lookup برای هر GID (تا درخواست‌های تکراری تخصیص idempotent بمانند). از این مسیر برای شکل‌های خوشه‌ای دواناگری، alternateهای stylistic و دنباله‌های variation ایدئوگرافیک CJK که GSUB معرفی می‌کند اما cmap به آن‌ها نمی‌رسد استفاده کنید

 

رابطه با موتور OpenType GSUB

شکل‌دهندهٔ post-pass ایستی که بالا توصیف شد (v2.85.0 + v2.119.32 / 58 / 60 / 62) به‌طور پیش‌فرض از موتور OpenType GSUB مستقل است. وقتی sfArabicGSUB از طریق ShapingFeatures فعال شود، موتور GSUB بخشی از مسیر صدور سمت تولیدکننده می‌شود: HotPDF cmap را بررسی می‌کند تا یک آرایهٔ پایهٔ GID بسازد، lookupهای positional و contextual عربی بومی را روی آن run glyph اعمال می‌کند، برای GIDهای substitute که Presentation Form Unicode ندارند کدپوینت‌های مصنوعی اختصاص می‌دهد و MarkUnicodeGlyphUsed را فراخوانی می‌کند تا glyphهای substitute داخل embedded font subset بمانند

 

برای glyphهای جایگزینِ بدون codepoint یونیکد، فراخواننده‌ها ShapingFeatures را با تخصیص‌دهندهٔ synthetic-codepointِ PUA نسخهٔ v2.119.68 ترکیب می‌کنند تا GID جایگزین همچنان از مسیر استاندارد hex pipeline قابل دسترسی بماند. زنجیرهٔ post-pass ایستا همچنان fallback پیش‌فرض برای codepointهایی است که اعلان‌های GSUB فونت پوشش نمی‌دهند

 

دامنه و محدودیت‌ها

الگوریتم BiDi بیرون از این صفحه باقی می‌ماند: فراخواننده‌ها هنوز باید runهای ترکیبی LTR و RTL را خودشان مرتب کنند یا از یک کتابخانهٔ جداگانهٔ BiDi استفاده کنند. پشتیبانی GPOS، Indic/Tibetan/Mongolian، عبری، N'Ko، Adlam، Thai/Lao و Javanese اکنون در صفحه‌های جداگانهٔ opt-in مربوط به shaping flag و API قرار دارد، بنابراین این صفحه فقط بر شکل‌دهی ایستا و مبتنی بر GSUB عربی تمرکز می‌کند

 

همچنین ببینید: موتور جایگزینی OpenType GSUB, خط لولهٔ شکل‌دهی خودکار (Phase 8), شکل‌دهی سریانی / مغولی / دواناگری, THotPDF.AssignSyntheticCodepointForGID, THPDFPage.RtLTextOut, THPDFPage.UnicodeTextOut, CFF / OpenType Font Subsetting