مسار عرض HTML
لمحة سريعة
قسم بعنوان «لمحة سريعة»عند استدعاء writeHtml()، ينفّذ المسار مرورًا أماميًا واحدًا على لغة ترميز النص التشعّبي (HTML): يحوّل المُدخل إلى رموز، ويحلّ @page والأنماط، ويُخطّط المحتوى، ويرسم مُعامِلات تنسيق المستندات المحمول (PDF). ولا يحتفظ بشجرة عناصر بين المراحل.
التثبيت
قسم بعنوان «التثبيت»composer require nextpdf/core:^3نظرة مفاهيمية عامة
قسم بعنوان «نظرة مفاهيمية عامة»يُحوّل مسار عرض HTML مزيج HTML+CSS، أي HTML مع صفحات الأنماط المتتالية (CSS)، إلى مُعامِلات دفق محتوى PDF في مرور أمامي واحد. ولا يبني شجرة مستند محفوظة. تعكس المراحل أدناه سلوك HtmlParser::parse() على main.
المرحلة 1 — التنقية والتسوية. يرفض HtmlParser::parse() أي مُدخل يتجاوز 10 MB، ويُزيل محارف التحكّم، ويُسوّي نهايات الأسطر: يتحوّل كلٌّ من CRLF وCR المفرد إلى LF، بما يطابق تسوية نهايات الأسطر في HTML في المصدر. ثم يُعيد تعيين كل حقل في المثيل، فلا يمكن أن تنتقل حالة من استدعاء سابق إلى المعالجة اللاحقة.
المرحلة 2 — استخراج كتل @page وكتل الأنماط. يستخرج المُحلّل أولًا كتل <style>، ثم يُطبّق قواعد @page المُكتشَفة لإعادة ضبط هندسة الصفحة. ويحدث ذلك قبل معالجة أي رمز، لأن حجم الصفحة يؤثّر في كل قرار تخطيط لاحق.
المرحلة 3 — الترميز. يُسوّي HtmlTokenizer::cleanHtml() المسافات البيضاء مع الحفاظ على محتوى <pre>. ثم يُنتج tokenize() قائمة مسطّحة من نوع list<HtmlToken>. إنها قائمة رموز، وليست رسمًا بيانيًا للعُقَد. ويتخلّص المسار فورًا من الرموز النصية التي لا تحتوي إلا على مسافات بيضاء. يبني HtmlChildScanner::scan() خرائط فهرسة (عدد الأبناء، وعدد الوسوم، والخلوّ) فوق القائمة المسطّحة، لذلك لا تحتاج المُحدِّدات البنيوية إلى شجرة.
المرحلة 4 — فحص :has() المسبق الاختياري. عند تفعيل ميزة css.has التجريبية، يُجري CssResolver::resolveHasSelectors() فحصًا مسبقًا واحدًا ومحدودًا فوق قائمة الرموز لحلّ المُحدِّد العلائقي. هذه الخطوة المحدودة والموثَّقة هي الاستثناء من قاعدة المرور الواحد.
المرحلة 5 — معالجة الرموز (النمط، والتخطيط، والرسم). يجتاز HtmlParser::processTokens() قائمة الرموز مرة واحدة. ولكل عنصر، يحلّ التتالي (تكتب مُطبِّقات الطبقة 1 إلى HtmlStyleState)، ويحسب الهندسة (تخطيط الطبقة 3)، ويُصدِر مُعامِلات PDF (رسم الطبقة 4). يستخدم توارث الأنماط مكدّس HtmlStyleState القائم على الدفع والسحب. ويتنقّل المؤشّر (x، وy، والهوامش، وإزاحة الدفق) بين المُعالِجات عبر لقطات HtmlBlockCursor.
المرحلة 6 — إرجاع النتيجة. يُرجِع parse() كائن HtmlRenderResult غير قابل للتغيير يحتوي على دفق المحتوى المُصدَر، وموضع المؤشّر النهائي، ومفاتيح الخطوط المُستخدَمة. يعيد المُستدعي (writeHtml()) تمرير المؤشّر إلى إطار إحداثيات الصفحة.
للاطّلاع على الفصل بين الطبقات الأربع داخل المرحلة 5، راجع صفحة عقود الطبقات. وللاطّلاع على خاصية عدم الاحتفاظ بشجرة وحدودها، راجع صفحة قيود التدفّق.
واجهة برمجة التطبيقات
قسم بعنوان «واجهة برمجة التطبيقات»| الرمز | الموقع | المرحلة |
|---|---|---|
Document::writeHtml(string $html): static | src/Core/Concerns/HasTextOutput.php | نقطة الدخول العامة |
HtmlParser::parse(string $html): HtmlRenderResult | src/Html/HtmlParser.php | تُنسّق جميع المراحل |
HtmlTokenizer::cleanHtml() / tokenize() | src/Html/HtmlTokenizer.php | المرحلة 3 |
HtmlChildScanner::scan() | src/Html/HtmlChildScanner.php | خرائط فهرسة المرحلة 3 |
CssResolver::resolveHasSelectors() | src/Html/CssResolver.php | المرحلة 4 (مُقيَّدة بالبوّابة) |
HtmlRenderResult (stream, endX, endY, usedFontKeys) | src/Html/HtmlRenderResult.php | المرحلة 6 |
عيّنة برمجية — البدء السريع
قسم بعنوان «عيّنة برمجية — البدء السريع»مصدرها examples/08-html-basic.php.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('HTML Basic');$doc->addPage();$doc->writeHtml('<h1 style="color:#1E3A8A;">HTML Rendering</h1><p>One pass.</p>');$doc->save(__DIR__ . '/output/08-html-basic.pdf');عيّنة برمجية — الإنتاج
قسم بعنوان «عيّنة برمجية — الإنتاج»اعرِض تقريرًا مُنسَّقًا مع كتلة <style> مُضمَّنة. يستخرج المسار كتلة الأنماط ويُطبّقها قبل أن يعالج أي رمز.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;use NextPDF\Exception\HtmlParsingException;
function renderInvoice(string $bodyHtml, string $out): void{ $doc = Document::createStandalone(); $doc->setTitle('Invoice'); $doc->addPage();
$html = '<style>@page { margin: 20mm; } ' . 'h1 { color: #1E3A8A; } ' . 'table { width: 100%; }</style>' . $bodyHtml;
try { $doc->writeHtml($html); } catch (HtmlParsingException $e) { // Sanitize/cap failures surface here. Do not retry. throw $e; }
$doc->save($out);}الحالات الحدّية والمزالق
قسم بعنوان «الحالات الحدّية والمزالق»- تُقرأ
@pageقبل الرموز. تظل قاعدة@pageالواردة بعد المحتوى سارية المفعول، لأن استخراج الأنماط يسبق الترميز. وتُثبَّت هندسة الصفحة قبل المرحلة 5. - يُحافَظ على المسافات البيضاء في
<pre>. يحميcleanHtml()محتوى<pre>؛ ويطوي المسار المسافات البيضاء فيما عدا ذلك. :has()مُقيَّدة بالبوّابة. إن لم تُفعّل ميزةcss.hasالتجريبية، فلن تعمل المرحلة 4 ولن تتطابق مُحدِّدات:has().- مخزن دفق واحد. يكتب المسار إلى مخزن سلسلة نصية واحد. ولا يُحرّك أبدًا المحتوى المكتوب سابقًا. لا توجد إعادة تخطيط.
- تُطبَّق الحدود في منتصف المرور. تُطرح حدود العناصر والتداخل أثناء المرحلة 5، لا قبلها. يمكن أن يفشل المستند في منتصف الطريق.
الأداء
قسم بعنوان «الأداء»يجتاز المسار الرموز بترتيب O(عدد الرموز). ويُضيف تحديد أبعاد أعمدة الجداول مسحًا محدودًا لصفوف كل جدول (المرحلة 5، TableParser). وعند التفعيل، يُضيف الفحص المسبق لـ :has() مرورًا واحدًا محدودًا على قائمة الرموز (المرحلة 4). يكون استهلاك الذاكرة بترتيب O(عمق التداخل) لمكدّس الأنماط، لا O(عدد العناصر)؛ راجع قيود التدفّق. يحمي معيار قياس أداء مسار عرض HTML من الانحدارات ببوّابة 5% (عمل مدمج، PR #564). ويمثّل performance_budget لكل صفحة (wall_ms: 1500، وpeak_mb: 64) السقف التشغيلي.
ملاحظات أمنية
قسم بعنوان «ملاحظات أمنية»المرحلة 1 هي خط الدفاع الأمني الأول: يعمل كلٌّ من حدّ المُدخل البالغ 10 MB، وإزالة محارف التحكّم، وتسوية نهايات الأسطر قبل الترميز. أثناء المرحلة 5، يُقيّد DefaultHtmlSecurityPolicy الوسوم والسمات وخصائص CSS ومخطّطات الروابط المسموح بها. راجع نموذج أمان وحدة HTML.
المطابقة
قسم بعنوان «المطابقة»تتبع تسوية نهايات الأسطر معالجة نهايات الأسطر في معيار HTML: يتحوّل CRLF وCR المفرد إلى LF. تُوثَّق مطابقة CSS لكل خاصية في مصفوفة دعم CSS، ويُوثَّق سلوك التتالي في css-resolver. ولا تُعيد هذه الصفحة عرض الدعم لكل خاصية.
السياق التجاري
قسم بعنوان «السياق التجاري»قدرة Enterprise. يُوسّع Premium تغطية CSS على المسار نفسه. لا يتغيّر تسلسل المراحل الست بين الإصدارات. راجع مصفوفة دعم CSS.