htmlsvgtextfontsforeignobject

Having trouble rendering a custom external font within a ForeignObject's HTML of an SVG element


This is a complicated one. I've created a Chrome Extension that will receive JSON-RPC requests over a WebSocket from a client, render text using HTML decoration, and respond back to the client with a PNG image. I'm using a Canvas and an SVG element to render the text using the foreignObject tag that contains the HTML I'm rendering. This all works fantastic except for when I need to use an external font. There are three levels of indirection happening here, so maybe I'm asking too much of the browser; but I hope not.

You might think that rendering text directly to an SVG would be an option, but that means I would lose some of the rich features provided by HTML like word-wrap. There are hacks for word-wrap for SVGs, but I don't want to go down that road. That likely would be just the first of many problems I would encounter.

What I need is for the HTML inside of the SVG tag to recognize the external font I want it to use. This only needs to work in Chromium, so a solution specific to Chromium is a viable option for me.

<link rel='preload' href='https://fonts.gstatic.com/s/roboto/v27/KFOkCnqEu92Fr1MmgVxIIzI.woff2' as='font' crossorigin='anonymous' />
<style>@font-face { font-family: Roboto; src: url('https://fonts.gstatic.com/s/roboto/v27/KFOkCnqEu92Fr1MmgVxIIzI.woff2'); } body { font-family: Roboto; font-size: 28px; }</style>
<canvas style='position:absolute; top:90px; left:394px;' id='canvas'></canvas>
<div><span style="font-family:courier; font-size:20px">External straight-HTML (works): </span>Hello World!</div><br/>
<span style='font-family:courier; font-size:20px'>HTML within SVG (doesn't work): </span><br/><br/>
<span style='font-family:courier; font-size:20px'>&nbsp;&nbsp;Text directly to SVG (works): </span><br/><br/>

<script>

   // Get the canvas element from the above HTML and an associated context.
    var canvas = document.querySelector('#canvas');
    var ctx = canvas.getContext('2d');

    // Create an empty SVG image.
    var svg = new Image();

    // Before we set the svg.src value, we need to define what to do 
    // immediately after the svg element has completed loading.
    svg.onload = function() {

        // DOES NOT RENDER USING CORRECT FONT HERE.
        // Draw the image into the canvas context.  This is the HTML
        // source containing the foreign object that I wish to render
        // using the external font.
        ctx.drawImage(svg, 0, 0);
    
        // Prove that the SVG element itself can use the external font.
        // THIS WORKS, but is not what I want.
        ctx.font = "28px Roboto";
        ctx.fillText("Hello World!", 0, 80);
   }

    // Build HTML to create a SVG image generated from HTML.
    var source = "<svg xmlns='http://www.w3.org/2000/svg'>"
               + "<foreignObject width='2000' height='800' overflow='visible'>"
               + "<div xmlns='http://www.w3.org/1999/xhtml'>" 
               + "<link rel='preload' href='https://fonts.gstatic.com/s/roboto/v27/KFOkCnqEu92Fr1MmgVxIIzI.woff2' as='font' type='font/woff2' crossorigin='anonymous' />"
               + "<style>@font-face { font-family: Roboto; src: url('https://fonts.gstatic.com/s/roboto/v27/KFOkCnqEu92Fr1MmgVxIIzI.woff2); } body { font-family: Roboto; font-size: 28px; }</style>"
               + "<div>Hello World!</div>"
               + "</div>"
               + "</foreignObject>"
               + "</svg>";

    // This doesn't always work because sometimes the font isn't yet available even though we've theoretically preloaded the font.
    svg.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(source);

</script>


Solution

  • Special thanks to Robert Longson for setting me on the right track. The primary issue was that when you're setting the SVG's src data value, your SVG data must contain EVERYTHING it needs to draw the image within that source data. This is also true when using a foreign object. This is very different than drawing an SVG image on an HTML canvas. So (along with some other minor changes) the external font itself must be part of that src data, and therefore you must provide a data URL containing that font data. The other thing I had to do was explicitly specify which font to use within the div's style.

    <style id="myStyle">@font-face { font-family: Roboto; src: url('data:application/octet-stream;base64,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'); } body { font-family: Roboto; font-size: 28px; }</style>
    <canvas style='position:absolute; top:75px; left:394px;' id='canvas'></canvas>
    <div><span style="font-family:courier; font-size:20px">External straight-HTML (works): </span>Hello World!</div><br/>
    <span style='font-family:courier; font-size:20px'>&nbsp;&nbsp;&nbsp;HTML within SVG (now works): </span><br/><br/>
    <span style='font-family:courier; font-size:20px'>&nbsp;&nbsp;Text directly to SVG (works): </span><br/><br/>
    
    <script>
    
        // Get the canvas element from the above HTML and an associated context.
        var canvas = document.querySelector('#canvas');
        var ctx = canvas.getContext('2d');
    
        // Create an empty SVG image.
        var svg = new Image();
    
        // Before we set the svg.src value, we need to define what to do 
        // immediately after the svg element has completed loading.
        svg.onload = function() {
    
            // Draw the image into the canvas context.  This is the HTML
            // source containing the foreign object that I wish to render
            // using the external font.  THIS NOW WORKS.
            ctx.drawImage(svg, 0, 0);
        
            // Prove that the SVG element itself can use the external font.
            // THIS WORKS, but is not what I want.
            ctx.font = "28px Roboto";
            ctx.fillText("Hello World!", 0, 95);
        }
    
        // Hacky way of getting the data URI from the above HTML.
        // I would have just duplicated the data URI below, but Stack 
        // Overflow limits the size of this source, and that would make
        // it too big, so I have to programmatically extract it.
        var dataUri = document.getElementById("myStyle").innerText.split("url('")[1].split("');")[0];
        
        // Build HTML to create a SVG image generated from HTML.
        var source = "<svg xmlns='http://www.w3.org/2000/svg'>"
        
                   // Beginning of foreign object.
                   + "<foreignObject width='2000' height='800' overflow='visible'><div xmlns='http://www.w3.org/1999/xhtml'>" 
    
                   // This NOW WORKS inside of the foreign object.
                   + "<style>@font-face { font-family: Roboto; src: url('" + dataUri + "'); }</style>"
                   + "<div style='font-family:Roboto; font-size:28px'>Hello World!</div>"
    
                   // End of foreign object.
                   + "</div></foreignObject>"
                   + "</svg>";
    
        // Set the SVG source data now.
        svg.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(source);
    
    </script>