Bug 1507895 - Part III, Remove the marquee binding r=smaug
authorTimothy Guan-tin Chien <timdream@gmail.com>
Fri, 25 Jan 2019 14:24:43 +0000
changeset 455666 951448bcc1fcebcad89deb2a7d03770a261eb79b
parent 455665 de0a1a2cdc12a19d78b59e9534dbc5a570903695
child 455667 86c320724c8100d358e92dfe4d72c84e5984322b
push id76921
push usertchien@mozilla.com
push dateMon, 28 Jan 2019 18:34:59 +0000
treeherderautoland@bcf07920d63f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1507895
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1507895 - Part III, Remove the marquee binding r=smaug This patch removes the XBL marquee binding and always uses UA Widget for the internal "gut" of the marquee element. Depends on D17572 Differential Revision: https://phabricator.services.mozilla.com/D17573
dom/html/HTMLMarqueeElement.cpp
dom/html/HTMLMarqueeElement.h
dom/webidl/HTMLMarqueeElement.webidl
dom/xbl/nsXBLService.cpp
layout/style/contenteditable.css
layout/style/moz.build
layout/style/res/html.css
layout/style/xbl-marquee/jar.mn
layout/style/xbl-marquee/moz.build
layout/style/xbl-marquee/xbl-marquee.css
layout/style/xbl-marquee/xbl-marquee.xml
--- a/dom/html/HTMLMarqueeElement.cpp
+++ b/dom/html/HTMLMarqueeElement.cpp
@@ -17,22 +17,16 @@
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Marquee)
 
 namespace mozilla {
 namespace dom {
 
 HTMLMarqueeElement::~HTMLMarqueeElement() {}
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLMarqueeElement, nsGenericHTMLElement,
-                                   mStartStopCallback)
-
-NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(HTMLMarqueeElement,
-                                               nsGenericHTMLElement)
-
 NS_IMPL_ELEMENT_CLONE(HTMLMarqueeElement)
 
 static const nsAttrValue::EnumTable kBehaviorTable[] = {
     {"scroll", 1}, {"slide", 2}, {"alternate", 3}, {nullptr, 0}};
 
 // Default behavior value is "scroll".
 static const nsAttrValue::EnumTable* kDefaultBehavior = &kBehaviorTable[0];
 
@@ -54,39 +48,34 @@ JSObject* HTMLMarqueeElement::WrapNode(J
 
 nsresult HTMLMarqueeElement::BindToTree(Document* aDocument,
                                         nsIContent* aParent,
                                         nsIContent* aBindingParent) {
   nsresult rv =
       nsGenericHTMLElement::BindToTree(aDocument, aParent, aBindingParent);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (nsContentUtils::IsUAWidgetEnabled() && IsInComposedDoc()) {
+  if (IsInComposedDoc()) {
     AttachAndSetUAShadowRoot();
     NotifyUAWidgetSetupOrChange();
   }
 
   return rv;
 }
 
 void HTMLMarqueeElement::UnbindFromTree(bool aDeep, bool aNullParent) {
-  if (nsContentUtils::IsUAWidgetEnabled() && IsInComposedDoc()) {
+  if (IsInComposedDoc()) {
     // We don't want to unattach the shadow root because it used to
     // contain a <slot>.
     NotifyUAWidgetTeardown(UnattachShadowRoot::No);
   }
 
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
 }
 
-void HTMLMarqueeElement::SetStartStopCallback(
-    FunctionStringCallback* aCallback) {
-  mStartStopCallback = aCallback;
-}
-
 void HTMLMarqueeElement::GetBehavior(nsAString& aValue) {
   GetEnumAttr(nsGkAtoms::behavior, kDefaultBehavior->tag, aValue);
 }
 
 void HTMLMarqueeElement::GetDirection(nsAString& aValue) {
   GetEnumAttr(nsGkAtoms::direction, kDefaultDirection->tag, aValue);
 }
 
@@ -129,17 +118,17 @@ bool HTMLMarqueeElement::ParseAttribute(
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 nsresult HTMLMarqueeElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
                                           const nsAttrValue* aValue,
                                           const nsAttrValue* aOldValue,
                                           nsIPrincipal* aMaybeScriptedPrincipal,
                                           bool aNotify) {
-  if (nsContentUtils::IsUAWidgetEnabled() && IsInComposedDoc() &&
+  if (IsInComposedDoc() &&
       aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::direction) {
     NotifyUAWidgetSetupOrChange();
   }
   return nsGenericHTMLElement::AfterSetAttr(
       aNameSpaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify);
 }
 
 void HTMLMarqueeElement::MapAttributesIntoRule(
@@ -173,23 +162,19 @@ void HTMLMarqueeElement::DispatchEventTo
   event->InitEvent(aEventTypeArg, false, false);
   event->SetTrusted(true);
   shadow->DispatchEvent(*event, IgnoreErrors());
 }
 
 void HTMLMarqueeElement::Start() {
   if (GetShadowRoot()) {
     DispatchEventToShadowRoot(NS_LITERAL_STRING("marquee-start"));
-  } else if (mStartStopCallback) {
-    mStartStopCallback->Call(NS_LITERAL_STRING("start"));
   }
 }
 
 void HTMLMarqueeElement::Stop() {
   if (GetShadowRoot()) {
     DispatchEventToShadowRoot(NS_LITERAL_STRING("marquee-stop"));
-  } else if (mStartStopCallback) {
-    mStartStopCallback->Call(NS_LITERAL_STRING("stop"));
   }
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/html/HTMLMarqueeElement.h
+++ b/dom/html/HTMLMarqueeElement.h
@@ -7,40 +7,31 @@
 #define HTMLMarqueeElement_h___
 
 #include "mozilla/Attributes.h"
 #include "nsGenericHTMLElement.h"
 #include "nsContentUtils.h"
 
 namespace mozilla {
 namespace dom {
-class FunctionStringCallback;
-
 class HTMLMarqueeElement final : public nsGenericHTMLElement {
  public:
   explicit HTMLMarqueeElement(already_AddRefed<dom::NodeInfo>&& aNodeInfo)
       : nsGenericHTMLElement(std::move(aNodeInfo)) {}
 
-  // nsISupports
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLMarqueeElement,
-                                           nsGenericHTMLElement)
-
   nsresult BindToTree(Document* aDocument, nsIContent* aParent,
                       nsIContent* aBindingParent) override;
   void UnbindFromTree(bool aDeep = true, bool aNullParent = true) override;
 
   static const int kDefaultLoop = -1;
   static const int kDefaultScrollAmount = 6;
   static const int kDefaultScrollDelayMS = 85;
 
   bool IsEventAttributeNameInternal(nsAtom* aName) override;
 
-  void SetStartStopCallback(FunctionStringCallback* aCallback);
-
   void GetBehavior(nsAString& aValue);
   void SetBehavior(const nsAString& aValue, ErrorResult& aError) {
     SetHTMLAttr(nsGkAtoms::behavior, aValue, aError);
   }
 
   void GetDirection(nsAString& aValue);
   void SetDirection(const nsAString& aValue, ErrorResult& aError) {
     SetHTMLAttr(nsGkAtoms::direction, aValue, aError);
@@ -121,17 +112,16 @@ class HTMLMarqueeElement final : public 
 
  protected:
   virtual ~HTMLMarqueeElement();
 
   JSObject* WrapNode(JSContext* aCx,
                      JS::Handle<JSObject*> aGivenProto) override;
 
  private:
-  RefPtr<FunctionStringCallback> mStartStopCallback;
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
                                     MappedDeclarations&);
 
   void DispatchEventToShadowRoot(const nsAString& aEventTypeArg);
 };
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/webidl/HTMLMarqueeElement.webidl
+++ b/dom/webidl/HTMLMarqueeElement.webidl
@@ -27,13 +27,10 @@ interface HTMLMarqueeElement : HTMLEleme
   [CEReactions, SetterThrows] attribute DOMString width;
 
   attribute EventHandler onbounce;
   attribute EventHandler onfinish;
   attribute EventHandler onstart;
 
   void start();
   void stop();
-
-  [Func="IsChromeOrXBL"]
-  void setStartStopCallback(FunctionStringCallback? callback);
 };
 
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -482,19 +482,17 @@ nsresult nsXBLService::LoadBindings(Elem
       IsSystemOrChromeURLPrincipal(aOriginPrincipal) && aElement->OwnerDoc() &&
       !aElement->OwnerDoc()->AllowXULXBL() &&
       !aURL->GetSpecOrDefault().EqualsLiteral(
           "chrome://global/content/xml/XMLPrettyPrint.xml#prettyprint")) {
     nsAtom* tag = aElement->NodeInfo()->NameAtom();
     MOZ_ASSERT(
         // pluginProblem
         tag == nsGkAtoms::embed || tag == nsGkAtoms::applet ||
-            tag == nsGkAtoms::object ||
-            // xbl-marquee
-            tag == nsGkAtoms::marquee,
+            tag == nsGkAtoms::object,
         "Unexpected XBL binding used in the content process");
   }
 #endif
 
   // Easy case: The binding was already loaded.
   nsXBLBinding* binding = aElement->GetXBLBinding();
   if (binding && !binding->MarkedForDeath() &&
       binding->PrototypeBinding()->CompareBindingURI(aURL)) {
--- a/layout/style/contenteditable.css
+++ b/layout/style/contenteditable.css
@@ -9,23 +9,23 @@
   cursor: text;
 }
 
 input:-moz-read-write > .anonymous-div:-moz-read-only,
 textarea:-moz-read-write > .anonymous-div:-moz-read-only {
   -moz-user-select: text;
 }
 
-/* Use default arrow over objects with size that 
+/* Use default arrow over objects with size that
    are selected when clicked on.
    Override the browser's pointer cursor over links
 */
 
 img:-moz-read-write, img:-moz-read-write[usemap], area:-moz-read-write,
-object:-moz-read-write, object:-moz-read-write[usemap], 
+object:-moz-read-write, object:-moz-read-write[usemap],
 applet:-moz-read-write, hr:-moz-read-write, button:-moz-read-write,
 select:-moz-read-write,
 a:-moz-read-write:link img, a:-moz-read-write:visited img,
 a:-moz-read-write:active img, a:-moz-read-write:-moz-only-whitespace[name] {
   cursor: default;
 }
 
 *|*:any-link:-moz-read-write {
@@ -33,17 +33,17 @@ a:-moz-read-write:active img, a:-moz-rea
 }
 
 /* Prevent clicking on links from going to link */
 a:link:-moz-read-write img, a:visited:-moz-read-write img,
 a:active:-moz-read-write img {
   -moz-user-input: none;
 }
 
-/* We suppress user/author's prefs for link underline, 
+/* We suppress user/author's prefs for link underline,
    so we must set explicitly. This isn't good!
 */
 a:link:-moz-read-write {
   color: -moz-hyperlinktext;
 }
 
 /* Allow double-clicks on these widgets to open properties dialogs
    XXX except when the widget has disabled attribute */
@@ -65,30 +65,16 @@ input[contenteditable="true"]:disabled,
 input[contenteditable="true"][type="checkbox"],
 input[contenteditable="true"][type="radio"],
 input[contenteditable="true"][type="file"] {
   -moz-user-select: all;
   -moz-user-input: none !important;
   -moz-user-focus: none !important;
 }
 
-/* emulation of non-standard HTML <marquee> tag */
-
-@supports not -moz-bool-pref("dom.ua_widget.enabled") {
-
-  marquee:-moz-read-write {
-    -moz-binding: url('chrome://xbl-marquee/content/xbl-marquee.xml#marquee-horizontal-editable');
-  }
-
-  marquee[direction="up"]:-moz-read-write, marquee[direction="down"]:-moz-read-write {
-    -moz-binding: url('chrome://xbl-marquee/content/xbl-marquee.xml#marquee-vertical-editable');
-  }
-
-}
-
 *|*:-moz-read-write > input[type="hidden"],
 input[contenteditable="true"][type="hidden"] {
   border: 1px solid black !important;
   visibility: visible !important;
 }
 
 label:-moz-read-write {
   -moz-user-select: all;
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -29,17 +29,16 @@ with Files('nsAnimationManager.*'):
     BUG_COMPONENT = ('Core', 'CSS Transitions and Animations')
 
 with Files('nsTransitionManager.*'):
     BUG_COMPONENT = ('Core', 'CSS Transitions and Animations')
 
 with Files('StyleAnimationValue.*'):
     BUG_COMPONENT = ('Core', 'CSS Transitions and Animations')
 
-DIRS += ['xbl-marquee']
 TEST_DIRS += ['test']
 
 EXPORTS += [
     '!nsCSSPropertyID.h',
     'AnimationCommon.h',
     'CounterStyleManager.h',
     'nsAnimationManager.h',
     'nsCSSAnonBoxes.h',
--- a/layout/style/res/html.css
+++ b/layout/style/res/html.css
@@ -807,40 +807,27 @@ dialog {
   background: white;
   width: -moz-fit-content;
 }
 
 dialog:not([open]) {
   display: none;
 }
 
-/* emulation of non-standard HTML <marquee> tag */
 marquee {
   inline-size: -moz-available;
   display: inline-block;
   vertical-align: text-bottom;
   text-align: start;
 }
 
 marquee[direction="up"], marquee[direction="down"] {
   block-size: 200px;
 }
 
-@supports not -moz-bool-pref("dom.ua_widget.enabled") {
-
-  marquee {
-    -moz-binding: url('chrome://xbl-marquee/content/xbl-marquee.xml#marquee-horizontal');
-  }
-
-  marquee[direction="up"], marquee[direction="down"] {
-    -moz-binding: url('chrome://xbl-marquee/content/xbl-marquee.xml#marquee-vertical');
-  }
-
-}
-
 /* PRINT ONLY rules follow */
 @media print {
 
   marquee { -moz-binding: none; }
 
 }
 
 /* Ruby */
deleted file mode 100644
--- a/layout/style/xbl-marquee/jar.mn
+++ /dev/null
@@ -1,8 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-toolkit.jar:
-%   content xbl-marquee %content/xbl-marquee/ contentaccessible=yes
-    content/xbl-marquee/xbl-marquee.xml
-    content/xbl-marquee/xbl-marquee.css
deleted file mode 100644
--- a/layout/style/xbl-marquee/moz.build
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-JAR_MANIFESTS += ['jar.mn']
\ No newline at end of file
deleted file mode 100644
--- a/layout/style/xbl-marquee/xbl-marquee.css
+++ /dev/null
@@ -1,12 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* PRINT ONLY rules */
-@media print {
-
-  marquee > * > * { 
-    margin: 0 !important; 
-    padding: 0 !important;
-  } /* This hack is needed until bug 119078 gets fixed */
-}
deleted file mode 100644
--- a/layout/style/xbl-marquee/xbl-marquee.xml
+++ /dev/null
@@ -1,389 +0,0 @@
-<?xml version="1.0"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<bindings id="marqueeBindings"
-          xmlns="http://www.mozilla.org/xbl"
-          xmlns:html="http://www.w3.org/1999/xhtml"
-          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-          xmlns:xbl="http://www.mozilla.org/xbl">
-
-
-  <binding id="marquee" bindToUntrustedContent="true">
-
-    <resources>
-      <stylesheet src="chrome://xbl-marquee/content/xbl-marquee.css"/>
-    </resources>
-    <implementation>
-
-      <property name="outerDiv"
-        onget="return document.getAnonymousNodes(this)[0]"
-      />
-
-      <property name="innerDiv"
-        onget="return document.getAnonymousElementByAttribute(this, 'class', 'innerDiv');"
-      />
-
-      <property name="scrollDelayWithTruespeed">
-        <getter>
-          <![CDATA[
-          if (this.scrollDelay < 60 && !this.trueSpeed) {
-            return 60;
-          }
-          return this.scrollDelay;
-          ]]>
-        </getter>
-      </property>
-
-      <method name="doStart">
-        <body>
-        <![CDATA[
-          if (this.runId == 0) {
-            var lambda = () => this._doMove(false);
-            this.runId = window.setTimeout(lambda, this.scrollDelayWithTruespeed - this._deltaStartStop);
-            this._deltaStartStop = 0;
-          }
-        ]]>
-        </body>
-      </method>
-      <method name="doStop">
-        <body>
-        <![CDATA[
-          if (this.runId != 0) {
-            this._deltaStartStop = Date.now()- this._lastMoveDate;
-            clearTimeout(this.runId);
-          }
-
-          this.runId = 0;
-        ]]>
-        </body>
-      </method>
-
-      <method name="_fireEvent">
-        <parameter name="aName"/>
-        <parameter name="aBubbles"/>
-        <parameter name="aCancelable"/>
-        <body>
-        <![CDATA[
-          var e = document.createEvent("Events");
-          e.initEvent(aName, aBubbles, aCancelable);
-          this.dispatchEvent(e);
-        ]]>
-        </body>
-      </method>
-
-      <method name="_doMove">
-        <parameter name="aResetPosition"/>
-        <body>
-        <![CDATA[
-          this._lastMoveDate = Date.now();
-
-          // invalidateCache is true at first load and whenever an attribute
-          // is changed
-          if (this.invalidateCache) {
-            this.invalidateCache = false; //we only want this to run once every scroll direction change
-
-            var corrvalue = 0;
-
-            switch (this._currentDirection)
-            {
-              case "up":
-                var height = document.defaultView.getComputedStyle(this).height;
-                this.outerDiv.style.height = height;
-                if (this.originalHeight > this.outerDiv.offsetHeight) {
-                    corrvalue = this.originalHeight - this.outerDiv.offsetHeight;
-                }
-                this.innerDiv.style.padding = height + " 0";
-                this.dirsign = 1;
-                this.startAt = (this.behavior == 'alternate') ? (this.originalHeight - corrvalue) : 0;
-                this.stopAt  = (this.behavior == 'alternate' || this.behavior == 'slide') ? 
-                                (parseInt(height) + corrvalue) : (this.originalHeight + parseInt(height));
-              break;
-
-              case "down":
-                var height = document.defaultView.getComputedStyle(this).height;
-                this.outerDiv.style.height = height;
-                if (this.originalHeight > this.outerDiv.offsetHeight) {
-                    corrvalue = this.originalHeight - this.outerDiv.offsetHeight;
-                }
-                this.innerDiv.style.padding = height + " 0";
-                this.dirsign = -1;
-                this.startAt  = (this.behavior == 'alternate') ?
-                                (parseInt(height) + corrvalue) : (this.originalHeight + parseInt(height));
-                this.stopAt = (this.behavior == 'alternate' || this.behavior == 'slide') ? 
-                              (this.originalHeight - corrvalue) : 0;
-              break;
-
-              case "right":
-                if (this.innerDiv.offsetWidth > this.outerDiv.offsetWidth) {
-                    corrvalue = this.innerDiv.offsetWidth - this.outerDiv.offsetWidth;
-                }
-                this.dirsign = -1;
-                this.stopAt  = (this.behavior == 'alternate' || this.behavior == 'slide') ? 
-                               (this.innerDiv.offsetWidth - corrvalue) : 0;
-                this.startAt = this.outerDiv.offsetWidth + ((this.behavior == 'alternate') ? 
-                               corrvalue : (this.innerDiv.offsetWidth + this.stopAt));   
-              break;
-
-              case "left":
-              default:
-                if (this.innerDiv.offsetWidth > this.outerDiv.offsetWidth) {
-                    corrvalue = this.innerDiv.offsetWidth - this.outerDiv.offsetWidth;
-                }
-                this.dirsign = 1;
-                this.startAt = (this.behavior == 'alternate') ? (this.innerDiv.offsetWidth - corrvalue) : 0;
-                this.stopAt  = this.outerDiv.offsetWidth + 
-                               ((this.behavior == 'alternate' || this.behavior == 'slide') ? 
-                               corrvalue : (this.innerDiv.offsetWidth + this.startAt));
-            }
-
-            if (aResetPosition) {
-              this.newPosition = this.startAt;
-              this._fireEvent("start", false, false);
-            }
-          } //end if
-
-          this.newPosition = this.newPosition + (this.dirsign * this.scrollAmount);
-
-          if ((this.dirsign == 1 && this.newPosition > this.stopAt) ||
-              (this.dirsign == -1 && this.newPosition < this.stopAt))
-          {
-            switch (this.behavior) 
-            {
-              case 'alternate':
-                // lets start afresh
-                this.invalidateCache = true;
-
-                // swap direction
-                const swap = {left: "right", down: "up", up: "down", right: "left"};
-                this._currentDirection = swap[this._currentDirection] || "left";
-                this.newPosition = this.stopAt;
-
-                if ((this._currentDirection == "up") || (this._currentDirection == "down")) {
-                  this.outerDiv.scrollTop = this.newPosition;
-                } else {
-                  this.outerDiv.scrollLeft = this.newPosition;
-                }
-
-                if (this._currentLoop != 1) {
-                  this._fireEvent("bounce", false, true);
-                }
-              break;
-
-              case 'slide':
-                if (this._currentLoop > 1) {
-                  this.newPosition = this.startAt;
-                }
-              break;
-
-              default:
-                this.newPosition = this.startAt;
-
-                if ((this._currentDirection == "up") || (this._currentDirection == "down")) {
-                  this.outerDiv.scrollTop = this.newPosition;
-                } else {
-                  this.outerDiv.scrollLeft = this.newPosition;
-                }
-
-                //dispatch start event, even when this._currentLoop == 1, comp. with IE6
-                this._fireEvent("start", false, false);
-            }
-
-            if (this._currentLoop > 1) {
-              this._currentLoop--;
-            } else if (this._currentLoop == 1) {
-              if ((this._currentDirection == "up") || (this._currentDirection == "down")) {
-                this.outerDiv.scrollTop = this.stopAt;
-              } else {
-                this.outerDiv.scrollLeft = this.stopAt;
-              }
-              this.stop();
-              this._fireEvent("finish", false, true);
-              return;
-            }
-          }
-          else {
-            if ((this._currentDirection == "up") || (this._currentDirection == "down")) {
-              this.outerDiv.scrollTop = this.newPosition;
-            } else {
-              this.outerDiv.scrollLeft = this.newPosition;
-            }
-          }
-
-          var myThis = this;
-          var lambda = function myTimeOutFunction(){myThis._doMove(false);}
-          this.runId = window.setTimeout(lambda, this.scrollDelayWithTruespeed);
-        ]]>
-        </body>
-      </method>
-
-      <method name="init">
-        <body>
-        <![CDATA[
-          this.stop();
-
-          if ((this._currentDirection != "up") && (this._currentDirection != "down")) {
-            var width = window.getComputedStyle(this).width;
-            this.innerDiv.parentNode.style.margin = '0 ' + width;
-
-            //XXX Adding the margin sometimes causes the marquee to widen, 
-            // see testcase from bug bug 364434: 
-            // https://bugzilla.mozilla.org/attachment.cgi?id=249233
-            // Just add a fixed width with current marquee's width for now
-            if (width != window.getComputedStyle(this).width) {
-              var width = window.getComputedStyle(this).width;
-              this.outerDiv.style.width = width;
-              this.innerDiv.parentNode.style.margin = '0 ' + width;
-            }
-          }
-          else {
-            // store the original height before we add padding
-            this.innerDiv.style.padding = 0;
-            this.originalHeight = this.innerDiv.offsetHeight;
-          }
-
-          this._doMove(true);
-        ]]>
-        </body>
-      </method>
-
-      <method name="_mutationActor">
-        <parameter name="aMutations"/>
-        <body>
-        <![CDATA[
-          while (aMutations.length > 0) {
-            var mutation = aMutations.shift();
-            var attrName = mutation.attributeName.toLowerCase();
-            var oldValue = mutation.oldValue;
-            var target = mutation.target;
-            var newValue = target.getAttribute(attrName);
-
-            if (oldValue != newValue) {
-              target.invalidateCache = true;
-              switch (attrName) {
-                case "loop":
-                  target._currentLoop = target.loop;
-                  break;
-                case "direction":
-                  target._currentDirection = target.direction;
-                  break;
-              }
-            }
-          }
-        ]]>
-        </body>
-      </method>
-
-      <constructor>
-        <![CDATA[
-          this.setStartStopCallback(val => {
-            if (val == "start") {
-              this.doStart();
-            } else if (val == "stop") {
-              this.doStop();
-            } else {
-              throw new Error(`setStartStopCallback passed an invalid value: ${val}`);
-            }
-          });
-          // Set up state.
-          this._currentDirection = this.direction || "left";
-          this._currentLoop = this.loop;
-          this.dirsign = 1;
-          this.startAt = 0;
-          this.stopAt = 0;
-          this.newPosition = 0;
-          this.runId = 0;
-          this.originalHeight = 0;
-          this.invalidateCache = true;
-
-          // hack needed to fix js error, see bug 386470
-          var myThis = this;
-          var lambda = function myScopeFunction() { if (myThis.init) myThis.init(); }
-
-          this._mutationObserver = new MutationObserver(this._mutationActor);
-          this._mutationObserver.observe(this, { attributes: true,
-            attributeOldValue: true,
-            attributeFilter: ['loop', '', 'behavior',
-              'direction', 'width', 'height'] });
-
-          // init needs to be run after the page has loaded in order to calculate
-          // the correct height/width
-          if (document.readyState == "complete") {
-            lambda();
-          } else {
-            window.addEventListener("load", lambda);
-          }
-        ]]>
-      </constructor>
-      <destructor>
-        <![CDATA[
-        this.setStartStopCallback(null);
-        ]]>
-      </destructor>
-    </implementation>
-
-  </binding>
-
-  <binding id="marquee-horizontal" bindToUntrustedContent="true"
-           extends="chrome://xbl-marquee/content/xbl-marquee.xml#marquee"
-           inheritstyle="false">
-
-    <!-- White-space isn't allowed because a marquee could be
-         inside 'white-space: pre' -->
-    <content>
-      <html:div style="display: -moz-box; overflow: hidden; width: -moz-available;"
-        ><html:div style="display: -moz-box;"
-          ><html:div class="innerDiv" style="display: table; border-spacing: 0;"
-            ><html:div
-              ><children
-            /></html:div
-          ></html:div
-        ></html:div
-      ></html:div>
-    </content>
-
-  </binding>
-
-  <binding id="marquee-vertical" bindToUntrustedContent="true"
-           extends="chrome://xbl-marquee/content/xbl-marquee.xml#marquee"
-           inheritstyle="false">
-
-    <!-- White-space isn't allowed because a marquee could be
-         inside 'white-space: pre' -->
-    <content>
-      <html:div style="overflow: hidden; width: -moz-available;"
-        ><html:div class="innerDiv"
-          ><children
-        /></html:div
-      ></html:div>
-    </content>
-
-  </binding>
-
-  <binding id="marquee-horizontal-editable" bindToUntrustedContent="true"
-           inheritstyle="false">
-
-    <!-- White-space isn't allowed because a marquee could be 
-         inside 'white-space: pre' -->
-    <content>
-      <html:div style="display: inline-block; overflow: auto; width: -moz-available;"
-        ><children
-      /></html:div>
-    </content>
-
-  </binding>
-
-  <binding id="marquee-vertical-editable" bindToUntrustedContent="true"
-           inheritstyle="false">
-
-    <!-- White-space isn't allowed because a marquee could be 
-         inside 'white-space: pre' -->
-    <content>
-      <html:div style="overflow: auto; height: inherit; width: -moz-available;"
-        ><children/></html:div>
-    </content>
-
-  </binding>
-
-</bindings>