Merge m-c to inbound, a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 13 Jan 2017 15:48:34 -0800
changeset 374448 b6e44e6e6dc5e3bac77d4c9ec1356a2d6f65473b
parent 374447 0431a0ab907d53646d359ad10507efe7f89dd487 (current diff)
parent 374364 ac3275723df59db0f09198fdb61b51e7002c391a (diff)
child 374449 a6f5417cf3f249688ee74c9a95bd35c58a086ef9
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone53.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to inbound, a=merge MozReview-Commit-ID: ASajzspkOe1
build/mobile/b2gautomation.py
layout/style/CSSStyleSheet.cpp
layout/tools/reftest/b2g_start_script.js
layout/tools/reftest/gaia_lock_screen.js
layout/tools/reftest/runreftestb2g.py
layout/tools/reftest/runreftestmulet.py
services/sync/tps/extensions/tps/resource/tps.jsm
--- a/.eslintignore
+++ b/.eslintignore
@@ -179,16 +179,22 @@ mobile/android/components/Snippets.js
 # Bug 1178739: Ignore this file as a quick fix for "Illegal yield expression"
 mobile/android/modules/HomeProvider.jsm
 
 # services/ exclusions
 
 # Uses `#filter substitution`
 services/sync/modules/constants.js
 
+# Third party services
+services/sync/tps/extensions/mozmill/resource/stdlib/json2.js
+services/common/kinto-http-client.js
+services/common/kinto-offline-client.js
+services/sync/tps/extensions/mozmill
+
 # toolkit/ exclusions
 
 # Not part of the default build
 toolkit/components/help/**
 
 # Intentionally invalid JS
 toolkit/components/workerloader/tests/moduleF-syntax-error.js
 
--- a/browser/components/preferences/colors.xul
+++ b/browser/components/preferences/colors.xul
@@ -80,23 +80,23 @@
         </hbox>
       </groupbox>
     </hbox>
 #ifdef XP_WIN
     <vbox align="start">
 #else
     <vbox>
 #endif
-      <label accesskey="&overridePageColors.accesskey;"
-             control="useDocumentColors">&overridePageColors.label;</label>
+      <label accesskey="&overrideDefaultPageColors.accesskey;"
+             control="useDocumentColors">&overrideDefaultPageColors.label;</label>
       <menulist id="useDocumentColors" preference="browser.display.document_color_use">
         <menupopup>
-          <menuitem label="&overridePageColors.always.label;"
+          <menuitem label="&overrideDefaultPageColors.always.label;"
                     value="2" id="documentColorAlways"/>
-          <menuitem label="&overridePageColors.auto.label;"
+          <menuitem label="&overrideDefaultPageColors.auto.label;"
                     value="0" id="documentColorAutomatic"/>
-          <menuitem label="&overridePageColors.never.label;"
+          <menuitem label="&overrideDefaultPageColors.never.label;"
                     value="1" id="documentColorNever"/>
         </menupopup>
       </menulist>
     </vbox>
   </prefpane>
 </prefwindow>
--- a/browser/components/preferences/fonts.xul
+++ b/browser/components/preferences/fonts.xul
@@ -233,17 +233,17 @@
             </menupopup>
           </menulist>
         </hbox>
       </hbox>
       <separator/>
       <separator class="groove"/>
       <hbox>
         <checkbox id="useDocumentFonts" 
-                  label="&allowPagesToUse.label;" accesskey="&allowPagesToUse.accesskey;"
+                  label="&allowPagesToUseOwn.label;" accesskey="&allowPagesToUseOwn.accesskey;"
                   preference="browser.display.use_document_fonts"
                   onsyncfrompreference="return gFontsDialog.readUseDocumentFonts();"
                   onsynctopreference="return gFontsDialog.writeUseDocumentFonts();"/>
       </hbox>
     </groupbox>
 
     <!-- Text Encoding -->
     <groupbox>
--- a/browser/components/preferences/in-content/advanced.xul
+++ b/browser/components/preferences/in-content/advanced.xul
@@ -162,22 +162,22 @@
                   accesskey="&useOnScreenKeyboard.accesskey;"
                   preference="ui.osk.enabled"/>
 #endif
         <checkbox id="useCursorNavigation"
                   label="&useCursorNavigation.label;"
                   accesskey="&useCursorNavigation.accesskey;"
                   preference="accessibility.browsewithcaret"/>
         <checkbox id="searchStartTyping"
-                  label="&searchStartTyping.label;"
-                  accesskey="&searchStartTyping.accesskey;"
+                  label="&searchOnStartTyping.label;"
+                  accesskey="&searchOnStartTyping.accesskey;"
                   preference="accessibility.typeaheadfind"/>
         <checkbox id="blockAutoRefresh"
-                  label="&blockAutoRefresh.label;"
-                  accesskey="&blockAutoRefresh.accesskey;"
+                  label="&blockAutoReload.label;"
+                  accesskey="&blockAutoReload.accesskey;"
                   preference="accessibility.blockautorefresh"/>
       </groupbox>
       <!-- Browsing -->
       <groupbox id="browsingGroup" align="start">
         <caption><label>&browsing.label;</label></caption>
 
         <checkbox id="useAutoScroll"
                   label="&useAutoScroll.label;"
@@ -187,18 +187,18 @@
                   label="&useSmoothScrolling.label;"
                   accesskey="&useSmoothScrolling.accesskey;"
                   preference="general.smoothScroll"/>
         <checkbox id="allowHWAccel"
                   label="&allowHWAccel.label;"
                   accesskey="&allowHWAccel.accesskey;"
                   preference="layers.acceleration.disabled"/>
         <checkbox id="checkSpelling"
-                  label="&checkSpelling.label;"
-                  accesskey="&checkSpelling.accesskey;"
+                  label="&checkUserSpelling.label;"
+                  accesskey="&checkUserSpelling.accesskey;"
                   onsyncfrompreference="return gAdvancedPane.readCheckSpelling();"
                   onsynctopreference="return gAdvancedPane.writeCheckSpelling();"
                   preference="layout.spellcheckDefault"/>
       </groupbox>
     </tabpanel>
 #ifdef MOZ_DATA_REPORTING
     <!-- Data Choices -->
     <tabpanel id="dataChoicesPanel" orient="vertical">
@@ -296,23 +296,23 @@
 
         <hbox align="center">
           <label id="actualAppCacheSize" flex="1"/>
           <button id="clearOfflineAppCacheButton" icon="clear"
                   label="&clearOfflineAppCacheNow.label;" accesskey="&clearOfflineAppCacheNow.accesskey;"/>
         </hbox>
         <hbox align="center">
           <checkbox id="offlineNotify"
-                    label="&offlineNotify.label;" accesskey="&offlineNotify.accesskey;"
+                    label="&offlineStorageNotify.label;" accesskey="&offlineStorageNotify.accesskey;"
                     preference="browser.offline-apps.notify"
                     onsyncfrompreference="return gAdvancedPane.readOfflineNotify();"/>
           <spacer flex="1"/>
           <button id="offlineNotifyExceptions"
-                  label="&offlineNotifyExceptions.label;"
-                  accesskey="&offlineNotifyExceptions.accesskey;"/>
+                  label="&offlineStorageNotifyExceptions.label;"
+                  accesskey="&offlineStorageNotifyExceptions.accesskey;"/>
         </hbox>
         <hbox>
           <vbox flex="1">
             <label id="offlineAppsListLabel">&offlineAppsList2.label;</label>
             <listbox id="offlineAppsList"
                     flex="1"
                     aria-labelledby="offlineAppsListLabel">
             </listbox>
@@ -349,18 +349,18 @@
       <groupbox id="updateApp" align="start">
         <caption><label>&updateApplication.label;</label></caption>
         <radiogroup id="updateRadioGroup" align="start">
           <radio id="autoDesktop"
                  value="auto"
                  label="&updateAuto1.label;"
                  accesskey="&updateAuto1.accesskey;"/>
           <radio value="checkOnly"
-                label="&updateCheck.label;"
-                accesskey="&updateCheck.accesskey;"/>
+                label="&updateCheckChoose.label;"
+                accesskey="&updateCheckChoose.accesskey;"/>
           <radio value="manual"
                 label="&updateManual.label;"
                 accesskey="&updateManual.accesskey;"/>
         </radiogroup>
         <separator class="thin"/>
         <hbox>
           <button id="showUpdateHistory"
                   label="&updateHistory.label;"
@@ -383,33 +383,33 @@
                   accesskey="&enableSearchUpdate.accesskey;"
                   preference="browser.search.update"/>
       </groupbox>
     </tabpanel>
 
     <!-- Certificates -->
     <tabpanel id="encryptionPanel" orient="vertical">
       <groupbox id="certSelection" align="start">
-        <caption><label>&certSelection.label;</label></caption>
-        <description id="CertSelectionDesc" control="certSelection">&certSelection.description;</description>
+        <caption><label>&certPersonal.label;</label></caption>
+        <description id="CertSelectionDesc" control="certSelection">&certPersonal.description;</description>
 
         <!--
           The values on these radio buttons may look like l12y issues, but
           they're not - this preference uses *those strings* as its values.
           I KID YOU NOT.
         -->
         <radiogroup id="certSelection"
                     preftype="string"
                     preference="security.default_personal_cert"
                     aria-labelledby="CertSelectionDesc">
-          <radio label="&certs.auto;"
-                 accesskey="&certs.auto.accesskey;"
+          <radio label="&selectCerts.auto;"
+                 accesskey="&selectCerts.auto.accesskey;"
                  value="Select Automatically"/>
-          <radio label="&certs.ask;"
-                 accesskey="&certs.ask.accesskey;"
+          <radio label="&selectCerts.ask;"
+                 accesskey="&selectCerts.ask.accesskey;"
                  value="Ask Every Time"/>
         </radiogroup>
       </groupbox>
       <separator/>
       <checkbox id="enableOCSP"
                 label="&enableOCSP.label;"
                 accesskey="&enableOCSP.accesskey;"
                 onsyncfrompreference="return gAdvancedPane.readEnableOCSP();"
--- a/browser/components/preferences/in-content/main.xul
+++ b/browser/components/preferences/in-content/main.xul
@@ -167,23 +167,23 @@
         <label accesskey="&startupPage.accesskey;"
                control="browserStartupPage">&startupPage.label;</label>
       </html:td>
       <html:td class="content-cell">
         <menulist id="browserStartupPage"
                   class="content-cell-item"
                   preference="browser.startup.page">
           <menupopup>
-          <menuitem label="&startupHomePage.label;"
+          <menuitem label="&startupUserHomePage.label;"
                     value="1"
                     id="browserStartupHomePage"/>
           <menuitem label="&startupBlankPage.label;"
                     value="0"
                     id="browserStartupBlank"/>
-          <menuitem label="&startupLastSession.label;"
+          <menuitem label="&startupPrevSession.label;"
                     value="3"
                     id="browserStartupLastSession"/>
           </menupopup>
         </menulist>
       </html:td>
     </html:tr>
     <html:tr>
       <html:td class="label-cell">
@@ -255,18 +255,18 @@
               accesskey="&chooseFolderWin.accesskey;"
               label="&chooseFolderWin.label;"
 #endif
       />
     </hbox>
     <hbox>
       <radio id="alwaysAsk"
              value="false"
-             label="&alwaysAsk.label;"
-             accesskey="&alwaysAsk.accesskey;"/>
+             label="&alwaysAskWhere.label;"
+             accesskey="&alwaysAskWhere.accesskey;"/>
     </hbox>
   </radiogroup>
 </groupbox>
 
 <!-- Tab preferences -->
 <groupbox data-category="paneGeneral"
           hidden="true" align="start">
     <caption><label>&tabsGroup.label;</label></caption>
@@ -276,26 +276,26 @@
               preference="browser.ctrlTab.previews"/>
 
     <checkbox id="linkTargeting" label="&newWindowsAsTabs.label;"
               accesskey="&newWindowsAsTabs.accesskey;"
               preference="browser.link.open_newwindow"
               onsyncfrompreference="return gMainPane.readLinkTarget();"
               onsynctopreference="return gMainPane.writeLinkTarget();"/>
 
-    <checkbox id="warnCloseMultiple" label="&warnCloseMultipleTabs.label;"
-              accesskey="&warnCloseMultipleTabs.accesskey;"
+    <checkbox id="warnCloseMultiple" label="&warnOnCloseMultipleTabs.label;"
+              accesskey="&warnOnCloseMultipleTabs.accesskey;"
               preference="browser.tabs.warnOnClose"/>
 
-    <checkbox id="warnOpenMany" label="&warnOpenManyTabs.label;"
-              accesskey="&warnOpenManyTabs.accesskey;"
+    <checkbox id="warnOpenMany" label="&warnOnOpenManyTabs.label;"
+              accesskey="&warnOnOpenManyTabs.accesskey;"
               preference="browser.tabs.warnOnOpen"/>
 
-    <checkbox id="switchToNewTabs" label="&switchToNewTabs.label;"
-              accesskey="&switchToNewTabs.accesskey;"
+    <checkbox id="switchToNewTabs" label="&switchLinksToNewTabs.label;"
+              accesskey="&switchLinksToNewTabs.accesskey;"
               preference="browser.tabs.loadInBackground"/>
 
 #ifdef XP_WIN
     <checkbox id="showTabsInTaskbar" label="&showTabsInTaskbar.label;"
               accesskey="&showTabsInTaskbar.accesskey;"
               preference="browser.taskbar.previews.enable"/>
 #endif
 </groupbox>
--- a/browser/components/preferences/in-content/security.xul
+++ b/browser/components/preferences/in-content/security.xul
@@ -57,18 +57,18 @@
 </hbox>
 
 <!-- addons, forgery (phishing) UI -->
 <groupbox id="addonsPhishingGroup" data-category="paneSecurity" hidden="true">
   <caption><label>&general.label;</label></caption>
 
   <hbox id="addonInstallBox">
     <checkbox id="warnAddonInstall"
-              label="&warnAddonInstall.label;"
-              accesskey="&warnAddonInstall.accesskey;"
+              label="&warnOnAddonInstall.label;"
+              accesskey="&warnOnAddonInstall.accesskey;"
               preference="xpinstall.whitelist.required"
               onsyncfrompreference="return gSecurityPane.readWarnAddonInstall();"/>
     <spacer flex="1"/>
     <button id="addonExceptions"
             label="&addonExceptions.label;"
             accesskey="&addonExceptions.accesskey;"/>
   </hbox>
 
@@ -77,18 +77,18 @@
     <checkbox id="enableSafeBrowsing"
               label="&enableSafeBrowsing.label;"
               accesskey="&enableSafeBrowsing.accesskey;" />
     <vbox class="indent">
       <checkbox id="blockDownloads"
                 label="&blockDownloads.label;"
                 accesskey="&blockDownloads.accesskey;" />
       <checkbox id="blockUncommonUnwanted"
-                label="&blockUncommonUnwanted.label;"
-                accesskey="&blockUncommonUnwanted.accesskey;" />
+                label="&blockUncommonAndUnwanted.label;"
+                accesskey="&blockUncommonAndUnwanted.accesskey;" />
     </vbox>
   </vbox>
 </groupbox>
 
 <!-- Passwords -->
 <groupbox id="passwordsGroup" orient="vertical" data-category="paneSecurity" hidden="true">
   <caption><label>&logins.label;</label></caption>
 
--- a/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
@@ -5,33 +5,33 @@
 <!-- Note: each tab panel must contain unique accesskeys -->
 
 <!ENTITY generalTab.label                "General">
 
 <!ENTITY accessibility.label             "Accessibility">
 
 <!ENTITY useCursorNavigation.label       "Always use the cursor keys to navigate within pages">
 <!ENTITY useCursorNavigation.accesskey   "c">
-<!ENTITY searchStartTyping.label         "Search for text when I start typing">
-<!ENTITY searchStartTyping.accesskey     "x">
-<!ENTITY blockAutoRefresh.label          "Warn me when websites try to redirect or reload the page">
-<!ENTITY blockAutoRefresh.accesskey      "b">
+<!ENTITY searchOnStartTyping.label       "Search for text when you start typing">
+<!ENTITY searchOnStartTyping.accesskey   "x">
+<!ENTITY blockAutoReload.label           "Warn you when websites try to redirect or reload the page">
+<!ENTITY blockAutoReload.accesskey       "b">
 <!ENTITY useOnScreenKeyboard.label       "Show a touch keyboard when necessary">
 <!ENTITY useOnScreenKeyboard.accesskey   "k">
 
 <!ENTITY browsing.label                  "Browsing">
 
 <!ENTITY useAutoScroll.label             "Use autoscrolling">
 <!ENTITY useAutoScroll.accesskey         "a">
 <!ENTITY useSmoothScrolling.label        "Use smooth scrolling">
 <!ENTITY useSmoothScrolling.accesskey    "m">
 <!ENTITY allowHWAccel.label              "Use hardware acceleration when available">
 <!ENTITY allowHWAccel.accesskey          "r">
-<!ENTITY checkSpelling.label             "Check my spelling as I type">
-<!ENTITY checkSpelling.accesskey         "t">
+<!ENTITY checkUserSpelling.label         "Check your spelling as you type">
+<!ENTITY checkUserSpelling.accesskey     "t">
 
 <!ENTITY dataChoicesTab.label            "Data Choices">
 
 <!ENTITY healthReportDesc.label          "Helps you understand your browser performance and shares data with &vendorShortName; about your browser health">
 <!ENTITY enableHealthReport.label        "Enable &brandShortName; Health Report">
 <!ENTITY enableHealthReport.accesskey    "R">
 <!ENTITY healthReportLearnMore.label     "Learn More">
 
@@ -80,47 +80,47 @@
 <!ENTITY overrideSmartCacheSize.label    "Override automatic cache management">
 <!ENTITY overrideSmartCacheSize.accesskey "O">
 
 <!ENTITY updateTab.label                 "Update">
 
 <!ENTITY updateApplication.label         "&brandShortName; updates">
 <!ENTITY updateAuto1.label               "Automatically install updates (recommended: improved security)">
 <!ENTITY updateAuto1.accesskey           "A">
-<!ENTITY updateCheck.label               "Check for updates, but let me choose whether to install them">
-<!ENTITY updateCheck.accesskey           "C">
+<!ENTITY updateCheckChoose.label         "Check for updates, but let you choose whether to install them">
+<!ENTITY updateCheckChoose.accesskey     "C">
 <!ENTITY updateManual.label              "Never check for updates (not recommended: security risk)">
 <!ENTITY updateManual.accesskey          "N">
 
 <!ENTITY updateHistory.label             "Show Update History">
 <!ENTITY updateHistory.accesskey         "p">
 
 <!ENTITY useService.label                "Use a background service to install updates">
 <!ENTITY useService.accesskey            "b">
 
 <!ENTITY autoUpdateOthers.label          "Automatically update">
 <!ENTITY enableSearchUpdate.label        "Search Engines">
 <!ENTITY enableSearchUpdate.accesskey    "E">
 
-<!ENTITY offlineNotify.label             "Tell me when a website asks to store data for offline use">
-<!ENTITY offlineNotify.accesskey         "T">
-<!ENTITY offlineNotifyExceptions.label   "Exceptions…">
-<!ENTITY offlineNotifyExceptions.accesskey "x">
+<!ENTITY offlineStorageNotify.label               "Tell you when a website asks to store data for offline use">
+<!ENTITY offlineStorageNotify.accesskey           "T">
+<!ENTITY offlineStorageNotifyExceptions.label     "Exceptions…">
+<!ENTITY offlineStorageNotifyExceptions.accesskey "x">
 
 <!ENTITY offlineAppsList2.label          "The following websites are allowed to store data for offline use:">
 <!ENTITY offlineAppsList.height          "7em">
 <!ENTITY offlineAppsListRemove.label     "Remove…">
 <!ENTITY offlineAppsListRemove.accesskey "R">
 <!ENTITY offlineAppRemove.confirm        "Remove offline data">
 
 <!ENTITY certificateTab.label            "Certificates">
-<!ENTITY certSelection.label             "Requests">
-<!ENTITY certSelection.description       "When a server requests my personal certificate:">
-<!ENTITY certs.auto                      "Select one automatically">
-<!ENTITY certs.auto.accesskey            "S">
-<!ENTITY certs.ask                       "Ask me every time">
-<!ENTITY certs.ask.accesskey             "A">
+<!ENTITY certPersonal.label              "Requests">
+<!ENTITY certPersonal.description        "When a server requests your personal certificate:">
+<!ENTITY selectCerts.auto                "Select one automatically">
+<!ENTITY selectCerts.auto.accesskey      "S">
+<!ENTITY selectCerts.ask                 "Ask you every time">
+<!ENTITY selectCerts.ask.accesskey       "A">
 <!ENTITY enableOCSP.label                "Query OCSP responder servers to confirm the current validity of certificates">
 <!ENTITY enableOCSP.accesskey            "Q">
 <!ENTITY viewCerts.label                 "View Certificates">
 <!ENTITY viewCerts.accesskey             "C">
 <!ENTITY viewSecurityDevices.label       "Security Devices">
 <!ENTITY viewSecurityDevices.accesskey   "D">
--- a/browser/locales/en-US/chrome/browser/preferences/colors.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/colors.dtd
@@ -1,22 +1,22 @@
 <!-- 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/. -->
 
 <!ENTITY  colorsDialog.title              "Colors">
 <!ENTITY  window.width                    "38em">
 <!ENTITY  window.macWidth                 "41em">
 
-<!ENTITY  overridePageColors.label        "Override the colors specified by the page with my selections above:">
-<!ENTITY  overridePageColors.accesskey    "O">
+<!ENTITY  overrideDefaultPageColors.label        "Override the colors specified by the page with your selections above:">
+<!ENTITY  overrideDefaultPageColors.accesskey    "O">
 
-<!ENTITY  overridePageColors.always.label "Always">
-<!ENTITY  overridePageColors.auto.label   "Only with High Contrast themes">
-<!ENTITY  overridePageColors.never.label  "Never">
+<!ENTITY  overrideDefaultPageColors.always.label "Always">
+<!ENTITY  overrideDefaultPageColors.auto.label   "Only with High Contrast themes">
+<!ENTITY  overrideDefaultPageColors.never.label  "Never">
 
 <!ENTITY  color                           "Text and Background">
 <!ENTITY  textColor.label                 "Text:">
 <!ENTITY  textColor.accesskey             "T">
 <!ENTITY  backgroundColor.label           "Background:">
 <!ENTITY  backgroundColor.accesskey       "B">
 <!ENTITY  useSystemColors.label           "Use system colors">
 <!ENTITY  useSystemColors.accesskey       "s">
--- a/browser/locales/en-US/chrome/browser/preferences/fonts.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/fonts.dtd
@@ -56,18 +56,18 @@
 <!ENTITY minSize.label                            "Minimum font size:">
 <!ENTITY minSize.accesskey                        "o">
 <!ENTITY minSize.none                             "None">
 
 <!-- default font type -->
 <!ENTITY  useDefaultFontSerif.label               "Serif">
 <!ENTITY  useDefaultFontSansSerif.label           "Sans Serif">
 
-<!ENTITY  allowPagesToUse.label                   "Allow pages to choose their own fonts, instead of my selections above">
-<!ENTITY  allowPagesToUse.accesskey               "A">
+<!ENTITY  allowPagesToUseOwn.label                "Allow pages to choose their own fonts, instead of your selections above">
+<!ENTITY  allowPagesToUseOwn.accesskey            "A">
 
 <!ENTITY languages.customize.Fallback2.grouplabel "Text Encoding for Legacy Content">
 <!ENTITY languages.customize.Fallback2.label      "Fallback Text Encoding:">
 <!ENTITY languages.customize.Fallback2.accesskey  "T">
 <!ENTITY languages.customize.Fallback2.desc       "This text encoding is used for legacy content that fails to declare its encoding.">
 
 <!ENTITY languages.customize.Fallback.auto        "Default for Current Locale">
 <!-- LOCALIZATION NOTE (languages.customize.Fallback.arabic):
--- a/browser/locales/en-US/chrome/browser/preferences/main.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/main.dtd
@@ -1,19 +1,19 @@
 <!-- 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/. -->
 
 <!ENTITY startup.label             "Startup">
 
 <!ENTITY startupPage.label         "When &brandShortName; starts:">
 <!ENTITY startupPage.accesskey     "s">
-<!ENTITY startupHomePage.label     "Show my home page">
+<!ENTITY startupUserHomePage.label "Show your home page">
 <!ENTITY startupBlankPage.label    "Show a blank page">
-<!ENTITY startupLastSession.label  "Show my windows and tabs from last time">
+<!ENTITY startupPrevSession.label  "Show your windows and tabs from last time">
 
 <!ENTITY homepage.label            "Home Page:">
 <!ENTITY homepage.accesskey        "P">
 <!ENTITY useCurrentPage.label      "Use Current Page">
 <!ENTITY useCurrentPage.accesskey  "C">
 <!ENTITY useMultiple.label         "Use Current Pages">
 <!ENTITY chooseBookmark.label      "Use Bookmark…">
 <!ENTITY chooseBookmark.accesskey  "B">
@@ -23,18 +23,18 @@
 <!ENTITY downloads.label     "Downloads">
 
 <!ENTITY saveTo.label "Save files to">
 <!ENTITY saveTo.accesskey "v">
 <!ENTITY chooseFolderWin.label        "Browse…">
 <!ENTITY chooseFolderWin.accesskey    "o">
 <!ENTITY chooseFolderMac.label        "Choose…">
 <!ENTITY chooseFolderMac.accesskey    "e">
-<!ENTITY alwaysAsk.label "Always ask me where to save files">
-<!ENTITY alwaysAsk.accesskey "A">
+<!ENTITY alwaysAskWhere.label         "Always ask you where to save files">
+<!ENTITY alwaysAskWhere.accesskey     "A">
 
 <!ENTITY alwaysCheckDefault2.label        "Always check if &brandShortName; is your default browser">
 <!ENTITY alwaysCheckDefault2.accesskey    "y">
 <!ENTITY setAsMyDefaultBrowser2.label     "Make Default">
 <!ENTITY setAsMyDefaultBrowser2.accesskey "D">
 <!ENTITY isDefault.label                  "&brandShortName; is currently your default browser">
 <!ENTITY isNotDefault.label               "&brandShortName; is not your default browser">
 
--- a/browser/locales/en-US/chrome/browser/preferences/security.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/security.dtd
@@ -1,29 +1,29 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <!ENTITY  general.label                 "General">
 
-<!ENTITY  warnAddonInstall.label        "Warn me when sites try to install add-ons">
-<!ENTITY  warnAddonInstall.accesskey    "W">
+<!ENTITY  warnOnAddonInstall.label        "Warn you when sites try to install add-ons">
+<!ENTITY  warnOnAddonInstall.accesskey    "W">
 
 <!-- LOCALIZATION NOTE (enableSafeBrowsing.label, blockDownloads.label, blockUncommonUnwanted.label):
   It is important that wording follows the guidelines outlined on this page:
   https://developers.google.com/safe-browsing/developers_guide_v2#AcceptableUsage
 -->
 <!ENTITY  enableSafeBrowsing.label        "Block dangerous and deceptive content">
 <!ENTITY  enableSafeBrowsing.accesskey    "B">
 
 <!ENTITY  blockDownloads.label            "Block dangerous downloads">
 <!ENTITY  blockDownloads.accesskey        "D">
 
-<!ENTITY  blockUncommonUnwanted.label     "Warn me about unwanted and uncommon software">
-<!ENTITY  blockUncommonUnwanted.accesskey "C">
+<!ENTITY  blockUncommonAndUnwanted.label     "Warn you about unwanted and uncommon software">
+<!ENTITY  blockUncommonAndUnwanted.accesskey "C">
 
 <!ENTITY  addonExceptions.label         "Exceptions…">
 <!ENTITY  addonExceptions.accesskey     "E">
 
 
 <!ENTITY  logins.label                  "Logins">
 
 <!ENTITY  rememberLogins.label          "Remember logins for sites">
--- a/browser/locales/en-US/chrome/browser/preferences/tabs.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/tabs.dtd
@@ -3,20 +3,20 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <!ENTITY ctrlTabRecentlyUsedOrder.label       "Ctrl+Tab cycles through tabs in recently used order">
 <!ENTITY ctrlTabRecentlyUsedOrder.accesskey   "T">
 
 <!ENTITY newWindowsAsTabs.label       "Open new windows in a new tab instead">
 <!ENTITY newWindowsAsTabs.accesskey   "w">
 
-<!ENTITY warnCloseMultipleTabs.label  "Warn me when closing multiple tabs">
-<!ENTITY warnCloseMultipleTabs.accesskey  "m">
+<!ENTITY warnOnCloseMultipleTabs.label      "Warn you when closing multiple tabs">
+<!ENTITY warnOnCloseMultipleTabs.accesskey  "m">
 
-<!ENTITY warnOpenManyTabs.label       "Warn me when opening multiple tabs might slow down &brandShortName;">
-<!ENTITY warnOpenManyTabs.accesskey   "d">
+<!ENTITY warnOnOpenManyTabs.label       "Warn you when opening multiple tabs might slow down &brandShortName;">
+<!ENTITY warnOnOpenManyTabs.accesskey   "d">
 
-<!ENTITY switchToNewTabs.label        "When I open a link in a new tab, switch to it immediately">
-<!ENTITY switchToNewTabs.accesskey    "h">
+<!ENTITY switchLinksToNewTabs.label        "When you open a link in a new tab, switch to it immediately">
+<!ENTITY switchLinksToNewTabs.accesskey    "h">
 
 <!ENTITY showTabsInTaskbar.label          "Show tab previews in the Windows taskbar">
 <!ENTITY showTabsInTaskbar.accesskey      "k">
 <!ENTITY tabsGroup.label          "Tabs">
deleted file mode 100644
--- a/build/mobile/b2gautomation.py
+++ /dev/null
@@ -1,455 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-import datetime
-import mozcrash
-import threading
-import os
-import posixpath
-import Queue
-import re
-import shutil
-import signal
-import tempfile
-import time
-import traceback
-import zipfile
-
-from automation import Automation
-from mozlog import get_default_logger
-from mozprocess import ProcessHandlerMixin
-
-
-class StdOutProc(ProcessHandlerMixin):
-    """Process handler for b2g which puts all output in a Queue.
-    """
-
-    def __init__(self, cmd, queue, **kwargs):
-        self.queue = queue
-        kwargs.setdefault('processOutputLine', []).append(self.handle_output)
-        ProcessHandlerMixin.__init__(self, cmd, **kwargs)
-
-    def handle_output(self, line):
-        self.queue.put_nowait(line)
-
-
-class B2GRemoteAutomation(Automation):
-    _devicemanager = None
-
-    def __init__(self, deviceManager, appName='', remoteLog=None,
-                 marionette=None):
-        self._devicemanager = deviceManager
-        self._appName = appName
-        self._remoteProfile = None
-        self._remoteLog = remoteLog
-        self.marionette = marionette
-        self._is_emulator = False
-        self.test_script = None
-        self.test_script_args = None
-
-        # Default our product to b2g
-        self._product = "b2g"
-        self.lastTestSeen = "b2gautomation.py"
-        # Default log finish to mochitest standard
-        self.logFinish = 'INFO SimpleTest FINISHED'
-        Automation.__init__(self)
-
-    def setEmulator(self, is_emulator):
-        self._is_emulator = is_emulator
-
-    def setDeviceManager(self, deviceManager):
-        self._devicemanager = deviceManager
-
-    def setAppName(self, appName):
-        self._appName = appName
-
-    def setRemoteProfile(self, remoteProfile):
-        self._remoteProfile = remoteProfile
-
-    def setProduct(self, product):
-        self._product = product
-
-    def setRemoteLog(self, logfile):
-        self._remoteLog = logfile
-
-    def getExtensionIDFromRDF(self, rdfSource):
-        """
-        Retrieves the extension id from an install.rdf file (or string).
-        """
-        from xml.dom.minidom import parse, parseString, Node
-
-        if isinstance(rdfSource, file):
-            document = parse(rdfSource)
-        else:
-            document = parseString(rdfSource)
-
-        # Find the <em:id> element. There can be multiple <em:id> tags
-        # within <em:targetApplication> tags, so we have to check this way.
-        for rdfChild in document.documentElement.childNodes:
-            if rdfChild.nodeType == Node.ELEMENT_NODE and rdfChild.tagName == "Description":
-                for descChild in rdfChild.childNodes:
-                    if descChild.nodeType == Node.ELEMENT_NODE and descChild.tagName == "em:id":
-                        return descChild.childNodes[0].data
-        return None
-
-    def installExtension(self, extensionSource, profileDir, extensionID=None):
-        # Bug 827504 - installing special-powers extension separately causes problems in B2G
-        if extensionID != "special-powers@mozilla.org":
-            if not os.path.isdir(profileDir):
-              self.log.info("INFO | automation.py | Cannot install extension, invalid profileDir at: %s", profileDir)
-              return
-
-            installRDFFilename = "install.rdf"
-
-            extensionsRootDir = os.path.join(profileDir, "extensions", "staged")
-            if not os.path.isdir(extensionsRootDir):
-              os.makedirs(extensionsRootDir)
-
-            if os.path.isfile(extensionSource):
-              reader = zipfile.ZipFile(extensionSource, "r")
-
-              for filename in reader.namelist():
-                # Sanity check the zip file.
-                if os.path.isabs(filename):
-                  self.log.info("INFO | automation.py | Cannot install extension, bad files in xpi")
-                  return
-
-                # We may need to dig the extensionID out of the zip file...
-                if extensionID is None and filename == installRDFFilename:
-                  extensionID = self.getExtensionIDFromRDF(reader.read(filename))
-
-              # We must know the extensionID now.
-              if extensionID is None:
-                self.log.info("INFO | automation.py | Cannot install extension, missing extensionID")
-                return
-
-              # Make the extension directory.
-              extensionDir = os.path.join(extensionsRootDir, extensionID)
-              os.mkdir(extensionDir)
-
-              # Extract all files.
-              reader.extractall(extensionDir)
-
-            elif os.path.isdir(extensionSource):
-              if extensionID is None:
-                filename = os.path.join(extensionSource, installRDFFilename)
-                if os.path.isfile(filename):
-                  with open(filename, "r") as installRDF:
-                    extensionID = self.getExtensionIDFromRDF(installRDF)
-
-                if extensionID is None:
-                  self.log.info("INFO | automation.py | Cannot install extension, missing extensionID")
-                  return
-
-              # Copy extension tree into its own directory.
-              # "destination directory must not already exist".
-              shutil.copytree(extensionSource, os.path.join(extensionsRootDir, extensionID))
-
-            else:
-              self.log.info("INFO | automation.py | Cannot install extension, invalid extensionSource at: %s", extensionSource)
-
-    # Set up what we need for the remote environment
-    def environment(self, env=None, xrePath=None, crashreporter=True, debugger=False):
-        # Because we are running remote, we don't want to mimic the local env
-        # so no copying of os.environ
-        if env is None:
-            env = {}
-
-        if crashreporter:
-            env['MOZ_CRASHREPORTER'] = '1'
-            env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
-
-        # We always hide the results table in B2G; it's much slower if we don't.
-        env['MOZ_HIDE_RESULTS_TABLE'] = '1'
-        return env
-
-    def waitForNet(self):
-        active = False
-        time_out = 0
-        while not active and time_out < 40:
-            data = self._devicemanager._runCmd(['shell', '/system/bin/netcfg']).stdout.readlines()
-            data.pop(0)
-            for line in data:
-                if (re.search(r'UP\s+(?:[0-9]{1,3}\.){3}[0-9]{1,3}', line)):
-                    active = True
-                    break
-            time_out += 1
-            time.sleep(1)
-        return active
-
-    def checkForCrashes(self, directory, symbolsPath):
-        crashed = False
-        remote_dump_dir = self._remoteProfile + '/minidumps'
-        print "checking for crashes in '%s'" % remote_dump_dir
-        if self._devicemanager.dirExists(remote_dump_dir):
-            local_dump_dir = tempfile.mkdtemp()
-            self._devicemanager.getDirectory(remote_dump_dir, local_dump_dir)
-            try:
-                logger = get_default_logger()
-                if logger is not None:
-                    crashed = mozcrash.log_crashes(logger, local_dump_dir, symbolsPath, test=self.lastTestSeen)
-                else:
-                    crashed = mozcrash.check_for_crashes(local_dump_dir, symbolsPath, test_name=self.lastTestSeen)
-            except:
-                traceback.print_exc()
-            finally:
-                shutil.rmtree(local_dump_dir)
-                self._devicemanager.removeDir(remote_dump_dir)
-        return crashed
-
-    def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs):
-        # if remote profile is specified, use that instead
-        if (self._remoteProfile):
-            profileDir = self._remoteProfile
-
-        cmd, args = Automation.buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs)
-
-        return app, args
-
-    def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime,
-                      debuggerInfo, symbolsPath, outputHandler=None):
-        """ Wait for tests to finish (as evidenced by a signature string
-            in logcat), or for a given amount of time to elapse with no
-            output.
-        """
-        timeout = timeout or 120
-        while True:
-            lines = proc.getStdoutLines(timeout)
-            if lines:
-                currentlog = '\n'.join(lines)
-
-                if outputHandler:
-                    for line in lines:
-                        outputHandler(line)
-                else:
-                    print(currentlog)
-
-                # Match the test filepath from the last TEST-START line found in the new
-                # log content. These lines are in the form:
-                # ... INFO TEST-START | /filepath/we/wish/to/capture.html\n
-                testStartFilenames = re.findall(r"TEST-START \| ([^\s]*)", currentlog)
-                if testStartFilenames:
-                    self.lastTestSeen = testStartFilenames[-1]
-                if (outputHandler and outputHandler.suite_finished) or (
-                        hasattr(self, 'logFinish') and self.logFinish in currentlog):
-                    return 0
-            else:
-                self.log.info("TEST-UNEXPECTED-FAIL | %s | application timed "
-                              "out after %d seconds with no output",
-                              self.lastTestSeen, int(timeout))
-                self._devicemanager.killProcess('/system/b2g/b2g', sig=signal.SIGABRT)
-
-                timeout = 10 # seconds
-                starttime = datetime.datetime.now()
-                while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
-                    if not self._devicemanager.processExist('/system/b2g/b2g'):
-                        break
-                    time.sleep(1)
-                else:
-                    print "timed out after %d seconds waiting for b2g process to exit" % timeout
-                    return 1
-
-                self.checkForCrashes(None, symbolsPath)
-                return 1
-
-    def getDeviceStatus(self, serial=None):
-        # Get the current status of the device.  If we know the device
-        # serial number, we look for that, otherwise we use the (presumably
-        # only) device shown in 'adb devices'.
-        serial = serial or self._devicemanager._deviceSerial
-        status = 'unknown'
-
-        for line in self._devicemanager._runCmd(['devices']).stdout.readlines():
-            result = re.match('(.*?)\t(.*)', line)
-            if result:
-                thisSerial = result.group(1)
-                if not serial or thisSerial == serial:
-                    serial = thisSerial
-                    status = result.group(2)
-
-        return (serial, status)
-
-    def restartB2G(self):
-        # TODO hangs in subprocess.Popen without this delay
-        time.sleep(5)
-        self._devicemanager._checkCmd(['shell', 'stop', 'b2g'])
-        # Wait for a bit to make sure B2G has completely shut down.
-        time.sleep(10)
-        self._devicemanager._checkCmd(['shell', 'start', 'b2g'])
-        if self._is_emulator:
-            self.marionette.emulator.wait_for_port(self.marionette.port)
-
-    def rebootDevice(self):
-        # find device's current status and serial number
-        serial, status = self.getDeviceStatus()
-
-        # reboot!
-        self._devicemanager._runCmd(['shell', '/system/bin/reboot'])
-
-        # The above command can return while adb still thinks the device is
-        # connected, so wait a little bit for it to disconnect from adb.
-        time.sleep(10)
-
-        # wait for device to come back to previous status
-        print 'waiting for device to come back online after reboot'
-        start = time.time()
-        rserial, rstatus = self.getDeviceStatus(serial)
-        while rstatus != 'device':
-            if time.time() - start > 120:
-                # device hasn't come back online in 2 minutes, something's wrong
-                raise Exception("Device %s (status: %s) not back online after reboot" % (serial, rstatus))
-            time.sleep(5)
-            rserial, rstatus = self.getDeviceStatus(serial)
-        print 'device:', serial, 'status:', rstatus
-
-    def Process(self, cmd, stdout=None, stderr=None, env=None, cwd=None):
-        # On a desktop or fennec run, the Process method invokes a gecko
-        # process in which to the tests.  For B2G, we simply
-        # reboot the device (which was configured with a test profile
-        # already), wait for B2G to start up, and then navigate to the
-        # test url using Marionette.  There doesn't seem to be any way
-        # to pass env variables into the B2G process, but this doesn't
-        # seem to matter.
-
-        # reboot device so it starts up with the mochitest profile
-        # XXX:  We could potentially use 'stop b2g' + 'start b2g' to achieve
-        # a similar effect; will see which is more stable while attempting
-        # to bring up the continuous integration.
-        if not self._is_emulator:
-            self.rebootDevice()
-            time.sleep(5)
-            #wait for wlan to come up
-            if not self.waitForNet():
-                raise Exception("network did not come up, please configure the network" +
-                                " prior to running before running the automation framework")
-
-        # stop b2g
-        self._devicemanager._runCmd(['shell', 'stop', 'b2g'])
-        time.sleep(5)
-
-        # For some reason user.js in the profile doesn't get picked up.
-        # Manually copy it over to prefs.js. See bug 1009730 for more details.
-        self._devicemanager.moveTree(posixpath.join(self._remoteProfile, 'user.js'),
-                                     posixpath.join(self._remoteProfile, 'prefs.js'))
-
-        # relaunch b2g inside b2g instance
-        instance = self.B2GInstance(self._devicemanager, env=env)
-
-        time.sleep(5)
-
-        # Set up port forwarding again for Marionette, since any that
-        # existed previously got wiped out by the reboot.
-        if not self._is_emulator:
-            self._devicemanager._checkCmd(['forward',
-                                           'tcp:%s' % self.marionette.port,
-                                           'tcp:%s' % self.marionette.port])
-
-        if self._is_emulator:
-            self.marionette.emulator.wait_for_port(self.marionette.port)
-        else:
-            time.sleep(5)
-
-        # start a marionette session
-        session = self.marionette.start_session()
-        if 'b2g' not in session:
-            raise Exception("bad session value %s returned by start_session" % session)
-
-        with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
-            self.marionette.execute_script("""
-                let SECURITY_PREF = "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer";
-                Components.utils.import("resource://gre/modules/Services.jsm");
-                Services.prefs.setBoolPref(SECURITY_PREF, true);
-
-                if (!testUtils.hasOwnProperty("specialPowersObserver")) {
-                  let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
-                    .getService(Components.interfaces.mozIJSSubScriptLoader);
-                  loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.jsm",
-                    testUtils);
-                  testUtils.specialPowersObserver = new testUtils.SpecialPowersObserver();
-                  testUtils.specialPowersObserver.init();
-                }
-                """)
-
-            # run the script that starts the tests
-            if self.test_script:
-                if os.path.isfile(self.test_script):
-                    script = open(self.test_script, 'r')
-                    self.marionette.execute_script(script.read(), script_args=self.test_script_args)
-                    script.close()
-                elif isinstance(self.test_script, basestring):
-                    self.marionette.execute_script(self.test_script, script_args=self.test_script_args)
-            else:
-                # assumes the tests are started on startup automatically
-                pass
-
-        return instance
-
-    # be careful here as this inner class doesn't have access to outer class members
-    class B2GInstance(object):
-        """Represents a B2G instance running on a device, and exposes
-           some process-like methods/properties that are expected by the
-           automation.
-        """
-
-        def __init__(self, dm, env=None):
-            self.dm = dm
-            self.env = env or {}
-            self.stdout_proc = None
-            self.queue = Queue.Queue()
-
-            # Launch b2g in a separate thread, and dump all output lines
-            # into a queue.  The lines in this queue are
-            # retrieved and returned by accessing the stdout property of
-            # this class.
-            cmd = [self.dm._adbPath]
-            if self.dm._deviceSerial:
-                cmd.extend(['-s', self.dm._deviceSerial])
-            cmd.append('shell')
-            for k, v in self.env.iteritems():
-                cmd.append("%s=%s" % (k, v))
-            cmd.append('/system/bin/b2g.sh')
-            proc = threading.Thread(target=self._save_stdout_proc, args=(cmd, self.queue))
-            proc.daemon = True
-            proc.start()
-
-        def _save_stdout_proc(self, cmd, queue):
-            self.stdout_proc = StdOutProc(cmd, queue)
-            self.stdout_proc.run()
-            if hasattr(self.stdout_proc, 'processOutput'):
-                self.stdout_proc.processOutput()
-            self.stdout_proc.wait()
-            self.stdout_proc = None
-
-        @property
-        def pid(self):
-            # a dummy value to make the automation happy
-            return 0
-
-        def getStdoutLines(self, timeout):
-            # Return any lines in the queue used by the
-            # b2g process handler.
-            lines = []
-            # get all of the lines that are currently available
-            while True:
-                try:
-                    lines.append(self.queue.get_nowait())
-                except Queue.Empty:
-                    break
-
-            # wait 'timeout' for any additional lines
-            if not lines:
-                try:
-                    lines.append(self.queue.get(True, timeout))
-                except Queue.Empty:
-                    pass
-            return lines
-
-        def wait(self, timeout=None):
-            # this should never happen
-            raise Exception("'wait' called on B2GInstance")
-
-        def kill(self):
-            # this should never happen
-            raise Exception("'kill' called on B2GInstance")
-
--- a/devtools/client/netmonitor/actions/filters.js
+++ b/devtools/client/netmonitor/actions/filters.js
@@ -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/. */
 
 "use strict";
 
 const {
+  ENABLE_REQUEST_FILTER_TYPE_ONLY,
   TOGGLE_REQUEST_FILTER_TYPE,
-  ENABLE_REQUEST_FILTER_TYPE_ONLY,
   SET_REQUEST_FILTER_TEXT,
 } = require("../constants");
 
 /**
  * Toggle an existing filter type state.
  * If type 'all' is specified, all the other filter types are set to false.
  * Available filter types are defined in filters reducer.
  *
@@ -35,24 +35,24 @@ function toggleRequestFilterType(filter)
 function enableRequestFilterTypeOnly(filter) {
   return {
     type: ENABLE_REQUEST_FILTER_TYPE_ONLY,
     filter,
   };
 }
 
 /**
- * Set filter text.
+ * Set filter text in toolbar.
  *
  * @param {string} text - A filter text is going to be set
  */
 function setRequestFilterText(text) {
   return {
     type: SET_REQUEST_FILTER_TEXT,
     text,
   };
 }
 
 module.exports = {
+  enableRequestFilterTypeOnly,
   toggleRequestFilterType,
-  enableRequestFilterTypeOnly,
   setRequestFilterText,
 };
