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

مسار معالجة HTML

Spec: CSS Cascade 5, §6.1 Spec: CSS Display 3, §2 Evidence: Code-backed

يُصيِّر ⁨NextPDF⁩ محتوى ⁨HTML⁩ وأنماط ⁨CSS⁩ إلى ⁨PDF⁩ داخل عملية ⁨PHP⁩ لديك: بلا متصفّح، وبلا عملية فرعية افتراضيًا. توضّح هذه الصفحة المراحل الطبقية التي يمرّ بها التحويل، وما الذي يغطّيه محرّك ⁨CSS⁩ فعليًا، ومتى يكون التفويض إلى مُصيِّر متصفّح حقيقي هو الخيار الصادق.

يبدو “تحويل ⁨HTML⁩ إلى ⁨PDF⁩” كأنه عملية واحدة. لكنه في الواقع تتالٍ (⁨cascade⁩)، ونموذج صندوق، ومرحلة تخطيط، ومرحلة رسم. كل واحد منها مسألة محدّدة بدقّة ولها أنماط فشلها الخاصة. والمحرّك الذي يدمجها في إجراء واحد يكون هشًّا؛ فقد يؤدّي تغيير في تحليل الألوان إلى تحريك صندوق، ولا تكون الطريقة الوحيدة لاكتشاف ذلك إلا التصيير والمعاينة.

للنموذج داخل العملية ميزة حقيقية: لا متصفّح تُثبّته، ولا بيئة عزل تُديرها، ولا حدّ بين العمليات تنقل البيانات عبره. لكن هذه الميزة لا تؤتي ثمارها إلا إذا كان التحويل مفكّكًا بوضوح يكفي لاختبار كل مسؤولية على حدة. البنية هي ما يجعل “تصيير ⁨HTML⁩ في ⁨PHP⁩” جديرًا بالثقة، لا مجرّد أمر ممكن.

  • يجري تحويل ⁨HTML/CSS⁩ داخل العملية عبر writeHtml(). والنتيجة محتوى ⁨PDF⁩ أصلي، لا صورة لصفحة.
  • وهو أحادي المرور ومتدفّق. يُنتج المُجزِّئ (⁨tokenizer⁩) قائمة رموز، ويستهلكها المُحلِّل من اليسار إلى اليمين، ولا يُحتفَظ بشجرة ⁨DOM⁩ كاملة (⁨ADR-001⁩). وتحدّ سقوف صارمة عددَ العناصر وعمقَ التداخل.
  • المحرّك منظَّم في صورة طبقات صريحة: تحليل ⁨CSS⁩ والمُطبِّقات، وحالة النمط، والتخطيط والتنسيق، والرسم، والوسائط المُقسَّمة إلى صفحات — مع قواعد صارمة حول ما يجوز لكل طبقة فعله (⁨ADR-010⁩).
  • يغطّي محرّك ⁨CSS⁩ التتالي، ونموذج الصندوق، والتخطيط الشائع (⁨block⁩ و⁨inline⁩ والجداول والعناصر العائمة وغيرها) — وهو نطاق واسع، لكنه مجموعة جزئية محدّدة ممّا يُنفِّذه متصفّح حديث.
  • عندما تحتاج إلى مطابقة دقيقة للمتصفّح مع أنماط ⁨CSS⁩ حديثة عشوائية، يستطيع ⁨NextPDF⁩ التفويض إلى مُصيِّر متصفّح بلا واجهة عبر امتداد اختياري — وهي وصلة مقصودة معزولة عن الشبكة، وليست المسار الافتراضي.

كيف يتعامل ⁨NextPDF⁩ مع الأمر

قسم بعنوان «كيف يتعامل ⁨NextPDF⁩ مع الأمر»

التحويل سلسلة من المراحل، تستهلك كلٌّ منها المُخرَج المُحدَّد النوع للمرحلة السابقة.

  1. Tokenize HTML becomes an ordered token list — no retained DOM tree.
  2. Resolve CSS Parse styles; the cascade and applicators compute typed values.
  3. Style state A push/pop style stack carries computed values per nesting level.
  4. Layout Block, inline, table, and float geometry computed; no paint here.
  5. Paint Borders, backgrounds, text, and decorations emit PDF operators.
  6. Paged media Page-break and @page rules applied as the cursor crosses page bounds.
مسار معالجة HTML داخل العملية: مرور واحد من اليسار إلى اليمين على دفق رموز، مع تحليل CSS وحالة النمط والتخطيط والرسم كطبقات منفصلة، وتطبيق فواصل الوسائط المُقسَّمة إلى صفحات كلما تقدّم المؤشّر.

قاعدتان معماريتان تجعلان هذا المسار أكثر من مجرّد تدفّق.

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

