diff --git a/src/Feature.js b/src/Feature.js
index 2e158da..a0cda97 100644
--- a/src/Feature.js
+++ b/src/Feature.js
@@ -1,6 +1,8 @@
/* @flow */
'use strict';
+import {createForeignObjectSVG, loadSerializedSVG} from './renderer/ForeignObjectRenderer';
+
const testRangeBounds = document => {
const TEST_HEIGHT = 123;
@@ -72,40 +74,45 @@ const testSVG = document => {
return true;
};
+const isGreenPixel = data => data[0] === 0 && data[1] === 255 && data[2] === 0 && data[3] === 255;
+
const testForeignObject = document => {
- const img = new Image();
const canvas = document.createElement('canvas');
- canvas.width = 1;
- canvas.height = 1;
+ const size = 100;
+ canvas.width = size;
+ canvas.height = size;
const ctx = canvas.getContext('2d');
+ ctx.fillStyle = 'rgb(0, 255, 0)';
+ ctx.fillRect(0, 0, size, size);
+
+ const img = new Image();
+ const greenImageSrc = canvas.toDataURL();
+ img.src = greenImageSrc;
+ const svg = createForeignObjectSVG(size, size, img);
ctx.fillStyle = 'red';
- ctx.fillRect(0, 0, 1, 1);
+ ctx.fillRect(0, 0, size, size);
- img.src = `data:image/svg+xml,`;
+ return loadSerializedSVG(svg)
+ .then(img => {
+ ctx.drawImage(img, 0, 0);
+ const data = ctx.getImageData(0, 0, size, size).data;
+ ctx.fillStyle = 'red';
+ ctx.fillRect(0, 0, size, size);
- return new Promise(resolve => {
- const onload = () => {
- try {
- ctx.drawImage(img, 0, 0);
- canvas.toDataURL();
- } catch (e) {
- return resolve(false);
- }
-
- return resolve(true);
- };
-
- img.onload = onload;
- img.onerror = () => resolve(false);
-
- if (img.complete === true) {
- setTimeout(() => {
- onload();
- }, 50);
- }
- });
+ const node = document.createElement('div');
+ node.style.backgroundImage = `url(${greenImageSrc})`;
+ node.style.height = `${size}px`;
+ // Firefox 55 does not render inline
tags
+ return isGreenPixel(data)
+ ? loadSerializedSVG(createForeignObjectSVG(size, size, node))
+ : Promise.reject(false);
+ })
+ .then(img => {
+ ctx.drawImage(img, 0, 0);
+ // Edge does not render background-images
+ return isGreenPixel(ctx.getImageData(0, 0, size, size).data);
+ })
+ .catch(e => false);
};
const FEATURES = {
diff --git a/src/renderer/ForeignObjectRenderer.js b/src/renderer/ForeignObjectRenderer.js
index 81a10eb..10a7f40 100644
--- a/src/renderer/ForeignObjectRenderer.js
+++ b/src/renderer/ForeignObjectRenderer.js
@@ -19,36 +19,48 @@ export default class ForeignObjectRenderer {
this.ctx.scale(this.options.scale, this.options.scale);
options.logger.log(`ForeignObject renderer initialized with scale ${this.options.scale}`);
+ const svg = createForeignObjectSVG(
+ options.bounds.width,
+ options.bounds.height,
+ this.element
+ );
- const xmlns = 'http://www.w3.org/2000/svg';
- const svg = document.createElementNS(xmlns, 'svg');
- const foreignObject = document.createElementNS(xmlns, 'foreignObject');
- svg.setAttributeNS(null, 'width', options.bounds.width);
- svg.setAttributeNS(null, 'height', options.bounds.height);
-
- foreignObject.setAttributeNS(null, 'width', '100%');
- foreignObject.setAttributeNS(null, 'height', '100%');
- foreignObject.setAttributeNS(null, 'externalResourcesRequired', 'true');
- svg.appendChild(foreignObject);
-
- foreignObject.appendChild(this.element);
-
- return new Promise((resolve, reject) => {
- const img = new Image();
- img.onload = () => {
- if (options.backgroundColor) {
- this.ctx.fillStyle = options.backgroundColor.toString();
- this.ctx.fillRect(0, 0, options.bounds.width, options.bounds.height);
- }
- this.ctx.drawImage(img, 0, 0);
- resolve(this.canvas);
- };
-
- img.onerror = reject;
-
- img.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(
- new XMLSerializer().serializeToString(svg)
- )}`;
+ return loadSerializedSVG(svg).then(img => {
+ if (options.backgroundColor) {
+ this.ctx.fillStyle = options.backgroundColor.toString();
+ this.ctx.fillRect(0, 0, options.bounds.width, options.bounds.height);
+ }
+ this.ctx.drawImage(img, 0, 0);
+ return this.canvas;
});
}
}
+
+export const createForeignObjectSVG = (width: number, height: number, node: Node) => {
+ const xmlns = 'http://www.w3.org/2000/svg';
+ const svg = document.createElementNS(xmlns, 'svg');
+ const foreignObject = document.createElementNS(xmlns, 'foreignObject');
+ svg.setAttributeNS(null, 'width', width);
+ svg.setAttributeNS(null, 'height', height);
+
+ foreignObject.setAttributeNS(null, 'width', '100%');
+ foreignObject.setAttributeNS(null, 'height', '100%');
+ foreignObject.setAttributeNS(null, 'externalResourcesRequired', 'true');
+ svg.appendChild(foreignObject);
+
+ foreignObject.appendChild(node);
+
+ return svg;
+};
+
+export const loadSerializedSVG = (svg: Node) => {
+ return new Promise((resolve, reject) => {
+ const img = new Image();
+ img.onload = () => resolve(img);
+ img.onerror = reject;
+
+ img.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(
+ new XMLSerializer().serializeToString(svg)
+ )}`;
+ });
+};