merge from firefox57
authorWolfgang Rosenauer <wr@rosenauer.org>
Wed, 10 Jan 2018 22:27:13 +0100
changeset 1018 0e45f8ad501c
parent 1008 77c890186192 (current diff)
parent 1017 8ccb9c3cbe47 (diff)
child 1019 b0c883afdffa
merge from firefox57
MozillaFirefox/MozillaFirefox.spec
MozillaFirefox/create-tar.sh
--- a/MozillaFirefox/MozillaFirefox.changes	Sat Nov 11 10:08:36 2017 +0100
+++ b/MozillaFirefox/MozillaFirefox.changes	Wed Jan 10 22:27:13 2018 +0100
@@ -1,15 +1,123 @@
 -------------------------------------------------------------------
-Thu Nov  9 15:01:30 UTC 2017 - wr@rosenauer.org
-
-- update to Firefox 57.0b14
+Tue Jan  9 18:48:02 UTC 2018 - wr@rosenauer.org
+
+- fixed build with latest rust (mozilla-rust-1.23.patch)
+
+-------------------------------------------------------------------
+Thu Jan  4 12:23:41 UTC 2018 - wr@rosenauer.org
+
+- update to Firefox 57.0.4
+  MFSA 2018-1: Speculative execution side-channel attack ("Spectre")
+  (boo#1074723)
+
+-------------------------------------------------------------------
+Wed Jan  3 08:29:38 UTC 2018 - wr@rosenauer.org
+
+- fixed regression introduced Oct 10th which made Firefox crash
+  when cancelling the KDE file dialog (boo#1069962)
+
+-------------------------------------------------------------------
+Fri Dec 29 19:52:34 UTC 2017 - astieger@suse.com
+
+- Mozilla Firefox 57.0.3:
+  * Fix a crash reporting issue that inadvertently sends background
+    tab crash reports to Mozilla without user opt-in (bmo#1427111,
+    bsc#1074235)
+- Includes changes from 57.0.2:
+  * fixes for platforms other than GNU/Linux
+
+-------------------------------------------------------------------
+Fri Dec  8 15:52:17 UTC 2017 - dimstar@opensuse.org
+
+- Explicitly buildrequires python2-xml: The build system relies on
+  it. We wrongly relied on other packages pulling it in for us.
+
+-------------------------------------------------------------------
+Thu Dec  7 11:12:31 UTC 2017 - dimstar@opensuse.org
+
+- Escape the usage of %{VERSION} when calling out to rpm.
+  RPM 4.14 has %{VERSION} defined as 'the main packages version'.
+
+-------------------------------------------------------------------
+Wed Nov 29 23:45:03 UTC 2017 - wr@rosenauer.org
+
+- update to Firefox 57.0.1
+  * CVE-2017-7843: Web worker in Private Browsing mode can write
+    IndexedDB data (bsc#1072034, bmo#1410106)
+  * CVE-2017-7844: Visited history information leak through SVG
+    image (bsc#1072036, bmo#1420001)
+  * Fix a video color distortion issue on YouTube and other video
+    sites with some AMD devices (bmo#1417442)
+  * Fix an issue with prefs.js when the profile path has non-ascii
+    characters (bmo#1420427)
+
+-------------------------------------------------------------------
+Tue Nov 21 09:00:48 UTC 2017 - christophe@krop.fr
+
+- Add mozilla-bmo1360278.patch
+  Starting with Firefox 57, the context menu appears on key press.
+  This patch creates a config entry to restore the
+  old behaviour. Without the patch, the mouse gesture extensions
+  require 2 clicks to work (bmo#1360278).
+  The new config entry is named ui.context_menus.after_mouseup
+  (default : false).
+
+-------------------------------------------------------------------
+Sat Nov 18 08:35:21 UTC 2017 - wr@rosenauer.org
+
+- Allow experimental CSD for Gtk3 (bmo#1399611) if available and enabled
+  widget.allow-client-side-decoration=true
+  (mozilla-bmo1399611-csd.patch)
+
+-------------------------------------------------------------------
+Wed Nov 15 06:46:06 UTC 2017 - wr@rosenauer.org
+
+- update to Firefox 57.0 (boo#1068101)
   * Firefox Quantum
   * Photon UI
+  * Unified address and search bar
   * AMD VP9 hardware video decoder support
   * Added support for Date/Time input
   * stricter security sandbox blocking filesystem reading and
     writing on Linux systems
   * middle mouse paste in the content area no longer navigates to
     URLs by default on Unix systems
+  MFSA 2017-24
+  * CVE-2017-7828 (bmo#1406750. bmo#1412252)
+    Use-after-free of PressShell while restyling layout
+  * CVE-2017-7830 (bmo#1408990)
+    Cross-origin URL information leak through Resource Timing API
+  * CVE-2017-7831 (bmo#1392026)
+    Information disclosure of exposed properties on JavaScript proxy
+    objects
+  * CVE-2017-7832 (bmo#1408782)
+    Domain spoofing through use of dotless 'i' character followed
+    by accent markers
+  * CVE-2017-7833 (bmo#1370497)
+    Domain spoofing with Arabic and Indic vowel marker characters
+  * CVE-2017-7834 (bmo#1358009)
+    data: URLs opened in new tabs bypass CSP protections
+  * CVE-2017-7835 (bmo#1402363)
+    Mixed content blocking incorrectly applies with redirects
+  * CVE-2017-7836 (bmo#1401339)
+    Pingsender dynamically loads libcurl on Linux and OS X
+  * CVE-2017-7837 (bmo#1325923)
+    SVG loaded as <img> can use meta tags to set cookies
+  * CVE-2017-7838 (bmo#1399540)
+    Failure of individual decoding of labels in international domain
+    names triggers punycode display of entire IDN
+  * CVE-2017-7839 (bmo#1402896)
+    Control characters before javascript: URLs defeats self-XSS
+    prevention mechanism
+  * CVE-2017-7840 (bmo#1366420)
+    Exported bookmarks do not strip script elements from user-supplied
+    tags
+  * CVE-2017-7842 (bmo#1397064)
+    Referrer Policy is not always respected for <link> elements
+  * CVE-2017-7827
+    Memory safety bugs fixed in Firefox 57
+  * CVE-2017-7826
+    Memory safety bugs fixed in Firefox 57 and Firefox ESR 52.5
 - requires NSPR 4.17, NSS 3.33 and rustc 1.19
 - rebased patches
 - added mozilla-bindgen-systemlibs.patch to allow stylo build
--- a/MozillaFirefox/MozillaFirefox.spec	Sat Nov 11 10:08:36 2017 +0100
+++ b/MozillaFirefox/MozillaFirefox.spec	Wed Jan 10 22:27:13 2018 +0100
@@ -1,8 +1,8 @@
 #
 # spec file for package MozillaFirefox
 #
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
-#               2006-2017 Wolfgang Rosenauer
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+#               2006-2018 Wolfgang Rosenauer
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,11 +18,11 @@
 
 
 # changed with every update
-%define major 56
+%define major 57
 %define mainver %major.99
 %define update_channel beta
 %define branding 1
-%define releasedate 20171102181127
+%define releasedate 20180108140638
 
 # PIE, full relro (x86_64 for now)
 %define build_hardened 1
@@ -75,6 +75,7 @@
 BuildRequires:  mozilla-nspr-devel >= 4.17
 BuildRequires:  mozilla-nss-devel >= 3.33
 BuildRequires:  python-devel
+BuildRequires:  python2-xml
 BuildRequires:  rust >= 1.19
 BuildRequires:  rust-std
 BuildRequires:  startup-notification-devel
@@ -153,6 +154,9 @@
 Patch6:         mozilla-reduce-files-per-UnifiedBindings.patch
 Patch7:         mozilla-aarch64-startup-crash.patch
 Patch8:         mozilla-bindgen-systemlibs.patch
+Patch9:         mozilla-bmo1360278.patch
+Patch10:        mozilla-bmo1399611-csd.patch
+Patch11:        mozilla-rust-1.23.patch
 # Firefox/browser
 Patch101:       firefox-kde.patch
 Patch102:       firefox-no-default-ualocale.patch
@@ -164,8 +168,8 @@
 %if %branding
 Requires:       %{name}-branding > 44.0
 %endif
-Requires:       mozilla-nspr >= %(rpm -q --queryformat '%{VERSION}' mozilla-nspr)
-Requires:       mozilla-nss >= %(rpm -q --queryformat '%{VERSION}' mozilla-nss)
+Requires:       mozilla-nspr >= %(rpm -q --queryformat '%%{VERSION}' mozilla-nspr)
+Requires:       mozilla-nss >= %(rpm -q --queryformat '%%{VERSION}' mozilla-nss)
 Recommends:     libcanberra0
 Recommends:     libpulse0
 # addon leads to startup crash (bnc#908892)
@@ -264,6 +268,9 @@
 %endif
 %patch7 -p1
 %patch8 -p1
+%patch9 -p1
+%patch10 -p1
+%patch11 -p1
 # Firefox
 %patch101 -p1
 %patch102 -p1
--- a/MozillaFirefox/create-tar.sh	Sat Nov 11 10:08:36 2017 +0100
+++ b/MozillaFirefox/create-tar.sh	Wed Jan 10 22:27:13 2018 +0100
@@ -7,8 +7,8 @@
 
 CHANNEL="beta"
 BRANCH="releases/mozilla-$CHANNEL"
-RELEASE_TAG="FIREFOX_57_0b14_RELEASE"
-VERSION="56.99"
+RELEASE_TAG="FIREFOX_58_0b15_RELEASE"
+VERSION="57.99
 
 # mozilla
 if [ -d mozilla ]; then
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MozillaFirefox/mozilla-bmo1360278.patch	Wed Jan 10 22:27:13 2018 +0100
@@ -0,0 +1,1 @@
+../mozilla-bmo1360278.patch
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MozillaFirefox/mozilla-bmo1399611-csd.patch	Wed Jan 10 22:27:13 2018 +0100
@@ -0,0 +1,1 @@
+../mozilla-bmo1399611-csd.patch
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MozillaFirefox/mozilla-rust-1.23.patch	Wed Jan 10 22:27:13 2018 +0100
@@ -0,0 +1,1 @@
+../mozilla-rust-1.23.patch
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mozilla-bmo1360278.patch	Wed Jan 10 22:27:13 2018 +0100
@@ -0,0 +1,260 @@
+
+# HG changeset patch
+# User Robin Grenet <robin.grenet@wanadoo.fr>
+# Date 1510835758 -3600
+# Node ID f540f9e801cb2e0be5259baea13dfce953ccb520
+# Parent  0abbf75bd0ecfa99ab4386f551a622983f5f27ea
+Bug 1360278 - Add preference to trigger context menu on mouse up for GTK+ and macOS, r=mstange,smaug
+
+MozReview-Commit-ID: Bg60bD8jIg6
+
+diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
+--- a/modules/libpref/init/all.js
++++ b/modules/libpref/init/all.js
+@@ -229,16 +229,20 @@ pref("dom.script_loader.bytecode_cache.e
+ pref("dom.script_loader.bytecode_cache.strategy", 0);
+ 
+ // Fastback caching - if this pref is negative, then we calculate the number
+ // of content viewers to cache based on the amount of available memory.
+ pref("browser.sessionhistory.max_total_viewers", -1);
+ 
+ pref("ui.use_native_colors", true);
+ pref("ui.click_hold_context_menus", false);
++
++// Pop up context menu on mouseup instead of mousedown, if that's the OS default.
++// Note: ignored on Windows (context menus always use mouseup)
++pref("ui.context_menus.after_mouseup", false);
+ // Duration of timeout of incremental search in menus (ms).  0 means infinite.
+ pref("ui.menu.incremental_search.timeout", 1000);
+ // If true, all popups won't hide automatically on blur
+ pref("ui.popup.disable_autohide", false);
+ 
+ pref("browser.display.use_document_fonts",  1);  // 0 = never, 1 = quick, 2 = always
+ // 0 = default: always, except in high contrast mode
+ // 1 = always
+diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm
+--- a/widget/cocoa/nsChildView.mm
++++ b/widget/cocoa/nsChildView.mm
+@@ -4695,18 +4695,20 @@ NSEvent* gLastDragMouseDownEvent = nil;
+   [self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
+   geckoEvent.button = WidgetMouseEvent::eRightButton;
+   geckoEvent.mClickCount = [theEvent clickCount];
+ 
+   mGeckoChild->DispatchInputEvent(&geckoEvent);
+   if (!mGeckoChild)
+     return;
+ 
+-  // Let the superclass do the context menu stuff.
+-  [super rightMouseDown:theEvent];
++  if (!nsBaseWidget::ShowContextMenuAfterMouseUp()) {
++    // Let the superclass do the context menu stuff.
++    [super rightMouseDown:theEvent];
++  }
+ 
+   NS_OBJC_END_TRY_ABORT_BLOCK;
+ }
+ 
+ - (void)rightMouseUp:(NSEvent *)theEvent
+ {
+   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+ 
+@@ -4719,16 +4721,33 @@ NSEvent* gLastDragMouseDownEvent = nil;
+   WidgetMouseEvent geckoEvent(true, eMouseUp, mGeckoChild,
+                               WidgetMouseEvent::eReal);
+   [self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
+   geckoEvent.button = WidgetMouseEvent::eRightButton;
+   geckoEvent.mClickCount = [theEvent clickCount];
+ 
+   nsAutoRetainCocoaObject kungFuDeathGrip(self);
+   mGeckoChild->DispatchInputEvent(&geckoEvent);
++  if (!mGeckoChild)
++    return;
++
++  if (nsBaseWidget::ShowContextMenuAfterMouseUp()) {
++    // Let the superclass do the context menu stuff, but pretend it's rightMouseDown.
++    NSEvent *dupeEvent = [NSEvent mouseEventWithType:NSRightMouseDown
++                                            location:theEvent.locationInWindow
++                                       modifierFlags:theEvent.modifierFlags
++                                           timestamp:theEvent.timestamp
++                                        windowNumber:theEvent.windowNumber
++                                             context:theEvent.context
++                                         eventNumber:theEvent.eventNumber
++                                          clickCount:theEvent.clickCount
++                                            pressure:theEvent.pressure];
++
++    [super rightMouseDown:dupeEvent];
++  }
+ 
+   NS_OBJC_END_TRY_ABORT_BLOCK;
+ }
+ 
+ - (void)rightMouseDragged:(NSEvent*)theEvent
+ {
+   if (!mGeckoChild)
+     return;
+diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp
+--- a/widget/gtk/nsWindow.cpp
++++ b/widget/gtk/nsWindow.cpp
+@@ -2733,16 +2733,29 @@ nsWindow::InitButtonEvent(WidgetMouseEve
+ }
+ 
+ static guint ButtonMaskFromGDKButton(guint button)
+ {
+     return GDK_BUTTON1_MASK << (button - 1);
+ }
+ 
+ void
++nsWindow::DispatchContextMenuEventFromMouseEvent(uint16_t domButton,
++                                                 GdkEventButton *aEvent)
++{
++    if (domButton == WidgetMouseEvent::eRightButton && MOZ_LIKELY(!mIsDestroyed)) {
++        WidgetMouseEvent contextMenuEvent(true, eContextMenu, this,
++                                          WidgetMouseEvent::eReal);
++        InitButtonEvent(contextMenuEvent, aEvent);
++        contextMenuEvent.pressure = mLastMotionPressure;
++        DispatchInputEvent(&contextMenuEvent);
++    }
++}
++
++void
+ nsWindow::OnButtonPressEvent(GdkEventButton *aEvent)
+ {
+     LOG(("Button %u press on %p\n", aEvent->button, (void *)this));
+ 
+     // If you double click in GDK, it will actually generate a second
+     // GDK_BUTTON_PRESS before sending the GDK_2BUTTON_PRESS, and this is
+     // different than the DOM spec.  GDK puts this in the queue
+     // programatically, so it's safe to assume that if there's a
+@@ -2801,23 +2814,18 @@ nsWindow::OnButtonPressEvent(GdkEventBut
+     WidgetMouseEvent event(true, eMouseDown, this, WidgetMouseEvent::eReal);
+     event.button = domButton;
+     InitButtonEvent(event, aEvent);
+     event.pressure = mLastMotionPressure;
+ 
+     DispatchInputEvent(&event);
+ 
+     // right menu click on linux should also pop up a context menu
+-    if (domButton == WidgetMouseEvent::eRightButton &&
+-        MOZ_LIKELY(!mIsDestroyed)) {
+-        WidgetMouseEvent contextMenuEvent(true, eContextMenu, this,
+-                                          WidgetMouseEvent::eReal);
+-        InitButtonEvent(contextMenuEvent, aEvent);
+-        contextMenuEvent.pressure = mLastMotionPressure;
+-        DispatchInputEvent(&contextMenuEvent);
++    if (!nsBaseWidget::ShowContextMenuAfterMouseUp()) {
++        DispatchContextMenuEventFromMouseEvent(domButton, aEvent);
+     }
+ }
+ 
+ void
+ nsWindow::OnButtonReleaseEvent(GdkEventButton *aEvent)
+ {
+     LOG(("Button %u release on %p\n", aEvent->button, (void *)this));
+ 
+@@ -2843,16 +2851,21 @@ nsWindow::OnButtonReleaseEvent(GdkEventB
+     event.button = domButton;
+     InitButtonEvent(event, aEvent);
+     gdouble pressure = 0;
+     gdk_event_get_axis ((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
+     event.pressure = pressure ? pressure : mLastMotionPressure;
+ 
+     DispatchInputEvent(&event);
+     mLastMotionPressure = pressure;
++
++    // right menu click on linux should also pop up a context menu
++    if (nsBaseWidget::ShowContextMenuAfterMouseUp()) {
++        DispatchContextMenuEventFromMouseEvent(domButton, aEvent);
++    }
+ }
+ 
+ void
+ nsWindow::OnContainerFocusInEvent(GdkEventFocus *aEvent)
+ {
+     LOGFOCUS(("OnContainerFocusInEvent [%p]\n", (void *)this));
+ 
+     // Unset the urgency hint, if possible
+diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h
+--- a/widget/gtk/nsWindow.h
++++ b/widget/gtk/nsWindow.h
+@@ -240,16 +240,18 @@ private:
+     LayoutDeviceIntSize GetSafeWindowSize(LayoutDeviceIntSize aSize);
+ 
+     void               EnsureGrabs  (void);
+     void               GrabPointer  (guint32 aTime);
+     void               ReleaseGrabs (void);
+ 
+     void               UpdateClientOffset();
+ 
++    void               DispatchContextMenuEventFromMouseEvent(uint16_t domButton,
++                                                              GdkEventButton *aEvent);
+ public:
+     void               ThemeChanged(void);
+     void               OnDPIChanged(void);
+     void               OnCheckResize(void);
+     void               OnCompositedChanged(void);
+ 
+ #ifdef MOZ_X11
+     Window             mOldFocusWindow;
+diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp
+--- a/widget/nsBaseWidget.cpp
++++ b/widget/nsBaseWidget.cpp
+@@ -1213,16 +1213,32 @@ nsBaseWidget::DispatchEventToAPZOnly(moz
+   if (mAPZC) {
+     MOZ_ASSERT(APZThreadUtils::IsControllerThread());
+     uint64_t inputBlockId = 0;
+     ScrollableLayerGuid guid;
+     mAPZC->ReceiveInputEvent(*aEvent, &guid, &inputBlockId);
+   }
+ }
+ 
++// static
++bool
++nsBaseWidget::ShowContextMenuAfterMouseUp()
++{
++  static bool gContextMenuAfterMouseUp = false;
++  static bool gContextMenuAfterMouseUpCached = false;
++  if (!gContextMenuAfterMouseUpCached) {
++    Preferences::AddBoolVarCache(&gContextMenuAfterMouseUp,
++                                 "ui.context_menus.after_mouseup",
++                                 false);
++
++    gContextMenuAfterMouseUpCached = true;
++  }
++  return gContextMenuAfterMouseUp;
++}
++
+ nsIDocument*
+ nsBaseWidget::GetDocument() const
+ {
+   if (mWidgetListener) {
+     if (nsIPresShell* presShell = mWidgetListener->GetPresShell()) {
+       return presShell->GetDocument();
+     }
+   }
+diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h
+--- a/widget/nsBaseWidget.h
++++ b/widget/nsBaseWidget.h
+@@ -412,16 +412,22 @@ public:
+   void NotifyLiveResizeStopped();
+ 
+ #if defined(MOZ_WIDGET_ANDROID)
+   void RecvToolbarAnimatorMessageFromCompositor(int32_t) override {};
+   void UpdateRootFrameMetrics(const ScreenPoint& aScrollOffset, const CSSToScreenScale& aZoom) override {};
+   void RecvScreenPixels(mozilla::ipc::Shmem&& aMem, const ScreenIntSize& aSize) override {};
+ #endif
+ 
++  /**
++   * Whether context menus should only appear on mouseup instead of mousedown,
++   * on OSes where they normally appear on mousedown (macOS, *nix).
++   */
++  static bool ShowContextMenuAfterMouseUp();
++
+ protected:
+   // These are methods for CompositorWidgetWrapper, and should only be
+   // accessed from that class. Derived widgets can choose which methods to
+   // implement, or none if supporting out-of-process compositing.
+   virtual bool PreRender(mozilla::widget::WidgetRenderingContext* aContext) {
+     return true;
+   }
+   virtual void PostRender(mozilla::widget::WidgetRenderingContext* aContext)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mozilla-bmo1399611-csd.patch	Wed Jan 10 22:27:13 2018 +0100
@@ -0,0 +1,1744 @@
+diff -up firefox-57.0b8/browser/app/profile/firefox.js.1399611 firefox-57.0b8/browser/app/profile/firefox.js
+--- firefox-57.0b8/browser/app/profile/firefox.js.1399611	2017-10-16 12:11:45.364240654 +0200
++++ firefox-57.0b8/browser/app/profile/firefox.js	2017-10-16 12:28:03.860720910 +0200
+@@ -457,11 +457,7 @@ pref("browser.tabs.loadBookmarksInBackgr
+ pref("browser.tabs.loadBookmarksInTabs", false);
+ pref("browser.tabs.tabClipWidth", 140);
+ pref("browser.tabs.tabMinWidth", 76);
+-#ifdef UNIX_BUT_NOT_MAC
+-pref("browser.tabs.drawInTitlebar", false);
+-#else
+ pref("browser.tabs.drawInTitlebar", true);
+-#endif
+ 
+ // Offer additional drag space to the user. The drag space
+ // will only be shown if browser.tabs.drawInTitlebar is true.
+diff -up firefox-57.0b8/browser/base/content/browser-tabsintitlebar.js.1399611 firefox-57.0b8/browser/base/content/browser-tabsintitlebar.js
+--- firefox-57.0b8/browser/base/content/browser-tabsintitlebar.js.1399611	2017-10-09 22:17:13.000000000 +0200
++++ firefox-57.0b8/browser/base/content/browser-tabsintitlebar.js	2017-10-16 12:11:45.364240654 +0200
+@@ -14,6 +14,11 @@ var TabsInTitlebar = {
+     this._readPref();
+     Services.prefs.addObserver(this._prefName, this);
+ 
++    // Always disable on unsupported GTK versions.
++    if (AppConstants.MOZ_WIDGET_TOOLKIT == "gtk3") {
++      this.allowedBy("gtk", window.matchMedia("(-moz-gtk-csd-available)"));
++    }
++
+     // We need to update the appearance of the titlebar when the menu changes
+     // from the active to the inactive state. We can't, however, rely on
+     // DOMMenuBarInactive, because the menu fires this event and then removes
+diff -up firefox-57.0b8/browser/base/moz.build.1399611 firefox-57.0b8/browser/base/moz.build
+--- firefox-57.0b8/browser/base/moz.build.1399611	2017-09-29 18:16:45.000000000 +0200
++++ firefox-57.0b8/browser/base/moz.build	2017-10-16 12:11:45.364240654 +0200
+@@ -57,7 +57,7 @@ DEFINES['APP_LICENSE_BLOCK'] = '%s/conte
+ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3', 'cocoa'):
+     DEFINES['CONTEXT_COPY_IMAGE_CONTENTS'] = 1
+ 
+-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
++if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa', 'gtk3'):
+     DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
+ 
+ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'):
+diff -up firefox-57.0b8/browser/themes/linux/browser.css.1399611 firefox-57.0b8/browser/themes/linux/browser.css
+--- firefox-57.0b8/browser/themes/linux/browser.css.1399611	2017-10-05 06:17:37.000000000 +0200
++++ firefox-57.0b8/browser/themes/linux/browser.css	2017-10-16 12:11:45.365240651 +0200
+@@ -556,7 +556,9 @@ html|span.ac-emphasize-text-url {
+ 
+ #nav-bar,
+ #toolbar-menubar:not([autohide="true"]):not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
+-#TabsToolbar:not(:-moz-lwtheme):-moz-system-metric(menubar-drag) {
++#TabsToolbar:not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
++#main-window[tabsintitlebar] #toolbar-menubar:not([autohide="true"]),
++#main-window[tabsintitlebar] #TabsToolbar {
+   -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag");
+ }
+ 
+@@ -713,3 +715,85 @@ html|span.ac-emphasize-text-url {
+ .restore-tabs-button:hover:active:not([disabled="true"]) {
+   padding: 3px;
+ }
++
++@media not all and (-moz-gtk-csd-available) {
++  #main-window > #titlebar {
++    /* We need to hide the titlebar explicitly on versions of GTK without CSD. */
++    display: none;
++  }
++}
++
++/* Titlebar/CSD */
++@media (-moz-gtk-csd-available) {
++  #main-window[tabsintitlebar][sizemode="normal"] > #titlebar {
++    min-height: calc(var(--tab-min-height) + 12px);
++  }
++
++  #main-window[tabsintitlebar] #titlebar:-moz-lwtheme {
++    visibility: hidden;
++  }
++  #main-window[tabsintitlebar] #titlebar-content:-moz-lwtheme {
++    visibility: visible;
++  }
++
++  #main-window[tabsintitlebar][sizemode="normal"] > #titlebar {
++    -moz-appearance: -moz-window-titlebar;
++  }
++  #main-window[tabsintitlebar][sizemode="maximized"] > #titlebar {
++    -moz-appearance: -moz-window-titlebar-maximized;
++  }
++
++  /* The button box must appear on top of the navigator-toolbox in order for
++   * click and hover mouse events to work properly for the button in the restored
++   * window state. Otherwise, elements in the navigator-toolbox, like the menubar,
++   * can swallow those events.
++   */
++  #titlebar-buttonbox {
++    z-index: 1;
++  }
++
++  /* titlebar command buttons */
++  /* Use full scale icons here as the Gtk+ does. */
++  @media (-moz-gtk-csd-minimize-button) {
++    #titlebar-min {
++      list-style-image: url("moz-icon://stock/window-minimize-symbolic");
++      -moz-appearance: -moz-window-button-minimize;
++    }
++  }
++  @media not all and (-moz-gtk-csd-minimize-button) {
++    #titlebar-min {
++      display: none;
++    }
++  }
++
++  @media (-moz-gtk-csd-maximize-button) {
++    #titlebar-max {
++      list-style-image: url("moz-icon://stock/window-maximize-symbolic");
++      -moz-appearance: -moz-window-button-maximize;
++    }
++    #main-window[sizemode="maximized"] #titlebar-max {
++      list-style-image: url("moz-icon://stock/window-restore-symbolic");
++      -moz-appearance: -moz-window-button-restore;
++    }
++  }
++  @media not all and (-moz-gtk-csd-maximize-button) {
++    #titlebar-max {
++      display: none;
++    }
++    #main-window[sizemode="maximized"] #titlebar-max {
++      display: none;
++    }
++  }
++
++  @media (-moz-gtk-csd-close-button) {
++    #titlebar-close {
++      list-style-image: url("moz-icon://stock/window-close-symbolic");
++      -moz-appearance: -moz-window-button-close;
++    }
++  }
++  @media not all and (-moz-gtk-csd-close-button) {
++    #titlebar-close {
++      display: none;
++    }
++  }
++}
+diff -up firefox-57.0b8/dom/base/nsGkAtomList.h.1399611 firefox-57.0b8/dom/base/nsGkAtomList.h
+--- firefox-57.0b8/dom/base/nsGkAtomList.h.1399611	2017-09-15 06:15:41.000000000 +0200
++++ firefox-57.0b8/dom/base/nsGkAtomList.h	2017-10-16 12:11:45.365240651 +0200
+@@ -2270,6 +2270,10 @@ GK_ATOM(touch_enabled, "touch-enabled")
+ GK_ATOM(menubar_drag, "menubar-drag")
+ GK_ATOM(swipe_animation_enabled, "swipe-animation-enabled")
+ GK_ATOM(physical_home_button, "physical-home-button")
++GK_ATOM(gtk_csd_available, "gtk-csd-available")
++GK_ATOM(gtk_csd_minimize_button, "gtk-csd-minimize-button")
++GK_ATOM(gtk_csd_maximize_button, "gtk-csd-maximize-button")
++GK_ATOM(gtk_csd_close_button, "gtk-csd-close-button")
+ 
+ // windows theme selector metrics
+ GK_ATOM(windows_classic, "windows-classic")
+@@ -2306,6 +2310,10 @@ GK_ATOM(_moz_device_orientation, "-moz-d
+ GK_ATOM(_moz_is_resource_document, "-moz-is-resource-document")
+ GK_ATOM(_moz_swipe_animation_enabled, "-moz-swipe-animation-enabled")
+ GK_ATOM(_moz_physical_home_button, "-moz-physical-home-button")
++GK_ATOM(_moz_gtk_csd_available, "-moz-gtk-csd-available")
++GK_ATOM(_moz_gtk_csd_minimize_button, "-moz-gtk-csd-minimize-button")
++GK_ATOM(_moz_gtk_csd_maximize_button, "-moz-gtk-csd-maximize-button")
++GK_ATOM(_moz_gtk_csd_close_button, "-moz-gtk-csd-close-button")
+ 
+ // application commands
+ GK_ATOM(Back, "Back")
+diff -up firefox-57.0b8/gfx/src/nsThemeConstants.h.1399611 firefox-57.0b8/gfx/src/nsThemeConstants.h
+--- firefox-57.0b8/gfx/src/nsThemeConstants.h.1399611	2017-06-12 18:37:10.000000000 +0200
++++ firefox-57.0b8/gfx/src/nsThemeConstants.h	2017-10-16 12:11:45.365240651 +0200
+@@ -299,6 +299,7 @@ enum ThemeWidgetType : uint8_t {
+   NS_THEME_MAC_SOURCE_LIST,
+   NS_THEME_MAC_SOURCE_LIST_SELECTION,
+   NS_THEME_MAC_ACTIVE_SOURCE_LIST_SELECTION,
++  NS_THEME_GTK_WINDOW_DECORATION,
+ 
+   ThemeWidgetType_COUNT
+ };
+diff -up firefox-57.0b8/layout/style/nsCSSRuleProcessor.cpp.1399611 firefox-57.0b8/layout/style/nsCSSRuleProcessor.cpp
+--- firefox-57.0b8/layout/style/nsCSSRuleProcessor.cpp.1399611	2017-08-02 14:27:54.000000000 +0200
++++ firefox-57.0b8/layout/style/nsCSSRuleProcessor.cpp	2017-10-16 12:11:45.365240651 +0200
+@@ -1180,6 +1180,30 @@ nsCSSRuleProcessor::InitSystemMetrics()
+     sSystemMetrics->AppendElement(nsGkAtoms::physical_home_button);
+   }
+ 
++  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDAvailable,
++                           &metricResult);
++  if (NS_SUCCEEDED(rv) && metricResult) {
++    sSystemMetrics->AppendElement(nsGkAtoms::gtk_csd_available);
++  }
++
++  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDMinimizeButton,
++                           &metricResult);
++  if (NS_SUCCEEDED(rv) && metricResult) {
++    sSystemMetrics->AppendElement(nsGkAtoms::gtk_csd_minimize_button);
++  }
++
++  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDMaximizeButton,
++                           &metricResult);
++  if (NS_SUCCEEDED(rv) && metricResult) {
++    sSystemMetrics->AppendElement(nsGkAtoms::gtk_csd_maximize_button);
++  }
++
++  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDCloseButton,
++                           &metricResult);
++  if (NS_SUCCEEDED(rv) && metricResult) {
++    sSystemMetrics->AppendElement(nsGkAtoms::gtk_csd_close_button);
++  }
++
+ #ifdef XP_WIN
+   if (NS_SUCCEEDED(
+         LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsThemeIdentifier,
+diff -up firefox-57.0b8/layout/style/nsMediaFeatures.cpp.1399611 firefox-57.0b8/layout/style/nsMediaFeatures.cpp
+--- firefox-57.0b8/layout/style/nsMediaFeatures.cpp.1399611	2017-09-15 06:15:42.000000000 +0200
++++ firefox-57.0b8/layout/style/nsMediaFeatures.cpp	2017-10-16 12:11:45.366240647 +0200
+@@ -788,6 +788,42 @@ nsMediaFeatures::features[] = {
+     GetSystemMetric
+   },
+ 
++  {
++    &nsGkAtoms::_moz_gtk_csd_available,
++    nsMediaFeature::eMinMaxNotAllowed,
++    nsMediaFeature::eBoolInteger,
++    nsMediaFeature::eNoRequirements,
++    { &nsGkAtoms::gtk_csd_available },
++    GetSystemMetric
++  },
++
++  {
++    &nsGkAtoms::_moz_gtk_csd_minimize_button,
++    nsMediaFeature::eMinMaxNotAllowed,
++    nsMediaFeature::eBoolInteger,
++    nsMediaFeature::eNoRequirements,
++    { &nsGkAtoms::gtk_csd_minimize_button },
++    GetSystemMetric
++  },
++
++  {
++    &nsGkAtoms::_moz_gtk_csd_maximize_button,
++    nsMediaFeature::eMinMaxNotAllowed,
++    nsMediaFeature::eBoolInteger,
++    nsMediaFeature::eNoRequirements,
++    { &nsGkAtoms::gtk_csd_maximize_button },
++    GetSystemMetric
++  },
++
++  {
++    &nsGkAtoms::_moz_gtk_csd_close_button,
++    nsMediaFeature::eMinMaxNotAllowed,
++    nsMediaFeature::eBoolInteger,
++    nsMediaFeature::eNoRequirements,
++    { &nsGkAtoms::gtk_csd_close_button },
++    GetSystemMetric
++  },
++
+   // Internal -moz-is-glyph media feature: applies only inside SVG glyphs.
+   // Internal because it is really only useful in the user agent anyway
+   //  and therefore not worth standardizing.
+diff -up firefox-57.0b8/modules/libpref/init/all.js.1399611 firefox-57.0b8/modules/libpref/init/all.js
+--- firefox-57.0b8/modules/libpref/init/all.js.1399611	2017-10-12 18:12:09.000000000 +0200
++++ firefox-57.0b8/modules/libpref/init/all.js	2017-10-16 12:11:45.366240647 +0200
+@@ -4911,6 +4911,7 @@ pref("gfx.apitrace.enabled",false);
+ pref("gfx.xrender.enabled",false);
+ pref("widget.chrome.allow-gtk-dark-theme", false);
+ pref("widget.content.allow-gtk-dark-theme", false);
++pref("widget.allow-client-side-decoration", false);
+ #endif
+ #endif
+ 
+diff -up firefox-57.0b8/toolkit/modules/moz.build.1399611 firefox-57.0b8/toolkit/modules/moz.build
+--- firefox-57.0b8/toolkit/modules/moz.build.1399611	2017-09-15 06:15:40.000000000 +0200
++++ firefox-57.0b8/toolkit/modules/moz.build	2017-10-16 12:11:45.366240647 +0200
+@@ -259,7 +259,7 @@ EXTRA_JS_MODULES.sessionstore += [
+ ]
+ 
+ DEFINES['INSTALL_COMPACT_THEMES'] = 1
+-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
++if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa', 'gtk3'):
+     DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
+ 
+ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'):
+diff -up firefox-57.0b8/widget/gtk/gtk3drawing.cpp.1399611 firefox-57.0b8/widget/gtk/gtk3drawing.cpp
+--- firefox-57.0b8/widget/gtk/gtk3drawing.cpp.1399611	2017-09-15 06:15:40.000000000 +0200
++++ firefox-57.0b8/widget/gtk/gtk3drawing.cpp	2017-10-16 12:11:45.367240644 +0200
+@@ -17,6 +17,7 @@
+ #include "WidgetStyleCache.h"
+ 
+ #include <math.h>
++#include <dlfcn.h>
+ 
+ static gboolean checkbox_check_state;
+ static gboolean notebook_has_tab_gap;
+@@ -39,9 +40,25 @@ static gint
+ moz_gtk_menu_item_paint(WidgetNodeType widget, cairo_t *cr, GdkRectangle* rect,
+                         GtkWidgetState* state, GtkTextDirection direction);
+ 
++static void
++moz_gtk_add_style_margin(GtkStyleContext* style,
++                         gint* left, gint* top, gint* right, gint* bottom);
++static void
++moz_gtk_add_style_border(GtkStyleContext* style,
++                         gint* left, gint* top, gint* right, gint* bottom);
++static void
++moz_gtk_add_style_padding(GtkStyleContext* style,
++                          gint* left, gint* top, gint* right, gint* bottom);
++static void moz_gtk_add_margin_border_padding(GtkStyleContext *style,
++                                              gint* left, gint* top,
++                                              gint* right, gint* bottom);
++static void moz_gtk_add_border_padding(GtkStyleContext *style,
++                                       gint* left, gint* top,
++                                       gint* right, gint* bottom);
+ static GtkBorder
+ GetMarginBorderPadding(GtkStyleContext* aStyle);
+ 
++
+ // GetStateFlagsFromGtkWidgetState() can be safely used for the specific
+ // GtkWidgets that set both prelight and active flags.  For other widgets,
+ // either the GtkStateFlags or Gecko's GtkWidgetState need to be carefully
+@@ -233,6 +250,43 @@ moz_gtk_splitter_get_metrics(gint orient
+     return MOZ_GTK_SUCCESS;
+ }
+ 
++void
++moz_gtk_get_window_border(gint* top, gint* right, gint* bottom, gint* left)
++{
++  MOZ_ASSERT(gtk_check_version(3, 20, 0) == nullptr,
++             "Window decorations are only supported on GTK 3.20+.");
++
++  GtkStyleContext* style = GetStyleContext(MOZ_GTK_WINDOW);
++
++  *top = *right = *bottom = *left = 0;
++  moz_gtk_add_border_padding(style, left, top, right, bottom);
++  GtkBorder windowMargin;
++  gtk_style_context_get_margin(style, GTK_STATE_FLAG_NORMAL, &windowMargin);
++
++  style = GetStyleContext(MOZ_GTK_WINDOW_DECORATION);
++
++  // Available on GTK 3.20+.
++  static auto sGtkRenderBackgroundGetClip =
++    (void (*)(GtkStyleContext*, gdouble, gdouble, gdouble, gdouble, GdkRectangle*))
++    dlsym(RTLD_DEFAULT, "gtk_render_background_get_clip");
++
++  GdkRectangle shadowClip;
++  sGtkRenderBackgroundGetClip(style, 0, 0, 0, 0, &shadowClip);
++
++  // Transfer returned inset rectangle to GtkBorder
++  GtkBorder shadowBorder = {
++      static_cast<gint16>(-shadowClip.x),                    // left
++      static_cast<gint16>(shadowClip.width + shadowClip.x),  // right
++      static_cast<gint16>(-shadowClip.y),                    // top
++      static_cast<gint16>(shadowClip.height + shadowClip.y), // bottom
++  };
++
++  *left += MAX(windowMargin.left, shadowBorder.left);
++  *right += MAX(windowMargin.right, shadowBorder.right);
++  *top += MAX(windowMargin.top, shadowBorder.top);
++  *bottom += MAX(windowMargin.bottom, shadowBorder.bottom);
++}
++
+ static gint
+ moz_gtk_window_paint(cairo_t *cr, GdkRectangle* rect,
+                      GtkTextDirection direction)
+@@ -302,6 +356,24 @@ moz_gtk_button_paint(cairo_t *cr, GdkRec
+ }
+ 
+ static gint
++moz_gtk_header_bar_button_paint(cairo_t *cr, GdkRectangle* rect,
++                                GtkWidgetState* state,
++                                GtkReliefStyle relief, GtkWidget* widget,
++                                GtkTextDirection direction)
++{
++    GtkBorder margin;
++    GtkStyleContext* style = gtk_widget_get_style_context(widget);
++    gtk_style_context_get_margin(style, GTK_STATE_FLAG_NORMAL, &margin);
++
++    rect->x += margin.left;
++    rect->y += margin.top;
++    rect->width -= margin.left + margin.right;
++    rect->height -= margin.top + margin.bottom;
++
++    return moz_gtk_button_paint(cr, rect, state, relief, widget, direction);
++}
++
++static gint
+ moz_gtk_toggle_paint(cairo_t *cr, GdkRectangle* rect,
+                      GtkWidgetState* state,
+                      gboolean selected, gboolean inconsistent,
+@@ -1948,6 +2020,38 @@ moz_gtk_info_bar_paint(cairo_t *cr, GdkR
+     return MOZ_GTK_SUCCESS;
+ }
+ 
++static gint
++moz_gtk_header_bar_paint(WidgetNodeType widgetType,
++                         cairo_t *cr, GdkRectangle* rect, GtkWidgetState* state)
++{
++    GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
++    GtkStyleContext *style;
++
++    style = GetStyleContext(widgetType, GTK_TEXT_DIR_LTR,
++                            state_flags);
++    InsetByMargin(rect, style);
++    gtk_render_background(style, cr, rect->x, rect->y, rect->width,
++                          rect->height);
++    gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
++
++    return MOZ_GTK_SUCCESS;
++}
++
++void
++moz_gtk_header_bar_paint(cairo_t *cr, GdkRectangle* rect)
++{
++    static GtkWidgetState state;
++    moz_gtk_header_bar_paint(MOZ_GTK_HEADER_BAR, cr, rect, &state);
++}
++
++void
++moz_gtk_get_header_bar_border(gint* top, gint* right, gint* bottom, gint* left)
++{
++    *left = *top = *right = *bottom = 0;
++    moz_gtk_add_border_padding(GetStyleContext(MOZ_GTK_HEADER_BAR),
++                               left, top, right, bottom);
++}
++
+ static void
+ moz_gtk_add_style_margin(GtkStyleContext* style,
+                          gint* left, gint* top, gint* right, gint* bottom)
+@@ -1999,6 +2103,14 @@ static void moz_gtk_add_margin_border_pa
+     moz_gtk_add_style_padding(style, left, top, right, bottom);
+ }
+ 
++static void moz_gtk_add_border_padding(GtkStyleContext *style,
++                                       gint* left, gint* top,
++                                       gint* right, gint* bottom)
++{
++    moz_gtk_add_style_border(style, left, top, right, bottom);
++    moz_gtk_add_style_padding(style, left, top, right, bottom);
++}
++
+ static GtkBorder
+ GetMarginBorderPadding(GtkStyleContext* aStyle)
+ {
+@@ -2054,8 +2166,7 @@ moz_gtk_get_widget_border(WidgetNodeType
+             // XXX: Subtract 1 pixel from the padding to account for the default
+             // padding in forms.css. See bug 1187385.
+             *left = *top = *right = *bottom = -1;
+-            moz_gtk_add_style_padding(style, left, top, right, bottom);
+-            moz_gtk_add_style_border(style, left, top, right, bottom);
++            moz_gtk_add_border_padding(style, left, top, right, bottom);
+ 
+             return MOZ_GTK_SUCCESS;
+         }
+@@ -2076,10 +2187,8 @@ moz_gtk_get_widget_border(WidgetNodeType
+             *left = *top = *right = *bottom =
+                 gtk_container_get_border_width(GTK_CONTAINER(
+                                                GetWidget(MOZ_GTK_TREE_HEADER_CELL)));
+-
+             style = GetStyleContext(MOZ_GTK_TREE_HEADER_CELL);
+-            moz_gtk_add_style_border(style, left, top, right, bottom);
+-            moz_gtk_add_style_padding(style, left, top, right, bottom);
++            moz_gtk_add_border_padding(style, left, top, right, bottom);
+             return MOZ_GTK_SUCCESS;
+         }
+     case MOZ_GTK_TREE_HEADER_SORTARROW:
+@@ -2105,8 +2214,7 @@ moz_gtk_get_widget_border(WidgetNodeType
+                 gtk_container_get_border_width(GTK_CONTAINER(
+                                                GetWidget(MOZ_GTK_COMBOBOX_BUTTON)));
+             style = GetStyleContext(MOZ_GTK_COMBOBOX_BUTTON);
+-            moz_gtk_add_style_padding(style, left, top, right, bottom);
+-            moz_gtk_add_style_border(style, left, top, right, bottom);
++            moz_gtk_add_border_padding(style, left, top, right, bottom);
+ 
+             /* If there is no separator, don't try to count its width. */
+             separator_width = 0;
+@@ -2160,10 +2268,8 @@ moz_gtk_get_widget_border(WidgetNodeType
+             style = gtk_widget_get_style_context(w);
+ 
+             *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(w));
+-            moz_gtk_add_style_border(style,
+-                                     left, top, right, bottom);
+-            moz_gtk_add_style_padding(style,
+-                                      left, top, right, bottom);
++            moz_gtk_add_border_padding(style,
++                                       left, top, right, bottom);
+             return MOZ_GTK_SUCCESS;
+         }
+     case MOZ_GTK_MENUPOPUP:
+@@ -2210,6 +2316,21 @@ moz_gtk_get_widget_border(WidgetNodeType
+ 
+             return MOZ_GTK_SUCCESS;
+         }
++    case MOZ_GTK_HEADER_BAR:
++    case MOZ_GTK_HEADER_BAR_MAXIMIZED:
++        {
++            style = GetStyleContext(widget);
++            moz_gtk_add_border_padding(style, left, top, right, bottom);
++            return MOZ_GTK_SUCCESS;
++        }
++    case MOZ_GTK_HEADER_BAR_BUTTON_CLOSE:
++    case MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE:
++    case MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE:
++        {
++            style = GetStyleContext(widget);
++            moz_gtk_add_margin_border_padding(style, left, top, right, bottom);
++            return MOZ_GTK_SUCCESS;
++        }
+ 
+     /* These widgets have no borders, since they are not containers. */
+     case MOZ_GTK_CHECKBUTTON_LABEL:
+@@ -2646,6 +2767,36 @@ GetScrollbarMetrics(GtkOrientation aOrie
+     return metrics;
+ }
+ 
++void
++moz_gtk_window_decoration_paint(cairo_t *cr, GdkRectangle* rect)
++{
++    gint top, right, bottom, left;
++    moz_gtk_get_window_border(&top, &right, &bottom, &left);
++
++    cairo_save(cr);
++    cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
++    cairo_rectangle(cr, rect->x, rect->y, left, rect->height);
++    cairo_fill(cr);
++    cairo_rectangle(cr, rect->x+rect->width-right, rect->y, right, rect->height);
++    cairo_fill(cr);
++    cairo_rectangle(cr, rect->x, rect->y, rect->width, top);
++    cairo_fill(cr);
++    cairo_rectangle(cr, rect->x, rect->height-bottom, rect->width, bottom);
++    cairo_fill(cr);
++    cairo_restore(cr);
++
++    GtkStyleContext* style = GetStyleContext(MOZ_GTK_WINDOW_DECORATION,
++                                               GTK_TEXT_DIR_NONE);
++    rect->x += left;
++    rect->y += top;
++    rect->width -= left + right;
++    rect->height -= top + bottom;
++
++    gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
++    gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
++}
++
++
+ /* cairo_t *cr argument has to be a system-cairo. */
+ gint
+ moz_gtk_widget_paint(WidgetNodeType widget, cairo_t *cr,
+@@ -2671,6 +2822,14 @@ moz_gtk_widget_paint(WidgetNodeType widg
+                                     GetWidget(MOZ_GTK_BUTTON),
+                                     direction);
+         break;
++    case MOZ_GTK_HEADER_BAR_BUTTON_CLOSE:
++    case MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE:
++    case MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE:
++        return moz_gtk_header_bar_button_paint(cr, rect, state,
++                                               (GtkReliefStyle) flags,
++                                               GetWidget(widget),
++                                               direction);
++        break;
+     case MOZ_GTK_CHECKBUTTON:
+     case MOZ_GTK_RADIOBUTTON:
+         return moz_gtk_toggle_paint(cr, rect, state,
+@@ -2877,6 +3036,10 @@ moz_gtk_widget_paint(WidgetNodeType widg
+     case MOZ_GTK_INFO_BAR:
+         return moz_gtk_info_bar_paint(cr, rect, state);
+         break;
++    case MOZ_GTK_HEADER_BAR:
++    case MOZ_GTK_HEADER_BAR_MAXIMIZED:
++        return moz_gtk_header_bar_paint(widget, cr, rect, state);
++        break;
+     default:
+         g_warning("Unknown widget type: %d", widget);
+     }
+diff -up firefox-57.0b8/widget/gtk/gtkdrawing.h.1399611 firefox-57.0b8/widget/gtk/gtkdrawing.h
+--- firefox-57.0b8/widget/gtk/gtkdrawing.h.1399611	2017-06-12 18:37:20.000000000 +0200
++++ firefox-57.0b8/widget/gtk/gtkdrawing.h	2017-10-16 12:11:45.367240644 +0200
+@@ -268,8 +268,14 @@ typedef enum {
+   MOZ_GTK_SPLITTER_SEPARATOR_VERTICAL,
+   /* Paints the background of a window, dialog or page. */
+   MOZ_GTK_WINDOW,
++  /* Used only as a container for MOZ_GTK_HEADER_BAR_MAXIMIZED. */
++  MOZ_GTK_WINDOW_MAXIMIZED,
+   /* Window container for all widgets */
+   MOZ_GTK_WINDOW_CONTAINER,
++  /* Window with the 'csd' style class. */
++  MOZ_GTK_WINDOW_CSD,
++  /* Client-side window decoration node. Available on GTK 3.20+. */
++  MOZ_GTK_WINDOW_DECORATION,
+   /* Paints a GtkInfoBar, for notifications. */
+   MOZ_GTK_INFO_BAR,
+   /* Used for widget tree construction. */
+@@ -290,6 +296,14 @@ typedef enum {
+   MOZ_GTK_COMBOBOX_ENTRY_ARROW,
+   /* Used for scrolled window shell. */
+   MOZ_GTK_SCROLLED_WINDOW,
++  /* Paints a GtkHeaderBar */
++  MOZ_GTK_HEADER_BAR,
++  /* Paints a GtkHeaderBar in maximized state */
++  MOZ_GTK_HEADER_BAR_MAXIMIZED,
++  /* Paints a GtkHeaderBar title buttons */
++  MOZ_GTK_HEADER_BAR_BUTTON_CLOSE,
++  MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE,
++  MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE,
+ 
+   MOZ_GTK_WIDGET_NODE_COUNT
+ } WidgetNodeType;
+@@ -542,6 +556,32 @@ gint moz_gtk_get_menu_separator_height(g
+  */
+ gint moz_gtk_splitter_get_metrics(gint orientation, gint* size);
+ 
++#if (MOZ_WIDGET_GTK == 3)
++/**
++ * Gets the margins to be used for window decorations, typically the extra space
++ * required to draw a drop shadow (obtained from gtk_render_background_get_clip).
++ * Only available on GTK 3.20+.
++ */
++void moz_gtk_get_window_border(gint* top, gint* right, gint* bottom, gint* left);
++
++/**
++ * Draw window decorations, typically a shadow.
++ * Only available on GTK 3.20+.
++ */
++void moz_gtk_window_decoration_paint(cairo_t *cr, GdkRectangle* rect);
++
++/**
++ * Gets the border of window header bar, only available on GTK 3.20+.
++ */
++void moz_gtk_get_header_bar_border(gint* top, gint* right, gint* bottom, gint* left);
++
++/**
++ * Draw window header bar, only available on GTK 3.20+.
++ */
++void moz_gtk_header_bar_paint(cairo_t *cr, GdkRectangle* rect);
++
++#endif
++
+ /**
+  * Get the YTHICKNESS of a tab (notebook extension).
+  */
+diff -up firefox-57.0b8/widget/gtk/mozgtk/mozgtk.c.1399611 firefox-57.0b8/widget/gtk/mozgtk/mozgtk.c
+--- firefox-57.0b8/widget/gtk/mozgtk/mozgtk.c.1399611	2017-10-09 22:17:13.000000000 +0200
++++ firefox-57.0b8/widget/gtk/mozgtk/mozgtk.c	2017-10-16 12:11:45.367240644 +0200
+@@ -580,6 +580,8 @@ STUB(gtk_style_context_set_state)
+ STUB(gtk_style_properties_lookup_property)
+ STUB(gtk_tree_view_column_get_button)
+ STUB(gtk_widget_get_preferred_size)
++STUB(gtk_widget_get_preferred_width)
++STUB(gtk_widget_get_preferred_height)
+ STUB(gtk_widget_get_state_flags)
+ STUB(gtk_widget_get_style_context)
+ STUB(gtk_widget_path_append_type)
+@@ -589,6 +591,10 @@ STUB(gtk_widget_path_iter_add_class)
+ STUB(gtk_widget_path_get_object_type)
+ STUB(gtk_widget_path_new)
+ STUB(gtk_widget_path_unref)
++STUB(gtk_widget_set_margin_left)
++STUB(gtk_widget_set_margin_right)
++STUB(gtk_widget_set_margin_top)
++STUB(gtk_widget_set_margin_bottom)
+ STUB(gtk_widget_set_visual)
+ STUB(gtk_app_chooser_dialog_new_for_content_type)
+ STUB(gtk_app_chooser_get_type)
+@@ -601,6 +607,7 @@ STUB(gtk_color_chooser_get_type)
+ STUB(gtk_color_chooser_set_rgba)
+ STUB(gtk_color_chooser_get_rgba)
+ STUB(gtk_color_chooser_set_use_alpha)
++STUB(gtk_window_get_size)
+ #endif
+ 
+ #ifdef GTK2_SYMBOLS
+diff -up firefox-57.0b8/widget/gtk/nsLookAndFeel.cpp.1399611 firefox-57.0b8/widget/gtk/nsLookAndFeel.cpp
+--- firefox-57.0b8/widget/gtk/nsLookAndFeel.cpp.1399611	2017-09-21 06:10:10.000000000 +0200
++++ firefox-57.0b8/widget/gtk/nsLookAndFeel.cpp	2017-10-16 12:11:45.367240644 +0200
+@@ -642,6 +642,22 @@ nsLookAndFeel::GetIntImpl(IntID aID, int
+     case eIntID_ContextMenuOffsetHorizontal:
+         aResult = 2;
+         break;
++    case eIntID_GTKCSDAvailable:
++        EnsureInit();
++        aResult = sCSDAvailable;
++        break;
++    case eIntID_GTKCSDMaximizeButton:
++        EnsureInit();
++        aResult = sCSDMaximizeButton;
++        break;
++    case eIntID_GTKCSDMinimizeButton:
++        EnsureInit();
++        aResult = sCSDMinimizeButton;
++        break;
++    case eIntID_GTKCSDCloseButton:
++        EnsureInit();
++        aResult = sCSDCloseButton;
++        break;
+     default:
+         aResult = 0;
+         res     = NS_ERROR_FAILURE;
+@@ -1048,6 +1064,40 @@ nsLookAndFeel::EnsureInit()
+ 
+     gtk_widget_destroy(window);
+     g_object_unref(labelWidget);
++
++    // Require GTK 3.20 for client-side decoration support.
++    // 3.20 exposes gtk_render_background_get_clip, which is required for
++    // calculating shadow metrics for decorated windows.
++    sCSDAvailable = gtk_check_version(3, 20, 0) == nullptr;
++    if (sCSDAvailable) {
++        sCSDAvailable =
++            mozilla::Preferences::GetBool("widget.allow-client-side-decoration",
++                                          false);
++    }
++
++    const gchar* decorationLayout = nullptr;
++    if (gtk_check_version(3, 12, 0) == nullptr) {
++        static auto sGtkHeaderBarGetDecorationLayoutPtr =
++          (const gchar* (*)(GtkWidget*))
++          dlsym(RTLD_DEFAULT, "gtk_header_bar_get_decoration_layout");
++
++        GtkWidget* headerBar = GetWidget(MOZ_GTK_HEADER_BAR);
++        decorationLayout = sGtkHeaderBarGetDecorationLayoutPtr(headerBar);
++        if (!decorationLayout) {
++            g_object_get(settings, "gtk-decoration-layout", &decorationLayout,
++                         nullptr);
++        }
++    }
++
++    if (decorationLayout) {
++        sCSDCloseButton = (strstr(decorationLayout, "close") != nullptr);
++        sCSDMaximizeButton = (strstr(decorationLayout, "maximize") != nullptr);
++        sCSDMinimizeButton = (strstr(decorationLayout, "minimize") != nullptr);
++    } else {
++        sCSDCloseButton = true;
++        sCSDMaximizeButton = true;
++        sCSDMinimizeButton = true;
++    }
+ }
+ 
+ // virtual
+diff -up firefox-57.0b8/widget/gtk/nsLookAndFeel.h.1399611 firefox-57.0b8/widget/gtk/nsLookAndFeel.h
+--- firefox-57.0b8/widget/gtk/nsLookAndFeel.h.1399611	2017-09-21 06:10:10.000000000 +0200
++++ firefox-57.0b8/widget/gtk/nsLookAndFeel.h	2017-10-16 12:11:45.367240644 +0200
+@@ -32,6 +32,8 @@ public:
+     virtual char16_t GetPasswordCharacterImpl();
+     virtual bool GetEchoPasswordImpl();
+ 
++    bool IsCSDAvailable() const { return sCSDAvailable; }
++
+ protected:
+ 
+     // Cached fonts
+@@ -82,6 +84,10 @@ protected:
+     char16_t sInvisibleCharacter;
+     float   sCaretRatio;
+     bool    sMenuSupportsDrag;
++    bool    sCSDAvailable;
++    bool    sCSDMaximizeButton;
++    bool    sCSDMinimizeButton;
++    bool    sCSDCloseButton;
+     bool    mInitialized;
+ 
+     void EnsureInit();
+diff -up firefox-57.0b8/widget/gtk/nsNativeThemeGTK.cpp.1399611 firefox-57.0b8/widget/gtk/nsNativeThemeGTK.cpp
+--- firefox-57.0b8/widget/gtk/nsNativeThemeGTK.cpp.1399611	2017-09-19 06:18:28.000000000 +0200
++++ firefox-57.0b8/widget/gtk/nsNativeThemeGTK.cpp	2017-10-16 12:11:45.368240640 +0200
+@@ -23,6 +23,7 @@
+ #include "nsIDOMHTMLInputElement.h"
+ #include "nsGkAtoms.h"
+ #include "nsAttrValueInlines.h"
++#include "nsWindow.h"
+ 
+ #include "mozilla/EventStates.h"
+ #include "mozilla/Services.h"
+@@ -703,6 +704,24 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u
+   case NS_THEME_GTK_INFO_BAR:
+     aGtkWidgetType = MOZ_GTK_INFO_BAR;
+     break;
++  case NS_THEME_WINDOW_TITLEBAR:
++    aGtkWidgetType = MOZ_GTK_HEADER_BAR;
++    break;
++  case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED:
++    aGtkWidgetType = MOZ_GTK_HEADER_BAR_MAXIMIZED;
++    break;
++  case NS_THEME_WINDOW_BUTTON_CLOSE:
++    aGtkWidgetType = MOZ_GTK_HEADER_BAR_BUTTON_CLOSE;
++    break;
++  case NS_THEME_WINDOW_BUTTON_MINIMIZE:
++    aGtkWidgetType = MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE;
++    break;
++  case NS_THEME_WINDOW_BUTTON_MAXIMIZE:
++    aGtkWidgetType = MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE;
++    break;
++  case NS_THEME_WINDOW_BUTTON_RESTORE:
++    aGtkWidgetType = MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE;
++    break;
+   default:
+     return false;
+   }
+@@ -1627,6 +1646,10 @@ nsNativeThemeGTK::GetMinimumWidgetSize(n
+   case NS_THEME_MENULIST:
+   case NS_THEME_TOOLBARBUTTON:
+   case NS_THEME_TREEHEADERCELL:
++  case NS_THEME_WINDOW_BUTTON_CLOSE:
++  case NS_THEME_WINDOW_BUTTON_MINIMIZE:
++  case NS_THEME_WINDOW_BUTTON_MAXIMIZE:
++  case NS_THEME_WINDOW_BUTTON_RESTORE:
+     {
+       if (aWidgetType == NS_THEME_MENULIST) {
+         // Include the arrow size.
+@@ -1892,9 +1915,21 @@ nsNativeThemeGTK::ThemeSupportsWidget(ns
+   case NS_THEME_DIALOG:
+ #if (MOZ_WIDGET_GTK == 3)
+   case NS_THEME_GTK_INFO_BAR:
++  case NS_THEME_GTK_WINDOW_DECORATION:
+ #endif
+     return !IsWidgetStyled(aPresContext, aFrame, aWidgetType);
+ 
++  case NS_THEME_WINDOW_BUTTON_CLOSE:
++  case NS_THEME_WINDOW_BUTTON_MINIMIZE:
++  case NS_THEME_WINDOW_BUTTON_MAXIMIZE:
++  case NS_THEME_WINDOW_BUTTON_RESTORE:
++  case NS_THEME_WINDOW_TITLEBAR:
++  case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED:
++    // GtkHeaderBar is available on GTK 3.10+, which is used for styling
++    // title bars and title buttons.
++    return gtk_check_version(3, 10, 0) == nullptr &&
++           !IsWidgetStyled(aPresContext, aFrame, aWidgetType);
++
+   case NS_THEME_MENULIST_BUTTON:
+     if (aFrame && aFrame->GetWritingMode().IsVertical()) {
+       return false;
+@@ -1978,6 +2013,13 @@ nsNativeThemeGTK::GetWidgetTransparency(
+ #else
+     return eTransparent;
+ #endif
++  case NS_THEME_GTK_WINDOW_DECORATION:
++  {
++    nsWindow* window = static_cast<nsWindow*>(aFrame->GetNearestWidget());
++    if (window)
++      return window->IsComposited() ? eTransparent : eOpaque;
++    return eOpaque;
++  }
+   }
+ 
+   return eUnknownTransparency;
+diff -up firefox-57.0b8/widget/gtk/nsWindow.cpp.1399611 firefox-57.0b8/widget/gtk/nsWindow.cpp
+--- firefox-57.0b8/widget/gtk/nsWindow.cpp.1399611	2017-10-16 12:11:45.361240666 +0200
++++ firefox-57.0b8/widget/gtk/nsWindow.cpp	2017-10-16 12:11:45.369240636 +0200
+@@ -85,6 +85,7 @@
+ #include "nsIPropertyBag2.h"
+ #include "GLContext.h"
+ #include "gfx2DGlue.h"
++#include "nsLookAndFeel.h"
+ 
+ #ifdef ACCESSIBILITY
+ #include "mozilla/a11y/Accessible.h"
+@@ -139,6 +140,8 @@ using namespace mozilla::widget;
+ 
+ #include "mozilla/layers/APZCTreeManager.h"
+ 
++#include "gtkdrawing.h"
++
+ using namespace mozilla;
+ using namespace mozilla::gfx;
+ using namespace mozilla::widget;
+@@ -186,6 +189,8 @@ static gboolean expose_event_cb
+ #else
+ static gboolean expose_event_cb           (GtkWidget *widget,
+                                            cairo_t *rect);
++static gboolean expose_event_decoration_draw_cb (GtkWidget *widget,
++                                                cairo_t *cr);
+ #endif
+ static gboolean configure_event_cb        (GtkWidget *widget,
+                                            GdkEventConfigure *event);
+@@ -231,7 +236,6 @@ static void     screen_composited_change
+                                                   gpointer user_data);
+ static void     widget_composited_changed_cb     (GtkWidget* widget,
+                                                   gpointer user_data);
+-
+ #if (MOZ_WIDGET_GTK == 3)
+ static void     scale_changed_cb          (GtkWidget* widget,
+                                            GParamSpec* aPSpec,
+@@ -440,6 +444,7 @@ nsWindow::nsWindow()
+ 
+     mContainer           = nullptr;
+     mGdkWindow           = nullptr;
++    mIsCSDEnabled        = false;
+     mShell               = nullptr;
+     mCompositorWidgetDelegate = nullptr;
+     mHasMappedToplevel   = false;
+@@ -481,6 +486,9 @@ nsWindow::nsWindow()
+     mLastScrollEventTime = GDK_CURRENT_TIME;
+ #endif
+     mPendingConfigures = 0;
++    mDrawWindowDecoration = false;
++    mDecorationSize = {0,0,0,0};
++    mCSDSupportLevel = CSD_SUPPORT_UNKNOWN;
+ }
+ 
+ nsWindow::~nsWindow()
+@@ -1479,8 +1487,8 @@ LayoutDeviceIntRect
+ nsWindow::GetScreenBounds()
+ {
+     LayoutDeviceIntRect rect;
+-    if (mIsTopLevel && mContainer) {
+-        // use the point including window decorations
++    if (mIsTopLevel && mContainer && !IsClientDecorated()) {
++        // use the point including default Gtk+ window decorations
+         gint x, y;
+         gdk_window_get_root_origin(gtk_widget_get_window(GTK_WIDGET(mContainer)), &x, &y);
+         rect.MoveTo(GdkPointToDevicePixels({ x, y }));
+@@ -1606,6 +1614,10 @@ nsWindow::SetCursor(nsCursor aCursor)
+                 return;
+ 
+             gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(mContainer)), newCursor);
++            if (IsClientDecorated()) {
++                gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(mShell)),
++                                      newCursor);
++            }
+         }
+     }
+ }
+@@ -1662,6 +1674,10 @@ nsWindow::SetCursor(imgIContainer* aCurs
+     if (cursor) {
+         if (mContainer) {
+             gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(mContainer)), cursor);
++            if (IsClientDecorated()) {
++                gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(mShell)),
++                                      cursor);
++            }
+             rv = NS_OK;
+         }
+ #if (MOZ_WIDGET_GTK == 3)
+@@ -2176,6 +2192,12 @@ nsWindow::OnExposeEvent(cairo_t *cr)
+         return TRUE;
+     }
+ 
++    // Clip upper part of the mContainer to get visible rounded corners
++    // of GtkHeaderBar which is renderd to mShell.
++    if (mIsCSDEnabled) {
++        ApplyCSDClipping();
++    }
++
+     // If this widget uses OMTC...
+     if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT ||
+         GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_WR) {
+@@ -2586,6 +2608,53 @@ nsWindow::OnMotionNotifyEvent(GdkEventMo
+         }
+     }
+ #endif /* MOZ_X11 */
++    // Client is decorated and we're getting the motion event for mShell
++    // window which draws the CSD decorations around mContainer.
++    if (IsClientDecorated()) {
++        if (aEvent->window == gtk_widget_get_window(mShell)) {
++            GdkWindowEdge edge;
++            LayoutDeviceIntPoint refPoint =
++                GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y);
++            if (CheckResizerEdge(refPoint, edge)) {
++                nsCursor cursor = eCursor_none;
++                switch (edge) {
++                case GDK_WINDOW_EDGE_NORTH:
++                    cursor = eCursor_n_resize;
++                    break;
++                case GDK_WINDOW_EDGE_NORTH_WEST:
++                    cursor = eCursor_nw_resize;
++                    break;
++                case GDK_WINDOW_EDGE_NORTH_EAST:
++                    cursor = eCursor_ne_resize;
++                    break;
++                case GDK_WINDOW_EDGE_WEST:
++                    cursor = eCursor_w_resize;
++                    break;
++                case GDK_WINDOW_EDGE_EAST:
++                    cursor = eCursor_e_resize;
++                    break;
++                case GDK_WINDOW_EDGE_SOUTH:
++                    cursor = eCursor_s_resize;
++                    break;
++                case GDK_WINDOW_EDGE_SOUTH_WEST:
++                    cursor = eCursor_sw_resize;
++                    break;
++                case GDK_WINDOW_EDGE_SOUTH_EAST:
++                    cursor = eCursor_se_resize;
++                    break;
++                }
++                SetCursor(cursor);
++                return;
++            }
++        }
++        // We're not on resize handle - check if we need to reset cursor back.
++        if (mCursor == eCursor_n_resize || mCursor == eCursor_nw_resize ||
++            mCursor == eCursor_ne_resize ||  mCursor == eCursor_w_resize ||
++            mCursor == eCursor_e_resize || mCursor == eCursor_s_resize ||
++            mCursor == eCursor_sw_resize || mCursor == eCursor_se_resize) {
++            SetCursor(eCursor_standard);
++        }
++    }
+ 
+     WidgetMouseEvent event(true, eMouseMove, this, WidgetMouseEvent::eReal);
+ 
+@@ -2756,6 +2825,20 @@ nsWindow::OnButtonPressEvent(GdkEventBut
+     if (CheckForRollup(aEvent->x_root, aEvent->y_root, false, false))
+         return;
+ 
++    if (IsClientDecorated() && aEvent->window == gtk_widget_get_window(mShell)) {
++        // Check to see if the event is within our window's resize region
++        GdkWindowEdge edge;
++        LayoutDeviceIntPoint refPoint =
++            GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y);
++        if (CheckResizerEdge(refPoint, edge)) {
++            gdk_window_begin_resize_drag(gtk_widget_get_window(mShell),
++                                         edge, aEvent->button,
++                                         aEvent->x_root, aEvent->y_root,
++                                         aEvent->time);
++            return;
++        }
++    }
++
+     gdouble pressure = 0;
+     gdk_event_get_axis ((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
+     mLastMotionPressure = pressure;
+@@ -3341,6 +3424,8 @@ nsWindow::OnWindowStateEvent(GtkWidget *
+ #endif //ACCESSIBILITY
+     }
+ 
++    UpdateClientDecorations();
++
+     if (mWidgetListener) {
+       mWidgetListener->SizeModeChanged(mSizeState);
+       if (aEvent->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
+@@ -3405,6 +3490,7 @@ nsWindow::OnCompositedChanged()
+       presShell->ThemeChanged();
+     }
+   }
++  UpdateClientDecorations();
+ }
+ 
+ void
+@@ -3593,7 +3679,8 @@ nsWindow::Create(nsIWidget* aParent,
+     GtkWindow      *topLevelParent = nullptr;
+     nsWindow       *parentnsWindow = nullptr;
+     GtkWidget      *eventWidget = nullptr;
+-    bool            shellHasCSD = false;
++    GtkWidget      *drawWidget = nullptr;
++    bool            drawToContainer = false;
+ 
+     if (aParent) {
+         parentnsWindow = static_cast<nsWindow*>(aParent);
+@@ -3640,29 +3727,47 @@ nsWindow::Create(nsIWidget* aParent,
+               GTK_WINDOW_TOPLEVEL : GTK_WINDOW_POPUP;
+         mShell = gtk_window_new(type);
+ 
+-        bool useAlphaVisual = (mWindowType == eWindowType_popup &&
+-                               aInitData->mSupportTranslucency);
++        bool useAlphaVisual = false;
++#if (MOZ_WIDGET_GTK == 3)
++        // When CSD is available we can emulate it for toplevel windows.
++        // Content is rendered to mContainer and transparent decorations to mShell.
++        if (GetCSDSupportLevel() != CSD_SUPPORT_NONE &&
++            mWindowType == eWindowType_toplevel) {
++            int32_t isCSDAvailable = false;
++            nsresult rv = LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDAvailable,
++                                             &isCSDAvailable);
++            if (NS_SUCCEEDED(rv)) {
++                mIsCSDEnabled = useAlphaVisual = isCSDAvailable;
++            }
++        } else
++#endif
++        if (mWindowType == eWindowType_popup) {
++            useAlphaVisual = aInitData->mSupportTranslucency;
++        }
+ 
+         // mozilla.widget.use-argb-visuals is a hidden pref defaulting to false
+         // to allow experimentation
+         if (Preferences::GetBool("mozilla.widget.use-argb-visuals", false))
+             useAlphaVisual = true;
+ 
++        // An ARGB visual is only useful if we are on a compositing
++        // window manager.
++        GdkScreen *screen = gtk_widget_get_screen(mShell);
++        if (useAlphaVisual && !gdk_screen_is_composited(screen)) {
++            useAlphaVisual = false;
++        }
++
+         // We need to select an ARGB visual here instead of in
+         // SetTransparencyMode() because it has to be done before the
+-        // widget is realized.  An ARGB visual is only useful if we
+-        // are on a compositing window manager.
++        // widget is realized.
+         if (useAlphaVisual) {
+-            GdkScreen *screen = gtk_widget_get_screen(mShell);
+-            if (gdk_screen_is_composited(screen)) {
+ #if (MOZ_WIDGET_GTK == 2)
+-                GdkColormap *colormap = gdk_screen_get_rgba_colormap(screen);
+-                gtk_widget_set_colormap(mShell, colormap);
++            GdkColormap *colormap = gdk_screen_get_rgba_colormap(screen);
++            gtk_widget_set_colormap(mShell, colormap);
+ #else
+-                GdkVisual *visual = gdk_screen_get_rgba_visual(screen);
+-                gtk_widget_set_visual(mShell, visual);
++            GdkVisual *visual = gdk_screen_get_rgba_visual(screen);
++            gtk_widget_set_visual(mShell, visual);
+ #endif
+-            }
+         }
+ 
+         // We only move a general managed toplevel window if someone has
+@@ -3756,24 +3861,56 @@ nsWindow::Create(nsIWidget* aParent,
+         mContainer = MOZ_CONTAINER(container);
+ 
+ #if (MOZ_WIDGET_GTK == 3)
+-        // "csd" style is set when widget is realized so we need to call
+-        // it explicitly now.
+-        gtk_widget_realize(mShell);
+-
+-        // We can't draw directly to top-level window when client side
+-        // decorations are enabled. We use container with GdkWindow instead.
+-        GtkStyleContext* style = gtk_widget_get_style_context(mShell);
+-        shellHasCSD = gtk_style_context_has_class(style, "csd");
+-#endif
+-        if (!shellHasCSD) {
+-            // Use mShell's window for drawing and events.
+-            gtk_widget_set_has_window(container, FALSE);
+-            // Prevent GtkWindow from painting a background to flicker.
+-            gtk_widget_set_app_paintable(mShell, TRUE);
+-        }
+-        // Set up event widget
+-        eventWidget = shellHasCSD ? container : mShell;
++        /* There are tree possible situations here:
++         *
++         * 1) We're running on Gtk+ < 3.20 without any decorations. Content
++         *    is rendered to mShell window and we listen Gtk+ events on mShell.
++         * 2) We're running on Gtk+ > 3.20 and window decorations are drawn
++         *    by default by Gtk+. Content is rendered to mContainer,
++         *    we listen events on mContainer. mShell contains default Gtk+
++         *    window decorations rendered by Gtk+.
++         * 3) We're running on Gtk+ > 3.20 and both window decorations and
++         *    content is rendered by gecko. We emulate Gtk+ decoration rendering
++         *    to mShell and we need to listen Gtk events on both mShell
++         *    and mContainer.
++         */
++
++        // When client side decorations are enabled (rendered by us or by Gtk+)
++        // the decoration is rendered to mShell (toplevel) window and
++        // we draw our content to mContainer.
++        if (mIsCSDEnabled) {
++            drawToContainer = true;
++        } else {
++            // mIsCSDEnabled can be disabled by preference so look at actual
++            // toplevel window style to to detect active "csd" style.
++            // The "csd" style is set when widget is realized so we need to call
++            // it explicitly now.
++            gtk_widget_realize(mShell);
++
++            GtkStyleContext* style = gtk_widget_get_style_context(mShell);
++            drawToContainer = gtk_style_context_has_class(style, "csd");
++        }
++#endif
++        drawWidget = (drawToContainer) ? container : mShell;
++        // When we draw decorations on our own we need to handle resize events
++        // because Gtk+ does not provide resizers for undecorated windows.
++        // The CSD on mShell borders act as resize handlers
++        // so we need to listen there.
++        eventWidget = (drawToContainer && !mIsCSDEnabled) ? container : mShell;
++
+         gtk_widget_add_events(eventWidget, kEvents);
++        if (eventWidget != drawWidget) {
++            // CSD is rendered by us (not by Gtk+) so we also need to listen
++            // at mShell window for events.
++            gtk_widget_add_events(drawWidget, kEvents);
++        }
++
++        // Prevent GtkWindow from painting a background to flicker.
++        gtk_widget_set_app_paintable(drawWidget, TRUE);
++
++        // gtk_container_add() realizes the child widget so we need to
++        // set it now.
++        gtk_widget_set_has_window(container, drawToContainer);
+ 
+         gtk_container_add(GTK_CONTAINER(mShell), container);
+         gtk_widget_realize(container);
+@@ -3783,7 +3920,7 @@ nsWindow::Create(nsIWidget* aParent,
+         gtk_widget_grab_focus(container);
+ 
+         // the drawing window
+-        mGdkWindow = gtk_widget_get_window(eventWidget);
++        mGdkWindow = gtk_widget_get_window(drawWidget);
+ 
+         if (mWindowType == eWindowType_popup) {
+             // gdk does not automatically set the cursor for "temporary"
+@@ -3856,6 +3993,11 @@ nsWindow::Create(nsIWidget* aParent,
+ 
+     // label the drawing window with this object so we can find our way home
+     g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", this);
++    if (mIsCSDEnabled) {
++        // label the CSD window with this object so we can find our way home
++        g_object_set_data(G_OBJECT(gtk_widget_get_window(mShell)),
++                          "nsWindow", this);
++    }
+ 
+     if (mContainer)
+         g_object_set_data(G_OBJECT(mContainer), "nsWindow", this);
+@@ -3893,6 +4035,10 @@ nsWindow::Create(nsIWidget* aParent,
+         g_signal_connect_after(default_settings,
+                                "notify::gtk-font-name",
+                                G_CALLBACK(theme_changed_cb), this);
++        if (mIsCSDEnabled) {
++            g_signal_connect(G_OBJECT(mShell), "draw",
++                             G_CALLBACK(expose_event_decoration_draw_cb), nullptr);
++        }
+     }
+ 
+     if (mContainer) {
+@@ -3943,7 +4089,7 @@ nsWindow::Create(nsIWidget* aParent,
+                          G_CALLBACK(drag_data_received_event_cb), nullptr);
+ 
+         GtkWidget *widgets[] = { GTK_WIDGET(mContainer),
+-                                 !shellHasCSD ? mShell : nullptr };
++                                 !drawToContainer ? mShell : nullptr };
+         for (size_t i = 0; i < ArrayLength(widgets) && widgets[i]; ++i) {
+             // Visibility events are sent to the owning widget of the relevant
+             // window but do not propagate to parent widgets so connect on
+@@ -3973,7 +4119,6 @@ nsWindow::Create(nsIWidget* aParent,
+         // Don't let GTK mess with the shapes of our GdkWindows
+         GTK_PRIVATE_SET_FLAG(eventWidget, GTK_HAS_SHAPE_MASK);
+ #endif
+-
+         // These events are sent to the owning widget of the relevant window
+         // and propagate up to the first widget that handles the events, so we
+         // need only connect on mShell, if it exists, to catch events on its
+@@ -4110,6 +4255,12 @@ nsWindow::NativeResize()
+          size.width, size.height));
+ 
+     if (mIsTopLevel) {
++        // When we draw decorations add extra space to draw shadows
++        // around the main window.
++        if (mDrawWindowDecoration) {
++            size.width += mDecorationSize.left + mDecorationSize.right;
++            size.height += mDecorationSize.top + mDecorationSize.bottom;
++        }
+         gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height);
+     }
+     else if (mContainer) {
+@@ -4166,6 +4317,11 @@ nsWindow::NativeMoveResize()
+     if (mIsTopLevel) {
+         // x and y give the position of the window manager frame top-left.
+         gtk_window_move(GTK_WINDOW(mShell), topLeft.x, topLeft.y);
++
++        if (mDrawWindowDecoration) {
++            size.width += mDecorationSize.left + mDecorationSize.right;
++            size.height += mDecorationSize.top + mDecorationSize.bottom;
++        }
+         // This sets the client window size.
+         gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height);
+     }
+@@ -5524,6 +5680,33 @@ expose_event_cb(GtkWidget *widget, cairo
+ 
+     return FALSE;
+ }
++
++/* static */
++gboolean
++expose_event_decoration_draw_cb(GtkWidget *widget, cairo_t *cr)
++{
++  GdkWindow* gdkWindow = gtk_widget_get_window(widget);
++  if (gtk_cairo_should_draw_window(cr, gdkWindow)) {
++      RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
++      if (!window) {
++          NS_WARNING("Cannot get nsWindow from GtkWidget");
++      }
++      else if (window->IsClientDecorated()) {
++          cairo_save(cr);
++          gtk_cairo_transform_to_window(cr, widget, gdkWindow);
++
++          GdkRectangle rect = {0,0,0,0};
++          gtk_window_get_size(GTK_WINDOW(widget), &rect.width, &rect.height);
++          moz_gtk_window_decoration_paint(cr, &rect);
++
++          rect.height = 40;
++          moz_gtk_header_bar_paint(cr, &rect);
++          cairo_restore(cr);
++      }
++  }
++  return TRUE;
++}
++
+ #endif //MOZ_WIDGET_GTK == 2
+ 
+ static gboolean
+@@ -6576,6 +6759,28 @@ nsWindow::ClearCachedResources()
+     }
+ }
+ 
++NS_IMETHODIMP
++nsWindow::SetNonClientMargins(LayoutDeviceIntMargin &aMargins)
++{
++  SetDrawsInTitlebar(aMargins.top == 0);
++  return NS_OK;
++}
++
++void
++nsWindow::SetDrawsInTitlebar(bool aState)
++{
++  if (!mIsCSDEnabled || aState == mDrawWindowDecoration)
++    return;
++
++  if (mShell) {
++    gtk_window_set_decorated(GTK_WINDOW(mShell), !aState);
++    gtk_widget_set_app_paintable(mShell, aState);
++  }
++
++  mDrawWindowDecoration = aState;
++  UpdateClientDecorations();
++}
++
+ gint
+ nsWindow::GdkScaleFactor()
+ {
+@@ -6846,6 +7051,157 @@ nsWindow::SynthesizeNativeTouchPoint(uin
+ }
+ #endif
+ 
++bool
++nsWindow::IsClientDecorated() const
++{
++    return mDrawWindowDecoration && mSizeState == nsSizeMode_Normal;
++}
++
++int
++nsWindow::GetClientResizerSize()
++{
++  if (!mShell)
++    return 0;
++
++  // GTK uses a default size of 20px as of 3.20.
++  gint size = 20;
++  gtk_widget_style_get(mShell, "decoration-resize-handle", &size, nullptr);
++
++  return GdkCoordToDevicePixels(size);
++}
++
++nsWindow::CSDSupportLevel
++nsWindow::GetCSDSupportLevel() {
++    if (mCSDSupportLevel != CSD_SUPPORT_UNKNOWN) {
++        return mCSDSupportLevel;
++    }
++    // TODO: MATE
++    const char* currentDesktop = getenv("XDG_CURRENT_DESKTOP");
++    if (currentDesktop) {
++        if (strcmp(currentDesktop, "GNOME") == 0) {
++            mCSDSupportLevel = CSD_SUPPORT_FULL;
++        } else if (strcmp(currentDesktop, "XFCE") == 0) {
++            mCSDSupportLevel = CSD_SUPPORT_FULL;
++        } else if (strcmp(currentDesktop, "X-Cinnamon") == 0) {
++            mCSDSupportLevel = CSD_SUPPORT_FULL;
++        } else if (strcmp(currentDesktop, "KDE") == 0) {
++            mCSDSupportLevel = CSD_SUPPORT_FLAT;
++        } else if (strcmp(currentDesktop, "LXDE") == 0) {
++            mCSDSupportLevel = CSD_SUPPORT_FLAT;
++        } else if (strcmp(currentDesktop, "openbox") == 0) {
++            mCSDSupportLevel = CSD_SUPPORT_FLAT;
++        } else if (strcmp(currentDesktop, "i3") == 0) {
++            mCSDSupportLevel = CSD_SUPPORT_NONE;
++        } else {
++            mCSDSupportLevel = CSD_SUPPORT_NONE;
++        }
++    }
++    return mCSDSupportLevel;
++}
++
++void
++nsWindow::UpdateClientDecorations()
++{
++  // When the CSD is not fully supported by window manager (ie. WM is not
++  // expecting that application is going to draw window shadows) we can't
++  // add shadows widths to the window margin. That would lead to completely
++  // opaque black border of the window.
++  if (!mDrawWindowDecoration || GetCSDSupportLevel() != CSD_SUPPORT_FULL)
++      return;
++
++  gint top = 0, right = 0, bottom = 0, left = 0;
++  if (mSizeState == nsSizeMode_Normal) {
++      moz_gtk_get_window_border(&top, &right, &bottom, &left);
++  }
++
++  static auto sGdkWindowSetShadowWidth =
++     (void (*)(GdkWindow*, gint, gint, gint, gint))
++     dlsym(RTLD_DEFAULT, "gdk_window_set_shadow_width");
++  sGdkWindowSetShadowWidth(gtk_widget_get_window(mShell),
++                           left, right, top, bottom);
++
++  mDecorationSize.left = left;
++  mDecorationSize.right = right;
++  mDecorationSize.top = top;
++  mDecorationSize.bottom = bottom;
++
++  // Gtk+ doesn't like when we set mContainer margin bigger than actual
++  // mContainer window size. That happens when we're called early and the
++  // mShell/mContainer is not allocated/resized yet and has default 1x1 size.
++  // Just resize to some minimal value which will be changed
++  // by Gecko soon.
++  GtkAllocation allocation;
++  gtk_widget_get_allocation(GTK_WIDGET(mContainer), &allocation);
++  if (allocation.width < left + right || allocation.height < top + bottom) {
++      gtk_widget_get_preferred_width(GTK_WIDGET(mContainer), nullptr,
++                                     &allocation.width);
++      gtk_widget_get_preferred_height(GTK_WIDGET(mContainer), nullptr,
++                                      &allocation.height);
++      allocation.width += left + right + 1;
++      allocation.height += top + bottom + 1;
++      gtk_widget_size_allocate(GTK_WIDGET(mContainer), &allocation);
++  }
++
++  gtk_widget_set_margin_left(GTK_WIDGET(mContainer), mDecorationSize.left);
++  gtk_widget_set_margin_right(GTK_WIDGET(mContainer), mDecorationSize.right);
++  gtk_widget_set_margin_top(GTK_WIDGET(mContainer), mDecorationSize.top);
++  gtk_widget_set_margin_bottom(GTK_WIDGET(mContainer), mDecorationSize.bottom);
++}
++
++void
++nsWindow::ApplyCSDClipping()
++{
++  if (IsClientDecorated()) {
++      gint top, right, bottom, left;
++      moz_gtk_get_header_bar_border(&top, &right, &bottom, &left);
++      cairo_rectangle_int_t rect = { 0, top, mBounds.width, mBounds.height};
++      cairo_region_t *region = cairo_region_create_rectangle(&rect);
++      gdk_window_shape_combine_region(mGdkWindow, region, 0, 0);
++      cairo_region_destroy(region);
++  } else {
++      gdk_window_shape_combine_region(mGdkWindow, nullptr, 0, 0);
++  }
++}
++
++bool
++nsWindow::CheckResizerEdge(LayoutDeviceIntPoint aPoint, GdkWindowEdge& aOutEdge)
++{
++  gint scale = GdkScaleFactor();
++  gint left = scale * mDecorationSize.left;
++  gint top = scale * mDecorationSize.top;
++  gint right = scale * mDecorationSize.right;
++  gint bottom = scale * mDecorationSize.bottom;
++
++  int resizerSize = GetClientResizerSize();
++  int topDist = aPoint.y;
++  int leftDist = aPoint.x;
++  int rightDist = mBounds.width - aPoint.x;
++  int bottomDist = mBounds.height - aPoint.y;
++
++  //TODO -> wrong sizes
++
++  if (leftDist <= resizerSize && topDist <= resizerSize) {
++    aOutEdge = GDK_WINDOW_EDGE_NORTH_WEST;
++  } else if (rightDist <= resizerSize && topDist <= resizerSize) {
++    aOutEdge = GDK_WINDOW_EDGE_NORTH_EAST;
++  } else if (leftDist <= resizerSize && bottomDist <= resizerSize) {
++    aOutEdge = GDK_WINDOW_EDGE_SOUTH_WEST;
++  } else if (rightDist <= resizerSize && bottomDist <= resizerSize) {
++    aOutEdge = GDK_WINDOW_EDGE_SOUTH_EAST;
++  } else if (topDist <= top) {
++    aOutEdge = GDK_WINDOW_EDGE_NORTH;
++  } else if (leftDist <= left) {
++    aOutEdge = GDK_WINDOW_EDGE_WEST;
++  } else if (rightDist <= right) {
++    aOutEdge = GDK_WINDOW_EDGE_EAST;
++  } else if (bottomDist <= bottom) {
++    aOutEdge = GDK_WINDOW_EDGE_SOUTH;
++  } else {
++    return false;
++  }
++  return true;
++}
++
+ int32_t
+ nsWindow::RoundsWidgetCoordinatesTo()
+ {
+diff -up firefox-57.0b8/widget/gtk/nsWindow.h.1399611 firefox-57.0b8/widget/gtk/nsWindow.h
+--- firefox-57.0b8/widget/gtk/nsWindow.h.1399611	2017-09-15 06:15:40.000000000 +0200
++++ firefox-57.0b8/widget/gtk/nsWindow.h	2017-10-16 12:11:45.369240636 +0200
+@@ -123,6 +123,7 @@ public:
+                                          double aHeight,
+                                          bool   aRepaint) override;
+     virtual bool       IsEnabled() const override;
++    bool               IsComposited() const;
+ 
+     void               SetZIndex(int32_t aZIndex) override;
+     virtual void       SetSizeMode(nsSizeMode aMode) override;
+@@ -351,6 +352,9 @@ public:
+ #endif
+     virtual void GetCompositorWidgetInitData(mozilla::widget::CompositorWidgetInitData* aInitData) override;
+ 
++    NS_IMETHOD SetNonClientMargins(LayoutDeviceIntMargin& aMargins) override;
++    void SetDrawsInTitlebar(bool aState) override;
++
+     // HiDPI scale conversion
+     gint GdkScaleFactor();
+ 
+@@ -367,6 +371,9 @@ public:
+     LayoutDeviceIntRect GdkRectToDevicePixels(GdkRectangle rect);
+ 
+     virtual bool WidgetTypeSupportsAcceleration() override;
++
++    // Decorations
++    bool IsClientDecorated() const;
+ protected:
+     virtual ~nsWindow();
+ 
+@@ -384,6 +391,16 @@ protected:
+ 
+     virtual void RegisterTouchWindow() override;
+ 
++    int GetClientResizerSize();
++
++    // Informs the window manager about the size of the shadows surrounding
++    // a client-side decorated window.
++    void UpdateClientDecorations();
++
++    // Returns true if the given point (in device pixels) is within a resizer
++    // region of the window. Only used when drawing decorations client side.
++    bool CheckResizerEdge(LayoutDeviceIntPoint aPoint, GdkWindowEdge& aOutEdge);
++
+     nsCOMPtr<nsIWidget> mParent;
+     // Is this a toplevel window?
+     bool                mIsTopLevel;
+@@ -432,12 +449,12 @@ private:
+                                    gint* aRootX, gint* aRootY);
+     void               ClearCachedResources();
+     nsIWidgetListener* GetListener();
+-    bool               IsComposited() const;
+-
++    void               ApplyCSDClipping();
+ 
+     GtkWidget          *mShell;
+     MozContainer       *mContainer;
+     GdkWindow          *mGdkWindow;
++    bool                mIsCSDEnabled;
+     PlatformCompositorWidgetDelegate* mCompositorWidgetDelegate;
+ 
+ 
+@@ -536,6 +553,10 @@ private:
+     // leaving fullscreen
+     nsSizeMode         mLastSizeMode;
+ 
++    // If true, draw our own window decorations (where supported).
++    bool              mDrawWindowDecoration;
++    GtkBorder         mDecorationSize;
++
+     static bool DragInProgress(void);
+ 
+     void DispatchMissedButtonReleases(GdkEventCrossing *aGdkEvent);
+@@ -567,6 +588,17 @@ private:
+     RefPtr<mozilla::widget::IMContextWrapper> mIMContext;
+ 
+     mozilla::UniquePtr<mozilla::CurrentX11TimeGetter> mCurrentTimeGetter;
++    typedef enum { CSD_SUPPORT_FULL,    // CSD including shadows
++                   CSD_SUPPORT_FLAT,    // CSD without shadows
++                   CSD_SUPPORT_NONE,    // WM does not support CSD at all
++                   CSD_SUPPORT_UNKNOWN
++    } CSDSupportLevel;
++    /**
++     * Get the support of Client Side Decoration by checking
++     * the XDG_CURRENT_DESKTOP environment variable.
++     */
++    CSDSupportLevel GetCSDSupportLevel();
++    CSDSupportLevel mCSDSupportLevel;
+ };
+ 
+ #endif /* __nsWindow_h__ */
+diff -up firefox-57.0b8/widget/gtk/WidgetStyleCache.cpp.1399611 firefox-57.0b8/widget/gtk/WidgetStyleCache.cpp
+--- firefox-57.0b8/widget/gtk/WidgetStyleCache.cpp.1399611	2017-09-15 06:15:40.000000000 +0200
++++ firefox-57.0b8/widget/gtk/WidgetStyleCache.cpp	2017-10-16 12:11:45.369240636 +0200
+@@ -26,10 +26,14 @@ static GtkStyleContext*
+ GetCssNodeStyleInternal(WidgetNodeType aNodeType);
+ 
+ static GtkWidget*
+-CreateWindowWidget()
++CreateWindowWidget(WidgetNodeType type)
+ {
+   GtkWidget *widget = gtk_window_new(GTK_WINDOW_POPUP);
+   gtk_widget_set_name(widget, "MozillaGtkWidget");
++  if (type == MOZ_GTK_WINDOW_CSD) {
++      GtkStyleContext* style = gtk_widget_get_style_context(widget);
++      gtk_style_context_add_class(style, "csd");
++  }
+   return widget;
+ }
+ 
+@@ -101,7 +105,7 @@ CreateTooltipWidget()
+ {
+   MOZ_ASSERT(gtk_check_version(3, 20, 0) != nullptr,
+              "CreateTooltipWidget should be used for Gtk < 3.20 only.");
+-  GtkWidget* widget = CreateWindowWidget();
++  GtkWidget* widget = CreateWindowWidget(MOZ_GTK_WINDOW);
+   GtkStyleContext* style = gtk_widget_get_style_context(widget);
+   gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLTIP);
+   return widget;
+@@ -529,11 +533,82 @@ CreateNotebookWidget()
+ }
+ 
+ static GtkWidget*
++CreateHeaderBar(bool aMaximized)
++{
++  MOZ_ASSERT(gtk_check_version(3, 10, 0) == nullptr,
++             "GtkHeaderBar is only available on GTK 3.10+.");
++  if (gtk_check_version(3, 10, 0) != nullptr)
++    return nullptr;
++
++  static auto sGtkHeaderBarNewPtr = (GtkWidget* (*)())
++    dlsym(RTLD_DEFAULT, "gtk_header_bar_new");
++  static const char* MOZ_GTK_STYLE_CLASS_TITLEBAR = "titlebar";
++
++  GtkWidget* headerbar = sGtkHeaderBarNewPtr();
++  if (aMaximized) {
++    GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
++    gtk_widget_set_name(window, "MozillaMaximizedGtkWidget");
++    GtkStyleContext* style = gtk_widget_get_style_context(window);
++    gtk_style_context_add_class(style, "maximized");
++    GtkWidget *fixed = gtk_fixed_new();
++    gtk_container_add(GTK_CONTAINER(window), fixed);
++    gtk_container_add(GTK_CONTAINER(fixed), headerbar);
++    // Save the window container so we don't leak it.
++    sWidgetStorage[MOZ_GTK_WINDOW_MAXIMIZED] = window;
++  } else {
++    AddToWindowContainer(headerbar);
++  }
++
++  // Emulate what create_titlebar() at gtkwindow.c does.
++  GtkStyleContext* style = gtk_widget_get_style_context(headerbar);
++  gtk_style_context_add_class(style, MOZ_GTK_STYLE_CLASS_TITLEBAR);
++  gtk_style_context_add_class(style, "default-decoration");
++
++  return headerbar;
++}
++
++// TODO - Also return style for buttons located at Maximized toolbar.
++static GtkWidget*
++CreateHeaderBarButton(WidgetNodeType aWidgetType)
++{
++  MOZ_ASSERT(gtk_check_version(3, 10, 0) == nullptr,
++             "GtkHeaderBar is only available on GTK 3.10+.");
++
++  if (gtk_check_version(3, 10, 0) != nullptr)
++    return nullptr;
++
++  static const char* MOZ_GTK_STYLE_CLASS_TITLEBUTTON = "titlebutton";
++
++  GtkWidget* widget = gtk_button_new();
++  gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_HEADER_BAR)), widget);
++
++  GtkStyleContext* style = gtk_widget_get_style_context(widget);
++  gtk_style_context_add_class(style, MOZ_GTK_STYLE_CLASS_TITLEBUTTON);
++
++  switch (aWidgetType) {
++    case MOZ_GTK_HEADER_BAR_BUTTON_CLOSE:
++      gtk_style_context_add_class(style, "close");
++      break;
++    case MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE:
++      gtk_style_context_add_class(style, "minimize");
++      break;
++    case MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE:
++      gtk_style_context_add_class(style, "maximize");
++      break;
++    default:
++      break;
++  }
++
++  return widget;
++}
++
++static GtkWidget*
+ CreateWidget(WidgetNodeType aWidgetType)
+ {
+   switch (aWidgetType) {
+     case MOZ_GTK_WINDOW:
+-      return CreateWindowWidget();
++    case MOZ_GTK_WINDOW_CSD:
++      return CreateWindowWidget(aWidgetType);
+     case MOZ_GTK_WINDOW_CONTAINER:
+       return CreateWindowContainerWidget();
+     case MOZ_GTK_CHECKBUTTON_CONTAINER:
+@@ -610,6 +685,13 @@ CreateWidget(WidgetNodeType aWidgetType)
+       return CreateComboBoxEntryButtonWidget();
+     case MOZ_GTK_COMBOBOX_ENTRY_ARROW:
+       return CreateComboBoxEntryArrowWidget();
++    case MOZ_GTK_HEADER_BAR:
++    case MOZ_GTK_HEADER_BAR_MAXIMIZED:
++      return CreateHeaderBar(aWidgetType == MOZ_GTK_HEADER_BAR_MAXIMIZED);
++    case MOZ_GTK_HEADER_BAR_BUTTON_CLOSE:
++    case MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE:
++    case MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE:
++      return CreateHeaderBarButton(aWidgetType);
+     default:
+       /* Not implemented */
+       return nullptr;
+@@ -1049,6 +1131,10 @@ GetCssNodeStyleInternal(WidgetNodeType a
+       GtkWidget* widget = GetWidget(MOZ_GTK_NOTEBOOK);
+       return gtk_widget_get_style_context(widget);
+     }
++    case MOZ_GTK_WINDOW_DECORATION:
++      style = CreateChildCSSNode("decoration",
++                                 MOZ_GTK_WINDOW_CSD);
++      break;
+     default:
+       return GetWidgetRootStyle(aNodeType);
+   }
+@@ -1214,6 +1300,8 @@ ResetWidgetCache(void)
+   /* This will destroy all of our widgets */
+   if (sWidgetStorage[MOZ_GTK_WINDOW])
+     gtk_widget_destroy(sWidgetStorage[MOZ_GTK_WINDOW]);
++  if (sWidgetStorage[MOZ_GTK_WINDOW_MAXIMIZED])
++    gtk_widget_destroy(sWidgetStorage[MOZ_GTK_WINDOW_MAXIMIZED]);
+ 
+   /* Clear already freed arrays */
+   mozilla::PodArrayZero(sWidgetStorage);
+diff -up firefox-57.0b8/widget/LookAndFeel.h.1399611 firefox-57.0b8/widget/LookAndFeel.h
+--- firefox-57.0b8/widget/LookAndFeel.h.1399611	2017-09-16 18:22:54.000000000 +0200
++++ firefox-57.0b8/widget/LookAndFeel.h	2017-10-16 12:11:45.369240636 +0200
+@@ -405,6 +405,30 @@ public:
+      eIntID_PhysicalHomeButton,
+ 
+      /*
++      * A boolean value indicating whether client-side decorations are
++      * supported by the user's GTK version.
++      */
++     eIntID_GTKCSDAvailable,
++
++     /*
++      * A boolean value indicating whether client-side decorations should
++      * contain a minimize button.
++      */
++     eIntID_GTKCSDMinimizeButton,
++
++     /*
++      * A boolean value indicating whether client-side decorations should
++      * contain a maximize button.
++      */
++     eIntID_GTKCSDMaximizeButton,
++
++     /*
++      * A boolean value indicating whether client-side decorations should
++      * contain a close button.
++      */
++     eIntID_GTKCSDCloseButton,
++
++     /*
+       * Controls whether overlay scrollbars display when the user moves
+       * the mouse in a scrollable frame.
+       */
--- a/mozilla-kde.patch	Sat Nov 11 10:08:36 2017 +0100
+++ b/mozilla-kde.patch	Wed Jan 10 22:27:13 2018 +0100
@@ -1,5 +1,5 @@
 # HG changeset patch
-# Parent  87a32e5d11e9d652e331a5f852bb951069b20c4a
+# Parent  2504512f9a9ba7b52dd99745d15f049f2a03f4f4
 Description: Add KDE integration to Firefox (toolkit parts)
 Author: Wolfgang Rosenauer <wolfgang@rosenauer.org>
 Author: Lubos Lunak <lunak@suse.com>
@@ -3275,7 +3275,7 @@
  
    mFilters.AppendElement(filter);
    mFilterNames.AppendElement(name);
-@@ -371,16 +375,37 @@ nsFilePicker::Show(int16_t *aReturn)
+@@ -371,16 +375,39 @@ nsFilePicker::Show(int16_t *aReturn)
  
  NS_IMETHODIMP
  nsFilePicker::Open(nsIFilePickerShownCallback *aCallback)
@@ -3288,6 +3288,7 @@
 +  if( nsKDEUtils::kdeSupport()) {
 +    mCallback = aCallback;
 +    mRunning = true;
++    NS_ADDREF_THIS();
 +    g_idle_add([](gpointer data) -> gboolean {
 +      nsFilePicker* queuedPicker = (nsFilePicker*) data;
 +      int16_t result;
@@ -3299,6 +3300,7 @@
 +        queuedPicker->mResult = result;
 +      }
 +      queuedPicker->mRunning = false;
++      NS_RELEASE(queuedPicker);
 +      return G_SOURCE_REMOVE;
 +    }, this);
 +
@@ -3313,7 +3315,7 @@
  
    GtkFileChooserAction action = GetGtkFileChooserAction(mMode);
  
-@@ -603,8 +628,233 @@ nsFilePicker::Done(GtkWidget* file_choos
+@@ -603,8 +630,233 @@ nsFilePicker::Done(GtkWidget* file_choos
    if (mCallback) {
      mCallback->Done(result);
      mCallback = nullptr;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mozilla-rust-1.23.patch	Wed Jan 10 22:27:13 2018 +0100
@@ -0,0 +1,1083 @@
+
+# HG changeset patch
+# User Simon Sapin <simon.sapin@exyr.org>
+# Date 1510231769 21600
+# Node ID 3242ac6fdb3879f723145e6b07fff04a5c960d1e
+# Parent  bf63b9d8f2410464d5f2526588e380f934e937cc
+servo: Merge #19162 - Allow unused imports for AsciiExt in style code (from emilio:ascii-ext); r=emilio
+
+See #19128, this part is cherry-picked so Gecko can build with rust nightly.
+
+Source-Repo: https://github.com/servo/servo
+Source-Revision: e7a654dd13f589e127193267bcb576ffd661c11d
+
+diff --git a/servo/components/gfx/font.rs b/servo/components/gfx/font.rs
+--- a/servo/components/gfx/font.rs
++++ b/servo/components/gfx/font.rs
+@@ -5,17 +5,17 @@
+ use app_units::Au;
+ use euclid::{Point2D, Rect, Size2D};
+ use font_template::FontTemplateDescriptor;
+ use ordered_float::NotNaN;
+ use platform::font::{FontHandle, FontTable};
+ use platform::font_context::FontContextHandle;
+ use platform::font_template::FontTemplateData;
+ use smallvec::SmallVec;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::ToOwned;
+ use std::cell::RefCell;
+ use std::collections::HashMap;
+ use std::rc::Rc;
+ use std::str;
+ use std::sync::Arc;
+ use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
+ use style::computed_values::{font_stretch, font_variant_caps, font_weight};
+diff --git a/servo/components/net/fetch/cors_cache.rs b/servo/components/net/fetch/cors_cache.rs
+--- a/servo/components/net/fetch/cors_cache.rs
++++ b/servo/components/net/fetch/cors_cache.rs
+@@ -7,17 +7,17 @@
+ //! For stuff involving `<img>`, `<iframe>`, `<form>`, etc please check what
+ //! the request mode should be and compare with the fetch spec
+ //! This library will eventually become the core of the Fetch crate
+ //! with CORSRequest being expanded into FetchRequest (etc)
+ 
+ use hyper::method::Method;
+ use net_traits::request::{CredentialsMode, Origin, Request};
+ use servo_url::ServoUrl;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use time::{self, Timespec};
+ 
+ /// Union type for CORS cache entries
+ ///
+ /// Each entry might pertain to a header or method
+ #[derive(Clone, Debug)]
+ pub enum HeaderOrMethod {
+     HeaderData(String),
+diff --git a/servo/components/net/fetch/methods.rs b/servo/components/net/fetch/methods.rs
+--- a/servo/components/net/fetch/methods.rs
++++ b/servo/components/net/fetch/methods.rs
+@@ -16,17 +16,17 @@ use hyper::method::Method;
+ use hyper::mime::{Mime, SubLevel, TopLevel};
+ use hyper::status::StatusCode;
+ use mime_guess::guess_mime_type;
+ use net_traits::{FetchTaskTarget, NetworkError, ReferrerPolicy};
+ use net_traits::request::{CredentialsMode, Referrer, Request, RequestMode, ResponseTainting};
+ use net_traits::request::{Type, Origin, Window};
+ use net_traits::response::{Response, ResponseBody, ResponseType};
+ use servo_url::ServoUrl;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::Cow;
+ use std::fmt;
+ use std::fs::File;
+ use std::io::Read;
+ use std::mem;
+ use std::str;
+ use std::sync::Arc;
+ use std::sync::mpsc::{Sender, Receiver};
+diff --git a/servo/components/net/http_loader.rs b/servo/components/net/http_loader.rs
+--- a/servo/components/net/http_loader.rs
++++ b/servo/components/net/http_loader.rs
+@@ -34,17 +34,17 @@ use log;
+ use msg::constellation_msg::PipelineId;
+ use net_traits::{CookieSource, FetchMetadata, NetworkError, ReferrerPolicy};
+ use net_traits::request::{CacheMode, CredentialsMode, Destination, Origin};
+ use net_traits::request::{RedirectMode, Referrer, Request, RequestMode};
+ use net_traits::request::{ResponseTainting, ServiceWorkersMode, Type};
+ use net_traits::response::{HttpsState, Response, ResponseBody, ResponseType};
+ use resource_thread::AuthCache;
+ use servo_url::{ImmutableOrigin, ServoUrl};
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::collections::HashSet;
+ use std::error::Error;
+ use std::io::{self, Read, Write};
+ use std::iter::FromIterator;
+ use std::mem;
+ use std::ops::Deref;
+ use std::sync::RwLock;
+ use std::sync::mpsc::{channel, Sender};
+diff --git a/servo/components/net/websocket_loader.rs b/servo/components/net/websocket_loader.rs
+--- a/servo/components/net/websocket_loader.rs
++++ b/servo/components/net/websocket_loader.rs
+@@ -14,17 +14,17 @@ use hyper::http::h1::{LINE_ENDING, parse
+ use hyper::method::Method;
+ use hyper::net::HttpStream;
+ use hyper::status::StatusCode;
+ use hyper::version::HttpVersion;
+ use net_traits::{CookieSource, MessageData, NetworkError, WebSocketCommunicate, WebSocketConnectData};
+ use net_traits::{WebSocketDomAction, WebSocketNetworkEvent};
+ use net_traits::request::{Destination, Type};
+ use servo_url::ServoUrl;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::io::{self, Write};
+ use std::net::TcpStream;
+ use std::sync::{Arc, Mutex};
+ use std::sync::atomic::{AtomicBool, Ordering};
+ use std::thread;
+ use url::Position;
+ use websocket::{Message, Receiver as WSReceiver, Sender as WSSender};
+ use websocket::header::{Origin, WebSocketAccept, WebSocketKey, WebSocketProtocol, WebSocketVersion};
+diff --git a/servo/components/net_traits/response.rs b/servo/components/net_traits/response.rs
+--- a/servo/components/net_traits/response.rs
++++ b/servo/components/net_traits/response.rs
+@@ -4,17 +4,17 @@
+ 
+ //! The [Response](https://fetch.spec.whatwg.org/#responses) object
+ //! resulting from a [fetch operation](https://fetch.spec.whatwg.org/#concept-fetch)
+ use {FetchMetadata, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy};
+ use hyper::header::{AccessControlExposeHeaders, ContentType, Headers};
+ use hyper::status::StatusCode;
+ use hyper_serde::Serde;
+ use servo_url::ServoUrl;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::sync::{Arc, Mutex};
+ 
+ /// [Response type](https://fetch.spec.whatwg.org/#concept-response-type)
+ #[derive(Clone, Debug, Deserialize, HeapSizeOf, PartialEq, Serialize)]
+ pub enum ResponseType {
+     Basic,
+     Cors,
+     Default,
+diff --git a/servo/components/script/dom/bindings/str.rs b/servo/components/script/dom/bindings/str.rs
+--- a/servo/components/script/dom/bindings/str.rs
++++ b/servo/components/script/dom/bindings/str.rs
+@@ -2,17 +2,17 @@
+  * 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/. */
+ 
+ //! The `ByteString` struct.
+ 
+ use cssparser::CowRcStr;
+ use html5ever::{LocalName, Namespace};
+ use servo_atoms::Atom;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::{Borrow, Cow, ToOwned};
+ use std::fmt;
+ use std::hash::{Hash, Hasher};
+ use std::marker::PhantomData;
+ use std::ops;
+ use std::ops::{Deref, DerefMut};
+ use std::str;
+ use std::str::{Bytes, FromStr};
+diff --git a/servo/components/script/dom/blob.rs b/servo/components/script/dom/blob.rs
+--- a/servo/components/script/dom/blob.rs
++++ b/servo/components/script/dom/blob.rs
+@@ -11,17 +11,17 @@ use dom::bindings::js::{JS, Root};
+ use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
+ use dom::bindings::str::DOMString;
+ use dom::globalscope::GlobalScope;
+ use dom_struct::dom_struct;
+ use ipc_channel::ipc;
+ use net_traits::{CoreResourceMsg, IpcSend};
+ use net_traits::blob_url_store::{BlobBuf, get_blob_origin};
+ use net_traits::filemanager_thread::{FileManagerThreadMsg, ReadFileProgress, RelativePos};
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::mem;
+ use std::ops::Index;
+ use std::path::PathBuf;
+ use uuid::Uuid;
+ 
+ /// File-based blob
+ #[derive(JSTraceable)]
+ pub struct FileBlob {
+diff --git a/servo/components/script/dom/cssstyledeclaration.rs b/servo/components/script/dom/cssstyledeclaration.rs
+--- a/servo/components/script/dom/cssstyledeclaration.rs
++++ b/servo/components/script/dom/cssstyledeclaration.rs
+@@ -11,17 +11,17 @@ use dom::bindings::reflector::{DomObject
+ use dom::bindings::str::DOMString;
+ use dom::cssrule::CSSRule;
+ use dom::element::Element;
+ use dom::node::{Node, window_from_node, document_from_node};
+ use dom::window::Window;
+ use dom_struct::dom_struct;
+ use servo_arc::Arc;
+ use servo_url::ServoUrl;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use style::attr::AttrValue;
+ use style::properties::{Importance, PropertyDeclarationBlock, PropertyId, LonghandId, ShorthandId};
+ use style::properties::{parse_one_declaration_into, parse_style_attribute, SourcePropertyDeclaration};
+ use style::selector_parser::PseudoElement;
+ use style::shared_lock::Locked;
+ use style_traits::{PARSING_MODE_DEFAULT, ToCss};
+ 
+ // http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
+diff --git a/servo/components/script/dom/document.rs b/servo/components/script/dom/document.rs
+--- a/servo/components/script/dom/document.rs
++++ b/servo/components/script/dom/document.rs
+@@ -118,17 +118,17 @@ use script_traits::{AnimationState, Comp
+ use script_traits::{MouseButton, MouseEventType, MozBrowserEvent};
+ use script_traits::{MsDuration, ScriptMsg, TouchpadPressurePhase};
+ use script_traits::{TouchEventType, TouchId};
+ use script_traits::UntrustedNodeAddress;
+ use servo_arc::Arc;
+ use servo_atoms::Atom;
+ use servo_config::prefs::PREFS;
+ use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::ToOwned;
+ use std::cell::{Cell, Ref, RefMut};
+ use std::collections::{HashMap, HashSet, VecDeque};
+ use std::collections::hash_map::Entry::{Occupied, Vacant};
+ use std::default::Default;
+ use std::iter::once;
+ use std::mem;
+ use std::rc::Rc;
+diff --git a/servo/components/script/dom/element.rs b/servo/components/script/dom/element.rs
+--- a/servo/components/script/dom/element.rs
++++ b/servo/components/script/dom/element.rs
+@@ -90,17 +90,17 @@ use script_layout_interface::message::Re
+ use script_thread::ScriptThread;
+ use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
+ use selectors::matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext, MatchingMode};
+ use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
+ use selectors::matching::{RelevantLinkStatus, matches_selector_list};
+ use selectors::sink::Push;
+ use servo_arc::Arc;
+ use servo_atoms::Atom;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::Cow;
+ use std::cell::{Cell, Ref};
+ use std::convert::TryFrom;
+ use std::default::Default;
+ use std::fmt;
+ use std::mem;
+ use std::rc::Rc;
+ use style::CaseSensitivityExt;
+diff --git a/servo/components/script/dom/htmlelement.rs b/servo/components/script/dom/htmlelement.rs
+--- a/servo/components/script/dom/htmlelement.rs
++++ b/servo/components/script/dom/htmlelement.rs
+@@ -25,17 +25,17 @@ use dom::htmlhtmlelement::HTMLHtmlElemen
+ use dom::htmlinputelement::HTMLInputElement;
+ use dom::htmllabelelement::HTMLLabelElement;
+ use dom::node::{Node, SEQUENTIALLY_FOCUSABLE};
+ use dom::node::{document_from_node, window_from_node};
+ use dom::nodelist::NodeList;
+ use dom::virtualmethods::VirtualMethods;
+ use dom_struct::dom_struct;
+ use html5ever::{LocalName, Prefix};
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::default::Default;
+ use std::rc::Rc;
+ use style::attr::AttrValue;
+ use style::element_state::*;
+ 
+ #[dom_struct]
+ pub struct HTMLElement {
+     element: Element,
+diff --git a/servo/components/script/dom/htmllinkelement.rs b/servo/components/script/dom/htmllinkelement.rs
+--- a/servo/components/script/dom/htmllinkelement.rs
++++ b/servo/components/script/dom/htmllinkelement.rs
+@@ -21,17 +21,17 @@ use dom::htmlelement::HTMLElement;
+ use dom::node::{Node, UnbindContext, document_from_node, window_from_node};
+ use dom::stylesheet::StyleSheet as DOMStyleSheet;
+ use dom::virtualmethods::VirtualMethods;
+ use dom_struct::dom_struct;
+ use html5ever::{LocalName, Prefix};
+ use net_traits::ReferrerPolicy;
+ use script_traits::{MozBrowserEvent, ScriptMsg};
+ use servo_arc::Arc;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::ToOwned;
+ use std::cell::Cell;
+ use std::default::Default;
+ use style::attr::AttrValue;
+ use style::media_queries::parse_media_query_list;
+ use style::parser::ParserContext as CssParserContext;
+ use style::str::HTML_SPACE_CHARACTERS;
+ use style::stylesheets::{CssRuleType, Stylesheet};
+diff --git a/servo/components/script/dom/htmlmetaelement.rs b/servo/components/script/dom/htmlmetaelement.rs
+--- a/servo/components/script/dom/htmlmetaelement.rs
++++ b/servo/components/script/dom/htmlmetaelement.rs
+@@ -17,17 +17,17 @@ use dom::htmlelement::HTMLElement;
+ use dom::htmlheadelement::HTMLHeadElement;
+ use dom::node::{Node, UnbindContext, document_from_node, window_from_node};
+ use dom::virtualmethods::VirtualMethods;
+ use dom_struct::dom_struct;
+ use html5ever::{LocalName, Prefix};
+ use parking_lot::RwLock;
+ use servo_arc::Arc;
+ use servo_config::prefs::PREFS;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::sync::atomic::AtomicBool;
+ use style::attr::AttrValue;
+ use style::media_queries::MediaList;
+ use style::str::HTML_SPACE_CHARACTERS;
+ use style::stylesheets::{Stylesheet, StylesheetContents, CssRule, CssRules, Origin, ViewportRule};
+ 
+ #[dom_struct]
+ pub struct HTMLMetaElement {
+diff --git a/servo/components/script/dom/htmlscriptelement.rs b/servo/components/script/dom/htmlscriptelement.rs
+--- a/servo/components/script/dom/htmlscriptelement.rs
++++ b/servo/components/script/dom/htmlscriptelement.rs
+@@ -31,17 +31,17 @@ use ipc_channel::ipc;
+ use ipc_channel::router::ROUTER;
+ use js::jsval::UndefinedValue;
+ use net_traits::{FetchMetadata, FetchResponseListener, Metadata, NetworkError};
+ use net_traits::request::{CorsSettings, CredentialsMode, Destination, RequestInit, RequestMode, Type as RequestType};
+ use network_listener::{NetworkListener, PreInvoke};
+ use servo_atoms::Atom;
+ use servo_config::opts;
+ use servo_url::ServoUrl;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::cell::Cell;
+ use std::fs::File;
+ use std::io::{Read, Write};
+ use std::path::PathBuf;
+ use std::process::{Command, Stdio};
+ use std::sync::{Arc, Mutex};
+ use style::str::{HTML_SPACE_CHARACTERS, StaticStringVec};
+ use uuid::Uuid;
+diff --git a/servo/components/script/dom/macros.rs b/servo/components/script/dom/macros.rs
+--- a/servo/components/script/dom/macros.rs
++++ b/servo/components/script/dom/macros.rs
+@@ -144,17 +144,17 @@ macro_rules! make_string_or_document_url
+ );
+ 
+ #[macro_export]
+ macro_rules! make_enumerated_getter(
+     ( $attr:ident, $htmlname:tt, $default:expr, $($choices: pat)|+) => (
+         fn $attr(&self) -> DOMString {
+             use dom::bindings::inheritance::Castable;
+             use dom::element::Element;
+-            use std::ascii::AsciiExt;
++            #[allow(unused_imports)] use std::ascii::AsciiExt;
+             let element = self.upcast::<Element>();
+             let mut val = element.get_string_attribute(&local_name!($htmlname));
+             val.make_ascii_lowercase();
+             // https://html.spec.whatwg.org/multipage/#attr-fs-method
+             match &*val {
+                 $($choices)|+ => val,
+                 _ => DOMString::from($default)
+             }
+diff --git a/servo/components/script/dom/namednodemap.rs b/servo/components/script/dom/namednodemap.rs
+--- a/servo/components/script/dom/namednodemap.rs
++++ b/servo/components/script/dom/namednodemap.rs
+@@ -10,17 +10,17 @@ use dom::bindings::error::{Error, Fallib
+ use dom::bindings::js::{JS, Root};
+ use dom::bindings::reflector::{Reflector, reflect_dom_object};
+ use dom::bindings::str::DOMString;
+ use dom::bindings::xmlname::namespace_from_domstring;
+ use dom::element::Element;
+ use dom::window::Window;
+ use dom_struct::dom_struct;
+ use html5ever::LocalName;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ 
+ #[dom_struct]
+ pub struct NamedNodeMap {
+     reflector_: Reflector,
+     owner: JS<Element>,
+ }
+ 
+ impl NamedNodeMap {
+diff --git a/servo/components/script/dom/serviceworkercontainer.rs b/servo/components/script/dom/serviceworkercontainer.rs
+--- a/servo/components/script/dom/serviceworkercontainer.rs
++++ b/servo/components/script/dom/serviceworkercontainer.rs
+@@ -11,17 +11,17 @@ use dom::bindings::str::USVString;
+ use dom::client::Client;
+ use dom::eventtarget::EventTarget;
+ use dom::globalscope::GlobalScope;
+ use dom::promise::Promise;
+ use dom::serviceworker::ServiceWorker;
+ use dom_struct::dom_struct;
+ use script_thread::ScriptThread;
+ use serviceworkerjob::{Job, JobType};
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::default::Default;
+ use std::rc::Rc;
+ 
+ #[dom_struct]
+ pub struct ServiceWorkerContainer {
+     eventtarget: EventTarget,
+     controller: MutNullableJS<ServiceWorker>,
+     client: JS<Client>
+diff --git a/servo/components/script/dom/servoparser/async_html.rs b/servo/components/script/dom/servoparser/async_html.rs
+--- a/servo/components/script/dom/servoparser/async_html.rs
++++ b/servo/components/script/dom/servoparser/async_html.rs
+@@ -22,17 +22,17 @@ use dom::virtualmethods::vtable_for;
+ use html5ever::{Attribute as HtmlAttribute, ExpandedName, LocalName, QualName};
+ use html5ever::buffer_queue::BufferQueue;
+ use html5ever::tendril::{SendTendril, StrTendril, Tendril};
+ use html5ever::tendril::fmt::UTF8;
+ use html5ever::tokenizer::{Tokenizer as HtmlTokenizer, TokenizerOpts, TokenizerResult};
+ use html5ever::tree_builder::{ElementFlags, NodeOrText as HtmlNodeOrText, NextParserState, QuirksMode, TreeSink};
+ use html5ever::tree_builder::{TreeBuilder, TreeBuilderOpts};
+ use servo_url::ServoUrl;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::Cow;
+ use std::cell::Cell;
+ use std::collections::HashMap;
+ use std::collections::vec_deque::VecDeque;
+ use std::sync::mpsc::{channel, Receiver, Sender};
+ use std::thread;
+ use style::context::QuirksMode as ServoQuirksMode;
+ 
+diff --git a/servo/components/script/dom/servoparser/mod.rs b/servo/components/script/dom/servoparser/mod.rs
+--- a/servo/components/script/dom/servoparser/mod.rs
++++ b/servo/components/script/dom/servoparser/mod.rs
+@@ -41,17 +41,17 @@ use net_traits::{FetchMetadata, FetchRes
+ use network_listener::PreInvoke;
+ use profile_traits::time::{TimerMetadata, TimerMetadataFrameType};
+ use profile_traits::time::{TimerMetadataReflowType, ProfilerCategory, profile};
+ use script_thread::ScriptThread;
+ use script_traits::DocumentActivity;
+ use servo_config::prefs::PREFS;
+ use servo_config::resource_files::read_resource_file;
+ use servo_url::ServoUrl;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::Cow;
+ use std::cell::Cell;
+ use std::mem;
+ use style::context::QuirksMode as ServoQuirksMode;
+ 
+ mod async_html;
+ mod html;
+ mod xml;
+diff --git a/servo/components/script/dom/websocket.rs b/servo/components/script/dom/websocket.rs
+--- a/servo/components/script/dom/websocket.rs
++++ b/servo/components/script/dom/websocket.rs
+@@ -27,17 +27,17 @@ use js::jsapi::JSAutoCompartment;
+ use js::jsval::UndefinedValue;
+ use js::typedarray::{ArrayBuffer, CreateWith};
+ use net_traits::{WebSocketCommunicate, WebSocketConnectData, WebSocketDomAction, WebSocketNetworkEvent};
+ use net_traits::CoreResourceMsg::WebsocketConnect;
+ use net_traits::MessageData;
+ use script_runtime::CommonScriptMsg;
+ use script_runtime::ScriptThreadEventCategory::WebSocketEvent;
+ use servo_url::ServoUrl;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::ToOwned;
+ use std::cell::Cell;
+ use std::ptr;
+ use std::thread;
+ use task::{TaskOnce, TaskCanceller};
+ use task_source::TaskSource;
+ use task_source::networking::NetworkingTaskSource;
+ 
+diff --git a/servo/components/script/dom/window.rs b/servo/components/script/dom/window.rs
+--- a/servo/components/script/dom/window.rs
++++ b/servo/components/script/dom/window.rs
+@@ -82,17 +82,17 @@ use script_traits::{ConstellationControl
+ use script_traits::{ScriptToConstellationChan, ScriptMsg, ScrollState, TimerEvent, TimerEventId};
+ use script_traits::{TimerSchedulerMsg, UntrustedNodeAddress, WindowSizeData, WindowSizeType};
+ use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
+ use selectors::attr::CaseSensitivity;
+ use servo_config::opts;
+ use servo_config::prefs::PREFS;
+ use servo_geometry::{f32_rect_to_au_rect, max_rect};
+ use servo_url::{Host, MutableOrigin, ImmutableOrigin, ServoUrl};
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::ToOwned;
+ use std::cell::Cell;
+ use std::collections::{HashMap, HashSet};
+ use std::collections::hash_map::Entry;
+ use std::default::Default;
+ use std::env;
+ use std::fs;
+ use std::io::{Write, stderr, stdout};
+diff --git a/servo/components/script/dom/xmlhttprequest.rs b/servo/components/script/dom/xmlhttprequest.rs
+--- a/servo/components/script/dom/xmlhttprequest.rs
++++ b/servo/components/script/dom/xmlhttprequest.rs
+@@ -57,17 +57,17 @@ use net_traits::{FetchResponseListener, 
+ use net_traits::CoreResourceMsg::Fetch;
+ use net_traits::request::{CredentialsMode, Destination, RequestInit, RequestMode};
+ use net_traits::trim_http_whitespace;
+ use network_listener::{NetworkListener, PreInvoke};
+ use script_traits::DocumentActivity;
+ use servo_atoms::Atom;
+ use servo_config::prefs::PREFS;
+ use servo_url::ServoUrl;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::ToOwned;
+ use std::cell::Cell;
+ use std::default::Default;
+ use std::str;
+ use std::sync::{Arc, Mutex};
+ use task_source::networking::NetworkingTaskSource;
+ use time;
+ use timers::{OneshotTimerCallback, OneshotTimerHandle};
+diff --git a/servo/components/selectors/attr.rs b/servo/components/selectors/attr.rs
+--- a/servo/components/selectors/attr.rs
++++ b/servo/components/selectors/attr.rs
+@@ -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/. */
+ 
+ use cssparser::ToCss;
+ use parser::SelectorImpl;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] #[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::fmt;
+ 
+ #[derive(Clone, Eq, PartialEq)]
+ pub struct AttrSelectorWithNamespace<Impl: SelectorImpl> {
+     pub namespace: NamespaceConstraint<(Impl::NamespacePrefix, Impl::NamespaceUrl)>,
+     pub local_name: Impl::LocalName,
+     pub local_name_lower: Impl::LocalName,
+     pub operation: ParsedAttrSelectorOperation<Impl::AttrValue>,
+diff --git a/servo/components/selectors/parser.rs b/servo/components/selectors/parser.rs
+--- a/servo/components/selectors/parser.rs
++++ b/servo/components/selectors/parser.rs
+@@ -8,17 +8,17 @@ use bloom::BLOOM_HASH_MASK;
+ use builder::{SelectorBuilder, SpecificityAndFlags};
+ use context::QuirksMode;
+ use cssparser::{ParseError, BasicParseError, CowRcStr, Delimiter};
+ use cssparser::{Token, Parser as CssParser, parse_nth, ToCss, serialize_identifier, CssStringWriter};
+ use precomputed_hash::PrecomputedHash;
+ use servo_arc::ThinArc;
+ use sink::Push;
+ use smallvec::SmallVec;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::{Borrow, Cow};
+ use std::fmt::{self, Display, Debug, Write};
+ use std::iter::Rev;
+ use std::slice;
+ use visitor::SelectorVisitor;
+ 
+ /// A trait that represents a pseudo-element.
+ pub trait PseudoElement : Sized + ToCss {
+diff --git a/servo/components/style/attr.rs b/servo/components/style/attr.rs
+--- a/servo/components/style/attr.rs
++++ b/servo/components/style/attr.rs
+@@ -11,17 +11,17 @@ use app_units::Au;
+ use cssparser::{self, Color, RGBA};
+ use euclid::num::Zero;
+ use num_traits::ToPrimitive;
+ use properties::PropertyDeclarationBlock;
+ use selectors::attr::AttrSelectorOperation;
+ use servo_arc::Arc;
+ use servo_url::ServoUrl;
+ use shared_lock::Locked;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] #[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::str::FromStr;
+ use str::{HTML_SPACE_CHARACTERS, read_exponent, read_fraction};
+ use str::{read_numbers, split_commas, split_html_space_chars};
+ use str::str_join;
+ use values::specified::Length;
+ 
+ // Duplicated from script::dom::values.
+ const UNSIGNED_LONG_MAX: u32 = 2147483647;
+diff --git a/servo/components/style/counter_style/mod.rs b/servo/components/style/counter_style/mod.rs
+--- a/servo/components/style/counter_style/mod.rs
++++ b/servo/components/style/counter_style/mod.rs
+@@ -10,17 +10,17 @@ use Atom;
+ use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser};
+ use cssparser::{Parser, Token, serialize_identifier, BasicParseError, CowRcStr};
+ use error_reporting::{ContextualParseError, ParseErrorReporter};
+ #[cfg(feature = "gecko")] use gecko::rules::CounterStyleDescriptors;
+ #[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSCounterDesc;
+ use parser::{ParserContext, ParserErrorContext, Parse};
+ use selectors::parser::SelectorParseError;
+ use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::Cow;
+ use std::fmt;
+ use std::ops::Range;
+ use style_traits::{Comma, OneOrMoreSeparated, ParseError, StyleParseError, ToCss};
+ use values::CustomIdent;
+ 
+ /// Parse the prelude of an @counter-style rule
+ pub fn parse_counter_style_name<'i, 't>(input: &mut Parser<'i, 't>) -> Result<CustomIdent, ParseError<'i>> {
+diff --git a/servo/components/style/custom_properties.rs b/servo/components/style/custom_properties.rs
+--- a/servo/components/style/custom_properties.rs
++++ b/servo/components/style/custom_properties.rs
+@@ -9,17 +9,17 @@
+ use Atom;
+ use cssparser::{Delimiter, Parser, ParserInput, SourcePosition, Token, TokenSerializationType};
+ use parser::ParserContext;
+ use precomputed_hash::PrecomputedHash;
+ use properties::{CSSWideKeyword, DeclaredValue};
+ use selector_map::{PrecomputedHashSet, PrecomputedHashMap};
+ use selectors::parser::SelectorParseError;
+ use servo_arc::Arc;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::{Borrow, Cow};
+ use std::fmt;
+ use std::hash::Hash;
+ use style_traits::{ToCss, StyleParseError, ParseError};
+ 
+ /// A custom property name is just an `Atom`.
+ ///
+ /// Note that this does not include the `--` prefix
+diff --git a/servo/components/style/gecko/generated/pseudo_element_definition.rs b/servo/components/style/gecko/generated/pseudo_element_definition.rs
+--- a/servo/components/style/gecko/generated/pseudo_element_definition.rs
++++ b/servo/components/style/gecko/generated/pseudo_element_definition.rs
+@@ -1262,17 +1262,17 @@ None
+     /// user-agent stylesheet.
+     ///
+     /// If we're not in a user-agent stylesheet, we will never parse anonymous
+     /// box pseudo-elements.
+     ///
+     /// Returns `None` if the pseudo-element is not recognised.
+     #[inline]
+     pub fn from_slice(s: &str, in_ua_stylesheet: bool) -> Option<Self> {
+-        use std::ascii::AsciiExt;
++        #[allow(unused_imports)] #[allow(unused_imports)] use std::ascii::AsciiExt;
+ 
+         // We don't need to support tree pseudos because functional
+         // pseudo-elements needs arguments, and thus should be created
+         // via other methods.
+             if in_ua_stylesheet || PseudoElement::After.exposed_in_non_ua_sheets() {
+                 if s.eq_ignore_ascii_case("after") {
+                     return Some(PseudoElement::After);
+                 }
+@@ -1632,17 +1632,17 @@ None
+     }
+ 
+     /// Constructs a tree pseudo-element from the given name and arguments.
+     /// "name" must start with "-moz-tree-".
+     ///
+     /// Returns `None` if the pseudo-element is not recognized.
+     #[inline]
+     pub fn tree_pseudo_element(name: &str, args: Box<[String]>) -> Option<Self> {
+-        use std::ascii::AsciiExt;
++        #[allow(unused_imports)] use std::ascii::AsciiExt;
+         debug_assert!(name.starts_with("-moz-tree-"));
+         let tree_part = &name[10..];
+             if tree_part.eq_ignore_ascii_case("column") {
+                 return Some(PseudoElement::MozTreeColumn(args));
+             }
+             if tree_part.eq_ignore_ascii_case("row") {
+                 return Some(PseudoElement::MozTreeRow(args));
+             }
+diff --git a/servo/components/style/gecko/pseudo_element_definition.mako.rs b/servo/components/style/gecko/pseudo_element_definition.mako.rs
+--- a/servo/components/style/gecko/pseudo_element_definition.mako.rs
++++ b/servo/components/style/gecko/pseudo_element_definition.mako.rs
+@@ -181,17 +181,17 @@ impl PseudoElement {
+     /// user-agent stylesheet.
+     ///
+     /// If we're not in a user-agent stylesheet, we will never parse anonymous
+     /// box pseudo-elements.
+     ///
+     /// Returns `None` if the pseudo-element is not recognised.
+     #[inline]
+     pub fn from_slice(s: &str, in_ua_stylesheet: bool) -> Option<Self> {
+-        use std::ascii::AsciiExt;
++        #[allow(unused_imports)] #[allow(unused_imports)] use std::ascii::AsciiExt;
+ 
+         // We don't need to support tree pseudos because functional
+         // pseudo-elements needs arguments, and thus should be created
+         // via other methods.
+         % for pseudo in SIMPLE_PSEUDOS:
+             if in_ua_stylesheet || ${pseudo_element_variant(pseudo)}.exposed_in_non_ua_sheets() {
+                 if s.eq_ignore_ascii_case("${pseudo.value[1:]}") {
+                     return Some(${pseudo_element_variant(pseudo)});
+@@ -203,17 +203,17 @@ impl PseudoElement {
+     }
+ 
+     /// Constructs a tree pseudo-element from the given name and arguments.
+     /// "name" must start with "-moz-tree-".
+     ///
+     /// Returns `None` if the pseudo-element is not recognized.
+     #[inline]
+     pub fn tree_pseudo_element(name: &str, args: Box<[String]>) -> Option<Self> {
+-        use std::ascii::AsciiExt;
++        #[allow(unused_imports)] use std::ascii::AsciiExt;
+         debug_assert!(name.starts_with("-moz-tree-"));
+         let tree_part = &name[10..];
+         % for pseudo in TREE_PSEUDOS:
+             if tree_part.eq_ignore_ascii_case("${pseudo.value[11:]}") {
+                 return Some(${pseudo_element_variant(pseudo, "args")});
+             }
+         % endfor
+         None
+diff --git a/servo/components/style/gecko_string_cache/mod.rs b/servo/components/style/gecko_string_cache/mod.rs
+--- a/servo/components/style/gecko_string_cache/mod.rs
++++ b/servo/components/style/gecko_string_cache/mod.rs
+@@ -8,17 +8,17 @@
+ 
+ use gecko_bindings::bindings::Gecko_AddRefAtom;
+ use gecko_bindings::bindings::Gecko_Atomize;
+ use gecko_bindings::bindings::Gecko_Atomize16;
+ use gecko_bindings::bindings::Gecko_ReleaseAtom;
+ use gecko_bindings::structs::{nsIAtom, nsIAtom_AtomKind};
+ use nsstring::{nsAString, nsString};
+ use precomputed_hash::PrecomputedHash;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::{Cow, Borrow};
+ use std::char::{self, DecodeUtf16};
+ use std::fmt::{self, Write};
+ use std::hash::{Hash, Hasher};
+ use std::iter::Cloned;
+ use std::mem;
+ use std::ops::Deref;
+ use std::slice;
+diff --git a/servo/components/style/properties/longhand/font.mako.rs b/servo/components/style/properties/longhand/font.mako.rs
+--- a/servo/components/style/properties/longhand/font.mako.rs
++++ b/servo/components/style/properties/longhand/font.mako.rs
+@@ -2137,17 +2137,17 @@ https://drafts.csswg.org/css-fonts-4/#lo
+         SpecifiedValue::Normal
+     }
+ 
+     impl ToComputedValue for SpecifiedValue {
+         type ComputedValue = computed_value::T;
+ 
+         #[inline]
+         fn to_computed_value(&self, _context: &Context) -> computed_value::T {
+-            use std::ascii::AsciiExt;
++            #[allow(unused_imports)] #[allow(unused_imports)] use std::ascii::AsciiExt;
+             match *self {
+                 SpecifiedValue::Normal => computed_value::T(0),
+                 SpecifiedValue::Override(ref lang) => {
+                     if lang.is_empty() || lang.len() > 4 || !lang.is_ascii() {
+                         return computed_value::T(0)
+                     }
+                     let mut computed_lang = lang.clone();
+                     while computed_lang.len() < 4 {
+diff --git a/servo/components/style/properties/longhand/pointing.mako.rs b/servo/components/style/properties/longhand/pointing.mako.rs
+--- a/servo/components/style/properties/longhand/pointing.mako.rs
++++ b/servo/components/style/properties/longhand/pointing.mako.rs
+@@ -85,17 +85,17 @@
+             images: vec![],
+             keyword: computed_value::Keyword::Auto
+         }
+     }
+ 
+     impl Parse for computed_value::Keyword {
+         fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
+                          -> Result<computed_value::Keyword, ParseError<'i>> {
+-            use std::ascii::AsciiExt;
++            #[allow(unused_imports)] use std::ascii::AsciiExt;
+             use style_traits::cursor::Cursor;
+             let ident = input.expect_ident()?;
+             if ident.eq_ignore_ascii_case("auto") {
+                 Ok(computed_value::Keyword::Auto)
+             } else {
+                 Cursor::from_css_keyword(&ident)
+                     .map(computed_value::Keyword::Cursor)
+                     .map_err(|()| SelectorParseError::UnexpectedIdent(ident.clone()).into())
+diff --git a/servo/components/style/servo/selector_parser.rs b/servo/components/style/servo/selector_parser.rs
+--- a/servo/components/style/servo/selector_parser.rs
++++ b/servo/components/style/servo/selector_parser.rs
+@@ -16,17 +16,17 @@ use invalidation::element::element_wrapp
+ use properties::ComputedValues;
+ use properties::PropertyFlags;
+ use properties::longhands::display::computed_value as display;
+ use selector_parser::{AttrValue as SelectorAttrValue, ElementExt, PseudoElementCascadeType, SelectorParser};
+ use selectors::Element;
+ use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
+ use selectors::parser::{SelectorMethods, SelectorParseError};
+ use selectors::visitor::SelectorVisitor;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::fmt;
+ use std::fmt::Debug;
+ use std::mem;
+ use std::ops::{Deref, DerefMut};
+ use style_traits::{ParseError, StyleParseError};
+ 
+ /// A pseudo-element, both public and private.
+ ///
+diff --git a/servo/components/style/str.rs b/servo/components/style/str.rs
+--- a/servo/components/style/str.rs
++++ b/servo/components/style/str.rs
+@@ -2,17 +2,17 @@
+  * 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/. */
+ 
+ //! String utils for attributes and similar stuff.
+ 
+ #![deny(missing_docs)]
+ 
+ use num_traits::ToPrimitive;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] #[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::Cow;
+ use std::convert::AsRef;
+ use std::iter::{Filter, Peekable};
+ use std::str::Split;
+ 
+ /// A static slice of characters.
+ pub type StaticCharVec = &'static [char];
+ 
+diff --git a/servo/components/style/stylesheets/viewport_rule.rs b/servo/components/style/stylesheets/viewport_rule.rs
+--- a/servo/components/style/stylesheets/viewport_rule.rs
++++ b/servo/components/style/stylesheets/viewport_rule.rs
+@@ -15,17 +15,17 @@ use error_reporting::{ContextualParseErr
+ use euclid::TypedSize2D;
+ use font_metrics::get_metrics_provider_for_product;
+ use media_queries::Device;
+ use parser::{ParserContext, ParserErrorContext};
+ use properties::StyleBuilder;
+ use rule_cache::RuleCacheConditions;
+ use selectors::parser::SelectorParseError;
+ use shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard};
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::borrow::Cow;
+ use std::cell::RefCell;
+ use std::fmt;
+ use std::iter::Enumerate;
+ use std::str::Chars;
+ use style_traits::{PinchZoomFactor, ToCss, ParseError, StyleParseError};
+ use style_traits::viewport::{Orientation, UserZoom, ViewportConstraints, Zoom};
+ use stylesheets::{StylesheetInDocument, Origin};
+diff --git a/servo/components/style/values/mod.rs b/servo/components/style/values/mod.rs
+--- a/servo/components/style/values/mod.rs
++++ b/servo/components/style/values/mod.rs
+@@ -7,17 +7,17 @@
+ //! [values]: https://drafts.csswg.org/css-values/
+ 
+ #![deny(missing_docs)]
+ 
+ use Atom;
+ pub use cssparser::{RGBA, Token, Parser, serialize_identifier, BasicParseError, CowRcStr};
+ use parser::{Parse, ParserContext};
+ use selectors::parser::SelectorParseError;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::fmt::{self, Debug};
+ use std::hash;
+ use style_traits::{ToCss, ParseError, StyleParseError};
+ 
+ pub mod animated;
+ pub mod computed;
+ pub mod distance;
+ pub mod generics;
+diff --git a/servo/components/style/values/specified/align.rs b/servo/components/style/values/specified/align.rs
+--- a/servo/components/style/values/specified/align.rs
++++ b/servo/components/style/values/specified/align.rs
+@@ -5,17 +5,17 @@
+ //! Values for CSS Box Alignment properties
+ //!
+ //! https://drafts.csswg.org/css-align/
+ 
+ use cssparser::Parser;
+ use gecko_bindings::structs;
+ use parser::{Parse, ParserContext};
+ use selectors::parser::SelectorParseError;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::fmt;
+ use style_traits::{ToCss, ParseError, StyleParseError};
+ 
+ bitflags! {
+     /// Constants shared by multiple CSS Box Alignment properties
+     ///
+     /// These constants match Gecko's `NS_STYLE_ALIGN_*` constants.
+     #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
+diff --git a/servo/components/style/values/specified/angle.rs b/servo/components/style/values/specified/angle.rs
+--- a/servo/components/style/values/specified/angle.rs
++++ b/servo/components/style/values/specified/angle.rs
+@@ -1,17 +1,17 @@
+ /* 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/. */
+ 
+ //! Specified angles.
+ 
+ use cssparser::{Parser, Token, BasicParseError};
+ use parser::{ParserContext, Parse};
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::fmt;
+ use style_traits::{ToCss, ParseError};
+ use values::CSSFloat;
+ use values::computed::{Context, ToComputedValue};
+ use values::computed::angle::Angle as ComputedAngle;
+ use values::specified::calc::CalcNode;
+ 
+ /// A specified angle.
+diff --git a/servo/components/style/values/specified/calc.rs b/servo/components/style/values/specified/calc.rs
+--- a/servo/components/style/values/specified/calc.rs
++++ b/servo/components/style/values/specified/calc.rs
+@@ -3,17 +3,17 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ //! [Calc expressions][calc].
+ //!
+ //! [calc]: https://drafts.csswg.org/css-values/#calc-notation
+ 
+ use cssparser::{Parser, Token, BasicParseError};
+ use parser::ParserContext;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::fmt;
+ use style_traits::{ToCss, ParseError, StyleParseError};
+ use style_traits::values::specified::AllowedNumericType;
+ use values::{CSSInteger, CSSFloat};
+ use values::computed;
+ use values::specified::{Angle, Time};
+ use values::specified::length::{AbsoluteLength, FontRelativeLength, NoCalcLength};
+ use values::specified::length::ViewportPercentageLength;
+diff --git a/servo/components/style/values/specified/grid.rs b/servo/components/style/values/specified/grid.rs
+--- a/servo/components/style/values/specified/grid.rs
++++ b/servo/components/style/values/specified/grid.rs
+@@ -2,17 +2,17 @@
+  * 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/. */
+ 
+ //! CSS handling for the computed value of
+ //! [grids](https://drafts.csswg.org/css-grid/)
+ 
+ use cssparser::{Parser, Token, BasicParseError};
+ use parser::{Parse, ParserContext};
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::mem;
+ use style_traits::{ParseError, StyleParseError};
+ use values::{CSSFloat, CustomIdent};
+ use values::computed::{self, Context, ToComputedValue};
+ use values::generics::grid::{GridTemplateComponent, RepeatCount, TrackBreadth, TrackKeyword, TrackRepeat};
+ use values::generics::grid::{LineNameList, TrackSize, TrackList, TrackListType, TrackListValue};
+ use values::specified::{LengthOrPercentage, Integer};
+ 
+diff --git a/servo/components/style/values/specified/length.rs b/servo/components/style/values/specified/length.rs
+--- a/servo/components/style/values/specified/length.rs
++++ b/servo/components/style/values/specified/length.rs
+@@ -7,17 +7,17 @@
+ //! [length]: https://drafts.csswg.org/css-values/#lengths
+ 
+ use app_units::Au;
+ use cssparser::{Parser, Token, BasicParseError};
+ use euclid::Size2D;
+ use font_metrics::FontMetricsQueryResult;
+ use parser::{Parse, ParserContext};
+ use std::{cmp, fmt, mem};
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::ops::{Add, Mul};
+ use style_traits::{ToCss, ParseError, StyleParseError};
+ use style_traits::values::specified::AllowedNumericType;
+ use stylesheets::CssRuleType;
+ use super::{AllowQuirks, Number, ToComputedValue, Percentage};
+ use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, None_, Normal};
+ use values::{ExtremumLength, serialize_dimension};
+ use values::computed::{self, CSSPixelLength, Context};
+diff --git a/servo/components/style/values/specified/mod.rs b/servo/components/style/values/specified/mod.rs
+--- a/servo/components/style/values/specified/mod.rs
++++ b/servo/components/style/values/specified/mod.rs
+@@ -6,17 +6,17 @@
+ //!
+ //! TODO(emilio): Enhance docs.
+ 
+ use Namespace;
+ use context::QuirksMode;
+ use cssparser::{Parser, Token, serialize_identifier, BasicParseError};
+ use parser::{ParserContext, Parse};
+ use self::url::SpecifiedUrl;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::f32;
+ use std::fmt;
+ use style_traits::{ToCss, ParseError, StyleParseError};
+ use style_traits::values::specified::AllowedNumericType;
+ use super::{Auto, CSSFloat, CSSInteger, Either, None_};
+ use super::computed::{Context, ToComputedValue};
+ use super::generics::{GreaterThanOrEqualToOne, NonNegative};
+ use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth};
+diff --git a/servo/components/style/values/specified/percentage.rs b/servo/components/style/values/specified/percentage.rs
+--- a/servo/components/style/values/specified/percentage.rs
++++ b/servo/components/style/values/specified/percentage.rs
+@@ -1,17 +1,17 @@
+ /* 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/. */
+ 
+ //! Specified percentages.
+ 
+ use cssparser::{BasicParseError, Parser, Token};
+ use parser::{Parse, ParserContext};
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::fmt;
+ use style_traits::{ParseError, ToCss};
+ use style_traits::values::specified::AllowedNumericType;
+ use values::{CSSFloat, serialize_percentage};
+ use values::computed::{Context, ToComputedValue};
+ use values::computed::percentage::Percentage as ComputedPercentage;
+ use values::specified::calc::CalcNode;
+ 
+diff --git a/servo/components/style/values/specified/text.rs b/servo/components/style/values/specified/text.rs
+--- a/servo/components/style/values/specified/text.rs
++++ b/servo/components/style/values/specified/text.rs
+@@ -2,17 +2,17 @@
+  * 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/. */
+ 
+ //! Specified types for text properties.
+ 
+ use cssparser::Parser;
+ use parser::{Parse, ParserContext};
+ use selectors::parser::SelectorParseError;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use style_traits::ParseError;
+ use values::computed::{Context, ToComputedValue};
+ use values::computed::text::LineHeight as ComputedLineHeight;
+ use values::generics::text::InitialLetter as GenericInitialLetter;
+ use values::generics::text::LineHeight as GenericLineHeight;
+ use values::generics::text::Spacing;
+ use values::specified::{AllowQuirks, Integer, NonNegativeNumber, Number};
+ use values::specified::length::{FontRelativeLength, Length, LengthOrPercentage, NoCalcLength};
+diff --git a/servo/components/style/values/specified/time.rs b/servo/components/style/values/specified/time.rs
+--- a/servo/components/style/values/specified/time.rs
++++ b/servo/components/style/values/specified/time.rs
+@@ -1,17 +1,17 @@
+ /* 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/. */
+ 
+ //! Specified time values.
+ 
+ use cssparser::{Parser, Token, BasicParseError};
+ use parser::{ParserContext, Parse};
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::fmt;
+ use style_traits::{ToCss, ParseError, StyleParseError};
+ use style_traits::values::specified::AllowedNumericType;
+ use values::CSSFloat;
+ use values::computed::{Context, ToComputedValue};
+ use values::computed::time::Time as ComputedTime;
+ use values::specified::calc::CalcNode;
+ 
+diff --git a/servo/components/style_traits/viewport.rs b/servo/components/style_traits/viewport.rs
+--- a/servo/components/style_traits/viewport.rs
++++ b/servo/components/style_traits/viewport.rs
+@@ -2,17 +2,17 @@
+  * 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/. */
+ 
+ //! Helper types for the `@viewport` rule.
+ 
+ use {CSSPixel, PinchZoomFactor, ParseError};
+ use cssparser::{Parser, ToCss, ParseError as CssParseError, BasicParseError};
+ use euclid::TypedSize2D;
+-use std::ascii::AsciiExt;
++#[allow(unused_imports)] use std::ascii::AsciiExt;
+ use std::fmt;
+ 
+ define_css_keyword_enum!(UserZoom:
+                          "zoom" => Zoom,
+                          "fixed" => Fixed);
+ 
+ define_css_keyword_enum!(Orientation:
+                          "auto" => Auto,
--- a/series	Sat Nov 11 10:08:36 2017 +0100
+++ b/series	Wed Jan 10 22:27:13 2018 +0100
@@ -8,6 +8,9 @@
 mozilla-reduce-files-per-UnifiedBindings.patch
 mozilla-aarch64-startup-crash.patch
 mozilla-bindgen-systemlibs.patch
+mozilla-bmo1360278.patch
+mozilla-bmo1399611-csd.patch
+mozilla-rust-1.23.patch
 
 # Firefox patches
 firefox-kde.patch