Recent

Author Topic: Pixie: A lightweight HTML/CSS rendering engine for Free Pascal and Lazarus 🌟  (Read 14673 times)

dsiders

  • Hero Member
  • *****
  • Posts: 1635
@dsiders,

Is it a pure md rendering engine or it does more than just render ?   The reason I ask is because, having something that is really lightweight would be very nice, i.e, just rendering and nothing else.

The demo certainly is lightweight. Direct to Canvas.

https://gitlab.com/freepascal.org/lazarus/lazarus/-/blob/main/components/markdown/README.md?ref_type=heads

440bx

  • Hero Member
  • *****
  • Posts: 6540
The demo certainly is lightweight. Direct to Canvas.
I'll check it out.  Thank you dsiders.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Retrofoxed

  • Guest
Actually that's an interesting idea to add MD support to Pixie in addition to HTML. The simplest but ugly way would be converting MD to HTML, but for best performance and compact size it would need to be a separate implementation. I'll have a look at that - shouldn't be too hard MD is a lot simpler.,

Retrofoxed

  • Guest
Adding Markdown rendering to Pixie — two approaches

We're considering Markdown rendering support in Pixie. There are two viable paths and they have very different tradeoffs. Looking for input on which way to go.

Option A — MD → HTML → existing HTML engine

Convert Markdown to HTML in a small new unit, then feed the output to TPixieHtmlView. The HTML/CSS engine handles everything else.

Pros
  • Minimal new code: just a CommonMark/GFM → HTML converter (~1-2k lines, mostly parser).
  • Full CommonMark + GFM compliance for free, including raw HTML passthrough (<kbd>, <details>, <img width="...">, <sub>, <div align="center"> — common in real-world READMEs).
  • MD extensions are trivial: footnotes become anchored sections, task lists become checkboxes, math becomes MathML or img tags, mermaid becomes <pre class="mermaid">. Renderer doesn't change.
  • Full CSS-based theming: users can override anything per-element.
  • PDF export, image loading, SVG embedding, text selection, clipboard, find-in-page, link hover, focus, accessibility — all inherited from the existing HtmlView.
  • Future-proof: new MD features = parser-only changes.

Cons
  • Brings the entire HTML engine (~60k lines) into any application that wants Markdown rendering.
  • Heavier runtime: HTML parser builds a DOM, CSS cascade computes styles, formatting contexts run, render tree builds — even for a one-paragraph chat message.
  • Higher memory footprint per document.
  • Pays for HTML quirks (margin collapse, float positioning, complex layout) even where not needed.
  • Wrong shape for embedded log viewers, chat bubbles, or anything where you want a fast, lean MD widget.

Option B — parallel MD-only renderer

A self-contained Markdown engine: own parser, own minimal node tree, own layout pass. Depends only on common/ (canvas, font descriptions, colours, types).

Pros
  • Order-of-magnitude smaller: estimated ~3-5k lines total (parser + layout + inline wrapper + components).
  • Depends only on common/ — apps that don't need HTML don't pay for HTML.
  • Single-pass parse, single-pass layout. No CSS cascade, no style invalidation, no formatting-context machinery.
  • Predictable performance and memory — well-suited to log viewers, chat UIs, in-app help, notes apps.
  • Simple theme record (fonts, colours, spacing) covers the common customisation cases without CSS.
  • Same TPixieCanvas abstraction means D2D / Cairo / CG / Qt / FMX / PDF backends all work.

