这是一个复杂的问题。我创建了一个 Chrome 扩展,它将通过 WebSocket 从客户端接收 JSON-RPC 请求,使用 HTML 装饰呈现文本,并使用 PNG 图像响应客户端。我正在使用 Canvas 和 SVG 元素使用包含我正在呈现的 HTML 的 foreignObject 标记来呈现文本。除了当我需要使用外部字体时,这一切都很棒。这里发生了三个级别的间接,所以也许我对浏览器的要求太多了;但我希望不会。
您可能认为直接将文本渲染到 SVG 是一种选择,但这意味着我会失去一些 HTML 提供的丰富功能,例如自动换行。SVG 的自动换行有一些技巧,但我不想走那条路。这可能只是我遇到的许多问题中的第一个。
我需要的是 SVG 标记内的 HTML 来识别我希望它使用的外部字体。这只需要在 Chromium 中工作,因此特定于 Chromium 的解决方案对我来说是一个可行的选择。
<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'> 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>