لا وجود لـ ⁨DOM.⁩ المسار أحادي المرور ومتدفّق بقرار مقصود (⁨ADR-001⁩): حالة نمط واحدة على الأكثر لكل مستوى تداخل إضافةً إلى المؤشّر النشِط، لا كائن واحد لكل عنصر. تحتاج بعض العمليات حقًّا إلى استشراف أمامي — تحديد أحجام أعمدة الجداول، و:has()، و:last-child. تُعالَج هذه عبر بُنى فهرسة محدودة الحجم ومسبقة المسح فوق قائمة الرموز المسطّحة، لا عبر الاحتفاظ بشجرة. عدد العناصر وعمق التداخل محدودان بسقوف صارمة، فيفشل الإدخال المُرضِي بسرعة بدلًا من استنزاف الذاكرة.

يحلّ محرّك ⁨CSS⁩ دلالات ⁨CSS⁩ الحقيقية، لا محاكاة شبيهة بها. تُختزل الإعلانات المتنافسة إلى قيمة واحدة لكل خاصّية حسب المصدر والأهمّية والطبقة والتخصيص والترتيب — أي التتالي الفعلي. يتبع التخطيط نموذج الصندوق. نوع الصندوق وسياق التنسيق الذي يُنشئه يحدّدان كيف يُوضَع هو وأشقّاؤه ضمن التدفّق. المصدر البرمجي للمحرّك منظَّم حول هذه الاهتمامات تحديدًا (التتالي، و⁨box/display⁩، و⁨flex⁩، و⁨float⁩، والجداول، والتجزئة). لذلك يمكنك الاستدلال على سلوكه استنادًا إلى المواصفات، بدلًا من اكتشافه بالتجربة.

هذه الصفحة Evidence: Code-backed . تنطبق المراحل والقواعد على مستودع core:

  • نقطة الدخول داخل العملية هي writeHtml(string $html): static في src/Core/Concerns/HasTextOutput.php.
  • تصميم المرور الأحادي بلا الاحتفاظ بـ ⁨DOM⁩ مع سقوف العناصر والتداخل موثّق في ⁨ADR-001⁩ وكود ⁨tokenizer/parser/⁩مكدّس النمط في src/Html/.
  • عقد المحرّك الطبقي — ⁨parsing/applicators⁩ لـ ⁨CSS⁩، وحالة النمط، والتخطيط، والرسم، والوسائط المُقسَّمة إلى صفحات — هو ⁨ADR-010⁩، وينعكس في تخطيط src/Html/ (على سبيل المثال Cascade/، وCss/، وFlex/، وFloat/، وFragmentation/، وأصناف المُطبِّقات).
  • وصلة التفويض إلى المتصفّح هي writeHtmlChrome() في الملف نفسه، وهي موثَّقة بأنها تتطلّب امتداد المُصيِّر الاختياري إضافةً إلى ملف تنفيذي لـ ⁨Chrome/Chromium.⁩

ترسّخ المعايير ادّعاء التغطية بصدق. يختزل التتالي الإعلانات المتنافسة إلى قيمة واحدة لكل خاصّية — المصدر، والأهمّية، والطبقة، والتخصيص، والترتيب — وفقًا لـ Spec: CSS Cascade 5, §6.1 ، ويتبع وضعُ العناصر ضمن التدفّق قواعدَ الصندوق وسياق التنسيق وفقًا لـ Spec: CSS Display 3, §2 . ولا يقلّ الحدُّ الفاصل أهميةً عن ذلك: يوجد استعلام عن الميزة (⁨feature query⁩) تحديدًا لأنه ليس كل مُعالِج يدعم كل ميزة وفقًا لـ Spec: CSS Conditional 5, §2 . محرّك CSS في NextPDF هو مجموعة جزئية محدّدة ومتوافقة مع المواصفات، والتصريح بذلك جزء من العقد.

التصيير داخل العملية استدعاء واحد. والمُخرَج نصّ ⁨PDF⁩ قابل للتحديد، لا صفحة نقطية:

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('HTML Basic');
$doc->addPage();
$html = <<<'HTML'
<h1 style="color: #1E3A8A;">HTML Rendering in NextPDF</h1>
<p>NextPDF renders <strong>HTML and CSS</strong> directly into PDF pages,
<em>in-process</em>.</p>
<ul>
<li>Headings, paragraphs, bold and italic</li>
<li>Lists, tables, inline styles</li>
</ul>
HTML;
$doc->writeHtml($html);
$doc->save(__DIR__ . '/html-basic.pdf');

لو تطلّب المستند نفسه أنماط ⁨CSS⁩ حديثة عشوائية مع مطابقة دقيقة للمتصفّح، فسيكون الاستدعاء بدلًا من ذلك writeHtmlChrome($html) — المستند نفسه، ومسار تصيير مختلف، واعتماد مقصود على مُصيِّر المتصفّح الاختياري.

