diff --git a/dom/media/tests/crashtests/1505957.html b/dom/media/tests/crashtests/1505957.html index 85a67f1c290c..7b0780a9cfb3 100644 --- a/dom/media/tests/crashtests/1505957.html +++ b/dom/media/tests/crashtests/1505957.html @@ -2,7 +2,7 @@ +
+ + diff --git a/dom/media/tests/crashtests/crashtests.list b/dom/media/tests/crashtests/crashtests.list index efec885d499e..d4b38c20a2e8 100644 --- a/dom/media/tests/crashtests/crashtests.list +++ b/dom/media/tests/crashtests/crashtests.list @@ -25,3 +25,4 @@ pref(browser.link.open_newwindow,2) load 1429507_2.html # window.open() in tab d load 1453030.html skip-if(Android) load 1490700.html # No screenshare on Android load 1505957.html +load 1511130.html diff --git a/toolkit/actors/UAWidgetsChild.jsm b/toolkit/actors/UAWidgetsChild.jsm index e557a638b085..fd019f83282c 100644 --- a/toolkit/actors/UAWidgetsChild.jsm +++ b/toolkit/actors/UAWidgetsChild.jsm @@ -38,8 +38,12 @@ class UAWidgetsChild extends ActorChild { this.setupWidget(aElement); return; } - if (typeof widget.wrappedJSObject.onattributechange == "function") { - widget.wrappedJSObject.onattributechange(); + if (typeof widget.wrappedJSObject.onchange == "function") { + try { + widget.wrappedJSObject.onchange(); + } catch (ex) { + Cu.reportError(ex); + } } } @@ -50,7 +54,7 @@ class UAWidgetsChild extends ActorChild { case "video": case "audio": uri = "chrome://global/content/elements/videocontrols.js"; - widgetName = "VideoControlsPageWidget"; + widgetName = "VideoControlsWidget"; break; case "input": uri = "chrome://global/content/elements/datetimebox.js"; @@ -72,7 +76,13 @@ class UAWidgetsChild extends ActorChild { } let shadowRoot = aElement.openOrClosedShadowRoot; - let sandbox = aElement.nodePrincipal.isSystemPrincipal ? + if (!shadowRoot) { + Cu.reportError("Getting a UAWidgetBindToTree/UAWidgetAttributeChanged event without the Shadow Root."); + return; + } + + let isSystemPrincipal = aElement.nodePrincipal.isSystemPrincipal; + let sandbox = isSystemPrincipal ? Object.create(null) : Cu.getUAWidgetScope(aElement.nodePrincipal); if (!sandbox[widgetName]) { @@ -81,6 +91,15 @@ class UAWidgetsChild extends ActorChild { let widget = new sandbox[widgetName](shadowRoot); this.widgets.set(aElement, widget); + try { + if (!isSystemPrincipal) { + widget.wrappedJSObject.onsetup(); + } else { + widget.onsetup(); + } + } catch (ex) { + Cu.reportError(ex); + } } teardownWidget(aElement) { @@ -89,7 +108,11 @@ class UAWidgetsChild extends ActorChild { return; } if (typeof widget.wrappedJSObject.destructor == "function") { - widget.wrappedJSObject.destructor(); + try { + widget.wrappedJSObject.destructor(); + } catch (ex) { + Cu.reportError(ex); + } } this.widgets.delete(aElement); } diff --git a/toolkit/content/widgets/datetimebox.js b/toolkit/content/widgets/datetimebox.js index 264e661a1cb2..c6dc8c8cbc78 100644 --- a/toolkit/content/widgets/datetimebox.js +++ b/toolkit/content/widgets/datetimebox.js @@ -17,14 +17,19 @@ this.DateTimeBoxWidget = class { this.element = shadowRoot.host; this.document = this.element.ownerDocument; this.window = this.document.defaultView; + } + /* + * Callback called by UAWidgets right after constructor. + */ + onsetup() { this.switchImpl(); } /* * Callback called by UAWidgets when the "type" property changes. */ - onattributechange() { + onchange() { this.switchImpl(); } @@ -52,6 +57,7 @@ this.DateTimeBoxWidget = class { } if (newImpl) { this.impl = new newImpl(this.shadowRoot); + this.impl.onsetup(); } else { this.impl = undefined; } @@ -73,12 +79,14 @@ this.DateTimeInputBaseImplWidget = class { this.element = shadowRoot.host; this.document = this.element.ownerDocument; this.window = this.document.defaultView; + } + onsetup() { this.generateContent(); this.DEBUG = false; - this.mDateTimeBoxElement = shadowRoot.firstChild; + this.mDateTimeBoxElement = this.shadowRoot.firstChild; this.mInputElement = this.element; this.mLocales = this.window.getRegionalPrefsLocales(); @@ -628,6 +636,10 @@ this.DateTimeInputBaseImplWidget = class { this.DateInputImplWidget = class extends DateTimeInputBaseImplWidget { constructor(shadowRoot) { super(shadowRoot); + } + + onsetup() { + super.onsetup(); this.mMinMonth = 1; this.mMaxMonth = 12; @@ -966,6 +978,10 @@ this.DateInputImplWidget = class extends DateTimeInputBaseImplWidget { this.TimeInputImplWidget = class extends DateTimeInputBaseImplWidget { constructor(shadowRoot) { super(shadowRoot); + } + + onsetup() { + super.onsetup(); const kDefaultAMString = "AM"; const kDefaultPMString = "PM"; diff --git a/toolkit/content/widgets/docs/ua_widget.rst b/toolkit/content/widgets/docs/ua_widget.rst index 2d022271cf3c..c16b34242a6b 100644 --- a/toolkit/content/widgets/docs/ua_widget.rst +++ b/toolkit/content/widgets/docs/ua_widget.rst @@ -15,11 +15,13 @@ When the element is appended to the tree, a chrome-only ``UAWidgetBindToTree`` e UAWidgetsChild then grabs the sandbox for that origin (lazily creating it as needed), loads the script as needed, and initializes an instance by calling the JS constructor with a reference to the UA Widget Shadow Root created by the DOM. We will discuss the sandbox in the latter section. +The ``onsetup`` method is called right after the instance is constructed. The call to constructor must not throw, or UAWidgetsChild will be confused since an instance of the widget will not be returned, but the widget is already half-initalized. If the ``onsetup`` method call throws, UAWidgetsChild will still be able to hold the reference of the widget and call the destructor later on. + When the element is removed from the tree, ``UAWidgetUnbindFromTree`` is dispatched so UAWidgetsChild can destroy the widget, if it exists. If so, the UAWidgetsChild calls the ``destructor()`` method on the widget, causing the widget to destruct itself. When a UA Widget initializes, it should create its own DOM inside the passed UA Widget Shadow Root, including the ```` element necessary to load the stylesheet, add event listeners, etc. When destroyed (i.e. the destructor method is called), it should do the opposite. -**Specialization**: for video controls, we do not want to do the work if the control is not needed (i.e. when the ``