Fix failing instanceof when reading context

`instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is inside an iframe or when running in a protected environment. We could guess the types from their toString() value but let's keep things flexible and assume it's a sufficient condition if the item has a context2D which has item as `canvas`.
This commit is contained in:
Simon Brunel 2017-04-22 09:49:10 +02:00 committed by Evert Timberg
parent f2c569ef25
commit f7d2d7536a
3 changed files with 39 additions and 11 deletions

View File

@ -196,15 +196,21 @@ module.exports = function(Chart) {
item = item.canvas; item = item.canvas;
} }
if (item instanceof HTMLCanvasElement) { // To prevent canvas fingerprinting, some add-ons undefine the getContext
// To prevent canvas fingerprinting, some add-ons undefine the getContext // method, for example: https://github.com/kkapsner/CanvasBlocker
// method, for example: https://github.com/kkapsner/CanvasBlocker // https://github.com/chartjs/Chart.js/issues/2807
// https://github.com/chartjs/Chart.js/issues/2807 var context = item && item.getContext && item.getContext('2d');
var context = item.getContext && item.getContext('2d');
if (context instanceof CanvasRenderingContext2D) { // `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
initCanvas(item, config); // inside an iframe or when running in a protected environment. We could guess the
return context; // types from their toString() value but let's keep things flexible and assume it's
} // a sufficient condition if the item has a context2D which has item as `canvas`.
// https://github.com/chartjs/Chart.js/issues/3887
// https://github.com/chartjs/Chart.js/issues/4102
// https://github.com/chartjs/Chart.js/issues/4152
if (context && context.canvas === item) {
initCanvas(item, config);
return context;
} }
return null; return null;

View File

@ -93,9 +93,9 @@ function toBeValidChart() {
if (!(actual instanceof Chart)) { if (!(actual instanceof Chart)) {
message = 'Expected ' + actual + ' to be an instance of Chart'; message = 'Expected ' + actual + ' to be an instance of Chart';
} else if (!(actual.canvas instanceof HTMLCanvasElement)) { } else if (Object.prototype.toString.call(actual.canvas) !== '[object HTMLCanvasElement]') {
message = 'Expected canvas to be an instance of HTMLCanvasElement'; message = 'Expected canvas to be an instance of HTMLCanvasElement';
} else if (!(actual.ctx instanceof CanvasRenderingContext2D)) { } else if (Object.prototype.toString.call(actual.ctx) !== '[object CanvasRenderingContext2D]') {
message = 'Expected context to be an instance of CanvasRenderingContext2D'; message = 'Expected context to be an instance of CanvasRenderingContext2D';
} else if (typeof actual.height !== 'number' || !isFinite(actual.height)) { } else if (typeof actual.height !== 'number' || !isFinite(actual.height)) {
message = 'Expected height to be a strict finite number'; message = 'Expected height to be a strict finite number';

View File

@ -79,6 +79,28 @@ describe('Platform.dom', function() {
chart.destroy(); chart.destroy();
}); });
it('should accept a canvas from an iframe', function(done) {
var iframe = document.createElement('iframe');
iframe.onload = function() {
var doc = iframe.contentDocument;
doc.body.innerHTML += '<canvas id="chart"></canvas>';
var canvas = doc.getElementById('chart');
var chart = new Chart(canvas);
expect(chart).toBeValidChart();
expect(chart.canvas).toBe(canvas);
expect(chart.ctx).toBe(canvas.getContext('2d'));
chart.destroy();
canvas.remove();
iframe.remove();
done();
};
document.body.appendChild(iframe);
});
}); });
describe('config.options.aspectRatio', function() { describe('config.options.aspectRatio', function() {