diff --git a/src/ShadowRenderer.js b/src/ShadowRenderer.js index 42732b6..1c9079e 100644 --- a/src/ShadowRenderer.js +++ b/src/ShadowRenderer.js @@ -14,6 +14,7 @@ var getTreeScope = scope.getTreeScope; var mixin = scope.mixin; var oneOf = scope.oneOf; + var unsafeUnwrap = scope.unsafeUnwrap; var unwrap = scope.unwrap; var wrap = scope.wrap; @@ -484,7 +485,7 @@ }, associateNode: function(node) { - node.impl.polymerShadowRenderer_ = this; + unsafeUnwrap(node).polymerShadowRenderer_ = this; } }; @@ -607,7 +608,7 @@ * This gets called when a node was added or removed to it. */ Node.prototype.invalidateShadowRenderer = function(force) { - var renderer = this.impl.polymerShadowRenderer_; + var renderer = unsafeUnwrap(this).polymerShadowRenderer_; if (renderer) { renderer.invalidate(); return true; @@ -638,7 +639,7 @@ var renderer; if (shadowRoot) renderer = getRendererForShadowRoot(shadowRoot); - this.impl.polymerShadowRenderer_ = renderer; + unsafeUnwrap(this).polymerShadowRenderer_ = renderer; if (renderer) renderer.invalidate(); }; diff --git a/src/querySelector.js b/src/querySelector.js index 96bf2ec..b6b97cb 100644 --- a/src/querySelector.js +++ b/src/querySelector.js @@ -8,6 +8,7 @@ var HTMLCollection = scope.wrappers.HTMLCollection; var NodeList = scope.wrappers.NodeList; var getTreeScope = scope.getTreeScope; + var unsafeUnwrap = scope.unsafeUnwrap; var wrap = scope.wrap; var originalDocumentQuerySelector = document.querySelector; @@ -37,7 +38,7 @@ } result[index++] = wrappedItem; } - + return index; } @@ -98,7 +99,7 @@ // http://www.w3.org/TR/css3-selectors/#simple-selectors function querySelectorAllFiltered (p, index, result, selector) { - var target = this.impl; + var target = unsafeUnwrap(this); var list; var root = getTreeScope(this).root; if (root instanceof scope.wrappers.ShadowRoot) { @@ -120,7 +121,7 @@ var SelectorsInterface = { querySelector: function(selector) { - var target = this.impl; + var target = unsafeUnwrap(this); var wrappedItem; var root = getTreeScope(this).root; if (root instanceof scope.wrappers.ShadowRoot) { @@ -165,7 +166,7 @@ }; function getElementsByTagNameFiltered (p, index, result, localName, lowercase) { - var target = this.impl; + var target = unsafeUnwrap(this); var list; var root = getTreeScope(this).root; if (root instanceof scope.wrappers.ShadowRoot) { @@ -186,7 +187,7 @@ } function getElementsByTagNameNSFiltered (p, index, result, ns, localName) { - var target = this.impl; + var target = unsafeUnwrap(this); var list; var root = getTreeScope(this).root; if (root instanceof scope.wrappers.ShadowRoot) { diff --git a/src/wrappers.js b/src/wrappers.js index 527cdb5..0e5bc15 100644 --- a/src/wrappers.js +++ b/src/wrappers.js @@ -136,23 +136,31 @@ window.ShadowDOMPolyfill = {}; return /^\w[a-zA-Z_0-9]*$/.test(name); } + // The name of the implementation property is intentionally hard to + // remember. Unfortunately, browsers are slower doing obj[expr] than + // obj.foo so we resort to repeat this ugly name. This ugly name is never + // used outside of this file though. + function getGetter(name) { return hasEval && isIdentifierName(name) ? - new Function('return this.impl.' + name) : - function() { return this.impl[name]; }; + new Function('return this.__impl4cf1e782hg__.' + name) : + function() { return this.__impl4cf1e782hg__[name]; }; } function getSetter(name) { return hasEval && isIdentifierName(name) ? - new Function('v', 'this.impl.' + name + ' = v') : - function(v) { this.impl[name] = v; }; + new Function('v', 'this.__impl4cf1e782hg__.' + name + ' = v') : + function(v) { this.__impl4cf1e782hg__[name] = v; }; } function getMethod(name) { return hasEval && isIdentifierName(name) ? - new Function('return this.impl.' + name + - '.apply(this.impl, arguments)') : - function() { return this.impl[name].apply(this.impl, arguments); }; + new Function('return this.__impl4cf1e782hg__.' + name + + '.apply(this.__impl4cf1e782hg__, arguments)') : + function() { + return this.__impl4cf1e782hg__[name].apply( + this.__impl4cf1e782hg__, arguments); + }; } function getDescriptor(source, name) { @@ -273,41 +281,12 @@ window.ShadowDOMPolyfill = {}; return GeneratedWrapper; } - var OriginalDOMImplementation = window.DOMImplementation; - var OriginalEventTarget = window.EventTarget; - var OriginalEvent = window.Event; - var OriginalNode = window.Node; - var OriginalWindow = window.Window; - var OriginalRange = window.Range; - var OriginalCanvasRenderingContext2D = window.CanvasRenderingContext2D; - var OriginalWebGLRenderingContext = window.WebGLRenderingContext; - var OriginalSVGElementInstance = window.SVGElementInstance; - var OriginalFormData = window.FormData; - function isWrapper(object) { - return object instanceof wrappers.EventTarget || - object instanceof wrappers.Event || - object instanceof wrappers.Range || - object instanceof wrappers.DOMImplementation || - object instanceof wrappers.CanvasRenderingContext2D || - object instanceof wrappers.FormData || - wrappers.WebGLRenderingContext && - object instanceof wrappers.WebGLRenderingContext; + return object && object.__impl4cf1e782hg__; } function isNative(object) { - return OriginalEventTarget && object instanceof OriginalEventTarget || - object instanceof OriginalNode || - object instanceof OriginalEvent || - object instanceof OriginalWindow || - object instanceof OriginalRange || - object instanceof OriginalDOMImplementation || - object instanceof OriginalCanvasRenderingContext2D || - object instanceof OriginalFormData || - OriginalWebGLRenderingContext && - object instanceof OriginalWebGLRenderingContext || - OriginalSVGElementInstance && - object instanceof OriginalSVGElementInstance; + return !isWrapper(object); } /** @@ -321,8 +300,8 @@ window.ShadowDOMPolyfill = {}; return null; assert(isNative(impl)); - return impl.polymerWrapper_ || - (impl.polymerWrapper_ = new (getWrapperConstructor(impl))(impl)); + return impl.__wrapper8e3dd93a60__ || + (impl.__wrapper8e3dd93a60__ = new (getWrapperConstructor(impl))(impl)); } /** @@ -334,7 +313,16 @@ window.ShadowDOMPolyfill = {}; if (wrapper === null) return null; assert(isWrapper(wrapper)); - return wrapper.impl; + return wrapper.__impl4cf1e782hg__; + } + + function unsafeUnwrap(wrapper) { + return wrapper.__impl4cf1e782hg__; + } + + function setWrapper(impl, wrapper) { + wrapper.__impl4cf1e782hg__ = impl; + impl.__wrapper8e3dd93a60__ = wrapper; } /** @@ -366,7 +354,7 @@ window.ShadowDOMPolyfill = {}; return; assert(isNative(node)); assert(wrapper === undefined || isWrapper(wrapper)); - node.polymerWrapper_ = wrapper; + node.__wrapper8e3dd93a60__ = wrapper; } var getterDescriptor = { @@ -382,7 +370,7 @@ window.ShadowDOMPolyfill = {}; function defineWrapGetter(constructor, name) { defineGetter(constructor, name, function() { - return wrap(this.impl[name]); + return wrap(this.__impl4cf1e782hg__[name]); }); } @@ -417,6 +405,8 @@ window.ShadowDOMPolyfill = {}; scope.registerObject = registerObject; scope.registerWrapper = register; scope.rewrap = rewrap; + scope.setWrapper = setWrapper; + scope.unsafeUnwrap = unsafeUnwrap; scope.unwrap = unwrap; scope.unwrapIfNeeded = unwrapIfNeeded; scope.wrap = wrap; diff --git a/src/wrappers/CanvasRenderingContext2D.js b/src/wrappers/CanvasRenderingContext2D.js index 5d600d6..dcbfef6 100644 --- a/src/wrappers/CanvasRenderingContext2D.js +++ b/src/wrappers/CanvasRenderingContext2D.js @@ -7,6 +7,8 @@ var mixin = scope.mixin; var registerWrapper = scope.registerWrapper; + var setWrapper = scope.setWrapper; + var unsafeUnwrap = scope.unsafeUnwrap; var unwrap = scope.unwrap; var unwrapIfNeeded = scope.unwrapIfNeeded; var wrap = scope.wrap; @@ -14,22 +16,22 @@ var OriginalCanvasRenderingContext2D = window.CanvasRenderingContext2D; function CanvasRenderingContext2D(impl) { - this.impl = impl; + setWrapper(impl, this); } mixin(CanvasRenderingContext2D.prototype, { get canvas() { - return wrap(this.impl.canvas); + return wrap(unsafeUnwrap(this).canvas); }, drawImage: function() { arguments[0] = unwrapIfNeeded(arguments[0]); - this.impl.drawImage.apply(this.impl, arguments); + unsafeUnwrap(this).drawImage.apply(unsafeUnwrap(this), arguments); }, createPattern: function() { arguments[0] = unwrap(arguments[0]); - return this.impl.createPattern.apply(this.impl, arguments); + return unsafeUnwrap(this).createPattern.apply(unsafeUnwrap(this), arguments); } }); diff --git a/src/wrappers/CharacterData.js b/src/wrappers/CharacterData.js index e2655ff..061da86 100644 --- a/src/wrappers/CharacterData.js +++ b/src/wrappers/CharacterData.js @@ -10,6 +10,7 @@ var enqueueMutation = scope.enqueueMutation; var mixin = scope.mixin; var registerWrapper = scope.registerWrapper; + var unsafeUnwrap = scope.unsafeUnwrap; var OriginalCharacterData = window.CharacterData; @@ -25,14 +26,14 @@ this.data = value; }, get data() { - return this.impl.data; + return unsafeUnwrap(this).data; }, set data(value) { - var oldValue = this.impl.data; + var oldValue = unsafeUnwrap(this).data; enqueueMutation(this, 'characterData', { oldValue: oldValue }); - this.impl.data = value; + unsafeUnwrap(this).data = value; } }); diff --git a/src/wrappers/DOMTokenList.js b/src/wrappers/DOMTokenList.js index d9e4381..84b62e2 100644 --- a/src/wrappers/DOMTokenList.js +++ b/src/wrappers/DOMTokenList.js @@ -5,40 +5,43 @@ (function(scope) { 'use strict'; + var setWrapper = scope.setWrapper; + var unsafeUnwrap = scope.unsafeUnwrap; + function invalidateClass(el) { scope.invalidateRendererBasedOnAttribute(el, 'class'); } function DOMTokenList(impl, ownerElement) { - this.impl = impl; + setWrapper(impl, this); this.ownerElement_ = ownerElement; } DOMTokenList.prototype = { get length() { - return this.impl.length; + return unsafeUnwrap(this).length; }, item: function(index) { - return this.impl.item(index); + return unsafeUnwrap(this).item(index); }, contains: function(token) { - return this.impl.contains(token); + return unsafeUnwrap(this).contains(token); }, add: function() { - this.impl.add.apply(this.impl, arguments); + unsafeUnwrap(this).add.apply(unsafeUnwrap(this), arguments); invalidateClass(this.ownerElement_); }, remove: function() { - this.impl.remove.apply(this.impl, arguments); + unsafeUnwrap(this).remove.apply(unsafeUnwrap(this), arguments); invalidateClass(this.ownerElement_); }, toggle: function(token) { - var rv = this.impl.toggle.apply(this.impl, arguments); + var rv = unsafeUnwrap(this).toggle.apply(unsafeUnwrap(this), arguments); invalidateClass(this.ownerElement_); return rv; }, toString: function() { - return this.impl.toString(); + return unsafeUnwrap(this).toString(); } }; diff --git a/src/wrappers/Document.js b/src/wrappers/Document.js index 8769773..6f0b5d6 100644 --- a/src/wrappers/Document.js +++ b/src/wrappers/Document.js @@ -21,6 +21,8 @@ var registerWrapper = scope.registerWrapper; var renderAllPending = scope.renderAllPending; var rewrap = scope.rewrap; + var setWrapper = scope.setWrapper; + var unsafeUnwrap = scope.unsafeUnwrap; var unwrap = scope.unwrap; var wrap = scope.wrap; var wrapEventTargetMethods = scope.wrapEventTargetMethods; @@ -47,7 +49,7 @@ function wrapMethod(name) { var original = document[name]; Document.prototype[name] = function() { - return wrap(original.apply(this.impl, arguments)); + return wrap(original.apply(unsafeUnwrap(this), arguments)); }; } @@ -66,7 +68,7 @@ var originalAdoptNode = document.adoptNode; function adoptNodeNoRemove(node, doc) { - originalAdoptNode.call(doc.impl, unwrap(node)); + originalAdoptNode.call(unsafeUnwrap(doc), unwrap(node)); adoptSubtree(node, doc); } @@ -99,7 +101,7 @@ return elementFromPoint(this, this, x, y); }, importNode: function(node, deep) { - return cloneNode(node, deep, this.impl); + return cloneNode(node, deep, unsafeUnwrap(this)); }, getSelection: function() { renderAllPending(); @@ -194,7 +196,7 @@ return document.createElement(tagName); } } - this.impl = node; + setWrapper(node, this); } CustomElementConstructor.prototype = prototype; CustomElementConstructor.prototype.constructor = CustomElementConstructor; @@ -291,20 +293,20 @@ ]); function DOMImplementation(impl) { - this.impl = impl; + setWrapper(impl, this); } function wrapImplMethod(constructor, name) { var original = document.implementation[name]; constructor.prototype[name] = function() { - return wrap(original.apply(this.impl, arguments)); + return wrap(original.apply(unsafeUnwrap(this), arguments)); }; } function forwardImplMethod(constructor, name) { var original = document.implementation[name]; constructor.prototype[name] = function() { - return original.apply(this.impl, arguments); + return original.apply(unsafeUnwrap(this), arguments); }; } diff --git a/src/wrappers/Element.js b/src/wrappers/Element.js index c4c9398..4a199b4 100644 --- a/src/wrappers/Element.js +++ b/src/wrappers/Element.js @@ -16,7 +16,7 @@ var mixin = scope.mixin; var oneOf = scope.oneOf; var registerWrapper = scope.registerWrapper; - var unwrap = scope.unwrap; + var unsafeUnwrap = scope.unsafeUnwrap; var wrappers = scope.wrappers; var OriginalElement = window.Element; @@ -65,7 +65,7 @@ mixin(Element.prototype, { createShadowRoot: function() { var newShadowRoot = new wrappers.ShadowRoot(this); - this.impl.polymerShadowRoot_ = newShadowRoot; + unsafeUnwrap(this).polymerShadowRoot_ = newShadowRoot; var renderer = scope.getRendererForHost(this); renderer.invalidate(); @@ -74,40 +74,40 @@ }, get shadowRoot() { - return this.impl.polymerShadowRoot_ || null; + return unsafeUnwrap(this).polymerShadowRoot_ || null; }, // getDestinationInsertionPoints added in ShadowRenderer.js setAttribute: function(name, value) { - var oldValue = this.impl.getAttribute(name); - this.impl.setAttribute(name, value); + var oldValue = unsafeUnwrap(this).getAttribute(name); + unsafeUnwrap(this).setAttribute(name, value); enqueAttributeChange(this, name, oldValue); invalidateRendererBasedOnAttribute(this, name); }, removeAttribute: function(name) { - var oldValue = this.impl.getAttribute(name); - this.impl.removeAttribute(name); + var oldValue = unsafeUnwrap(this).getAttribute(name); + unsafeUnwrap(this).removeAttribute(name); enqueAttributeChange(this, name, oldValue); invalidateRendererBasedOnAttribute(this, name); }, matches: function(selector) { - return originalMatches.call(this.impl, selector); + return originalMatches.call(unsafeUnwrap(this), selector); }, get classList() { var list = classListTable.get(this); if (!list) { classListTable.set(this, - list = new DOMTokenList(unwrap(this).classList, this)); + list = new DOMTokenList(unsafeUnwrap(this).classList, this)); } return list; }, get className() { - return unwrap(this).className; + return unsafeUnwrap(this).className; }, set className(v) { @@ -115,7 +115,7 @@ }, get id() { - return unwrap(this).id; + return unsafeUnwrap(this).id; }, set id(v) { diff --git a/src/wrappers/FormData.js b/src/wrappers/FormData.js index 9f2c54e..d283c3c 100644 --- a/src/wrappers/FormData.js +++ b/src/wrappers/FormData.js @@ -8,15 +8,19 @@ 'use strict'; var registerWrapper = scope.registerWrapper; + var setWrapper = scope.setWrapper; var unwrap = scope.unwrap; var OriginalFormData = window.FormData; function FormData(formElement) { - if (formElement instanceof OriginalFormData) - this.impl = formElement; - else - this.impl = new OriginalFormData(formElement && unwrap(formElement)); + var impl; + if (formElement instanceof OriginalFormData) { + impl = formElement; + } else { + impl = new OriginalFormData(formElement && unwrap(formElement)); + } + setWrapper(impl, this); } registerWrapper(OriginalFormData, FormData, new OriginalFormData()); diff --git a/src/wrappers/HTMLCanvasElement.js b/src/wrappers/HTMLCanvasElement.js index 63e3556..7162bf1 100644 --- a/src/wrappers/HTMLCanvasElement.js +++ b/src/wrappers/HTMLCanvasElement.js @@ -8,6 +8,7 @@ var HTMLElement = scope.wrappers.HTMLElement; var mixin = scope.mixin; var registerWrapper = scope.registerWrapper; + var unsafeUnwrap = scope.unsafeUnwrap; var wrap = scope.wrap; var OriginalHTMLCanvasElement = window.HTMLCanvasElement; @@ -19,7 +20,7 @@ mixin(HTMLCanvasElement.prototype, { getContext: function() { - var context = this.impl.getContext.apply(this.impl, arguments); + var context = unsafeUnwrap(this).getContext.apply(unsafeUnwrap(this), arguments); return context && wrap(context); } }); diff --git a/src/wrappers/HTMLElement.js b/src/wrappers/HTMLElement.js index fdc6b62..b88b710 100644 --- a/src/wrappers/HTMLElement.js +++ b/src/wrappers/HTMLElement.js @@ -13,6 +13,7 @@ var nodesWereRemoved = scope.nodesWereRemoved; var registerWrapper = scope.registerWrapper; var snapshotNodeList = scope.snapshotNodeList; + var unsafeUnwrap = scope.unsafeUnwrap; var unwrap = scope.unwrap; var wrap = scope.wrap; var wrappers = scope.wrappers; @@ -179,7 +180,7 @@ this instanceof wrappers.HTMLTemplateElement) { setInnerHTML(this.content, value); } else { - this.impl.innerHTML = value; + unsafeUnwrap(this).innerHTML = value; } var addedNodes = snapshotNodeList(this.childNodes); @@ -259,7 +260,7 @@ function getter(name) { return function() { scope.renderAllPending(); - return this.impl[name]; + return unsafeUnwrap(this)[name]; }; } @@ -285,7 +286,7 @@ get: getter(name), set: function(v) { scope.renderAllPending(); - this.impl[name] = v; + unsafeUnwrap(this)[name] = v; }, configurable: true, enumerable: true @@ -301,7 +302,7 @@ Object.defineProperty(HTMLElement.prototype, name, { value: function() { scope.renderAllPending(); - return this.impl[name].apply(this.impl, arguments); + return unsafeUnwrap(this)[name].apply(unsafeUnwrap(this), arguments); }, configurable: true, enumerable: true diff --git a/src/wrappers/HTMLTemplateElement.js b/src/wrappers/HTMLTemplateElement.js index 10ef039..cb13f08 100644 --- a/src/wrappers/HTMLTemplateElement.js +++ b/src/wrappers/HTMLTemplateElement.js @@ -8,6 +8,7 @@ var HTMLElement = scope.wrappers.HTMLElement; var mixin = scope.mixin; var registerWrapper = scope.registerWrapper; + var unsafeUnwrap = scope.unsafeUnwrap; var unwrap = scope.unwrap; var wrap = scope.wrap; @@ -56,7 +57,7 @@ mixin(HTMLTemplateElement.prototype, { get content() { if (OriginalHTMLTemplateElement) - return wrap(this.impl.content); + return wrap(unsafeUnwrap(this).content); return contentTable.get(this); }, diff --git a/src/wrappers/Node.js b/src/wrappers/Node.js index 64cae73..b52facc 100644 --- a/src/wrappers/Node.js +++ b/src/wrappers/Node.js @@ -19,6 +19,7 @@ var registerTransientObservers = scope.registerTransientObservers; var registerWrapper = scope.registerWrapper; var setTreeScope = scope.setTreeScope; + var unsafeUnwrap = scope.unsafeUnwrap; var unwrap = scope.unwrap; var unwrapIfNeeded = scope.unwrapIfNeeded; var wrap = scope.wrap; @@ -252,9 +253,9 @@ function cloneNode(node, deep, opt_doc) { var clone; if (opt_doc) - clone = wrap(originalImportNode.call(opt_doc, node.impl, false)); + clone = wrap(originalImportNode.call(opt_doc, unsafeUnwrap(node), false)); else - clone = wrap(originalCloneNode.call(node.impl, false)); + clone = wrap(originalCloneNode.call(unsafeUnwrap(node), false)); if (deep) { for (var child = node.firstChild; child; child = child.nextSibling) { @@ -397,7 +398,7 @@ if (useNative) { ensureSameOwnerDocument(this, childWrapper); clearChildNodes(this); - originalInsertBefore.call(this.impl, unwrap(childWrapper), refNode); + originalInsertBefore.call(unsafeUnwrap(this), unwrap(childWrapper), refNode); } else { if (!previousNode) this.firstChild_ = nodes[0]; @@ -407,7 +408,7 @@ this.firstChild_ = this.firstChild; } - var parentNode = refNode ? refNode.parentNode : this.impl; + var parentNode = refNode ? refNode.parentNode : unsafeUnwrap(this); // insertBefore refWrapper no matter what the parent is? if (parentNode) { @@ -478,7 +479,7 @@ childWrapper.parentNode_ = undefined; } else { clearChildNodes(this); - removeChildOriginalHelper(this.impl, childNode); + removeChildOriginalHelper(unsafeUnwrap(this), childNode); } if (!surpressMutations) { @@ -544,7 +545,7 @@ } else { ensureSameOwnerDocument(this, newChildWrapper); clearChildNodes(this); - originalReplaceChild.call(this.impl, unwrap(newChildWrapper), + originalReplaceChild.call(unsafeUnwrap(this), unwrap(newChildWrapper), oldChildNode); } @@ -580,31 +581,31 @@ get parentNode() { // If the parentNode has not been overridden, use the original parentNode. return this.parentNode_ !== undefined ? - this.parentNode_ : wrap(this.impl.parentNode); + this.parentNode_ : wrap(unsafeUnwrap(this).parentNode); }, /** @type {Node} */ get firstChild() { return this.firstChild_ !== undefined ? - this.firstChild_ : wrap(this.impl.firstChild); + this.firstChild_ : wrap(unsafeUnwrap(this).firstChild); }, /** @type {Node} */ get lastChild() { return this.lastChild_ !== undefined ? - this.lastChild_ : wrap(this.impl.lastChild); + this.lastChild_ : wrap(unsafeUnwrap(this).lastChild); }, /** @type {Node} */ get nextSibling() { return this.nextSibling_ !== undefined ? - this.nextSibling_ : wrap(this.impl.nextSibling); + this.nextSibling_ : wrap(unsafeUnwrap(this).nextSibling); }, /** @type {Node} */ get previousSibling() { return this.previousSibling_ !== undefined ? - this.previousSibling_ : wrap(this.impl.previousSibling); + this.previousSibling_ : wrap(unsafeUnwrap(this).previousSibling); }, get parentElement() { @@ -616,7 +617,7 @@ }, get textContent() { - // TODO(arv): This should fallback to this.impl.textContent if there + // TODO(arv): This should fallback to unsafeUnwrap(this).textContent if there // are no shadow trees below or above the context node. var s = ''; for (var child = this.firstChild; child; child = child.nextSibling) { @@ -632,12 +633,12 @@ if (this.invalidateShadowRenderer()) { removeAllChildNodes(this); if (textContent !== '') { - var textNode = this.impl.ownerDocument.createTextNode(textContent); + var textNode = unsafeUnwrap(this).ownerDocument.createTextNode(textContent); this.appendChild(textNode); } } else { clearChildNodes(this); - this.impl.textContent = textContent; + unsafeUnwrap(this).textContent = textContent; } var addedNodes = snapshotNodeList(this.childNodes); @@ -672,7 +673,7 @@ compareDocumentPosition: function(otherNode) { // This only wraps, it therefore only operates on the composed DOM and not // the logical DOM. - return originalCompareDocumentPosition.call(this.impl, + return originalCompareDocumentPosition.call(unsafeUnwrap(this), unwrapIfNeeded(otherNode)); }, diff --git a/src/wrappers/NodeList.js b/src/wrappers/NodeList.js index 5004f7e..8c5322a 100644 --- a/src/wrappers/NodeList.js +++ b/src/wrappers/NodeList.js @@ -5,6 +5,7 @@ (function(scope) { 'use strict'; + var unsafeUnwrap = scope.unsafeUnwrap; var wrap = scope.wrap; var nonEnumDescriptor = {enumerable: false}; @@ -37,7 +38,8 @@ function addWrapNodeListMethod(wrapperConstructor, name) { wrapperConstructor.prototype[name] = function() { - return wrapNodeList(this.impl[name].apply(this.impl, arguments)); + return wrapNodeList( + unsafeUnwrap(this)[name].apply(unsafeUnwrap(this), arguments)); }; } diff --git a/src/wrappers/Range.js b/src/wrappers/Range.js index 7e85aeb..7af9c21 100644 --- a/src/wrappers/Range.js +++ b/src/wrappers/Range.js @@ -6,6 +6,8 @@ 'use strict'; var registerWrapper = scope.registerWrapper; + var setWrapper = scope.setWrapper; + var unsafeUnwrap = scope.unsafeUnwrap; var unwrap = scope.unwrap; var unwrapIfNeeded = scope.unwrapIfNeeded; var wrap = scope.wrap; @@ -13,78 +15,78 @@ var OriginalRange = window.Range; function Range(impl) { - this.impl = impl; + setWrapper(impl, this); } Range.prototype = { get startContainer() { - return wrap(this.impl.startContainer); + return wrap(unsafeUnwrap(this).startContainer); }, get endContainer() { - return wrap(this.impl.endContainer); + return wrap(unsafeUnwrap(this).endContainer); }, get commonAncestorContainer() { - return wrap(this.impl.commonAncestorContainer); + return wrap(unsafeUnwrap(this).commonAncestorContainer); }, setStart: function(refNode,offset) { - this.impl.setStart(unwrapIfNeeded(refNode), offset); + unsafeUnwrap(this).setStart(unwrapIfNeeded(refNode), offset); }, setEnd: function(refNode,offset) { - this.impl.setEnd(unwrapIfNeeded(refNode), offset); + unsafeUnwrap(this).setEnd(unwrapIfNeeded(refNode), offset); }, setStartBefore: function(refNode) { - this.impl.setStartBefore(unwrapIfNeeded(refNode)); + unsafeUnwrap(this).setStartBefore(unwrapIfNeeded(refNode)); }, setStartAfter: function(refNode) { - this.impl.setStartAfter(unwrapIfNeeded(refNode)); + unsafeUnwrap(this).setStartAfter(unwrapIfNeeded(refNode)); }, setEndBefore: function(refNode) { - this.impl.setEndBefore(unwrapIfNeeded(refNode)); + unsafeUnwrap(this).setEndBefore(unwrapIfNeeded(refNode)); }, setEndAfter: function(refNode) { - this.impl.setEndAfter(unwrapIfNeeded(refNode)); + unsafeUnwrap(this).setEndAfter(unwrapIfNeeded(refNode)); }, selectNode: function(refNode) { - this.impl.selectNode(unwrapIfNeeded(refNode)); + unsafeUnwrap(this).selectNode(unwrapIfNeeded(refNode)); }, selectNodeContents: function(refNode) { - this.impl.selectNodeContents(unwrapIfNeeded(refNode)); + unsafeUnwrap(this).selectNodeContents(unwrapIfNeeded(refNode)); }, compareBoundaryPoints: function(how, sourceRange) { - return this.impl.compareBoundaryPoints(how, unwrap(sourceRange)); + return unsafeUnwrap(this).compareBoundaryPoints(how, unwrap(sourceRange)); }, extractContents: function() { - return wrap(this.impl.extractContents()); + return wrap(unsafeUnwrap(this).extractContents()); }, cloneContents: function() { - return wrap(this.impl.cloneContents()); + return wrap(unsafeUnwrap(this).cloneContents()); }, insertNode: function(node) { - this.impl.insertNode(unwrapIfNeeded(node)); + unsafeUnwrap(this).insertNode(unwrapIfNeeded(node)); }, surroundContents: function(newParent) { - this.impl.surroundContents(unwrapIfNeeded(newParent)); + unsafeUnwrap(this).surroundContents(unwrapIfNeeded(newParent)); }, cloneRange: function() { - return wrap(this.impl.cloneRange()); + return wrap(unsafeUnwrap(this).cloneRange()); }, isPointInRange: function(node, offset) { - return this.impl.isPointInRange(unwrapIfNeeded(node), offset); + return unsafeUnwrap(this).isPointInRange(unwrapIfNeeded(node), offset); }, comparePoint: function(node, offset) { - return this.impl.comparePoint(unwrapIfNeeded(node), offset); + return unsafeUnwrap(this).comparePoint(unwrapIfNeeded(node), offset); }, intersectsNode: function(node) { - return this.impl.intersectsNode(unwrapIfNeeded(node)); + return unsafeUnwrap(this).intersectsNode(unwrapIfNeeded(node)); }, toString: function() { - return this.impl.toString(); + return unsafeUnwrap(this).toString(); } }; // IE9 does not have createContextualFragment. if (OriginalRange.prototype.createContextualFragment) { Range.prototype.createContextualFragment = function(html) { - return wrap(this.impl.createContextualFragment(html)); + return wrap(unsafeUnwrap(this).createContextualFragment(html)); }; } diff --git a/src/wrappers/SVGElementInstance.js b/src/wrappers/SVGElementInstance.js index bca4719..75598a4 100644 --- a/src/wrappers/SVGElementInstance.js +++ b/src/wrappers/SVGElementInstance.js @@ -8,6 +8,7 @@ var EventTarget = scope.wrappers.EventTarget; var mixin = scope.mixin; var registerWrapper = scope.registerWrapper; + var unsafeUnwrap = scope.unsafeUnwrap; var wrap = scope.wrap; var OriginalSVGElementInstance = window.SVGElementInstance; @@ -22,17 +23,17 @@ mixin(SVGElementInstance.prototype, { /** @type {SVGElement} */ get correspondingElement() { - return wrap(this.impl.correspondingElement); + return wrap(unsafeUnwrap(this).correspondingElement); }, /** @type {SVGUseElement} */ get correspondingUseElement() { - return wrap(this.impl.correspondingUseElement); + return wrap(unsafeUnwrap(this).correspondingUseElement); }, /** @type {SVGElementInstance} */ get parentNode() { - return wrap(this.impl.parentNode); + return wrap(unsafeUnwrap(this).parentNode); }, /** @type {SVGElementInstanceList} */ @@ -42,22 +43,22 @@ /** @type {SVGElementInstance} */ get firstChild() { - return wrap(this.impl.firstChild); + return wrap(unsafeUnwrap(this).firstChild); }, /** @type {SVGElementInstance} */ get lastChild() { - return wrap(this.impl.lastChild); + return wrap(unsafeUnwrap(this).lastChild); }, /** @type {SVGElementInstance} */ get previousSibling() { - return wrap(this.impl.previousSibling); + return wrap(unsafeUnwrap(this).previousSibling); }, /** @type {SVGElementInstance} */ get nextSibling() { - return wrap(this.impl.nextSibling); + return wrap(unsafeUnwrap(this).nextSibling); } }); diff --git a/src/wrappers/Selection.js b/src/wrappers/Selection.js index 44c337c..e35c437 100644 --- a/src/wrappers/Selection.js +++ b/src/wrappers/Selection.js @@ -6,6 +6,8 @@ 'use strict'; var registerWrapper = scope.registerWrapper; + var setWrapper = scope.setWrapper; + var unsafeUnwrap = scope.unsafeUnwrap; var unwrap = scope.unwrap; var unwrapIfNeeded = scope.unwrapIfNeeded; var wrap = scope.wrap; @@ -13,38 +15,38 @@ var OriginalSelection = window.Selection; function Selection(impl) { - this.impl = impl; + setWrapper(impl, this); } Selection.prototype = { get anchorNode() { - return wrap(this.impl.anchorNode); + return wrap(unsafeUnwrap(this).anchorNode); }, get focusNode() { - return wrap(this.impl.focusNode); + return wrap(unsafeUnwrap(this).focusNode); }, addRange: function(range) { - this.impl.addRange(unwrap(range)); + unsafeUnwrap(this).addRange(unwrap(range)); }, collapse: function(node, index) { - this.impl.collapse(unwrapIfNeeded(node), index); + unsafeUnwrap(this).collapse(unwrapIfNeeded(node), index); }, containsNode: function(node, allowPartial) { - return this.impl.containsNode(unwrapIfNeeded(node), allowPartial); + return unsafeUnwrap(this).containsNode(unwrapIfNeeded(node), allowPartial); }, extend: function(node, offset) { - this.impl.extend(unwrapIfNeeded(node), offset); + unsafeUnwrap(this).extend(unwrapIfNeeded(node), offset); }, getRangeAt: function(index) { - return wrap(this.impl.getRangeAt(index)); + return wrap(unsafeUnwrap(this).getRangeAt(index)); }, removeRange: function(range) { - this.impl.removeRange(unwrap(range)); + unsafeUnwrap(this).removeRange(unwrap(range)); }, selectAllChildren: function(node) { - this.impl.selectAllChildren(unwrapIfNeeded(node)); + unsafeUnwrap(this).selectAllChildren(unwrapIfNeeded(node)); }, toString: function() { - return this.impl.toString(); + return unsafeUnwrap(this).toString(); } }; diff --git a/src/wrappers/ShadowRoot.js b/src/wrappers/ShadowRoot.js index 3e3c8cf..329850d 100644 --- a/src/wrappers/ShadowRoot.js +++ b/src/wrappers/ShadowRoot.js @@ -13,6 +13,7 @@ var mixin = scope.mixin; var rewrap = scope.rewrap; var setInnerHTML = scope.setInnerHTML; + var unsafeUnwrap = scope.unsafeUnwrap; var unwrap = scope.unwrap; var shadowHostTable = new WeakMap(); @@ -21,7 +22,7 @@ var spaceCharRe = /[ \t\n\r\f]/; function ShadowRoot(hostWrapper) { - var node = unwrap(hostWrapper.impl.ownerDocument.createDocumentFragment()); + var node = unwrap(unsafeUnwrap(hostWrapper).ownerDocument.createDocumentFragment()); DocumentFragment.call(this, node); // createDocumentFragment associates the node with a wrapper diff --git a/src/wrappers/TouchEvent.js b/src/wrappers/TouchEvent.js index b751d22..f3a4552 100644 --- a/src/wrappers/TouchEvent.js +++ b/src/wrappers/TouchEvent.js @@ -10,7 +10,8 @@ var UIEvent = scope.wrappers.UIEvent; var mixin = scope.mixin; var registerWrapper = scope.registerWrapper; - var unwrap = scope.unwrap; + var setWrapper = scope.setWrapper; + var unsafeUnwrap = scope.unsafeUnwrap; var wrap = scope.wrap; // TouchEvent is WebKit/Blink only. @@ -34,12 +35,12 @@ } function Touch(impl) { - this.impl = impl; + setWrapper(impl, this); } Touch.prototype = { get target() { - return wrap(this.impl.target); + return wrap(unsafeUnwrap(this).target); } }; @@ -63,7 +64,7 @@ 'webkitForce' ].forEach(function(name) { descr.get = function() { - return this.impl[name]; + return unsafeUnwrap(this)[name]; }; Object.defineProperty(Touch.prototype, name, descr); }); @@ -96,15 +97,15 @@ mixin(TouchEvent.prototype, { get touches() { - return wrapTouchList(unwrap(this).touches); + return wrapTouchList(unsafeUnwrap(this).touches); }, get targetTouches() { - return wrapTouchList(unwrap(this).targetTouches); + return wrapTouchList(unsafeUnwrap(this).targetTouches); }, get changedTouches() { - return wrapTouchList(unwrap(this).changedTouches); + return wrapTouchList(unsafeUnwrap(this).changedTouches); }, initTouchEvent: function() { diff --git a/src/wrappers/WebGLRenderingContext.js b/src/wrappers/WebGLRenderingContext.js index bfb4230..f009263 100644 --- a/src/wrappers/WebGLRenderingContext.js +++ b/src/wrappers/WebGLRenderingContext.js @@ -7,6 +7,8 @@ var mixin = scope.mixin; var registerWrapper = scope.registerWrapper; + var setWrapper = scope.setWrapper; + var unsafeUnwrap = scope.unsafeUnwrap; var unwrapIfNeeded = scope.unwrapIfNeeded; var wrap = scope.wrap; @@ -17,22 +19,22 @@ return; function WebGLRenderingContext(impl) { - this.impl = impl; + setWrapper(impl, this); } mixin(WebGLRenderingContext.prototype, { get canvas() { - return wrap(this.impl.canvas); + return wrap(unsafeUnwrap(this).canvas); }, texImage2D: function() { arguments[5] = unwrapIfNeeded(arguments[5]); - this.impl.texImage2D.apply(this.impl, arguments); + unsafeUnwrap(this).texImage2D.apply(unsafeUnwrap(this), arguments); }, texSubImage2D: function() { arguments[6] = unwrapIfNeeded(arguments[6]); - this.impl.texSubImage2D.apply(this.impl, arguments); + unsafeUnwrap(this).texSubImage2D.apply(unsafeUnwrap(this), arguments); } }); diff --git a/src/wrappers/events.js b/src/wrappers/events.js index e1a1911..0c8fe46 100644 --- a/src/wrappers/events.js +++ b/src/wrappers/events.js @@ -9,6 +9,8 @@ var getTreeScope = scope.getTreeScope; var mixin = scope.mixin; var registerWrapper = scope.registerWrapper; + var setWrapper = scope.setWrapper; + var unsafeUnwrap = scope.unsafeUnwrap; var unwrap = scope.unwrap; var wrap = scope.wrap; var wrappers = scope.wrappers; @@ -463,9 +465,10 @@ function Event(type, options) { if (type instanceof OriginalEvent) { var impl = type; - if (!OriginalBeforeUnloadEvent && impl.type === 'beforeunload') + if (!OriginalBeforeUnloadEvent && impl.type === 'beforeunload') { return new BeforeUnloadEvent(impl); - this.impl = impl; + } + setWrapper(impl, this); } else { return wrap(constructEvent(OriginalEvent, 'Event', type, options)); } @@ -509,7 +512,7 @@ var OriginalEvent = window[name]; var GenericEvent = function(type, options) { if (type instanceof OriginalEvent) - this.impl = type; + setWrapper(type, this); else return wrap(constructEvent(OriginalEvent, name, type, options)); }; @@ -640,10 +643,10 @@ BeforeUnloadEvent.prototype = Object.create(Event.prototype); mixin(BeforeUnloadEvent.prototype, { get returnValue() { - return this.impl.returnValue; + return unsafeUnwrap(this).returnValue; }, set returnValue(v) { - this.impl.returnValue = v; + unsafeUnwrap(this).returnValue = v; } }); @@ -680,7 +683,7 @@ * @constructor */ function EventTarget(impl) { - this.impl = impl; + setWrapper(impl, this); } // Node and Window have different internal type checks in WebKit so we cannot @@ -818,7 +821,8 @@ function elementFromPoint(self, document, x, y) { scope.renderAllPending(); - var element = wrap(originalElementFromPoint.call(document.impl, x, y)); + var element = + wrap(originalElementFromPoint.call(unsafeUnwrap(document), x, y)); if (!element) return null; var path = getEventPath(element, null); diff --git a/test/js/FormData.js b/test/js/FormData.js index a0bcf8b..2fe2196 100644 --- a/test/js/FormData.js +++ b/test/js/FormData.js @@ -24,7 +24,7 @@ suite('FormData', function() { var fd = new FormData(); var unwrapped = unwrap(fd); var wrapped = wrap(unwrapped); - assert.equal(fd.impl, wrapped.impl); + assert.equal(fd, wrapped); }); }); diff --git a/test/js/rerender.js b/test/js/rerender.js index cfc49ae..d4261ab 100644 --- a/test/js/rerender.js +++ b/test/js/rerender.js @@ -6,6 +6,7 @@ suite('Shadow DOM rerender', function() { + var unsafeUnwrap = ShadowDOMPolyfill.unsafeUnwrap; var unwrap = ShadowDOMPolyfill.unwrap; function getVisualInnerHtml(el) { @@ -501,40 +502,40 @@ suite('Shadow DOM rerender', function() { a.textContent = 'x'; // Don't use getVisualInnerHtml but it does invalidation. - assert.equal(host.impl.innerHTML, 'x'); + assert.equal(unsafeUnwrap(host).innerHTML, 'x'); host.appendChild(document.createTextNode('y')); - assert.equal(host.impl.innerHTML, 'xy'); //dirty + assert.equal(unsafeUnwrap(host).innerHTML, 'xy'); //dirty host.offsetWidth; - assert.equal(host.impl.innerHTML, 'xy'); + assert.equal(unsafeUnwrap(host).innerHTML, 'xy'); sr.appendChild(document.createTextNode('z')); - assert.equal(host.impl.innerHTML, 'xy'); //dirty + assert.equal(unsafeUnwrap(host).innerHTML, 'xy'); //dirty host.offsetWidth; - assert.equal(host.impl.innerHTML, 'xyz'); + assert.equal(unsafeUnwrap(host).innerHTML, 'xyz'); sr.insertBefore(document.createTextNode('w'), content); - assert.equal(host.impl.innerHTML, 'xyz'); // dirty + assert.equal(unsafeUnwrap(host).innerHTML, 'xyz'); // dirty host.offsetWidth; - assert.equal(host.impl.innerHTML, 'wxyz'); + assert.equal(unsafeUnwrap(host).innerHTML, 'wxyz'); // This case does not need invalidation. // We could make the check a bit more specific (check for nextSibling being // null or a content/shadow). sr.insertBefore(document.createTextNode('v'), c); - assert.equal(host.impl.innerHTML, 'wxyvz'); + assert.equal(unsafeUnwrap(host).innerHTML, 'wxyvz'); host.offsetWidth; - assert.equal(host.impl.innerHTML, 'wxyvz'); + assert.equal(unsafeUnwrap(host).innerHTML, 'wxyvz'); content.select = '*'; - assert.equal(host.impl.innerHTML, 'wxyvz'); // dirty + assert.equal(unsafeUnwrap(host).innerHTML, 'wxyvz'); // dirty host.offsetWidth; - assert.equal(host.impl.innerHTML, 'wxvz'); + assert.equal(unsafeUnwrap(host).innerHTML, 'wxvz'); content.setAttribute('SelecT', 'no-match'); - assert.equal(host.impl.innerHTML, 'wxvz'); // dirty + assert.equal(unsafeUnwrap(host).innerHTML, 'wxvz'); // dirty host.offsetWidth; - assert.equal(host.impl.innerHTML, 'wvz'); + assert.equal(unsafeUnwrap(host).innerHTML, 'wvz'); }); test('minimal dom changes', function() {