تخطَّ إلى المحتوى

النص: حدّ التشكيل، ومعالجة CJK والمقاطع

تُعرّف وحدة النص حدّ التشكيل. فهي تعرض واجهة صغيرة تحوّل مقطعًا بصيغة تحويل يونيكود ذات الثماني بتات (⁨UTF-8⁩) إلى محارف رسومية مُموضَعة، وتختار خلفية ⁨OpenType⁩ حقيقية عند توفّرها، وتلجأ إلى بديل حتمي عند عدم توفّر أيّ خلفية، وتوفّر سجلًّا للمُشكِّلات الخاصة بكلّ كتابة.

Terminal window
composer require nextpdf/core:^3

يربط ShaperInterface مسار تخطيط النص بمحرّك تشكيل ⁨OpenType.⁩ وتبقى الواجهة صغيرة عن قصد: تستهلك طريقة واحدة، هي shape()، قيمة ShaperInput وتُعيد قيمة ShapingResult. ونوع الإرجاع هذا هو المخرَج الوحيد الذي يراه المستهلكون. يجب ألّا تُسرّب التطبيقات تفاصيل محرّك التشكيل الداخلية، ويفرض نوع الإرجاع المحدّد ذلك الحدّ. يحمل ShapingResult قائمة سجلّات GlyphRun، ونصّ المصدر المُكرَّر، والكتابة والاتجاه، ووسم shaperImpl الذي يحدّد الخلفية التي أنتجت النتيجة.

اختيار الخلفية صريح ويُبلّغ عن القدرة دون تخمين. يُجري ShaperFactory فحص قدرة واحدًا. إذا كان لدى المضيف ربط ⁨HarfBuzz⁩ عامل، تُعيد create() المُشكِّل المدعوم بـ ⁨HarfBuzz.⁩ وإلا، فإنها تُعيد NullShaper. يُعدّ NullShaper مُشكِّلًا بديلًا يمرّر المُدخل كما هو. يُصدِر محرفًا رسوميًا اصطناعيًا واحدًا لكلّ نقطة ترميز يونيكود، بتقدّمات صفرية وإزاحات صفرية. يَسِم النتيجة كي تستطيع المراقبة كشف اللجوء إلى البديل، ويترك حلّ التقدّمات لوحدة قياسات الخطوط. هذا المسار تدهور موثَّق، وليس تشكيلًا كاملًا. تتطلّب الاستبدالات والربائط ومواضع العلامات والأشكال السياقية خلفية حقيقية. wouldUseRealShaper() مُسنَد تشخيصي. وفي شيفرة الإنتاج، تفرّع بناءً على وسم shaperImpl في النتيجة بدلًا من ذلك.

التشكيل الخاص بالكتابة واجهة موفّر خدمة (⁨SPI⁩)، وليس تطبيقًا مُضمَّنًا. يُعدّ ScriptShaperRegistry سجلًّا بنمط توصية معايير ⁨PHP⁩ رقم 11 ‏(⁨PSR-11⁩)، ويحلّ قيمة MongolianShaperInterface أو TibetanShaperInterface بحسب وسم كتابة المنظمة الدولية للتوحيد القياسي (⁨ISO⁩) رقم 15924. يخزّن السجلّ المفاتيح بصرف النظر عن حالة الأحرف، ويعتمد على مصدر حقيقة واحد لقبول رموز الكتابة. السجلّ وواجهات مُشكِّلات الكتابة عقد مُجمَّد، لذا يستطيع الامتداد تسجيل موفّر من الطور 12 دون المساس بمواضع الاستدعاء. يشحن المحرّك الحدّ، ويوفّر المستهلكون موفّري الكتابات المركّبة.

تقع معالجة مقاطع الصينية واليابانية والكورية (⁨CJK⁩) عند حدّ ترميز الطباعة. يُصدَر وجه ⁨TrueType⁩ مُضمَّن للـ ⁨CJK⁩ كخطّ من النوع 0 مع ⁨CMap⁩ من نوع ⁨Identity-H⁩ وفرع تابع CIDFontType2، كما يشمله ⁨ISO 32000-2⁩ §9.7.4 ‏(مُلخَّص التوليد المعزَّز بالاسترجاع (⁨RAG⁩) مُقتطَع بسبب حدّ الترخيص؛ مُسجَّل في _downgraded-claims-o3.md). عندما يكون برنامج ⁨TrueType⁩ مُضمَّنًا، يربط خطّ ⁨CIDFont⁩ من النوع 2 معرّفات المحارف بفهارس المحارف الرسومية عبر مُدخل CIDToGIDMap، كما يشمله ⁨ISO 32000-2⁩ §9 ‏(المُلخَّص المُثبَّت بحسب صفحة عقد ⁨B1⁩). يحافظ مُجزّئ الخطوط على ترقيم المحارف الرسومية الأصلي بحيث يظلّ /CIDToGIDMap /Identity صالحًا للمجموعة الجزئية. يتحقّق CjkFontValidator ممّا إذا كان الخطّ المرشّح يغطّي كتل يونيكود التي تحتاجها كتابة ما قبل اختيار ذلك الخطّ.