--- a/devtools/client/netmonitor/components/search-box.js
+++ b/devtools/client/netmonitor/components/search-box.js
@@ -3,23 +3,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 const SearchBox = require("devtools/client/shared/components/search-box");
 const { L10N } = require("../l10n");
 const Actions = require("../actions/index");
-const { FREETEXT_FILTER_SEARCH_DELAY } = require("../constants");
+const { FILTER_SEARCH_DELAY } = require("../constants");
 
 module.exports = connect(
   (state) => ({
-    delay: FREETEXT_FILTER_SEARCH_DELAY,
+    delay: FILTER_SEARCH_DELAY,
     keyShortcut: L10N.getStr("netmonitor.toolbar.filterFreetext.key"),
     placeholder: L10N.getStr("netmonitor.toolbar.filterFreetext.label"),
     type: "filter",
   }),
   (dispatch) => ({
-    onChange: (url) => {
-      dispatch(Actions.setRequestFilterText(url));
-    },
+    onChange: (text) => dispatch(Actions.setRequestFilterText(text)),
   })
 )(SearchBox);
--- a/devtools/client/netmonitor/components/toolbar.js
+++ b/devtools/client/netmonitor/components/toolbar.js
@@ -5,17 +5,17 @@
 "use strict";
 
 const {
   createFactory,
   DOM,
 } = require("devtools/client/shared/vendor/react");
 const ClearButton = createFactory(require("./clear-button"));
 const FilterButtons = createFactory(require("./filter-buttons"));
-const SearchBox = createFactory(require("./search-box"));
+const ToolbarSearchBox = createFactory(require("./search-box"));
 const SummaryButton = createFactory(require("./summary-button"));
 const ToggleButton = createFactory(require("./toggle-button"));
 
 const { span } = DOM;
 
 /*
  * Network monitor toolbar component
  * Toolbar contains a set of useful tools to control network requests
@@ -23,15 +23,15 @@ const { span } = DOM;
 function Toolbar() {
   return span({ className: "devtools-toolbar devtools-toolbar-container" },
     span({ className: "devtools-toolbar-group" },
       ClearButton(),
       FilterButtons()
     ),
     span({ className: "devtools-toolbar-group" },
       SummaryButton(),
-      SearchBox(),
+      ToolbarSearchBox(),
       ToggleButton()
     )
   );
 }
 
 module.exports = Toolbar;
--- a/devtools/client/netmonitor/details-view.js
+++ b/devtools/client/netmonitor/details-view.js
@@ -1,48 +1,34 @@
 /* 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/. */
 
 /* eslint-disable mozilla/reject-some-requires */
-/* globals window, dumpn, $, gNetwork */
+/* globals window, dumpn, $ */
 
 "use strict";
 
 const promise = require("promise");
 const EventEmitter = require("devtools/shared/event-emitter");
-const { Heritage } = require("devtools/client/shared/widgets/view-helpers");
 const { Task } = require("devtools/shared/task");
 const { ToolSidebar } = require("devtools/client/framework/sidebar");
-const { VariablesView } = require("resource://devtools/client/shared/widgets/VariablesView.jsm");
 const { EVENTS } = require("./events");
-const { L10N } = require("./l10n");
 const { Filters } = require("./filter-predicates");
 const { createFactory } = require("devtools/client/shared/vendor/react");
 const ReactDOM = require("devtools/client/shared/vendor/react-dom");
 const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
+const CookiesPanel = createFactory(require("./shared/components/cookies-panel"));
 const HeadersPanel = createFactory(require("./shared/components/headers-panel"));
 const ParamsPanel = createFactory(require("./shared/components/params-panel"));
 const PreviewPanel = createFactory(require("./shared/components/preview-panel"));
 const ResponsePanel = createFactory(require("./shared/components/response-panel"));
 const SecurityPanel = createFactory(require("./shared/components/security-panel"));
 const TimingsPanel = createFactory(require("./shared/components/timings-panel"));
 
-const GENERIC_VARIABLES_VIEW_SETTINGS = {
-  lazyEmpty: true,
-  // ms
-  lazyEmptyDelay: 10,
-  searchEnabled: true,
-  editableValueTooltip: "",
-  editableNameTooltip: "",
-  preventDisableOnChange: true,
-  preventDescriptorModifiers: true,
-  eval: () => {}
-};
-
 /**
  * Functions handling the requests details view.
  */
 function DetailsView() {
   dumpn("DetailsView was instantiated");
 
   // The ToolSidebar requires the panel object to be able to emit events.
   EventEmitter.decorate(this);
@@ -65,16 +51,23 @@ DetailsView.prototype = {
   },
 
   /**
    * Initialization function, called when the network monitor is started.
    */
   initialize: function (store) {
     dumpn("Initializing the DetailsView");
 
+    this._cookiesPanelNode = $("#react-cookies-tabpanel-hook");
+
+    ReactDOM.render(Provider(
+      { store },
+      CookiesPanel()
+    ), this._cookiesPanelNode);
+
     this._headersPanelNode = $("#react-headers-tabpanel-hook");
 
     ReactDOM.render(Provider(
       { store },
       HeadersPanel()
     ), this._headersPanelNode);
 
     this._paramsPanelNode = $("#react-params-tabpanel-hook");
@@ -112,36 +105,27 @@ DetailsView.prototype = {
       TimingsPanel()
     ), this._timingsPanelNode);
 
     this.widget = $("#event-details-pane");
     this.sidebar = new ToolSidebar(this.widget, this, "netmonitor", {
       disableTelemetry: true,
       showAllTabsMenu: true
     });
-
-    this._cookies = new VariablesView($("#all-cookies"),
-      Heritage.extend(GENERIC_VARIABLES_VIEW_SETTINGS, {
-        emptyText: L10N.getStr("cookiesEmptyText"),
-        searchPlaceholder: L10N.getStr("cookiesFilterText")
-      }));
-
-    this._requestCookies = L10N.getStr("requestCookies");
-    this._responseCookies = L10N.getStr("responseCookies");
-
     $("tabpanels", this.widget).addEventListener("select", this._onTabSelect);
   },
 
   /**
    * Destruction function, called when the network monitor is closed.
    */
   destroy: function () {
     dumpn("Destroying the DetailsView");
+    ReactDOM.unmountComponentAtNode(this._cookiesPanelNode);
+    ReactDOM.unmountComponentAtNode(this._headersPanelNode);
     ReactDOM.unmountComponentAtNode(this._paramsPanelNode);
-    ReactDOM.unmountComponentAtNode(this._headersPanelNode);
     ReactDOM.unmountComponentAtNode(this._previewPanelNode);
     ReactDOM.unmountComponentAtNode(this._responsePanelNode);
     ReactDOM.unmountComponentAtNode(this._securityPanelNode);
     ReactDOM.unmountComponentAtNode(this._timingsPanelNode);
     this.sidebar.destroy();
     $("tabpanels", this.widget).removeEventListener("select",
       this._onTabSelect);
   },
@@ -172,18 +156,16 @@ DetailsView.prototype = {
     // request has no security information.
 
     if (!isHtml && this.widget.selectedPanel === $("#preview-tabpanel") ||
         !hasSecurityInfo && this.widget.selectedPanel ===
           $("#security-tabpanel")) {
       this.widget.selectedIndex = 0;
     }
 
-    this._cookies.empty();
-
     this._dataSrc = { src: data, populated: [] };
     this._onTabSelect();
     window.emit(EVENTS.NETWORKDETAILSVIEW_POPULATED);
 
     return promise.resolve();
   },
 
   /**
@@ -206,24 +188,16 @@ DetailsView.prototype = {
       // 997065 and 984687. As there's no way to stop the current task mark the
       // tab dirty and refresh the panel once the current task finishes.
       viewState.dirty[tab] = true;
       viewState.latestData = src;
       return;
     }
 
     Task.spawn(function* () {
-      viewState.updating[tab] = true;
-      switch (tab) {
-        // "Cookies"
-        case 1:
-          yield view._setResponseCookies(src.responseCookies);
-          yield view._setRequestCookies(src.requestCookies);
-          break;
-      }
       viewState.updating[tab] = false;
     }).then(() => {
       if (tab == this.widget.selectedIndex) {
         if (viewState.dirty[tab]) {
           // The request information was updated while the task was running.
           viewState.dirty[tab] = false;
           view.populate(viewState.latestData);
         } else {
@@ -234,83 +208,12 @@ DetailsView.prototype = {
       } else if (viewState.dirty[tab]) {
         // Tab is dirty but no longer selected. Don't refresh it now, it'll be
         // done if the tab is shown again.
         viewState.dirty[tab] = false;
       }
     }, e => console.error(e));
   },
 
-  /**
-   * Sets the network request cookies shown in this view.
-   *
-   * @param object response
-   *        The message received from the server.
-   * @return object
-   *        A promise that is resolved when the request cookies are set.
-   */
-  _setRequestCookies: Task.async(function* (response) {
-    if (response && response.cookies.length) {
-      response.cookies.sort((a, b) => a.name > b.name);
-      yield this._addCookies(this._requestCookies, response);
-    }
-  }),
-
-  /**
-   * Sets the network response cookies shown in this view.
-   *
-   * @param object response
-   *        The message received from the server.
-   * @return object
-   *        A promise that is resolved when the response cookies are set.
-   */
-  _setResponseCookies: Task.async(function* (response) {
-    if (response && response.cookies.length) {
-      yield this._addCookies(this._responseCookies, response);
-    }
-  }),
-
-  /**
-   * Populates the cookies container in this view with the specified data.
-   *
-   * @param string name
-   *        The type of cookies to populate (request or response).
-   * @param object response
-   *        The message received from the server.
-   * @return object
-   *        Returns a promise that resolves upon the adding of cookies.
-   */
-  _addCookies: Task.async(function* (name, response) {
-    let cookiesScope = this._cookies.addScope(name);
-    cookiesScope.expanded = true;
-
-    for (let cookie of response.cookies) {
-      let cookieVar = cookiesScope.addItem(cookie.name, {}, {relaxed: true});
-      let cookieValue = yield gNetwork.getString(cookie.value);
-      cookieVar.setGrip(cookieValue);
-
-      // By default the cookie name and value are shown. If this is the only
-      // information available, then nothing else is to be displayed.
-      let cookieProps = Object.keys(cookie);
-      if (cookieProps.length == 2) {
-        continue;
-      }
-
-      // Display any other information other than the cookie name and value
-      // which may be available.
-      let rawObject = Object.create(null);
-      let otherProps = cookieProps.filter(e => e != "name" && e != "value");
-      for (let prop of otherProps) {
-        rawObject[prop] = cookie[prop];
-      }
-      cookieVar.populate(rawObject);
-      cookieVar.twisty = true;
-      cookieVar.expanded = true;
-    }
-  }),
-
   _dataSrc: null,
-  _cookies: null,
-  _requestCookies: "",
-  _responseCookies: ""
 };
 
 exports.DetailsView = DetailsView;
--- a/devtools/client/netmonitor/netmonitor.xul
+++ b/devtools/client/netmonitor/netmonitor.xul
@@ -124,17 +124,18 @@
               <tabpanel id="headers-tabpanel"
                         class="tabpanel-content">
                 <html:div xmlns="http://www.w3.org/1999/xhtml"
                           id="react-headers-tabpanel-hook"/>
               </tabpanel>
               <tabpanel id="cookies-tabpanel"
                         class="tabpanel-content">
                 <vbox flex="1">
-                  <vbox id="all-cookies" flex="1"/>
+                  <html:div xmlns="http://www.w3.org/1999/xhtml"
+                      id="react-cookies-tabpanel-hook"/>
                 </vbox>
               </tabpanel>
               <tabpanel id="params-tabpanel"
                         class="tabpanel-content">
                 <html:div xmlns="http://www.w3.org/1999/xhtml"
                           id="react-params-tabpanel-hook"/>
               </tabpanel>
               <tabpanel id="response-tabpanel"
--- a/devtools/client/netmonitor/reducers/filters.js
+++ b/devtools/client/netmonitor/reducers/filters.js
@@ -1,18 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const I = require("devtools/client/shared/vendor/immutable");
 const {
+  ENABLE_REQUEST_FILTER_TYPE_ONLY,
   TOGGLE_REQUEST_FILTER_TYPE,
-  ENABLE_REQUEST_FILTER_TYPE_ONLY,
   SET_REQUEST_FILTER_TEXT,
 } = require("../constants");
 
 const FilterTypes = I.Record({
   all: false,
   html: false,
   css: false,
   js: false,
@@ -62,22 +62,22 @@ function enableRequestFilterTypeOnly(sta
     return state;
   }
 
   return new FilterTypes({ [filter]: true });
 }
 
 function filters(state = new Filters(), action) {
   switch (action.type) {
+    case ENABLE_REQUEST_FILTER_TYPE_ONLY:
+      return state.set("requestFilterTypes",
+        enableRequestFilterTypeOnly(state.requestFilterTypes, action));
     case TOGGLE_REQUEST_FILTER_TYPE:
       return state.set("requestFilterTypes",
         toggleRequestFilterType(state.requestFilterTypes, action));
-    case ENABLE_REQUEST_FILTER_TYPE_ONLY:
-      return state.set("requestFilterTypes",
-        enableRequestFilterTypeOnly(state.requestFilterTypes, action));
     case SET_REQUEST_FILTER_TEXT:
       return state.set("requestFilterText", action.text);
     default:
       return state;
   }
 }
 
 module.exports = filters;
--- a/devtools/client/netmonitor/requests-menu-view.js
+++ b/devtools/client/netmonitor/requests-menu-view.js
@@ -23,20 +23,20 @@ const { Prefs } = require("./prefs");
 const {
   fetchHeaders,
   formDataURI,
   getFormDataSections,
 } = require("./request-utils");
 
 const {
   getActiveFilters,
-  getSortedRequests,
   getDisplayedRequests,
   getRequestById,
   getSelectedRequest,
+  getSortedRequests,
 } = require("./selectors/index");
 
 // ms
 const RESIZE_REFRESH_RATE = 50;
 
 // A smart store watcher to notify store changes as necessary
 function storeWatcher(initialValue, reduceValue, onChange) {
   let currentValue = initialValue;
@@ -219,34 +219,36 @@ RequestsMenuView.prototype = {
       id,
       {
         startedMillis,
         method,
         url,
         isXHR,
         cause,
         fromCache,
-        fromServiceWorker
+        fromServiceWorker,
       },
       true
     );
 
     this.store.dispatch(action).then(() => window.emit(EVENTS.REQUEST_ADDED, action.id));
   },
 
   updateRequest: Task.async(function* (id, data) {
     const action = Actions.updateRequest(id, data, true);
     yield this.store.dispatch(action);
-
     let {
+      responseContent,
+      responseCookies,
+      responseHeaders,
+      requestCookies,
       requestHeaders,
       requestPostData,
-      responseContent,
-      responseHeaders,
     } = action.data;
+    let request = getRequestById(this.store.getState(), action.id);
 
     if (requestHeaders && requestHeaders.headers && requestHeaders.headers.length) {
       let headers = yield fetchHeaders(
         requestHeaders, gNetwork.getString.bind(gNetwork));
       if (headers) {
         yield this.store.dispatch(Actions.updateRequest(
           action.id,
           { requestHeaders: headers },
@@ -262,36 +264,33 @@ RequestsMenuView.prototype = {
         yield this.store.dispatch(Actions.updateRequest(
           action.id,
           { responseHeaders: headers },
           true,
         ));
       }
     }
 
-    if (responseContent && responseContent.content) {
-      let request = getRequestById(this.store.getState(), action.id);
-      if (request) {
-        let { mimeType } = request;
-        let { text, encoding } = responseContent.content;
-        let response = yield gNetwork.getString(text);
-        let payload = {};
+    if (request && responseContent && responseContent.content) {
+      let { mimeType } = request;
+      let { text, encoding } = responseContent.content;
+      let response = yield gNetwork.getString(text);
+      let payload = {};
 
-        if (mimeType.includes("image/")) {
-          payload.responseContentDataUri = formDataURI(mimeType, encoding, response);
-        }
+      if (mimeType.includes("image/")) {
+        payload.responseContentDataUri = formDataURI(mimeType, encoding, response);
+      }
 
-        responseContent.content.text = response;
-        payload.responseContent = responseContent;
+      responseContent.content.text = response;
+      payload.responseContent = responseContent;
 
-        yield this.store.dispatch(Actions.updateRequest(action.id, payload, true));
+      yield this.store.dispatch(Actions.updateRequest(action.id, payload, true));
 
-        if (mimeType.includes("image/")) {
-          window.emit(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED);
-        }
+      if (mimeType.includes("image/")) {
+        window.emit(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED);
       }
     }
 
     // Search the POST data upload stream for request headers and add
     // them as a separate property, different from the classic headers.
     if (requestPostData && requestPostData.postData) {
       let { text } = requestPostData.postData;
       let postData = yield gNetwork.getString(text);
@@ -301,16 +300,61 @@ RequestsMenuView.prototype = {
       }, 0);
       let payload = {};
       requestPostData.postData.text = postData;
       payload.requestPostData = Object.assign({}, requestPostData);
       payload.requestHeadersFromUploadStream = { headers, headersSize };
 
       yield this.store.dispatch(Actions.updateRequest(action.id, payload, true));
     }
+
+    // Fetch request and response cookies long value.
+    // Actor does not provide full sized cookie value when the value is too long
+    // To display values correctly, we need fetch them in each request.
+    if (requestCookies) {
+      let reqCookies = [];
+      // request store cookies in requestCookies or requestCookies.cookies
+      let cookies = requestCookies.cookies ?
+        requestCookies.cookies : requestCookies;
+      // make sure cookies is iterable
+      if (typeof cookies[Symbol.iterator] === "function") {
+        for (let cookie of cookies) {
+          reqCookies.push(Object.assign({}, cookie, {
+            value: yield gNetwork.getString(cookie.value),
+          }));
+        }
+        if (reqCookies.length) {
+          yield this.store.dispatch(Actions.updateRequest(
+            action.id,
+            { requestCookies: reqCookies },
+            true));
+        }
+      }
+    }
+
+    if (responseCookies) {
+      let resCookies = [];
+      // response store cookies in responseCookies or responseCookies.cookies
+      let cookies = responseCookies.cookies ?
+        responseCookies.cookies : responseCookies;
+      // make sure cookies is iterable
+      if (typeof cookies[Symbol.iterator] === "function") {
+        for (let cookie of cookies) {
+          resCookies.push(Object.assign({}, cookie, {
+            value: yield gNetwork.getString(cookie.value),
+          }));
+        }
+        if (resCookies.length) {
+          yield this.store.dispatch(Actions.updateRequest(
+            action.id,
+            { responseCookies: resCookies },
+            true));
+        }
+      }
+    }
   }),
 
   /**
    * Disable batched updates. Used by tests.
    */
   set lazyUpdate(value) {
     this.store.dispatch(Actions.batchEnable(value));
   },
--- a/devtools/client/netmonitor/selectors/requests.js
+++ b/devtools/client/netmonitor/selectors/requests.js
@@ -92,24 +92,52 @@ const getDisplayedRequestsSummary = crea
   }
 );
 
 const getSelectedRequest = createSelector(
   state => state.requests,
   ({ selectedId, requests }) => selectedId ? requests.get(selectedId) : null
 );
 
+const getSelectedRequestCookies = createSelector(
+  getSelectedRequest,
+  selectedRequest => {
+    // request store cookies in requestCookies or requestCookies.cookies
+    if (selectedRequest && selectedRequest.requestCookies) {
+      return selectedRequest.requestCookies.cookies ?
+        selectedRequest.requestCookies.cookies : selectedRequest.requestCookies;
+    }
+
+    return [];
+  }
+);
+
+const getSelectedResponseCookies = createSelector(
+  getSelectedRequest,
+  selectedRequest => {
+    // response store cookies in responseCookies or responseCookies.cookies
+    if (selectedRequest && selectedRequest.responseCookies) {
+      return selectedRequest.responseCookies.cookies ?
+        selectedRequest.responseCookies.cookies : selectedRequest.responseCookies;
+    }
+
+    return [];
+  }
+);
+
 function getRequestById(state, id) {
   return state.requests.requests.get(id);
 }
 
 function getDisplayedRequestById(state, id) {
   return getDisplayedRequests(state).find(r => r.id === id);
 }
 
 module.exports = {
   getDisplayedRequestById,
   getDisplayedRequests,
   getDisplayedRequestsSummary,
   getRequestById,
   getSelectedRequest,
+  getSelectedRequestCookies,
+  getSelectedResponseCookies,
   getSortedRequests,
 };
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/shared/components/cookies-panel.js
@@ -0,0 +1,99 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {
+  createFactory,
+  DOM,
+  PropTypes,
+} = require("devtools/client/shared/vendor/react");
+const { connect } = require("devtools/client/shared/vendor/react-redux");
+const { L10N } = require("../../l10n");
+const {
+  getSelectedRequestCookies,
+  getSelectedResponseCookies,
+} = require("../../selectors/index");
+
+// Component
+const PropertiesView = createFactory(require("./properties-view"));
+
+const { div } = DOM;
+
+const COOKIES_EMPTY_TEXT = L10N.getStr("cookiesEmptyText");
+const COOKIES_FILTER_TEXT = L10N.getStr("cookiesFilterText");
+const REQUEST_COOKIES = L10N.getStr("requestCookies");
+const RESPONSE_COOKIES = L10N.getStr("responseCookies");
+const SECTION_NAMES = [
+  RESPONSE_COOKIES,
+  REQUEST_COOKIES,
+];
+
+/*
+ * Cookies panel component
+ * This tab lists full details of any cookies sent with the request or response
+ */
+function CookiesPanel({
+  request,
+  response,
+}) {
+  if (!response.length && !request.length) {
+    return div({ className: "empty-notice" },
+      COOKIES_EMPTY_TEXT
+    );
+  }
+
+  let object = {};
+  if (response.length) {
+    object[RESPONSE_COOKIES] = getProperties(response);
+  }
+  if (request.length) {
+    object[REQUEST_COOKIES] = getProperties(request);
+  }
+
+  return (
+    PropertiesView({
+      object,
+      filterPlaceHolder: COOKIES_FILTER_TEXT,
+      sectionNames: SECTION_NAMES,
+    })
+  );
+}
+
+CookiesPanel.displayName = "CookiesPanel";
+
+CookiesPanel.propTypes = {
+  request: PropTypes.array.isRequired,
+  response: PropTypes.array.isRequired,
+};
+
+/**
+ * Mapping array to dict for TreeView usage.
+ * Since TreeView only support Object(dict) format.
+ *
+ * @param {Object[]} arr - key-value pair array like cookies or params
+ * @returns {Object}
+ */
+function getProperties(arr) {
+  return arr.reduce((map, obj) => {
+    // Generally cookies object contains only name and value properties and can
+    // be rendered as name: value pair.
+    // When there are more properties in cookies object such as extra or path,
+    // We will pass the object to display these extra information
+    if (Object.keys(obj).length > 2) {
+      map[obj.name] = Object.assign({}, obj);
+      delete map[obj.name].name;
+    } else {
+      map[obj.name] = obj.value;
+    }
+    return map;
+  }, {});
+}
+
+module.exports = connect(
+  state => ({
+    request: getSelectedRequestCookies(state),
+    response: getSelectedResponseCookies(state),
+  })
+)(CookiesPanel);
--- a/devtools/client/netmonitor/shared/components/moz.build
+++ b/devtools/client/netmonitor/shared/components/moz.build
@@ -1,13 +1,14 @@
 # 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/.
 
 DevToolsModules(
+    'cookies-panel.js',
     'editor.js',
     'headers-panel.js',
     'params-panel.js',
     'preview-panel.js',
     'properties-view.js',
     'response-panel.js',
     'security-panel.js',
     'timings-panel.js',
--- a/devtools/client/themes/netmonitor.css
+++ b/devtools/client/themes/netmonitor.css
@@ -1267,30 +1267,32 @@
   width: 100%;
   height: 100%;
 }
 
 /*
  * FIXME: normal html block element cannot fill outer XUL element
  * This workaround should be removed after netmonitor is migrated to react
  */
+#react-cookies-tabpanel-hook,
 #react-headers-tabpanel-hook,
 #react-params-tabpanel-hook,
 #react-preview-tabpanel-hook,
 #react-response-tabpanel-hook,
 #react-security-tabpanel-hook,
 #react-timings-tabpanel-hook,
 #network-statistics-charts,
 #primed-cache-chart,
 #empty-cache-chart {
   display: -moz-box;
   -moz-box-flex: 1;
 }
 
 /* For vbox */
+#react-cookies-tabpanel-hook,
 #react-headers-tabpanel-hook,
 #react-params-tabpanel-hook,
 #react-preview-tabpanel-hook,
 #react-response-tabpanel-hook,
 #react-security-tabpanel-hook,
 #react-timings-tabpanel-hook,
 #primed-cache-chart,
 #empty-cache-chart {
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -103,16 +103,18 @@ public:
 
     return copy.forget();
   }
 
   void WillRefresh(TimeStamp aTime) override
   {
     MOZ_ASSERT(NS_IsMainThread());
 
+    PROFILER_LABEL("HTMLCanvasElement", "FrameCapture", js::ProfileEntry::Category::OTHER);
+
     if (!mOwningElement) {
       return;
     }
 
     if (mOwningElement->IsWriteOnly()) {
       return;
     }
 
@@ -121,28 +123,39 @@ public:
     }
 
     mOwningElement->ProcessDestroyedFrameListeners();
 
     if (!mOwningElement->IsFrameCaptureRequested()) {
       return;
     }
 
-    RefPtr<SourceSurface> snapshot = mOwningElement->GetSurfaceSnapshot(nullptr);
-    if (!snapshot) {
-      return;
+    RefPtr<SourceSurface> snapshot;
+    {
+      PROFILER_LABEL("HTMLCanvasElement", "GetSnapshot", js::ProfileEntry::Category::OTHER);
+      snapshot = mOwningElement->GetSurfaceSnapshot(nullptr);
+      if (!snapshot) {
+        return;
+      }
     }
 
-    RefPtr<DataSourceSurface> copy = CopySurface(snapshot);
-    if (!copy) {
-      return;
+    RefPtr<DataSourceSurface> copy;
+    {
+      PROFILER_LABEL("HTMLCanvasElement", "CopySnapshot", js::ProfileEntry::Category::OTHER);
+      copy = CopySurface(snapshot);
+      if (!copy) {
+        return;
+      }
     }
 
-    mOwningElement->SetFrameCapture(copy.forget());
-    mOwningElement->MarkContextCleanForFrameCapture();
+    {
+      PROFILER_LABEL("HTMLCanvasElement", "SetFrame", js::ProfileEntry::Category::OTHER);
+      mOwningElement->SetFrameCapture(copy.forget());
+      mOwningElement->MarkContextCleanForFrameCapture();
+    }
   }
 
   void DetachFromRefreshDriver()
   {
     MOZ_ASSERT(mOwningElement);
     MOZ_ASSERT(mRefreshDriver);
 
     Unregister();
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -747,20 +747,20 @@ MediaDecoder::DiscardOngoingSeekIfExists
 
 void
 MediaDecoder::CallSeek(const SeekTarget& aTarget, dom::Promise* aPromise)
 {
   MOZ_ASSERT(NS_IsMainThread());
   DiscardOngoingSeekIfExists();
 
   mSeekDOMPromise = aPromise;
-  mSeekRequest.Begin(
-    mDecoderStateMachine->InvokeSeek(aTarget)
-    ->Then(AbstractThread::MainThread(), __func__, this,
-           &MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected));
+  mDecoderStateMachine->InvokeSeek(aTarget)
+  ->Then(AbstractThread::MainThread(), __func__, this,
+         &MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected)
+  ->Track(mSeekRequest);
 }
 
 double
 MediaDecoder::GetCurrentTime()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mLogicalPosition;
 }
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -335,24 +335,25 @@ public:
     MOZ_ASSERT(!mMetadataRequest.Exists());
     SLOG("Dispatching AsyncReadMetadata");
 
     // Set mode to METADATA since we are about to read metadata.
     Resource()->SetReadMode(MediaCacheStream::MODE_METADATA);
 
     // We disconnect mMetadataRequest in Exit() so it is fine to capture
     // a raw pointer here.
-    mMetadataRequest.Begin(Reader()->ReadMetadata()
+    Reader()->ReadMetadata()
       ->Then(OwnerThread(), __func__,
         [this] (MetadataHolder* aMetadata) {
           OnMetadataRead(aMetadata);
         },
         [this] (const MediaResult& aError) {
           OnMetadataNotRead(aError);
-        }));
+        })
+      ->Track(mMetadataRequest);
   }
 
   void Exit() override
   {
     mMetadataRequest.DisconnectIfExists();
   }
 
   State GetState() const override