المفهوم الخاطئ المتكرّر هو أن محرّك تحويل ⁨HTML⁩ إلى ⁨PDF⁩ هو “في جوهره متصفّح.” لكنه ليس كذلك، ولا يدّعي ذلك. المتصفّح تنفيذ هائل ومُحدَّث باستمرار لمنصّة الويب بأكملها. المحرّك داخل العملية في ⁨NextPDF⁩ هو مجموعة جزئية متوافقة مع المواصفات ومركّزة على تخطيط المستندات. النموذج الذهني الصادق هو “محرّك ⁨CSS⁩ كفء لمستندات الطباعة”، لا “⁨Chrome⁩ في ⁨PHP.⁩” وعندما تحتاج حقًّا إلى المنصّة الكاملة، فهذا هو الغرض من writeHtmlChrome(). إنه مسار منفصل اختياري له بصمته التشغيلية الخاصة، لا بديل صامت.

مفهوم خاطئ ثانٍ: افتراض أن مسار المتصفّح هو مجرّد “تصيير الصفحة عبر الشبكة.” العكس هو الصحيح بحكم التصميم. تُصيِّر وصلة التفويض دائمًا مع حظر وصول الموارد الفرعية إلى الشبكة — لا صور أو خطوط أو صفحات أنماط أو إطارات بعيدة — فلا يمكن أن تتحوّل إلى ناقل لطلبات صادرة. مطابقة على مستوى البكسل، نعم؛ ومنفذ شبكة خارجي مفتوح، لا.

توضّح هذه الصفحة شكل المسار والاختيار بين داخل العملية / المتصفّح. وهي ليست مصفوفة دعم ⁨CSS.⁩ أمّا الخصائص والوحدات والمُحدِّدات التي يغطّيها المحرّك داخل العملية بالضبط، فيحدّدها الكود واختبارات مطابقته، لا هذه النظرة العامة. وتلك التغطية تتطوّر. يتطلّب مسار التفويض إلى المتصفّح امتدادًا اختياريًا وملفًا تنفيذيًا لـ ⁨Chrome/Chromium.⁩ أمّا إعداده وخصائصه التشغيلية والتخطيط الداخلي لذلك الامتداد، فهي خارج نطاق هذه الصفحة وموثَّقة مع تلك الحزمة. يصف “داخل العملية” مسار writeHtml() الافتراضي. وهو ليس ادّعاءً بأن كل مسار تصيير يتجنّب عملية فرعية. الادّعاءات المعمارية دقيقة اعتبارًا من تاريخ مراجعة هذه الصفحة. المصادر المرجعية الموثوقة هي src/Html/، و⁨ADR-001⁩، و⁨ADR-010⁩ في مستودع ⁨core.⁩

محرّك ⁨CSS⁩ داخل العملية قدرة من قدرات ⁨Core.⁩ ووصلة التفويض إلى المتصفّح امتداد اختياري، وتظهر هنا على مستوى القدرة فقط:

HTML rendering paths — edition availability
Edition Availability
Core توفّر Core محرّك HTML/CSS داخل العملية (writeHtml).
Pro مسار التفويض إلى المتصفّح امتداد إضافي اختياري، ومستقلّ عن مستوى الإصدار.
Enterprise مسار التفويض إلى المتصفّح امتداد إضافي اختياري، ومستقلّ عن مستوى الإصدار.
  • التصيير داخل العملية — تحويل ⁨HTML/CSS⁩ إلى ⁨PDF⁩ داخل عملية ⁨PHP⁩، بلا متصفّح أو عملية فرعية افتراضية (writeHtml()).
  • أحادي المرور / متدفّق — استهلاك دفق رموز من اليسار إلى اليمين دون الاحتفاظ بشجرة ⁨DOM⁩ كاملة (⁨ADR-001⁩).
  • التتالي — عملية ⁨CSS⁩ التي تحلّ الإعلانات المتنافسة إلى قيمة واحدة لكل خاصّية حسب المصدر والأهمّية والطبقة والتخصيص والترتيب.
  • سياق التنسيق — بيئة التخطيط التي يُنشئها الصندوق، وتحكم كيفية وضع محتوياته ضمن التدفّق.
  • عقد طبقات المحرّك — مجموعة القواعد المفروضة (⁨ADR-010⁩) التي تحدّد ما يجوز لكلٍّ من طبقات التحليل والنمط والتخطيط والرسم والوسائط المُقسَّمة إلى صفحات فعله.
  • وصلة التفويض إلى المتصفّح — مسار writeHtmlChrome() الاختياري الذي يُصيِّر عبر متصفّح بلا واجهة مع حظر وصول الموارد الفرعية إلى الشبكة.