النوعالصنفالأعضاء الرئيسيةالاستقرارمنذ
ShaperInterfaceواجهةshape(ShaperInput): ShapingResultمستقر3.2.0
ShaperFactoryصنف نهائيdefault()، create()، wouldUseRealShaper()مستقر3.2.0
NullShaperصنف نهائي للقراءة فقطمُشكِّل بديل يمرّر المُدخل كما هومستقر3.2.0
ShapingResultصنف نهائي للقراءة فقط$glyphRuns، $originalText، $script، $direction، $shaperImplمستقر3.2.0
ScriptShaperRegistryصنف نهائيregisterMongolian()، getMongolian()، hasMongolian()، والمكافئات التبتيةمستقر3.1.0
CjkFontValidatorصنف نهائيvalidateCoverage()، detectScript()، isCjkCodepoint()مستقر1.0.0

إنّ شكل طرق register* وget* وhas* في ScriptShaperRegistry وواجهات مُشكِّلات الكتابة عقد مُجمَّد. وبحسب التصميم، يُعدّ ShapingResult المخرَج الوحيد للمُشكِّل الذي يمكن للمستهلكين رؤيته.

examples/text/shaper-factory.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Font\Shaper\ShaperFactory;
use NextPDF\Font\Shaper\ShaperImpl;
$factory = ShaperFactory::default();
$shaper = $factory->create();
// Branch on the result tag, not on the concrete class.
$wouldShape = $factory->wouldUseRealShaper()
? 'HarfBuzz backend available'
: 'NullShaper fallback (degraded — no substitution or positioning)';
echo $wouldShape, "\n";

يوصّل ShaperFactory::default() فحص قدرة الإنتاج. يخزّن create() الخلفية المختارة مؤقتًا طوال عمر المصنع. استخدم wouldUseRealShaper() ووسم shaperImpl في كلّ نتيجة لفحص القدرة.

examples/text/script-shaper-registry.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Text\Shaping\MongolianShaperInterface;
use NextPDF\Text\Shaping\ScriptShaperRegistry;
final readonly class ComplexScriptBootstrap
{
public function __construct(private ScriptShaperRegistry $registry) {}
/**
* Register a consumer-supplied Mongolian shaper provider at boot so
* the layout pipeline can resolve it by ISO 15924 script tag.
*/
public function register(MongolianShaperInterface $mongolian): void
{
$this->registry->registerMongolian($mongolian);
}
public function hasMongolian(): bool
{
return $this->registry->hasMongolian();
}
}

السجلّ هو نقطة التكامل لموفّري الكتابات المركّبة. يشحن المحرّك الحدّ وشكل الوصول المُجمَّد، ويوفّر المستهلكون تطبيقي المنغولية والتبتية.

  • نتيجة NullShaper ذات تقدّمات صفرية وإزاحات صفرية. لا تُغذِّ تلك المواضع مباشرةً في تخطيط النص. حُلّ التقدّمات من وحدة قياسات الخطوط، واكشف اللجوء إلى البديل عبر وسم shaperImpl.
  • ينتج عن المُدخل الفارغ قائمة glyphRuns فارغة، لا مقطع فارغ. لا تحتاج شيفرة تكرار المستهلك إلى حالة خاصة لمقطع بطول صفري.
  • لا يُطبّق ScriptShaperRegistry الواجهة Psr\Container\ContainerInterface مباشرةً، وبذلك تحتفظ موصّلات الوصول المُحدَّدة النوع بنوع إرجاعها المُضيَّق تحت التحليل الساكن. استخدم getMongolian() وgetTibetan()، لا get() عامًّا.
  • تُطابَق وسوم الكتابة بحسب قيمة ⁨ISO 15924⁩ القانونية من أربعة أحرف لاتينية وتُخزَّن بصرف النظر عن حالة الأحرف. مرّر Mong أو Tibt. لا تؤثّر حالة الأحرف في البحث.
  • تقع محارف امتداد ⁨CJK⁩ من النوع ⁨B⁩ في مستوى يونيكود 2 وتفرض جدولًا فرعيًا من نوع ⁨cmap Format 12⁩ في المجموعة الجزئية. يعالج مسار الترميز ذلك. لا تفترض أنّ المستوى متعدّد اللغات الأساسي يغطّي كلّ نصوص ⁨CJK.⁩