@@ -1103,24 +1104,25 @@ public:
 
     RequestVideoData();
   }
 
 private:
   void DemuxerSeek()
   {
     // Request the demuxer to perform seek.
-    mSeekRequest.Begin(Reader()->Seek(mSeekJob.mTarget.ref())
+    Reader()->Seek(mSeekJob.mTarget.ref())
       ->Then(OwnerThread(), __func__,
              [this] (const media::TimeUnit& aUnit) {
                OnSeekResolved(aUnit);
              },
              [this] (const SeekRejectValue& aReject) {
                OnSeekRejected(aReject);
-             }));
+             })
+      ->Track(mSeekRequest);
   }
 
   void DoSeek() override
   {
     mDoneAudioSeeking = !Info().HasAudio() || mSeekJob.mTarget->IsVideoOnly();
     mDoneVideoSeeking = !Info().HasVideo();
 
     if (mSeekJob.mTarget->IsVideoOnly()) {
@@ -1186,30 +1188,28 @@ private:
     if (aReject.mError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
       SLOG("OnSeekRejected reason=WAITING_FOR_DATA type=%d", aReject.mType);
       MOZ_ASSERT(!mMaster->IsRequestingAudioData());
       MOZ_ASSERT(!mMaster->IsRequestingVideoData());
       MOZ_ASSERT(!mMaster->IsWaitingAudioData());
       MOZ_ASSERT(!mMaster->IsWaitingVideoData());
       // Fire 'waiting' to notify the player that we are waiting for data.
       mMaster->UpdateNextFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING);
-      mWaitRequest.Begin(
-        Reader()->WaitForData(aReject.mType)->Then(
-          OwnerThread(), __func__,
-          [this] (MediaData::Type aType) {
-            SLOG("OnSeekRejected wait promise resolved");
-            mWaitRequest.Complete();
-            DemuxerSeek();
-          },
-          [this] (const WaitForDataRejectValue& aRejection) {
-            SLOG("OnSeekRejected wait promise rejected");
-            mWaitRequest.Complete();
-            mMaster->DecodeError(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
-          })
-      );
+      Reader()->WaitForData(aReject.mType)->Then(
+        OwnerThread(), __func__,
+        [this] (MediaData::Type aType) {
+          SLOG("OnSeekRejected wait promise resolved");
+          mWaitRequest.Complete();
+          DemuxerSeek();
+        },
+        [this] (const WaitForDataRejectValue& aRejection) {
+          SLOG("OnSeekRejected wait promise rejected");
+          mWaitRequest.Complete();
+          mMaster->DecodeError(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
+        })->Track(mWaitRequest);
       return;
     }
 
     MOZ_ASSERT(NS_FAILED(aReject.mError), "Cancels should also disconnect mSeekRequest");
     mMaster->DecodeError(aReject.mError);
   }
 
   void RequestAudioData()
@@ -2081,17 +2081,17 @@ DecodingState::Enter()
   if (!mMaster->mIsVisible &&
       !mMaster->mVideoDecodeSuspendTimer.IsScheduled() &&
       !mMaster->mVideoDecodeSuspended) {
     // If we are not visible and the timer is not schedule, it means the timer
     // has timed out and we should suspend video decoding now if necessary.
     HandleVideoSuspendTimeout();
   }
 
-  if (mMaster->CheckIfDecodeComplete()) {
+  if (!mMaster->IsVideoDecoding() && !mMaster->IsAudioDecoding()) {
     SetState<CompletedState>();
     return;
   }
 
   mOnAudioPopped = AudioQueue().PopEvent().Connect(
     OwnerThread(), [this] () {
     if (mMaster->IsAudioDecoding() && !mMaster->HaveEnoughDecodedAudio()) {
       EnsureAudioDecodeTaskQueued();
@@ -2121,29 +2121,29 @@ DecodingState::Enter()
   }
 }
 
 void
 MediaDecoderStateMachine::
 DecodingState::HandleEndOfAudio()
 {
   AudioQueue().Finish();
-  if (mMaster->CheckIfDecodeComplete()) {
+  if (!mMaster->IsVideoDecoding()) {
     SetState<CompletedState>();
   } else {
     MaybeStopPrerolling();
   }
 }
 
 void
 MediaDecoderStateMachine::
 DecodingState::HandleEndOfVideo()
 {
   VideoQueue().Finish();
-  if (mMaster->CheckIfDecodeComplete()) {
+  if (!mMaster->IsAudioDecoding()) {
     SetState<CompletedState>();
   } else {
     MaybeStopPrerolling();
   }
 }
 
 void
 MediaDecoderStateMachine::
@@ -2377,30 +2377,30 @@ BufferingState::Step()
   SetState<DecodingState>();
 }
 
 void
 MediaDecoderStateMachine::
 BufferingState::HandleEndOfAudio()
 {
   AudioQueue().Finish();
-  if (mMaster->CheckIfDecodeComplete()) {
+  if (!mMaster->IsVideoDecoding()) {
     SetState<CompletedState>();
   } else {
     // Check if we can exit buffering.
     mMaster->ScheduleStateMachine();
   }
 }
 
 void
 MediaDecoderStateMachine::
 BufferingState::HandleEndOfVideo()
 {
   VideoQueue().Finish();
-  if (mMaster->CheckIfDecodeComplete()) {
+  if (!mMaster->IsAudioDecoding()) {
     SetState<CompletedState>();
   } else {
     // Check if we can exit buffering.
     mMaster->ScheduleStateMachine();
   }
 }
 
 RefPtr<ShutdownPromise>
@@ -2694,27 +2694,16 @@ MediaDecoderStateMachine::IsAudioDecodin
 
 bool
 MediaDecoderStateMachine::IsVideoDecoding()
 {
   MOZ_ASSERT(OnTaskQueue());
   return HasVideo() && !VideoQueue().IsFinished();
 }
 
-bool
-MediaDecoderStateMachine::CheckIfDecodeComplete()
-{
-  MOZ_ASSERT(OnTaskQueue());
-  // DecodeComplete is possible only after decoding first frames.
-  MOZ_ASSERT(mSentFirstFrameLoadedEvent);
-  MOZ_ASSERT(mState == DECODER_STATE_DECODING ||
-             mState == DECODER_STATE_BUFFERING);
-  return !IsVideoDecoding() && !IsAudioDecoding();
-}
-
 bool MediaDecoderStateMachine::IsPlaying() const
 {
   MOZ_ASSERT(OnTaskQueue());
   return mMediaSink->IsPlaying();
 }
 
 nsresult MediaDecoderStateMachine::Init(MediaDecoder* aDecoder)
 {
@@ -2734,20 +2723,21 @@ nsresult MediaDecoderStateMachine::Init(
 
   mOnMediaNotSeekable = mReader->OnMediaNotSeekable().Connect(
     OwnerThread(), [this] () {
       mMediaSeekable = false;
     });
 
   mMediaSink = CreateMediaSink(mAudioCaptured);
 
-  mCDMProxyPromise.Begin(aDecoder->RequestCDMProxy()->Then(
+  aDecoder->RequestCDMProxy()->Then(
     OwnerThread(), __func__, this,
     &MediaDecoderStateMachine::OnCDMProxyReady,
-    &MediaDecoderStateMachine::OnCDMProxyNotReady));
+    &MediaDecoderStateMachine::OnCDMProxyNotReady)
+  ->Track(mCDMProxyPromise);
 
   nsresult rv = mReader->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   RefPtr<MediaDecoderStateMachine> self = this;
   OwnerThread()->Dispatch(NS_NewRunnableFunction([self] () {
     MOZ_ASSERT(self->mState == DECODER_STATE_DECODING_METADATA);
     MOZ_ASSERT(!self->mStateObj);
@@ -3014,149 +3004,143 @@ MediaDecoderStateMachine::RequestAudioDa
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_ASSERT(IsAudioDecoding());
   MOZ_ASSERT(!IsRequestingAudioData());
   MOZ_ASSERT(!IsWaitingAudioData());
   SAMPLE_LOG("Queueing audio task - queued=%i, decoder-queued=%o",
              AudioQueue().GetSize(), mReader->SizeOfAudioQueueInFrames());
 
-  mAudioDataRequest.Begin(
-    mReader->RequestAudioData()->Then(
-      OwnerThread(), __func__,
-      [this] (MediaData* aAudio) {
-        MOZ_ASSERT(aAudio);
-        mAudioDataRequest.Complete();
-        // audio->GetEndTime() is not always mono-increasing in chained ogg.
-        mDecodedAudioEndTime = std::max(aAudio->GetEndTime(), mDecodedAudioEndTime);
-        SAMPLE_LOG("OnAudioDecoded [%lld,%lld]", aAudio->mTime, aAudio->GetEndTime());
-        mStateObj->HandleAudioDecoded(aAudio);
-      },
-      [this] (const MediaResult& aError) {
-        SAMPLE_LOG("OnAudioNotDecoded aError=%u", aError.Code());
-        mAudioDataRequest.Complete();
-        switch (aError.Code()) {
-          case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
-            mStateObj->HandleWaitingForAudio();
-            break;
-          case NS_ERROR_DOM_MEDIA_CANCELED:
-            mStateObj->HandleAudioCanceled();
-            break;
-          case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
-            mStateObj->HandleEndOfAudio();
-            break;
-          default:
-            DecodeError(aError);
-        }
-      })
-  );
+  mReader->RequestAudioData()->Then(
+    OwnerThread(), __func__,
+    [this] (MediaData* aAudio) {
+      MOZ_ASSERT(aAudio);
+      mAudioDataRequest.Complete();
+      // audio->GetEndTime() is not always mono-increasing in chained ogg.
+      mDecodedAudioEndTime = std::max(aAudio->GetEndTime(), mDecodedAudioEndTime);
+      SAMPLE_LOG("OnAudioDecoded [%lld,%lld]", aAudio->mTime, aAudio->GetEndTime());
+      mStateObj->HandleAudioDecoded(aAudio);
+    },
+    [this] (const MediaResult& aError) {
+      SAMPLE_LOG("OnAudioNotDecoded aError=%u", aError.Code());
+      mAudioDataRequest.Complete();
+      switch (aError.Code()) {
+        case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
+          mStateObj->HandleWaitingForAudio();
+          break;
+        case NS_ERROR_DOM_MEDIA_CANCELED:
+          mStateObj->HandleAudioCanceled();
+          break;
+        case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
+          mStateObj->HandleEndOfAudio();
+          break;
+        default:
+          DecodeError(aError);
+      }
+    })->Track(mAudioDataRequest);
 }
 
 void
 MediaDecoderStateMachine::RequestVideoData(bool aSkipToNextKeyframe,
                                            const media::TimeUnit& aCurrentTime)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_ASSERT(IsVideoDecoding());
   MOZ_ASSERT(!IsRequestingVideoData());
   MOZ_ASSERT(!IsWaitingVideoData());
   SAMPLE_LOG("Queueing video task - queued=%i, decoder-queued=%o, skip=%i, time=%lld",
              VideoQueue().GetSize(), mReader->SizeOfVideoQueueInFrames(), aSkipToNextKeyframe,
              aCurrentTime.ToMicroseconds());
 
   TimeStamp videoDecodeStartTime = TimeStamp::Now();
-  mVideoDataRequest.Begin(
-    mReader->RequestVideoData(aSkipToNextKeyframe, aCurrentTime)->Then(
-      OwnerThread(), __func__,
-      [this, videoDecodeStartTime] (MediaData* aVideo) {
-        MOZ_ASSERT(aVideo);
-        mVideoDataRequest.Complete();
-        // Handle abnormal or negative timestamps.
-        mDecodedVideoEndTime = std::max(mDecodedVideoEndTime, aVideo->GetEndTime());
-        SAMPLE_LOG("OnVideoDecoded [%lld,%lld]", aVideo->mTime, aVideo->GetEndTime());
-        mStateObj->HandleVideoDecoded(aVideo, videoDecodeStartTime);
-      },
-      [this] (const MediaResult& aError) {
-        SAMPLE_LOG("OnVideoNotDecoded aError=%u", aError.Code());
-        mVideoDataRequest.Complete();
-        switch (aError.Code()) {
-          case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
-            mStateObj->HandleWaitingForVideo();
-            break;
-          case NS_ERROR_DOM_MEDIA_CANCELED:
-            mStateObj->HandleVideoCanceled();
-            break;
-          case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
-            mStateObj->HandleEndOfVideo();
-            break;
-          default:
-            DecodeError(aError);
-        }
-      })
-  );
+  mReader->RequestVideoData(aSkipToNextKeyframe, aCurrentTime)->Then(
+    OwnerThread(), __func__,
+    [this, videoDecodeStartTime] (MediaData* aVideo) {
+      MOZ_ASSERT(aVideo);
+      mVideoDataRequest.Complete();
+      // Handle abnormal or negative timestamps.
+      mDecodedVideoEndTime = std::max(mDecodedVideoEndTime, aVideo->GetEndTime());
+      SAMPLE_LOG("OnVideoDecoded [%lld,%lld]", aVideo->mTime, aVideo->GetEndTime());
+      mStateObj->HandleVideoDecoded(aVideo, videoDecodeStartTime);
+    },
+    [this] (const MediaResult& aError) {
+      SAMPLE_LOG("OnVideoNotDecoded aError=%u", aError.Code());
+      mVideoDataRequest.Complete();
+      switch (aError.Code()) {
+        case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
+          mStateObj->HandleWaitingForVideo();
+          break;
+        case NS_ERROR_DOM_MEDIA_CANCELED:
+          mStateObj->HandleVideoCanceled();
+          break;
+        case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
+          mStateObj->HandleEndOfVideo();
+          break;
+        default:
+          DecodeError(aError);
+      }
+    })->Track(mVideoDataRequest);
 }
 
 void
 MediaDecoderStateMachine::WaitForData(MediaData::Type aType)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_ASSERT(aType == MediaData::AUDIO_DATA || aType == MediaData::VIDEO_DATA);
   if (aType == MediaData::AUDIO_DATA) {
-    mAudioWaitRequest.Begin(
-      mReader->WaitForData(MediaData::AUDIO_DATA)->Then(
-        OwnerThread(), __func__,
-        [this] (MediaData::Type aType) {
-          mAudioWaitRequest.Complete();
-          MOZ_ASSERT(aType == MediaData::AUDIO_DATA);
-          mStateObj->HandleAudioWaited(aType);
-        },
-        [this] (const WaitForDataRejectValue& aRejection) {
-          mAudioWaitRequest.Complete();
-          DecodeError(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
-        })
-    );
+    mReader->WaitForData(MediaData::AUDIO_DATA)->Then(
+      OwnerThread(), __func__,
+      [this] (MediaData::Type aType) {
+        mAudioWaitRequest.Complete();
+        MOZ_ASSERT(aType == MediaData::AUDIO_DATA);
+        mStateObj->HandleAudioWaited(aType);
+      },
+      [this] (const WaitForDataRejectValue& aRejection) {
+        mAudioWaitRequest.Complete();
+        DecodeError(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
+      })->Track(mAudioWaitRequest);
   } else {
-    mVideoWaitRequest.Begin(
-      mReader->WaitForData(MediaData::VIDEO_DATA)->Then(
-        OwnerThread(), __func__,
-        [this] (MediaData::Type aType) {
-          mVideoWaitRequest.Complete();
-          MOZ_ASSERT(aType == MediaData::VIDEO_DATA);
-          mStateObj->HandleVideoWaited(aType);
-        },
-        [this] (const WaitForDataRejectValue& aRejection) {
-          mVideoWaitRequest.Complete();
-          DecodeError(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
-        })
-    );
+    mReader->WaitForData(MediaData::VIDEO_DATA)->Then(
+      OwnerThread(), __func__,
+      [this] (MediaData::Type aType) {
+        mVideoWaitRequest.Complete();
+        MOZ_ASSERT(aType == MediaData::VIDEO_DATA);
+        mStateObj->HandleVideoWaited(aType);
+      },
+      [this] (const WaitForDataRejectValue& aRejection) {
+        mVideoWaitRequest.Complete();
+        DecodeError(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
+      })->Track(mVideoWaitRequest);
   }
 }
 
 void
 MediaDecoderStateMachine::StartMediaSink()
 {
   MOZ_ASSERT(OnTaskQueue());
   if (!mMediaSink->IsStarted()) {
     mAudioCompleted = false;
     mMediaSink->Start(GetMediaTime(), Info());
 
     auto videoPromise = mMediaSink->OnEnded(TrackInfo::kVideoTrack);
     auto audioPromise = mMediaSink->OnEnded(TrackInfo::kAudioTrack);
 
     if (audioPromise) {
-      mMediaSinkAudioPromise.Begin(audioPromise->Then(
+      audioPromise->Then(
         OwnerThread(), __func__, this,
         &MediaDecoderStateMachine::OnMediaSinkAudioComplete,
-        &MediaDecoderStateMachine::OnMediaSinkAudioError));
+        &MediaDecoderStateMachine::OnMediaSinkAudioError)
+      ->Track(mMediaSinkAudioPromise);
     }
     if (videoPromise) {
-      mMediaSinkVideoPromise.Begin(videoPromise->Then(
+      videoPromise->Then(
         OwnerThread(), __func__, this,
         &MediaDecoderStateMachine::OnMediaSinkVideoComplete,
-        &MediaDecoderStateMachine::OnMediaSinkVideoError));
+        &MediaDecoderStateMachine::OnMediaSinkVideoError)
+      ->Track(mMediaSinkVideoPromise);
     }
   }
 }
 
 bool
 MediaDecoderStateMachine::HasLowDecodedAudio()
 {
   MOZ_ASSERT(OnTaskQueue());
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -438,19 +438,16 @@ protected:
   // which has been pushed to the audio hardware for playback. Note that after
   // calling this, the audio hardware may play some of the audio pushed to
   // hardware, so this can only be used as a upper bound. The decoder monitor
   // must be held when calling this. Called on the decode thread.
   int64_t GetDecodedAudioDuration();
 
   void FinishDecodeFirstFrame();
 
-  // Queries our state to see whether the decode has finished for all streams.
-  bool CheckIfDecodeComplete();
-
   // Performs one "cycle" of the state machine.
   void RunStateMachine();
 
   bool IsStateMachineScheduled() const;
 
   // These return true if the respective stream's decode has not yet reached
   // the end of stream.
   bool IsAudioDecoding();
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -285,28 +285,28 @@ private:
 void
 MediaFormatReader::DecoderFactory::RunStage(TrackType aTrack)
 {
   auto& data = aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo;
 
   switch (data.mStage) {
     case Stage::None: {
       MOZ_ASSERT(!data.mToken);
-      data.mTokenPromise.Begin(DecoderAllocPolicy::Instance(aTrack).Alloc()->Then(
+      DecoderAllocPolicy::Instance(aTrack).Alloc()->Then(
         mOwner->OwnerThread(), __func__,
         [this, &data, aTrack] (Token* aToken) {
           data.mTokenPromise.Complete();
           data.mToken = aToken;
           data.mStage = Stage::CreateDecoder;
           RunStage(aTrack);
         },
         [&data] () {
           data.mTokenPromise.Complete();
           data.mStage = Stage::None;
-        }));
+        })->Track(data.mTokenPromise);
       data.mStage = Stage::WaitForToken;
       break;
     }
 
     case Stage::WaitForToken: {
       MOZ_ASSERT(!data.mToken);
       MOZ_ASSERT(data.mTokenPromise.Exists());
       break;
@@ -404,34 +404,34 @@ MediaFormatReader::DecoderFactory::DoCre
 }
 
 void
 MediaFormatReader::DecoderFactory::DoInitDecoder(TrackType aTrack)
 {
   auto& ownerData = mOwner->GetDecoderData(aTrack);
   auto& data = aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo;
 
-  data.mInitPromise.Begin(data.mDecoder->Init()->Then(
+  data.mDecoder->Init()->Then(
     mOwner->OwnerThread(), __func__,
     [this, &data, &ownerData] (TrackType aTrack) {
       data.mInitPromise.Complete();
       data.mStage = Stage::None;
       MutexAutoLock lock(ownerData.mMutex);
       ownerData.mDecoder = data.mDecoder.forget();
       ownerData.mDescription = ownerData.mDecoder->GetDescriptionName();
       mOwner->SetVideoDecodeThreshold();
       mOwner->ScheduleUpdate(aTrack);
     },
     [this, &data, aTrack] (MediaResult aError) {
       data.mInitPromise.Complete();
       data.mStage = Stage::None;
       data.mDecoder->Shutdown();
       data.mDecoder = nullptr;
       mOwner->NotifyError(aTrack, aError);
-    }));
+    })->Track(data.mInitPromise);
 }
 
 // DemuxerProxy ensures that the original main demuxer is only ever accessed
 // via its own dedicated task queue.
 // This ensure that the reader's taskqueue will never blocked while a demuxer
 // is itself blocked attempting to access the MediaCache or the MediaResource.
 class MediaFormatReader::DemuxerProxy
 {
@@ -972,20 +972,21 @@ MediaFormatReader::AsyncReadMetadata()
     RefPtr<MetadataHolder> metadata = new MetadataHolder();
     metadata->mInfo = mInfo;
     metadata->mTags = nullptr;
     return MetadataPromise::CreateAndResolve(metadata, __func__);
   }
 
   RefPtr<MetadataPromise> p = mMetadataPromise.Ensure(__func__);
 
-  mDemuxerInitRequest.Begin(mDemuxer->Init()
-                       ->Then(OwnerThread(), __func__, this,
-                              &MediaFormatReader::OnDemuxerInitDone,
-                              &MediaFormatReader::OnDemuxerInitFailed));
+  mDemuxer->Init()
+    ->Then(OwnerThread(), __func__, this,
+           &MediaFormatReader::OnDemuxerInitDone,
+           &MediaFormatReader::OnDemuxerInitFailed)
+    ->Track(mDemuxerInitRequest);
   return p;
 }
 
 void
 MediaFormatReader::OnDemuxerInitDone(nsresult)
 {
   MOZ_ASSERT(OnTaskQueue());
   mDemuxerInitRequest.Complete();
@@ -1272,19 +1273,20 @@ MediaFormatReader::DoDemuxVideo()
                 [self] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
                   self->OnFirstDemuxCompleted(TrackInfo::kVideoTrack, aSamples);
                 },
                 [self] (const MediaResult& aError) {
                   self->OnFirstDemuxFailed(TrackInfo::kVideoTrack, aError);
                 });
   }
 
-  mVideo.mDemuxRequest.Begin(p->Then(OwnerThread(), __func__, this,
-                                     &MediaFormatReader::OnVideoDemuxCompleted,
-                                     &MediaFormatReader::OnVideoDemuxFailed));
+  p->Then(OwnerThread(), __func__, this,
+          &MediaFormatReader::OnVideoDemuxCompleted,
+          &MediaFormatReader::OnVideoDemuxFailed)
+   ->Track(mVideo.mDemuxRequest);
 }
 
 void
 MediaFormatReader::OnVideoDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples)
 {
   LOGV("%d video samples demuxed (sid:%d)",
        aSamples->mSamples.Length(),
        aSamples->mSamples[0]->mTrackInfo ? aSamples->mSamples[0]->mTrackInfo->GetID() : 0);
@@ -1338,19 +1340,20 @@ MediaFormatReader::DoDemuxAudio()
                 [self] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
                   self->OnFirstDemuxCompleted(TrackInfo::kAudioTrack, aSamples);
                 },
                 [self] (const MediaResult& aError) {
                   self->OnFirstDemuxFailed(TrackInfo::kAudioTrack, aError);
                 });
   }
 
-  mAudio.mDemuxRequest.Begin(p->Then(OwnerThread(), __func__, this,
-                                     &MediaFormatReader::OnAudioDemuxCompleted,
-                                     &MediaFormatReader::OnAudioDemuxFailed));
+  p->Then(OwnerThread(), __func__, this,
+          &MediaFormatReader::OnAudioDemuxCompleted,
+          &MediaFormatReader::OnAudioDemuxFailed)
+   ->Track(mAudio.mDemuxRequest);
 }
 
 void
 MediaFormatReader::OnAudioDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples)
 {
   LOGV("%d audio samples demuxed (sid:%d)",
        aSamples->mSamples.Length(),
        aSamples->mSamples[0]->mTrackInfo ? aSamples->mSamples[0]->mTrackInfo->GetID() : 0);
@@ -1700,47 +1703,48 @@ MediaFormatReader::InternalSeek(TrackTyp
   LOG("%s internal seek to %f",
       TrackTypeToStr(aTrack), aTarget.Time().ToSeconds());
 
   auto& decoder = GetDecoderData(aTrack);
   decoder.Flush();
   decoder.ResetDemuxer();
   decoder.mTimeThreshold = Some(aTarget);
   RefPtr<MediaFormatReader> self = this;
-  decoder.mSeekRequest.Begin(decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().Time())
-             ->Then(OwnerThread(), __func__,
-                    [self, aTrack] (media::TimeUnit aTime) {
-                      auto& decoder = self->GetDecoderData(aTrack);
-                      decoder.mSeekRequest.Complete();
-                      MOZ_ASSERT(decoder.mTimeThreshold,
-                                 "Seek promise must be disconnected when timethreshold is reset");
-                      decoder.mTimeThreshold.ref().mHasSeeked = true;
-                      self->SetVideoDecodeThreshold();
-                      self->ScheduleUpdate(aTrack);
-                    },
-                    [self, aTrack] (const MediaResult& aError) {
-                      auto& decoder = self->GetDecoderData(aTrack);
-                      decoder.mSeekRequest.Complete();
-                      switch (aError.Code()) {
-                        case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
-                          self->NotifyWaitingForData(aTrack);
-                          break;
-                        case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
-                          decoder.mTimeThreshold.reset();
-                          self->NotifyEndOfStream(aTrack);
-                          break;
-                        case NS_ERROR_DOM_MEDIA_CANCELED:
-                          decoder.mTimeThreshold.reset();
-                          break;
-                        default:
-                          decoder.mTimeThreshold.reset();
-                          self->NotifyError(aTrack, aError);
-                          break;
-                      }
-                    }));
+  decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().Time())
+    ->Then(OwnerThread(), __func__,
+           [self, aTrack] (media::TimeUnit aTime) {
+             auto& decoder = self->GetDecoderData(aTrack);
+             decoder.mSeekRequest.Complete();
+             MOZ_ASSERT(decoder.mTimeThreshold,
+                        "Seek promise must be disconnected when timethreshold is reset");
+             decoder.mTimeThreshold.ref().mHasSeeked = true;
+             self->SetVideoDecodeThreshold();
+             self->ScheduleUpdate(aTrack);
+           },
+           [self, aTrack] (const MediaResult& aError) {
+             auto& decoder = self->GetDecoderData(aTrack);
+             decoder.mSeekRequest.Complete();
+             switch (aError.Code()) {
+               case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
+                 self->NotifyWaitingForData(aTrack);
+                 break;
+               case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
+                 decoder.mTimeThreshold.reset();
+                 self->NotifyEndOfStream(aTrack);
+                 break;
+               case NS_ERROR_DOM_MEDIA_CANCELED:
+                 decoder.mTimeThreshold.reset();
+                 break;
+               default:
+                 decoder.mTimeThreshold.reset();
+                 self->NotifyError(aTrack, aError);
+                 break;
+             }
+           })
+    ->Track(decoder.mSeekRequest);
 }
 
 void
 MediaFormatReader::DrainDecoder(TrackType aTrack)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   auto& decoder = GetDecoderData(aTrack);
@@ -2192,20 +2196,21 @@ MediaFormatReader::SkipVideoDemuxToNextK
   // As such we can drop all already decoded samples and discard all pending
   // samples.
   // TODO: Ideally we should set mOutputRequested to false so that all pending
   // frames are dropped too. However, we can't do such thing as the code assumes
   // that the decoder just got flushed. Once bug 1257107 land, we could set the
   // decoder threshold to the value of currentTime.
   DropDecodedSamples(TrackInfo::kVideoTrack);
 
-  mSkipRequest.Begin(mVideo.mTrackDemuxer->SkipToNextRandomAccessPoint(aTimeThreshold)
-                          ->Then(OwnerThread(), __func__, this,
-                                 &MediaFormatReader::OnVideoSkipCompleted,
-                                 &MediaFormatReader::OnVideoSkipFailed));
+  mVideo.mTrackDemuxer->SkipToNextRandomAccessPoint(aTimeThreshold)
+    ->Then(OwnerThread(), __func__, this,
+           &MediaFormatReader::OnVideoSkipCompleted,
+           &MediaFormatReader::OnVideoSkipFailed)
+    ->Track(mSkipRequest);
   return;
 }
 
 void
 MediaFormatReader::VideoSkipReset(uint32_t aSkipped)
 {
   MOZ_ASSERT(OnTaskQueue());
 
@@ -2403,20 +2408,21 @@ MediaFormatReader::OnSeekFailed(TrackTyp
 }
 
 void
 MediaFormatReader::DoVideoSeek()
 {
   MOZ_ASSERT(mPendingSeekTime.isSome());
   LOGV("Seeking video to %lld", mPendingSeekTime.ref().ToMicroseconds());
   media::TimeUnit seekTime = mPendingSeekTime.ref();
-  mVideo.mSeekRequest.Begin(mVideo.mTrackDemuxer->Seek(seekTime)
-                          ->Then(OwnerThread(), __func__, this,
-                                 &MediaFormatReader::OnVideoSeekCompleted,
-                                 &MediaFormatReader::OnVideoSeekFailed));
+  mVideo.mTrackDemuxer->Seek(seekTime)
+    ->Then(OwnerThread(), __func__, this,
+           &MediaFormatReader::OnVideoSeekCompleted,
+           &MediaFormatReader::OnVideoSeekFailed)
+    ->Track(mVideo.mSeekRequest);
 }
 
 void
 MediaFormatReader::OnVideoSeekCompleted(media::TimeUnit aTime)
 {
   MOZ_ASSERT(OnTaskQueue());
   LOGV("Video seeked to %lld", aTime.ToMicroseconds());
   mVideo.mSeekRequest.Complete();
@@ -2485,20 +2491,21 @@ MediaFormatReader::SetVideoDecodeThresho
 }
 
 void
 MediaFormatReader::DoAudioSeek()
 {
   MOZ_ASSERT(mPendingSeekTime.isSome());
   LOGV("Seeking audio to %lld", mPendingSeekTime.ref().ToMicroseconds());
   media::TimeUnit seekTime = mPendingSeekTime.ref();
-  mAudio.mSeekRequest.Begin(mAudio.mTrackDemuxer->Seek(seekTime)
-                         ->Then(OwnerThread(), __func__, this,
-                                &MediaFormatReader::OnAudioSeekCompleted,
-                                &MediaFormatReader::OnAudioSeekFailed));
+  mAudio.mTrackDemuxer->Seek(seekTime)
+    ->Then(OwnerThread(), __func__, this,
+           &MediaFormatReader::OnAudioSeekCompleted,
+           &MediaFormatReader::OnAudioSeekFailed)
+    ->Track(mAudio.mSeekRequest);
 }
 
 void
 MediaFormatReader::OnAudioSeekCompleted(media::TimeUnit aTime)
 {
   MOZ_ASSERT(OnTaskQueue());
   LOGV("Audio seeked to %lld", aTime.ToMicroseconds());
   mAudio.mSeekRequest.Complete();
@@ -2559,24 +2566,25 @@ MediaFormatReader::NotifyDataArrived()
     // Already one in progress. Reschedule for later.
     RefPtr<nsIRunnable> task(
         NewRunnableMethod(this, &MediaFormatReader::NotifyDataArrived));
     OwnerThread()->Dispatch(task.forget());
     return;
   }
 
   RefPtr<MediaFormatReader> self = this;
-  mNotifyDataArrivedPromise.Begin(mDemuxer->NotifyDataArrived()->Then(
-      OwnerThread(), __func__,
-      [self]() {
-        self->mNotifyDataArrivedPromise.Complete();
-        self->UpdateBuffered();
-        self->NotifyTrackDemuxers();
-      },
-      [self]() { self->mNotifyDataArrivedPromise.Complete(); }));
+  mDemuxer->NotifyDataArrived()
+    ->Then(OwnerThread(), __func__,
+           [self]() {
+             self->mNotifyDataArrivedPromise.Complete();
+             self->UpdateBuffered();
+             self->NotifyTrackDemuxers();
+           },
+           [self]() { self->mNotifyDataArrivedPromise.Complete(); })
+    ->Track(mNotifyDataArrivedPromise);
 }
 
 void
 MediaFormatReader::UpdateBuffered()
 {
   MOZ_ASSERT(OnTaskQueue());
 
   if (mShutdown) {
--- a/dom/media/MediaTimer.h
+++ b/dom/media/MediaTimer.h
@@ -140,20 +140,21 @@ public:
               RejectFunc&& aRejector)
   {
     MOZ_ASSERT(mTargetThread->IsCurrentThreadIn());
     if (IsScheduled() && mTarget <= aTarget) {
       return;
     }
     Reset();
     mTarget = aTarget;
-    mRequest.Begin(mMediaTimer->WaitUntil(mTarget, __func__)->Then(
+    mMediaTimer->WaitUntil(mTarget, __func__)->Then(
       mTargetThread, __func__,
       Forward<ResolveFunc>(aResolver),
-      Forward<RejectFunc>(aRejector)));
+      Forward<RejectFunc>(aRejector))
+    ->Track(mRequest);
   }
 
   void CompleteRequest()
   {
     MOZ_ASSERT(mTargetThread->IsCurrentThreadIn());
     mRequest.Complete();
     mTarget = TimeStamp();
   }
--- a/dom/media/android/AndroidMediaReader.cpp
+++ b/dom/media/android/AndroidMediaReader.cpp
@@ -325,25 +325,25 @@ AndroidMediaReader::Seek(const SeekTarge
     // a sync point, whereas for video there are only keyframes once every few
     // seconds. So if we have both audio and video, we must seek the video
     // stream to the preceeding keyframe first, get the stream time, and then
     // seek the audio stream to match the video stream's time. Otherwise, the
     // audio and video streams won't be in sync after the seek.
     mVideoSeekTimeUs = aTarget.GetTime().ToMicroseconds();
 
     RefPtr<AndroidMediaReader> self = this;
-    mSeekRequest.Begin(DecodeToFirstVideoData()->Then(OwnerThread(), __func__, [self] (MediaData* v) {
+    DecodeToFirstVideoData()->Then(OwnerThread(), __func__, [self] (MediaData* v) {
       self->mSeekRequest.Complete();
       self->mAudioSeekTimeUs = v->mTime;
       self->mSeekPromise.Resolve(media::TimeUnit::FromMicroseconds(self->mAudioSeekTimeUs), __func__);
     }, [self, aTarget] () {
       self->mSeekRequest.Complete();
       self->mAudioSeekTimeUs = aTarget.GetTime().ToMicroseconds();
       self->mSeekPromise.Resolve(aTarget.GetTime(), __func__);
-    }));
+    })->Track(mSeekRequest);
   } else {
     mAudioSeekTimeUs = mVideoSeekTimeUs = aTarget.GetTime().ToMicroseconds();
     mSeekPromise.Resolve(aTarget.GetTime(), __func__);
   }
 
   return p;
 }
 
--- a/dom/media/encoder/VP8TrackEncoder.cpp
+++ b/dom/media/encoder/VP8TrackEncoder.cpp
@@ -19,17 +19,16 @@
 namespace mozilla {
 
 LazyLogModule gVP8TrackEncoderLog("VP8TrackEncoder");
 #define VP8LOG(msg, ...) MOZ_LOG(gVP8TrackEncoderLog, mozilla::LogLevel::Debug, \
                                   (msg, ##__VA_ARGS__))
 // Debug logging macro with object pointer and class name.
 
 #define DEFAULT_BITRATE_BPS 2500000
-#define DEFAULT_ENCODE_FRAMERATE 30
 
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using namespace mozilla::media;
 
 static already_AddRefed<SourceSurface>
 GetSourceSurface(already_AddRefed<Image> aImg)
 {
@@ -51,19 +50,17 @@ GetSourceSurface(already_AddRefed<Image>
   });
 
   NS_DispatchToMainThread(runnable, NS_DISPATCH_SYNC);
   return surf.forget();
 }
 
 VP8TrackEncoder::VP8TrackEncoder(TrackRate aTrackRate)
   : VideoTrackEncoder(aTrackRate)
-  , mEncodedFrameDuration(0)
   , mEncodedTimestamp(0)
-  , mRemainingTicks(0)
   , mVPXContext(new vpx_codec_ctx_t())
   , mVPXImageWrapper(new vpx_image_t())
 {
   MOZ_COUNT_CTOR(VP8TrackEncoder);
 }
 
 VP8TrackEncoder::~VP8TrackEncoder()
 {
@@ -82,18 +79,16 @@ VP8TrackEncoder::Init(int32_t aWidth, in
                       int32_t aDisplayHeight)
 {
   if (aWidth < 1 || aHeight < 1 || aDisplayWidth < 1 || aDisplayHeight < 1) {
     return NS_ERROR_FAILURE;
   }
 
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
-  mEncodedFrameRate = DEFAULT_ENCODE_FRAMERATE;
-  mEncodedFrameDuration = mTrackRate / mEncodedFrameRate;
   mFrameWidth = aWidth;
   mFrameHeight = aHeight;
   mDisplayWidth = aDisplayWidth;
   mDisplayHeight = aDisplayHeight;
 
   // Encoder configuration structure.
   vpx_codec_enc_cfg_t config;
   memset(&config, 0, sizeof(vpx_codec_enc_cfg_t));
@@ -142,17 +137,17 @@ VP8TrackEncoder::Init(int32_t aWidth, in
   config.rc_undershoot_pct = 100;
   config.rc_overshoot_pct = 15;
   config.rc_buf_initial_sz = 500;
   config.rc_buf_optimal_sz = 600;
   config.rc_buf_sz = 1000;
 
   config.kf_mode = VPX_KF_AUTO;
   // Ensure that we can output one I-frame per second.
-  config.kf_max_dist = mEncodedFrameRate;
+  config.kf_max_dist = 60;
 
   vpx_codec_flags_t flags = 0;
   flags |= VPX_CODEC_USE_OUTPUT_PARTITION;
   if (vpx_codec_enc_init(mVPXContext, vpx_codec_vp8_cx(), &config, flags)) {
     return NS_ERROR_FAILURE;
   }
 
   vpx_codec_control(mVPXContext, VP8E_SET_STATIC_THRESHOLD, 1);
@@ -183,17 +178,16 @@ VP8TrackEncoder::GetMetadata()
     return nullptr;
   }
 
   RefPtr<VP8Metadata> meta = new VP8Metadata();
   meta->mWidth = mFrameWidth;
   meta->mHeight = mFrameHeight;
   meta->mDisplayWidth = mDisplayWidth;
   meta->mDisplayHeight = mDisplayHeight;
-  meta->mEncodedFrameRate = mEncodedFrameRate;
 
   return meta.forget();
 }
 
 bool
 VP8TrackEncoder::GetEncodedPartitions(EncodedFrameContainer& aData)
 {
   vpx_codec_iter_t iter = nullptr;
@@ -468,201 +462,128 @@ nsresult VP8TrackEncoder::PrepareRawFram
  * the processed frame duration in mSourceSegment
  * in order to set the nextEncodeOperation for next target frame.
  */
 VP8TrackEncoder::EncodeOperation
 VP8TrackEncoder::GetNextEncodeOperation(TimeDuration aTimeElapsed,
                                         StreamTime aProcessedDuration)
 {
   int64_t durationInUsec =
-    FramesToUsecs(aProcessedDuration + mEncodedFrameDuration,
-                  mTrackRate).value();
+    FramesToUsecs(aProcessedDuration, mTrackRate).value();
   if (aTimeElapsed.ToMicroseconds() > (durationInUsec * SKIP_FRAME_RATIO)) {
     // The encoder is too slow.
     // We should skip next frame to consume the mSourceSegment.
     return SKIP_FRAME;
   } else if (aTimeElapsed.ToMicroseconds() > (durationInUsec * I_FRAME_RATIO)) {
     // The encoder is a little slow.
     // We force the encoder to encode an I-frame to accelerate.
     return ENCODE_I_FRAME;
   } else {
     return ENCODE_NORMAL_FRAME;
   }
 }
 
-StreamTime
-VP8TrackEncoder::CalculateRemainingTicks(StreamTime aDurationCopied,
-                                         StreamTime aEncodedDuration)
-{
-  return mRemainingTicks + aEncodedDuration - aDurationCopied;
-}
-
-// Try to extend the encodedDuration as long as possible if the target frame
-// has a long duration.
-StreamTime
-VP8TrackEncoder::CalculateEncodedDuration(StreamTime aDurationCopied)
-{
-  StreamTime temp64 = aDurationCopied;
-  StreamTime encodedDuration = mEncodedFrameDuration;
-  temp64 -= mRemainingTicks;
-  while (temp64 > mEncodedFrameDuration) {
-    temp64 -= mEncodedFrameDuration;
-    encodedDuration += mEncodedFrameDuration;
-  }
-  return encodedDuration;
-}
-
 /**
  * Encoding flow in GetEncodedTrack():
  * 1: Check the mInitialized state and the packet duration.
  * 2: Move the data from mRawSegment to mSourceSegment.
  * 3: Encode the video chunks in mSourceSegment in a for-loop.
- * 3.1: Pick the video chunk by mRemainingTicks.
- * 3.2: Calculate the encoding duration for the parameter of vpx_codec_encode().
- *      The encoding duration is a multiple of mEncodedFrameDuration.
- * 3.3: Setup the video chunk to mVPXImageWrapper by PrepareRawFrame().
- * 3.4: Send frame into vp8 encoder by vpx_codec_encode().
- * 3.5: Get the output frame from encoder by calling GetEncodedPartitions().
- * 3.6: Calculate the mRemainingTicks for next target frame.
- * 3.7: Set the nextEncodeOperation for the next target frame.
+ * 3.1: The duration is taken straight from the video chunk's duration.
+ * 3.2: Setup the video chunk with mVPXImageWrapper by PrepareRawFrame().
+ * 3.3: Pass frame to vp8 encoder by vpx_codec_encode().
+ * 3.4: Get the encoded frame from encoder by GetEncodedPartitions().
+ * 3.5: Set the nextEncodeOperation for the next target frame.
  *      There is a heuristic: If the frame duration we have processed in
  *      mSourceSegment is 100ms, means that we can't spend more than 100ms to
  *      encode it.
  * 4. Remove the encoded chunks in mSourceSegment after for-loop.
- *
- * Ex1: Input frame rate is 100 => input frame duration is 10ms for each.
- *     mEncodedFrameRate is 30 => output frame duration is 33ms.
- *     In this case, the frame duration in mSourceSegment will be:
- *     1st : 0~10ms
- *     2nd : 10~20ms
- *     3rd : 20~30ms
- *     4th : 30~40ms
- *     ...
- *     The VP8 encoder will take the 1st and 4th frames to encode. At beginning
- *     mRemainingTicks is 0 for 1st frame, then the mRemainingTicks is set
- *     to 23 to pick the 4th frame. (mEncodedFrameDuration - 1st frame duration)
- *
- * Ex2: Input frame rate is 25 => frame duration is 40ms for each.
- *     mEncodedFrameRate is 30 => output frame duration is 33ms.
- *     In this case, the frame duration in mSourceSegment will be:
- *     1st : 0~40ms
- *     2nd : 40~80ms
- *     3rd : 80~120ms
- *     4th : 120~160ms
- *     ...
- *     Because the input frame duration is 40ms larger than 33ms, so the first
- *     encoded frame duration will be 66ms by calling CalculateEncodedDuration.
- *     And the mRemainingTicks will be set to 26
- *     (CalculateRemainingTicks 0+66-40) in order to pick the next frame(2nd)
- *     in mSourceSegment.
  */
 nsresult
 VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
 {
   PROFILER_LABEL("VP8TrackEncoder", "GetEncodedTrack",
     js::ProfileEntry::Category::OTHER);
   bool EOS;
   {
     // Move all the samples from mRawSegment to mSourceSegment. We only hold
     // the monitor in this block.
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     // Wait if mEncoder is not initialized, or when not enough raw data, but is
     // not the end of stream nor is being canceled.
     while (!mCanceled && (!mInitialized ||
-           (mRawSegment.GetDuration() + mSourceSegment.GetDuration() <
-            mEncodedFrameDuration && !mEndOfStream))) {
+           (mRawSegment.GetDuration() + mSourceSegment.GetDuration() == 0 &&
+            !mEndOfStream))) {
       mon.Wait();
     }
     if (mCanceled || mEncodingComplete) {
       return NS_ERROR_FAILURE;
     }
     mSourceSegment.AppendFrom(&mRawSegment);
     EOS = mEndOfStream;
   }
 
-  VideoSegment::ChunkIterator iter(mSourceSegment);
-  StreamTime durationCopied = 0;
   StreamTime totalProcessedDuration = 0;
   TimeStamp timebase = TimeStamp::Now();
   EncodeOperation nextEncodeOperation = ENCODE_NORMAL_FRAME;
 
-  for (; !iter.IsEnded(); iter.Next()) {
+  for (VideoSegment::ChunkIterator iter(mSourceSegment);
+       !iter.IsEnded(); iter.Next()) {
     VideoChunk &chunk = *iter;
-    // Accumulate chunk's duration to durationCopied until it reaches
-    // mRemainingTicks.
-    durationCopied += chunk.GetDuration();
-    MOZ_ASSERT(mRemainingTicks <= mEncodedFrameDuration);
-    VP8LOG("durationCopied %lld mRemainingTicks %lld\n",
-           durationCopied, mRemainingTicks);
-    if (durationCopied >= mRemainingTicks) {
-      VP8LOG("nextEncodeOperation is %d\n",nextEncodeOperation);
-      // Calculate encodedDuration for this target frame.
-      StreamTime encodedDuration = CalculateEncodedDuration(durationCopied);
+    VP8LOG("nextEncodeOperation is %d for frame of duration %lld\n",
+           nextEncodeOperation, chunk.GetDuration());
 
-      // Encode frame.
-      if (nextEncodeOperation != SKIP_FRAME) {
-        nsresult rv = PrepareRawFrame(chunk);
-        NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+    // Encode frame.
+    if (nextEncodeOperation != SKIP_FRAME) {
+      nsresult rv = PrepareRawFrame(chunk);
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
 
-        // Encode the data with VP8 encoder
-        int flags = (nextEncodeOperation == ENCODE_NORMAL_FRAME) ?
-                    0 : VPX_EFLAG_FORCE_KF;
-        if (vpx_codec_encode(mVPXContext, mVPXImageWrapper, mEncodedTimestamp,
-                             (unsigned long)encodedDuration, flags,
-                             VPX_DL_REALTIME)) {
-          return NS_ERROR_FAILURE;
-        }
-        // Get the encoded data from VP8 encoder.
-        GetEncodedPartitions(aData);
-      } else {
-        // SKIP_FRAME
-        // Extend the duration of the last encoded data in aData
-        // because this frame will be skip.
-        RefPtr<EncodedFrame> last = nullptr;
-        last = aData.GetEncodedFrames().LastElement();
-        if (last) {
-          last->SetDuration(last->GetDuration() + encodedDuration);
-        }
+      // Encode the data with VP8 encoder
+      int flags = (nextEncodeOperation == ENCODE_NORMAL_FRAME) ?
+                  0 : VPX_EFLAG_FORCE_KF;
+      if (vpx_codec_encode(mVPXContext, mVPXImageWrapper, mEncodedTimestamp,
+                           (unsigned long)chunk.GetDuration(), flags,
+                           VPX_DL_REALTIME)) {
+        return NS_ERROR_FAILURE;
       }
-      // Move forward the mEncodedTimestamp.
-      mEncodedTimestamp += encodedDuration;
-      totalProcessedDuration += durationCopied;
-      // Calculate mRemainingTicks for next target frame.
-      mRemainingTicks = CalculateRemainingTicks(durationCopied,
-                                                encodedDuration);
-
-      // Check the remain data is enough for next target frame.
-      if (mSourceSegment.GetDuration() - totalProcessedDuration
-          >= mEncodedFrameDuration) {
-        TimeDuration elapsedTime = TimeStamp::Now() - timebase;
-        nextEncodeOperation = GetNextEncodeOperation(elapsedTime,
-                                                     totalProcessedDuration);
-        // Reset durationCopied for next iteration.
-        durationCopied = 0;
-      } else {
-        // Process done, there is no enough data left for next iteration,
-        // break the for-loop.
-        break;
+      // Get the encoded data from VP8 encoder.
+      GetEncodedPartitions(aData);
+    } else {
+      // SKIP_FRAME
+      // Extend the duration of the last encoded data in aData
+      // because this frame will be skip.
+      NS_WARNING("MediaRecorder lagging behind. Skipping a frame.");
+      RefPtr<EncodedFrame> last = aData.GetEncodedFrames().LastElement();
+      if (last) {
+        last->SetDuration(last->GetDuration() + chunk.GetDuration());
       }
     }
+
+    // Move forward the mEncodedTimestamp.
+    mEncodedTimestamp += chunk.GetDuration();
+    totalProcessedDuration += chunk.GetDuration();
+
+    // Check what to do next.
+    TimeDuration elapsedTime = TimeStamp::Now() - timebase;
+    nextEncodeOperation = GetNextEncodeOperation(elapsedTime,
+                                                 totalProcessedDuration);
   }
+
   // Remove the chunks we have processed.
-  mSourceSegment.RemoveLeading(totalProcessedDuration);
-  VP8LOG("RemoveLeading %lld\n",totalProcessedDuration);
+  mSourceSegment.Clear();
 
   // End of stream, pull the rest frames in encoder.
   if (EOS) {
     VP8LOG("mEndOfStream is true\n");
     mEncodingComplete = true;
     // Bug 1243611, keep calling vpx_codec_encode and vpx_codec_get_cx_data
     // until vpx_codec_get_cx_data return null.
 
     do {
       if (vpx_codec_encode(mVPXContext, nullptr, mEncodedTimestamp,
-                           mEncodedFrameDuration, 0, VPX_DL_REALTIME)) {
+                           0, 0, VPX_DL_REALTIME)) {
         return NS_ERROR_FAILURE;
       }
     } while(GetEncodedPartitions(aData));
   }
 
   return NS_OK ;
 }
 
--- a/dom/media/encoder/VP8TrackEncoder.h
+++ b/dom/media/encoder/VP8TrackEncoder.h
@@ -11,20 +11,19 @@
 
 namespace mozilla {
 
 typedef struct vpx_codec_ctx vpx_codec_ctx_t;
 typedef struct vpx_codec_enc_cfg vpx_codec_enc_cfg_t;
 typedef struct vpx_image vpx_image_t;
 
 /**
- * VP8TrackEncoder implements VideoTrackEncoder by using libvpx library.
- * We implement a realtime and fixed FPS encoder. In order to achieve that,
- * there is a pick target frame and drop frame encoding policy implemented in
- * GetEncodedTrack.
+ * VP8TrackEncoder implements VideoTrackEncoder by using the libvpx library.
+ * We implement a realtime and variable frame rate encoder. In order to achieve
+ * that, there is a frame-drop encoding policy implemented in GetEncodedTrack.
  */
 class VP8TrackEncoder : public VideoTrackEncoder
 {
   enum EncodeOperation {
     ENCODE_NORMAL_FRAME, // VP8 track encoder works normally.
     ENCODE_I_FRAME, // The next frame will be encoded as I-Frame.
     SKIP_FRAME, // Skip the next frame.
   };
@@ -36,55 +35,40 @@ public:
 
   nsresult GetEncodedTrack(EncodedFrameContainer& aData) final override;
 
 protected:
   nsresult Init(int32_t aWidth, int32_t aHeight,
                 int32_t aDisplayWidth, int32_t aDisplayHeight) final override;
 
 private:
-  // Calculate the target frame's encoded duration.
-  StreamTime CalculateEncodedDuration(StreamTime aDurationCopied);
-
-  // Calculate the mRemainingTicks for next target frame.
-  StreamTime CalculateRemainingTicks(StreamTime aDurationCopied,
-                                     StreamTime aEncodedDuration);
-
   // Get the EncodeOperation for next target frame.
   EncodeOperation GetNextEncodeOperation(TimeDuration aTimeElapsed,
                                          StreamTime aProcessedDuration);
 
   // Get the encoded data from encoder to aData.
   // Return value: false if the vpx_codec_get_cx_data returns null
   //               for EOS detection.
   bool GetEncodedPartitions(EncodedFrameContainer& aData);
 
   // Prepare the input data to the mVPXImageWrapper for encoding.
   nsresult PrepareRawFrame(VideoChunk &aChunk);
 
-  // Output frame rate.
-  uint32_t mEncodedFrameRate;
-  // Duration for the output frame, reciprocal to mEncodedFrameRate.
-  StreamTime mEncodedFrameDuration;
   // Encoded timestamp.
   StreamTime mEncodedTimestamp;
-  // Duration to the next encode frame.
-  StreamTime mRemainingTicks;
 
   // Muted frame, we only create it once.
   RefPtr<layers::Image> mMuteFrame;
 
   // I420 frame, for converting to I420.
   nsTArray<uint8_t> mI420Frame;
 
   /**
    * A local segment queue which takes the raw data out from mRawSegment in the
-   * call of GetEncodedTrack(). Since we implement the fixed FPS encoding
-   * policy, it needs to be global in order to store the leftover segments
-   * taken from mRawSegment.
+   * call of GetEncodedTrack().
    */
   VideoSegment mSourceSegment;
 
   // VP8 relative members.
   // Codec context structure.
   nsAutoPtr<vpx_codec_ctx_t> mVPXContext;
   // Image Descriptor.
   nsAutoPtr<vpx_image_t> mVPXImageWrapper;
--- a/dom/media/gtest/TestMozPromise.cpp
+++ b/dom/media/gtest/TestMozPromise.cpp
@@ -275,13 +275,13 @@ TEST(MozPromise, Chaining)
             holder.Disconnect();
             queue->BeginShutdown();
           },
           DO_FAIL);
       }
     }
     // We will hit the assertion if we don't disconnect the leaf Request
     // in the promise chain.
-    holder.Begin(p->Then(queue, __func__, [] () {}, [] () {}));
+    p->Then(queue, __func__, [] () {}, [] () {})->Track(holder);
   });
 }
 
 #undef DO_FAIL
--- a/dom/media/mediasink/AudioSinkWrapper.cpp
+++ b/dom/media/mediasink/AudioSinkWrapper.cpp
@@ -188,20 +188,21 @@ AudioSinkWrapper::Start(int64_t aStartTi
 
   // no audio is equivalent to audio ended before video starts.
   mAudioEnded = !aInfo.HasAudio();
 
   if (aInfo.HasAudio()) {
     mAudioSink = mCreator->Create();
     mEndPromise = mAudioSink->Init(mParams);
 
-    mAudioSinkPromise.Begin(mEndPromise->Then(
+    mEndPromise->Then(
       mOwnerThread.get(), __func__, this,
       &AudioSinkWrapper::OnAudioEnded,
-      &AudioSinkWrapper::OnAudioEnded));
+      &AudioSinkWrapper::OnAudioEnded
+    )->Track(mAudioSinkPromise);
   }
 }
 
 void
 AudioSinkWrapper::Stop()
 {
   AssertOwnerThread();
   MOZ_ASSERT(mIsStarted, "playback not started.");
--- a/dom/media/mediasink/VideoSink.cpp
+++ b/dom/media/mediasink/VideoSink.cpp
@@ -180,29 +180,30 @@ VideoSink::Start(int64_t aStartTime, con
     // If the underlying MediaSink has an end promise for the video track (which
     // happens when mAudioSink refers to a DecodedStream), we must wait for it
     // to complete before resolving our own end promise. Otherwise, MDSM might
     // stop playback before DecodedStream plays to the end and cause
     // test_streams_element_capture.html to time out.
     RefPtr<GenericPromise> p = mAudioSink->OnEnded(TrackInfo::kVideoTrack);
     if (p) {
       RefPtr<VideoSink> self = this;
-      mVideoSinkEndRequest.Begin(p->Then(mOwnerThread, __func__,
+      p->Then(mOwnerThread, __func__,
         [self] () {
           self->mVideoSinkEndRequest.Complete();
           self->TryUpdateRenderedVideoFrames();
           // It is possible the video queue size is 0 and we have no frames to
           // render. However, we need to call MaybeResolveEndPromise() to ensure
           // mEndPromiseHolder is resolved.
           self->MaybeResolveEndPromise();
         }, [self] () {
           self->mVideoSinkEndRequest.Complete();
           self->TryUpdateRenderedVideoFrames();
           self->MaybeResolveEndPromise();
-        }));
+        })
+        ->Track(mVideoSinkEndRequest);
     }
 
     ConnectListener();
     // Run the render loop at least once so we can resolve the end promise
     // when video duration is 0.
     UpdateRenderedVideoFrames();
   }
 }
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -253,25 +253,25 @@ SourceBuffer::Remove(double aStart, doub
 }
 
 void
 SourceBuffer::RangeRemoval(double aStart, double aEnd)
 {
   StartUpdating();
 
   RefPtr<SourceBuffer> self = this;
-  mPendingRemoval.Begin(
     mTrackBuffersManager->RangeRemoval(TimeUnit::FromSeconds(aStart),
                                        TimeUnit::FromSeconds(aEnd))
       ->Then(AbstractThread::MainThread(), __func__,
              [self] (bool) {
                self->mPendingRemoval.Complete();
                self->StopUpdating();
              },
-             []() { MOZ_ASSERT(false); }));
+             []() { MOZ_ASSERT(false); })
+      ->Track(mPendingRemoval);
 }
 
 void
 SourceBuffer::Detach()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("Detach");
   if (!mMediaSource) {
@@ -410,20 +410,21 @@ SourceBuffer::AppendData(const uint8_t* 
   MSE_DEBUG("AppendData(aLength=%u)", aLength);
 
   RefPtr<MediaByteBuffer> data = PrepareAppend(aData, aLength, aRv);
   if (!data) {
     return;
   }
   StartUpdating();
 
-  mPendingAppend.Begin(mTrackBuffersManager->AppendData(data, mCurrentAttributes)
-                       ->Then(AbstractThread::MainThread(), __func__, this,
-                              &SourceBuffer::AppendDataCompletedWithSuccess,
-                              &SourceBuffer::AppendDataErrored));
+  mTrackBuffersManager->AppendData(data, mCurrentAttributes)
+    ->Then(AbstractThread::MainThread(), __func__, this,
+           &SourceBuffer::AppendDataCompletedWithSuccess,
+           &SourceBuffer::AppendDataErrored)
+    ->Track(mPendingAppend);
 }
 
 void
 SourceBuffer::AppendDataCompletedWithSuccess(SourceBufferTask::AppendBufferResult aResult)
 {
   MOZ_ASSERT(mUpdating);
   mPendingAppend.Complete();
 
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -728,30 +728,31 @@ TrackBuffersManager::SegmentParserLoop()
           mInputBuffer = nullptr;
           NeedMoreData();
           return;
         }
       }
 
       // 3. If the input buffer contains one or more complete coded frames, then run the coded frame processing algorithm.
       RefPtr<TrackBuffersManager> self = this;
-      mProcessingRequest.Begin(CodedFrameProcessing()
-          ->Then(GetTaskQueue(), __func__,
-                 [self] (bool aNeedMoreData) {
-                   self->mProcessingRequest.Complete();
-                   if (aNeedMoreData) {
-                     self->NeedMoreData();
-                   } else {
-                     self->ScheduleSegmentParserLoop();
-                   }
-                 },
-                 [self] (const MediaResult& aRejectValue) {
-                   self->mProcessingRequest.Complete();
-                   self->RejectAppend(aRejectValue, __func__);
-                 }));
+      CodedFrameProcessing()
+        ->Then(GetTaskQueue(), __func__,
+               [self] (bool aNeedMoreData) {
+                 self->mProcessingRequest.Complete();
+                 if (aNeedMoreData) {
+                   self->NeedMoreData();
+                 } else {
+                   self->ScheduleSegmentParserLoop();
+                 }
+               },
+               [self] (const MediaResult& aRejectValue) {
+                 self->mProcessingRequest.Complete();
+                 self->RejectAppend(aRejectValue, __func__);
+               })
+        ->Track(mProcessingRequest);
       return;
     }
   }
 }
 
 void
 TrackBuffersManager::NeedMoreData()
 {
@@ -837,21 +838,22 @@ TrackBuffersManager::ResetDemuxingState(
   // that data has been appended yet ; so we simply append the init segment
   // to the resource.
   mCurrentInputBuffer->AppendData(mParser->InitData());
   CreateDemuxerforMIMEType();
   if (!mInputDemuxer) {
     RejectAppend(NS_ERROR_FAILURE, __func__);
     return;
   }
-  mDemuxerInitRequest.Begin(mInputDemuxer->Init()
-                      ->Then(GetTaskQueue(), __func__,
-                             this,
-                             &TrackBuffersManager::OnDemuxerResetDone,
-                             &TrackBuffersManager::OnDemuxerInitFailed));
+  mInputDemuxer->Init()
+    ->Then(GetTaskQueue(), __func__,
+           this,
+           &TrackBuffersManager::OnDemuxerResetDone,
+           &TrackBuffersManager::OnDemuxerInitFailed)
+    ->Track(mDemuxerInitRequest);
 }
 
 void
 TrackBuffersManager::OnDemuxerResetDone(nsresult)
 {
   MOZ_ASSERT(OnTaskQueue());
   mDemuxerInitRequest.Complete();
   // mInputDemuxer shouldn't have been destroyed while a demuxer init/reset
@@ -911,21 +913,22 @@ TrackBuffersManager::InitializationSegme
     mInputBuffer->RemoveElementsAt(0, length);
   }
   CreateDemuxerforMIMEType();
   if (!mInputDemuxer) {
     NS_WARNING("TODO type not supported");
     RejectAppend(NS_ERROR_DOM_NOT_SUPPORTED_ERR, __func__);
     return;
   }
-  mDemuxerInitRequest.Begin(mInputDemuxer->Init()
-                      ->Then(GetTaskQueue(), __func__,
-                             this,
-                             &TrackBuffersManager::OnDemuxerInitDone,
-                             &TrackBuffersManager::OnDemuxerInitFailed));
+  mInputDemuxer->Init()
+    ->Then(GetTaskQueue(), __func__,
+           this,
+           &TrackBuffersManager::OnDemuxerInitDone,
+           &TrackBuffersManager::OnDemuxerInitFailed)
+    ->Track(mDemuxerInitRequest);
 }
 
 void
 TrackBuffersManager::OnDemuxerInitDone(nsresult)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_DIAGNOSTIC_ASSERT(mInputDemuxer, "mInputDemuxer has been destroyed");
 
