Merge m-c to inbound, a=merge
authorWes Kocher <wkocher@mozilla.com>
Thu, 01 Jun 2017 17:31:41 -0700
changeset 361984 f0f74276deb7bdfb29388574aa5793dc7c53df17
parent 361983 6ff0dd2d87d1899dfea7abdf5f0dde9b7f28aa45 (current diff)
parent 361912 1e229cf8933b08191e4243a6b9dbb3c821db60ab (diff)
child 361985 7a5c8b4e83624a07659e1effbb6f3188d5812145
push id31953
push usercbook@mozilla.com
push dateFri, 02 Jun 2017 12:22:33 +0000
treeherdermozilla-central@2a8478029a0c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone55.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
Merge m-c to inbound, a=merge MozReview-Commit-ID: 5RAH1yS3Ebt
browser/themes/shared/jar.inc.mn
testing/marionette/harness/marionette_harness/tests/unit/test_chrome_async_finish.js
testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_chrome.js
testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_fail.js
testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_pass.js
testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_sanity.py
testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_timeout.js
testing/marionette/simpletest.js
toolkit/themes/osx/global/arrow.css
toolkit/themes/osx/global/arrow/arrow-lft-sharp-end.gif
toolkit/themes/osx/global/arrow/arrow-rit-sharp-end.gif
toolkit/themes/windows/global/arrow.css
toolkit/themes/windows/global/arrow/arrow-dn-hov.gif
toolkit/themes/windows/global/arrow/arrow-dn-sharp.gif
toolkit/themes/windows/global/arrow/arrow-down.png
toolkit/themes/windows/global/arrow/arrow-lft-sharp-end.gif
toolkit/themes/windows/global/arrow/arrow-lft-sharp.gif
toolkit/themes/windows/global/arrow/arrow-rit-sharp-end.gif
toolkit/themes/windows/global/arrow/arrow-rit-sharp.gif
toolkit/themes/windows/global/arrow/arrow-up-hov.gif
toolkit/themes/windows/global/arrow/arrow-up-sharp.gif
--- a/addon-sdk/source/test/fixtures/test-addon-extras.html
+++ b/addon-sdk/source/test/fixtures/test-addon-extras.html
@@ -8,17 +8,17 @@
     <title>Worker test</title>
 </head>
 <body>
   <p id="paragraph">Lorem ipsum dolor sit amet.</p>
   <script>
     if ("addon" in window) {
       var count = 1;
       addon.port.on("get-result", () => {
-        console.log("get-result recieved");
+        console.log("get-result received");
         addon.port.emit("result" + count++, extras && extras.test())
       });
     }
 
     window.addEventListener("message", function getMessage({ data }) {
       if (data.name == "start") {
         window.postMessage({
           name: "extras",
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -190,16 +190,17 @@ pref("extensions.update.interval", 86400
                                             // Themes every day
 // Non-symmetric (not shared by extensions) extension-specific [update] preferences
 pref("extensions.dss.switchPending", false);    // Non-dynamic switch pending after next
                                                 // restart.
 
 pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.name", "chrome://browser/locale/browser.properties");
 pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.description", "chrome://browser/locale/browser.properties");
 
+pref("extensions.webextensions.themes.enabled", true);
 pref("extensions.webextensions.themes.icons.buttons", "back,forward,reload,stop,bookmark_star,bookmark_menu,downloads,home,app_menu,cut,copy,paste,new_window,new_private_window,save_page,print,history,full_screen,find,options,addons,developer,synced_tabs,open_file,sidebars,share_page,subscribe,text_encoding,email_link,forget,pocket");
 
 pref("lightweightThemes.update.enabled", true);
 pref("lightweightThemes.getMoreURL", "https://addons.mozilla.org/%LOCALE%/firefox/themes");
 pref("lightweightThemes.recommendedThemes", "[{\"id\":\"recommended-1\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/a-web-browser-renaissance/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.header.jpg\",\"textcolor\":\"#000000\",\"accentcolor\":\"#f2d9b1\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.preview.jpg\",\"author\":\"Sean.Martell\",\"version\":\"0\"},{\"id\":\"recommended-2\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/space-fantasy/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.header.jpg\",\"textcolor\":\"#ffffff\",\"accentcolor\":\"#d9d9d9\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.preview.jpg\",\"author\":\"fx5800p\",\"version\":\"1.0\"},{\"id\":\"recommended-4\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/pastel-gradient/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.header.png\",\"textcolor\":\"#000000\",\"accentcolor\":\"#000000\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.icon.png\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.preview.png\",\"author\":\"darrinhenein\",\"version\":\"1.0\"}]");
 
 #if defined(MOZ_WIDEVINE_EME)
 pref("browser.eme.ui.enabled", true);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -5507,41 +5507,49 @@ var gHomeButton = {
 };
 
 const nodeToTooltipMap = {
   "bookmarks-menu-button": "bookmarksMenuButton.tooltip",
   "context-reload": "reloadButton.tooltip",
   "context-stop": "stopButton.tooltip",
   "downloads-button": "downloads.tooltip",
   "fullscreen-button": "fullscreenButton.tooltip",
+  "appMenu-fullscreen-button": "fullscreenButton.tooltip",
   "new-window-button": "newWindowButton.tooltip",
   "new-tab-button": "newTabButton.tooltip",
   "tabs-newtab-button": "newTabButton.tooltip",
   "reload-button": "reloadButton.tooltip",
   "stop-button": "stopButton.tooltip",
   "urlbar-zoom-button": "urlbar-zoom-button.tooltip",
   "appMenu-cut-button": "cut-button.tooltip",
   "appMenu-copy-button": "copy-button.tooltip",
   "appMenu-paste-button": "paste-button.tooltip",
+  "appMenu-zoomEnlarge-button": "zoomEnlarge-button.tooltip",
+  "appMenu-zoomReset-button": "zoomReset-button.tooltip",
+  "appMenu-zoomReduce-button": "zoomReduce-button.tooltip",
 };
 const nodeToShortcutMap = {
   "bookmarks-menu-button": "manBookmarkKb",
   "context-reload": "key_reload",
   "context-stop": "key_stop",
   "downloads-button": "key_openDownloads",
   "fullscreen-button": "key_fullScreen",
+  "appMenu-fullscreen-button": "key_fullScreen",
   "new-window-button": "key_newNavigator",
   "new-tab-button": "key_newNavigatorTab",
   "tabs-newtab-button": "key_newNavigatorTab",
   "reload-button": "key_reload",
   "stop-button": "key_stop",
   "urlbar-zoom-button": "key_fullZoomReset",
   "appMenu-cut-button": "key_cut",
   "appMenu-copy-button": "key_copy",
   "appMenu-paste-button": "key_paste",
+  "appMenu-zoomEnlarge-button": "key_fullZoomEnlarge",
+  "appMenu-zoomReset-button": "key_fullZoomReset",
+  "appMenu-zoomReduce-button": "key_fullZoomReduce",
 };
 
 if (AppConstants.platform == "macosx") {
   nodeToTooltipMap["print-button"] = "printButton.tooltip";
   nodeToShortcutMap["print-button"] = "printKb";
 }
 
 const gDynamicTooltipCache = new Map();
--- a/browser/base/content/test/static/browser_all_files_referenced.js
+++ b/browser/base/content/test/static/browser_all_files_referenced.js
@@ -93,21 +93,21 @@ var whitelist = new Set([
 
   // The l10n build system can't package string files only for some platforms.
   {file: "resource://gre/chrome/en-US/locale/en-US/global-platform/mac/accessible.properties",
    platforms: ["linux", "win"]},
   {file: "resource://gre/chrome/en-US/locale/en-US/global-platform/mac/intl.properties",
    platforms: ["linux", "win"]},
   {file: "resource://gre/chrome/en-US/locale/en-US/global-platform/mac/platformKeys.properties",
    platforms: ["linux", "win"]},
-  {file: "resource://gre/chrome/en-US/locale/en-US/global-platform/gtk/accessible.properties",
+  {file: "resource://gre/chrome/en-US/locale/en-US/global-platform/unix/accessible.properties",
    platforms: ["macosx", "win"]},
-  {file: "resource://gre/chrome/en-US/locale/en-US/global-platform/gtk/intl.properties",
+  {file: "resource://gre/chrome/en-US/locale/en-US/global-platform/unix/intl.properties",
    platforms: ["macosx", "win"]},
-  {file: "resource://gre/chrome/en-US/locale/en-US/global-platform/gtk/platformKeys.properties",
+  {file: "resource://gre/chrome/en-US/locale/en-US/global-platform/unix/platformKeys.properties",
    platforms: ["macosx", "win"]},
   {file: "resource://gre/chrome/en-US/locale/en-US/global-platform/win/accessible.properties",
    platforms: ["linux", "macosx"]},
   {file: "resource://gre/chrome/en-US/locale/en-US/global-platform/win/intl.properties",
    platforms: ["linux", "macosx"]},
   {file: "resource://gre/chrome/en-US/locale/en-US/global-platform/win/platformKeys.properties",
    platforms: ["linux", "macosx"]},
 
@@ -132,34 +132,16 @@ var whitelist = new Set([
   // Bug 1316187
   {file: "chrome://global/content/customizeToolbar.xul"},
   // Bug 1343837
   {file: "chrome://global/content/findUtils.js"},
   // Bug 1343843
   {file: "chrome://global/content/url-classifier/unittests.xul"},
   // Bug 1343839
   {file: "chrome://global/locale/headsUpDisplay.properties"},
-  // Bug 1348358
-  {file: "chrome://global/skin/arrow.css"},
-  {file: "chrome://global/skin/arrow/arrow-dn-sharp.gif",
-   platforms: ["linux", "win"]},
-  {file: "chrome://global/skin/arrow/arrow-down.png",
-   platforms: ["linux", "win"]},
-  {file: "chrome://global/skin/arrow/arrow-lft-sharp-end.gif"},
-  {file: "chrome://global/skin/arrow/arrow-lft-sharp.gif",
-   platforms: ["linux", "win"]},
-  {file: "chrome://global/skin/arrow/arrow-rit-sharp-end.gif"},
-  {file: "chrome://global/skin/arrow/arrow-rit-sharp.gif",
-   platforms: ["linux", "win"]},
-  {file: "chrome://global/skin/arrow/arrow-up-sharp.gif",
-   platforms: ["linux", "win"]},
-  {file: "chrome://global/skin/arrow/panelarrow-horizontal.svg",
-   platforms: ["linux"]},
-  {file: "chrome://global/skin/arrow/panelarrow-vertical.svg",
-   platforms: ["linux"]},
   // Bug 1348362
   {file: "chrome://global/skin/icons/warning-64.png", platforms: ["linux", "win"]},
   // Bug 1348525
   {file: "chrome://global/skin/splitter/grip-bottom.gif", platforms: ["linux"]},
   {file: "chrome://global/skin/splitter/grip-left.gif", platforms: ["linux"]},
   {file: "chrome://global/skin/splitter/grip-right.gif", platforms: ["linux"]},
   {file: "chrome://global/skin/splitter/grip-top.gif", platforms: ["linux"]},
   // Bug 1348526
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -512,32 +512,32 @@
         <vbox id="appMenu-addon-banners"/>
         <toolbarbutton class="panel-banner-item"
                        label-update-available="&updateAvailable.panelUI.label;"
                        label-update-manual="&updateManual.panelUI.label;"
                        label-update-restart="&updateRestart.panelUI.label2;"
                        oncommand="PanelUI._onBannerItemSelected(event)"
                        wrap="true"
                        hidden="true"/>
-        <toolbaritem id="appMenu-fxa-container">
+        <toolbaritem id="appMenu-fxa-container" class="toolbaritem-combined-buttons">
           <hbox id="appMenu-fxa-status"
                 flex="1"
                 defaultlabel="&fxaSignIn.label;"
                 signedinTooltiptext="&fxaSignedIn.tooltip;"
                 tooltiptext="&fxaSignedIn.tooltip;"
                 errorlabel="&fxaSignInError.label;"
                 unverifiedlabel="&fxaUnverified.label;"
                 onclick="if (event.which == 1) gSync.onMenuPanelCommand();">
             <image id="appMenu-fxa-avatar"/>
             <toolbarbutton id="appMenu-fxa-label"
                            class="subviewbutton subviewbutton-iconic"
                            label="&fxaSignIn.label;"
                            fxabrandname="&syncBrand.fxAccount.label;"/>
           </hbox>
-          <toolbarseparator/>
+          <toolbarseparator orient="vertical"/>
           <toolbarbutton id="appMenu-fxa-icon"
                          class="subviewbutton subviewbutton-iconic"
                          oncommand="gSync.doSync();"
                          closemenu="none">
             <observes element="sync-status" attribute="syncstatus"/>
             <observes element="sync-status" attribute="tooltiptext"/>
           </toolbarbutton>
         </toolbaritem>
@@ -548,16 +548,38 @@
                        key="key_newNavigator"
                        command="cmd_newNavigator"/>
         <toolbarbutton id="appMenu-private-window-button"
                        class="subviewbutton subviewbutton-iconic"
                        label="&newPrivateWindow.label;"
                        key="key_privatebrowsing"
                        command="Tools:PrivateBrowsing"/>
         <toolbarseparator/>
+        <toolbaritem id="appMenu-zoom-controls" class="toolbaritem-combined-buttons" closemenu="none">
+          <label value="&fullZoom.label;"/>
+          <toolbarbutton id="appMenu-zoomReduce-button"
+                         class="subviewbutton subviewbutton-iconic"
+                         command="cmd_fullZoomReduce"
+                         tooltip="dynamic-shortcut-tooltip"/>
+          <toolbarbutton id="appMenu-zoomReset-button"
+                         class="subviewbutton"
+                         command="cmd_fullZoomReset"
+                         tooltip="dynamic-shortcut-tooltip"/>
+          <toolbarbutton id="appMenu-zoomEnlarge-button"
+                         class="subviewbutton subviewbutton-iconic"
+                         command="cmd_fullZoomEnlarge"
+                         tooltip="dynamic-shortcut-tooltip"/>
+          <toolbarseparator orient="vertical"/>
+          <toolbarbutton id="appMenu-fullscreen-button"
+                         class="subviewbutton subviewbutton-iconic"
+                         observes="View:FullScreen"
+                         type="checkbox"
+                         tooltip="dynamic-shortcut-tooltip"/>
+        </toolbaritem>
+        <toolbarseparator/>
         <toolbaritem id="appMenu-edit-controls" class="toolbaritem-combined-buttons" closemenu="none">
           <label value="&editMenu.label;"/>
           <toolbarbutton id="appMenu-cut-button"
                          class="subviewbutton subviewbutton-iconic"
                          command="cmd_cut"
                          tooltip="dynamic-shortcut-tooltip"/>
           <toolbarbutton id="appMenu-copy-button"
                          class="subviewbutton subviewbutton-iconic"
--- a/browser/extensions/flyweb/jar.mn
+++ b/browser/extensions/flyweb/jar.mn
@@ -1,10 +1,10 @@
 # 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/.
 
 [features/flyweb@mozilla.org] chrome.jar:
-% skin flyweb classic/1.0 %skin/linux/
+% skin flyweb classic/1.0 %skin/linux/ os=LikeUnix
 % skin flyweb classic/1.0 %skin/osx/ os=Darwin
 % skin flyweb classic/1.0 %skin/windows/ os=WINNT
 % skin flyweb-shared classic/1.0 %skin/shared/
   skin/  (skin/*)
--- a/browser/extensions/formautofill/jar.mn
+++ b/browser/extensions/formautofill/jar.mn
@@ -4,13 +4,13 @@
 
 [features/formautofill@mozilla.org] chrome.jar:
 % resource formautofill %res/
   res/ (*.jsm)
 
 % content formautofill %content/
   content/ (content/*)
 
-% skin formautofill classic/1.0 %skin/linux/
+% skin formautofill classic/1.0 %skin/linux/ os=LikeUnix
 % skin formautofill classic/1.0 %skin/osx/ os=Darwin
 % skin formautofill classic/1.0 %skin/windows/ os=WINNT
 % skin formautofill-shared classic/1.0 %skin/shared/
   skin/  (skin/*)
--- a/browser/extensions/pocket/jar.mn
+++ b/browser/extensions/pocket/jar.mn
@@ -1,15 +1,15 @@
 # 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/.
 
 [features/firefox@getpocket.com] chrome.jar:
 % content pocket %content/ contentaccessible=yes
-% skin pocket classic/1.0 %skin/linux/
+% skin pocket classic/1.0 %skin/linux/ os=LikeUnix
 % skin pocket classic/1.0 %skin/osx/ os=Darwin
 % skin pocket classic/1.0 %skin/windows/ os=WINNT
 % skin pocket-shared classic/1.0 %skin/shared/
   content/  (content/*)
   skin/shared (skin/shared/*)
 #ifdef XP_WIN
   skin/windows/ (skin/windows/*.png)
 * skin/windows/pocket.css (skin/windows/pocket.css)
--- a/browser/installer/allowed-dupes.mn
+++ b/browser/installer/allowed-dupes.mn
@@ -187,19 +187,19 @@ chrome/en-US/locale/en-US/browser/overri
 chrome/en-US/locale/en-US/browser/overrides/global/mozilla.dtd
 chrome/en-US/locale/en-US/browser/overrides/intl.css
 chrome/en-US/locale/en-US/browser/overrides/intl.properties
 chrome/en-US/locale/en-US/browser/overrides/passwordmgr.properties
 chrome/en-US/locale/en-US/browser/overrides/plugins.properties
 chrome/en-US/locale/en-US/browser/overrides/plugins/pluginproblem.dtd
 chrome/en-US/locale/en-US/browser/overrides/search/search.properties
 chrome/en-US/locale/en-US/global-platform/mac/intl.properties
-chrome/en-US/locale/en-US/global-platform/gtk/accessible.properties
-chrome/en-US/locale/en-US/global-platform/gtk/intl.properties
-chrome/en-US/locale/en-US/global-platform/gtk/platformKeys.properties
+chrome/en-US/locale/en-US/global-platform/unix/accessible.properties
+chrome/en-US/locale/en-US/global-platform/unix/intl.properties
+chrome/en-US/locale/en-US/global-platform/unix/platformKeys.properties
 chrome/en-US/locale/en-US/global-platform/win/accessible.properties
 chrome/en-US/locale/en-US/global-platform/win/intl.properties
 chrome/en-US/locale/en-US/global-platform/win/platformKeys.properties
 chrome/en-US/locale/en-US/global/AccessFu.properties
 chrome/en-US/locale/en-US/global/about.dtd
 chrome/en-US/locale/en-US/global/aboutAbout.dtd
 chrome/en-US/locale/en-US/global/aboutReader.properties
 chrome/en-US/locale/en-US/global/aboutRights.dtd
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -485,16 +485,23 @@ pu.notifyButton.label=Details…
 pu.notifyButton.accesskey=D
 # LOCALIZATION NOTE %S will be replaced by the short name of the application.
 puNotifyText=%S has been updated
 puAlertTitle=%S Updated
 puAlertText=Click here for details
 
 # Application menu
 
+# LOCALIZATION NOTE(zoomReduce-button.tooltip): %S is the keyboard shortcut.
+zoomReduce-button.tooltip = Zoom out (%S)
+# LOCALIZATION NOTE(zoomReset-button.tooltip): %S is the keyboard shortcut.
+zoomReset-button.tooltip = Reset zoom level (%S)
+# LOCALIZATION NOTE(zoomEnlarge-button.tooltip): %S is the keyboard shortcut.
+zoomEnlarge-button.tooltip = Zoom in (%S)
+
 # LOCALIZATION NOTE (cut-button.tooltip): %S is the keyboard shortcut.
 cut-button.tooltip = Cut (%S)
 # LOCALIZATION NOTE (copy-button.tooltip): %S is the keyboard shortcut.
 copy-button.tooltip = Copy (%S)
 # LOCALIZATION NOTE (paste-button.tooltip): %S is the keyboard shortcut.
 paste-button.tooltip = Paste (%S)
 
 # Geolocation UI
--- a/browser/modules/FullZoomUI.jsm
+++ b/browser/modules/FullZoomUI.jsm
@@ -57,29 +57,33 @@ function onFullZoomChange(event) {
  *   change is related to tab switching. Optional
  */
 function updateZoomUI(aBrowser, aAnimate = false) {
   let win = aBrowser.ownerGlobal;
   if (aBrowser != win.gBrowser.selectedBrowser) {
     return;
   }
 
+  let appMenuZoomReset = win.document.getElementById("appMenu-zoomReset-button");
   let customizableZoomControls = win.document.getElementById("zoom-controls");
   let customizableZoomReset = win.document.getElementById("zoom-reset-button");
   let urlbarZoomButton = win.document.getElementById("urlbar-zoom-button");
   let zoomFactor = Math.round(win.ZoomManager.zoom * 100);
 
   // Hide urlbar zoom button if zoom is at 100% or the customizable control is
   // in the toolbar.
   urlbarZoomButton.hidden =
     (zoomFactor == 100 ||
      (customizableZoomControls &&
       customizableZoomControls.getAttribute("cui-areatype") == "toolbar"));
 
   let label = win.gNavigatorBundle.getFormattedString("zoom-button.label", [zoomFactor]);
+  if (appMenuZoomReset) {
+    appMenuZoomReset.setAttribute("label", label);
+  }
   if (customizableZoomReset) {
     customizableZoomReset.setAttribute("label", label);
   }
   if (!urlbarZoomButton.hidden) {
     if (aAnimate) {
       urlbarZoomButton.setAttribute("animate", "true");
     } else {
       urlbarZoomButton.removeAttribute("animate");
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -721,40 +721,28 @@ toolbarpaletteitem[place="palette"] > to
   padding-inline-start: 10px;
 }
 
 .panel-banner-item > .toolbarbutton-text {
   width: 0; /* Fancy cropping solution for flexbox. */
 }
 
 /* FxAccount indicator bits. */
+#appMenu-fxa-container:not([fxastatus="signedin"]) {
+  margin-inline-end: 0;
+}
+
 #appMenu-fxa-label,
 #appMenu-fxa-icon {
-  padding: 4px;
-  -moz-appearance: none;
-  box-shadow: none;
-  border-radius: 0;
-  border: 0 none;
-  -moz-box-orient: horizontal;
   -moz-image-region: rect(0, 16px, 16px, 0);
   list-style-image: url(chrome://browser/skin/sync-horizontalbar.png);
 }
 
 #appMenu-fxa-label {
   -moz-box-flex: 1;
-  padding-inline-start: 12px;
-  margin: 0;
-}
-
-#appMenu-fxa-icon {
-  margin: 0 10px;
-}
-
-#appMenu-fxa-icon > .toolbarbutton-text {
-  display: none;
 }
 
 #appMenu-fxa-icon[syncstatus="active"] {
   list-style-image: url(chrome://browser/skin/syncProgress-horizontalbar.png);
 }
 
 #appMenu-fxa-status {
   -moz-box-align: center;
@@ -772,52 +760,34 @@ toolbarpaletteitem[place="palette"] > to
     -moz-image-region: rect(0, 32px, 32px, 0);
   }
 
   #appMenu-fxa-icon[syncstatus="active"] {
     list-style-image: url(chrome://browser/skin/syncProgress-horizontalbar@2x.png);
   }
 }
 
-#appMenu-fxa-container {
-  -moz-box-orient: horizontal;
-}
-
 /* Handle different UI states. */
 #appMenu-fxa-container[fxastatus="signedin"] > #appMenu-fxa-status > #appMenu-fxa-label > .toolbarbutton-icon,
 #appMenu-fxa-container:not([fxastatus="signedin"]) > toolbarseparator,
 #appMenu-fxa-container:not([fxastatus="signedin"]) > #appMenu-fxa-icon,
 #appMenu-fxa-container:not([fxastatus="signedin"]) > #appMenu-fxa-status > #appMenu-fxa-avatar {
   display: none;
 }
 
 #appMenu-fxa-container[fxastatus="signedin"] > #appMenu-fxa-status > #appMenu-fxa-label {
   /* 12px space before the avatar, then 16px for the avatar */
   padding-inline-start: 28px;
   margin-inline-start: -28px;
 }
-#appMenu-fxa-container[fxastatus="signedin"] > #appMenu-fxa-status {
-  margin-inline-end: 10px;
-}
 
 #appMenu-fxa-container[fxastatus="signedin"] > #appMenu-fxa-status > #appMenu-fxa-avatar {
   margin-inline-start: 12px;
 }
 
-#appMenu-fxa-container[fxastatus="signedin"] > toolbarseparator {
-  -moz-appearance: none;
-  height: 24px;
-  margin: 0;
-  border: 0 none;
-  width: 1px;
-  /* Use background: rather than background-color: to override background-image
-   * styles on OS X */
-  background: var(--arrowpanel-dimmed);
-}
-
 /* Error states */
 #appMenu-fxa-container[fxastatus="unverified"] > #appMenu-fxa-status > #appMenu-fxa-label,
 #appMenu-fxa-container[fxastatus="login-failed"] > #appMenu-fxa-status > #appMenu-fxa-label {
   list-style-image: url(chrome://browser/skin/warning.svg);
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
 #appMenu-fxa-container[fxastatus="login-failed"],
@@ -1307,20 +1277,21 @@ photonpanelmultiview .subviewbutton[chec
   list-style-image: url(chrome://browser/skin/check.svg);
 }
 
 photonpanelmultiview .subviewbutton > .menu-iconic-left {
   -moz-appearance: none;
   margin-inline-end: 0;
 }
 
-photonpanelmultiview .toolbaritem-combined-buttons:-moz-any(:not([cui-areatype="toolbar"]), [overflowedItem="true"]) {
+photonpanelmultiview .toolbaritem-combined-buttons@inAnyPanel@ {
   -moz-box-align: center;
   -moz-box-orient: horizontal;
   border: 0;
+  border-radius: 0;
   margin-inline-end: 8px;
 }
 
 photonpanelmultiview .toolbaritem-combined-buttons > label {
   -moz-box-flex: 1;
   font: menu;
   margin: 0;
   padding-inline-start: 36px; /* 12px toolbarbutton padding + 16px icon + 8px label padding start */
@@ -1329,20 +1300,46 @@ photonpanelmultiview .toolbaritem-combin
 photonpanelmultiview .PanelUI-subView .toolbaritem-combined-buttons > .subviewbutton {
   -moz-box-flex: 0;
   height: auto;
   margin-inline-start: 18px;
   min-width: auto;
   padding: 4px;
 }
 
-photonpanelmultiview .PanelUI-subView .toolbaritem-combined-buttons > .subviewbutton > .toolbarbutton-text {
+#appMenu-zoom-controls > .subviewbutton {
+  margin-inline-start: 10px;
+}
+
+.toolbaritem-combined-buttons > toolbarseparator[orient="vertical"] + .subviewbutton,
+#appMenu-zoom-controls > toolbarseparator[orient="vertical"] + .subviewbutton {
+  margin-inline-start: 0;
+}
+
+photonpanelmultiview .PanelUI-subView .toolbaritem-combined-buttons >
+  .subviewbutton-iconic > .toolbarbutton-text,
+photonpanelmultiview .PanelUI-subView .toolbaritem-combined-buttons >
+  .subviewbutton:not(.subviewbutton-iconic) > .toolbarbutton-icon {
   display: none;
 }
 
+/* Using this selector, because this way the hover and active selectors will apply properly. */
+photonpanelmultiview .PanelUI-subView .toolbaritem-combined-buttons >
+  .subviewbutton:not(.subviewbutton-iconic) {
+  background-color: #f9f9f9;
+  border: 1px solid #e1e1e1;
+  border-radius: 10000px;
+  padding: 1px 8px;
+}
+
+photonpanelmultiview .toolbaritem-combined-buttons > .subviewbutton:not(.subviewbutton-iconic) > .toolbarbutton-text {
+  font-size: 1em;
+  padding-inline-start: 0;
+}
+
 photonpanelmultiview .panel-banner-item::after {
   margin-inline-end: 14px;
   margin-inline-start: 10px;
 }
 
 /* END photon adjustments */
 
 panelview .toolbarbutton-1,
@@ -1462,16 +1459,25 @@ menuitem.panel-subview-footer@menuStateA
   margin-right: 5px;
 }
 
 .cui-widget-panelview menuseparator.small-separator {
   margin-left: 10px;
   margin-right: 10px;
 }
 
+.PanelUI-subView toolbarseparator[orient="vertical"] {
+  height: 24px;
+  border-inline-start: 1px solid var(--panel-separator-color);
+  border-top: none;
+  margin: 0;
+  margin-inline-start: 4px;
+  margin-inline-end: 5px;
+}
+
 .subviewbutton > .menu-accel-container {
   -moz-box-pack: start;
   margin-inline-start: 10px;
   margin-inline-end: auto;
   color: GrayText;
 }
 
 #PanelUI-remotetabs-tabslist > toolbarbutton[itemtype="tab"],
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/icons/fullscreen-enter.svg
@@ -0,0 +1,6 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <path fill="context-fill" d="M7.707 8.293a1 1 0 0 0-1.414 0L3 11.586V9a1 1 0 0 0-2 0v5a1 1 0 0 0 1 1h5a1 1 0 1 0 0-2H4.414l3.293-3.293a1 1 0 0 0 0-1.414zM14 1H9a1 1 0 0 0 0 2h2.586L8.293 6.293a1 1 0 1 0 1.414 1.414L13 4.414V7a1 1 0 0 0 2 0V2a1 1 0 0 0-1-1z"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/icons/fullscreen-exit.svg
@@ -0,0 +1,6 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <path fill="context-fill" d="M1.3 14.7c.4.4 1 .4 1.4 0L6 11.4V14c0 .6.4 1 1 1s1-.4 1-1V9c0-.6-.4-1-1-1H2c-.6 0-1 .4-1 1s.4 1 1 1h2.6l-3.3 3.3c-.4.4-.4 1 0 1.4zM9 8h5c.6 0 1-.4 1-1s-.4-1-1-1h-2.6l3.3-3.3c.4-.4.4-1 0-1.4-.4-.4-1-.4-1.4 0L10 4.6V2c0-.6-.4-1-1-1s-1 .5-1 1v5c0 .6.4 1 1 1z"/>
+</svg>
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -123,16 +123,18 @@
   skin/classic/browser/edit-cut.svg                   (../shared/icons/edit-cut.svg)
   skin/classic/browser/edit-paste.svg                 (../shared/icons/edit-paste.svg)
   skin/classic/browser/email-link.svg                 (../shared/icons/email-link.svg)
   skin/classic/browser/feed.svg                       (../shared/icons/feed.svg)
   skin/classic/browser/find.svg                       (../shared/icons/find.svg)
   skin/classic/browser/forget.svg                     (../shared/icons/forget.svg)
   skin/classic/browser/forward.svg                    (../shared/icons/forward.svg)
   skin/classic/browser/fullscreen.svg                 (../shared/icons/fullscreen.svg)
+  skin/classic/browser/fullscreen-enter.svg           (../shared/icons/fullscreen-enter.svg)
+  skin/classic/browser/fullscreen-exit.svg            (../shared/icons/fullscreen-exit.svg)
   skin/classic/browser/help.svg                       (../shared/icons/help.svg)
   skin/classic/browser/history.svg                    (../shared/icons/history.svg)
   skin/classic/browser/home.svg                       (../shared/icons/home.svg)
   skin/classic/browser/library.svg                    (../shared/icons/library.svg)
   skin/classic/browser/link.svg                       (../shared/icons/link.svg)
   skin/classic/browser/mail.svg                       (../shared/icons/mail.svg)
   skin/classic/browser/menu.svg                       (../shared/icons/menu.svg)
   skin/classic/browser/new-tab.svg                    (../shared/icons/new-tab.svg)
--- a/browser/themes/shared/menupanel.inc.css
+++ b/browser/themes/shared/menupanel.inc.css
@@ -228,8 +228,24 @@ toolbarpaletteitem[place="palette"] > #z
 
 #appMenu-paste-button {
   list-style-image: url(chrome://browser/skin/edit-paste.svg);
 }
 
 #appMenu-quit-button {
   list-style-image: url(chrome://browser/skin/quit.svg);
 }
+
+#appMenu-zoomEnlarge-button {
+  list-style-image: url(chrome://browser/skin/zoom-in.svg);
+}
+
+#appMenu-zoomReduce-button {
+  list-style-image: url(chrome://browser/skin/zoom-out.svg);
+}
+
+#appMenu-fullscreen-button {
+  list-style-image: url(chrome://browser/skin/fullscreen-enter.svg);
+}
+
+#appMenu-fullscreen-button[checked] {
+  list-style-image: url(chrome://browser/skin/fullscreen-exit.svg);
+}
--- a/dom/locales/jar.mn
+++ b/dom/locales/jar.mn
@@ -25,11 +25,11 @@
   locale/@AB_CD@/global/layout/xmlparser.properties            (%chrome/layout/xmlparser.properties)
   locale/@AB_CD@/global/layout/HtmlForm.properties             (%chrome/layout/HtmlForm.properties)
   locale/@AB_CD@/global/security/caps.properties               (%chrome/security/caps.properties)
   locale/@AB_CD@/global/security/csp.properties                (%chrome/security/csp.properties)
   locale/@AB_CD@/global/security/security.properties           (%chrome/security/security.properties)
   locale/@AB_CD@/global/xml/prettyprint.dtd                    (%chrome/xml/prettyprint.dtd)
   locale/@AB_CD@/global-platform/win/accessible.properties     (%chrome/accessibility/win/accessible.properties)
   locale/@AB_CD@/global-platform/mac/accessible.properties     (%chrome/accessibility/mac/accessible.properties)
-  locale/@AB_CD@/global-platform/gtk/accessible.properties     (%chrome/accessibility/unix/accessible.properties)
+  locale/@AB_CD@/global-platform/unix/accessible.properties    (%chrome/accessibility/unix/accessible.properties)
   locale/@AB_CD@/global/AccessFu.properties                    (%chrome/accessibility/AccessFu.properties)
   locale/@AB_CD@/global/mathml/mathml.properties               (%chrome/mathml/mathml.properties)
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -510,16 +510,22 @@ ServoRestyleManager::FrameForPseudoEleme
   if (aPseudoTagOrNull == nsCSSPseudoElements::before) {
     return nsLayoutUtils::GetBeforeFrame(aContent);
   }
 
   if (aPseudoTagOrNull == nsCSSPseudoElements::after) {
     return nsLayoutUtils::GetAfterFrame(aContent);
   }
 
+  if (aPseudoTagOrNull == nsCSSPseudoElements::firstLine ||
+      aPseudoTagOrNull == nsCSSPseudoElements::firstLetter) {
+    // TODO(emilio, bz): Figure out the best way to diff these styles.
+    return nullptr;
+  }
+
   MOZ_CRASH("Unkown pseudo-element given to "
             "ServoRestyleManager::FrameForPseudoElement");
   return nullptr;
 }
 
 void
 ServoRestyleManager::DoProcessPendingRestyles(TraversalRestyleBehavior
                                                 aRestyleBehavior)
--- a/layout/reftests/bidi/reftest.list
+++ b/layout/reftests/bidi/reftest.list
@@ -111,17 +111,17 @@ fails-if(webrender) == 413928-1.html 413
 == 612843-1.html 612843-1-ref.html
 == 613149-1a.html 613149-1-ref.html
 == 613149-1b.html 613149-1-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia,36,2) == 613149-2a.html 613149-2-ref.html
 fuzzy-if(Android,24,1) fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia,36,2) == 613149-2b.html 613149-2-ref.html
 == 613157-1.html 613157-1-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia,255,6) == 613157-2.html 613157-2-ref.html
 == 662288-1.html 662288-1-ref.html
-fails-if(styloVsGecko||stylo) == 670226-1.html 670226-1-ref.html
+== 670226-1.html 670226-1-ref.html
 == 676245-1.html 676245-1-ref.html
 fuzzy-if(skiaContent,1,3) fails-if(styloVsGecko) == 698291-1.html 698291-1-ref.html
 == 698706-1.html 698706-1-ref.html
 == 704837-1.html 704837-1-ref.html
 == 712600-1.html 712600-1-ref.html
 == 712600-2.html 712600-2-ref.html
 == 712600-2-dyn.html 712600-2-ref.html
 == 712600-3.html 712600-3-ref.html
--- a/layout/reftests/first-letter/reftest.list
+++ b/layout/reftests/first-letter/reftest.list
@@ -19,44 +19,44 @@ fails-if(!styloVsGecko) == quote-1c.html
 == quote-1c.html quote-1b.html
 fails-if(!styloVsGecko) == quote-1d.html quote-1-ref.html
 == quote-1d.html quote-1b.html
 fails-if(!styloVsGecko) == quote-1e.html quote-1-ref.html # bug 509685
 == quote-1e.html quote-1b.html
 == quote-1f.html quote-1-ref.html
 fails-if(!stylo) fails-if(styloVsGecko) == dynamic-1.html dynamic-1-ref.html # bug 8253
 random-if(d2d) == dynamic-2.html dynamic-2-ref.html
-fails-if(styloVsGecko) asserts-if(styloVsGecko,6) asserts-if(stylo,6) fails-if(stylo) == dynamic-3a.html dynamic-3-ref.html
-fails-if(styloVsGecko) asserts-if(styloVsGecko,6) asserts-if(stylo,6) fails-if(stylo) == dynamic-3b.html dynamic-3-ref.html
+== dynamic-3a.html dynamic-3-ref.html
+== dynamic-3b.html dynamic-3-ref.html
 == 23605-1.html 23605-1-ref.html
 == 23605-2.html 23605-2-ref.html
 == 23605-3.html 23605-3-ref.html
 == 23605-4.html 23605-4-ref.html
 == 23605-5.html 23605-5-ref.html
 == 23605-6.html 23605-6-ref.html
 != 229764-1.html 229764-ref.html
-fails-if(styloVsGecko||stylo) == 229764-2.html 229764-ref.html
+== 229764-2.html 229764-ref.html
 == 329069-1.html 329069-1-ref.html
 fails-if(Android) == 329069-2.html 329069-2-ref.html # Bug 999139
 == 329069-3.html 329069-3-ref.html
 == 329069-4.html 329069-4-ref.html
 HTTP(..) == 329069-5.html 329069-5-ref.html
 == 342120-1.xhtml 342120-1-ref.xhtml
-fails-if(styloVsGecko) asserts-if(styloVsGecko,6) asserts-if(stylo,6) fails-if(stylo) == 379799-1.html 379799-1-ref.html
+== 379799-1.html 379799-1-ref.html
 == 399941-1.html 399941-1-ref.html
 == 399941-2.html 399941-2-ref.html
 == 399941-3.html 399941-3-ref.html
 == 399941-4.html 399941-4-ref.html
 == 399941-5.html 399941-5-ref.html
 == 399941-6.html 399941-6-ref.html
 == 399941-7.html 399941-7-ref.html
 == 399941-8.html 399941-8-ref.html
 == 399941-9.html 399941-9-ref.html
 == 429968-1a.html 429968-1-ref.html
-fails-if(styloVsGecko||stylo) == 429968-1b.html 429968-1-ref.html
+== 429968-1b.html 429968-1-ref.html
 == 429968-2a.html 429968-2-ref.html
 == 429968-2b.html 429968-2-ref.html
 == 429968-2c.html 429968-2-ref.html
 == 441418-1.html 441418-1-ref.html
 == 469227-1.html 469227-1-ref.html
 == 484400-1.html 484400-1-ref.html
 == 594303-1.html 594303-1-ref.html
 fails-if(winWidget||cocoaWidget) == 617869-1.html 617869-1-ref.html
--- a/mobile/android/installer/allowed-dupes.mn
+++ b/mobile/android/installer/allowed-dupes.mn
@@ -79,19 +79,19 @@ chrome/en-US/locale/en-US/browser/overri
 chrome/en-US/locale/en-US/browser/overrides/global/aboutTelemetry.properties
 chrome/en-US/locale/en-US/browser/overrides/global/aboutWebrtc.properties
 chrome/en-US/locale/en-US/browser/overrides/intl.properties
 chrome/en-US/locale/en-US/browser/overrides/passwordmgr.properties
 chrome/en-US/locale/en-US/browser/overrides/plugins.properties
 chrome/en-US/locale/en-US/browser/overrides/plugins/pluginproblem.dtd
 chrome/en-US/locale/en-US/browser/overrides/search/search.properties
 chrome/en-US/locale/en-US/global-platform/mac/intl.properties
-chrome/en-US/locale/en-US/global-platform/gtk/accessible.properties
-chrome/en-US/locale/en-US/global-platform/gtk/intl.properties
-chrome/en-US/locale/en-US/global-platform/gtk/platformKeys.properties
+chrome/en-US/locale/en-US/global-platform/unix/accessible.properties
+chrome/en-US/locale/en-US/global-platform/unix/intl.properties
+chrome/en-US/locale/en-US/global-platform/unix/platformKeys.properties
 chrome/en-US/locale/en-US/global-platform/win/accessible.properties
 chrome/en-US/locale/en-US/global-platform/win/intl.properties
 chrome/en-US/locale/en-US/global-platform/win/platformKeys.properties
 chrome/en-US/locale/en-US/global/AccessFu.properties
 chrome/en-US/locale/en-US/global/about.dtd
 chrome/en-US/locale/en-US/global/aboutAbout.dtd
 chrome/en-US/locale/en-US/global/aboutReader.properties
 chrome/en-US/locale/en-US/global/aboutRights.dtd
--- a/mobile/android/locales/all-locales
+++ b/mobile/android/locales/all-locales
@@ -1,13 +1,14 @@
 an
 ar
 as
 ast
 az
+be
 bg
 bn-BD
 bn-IN
 br
 ca
 cak
 cs
 cy
--- a/python/mozbuild/mozpack/packager/l10n.py
+++ b/python/mozbuild/mozpack/packager/l10n.py
@@ -134,17 +134,17 @@ def _repack(app_finder, l10n_finder, cop
     paths = {}
     for e in app.entries:
         if isinstance(e, ManifestEntryWithRelPath):
             base = mozpath.basedir(e.path, app.bases)
             if base not in l10n_paths:
                 errors.fatal("Locale doesn't contain %s/" % base)
                 # Allow errors to accumulate
                 continue
-            if e.name not in l10n_paths[base]:
+            if key(e) not in l10n_paths[base]:
                 errors.fatal("Locale doesn't have a manifest entry for '%s'" %
                     e.name)
                 # Allow errors to accumulate
                 continue
             paths[e.path] = l10n_paths[base][key(e)]
 
     for pattern in non_chrome:
         for base in app.bases:
--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -383,16 +383,38 @@ dependencies = [
  "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "clipboard"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "clipboard-win 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "objc_id 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "x11-clipboard 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "clipboard-win"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "cmake"
 version = "0.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "gcc 0.3.47 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -454,16 +476,17 @@ dependencies = [
 [[package]]
 name = "constellation"
 version = "0.0.1"
 dependencies = [
  "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "bluetooth_traits 0.0.1",
  "canvas 0.0.1",
  "canvas_traits 0.0.1",
+ "clipboard 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "compositing 0.0.1",
  "debugger 0.0.1",
  "devtools_traits 0.0.1",
  "euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gaol 0.0.1 (git+https://github.com/servo/gaol)",
  "gfx 0.0.1",
  "gfx_traits 0.0.1",
  "ipc-channel 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -850,16 +873,24 @@ dependencies = [
 ]
 
 [[package]]
 name = "error-chain"
 version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "error-chain"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "euclid"
 version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "heapsize 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1878,16 +1909,34 @@ dependencies = [
 name = "objc"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "objc-foundation"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "objc_id 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "objc_id"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "odds"
 version = "0.2.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "offscreen_gl_context"
 version = "0.8.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3378,26 +3427,44 @@ name = "x11"
 version = "2.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "metadeps 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "x11-clipboard"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "xcb 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "x11-dl"
 version = "2.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "xcb"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "xdg"
 version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "xi-unicode"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3458,16 +3525,18 @@ dependencies = [
 "checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8"
 "checksum bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c129aff112dcc562970abb69e2508b40850dd24c274761bb50fb8a0067ba6c27"
 "checksum caseless 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8950b075cff75cdabadee97148a8b5816c7cf62e5948a6005b5255d564b42fe7"
 "checksum cexpr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "393a5f0088efbe41f9d1fcd062f24e83c278608420e62109feb2c8abee07de7d"
 "checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
 "checksum cgl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86765cb42c2a2c497e142af72517c1b4d7ae5bb2f25dfa77a5c69642f2342d89"
 "checksum clang-sys 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff7c2d1502c65748c7221f43ce670b3ba5c697acebfeb85a580827daca6975fc"
 "checksum clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7db281b0520e97fbd15cd615dcd8f8bcad0c26f5f7d5effe705f090f39e9a758"
+"checksum clipboard 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "564a8fdbec95bd0a02df93018ed8f55ecf62449a40f731d54caf8c3a84e3e1e6"
+"checksum clipboard-win 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "693b1280c514045382dfdbb78d1594b1b03cdb66320aeb7ebd2bd38d49bae959"
 "checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac"
 "checksum cocoa 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a5d0bcb4d345adf9b4ada6c5bb3e2b87c8150b79c46f3f26446de5f4d48de4b"
 "checksum color_quant 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a475fc4af42d83d28adf72968d9bcfaf035a1a9381642d8e85d8a04957767b0d"
 "checksum compiletest_rs 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "df47edea8bf052f23ce25a15cbf0be09c96911e3be943d1e81415bfaf0e74bf8"
 "checksum cookie 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30b3493e12a550c2f96be785088d1da8d93189e7237c8a8d0d871bc9070334c3"
 "checksum core-foundation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f51ce3b8ebe311c56de14231eb57572c15abebd2d32b3bcb99bcdb9c101f5ac3"
 "checksum core-foundation-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "41115a6aa5d3e1e5ef98148373f25971d1fad53818553f216495f9e67e90a624"
 "checksum core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ead017dcf77f503dc991f6b52de6084eeea60a94b0a652baa9bf88654a28e83f"
@@ -3493,16 +3562,17 @@ dependencies = [
 "checksum encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
 "checksum energy-monitor 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe872d0664f1cc60db36349af245d892ee67d3c8f78055df0ebc43271fd4e05c"
 "checksum energymon 0.3.0 (git+https://github.com/energymon/energymon-rust.git)" = "<none>"
 "checksum energymon-builder 0.3.0 (git+https://github.com/energymon/energymon-sys.git)" = "<none>"
 "checksum energymon-default-sys 0.3.0 (git+https://github.com/energymon/energymon-sys.git)" = "<none>"
 "checksum energymon-sys 0.3.0 (git+https://github.com/energymon/energymon-sys.git)" = "<none>"
 "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
 "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
+"checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
 "checksum error-chain 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "318cb3c71ee4cdea69fdc9e15c173b245ed6063e1709029e8fd32525a881120f"
 "checksum euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f5517462c626a893f3b027615e88d7102cc6dd3f7f1bcb90c7220fb1da4970b5"
 "checksum expat-sys 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cef36cd1a8a02d28b91d97347c63247b9e4cb8a8e36df36f8201dc87a1c0859c"
 "checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c"
 "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
 "checksum fontsan 0.3.2 (git+https://github.com/servo/fontsan)" = "<none>"
 "checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d"
 "checksum freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fde23272c687e4570aefec06cb71174ec0f5284b725deac4e77ba2665d635faf"
@@ -3571,16 +3641,18 @@ dependencies = [
 "checksum nodrop 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbadd3f4c98dea0bd3d9b4be4c0cdaf1ab57035cb2e41fce3983db5add7cc5"
 "checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
 "checksum num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "ef1a4bf6f9174aa5783a9b4cc892cacd11aebad6c69ad027a0b65c6ca5f8aa37"
 "checksum num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d1891bd7b936f12349b7d1403761c8a0b85a18b148e9da4429d5d102c1a41e"
 "checksum num-rational 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "c2dc5ea04020a8f18318ae485c751f8cfa1c0e69dcf465c29ddaaa64a313cc44"
 "checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99"
 "checksum num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca313f1862c7ec3e0dfe8ace9fa91b1d9cb5c84ace3d00f5ec4216238e93c167"
 "checksum objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "877f30f37acef6749b1841cceab289707f211aecfc756553cd63976190e6cc2e"
+"checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
+"checksum objc_id 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4730aa1c64d722db45f7ccc4113a3e2c465d018de6db4d3e7dfe031e8c8a297"
 "checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba"
 "checksum offscreen_gl_context 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3cadec7378139fd7e48badba0d59cbb6312c7e0eca9b5e3b8ec7a78fc0c6cb28"
 "checksum ogg 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7137bf02687385302f4c0aecd77cfce052b69f5b4ee937be778e125c62f67e30"
 "checksum ogg_metadata 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc665717454399cba557c55ad226148996e9266ee291f8a37a98bb2cded0a490"
 "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842"
 "checksum openssl 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bb5d1663b73d10c6a3eda53e2e9d0346f822394e7b858d7257718f65f61dfbe2"
 "checksum openssl-sys 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)" = "3a5886d87d3e2a0d890bf62dc8944f5e3769a405f7e1e9ef6e517e47fd7a0897"
 "checksum ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da12c96037889ae0be29dd2bdd260e5a62a7df24e6466d5a15bb8131c1c200a8"
@@ -3687,13 +3759,15 @@ dependencies = [
 "checksum webdriver 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d548aabf87411b1b4ba91fd07eacd8b238135c7131a452b8a9f6386209167e18"
 "checksum webrender 0.39.0 (git+https://github.com/servo/webrender)" = "<none>"
 "checksum webrender_traits 0.39.0 (git+https://github.com/servo/webrender)" = "<none>"
 "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
 "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
 "checksum ws 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "04614a58714f3fd4a8b1da4bcae9f031c532d35988c3d39627619248113f8be8"
 "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
 "checksum x11 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db27c597c187da52194a4b8232e7d869503911aab9ff726fefb76d7a830f78ed"
+"checksum x11-clipboard 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "731230b8edcbb9d99247105e4c9ec0a538594d50ad68d2afa8662195f9db2973"
 "checksum x11-dl 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "326c500cdc166fd7c70dd8c8a829cd5c0ce7be5a5d98c25817de2b9bdc67faf8"
+"checksum xcb 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "63e3a849b73e4e1905e4f4d48f1750429bc86ea9f473632ab382a6f69ecb6b33"
 "checksum xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a66b7c2281ebde13cf4391d70d4c7e5946c3c25e72a7b859ca8f677dcd0b0c61"
 "checksum xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "12ea8eda4b1eb72f02d148402e23832d56a33f55d8c1b2d5bcdde91d79d47cb1"
 "checksum xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7ec6c39eaa68382c8e31e35239402c0a9489d4141a8ceb0c716099a0b515b562"
 "checksum xml5ever 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b556f07ec35053061ffa5a1b13468ed6a877a7563756719588fbe0623ee52939"
--- a/servo/components/constellation/Cargo.toml
+++ b/servo/components/constellation/Cargo.toml
@@ -8,16 +8,17 @@ publish = false
 [lib]
 name = "constellation"
 path = "lib.rs"
 
 [dependencies]
 backtrace = "0.3"
 bluetooth_traits = { path = "../bluetooth_traits" }
 canvas = {path = "../canvas"}
+clipboard = "0.3"
 canvas_traits = {path = "../canvas_traits"}
 compositing = {path = "../compositing"}
 debugger = {path = "../debugger"}
 devtools_traits = {path = "../devtools_traits"}
 euclid = "0.11"
 gfx = {path = "../gfx"}
 gfx_traits = {path = "../gfx_traits"}
 ipc-channel = "0.7"
--- a/servo/components/constellation/constellation.rs
+++ b/servo/components/constellation/constellation.rs
@@ -66,16 +66,17 @@
 
 use backtrace::Backtrace;
 use bluetooth_traits::BluetoothRequest;
 use browsingcontext::{BrowsingContext, SessionHistoryChange, SessionHistoryEntry};
 use browsingcontext::{FullyActiveBrowsingContextsIterator, AllBrowsingContextsIterator};
 use canvas::canvas_paint_thread::CanvasPaintThread;
 use canvas::webgl_paint_thread::WebGLPaintThread;
 use canvas_traits::CanvasMsg;
+use clipboard::{ClipboardContext, ClipboardProvider};
 use compositing::SendableFrameTree;
 use compositing::compositor_thread::CompositorProxy;
 use compositing::compositor_thread::Msg as ToCompositorMsg;
 use debugger;
 use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg};
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::{Size2D, TypedSize2D};
 use event_loop::EventLoop;
@@ -258,16 +259,19 @@ pub struct Constellation<Message, LTF, S
 
     /// Pipeline IDs are namespaced in order to avoid name collisions,
     /// and the namespaces are allocated by the constellation.
     next_pipeline_namespace_id: PipelineNamespaceId,
 
     /// The size of the top-level window.
     window_size: WindowSizeData,
 
+    /// Means of accessing the clipboard
+    clipboard_ctx: Option<ClipboardContext>,
+
     /// Bits of state used to interact with the webdriver implementation
     webdriver: WebDriverData,
 
     /// Document states for loaded pipelines (used only when writing screenshots).
     document_states: HashMap<PipelineId, DocumentState>,
 
     /// Are we shutting down?
     shutting_down: bool,
@@ -530,16 +534,27 @@ impl<Message, LTF, STF> Constellation<Me
                 mem_profiler_chan: state.mem_profiler_chan,
                 window_size: WindowSizeData {
                     initial_viewport: opts::get().initial_window_size.to_f32() *
                         ScaleFactor::new(1.0),
                     device_pixel_ratio:
                         ScaleFactor::new(opts::get().device_pixels_per_px.unwrap_or(1.0)),
                 },
                 phantom: PhantomData,
+                clipboard_ctx: if state.supports_clipboard {
+                    match ClipboardContext::new() {
+                        Ok(c) => Some(c),
+                        Err(e) => {
+                            warn!("Error creating clipboard context ({})", e);
+                            None
+                        },
+                    }
+                } else {
+                    None
+                },
                 webdriver: WebDriverData::new(),
                 scheduler_chan: TimerScheduler::start(),
                 document_states: HashMap::new(),
                 webrender_api_sender: state.webrender_api_sender,
                 shutting_down: false,
                 handled_warnings: VecDeque::new(),
                 random_pipeline_closure: opts::get().random_pipeline_closure_probability.map(|prob| {
                     let seed = opts::get().random_pipeline_closure_seed.unwrap_or_else(random);
@@ -1014,21 +1029,36 @@ impl<Message, LTF, STF> Constellation<Me
                     None => { debug!("Pipeline {:?} got event after closure.", pipeline_id); return; }
                     Some(pipeline) => pipeline.event_loop.send(msg),
                 };
                 if let Err(e) = result {
                     self.handle_send_error(pipeline_id, e);
                 }
             }
             FromScriptMsg::GetClipboardContents(sender) => {
-                if let Err(e) = sender.send("".to_owned()) {
+                let contents = match self.clipboard_ctx {
+                    Some(ref mut ctx) => match ctx.get_contents() {
+                        Ok(c) => c,
+                        Err(e) => {
+                            warn!("Error getting clipboard contents ({}), defaulting to empty string", e);
+                            "".to_owned()
+                        },
+                    },
+                    None => "".to_owned(),
+                };
+                if let Err(e) = sender.send(contents.to_owned()) {
                     warn!("Failed to send clipboard ({})", e);
                 }
             }
-            FromScriptMsg::SetClipboardContents(_) => {
+            FromScriptMsg::SetClipboardContents(s) => {
+                if let Some(ref mut ctx) = self.clipboard_ctx {
+                    if let Err(e) = ctx.set_contents(s) {
+                        warn!("Error setting clipboard contents ({})", e);
+                    }
+                }
             }
             FromScriptMsg::SetVisible(pipeline_id, visible) => {
                 debug!("constellation got set visible messsage");
                 self.handle_set_visible_msg(pipeline_id, visible);
             }
             FromScriptMsg::VisibilityChangeComplete(pipeline_id, visible) => {
                 debug!("constellation got set visibility change complete message");
                 self.handle_visibility_change_complete(pipeline_id, visible);
--- a/servo/components/constellation/lib.rs
+++ b/servo/components/constellation/lib.rs
@@ -6,16 +6,17 @@
 #![feature(box_syntax)]
 #![feature(conservative_impl_trait)]
 #![feature(mpsc_select)]
 
 extern crate backtrace;
 extern crate bluetooth_traits;
 extern crate canvas;
 extern crate canvas_traits;
+extern crate clipboard;
 extern crate compositing;
 extern crate debugger;
 extern crate devtools_traits;
 extern crate euclid;
 #[cfg(not(target_os = "windows"))]
 extern crate gaol;
 extern crate gfx;
 extern crate gfx_traits;
--- a/servo/components/script/textinput.rs
+++ b/servo/components/script/textinput.rs
@@ -608,27 +608,27 @@ impl<T: ClipboardProvider> TextInput<T> 
                 self.adjust_horizontal_to_line_end(Direction::Backward, maybe_select);
                 KeyReaction::RedrawSelection
             },
             #[cfg(target_os = "macos")]
             (None, Key::E) if mods == CONTROL => {
                 self.adjust_horizontal_to_line_end(Direction::Forward, maybe_select);
                 KeyReaction::RedrawSelection
             },
-            (Some('a'), _) if is_control_key(mods) => {
+            (_, Key::A) if is_control_key(mods) => {
                 self.select_all();
                 KeyReaction::RedrawSelection
             },
-            (Some('c'), _) if is_control_key(mods) => {
+            (_, Key::C) if is_control_key(mods) => {
                 if let Some(text) = self.get_selection_text() {
                     self.clipboard_provider.set_clipboard_contents(text);
                 }
                 KeyReaction::DispatchInput
             },
-            (Some('v'), _) if is_control_key(mods) => {
+            (_, Key::V) if is_control_key(mods) => {
                 let contents = self.clipboard_provider.clipboard_contents();
                 self.insert_string(contents);
                 KeyReaction::DispatchInput
             },
             (Some(c), _) => {
                 self.insert_char(c);
                 KeyReaction::DispatchInput
             },
--- a/servo/components/style/data.rs
+++ b/servo/components/style/data.rs
@@ -1,14 +1,15 @@
 /* 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/. */
 
 //! Per-node data used in style calculation.
 
+use arrayvec::ArrayVec;
 use context::SharedStyleContext;
 use dom::TElement;
 use properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock};
 use properties::longhands::display::computed_value as display;
 use restyle_hints::{HintComputationContext, RestyleReplacements, RestyleHint};
 use rule_tree::StrongRuleNode;
 use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
 use selectors::matching::VisitedHandlingMode;
@@ -188,18 +189,18 @@ impl EagerPseudoStyles {
         let empty = self.0.as_ref().unwrap().iter().all(|x| x.is_none());
         if empty {
             self.0 = None;
         }
         result
     }
 
     /// Returns a list of the pseudo-elements.
-    pub fn keys(&self) -> Vec<PseudoElement> {
-        let mut v = Vec::new();
+    pub fn keys(&self) -> ArrayVec<[PseudoElement; EAGER_PSEUDO_COUNT]> {
+        let mut v = ArrayVec::new();
         if let Some(ref arr) = self.0 {
             for i in 0..EAGER_PSEUDO_COUNT {
                 if arr[i].is_some() {
                     v.push(PseudoElement::from_eager_index(i));
                 }
             }
         }
         v
--- a/servo/components/style/dom.rs
+++ b/servo/components/style/dom.rs
@@ -377,16 +377,30 @@ pub trait TElement : Eq + PartialEq + De
     /// XXX(emilio): It's a bit unfortunate we need to pass the current computed
     /// values as an argument here, but otherwise Servo would crash due to
     /// double borrows to return it.
     fn existing_style_for_restyle_damage<'a>(&'a self,
                                              current_computed_values: &'a ComputedValues,
                                              pseudo: Option<&PseudoElement>)
                                              -> Option<&'a PreExistingComputedValues>;
 
+    /// Whether a given element may generate a pseudo-element.
+    ///
+    /// This is useful to avoid computing, for example, pseudo styles for
+    /// `::-first-line` or `::-first-letter`, when we know it won't affect us.
+    ///
+    /// TODO(emilio, bz): actually implement the logic for it.
+    fn may_generate_pseudo(
+        &self,
+        _pseudo: &PseudoElement,
+        _primary_style: &ComputedValues,
+    ) -> bool {
+        true
+    }
+
     /// Returns true if this element may have a descendant needing style processing.
     ///
     /// Note that we cannot guarantee the existence of such an element, because
     /// it may have been removed from the DOM between marking it for restyle and
     /// the actual restyle traversal.
     fn has_dirty_descendants(&self) -> bool;
 
     /// Returns whether state or attributes that may change style have changed
@@ -439,17 +453,18 @@ pub trait TElement : Eq + PartialEq + De
     unsafe fn unset_dirty_descendants(&self);
 
     /// Similar to the dirty_descendants but for representing a descendant of
     /// the element needs to be updated in animation-only traversal.
     fn has_animation_only_dirty_descendants(&self) -> bool {
         false
     }
 
-    /// Flag that this element has a descendant for animation-only restyle processing.
+    /// Flag that this element has a descendant for animation-only restyle
+    /// processing.
     ///
     /// Only safe to call with exclusive access to the element.
     unsafe fn set_animation_only_dirty_descendants(&self) {
     }
 
     /// Flag that this element has no descendant for animation-only restyle processing.
     ///
     /// Only safe to call with exclusive access to the element.
--- a/servo/components/style/gecko/generated/pseudo_element_definition.rs
+++ b/servo/components/style/gecko/generated/pseudo_element_definition.rs
@@ -171,22 +171,24 @@ pub enum PseudoElement {
         MozSVGForeignContent,
         /// :-moz-svg-text
         MozSVGText,
 }
 
 
 
 /// The number of eager pseudo-elements.
-pub const EAGER_PSEUDO_COUNT: usize = 2;
+pub const EAGER_PSEUDO_COUNT: usize = 4;
 
 /// The list of eager pseudos.
 pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
     PseudoElement::Before,
     PseudoElement::After,
+    PseudoElement::FirstLine,
+    PseudoElement::FirstLetter,
 ];
 
 impl PseudoElement {
     /// Executes a closure with each pseudo-element as an argument.
     pub fn each<F>(mut fun: F)
         where F: FnMut(Self),
     {
             fun(PseudoElement::After);
@@ -453,17 +455,17 @@ impl PseudoElement {
                 PseudoElement::MozSVGText => true,
         }
     }
 
     /// Whether this pseudo-element is eagerly-cascaded.
     #[inline]
     pub fn is_eager(&self) -> bool {
         matches!(*self,
-                 PseudoElement::Before | PseudoElement::After)
+                 PseudoElement::Before | PseudoElement::After | PseudoElement::FirstLine | PseudoElement::FirstLetter)
     }
 
     /// Gets the flags associated to this pseudo-element, or 0 if it's an
     /// anonymous box.
     pub fn flags(&self) -> u32 {
         match *self {
                 PseudoElement::After => {
                         structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_after
--- a/servo/components/style/gecko/pseudo_element_definition.mako.rs
+++ b/servo/components/style/gecko/pseudo_element_definition.mako.rs
@@ -6,17 +6,17 @@
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub enum PseudoElement {
     % for pseudo in PSEUDOS:
         /// ${pseudo.value}
         ${pseudo.capitalized()},
     % endfor
 }
 
-<% EAGER_PSEUDOS = ["Before", "After"] %>
+<% EAGER_PSEUDOS = ["Before", "After", "FirstLine", "FirstLetter"] %>
 
 /// The number of eager pseudo-elements.
 pub const EAGER_PSEUDO_COUNT: usize = ${len(EAGER_PSEUDOS)};
 
 /// The list of eager pseudos.
 pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
     % for eager_pseudo_name in EAGER_PSEUDOS:
     PseudoElement::${eager_pseudo_name},
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -352,16 +352,17 @@ trait PrivateMatchMethods: TElement {
             // pseudo-elements, it doesn't seem worth the effort at a glance.
             //
             // For the same reason as described in match_primary, if we are
             // computing default styles, we aren't guaranteed the parent
             // will have eagerly computed our styles, so we just handled it
             // below like a lazy pseudo.
             let only_default_rules = context.shared.traversal_flags.for_default_styles();
             if pseudo.is_eager() && !only_default_rules {
+                debug_assert!(pseudo.is_before_or_after());
                 let parent = self.parent_element().unwrap();
                 if !parent.may_have_animations() ||
                    primary_style.rules.get_animation_rules().is_empty() {
                     let parent_data = parent.borrow_data().unwrap();
                     let pseudo_style =
                         parent_data.styles().pseudos.get(&pseudo).unwrap();
                     let values = cascade_visited.values(pseudo_style);
                     return values.clone()
@@ -1101,16 +1102,20 @@ pub trait MatchMethods : TElement {
         SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
             // For pseudo-elements, we only try to match visited rules if there
             // are also unvisited rules.  (This matches Gecko's behavior.)
             if visited_handling == VisitedHandlingMode::RelevantLinkVisited &&
                !data.styles().pseudos.has(&pseudo) {
                 return
             }
 
+            if !self.may_generate_pseudo(&pseudo, data.styles().primary.values()) {
+                return;
+            }
+
             debug_assert!(applicable_declarations.is_empty());
             // NB: We handle animation rules for ::before and ::after when
             // traversing them.
             stylist.push_applicable_declarations(self,
                                                  Some(&pseudo),
                                                  None,
                                                  None,
                                                  AnimationRules(None, None),
--- a/servo/ports/glutin/window.rs
+++ b/servo/ports/glutin/window.rs
@@ -1280,17 +1280,17 @@ impl WindowMethods for Window {
         }
     }
 
     fn allow_navigation(&self, _: ServoUrl) -> bool {
         true
     }
 
     fn supports_clipboard(&self) -> bool {
-        false
+        true
     }
 }
 
 struct GlutinCompositorProxy {
     sender: Sender<compositor_thread::Msg>,
     window_proxy: Option<glutin::WindowProxy>,
 }
 
--- a/servo/servo-tidy.toml
+++ b/servo/servo-tidy.toml
@@ -28,16 +28,17 @@ rand = [
   "uuid",
   "ws",
 ]
 num = []
 
 [ignore]
 # Ignored packages with duplicated versions
 packages = [
+  "error-chain",
   "bitflags",
   "libloading", # Conflicting version is only used at build-time by geckolib.
 ]
 # Files that are ignored for all tidy and lint checks.
 files = [
   # Helper macro where actually a pseudo-element per line makes sense.
   "./components/style/gecko/non_ts_pseudo_class_list.rs",
   # Generated and upstream code combined with our own. Could use cleanup
--- a/taskcluster/ci/l10n/kind.yml
+++ b/taskcluster/ci/l10n/kind.yml
@@ -37,28 +37,16 @@ job-template:
       by-build-platform:
          default: 36000
          android-api-15-l10n: 18000
    tooltool:
       by-build-platform:
          default: public
          android-api-15-l10n: internal
          macosx64-nightly: internal
-   index:
-      type: l10n
-      product:
-         by-build-platform:
-            default: firefox
-            android-api-15-l10n: mobile
-      job-name:
-         by-build-platform:
-            linux-l10n: linux-opt
-            linux64-l10n: linux64-opt
-            macosx64: macosx64-opt
-            android-api-15-l10n: android-api-15-opt
    worker-type:
       by-build-platform:
          default: aws-provisioner-v1/gecko-{level}-b-linux
          android: aws-provisioner-v1/gecko-{level}-b-android
    treeherder:
       symbol: tc(L10n)
       tier:
          by-build-platform:
--- a/testing/marionette/client/marionette_driver/marionette.py
+++ b/testing/marionette/client/marionette_driver/marionette.py
@@ -1331,17 +1331,16 @@ class Marionette(object):
         return self.session
 
     @property
     def test_name(self):
         return self._test_name
 
     @test_name.setter
     def test_name(self, test_name):
-        self._send_message("setTestName", {"value": test_name})
         self._test_name = test_name
 
     def delete_session(self, send_request=True, reset_session_id=False):
         """Close the current session and disconnect from the server.
 
         :param send_request: Optional, if `True` a request to close the session on
             the server side will be send. Use `False` in case of eg. in_app restart()
             or quit(), which trigger a deletion themselves. Defaults to `True`.
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -30,17 +30,16 @@ Cu.import("chrome://marionette/content/e
 Cu.import("chrome://marionette/content/event.js");
 Cu.import("chrome://marionette/content/interaction.js");
 Cu.import("chrome://marionette/content/l10n.js");
 Cu.import("chrome://marionette/content/legacyaction.js");
 Cu.import("chrome://marionette/content/logging.js");
 Cu.import("chrome://marionette/content/modal.js");
 Cu.import("chrome://marionette/content/proxy.js");
 Cu.import("chrome://marionette/content/session.js");
-Cu.import("chrome://marionette/content/simpletest.js");
 Cu.import("chrome://marionette/content/wait.js");
 
 this.EXPORTED_SYMBOLS = ["GeckoDriver", "Context"];
 
 var FRAME_SCRIPT = "chrome://marionette/content/listener.js";
 
 const CLICK_TO_START_PREF = "marionette.debugging.clicktostart";
 const CONTENT_LISTENER_PREF = "marionette.contentListener";
@@ -889,59 +888,16 @@ GeckoDriver.prototype.execute_ = functio
       opts.timeout = timeout;
       let wargs = evaluate.fromJSON(args, this.curBrowser.seenEls, sb.window);
       let evaluatePromise = evaluate.sandbox(sb, script, wargs, opts);
       return evaluatePromise.then(res => evaluate.toJSON(res, this.curBrowser.seenEls));
   }
 };
 
 /**
- * Execute pure JavaScript.  Used to execute simpletest harness tests,
- * which are like mochitests only injected using Marionette.
- *
- * Scripts are expected to call the {@code finish} global when done.
- */
-GeckoDriver.prototype.executeJSScript = function* (cmd, resp) {
-  let win = assert.window(this.getCurrentWindow());
-
-  let {script, args, scriptTimeout} = cmd.parameters;
-  scriptTimeout = scriptTimeout || this.timeouts.script;
-
-  let opts = {
-    filename: cmd.parameters.filename,
-    line: cmd.parameters.line,
-    async: cmd.parameters.async,
-  };
-
-  switch (this.context) {
-    case Context.CHROME:
-      let wargs = evaluate.fromJSON(args, this.curBrowser.seenEls, win);
-      let harness = new simpletest.Harness(
-          win,
-          Context.CHROME,
-          this.marionetteLog,
-          scriptTimeout,
-          function() {},
-          this.testName);
-
-      let sb = sandbox.createSimpleTest(win, harness);
-      // TODO(ato): Not sure this is needed:
-      sb = sandbox.augment(sb, new logging.Adapter(this.marionetteLog));
-
-      let res = yield evaluate.sandbox(sb, script, wargs, opts);
-      resp.body.value = evaluate.toJSON(res, this.curBrowser.seenEls);
-      break;
-
-    case Context.CONTENT:
-      resp.body.value = yield this.listener.executeSimpleTest(script, args, scriptTimeout, opts);
-      break;
-  }
-};
-
-/**
  * Navigate to given URL.
  *
  * Navigates the current browsing context to the given URL and waits for
  * the document to load or the session's page timeout duration to elapse
  * before returning.
  *
  * The command will return with a failure if there is an error loading
  * the document or the URL is blocked.  This can occur if it fails to
@@ -2387,25 +2343,16 @@ GeckoDriver.prototype.sendKeysToElement 
       break;
 
     case Context.CONTENT:
       yield this.listener.sendKeysToElement(id, text);
       break;
   }
 };
 
-/** Sets the test name.  The test name is used for logging purposes. */
-GeckoDriver.prototype.setTestName = function*(cmd, resp) {
-  assert.window(this.getCurrentWindow());
-
-  let val = cmd.parameters.value;
-  this.testName = val;
-  yield this.listener.setTestName({value: val});
-};
-
 /**
  * Clear the text of an element.
  *
  * @param {string} id
  *     Reference ID to the element that will be cleared.
  *
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
--- a/testing/marionette/harness/marionette_harness/marionette_test/testcases.py
+++ b/testing/marionette/harness/marionette_harness/marionette_test/testcases.py
@@ -1,31 +1,29 @@
 # 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/.
 
 import imp
-import os
 import re
 import sys
 import time
 import types
 import unittest
 import warnings
 import weakref
 
 from unittest.case import (
     _ExpectedFailure,
     _UnexpectedSuccess,
     SkipTest,
 )
 
 from marionette_driver.errors import (
     MarionetteException,
-    ScriptTimeoutException,
     TimeoutException,
 )
 from mozlog import get_default_logger
 
 
 def _wraps_parameterized(func, func_suffix, args, kwargs):
     """Internal: Decorator used in class MetaParameterized."""
     def wrapper(self):
@@ -55,23 +53,16 @@ class MetaParameterized(type):
                         raise KeyError("{0} is already a defined method on {1}"
                                        .format(wrapper.__name__, name))
                     attrs[wrapper.__name__] = wrapper
                 del attrs[k]
 
         return type.__new__(cls, name, bases, attrs)
 
 
-class JSTest:
-    head_js_re = re.compile(r"MARIONETTE_HEAD_JS(\s*)=(\s*)['|\"](.*?)['|\"];")
-    context_re = re.compile(r"MARIONETTE_CONTEXT(\s*)=(\s*)['|\"](.*?)['|\"];")
-    timeout_re = re.compile(r"MARIONETTE_TIMEOUT(\s*)=(\s*)(\d+);")
-    inactivity_timeout_re = re.compile(r"MARIONETTE_INACTIVITY_TIMEOUT(\s*)=(\s*)(\d+);")
-
-
 class CommonTestCase(unittest.TestCase):
 
     __metaclass__ = MetaParameterized
     match_re = None
     failureException = AssertionError
     pydebugger = None
 
     def __init__(self, methodName, marionette_weakref, fixtures, **kwargs):
@@ -230,22 +221,19 @@ class CommonTestCase(unittest.TestCase):
     @classmethod
     def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette,
                            fixtures, testvars, **kwargs):
         """Add all the tests in the specified file to the specified suite."""
         raise NotImplementedError
 
     @property
     def test_name(self):
-        if hasattr(self, 'jsFile'):
-            return os.path.basename(self.jsFile)
-        else:
-            return '{0}.py {1}.{2}'.format(self.__class__.__module__,
-                                           self.__class__.__name__,
-                                           self._testMethodName)
+        return '{0}.py {1}.{2}'.format(self.__class__.__module__,
+                                       self.__class__.__name__,
+                                       self._testMethodName)
 
     def id(self):
         # TBPL starring requires that the "test name" field of a failure message
         # not differ over time. The test name to be used is passed to
         # mozlog via the test id, so this is overriden to maintain
         # consistency.
         return self.test_name
 
@@ -293,137 +281,16 @@ if (!testUtils.hasOwnProperty("specialPo
     .getService(Components.interfaces.mozIJSSubScriptLoader);
   loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.jsm",
     testUtils);
   testUtils.specialPowersObserver = new testUtils.SpecialPowersObserver();
   testUtils.specialPowersObserver.init();
 }
 """)
 
-    def run_js_test(self, filename, marionette=None):
-        """Run a JavaScript test file.
-
-        It collects its set of assertions into the current test's results.
-
-        :param filename: The path to the JavaScript test file to execute.
-                         May be relative to the current script.
-        :param marionette: The Marionette object in which to execute the test.
-                           Defaults to self.marionette.
-        """
-        marionette = marionette or self.marionette
-        if not os.path.isabs(filename):
-            # Find the caller's filename and make the path relative to that.
-            caller_file = sys._getframe(1).f_globals.get('__file__', '')
-            caller_file = os.path.abspath(caller_file)
-            filename = os.path.join(os.path.dirname(caller_file), filename)
-        self.assert_(os.path.exists(filename),
-                     'Script "{}" must exist' .format(filename))
-        original_test_name = self.marionette.test_name
-        self.marionette.test_name = os.path.basename(filename)
-        f = open(filename, 'r')
-        js = f.read()
-        args = []
-
-        head_js = JSTest.head_js_re.search(js)
-        if head_js:
-            head_js = head_js.group(3)
-            head = open(os.path.join(os.path.dirname(filename), head_js), 'r')
-            js = head.read() + js
-
-        context = JSTest.context_re.search(js)
-        if context:
-            context = context.group(3)
-        else:
-            context = 'content'
-
-        if 'SpecialPowers' in js:
-            self.setup_SpecialPowers_observer()
-
-            if context == 'content':
-                js = "var SpecialPowers = window.wrappedJSObject.SpecialPowers;\n" + js
-            else:
-                marionette.execute_script("""
-                if (typeof(SpecialPowers) == 'undefined') {
-                  let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
-                    .getService(Components.interfaces.mozIJSSubScriptLoader);
-                  loader.loadSubScript("chrome://specialpowers/content/specialpowersAPI.js");
-                  loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserverAPI.js");
-                  loader.loadSubScript("chrome://specialpowers/content/ChromePowers.js");
-                }
-                """)
-
-        marionette.set_context(context)
-
-        if context != 'chrome':
-            marionette.navigate('data:text/html,<html>test page</html>')
-
-        timeout = JSTest.timeout_re.search(js)
-        if timeout:
-            ms = timeout.group(3)
-            marionette.timeout.script = int(ms) / 1000.0
-
-        inactivity_timeout = JSTest.inactivity_timeout_re.search(js)
-        if inactivity_timeout:
-            inactivity_timeout = int(inactivity_timeout.group(3))
-
-        try:
-            results = marionette.execute_js_script(
-                js,
-                args,
-                inactivity_timeout=inactivity_timeout,
-                filename=os.path.basename(filename)
-            )
-
-            self.assertTrue('timeout' not in filename,
-                            'expected timeout not triggered')
-
-            if 'fail' in filename:
-                self.assertTrue(len(results['failures']) > 0,
-                                "expected test failures didn't occur")
-            else:
-                for failure in results['failures']:
-                    diag = "" if failure.get('diag') is None else failure['diag']
-                    name = ("got false, expected true" if failure.get('name') is None else
-                            failure['name'])
-                    self.logger.test_status(self.test_name, name, 'FAIL',
-                                            message=diag)
-                for failure in results['expectedFailures']:
-                    diag = "" if failure.get('diag') is None else failure['diag']
-                    name = ("got false, expected false" if failure.get('name') is None else
-                            failure['name'])
-                    self.logger.test_status(self.test_name, name, 'FAIL',
-                                            expected='FAIL', message=diag)
-                for failure in results['unexpectedSuccesses']:
-                    diag = "" if failure.get('diag') is None else failure['diag']
-                    name = ("got true, expected false" if failure.get('name') is None else
-                            failure['name'])
-                    self.logger.test_status(self.test_name, name, 'PASS',
-                                            expected='FAIL', message=diag)
-                self.assertEqual(0, len(results['failures']),
-                                 '{} tests failed' .format(len(results['failures'])))
-                if len(results['unexpectedSuccesses']) > 0:
-                    raise _UnexpectedSuccess('')
-                if len(results['expectedFailures']) > 0:
-                    raise _ExpectedFailure((AssertionError, AssertionError(''), None))
-
-            self.assertTrue(results['passed'] +
-                            len(results['failures']) +
-                            len(results['expectedFailures']) +
-                            len(results['unexpectedSuccesses']) > 0,
-                            'no tests run')
-
-        except ScriptTimeoutException:
-            if 'timeout' in filename:
-                # expected exception
-                pass
-            else:
-                self.loglines = marionette.get_logs()
-                raise
-        self.marionette.test_name = original_test_name
-
 
 class MarionetteTestCase(CommonTestCase):
 
     match_re = re.compile(r"test_(.*)\.py$")
 
     def __init__(self, marionette_weakref, fixtures, methodName='runTest',
                  filepath='', **kwargs):
         self.filepath = filepath
@@ -462,33 +329,31 @@ class MarionetteTestCase(CommonTestCase)
                                       methodName=testname,
                                       filepath=filepath,
                                       testvars=testvars,
                                       **kwargs))
 
     def setUp(self):
         super(MarionetteTestCase, self).setUp()
         self.marionette.test_name = self.test_name
-        self.marionette.execute_script("log('TEST-START: {0}:{1}')"
-                                       .format(self.filepath.replace('\\', '\\\\'),
-                                               self.methodName),
+        self.marionette.execute_script("log('TEST-START: {0}')"
+                                       .format(self.test_name),
                                        sandbox="simpletest")
 
     def tearDown(self):
         # In the case no session is active (eg. the application was quit), start
         # a new session for clean-up steps.
         if not self.marionette.session:
             self.marionette.start_session()
 
         if not self.marionette.crashed:
             try:
                 self.marionette.clear_imported_scripts()
-                self.marionette.execute_script("log('TEST-END: {0}:{1}')"
-                                               .format(self.filepath.replace('\\', '\\\\'),
-                                                       self.methodName),
+                self.marionette.execute_script("log('TEST-END: {0}')"
+                                               .format(self.test_name),
                                                sandbox="simpletest")
                 self.marionette.test_name = None
             except (MarionetteException, IOError):
                 # We have tried to log the test end when there is no listener
                 # object that we can access
                 pass
 
         super(MarionetteTestCase, self).tearDown()
--- a/testing/marionette/harness/marionette_harness/runner/base.py
+++ b/testing/marionette/harness/marionette_harness/runner/base.py
@@ -178,18 +178,16 @@ class MarionetteTestResult(StructuredTes
         return test.test_name
 
     def getDescription(self, test):
         doc_first_line = test.shortDescription()
         if self.descriptions and doc_first_line:
             return '\n'.join((str(test), doc_first_line))
         else:
             desc = str(test)
-            if hasattr(test, 'jsFile'):
-                desc = "{0}, {1}".format(test.jsFile, desc)
             return desc
 
     def printLogs(self, test):
         for testcase in test._tests:
             if hasattr(testcase, 'loglines') and testcase.loglines:
                 # Don't dump loglines to the console if they only contain
                 # TEST-START and TEST-END.
                 skip_log = True
@@ -601,17 +599,17 @@ class BaseMarionetteTestRunner(object):
             self.gecko_log = gecko_log
 
         self.results = []
 
     @property
     def filename_pattern(self):
         if self._filename_pattern is None:
             self._filename_pattern = re.compile(
-                "^test(((_.+?)+?\.((py)|(js)))|(([A-Z].*?)+?\.js))$")
+                "^test(((_.+?)+?\.((py))))$")
 
         return self._filename_pattern
 
     @property
     def testvars(self):
         if self._testvars is not None:
             return self._testvars
 
@@ -798,17 +796,17 @@ class BaseMarionetteTestRunner(object):
     def _add_tests(self, tests):
         for test in tests:
             self.add_test(test)
 
         invalid_tests = [t['filepath'] for t in self.tests
                          if not self._is_filename_valid(t['filepath'])]
         if invalid_tests:
             raise Exception("Test file names must be of the form "
-                            "'test_something.py', 'test_something.js', or 'testSomething.js'."
+                            "'test_something.py'."
                             " Invalid test names:\n  {}".format('\n  '.join(invalid_tests)))
 
     def _is_filename_valid(self, filename):
         filename = os.path.basename(filename)
         return self.filename_pattern.match(filename)
 
     def _log_skipped_tests(self):
         for test in self.manifest_skipped_tests:
--- a/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_runner.py
+++ b/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_runner.py
@@ -277,29 +277,29 @@ def test_add_test_module(runner):
         assert expected in runner.tests
     # add_test doesn't validate module names; 'bad_test.py' gets through
     assert len(runner.tests) == 3
 
 
 def test_add_test_directory(runner):
     test_dir = 'path/to/tests'
     dir_contents = [
-        (test_dir, ('subdir',), ('test_a.py', 'test_a.js', 'bad_test_a.py', 'bad_test_a.js')),
-        (test_dir + '/subdir', (), ('test_b.py', 'test_b.js', 'bad_test_b.py', 'bad_test_b.js')),
+        (test_dir, ('subdir',), ('test_a.py', 'bad_test_a.py')),
+        (test_dir + '/subdir', (), ('test_b.py', 'bad_test_b.py')),
     ]
     tests = list(dir_contents[0][2] + dir_contents[1][2])
     assert len(runner.tests) == 0
     # Need to use side effect to make isdir return True for test_dir and False for tests
     with patch('os.path.isdir', side_effect=[True] + [False for t in tests]) as isdir:
         with patch('os.walk', return_value=dir_contents) as walk:
             runner.add_test(test_dir)
     assert isdir.called and walk.called
     for test in runner.tests:
         assert test_dir in test['filepath']
-    assert len(runner.tests) == 4
+    assert len(runner.tests) == 2
 
 
 @pytest.mark.parametrize("test_files_exist", [True, False])
 def test_add_test_manifest(mock_runner, manifest_with_tests, monkeypatch, test_files_exist):
     monkeypatch.setattr('marionette_harness.runner.base.TestManifest',
                         manifest_with_tests.manifest_class)
     mock_runner.marionette = mock_runner.driverclass()
     with patch('marionette_harness.runner.base.os.path.exists', return_value=test_files_exist):
@@ -399,20 +399,20 @@ def test_add_tests(mock_runner):
     fake_tests = ["test_" + i + ".py" for i in "abc"]
     mock_runner.run_tests(fake_tests)
     assert len(mock_runner.tests) == 3
     for (test_name, added_test) in zip(fake_tests, mock_runner.tests):
         assert added_test['filepath'].endswith(test_name)
 
 
 def test_catch_invalid_test_names(runner):
-    good_tests = [u'test_ok.py', u'test_is_ok.py', u'test_is_ok.js', u'testIsOk.js']
-    bad_tests = [u'bad_test.py', u'testbad.py', u'_test_bad.py', u'testBad.notjs',
-                 u'test_bad.notpy', u'test_bad', u'testbad.js', u'badtest.js',
-                 u'test.py', u'test_.py', u'test.js', u'test_.js']
+    good_tests = [u'test_ok.py', u'test_is_ok.py']
+    bad_tests = [u'bad_test.py', u'testbad.py', u'_test_bad.py',
+                 u'test_bad.notpy', u'test_bad',
+                 u'test.py', u'test_.py']
     with pytest.raises(Exception) as exc:
         runner._add_tests(good_tests + bad_tests)
     msg = exc.value.message
     assert "Test file names must be of the form" in msg
     for bad_name in bad_tests:
         assert bad_name in msg
     for good_name in good_tests:
         assert good_name not in msg
deleted file mode 100644
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_chrome_async_finish.js
+++ /dev/null
@@ -1,6 +0,0 @@
-MARIONETTE_TIMEOUT = 60000;
-MARIONETTE_CONTEXT = "chrome";
-ok(true);
-(function () {
-  finish();
-})();
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_execute_script.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_execute_script.py
@@ -24,29 +24,16 @@ globals = set([
               "btoa",
               "document",
               "navigator",
               "URL",
               "window",
               ])
 
 
-class TestExecuteSimpleTestContent(MarionetteTestCase):
-    def test_stack_trace(self):
-        try:
-            self.marionette.execute_js_script("""
-                let a = 1;
-                throwHere();
-                """, filename="file.js")
-            self.assertFalse(True)
-        except errors.JavascriptException as e:
-            self.assertIn("throwHere is not defined", e.message)
-            self.assertIn("@file.js:2", e.stacktrace)
-
-
 class TestExecuteContent(MarionetteTestCase):
 
     def assert_is_defined(self, property, sandbox="default"):
         self.assertTrue(self.marionette.execute_script(
             "return typeof arguments[0] != 'undefined'", [property], sandbox=sandbox),
             "property {} is undefined".format(property))
 
     def assert_is_web_element(self, element):
deleted file mode 100644
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_chrome.js
+++ /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/. */
-
-MARIONETTE_TIMEOUT = 1000;
-MARIONETTE_CONTEXT = 'chrome';
-
-is(2, 2, "test for is()");
-isnot(2, 3, "test for isnot()");
-ok(2 == 2, "test for ok()");
-finish();
-
deleted file mode 100644
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_fail.js
+++ /dev/null
@@ -1,16 +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/. */
-
-MARIONETTE_TIMEOUT = 1000;
-
-/* this test will fail */
-
-setTimeout(function() { 
-    is(1, 2, "is(1,2) should fail", TEST_UNEXPECTED_FAIL, TEST_PASS); 
-    finish();
-}, 100);
-isnot(1, 1, "isnot(1,1) should fail", TEST_UNEXPECTED_FAIL, TEST_PASS);
-ok(1 == 2, "ok(1==2) should fail", TEST_UNEXPECTED_FAIL, TEST_PASS);
-
-
deleted file mode 100644
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_pass.js
+++ /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/. */
-
-MARIONETTE_TIMEOUT = 1000;
-
-is(2, 2, "test for is()");
-isnot(2, 3, "test for isnot()");
-ok(2 == 2, "test for ok()");
-
-setTimeout(finish, 100);
-
deleted file mode 100644
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_sanity.py
+++ /dev/null
@@ -1,107 +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/.
-
-from marionette_harness import MarionetteTestCase
-
-
-class SimpletestSanityTest(MarionetteTestCase):
-    callFinish = "return finish();"
-
-    def run_sync(self, test):
-        return self.marionette.execute_js_script(test, async=False)
-
-    def run_async(self, test):
-        return self.marionette.execute_js_script(test)
-
-    def test_is(self):
-        def runtests():
-            sentFail1 = "is(true, false, 'isTest1', TEST_UNEXPECTED_FAIL, TEST_PASS);" + self.callFinish
-            sentFail2 = "is(true, false, 'isTest2', TEST_UNEXPECTED_FAIL, TEST_PASS);" + self.callFinish
-            sentPass1 = "is(true, true, 'isTest3');" + self.callFinish
-            sentPass2 = "is(true, true, 'isTest4');" + self.callFinish
-
-            self.assertEqual(1, len(self.run_sync(sentFail1)["failures"]))
-            self.assertEqual(0, self.run_sync(sentFail2)["passed"])
-            self.assertEqual(1, self.run_sync(sentPass1)["passed"])
-            self.assertEqual(0, len(self.run_sync(sentPass2)["failures"]))
-
-            self.marionette.timeout.script = 1
-            self.assertEqual(1, len(self.run_async(sentFail1)["failures"]))
-            self.assertEqual(0, self.run_async(sentFail2)["passed"])
-            self.assertEqual(1, self.run_async(sentPass1)["passed"])
-            self.assertEqual(0, len(self.run_async(sentPass2)["failures"]))
-
-        self.marionette.set_context("content")
-        runtests()
-        self.marionette.set_context("chrome")
-        runtests()
-
-    def test_isnot(self):
-        def runtests():
-           sentFail1 = "isnot(true, true, 'isnotTest3', TEST_UNEXPECTED_FAIL, TEST_PASS);" + self.callFinish
-           sentFail2 = "isnot(true, true, 'isnotTest4', TEST_UNEXPECTED_FAIL, TEST_PASS);" + self.callFinish
-           sentPass1 = "isnot(true, false, 'isnotTest1');" + self.callFinish
-           sentPass2 = "isnot(true, false, 'isnotTest2');" + self.callFinish
-
-           self.assertEqual(1, len(self.run_sync(sentFail1)["failures"]));
-           self.assertEqual(0, self.run_sync(sentFail2)["passed"]);
-           self.assertEqual(0, len(self.run_sync(sentPass1)["failures"]));
-           self.assertEqual(1, self.run_sync(sentPass2)["passed"]);
-
-           self.marionette.timeout.script = 1
-           self.assertEqual(1, len(self.run_async(sentFail1)["failures"]));
-           self.assertEqual(0, self.run_async(sentFail2)["passed"]);
-           self.assertEqual(0, len(self.run_async(sentPass1)["failures"]));
-           self.assertEqual(1, self.run_async(sentPass2)["passed"]);
-
-        self.marionette.set_context("content")
-        runtests()
-        self.marionette.set_context("chrome")
-        runtests()
-
-    def test_ok(self):
-        def runtests():
-            sentFail1 = "ok(1==2, 'testOk1', TEST_UNEXPECTED_FAIL, TEST_PASS);" + self.callFinish
-            sentFail2 = "ok(1==2, 'testOk2', TEST_UNEXPECTED_FAIL, TEST_PASS);" + self.callFinish
-            sentPass1 = "ok(1==1, 'testOk3');" + self.callFinish
-            sentPass2 = "ok(1==1, 'testOk4');" + self.callFinish
-
-            self.assertEqual(1, len(self.run_sync(sentFail1)["failures"]));
-            self.assertEqual(0, self.run_sync(sentFail2)["passed"]);
-            self.assertEqual(0, len(self.run_sync(sentPass1)["failures"]));
-            self.assertEqual(1, self.run_sync(sentPass2)["passed"]);
-
-            self.marionette.timeout.script = 1
-            self.assertEqual(1, len(self.run_async(sentFail1)["failures"]));
-            self.assertEqual(0, self.run_async(sentFail2)["passed"]);
-            self.assertEqual(0, len(self.run_async(sentPass1)["failures"]));
-            self.assertEqual(1, self.run_async(sentPass2)["passed"]);
-
-        self.marionette.set_context("content")
-        runtests()
-        self.marionette.set_context("chrome")
-        runtests()
-
-    def test_todo(self):
-        def runtests():
-            sentFail1 = "todo(1==1, 'testTodo1', TEST_UNEXPECTED_PASS, TEST_KNOWN_FAIL);" + self.callFinish
-            sentFail2 = "todo(1==1, 'testTodo2', TEST_UNEXPECTED_PASS, TEST_KNOWN_FAIL);" + self.callFinish
-            sentPass1 = "todo(1==2, 'testTodo3');" + self.callFinish
-            sentPass2 = "todo(1==2, 'testTodo4');" + self.callFinish
-
-            self.assertEqual(1, len(self.run_sync(sentFail1)["unexpectedSuccesses"]));
-            self.assertEqual(0, len(self.run_sync(sentFail2)["expectedFailures"]));
-            self.assertEqual(0, len(self.run_sync(sentPass1)["unexpectedSuccesses"]));
-            self.assertEqual(1, len(self.run_sync(sentPass2)["expectedFailures"]));
-
-            self.marionette.timeout.script = 1
-            self.assertEqual(1, len(self.run_async(sentFail1)["unexpectedSuccesses"]));
-            self.assertEqual(0, len(self.run_async(sentFail2)["expectedFailures"]));
-            self.assertEqual(0, len(self.run_async(sentPass1)["unexpectedSuccesses"]));
-            self.assertEqual(1, len(self.run_async(sentPass2)["expectedFailures"]));
-
-        self.marionette.set_context("content")
-        runtests()
-        self.marionette.set_context("chrome")
-        runtests()
deleted file mode 100644
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_simpletest_timeout.js
+++ /dev/null
@@ -1,16 +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/. */
-
-MARIONETTE_TIMEOUT = 100;
-
-/* this test will timeout */
-
-function do_test() {
-  is(1, 1);
-  isnot(1, 2);
-  ok(1 == 1);
-  finish();
-}
-
-setTimeout(do_test, 1000);
--- a/testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
+++ b/testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
@@ -28,33 +28,28 @@ skip-if = true # "Bug 896046"
 
 [test_clearing.py]
 [test_typing.py]
 
 [test_log.py]
 
 [test_execute_async_script.py]
 [test_execute_script.py]
-[test_simpletest_fail.js]
 [test_element_retrieval.py]
 [test_findelement_chrome.py]
 skip-if = appname == 'fennec'
 
 [test_get_current_url_chrome.py]
 [test_navigation.py]
 
 [test_timeouts.py]
 
 [test_single_finger_desktop.py]
 skip-if = appname == 'fennec' || os == "win" # Bug 1025040
 
-[test_simpletest_pass.js]
-[test_simpletest_sanity.py]
-[test_simpletest_chrome.js]
-[test_simpletest_timeout.js]
 [test_anonymous_content.py]
 skip-if = appname == 'fennec'
 [test_switch_frame.py]
 [test_switch_frame_chrome.py]
 skip-if = appname == 'fennec'
 [test_switch_remote_frame.py]
 skip-if = appname == 'fennec'
 [test_switch_window_chrome.py]
@@ -88,17 +83,16 @@ skip-if = appname == 'fennec'
 [test_window_type_chrome.py]
 skip-if = appname == 'fennec'
 [test_implicit_waits.py]
 [test_wait.py]
 [test_expected.py]
 [test_date_time_value.py]
 [test_getactiveframe_oop.py]
 skip-if = true # Bug 925688
-[test_chrome_async_finish.js]
 [test_screen_orientation.py]
 [test_errors.py]
 
 [test_execute_isolate.py]
 [test_click_scrolling.py]
 [test_profile_management.py]
 skip-if = manage_instance == false || appname == 'fennec' # Bug 1298921 and bug 1322993
 [test_quit_restart.py]
--- a/testing/marionette/jar.mn
+++ b/testing/marionette/jar.mn
@@ -8,17 +8,16 @@ marionette.jar:
   content/driver.js (driver.js)
   content/action.js (action.js)
   content/legacyaction.js (legacyaction.js)
   content/browser.js (browser.js)
   content/interaction.js (interaction.js)
   content/accessibility.js (accessibility.js)
   content/listener.js (listener.js)
   content/element.js (element.js)
-  content/simpletest.js (simpletest.js)
   content/frame.js (frame.js)
   content/cert.js (cert.js)
   content/event.js  (event.js)
   content/error.js (error.js)
   content/wait.js (wait.js)
   content/message.js (message.js)
   content/modal.js (modal.js)
   content/proxy.js (proxy.js)
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -22,17 +22,16 @@ Cu.import("chrome://marionette/content/e
 Cu.import("chrome://marionette/content/evaluate.js");
 Cu.import("chrome://marionette/content/event.js");
 Cu.import("chrome://marionette/content/interaction.js");
 Cu.import("chrome://marionette/content/legacyaction.js");
 Cu.import("chrome://marionette/content/logging.js");
 Cu.import("chrome://marionette/content/navigate.js");
 Cu.import("chrome://marionette/content/proxy.js");
 Cu.import("chrome://marionette/content/session.js");
-Cu.import("chrome://marionette/content/simpletest.js");
 
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 Cu.importGlobalProperties(["URL"]);
 
@@ -485,27 +484,25 @@ var performActionsFn = dispatch(performA
 var releaseActionsFn = dispatch(releaseActions);
 var actionChainFn = dispatch(actionChain);
 var multiActionFn = dispatch(multiAction);
 var addCookieFn = dispatch(addCookie);
 var deleteCookieFn = dispatch(deleteCookie);
 var deleteAllCookiesFn = dispatch(deleteAllCookies);
 var executeFn = dispatch(execute);
 var executeInSandboxFn = dispatch(executeInSandbox);
-var executeSimpleTestFn = dispatch(executeSimpleTest);
 var sendKeysToElementFn = dispatch(sendKeysToElement);
 
 /**
  * Start all message listeners
  */
 function startListeners() {
   addMessageListenerId("Marionette:newSession", newSession);
   addMessageListenerId("Marionette:execute", executeFn);
   addMessageListenerId("Marionette:executeInSandbox", executeInSandboxFn);
-  addMessageListenerId("Marionette:executeSimpleTest", executeSimpleTestFn);
   addMessageListenerId("Marionette:singleTap", singleTapFn);
   addMessageListenerId("Marionette:performActions", performActionsFn);
   addMessageListenerId("Marionette:releaseActions", releaseActionsFn);
   addMessageListenerId("Marionette:actionChain", actionChainFn);
   addMessageListenerId("Marionette:multiAction", multiActionFn);
   addMessageListenerId("Marionette:get", get);
   addMessageListenerId("Marionette:waitForPageLoaded", waitForPageLoaded);
   addMessageListenerId("Marionette:cancelRequest", cancelRequest);
@@ -530,17 +527,16 @@ function startListeners() {
   addMessageListenerId("Marionette:sendKeysToElement", sendKeysToElementFn);
   addMessageListenerId("Marionette:clearElement", clearElementFn);
   addMessageListenerId("Marionette:switchToFrame", switchToFrame);
   addMessageListenerId("Marionette:switchToParentFrame", switchToParentFrame);
   addMessageListenerId("Marionette:switchToShadowRoot", switchToShadowRootFn);
   addMessageListenerId("Marionette:deleteSession", deleteSession);
   addMessageListenerId("Marionette:sleepSession", sleepSession);
   addMessageListenerId("Marionette:getAppCacheStatus", getAppCacheStatus);
-  addMessageListenerId("Marionette:setTestName", setTestName);
   addMessageListenerId("Marionette:takeScreenshot", takeScreenshotFn);
   addMessageListenerId("Marionette:addCookie", addCookieFn);
   addMessageListenerId("Marionette:getCookies", getCookiesFn);
   addMessageListenerId("Marionette:deleteAllCookies", deleteAllCookiesFn);
   addMessageListenerId("Marionette:deleteCookie", deleteCookieFn);
 }
 
 /**
@@ -571,17 +567,16 @@ function restart(msg) {
 
 /**
  * Removes all listeners
  */
 function deleteSession(msg) {
   removeMessageListenerId("Marionette:newSession", newSession);
   removeMessageListenerId("Marionette:execute", executeFn);
   removeMessageListenerId("Marionette:executeInSandbox", executeInSandboxFn);
-  removeMessageListenerId("Marionette:executeSimpleTest", executeSimpleTestFn);
   removeMessageListenerId("Marionette:singleTap", singleTapFn);
   removeMessageListenerId("Marionette:performActions", performActionsFn);
   removeMessageListenerId("Marionette:releaseActions", releaseActionsFn);
   removeMessageListenerId("Marionette:actionChain", actionChainFn);
   removeMessageListenerId("Marionette:multiAction", multiActionFn);
   removeMessageListenerId("Marionette:get", get);
   removeMessageListenerId("Marionette:waitForPageLoaded", waitForPageLoaded);
   removeMessageListenerId("Marionette:cancelRequest", cancelRequest);
@@ -606,17 +601,16 @@ function deleteSession(msg) {
   removeMessageListenerId("Marionette:sendKeysToElement", sendKeysToElementFn);
   removeMessageListenerId("Marionette:clearElement", clearElementFn);
   removeMessageListenerId("Marionette:switchToFrame", switchToFrame);
   removeMessageListenerId("Marionette:switchToParentFrame", switchToParentFrame);
   removeMessageListenerId("Marionette:switchToShadowRoot", switchToShadowRootFn);
   removeMessageListenerId("Marionette:deleteSession", deleteSession);
   removeMessageListenerId("Marionette:sleepSession", sleepSession);
   removeMessageListenerId("Marionette:getAppCacheStatus", getAppCacheStatus);
-  removeMessageListenerId("Marionette:setTestName", setTestName);
   removeMessageListenerId("Marionette:takeScreenshot", takeScreenshotFn);
   removeMessageListenerId("Marionette:addCookie", addCookieFn);
   removeMessageListenerId("Marionette:getCookies", getCookiesFn);
   removeMessageListenerId("Marionette:deleteAllCookies", deleteAllCookiesFn);
   removeMessageListenerId("Marionette:deleteCookie", deleteCookieFn);
 
   seenEls.clear();
   // reset container frame to the top-most frame
@@ -758,49 +752,16 @@ function* executeInSandbox(script, args,
 
   let res = yield evaluatePromise;
   sendSyncMessage(
       "Marionette:shareData",
       {log: evaluate.toJSON(contentLog.get(), seenEls)});
   return evaluate.toJSON(res, seenEls);
 }
 
-function* executeSimpleTest(script, args, timeout, opts) {
-  opts.timeout = timeout;
-  let win = curContainer.frame;
-
-  let harness = new simpletest.Harness(
-      win,
-      "content",
-      contentLog,
-      timeout,
-      marionetteTestName);
-  let sb = sandbox.createSimpleTest(curContainer.frame, harness);
-  // TODO(ato): Not sure this is needed:
-  sb = sandbox.augment(sb, new logging.Adapter(contentLog));
-
-  let wargs = evaluate.fromJSON(
-      args, seenEls, curContainer.frame, curContainer.shadowRoot);
-  let evaluatePromise = evaluate.sandbox(sb, script, wargs, opts);
-
-  let res = yield evaluatePromise;
-  sendSyncMessage(
-      "Marionette:shareData",
-      {log: evaluate.toJSON(contentLog.get(), seenEls)});
-  return evaluate.toJSON(res, seenEls);
-}
-
-/**
- * Sets the test name, used in logging messages.
- */
-function setTestName(msg) {
-  marionetteTestName = msg.json.value;
-  sendOk(msg.json.command_id);
-}
-
 /**
  * This function creates a touch event given a touch type and a touch
  */
 function emitTouchEvent(type, touch) {
   if (!wasInterrupted()) {
     logger.info(`Emitting Touch event of type ${type} to element with id: ${touch.target.id} ` +
                 `and tag name: ${touch.target.tagName} at coordinates (${touch.clientX}, ` +
                 `${touch.clientY}) relative to the viewport`);
deleted file mode 100644
--- a/testing/marionette/simpletest.js
+++ /dev/null
@@ -1,208 +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/. */
-
-"use strict";
-
-const {utils: Cu} = Components;
-
-Cu.import("chrome://marionette/content/error.js");
-
-this.EXPORTED_SYMBOLS = ["simpletest"];
-
-this.simpletest = {};
-
-/**
- * The simpletest harness, exposed in the script evaluation sandbox.
- */
-simpletest.Harness = class {
-  constructor(window, context, contentLogger, timeout, testName) {
-    this.window = window;
-    this.tests = [];
-    this.logger = contentLogger;
-    this.context = context;
-    this.timeout = timeout;
-    this.testName = testName;
-    this.TEST_UNEXPECTED_FAIL = "TEST-UNEXPECTED-FAIL";
-    this.TEST_UNEXPECTED_PASS = "TEST-UNEXPECTED-PASS";
-    this.TEST_PASS = "TEST-PASS";
-    this.TEST_KNOWN_FAIL = "TEST-KNOWN-FAIL";
-  }
-
-  get exports() {
-    return new Map([
-      ["ok", this.ok.bind(this)],
-      ["is", this.is.bind(this)],
-      ["isnot", this.isnot.bind(this)],
-      ["todo", this.todo.bind(this)],
-      ["log", this.log.bind(this)],
-      ["getLogs", this.getLogs.bind(this)],
-      ["generate_results", this.generate_results.bind(this)],
-      ["waitFor", this.waitFor.bind(this)],
-      ["TEST_PASS", this.TEST_PASS],
-      ["TEST_KNOWN_FAIL", this.TEST_KNOWN_FAIL],
-      ["TEST_UNEXPECTED_FAIL", this.TEST_UNEXPECTED_FAIL],
-      ["TEST_UNEXPECTED_PASS", this.TEST_UNEXPECTED_PASS],
-    ]);
-  }
-
-  addTest(condition, name, passString, failString, diag, state) {
-    let test = {
-      result: !!condition,
-      name: name,
-      diag: diag,
-      state: state
-    };
-    this.logResult(
-        test,
-        typeof passString == "undefined" ? this.TEST_PASS : passString,
-        typeof failString == "undefined" ? this.TEST_UNEXPECTED_FAIL : failString);
-    this.tests.push(test);
-  }
-
-  ok(condition, name, passString, failString) {
-    let diag = `${this.repr(condition)} was ${!!condition}, expected true`;
-    this.addTest(condition, name, passString, failString, diag);
-  }
-
-  is(a, b, name, passString, failString) {
-    let pass = (a == b);
-    let diag = pass ? this.repr(a) + " should equal " + this.repr(b)
-                    : "got " + this.repr(a) + ", expected " + this.repr(b);
-    this.addTest(pass, name, passString, failString, diag);
-  }
-
-  isnot(a, b, name, passString, failString) {
-    let pass = (a != b);
-    let diag = pass ? this.repr(a) + " should not equal " + this.repr(b)
-                    : "didn't expect " + this.repr(a) + ", but got it";
-    this.addTest(pass, name, passString, failString, diag);
-  }
-
-  todo(condition, name, passString, failString) {
-    let diag = this.repr(condition) + " was expected false";
-    this.addTest(!condition,
-                 name,
-                 typeof(passString) == "undefined" ? this.TEST_KNOWN_FAIL : passString,
-                 typeof(failString) == "undefined" ? this.TEST_UNEXPECTED_FAIL : failString,
-                 diag,
-                 "todo");
-  }
-
-  log(msg, level) {
-    dump("MARIONETTE LOG: " + (level ? level : "INFO") + ": " + msg + "\n");
-    if (this.logger) {
-      this.logger.log(msg, level);
-    }
-  }
-
-  // TODO(ato): Suspect this isn't used anywhere
-  getLogs() {
-    if (this.logger) {
-      return this.logger.get();
-    }
-  }
-
-  generate_results() {
-    let passed = 0;
-    let failures = [];
-    let expectedFailures = [];
-    let unexpectedSuccesses = [];
-    for (let i in this.tests) {
-      let isTodo = (this.tests[i].state == "todo");
-      if(this.tests[i].result) {
-        if (isTodo) {
-          expectedFailures.push({'name': this.tests[i].name, 'diag': this.tests[i].diag});
-        }
-        else {
-          passed++;
-        }
-      }
-      else {
-        if (isTodo) {
-          unexpectedSuccesses.push({'name': this.tests[i].name, 'diag': this.tests[i].diag});
-        }
-        else {
-          failures.push({'name': this.tests[i].name, 'diag': this.tests[i].diag});
-        }
-      }
-    }
-    // Reset state in case this object is reused for more tests.
-    this.tests = [];
-    return {
-      passed: passed,
-      failures: failures,
-      expectedFailures: expectedFailures,
-      unexpectedSuccesses: unexpectedSuccesses,
-    };
-  }
-
-  logToFile(file) {
-    //TODO
-  }
-
-  logResult(test, passString, failString) {
-    //TODO: dump to file
-    let resultString = test.result ? passString : failString;
-    let diagnostic = test.name + (test.diag ? " - " + test.diag : "");
-    let msg = resultString + " | " + this.testName + " | " + diagnostic;
-    dump("MARIONETTE TEST RESULT:" + msg + "\n");
-  }
-
-  repr(o) {
-    if (typeof o == "undefined") {
-      return "undefined";
-    } else if (o === null) {
-      return "null";
-    }
-
-    try {
-        if (typeof o.__repr__ == "function") {
-          return o.__repr__();
-        } else if (typeof o.repr == "function" && o.repr !== arguments.callee) {
-          return o.repr();
-        }
-   } catch (e) {}
-
-   try {
-      if (typeof o.NAME === "string" &&
-          (o.toString === Function.prototype.toString || o.toString === Object.prototype.toString)) {
-        return o.NAME;
-      }
-    } catch (e) {}
-
-    let ostring;
-    try {
-      ostring = (o + "");
-    } catch (e) {
-      return "[" + typeof(o) + "]";
-    }
-
-    if (typeof o == "function") {
-      o = ostring.replace(/^\s+/, "");
-      let idx = o.indexOf("{");
-      if (idx != -1) {
-        o = o.substr(0, idx) + "{...}";
-      }
-    }
-    return ostring;
-  }
-
-  waitFor(callback, test, timeout) {
-    if (test()) {
-      callback();
-      return;
-    }
-
-    let now = new Date();
-    let deadline = (timeout instanceof Date) ? timeout :
-        new Date(now.valueOf() + (typeof timeout == "undefined" ? this.timeout : timeout));
-    if (deadline <= now) {
-      dump("waitFor timeout: " + test.toString() + "\n");
-      // the script will timeout here, so no need to raise a separate
-      // timeout exception
-      return;
-    }
-    this.window.setTimeout(this.waitFor.bind(this), 100, callback, test, deadline);
-  }
-};
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -1478,16 +1478,17 @@
   },
   "GHOST_WINDOWS": {
     "record_in_processes": ["main", "content"],
     "alert_emails": ["memshrink-telemetry-alerts@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 128,
     "n_buckets": 32,
+    "releaseChannelCollection": "opt-out",
     "description": "Number of ghost windows"
   },
   "MEMORY_FREE_PURGED_PAGES_MS": {
     "record_in_processes": ["main", "content"],
     "alert_emails": ["memshrink-telemetry-alerts@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 1024,
--- a/toolkit/components/telemetry/TelemetrySession.jsm
+++ b/toolkit/components/telemetry/TelemetrySession.jsm
@@ -1100,20 +1100,16 @@ var Impl = {
 
     return ret;
   },
 
   /**
    * Pull values from about:memory into corresponding histograms
    */
   gatherMemory: function gatherMemory() {
-    if (!Telemetry.canRecordExtended) {
-      return;
-    }
-
     let mgr;
     try {
       mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
             getService(Ci.nsIMemoryReporterManager);
     } catch (e) {
       // OK to skip memory reporters in xpcshell
       return;
     }
@@ -1152,30 +1148,36 @@ var Impl = {
       } catch (e) {
       }
     }
     let b = (id, n) => h(id, Ci.nsIMemoryReporter.UNITS_BYTES, n);
     let c = (id, n) => h(id, Ci.nsIMemoryReporter.UNITS_COUNT, n);
     let cc = (id, n) => h(id, Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE, n);
     let p = (id, n) => h(id, Ci.nsIMemoryReporter.UNITS_PERCENTAGE, n);
 
+    // GHOST_WINDOWS is opt-out as of Firefox 55
+    c("GHOST_WINDOWS", "ghostWindows");
+
+    if (!Telemetry.canRecordExtended) {
+      return;
+    }
+
     b("MEMORY_VSIZE", "vsize");
     b("MEMORY_VSIZE_MAX_CONTIGUOUS", "vsizeMaxContiguous");
     b("MEMORY_RESIDENT_FAST", "residentFast");
     b("MEMORY_UNIQUE", "residentUnique");
     b("MEMORY_HEAP_ALLOCATED", "heapAllocated");
     p("MEMORY_HEAP_OVERHEAD_FRACTION", "heapOverheadFraction");
     b("MEMORY_JS_GC_HEAP", "JSMainRuntimeGCHeap");
     c("MEMORY_JS_COMPARTMENTS_SYSTEM", "JSMainRuntimeCompartmentsSystem");
     c("MEMORY_JS_COMPARTMENTS_USER", "JSMainRuntimeCompartmentsUser");
     b("MEMORY_IMAGES_CONTENT_USED_UNCOMPRESSED", "imagesContentUsedUncompressed");
     b("MEMORY_STORAGE_SQLITE", "storageSQLite");
     cc("LOW_MEMORY_EVENTS_VIRTUAL", "lowMemoryEventsVirtual");
     cc("LOW_MEMORY_EVENTS_PHYSICAL", "lowMemoryEventsPhysical");
-    c("GHOST_WINDOWS", "ghostWindows");
     cc("PAGE_FAULTS_HARD", "pageFaultsHard");
 
     if (!Utils.isContentProcess && !this._totalMemoryTimeout) {
       // Only the chrome process should gather total memory
       // total = parent RSS + sum(child USS)
       this._totalMemory = mgr.residentFast;
       if (ppmm.childCount > 1) {
         // Do not report If we time out waiting for the children to call
--- a/toolkit/locales/jar.mn
+++ b/toolkit/locales/jar.mn
@@ -87,24 +87,24 @@
   locale/@AB_CD@/global/textcontext.dtd                 (%chrome/global/textcontext.dtd)
   locale/@AB_CD@/global/videocontrols.dtd               (%chrome/global/videocontrols.dtd)
   locale/@AB_CD@/global/viewSource.dtd                  (%chrome/global/viewSource.dtd)
   locale/@AB_CD@/global/viewSource.properties           (%chrome/global/viewSource.properties)
   locale/@AB_CD@/global/wizard.dtd                      (%chrome/global/wizard.dtd)
   locale/@AB_CD@/global/wizard.properties               (%chrome/global/wizard.properties)
   locale/@AB_CD@/global/crashes.dtd                     (%crashreporter/crashes.dtd)
   locale/@AB_CD@/global/crashes.properties              (%crashreporter/crashes.properties)
-% locale global-platform @AB_CD@ %locale/@AB_CD@/global-platform/gtk/
+% locale global-platform @AB_CD@ %locale/@AB_CD@/global-platform/unix/ os=LikeUnix
 % locale global-platform @AB_CD@ %locale/@AB_CD@/global-platform/mac/ os=Darwin
 % locale global-platform @AB_CD@ %locale/@AB_CD@/global-platform/win/ os=WINNT
   locale/@AB_CD@/global-platform/mac/platformKeys.properties  (%chrome/global-platform/mac/platformKeys.properties)
-  locale/@AB_CD@/global-platform/gtk/platformKeys.properties  (%chrome/global-platform/unix/platformKeys.properties)
+  locale/@AB_CD@/global-platform/unix/platformKeys.properties (%chrome/global-platform/unix/platformKeys.properties)
   locale/@AB_CD@/global-platform/win/platformKeys.properties  (%chrome/global-platform/win/platformKeys.properties)
   locale/@AB_CD@/global-platform/mac/intl.properties          (%chrome/global-platform/mac/intl.properties)
-  locale/@AB_CD@/global-platform/gtk/intl.properties          (%chrome/global-platform/unix/intl.properties)
+  locale/@AB_CD@/global-platform/unix/intl.properties         (%chrome/global-platform/unix/intl.properties)
   locale/@AB_CD@/global-platform/win/intl.properties          (%chrome/global-platform/win/intl.properties)
 % locale mozapps @AB_CD@ %locale/@AB_CD@/mozapps/
   locale/@AB_CD@/mozapps/downloads/unknownContentType.properties  (%chrome/mozapps/downloads/unknownContentType.properties)
   locale/@AB_CD@/mozapps/downloads/unknownContentType.dtd         (%chrome/mozapps/downloads/unknownContentType.dtd)
   locale/@AB_CD@/mozapps/downloads/settingsChange.dtd             (%chrome/mozapps/downloads/settingsChange.dtd)
   locale/@AB_CD@/mozapps/downloads/downloads.properties           (%chrome/mozapps/downloads/downloads.properties)
   locale/@AB_CD@/mozapps/extensions/extensions.dtd                (%chrome/mozapps/extensions/extensions.dtd)
 #ifndef MOZ_FENNEC
rename from toolkit/themes/windows/global/arrow/arrow-dn-hov.gif
rename to toolkit/themes/linux/global/arrow/arrow-dn-hov.gif
rename from toolkit/themes/windows/global/arrow/arrow-up-hov.gif
rename to toolkit/themes/linux/global/arrow/arrow-up-hov.gif
--- a/toolkit/themes/linux/global/jar.mn
+++ b/toolkit/themes/linux/global/jar.mn
@@ -30,16 +30,18 @@ toolkit.jar:
    skin/classic/global/scrollbox.css
    skin/classic/global/splitter.css
    skin/classic/global/tabbox.css
    skin/classic/global/textbox.css
    skin/classic/global/toolbar.css
    skin/classic/global/toolbarbutton.css
    skin/classic/global/tree.css
    skin/classic/global/alerts/alert.css                        (alerts/alert.css)
+   skin/classic/global/arrow/arrow-dn-hov.gif                  (arrow/arrow-dn-hov.gif)
+   skin/classic/global/arrow/arrow-up-hov.gif                  (arrow/arrow-up-hov.gif)
 
    skin/classic/global/icons/Authentication.png                (icons/Authentication.png)
    skin/classic/global/icons/autoscroll.png                    (icons/autoscroll.png)
    skin/classic/global/icons/blacklist_favicon.png             (icons/blacklist_favicon.png)
    skin/classic/global/icons/blacklist_large.png               (icons/blacklist_large.png)
    skin/classic/global/icons/Close.gif                         (icons/Close.gif)
    skin/classic/global/icons/close.svg                         (icons/close.svg)
    skin/classic/global/icons/Minimize.gif                      (icons/Minimize.gif)
deleted file mode 100644
--- a/toolkit/themes/osx/global/arrow.css
+++ /dev/null
@@ -1,38 +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/. */
-
-
-@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
-
-.up {
-  min-width: 0px;
-  list-style-image: url("chrome://global/skin/arrow/arrow-up.gif");
-}               
-.up[disabled="true"] {
-  list-style-image: url("chrome://global/skin/arrow/arrow-up-dis.gif");
-}
-
-.down {
-  min-width: 0px;
-  list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif");
-}
-.down[disabled="true"] {
-  list-style-image: url("chrome://global/skin/arrow/arrow-dn-dis.gif");
-}
-
-.left {
-  min-width: 0px;
-  list-style-image: url("chrome://global/skin/arrow/arrow-lft.gif");
-}
-.left[disabled="true"] {
-  list-style-image: url("chrome://global/skin/arrow/arrow-lft-dis.gif");
-}
-
-.right {
-  min-width: 0px;
-  list-style-image: url("chrome://global/skin/arrow/arrow-rit.gif");
-}
-.right[disabled="true"] {
-  list-style-image: url("chrome://global/skin/arrow/arrow-rit-dis.gif");
-}
deleted file mode 100644
index c22294ba21beabd0c819f1219fdc82934f197727..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index c1b3750d4c88a67e45805f9248bb1be96fbcbe5c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/toolkit/themes/osx/global/jar.mn
+++ b/toolkit/themes/osx/global/jar.mn
@@ -2,17 +2,16 @@
 # 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/.
 
 #include ../../shared/jar.inc.mn
 
 toolkit.jar:
   skin/classic/global/10pct_transparent_grey.png
   skin/classic/global/50pct_transparent_grey.png
-  skin/classic/global/arrow.css
   skin/classic/global/autocomplete.css
   skin/classic/global/button.css
   skin/classic/global/checkbox.css
   skin/classic/global/colorpicker.css
   skin/classic/global/commonDialog.css
   skin/classic/global/customizeToolbar.css
   skin/classic/global/dialog.css
   skin/classic/global/dropmarker.css
@@ -48,22 +47,20 @@ toolkit.jar:
   skin/classic/global/alerts/alert.css                               (alerts/alert.css)
   skin/classic/global/arrow/arrow-dn-dis.gif                         (arrow/arrow-dn-dis.gif)
   skin/classic/global/arrow/arrow-dn-dis.png                         (arrow/arrow-dn-dis.png)
   skin/classic/global/arrow/arrow-dn-sharp.gif                       (arrow/arrow-dn-sharp.gif)
   skin/classic/global/arrow/arrow-dn.gif                             (arrow/arrow-dn.gif)
   skin/classic/global/arrow/arrow-dn.png                             (arrow/arrow-dn.png)
   skin/classic/global/arrow/arrow-lft-dis.gif                        (arrow/arrow-lft-dis.gif)
   skin/classic/global/arrow/arrow-lft-hov.gif                        (arrow/arrow-lft-hov.gif)
-  skin/classic/global/arrow/arrow-lft-sharp-end.gif                  (arrow/arrow-lft-sharp-end.gif)
   skin/classic/global/arrow/arrow-lft-sharp.gif                      (arrow/arrow-lft-sharp.gif)
   skin/classic/global/arrow/arrow-lft.gif                            (arrow/arrow-lft.gif)
   skin/classic/global/arrow/arrow-rit-dis.gif                        (arrow/arrow-rit-dis.gif)
   skin/classic/global/arrow/arrow-rit-hov.gif                        (arrow/arrow-rit-hov.gif)
-  skin/classic/global/arrow/arrow-rit-sharp-end.gif                  (arrow/arrow-rit-sharp-end.gif)
   skin/classic/global/arrow/arrow-rit-sharp.gif                      (arrow/arrow-rit-sharp.gif)
   skin/classic/global/arrow/arrow-rit.gif                            (arrow/arrow-rit.gif)
   skin/classic/global/arrow/arrow-up-dis.gif                         (arrow/arrow-up-dis.gif)
   skin/classic/global/arrow/arrow-up-sharp.gif                       (arrow/arrow-up-sharp.gif)
   skin/classic/global/arrow/arrow-up.gif                             (arrow/arrow-up.gif)
   skin/classic/global/arrow/panelarrow-horizontal.png                (arrow/panelarrow-horizontal.png)
   skin/classic/global/arrow/panelarrow-horizontal@2x.png             (arrow/panelarrow-horizontal@2x.png)
   skin/classic/global/arrow/panelarrow-vertical.png                  (arrow/panelarrow-vertical.png)
--- a/toolkit/themes/shared/non-mac.jar.inc.mn
+++ b/toolkit/themes/shared/non-mac.jar.inc.mn
@@ -5,50 +5,38 @@
 # This is not a complete / proper jar manifest. It is conditionally included
 # by the shared jar manifest, which in turn is included by the os-specific
 # manifests.
 # As a result, the source file paths are relative to the location of the
 # actual manifests.
 
 #include jar.inc.mn
 
-  skin/classic/global/arrow.css                            (../../windows/global/arrow.css)
   skin/classic/global/customizeToolbar.css                 (../../windows/global/customizeToolbar.css)
   skin/classic/global/datetimepicker.css                   (../../windows/global/datetimepicker.css)
   skin/classic/global/dialog.css                           (../../windows/global/dialog.css)
   skin/classic/global/expander.css                         (../../windows/global/expander.css)
   skin/classic/global/filefield.css                        (../../windows/global/filefield.css)
   skin/classic/global/globalBindings.xml                   (../../windows/global/globalBindings.xml)
   skin/classic/global/progressmeter.css                    (../../windows/global/progressmeter.css)
   skin/classic/global/resizer.css                          (../../windows/global/resizer.css)
   skin/classic/global/richlistbox.css                      (../../windows/global/richlistbox.css)
   skin/classic/global/scrollbars.css                       (../../windows/global/xulscrollbars.css)
   skin/classic/global/spinbuttons.css                      (../../windows/global/spinbuttons.css)
   skin/classic/global/tabprompts.css                       (../../windows/global/tabprompts.css)
   skin/classic/global/wizard.css                           (../../windows/global/wizard.css)
 
   skin/classic/global/arrow/arrow-dn.gif                   (../../windows/global/arrow/arrow-dn.gif)
   skin/classic/global/arrow/arrow-dn-dis.gif               (../../windows/global/arrow/arrow-dn-dis.gif)
-  skin/classic/global/arrow/arrow-dn-hov.gif               (../../windows/global/arrow/arrow-dn-hov.gif)
-  skin/classic/global/arrow/arrow-dn-sharp.gif             (../../windows/global/arrow/arrow-dn-sharp.gif)
-  skin/classic/global/arrow/arrow-down.png                 (../../windows/global/arrow/arrow-down.png)
   skin/classic/global/arrow/arrow-lft.gif                  (../../windows/global/arrow/arrow-lft.gif)
   skin/classic/global/arrow/arrow-lft-dis.gif              (../../windows/global/arrow/arrow-lft-dis.gif)
-  skin/classic/global/arrow/arrow-lft-sharp.gif            (../../windows/global/arrow/arrow-lft-sharp.gif)
-  skin/classic/global/arrow/arrow-lft-sharp-end.gif        (../../windows/global/arrow/arrow-lft-sharp-end.gif)
   skin/classic/global/arrow/arrow-rit.gif                  (../../windows/global/arrow/arrow-rit.gif)
   skin/classic/global/arrow/arrow-rit-dis.gif              (../../windows/global/arrow/arrow-rit-dis.gif)
-  skin/classic/global/arrow/arrow-rit-sharp.gif            (../../windows/global/arrow/arrow-rit-sharp.gif)
-  skin/classic/global/arrow/arrow-rit-sharp-end.gif        (../../windows/global/arrow/arrow-rit-sharp-end.gif)
   skin/classic/global/arrow/arrow-up.gif                   (../../windows/global/arrow/arrow-up.gif)
   skin/classic/global/arrow/arrow-up-dis.gif               (../../windows/global/arrow/arrow-up-dis.gif)
-  skin/classic/global/arrow/arrow-up-hov.gif               (../../windows/global/arrow/arrow-up-hov.gif)
-  skin/classic/global/arrow/arrow-up-sharp.gif             (../../windows/global/arrow/arrow-up-sharp.gif)
-  skin/classic/global/arrow/panelarrow-horizontal.svg      (../../windows/global/arrow/panelarrow-horizontal.svg)
-  skin/classic/global/arrow/panelarrow-vertical.svg        (../../windows/global/arrow/panelarrow-vertical.svg)
   skin/classic/global/arrow/panelarrow-horizontal-themed.svg (../../windows/global/arrow/panelarrow-horizontal-themed.svg)
   skin/classic/global/arrow/panelarrow-vertical-themed.svg   (../../windows/global/arrow/panelarrow-vertical-themed.svg)
 
 * skin/classic/global/dirListing/dirListing.css            (../../windows/global/dirListing/dirListing.css)
   skin/classic/global/icons/autocomplete-search.svg        (../../windows/global/icons/autocomplete-search.svg)
   skin/classic/global/icons/error-16.png                   (../../windows/global/icons/error-16.png)
   skin/classic/global/icons/question-16.png                (../../windows/global/icons/question-16.png)
   skin/classic/global/icons/question-64.png                (../../windows/global/icons/question-64.png)
deleted file mode 100644
--- a/toolkit/themes/windows/global/arrow.css
+++ /dev/null
@@ -1,50 +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/. */
-
-
-@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
-
-.up {
-  min-width: 0px;
-  list-style-image: url("chrome://global/skin/arrow/arrow-up.gif");
-}               
-.up:hover {
-  list-style-image: url("chrome://global/skin/arrow/arrow-up-hov.gif");
-}
-.up[disabled="true"] {
-  list-style-image: url("chrome://global/skin/arrow/arrow-up-dis.gif");
-}
-
-.down {
-  min-width: 0px;
-  list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif");
-}
-.down:hover {
-  list-style-image: url("chrome://global/skin/arrow/arrow-dn-hov.gif");
-}
-.down[disabled="true"] {
-  list-style-image: url("chrome://global/skin/arrow/arrow-dn-dis.gif");
-}
-
-.left {
-  min-width: 0px;
-  list-style-image: url("chrome://global/skin/arrow/arrow-lft.gif");
-}
-.left:hover {
-  list-style-image: url("chrome://global/skin/arrow/arrow-lft-hov.gif");
-}
-.left[disabled="true"] {
-  list-style-image: url("chrome://global/skin/arrow/arrow-lft-dis.gif");
-}
-
-.right {
-  min-width: 0px;
-  list-style-image: url("chrome://global/skin/arrow/arrow-rit.gif");
-}
-.right:hover {
-  list-style-image: url("chrome://global/skin/arrow/arrow-rit-hov.gif");
-}
-.right[disabled="true"] {
-  list-style-image: url("chrome://global/skin/arrow/arrow-rit-dis.gif");
-}
deleted file mode 100644
index 57254bb88d9dccc822c81acbb0985ad374dd487b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 8290b712c23f5eee754899a722f3281e4a1fa6d6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index f324779b2d8d71f3ce7b006766018a7d8810e3e2..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index f276538aa1a7c0beb901e9341532c576c3921e73..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 903451b17e687b2da2673a1bf08c87dec35757dd..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index cf36086261901e10fb95fe4d281fa2499dce3bc3..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 9f4e7a9d02de1d5f81500b48af1035e5c3b0a025..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/toolkit/themes/windows/global/jar.mn
+++ b/toolkit/themes/windows/global/jar.mn
@@ -28,16 +28,18 @@ toolkit.jar:
   skin/classic/global/printPageSetup.css
   skin/classic/global/printPreview.css
   skin/classic/global/scrollbox.css
   skin/classic/global/splitter.css
   skin/classic/global/toolbar.css
   skin/classic/global/toolbarbutton.css
 * skin/classic/global/tree.css
   skin/classic/global/alerts/alert.css                     (alerts/alert.css)
+  skin/classic/global/arrow/panelarrow-horizontal.svg      (arrow/panelarrow-horizontal.svg)
+  skin/classic/global/arrow/panelarrow-vertical.svg        (arrow/panelarrow-vertical.svg)
   skin/classic/global/dirListing/folder.png                (dirListing/folder.png)
   skin/classic/global/dirListing/up.png                    (dirListing/up.png)
   skin/classic/global/icons/blacklist_favicon.png          (icons/blacklist_favicon.png)
   skin/classic/global/icons/blacklist_large.png            (icons/blacklist_large.png)
   skin/classic/global/icons/close.png                      (icons/close.png)
   skin/classic/global/icons/close@2x.png                   (icons/close@2x.png)
   skin/classic/global/icons/Error.png                      (icons/Error.png)
   skin/classic/global/icons/close-win7.png                 (icons/close-win7.png)
--- a/xpcom/components/ManifestParser.cpp
+++ b/xpcom/components/ManifestParser.cpp
@@ -314,16 +314,29 @@ CheckStringFlag(const nsSubstring& aFlag
     } else {
       aResult = comparison ? eBad : eOK;
     }
   }
 
   return true;
 }
 
+static bool
+CheckOsFlag(const nsSubstring& aFlag, const nsSubstring& aData,
+            const nsSubstring& aValue, TriState& aResult)
+{
+  bool result = CheckStringFlag(aFlag, aData, aValue, aResult);
+#if defined(XP_UNIX) && !defined(XP_DARWIN) && !defined(ANDROID)
+  if (result && aResult == eBad) {
+    result = CheckStringFlag(aFlag, aData, NS_LITERAL_STRING("likeunix"), aResult);
+  }
+#endif
+  return result;
+}
+
 /**
  * Check for a modifier flag of the following form:
  *   "flag=version"
  *   "flag<=version"
  *   "flag<version"
  *   "flag>=version"
  *   "flag>version"
  * @param aFlag The flag to compare.
@@ -660,17 +673,17 @@ ParseManifest(NSLocationType aType, File
     int flags = 0;
 
     while ((token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
            ok) {
       ToLowerCase(token);
       NS_ConvertASCIItoUTF16 wtoken(token);
 
       if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
-          CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
+          CheckOsFlag(kOs, wtoken, osTarget, stOs) ||
           CheckStringFlag(kABI, wtoken, abi, stABI) ||
           CheckStringFlag(kProcess, wtoken, process, stProcess) ||
           CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) ||
           CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion) ||
           CheckVersionFlag(kGeckoVersion, wtoken, geckoVersion, stGeckoVersion)) {
         continue;
       }