Cons
  • No HTML passthrough. Real-world .md files use HTML constructs constantly (<kbd>, <details>/<summary>, <img width="...">, <sub>, <div align="center">, etc.). CommonMark explicitly allows this; a pure-MD renderer mis-renders these into literal text or has to silently strip them. This is the load-bearing tradeoff.
  • Every MD extension (footnotes, task lists, math, mermaid, definition lists, front-matter) requires parser + node + layout + theme changes. Closed system.
  • No per-element styling — theme is global. "This one heading in red" requires inventing a directive syntax.
  • We re-implement features the HtmlView already has: text selection across blocks, clipboard formatting, link hit-testing, find-in-page, keyboard navigation. Each is bounded but still ~300-500 lines.
  • PDF export needs to be wired up explicitly (uses the same canvas API, but it's not free).
  • Inline math is genuinely hard without a real typesetter — likely punt to "code block" rendering.
  • Two parallel rendering codebases to maintain long-term.

Comparison at a glance

DimensionOption A (MD → HTML)Option B (parallel)
New code added~1-2k lines~3-5k lines
Total engine cost~60k lines (HTML engine)~3-5k + common/
PerformanceHTML pipeline overheadSingle-pass, lean
Memory per docHigher (DOM + render tree + computed styles)Low (flat node tree)
CommonMark complianceFull, including raw HTMLMD subset, no HTML
GFM extensionsEasy to add (parser only)Each requires layout work
Custom stylingFull CSSFixed theme record
PDF exportFreeWire up via PdfCanvas
Selection / clipboard / linksInheritedReimplement
Best fitRender arbitrary README files, full-fidelity docsChat / log / notes / in-app help

The real decision

The choice is essentially:

  • A if the goal is "render arbitrary .md files, including ones from the wild" with full fidelity, and the engine size cost is acceptable.
  • B if the goal is "fast, lean MD widget for our own content" where we control the input and never need HTML escape hatches, and minimising dependency footprint matters.

I am leaning towards option A. Thoughts?

440bx

  • Hero Member
  • *****
  • Posts: 6540
I am leaning towards option A. Thoughts?
I do too.   I think option B should be considered if genuinely significant cons appear in option A, which I believe is unlikely, except possibly for performance in really low end machines.  Also, the work required is significantly less, which is something that should be taken into account.

IOW, the extra effort required to implement option B should be considered only if some deficiency in the implementation of Option A justifies it.  In addition to that, since a lot of md files use HTML elements, it is actually more likely to be Option B to have cons that justify going with Option A.

It's an Einstein problem, make the md viewer as lean as possible but no leaner and, removing HTML support may actually make it leaner than it should be in the practical world.


FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

AlexTP

  • Hero Member
  • *****
  • Posts: 2714
    • UVviewsoft
I want the way B, please. The fastest reaction of MD control is wanted, when user changes the MD text in the editor.
« Last Edit: May 03, 2026, 09:30:23 am by AlexTP »

creaothceann

  • Sr. Member
  • ****
  • Posts: 375
I want the way B, please. The fastest reaction of MD control is wanted, when user changes the MD text in the editor.

A's speed may already be fast enough though, hard to say without knowing the size of your files.

AlexTP

  • Hero Member
  • *****
  • Posts: 2714
    • UVviewsoft
Size of files can be any average size of random MD files from the web, e.g. 10-30Kb.

Retrofoxed

  • Guest
MD view component has been implemented.

440bx

  • Hero Member
  • *****
  • Posts: 6540
Thank you @retrofoxed.  I most definitely plan to take it for an extended "walk" within the next few hours.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

AlexTP

  • Hero Member
  • *****
  • Posts: 2714
    • UVviewsoft
Great news. Thank you for MD component.

alaa123456789

  • Sr. Member
  • ****
  • Posts: 262
  • Try your Best to learn & help others
    • youtube:
hi , this great job , could you please add it to online package manager
regards

trapanator

  • New Member
  • *
  • Posts: 15
A question to the author: can I use the pdf export from HTML, without the GUI (headless mode)? It would be useful to produce mail merges. Chromium, for example, has --print-to-pdf option to export any html to pdf.

Retrofoxed

  • Guest
A question to the author: can I use the pdf export from HTML, without the GUI (headless mode)? It would be useful to produce mail merges. Chromium, for example, has --print-to-pdf option to export any html to pdf.

Yes — Pixie's PDF export is fully headless.

There's no GUI dependency at all: TPixiePdfExport takes an HTML string and writes a PDF, rendering through its own PDF canvas and built-in TrueType engine, so it never opens a window or touches a platform backend.

Code: Pascal  [Select][+][-]
  1. uses
  2.   Pixie.PdfExport;
  3.  
  4. var
  5.   Pdf: TPixiePdfExport;
  6. begin
  7.   Pdf := TPixiePdfExport.Create;
  8.   try
  9.     Pdf.PageSize := ppsA4;
  10.     Pdf.Margins  := TPixiePdfMargins.Create(56, 56, 56, 56); // points
  11.     Pdf.Title    := 'Invoice 1234';
  12.     Pdf.SaveToFile(MergedHtml, 'out\invoice_1234.pdf');
  13.     // or: Pdf.SaveToStream(MergedHtml, AStream);  // straight to memory / attachment
  14.   finally
  15.     Pdf.Free;
  16.   end;
  17. end.
  18.  

Loop that over your records and you've got a mail merge. Handy properties for it:

  • UserCss — inject a shared stylesheet without editing each merged document.
  • BaseUrl + OnFetchUrl — resolve and fetch images/CSS (e.g. logos, remote assets).
  • SaveToStream — render to a TStream with no temp file, e.g. to attach the PDF directly to an email.
  • PageSize / Margins / Title / Author — page setup and document metadata.

Multi-page documents paginate automatically, with break points chosen so block elements aren't split across pages. Fonts are embedded (and subsetted), so the output is self-contained and the text stays selectable/searchable.

One build note: a headless build still links the LCL package on the unit path (the engine pulls in LCLType/clipboard for its owner-drawn form controls), but nothing GUI is initialised at runtime — it runs fine as a console app.

wp

  • Hero Member
  • *****
  • Posts: 13571
That's very impressive...

The IDE uses the TurboPower IPro library for rendering its help texts (popup help, chm files in LHelp), and that is very buggy and incomplete. One idea:  Could you ask your AI to create a reduced version of pixie (html only, Lazarus only) for inclusion in the IDE, and to adapt LHelp and the popup hints to it?

 

TinyPortal © 2005-2018