@@ -1195,20 +1198,21 @@ TrackBuffersManager::OnDemuxFailed(Track
 void
 TrackBuffersManager::DoDemuxVideo()
 {
   MOZ_ASSERT(OnTaskQueue());
   if (!HasVideo()) {
     DoDemuxAudio();
     return;
   }
-  mVideoTracks.mDemuxRequest.Begin(mVideoTracks.mDemuxer->GetSamples(-1)
-                             ->Then(GetTaskQueue(), __func__, this,
-                                    &TrackBuffersManager::OnVideoDemuxCompleted,
-                                    &TrackBuffersManager::OnVideoDemuxFailed));
+  mVideoTracks.mDemuxer->GetSamples(-1)
+    ->Then(GetTaskQueue(), __func__, this,
+           &TrackBuffersManager::OnVideoDemuxCompleted,
+           &TrackBuffersManager::OnVideoDemuxFailed)
+    ->Track(mVideoTracks.mDemuxRequest);
 }
 
 void
 TrackBuffersManager::OnVideoDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples)
 {
   MOZ_ASSERT(OnTaskQueue());
   MSE_DEBUG("%d video samples demuxed", aSamples->mSamples.Length());
   mVideoTracks.mDemuxRequest.Complete();
@@ -1219,20 +1223,21 @@ TrackBuffersManager::OnVideoDemuxComplet
 void
 TrackBuffersManager::DoDemuxAudio()
 {
   MOZ_ASSERT(OnTaskQueue());
   if (!HasAudio()) {
     CompleteCodedFrameProcessing();
     return;
   }
-  mAudioTracks.mDemuxRequest.Begin(mAudioTracks.mDemuxer->GetSamples(-1)
-                             ->Then(GetTaskQueue(), __func__, this,
-                                    &TrackBuffersManager::OnAudioDemuxCompleted,
-                                    &TrackBuffersManager::OnAudioDemuxFailed));
+  mAudioTracks.mDemuxer->GetSamples(-1)
+    ->Then(GetTaskQueue(), __func__, this,
+           &TrackBuffersManager::OnAudioDemuxCompleted,
+           &TrackBuffersManager::OnAudioDemuxFailed)
+    ->Track(mAudioTracks.mDemuxRequest);
 }
 
 void
 TrackBuffersManager::OnAudioDemuxCompleted(RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples)
 {
   MOZ_ASSERT(OnTaskQueue());
   MSE_DEBUG("%d audio samples demuxed", aSamples->mSamples.Length());
   mAudioTracks.mDemuxRequest.Complete();
--- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
@@ -55,20 +55,21 @@ public:
       return;
     }
 
     nsAutoPtr<MediaRawDataWriter> writer(aSample->CreateWriter());
     mProxy->GetSessionIdsForKeyId(aSample->mCrypto.mKeyId,
                                   writer->mCrypto.mSessionIds);
 
     mDecrypts.Put(aSample, new DecryptPromiseRequestHolder());
-    mDecrypts.Get(aSample)->Begin(mProxy->Decrypt(aSample)->Then(
+    mProxy->Decrypt(aSample)->Then(
       mTaskQueue, __func__, this,
       &EMEDecryptor::Decrypted,
-      &EMEDecryptor::Decrypted));
+      &EMEDecryptor::Decrypted)
+    ->Track(*mDecrypts.Get(aSample));
     return;
   }
 
   void Decrypted(const DecryptResult& aDecrypted) {
     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
     MOZ_ASSERT(aDecrypted.mSample);
 
     nsAutoPtr<DecryptPromiseRequestHolder> holder;
--- a/dom/media/platforms/wrappers/FuzzingWrapper.cpp
+++ b/dom/media/platforms/wrappers/FuzzingWrapper.cpp
@@ -237,33 +237,33 @@ void
 DecoderCallbackFuzzingWrapper::ScheduleOutputDelayedFrame()
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   if (mDelayedOutputRequest.Exists()) {
     // A delayed output is already scheduled, no need for more than one timer.
     return;
   }
   RefPtr<DecoderCallbackFuzzingWrapper> self = this;
-  mDelayedOutputRequest.Begin(
-    mDelayedOutputTimer->WaitUntil(
-      mPreviousOutput + mFrameOutputMinimumInterval,
-      __func__)
-    ->Then(mTaskQueue, __func__,
-           [self] () -> void {
-             if (self->mDelayedOutputRequest.Exists()) {
-               self->mDelayedOutputRequest.Complete();
-               self->OutputDelayedFrame();
-             }
-           },
-           [self] () -> void {
-             if (self->mDelayedOutputRequest.Exists()) {
-               self->mDelayedOutputRequest.Complete();
-               self->ClearDelayedOutput();
-             }
-           }));
+  mDelayedOutputTimer->WaitUntil(
+    mPreviousOutput + mFrameOutputMinimumInterval,
+    __func__)
+  ->Then(mTaskQueue, __func__,
+         [self] () -> void {
+           if (self->mDelayedOutputRequest.Exists()) {
+             self->mDelayedOutputRequest.Complete();
+             self->OutputDelayedFrame();
+           }
+         },
+         [self] () -> void {
+           if (self->mDelayedOutputRequest.Exists()) {
+             self->mDelayedOutputRequest.Complete();
+             self->ClearDelayedOutput();
+           }
+         })
+  ->Track(mDelayedOutputRequest);
 }
 
 void
 DecoderCallbackFuzzingWrapper::OutputDelayedFrame()
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   if (mDelayedOutput.empty()) {
     if (mDraining) {
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -226,20 +226,21 @@ H264Converter::CreateDecoderAndInit(Medi
   UpdateConfigFromExtraData(extra_data);
 
   nsresult rv = CreateDecoder(/* DecoderDoctorDiagnostics* */ nullptr);
 
   if (NS_SUCCEEDED(rv)) {
     // Queue the incoming sample.
     mMediaRawSamples.AppendElement(aSample);
 
-    mInitPromiseRequest.Begin(mDecoder->Init()
+    mDecoder->Init()
       ->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__, this,
              &H264Converter::OnDecoderInitDone,
-             &H264Converter::OnDecoderInitFailed));
+             &H264Converter::OnDecoderInitFailed)
+      ->Track(mInitPromiseRequest);
     return NS_ERROR_NOT_INITIALIZED;
   }
   return rv;
 }
 
 void
 H264Converter::OnDecoderInitDone(const TrackType aTrackType)
 {
--- a/dom/media/webm/EbmlComposer.cpp
+++ b/dom/media/webm/EbmlComposer.cpp
@@ -41,17 +41,17 @@ void EbmlComposer::GenerateHeader()
       {
         EbmlLoc trackLoc;
         Ebml_StartSubElement(&ebml, &trackLoc, Tracks);
         {
           // Video
           if (mWidth > 0 && mHeight > 0) {
             writeVideoTrack(&ebml, 0x1, 0, "V_VP8",
                             mWidth, mHeight,
-                            mDisplayWidth, mDisplayHeight, mFrameRate);
+                            mDisplayWidth, mDisplayHeight);
           }
           // Audio
           if (mCodecPrivateData.Length() > 0) {
             // Extract the pre-skip from mCodecPrivateData
             // then convert it to nanoseconds.
             // Details in OpusTrackEncoder.cpp.
             mCodecDelay =
               (uint64_t)LittleEndian::readUint16(mCodecPrivateData.Elements() + 10)
@@ -171,29 +171,26 @@ EbmlComposer::WriteSimpleBlock(EncodedFr
   MOZ_ASSERT(ebml.offset <= DEFAULT_HEADER_SIZE +
              aFrame->GetFrameData().Length(),
              "write more data > EBML_BUFFER_SIZE");
   block->SetLength(ebml.offset);
 }
 
 void
 EbmlComposer::SetVideoConfig(uint32_t aWidth, uint32_t aHeight,
-                             uint32_t aDisplayWidth, uint32_t aDisplayHeight,
-                             float aFrameRate)
+                             uint32_t aDisplayWidth, uint32_t aDisplayHeight)
 {
   MOZ_ASSERT(aWidth > 0, "Width should > 0");
   MOZ_ASSERT(aHeight > 0, "Height should > 0");
   MOZ_ASSERT(aDisplayWidth > 0, "DisplayWidth should > 0");
   MOZ_ASSERT(aDisplayHeight > 0, "DisplayHeight should > 0");
-  MOZ_ASSERT(aFrameRate > 0, "FrameRate should > 0");
   mWidth = aWidth;
   mHeight = aHeight;
   mDisplayWidth = aDisplayWidth;
   mDisplayHeight = aDisplayHeight;
-  mFrameRate = aFrameRate;
 }
 
 void
 EbmlComposer::SetAudioConfig(uint32_t aSampleFreq, uint32_t aChannels)
 {
   MOZ_ASSERT(aSampleFreq > 0, "SampleFreq should > 0");
   MOZ_ASSERT(aChannels > 0, "Channels should > 0");
   mSampleFreq = aSampleFreq;
@@ -223,14 +220,13 @@ EbmlComposer::ExtractBuffer(nsTArray<nsT
 EbmlComposer::EbmlComposer()
   : mFlushState(FLUSH_NONE)
   , mClusterHeaderIndex(0)
   , mClusterLengthLoc(0)
   , mCodecDelay(0)
   , mClusterTimecode(0)
   , mWidth(0)
   , mHeight(0)
-  , mFrameRate(0)
   , mSampleFreq(0)
   , mChannels(0)
 {}
 
 } // namespace mozilla
--- a/dom/media/webm/EbmlComposer.h
+++ b/dom/media/webm/EbmlComposer.h
@@ -14,18 +14,18 @@ namespace mozilla {
  * A WebM muxer helper for package the valid WebM format.
  */
 class EbmlComposer {
 public:
   EbmlComposer();
   /*
    * Assign the parameter which header required.
    */
-  void SetVideoConfig(uint32_t aWidth, uint32_t aHeight, uint32_t aDisplayWidth,
-                      uint32_t aDisplayHeight, float aFrameRate);
+  void SetVideoConfig(uint32_t aWidth, uint32_t aHeight,
+                      uint32_t aDisplayWidth, uint32_t aDisplayHeight);
 
   void SetAudioConfig(uint32_t aSampleFreq, uint32_t aChannels);
   /*
    * Set the CodecPrivateData for writing in header.
    */
   void SetAudioCodecPrivateData(nsTArray<uint8_t>& aBufs)
   {
     mCodecPrivateData.AppendElements(aBufs);
@@ -73,17 +73,16 @@ private:
   // The timecode of the cluster.
   uint64_t mClusterTimecode;
 
   // Video configuration
   int mWidth;
   int mHeight;
   int mDisplayWidth;
   int mDisplayHeight;
-  float mFrameRate;
   // Audio configuration
   float mSampleFreq;
   int mChannels;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/webm/WebMWriter.cpp
+++ b/dom/media/webm/WebMWriter.cpp
@@ -52,18 +52,17 @@ WebMWriter::SetMetadata(TrackMetadataBas
   MOZ_ASSERT(aMetadata);
   PROFILER_LABEL("WebMWriter", "SetMetadata",
     js::ProfileEntry::Category::OTHER);
 
   if (aMetadata->GetKind() == TrackMetadataBase::METADATA_VP8) {
     VP8Metadata* meta = static_cast<VP8Metadata*>(aMetadata);
     MOZ_ASSERT(meta, "Cannot find vp8 encoder metadata");
     mEbmlComposer->SetVideoConfig(meta->mWidth, meta->mHeight,
-                                  meta->mDisplayWidth, meta->mDisplayHeight,
-                                  meta->mEncodedFrameRate);
+                                  meta->mDisplayWidth, meta->mDisplayHeight);
     mMetadataRequiredFlag = mMetadataRequiredFlag & ~ContainerWriter::CREATE_VIDEO_TRACK;
   }
 
   if (aMetadata->GetKind() == TrackMetadataBase::METADATA_VORBIS) {
     VorbisMetadata* meta = static_cast<VorbisMetadata*>(aMetadata);
     MOZ_ASSERT(meta, "Cannot find vorbis encoder metadata");
     mEbmlComposer->SetAudioConfig(meta->mSamplingFrequency, meta->mChannels);
     mEbmlComposer->SetAudioCodecPrivateData(meta->mData);
--- a/dom/media/webm/WebMWriter.h
+++ b/dom/media/webm/WebMWriter.h
@@ -26,17 +26,16 @@ public:
 // VP8 meta data structure
 class VP8Metadata : public TrackMetadataBase
 {
 public:
   int32_t mWidth;
   int32_t mHeight;
   int32_t mDisplayWidth;
   int32_t mDisplayHeight;
-  int32_t mEncodedFrameRate;
   MetadataKind GetKind() const override { return METADATA_VP8; }
 };
 
 /**
  * WebM writer helper
  * This class accepts encoder to set audio or video meta data or
  * encoded data to ebml Composer, and get muxing data through GetContainerData.
  * The ctor/dtor run in the MediaRecorder thread, others run in MediaEncoder thread.
--- a/ipc/chromium/src/base/message_pump_default.cc
+++ b/ipc/chromium/src/base/message_pump_default.cc
@@ -53,27 +53,27 @@ void MessagePumpDefault::Run(Delegate* d
     if (did_work)
       continue;
 
     if (delayed_work_time_.is_null()) {
       hangMonitor.NotifyWait();
       PROFILER_LABEL("MessagePump", "Wait",
         js::ProfileEntry::Category::OTHER);
       {
-        GeckoProfilerSleepRAII profiler_sleep;
+        mozilla::GeckoProfilerSleepRAII profiler_sleep;
         event_.Wait();
       }
     } else {
       TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
       if (delay > TimeDelta()) {
         hangMonitor.NotifyWait();
         PROFILER_LABEL("MessagePump", "Wait",
           js::ProfileEntry::Category::OTHER);
         {
-          GeckoProfilerSleepRAII profiler_sleep;
+          mozilla::GeckoProfilerSleepRAII profiler_sleep;
           event_.TimedWait(delay);
         }
       } else {
         // It looks like delayed_work_time_ indicates a time in the past, so we
         // need to call DoDelayedWork now.
         delayed_work_time_ = TimeTicks();
       }
     }
--- a/layout/base/RestyleTracker.cpp
+++ b/layout/base/RestyleTracker.cpp
@@ -56,19 +56,17 @@ inline nsIDocument*
 RestyleTracker::Document() const {
   return mRestyleManager->PresContext()->Document();
 }
 
 #define RESTYLE_ARRAY_STACKSIZE 128
 
 struct RestyleEnumerateData : RestyleTracker::Hints {
   RefPtr<dom::Element> mElement;
-#if defined(MOZ_ENABLE_PROFILER_SPS)
   UniqueProfilerBacktrace mBacktrace;
-#endif
 };
 
 inline void
 RestyleTracker::ProcessOneRestyle(Element* aElement,
                                   nsRestyleHint aRestyleHint,
                                   nsChangeHint aChangeHint,
                                   const RestyleHintData& aRestyleHintData)
 {
@@ -252,22 +250,20 @@ RestyleTracker::DoProcessRestyles()
         }
 
         if (isTimelineRecording) {
           timelines->AddMarkerForDocShell(docShell, Move(
             MakeUnique<RestyleTimelineMarker>(
               data->mRestyleHint, MarkerTracingType::START)));
         }
 
-#if defined(MOZ_ENABLE_PROFILER_SPS)
         Maybe<GeckoProfilerTracingRAII> profilerRAII;
         if (profiler_feature_active("restyle")) {
           profilerRAII.emplace("Paint", "Styles", Move(data->mBacktrace));
         }
-#endif
         ProcessOneRestyle(element, data->mRestyleHint, data->mChangeHint,
                           data->mRestyleHintData);
         AddRestyleRootsIfAwaitingRestyle(data->mDescendants);
 
         if (isTimelineRecording) {
           timelines->AddMarkerForDocShell(docShell, Move(
             MakeUnique<RestyleTimelineMarker>(
               data->mRestyleHint, MarkerTracingType::END)));
@@ -332,19 +328,17 @@ RestyleTracker::DoProcessRestyles()
                               ConditionalDescendantsBit());
 
           restyle->mElement = element;
           restyle->mRestyleHint = data->mRestyleHint;
           restyle->mChangeHint = data->mChangeHint;
           // We can move data since we'll be clearing mPendingRestyles after
           // we finish enumerating it.
           restyle->mRestyleHintData = Move(data->mRestyleHintData);
-#if defined(MOZ_ENABLE_PROFILER_SPS)
           restyle->mBacktrace = Move(data->mBacktrace);
-#endif
 
 #ifdef RESTYLE_LOGGING
           count++;
 #endif
 
           // Increment to the next slot in the array
           restyle++;
         }
@@ -360,22 +354,20 @@ RestyleTracker::DoProcessRestyles()
         for (RestyleEnumerateData* currentRestyle = restylesToProcess;
              currentRestyle != lastRestyle;
              ++currentRestyle) {
           LOG_RESTYLE("processing pending restyle %s at index %d/%d",
                       FrameTagToString(currentRestyle->mElement).get(),
                       index++, count);
           LOG_RESTYLE_INDENT();
 
-#if defined(MOZ_ENABLE_PROFILER_SPS)
           Maybe<GeckoProfilerTracingRAII> profilerRAII;
           if (profiler_feature_active("restyle")) {
             profilerRAII.emplace("Paint", "Styles", Move(currentRestyle->mBacktrace));
           }
-#endif
           if (isTimelineRecording) {
             timelines->AddMarkerForDocShell(docShell, Move(
               MakeUnique<RestyleTimelineMarker>(
                 currentRestyle->mRestyleHint, MarkerTracingType::START)));
           }
 
           ProcessOneRestyle(currentRestyle->mElement,
                             currentRestyle->mRestyleHint,
--- a/layout/base/RestyleTracker.h
+++ b/layout/base/RestyleTracker.h
@@ -17,20 +17,16 @@
 #include "nsClassHashtable.h"
 #include "nsContainerFrame.h"
 #include "nsIContentInlines.h"
 #include "mozilla/SplayTree.h"
 #include "mozilla/RestyleLogging.h"
 #include "GeckoProfiler.h"
 #include "mozilla/Maybe.h"
 
-#if defined(MOZ_ENABLE_PROFILER_SPS)
-#include "ProfilerBacktrace.h"
-#endif
-
 namespace mozilla {
 
 class RestyleManager;
 class ElementRestyler;
 
 class RestyleTracker {
 public:
   typedef mozilla::dom::Element Element;
@@ -123,19 +119,17 @@ public:
       }
     }
 
     // Descendant elements we must check that we ended up restyling, ordered
     // with the same invariant as mRestyleRoots.  The elements here are those
     // that we called AddPendingRestyle for and found the element this is
     // the RestyleData for as its nearest restyle root.
     nsTArray<RefPtr<Element>> mDescendants;
-#if defined(MOZ_ENABLE_PROFILER_SPS)
     UniqueProfilerBacktrace mBacktrace;
-#endif
   };
 
   /**
    * If the given Element has a restyle pending for it, return the
    * relevant restyle data.  This function will clear everything other
    * than a possible eRestyle_LaterSiblings hint for aElement out of
    * our hashtable.  The returned aData will never have an
    * eRestyle_LaterSiblings hint in it.
@@ -260,21 +254,19 @@ RestyleTracker::AddPendingRestyleToTable
                  "why are we getting eRestyle_SomeDescendants in an "
                  "animation-only restyle?");
     aElement->SetFlags(ConditionalDescendantsBit());
   }
 
   if (!existingData) {
     RestyleData* rd =
       new RestyleData(aRestyleHint, aMinChangeHint, aRestyleHintData);
-#if defined(MOZ_ENABLE_PROFILER_SPS)
     if (profiler_feature_active("restyle")) {
       rd->mBacktrace = profiler_get_backtrace();
     }
-#endif
     mPendingRestyles.Put(aElement, rd);
     return false;
   }
 
   bool hadRestyleLaterSiblings =
     (existingData->mRestyleHint & eRestyle_LaterSiblings) != 0;
   existingData->mRestyleHint =
     nsRestyleHint(existingData->mRestyleHint | aRestyleHint);
new file mode 100644
--- /dev/null
+++ b/layout/base/ShapeUtils.cpp
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "mozilla/ShapeUtils.h"
+
+#include <cstdlib>
+
+#include "nsCSSRendering.h"
+#include "nsRuleNode.h"
+#include "nsStyleCoord.h"
+#include "nsStyleStruct.h"
+#include "SVGContentUtils.h"
+
+namespace mozilla {
+
+nscoord
+ShapeUtils::ComputeShapeRadius(const StyleShapeRadius aType,
+                               const nscoord aCenter,
+                               const nscoord aPosMin,
+                               const nscoord aPosMax)
+{
+  nscoord dist1 = std::abs(aPosMin - aCenter);
+  nscoord dist2 = std::abs(aPosMax - aCenter);
+  nscoord length = 0;
+  switch (aType) {
+    case StyleShapeRadius::FarthestSide:
+      length = dist1 > dist2 ? dist1 : dist2;
+      break;
+    case StyleShapeRadius::ClosestSide:
+      length = dist1 > dist2 ? dist2 : dist1;
+      break;
+  }
+  return length;
+}
+
+nsPoint
+ShapeUtils::ComputeCircleOrEllipseCenter(StyleBasicShape* const aBasicShape,
+                                         const nsRect& aRefBox)
+{
+  nsPoint topLeft, anchor;
+  nsSize size(aRefBox.Size());
+  nsImageRenderer::ComputeObjectAnchorPoint(aBasicShape->GetPosition(),
+                                            size, size,
+                                            &topLeft, &anchor);
+  return nsPoint(anchor.x + aRefBox.x, anchor.y + aRefBox.y);
+}
+
+nscoord
+ShapeUtils::ComputeCircleRadius(StyleBasicShape* const aBasicShape,
+                                const nsPoint& aCenter,
+                                const nsRect& aRefBox)
+{
+  const nsTArray<nsStyleCoord>& coords = aBasicShape->Coordinates();
+  MOZ_ASSERT(coords.Length() == 1, "wrong number of arguments");
+  nscoord r = 0;
+  if (coords[0].GetUnit() == eStyleUnit_Enumerated) {
+    const auto styleShapeRadius = coords[0].GetEnumValue<StyleShapeRadius>();
+    nscoord horizontal =
+      ComputeShapeRadius(styleShapeRadius, aCenter.x, aRefBox.x, aRefBox.XMost());
+    nscoord vertical =
+      ComputeShapeRadius(styleShapeRadius, aCenter.y, aRefBox.y, aRefBox.YMost());
+    r = styleShapeRadius == StyleShapeRadius::FarthestSide
+          ? std::max(horizontal, vertical)
+          : std::min(horizontal, vertical);
+  } else {
+    // We resolve percent <shape-radius> value for circle() as defined here:
+    // https://drafts.csswg.org/css-shapes/#funcdef-circle
+    double referenceLength =
+      SVGContentUtils::ComputeNormalizedHypotenuse(aRefBox.width,
+                                                   aRefBox.height);
+    r = nsRuleNode::ComputeCoordPercentCalc(coords[0],
+                                            NSToCoordRound(referenceLength));
+  }
+  return r;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/base/ShapeUtils.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_ShapeUtils_h
+#define mozilla_ShapeUtils_h
+
+#include "nsCoord.h"
+#include "nsStyleConsts.h"
+
+struct nsPoint;
+struct nsRect;
+
+namespace mozilla {
+class StyleBasicShape;
+
+// ShapeUtils is a namespace class containing utility functions related to
+// processing basic shapes in the CSS Shapes Module.
+// https://drafts.csswg.org/css-shapes/#basic-shape-functions
+//
+struct ShapeUtils final
+{
+  // Compute the length of a keyword <shape-radius>, i.e. closest-side or
+  // farthest-side, for a circle or an ellipse on a single dimension. The
+  // caller needs to call for both dimensions and combine the result.
+  // https://drafts.csswg.org/css-shapes/#typedef-shape-radius.
+  //
+  // @return The length of the radius in app units.
+  static nscoord ComputeShapeRadius(const StyleShapeRadius aType,
+                                    const nscoord aCenter,
+                                    const nscoord aPosMin,
+                                    const nscoord aPosMax);
+
+  // Compute the center of a circle or an ellipse.
+  //
+  // @param aRefBox The reference box of the basic shape.
+  // @return The point of the center.
+  static nsPoint ComputeCircleOrEllipseCenter(
+    StyleBasicShape* const aBasicShape,
+    const nsRect& aRefBox);
+
+  // Compute the radius for a circle.
+  // @param aCenter the center of the circle.
+  // @param aRefBox the reference box of the circle.
+  // @return The length of the radius in app units.
+  static nscoord ComputeCircleRadius(
+    mozilla::StyleBasicShape* const aBasicShape,
+    const nsPoint& aCenter, const nsRect& aRefBox);
+};
+
+} // namespace mozilla
+
+#endif // mozilla_ShapeUtils_h
--- a/layout/base/moz.build
+++ b/layout/base/moz.build
@@ -75,16 +75,17 @@ EXPORTS.mozilla += [
     'PresShell.h',
     'RestyleLogging.h',
     'RestyleManager.h',
     'RestyleManagerBase.h',
     'RestyleManagerHandle.h',
     'RestyleManagerHandleInlines.h',
     'ServoRestyleManager.h',
     'ServoRestyleManagerInlines.h',
+    'ShapeUtils.h',
     'StaticPresData.h',
 ]
 
 UNIFIED_SOURCES += [
     'AccessibleCaret.cpp',
     'AccessibleCaretEventHub.cpp',
     'AccessibleCaretManager.cpp',
     'FramePropertyTable.cpp',
@@ -109,16 +110,17 @@ UNIFIED_SOURCES += [
     'nsStyleSheetService.cpp',
     'PositionedEventTargeting.cpp',
     'PresShell.cpp',
     'RestyleManager.cpp',
     'RestyleManagerBase.cpp',
     'RestyleTracker.cpp',
     'ScrollbarStyles.cpp',
     'ServoRestyleManager.cpp',
+    'ShapeUtils.cpp',
     'StackArena.cpp',
     'StaticPresData.cpp',
     'TouchManager.cpp',
     'ZoomConstraintsClient.cpp',
 ]
 
 if CONFIG['ENABLE_INTL_API']:
     EXPORTS += [
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -17,16 +17,17 @@
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/layers/PAPZ.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/Unused.h"
 #include "nsCharTraits.h"
+#include "nsDocument.h"
 #include "nsFontMetrics.h"
 #include "nsPresContext.h"
 #include "nsIContent.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsFrameList.h"
 #include "nsGkAtoms.h"
 #include "nsHtml5Atoms.h"
--- a/layout/generic/BlockReflowInput.cpp
+++ b/layout/generic/BlockReflowInput.cpp
@@ -983,19 +983,18 @@ BlockReflowInput::FlowAndPlaceFloat(nsIF
     nsFloatManager::CalculateRegionFor(wm, aFloat, floatMargin,
                                        ContainerSize());
   // if the float split, then take up all of the vertical height
   if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus) &&
       (NS_UNCONSTRAINEDSIZE != ContentBSize())) {
     region.BSize(wm) = std::max(region.BSize(wm),
                                 ContentBSize() - floatPos.B(wm));
   }
-  DebugOnly<nsresult> rv = mFloatManager->AddFloat(aFloat, region, wm,
-                                                   ContainerSize());
-  MOZ_ASSERT(NS_SUCCEEDED(rv), "bad float placement");
+  mFloatManager->AddFloat(aFloat, region, wm, ContainerSize());
+
   // store region
   nsFloatManager::StoreRegionFor(wm, aFloat, region, ContainerSize());
 
   // If the float's dimensions have changed, note the damage in the
   // float manager.
   if (!region.IsEqualEdges(oldRegion)) {
     // XXXwaterson conservative: we could probably get away with noting
     // less damage; e.g., if only height has changed, then only note the
--- a/layout/generic/WritingModes.h
+++ b/layout/generic/WritingModes.h
@@ -779,16 +779,26 @@ public:
     CHECK_WRITING_MODE(aWritingMode);
     return mPoint.x;
   }
   nscoord B(WritingMode aWritingMode) const // block-axis
   {
     CHECK_WRITING_MODE(aWritingMode);
     return mPoint.y;
   }
+  nscoord LineRelative(WritingMode aWritingMode,
+                       const nsSize& aContainerSize) const // line-axis
+  {
+    CHECK_WRITING_MODE(aWritingMode);
+    if (aWritingMode.IsBidiLTR()) {
+      return I();
+    }
+    return (aWritingMode.IsVertical() ? aContainerSize.height
+                                      : aContainerSize.width) - I();
+  }
 
   /**
    * These non-const accessors return a reference (lvalue) that can be
    * assigned to by callers.
    */
   nscoord& I(WritingMode aWritingMode) // inline-axis
   {
     CHECK_WRITING_MODE(aWritingMode);
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -5,16 +5,17 @@
 
 /* class that manages rules for positioning floats */
 
 #include "nsFloatManager.h"
 
 #include <algorithm>
 
 #include "mozilla/ReflowInput.h"
+#include "mozilla/ShapeUtils.h"
 #include "nsBlockFrame.h"
 #include "nsError.h"
 #include "nsIPresShell.h"
 #include "nsMemory.h"
 
 using namespace mozilla;
 
 int32_t nsFloatManager::sCachedFloatManagerCount = 0;
@@ -182,17 +183,17 @@ nsFloatManager::GetFlowArea(WritingMode 
   // the list or we're above |blockStart|.
   bool haveFloats = false;
   for (uint32_t i = floatCount; i > 0; --i) {
     const FloatInfo &fi = mFloats[i-1];
     if (fi.mLeftBEnd <= blockStart && fi.mRightBEnd <= blockStart) {
       // There aren't any more floats that could intersect this band.
       break;
     }
-    if (fi.IsEmpty()) {
+    if (fi.IsEmpty(aShapeType)) {
       // For compatibility, ignore floats with empty rects, even though it
       // disagrees with the spec.  (We might want to fix this in the
       // future, though.)
       continue;
     }
 
     nscoord floatBStart = fi.BStart(aShapeType);
     nscoord floatBEnd = fi.BEnd(aShapeType);
@@ -256,17 +257,17 @@ nsFloatManager::GetFlowArea(WritingMode 
                         ? lineLeft - mLineLeft
                         : mLineLeft - lineRight +
                           LogicalSize(aWM, aContainerSize).ISize(aWM);
 
   return nsFlowAreaRect(aWM, inlineStart, blockStart - mBlockStart,
                         lineRight - lineLeft, blockSize, haveFloats);
 }
 
-nsresult
+void
 nsFloatManager::AddFloat(nsIFrame* aFloatFrame, const LogicalRect& aMarginRect,
                          WritingMode aWM, const nsSize& aContainerSize)
 {
   CHECK_BLOCK_AND_LINE_DIR(aWM);
   NS_ASSERTION(aMarginRect.ISize(aWM) >= 0, "negative inline size!");
   NS_ASSERTION(aMarginRect.BSize(aWM) >= 0, "negative block size!");
 
   FloatInfo info(aFloatFrame, mLineLeft, mBlockStart, aMarginRect, aWM,
@@ -285,20 +286,17 @@ nsFloatManager::AddFloat(nsIFrame* aFloa
   MOZ_ASSERT(floatStyle == StyleFloat::Left || floatStyle == StyleFloat::Right,
              "Unexpected float style!");
   nscoord& sideBEnd =
     floatStyle == StyleFloat::Left ? info.mLeftBEnd : info.mRightBEnd;
   nscoord thisBEnd = info.BEnd();
   if (thisBEnd > sideBEnd)
     sideBEnd = thisBEnd;
 
-  if (!mFloats.AppendElement(info))
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  return NS_OK;
+  mFloats.AppendElement(Move(info));
 }
 
 // static
 LogicalRect
 nsFloatManager::CalculateRegionFor(WritingMode          aWM,
                                    nsIFrame*            aFloat,
                                    const LogicalMargin& aMargin,
                                    const nsSize&        aContainerSize)
@@ -526,16 +524,155 @@ nsFloatManager::ClearContinues(StyleClea
           (aBreakType == StyleClear::Both ||
            aBreakType == StyleClear::Left)) ||
          ((mPushedRightFloatPastBreak || mSplitRightFloatAcrossBreak) &&
           (aBreakType == StyleClear::Both ||
            aBreakType == StyleClear::Right));
 }
 
 /////////////////////////////////////////////////////////////////////////////
+// BoxShapeInfo
+
+nscoord
+nsFloatManager::BoxShapeInfo::LineLeft(WritingMode aWM,
+                                       const nscoord aBStart,
+                                       const nscoord aBEnd) const
+{
+  nscoord radii[8];
+  bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
+
+  if (!hasRadii) {
+    return mShapeBoxRect.x;
+  }
+
+  // Get the physical side for line-left since border-radii are in
+  // the physical axis.
+  mozilla::Side lineLeftSide =
+    aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirLeft));
+  nscoord blockStartCornerRadiusL =
+    radii[SideToHalfCorner(lineLeftSide, true, false)];
+  nscoord blockStartCornerRadiusB =
+    radii[SideToHalfCorner(lineLeftSide, true, true)];
+  nscoord blockEndCornerRadiusL =
+    radii[SideToHalfCorner(lineLeftSide, false, false)];
+  nscoord blockEndCornerRadiusB =
+    radii[SideToHalfCorner(lineLeftSide, false, true)];
+
+  if (aWM.IsLineInverted()) {
+    // This happens only when aWM is vertical-lr. Need to swap blockStart
+    // and blockEnd corners.
+    std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
+    std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
+  }
+
+  nscoord lineLeftDiff =
+    ComputeEllipseLineInterceptDiff(
+      mShapeBoxRect.y, mShapeBoxRect.YMost(),
+      blockStartCornerRadiusL, blockStartCornerRadiusB,
+      blockEndCornerRadiusL, blockEndCornerRadiusB,
+      aBStart, aBEnd);
+  return mShapeBoxRect.x + lineLeftDiff;
+}
+
+nscoord
+nsFloatManager::BoxShapeInfo::LineRight(WritingMode aWM,
+                                        const nscoord aBStart,
+                                        const nscoord aBEnd) const
+{
+  nscoord radii[8];
+  bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
+
+  if (!hasRadii) {
+    return mShapeBoxRect.XMost();
+  }
+
+  // Get the physical side for line-right since border-radii are in
+  // the physical axis.
+  mozilla::Side lineRightSide =
+    aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirRight));
+  nscoord blockStartCornerRadiusL =
+    radii[SideToHalfCorner(lineRightSide, false, false)];
+  nscoord blockStartCornerRadiusB =
+    radii[SideToHalfCorner(lineRightSide, false, true)];
+  nscoord blockEndCornerRadiusL =
+    radii[SideToHalfCorner(lineRightSide, true, false)];
+  nscoord blockEndCornerRadiusB =
+    radii[SideToHalfCorner(lineRightSide, true, true)];
+
+  if (aWM.IsLineInverted()) {
+    // This happens only when aWM is vertical-lr. Need to swap blockStart
+    // and blockEnd corners.
+    std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
+    std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
+  }
+
+  nscoord lineRightDiff =
+    ComputeEllipseLineInterceptDiff(
+      mShapeBoxRect.y, mShapeBoxRect.YMost(),
+      blockStartCornerRadiusL, blockStartCornerRadiusB,
+      blockEndCornerRadiusL, blockEndCornerRadiusB,
+      aBStart, aBEnd);
+  return mShapeBoxRect.XMost() - lineRightDiff;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CircleShapeInfo
+
+nsFloatManager::CircleShapeInfo::CircleShapeInfo(
+  StyleBasicShape* const aBasicShape,
+  nscoord aLineLeft,
+  nscoord aBlockStart,
+  const LogicalRect& aShapeBoxRect,
+  WritingMode aWM,
+  const nsSize& aContainerSize)
+{
+  // Use physical coordinates to compute the center of the circle() since
+  // the <position> keywords such as 'left', 'top', etc. are physical.
+  // https://drafts.csswg.org/css-shapes-1/#funcdef-circle
+  nsRect physicalShapeBoxRect =
+    aShapeBoxRect.GetPhysicalRect(aWM, aContainerSize);
+  nsPoint physicalCenter =
+    ShapeUtils::ComputeCircleOrEllipseCenter(aBasicShape, physicalShapeBoxRect);
+  mRadius =
+    ShapeUtils::ComputeCircleRadius(aBasicShape, physicalCenter,
+                                    physicalShapeBoxRect);
+
+  // Convert the coordinate space back to the same as FloatInfo::mRect.
+  // mCenter.x is in the line-axis of the frame manager and mCenter.y are in
+  // the frame manager's real block-axis.
+  LogicalPoint logicalCenter(aWM, physicalCenter, aContainerSize);
+  mCenter = nsPoint(logicalCenter.LineRelative(aWM, aContainerSize) + aLineLeft,
+                    logicalCenter.B(aWM) + aBlockStart);
+}
+
+nscoord
+nsFloatManager::CircleShapeInfo::LineLeft(WritingMode aWM,
+                                          const nscoord aBStart,
+                                          const nscoord aBEnd) const
+{
+  nscoord lineLeftDiff =
+    ComputeEllipseLineInterceptDiff(BStart(), BEnd(),
+                                    mRadius, mRadius, mRadius, mRadius,
+                                    aBStart, aBEnd);
+  return mCenter.x - mRadius + lineLeftDiff;
+}
+
+nscoord
+nsFloatManager::CircleShapeInfo::LineRight(WritingMode aWM,
+                                           const nscoord aBStart,
+                                           const nscoord aBEnd) const
+{
+  nscoord lineRightDiff =
+    ComputeEllipseLineInterceptDiff(BStart(), BEnd(),
+                                    mRadius, mRadius, mRadius, mRadius,
+                                    aBStart, aBEnd);
+  return mCenter.x + mRadius - lineRightDiff;
+}
+
+/////////////////////////////////////////////////////////////////////////////
 // FloatInfo
 
 nsFloatManager::FloatInfo::FloatInfo(nsIFrame* aFrame,
                                      nscoord aLineLeft, nscoord aBlockStart,
                                      const LogicalRect& aMarginRect,
                                      WritingMode aWM,
                                      const nsSize& aContainerSize)
   : mFrame(aFrame)
@@ -543,51 +680,68 @@ nsFloatManager::FloatInfo::FloatInfo(nsI
           aMarginRect.BStart(aWM) + aBlockStart,
           aMarginRect.ISize(aWM),
           aMarginRect.BSize(aWM))
 {
   MOZ_COUNT_CTOR(nsFloatManager::FloatInfo);
 
   const StyleShapeOutside& shapeOutside = mFrame->StyleDisplay()->mShapeOutside;
 
-  if (shapeOutside.GetType() == StyleShapeSourceType::Box) {
-    // Initialize shape-box reference rect.
-    LogicalRect rect = aMarginRect;
+  if (shapeOutside.GetType() == StyleShapeSourceType::None) {
+    return;
+  }
+
+  // Initialize <shape-box>'s reference rect.
+  LogicalRect rect = aMarginRect;
 
-    switch (shapeOutside.GetReferenceBox()) {
-      case StyleShapeOutsideShapeBox::Content:
-        rect.Deflate(aWM, mFrame->GetLogicalUsedPadding(aWM));
-        MOZ_FALLTHROUGH;
-      case StyleShapeOutsideShapeBox::Padding:
-        rect.Deflate(aWM, mFrame->GetLogicalUsedBorder(aWM));
-        MOZ_FALLTHROUGH;
-      case StyleShapeOutsideShapeBox::Border:
-        rect.Deflate(aWM, mFrame->GetLogicalUsedMargin(aWM));
-        break;
-      case StyleShapeOutsideShapeBox::Margin:
-        // Do nothing. rect is already a margin rect.
-        break;
-      case StyleShapeOutsideShapeBox::NoBox:
-        MOZ_ASSERT_UNREACHABLE("Why don't we have a shape-box?");
-        break;
+  switch (shapeOutside.GetReferenceBox()) {
+    case StyleShapeOutsideShapeBox::Content:
+      rect.Deflate(aWM, mFrame->GetLogicalUsedPadding(aWM));
+      MOZ_FALLTHROUGH;
+    case StyleShapeOutsideShapeBox::Padding:
+      rect.Deflate(aWM, mFrame->GetLogicalUsedBorder(aWM));
+      MOZ_FALLTHROUGH;
+    case StyleShapeOutsideShapeBox::Border:
+      rect.Deflate(aWM, mFrame->GetLogicalUsedMargin(aWM));
+      break;
+    case StyleShapeOutsideShapeBox::Margin:
+      // Do nothing. rect is already a margin rect.
+      break;
+    case StyleShapeOutsideShapeBox::NoBox:
+      MOZ_ASSERT(shapeOutside.GetType() != StyleShapeSourceType::Box,
+                 "Box source type must have <shape-box> specified!");
+      break;
+  }
+
+  if (shapeOutside.GetType() == StyleShapeSourceType::Box) {
+    nsRect shapeBoxRect(rect.LineLeft(aWM, aContainerSize) + aLineLeft,
+                        rect.BStart(aWM) + aBlockStart,
+                        rect.ISize(aWM), rect.BSize(aWM));
+    mShapeInfo = MakeUnique<BoxShapeInfo>(shapeBoxRect, mFrame);
+  } else if (shapeOutside.GetType() == StyleShapeSourceType::Shape) {
+    StyleBasicShape* const basicShape = shapeOutside.GetBasicShape();
+
+    if (basicShape->GetShapeType() == StyleBasicShapeType::Circle) {
+      mShapeInfo = MakeUnique<CircleShapeInfo>(basicShape, aLineLeft, aBlockStart,
+                                               rect, aWM, aContainerSize);
     }
-
-    mShapeBoxRect.emplace(rect.LineLeft(aWM, aContainerSize) + aLineLeft,
-                          rect.BStart(aWM) + aBlockStart,
-                          rect.ISize(aWM), rect.BSize(aWM));
+  } else if (shapeOutside.GetType() == StyleShapeSourceType::URL) {
+    // Bug 1265343: Implement 'shape-image-threshold'.
+  } else {
+    MOZ_ASSERT_UNREACHABLE("Unknown StyleShapeSourceType!");
   }
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
-nsFloatManager::FloatInfo::FloatInfo(const FloatInfo& aOther)
-  : mFrame(aOther.mFrame)
-  , mLeftBEnd(aOther.mLeftBEnd)
-  , mRightBEnd(aOther.mRightBEnd)
-  , mRect(aOther.mRect)
-  , mShapeBoxRect(aOther.mShapeBoxRect)
+nsFloatManager::FloatInfo::FloatInfo(FloatInfo&& aOther)
+  : mFrame(Move(aOther.mFrame))
+  , mLeftBEnd(Move(aOther.mLeftBEnd))
+  , mRightBEnd(Move(aOther.mRightBEnd))
+  , mRect(Move(aOther.mRect))
+  , mShapeInfo(Move(aOther.mShapeInfo))
 {
   MOZ_COUNT_CTOR(nsFloatManager::FloatInfo);
 }
 
 nsFloatManager::FloatInfo::~FloatInfo()
 {
   MOZ_COUNT_DTOR(nsFloatManager::FloatInfo);
 }
@@ -599,123 +753,90 @@ nsFloatManager::FloatInfo::LineLeft(Writ
                                     const nscoord aBStart,
                                     const nscoord aBEnd) const
 {
   if (aShapeType == ShapeType::Margin) {
     return LineLeft();
   }
 
   MOZ_ASSERT(aShapeType == ShapeType::ShapeOutside);
-  const StyleShapeOutside& shapeOutside = mFrame->StyleDisplay()->mShapeOutside;
-  if (shapeOutside.GetType() == StyleShapeSourceType::None) {
+  if (!mShapeInfo) {
     return LineLeft();
   }
-
-  if (shapeOutside.GetType() == StyleShapeSourceType::Box) {
-    nscoord radii[8];
-    bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
-
-    if (!hasRadii) {
-      return ShapeBoxRect().x;
-    }
-
-    // Get the physical side for line-left since border-radii are in
-    // the physical axis.
-    mozilla::Side lineLeftSide =
-      aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirLeft));
-    nscoord blockStartCornerRadiusL =
-      radii[SideToHalfCorner(lineLeftSide, true, false)];
-    nscoord blockStartCornerRadiusB =
-      radii[SideToHalfCorner(lineLeftSide, true, true)];
-    nscoord blockEndCornerRadiusL =
-      radii[SideToHalfCorner(lineLeftSide, false, false)];
-    nscoord blockEndCornerRadiusB =
-      radii[SideToHalfCorner(lineLeftSide, false, true)];
-
-    if (aWM.IsLineInverted()) {
-      // This happens only when aWM is vertical-lr. Need to swap blockStart
-      // and blockEnd corners.
-      std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
-      std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
-    }
-
-    nscoord lineLeftDiff =
-      ComputeEllipseLineInterceptDiff(
-        ShapeBoxRect().y, ShapeBoxRect().YMost(),
-        blockStartCornerRadiusL, blockStartCornerRadiusB,
-        blockEndCornerRadiusL, blockEndCornerRadiusB,
-        aBStart, aBEnd);
-    return ShapeBoxRect().x + lineLeftDiff;
-  }
-
-  // XXX: Other shape source types are not implemented yet.
-
-  return LineLeft();
+  // Clip the flow area to the margin-box because
+  // https://drafts.csswg.org/css-shapes-1/#relation-to-box-model-and-float-behavior
+  // says "When a shape is used to define a float area, the shape is clipped
+  // to the float’s margin box."
+  return std::max(LineLeft(), mShapeInfo->LineLeft(aWM, aBStart, aBEnd));
 }
 
 nscoord
 nsFloatManager::FloatInfo::LineRight(WritingMode aWM,
                                      ShapeType aShapeType,
                                      const nscoord aBStart,
                                      const nscoord aBEnd) const
 {
   if (aShapeType == ShapeType::Margin) {
     return LineRight();
   }
 
   MOZ_ASSERT(aShapeType == ShapeType::ShapeOutside);
-  const StyleShapeOutside& shapeOutside = mFrame->StyleDisplay()->mShapeOutside;
-  if (shapeOutside.GetType() == StyleShapeSourceType::None) {
+  if (!mShapeInfo) {
     return LineRight();
   }
+  // Clip the flow area to the margin-box. See LineLeft().
+  return std::min(LineRight(), mShapeInfo->LineRight(aWM, aBStart, aBEnd));
+}
+
+nscoord
+nsFloatManager::FloatInfo::BStart(ShapeType aShapeType) const
+{
+  if (aShapeType == ShapeType::Margin) {
+    return BStart();
+  }
 
-  if (shapeOutside.GetType() == StyleShapeSourceType::Box) {
-    nscoord radii[8];
-    bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
-
-    if (!hasRadii) {
-      return ShapeBoxRect().XMost();
-    }
+  MOZ_ASSERT(aShapeType == ShapeType::ShapeOutside);
+  if (!mShapeInfo) {
+    return BStart();
+  }
+  // Clip the flow area to the margin-box. See LineLeft().
+  return std::max(BStart(), mShapeInfo->BStart());
+}
 
-    // Get the physical side for line-right since border-radii are in
-    // the physical axis.
-    mozilla::Side lineRightSide =
-      aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirRight));
-    nscoord blockStartCornerRadiusL =
-      radii[SideToHalfCorner(lineRightSide, false, false)];
-    nscoord blockStartCornerRadiusB =
-      radii[SideToHalfCorner(lineRightSide, false, true)];
-    nscoord blockEndCornerRadiusL =
-      radii[SideToHalfCorner(lineRightSide, true, false)];
-    nscoord blockEndCornerRadiusB =
-      radii[SideToHalfCorner(lineRightSide, true, true)];
-
-    if (aWM.IsLineInverted()) {
-      // This happens only when aWM is vertical-lr. Need to swap blockStart
-      // and blockEnd corners.
-      std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
-      std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
-    }
-
-    nscoord lineRightDiff =
-      ComputeEllipseLineInterceptDiff(
-        ShapeBoxRect().y, ShapeBoxRect().YMost(),
-        blockStartCornerRadiusL, blockStartCornerRadiusB,
-        blockEndCornerRadiusL, blockEndCornerRadiusB,
-        aBStart, aBEnd);
-    return ShapeBoxRect().XMost() - lineRightDiff;
+nscoord
+nsFloatManager::FloatInfo::BEnd(ShapeType aShapeType) const
+{
+  if (aShapeType == ShapeType::Margin) {
+    return BEnd();
   }
 
-  // XXX: Other shape source types are not implemented yet.
+  MOZ_ASSERT(aShapeType == ShapeType::ShapeOutside);
+  if (!mShapeInfo) {
+    return BEnd();
+  }
+  // Clip the flow area to the margin-box. See LineLeft().
+  return std::min(BEnd(), mShapeInfo->BEnd());
+}
 
-  return LineRight();
+bool
+nsFloatManager::FloatInfo::IsEmpty(ShapeType aShapeType) const
+{
+  if (aShapeType == ShapeType::Margin) {
+    return IsEmpty();
+  }
+
+  MOZ_ASSERT(aShapeType == ShapeType::ShapeOutside);
+  if (!mShapeInfo) {
+    return IsEmpty();
+  }
+  return mShapeInfo->IsEmpty();
 }
 
 /* static */ nscoord
-nsFloatManager::FloatInfo::ComputeEllipseLineInterceptDiff(
+nsFloatManager::ShapeInfo::ComputeEllipseLineInterceptDiff(
   const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
   const nscoord aBStartCornerRadiusL, const nscoord aBStartCornerRadiusB,
   const nscoord aBEndCornerRadiusL, const nscoord aBEndCornerRadiusB,
   const nscoord aBandBStart, const nscoord aBandBEnd)
 {
   // An example for the band intersecting with the top right corner of an
   // ellipse with writing-mode horizontal-tb.
   //
@@ -775,17 +896,17 @@ nsFloatManager::FloatInfo::ComputeEllips
       XInterceptAtY(b, aBEndCornerRadiusL, aBEndCornerRadiusB);
     lineDiff = aBEndCornerRadiusL - lineIntercept;
   }
 
   return lineDiff;
 }
 
 /* static */ nscoord
-nsFloatManager::FloatInfo::XInterceptAtY(const nscoord aY,
+nsFloatManager::ShapeInfo::XInterceptAtY(const nscoord aY,
                                          const nscoord aRadiusX,
                                          const nscoord aRadiusY)
 {
   // Solve for x in the ellipse equation (x/radiusX)^2 + (y/radiusY)^2 = 1.
   MOZ_ASSERT(aRadiusY > 0);
   return aRadiusX * std::sqrt(1 - (aY * aY) / double(aRadiusY * aRadiusY));
 }
 
--- a/layout/generic/nsFloatManager.h
+++ b/layout/generic/nsFloatManager.h
@@ -5,28 +5,30 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* class that manages rules for positioning floats */
 
 #ifndef nsFloatManager_h_
 #define nsFloatManager_h_
 
 #include "mozilla/Attributes.h"
-#include "mozilla/Maybe.h"
+#include "mozilla/UniquePtr.h"
 #include "mozilla/WritingModes.h"
 #include "nsCoord.h"
 #include "nsFrameList.h" // for DEBUG_FRAME_DUMP
 #include "nsIntervalSet.h"
+#include "nsPoint.h"
 #include "nsTArray.h"
 
 class nsIPresShell;
 class nsIFrame;
 class nsPresContext;
 namespace mozilla {
 struct ReflowInput;
+class StyleBasicShape;
 } // namespace mozilla
 
 /**
  * The available space for content not occupied by floats is divided
  * into a sequence of rectangles in the block direction.  However, we
  * need to know not only the rectangle, but also whether it was reduced
  * (from the content rectangle) by floats that actually intruded into
  * the content rectangle.
@@ -196,19 +198,19 @@ public:
   /**
    * Add a float that comes after all floats previously added.  Its
    * block start must be even with or below the top of all previous
    * floats.
    *
    * aMarginRect is relative to the current translation.  The caller
    * must ensure aMarginRect.height >= 0 and aMarginRect.width >= 0.
    */
-  nsresult AddFloat(nsIFrame* aFloatFrame,
-                    const mozilla::LogicalRect& aMarginRect,
-                    mozilla::WritingMode aWM, const nsSize& aContainerSize);
+  void AddFloat(nsIFrame* aFloatFrame,
+                const mozilla::LogicalRect& aMarginRect,
+                mozilla::WritingMode aWM, const nsSize& aContainerSize);
 
   /**
    * Notify that we tried to place a float that could not fit at all and
    * had to be pushed to the next page/column?  (If so, we can't place
    * any more floats in this page/column because of the rule that the
    * top of a float cannot be above the top of an earlier float.  It
    * also means that any clear needs to continue to the next column.)
    */
@@ -327,16 +329,111 @@ public:
   /**
    * Dump the state of the float manager out to a file.
    */
   nsresult List(FILE* out) const;
 #endif
 
 private:
 
+  // ShapeInfo is an abstract class for implementing all the shapes in CSS
+  // Shapes Module. A subclass needs to override all the methods to adjust
+  // the flow area with respect to its shape.
+  class ShapeInfo
+  {
+  public:
+    virtual ~ShapeInfo() {}
+
+    virtual nscoord LineLeft(mozilla::WritingMode aWM,
+                             const nscoord aBStart,
+                             const nscoord aBEnd) const = 0;
+    virtual nscoord LineRight(mozilla::WritingMode aWM,
+                              const nscoord aBStart,
+                              const nscoord aBEnd) const = 0;
+    virtual nscoord BStart() const = 0;
+    virtual nscoord BEnd() const = 0;
+    virtual bool IsEmpty() const = 0;
+
+  protected:
+    // Compute the minimum line-axis difference between the bounding shape
+    // box and its rounded corner within the given band (block-axis region).
+    // This is used as a helper function to compute the LineRight() and
+    // LineLeft(). See the picture in the implementation for an example.
+    // RadiusL and RadiusB stand for radius on the line-axis and block-axis.
+    //
+    // Returns radius-x diff on the line-axis, or 0 if there's no rounded
+    // corner within the given band.
+    static nscoord ComputeEllipseLineInterceptDiff(
+      const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
+      const nscoord aBStartCornerRadiusL, const nscoord aBStartCornerRadiusB,
+      const nscoord aBEndCornerRadiusL, const nscoord aBEndCornerRadiusB,
+      const nscoord aBandBStart, const nscoord aBandBEnd);
+
+    static nscoord XInterceptAtY(const nscoord aY, const nscoord aRadiusX,
+                                 const nscoord aRadiusY);
+  };
+
+  // Implements shape-outside: <shape-box>.
+  class BoxShapeInfo final : public ShapeInfo
+  {
+  public:
+    BoxShapeInfo(const nsRect& aShapeBoxRect, nsIFrame* const aFrame)
+      : mShapeBoxRect(aShapeBoxRect)
+      , mFrame(aFrame)
+    {
+    }
+
+    nscoord LineLeft(mozilla::WritingMode aWM,
+                     const nscoord aBStart,
+                     const nscoord aBEnd) const override;
+    nscoord LineRight(mozilla::WritingMode aWM,
+                      const nscoord aBStart,
+                      const nscoord aBEnd) const override;
+    nscoord BStart() const override { return mShapeBoxRect.y; }
+    nscoord BEnd() const override { return mShapeBoxRect.YMost(); }
+    bool IsEmpty() const override { return mShapeBoxRect.IsEmpty(); };
+
+  private:
+    // This is the reference box of css shape-outside if specified, which
+    // implements the <shape-box> value in the CSS Shapes Module Level 1.
+    // The coordinate space is the same as FloatInfo::mRect.
+    const nsRect mShapeBoxRect;
+    // The frame of the float.
+    nsIFrame* const mFrame;
+  };
+
+  // Implements shape-outside: circle().
+  class CircleShapeInfo final : public ShapeInfo
+  {
+  public:
+    CircleShapeInfo(mozilla::StyleBasicShape* const aBasicShape,
+                    nscoord aLineLeft,
+                    nscoord aBlockStart,
+                    const mozilla::LogicalRect& aShapeBoxRect,
+                    mozilla::WritingMode aWM,
+                    const nsSize& aContainerSize);
+
+    nscoord LineLeft(mozilla::WritingMode aWM,
+                     const nscoord aBStart,
+                     const nscoord aBEnd) const override;
+    nscoord LineRight(mozilla::WritingMode aWM,
+                      const nscoord aBStart,
+                      const nscoord aBEnd) const override;
+    nscoord BStart() const override { return mCenter.y - mRadius; }
+    nscoord BEnd() const override { return mCenter.y + mRadius; }
+    bool IsEmpty() const override { return mRadius == 0; };
+
+  private:
+    // The position of the center of the circle. The coordinate space is the
+    // same as FloatInfo::mRect.
+    nsPoint mCenter;
+    // The radius of the circle in app units.
+    nscoord mRadius;
+  };
+
   struct FloatInfo {
     nsIFrame *const mFrame;
     // The lowest block-ends of left/right floats up to and including
     // this one.
     nscoord mLeftBEnd, mRightBEnd;
 
     FloatInfo(nsIFrame* aFrame, nscoord aLineLeft, nscoord aBlockStart,
               const mozilla::LogicalRect& aMarginRect,
@@ -345,68 +442,42 @@ private:
     nscoord LineLeft() const { return mRect.x; }
     nscoord LineRight() const { return mRect.XMost(); }
     nscoord ISize() const { return mRect.width; }
     nscoord BStart() const { return mRect.y; }
     nscoord BEnd() const { return mRect.YMost(); }
     nscoord BSize() const { return mRect.height; }
     bool IsEmpty() const { return mRect.IsEmpty(); }
 
-    nsRect ShapeBoxRect() const { return mShapeBoxRect.valueOr(mRect); }
-
     // aBStart and aBEnd are the starting and ending coordinate of a band.
     // LineLeft() and LineRight() return the innermost line-left extent and
     // line-right extent within the given band, respectively.
     nscoord LineLeft(mozilla::WritingMode aWM, ShapeType aShapeType,
                      const nscoord aBStart, const nscoord aBEnd) const;
     nscoord LineRight(mozilla::WritingMode aWM, ShapeType aShapeType,
                       const nscoord aBStart, const nscoord aBEnd) const;
-
-    nscoord BStart(ShapeType aShapeType) const
-    {
-      return aShapeType == ShapeType::Margin ? BStart() : ShapeBoxRect().y;
-    }
-    nscoord BEnd(ShapeType aShapeType) const
-    {
-      return aShapeType == ShapeType::Margin ? BEnd() : ShapeBoxRect().YMost();
-    }
-
-    // Compute the minimum line-axis difference between the bounding shape
-    // box and its rounded corner within the given band (block-axis region).
-    // This is used as a helper function to compute the LineRight() and
-    // LineLeft(). See the picture in the implementation for an example.
-    // RadiusL and RadiusB stand for radius on the line-axis and block-axis.
-    //
-    // Returns radius-x diff on the line-axis, or 0 if there's no rounded
-    // corner within the given band.
-    static nscoord ComputeEllipseLineInterceptDiff(
-      const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
-      const nscoord aBStartCornerRadiusL, const nscoord aBStartCornerRadiusB,
-      const nscoord aBEndCornerRadiusL, const nscoord aBEndCornerRadiusB,
-      const nscoord aBandBStart, const nscoord aBandBEnd);
-
-    static nscoord XInterceptAtY(const nscoord aY, const nscoord aRadiusX,
-                                 const nscoord aRadiusY);
+    nscoord BStart(ShapeType aShapeType) const;
+    nscoord BEnd(ShapeType aShapeType) const;
+    bool IsEmpty(ShapeType aShapeType) const;
 
 #ifdef NS_BUILD_REFCNT_LOGGING
-    FloatInfo(const FloatInfo& aOther);
+    FloatInfo(FloatInfo&& aOther);
     ~FloatInfo();
 #endif
 
     // NB! This is really a logical rect in a writing mode suitable for
     // placing floats, which is not necessarily the actual writing mode
     // either of the block which created the frame manager or the block
     // that is calling the frame manager. The inline coordinates are in
     // the line-relative axis of the frame manager and its block
     // coordinates are in the frame manager's real block direction.
     nsRect mRect;
-    // This is the reference box of css shape-outside if specified, which
-    // implements the <shape-box> value in the CSS Shapes Module Level 1.
-    // The coordinate setup is the same as mRect.
-    mozilla::Maybe<nsRect> mShapeBoxRect;
+    // Pointer to a concrete subclass of ShapeInfo or null, which means that
+    // there is no shape-outside.
+    mozilla::UniquePtr<ShapeInfo> mShapeInfo;
   };
 
 #ifdef DEBUG
   // Store the writing mode from the block frame which establishes the block
   // formatting context (BFC) when the nsFloatManager is created.
   mozilla::WritingMode mWritingMode;
 #endif
 
--- a/layout/reftests/bugs/315920-26.html
+++ b/layout/reftests/bugs/315920-26.html
@@ -1,20 +1,21 @@
 <!DOCTYPE html>
-<html>
+<html class="reftest-wait">
   <head>
     <style>
       span {color: red}
       #one:checked + span {color: green}
       #two:default + span {color: green}
     </style>
   </head>
 
   <body onload='document.getElementById("one").setAttribute("type", "checkbox");
-                document.getElementById("two").setAttribute("type", "checkbox");'>
+                document.getElementById("two").setAttribute("type", "checkbox");
+                document.documentElement.removeAttribute("class");'>
     <div>
       <input type="text" id="one" checked="checked"/>
       <span>Should be no red </span>
     </div>
     <div>
       <input type="text" id="two" checked="checked"/>
       <span>Should be no red </span>
     </div>
--- a/layout/reftests/forms/input/datetime/reftest-stylo.list
+++ b/layout/reftests/forms/input/datetime/reftest-stylo.list
@@ -1,14 +1,14 @@
 # DO NOT EDIT! This is a auto-generated temporary list for Stylo testing
 default-preferences pref(dom.forms.datetime,true)
 
-# not valid on Android/B2G where type=time looks like type=text
+# not valid on Android where type=time looks like type=text
 # == time-simple-unthemed.html time-simple-unthemed.html
 # == time-large-font.html time-large-font.html
 # == time-width-height.html time-width-height.html
 # == time-border.html time-border.html
-# only valid on Android/B2G where type=number looks the same as type=text
+# only valid on Android where type=number looks the same as type=text
 # == time-simple-unthemed.html time-simple-unthemed.html
 
 # type change
 # == to-time-from-other-type-unthemed.html to-time-from-other-type-unthemed.html
 # == from-time-to-other-type-unthemed.html from-time-to-other-type-unthemed.html
--- a/layout/reftests/forms/input/datetime/reftest.list
+++ b/layout/reftests/forms/input/datetime/reftest.list
@@ -1,13 +1,13 @@
 default-preferences pref(dom.forms.datetime,true)
 
-# not valid on Android/B2G where type=time looks like type=text
-skip-if(Android||B2G||Mulet) != time-simple-unthemed.html time-simple-unthemed-ref.html
-skip-if(Android||B2G||Mulet) != time-large-font.html time-basic.html
-skip-if(Android||B2G||Mulet) != time-width-height.html time-basic.html
-skip-if(Android||B2G||Mulet) != time-border.html time-basic.html
-# only valid on Android/B2G where type=number looks the same as type=text
-skip-if(!Android&&!B2G&&!Mulet) == time-simple-unthemed.html time-simple-unthemed-ref.html
+# not valid on Android where type=time looks like type=text
+skip-if(Android) != time-simple-unthemed.html time-simple-unthemed-ref.html
+skip-if(Android) != time-large-font.html time-basic.html
+skip-if(Android) != time-width-height.html time-basic.html
+skip-if(Android) != time-border.html time-basic.html
+# only valid on Android where type=number looks the same as type=text
+skip-if(!Android) == time-simple-unthemed.html time-simple-unthemed-ref.html
 
 # type change
-skip-if(Android||B2G||Mulet) == to-time-from-other-type-unthemed.html time-simple-unthemed.html
-skip-if(Android||B2G||Mulet) == from-time-to-other-type-unthemed.html from-time-to-other-type-unthemed-ref.html
+skip-if(Android) == to-time-from-other-type-unthemed.html time-simple-unthemed.html
+skip-if(Android) == from-time-to-other-type-unthemed.html from-time-to-other-type-unthemed-ref.html
--- a/layout/reftests/w3c-css/submitted/reftest.list
+++ b/layout/reftests/w3c-css/submitted/reftest.list
@@ -48,17 +48,19 @@ include multicol3/reftest.list
 
 # Ruby Layout Module
 include ruby/reftest.list
 
 # Selectors Level 4
 include selectors4/reftest.list
 
 # Shapes Level 1
-include shapes1/reftest.list
+# Bug 1300355: Skip shapes reftests to prevent frequent intermittent failures
+# on Win7 debug.
+skip-if(winWidget&&isDebugBuild) include shapes1/reftest.list
 
 # Text Level 3
 # In Bug 1316482, we've added a large number of tests in this folder, which
 # indirectly causes frequent reftest failures on win7 debug. (see Bug 1300355)
 # Since the root cause is not these tests, skip them on win7 debug for now.
 # Once we come up with a better solution, we should re-enable this folder on
 # win7 debug.
 skip-if(winWidget&&isDebugBuild) include text3/reftest.list
--- a/layout/reftests/w3c-css/submitted/shapes1/reftest.list
+++ b/layout/reftests/w3c-css/submitted/shapes1/reftest.list
@@ -1,9 +1,9 @@
-default-preferences pref(layout.css.shape-outside.enabled,true)
+default-preferences pref(layout.css.shape-outside.enabled,true) pref(layout.css.clip-path-shapes.enabled,true)
 
 # <shape-box> only
 == shape-outside-margin-box-001.html shape-outside-margin-box-001-ref.html
 == shape-outside-margin-box-002.html shape-outside-margin-box-002-ref.html
 == shape-outside-border-box-001.html shape-outside-border-box-001-ref.html
 == shape-outside-border-box-002.html shape-outside-border-box-002-ref.html
 == shape-outside-padding-box-001.html shape-outside-padding-box-001-ref.html
 == shape-outside-padding-box-002.html shape-outside-padding-box-002-ref.html
@@ -30,8 +30,34 @@ fails == shape-outside-border-box-border
 == shape-outside-border-box-border-radius-009.html shape-outside-border-box-border-radius-009-ref.html
 == shape-outside-border-box-border-radius-010.html shape-outside-border-box-border-radius-010-ref.html
 == shape-outside-border-box-border-radius-011.html shape-outside-border-box-border-radius-011-ref.html
 == shape-outside-border-box-border-radius-012.html shape-outside-border-box-border-radius-012-ref.html
 == shape-outside-padding-box-border-radius-001.html shape-outside-padding-box-border-radius-001-ref.html
 == shape-outside-padding-box-border-radius-002.html shape-outside-padding-box-border-radius-002-ref.html
 == shape-outside-content-box-border-radius-001.html shape-outside-content-box-border-radius-001-ref.html
 == shape-outside-content-box-border-radius-002.html shape-outside-content-box-border-radius-002-ref.html
+
+# Basic shape: circle()
+== shape-outside-circle-001.html shape-outside-circle-001-ref.html
+== shape-outside-circle-002.html shape-outside-circle-002-ref.html
+== shape-outside-circle-003.html shape-outside-circle-003-ref.html
+== shape-outside-circle-004.html shape-outside-circle-004-ref.html
+== shape-outside-circle-005.html shape-outside-circle-005-ref.html
+== shape-outside-circle-006.html shape-outside-circle-005-ref.html
+== shape-outside-circle-007.html shape-outside-circle-005-ref.html
+== shape-outside-circle-008.html shape-outside-circle-008-ref.html
+== shape-outside-circle-009.html shape-outside-circle-008-ref.html
+== shape-outside-circle-010.html shape-outside-circle-010-ref.html
+== shape-outside-circle-011.html shape-outside-circle-011-ref.html
+== shape-outside-circle-012.html shape-outside-circle-011-ref.html
+== shape-outside-circle-013.html shape-outside-circle-011-ref.html
+== shape-outside-circle-014.html shape-outside-circle-014-ref.html
+== shape-outside-circle-015.html shape-outside-circle-014-ref.html
+== shape-outside-circle-016.html shape-outside-circle-016-ref.html
+== shape-outside-circle-017.html shape-outside-circle-017-ref.html
+== shape-outside-circle-018.html shape-outside-circle-018-ref.html
+== shape-outside-circle-019.html shape-outside-circle-019-ref.html
+== shape-outside-circle-020.html shape-outside-circle-020-ref.html
+== shape-outside-circle-021.html shape-outside-circle-021-ref.html
+== shape-outside-circle-022.html shape-outside-circle-022-ref.html
+== shape-outside-circle-023.html shape-outside-circle-023-ref.html
+== shape-outside-circle-024.html shape-outside-circle-024-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-001-ref.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, circle(50% at left top) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    position: absolute;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    /* Omit shape-outside */
+    clip-path: circle(50% at left top);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    width: 120px;
+    background-color: blue;
+  }
+
+  .long {
+    width: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="shape"></div>
+    <div class="box" style="height: 36px; top: 0px; left: 60px;"></div>
+    <div class="box" style="height: 12px; top: 36px; left: 48px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px; top: 48px; left: 36px;"></div>  <!-- Box at corner -->
+    <div class="long box" style="height: 60px; top: 60px; left: 0px;"></div> <!-- Fill the space between two floats -->
+    <div class="box" style="height: 36px; top: 120px; left: 60px;"></div>
+    <div class="box" style="height: 12px; top: 156px; left: 48px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px; top: 168px; left: 36px;"></div>  <!-- Box at corner -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-001.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, circle(50% at left top)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-001-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape circle(50% at left top) value.">
+  <style>
+  .container {
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: circle(50% at left top);
+    clip-path: circle(50% at left top);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 120px;
+    background-color: blue;
+  }
+
+  .long {
+    width: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="shape"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="long box" style="height: 60px;"></div> <!-- Fill the space between two floats -->
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-002-ref.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, circle(50% at right bottom) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    position: absolute;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    /* Omit shape-outside */
+    clip-path: circle(50% at right bottom);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    width: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    width: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="shape"></div>
+    <div class="long box" style="height: 60px; top: 0px; left: 0px;"></div> <!-- Fill the space above the first float -->
+    <div class="box" style="height: 36px; top: 60px; left: 120px;"></div>
+    <div class="box" style="height: 12px; top: 96px; left: 120px;"></div>
+    <div class="box" style="height: 12px; top: 108px; left: 120px;"></div>
+    <div class="long box" style="height: 60px; top: 120px; left: 0px;"></div> <!-- Fill the space between two floats -->
+    <div class="box" style="height: 36px; top: 180px; left: 120px;"></div>
+    <div class="box" style="height: 12px; top: 216px; left: 120px;"></div>
+    <div class="box" style="height: 12px; top: 228px; left: 120px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-002.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, circle(50% at right bottom)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-002-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape circle(50% at right bottom) value.">
+  <style>
+  .container {
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: circle(50% at right bottom);
+    clip-path: circle(50% at right bottom);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    width: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="shape"></div>
+    <div class="long box" style="height: 60px;"></div> <!-- Fill the space above the first float -->
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="long box" style="height: 60px;"></div> <!-- Fill the space between two floats -->
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-003-ref.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, circle(50% at right top) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    direction: rtl;
+    position: absolute;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    /* Omit shape-outside */
+    clip-path: circle(50% at right top);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    width: 120px;
+    background-color: blue;
+  }
+
+  .long {
+    width: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="shape"></div>
+    <div class="box" style="height: 36px; top: 0px; right: 60px;"></div>
+    <div class="box" style="height: 12px; top: 36px; right: 48px;"></div>
+    <div class="box" style="height: 12px; top: 48px; right: 36px;"></div>
+    <div class="long box" style="height: 60px; top: 60px; right: 0px;"></div> <!-- Fill the space between two floats -->
+    <div class="box" style="height: 36px; top: 120px; right: 60px;"></div>
+    <div class="box" style="height: 12px; top: 156px; right: 48px;"></div>
+    <div class="box" style="height: 12px; top: 168px; right: 36px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-003.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, circle(50% at right top)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-003-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the basic shape circle(50% at right top) value.">
+  <style>
+  .container {
+    direction: rtl;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: circle(50% at right top);
+    clip-path: circle(50% at right top);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 120px;
+    background-color: blue;
+  }
+
+  .long {
+    width: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="shape"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="long box" style="height: 60px;"></div> <!-- Fill the space between two floats -->
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-004-ref.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, circle(50% at left bottom) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    direction: rtl;
+    position: absolute;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    /* Omit shape-outside */
+    clip-path: circle(50% at left bottom);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    width: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    width: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="shape"></div>
+    <div class="long box" style="height: 60px; top: 0px; right: 0px;"></div> <!-- Fill the space above the first float -->
+    <div class="box" style="height: 36px; top: 60px; right: 120px;"></div>
+    <div class="box" style="height: 12px; top: 96px; right: 120px;"></div>
+    <div class="box" style="height: 12px; top: 108px; right: 120px;"></div>
+    <div class="long box" style="height: 60px; top: 120px; right: 0px;"></div> <!-- Fill the space between two floats -->
+    <div class="box" style="height: 36px; top: 180px; right: 120px;"></div>
+    <div class="box" style="height: 12px; top: 216px; right: 120px;"></div>
+    <div class="box" style="height: 12px; top: 228px; right: 120px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-004.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, circle(50% at left bottom)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-004-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the basic shape circle(50% at left bottom) value.">
+  <style>
+  .container {
+    direction: rtl;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: circle(50% at left bottom);
+    clip-path: circle(50% at left bottom);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    width: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="shape"></div>
+    <div class="long box" style="height: 60px;"></div> <!-- Fill the space above the first float -->
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="long box" style="height: 60px;"></div> <!-- Fill the space between two floats -->
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-005-ref.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, circle() reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    position: absolute;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    /* Omit shape-outside */
+    clip-path: circle();
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    width: 60px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px; top: 0px; left: 96px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px; top: 12px; left: 108px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 36px; top: 24px; left: 120px;"></div>
+    <div class="box" style="height: 36px; top: 60px; left: 120px;"></div>
+    <div class="box" style="height: 12px; top: 96px; left: 108px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px; top: 108px; left: 96px;"></div> <!-- Box at corner -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-005.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, circle()</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-005-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape circle() value.">
+  <style>
+  .container {
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: circle();
+    clip-path: circle();
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 60px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-006.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, circle(closest-side at center) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-005-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape circle(closest-side at center) border-box value.">
+  <style>
+  .container {
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: circle(closest-side at center) border-box;
+    clip-path: circle(closest-side at center) border-box;
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-right: 10px; /* Not affect layout of the boxes */
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 60px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-007.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, circle(farthest-side at center)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-005-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape circle(farthest-side at center) value.">
+  <style>
+  .container {
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: circle(farthest-side at center);
+    clip-path: circle(farthest-side at center);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 60px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-008-ref.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, circle(0%) border-box reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    position: absolute;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    /* Omit shape-outside */
+    clip-path: circle(0%) border-box;
+    box-sizing: content-box;
+    height: 20px;
+    width: 20px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin: 10px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    width: 200px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px; top: 0px; left: 0px;"></div>
+    <div class="box" style="height: 12px; top: 12px; left: 0px;"></div>
+    <div class="box" style="height: 36px; top: 24px; left: 0px;"></div>
+    <div class="box" style="height: 36px; top: 60px; left: 0px;"></div>
+    <div class="box" style="height: 12px; top: 96px; left: 0px;"></div>
+    <div class="box" style="height: 12px; top: 108px; left: 0px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-008.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, circle(0%) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-008-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the left float shape defines an empty float area by the basic shape circle(0%) border-box value.">
+  <style>
+  .container {
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: circle(0%) border-box;
+    clip-path: circle(0%) border-box;
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin: 10px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 200px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-009.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, circle(closest-side at left center) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-008-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the left float shape defines an empty float area by the basic shape circle(closest-side at left center) border-box value.">
+  <style>
+  .container {
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: circle(closest-side at left center) border-box;
+    clip-path: circle(closest-side at left center) border-box;
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin: 10px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 200px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-010-ref.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, circle(100%) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    position: absolute;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    /* Omit shape-outside */
+    clip-path: circle(100%);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    width: 60px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px; top: 0px; left: 120px;"></div>
+    <div class="box" style="height: 12px; top: 12px; left: 120px;"></div>
+    <div class="box" style="height: 36px; top: 24px; left: 120px;"></div>
+    <div class="box" style="height: 36px; top: 60px; left: 120px;"></div>
+    <div class="box" style="height: 12px; top: 96px; left: 120px;"></div>
+    <div class="box" style="height: 12px; top: 108px; left: 120px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-010.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, circle(100%)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-010-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape circle(100%) value.">
+  <style>
+  .container {
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: circle(100%);
+    clip-path: circle(100%); /* Rendered as a rectangle */
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 60px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-011-ref.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, circle() reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    direction: rtl;
+    position: absolute;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    /* Omit shape-outside */
+    clip-path: circle();
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    width: 60px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px; top: 0px; right: 96px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px; top: 12px; right: 108px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 36px; top: 24px; right: 120px;"></div>
+    <div class="box" style="height: 36px; top: 60px; right: 120px;"></div>
+    <div class="box" style="height: 12px; top: 96px; right: 108px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px; top: 108px; right: 96px;"></div> <!-- Box at corner -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-011.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, circle()</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-011-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the basic shape circle() value.">
+  <style>
+  .container {
+    direction: rtl;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: circle();
+    clip-path: circle();
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 60px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-012.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, circle(closest-side at center) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-011-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the basic shape circle(closest-side at center) border-box value.">
+  <style>
+  .container {
+    direction: rtl;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: circle(closest-side at center) border-box;
+    clip-path: circle(closest-side at center) border-box;
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-left: 10px; /* Not affect layout of the boxes */
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 60px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-013.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, circle(farthest-side at center)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-011-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the basic shape circle(farthest-side at center) value.">
+  <style>
+  .container {
+    direction: rtl;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: circle(farthest-side at center);
+    clip-path: circle(farthest-side at center);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 60px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="height: 12px;"></div> <!-- Box at corner -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-014-ref.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, circle(0%) border-box reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    direction: rtl;
+    position: absolute;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    /* Omit shape-outside */
+    clip-path: circle(0%) border-box;
+    box-sizing: content-box;
+    height: 20px;
+    width: 20px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin: 10px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    width: 200px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px; top: 0px; right: 0px;"></div>
+    <div class="box" style="height: 12px; top: 12px; right: 0px;"></div>
+    <div class="box" style="height: 36px; top: 24px; right: 0px;"></div>
+    <div class="box" style="height: 36px; top: 60px; right: 0px;"></div>
+    <div class="box" style="height: 12px; top: 96px; right: 0px;"></div>
+    <div class="box" style="height: 12px; top: 108px; right: 0px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-014.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, circle(0%) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-014-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the right float shape defines an empty float area by the basic shape circle(0%) border-box value.">
+  <style>
+  .container {
+    direction: rtl;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: circle(0%) border-box;
+    clip-path: circle(0%) border-box;
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin: 10px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 200px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-015.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, circle(closest-side at right center) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-014-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the right float shape defines an empty float area by the basic shape circle(closest-side at right center) border-box value.">
+  <style>
+  .container {
+    direction: rtl;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: circle(closest-side at right center) border-box;
+    clip-path: circle(closest-side at right center) border-box;
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin: 10px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 200px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-016-ref.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, circle(100%) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    direction: rtl;
+    position: absolute;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    /* Omit shape-outside */
+    clip-path: circle(100%);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    width: 60px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px; top: 0px; right: 120px;"></div>
+    <div class="box" style="height: 12px; top: 12px; right: 120px;"></div>
+    <div class="box" style="height: 36px; top: 24px; right: 120px;"></div>
+    <div class="box" style="height: 36px; top: 60px; right: 120px;"></div>
+    <div class="box" style="height: 12px; top: 96px; right: 120px;"></div>
+    <div class="box" style="height: 12px; top: 108px; right: 120px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-016.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, circle(100%)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-016-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the basic shape circle(100%) value.">
+  <style>
+  .container {
+    direction: rtl;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: circle(100%);
+    clip-path: circle(100%); /* Rendered as a rectangle */
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 60px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 12px;"></div>
+    <div class="box" style="height: 12px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-017-ref.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-rl, float left, circle(50% at left 40px top 40px) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: vertical-rl;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    /* Omit shape-outside */
+    clip-path: circle(50% at left 40px top 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-start: 20px;
+    margin-block-end: 28px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px; offset-block-start: 0px; offset-inline-start: 0;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px; offset-block-start: 20px; offset-inline-start: 96px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px; offset-block-start: 32px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 44px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 80px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 12px; offset-block-start: 116px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px; offset-block-start: 128px; offset-inline-start: 0;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-017.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-rl, float left, circle(50% at left 40px top 40px)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-017-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the left float shape defined by circle(50% at left 40px top 40px) value under vertical-rl writing-mode.">
+  <style>
+  .container {
+    writing-mode: vertical-rl;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: circle(50% at left 40px top 40px) border-box;
+    clip-path: circle(50% at left 40px top 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-end: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-018-ref.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-rl, float right, circle(50% at left 40px bottom 40px) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: vertical-rl;
+    direction: rtl;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    /* Omit shape-outside */
+    clip-path: circle(50% at left 40px bottom 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-start: 20px;
+    margin-block-end: 28px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px; offset-block-start: 0px; offset-inline-start: 0;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px; offset-block-start: 20px; offset-inline-start: 96px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px; offset-block-start: 32px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 44px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 80px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 12px; offset-block-start: 116px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px; offset-block-start: 128px; offset-inline-start: 0;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-018.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-rl, float right, circle(50% at left 40px bottom 40px)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-018-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by circle(50% at left 40px bottom 40px) value under vertical-rl writing-mode.">
+  <style>
+  .container {
+    writing-mode: vertical-rl;
+    direction: rtl;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: circle(50% at left 40px bottom 40px) border-box;
+    clip-path: circle(50% at left 40px bottom 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-end: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-019-ref.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-lr, float left, circle(50% at right 40px top 40px) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: vertical-lr;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    /* Omit shape-outside */
+    clip-path: circle(50% at right 40px top 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-start: 20px;
+    margin-block-end: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px; offset-block-start: 0px; offset-inline-start: 0;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px; offset-block-start: 20px; offset-inline-start: 96px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px; offset-block-start: 32px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 44px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 80px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 12px; offset-block-start: 116px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px; offset-block-start: 128px; offset-inline-start: 0;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-019.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-lr, float left, circle(50% at right 40px top 40px)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-019-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by circle(50% at right 40px top 40px) value under vertical-lr writing-mode.">
+  <style>
+  .container {
+    writing-mode: vertical-lr;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: circle(50% at right 40px top 40px) border-box;
+    clip-path: circle(50% at right 40px top 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-end: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-020-ref.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-lr, float right, circle(50% at right 40px bottom 40px) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: vertical-lr;
+    direction: rtl;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    /* Omit shape-outside */
+    clip-path: circle(50% at right 40px bottom 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-start: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px; offset-block-start: 0px; offset-inline-start: 0;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px; offset-block-start: 20px; offset-inline-start: 96px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px; offset-block-start: 32px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 44px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 80px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 12px; offset-block-start: 116px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px; offset-block-start: 128px; offset-inline-start: 0;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-020.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-lr, float right, circle(50% at right 40px bottom 40px)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-020-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by circle(50% at right 40px bottom 40px) value under vertical-lr writing-mode.">
+  <style>
+  .container {
+    writing-mode: vertical-lr;
+    direction: rtl;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: circle(50% at right 40px bottom 40px) border-box;
+    clip-path: circle(50% at right 40px bottom 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-end: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-021-ref.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: sideways-lr, float left, circle(50% at right 40px bottom 40px) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: sideways-lr;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    /* Omit shape-outside */
+    clip-path: circle(50% at right 40px bottom 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-start: 20px;
+    margin-block-end: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px; offset-block-start: 0px; offset-inline-start: 0;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px; offset-block-start: 20px; offset-inline-start: 96px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px; offset-block-start: 32px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 44px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 80px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 12px; offset-block-start: 116px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px; offset-block-start: 128px; offset-inline-start: 0;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-021.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: sideways-lr, float left, circle(50% at right 40px bottom 40px)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-021-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the left float shape defined by circle(50% at right 40px bottom 40px) value under sideways-lr writing-mode.">
+  <style>
+  .container {
+    writing-mode: sideways-lr;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: circle(50% at right 40px bottom 40px) border-box;
+    clip-path: circle(50% at right 40px bottom 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-end: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-022-ref.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: sideways-lr, float right, circle(50% at right 40px top 40px) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: sideways-lr;
+    direction: rtl;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    /* Omit shape-outside */
+    clip-path: circle(50% at right 40px top 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-start: 20px;
+    margin-block-end: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px; offset-block-start: 0px; offset-inline-start: 0;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px; offset-block-start: 20px; offset-inline-start: 96px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px; offset-block-start: 32px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 44px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 80px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 12px; offset-block-start: 116px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px; offset-block-start: 128px; offset-inline-start: 0;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-022.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: sideways-lr, float right, circle(50% at right 40px top 40px)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-022-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by circle(50% at right 40px top 40px) value under sideways-lr writing-mode.">
+  <style>
+  .container {
+    writing-mode: sideways-lr;
+    direction: rtl;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: circle(50% at right 40px top 40px) border-box;
+    clip-path: circle(50% at right 40px top 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-end: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-023-ref.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: horizontal-tb, float left, circle(50% at left 40px bottom 40px) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: horizontal-tb;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    /* Omit shape-outside */
+    clip-path: circle(50% at left 40px bottom 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-start: 20px;
+    margin-block-end: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px; offset-block-start: 0px; offset-inline-start: 0;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px; offset-block-start: 20px; offset-inline-start: 96px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px; offset-block-start: 32px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 44px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 80px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 12px; offset-block-start: 116px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px; offset-block-start: 128px; offset-inline-start: 0;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-023.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: horizontal-tb, float left, circle(50% at left 40px bottom 40px)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-023-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the left float shape defined by circle(50% at left 40px bottom 40px) value under horizontal-tb writing-mode.">
+  <style>
+  .container {
+    writing-mode: horizontal-tb;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: circle(50% at left 40px bottom 40px) border-box;
+    clip-path: circle(50% at left 40px bottom 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-end: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-024-ref.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: horizontal-tb, float right, circle(50% at right 40px bottom 40px) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: horizontal-tb;
+    direction: rtl;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    /* Omit shape-outside */
+    clip-path: circle(50% at right 40px bottom 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-start: 20px;
+    margin-block-end: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px; offset-block-start: 0px; offset-inline-start: 0;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px; offset-block-start: 20px; offset-inline-start: 96px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px; offset-block-start: 32px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 44px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 80px; offset-inline-start: 120px;"></div>
+    <div class="box" style="block-size: 12px; offset-block-start: 116px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px; offset-block-start: 128px; offset-inline-start: 0;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-024.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: horizontal-tb, float right, circle(50% at right 40px bottom 40px)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-circle-024-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by circle(50% at right 40px bottom 40px) value under horizontal-tb writing-mode.">
+  <style>
+  .container {
+    writing-mode: horizontal-tb;
+    direction: rtl;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: circle(50% at right 40px bottom 40px) border-box;
+    clip-path: circle(50% at right 40px bottom 40px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin-inline-start: 20px;
+    margin-inline-end: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 20px;"></div> <!-- Fill the border area due to the circle shifted -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 20px;"></div>
+  </body>
+</html>
--- a/layout/style/CSSStyleSheet.cpp
+++ b/layout/style/CSSStyleSheet.cpp
@@ -760,26 +760,16 @@ CSSStyleSheet::Clone(CSSStyleSheet* aClo
 static void
 ListRules(const nsCOMArray<css::Rule>& aRules, FILE* aOut, int32_t aIndent)
 {
   for (int32_t index = aRules.Count() - 1; index >= 0; --index) {
     aRules.ObjectAt(index)->List(aOut, aIndent);
   }
 }
 
-struct ListEnumData {
-  ListEnumData(FILE* aOut, int32_t aIndent)
-    : mOut(aOut),
-      mIndent(aIndent)
-  {
-  }
-  FILE*   mOut;
-  int32_t mIndent;
-};
-
 void
 CSSStyleSheet::List(FILE* out, int32_t aIndent) const
 {
 
   int32_t index;
 
   // Indent
   nsAutoCString str;
--- a/layout/svg/nsCSSClipPathInstance.cpp
+++ b/layout/svg/nsCSSClipPathInstance.cpp
@@ -6,16 +6,17 @@
 // Main header first:
 #include "nsCSSClipPathInstance.h"
 
 #include "gfx2DGlue.h"
 #include "gfxPlatform.h"
 #include "mozilla/dom/SVGSVGElement.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/PathHelpers.h"
+#include "mozilla/ShapeUtils.h"
 #include "nsCSSRendering.h"
 #include "nsIFrame.h"
 #include "nsRenderingContext.h"
 #include "nsRuleNode.h"
 #include "nsSVGElement.h"
 #include "nsSVGUtils.h"
 #include "nsSVGViewBox.h"
 
@@ -99,115 +100,71 @@ nsCSSClipPathInstance::CreateClipPath(Dr
     default:
       MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected shape type");
   }
   // Return an empty Path:
   RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
   return builder->Finish();
 }
 
-static void
-EnumerationToLength(nscoord& aCoord, StyleShapeRadius aType,
-                    nscoord aCenter, nscoord aPosMin, nscoord aPosMax)
-{
-  nscoord dist1 = abs(aPosMin - aCenter);
-  nscoord dist2 = abs(aPosMax - aCenter);
-  switch (aType) {
-    case StyleShapeRadius::FarthestSide:
-      aCoord = dist1 > dist2 ? dist1 : dist2;
-      break;
-    case StyleShapeRadius::ClosestSide:
-      aCoord = dist1 > dist2 ? dist2 : dist1;
-      break;
-  }
-}
-
 already_AddRefed<Path>
 nsCSSClipPathInstance::CreateClipPathCircle(DrawTarget* aDrawTarget,
                                             const nsRect& aRefBox)
 {
   StyleBasicShape* basicShape = mClipPathStyle.GetBasicShape();
 
   RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
 
-  nsPoint topLeft, anchor;
-  nsSize size = nsSize(aRefBox.width, aRefBox.height);
-  nsImageRenderer::ComputeObjectAnchorPoint(basicShape->GetPosition(),
-                                            size, size,
-                                            &topLeft, &anchor);
-  Point center = Point(anchor.x + aRefBox.x, anchor.y + aRefBox.y);
-
-  const nsTArray<nsStyleCoord>& coords = basicShape->Coordinates();
-  MOZ_ASSERT(coords.Length() == 1, "wrong number of arguments");
-  nscoord r = 0;
-  if (coords[0].GetUnit() == eStyleUnit_Enumerated) {
-    const auto styleShapeRadius = coords[0].GetEnumValue<StyleShapeRadius>();
-    nscoord horizontal, vertical;
-    EnumerationToLength(horizontal, styleShapeRadius,
-                        center.x, aRefBox.x, aRefBox.x + aRefBox.width);
-    EnumerationToLength(vertical, styleShapeRadius,
-                        center.y, aRefBox.y, aRefBox.y + aRefBox.height);
-    if (styleShapeRadius == StyleShapeRadius::FarthestSide) {
-      r = horizontal > vertical ? horizontal : vertical;
-    } else {
-      r = horizontal < vertical ? horizontal : vertical;
-    }
-  } else {
-    // We resolve percent <shape-radius> value for circle() as defined here:
-    // https://drafts.csswg.org/css-shapes/#funcdef-circle
-    double referenceLength =
-      SVGContentUtils::ComputeNormalizedHypotenuse(aRefBox.width,
-                                                   aRefBox.height);
-    r = nsRuleNode::ComputeCoordPercentCalc(coords[0],
-                                            NSToCoordRound(referenceLength));
-  }
-
+  nsPoint center =
+    ShapeUtils::ComputeCircleOrEllipseCenter(basicShape, aRefBox);
+  nscoord r = ShapeUtils::ComputeCircleRadius(basicShape, center, aRefBox);
   nscoord appUnitsPerDevPixel =
     mTargetFrame->PresContext()->AppUnitsPerDevPixel();
-  builder->Arc(center / appUnitsPerDevPixel, r / appUnitsPerDevPixel,
+  builder->Arc(Point(center.x, center.y) / appUnitsPerDevPixel,
+               r / appUnitsPerDevPixel,
                0, Float(2 * M_PI));
   builder->Close();
   return builder->Finish();
 }
 
 already_AddRefed<Path>
 nsCSSClipPathInstance::CreateClipPathEllipse(DrawTarget* aDrawTarget,
                                              const nsRect& aRefBox)
 {
   StyleBasicShape* basicShape = mClipPathStyle.GetBasicShape();
 
   RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
 
-  nsPoint topLeft, anchor;
-  nsSize size = nsSize(aRefBox.width, aRefBox.height);
-  nsImageRenderer::ComputeObjectAnchorPoint(basicShape->GetPosition(),
-                                            size, size,
-                                            &topLeft, &anchor);
-  Point center = Point(anchor.x + aRefBox.x, anchor.y + aRefBox.y);
+  nsPoint center =
+    ShapeUtils::ComputeCircleOrEllipseCenter(basicShape, aRefBox);
 
   const nsTArray<nsStyleCoord>& coords = basicShape->Coordinates();
   MOZ_ASSERT(coords.Length() == 2, "wrong number of arguments");
   nscoord rx = 0, ry = 0;
   if (coords[0].GetUnit() == eStyleUnit_Enumerated) {
-    EnumerationToLength(rx, coords[0].GetEnumValue<StyleShapeRadius>(),
-                        center.x, aRefBox.x, aRefBox.x + aRefBox.width);
+    rx = ShapeUtils::ComputeShapeRadius(coords[0].GetEnumValue<StyleShapeRadius>(),
+                                        center.x,
+                                        aRefBox.x,
+                                        aRefBox.x + aRefBox.width);
   } else {
     rx = nsRuleNode::ComputeCoordPercentCalc(coords[0], aRefBox.width);
   }
   if (coords[1].GetUnit() == eStyleUnit_Enumerated) {
-    EnumerationToLength(ry, coords[1].GetEnumValue<StyleShapeRadius>(),
-                        center.y, aRefBox.y, aRefBox.y + aRefBox.height);
+    ry = ShapeUtils::ComputeShapeRadius(coords[1].GetEnumValue<StyleShapeRadius>(),
+                                        center.y,
+                                        aRefBox.y,
+                                        aRefBox.y + aRefBox.height);
   } else {
     ry = nsRuleNode::ComputeCoordPercentCalc(coords[1], aRefBox.height);
   }
 
   nscoord appUnitsPerDevPixel =
     mTargetFrame->PresContext()->AppUnitsPerDevPixel();
   EllipseToBezier(builder.get(),
-                  center / appUnitsPerDevPixel,
+                  Point(center.x, center.y) / appUnitsPerDevPixel,
                   Size(rx, ry) / appUnitsPerDevPixel);
   builder->Close();
   return builder->Finish();
 }
 
 already_AddRefed<Path>
 nsCSSClipPathInstance::CreateClipPathPolygon(DrawTarget* aDrawTarget,
                                              const nsRect& aRefBox)
deleted file mode 100644
--- a/layout/tools/reftest/b2g_start_script.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
-
-function setPermissions() {
-  if (__webDriverArguments.length < 2) {
-    return;
-  }
-
-  let serverAddr = __webDriverArguments[0];
-  let serverPort = __webDriverArguments[1];
-  let perms = Cc["@mozilla.org/permissionmanager;1"]
-              .getService(Ci.nsIPermissionManager);
-  let ioService = Cc["@mozilla.org/network/io-service;1"]
-                  .getService(Ci.nsIIOService);
-  let uri = ioService.newURI("http://" + serverAddr + ":" + serverPort);
-  perms.add(uri, "allowXULXBL", Ci.nsIPermissionManager.ALLOW_ACTION);
-}
-
-var cm = Cc["@mozilla.org/categorymanager;1"]
-           .getService(Ci.nsICategoryManager);
-
-// Disable update timers that cause b2g failures.
-if (cm) {
-  cm.deleteCategoryEntry("update-timer", "nsUpdateService", false);
-}
-
-// Load into any existing windows
-var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
-            .getService(Ci.nsIWindowMediator);
-var win = wm.getMostRecentWindow('');
-
-setPermissions();
-
-// Loading this into the global namespace causes intermittent failures.
-// See bug 882888 for more details.
-var reftest = {};
-Cu.import("chrome://reftest/content/reftest.jsm", reftest);
-
-// Prevent display off during testing.
-navigator.mozPower.screenEnabled = true;
-var settingLock = navigator.mozSettings.createLock();
-var settingResult = settingLock.set({
-  'screen.timeout': 0
-});
-settingResult.onsuccess = function () {
-  dump("Set screen.time to 0\n");
-  // Start the reftests
-  reftest.OnRefTestLoad(win);
-}
-settingResult.onerror = function () {
-  dump("Change screen.time failed\n");
-  // Start the reftests
-  reftest.OnRefTestLoad(win);
-}
--- a/layout/tools/reftest/bootstrap.js
+++ b/layout/tools/reftest/bootstrap.js
@@ -28,21 +28,16 @@ var WindowListener = {
         // Add setTimeout here because windows.innerWidth/Height are not set yet.
         win.setTimeout(function() {OnRefTestLoad(win);}, 0);
       });
     }, false);
   }
 };
 
 function startup(data, reason) {
-  // b2g is bootstrapped by b2g_start_script.js
-  if (Services.appinfo.widgetToolkit == "gonk") {
-    return;
-  }
-
   if (Services.appinfo.OS == "Android") {
     Cm.addBootstrappedManifestLocation(data.installPath);
     Services.wm.addListener(WindowListener);
     return;
   }
 
   let orig = Services.wm.getMostRecentWindow("navigator:browser");
 
@@ -61,20 +56,16 @@ function startup(data, reason) {
 
     dummy.focus();
     wwatch.openWindow(null, "chrome://reftest/content/reftest.xul", "_blank",
                       "chrome,dialog=no,all", {});
   };
 }
 
 function shutdown(data, reason) {
-  if (Services.appinfo.widgetToolkit == "gonk") {
-    return;
-  }
-
   if (Services.appinfo.OS == "Android") {
     Services.wm.removeListener(WindowListener);
     Cm.removedBootstrappedManifestLocation(data.installPath);
     OnRefTestUnload();
     Cu.unload("chrome://reftest/content/reftest.jsm");
   }
 }
 
deleted file mode 100644
--- a/layout/tools/reftest/gaia_lock_screen.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// NOTE: This code was forked from:
-// https://github.com/mozilla-b2g/gaia/blob/master/tests/atoms/gaia_lock_screen.js
-
-'use strict';
-/* globals waitFor, finish */
-/* exported GaiaLockScreen */
-
-var GaiaLockScreen = {
-
-  unlock: function(forcibly) {
-    let setlock = window.wrappedJSObject.SettingsListener.getSettingsLock();
-    let service = window.wrappedJSObject.Service;
-    let obj = {'screen.timeout': 0};
-    setlock.set(obj);
-
-    waitFor(
-      function() {
-        service.request('unlock', { forcibly: forcibly });
-        waitFor(
-          function() {
-            finish(service.locked);
-          },
-          function() {
-            return !service.locked;
-          }
-        );
-      },
-      function() {
-        return !!service;
-      }
-    );
-  },
-
-  lock: function(forcibly) {
-    let service = window.wrappedJSObject.Service;
-    let setlock = window.wrappedJSObject.SettingsListener.getSettingsLock();
-    let obj = {'screen.timeout': 0};
-    setlock.set(obj);
-    waitFor(
-      function() {
-      service.request('lock', { forcibly: forcibly });
-        waitFor(
-          function() {
-            finish(!service.locked);
-          },
-          function() {
-            return service.locked;
-          }
-        );
-      },
-      function() {
-        return !!service;
-      }
-    );
-  }
-};
--- a/layout/tools/reftest/jar.mn
+++ b/layout/tools/reftest/jar.mn
@@ -1,7 +1,7 @@
 reftest.jar:
 % content reftest %content/
-*  content/reftest-content.js (reftest-content.js)
+  content/reftest-content.js (reftest-content.js)
   content/httpd.jsm (../../../netwerk/test/httpserver/httpd.js)
   content/StructuredLog.jsm (../../../testing/modules/StructuredLog.jsm)
 *  content/reftest.jsm (reftest.jsm)
   content/reftest.xul (reftest.xul)
--- a/layout/tools/reftest/mach_commands.py
+++ b/layout/tools/reftest/mach_commands.py
@@ -2,70 +2,31 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, unicode_literals
 
 import os
 import re
 import sys
-import warnings
-import which
 from argparse import Namespace
 
 from mozbuild.base import (
     MachCommandBase,
     MachCommandConditions as conditions,
     MozbuildObject,
 )
 
 from mach.decorators import (
     CommandProvider,
     Command,
 )
 
 import reftestcommandline
 
-ADB_NOT_FOUND = '''
-The %s command requires the adb binary to be on your path.
-
-If you have a B2G build, this can be found in
-'%s/out/host/<platform>/bin'.
-'''.lstrip()
-
-GAIA_PROFILE_NOT_FOUND = '''
-The reftest command requires a non-debug gaia profile on Mulet.
-Either pass in --profile, or set the GAIA_PROFILE environment variable.
-
-If you do not have a non-debug gaia profile, you can build one:
-    $ git clone https://github.com/mozilla-b2g/gaia
-    $ cd gaia
-    $ make
-
-The profile should be generated in a directory called 'profile'.
-'''.lstrip()
-
-GAIA_PROFILE_IS_DEBUG = '''
-The reftest command requires a non-debug gaia profile on Mulet.
-The specified profile, %s, is a debug profile.
-
-If you do not have a non-debug gaia profile, you can build one:
-    $ git clone https://github.com/mozilla-b2g/gaia
-    $ cd gaia
-    $ make
-
-The profile should be generated in a directory called 'profile'.
-'''.lstrip()
-
-MARIONETTE_DISABLED = '''
-The reftest command requires a marionette enabled build on Mulet.
-
-Add 'ac_add_options --enable-marionette' to your mozconfig file and re-build the application.
-Your currently active mozconfig is %s.
-'''.lstrip()
 
 parser = None
 
 
 class ReftestRunner(MozbuildObject):
     """Easily run reftests.
 
     This currently contains just the basics for running reftests. We may want
@@ -95,90 +56,16 @@ class ReftestRunner(MozbuildObject):
                 "crashtest": os.path.join('layout', 'crashtest'),
             }[args.suite]
             args.tests = [test_subdir]
 
         tests = os.path.join(self.reftest_dir, 'tests')
         if not os.path.isdir(tests):
             os.symlink(self.topsrcdir, tests)
 
-    def run_b2g_test(self, b2g_home=None, xre_path=None, **kwargs):
-        """Runs a b2g reftest.
-
-        filter is a regular expression (in JS syntax, as could be passed to the
-        RegExp constructor) to select which reftests to run from the manifest.
-
-        tests is a list of paths. It can be a relative path from the
-        top source directory, an absolute filename, or a directory containing
-        test files.
-
-        suite is the type of reftest to run. It can be one of ('reftest',
-        'crashtest').
-        """
-        args = Namespace(**kwargs)
-        if args.suite not in ('reftest', 'crashtest'):
-            raise Exception('None or unrecognized reftest suite type.')
-
-        self._setup_objdir(args)
-        import runreftestb2g
-
-        for i, path in enumerate(args.tests):
-            # Non-absolute paths are relative to the packaged directory, which
-            # has an extra tests/ at the start
-            if os.path.exists(os.path.abspath(path)):
-                path = os.path.relpath(path, os.path.join(self.topsrcdir))
-            args.tests[i] = os.path.join('tests', path)
-
-        try:
-            which.which('adb')
-        except which.WhichError:
-            # TODO Find adb automatically if it isn't on the path
-            raise Exception(ADB_NOT_FOUND % ('%s-remote' % args.suite, b2g_home))
-
-        args.b2gPath = b2g_home
-        args.logdir = self.reftest_dir
-        args.httpdPath = os.path.join(self.topsrcdir, 'netwerk', 'test', 'httpserver')
-        args.xrePath = xre_path
-        args.ignoreWindowSize = True
-
-        return runreftestb2g.run_test_harness(parser, args)
-
-    def run_mulet_test(self, **kwargs):
-        """Runs a mulet reftest."""
-        args = Namespace(**kwargs)
-        self._setup_objdir(args)
-
-        import runreftestmulet
-
-        if self.substs.get('ENABLE_MARIONETTE') != '1':
-            print(MARIONETTE_DISABLED % self.mozconfig['path'])
-            return 1
-
-        if not args.profile:
-            gaia_profile = os.environ.get('GAIA_PROFILE')
-            if not gaia_profile:
-                print(GAIA_PROFILE_NOT_FOUND)
-                return 1
-            args.profile = gaia_profile
-
-        if os.path.isfile(os.path.join(args.profile, 'extensions',
-                                       'httpd@gaiamobile.org')):
-            print(GAIA_PROFILE_IS_DEBUG % args.profile)
-            return 1
-
-        args.app = self.get_binary_path()
-        args.mulet = True
-
-        if not args.app.endswith('-bin'):
-            args.app = '%s-bin' % args.app
-        if not os.path.isfile(args.app):
-            args.app = args.app[:-len('-bin')]
-
-        return runreftestmulet.run_test_harness(parser, args)
-
     def run_desktop_test(self, **kwargs):
         """Runs a reftest, in desktop Firefox."""
         import runreftest
 
         args = Namespace(**kwargs)
         if args.suite not in ('reftest', 'crashtest', 'jstestbrowser'):
             raise Exception('None or unrecognized reftest suite type.')
 
@@ -296,18 +183,16 @@ def process_test_objects(kwargs):
 
 
 def get_parser():
     global parser
     here = os.path.abspath(os.path.dirname(__file__))
     build_obj = MozbuildObject.from_environment(cwd=here)
     if conditions.is_android(build_obj):
         parser = reftestcommandline.RemoteArgumentsParser()
-    elif conditions.is_mulet(build_obj):
-        parser = reftestcommandline.B2GArgumentParser()
     else:
         parser = reftestcommandline.DesktopArgumentsParser()
     return parser
 
 
 @CommandProvider
 class MachCommands(MachCommandBase):
     @Command('reftest',
@@ -339,55 +224,9 @@ class MachCommands(MachCommandBase):
 
     def _run_reftest(self, **kwargs):
         process_test_objects(kwargs)
         reftest = self._spawn(ReftestRunner)
         if conditions.is_android(self):
             from mozrunner.devices.android_device import verify_android_device
             verify_android_device(self, install=True, xre=True)
             return reftest.run_android_test(**kwargs)
-        elif conditions.is_mulet(self):
-            return reftest.run_mulet_test(**kwargs)
         return reftest.run_desktop_test(**kwargs)
-
-
-# TODO For now b2g commands will only work with the emulator,
-# they should be modified to work with all devices.
-def is_emulator(cls):
-    """Emulator needs to be configured."""
-    return cls.device_name.startswith('emulator')
-
-
-@CommandProvider
-class B2GCommands(MachCommandBase):
-    def __init__(self, context):
-        MachCommandBase.__init__(self, context)
-
-        for attr in ('b2g_home', 'xre_path', 'device_name'):
-            setattr(self, attr, getattr(context, attr, None))
-
-    @Command('reftest-remote', category='testing',
-             description='Run a remote reftest (b2g layout and graphics correctness, remote device).',
-             conditions=[conditions.is_b2g, is_emulator],
-             parser=get_parser)
-    def run_reftest_remote(self, **kwargs):
-        kwargs["suite"] = "reftest"
-        return self._run_reftest(**kwargs)
-
-    @Command('crashtest-remote', category='testing',
-             description='Run a remote crashtest (Check if b2g crashes on a page, remote device).',
-             conditions=[conditions.is_b2g, is_emulator],
-             parser=get_parser)
-    def run_crashtest_remote(self, test_file, **kwargs):
-        kwargs["suite"] = "crashtest"
-        return self._run_reftest(**kwargs)
-
-    def _run_reftest(self, **kwargs):
-        process_test_objects(kwargs)
-        if self.device_name:
-            if self.device_name.startswith('emulator'):
-                emulator = 'arm'
-                if 'x86' in self.device_name:
-                    emulator = 'x86'
-                kwargs['emulator'] = emulator
-
-        reftest = self._spawn(ReftestRunner)
-        return reftest.run_b2g_test(self.b2g_home, self.xre_path, **kwargs)
--- a/layout/tools/reftest/moz.build
+++ b/layout/tools/reftest/moz.build
@@ -11,28 +11,23 @@ XPI_NAME = 'reftest'
 USE_EXTENSION_MANIFEST = True
 JAR_MANIFESTS += ['jar.mn']
 FINAL_TARGET_PP_FILES += ['install.rdf']
 FINAL_TARGET_FILES += ['bootstrap.js']
 
 GENERATED_FILES += ['automation.py']
 TEST_HARNESS_FILES.reftest += [
     '!automation.py',
-    '/build/mobile/b2gautomation.py',
     '/build/mobile/remoteautomation.py',
     '/build/pgo/server-locations.txt',
     '/testing/mochitest/server.js',
-    'b2g_start_script.js',
-    'gaia_lock_screen.js',
     'mach_test_package_commands.py',
     'output.py',
     'reftest-preferences.js',
     'reftestcommandline.py',
     'remotereftest.py',
     'runreftest.py',
-    'runreftestb2g.py',
-    'runreftestmulet.py',
 ]
 
 TEST_HARNESS_FILES.reftest.chrome += [
     'chrome/binding.xml',
     'chrome/userContent.css',
 ]
--- a/layout/tools/reftest/output.py
+++ b/layout/tools/reftest/output.py
@@ -100,34 +100,29 @@ class OutputHandler(object):
     """Process the output of a process during a test run and translate
     raw data logged from reftest.js to an appropriate structured log action,
     where applicable.
     """
 
     def __init__(self, log, utilityPath, symbolsPath=None):
         self.stack_fixer_function = get_stack_fixer_function(utilityPath, symbolsPath)
         self.log = log
-        # needed for b2gautomation.py
-        self.suite_finished = False
 
     def __call__(self, line):
         # need to return processed messages to appease remoteautomation.py
         if not line.strip():
             return []
 
         try:
             data = json.loads(line)
         except ValueError:
             self.verbatim(line)
             return [line]
 
         if isinstance(data, dict) and 'action' in data:
-            if data['action'] == 'suite_end':
-                self.suite_finished = True
-
             self.log.log_raw(data)
         else:
             self.verbatim(json.dumps(data))
 
         return [data]
 
     def verbatim(self, line):
         if self.stack_fixer_function:
--- a/layout/tools/reftest/reftest-content.js
+++ b/layout/tools/reftest/reftest-content.js
@@ -95,19 +95,17 @@ function PaintWaitFinishedListener(event
     if (gExplicitPendingPaintCount == 0 &&
         gExplicitPendingPaintsCompleteHook) {
         gExplicitPendingPaintsCompleteHook();
     }
 }
 
 function OnInitialLoad()
 {
-#ifndef REFTEST_B2G
     removeEventListener("load", OnInitialLoad, true);
-#endif
 
     gDebug = CC[DEBUG_CONTRACTID].getService(CI.nsIDebug2);
     var env = CC[ENVIRONMENT_CONTRACTID].getService(CI.nsIEnvironment);
     gVerbose = !!env.get("MOZ_REFTEST_VERBOSE");
 
     RegisterMessageListeners();
 
     var initInfo = SendContentReady();
@@ -177,26 +175,21 @@ function setupFullZoom(contentRootElemen
         contentRootElement.getAttribute('reftest-zoom');
 }
 
 function resetZoom() {
     markupDocumentViewer().fullZoom = 1.0;
 }
 
 function doPrintMode(contentRootElement) {
-#if REFTEST_B2G
-    // nsIPrintSettings not available in B2G
-    return false;
-#else
     // use getAttribute because className works differently in HTML and SVG
     return contentRootElement &&
            contentRootElement.hasAttribute('class') &&
            contentRootElement.getAttribute('class').split(/\s+/)
                              .indexOf("reftest-print") != -1;
-#endif
 }
 
 function setupPrintMode() {
    var PSSVC =
        CC[PRINTSETTINGS_CONTRACTID].getService(CI.nsIPrintSettingsService);
    var ps = PSSVC.newPrintSettings;
    ps.paperWidth = 5;
    ps.paperHeight = 3;
@@ -1157,18 +1150,14 @@ function SendUpdateCanvasForEvent(event,
     // logic here.
     if (!gBrowserIsRemote) {
         sendSyncMessage("reftest:UpdateCanvasForInvalidation", { rects: rects });
     } else {
         SynchronizeForSnapshot(SYNC_ALLOW_DISABLE);
         sendAsyncMessage("reftest:UpdateCanvasForInvalidation", { rects: rects });
     }
 }
-#if REFTEST_B2G
-OnInitialLoad();
-#else
 if (content.document.readyState == "complete") {
   // load event has already fired for content, get started
   OnInitialLoad();
 } else {
   addEventListener("load", OnInitialLoad, true);
 }
-#endif
--- a/layout/tools/reftest/reftest.jsm
+++ b/layout/tools/reftest/reftest.jsm
@@ -58,17 +58,16 @@ var gFocusFilterMode = FOCUS_FILTER_ALL_
 var gCompareStyloToGecko = false;
 
 // "<!--CLEAR-->"
 const BLANK_URL_FOR_CLEARING = "data:text/html;charset=UTF-8,%3C%21%2D%2DCLEAR%2D%2D%3E";
 
 var gBrowser;
 // Are we testing web content loaded in a separate process?
 var gBrowserIsRemote;           // bool
-var gB2GisMulet;                // bool
 // Are we using <iframe mozbrowser>?
 var gBrowserIsIframe;           // bool
 var gBrowserMessageManager;
 var gCanvas1, gCanvas2;
 // gCurrentCanvas is non-null between InitCurrentCanvasWithSnapshot and the next
 // RecordResult.
 var gCurrentCanvas = null;
 var gURLs;
@@ -278,22 +277,16 @@ this.OnRefTestLoad = function OnRefTestL
                 getService(Components.interfaces.nsIPrefBranch);
     try {
         gBrowserIsRemote = prefs.getBoolPref("browser.tabs.remote.autostart");
     } catch (e) {
         gBrowserIsRemote = false;
     }
 
     try {
-        gB2GisMulet = prefs.getBoolPref("b2g.is_mulet");
-    } catch (e) {
-        gB2GisMulet = false;
-    }
-
-    try {
       gBrowserIsIframe = prefs.getBoolPref("reftest.browser.iframe.enabled");
     } catch (e) {
       gBrowserIsIframe = false;
     }
 
     try {
       gLogLevel = prefs.getCharPref("reftest.logLevel");
     } catch (e) {
@@ -318,22 +311,17 @@ this.OnRefTestLoad = function OnRefTestL
     gBrowser.setAttribute("type", "content");
     gBrowser.setAttribute("primary", "true");
     gBrowser.setAttribute("remote", gBrowserIsRemote ? "true" : "false");
     // Make sure the browser element is exactly 800x1000, no matter
     // what size our window is
     gBrowser.setAttribute("style", "padding: 0px; margin: 0px; border:none; min-width: 800px; min-height: 1000px; max-width: 800px; max-height: 1000px");
 
     if (Services.appinfo.OS == "Android") {
-      let doc;
-      if (Services.appinfo.widgetToolkit == "gonk") {
-        doc = gContainingWindow.document.getElementsByTagName("html")[0];
-      } else {
-        doc = gContainingWindow.document.getElementById('main-window');
-      }
+      let doc = gContainingWindow.document.getElementById('main-window');
       while (doc.hasChildNodes()) {
         doc.removeChild(doc.firstChild);
       }
       doc.appendChild(gBrowser);
     } else {
       document.getElementById("reftest-window").appendChild(gBrowser);
     }
 
@@ -686,18 +674,17 @@ function BuildConditionSandbox(aURL) {
     sandbox.d3d9 =
       gWindowUtils.layerManagerType == "Direct3D 9";
     sandbox.layersOpenGL =
       gWindowUtils.layerManagerType == "OpenGL";
     sandbox.layersOMTC =
       gWindowUtils.layerManagerRemote == true;
 
     // Shortcuts for widget toolkits.
-    sandbox.B2G = xr.widgetToolkit == "gonk";
-    sandbox.Android = xr.OS == "Android" && !sandbox.B2G;
+    sandbox.Android = xr.OS == "Android";
     sandbox.cocoaWidget = xr.widgetToolkit == "cocoa";
     sandbox.gtkWidget = xr.widgetToolkit == "gtk2"
                         || xr.widgetToolkit == "gtk3";
     sandbox.qtWidget = xr.widgetToolkit == "qt";
     sandbox.winWidget = xr.widgetToolkit == "windows";
 
     // Scrollbars that are semi-transparent. See bug 1169666.
     sandbox.transparentScrollbars = xr.widgetToolkit == "gtk3";
@@ -763,17 +750,16 @@ function BuildConditionSandbox(aURL) {
     sandbox.prefs = CU.cloneInto({
         getBoolPref: function(p) { return prefs.getBoolPref(p); },
         getIntPref:  function(p) { return prefs.getIntPref(p); }
     }, sandbox, { cloneFunctions: true });
 
     // Tests shouldn't care about this except for when they need to
     // crash the content process
     sandbox.browserIsRemote = gBrowserIsRemote;
-    sandbox.Mulet = gB2GisMulet;
 
     try {
         sandbox.asyncPan = gContainingWindow.document.docShell.asyncPanZoomEnabled;
     } catch (e) {
         sandbox.asyncPan = false;
     }
 
     if (!gDumpedConditionSandbox) {
--- a/layout/tools/reftest/reftestcommandline.py
+++ b/layout/tools/reftest/reftestcommandline.py
@@ -355,213 +355,16 @@ class DesktopArgumentsParser(ReftestArgu
                 options.app = bin_dir
 
         if options.symbolsPath and len(urlparse(options.symbolsPath).scheme) < 2:
             options.symbolsPath = reftest.getFullPath(options.symbolsPath)
 
         options.utilityPath = reftest.getFullPath(options.utilityPath)
 
 
-class B2GArgumentParser(ReftestArgumentsParser):
-    def __init__(self, **kwargs):
-        super(B2GArgumentParser, self).__init__(**kwargs)
-
-        self.add_argument("--browser-arg",
-                          action="store",
-                          type=str,
-                          dest="browser_arg",
-                          help="Optional command-line arg to pass to the browser")
-
-        self.add_argument("--b2gpath",
-                          action="store",
-                          type=str,
-                          dest="b2gPath",
-                          help="path to B2G repo or qemu dir")
-
-        self.add_argument("--emulator",
-                          action="store",
-                          type=str,
-                          dest="emulator",
-                          help="Architecture of emulator to use: x86 or arm")
-
-        self.add_argument("--emulator-res",
-                          action="store",
-                          type=str,
-                          dest="emulator_res",
-                          help="Emulator resolution of the format '<width>x<height>'")
-
-        self.add_argument("--no-window",
-                          action="store_true",
-                          dest="noWindow",
-                          default=False,
-                          help="Pass --no-window to the emulator")
-
-        self.add_argument("--adbpath",
-                          action="store",
-                          type=str,
-                          dest="adb_path",
-                          default="adb",
-                          help="path to adb")
-
-        self.add_argument("--deviceIP",
-                          action="store",
-                          type=str,
-                          dest="deviceIP",
-                          help="ip address of remote device to test")
-
-        self.add_argument("--devicePort",
-                          action="store",
-                          type=str,
-                          dest="devicePort",
-                          default="20701",
-                          help="port of remote device to test")
-
-        self.add_argument("--remote-logfile",
-                          action="store",
-                          type=str,
-                          dest="remoteLogFile",
-                          help="Name of log file on the device relative to the device root.  PLEASE ONLY USE A FILENAME.")
-
-        self.add_argument("--remote-webserver",
-                          action="store",
-                          type=str,
-                          dest="remoteWebServer",
-                          help="ip address where the remote web server is hosted at")
-
-        self.add_argument("--http-port",
-                          action="store",
-                          type=str,
-                          dest="httpPort",
-                          help="ip address where the remote web server is hosted at")
-
-        self.add_argument("--ssl-port",
-                          action="store",
-                          type=str,
-                          dest="sslPort",
-                          help="ip address where the remote web server is hosted at")
-
-        self.add_argument("--pidfile",
-                          action="store",
-                          type=str,
-                          dest="pidFile",
-                          default="",
-                          help="name of the pidfile to generate")
-
-        self.add_argument("--gecko-path",
-                          action="store",
-                          type=str,
-                          dest="geckoPath",
-                          help="the path to a gecko distribution that should "
-                          "be installed on the emulator prior to test")
-
-        self.add_argument("--logdir",
-                          action="store",
-                          type=str,
-                          dest="logdir",
-                          help="directory to store log files")
-
-        self.add_argument('--busybox',
-                          action='store',
-                          type=str,
-                          dest='busybox',
-                          help="Path to busybox binary to install on device")
-
-        self.add_argument("--httpd-path",
-                          action="store",
-                          type=str,
-                          dest="httpdPath",
-                          help="path to the httpd.js file")
-
-        self.add_argument("--profile",
-                          action="store",
-                          type=str,
-                          dest="profile",
-                          help="for mulet testing, the path to the "
-                          "gaia profile to use")
-
-        self.add_argument("--mulet",
-                          action="store_true",
-                          dest="mulet",
-                          default=False,
-                          help="Run the tests on a B2G desktop build")
-
-        self.set_defaults(remoteTestRoot=None,
-                          logFile="reftest.log",
-                          autorun=True,
-                          closeWhenDone=True,
-                          testPath="")
-
-    def validate_remote(self, options, automation):
-        if not options.app:
-            options.app = automation.DEFAULT_APP
-
-        if not options.remoteTestRoot:
-            options.remoteTestRoot = automation._devicemanager.deviceRoot + \
-                "/reftest"
-
-        options.remoteProfile = options.remoteTestRoot + "/profile"
-
-        productRoot = options.remoteTestRoot + "/" + automation._product
-        if options.utilityPath is None:
-            options.utilityPath = productRoot + "/bin"
-
-        if not options.httpPort:
-            options.httpPort = automation.DEFAULT_HTTP_PORT
-
-        if not options.sslPort:
-            options.sslPort = automation.DEFAULT_SSL_PORT
-
-        if options.remoteWebServer is None:
-            options.remoteWebServer = self.get_ip()
-
-        options.webServer = options.remoteWebServer
-
-        if options.geckoPath and not options.emulator:
-            self.error(
-                "You must specify --emulator if you specify --gecko-path")
-
-        if options.logdir and not options.emulator:
-            self.error("You must specify --emulator if you specify --logdir")
-
-        if options.remoteLogFile is None:
-            options.remoteLogFile = "reftest.log"
-
-        options.localLogName = options.remoteLogFile
-        options.remoteLogFile = options.remoteTestRoot + \
-            '/' + options.remoteLogFile
-
-        # Ensure that the options.logfile (which the base class uses) is set to
-        # the remote setting when running remote. Also, if the user set the
-        # log file name there, use that instead of reusing the remotelogfile as
-        # above.
-        if (options.logFile):
-            # If the user specified a local logfile name use that
-            options.localLogName = options.logFile
-        options.logFile = options.remoteLogFile
-
-        # Only reset the xrePath if it wasn't provided
-        if options.xrePath is None:
-            options.xrePath = options.utilityPath
-        options.xrePath = os.path.abspath(options.xrePath)
-
-        if options.pidFile != "":
-            f = open(options.pidFile, 'w')
-            f.write("%s" % os.getpid())
-            f.close()
-
-        # httpd-path is specified by standard makefile targets and may be specified
-        # on the command line to select a particular version of httpd.js. If not
-        # specified, try to select the one from from the xre bundle, as
-        # required in bug 882932.
-        if not options.httpdPath:
-            options.httpdPath = os.path.join(options.xrePath, "components")
-
-        return options
-
-
 class RemoteArgumentsParser(ReftestArgumentsParser):
     def __init__(self, **kwargs):
         super(RemoteArgumentsParser, self).__init__()
 
         # app, xrePath and utilityPath variables are set in main function
         self.set_defaults(logFile="reftest.log",
                           app="",
                           xrePath="",
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -599,21 +599,18 @@ class RefTest(object):
         }
 
         if interactive:
             # If an interactive debugger is attached,
             # don't use timeouts, and don't capture ctrl-c.
             timeout = None
             signal.signal(signal.SIGINT, lambda sigid, frame: None)
 
-        if mozinfo.info.get('appname') == 'b2g' and mozinfo.info.get('toolkit') != 'gonk':
-            runner_cls = mozrunner.Runner
-        else:
-            runner_cls = mozrunner.runners.get(mozinfo.info.get('appname', 'firefox'),
-                                               mozrunner.Runner)
+        runner_cls = mozrunner.runners.get(mozinfo.info.get('appname', 'firefox'),
+                                           mozrunner.Runner)
         runner = runner_cls(profile=profile,
                             binary=binary,
                             process_class=mozprocess.ProcessHandlerMixin,
                             cmdargs=cmdargs,
                             env=env,
                             process_args=kp_kwargs)
         runner.start(debug_args=debug_args,
                      interactive=interactive,
deleted file mode 100644
--- a/layout/tools/reftest/runreftestb2g.py
+++ /dev/null
@@ -1,425 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-import ConfigParser
-import os
-import sys
-import tempfile
-import traceback
-
-# We need to know our current directory so that we can serve our test files from it.
-here = os.path.abspath(os.path.dirname(__file__))
-if here not in sys.path:
-    sys.path.insert(0, here)
-
-from automation import Automation
-from b2gautomation import B2GRemoteAutomation
-from runreftestmulet import run_test_harness as run_mulet_reftests
-from output import OutputHandler
-from remotereftest import RemoteReftestResolver, ReftestServer
-from runreftest import RefTest
-import reftestcommandline
-
-from marionette_harness import Marionette
-from mozdevice import DeviceManagerADB, DMError
-
-
-class ProfileConfigParser(ConfigParser.RawConfigParser):
-    """Subclass of RawConfigParser that outputs .ini files in the exact
-       format expected for profiles.ini, which is slightly different
-       than the default format.
-    """
-
-    def optionxform(self, optionstr):
-        return optionstr
-
-    def write(self, fp):
-        if self._defaults:
-            fp.write("[%s]\n" % ConfigParser.DEFAULTSECT)
-            for (key, value) in self._defaults.items():
-                fp.write("%s=%s\n" % (key, str(value).replace('\n', '\n\t')))
-            fp.write("\n")
-        for section in self._sections:
-            fp.write("[%s]\n" % section)
-            for (key, value) in self._sections[section].items():
-                if key == "__name__":
-                    continue
-                if (value is not None) or (self._optcre == self.OPTCRE):
-                    key = "=".join((key, str(value).replace('\n', '\n\t')))
-                fp.write("%s\n" % (key))
-            fp.write("\n")
-
-class B2GRemoteReftest(RefTest):
-
-    _devicemanager = None
-    use_marionette = False
-    localProfile = None
-    remoteApp = ''
-    profile = None
-    resolver_cls = RemoteReftestResolver
-
-    def __init__(self, automation, devicemanager, options, scriptDir):
-        RefTest.__init__(self)
-        self.automation = automation
-        self._devicemanager = devicemanager
-        self.runSSLTunnel = False
-        self.remoteTestRoot = options.remoteTestRoot
-        self.remoteProfile = options.remoteProfile
-        self.automation.setRemoteProfile(self.remoteProfile)
-        self.localLogName = options.localLogName
-        self.remoteLogFile = options.remoteLogFile
-        self.bundlesDir = '/system/b2g/distribution/bundles'
-        self.remoteMozillaPath = '/data/b2g/mozilla'
-        self.remoteProfilesIniPath = os.path.join(self.remoteMozillaPath, 'profiles.ini')
-        self.originalProfilesIni = None
-        self.scriptDir = scriptDir
-        self.SERVER_STARTUP_TIMEOUT = 90
-        if self.automation.IS_DEBUG_BUILD:
-            self.SERVER_STARTUP_TIMEOUT = 180
-
-    def cleanup(self, profileDir):
-        # Pull results back from device
-        if (self.remoteLogFile):
-            try:
-                self._devicemanager.getFile(self.remoteLogFile, self.localLogName)
-            except:
-                print "ERROR: We were not able to retrieve the info from %s" % self.remoteLogFile
-                sys.exit(5)
-
-        # Delete any bundled extensions
-        if profileDir:
-            extensionDir = os.path.join(profileDir, 'extensions', 'staged')
-            for filename in os.listdir(extensionDir):
-                try:
-                    self._devicemanager._checkCmd(['shell', 'rm', '-rf',
-                                                     os.path.join(self.bundlesDir, filename)])
-                except DMError:
-                    pass
-
-        # Restore the original profiles.ini.
-        if self.originalProfilesIni:
-            try:
-                if not self.automation._is_emulator:
-                    self.restoreProfilesIni()
-                os.remove(self.originalProfilesIni)
-            except:
-                pass
-
-        if not self.automation._is_emulator:
-            self._devicemanager.removeFile(self.remoteLogFile)
-            self._devicemanager.removeDir(self.remoteProfile)
-            self._devicemanager.removeDir(self.remoteTestRoot)
-
-            # We've restored the original profile, so reboot the device so that
-            # it gets picked up.
-            self.automation.rebootDevice()
-
-        RefTest.cleanup(self, profileDir)
-        if getattr(self, 'pidFile', '') != '':
-            try:
-                os.remove(self.pidFile)
-                os.remove(self.pidFile + ".xpcshell.pid")
-            except:
-                print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % self.pidFile
-
-    def findPath(self, paths, filename = None):
-        for path in paths:
-            p = path
-            if filename:
-                p = os.path.join(p, filename)
-            if os.path.exists(self.getFullPath(p)):
-                return path
-        return None
-
-    def startWebServer(self, options):
-        """ Create the webserver on the host and start it up """
-        remoteXrePath = options.xrePath
-        remoteProfilePath = self.remoteProfile
-        remoteUtilityPath = options.utilityPath
-        localAutomation = Automation()
-        localAutomation.IS_WIN32 = False
-        localAutomation.IS_LINUX = False
-        localAutomation.IS_MAC = False
-        localAutomation.UNIXISH = False
-        hostos = sys.platform
-        if hostos in ['mac', 'darwin']:
-            localAutomation.IS_MAC = True
-        elif hostos in ['linux', 'linux2']:
-            localAutomation.IS_LINUX = True
-            localAutomation.UNIXISH = True
-        elif hostos in ['win32', 'win64']:
-            localAutomation.BIN_SUFFIX = ".exe"
-            localAutomation.IS_WIN32 = True
-
-        paths = [options.xrePath,
-                 localAutomation.DIST_BIN,
-                 self.automation._product,
-                 os.path.join('..', self.automation._product)]
-        options.xrePath = self.findPath(paths)
-        if options.xrePath == None:
-            print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name)
-            sys.exit(1)
-        paths.append("bin")
-        paths.append(os.path.join("..", "bin"))
-
-        xpcshell = "xpcshell"
-        if (os.name == "nt"):
-            xpcshell += ".exe"
-
-        options.utilityPath = self.findPath(paths, xpcshell)
-        if options.utilityPath == None:
-            print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name)
-            sys.exit(1)
-
-        xpcshell = os.path.join(options.utilityPath, xpcshell)
-        if self.automation.elf_arm(xpcshell):
-            raise Exception('xpcshell at %s is an ARM binary; please use '
-                            'the --utility-path argument to specify the path '
-                            'to a desktop version.' % xpcshell)
-
-        options.serverProfilePath = tempfile.mkdtemp()
-        self.server = ReftestServer(localAutomation, options, self.scriptDir)
-        retVal = self.server.start()
-        if retVal:
-            return retVal
-
-        if (options.pidFile != ""):
-            f = open(options.pidFile + ".xpcshell.pid", 'w')
-            f.write("%s" % self.server._process.pid)
-            f.close()
-
-        retVal = self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT)
-        if retVal:
-            return retVal
-
-        options.xrePath = remoteXrePath
-        options.utilityPath = remoteUtilityPath
-        options.profilePath = remoteProfilePath
-        return 0
-
-    def stopWebServer(self, options):
-        if hasattr(self, 'server'):
-            self.server.stop()
-
-    def restoreProfilesIni(self):
-        # restore profiles.ini on the device to its previous state
-        if not self.originalProfilesIni or not os.access(self.originalProfilesIni, os.F_OK):
-            raise DMError('Unable to install original profiles.ini; file not found: %s',
-                          self.originalProfilesIni)
-
-        self._devicemanager.pushFile(self.originalProfilesIni, self.remoteProfilesIniPath)
-
-    def updateProfilesIni(self, profilePath):
-        # update profiles.ini on the device to point to the test profile
-        self.originalProfilesIni = tempfile.mktemp()
-        self._devicemanager.getFile(self.remoteProfilesIniPath, self.originalProfilesIni)
-
-        config = ProfileConfigParser()
-        config.read(self.originalProfilesIni)
-        for section in config.sections():
-            if 'Profile' in section:
-                config.set(section, 'IsRelative', 0)
-                config.set(section, 'Path', profilePath)
-
-        newProfilesIni = tempfile.mktemp()
-        with open(newProfilesIni, 'wb') as configfile:
-            config.write(configfile)
-
-        self._devicemanager.pushFile(newProfilesIni, self.remoteProfilesIniPath)
-        try:
-            os.remove(newProfilesIni)
-        except:
-            pass
-
-
-    def createReftestProfile(self, options, manifests):
-        profile = RefTest.createReftestProfile(self, options, manifests,
-                                               server=options.remoteWebServer)
-        profileDir = profile.profile
-
-        prefs = {}
-
-        # Turn off the locale picker screen
-        prefs["browser.firstrun.show.localepicker"] = False
-        prefs["b2g.system_startup_url"] = "app://test-container.gaiamobile.org/index.html"
-        prefs["b2g.system_manifest_url"] = "app://test-container.gaiamobile.org/manifest.webapp"
-        prefs["dom.ipc.tabs.disabled"] = False
-        prefs["dom.mozBrowserFramesEnabled"] = True
-        prefs["font.size.inflation.emPerLine"] = 0
-        prefs["font.size.inflation.minTwips"] = 0
-        prefs["network.dns.localDomains"] = "app://test-container.gaiamobile.org"
-        prefs["reftest.browser.iframe.enabled"] = False
-        prefs["reftest.remote"] = True
-
-        # Make sure we disable system updates
-        prefs["app.update.enabled"] = False
-        prefs["app.update.url"] = ""
-        # Disable webapp updates
-        prefs["webapps.update.enabled"] = False
-        # Disable tiles also
-        prefs["browser.newtabpage.directory.source"] = ""
-        prefs["browser.newtabpage.directory.ping"] = ""
-
-        # Set the extra prefs.
-        profile.set_preferences(prefs)
-
-        # Copy the profile to the device.
-        self._devicemanager.removeDir(self.remoteProfile)
-        try:
-            self._devicemanager.pushDir(profileDir, self.remoteProfile)
-        except DMError:
-            print "Automation Error: Unable to copy profile to device."
-            raise
-
-        # Copy the extensions to the B2G bundles dir.
-        extensionDir = os.path.join(profileDir, 'extensions', 'staged')
-        # need to write to read-only dir
-        self._devicemanager._checkCmd(['remount'])
-        for filename in os.listdir(extensionDir):
-            self._devicemanager._checkCmd(['shell', 'rm', '-rf',
-                                             os.path.join(self.bundlesDir, filename)])
-        try:
-            self._devicemanager.pushDir(extensionDir, self.bundlesDir)
-        except DMError:
-            print "Automation Error: Unable to copy extensions to device."
-            raise
-
-        self.updateProfilesIni(self.remoteProfile)
-
-        options.profilePath = self.remoteProfile
-        return profile
-
-    def copyExtraFilesToProfile(self, options, profile):
-        profileDir = profile.profile
-        RefTest.copyExtraFilesToProfile(self, options, profile)
-        try:
-            self._devicemanager.pushDir(profileDir, options.remoteProfile)
-        except DMError:
-            print "Automation Error: Failed to copy extra files to device"
-            raise
-
-    def environment(self, **kwargs):
-     return self.automation.environment(**kwargs)
-
-    def runApp(self, profile, binary, cmdargs, env,
-               timeout=None, debuggerInfo=None,
-               symbolsPath=None, options=None,
-               valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None):
-
-        outputHandler = OutputHandler(self.log, options.utilityPath, options.symbolsPath)
-        status = self.automation.runApp(None, env,
-                                        binary,
-                                        profile.profile,
-                                        cmdargs,
-                                        utilityPath=options.utilityPath,
-                                        xrePath=options.xrePath,
-                                        debuggerInfo=debuggerInfo,
-                                        symbolsPath=symbolsPath,
-                                        timeout=timeout,
-                                        outputHandler=outputHandler)
-        return status
-
-
-def run_test_harness(parser, options):
-    if options.mulet:
-        return run_mulet_reftests(parser, options)
-
-    auto = B2GRemoteAutomation(None, "fennec")
-
-    # create our Marionette instance
-    kwargs = {}
-    if options.emulator:
-        kwargs['emulator'] = options.emulator
-        auto.setEmulator(True)
-        if options.noWindow:
-            kwargs['noWindow'] = True
-        if options.geckoPath:
-            kwargs['gecko_path'] = options.geckoPath
-        if options.logdir:
-            kwargs['logdir'] = options.logdir
-        if options.busybox:
-            kwargs['busybox'] = options.busybox
-        if options.symbolsPath:
-            kwargs['symbols_path'] = options.symbolsPath
-    if options.emulator_res:
-        kwargs['emulator_res'] = options.emulator_res
-    if options.b2gPath:
-        kwargs['homedir'] = options.b2gPath
-    if options.marionette:
-        host,port = options.marionette.split(':')
-        kwargs['host'] = host
-        kwargs['port'] = int(port)
-    if options.adb_path:
-        kwargs['adb_path'] = options.adb_path
-    marionette = Marionette(**kwargs)
-    auto.marionette = marionette
-
-    if options.emulator:
-        dm = marionette.emulator.dm
-    else:
-        # create the DeviceManager
-        kwargs = {'adbPath': options.adb_path,
-                  'deviceRoot': options.remoteTestRoot}
-        if options.deviceIP:
-            kwargs.update({'host': options.deviceIP,
-                           'port': options.devicePort})
-        dm = DeviceManagerADB(**kwargs)
-    auto.setDeviceManager(dm)
-
-    parser.validate_remote(options, auto)
-
-    # TODO fix exception
-    if not options.ignoreWindowSize:
-        parts = dm.getInfo('screen')['screen'][0].split()
-        width = int(parts[0].split(':')[1])
-        height = int(parts[1].split(':')[1])
-        if (width < 1366 or height < 1050):
-            print "ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % (width, height)
-            return 1
-
-    auto.setProduct("b2g")
-    auto.test_script = os.path.join(here, 'b2g_start_script.js')
-    auto.test_script_args = [options.remoteWebServer, options.httpPort]
-
-    reftest = B2GRemoteReftest(auto, dm, options, here)
-    parser.validate(options, reftest)
-
-    logParent = os.path.dirname(options.remoteLogFile)
-    dm.mkDir(logParent);
-    auto.setRemoteLog(options.remoteLogFile)
-    auto.setServerInfo(options.webServer, options.httpPort, options.sslPort)
-
-    # Hack in a symbolic link for jsreftest
-    os.system("ln -s %s %s" % (os.path.join('..', 'jsreftest'), os.path.join(here, 'jsreftest')))
-
-
-    # Start the webserver
-    retVal = 1
-    try:
-        retVal = reftest.startWebServer(options)
-        if retVal:
-            return retVal
-        procName = options.app.split('/')[-1]
-        if (dm.processExist(procName)):
-            dm.killProcess(procName)
-
-        retVal = reftest.runTests(options.tests, options)
-    except:
-        print "Automation Error: Exception caught while running tests"
-        traceback.print_exc()
-        reftest.stopWebServer(options)
-        try:
-            reftest.cleanup(None)
-        except:
-            pass
-        return 1
-
-    reftest.stopWebServer(options)
-    return retVal
-
-
-if __name__ == "__main__":
-    parser = reftestcommandline.B2GArgumentParser()
-    options = parser.parse_args()
-    sys.exit(run_test_harness(parser, options))
deleted file mode 100644
--- a/layout/tools/reftest/runreftestmulet.py
+++ /dev/null
@@ -1,203 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-from __future__ import print_function, unicode_literals
-
-import os
-import signal
-import sys
-
-here = os.path.abspath(os.path.dirname(__file__))
-
-from marionette_driver import expected
-from marionette_driver.by import By
-from marionette_driver.marionette import Marionette
-from marionette_driver.wait import Wait
-
-from mozprocess import ProcessHandler
-from mozrunner import FirefoxRunner
-import mozinfo
-import mozlog
-
-from runreftest import RefTest
-from output import OutputHandler
-import reftestcommandline
-
-
-class MuletReftest(RefTest):
-    build_type = "mulet"
-    marionette = None
-
-    def __init__(self, marionette_args):
-        RefTest.__init__(self)
-        self.last_test = os.path.basename(__file__)
-        self.marionette_args = marionette_args
-        self.profile = None
-        self.runner = None
-        self.test_script = os.path.join(here, 'b2g_start_script.js')
-        self.timeout = None
-
-    def run_marionette_script(self):
-        self.marionette = Marionette(**self.marionette_args)
-        assert(self.marionette.wait_for_port())
-        self.marionette.start_session()
-        if self.build_type == "mulet":
-            self._wait_for_homescreen(timeout=300)
-            self._unlockScreen()
-        self.marionette.set_context(self.marionette.CONTEXT_CHROME)
-
-        if os.path.isfile(self.test_script):
-            f = open(self.test_script, 'r')
-            self.test_script = f.read()
-            f.close()
-        self.marionette.execute_script(self.test_script)
-
-    def run_tests(self, tests, options):
-        manifests = self.resolver.resolveManifests(options, tests)
-
-        self.profile = self.create_profile(options, manifests,
-                                           profile_to_clone=options.profile)
-        env = self.buildBrowserEnv(options, self.profile.profile)
-
-        self._populate_logger(options)
-        outputHandler = OutputHandler(self.log, options.utilityPath, symbolsPath=options.symbolsPath)
-
-        kp_kwargs = { 'processOutputLine': [outputHandler],
-                      'onTimeout': [self._on_timeout],
-                      'kill_on_timeout': False }
-
-        if not options.debugger:
-            if not options.timeout:
-                if mozinfo.info['debug']:
-                    options.timeout = 420
-                else:
-                    options.timeout = 300
-            self.timeout = options.timeout + 30.0
-
-        self.log.info("%s | Running tests: start." % os.path.basename(__file__))
-        cmd, args = self.build_command_line(options.app,
-                            ignore_window_size=options.ignoreWindowSize,
-                            browser_arg=options.browser_arg)
-        self.runner = FirefoxRunner(profile=self.profile,
-                                    binary=cmd,
-                                    cmdargs=args,
-                                    env=env,
-                                    process_class=ProcessHandler,
-                                    process_args=kp_kwargs,
-                                    symbols_path=options.symbolsPath)
-
-        status = 0
-        try:
-            self.runner.start(outputTimeout=self.timeout)
-            self.log.info("%s | Application pid: %d" % (
-                     os.path.basename(__file__),
-                     self.runner.process_handler.pid))
-
-            # kick starts the reftest harness
-            self.run_marionette_script()
-            status = self.runner.wait()
-        finally:
-            self.runner.check_for_crashes(test_name=self.last_test)
-            self.runner.cleanup()
-
-        if status > 0:
-            self.log.testFail("%s | application terminated with exit code %s" % (
-                         self.last_test, status))
-        elif status < 0:
-            self.log.info("%s | application killed with signal %s" % (
-                         self.last_test, -status))
-
-        self.log.info("%s | Running tests: end." % os.path.basename(__file__))
-        return status
-
-    def create_profile(self, options, manifests, profile_to_clone=None):
-        profile = RefTest.createReftestProfile(self, options, manifests,
-                                               profile_to_clone=profile_to_clone)
-
-        prefs = {}
-        # Turn off the locale picker screen
-        prefs["browser.firstrun.show.localepicker"] = False
-        if not self.build_type == "mulet":
-            # FIXME: With Mulet we can't set this values since Gaia won't launch
-            prefs["b2g.system_startup_url"] = \
-                    "app://test-container.gaiamobile.org/index.html"
-            prefs["b2g.system_manifest_url"] = \
-                    "app://test-container.gaiamobile.org/manifest.webapp"
-        # Make sure we disable system updates
-        prefs["app.update.enabled"] = False
-        prefs["app.update.url"] = ""
-        # Disable webapp updates
-        prefs["webapps.update.enabled"] = False
-        # Disable tiles also
-        prefs["browser.newtabpage.directory.source"] = ""
-        prefs["browser.newtabpage.directory.ping"] = ""
-        prefs["dom.ipc.tabs.disabled"] = False
-        prefs["dom.mozBrowserFramesEnabled"] = True
-        prefs["font.size.inflation.emPerLine"] = 0
-        prefs["font.size.inflation.minTwips"] = 0
-        prefs["network.dns.localDomains"] = "app://test-container.gaiamobile.org"
-        prefs["reftest.browser.iframe.enabled"] = False
-        prefs["reftest.remote"] = False
-
-        # Set the extra prefs.
-        profile.set_preferences(prefs)
-        return profile
-
-    def build_command_line(self, app, ignore_window_size=False,
-                           browser_arg=None):
-        cmd = os.path.abspath(app)
-        args = ['-marionette']
-
-        if browser_arg:
-            args += [browser_arg]
-
-        if not ignore_window_size:
-            args.extend(['--screen', '800x1000'])
-
-        if self.build_type == "mulet":
-            args += ['-chrome', 'chrome://b2g/content/shell.html']
-        return cmd, args
-
-    def _on_timeout(self):
-        msg = "%s | application timed out after %s seconds with no output"
-        self.log.testFail(msg % (self.last_test, self.timeout))
-        self.log.error("Force-terminating active process(es).");
-
-        # kill process to get a stack
-        self.runner.stop(sig=signal.SIGABRT)
-
-    def _unlockScreen(self):
-        self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
-        self.marionette.import_script(os.path.abspath(
-            os.path.join(__file__, os.path.pardir, "gaia_lock_screen.js")))
-        self.marionette.switch_to_frame()
-        self.marionette.execute_async_script('GaiaLockScreen.unlock()')
-
-    def _wait_for_homescreen(self, timeout):
-        self.log.info("Waiting for home screen to load")
-        Wait(self.marionette, timeout).until(expected.element_present(
-            By.CSS_SELECTOR, '#homescreen[loading-state=false]'))
-
-
-def run_test_harness(parser, options):
-    marionette_args = {}
-    if options.marionette:
-        host, port = options.marionette.split(':')
-        marionette_args['host'] = host
-        marionette_args['port'] = int(port)
-
-    reftest = MuletReftest(marionette_args)
-    parser.validate(options, reftest)
-
-    # add a -bin suffix if b2g-bin exists, but just b2g was specified
-    if options.app[-4:] != '-bin':
-        if os.path.isfile("%s-bin" % options.app):
-            options.app = "%s-bin" % options.app
-
-    if options.xrePath is None:
-        options.xrePath = os.path.dirname(options.app)
-
-    if options.mulet and not options.profile:
-        raise Exception("must specify --profile when specifying --mulet")
-
-    return reftest.run_tests(options.tests, options)
--- a/media/libmkv/WebMElement.c
+++ b/media/libmkv/WebMElement.c
@@ -52,18 +52,17 @@ static UInt64 generateTrackID(unsigned i
   r = r << 32;
   r +=  rand();
 //  UInt64 rval = t ^ r;
   return t ^ r;
 }
 
 void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
                      const char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
-                     unsigned int displayWidth, unsigned int displayHeight,
-                     double frameRate) {
+                     unsigned int displayWidth, unsigned int displayHeight) {
   EbmlLoc start;
   UInt64 trackID;
   Ebml_StartSubElement(glob, &start, TrackEntry);
   Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
   trackID = generateTrackID(trackNumber);
   Ebml_SerializeUnsigned(glob, TrackUID, trackID);
   Ebml_SerializeString(glob, CodecName, "VP8");  // TODO shouldn't be fixed
 
@@ -75,17 +74,16 @@ void writeVideoTrack(EbmlGlobal *glob, u
     Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth);
     Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight);
     if (pixelWidth != displayWidth) {
       Ebml_SerializeUnsigned(glob, DisplayWidth, displayWidth);
     }
     if (pixelHeight != displayHeight) {
       Ebml_SerializeUnsigned(glob, DisplayHeight, displayHeight);
     }
-    Ebml_SerializeFloat(glob, FrameRate, frameRate);
     Ebml_EndSubElement(glob, &videoStart); // Video
   }
   Ebml_EndSubElement(glob, &start); // Track Entry
 }
 void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
                      const char *codecId, double samplingFrequency, unsigned int channels,
                      uint64_t codecDelay, uint64_t seekPreRoll,
                      unsigned char *private, unsigned long privateSize) {
--- a/media/libmkv/WebMElement.h
+++ b/media/libmkv/WebMElement.h
@@ -16,18 +16,17 @@ extern "C" {
 #include "EbmlWriter.h"
 
 // these are helper functions
 void writeHeader(EbmlGlobal *ebml);
 void writeSegmentInformation(EbmlGlobal *ebml, EbmlLoc *startInfo, unsigned long timeCodeScale, double duration);
 // this function is a helper only, it assumes a lot of defaults
 void writeVideoTrack(EbmlGlobal *ebml, unsigned int trackNumber, int flagLacing,
                      const char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
-                     unsigned int displayWidth, unsigned int displayHeight,
-                     double frameRate);
+                     unsigned int displayWidth, unsigned int displayHeight);
 void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
                      const char *codecId, double samplingFrequency, unsigned int channels,
                      uint64_t codecDelay, uint64_t seekPreRoll,
                      unsigned char *private_, unsigned long privateSize);
 
 void writeSimpleBlock(EbmlGlobal *ebml, unsigned char trackNumber, short timeCode,
                       int isKeyframe, unsigned char lacingFlag, int discardable,
                       unsigned char *data, unsigned long dataLength);
--- a/mobile/android/base/aidl/org/mozilla/gecko/media/ICodec.aidl
+++ b/mobile/android/base/aidl/org/mozilla/gecko/media/ICodec.aidl
@@ -10,18 +10,18 @@ import android.view.Surface;
 import org.mozilla.gecko.media.FormatParam;
 import org.mozilla.gecko.media.ICodecCallbacks;
 import org.mozilla.gecko.media.Sample;
 
 interface ICodec {
     void setCallbacks(in ICodecCallbacks callbacks);
     boolean configure(in FormatParam format, inout Surface surface, int flags, in String drmStubId);
     boolean isAdaptivePlaybackSupported();
-    oneway void start();
-    oneway void stop();
-    oneway void flush();
-    oneway void release();
+    void start();
+    void stop();
+    void flush();
+    void release();
 
     Sample dequeueInput(int size);
     oneway void queueInput(in Sample sample);
 
     oneway void releaseOutput(in Sample sample, in boolean render);
 }
--- a/mobile/android/base/java/org/mozilla/gecko/media/AsyncCodec.java
+++ b/mobile/android/base/java/org/mozilla/gecko/media/AsyncCodec.java
@@ -24,15 +24,17 @@ public interface AsyncCodec {
     }
 
     public abstract void setCallbacks(Callbacks callbacks, Handler handler);
     public abstract void configure(MediaFormat format, Surface surface, MediaCrypto crypto, int flags);
     public abstract boolean isAdaptivePlaybackSupported(String mimeType);
     public abstract void start();
     public abstract void stop();
     public abstract void flush();
+    // Must be called after flush().
+    public abstract void resumeReceivingInputs();
     public abstract void release();
     public abstract ByteBuffer getInputBuffer(int index);
     public abstract ByteBuffer getOutputBuffer(int index);
     public abstract void queueInputBuffer(int index, int offset, int size, long presentationTimeUs, int flags);
     public abstract void queueSecureInputBuffer(int index, int offset, CryptoInfo info, long presentationTimeUs, int flags);
     public abstract void releaseOutputBuffer(int index, boolean render);
 }
--- a/mobile/android/base/java/org/mozilla/gecko/media/Codec.java
+++ b/mobile/android/base/java/org/mozilla/gecko/media/Codec.java
@@ -27,31 +27,21 @@ import java.util.concurrent.ConcurrentLi
 
     public enum Error {
         DECODE, FATAL
     }
 
     private final class Callbacks implements AsyncCodec.Callbacks {
         @Override
         public void onInputBufferAvailable(AsyncCodec codec, int index) {
-            if (mFlushing) {
-                // Flush invalidates all buffers.
-                return;
-            }
-
             mInputProcessor.onBuffer(index);
         }
 
         @Override
         public void onOutputBufferAvailable(AsyncCodec codec, int index, MediaCodec.BufferInfo info) {
-            if (mFlushing) {
-                // Flush invalidates all buffers.
-                return;
-            }
-
             mOutputProcessor.onBuffer(index, info);
         }
 
         @Override
         public void onError(AsyncCodec codec, int error) {
             reportError(Error.FATAL, new Exception("codec error:" + error));
         }
 
@@ -61,16 +51,17 @@ import java.util.concurrent.ConcurrentLi
         }
     }
 
     private final class InputProcessor {
         private boolean mHasInputCapacitySet;
         private Queue<Integer> mAvailableInputBuffers = new LinkedList<>();
         private Queue<Sample> mDequeuedSamples = new LinkedList<>();
         private Queue<Sample> mInputSamples = new LinkedList<>();
+        private boolean mStopped;
 
         private synchronized Sample onAllocate(int size) {
             Sample sample = mSamplePool.obtainInput(size);
             mDequeuedSamples.add(sample);
             return sample;
         }
 
         private synchronized void onSample(Sample sample) {
@@ -90,16 +81,20 @@ import java.util.concurrent.ConcurrentLi
             if (mInputSamples.offer(sample)) {
                 feedSampleToBuffer();
             } else {
                 reportError(Error.FATAL, new Exception("FAIL: input sample queue is full"));
             }
         }
 
         private synchronized void onBuffer(int index) {
+            if (mStopped) {
+                return;
+            }
+
             if (!mHasInputCapacitySet) {
                 int capacity = mCodec.getInputBuffer(index).capacity();
                 if (capacity > 0) {
                     mSamplePool.setInputBufferSize(capacity);
                     mHasInputCapacitySet = true;
                 }
             }
 
@@ -138,36 +133,57 @@ import java.util.concurrent.ConcurrentLi
                 } else {
                     mCodec.queueInputBuffer(index, 0, len, pts, flags);
                 }
             }
         }
 
         private synchronized void reset() {
             for (Sample s : mInputSamples) {
-                mSamplePool.recycleInput(s);
+                if (!s.isEOS()) {
+                    mSamplePool.recycleInput(s);
+                }
             }
             mInputSamples.clear();
 
             for (Sample s : mDequeuedSamples) {
                 mSamplePool.recycleInput(s);
             }
             mDequeuedSamples.clear();
 
             mAvailableInputBuffers.clear();
         }
+
+        private synchronized void start() {
+            if (!mStopped) {
+                return;
+            }
+            mStopped = false;
+        }
+
+        private synchronized void stop() {
+            if (mStopped) {
+                return;
+            }
+            mStopped = true;
+            reset();
+        }
     }
 
     private class OutputProcessor {
         private boolean mHasOutputCapacitySet;
         private Queue<Integer> mSentIndices = new LinkedList<>();
         private Queue<Sample> mSentOutputs = new LinkedList<>();
-
+        private boolean mStopped;
 
         private synchronized void onBuffer(int index, MediaCodec.BufferInfo info) {
+            if (mStopped) {
+                return;
+            }
+
             ByteBuffer output = mCodec.getOutputBuffer(index);
             if (!mHasOutputCapacitySet) {
                 int capacity = output.capacity();
                 if (capacity > 0) {
                     mSamplePool.setOutputBufferSize(capacity);
                     mHasOutputCapacitySet = true;
                 }
             }
@@ -193,17 +209,17 @@ import java.util.concurrent.ConcurrentLi
             boolean eos = (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
             if (DEBUG && eos) {
                 Log.d(LOGTAG, "output EOS");
             }
        }
 
         private void outputDummy(MediaCodec.BufferInfo info) {
             try {
-                if (DEBUG) Log.d(LOGTAG, "return dummy sample");
+                if (DEBUG) { Log.d(LOGTAG, "return dummy sample"); }
                 mCallbacks.onOutput(Sample.create(null, info, null));
             } catch (RemoteException e) {
                 // Dead recipient.
                 e.printStackTrace();
             }
         }
 
         private synchronized void onRelease(Sample sample, boolean render) {
@@ -233,23 +249,37 @@ import java.util.concurrent.ConcurrentLi
                 mCodec.releaseOutputBuffer(i, false);
             }
             mSentIndices.clear();
             for (Sample s : mSentOutputs) {
                 mSamplePool.recycleOutput(s);
             }
             mSentOutputs.clear();
         }
+
+        private synchronized void start() {
+            if (!mStopped) {
+                return;
+            }
+            mStopped = false;
+        }
+
+        private synchronized void stop() {
+            if (mStopped) {
+                return;
+            }
+            mStopped = true;
+            reset();
+        }
     }
 
     private volatile ICodecCallbacks mCallbacks;
     private AsyncCodec mCodec;
     private InputProcessor mInputProcessor;
     private OutputProcessor mOutputProcessor;
-    private volatile boolean mFlushing = false;
     private SamplePool mSamplePool;
     private Queue<Sample> mSentOutputs = new ConcurrentLinkedQueue<>();
     // Value will be updated after configure called.
     private volatile boolean mIsAdaptivePlaybackSupported = false;
 
     public synchronized void setCallbacks(ICodecCallbacks callbacks) throws RemoteException {
         mCallbacks = callbacks;
         callbacks.asBinder().linkToDeath(this, 0);
@@ -272,21 +302,21 @@ import java.util.concurrent.ConcurrentLi
                                           int flags,
                                           String drmStubId) throws RemoteException {
         if (mCallbacks == null) {
             Log.e(LOGTAG, "FAIL: callbacks must be set before calling configure()");
             return false;
         }
 
         if (mCodec != null) {
-            if (DEBUG) Log.d(LOGTAG, "release existing codec: " + mCodec);
+            if (DEBUG) { Log.d(LOGTAG, "release existing codec: " + mCodec); }
             releaseCodec();
         }
 
-        if (DEBUG) Log.d(LOGTAG, "configure " + this);
+        if (DEBUG) { Log.d(LOGTAG, "configure " + this); }
 
         MediaFormat fmt = format.asFormat();
         String codecName = getDecoderForFormat(fmt);
         if (codecName == null) {
             Log.e(LOGTAG, "FAIL: cannot find codec");
             return false;
         }
 
@@ -301,45 +331,46 @@ import java.util.concurrent.ConcurrentLi
 
             codec.setCallbacks(new Callbacks(), null);
 
             // Video decoder should config with adaptive playback capability.
             if (surface != null) {
                 mIsAdaptivePlaybackSupported = codec.isAdaptivePlaybackSupported(
                                                    fmt.getString(MediaFormat.KEY_MIME));
                 if (mIsAdaptivePlaybackSupported) {
-                    if (DEBUG) Log.d(LOGTAG, "codec supports adaptive playback  = " + mIsAdaptivePlaybackSupported);
+                    if (DEBUG) { Log.d(LOGTAG, "codec supports adaptive playback  = " + mIsAdaptivePlaybackSupported); }
                     // TODO: may need to find a way to not use hard code to decide the max w/h.
                     fmt.setInteger(MediaFormat.KEY_MAX_WIDTH, 1920);
                     fmt.setInteger(MediaFormat.KEY_MAX_HEIGHT, 1080);
                 }
             }
 
             codec.configure(fmt, surface, crypto, flags);
             mCodec = codec;
             mInputProcessor = new InputProcessor();
             mOutputProcessor = new OutputProcessor();
             mSamplePool = new SamplePool(codecName);
-            if (DEBUG) Log.d(LOGTAG, codec.toString() + " created");
+            if (DEBUG) { Log.d(LOGTAG, codec.toString() + " created"); }
             return true;
         } catch (Exception e) {
-            if (DEBUG) Log.d(LOGTAG, "FAIL: cannot create codec -- " + codecName);
+            if (DEBUG) { Log.d(LOGTAG, "FAIL: cannot create codec -- " + codecName); }
             e.printStackTrace();
             return false;
         }
     }
 
     @Override
     public synchronized boolean isAdaptivePlaybackSupported() {
         return mIsAdaptivePlaybackSupported;
     }
 
     private void releaseCodec() {
-        mInputProcessor.reset();
-        mOutputProcessor.reset();
+        // In case Codec.stop() is not called yet.
+        mInputProcessor.stop();
+        mOutputProcessor.stop();
         try {
             mCodec.release();
         } catch (Exception e) {
             reportError(Error.FATAL, e);
         }
         mCodec = null;
     }
 
@@ -364,18 +395,19 @@ import java.util.concurrent.ConcurrentLi
         return null;
         // TODO: API 21+ is simpler.
         //static MediaCodecList sCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
         //return sCodecList.findDecoderForFormat(format);
     }
 
     @Override
     public synchronized void start() throws RemoteException {
-        if (DEBUG) Log.d(LOGTAG, "start " + this);
-        mFlushing = false;
+        if (DEBUG) { Log.d(LOGTAG, "start " + this); }
+        mInputProcessor.start();
+        mOutputProcessor.start();
         try {
             mCodec.start();
         } catch (Exception e) {
             reportError(Error.FATAL, e);
         }
     }
 
     private void reportError(Error error, Exception e) {
@@ -386,38 +418,40 @@ import java.util.concurrent.ConcurrentLi
             mCallbacks.onError(error == Error.FATAL);
         } catch (RemoteException re) {
             re.printStackTrace();
         }
     }
 
     @Override
     public synchronized void stop() throws RemoteException {
-        if (DEBUG) Log.d(LOGTAG, "stop " + this);
+        if (DEBUG) { Log.d(LOGTAG, "stop " + this); }
+        mInputProcessor.stop();
+        mOutputProcessor.stop();
         try {
             mCodec.stop();
         } catch (Exception e) {
             reportError(Error.FATAL, e);
         }
     }
 
     @Override
     public synchronized void flush() throws RemoteException {
-        mFlushing = true;
-        if (DEBUG) Log.d(LOGTAG, "flush " + this);
-        mInputProcessor.reset();
-        mOutputProcessor.reset();
+        if (DEBUG) { Log.d(LOGTAG, "flush " + this); }
+        mInputProcessor.stop();
+        mOutputProcessor.stop();
         try {
             mCodec.flush();
+            if (DEBUG) { Log.d(LOGTAG, "flushed " + this); }
+            mInputProcessor.start();
+            mOutputProcessor.start();
+            mCodec.resumeReceivingInputs();
         } catch (Exception e) {
             reportError(Error.FATAL, e);
         }
-
-        mFlushing = false;
-        if (DEBUG) Log.d(LOGTAG, "flushed " + this);
     }
 
     @Override
     public synchronized Sample dequeueInput(int size) {
         return mInputProcessor.onAllocate(size);
     }
 
     @Override
@@ -427,16 +461,16 @@ import java.util.concurrent.ConcurrentLi
 
     @Override
     public synchronized void releaseOutput(Sample sample, boolean render) {
         mOutputProcessor.onRelease(sample, render);
     }
 
     @Override
     public synchronized void release() throws RemoteException {
-        if (DEBUG) Log.d(LOGTAG, "release " + this);
+        if (DEBUG) { Log.d(LOGTAG, "release " + this); }
         releaseCodec();
         mSamplePool.reset();
         mSamplePool = null;
         mCallbacks.asBinder().unlinkToDeath(this, 0);
         mCallbacks = null;
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/media/CodecProxy.java
+++ b/mobile/android/base/java/org/mozilla/gecko/media/CodecProxy.java
@@ -183,34 +183,34 @@ public final class CodecProxy {
 
     @WrapForJNI
     public synchronized boolean flush() {
         if (mRemote == null) {
             Log.e(LOGTAG, "cannot flush an ended codec");
             return false;
         }
         try {
-            if (DEBUG) Log.d(LOGTAG, "flush " + this);
+            if (DEBUG) { Log.d(LOGTAG, "flush " + this); }
             mRemote.flush();
         } catch (DeadObjectException e) {
             return false;
         } catch (RemoteException e) {
             e.printStackTrace();
             return false;
         }
         return true;
     }
 
     @WrapForJNI
     public synchronized boolean release() {
         if (mRemote == null) {
             Log.w(LOGTAG, "codec already ended");
             return true;
         }
-        if (DEBUG) Log.d(LOGTAG, "release " + this);
+        if (DEBUG) { Log.d(LOGTAG, "release " + this); }
 
         if (!mSurfaceOutputs.isEmpty()) {
             // Flushing output buffers to surface may cause some frames to be skipped and
             // should not happen unless caller release codec before processing all buffers.
             Log.w(LOGTAG, "release codec when " + mSurfaceOutputs.size() + " output buffers unhandled");
             try {
                 for (Sample s : mSurfaceOutputs) {
                     mRemote.releaseOutput(s, true);
@@ -240,24 +240,25 @@ public final class CodecProxy {
         }
 
         if (mRemote == null) {
             Log.w(LOGTAG, "codec already ended");
             sample.dispose();
             return true;
         }
 
-        if (DEBUG && !render) Log.d(LOGTAG, "drop output:" + sample.info.presentationTimeUs);
+        if (DEBUG && !render) { Log.d(LOGTAG, "drop output:" + sample.info.presentationTimeUs); }
 
         try {
             mRemote.releaseOutput(sample, render);
         } catch (RemoteException e) {
+            Log.e(LOGTAG, "remote fail to render output:" + sample.info.presentationTimeUs);
             e.printStackTrace();
         }
         sample.dispose();
 
         return true;
     }
 
-    /* package */ synchronized void reportError(boolean fatal) {
+    /* package */ void reportError(boolean fatal) {
         mCallbacks.reportError(fatal);
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/media/JellyBeanAsyncCodec.java
+++ b/mobile/android/base/java/org/mozilla/gecko/media/JellyBeanAsyncCodec.java
@@ -56,17 +56,17 @@ final class JellyBeanAsyncCodec implemen
                 if (isCanceled() || handleMessageLocked(msg)) {
                     return;
                 }
             }
 
             switch (msg.what) {
                 case MSG_CANCELLATION:
                     // Just a marker. Nothing to do here.
-                    if (DEBUG) Log.d(LOGTAG, "handler " + this + " done cancellation, codec=" + JellyBeanAsyncCodec.this);
+                    if (DEBUG) { Log.d(LOGTAG, "handler " + this + " done cancellation, codec=" + JellyBeanAsyncCodec.this); }
                     break;
                 default:
                     super.handleMessage(msg);
                     break;
             }
         }
      }
 
@@ -268,17 +268,17 @@ final class JellyBeanAsyncCodec implemen
     private void initBufferPoller(String name) {
         if (mBufferPoller != null) {
             Log.e(LOGTAG, "poller already initialized");
             return;
         }
         HandlerThread thread = new HandlerThread(name);
         thread.start();
         mBufferPoller = new BufferPoller(thread.getLooper());
-        if (DEBUG) Log.d(LOGTAG, "start poller for codec:" + this + ", thread=" + thread.getThreadId());
+        if (DEBUG) { Log.d(LOGTAG, "start poller for codec:" + this + ", thread=" + thread.getThreadId()); }
     }
 
     @Override
     public void setCallbacks(AsyncCodec.Callbacks callbacks, Handler handler) {
         if (callbacks == null) {
             return;
         }
 
@@ -287,17 +287,17 @@ final class JellyBeanAsyncCodec implemen
             // Use this thread if no handler supplied.
             looper = Looper.myLooper();
         }
         if (looper == null) {
             // This thread has no looper. Use poller thread.
             looper = mBufferPoller.getLooper();
         }
         mCallbackSender = new CallbackSender(looper, callbacks);
-        if (DEBUG) Log.d(LOGTAG, "setCallbacks(): sender=" + mCallbackSender);
+        if (DEBUG) { Log.d(LOGTAG, "setCallbacks(): sender=" + mCallbackSender); }
     }
 
     @Override
     public void configure(MediaFormat format, Surface surface, MediaCrypto crypto, int flags) {
         assertCallbacks();
 
         mCodec.configure(format, surface, crypto, flags);
     }
@@ -316,20 +316,25 @@ final class JellyBeanAsyncCodec implemen
     @Override
     public void start() {
         assertCallbacks();
 
         mCodec.start();
         mInputEnded = false;
         mOutputEnded = false;
         mInputBuffers = mCodec.getInputBuffers();
+        resumeReceivingInputs();
+        mOutputBuffers = mCodec.getOutputBuffers();
+    }
+
+    @Override
+    public void resumeReceivingInputs() {
         for (int i = 0; i < mInputBuffers.length; i++) {
             mBufferPoller.schedulePolling(BufferPoller.MSG_POLL_INPUT_BUFFERS);
         }
-        mOutputBuffers = mCodec.getOutputBuffers();
     }
 
     @Override
     public final void queueInputBuffer(int index, int offset, int size, long presentationTimeUs, int flags) {
         assertCallbacks();
 
         mInputEnded = (flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
 
@@ -391,19 +396,16 @@ final class JellyBeanAsyncCodec implemen
     @Override
     public void flush() {
         assertCallbacks();
 
         mInputEnded = false;
         mOutputEnded = false;
         cancelPendingTasks();
         mCodec.flush();
-        for (int i = 0; i < mInputBuffers.length; i++) {
-            mBufferPoller.schedulePolling(BufferPoller.MSG_POLL_INPUT_BUFFERS);
-        }
     }
 
     private void cancelPendingTasks() {
         mBufferPoller.cancel();
         mCallbackSender.cancel();
     }
 
     @Override
@@ -428,11 +430,11 @@ final class JellyBeanAsyncCodec implemen
         if (mBufferPoller == null) {
             Log.e(LOGTAG, "no initialized poller.");
             return;
         }
 
         mBufferPoller.getLooper().quit();
         mBufferPoller = null;
 
-        if (DEBUG) Log.d(LOGTAG, "stop poller " + this);
+        if (DEBUG) { Log.d(LOGTAG, "stop poller " + this); }
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/media/RemoteManager.java
+++ b/mobile/android/base/java/org/mozilla/gecko/media/RemoteManager.java
@@ -13,18 +13,16 @@ import android.content.Intent;
 import android.content.ServiceConnection;
 import android.media.MediaFormat;
 import android.os.DeadObjectException;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.view.Surface;
 import android.util.Log;
 
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 import java.util.LinkedList;
 import java.util.List;
 
 public final class RemoteManager implements IBinder.DeathRecipient {
     private static final String LOGTAG = "GeckoRemoteManager";
     private static final boolean DEBUG = false;
     private static RemoteManager sRemoteManager = null;
 
@@ -34,93 +32,86 @@ public final class RemoteManager impleme
         }
 
         sRemoteManager.init();
         return sRemoteManager;
     }
 
     private List<CodecProxy> mProxies = new LinkedList<CodecProxy>();
     private volatile IMediaManager mRemote;
-    private volatile CountDownLatch mConnectionLatch;
-    private final ServiceConnection mConnection = new ServiceConnection() {
+
+    private final class RemoteConnection implements ServiceConnection {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             if (DEBUG) Log.d(LOGTAG, "service connected");
             try {
                 service.linkToDeath(RemoteManager.this, 0);
             } catch (RemoteException e) {
                 e.printStackTrace();
             }
-            mRemote = IMediaManager.Stub.asInterface(service);
-            if (mConnectionLatch != null) {
-                mConnectionLatch.countDown();
+            synchronized (this) {
+                mRemote = IMediaManager.Stub.asInterface(service);
+                notify();
             }
         }
 
-        /**
-         * Called when a connection to the Service has been lost.  This typically
-         * happens when the process hosting the service has crashed or been killed.
-         * This does <em>not</em> remove the ServiceConnection itself -- this
-         * binding to the service will remain active, and you will receive a call
-         * to {@link #onServiceConnected} when the Service is next running.
-         *
-         * @param name The concrete component name of the service whose
-         *             connection has been lost.
-         */
         @Override
         public void onServiceDisconnected(ComponentName name) {
             if (DEBUG) Log.d(LOGTAG, "service disconnected");
             mRemote.asBinder().unlinkToDeath(RemoteManager.this, 0);
-            mRemote = null;
-            if (mConnectionLatch != null) {
-                mConnectionLatch.countDown();
+            synchronized (this) {
+                mRemote = null;
+                notify();
+            }
+        }
+
+        private boolean connect() {
+            Context appCtxt = GeckoAppShell.getApplicationContext();
+            appCtxt.bindService(new Intent(appCtxt, MediaManager.class),
+                    mConnection, Context.BIND_AUTO_CREATE);
+            waitConnect();
+            return mRemote != null;
+        }
+
+        // Wait up to 5s.
+        private synchronized void waitConnect() {
+            int waitCount = 0;
+            while (mRemote == null && waitCount < 5) {
+                try {
+                    wait(1000);
+                    waitCount++;
+                } catch (InterruptedException e) {<