يُجرى فحص القدرة مرّة واحدة لكلّ نسخة من ShaperFactory، وتُخزَّن الخلفية مؤقتًا، فتكون استدعاءات create() المتكرّرة بلا تكلفة. يعمل NullShaper خطّيًا بحسب عدد نقاط الترميز في مقطع المُدخل، ولا يُجري أيّ ⁨input/output⁩ (⁨I/O⁩). حلّ ScriptShaperRegistry هو بحث مُفهرَس بزمن ثابت. يأخذ CjkFontValidator عيّنات من نقاط الترميز بخطوة بدلًا من اختبار كلّ واحدة، ممّا يُبقي فحوص التغطية زهيدة حتى أمام خطّ ⁨CJK⁩ يضمّ 20,000 محرف رسومي. يغطّي performance_budget البالغ 1500 ⁨ms⁩ للزمن الكلي و64 ⁨MB⁩ للذروة تشغيلًا نموذجيًا. في التشكيل الحقيقي، تكون التكلفة الغالبة هي خلفية ⁨OpenType.⁩ وتقع تلك التكلفة خارج نطاق هذه الوحدة عندما يكون البديل نشطًا.

يستهلك حدّ المُشكِّل سلسلة ⁨UTF-8.⁩ يتحمّل NullShaper سلسلة ⁨UTF-8⁩ المُشوَّهة بالتقسيم على أساس أفضل جهد بدلًا من إطلاق استثناء، لأنّ عقد البديل الموثَّق هو أصلًا “لا تشكيل حقيقي”. يكون المُستدعِي مُهيَّأً للمخرَج المنخفض الجودة. يستخدم عقد عناقيد إزاحة البايت طولًا موجّهًا بالبايت، وهذا صحيح للمُدخل متعدّد البايتات ويتجنّب عيب ربط العناقيد بإزاحة نقطة ترميز. عند توفّر الخلفية الحقيقية، تكون مكتبة أصلية من طرف ثالث. عامِل مُدخلها كغير موثوق، وحُدّ طول المقطع في الأعلى. يخزّن سجلّ مُشكِّلات الكتابة موفّرين من تزويد المستهلك. تقع تلك التطبيقات داخل حدّ ثقة المستهلك، لا حدّ المحرّك.

الادّعاءالمعيارالبندالدليل
يُصدَر وجه ⁨TrueType⁩ مُضمَّن للـ ⁨CJK⁩ كخطّ من النوع 0 مع ⁨CMap⁩ من نوع ⁨Identity-H⁩ وفرع تابع CIDFontType2.⁨ISO 32000-2⁩§9.7.4مُلخَّص التوليد المعزَّز بالاسترجاع (⁨RAG⁩) مُقتطَع بسبب حدّ الترخيص؛ البادئة 7a5258772f508e3b، انظر _downgraded-claims-o3.md
يربط خطّ ⁨CIDFont⁩ من النوع 2 مُضمَّن معرّفات المحارف بفهارس المحارف الرسومية عبر CIDToGIDMap.⁨ISO 32000-2⁩§9

كلا البندين مُعاد صياغته. الثاني مُثبَّت بالمُلخَّص (مُعاد استخدامه من صفحة عقد ⁨B1⁩)، والأول مُؤيَّد بـ ⁨ADR-013⁩ ونظرة المطوّر العامة على مُرمِّز ⁨cmap.⁩ لا يُعيد ⁨NextPDF⁩ إنتاج النصّ المعياري. خلفية المُشكِّل مستقلّة عن مطابقة صيغة المستندات المحمولة (⁨PDF⁩). تتعلّق ادّعاءات المطابقة هنا بإصدار قاموس خطّ ⁨CJK⁩ الذي يُنتجه حدّ الترميز. يوثّق ⁨ADR-013⁩ ونظرة المطوّر العامة على مُرمِّز ⁨cmap⁩ ذلك المسار بمزيد من التفصيل.

يَبني مسار معالجة نص مسبقة متقدّم وخدمات استخراج على حدّ مُشكِّل ⁨Core⁩ وأنواع قيم معالجة المقاطع. تشحن وحدة نص ⁨Core⁩ الحدّ والبديل وسجلّ مُشكِّلات الكتابة دون ترخيص. غياب رابط التحويل مقصود.