diff --git a/build.json b/build.json index 3b6fbc3..80217c7 100644 --- a/build.json +++ b/build.json @@ -10,10 +10,13 @@ "src/wrappers/CharacterData.js", "src/wrappers/Element.js", "src/wrappers/HTMLElement.js", + "src/wrappers/HTMLCanvasElement.js", "src/wrappers/HTMLContentElement.js", "src/wrappers/HTMLShadowElement.js", "src/wrappers/HTMLTemplateElement.js", "src/wrappers/HTMLUnknownElement.js", + "src/wrappers/CanvasRenderingContext2D.js", + "src/wrappers/WebGLRenderingContext.js", "src/wrappers/generic.js", "src/wrappers/ShadowRoot.js", "src/ShadowRenderer.js", diff --git a/shadowdom.js b/shadowdom.js index 98c76b4..e6a4858 100644 --- a/shadowdom.js +++ b/shadowdom.js @@ -26,10 +26,13 @@ 'src/wrappers/CharacterData.js', 'src/wrappers/Element.js', 'src/wrappers/HTMLElement.js', + 'src/wrappers/HTMLCanvasElement.js', 'src/wrappers/HTMLContentElement.js', 'src/wrappers/HTMLShadowElement.js', 'src/wrappers/HTMLTemplateElement.js', 'src/wrappers/HTMLUnknownElement.js', + 'src/wrappers/CanvasRenderingContext2D.js', + 'src/wrappers/WebGLRenderingContext.js', 'src/wrappers/generic.js', 'src/wrappers/ShadowRoot.js', 'src/ShadowRenderer.js', diff --git a/src/wrappers.js b/src/wrappers.js index c3795c6..cbb703b 100644 --- a/src/wrappers.js +++ b/src/wrappers.js @@ -228,17 +228,22 @@ var ShadowDOMPolyfill = {}; return GeneratedWrapper; } - var OriginalDOMImplementation = DOMImplementation; - var OriginalEvent = Event; - var OriginalNode = Node; - var OriginalWindow = Window; - var OriginalRange = Range; + var OriginalDOMImplementation = window.DOMImplementation; + var OriginalEvent = window.Event; + var OriginalNode = window.Node; + var OriginalWindow = window.Window; + var OriginalRange = window.Range; + var OriginalCanvasRenderingContext2D = window.CanvasRenderingContext2D; + var OriginalWebGLRenderingContext = window.WebGLRenderingContext; function isWrapper(object) { return object instanceof wrappers.EventTarget || object instanceof wrappers.Event || object instanceof wrappers.Range || - object instanceof wrappers.DOMImplementation; + object instanceof wrappers.DOMImplementation || + object instanceof wrappers.CanvasRenderingContext2D || + wrappers.WebGLRenderingContext && + object instanceof wrappers.WebGLRenderingContext; } function isNative(object) { @@ -246,7 +251,10 @@ var ShadowDOMPolyfill = {}; object instanceof OriginalEvent || object instanceof OriginalWindow || object instanceof OriginalRange || - object instanceof OriginalDOMImplementation; + object instanceof OriginalDOMImplementation || + object instanceof OriginalCanvasRenderingContext2D || + OriginalWebGLRenderingContext && + object instanceof OriginalWebGLRenderingContext; } /** diff --git a/src/wrappers/CanvasRenderingContext2D.js b/src/wrappers/CanvasRenderingContext2D.js new file mode 100644 index 0000000..7aaf236 --- /dev/null +++ b/src/wrappers/CanvasRenderingContext2D.js @@ -0,0 +1,38 @@ +// Copyright 2013 The Polymer Authors. All rights reserved. +// Use of this source code is goverened by a BSD-style +// license that can be found in the LICENSE file. + +(function(scope) { + 'use strict'; + + var mixin = scope.mixin; + var registerWrapper = scope.registerWrapper; + var unwrap = scope.unwrap; + var wrap = scope.wrap; + + var OriginalCanvasRenderingContext2D = window.CanvasRenderingContext2D; + + function CanvasRenderingContext2D(impl) { + this.impl = impl; + } + + mixin(CanvasRenderingContext2D.prototype, { + get canvas() { + return wrap(this.impl.canvas); + }, + + drawImage: function() { + arguments[0] = unwrap(arguments[0]); + this.impl.drawImage.apply(this.impl, arguments); + }, + + createPattern: function() { + arguments[0] = unwrap(arguments[0]); + return this.impl.createPattern.apply(this.impl, arguments); + } + }); + + registerWrapper(OriginalCanvasRenderingContext2D, CanvasRenderingContext2D); + + scope.wrappers.CanvasRenderingContext2D = CanvasRenderingContext2D; +})(this.ShadowDOMPolyfill); diff --git a/src/wrappers/HTMLCanvasElement.js b/src/wrappers/HTMLCanvasElement.js new file mode 100644 index 0000000..8a05495 --- /dev/null +++ b/src/wrappers/HTMLCanvasElement.js @@ -0,0 +1,30 @@ +// Copyright 2013 The Polymer Authors. All rights reserved. +// Use of this source code is goverened by a BSD-style +// license that can be found in the LICENSE file. + +(function(scope) { + 'use strict'; + + var HTMLElement = scope.wrappers.HTMLElement; + var mixin = scope.mixin; + var registerWrapper = scope.registerWrapper; + var wrap = scope.wrap; + + var OriginalHTMLCanvasElement = window.HTMLCanvasElement; + + function HTMLCanvasElement(node) { + HTMLElement.call(this, node); + } + HTMLCanvasElement.prototype = Object.create(HTMLElement.prototype); + + mixin(HTMLCanvasElement.prototype, { + getContext: function() { + var context = this.impl.getContext.apply(this.impl, arguments); + return context && wrap(context); + } + }); + + registerWrapper(OriginalHTMLCanvasElement, HTMLCanvasElement); + + scope.wrappers.HTMLCanvasElement = HTMLCanvasElement; +})(this.ShadowDOMPolyfill); diff --git a/src/wrappers/WebGLRenderingContext.js b/src/wrappers/WebGLRenderingContext.js new file mode 100644 index 0000000..74de34f --- /dev/null +++ b/src/wrappers/WebGLRenderingContext.js @@ -0,0 +1,42 @@ +// Copyright 2013 The Polymer Authors. All rights reserved. +// Use of this source code is goverened by a BSD-style +// license that can be found in the LICENSE file. + +(function(scope) { + 'use strict'; + + var mixin = scope.mixin; + var registerWrapper = scope.registerWrapper; + var unwrap = scope.unwrap; + var wrap = scope.wrap; + + var OriginalWebGLRenderingContext = window.WebGLRenderingContext; + + // IE10 does not have WebGL. + if (!OriginalWebGLRenderingContext) + return; + + function WebGLRenderingContext(impl) { + this.impl = impl; + } + + mixin(WebGLRenderingContext.prototype, { + get canvas() { + return wrap(this.impl.canvas); + }, + + texImage2D: function() { + arguments[5] = unwrap(arguments[5]); + this.impl.texImage2D.apply(this.impl, arguments); + }, + + texSubImage2D: function() { + arguments[6] = unwrap(arguments[6]); + this.impl.texSubImage2D.apply(this.impl, arguments); + } + }); + + registerWrapper(OriginalWebGLRenderingContext, WebGLRenderingContext); + + scope.wrappers.WebGLRenderingContext = WebGLRenderingContext; +})(this.ShadowDOMPolyfill); diff --git a/test/js/HTMLCanvasElement.js b/test/js/HTMLCanvasElement.js new file mode 100644 index 0000000..d732ab3 --- /dev/null +++ b/test/js/HTMLCanvasElement.js @@ -0,0 +1,101 @@ +/* + * Copyright 2013 The Polymer Authors. All rights reserved. + * Use of this source code is goverened by a BSD-style + * license that can be found in the LICENSE file. + */ + +suite('HTMLCanvasElement', function() { + + var iconUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAHklEQVQ4T2Nk+A+EFADGUQMYRsOAYTQMgHloGKQDAJXkH/HZpKBrAAAAAElFTkSuQmCC'; + + test('getContext null', function() { + var canvas = document.createElement('canvas'); + // IE10 returns undefined instead of null + assert.isTrue(canvas.getContext('unknown') == null); + }); + + test('getContext 2d', function() { + var canvas = document.createElement('canvas'); + var context = canvas.getContext('2d'); + assert.instanceOf(context, CanvasRenderingContext2D); + assert.equal(context.canvas, canvas); + }); + + test('getContext webgl', function() { + // IE10 does not have WebGL. + if (typeof WebGLRenderingContext === 'undefined') + return; + + var canvas = document.createElement('canvas'); + var context = canvas.getContext('webgl'); + // Chrome returns null if the graphics drivers are not good enough. + assert.isTrue(context === null || context instanceof WebGLRenderingContext); + + if (context != null) + assert.equal(context.canvas, canvas); + }); + + test('2d drawImage', function(done) { + var canvas = document.createElement('canvas'); + var context = canvas.getContext('2d'); + + var img = document.createElement('img'); + img.onload = function() { + context.drawImage(img, 0, 0); + done(); + }; + img.src = iconUrl; + }); + + test('2d createPattern', function(done) { + var canvas = document.createElement('canvas'); + var context = canvas.getContext('2d'); + var img = document.createElement('img'); + img.onload = function() { + var pattern = context.createPattern(img, 'repeat'); + done(); + }; + img.src = iconUrl; + }); + + test('WebGL texImage2D', function(done) { + var canvas = document.createElement('canvas'); + var gl = canvas.getContext('webgl'); + // IE10 does not have WebGL. + // Chrome returns null if the graphics card is not supported + if (!gl) { + done(); + return; + } + + var img = document.createElement('img'); + img.onload = function() { + var texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img); + done(); + }; + img.src = iconUrl; + }); + + test('WebGL texSubImage2D', function(done) { + var canvas = document.createElement('canvas'); + var gl = canvas.getContext('webgl'); + // IE10 does not have WebGL. + // Chrome returns null if the graphics card is not supported + if (!gl) { + done(); + return; + } + + var img = document.createElement('img'); + img.onload = function() { + var texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, img); + done(); + }; + img.src = iconUrl; + }); + +}); diff --git a/test/test.main.js b/test/test.main.js index 2a91cde..5273f20 100644 --- a/test/test.main.js +++ b/test/test.main.js @@ -56,6 +56,7 @@ var modules = [ 'Element.js', 'HTMLBodyElement.js', 'HTMLButtonElement.js', + 'HTMLCanvasElement.js', 'HTMLContentElement.js', 'HTMLFieldSetElement.js', 'HTMLHeadElement.js',