Hacker News new | ask | show | jobs
by chrismorgan 1636 days ago
<foreignObject> is a required part of SVG; but specific foreign namespaces like HTML, well, they’re not part of the spec at all; it just so happens that browsers all implement the same obvious but unspecified behaviour. In fact, the spec’s quite silly on the point of HTML in SVG, because you should be able to do something like this to use HTML in renderers that support that and fall back to SVG text otherwise:

  <switch>
    <foreignObject requiredExtensions="http://www.w3.org/1999/xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">…</div>
    </foreignObject>
    <text>…</text>
  </switch>
… except that no values for requiredExtensions were ever specified, so including this attribute will make some HTML-capable renderers use the fallback, and omitting it will cause all correct SVG renderers to use the <foreignObject> (rendering nothing if they don’t support the HTML namespace) and ignore the <text>. Quite why they preemptively didn’t declare XML namespaces valid extensions, I don’t know; not doing so rendered the entire feature uselessly broken for its main intended use case! (I dunno, maybe all browsers implement requiredExtensions="http://www.w3.org/1999/xhtml" now; the thread at https://www.w3.org/Graphics/SVG/WG/track/issues/2053 talks of Amaya emitting it and Firefox not liking it back in 2008, and https://github.com/w3c/svgwg/issues/138 talks of Firefox accepting it in 2016. I haven’t tested anything.)

—⁂—

To do manual word wrapping, you have two main choices:

(a) If it’s acceptable to use HTML at conversion time, Range does all you need, with Range.getClientRects on a range spanning an element returning more than one value if wrapping has occurred, and then you can do something like binary search on the process to find the point of line break, or you can get cleverer if you like to speed it up.

(b) If not, you’ll need to embed at least an OpenType font loader and shaper. HarfBuzz is a good choice for this, with a WASM version readily available (among other options); https://harfbuzz.github.io/harfbuzzjs/ demonstrates it. There are at least three pretty decent options in Rust, too (in alphabetical order: Allsorts, RustyBuzz, Swash), and a few immature libraries covering more to do with rich text formatting (including wrapping) rather than just stopping at shaping.

I’m pretty sure I’ve heard of at least one full HTML-to-SVG renderer that ran in the browser, too, used in such places as filing bug reports to take a “screenshot” of the page. HTML → PDF → SVG is very probably a more practical path for this in your case.