Merge mozilla-central to inbound on a CLOSED TREE
authorarthur.iakab <aiakab@mozilla.com>
Wed, 06 Jun 2018 01:10:33 +0300
changeset 475737 27822aace5b803327dfabd3e3b02b5cbb9e7c2ce
parent 475736 4b22431dee8391865ba5be637c12216148f124c6 (current diff)
parent 475678 da28b92efe6f6acaf79545697415b82038143338 (diff)
child 475738 ff2162607d61d0edd7db85c2e117b3d620c9d9ac
push id9374
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:43:20 +0000
treeherdermozilla-beta@160e085dfb0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone62.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 mozilla-central to inbound on a CLOSED TREE
browser/locales/search/list.json
browser/locales/searchplugins/allaannonser-sv-SE.xml
browser/locales/searchplugins/allegro-pl.xml
browser/locales/searchplugins/amazon-au.xml
browser/locales/searchplugins/amazon-br.xml
browser/locales/searchplugins/amazon-ca.xml
browser/locales/searchplugins/amazon-en-GB.xml
browser/locales/searchplugins/amazon-france.xml
browser/locales/searchplugins/amazon-in.xml
browser/locales/searchplugins/amazon-it.xml
browser/locales/searchplugins/amazon-jp.xml
browser/locales/searchplugins/amazon-mx.xml
browser/locales/searchplugins/amazon-nl.xml
browser/locales/searchplugins/amazondotcn.xml
browser/locales/searchplugins/amazondotcom-de.xml
browser/locales/searchplugins/amazondotcom.xml
browser/locales/searchplugins/atlas-sk.xml
browser/locales/searchplugins/azerdict.xml
browser/locales/searchplugins/azet-sk.xml
browser/locales/searchplugins/baidu.xml
browser/locales/searchplugins/bbc-alba.xml
browser/locales/searchplugins/bing.xml
browser/locales/searchplugins/bok-NO.xml
browser/locales/searchplugins/bolcom-fy-NL.xml
browser/locales/searchplugins/bolcom-nl.xml
browser/locales/searchplugins/bookplus-fi.xml
browser/locales/searchplugins/buscape.xml
browser/locales/searchplugins/ceneji.xml
browser/locales/searchplugins/chambers-en-GB.xml
browser/locales/searchplugins/cnrtl-tlfi-fr.xml
browser/locales/searchplugins/coccoc.xml
browser/locales/searchplugins/danawa-kr.xml
browser/locales/searchplugins/daum-kr.xml
browser/locales/searchplugins/ddg.xml
browser/locales/searchplugins/diccionariu-alla.xml
browser/locales/searchplugins/dict-enlv.xml
browser/locales/searchplugins/diec2.xml
browser/locales/searchplugins/drae.xml
browser/locales/searchplugins/ebay-at.xml
browser/locales/searchplugins/ebay-au.xml
browser/locales/searchplugins/ebay-be.xml
browser/locales/searchplugins/ebay-ca.xml
browser/locales/searchplugins/ebay-ch.xml
browser/locales/searchplugins/ebay-de.xml
browser/locales/searchplugins/ebay-es.xml
browser/locales/searchplugins/ebay-fr.xml
browser/locales/searchplugins/ebay-ie.xml
browser/locales/searchplugins/ebay-it.xml
browser/locales/searchplugins/ebay-nl.xml
browser/locales/searchplugins/ebay-uk.xml
browser/locales/searchplugins/ebay.xml
browser/locales/searchplugins/ecosia.xml
browser/locales/searchplugins/eki-ee.xml
browser/locales/searchplugins/elebila.xml
browser/locales/searchplugins/eudict.xml
browser/locales/searchplugins/faclair-beag.xml
browser/locales/searchplugins/flip.xml
browser/locales/searchplugins/freelang.xml
browser/locales/searchplugins/google-2018.xml
browser/locales/searchplugins/google.xml
browser/locales/searchplugins/gujaratilexicon.xml
browser/locales/searchplugins/gulesider-NO.xml
browser/locales/searchplugins/heureka-cz.xml
browser/locales/searchplugins/hoepli.xml
browser/locales/searchplugins/hotline-ua.xml
browser/locales/searchplugins/images/amazon.ico
browser/locales/searchplugins/images/ebay.ico
browser/locales/searchplugins/images/wikipedia.ico
browser/locales/searchplugins/images/yandex-en.ico
browser/locales/searchplugins/images/yandex-ru.ico
browser/locales/searchplugins/kannadastore.xml
browser/locales/searchplugins/kaz-kk.xml
browser/locales/searchplugins/klask.xml
browser/locales/searchplugins/leit-is.xml
browser/locales/searchplugins/leo_ende_de-rm.xml
browser/locales/searchplugins/leo_ende_de.xml
browser/locales/searchplugins/list-am.xml
browser/locales/searchplugins/longdo.xml
browser/locales/searchplugins/mailru.xml
browser/locales/searchplugins/mapy-cz.xml
browser/locales/searchplugins/marktplaats-fy-NL.xml
browser/locales/searchplugins/marktplaats-nl.xml
browser/locales/searchplugins/mercadolibre-ar.xml
browser/locales/searchplugins/mercadolibre-cl.xml
browser/locales/searchplugins/mercadolibre-mx.xml
browser/locales/searchplugins/mercadolivre.xml
browser/locales/searchplugins/meta-ua.xml
browser/locales/searchplugins/morfix-dic.xml
browser/locales/searchplugins/najdi-si.xml
browser/locales/searchplugins/naver-kr.xml
browser/locales/searchplugins/neti-ee.xml
browser/locales/searchplugins/odpiralni.xml
browser/locales/searchplugins/olx.xml
browser/locales/searchplugins/oshiete-goo.xml
browser/locales/searchplugins/osta-ee.xml
browser/locales/searchplugins/ozonru.xml
browser/locales/searchplugins/palasprint.xml
browser/locales/searchplugins/paroledigenova-lij.xml
browser/locales/searchplugins/pazaruvaj.xml
browser/locales/searchplugins/pledarigrond.xml
browser/locales/searchplugins/pogodak.xml
browser/locales/searchplugins/portalbgdict.xml
browser/locales/searchplugins/priberam.xml
browser/locales/searchplugins/priceru.xml
browser/locales/searchplugins/prisjakt-sv-SE.xml
browser/locales/searchplugins/pwn-pl.xml
browser/locales/searchplugins/qwant.xml
browser/locales/searchplugins/qxl-NO.xml
browser/locales/searchplugins/rakuten.xml
browser/locales/searchplugins/readmoo.xml
browser/locales/searchplugins/rediff.xml
browser/locales/searchplugins/reta-vortaro.xml
browser/locales/searchplugins/salidzinilv.xml
browser/locales/searchplugins/sapo.xml
browser/locales/searchplugins/seznam-cz.xml
browser/locales/searchplugins/slovnik-sk.xml
browser/locales/searchplugins/sslv.xml
browser/locales/searchplugins/sztaki-en-hu.xml
browser/locales/searchplugins/tearma.xml
browser/locales/searchplugins/termau.xml
browser/locales/searchplugins/twitter-ja.xml
browser/locales/searchplugins/twitter.xml
browser/locales/searchplugins/tyda-sv-SE.xml
browser/locales/searchplugins/vatera.xml
browser/locales/searchplugins/webdunia.xml
browser/locales/searchplugins/wikipedia-NN.xml
browser/locales/searchplugins/wikipedia-NO.xml
browser/locales/searchplugins/wikipedia-af.xml
browser/locales/searchplugins/wikipedia-an.xml
browser/locales/searchplugins/wikipedia-ar.xml
browser/locales/searchplugins/wikipedia-as.xml
browser/locales/searchplugins/wikipedia-ast.xml
browser/locales/searchplugins/wikipedia-az.xml
browser/locales/searchplugins/wikipedia-be-tarask.xml
browser/locales/searchplugins/wikipedia-be.xml
browser/locales/searchplugins/wikipedia-bg.xml
browser/locales/searchplugins/wikipedia-bn.xml
browser/locales/searchplugins/wikipedia-br.xml
browser/locales/searchplugins/wikipedia-bs.xml
browser/locales/searchplugins/wikipedia-ca.xml
browser/locales/searchplugins/wikipedia-crh.xml
browser/locales/searchplugins/wikipedia-cy.xml
browser/locales/searchplugins/wikipedia-cz.xml
browser/locales/searchplugins/wikipedia-da.xml
browser/locales/searchplugins/wikipedia-de.xml
browser/locales/searchplugins/wikipedia-dsb.xml
browser/locales/searchplugins/wikipedia-el.xml
browser/locales/searchplugins/wikipedia-eo.xml
browser/locales/searchplugins/wikipedia-es.xml
browser/locales/searchplugins/wikipedia-et.xml
browser/locales/searchplugins/wikipedia-eu.xml
browser/locales/searchplugins/wikipedia-fa.xml
browser/locales/searchplugins/wikipedia-fi.xml
browser/locales/searchplugins/wikipedia-fr.xml
browser/locales/searchplugins/wikipedia-fy-NL.xml
browser/locales/searchplugins/wikipedia-ga-IE.xml
browser/locales/searchplugins/wikipedia-gd.xml
browser/locales/searchplugins/wikipedia-gl.xml
browser/locales/searchplugins/wikipedia-gn.xml
browser/locales/searchplugins/wikipedia-gu.xml
browser/locales/searchplugins/wikipedia-he.xml
browser/locales/searchplugins/wikipedia-hi.xml
browser/locales/searchplugins/wikipedia-hr.xml
browser/locales/searchplugins/wikipedia-hsb.xml
browser/locales/searchplugins/wikipedia-hu.xml
browser/locales/searchplugins/wikipedia-hy.xml
browser/locales/searchplugins/wikipedia-ia.xml
browser/locales/searchplugins/wikipedia-id.xml
browser/locales/searchplugins/wikipedia-is.xml
browser/locales/searchplugins/wikipedia-it.xml
browser/locales/searchplugins/wikipedia-ja.xml
browser/locales/searchplugins/wikipedia-ka.xml
browser/locales/searchplugins/wikipedia-kab.xml
browser/locales/searchplugins/wikipedia-kk.xml
browser/locales/searchplugins/wikipedia-km.xml
browser/locales/searchplugins/wikipedia-kn.xml
browser/locales/searchplugins/wikipedia-kr.xml
browser/locales/searchplugins/wikipedia-lij.xml
browser/locales/searchplugins/wikipedia-lo.xml
browser/locales/searchplugins/wikipedia-lt.xml
browser/locales/searchplugins/wikipedia-ltg.xml
browser/locales/searchplugins/wikipedia-lv.xml
browser/locales/searchplugins/wikipedia-mk.xml
browser/locales/searchplugins/wikipedia-ml.xml
browser/locales/searchplugins/wikipedia-mr.xml
browser/locales/searchplugins/wikipedia-ms.xml
browser/locales/searchplugins/wikipedia-my.xml
browser/locales/searchplugins/wikipedia-ne.xml
browser/locales/searchplugins/wikipedia-nl.xml
browser/locales/searchplugins/wikipedia-oc.xml
browser/locales/searchplugins/wikipedia-or.xml
browser/locales/searchplugins/wikipedia-pa.xml
browser/locales/searchplugins/wikipedia-pl.xml
browser/locales/searchplugins/wikipedia-pt.xml
browser/locales/searchplugins/wikipedia-rm.xml
browser/locales/searchplugins/wikipedia-ro.xml
browser/locales/searchplugins/wikipedia-ru.xml
browser/locales/searchplugins/wikipedia-si.xml
browser/locales/searchplugins/wikipedia-sk.xml
browser/locales/searchplugins/wikipedia-sl.xml
browser/locales/searchplugins/wikipedia-sq.xml
browser/locales/searchplugins/wikipedia-sr.xml
browser/locales/searchplugins/wikipedia-sv-SE.xml
browser/locales/searchplugins/wikipedia-ta.xml
browser/locales/searchplugins/wikipedia-te.xml
browser/locales/searchplugins/wikipedia-th.xml
browser/locales/searchplugins/wikipedia-tl.xml
browser/locales/searchplugins/wikipedia-tr.xml
browser/locales/searchplugins/wikipedia-uk.xml
browser/locales/searchplugins/wikipedia-ur.xml
browser/locales/searchplugins/wikipedia-uz.xml
browser/locales/searchplugins/wikipedia-vi.xml
browser/locales/searchplugins/wikipedia-wo.xml
browser/locales/searchplugins/wikipedia-zh-CN.xml
browser/locales/searchplugins/wikipedia-zh-TW.xml
browser/locales/searchplugins/wikipedia.xml
browser/locales/searchplugins/wiktionary-oc.xml
browser/locales/searchplugins/wiktionary-te.xml
browser/locales/searchplugins/wolnelektury-pl.xml
browser/locales/searchplugins/yahoo-jp-auctions.xml
browser/locales/searchplugins/yahoo-jp.xml
browser/locales/searchplugins/yandex-az.xml
browser/locales/searchplugins/yandex-by.xml
browser/locales/searchplugins/yandex-en.xml
browser/locales/searchplugins/yandex-kk.xml
browser/locales/searchplugins/yandex-ru.xml
browser/locales/searchplugins/yandex-tr.xml
browser/locales/searchplugins/zoznam-sk.xml
browser/themes/shared/update-badge-failed.svg
browser/themes/shared/warning-white.svg
layout/generic/nsFrameStateBits.h
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-039-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-039.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-040.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-045-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-045.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-circle-046.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-018-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-018.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-019-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-019.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-polygon-026-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-polygon-026.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-polygon-027-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-polygon-027.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-polygon-028.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-polygon-029.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-polygon-030-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-polygon-030.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-polygon-031-ref.html
layout/reftests/w3c-css/submitted/shapes1/shape-outside-polygon-031.html
mobile/locales/search/list.json
mobile/locales/searchplugins/amazon-au.xml
mobile/locales/searchplugins/amazon-br.xml
mobile/locales/searchplugins/amazon-ca.xml
mobile/locales/searchplugins/amazon-co-uk.xml
mobile/locales/searchplugins/amazon-de.xml
mobile/locales/searchplugins/amazon-fr.xml
mobile/locales/searchplugins/amazon-in.xml
mobile/locales/searchplugins/amazon-it.xml
mobile/locales/searchplugins/amazon-jp.xml
mobile/locales/searchplugins/amazon-mx.xml
mobile/locales/searchplugins/amazon-nl.xml
mobile/locales/searchplugins/amazondotcom.xml
mobile/locales/searchplugins/azerdict.xml
mobile/locales/searchplugins/azet-sk.xml
mobile/locales/searchplugins/baidu.xml
mobile/locales/searchplugins/bing.xml
mobile/locales/searchplugins/bolcom-fy-NL.xml
mobile/locales/searchplugins/bolcom-nl.xml
mobile/locales/searchplugins/ceneje.xml
mobile/locales/searchplugins/coccoc.xml
mobile/locales/searchplugins/danawa-kr.xml
mobile/locales/searchplugins/daum-kr.xml
mobile/locales/searchplugins/ddg.xml
mobile/locales/searchplugins/diec2.xml
mobile/locales/searchplugins/drae.xml
mobile/locales/searchplugins/duckduckgo.xml
mobile/locales/searchplugins/elebila.xml
mobile/locales/searchplugins/faclair-beag.xml
mobile/locales/searchplugins/google-2018.xml
mobile/locales/searchplugins/google.xml
mobile/locales/searchplugins/gulesider-mobile-NO.xml
mobile/locales/searchplugins/heureka-cz.xml
mobile/locales/searchplugins/hotline-ua.xml
mobile/locales/searchplugins/leit-is.xml
mobile/locales/searchplugins/leo_ende_de.xml
mobile/locales/searchplugins/list-am.xml
mobile/locales/searchplugins/mapy-cz.xml
mobile/locales/searchplugins/mercadolibre-ar.xml
mobile/locales/searchplugins/mercadolibre-cl.xml
mobile/locales/searchplugins/mercadolibre-mx.xml
mobile/locales/searchplugins/naver-kr.xml
mobile/locales/searchplugins/odpiralni.xml
mobile/locales/searchplugins/pazaruvaj.xml
mobile/locales/searchplugins/pledarigrond.xml
mobile/locales/searchplugins/prisjakt-sv-SE.xml
mobile/locales/searchplugins/qwant.xml
mobile/locales/searchplugins/rediff.xml
mobile/locales/searchplugins/reta-vortaro.xml
mobile/locales/searchplugins/salidzinilv.xml
mobile/locales/searchplugins/seznam-cz.xml
mobile/locales/searchplugins/skroutz.xml
mobile/locales/searchplugins/slovnik-sk.xml
mobile/locales/searchplugins/sslv.xml
mobile/locales/searchplugins/sztaki-en-hu.xml
mobile/locales/searchplugins/taobao.xml
mobile/locales/searchplugins/tearma.xml
mobile/locales/searchplugins/twitter-ja.xml
mobile/locales/searchplugins/twitter.xml
mobile/locales/searchplugins/vatera.xml
mobile/locales/searchplugins/wikipedia-NN.xml
mobile/locales/searchplugins/wikipedia-NO.xml
mobile/locales/searchplugins/wikipedia-an.xml
mobile/locales/searchplugins/wikipedia-ar.xml
mobile/locales/searchplugins/wikipedia-as.xml
mobile/locales/searchplugins/wikipedia-ast.xml
mobile/locales/searchplugins/wikipedia-az.xml
mobile/locales/searchplugins/wikipedia-be.xml
mobile/locales/searchplugins/wikipedia-bg.xml
mobile/locales/searchplugins/wikipedia-bn.xml
mobile/locales/searchplugins/wikipedia-br.xml
mobile/locales/searchplugins/wikipedia-bs.xml
mobile/locales/searchplugins/wikipedia-ca.xml
mobile/locales/searchplugins/wikipedia-cy.xml
mobile/locales/searchplugins/wikipedia-cz.xml
mobile/locales/searchplugins/wikipedia-da.xml
mobile/locales/searchplugins/wikipedia-de.xml
mobile/locales/searchplugins/wikipedia-dsb.xml
mobile/locales/searchplugins/wikipedia-el.xml
mobile/locales/searchplugins/wikipedia-eo.xml
mobile/locales/searchplugins/wikipedia-es.xml
mobile/locales/searchplugins/wikipedia-et.xml
mobile/locales/searchplugins/wikipedia-eu.xml
mobile/locales/searchplugins/wikipedia-fa.xml
mobile/locales/searchplugins/wikipedia-fi.xml
mobile/locales/searchplugins/wikipedia-fr.xml
mobile/locales/searchplugins/wikipedia-fy-NL.xml
mobile/locales/searchplugins/wikipedia-ga-IE.xml
mobile/locales/searchplugins/wikipedia-gd.xml
mobile/locales/searchplugins/wikipedia-gl.xml
mobile/locales/searchplugins/wikipedia-gn.xml
mobile/locales/searchplugins/wikipedia-gu.xml
mobile/locales/searchplugins/wikipedia-he.xml
mobile/locales/searchplugins/wikipedia-hi.xml
mobile/locales/searchplugins/wikipedia-hr.xml
mobile/locales/searchplugins/wikipedia-hsb.xml
mobile/locales/searchplugins/wikipedia-hu.xml
mobile/locales/searchplugins/wikipedia-hy-AM.xml
mobile/locales/searchplugins/wikipedia-ia.xml
mobile/locales/searchplugins/wikipedia-id.xml
mobile/locales/searchplugins/wikipedia-is.xml
mobile/locales/searchplugins/wikipedia-it.xml
mobile/locales/searchplugins/wikipedia-ja.xml
mobile/locales/searchplugins/wikipedia-ka.xml
mobile/locales/searchplugins/wikipedia-kab.xml
mobile/locales/searchplugins/wikipedia-kk.xml
mobile/locales/searchplugins/wikipedia-km.xml
mobile/locales/searchplugins/wikipedia-kn.xml
mobile/locales/searchplugins/wikipedia-lij.xml
mobile/locales/searchplugins/wikipedia-lo.xml
mobile/locales/searchplugins/wikipedia-lt.xml
mobile/locales/searchplugins/wikipedia-ltg.xml
mobile/locales/searchplugins/wikipedia-lv.xml
mobile/locales/searchplugins/wikipedia-ml.xml
mobile/locales/searchplugins/wikipedia-mr.xml
mobile/locales/searchplugins/wikipedia-ms.xml
mobile/locales/searchplugins/wikipedia-my.xml
mobile/locales/searchplugins/wikipedia-ne.xml
mobile/locales/searchplugins/wikipedia-nl.xml
mobile/locales/searchplugins/wikipedia-oc.xml
mobile/locales/searchplugins/wikipedia-or.xml
mobile/locales/searchplugins/wikipedia-pa.xml
mobile/locales/searchplugins/wikipedia-pl.xml
mobile/locales/searchplugins/wikipedia-pt.xml
mobile/locales/searchplugins/wikipedia-rm.xml
mobile/locales/searchplugins/wikipedia-ro.xml
mobile/locales/searchplugins/wikipedia-ru.xml
mobile/locales/searchplugins/wikipedia-sk.xml
mobile/locales/searchplugins/wikipedia-sl.xml
mobile/locales/searchplugins/wikipedia-sq.xml
mobile/locales/searchplugins/wikipedia-sr.xml
mobile/locales/searchplugins/wikipedia-sv-SE.xml
mobile/locales/searchplugins/wikipedia-ta.xml
mobile/locales/searchplugins/wikipedia-te.xml
mobile/locales/searchplugins/wikipedia-th.xml
mobile/locales/searchplugins/wikipedia-tr.xml
mobile/locales/searchplugins/wikipedia-uk.xml
mobile/locales/searchplugins/wikipedia-ur.xml
mobile/locales/searchplugins/wikipedia-uz.xml
mobile/locales/searchplugins/wikipedia-vi.xml
mobile/locales/searchplugins/wikipedia-wo.xml
mobile/locales/searchplugins/wikipedia-zh-CN.xml
mobile/locales/searchplugins/wikipedia-zh-TW.xml
mobile/locales/searchplugins/wikipedia.xml
mobile/locales/searchplugins/wiktionary-kn.xml
mobile/locales/searchplugins/wiktionary-oc.xml
mobile/locales/searchplugins/wiktionary-or.xml
mobile/locales/searchplugins/wiktionary-ta.xml
mobile/locales/searchplugins/wiktionary-te.xml
mobile/locales/searchplugins/yahoo-jp.xml
mobile/locales/searchplugins/yandex-en.xml
mobile/locales/searchplugins/yandex-ru.xml
mobile/locales/searchplugins/yandex-tr.xml
mobile/locales/searchplugins/yandex.by.xml
mobile/locales/searchplugins/yandex.xml
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-039-ref.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-039.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-040.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-045-ref.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-045.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-046.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-inset-018-ref.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-inset-018.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-inset-019-ref.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-inset-019.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-026-ref.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-026.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-027-ref.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-027.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-028.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-029.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-030-ref.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-030.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-031-ref.html
testing/web-platform/tests/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-031.html
--- a/.cron.yml
+++ b/.cron.yml
@@ -113,11 +113,14 @@ jobs:
           by-project:
               # No default branch
               mozilla-central:
                   - {weekday: 'Monday', hour: 10, minute: 0}
                   - {weekday: 'Thursday', hour: 10, minute: 0}
               mozilla-esr60:
                   - {weekday: 'Monday', hour: 10, minute: 0}
                   - {weekday: 'Thursday', hour: 10, minute: 0}
+              mozilla-release:
+                  - {weekday: 'Monday', hour: 10, minute: 0}
+                  - {weekday: 'Thursday', hour: 10, minute: 0}
               mozilla-beta:
                   - {weekday: 'Monday', hour: 10, minute: 0}
                   - {weekday: 'Thursday', hour: 10, minute: 0}
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -47,26 +47,16 @@ module.exports = {
     ],
     "rules": {
       "mozilla/no-define-cc-etc": "off",
     }
   }, {
     // XXX Bug 1452706. These directories are still being fixed, so turn off
     //  mozilla/require-expected-throws-or-rejects for now.
     "files": [
-      "devtools/client/inspector/extensions/test/head_devtools_inspector_sidebar.js",
-      "storage/test/unit/**",
-    ],
-    "rules": {
-      "mozilla/require-expected-throws-or-rejects": "off",
-    }
-  }, {
-    // XXX Bug 1452706. These directories are still being fixed, so turn off
-    //  mozilla/require-expected-throws-or-rejects for now.
-    "files": [
       "services/fxaccounts/**",
       "toolkit/components/**",
     ],
     "rules": {
       "mozilla/rejects-requires-await": "off",
     }
   }]
 };
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -14,16 +14,19 @@ var StarUI = {
   _batching: false,
   _isNewBookmark: false,
   _isComposing: false,
   _autoCloseTimer: 0,
   // The autoclose timer is diasbled if the user interacts with the
   // popup, such as making a change through typing or clicking on
   // the popup.
   _autoCloseTimerEnabled: true,
+  // The autoclose timeout length. 3500ms matches the timeout that Pocket uses
+  // in browser/extensions/pocket/content/panels/js/saved.js.
+  _autoCloseTimeout: 3500,
   _removeBookmarksOnPopupHidden: false,
 
   _element(aID) {
     return document.getElementById(aID);
   },
 
   // Edit-bookmark panel
   get panel() {
@@ -79,18 +82,23 @@ var StarUI = {
       case "mousemove":
         clearTimeout(this._autoCloseTimer);
         // The autoclose timer is not disabled on generic mouseout
         // because the user may not have actually interacted with the popup.
         break;
       case "popuphidden": {
         clearTimeout(this._autoCloseTimer);
         if (aEvent.originalTarget == this.panel) {
-          if (!this._element("editBookmarkPanelContent").hidden)
+          let selectedFolderGuid;
+
+          if (!this._element("editBookmarkPanelContent").hidden) {
+            // Get the folder first, before we uninit the overlay.
+            selectedFolderGuid = gEditItemOverlay.selectedFolderGuid;
             this.quitEditMode();
+          }
 
           if (this._anchorToolbarButton) {
             this._anchorToolbarButton.removeAttribute("open");
             this._anchorToolbarButton = null;
           }
           this._restoreCommandsState();
           let removeBookmarksOnPopupHidden = this._removeBookmarksOnPopupHidden;
           this._removeBookmarksOnPopupHidden = false;
@@ -108,16 +116,20 @@ var StarUI = {
             }
             // Remove all bookmarks for the bookmark's url, this also removes
             // the tags for the url.
             PlacesTransactions.Remove(guidsForRemoval)
                               .transact().catch(Cu.reportError);
           } else if (this._isNewBookmark) {
             LibraryUI.triggerLibraryAnimation("bookmark");
           }
+
+          if (!removeBookmarksOnPopupHidden) {
+            this._storeRecentlyUsedFolder(selectedFolderGuid).catch(console.error);
+          }
         }
         break;
       }
       case "keypress":
         clearTimeout(this._autoCloseTimer);
         this._autoCloseTimerEnabled = false;
 
         if (aEvent.defaultPrevented) {
@@ -181,19 +193,17 @@ var StarUI = {
         // Explicit fall-through
       case "popupshown":
         // Don't handle events for descendent elements.
         if (aEvent.target != aEvent.currentTarget) {
           break;
         }
         // auto-close if new and not interacted with
         if (this._isNewBookmark && !this._isComposing) {
-          // 3500ms matches the timeout that Pocket uses in
-          // browser/extensions/pocket/content/panels/js/saved.js
-          let delay = 3500;
+          let delay = this._autoCloseTimeout;
           if (this._closePanelQuickForTesting) {
             delay /= 10;
           }
           clearTimeout(this._autoCloseTimer);
           this._autoCloseTimer = setTimeout(() => {
             if (!this.panel.mozMatchesSelector(":hover")) {
               this.panel.hidePopup(true);
             }
@@ -335,16 +345,43 @@ var StarUI = {
 
   endBatch() {
     if (!this._batching)
       return;
 
     this._batchBlockingDeferred.resolve();
     this._batchBlockingDeferred = null;
     this._batching = false;
+  },
+
+  async _storeRecentlyUsedFolder(selectedFolderGuid) {
+    // These are displayed by default, so don't save the folder for them.
+    if (!selectedFolderGuid ||
+        PlacesUtils.bookmarks.userContentRoots.includes(selectedFolderGuid)) {
+      return;
+    }
+
+    // List of recently used folders:
+    let lastUsedFolderGuids =
+      await PlacesUtils.metadata.get(PlacesUIUtils.LAST_USED_FOLDERS_META_KEY, []);
+
+    let index = lastUsedFolderGuids.indexOf(selectedFolderGuid);
+    if (index > 1) {
+      // The guid is in the array but not the most recent.
+      lastUsedFolderGuids.splice(index, 1);
+      lastUsedFolderGuids.unshift(selectedFolderGuid);
+    } else if (index == -1) {
+      lastUsedFolderGuids.unshift(selectedFolderGuid);
+    }
+    if (lastUsedFolderGuids.length > 5) {
+      lastUsedFolderGuids.pop();
+    }
+
+    await PlacesUtils.metadata.set(PlacesUIUtils.LAST_USED_FOLDERS_META_KEY,
+                                   lastUsedFolderGuids);
   }
 };
 
 var PlacesCommandHook = {
   /**
    * Adds a bookmark to the page loaded in the given browser.
    *
    * @param aBrowser
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -791,24 +791,23 @@ var gPopupBlockerObserver = {
         } else {
           // For host-less URIs like file://, prePath would effectively allow
           // popups everywhere on file://. Use the full spec:
           prefillValue = principalURI.spec;
         }
       }
     } catch (e) { }
 
-    var bundlePreferences = document.getElementById("bundle_preferences");
     var params = { blockVisible: false,
                    sessionVisible: false,
                    allowVisible: true,
                    prefilledHost: prefillValue,
                    permissionType: "popup",
-                   windowTitle: bundlePreferences.getString("popuppermissionstitle2"),
-                   introText: bundlePreferences.getString("popuppermissionstext") };
+    };
+
     var existingWindow = Services.wm.getMostRecentWindow("Browser:Permissions");
     if (existingWindow) {
       existingWindow.initWithParams(params);
       existingWindow.focus();
     } else
       window.openDialog("chrome://browser/content/preferences/permissions.xul",
                         "_blank", "resizable,dialog=no,centerscreen", params);
   },
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -131,17 +131,17 @@ window._gBrowser = {
     "resumeMedia", "mute", "unmute", "blockedPopups", "lastURI",
     "purgeSessionHistory", "stopScroll", "startScroll",
     "userTypedValue", "userTypedClear",
     "didStartLoadSinceLastUserTyping", "audioMuted"
   ],
 
   _removingTabs: [],
 
-  _multiSelectedTabsMap: new WeakMap(),
+  _multiSelectedTabsSet: new WeakSet(),
 
   _lastMultiSelectedTabRef: null,
 
   /**
    * Tab close requests are ignored if the window is closing anyway,
    * e.g. when holding Ctrl+W.
    */
   _windowIsClosing: false,
@@ -2619,18 +2619,18 @@ window._gBrowser = {
     this.removeCollectionOfTabs(tabs);
   },
 
   removeMultiSelectedTabs() {
     if (!this.warnAboutClosingTabs(this.closingTabsEnum.MULTI_SELECTED)) {
       return;
     }
 
-    let selectedTabs = ChromeUtils.nondeterministicGetWeakMapKeys(this._multiSelectedTabsMap)
-                                    .filter(tab => tab.isConnected);
+    let selectedTabs = ChromeUtils.nondeterministicGetWeakSetKeys(this._multiSelectedTabsSet)
+                                  .filter(tab => tab.isConnected);
     this.removeCollectionOfTabs(selectedTabs);
   },
 
   removeCollectionOfTabs(tabs) {
     let tabsWithBeforeUnload = [];
     let lastToClose;
     let aParams = {animation: true};
     for (let tab of tabs) {
@@ -3625,17 +3625,17 @@ window._gBrowser = {
   },
 
   addToMultiSelectedTabs(aTab) {
     if (aTab.multiselected) {
       return;
     }
 
     aTab.setAttribute("multiselected", "true");
-    this._multiSelectedTabsMap.set(aTab, null);
+    this._multiSelectedTabsSet.add(aTab);
   },
 
   /**
    * Adds two given tabs and all tabs between them into the (multi) selected tabs collection
    */
   addRangeToMultiSelectedTabs(aTab1, aTab2) {
     // Let's avoid going through all the heavy process below when the same
     // tab is given as params.
@@ -3656,38 +3656,38 @@ window._gBrowser = {
     }
   },
 
   removeFromMultiSelectedTabs(aTab) {
     if (!aTab.multiselected) {
       return;
     }
     aTab.removeAttribute("multiselected");
-    this._multiSelectedTabsMap.delete(aTab);
+    this._multiSelectedTabsSet.delete(aTab);
   },
 
   clearMultiSelectedTabs() {
-    const selectedTabs = ChromeUtils.nondeterministicGetWeakMapKeys(this._multiSelectedTabsMap);
+    const selectedTabs = ChromeUtils.nondeterministicGetWeakSetKeys(this._multiSelectedTabsSet);
     for (let tab of selectedTabs) {
       if (tab.isConnected && tab.multiselected) {
         tab.removeAttribute("multiselected");
       }
     }
-    this._multiSelectedTabsMap = new WeakMap();
+    this._multiSelectedTabsSet = new WeakSet();
   },
 
   get multiSelectedTabsCount() {
-    return ChromeUtils.nondeterministicGetWeakMapKeys(this._multiSelectedTabsMap)
+    return ChromeUtils.nondeterministicGetWeakSetKeys(this._multiSelectedTabsSet)
       .filter(tab => tab.isConnected && !tab.closing)
       .length;
   },
 
   get lastMultiSelectedTab() {
     let tab = this._lastMultiSelectedTabRef ? this._lastMultiSelectedTabRef.get() : null;
-    if (tab && tab.isConnected && this._multiSelectedTabsMap.has(tab)) {
+    if (tab && tab.isConnected && this._multiSelectedTabsSet.has(tab)) {
       return tab;
     }
     return gBrowser.selectedTab;
   },
 
   set lastMultiSelectedTab(aTab) {
     this._lastMultiSelectedTabRef = Cu.getWeakReference(aTab);
   },
--- a/browser/base/content/test/performance/browser_startup.js
+++ b/browser/base/content/test/performance/browser_startup.js
@@ -114,16 +114,17 @@ const startupPhases = {
   "before becoming idle": {blacklist: {
     components: new Set([
       "UnifiedComplete.js",
     ]),
     modules: new Set([
       "resource://gre/modules/AsyncPrefs.jsm",
       "resource://gre/modules/LoginManagerContextMenu.jsm",
       "resource://gre/modules/Task.jsm",
+      "resource://pdf.js/PdfStreamConverter.jsm",
     ]),
   }},
 };
 
 if (Services.prefs.getBoolPref("browser.startup.blankWindow")) {
   startupPhases["before profile selection"].whitelist.components.add("XULStore.js");
 }
 
--- a/browser/base/content/test/performance/browser_startup_content.js
+++ b/browser/base/content/test/performance/browser_startup_content.js
@@ -24,16 +24,18 @@ const blacklist = {
   ]),
   modules: new Set([
     "resource:///modules/ContentWebRTC.jsm",
     "resource://gre/modules/InlineSpellChecker.jsm",
     "resource://gre/modules/InlineSpellCheckerContent.jsm",
     "resource://gre/modules/Promise.jsm",
     "resource://gre/modules/Task.jsm",
     "resource://gre/modules/osfile.jsm",
+    "resource://pdf.js/PdfJs.jsm",
+    "resource://pdf.js/PdfStreamConverter.jsm",
   ]),
   services: new Set([
     "@mozilla.org/base/telemetry-startup;1",
     "@mozilla.org/push/Service;1",
   ])
 };
 
 add_task(async function() {
--- a/browser/base/content/test/static/browser_all_files_referenced.js
+++ b/browser/base/content/test/static/browser_all_files_referenced.js
@@ -7,17 +7,16 @@
 
 // Slow on asan builds.
 requestLongerTimeout(5);
 
 var isDevtools = SimpleTest.harnessParameters.subsuite == "devtools";
 
 var gExceptionPaths = [
   "chrome://browser/content/defaultthemes/",
-  "chrome://browser/locale/searchplugins/",
   "resource://app/defaults/settings/blocklists/",
   "resource://app/defaults/settings/main/",
   "resource://app/defaults/settings/pinning/",
   "resource://app/defaults/preferences/",
   "resource://gre/modules/commonjs/",
   "resource://gre/defaults/pref/",
 
   // These resources are referenced using relative paths from html files.
@@ -31,16 +30,19 @@ var gExceptionPaths = [
   "resource://activity-stream/prerendered/",
 
   // browser/extensions/pdfjs/content/build/pdf.js#1999
   "resource://pdf.js/web/images/",
 
   // Exclude all the metadata paths under the country metadata folder because these
   // paths will be concatenated in FormAutofillUtils.jsm based on different country/region.
   "resource://formautofill/addressmetadata/",
+
+  // Exclude all search-plugins because they aren't referenced by filename
+  "resource://search-plugins/",
 ];
 
 // These are not part of the omni.ja file, so we find them only when running
 // the test on a non-packaged build.
 if (AppConstants.platform == "macosx")
   gExceptionPaths.push("resource://gre/res/cursors/");
 
 var whitelist = [
--- a/browser/base/content/test/tabs/browser_multiselect_tabs_using_Ctrl.js
+++ b/browser/base/content/test/tabs/browser_multiselect_tabs_using_Ctrl.js
@@ -1,13 +1,13 @@
 const PREF_MULTISELECT_TABS = "browser.tabs.multiselect";
 
 add_task(async function clickWithoutPrefSet() {
   let tab = await addTab();
-  let mSelectedTabs = gBrowser._multiSelectedTabsMap;
+  let mSelectedTabs = gBrowser._multiSelectedTabsSet;
 
   isnot(gBrowser.selectedTab, tab, "Tab doesn't have focus");
 
   // We make sure that the tab-switch is completely done before executing checks
   await BrowserTestUtils.switchTab(gBrowser, () => {
     triggerClickOn(tab, { ctrlKey: true });
   });
 
@@ -24,17 +24,17 @@ add_task(async function clickWithoutPref
 
 add_task(async function clickWithPrefSet() {
   await SpecialPowers.pushPrefEnv({
     set: [
       [PREF_MULTISELECT_TABS, true]
     ]
   });
 
-  let mSelectedTabs = gBrowser._multiSelectedTabsMap;
+  let mSelectedTabs = gBrowser._multiSelectedTabsSet;
   const initialFocusedTab = gBrowser.selectedTab;
   const tab = await addTab();
 
   await triggerClickOn(tab, { ctrlKey: true });
   ok(tab.multiselected && mSelectedTabs.has(tab), "Tab should be (multi) selected after click");
   isnot(gBrowser.selectedTab, tab, "Multi-selected tab is not focused");
   is(gBrowser.selectedTab, initialFocusedTab, "Focused tab doesn't change");
 
@@ -55,18 +55,18 @@ add_task(async function clearSelection()
   const tab1 = await addTab();
   const tab2 = await addTab();
   const tab3 = await addTab();
 
   info("We multi-select tab1 and tab2 with ctrl key down");
   await triggerClickOn(tab1, { ctrlKey: true });
   await triggerClickOn(tab2, { ctrlKey: true });
 
-  ok(tab1.multiselected && gBrowser._multiSelectedTabsMap.has(tab1), "Tab1 is (multi) selected");
-  ok(tab2.multiselected && gBrowser._multiSelectedTabsMap.has(tab2), "Tab2 is (multi) selected");
+  ok(tab1.multiselected && gBrowser._multiSelectedTabsSet.has(tab1), "Tab1 is (multi) selected");
+  ok(tab2.multiselected && gBrowser._multiSelectedTabsSet.has(tab2), "Tab2 is (multi) selected");
   is(gBrowser.multiSelectedTabsCount, 2, "Two tabs (multi) selected");
   isnot(tab3, gBrowser.selectedTab, "Tab3 doesn't have focus");
 
   info("We select tab3 with Ctrl key up");
   await triggerClickOn(tab3, { ctrlKey: false });
 
   ok(!tab1.multiselected, "Tab1 is not (multi) selected");
   ok(!tab2.multiselected, "Tab2 is not (multi) selected");
--- a/browser/base/content/test/tabs/browser_multiselect_tabs_using_Shift.js
+++ b/browser/base/content/test/tabs/browser_multiselect_tabs_using_Shift.js
@@ -1,16 +1,16 @@
 const PREF_MULTISELECT_TABS = "browser.tabs.multiselect";
 
 add_task(async function prefNotSet() {
     let tab1 = await addTab();
     let tab2 = await addTab();
     let tab3 = await addTab();
 
-    let mSelectedTabs = gBrowser._multiSelectedTabsMap;
+    let mSelectedTabs = gBrowser._multiSelectedTabsSet;
 
     await BrowserTestUtils.switchTab(gBrowser, tab1);
 
     is(gBrowser.selectedTab, tab1, "Tab1 has focus now");
     is(gBrowser.multiSelectedTabsCount, 0, "No tab is mutli-selected");
 
     info("Click on tab3 while holding shift key");
     await BrowserTestUtils.switchTab(gBrowser, () => {
@@ -37,17 +37,17 @@ add_task(async function setPref() {
 });
 
 add_task(async function noItemsInTheCollectionBeforeShiftClicking() {
     let tab1 = await addTab();
     let tab2 = await addTab();
     let tab3 = await addTab();
     let tab4 = await addTab();
     let tab5 = await addTab();
-    let mSelectedTabs = gBrowser._multiSelectedTabsMap;
+    let mSelectedTabs = gBrowser._multiSelectedTabsSet;
 
     await BrowserTestUtils.switchTab(gBrowser, tab1);
 
     is(gBrowser.selectedTab, tab1, "Tab1 has focus now");
     is(gBrowser.multiSelectedTabsCount, 0, "No tab is multi-selected");
 
     gBrowser.hideTab(tab3);
     ok(tab3.hidden, "Tab3 is hidden");
@@ -72,17 +72,17 @@ add_task(async function noItemsInTheColl
 
 add_task(async function itemsInTheCollectionBeforeShiftClicking() {
     let tab1 = await addTab();
     let tab2 = await addTab();
     let tab3 = await addTab();
     let tab4 = await addTab();
     let tab5 = await addTab();
 
-    let mSelectedTabs = gBrowser._multiSelectedTabsMap;
+    let mSelectedTabs = gBrowser._multiSelectedTabsSet;
 
     await BrowserTestUtils.switchTab(gBrowser, () => triggerClickOn(tab1, {}));
 
     is(gBrowser.selectedTab, tab1, "Tab1 has focus now");
     is(gBrowser.multiSelectedTabsCount, 0, "No tab is multi-selected");
 
     await triggerClickOn(tab3, { ctrlKey: true });
     is(gBrowser.selectedTab, tab1, "Tab1 still has focus");
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -112,9 +112,8 @@ browser.jar:
         content/browser/blockedSite.xhtml               (content/blockedSite.xhtml)
 
 % override chrome://global/content/netError.xhtml chrome://browser/content/aboutNetError.xhtml
 
 # L10n resources and overrides.
 % override chrome://global/locale/appstrings.properties chrome://browser/locale/appstrings.properties
 % override chrome://global/locale/netError.dtd chrome://browser/locale/netError.dtd
 % override chrome://mozapps/locale/downloads/settingsChange.dtd chrome://browser/locale/downloads/settingsChange.dtd
-% resource search-plugins chrome://browser/locale/searchplugins/
--- a/browser/components/places/PlacesUIUtils.jsm
+++ b/browser/components/places/PlacesUIUtils.jsm
@@ -206,16 +206,17 @@ let InternalFaviconLoader = {
     let loadDataForWindow = gFaviconLoadDataMap.get(win);
     loadDataForWindow.push(loadData);
   },
 };
 
 var PlacesUIUtils = {
   LOAD_IN_SIDEBAR_ANNO: "bookmarkProperties/loadInSidebar",
   DESCRIPTION_ANNO: "bookmarkProperties/description",
+  LAST_USED_FOLDERS_META_KEY: "bookmarks/lastusedfolders",
 
   /**
    * Makes a URI from a spec, and do fixup
    * @param   aSpec
    *          The string spec of the URI
    * @return A URI object for the spec.
    */
   createFixedURI: function PUIU_createFixedURI(aSpec) {
@@ -1027,17 +1028,17 @@ var PlacesUIUtils = {
 
   setMouseoverURL(url, win) {
     // When the browser window is closed with an open sidebar, the sidebar
     // unload event happens after the browser's one.  In this case
     // top.XULBrowserWindow has been nullified already.
     if (win.top.XULBrowserWindow) {
       win.top.XULBrowserWindow.setOverLink(url, null);
     }
-  }
+  },
 };
 
 // These are lazy getters to avoid importing PlacesUtils immediately.
 XPCOMUtils.defineLazyGetter(PlacesUIUtils, "PLACES_FLAVORS", () => {
   return [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
           PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR,
           PlacesUtils.TYPE_X_MOZ_PLACE];
 });
--- a/browser/components/places/content/editBookmark.js
+++ b/browser/components/places/content/editBookmark.js
@@ -1,15 +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/. */
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
-const LAST_USED_ANNO = "bookmarkPropertiesDialog/folderLastUsed";
 const MAX_FOLDER_ITEM_IN_MENU_LIST = 5;
 
 var gEditItemOverlay = {
   _observersAdded: false,
   _staticFoldersListBuilt: false,
 
   _paneInfo: null,
   _setPaneInfo(aInitInfo) {
@@ -41,33 +40,31 @@ var gEditItemOverlay = {
     let uri = isURI || isTag ? Services.io.newURI(node.uri) : null;
     let title = node ? node.title : null;
     let isBookmark = isItem && isURI;
     let bulkTagging = !node;
     let uris = bulkTagging ? aInitInfo.uris : null;
     let visibleRows = new Set();
     let isParentReadOnly = false;
     let postData = aInitInfo.postData;
-    let parentId = -1;
     let parentGuid = null;
 
     if (node && isItem) {
       if (!node.parent || (node.parent.itemId > 0 && !node.parent.bookmarkGuid)) {
         throw new Error("Cannot use an incomplete node to initialize the edit bookmark panel");
       }
       let parent = node.parent;
       isParentReadOnly = !PlacesUtils.nodeIsFolder(parent);
-      parentId = parent.itemId;
       parentGuid = parent.bookmarkGuid;
     }
 
     let focusedElement = aInitInfo.focusedElement;
     let onPanelReady = aInitInfo.onPanelReady;
 
-    return this._paneInfo = { itemId, itemGuid, parentId, parentGuid, isItem,
+    return this._paneInfo = { itemId, itemGuid, parentGuid, isItem,
                               isURI, uri, title,
                               isBookmark, isFolderShortcut, isParentReadOnly,
                               bulkTagging, uris,
                               visibleRows, postData, isTag, focusedElement,
                               onPanelReady, tag };
   },
 
   get initialized() {
@@ -204,17 +201,17 @@ var gEditItemOverlay = {
       }
     }
 
     // For sanity ensure that the implementer has uninited the panel before
     // trying to init it again, or we could end up leaking due to observers.
     if (this.initialized)
       this.uninitPanel(false);
 
-    let { parentId, isItem, isURI,
+    let { parentGuid, isItem, isURI,
           isBookmark, bulkTagging, uris,
           visibleRows, focusedElement,
           onPanelReady } = this._setPaneInfo(aInfo);
 
     let showOrCollapse =
       (rowId, isAppropriateForInput, nameInHiddenRows = null) => {
         let visible = isAppropriateForInput;
         if (visible && "hiddenRows" in aInfo && nameInHiddenRows)
@@ -253,17 +250,17 @@ var gEditItemOverlay = {
       this._initLoadInSidebar();
     }
 
     // Folder picker.
     // Technically we should check that the item is not moveable, but that's
     // not cheap (we don't always have the parent), and there's no use case for
     // this (it's only the Star UI that shows the folderPicker)
     if (showOrCollapse("folderRow", isItem, "folderPicker")) {
-      this._initFolderMenuList(parentId).catch(Cu.reportError);
+      this._initFolderMenuList(parentGuid).catch(Cu.reportError);
     }
 
     // Selection count.
     if (showOrCollapse("selectionCount", bulkTagging)) {
       this._element("itemsCountText").value =
         PlacesUIUtils.getPluralString("detailsPane.itemsCountLabel",
                                       uris.length,
                                       [uris.length]);
@@ -352,97 +349,84 @@ var gEditItemOverlay = {
       }
     }
   },
 
   /**
    * Appends a menu-item representing a bookmarks folder to a menu-popup.
    * @param aMenupopup
    *        The popup to which the menu-item should be added.
-   * @param aFolderId
+   * @param aFolderGuid
    *        The identifier of the bookmarks folder.
    * @param aTitle
    *        The title to use as a label.
    * @return the new menu item.
    */
-  _appendFolderItemToMenupopup(aMenupopup, aFolderId, aTitle) {
+  _appendFolderItemToMenupopup(aMenupopup, aFolderGuid, aTitle) {
     // First make sure the folders-separator is visible
     this._element("foldersSeparator").hidden = false;
 
     var folderMenuItem = document.createElement("menuitem");
-    var folderTitle = aTitle;
-    folderMenuItem.folderId = aFolderId;
-    folderMenuItem.setAttribute("label", folderTitle);
+    folderMenuItem.folderGuid = aFolderGuid;
+    folderMenuItem.setAttribute("label", aTitle);
     folderMenuItem.className = "menuitem-iconic folder-icon";
     aMenupopup.appendChild(folderMenuItem);
     return folderMenuItem;
   },
 
-  async _initFolderMenuList(aSelectedFolder) {
+  async _initFolderMenuList(aSelectedFolderGuid) {
     // clean up first
     var menupopup = this._folderMenuList.menupopup;
     while (menupopup.childNodes.length > 6)
       menupopup.removeChild(menupopup.lastChild);
 
     // Build the static list
     if (!this._staticFoldersListBuilt) {
       let unfiledItem = this._element("unfiledRootItem");
       unfiledItem.label = PlacesUtils.getString("OtherBookmarksFolderTitle");
-      unfiledItem.folderId = PlacesUtils.unfiledBookmarksFolderId;
+      unfiledItem.folderGuid = PlacesUtils.bookmarks.unfiledGuid;
       let bmMenuItem = this._element("bmRootItem");
       bmMenuItem.label = PlacesUtils.getString("BookmarksMenuFolderTitle");
-      bmMenuItem.folderId = PlacesUtils.bookmarksMenuFolderId;
+      bmMenuItem.folderGuid = PlacesUtils.bookmarks.menuGuid;
       let toolbarItem = this._element("toolbarFolderItem");
       toolbarItem.label = PlacesUtils.getString("BookmarksToolbarFolderTitle");
-      toolbarItem.folderId = PlacesUtils.toolbarFolderId;
+      toolbarItem.folderGuid = PlacesUtils.bookmarks.toolbarGuid;
       this._staticFoldersListBuilt = true;
     }
 
     // List of recently used folders:
-    var folderIds =
-      PlacesUtils.annotations.getItemsWithAnnotation(LAST_USED_ANNO);
+    let lastUsedFolderGuids =
+      await PlacesUtils.metadata.get(PlacesUIUtils.LAST_USED_FOLDERS_META_KEY, []);
 
     /**
-     * The value of the LAST_USED_ANNO annotation is the time (in the form of
-     * Date.getTime) at which the folder has been last used.
+     * The list of last used folders is sorted in most-recent first order.
      *
      * First we build the annotated folders array, each item has both the
      * folder identifier and the time at which it was last-used by this dialog
      * set. Then we sort it descendingly based on the time field.
      */
     this._recentFolders = [];
-    for (let folderId of folderIds) {
-      var lastUsed =
-        PlacesUtils.annotations.getItemAnnotation(folderId, LAST_USED_ANNO);
-      let guid = await PlacesUtils.promiseItemGuid(folderId);
+    for (let guid of lastUsedFolderGuids) {
       let bm = await PlacesUtils.bookmarks.fetch(guid);
-      // Since this could be a root mobile folder, we should get the proper
-      // title.
-      let title = PlacesUtils.bookmarks.getLocalizedTitle(bm);
-      this._recentFolders.push({ folderId, guid, title, lastUsed });
+      if (bm) {
+        let title = PlacesUtils.bookmarks.getLocalizedTitle(bm);
+        this._recentFolders.push({ guid, title });
+      }
     }
-    this._recentFolders.sort(function(a, b) {
-      if (b.lastUsed < a.lastUsed)
-        return -1;
-      if (b.lastUsed > a.lastUsed)
-        return 1;
-      return 0;
-    });
 
     var numberOfItems = Math.min(MAX_FOLDER_ITEM_IN_MENU_LIST,
                                  this._recentFolders.length);
     for (let i = 0; i < numberOfItems; i++) {
       await this._appendFolderItemToMenupopup(menupopup,
-                                              this._recentFolders[i].folderId,
+                                              this._recentFolders[i].guid,
                                               this._recentFolders[i].title);
     }
 
-    let selectedFolderGuid = await PlacesUtils.promiseItemGuid(aSelectedFolder);
-    let title = (await PlacesUtils.bookmarks.fetch(selectedFolderGuid)).title;
-    var defaultItem = this._getFolderMenuItem(aSelectedFolder, title);
+    let title = (await PlacesUtils.bookmarks.fetch(aSelectedFolderGuid)).title;
+    var defaultItem = this._getFolderMenuItem(aSelectedFolderGuid, title);
     this._folderMenuList.selectedItem = defaultItem;
 
     // Set a selectedIndex attribute to show special icons
     this._folderMenuList.setAttribute("selectedIndex",
                                       this._folderMenuList.selectedIndex);
 
     // Hide the folders-separator if no folder is annotated as recently-used
     this._element("foldersSeparator").hidden = (menupopup.childNodes.length <= 6);
@@ -473,16 +457,20 @@ var gEditItemOverlay = {
       PlacesUtils.bookmarks.removeObserver(this);
       this._observersAdded = false;
     }
 
     this._setPaneInfo(null);
     this._firstEditedField = "";
   },
 
+  get selectedFolderGuid() {
+    return this._folderMenuList.selectedItem && this._folderMenuList.selectedItem.folderGuid;
+  },
+
   onTagsFieldChange() {
     // Check for _paneInfo existing as the dialog may be closing but receiving
     // async updates from unresolved promises.
     if (this._paneInfo &&
         (this._paneInfo.isURI || this._paneInfo.bulkTagging)) {
       this._updateTags().then(
         anyChanges => {
           // Check _paneInfo here as we might be closing the dialog.
@@ -690,145 +678,102 @@ var gEditItemOverlay = {
     }
   },
 
   /**
    * Get the corresponding menu-item in the folder-menu-list for a bookmarks
    * folder if such an item exists. Otherwise, this creates a menu-item for the
    * folder. If the items-count limit (see MAX_FOLDERS_IN_MENU_LIST) is reached,
    * the new item replaces the last menu-item.
-   * @param aFolderId
+   * @param aFolderGuid
    *        The identifier of the bookmarks folder.
    * @param aTitle
    *        The title to use in case of menuitem creation.
    * @return handle to the menuitem.
    */
-  _getFolderMenuItem(aFolderId, aTitle) {
+  _getFolderMenuItem(aFolderGuid, aTitle) {
     let menupopup = this._folderMenuList.menupopup;
     let menuItem = Array.prototype.find.call(
-      menupopup.childNodes, item => item.folderId === aFolderId);
+      menupopup.childNodes, item => item.folderGuid === aFolderGuid);
     if (menuItem !== undefined)
       return menuItem;
 
     // 3 special folders + separator + folder-items-count limit
     if (menupopup.childNodes.length == 4 + MAX_FOLDER_ITEM_IN_MENU_LIST)
       menupopup.removeChild(menupopup.lastChild);
 
-    return this._appendFolderItemToMenupopup(menupopup, aFolderId, aTitle);
+    return this._appendFolderItemToMenupopup(menupopup, aFolderGuid, aTitle);
   },
 
   async onFolderMenuListCommand(aEvent) {
     // Check for _paneInfo existing as the dialog may be closing but receiving
     // async updates from unresolved promises.
     if (!this._paneInfo) {
       return;
     }
     // Set a selectedIndex attribute to show special icons
     this._folderMenuList.setAttribute("selectedIndex",
                                       this._folderMenuList.selectedIndex);
 
     if (aEvent.target.id == "editBMPanel_chooseFolderMenuItem") {
       // reset the selection back to where it was and expand the tree
       // (this menu-item is hidden when the tree is already visible
-      let item = this._getFolderMenuItem(this._paneInfo.parentId,
+      let item = this._getFolderMenuItem(this._paneInfo.parentGuid,
                                          this._paneInfo.title);
       this._folderMenuList.selectedItem = item;
       // XXXmano HACK: setTimeout 100, otherwise focus goes back to the
       // menulist right away
       setTimeout(() => this.toggleFolderTreeVisibility(), 100);
       return;
     }
 
     // Move the item
-    let containerId = this._folderMenuList.selectedItem.folderId;
-    if (this._paneInfo.parentId != containerId &&
-        this._paneInfo.itemId != containerId) {
-      let newParentGuid = await PlacesUtils.promiseItemGuid(containerId);
-      let guid = this._paneInfo.itemGuid;
-      await PlacesTransactions.Move({ guid, newParentGuid }).transact();
-
-      // Mark the containing folder as recently-used if it isn't in the
-      // static list
-      if (containerId != PlacesUtils.unfiledBookmarksFolderId &&
-          containerId != PlacesUtils.toolbarFolderId &&
-          containerId != PlacesUtils.bookmarksMenuFolderId) {
-        this._markFolderAsRecentlyUsed(containerId)
-            .catch(Cu.reportError);
-      }
+    let containerGuid = this._folderMenuList.selectedItem.folderGuid;
+    if (this._paneInfo.parentGuid != containerGuid &&
+        this._paneInfo.itemGuid != containerGuid) {
+      await PlacesTransactions.Move({
+        guid: this._paneInfo.itemGuid,
+        newParentGuid: containerGuid
+      }).transact();
 
       // Auto-show the bookmarks toolbar when adding / moving an item there.
-      if (containerId == PlacesUtils.toolbarFolderId) {
+      if (containerGuid == PlacesUtils.bookmarks.toolbarGuid) {
         Services.obs.notifyObservers(null, "autoshow-bookmarks-toolbar");
       }
     }
 
     // Update folder-tree selection
     var folderTreeRow = this._element("folderTreeRow");
     if (!folderTreeRow.collapsed) {
       var selectedNode = this._folderTree.selectedNode;
       if (!selectedNode ||
-          PlacesUtils.getConcreteItemId(selectedNode) != containerId)
-        this._folderTree.selectItems([containerId]);
+          PlacesUtils.getConcreteItemGuid(selectedNode) != containerGuid)
+        this._folderTree.selectItems([containerGuid]);
     }
   },
 
   onFolderTreeSelect() {
     var selectedNode = this._folderTree.selectedNode;
 
     // Disable the "New Folder" button if we cannot create a new folder
     this._element("newFolderButton")
         .disabled = !this._folderTree.insertionPoint || !selectedNode;
 
     if (!selectedNode)
       return;
 
-    var folderId = PlacesUtils.getConcreteItemId(selectedNode);
-    if (this._folderMenuList.selectedItem.folderId == folderId)
+    var folderGuid = PlacesUtils.getConcreteItemGuid(selectedNode);
+    if (this._folderMenuList.selectedItem.folderGuid == folderGuid)
       return;
 
-    var folderItem = this._getFolderMenuItem(folderId, selectedNode.title);
+    var folderItem = this._getFolderMenuItem(folderGuid, selectedNode.title);
     this._folderMenuList.selectedItem = folderItem;
     folderItem.doCommand();
   },
 
-  async _markFolderAsRecentlyUsed(aFolderId) {
-    // Expire old unused recent folders.
-    let guids = [];
-    while (this._recentFolders.length > MAX_FOLDER_ITEM_IN_MENU_LIST) {
-      let folderId = this._recentFolders.pop().folderId;
-      let guid = await PlacesUtils.promiseItemGuid(folderId);
-      guids.push(guid);
-    }
-    if (guids.length > 0) {
-      let annotation = this._getLastUsedAnnotationObject(false);
-      PlacesTransactions.Annotate({ guids, annotation  })
-                        .transact().catch(Cu.reportError);
-    }
-
-    // Mark folder as recently used
-    let annotation = this._getLastUsedAnnotationObject(true);
-    let guid = await PlacesUtils.promiseItemGuid(aFolderId);
-    PlacesTransactions.Annotate({ guid, annotation })
-                      .transact().catch(Cu.reportError);
-  },
-
-  /**
-   * Returns an object which could then be used to set/unset the
-   * LAST_USED_ANNO annotation for a folder.
-   *
-   * @param aLastUsed
-   *        Whether to set or unset the LAST_USED_ANNO annotation.
-   * @returns an object representing the annotation which could then be used
-   *          with the transaction manager.
-   */
-  _getLastUsedAnnotationObject(aLastUsed) {
-    return { name: LAST_USED_ANNO,
-             value: aLastUsed ? new Date().getTime() : null };
-  },
-
   _rebuildTagsSelectorList() {
     let tagsSelector = this._element("tagsSelector");
     let tagsSelectorRow = this._element("tagsSelectorRow");
     if (tagsSelectorRow.collapsed)
       return;
 
     // Save the current scroll position and restore it after the rebuild.
     let firstIndex = tagsSelector.getIndexOfFirstVisibleRow();
@@ -1069,28 +1014,27 @@ var gEditItemOverlay = {
   },
 
   onItemMoved(id, oldParentId, oldIndex, newParentId, newIndex, type, guid,
               oldParentGuid, newParentGuid) {
     if (!this._paneInfo.isItem || this._paneInfo.itemId != id) {
       return;
     }
 
-    this._paneInfo.parentId = newParentId;
     this._paneInfo.parentGuid = newParentGuid;
 
     if (!this._paneInfo.visibleRows.has("folderRow") ||
-        newParentId == this._folderMenuList.selectedItem.folderId) {
+        newParentGuid == this._folderMenuList.selectedItem.folderGuid) {
       return;
     }
 
     // Just setting selectItem _does not_ trigger oncommand, so we don't
     // recurse.
     PlacesUtils.bookmarks.fetch(newParentGuid).then(bm => {
-      this._folderMenuList.selectedItem = this._getFolderMenuItem(newParentId,
+      this._folderMenuList.selectedItem = this._getFolderMenuItem(newParentGuid,
                                                                   bm.title);
     });
   },
 
   onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI) {
     this._lastNewItem = aItemId;
   },
 
--- a/browser/components/places/tests/browser/browser.ini
+++ b/browser/components/places/tests/browser/browser.ini
@@ -30,16 +30,17 @@ support-files =
 [browser_bookmarkProperties_addKeywordForThisSearch.js]
 [browser_bookmarkProperties_addLivemark.js]
 [browser_bookmarkProperties_bookmarkAllTabs.js]
 [browser_bookmarkProperties_cancel.js]
 [browser_bookmarkProperties_editFolder.js]
 [browser_bookmarkProperties_editTagContainer.js]
 [browser_bookmarkProperties_no_user_actions.js]
 [browser_bookmarkProperties_readOnlyRoot.js]
+[browser_bookmarkProperties_remember_folders.js]
 [browser_bookmarksProperties.js]
 [browser_check_correct_controllers.js]
 [browser_click_bookmarks_on_toolbar.js]
 [browser_controller_onDrop_sidebar.js]
 [browser_controller_onDrop_tagFolder.js]
 [browser_controller_onDrop.js]
 [browser_copy_query_without_tree.js]
 subsuite = clipboard
new file mode 100644
--- /dev/null
+++ b/browser/components/places/tests/browser/browser_bookmarkProperties_remember_folders.js
@@ -0,0 +1,156 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+/**
+ * Tests that multiple tags can be added to a bookmark using the star-shaped button, the library and the sidebar.
+ */
+
+const bookmarkPanel = document.getElementById("editBookmarkPanel");
+let folders;
+
+async function clickBookmarkStar() {
+  let shownPromise = promisePopupShown(bookmarkPanel);
+  BookmarkingUI.star.click();
+  await shownPromise;
+}
+
+async function hideBookmarksPanel() {
+  let hiddenPromise = promisePopupHidden(bookmarkPanel);
+  // Confirm and close the dialog.
+  document.getElementById("editBookmarkPanelDoneButton").click();
+  await hiddenPromise;
+}
+
+async function openPopupAndSelectFolder(guid) {
+  await clickBookmarkStar();
+
+  // Expand the folder tree.
+  document.getElementById("editBMPanel_foldersExpander").click();
+  document.getElementById("editBMPanel_folderTree").selectItems([guid]);
+
+  await hideBookmarksPanel();
+  // Ensure the meta data has had chance to be written to disk.
+  await PlacesTestUtils.promiseAsyncUpdates();
+}
+
+async function assertRecentFolders(expectedGuids, msg) {
+  await clickBookmarkStar();
+
+  let actualGuids = [];
+  function getGuids() {
+    const folderMenuPopup = document.getElementById("editBMPanel_folderMenuList").children[0];
+
+    let separatorFound = false;
+    // The list of folders goes from editBMPanel_foldersSeparator to the end.
+    for (let child of folderMenuPopup.children) {
+      if (separatorFound) {
+        actualGuids.push(child.folderGuid);
+      } else if (child.id == "editBMPanel_foldersSeparator") {
+        separatorFound = true;
+      }
+    }
+  }
+
+  await TestUtils.waitForCondition(() => {
+    getGuids();
+    return actualGuids.length == expectedGuids.length;
+  }, msg);
+
+  Assert.deepEqual(actualGuids, expectedGuids, msg);
+
+  await hideBookmarksPanel();
+}
+
+add_task(async function setup() {
+  await PlacesUtils.bookmarks.eraseEverything();
+  await PlacesUtils.metadata.delete(PlacesUIUtils.LAST_USED_FOLDERS_META_KEY);
+
+  bookmarkPanel.setAttribute("animate", false);
+
+  let oldTimeout = StarUI._autoCloseTimeout;
+  // Make the timeout something big, so it doesn't iteract badly with tests.
+  StarUI._autoCloseTimeout = 6000000;
+
+  let tab = await BrowserTestUtils.openNewForegroundTab({
+    gBrowser,
+    opening: "about:robots",
+    waitForStateStop: true
+  });
+
+  folders = await PlacesUtils.bookmarks.insertTree({
+    guid: PlacesUtils.bookmarks.unfiledGuid,
+    children: [{
+      title: "Bob",
+      type: PlacesUtils.bookmarks.TYPE_FOLDER,
+    }, {
+      title: "Place",
+      type: PlacesUtils.bookmarks.TYPE_FOLDER,
+    }, {
+      title: "Delight",
+      type: PlacesUtils.bookmarks.TYPE_FOLDER,
+    }, {
+      title: "Surprise",
+      type: PlacesUtils.bookmarks.TYPE_FOLDER,
+    }, {
+      title: "Treble Bob",
+      type: PlacesUtils.bookmarks.TYPE_FOLDER,
+    }, {
+      title: "Principal",
+      type: PlacesUtils.bookmarks.TYPE_FOLDER,
+    }]
+  });
+
+  registerCleanupFunction(async () => {
+    StarUI._autoCloseTimeout = oldTimeout;
+    BrowserTestUtils.removeTab(tab);
+    bookmarkPanel.removeAttribute("animate");
+    await PlacesUtils.bookmarks.eraseEverything();
+    await PlacesUtils.metadata.delete(PlacesUIUtils.LAST_USED_FOLDERS_META_KEY);
+  });
+});
+
+add_task(async function test_remember_last_folder() {
+  await assertRecentFolders([], "Should have no recent folders to start with.");
+
+  await openPopupAndSelectFolder(folders[0].guid);
+
+  await assertRecentFolders([folders[0].guid], "Should have one folder in the list.");
+});
+
+add_task(async function test_forget_oldest_folder() {
+  // Add some more folders.
+  let expectedFolders = [folders[0].guid];
+  for (let i = 1; i < folders.length; i++) {
+    await assertRecentFolders(expectedFolders,
+      "Should have only the expected folders in the list");
+
+    await openPopupAndSelectFolder(folders[i].guid);
+
+    expectedFolders.unshift(folders[i].guid);
+    if (expectedFolders.length > 5) {
+      expectedFolders.pop();
+    }
+  }
+
+  await assertRecentFolders(expectedFolders,
+    "Should have expired the original folder");
+});
+
+add_task(async function test_reorder_folders() {
+  let expectedFolders = [
+    folders[2].guid,
+    folders[5].guid,
+    folders[4].guid,
+    folders[3].guid,
+    folders[1].guid,
+  ];
+
+  // Take an old one and put it at the front.
+  await openPopupAndSelectFolder(folders[2].guid);
+
+  await assertRecentFolders(expectedFolders,
+    "Should have correctly re-ordered the list");
+});
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -62,16 +62,17 @@
     </content>
 
     <implementation implements="nsIObserver">
       <constructor><![CDATA[
         if (this.parentNode.parentNode.localName == "toolbarpaletteitem")
           return;
 
         Services.obs.addObserver(this, "browser-search-engine-modified");
+        Services.obs.addObserver(this, "browser-search-service");
 
         this._initialized = true;
 
         (window.delayedStartupPromise || Promise.resolve()).then(() => {
           window.requestIdleCallback(() => {
             Services.search.init(aStatus => {
               // Bail out if the binding's been destroyed
               if (!this._initialized)
@@ -109,16 +110,17 @@
       ]]></destructor>
 
       <method name="destroy">
         <body><![CDATA[
         if (this._initialized) {
           this._initialized = false;
 
           Services.obs.removeObserver(this, "browser-search-engine-modified");
+          Services.obs.removeObserver(this, "browser-search-service");
         }
 
         // Make sure to break the cycle from _textbox to us. Otherwise we leak
         // the world. But make sure it's actually pointing to us.
         // Also make sure the textbox has ever been constructed, otherwise the
         // _textbox getter will cause the textbox constructor to run, add an
         // observer, and leak the world too.
         if (this._textboxInitialized && this._textbox.mController.input == this)
@@ -178,17 +180,18 @@
         ]]></body>
       </method>
 
       <method name="observe">
         <parameter name="aEngine"/>
         <parameter name="aTopic"/>
         <parameter name="aVerb"/>
         <body><![CDATA[
-          if (aTopic == "browser-search-engine-modified") {
+          if (aTopic == "browser-search-engine-modified" ||
+              (aTopic == "browser-search-service" && aVerb == "init-complete")) {
             // Make sure the engine list is refetched next time it's needed
             this._engines = null;
 
             // Update the popup header and update the display after any modification.
             this._textbox.popup.updateHeader();
             this.updateDisplay();
           }
         ]]></body>
@@ -1301,16 +1304,17 @@
         menu.addEventListener("popuphidden", aEvent => {
           this._ignoreMouseEvents = false;
           aEvent.stopPropagation();
         });
 
         // Add weak referenced observers to invalidate our cached list of engines.
         Services.prefs.addObserver("browser.search.hiddenOneOffs", this, true);
         Services.obs.addObserver(this, "browser-search-engine-modified", true);
+        Services.obs.addObserver(this, "browser-search-service", true);
 
         // Rebuild the buttons when the theme changes.  See bug 1357800 for
         // details.  Summary: On Linux, switching between themes can cause a row
         // of buttons to disappear.
         Services.obs.addObserver(this, "lightweight-theme-changed", true);
       ]]></constructor>
 
       <!-- This handles events outside the one-off buttons, like on the popup
--- a/browser/components/search/jar.mn
+++ b/browser/components/search/jar.mn
@@ -1,8 +1,12 @@
 # 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/.
 
 browser.jar:
         content/browser/search/search.xml                           (content/search.xml)
         content/browser/search/searchReset.xhtml                    (content/searchReset.xhtml)
         content/browser/search/searchReset.js                       (content/searchReset.js)
+
+        searchplugins/                                              (searchplugins/**)
+
+% resource search-plugins %searchplugins/
rename from browser/locales/searchplugins/allaannonser-sv-SE.xml
rename to browser/components/search/searchplugins/allaannonser-sv-SE.xml
rename from browser/locales/searchplugins/allegro-pl.xml
rename to browser/components/search/searchplugins/allegro-pl.xml
rename from browser/locales/searchplugins/amazon-au.xml
rename to browser/components/search/searchplugins/amazon-au.xml
rename from browser/locales/searchplugins/amazon-br.xml
rename to browser/components/search/searchplugins/amazon-br.xml
rename from browser/locales/searchplugins/amazon-ca.xml
rename to browser/components/search/searchplugins/amazon-ca.xml
rename from browser/locales/searchplugins/amazon-en-GB.xml
rename to browser/components/search/searchplugins/amazon-en-GB.xml
rename from browser/locales/searchplugins/amazon-france.xml
rename to browser/components/search/searchplugins/amazon-france.xml
rename from browser/locales/searchplugins/amazon-in.xml
rename to browser/components/search/searchplugins/amazon-in.xml
rename from browser/locales/searchplugins/amazon-it.xml
rename to browser/components/search/searchplugins/amazon-it.xml
rename from browser/locales/searchplugins/amazon-jp.xml
rename to browser/components/search/searchplugins/amazon-jp.xml
rename from browser/locales/searchplugins/amazon-mx.xml
rename to browser/components/search/searchplugins/amazon-mx.xml
rename from browser/locales/searchplugins/amazon-nl.xml
rename to browser/components/search/searchplugins/amazon-nl.xml
rename from browser/locales/searchplugins/amazondotcn.xml
rename to browser/components/search/searchplugins/amazondotcn.xml
rename from browser/locales/searchplugins/amazondotcom-de.xml
rename to browser/components/search/searchplugins/amazondotcom-de.xml
rename from browser/locales/searchplugins/amazondotcom.xml
rename to browser/components/search/searchplugins/amazondotcom.xml
rename from browser/locales/searchplugins/atlas-sk.xml
rename to browser/components/search/searchplugins/atlas-sk.xml
rename from browser/locales/searchplugins/azerdict.xml
rename to browser/components/search/searchplugins/azerdict.xml
rename from browser/locales/searchplugins/azet-sk.xml
rename to browser/components/search/searchplugins/azet-sk.xml
rename from browser/locales/searchplugins/baidu.xml
rename to browser/components/search/searchplugins/baidu.xml
rename from browser/locales/searchplugins/bbc-alba.xml
rename to browser/components/search/searchplugins/bbc-alba.xml
rename from browser/locales/searchplugins/bing.xml
rename to browser/components/search/searchplugins/bing.xml
rename from browser/locales/searchplugins/bok-NO.xml
rename to browser/components/search/searchplugins/bok-NO.xml
rename from browser/locales/searchplugins/bolcom-fy-NL.xml
rename to browser/components/search/searchplugins/bolcom-fy-NL.xml
rename from browser/locales/searchplugins/bolcom-nl.xml
rename to browser/components/search/searchplugins/bolcom-nl.xml
rename from browser/locales/searchplugins/bookplus-fi.xml
rename to browser/components/search/searchplugins/bookplus-fi.xml
rename from browser/locales/searchplugins/buscape.xml
rename to browser/components/search/searchplugins/buscape.xml
rename from browser/locales/searchplugins/ceneji.xml
rename to browser/components/search/searchplugins/ceneji.xml
rename from browser/locales/searchplugins/chambers-en-GB.xml
rename to browser/components/search/searchplugins/chambers-en-GB.xml
rename from browser/locales/searchplugins/cnrtl-tlfi-fr.xml
rename to browser/components/search/searchplugins/cnrtl-tlfi-fr.xml
rename from browser/locales/searchplugins/coccoc.xml
rename to browser/components/search/searchplugins/coccoc.xml
rename from browser/locales/searchplugins/danawa-kr.xml
rename to browser/components/search/searchplugins/danawa-kr.xml
rename from browser/locales/searchplugins/daum-kr.xml
rename to browser/components/search/searchplugins/daum-kr.xml
rename from browser/locales/searchplugins/ddg.xml
rename to browser/components/search/searchplugins/ddg.xml
rename from browser/locales/searchplugins/diccionariu-alla.xml
rename to browser/components/search/searchplugins/diccionariu-alla.xml
rename from browser/locales/searchplugins/dict-enlv.xml
rename to browser/components/search/searchplugins/dict-enlv.xml
rename from browser/locales/searchplugins/diec2.xml
rename to browser/components/search/searchplugins/diec2.xml
rename from browser/locales/searchplugins/drae.xml
rename to browser/components/search/searchplugins/drae.xml
rename from browser/locales/searchplugins/ebay-at.xml
rename to browser/components/search/searchplugins/ebay-at.xml
rename from browser/locales/searchplugins/ebay-au.xml
rename to browser/components/search/searchplugins/ebay-au.xml
rename from browser/locales/searchplugins/ebay-be.xml
rename to browser/components/search/searchplugins/ebay-be.xml
rename from browser/locales/searchplugins/ebay-ca.xml
rename to browser/components/search/searchplugins/ebay-ca.xml
rename from browser/locales/searchplugins/ebay-ch.xml
rename to browser/components/search/searchplugins/ebay-ch.xml
rename from browser/locales/searchplugins/ebay-de.xml
rename to browser/components/search/searchplugins/ebay-de.xml
rename from browser/locales/searchplugins/ebay-es.xml
rename to browser/components/search/searchplugins/ebay-es.xml
rename from browser/locales/searchplugins/ebay-fr.xml
rename to browser/components/search/searchplugins/ebay-fr.xml
rename from browser/locales/searchplugins/ebay-ie.xml
rename to browser/components/search/searchplugins/ebay-ie.xml
rename from browser/locales/searchplugins/ebay-it.xml
rename to browser/components/search/searchplugins/ebay-it.xml
rename from browser/locales/searchplugins/ebay-nl.xml
rename to browser/components/search/searchplugins/ebay-nl.xml
rename from browser/locales/searchplugins/ebay-uk.xml
rename to browser/components/search/searchplugins/ebay-uk.xml
rename from browser/locales/searchplugins/ebay.xml
rename to browser/components/search/searchplugins/ebay.xml
rename from browser/locales/searchplugins/ecosia.xml
rename to browser/components/search/searchplugins/ecosia.xml
rename from browser/locales/searchplugins/eki-ee.xml
rename to browser/components/search/searchplugins/eki-ee.xml
rename from browser/locales/searchplugins/elebila.xml
rename to browser/components/search/searchplugins/elebila.xml
rename from browser/locales/searchplugins/eudict.xml
rename to browser/components/search/searchplugins/eudict.xml
rename from browser/locales/searchplugins/faclair-beag.xml
rename to browser/components/search/searchplugins/faclair-beag.xml
rename from browser/locales/searchplugins/flip.xml
rename to browser/components/search/searchplugins/flip.xml
rename from browser/locales/searchplugins/freelang.xml
rename to browser/components/search/searchplugins/freelang.xml
rename from browser/locales/searchplugins/google-2018.xml
rename to browser/components/search/searchplugins/google-2018.xml
rename from browser/locales/searchplugins/google.xml
rename to browser/components/search/searchplugins/google.xml
rename from browser/locales/searchplugins/gujaratilexicon.xml
rename to browser/components/search/searchplugins/gujaratilexicon.xml
rename from browser/locales/searchplugins/gulesider-NO.xml
rename to browser/components/search/searchplugins/gulesider-NO.xml
rename from browser/locales/searchplugins/heureka-cz.xml
rename to browser/components/search/searchplugins/heureka-cz.xml
rename from browser/locales/searchplugins/hoepli.xml
rename to browser/components/search/searchplugins/hoepli.xml
rename from browser/locales/searchplugins/hotline-ua.xml
rename to browser/components/search/searchplugins/hotline-ua.xml
rename from browser/locales/searchplugins/images/amazon.ico
rename to browser/components/search/searchplugins/images/amazon.ico
rename from browser/locales/searchplugins/images/ebay.ico
rename to browser/components/search/searchplugins/images/ebay.ico
rename from browser/locales/searchplugins/images/wikipedia.ico
rename to browser/components/search/searchplugins/images/wikipedia.ico
rename from browser/locales/searchplugins/images/yandex-en.ico
rename to browser/components/search/searchplugins/images/yandex-en.ico
rename from browser/locales/searchplugins/images/yandex-ru.ico
rename to browser/components/search/searchplugins/images/yandex-ru.ico
rename from browser/locales/searchplugins/kannadastore.xml
rename to browser/components/search/searchplugins/kannadastore.xml
rename from browser/locales/searchplugins/kaz-kk.xml
rename to browser/components/search/searchplugins/kaz-kk.xml
rename from browser/locales/searchplugins/klask.xml
rename to browser/components/search/searchplugins/klask.xml
rename from browser/locales/searchplugins/leit-is.xml
rename to browser/components/search/searchplugins/leit-is.xml
rename from browser/locales/searchplugins/leo_ende_de-rm.xml
rename to browser/components/search/searchplugins/leo_ende_de-rm.xml
rename from browser/locales/searchplugins/leo_ende_de.xml
rename to browser/components/search/searchplugins/leo_ende_de.xml
rename from browser/locales/searchplugins/list-am.xml
rename to browser/components/search/searchplugins/list-am.xml
rename from browser/locales/search/list.json
rename to browser/components/search/searchplugins/list.json
rename from browser/locales/searchplugins/longdo.xml
rename to browser/components/search/searchplugins/longdo.xml
rename from browser/locales/searchplugins/mailru.xml
rename to browser/components/search/searchplugins/mailru.xml
rename from browser/locales/searchplugins/mapy-cz.xml
rename to browser/components/search/searchplugins/mapy-cz.xml
rename from browser/locales/searchplugins/marktplaats-fy-NL.xml
rename to browser/components/search/searchplugins/marktplaats-fy-NL.xml
rename from browser/locales/searchplugins/marktplaats-nl.xml
rename to browser/components/search/searchplugins/marktplaats-nl.xml
rename from browser/locales/searchplugins/mercadolibre-ar.xml
rename to browser/components/search/searchplugins/mercadolibre-ar.xml
rename from browser/locales/searchplugins/mercadolibre-cl.xml
rename to browser/components/search/searchplugins/mercadolibre-cl.xml
rename from browser/locales/searchplugins/mercadolibre-mx.xml
rename to browser/components/search/searchplugins/mercadolibre-mx.xml
rename from browser/locales/searchplugins/mercadolivre.xml
rename to browser/components/search/searchplugins/mercadolivre.xml
rename from browser/locales/searchplugins/meta-ua.xml
rename to browser/components/search/searchplugins/meta-ua.xml
rename from browser/locales/searchplugins/morfix-dic.xml
rename to browser/components/search/searchplugins/morfix-dic.xml
rename from browser/locales/searchplugins/najdi-si.xml
rename to browser/components/search/searchplugins/najdi-si.xml
rename from browser/locales/searchplugins/naver-kr.xml
rename to browser/components/search/searchplugins/naver-kr.xml
rename from browser/locales/searchplugins/neti-ee.xml
rename to browser/components/search/searchplugins/neti-ee.xml
rename from browser/locales/searchplugins/odpiralni.xml
rename to browser/components/search/searchplugins/odpiralni.xml
rename from browser/locales/searchplugins/olx.xml
rename to browser/components/search/searchplugins/olx.xml
rename from browser/locales/searchplugins/oshiete-goo.xml
rename to browser/components/search/searchplugins/oshiete-goo.xml
rename from browser/locales/searchplugins/osta-ee.xml
rename to browser/components/search/searchplugins/osta-ee.xml
rename from browser/locales/searchplugins/ozonru.xml
rename to browser/components/search/searchplugins/ozonru.xml
rename from browser/locales/searchplugins/palasprint.xml
rename to browser/components/search/searchplugins/palasprint.xml
rename from browser/locales/searchplugins/paroledigenova-lij.xml
rename to browser/components/search/searchplugins/paroledigenova-lij.xml
rename from browser/locales/searchplugins/pazaruvaj.xml
rename to browser/components/search/searchplugins/pazaruvaj.xml
rename from browser/locales/searchplugins/pledarigrond.xml
rename to browser/components/search/searchplugins/pledarigrond.xml
rename from browser/locales/searchplugins/pogodak.xml
rename to browser/components/search/searchplugins/pogodak.xml
rename from browser/locales/searchplugins/portalbgdict.xml
rename to browser/components/search/searchplugins/portalbgdict.xml
rename from browser/locales/searchplugins/priberam.xml
rename to browser/components/search/searchplugins/priberam.xml
rename from browser/locales/searchplugins/priceru.xml
rename to browser/components/search/searchplugins/priceru.xml
rename from browser/locales/searchplugins/prisjakt-sv-SE.xml
rename to browser/components/search/searchplugins/prisjakt-sv-SE.xml
rename from browser/locales/searchplugins/pwn-pl.xml
rename to browser/components/search/searchplugins/pwn-pl.xml
rename from browser/locales/searchplugins/qwant.xml
rename to browser/components/search/searchplugins/qwant.xml
rename from browser/locales/searchplugins/qxl-NO.xml
rename to browser/components/search/searchplugins/qxl-NO.xml
rename from browser/locales/searchplugins/rakuten.xml
rename to browser/components/search/searchplugins/rakuten.xml
rename from browser/locales/searchplugins/readmoo.xml
rename to browser/components/search/searchplugins/readmoo.xml
rename from browser/locales/searchplugins/rediff.xml
rename to browser/components/search/searchplugins/rediff.xml
rename from browser/locales/searchplugins/reta-vortaro.xml
rename to browser/components/search/searchplugins/reta-vortaro.xml
rename from browser/locales/searchplugins/salidzinilv.xml
rename to browser/components/search/searchplugins/salidzinilv.xml
rename from browser/locales/searchplugins/sapo.xml
rename to browser/components/search/searchplugins/sapo.xml
rename from browser/locales/searchplugins/seznam-cz.xml
rename to browser/components/search/searchplugins/seznam-cz.xml
rename from browser/locales/searchplugins/slovnik-sk.xml
rename to browser/components/search/searchplugins/slovnik-sk.xml
rename from browser/locales/searchplugins/sslv.xml
rename to browser/components/search/searchplugins/sslv.xml
rename from browser/locales/searchplugins/sztaki-en-hu.xml
rename to browser/components/search/searchplugins/sztaki-en-hu.xml
rename from browser/locales/searchplugins/tearma.xml
rename to browser/components/search/searchplugins/tearma.xml
rename from browser/locales/searchplugins/termau.xml
rename to browser/components/search/searchplugins/termau.xml
rename from browser/locales/searchplugins/twitter-ja.xml
rename to browser/components/search/searchplugins/twitter-ja.xml
rename from browser/locales/searchplugins/twitter.xml
rename to browser/components/search/searchplugins/twitter.xml
rename from browser/locales/searchplugins/tyda-sv-SE.xml
rename to browser/components/search/searchplugins/tyda-sv-SE.xml
rename from browser/locales/searchplugins/vatera.xml
rename to browser/components/search/searchplugins/vatera.xml
rename from browser/locales/searchplugins/webdunia.xml
rename to browser/components/search/searchplugins/webdunia.xml
rename from browser/locales/searchplugins/wikipedia-NN.xml
rename to browser/components/search/searchplugins/wikipedia-NN.xml
rename from browser/locales/searchplugins/wikipedia-NO.xml
rename to browser/components/search/searchplugins/wikipedia-NO.xml
rename from browser/locales/searchplugins/wikipedia-af.xml
rename to browser/components/search/searchplugins/wikipedia-af.xml
rename from browser/locales/searchplugins/wikipedia-an.xml
rename to browser/components/search/searchplugins/wikipedia-an.xml
rename from browser/locales/searchplugins/wikipedia-ar.xml
rename to browser/components/search/searchplugins/wikipedia-ar.xml
rename from browser/locales/searchplugins/wikipedia-as.xml
rename to browser/components/search/searchplugins/wikipedia-as.xml
rename from browser/locales/searchplugins/wikipedia-ast.xml
rename to browser/components/search/searchplugins/wikipedia-ast.xml
rename from browser/locales/searchplugins/wikipedia-az.xml
rename to browser/components/search/searchplugins/wikipedia-az.xml
rename from browser/locales/searchplugins/wikipedia-be-tarask.xml
rename to browser/components/search/searchplugins/wikipedia-be-tarask.xml
rename from browser/locales/searchplugins/wikipedia-be.xml
rename to browser/components/search/searchplugins/wikipedia-be.xml
rename from browser/locales/searchplugins/wikipedia-bg.xml
rename to browser/components/search/searchplugins/wikipedia-bg.xml
rename from browser/locales/searchplugins/wikipedia-bn.xml
rename to browser/components/search/searchplugins/wikipedia-bn.xml
rename from browser/locales/searchplugins/wikipedia-br.xml
rename to browser/components/search/searchplugins/wikipedia-br.xml
rename from browser/locales/searchplugins/wikipedia-bs.xml
rename to browser/components/search/searchplugins/wikipedia-bs.xml
rename from browser/locales/searchplugins/wikipedia-ca.xml
rename to browser/components/search/searchplugins/wikipedia-ca.xml
rename from browser/locales/searchplugins/wikipedia-crh.xml
rename to browser/components/search/searchplugins/wikipedia-crh.xml
rename from browser/locales/searchplugins/wikipedia-cy.xml
rename to browser/components/search/searchplugins/wikipedia-cy.xml
rename from browser/locales/searchplugins/wikipedia-cz.xml
rename to browser/components/search/searchplugins/wikipedia-cz.xml
rename from browser/locales/searchplugins/wikipedia-da.xml
rename to browser/components/search/searchplugins/wikipedia-da.xml
rename from browser/locales/searchplugins/wikipedia-de.xml
rename to browser/components/search/searchplugins/wikipedia-de.xml
rename from browser/locales/searchplugins/wikipedia-dsb.xml
rename to browser/components/search/searchplugins/wikipedia-dsb.xml
rename from browser/locales/searchplugins/wikipedia-el.xml
rename to browser/components/search/searchplugins/wikipedia-el.xml
rename from browser/locales/searchplugins/wikipedia-eo.xml
rename to browser/components/search/searchplugins/wikipedia-eo.xml
rename from browser/locales/searchplugins/wikipedia-es.xml
rename to browser/components/search/searchplugins/wikipedia-es.xml
rename from browser/locales/searchplugins/wikipedia-et.xml
rename to browser/components/search/searchplugins/wikipedia-et.xml
rename from browser/locales/searchplugins/wikipedia-eu.xml
rename to browser/components/search/searchplugins/wikipedia-eu.xml
rename from browser/locales/searchplugins/wikipedia-fa.xml
rename to browser/components/search/searchplugins/wikipedia-fa.xml
rename from browser/locales/searchplugins/wikipedia-fi.xml
rename to browser/components/search/searchplugins/wikipedia-fi.xml
rename from browser/locales/searchplugins/wikipedia-fr.xml
rename to browser/components/search/searchplugins/wikipedia-fr.xml
rename from browser/locales/searchplugins/wikipedia-fy-NL.xml
rename to browser/components/search/searchplugins/wikipedia-fy-NL.xml
rename from browser/locales/searchplugins/wikipedia-ga-IE.xml
rename to browser/components/search/searchplugins/wikipedia-ga-IE.xml
rename from browser/locales/searchplugins/wikipedia-gd.xml
rename to browser/components/search/searchplugins/wikipedia-gd.xml
rename from browser/locales/searchplugins/wikipedia-gl.xml
rename to browser/components/search/searchplugins/wikipedia-gl.xml
rename from browser/locales/searchplugins/wikipedia-gn.xml
rename to browser/components/search/searchplugins/wikipedia-gn.xml
rename from browser/locales/searchplugins/wikipedia-gu.xml
rename to browser/components/search/searchplugins/wikipedia-gu.xml
rename from browser/locales/searchplugins/wikipedia-he.xml
rename to browser/components/search/searchplugins/wikipedia-he.xml
rename from browser/locales/searchplugins/wikipedia-hi.xml
rename to browser/components/search/searchplugins/wikipedia-hi.xml
rename from browser/locales/searchplugins/wikipedia-hr.xml
rename to browser/components/search/searchplugins/wikipedia-hr.xml
rename from browser/locales/searchplugins/wikipedia-hsb.xml
rename to browser/components/search/searchplugins/wikipedia-hsb.xml
rename from browser/locales/searchplugins/wikipedia-hu.xml
rename to browser/components/search/searchplugins/wikipedia-hu.xml
rename from browser/locales/searchplugins/wikipedia-hy.xml
rename to browser/components/search/searchplugins/wikipedia-hy.xml
rename from browser/locales/searchplugins/wikipedia-ia.xml
rename to browser/components/search/searchplugins/wikipedia-ia.xml
rename from browser/locales/searchplugins/wikipedia-id.xml
rename to browser/components/search/searchplugins/wikipedia-id.xml
rename from browser/locales/searchplugins/wikipedia-is.xml
rename to browser/components/search/searchplugins/wikipedia-is.xml
rename from browser/locales/searchplugins/wikipedia-it.xml
rename to browser/components/search/searchplugins/wikipedia-it.xml
rename from browser/locales/searchplugins/wikipedia-ja.xml
rename to browser/components/search/searchplugins/wikipedia-ja.xml
rename from browser/locales/searchplugins/wikipedia-ka.xml
rename to browser/components/search/searchplugins/wikipedia-ka.xml
rename from browser/locales/searchplugins/wikipedia-kab.xml
rename to browser/components/search/searchplugins/wikipedia-kab.xml
rename from browser/locales/searchplugins/wikipedia-kk.xml
rename to browser/components/search/searchplugins/wikipedia-kk.xml
rename from browser/locales/searchplugins/wikipedia-km.xml
rename to browser/components/search/searchplugins/wikipedia-km.xml
rename from browser/locales/searchplugins/wikipedia-kn.xml
rename to browser/components/search/searchplugins/wikipedia-kn.xml
rename from browser/locales/searchplugins/wikipedia-kr.xml
rename to browser/components/search/searchplugins/wikipedia-kr.xml
rename from browser/locales/searchplugins/wikipedia-lij.xml
rename to browser/components/search/searchplugins/wikipedia-lij.xml
rename from browser/locales/searchplugins/wikipedia-lo.xml
rename to browser/components/search/searchplugins/wikipedia-lo.xml
rename from browser/locales/searchplugins/wikipedia-lt.xml
rename to browser/components/search/searchplugins/wikipedia-lt.xml
rename from browser/locales/searchplugins/wikipedia-ltg.xml
rename to browser/components/search/searchplugins/wikipedia-ltg.xml
rename from browser/locales/searchplugins/wikipedia-lv.xml
rename to browser/components/search/searchplugins/wikipedia-lv.xml
rename from browser/locales/searchplugins/wikipedia-mk.xml
rename to browser/components/search/searchplugins/wikipedia-mk.xml
rename from browser/locales/searchplugins/wikipedia-ml.xml
rename to browser/components/search/searchplugins/wikipedia-ml.xml
rename from browser/locales/searchplugins/wikipedia-mr.xml
rename to browser/components/search/searchplugins/wikipedia-mr.xml
rename from browser/locales/searchplugins/wikipedia-ms.xml
rename to browser/components/search/searchplugins/wikipedia-ms.xml
rename from browser/locales/searchplugins/wikipedia-my.xml
rename to browser/components/search/searchplugins/wikipedia-my.xml
rename from browser/locales/searchplugins/wikipedia-ne.xml
rename to browser/components/search/searchplugins/wikipedia-ne.xml
rename from browser/locales/searchplugins/wikipedia-nl.xml
rename to browser/components/search/searchplugins/wikipedia-nl.xml
rename from browser/locales/searchplugins/wikipedia-oc.xml
rename to browser/components/search/searchplugins/wikipedia-oc.xml
rename from browser/locales/searchplugins/wikipedia-or.xml
rename to browser/components/search/searchplugins/wikipedia-or.xml
rename from browser/locales/searchplugins/wikipedia-pa.xml
rename to browser/components/search/searchplugins/wikipedia-pa.xml
rename from browser/locales/searchplugins/wikipedia-pl.xml
rename to browser/components/search/searchplugins/wikipedia-pl.xml
rename from browser/locales/searchplugins/wikipedia-pt.xml
rename to browser/components/search/searchplugins/wikipedia-pt.xml
rename from browser/locales/searchplugins/wikipedia-rm.xml
rename to browser/components/search/searchplugins/wikipedia-rm.xml
rename from browser/locales/searchplugins/wikipedia-ro.xml
rename to browser/components/search/searchplugins/wikipedia-ro.xml
rename from browser/locales/searchplugins/wikipedia-ru.xml
rename to browser/components/search/searchplugins/wikipedia-ru.xml
rename from browser/locales/searchplugins/wikipedia-si.xml
rename to browser/components/search/searchplugins/wikipedia-si.xml
rename from browser/locales/searchplugins/wikipedia-sk.xml
rename to browser/components/search/searchplugins/wikipedia-sk.xml
rename from browser/locales/searchplugins/wikipedia-sl.xml
rename to browser/components/search/searchplugins/wikipedia-sl.xml
rename from browser/locales/searchplugins/wikipedia-sq.xml
rename to browser/components/search/searchplugins/wikipedia-sq.xml
rename from browser/locales/searchplugins/wikipedia-sr.xml
rename to browser/components/search/searchplugins/wikipedia-sr.xml
rename from browser/locales/searchplugins/wikipedia-sv-SE.xml
rename to browser/components/search/searchplugins/wikipedia-sv-SE.xml
rename from browser/locales/searchplugins/wikipedia-ta.xml
rename to browser/components/search/searchplugins/wikipedia-ta.xml
rename from browser/locales/searchplugins/wikipedia-te.xml
rename to browser/components/search/searchplugins/wikipedia-te.xml
rename from browser/locales/searchplugins/wikipedia-th.xml
rename to browser/components/search/searchplugins/wikipedia-th.xml
rename from browser/locales/searchplugins/wikipedia-tl.xml
rename to browser/components/search/searchplugins/wikipedia-tl.xml
rename from browser/locales/searchplugins/wikipedia-tr.xml
rename to browser/components/search/searchplugins/wikipedia-tr.xml
rename from browser/locales/searchplugins/wikipedia-uk.xml
rename to browser/components/search/searchplugins/wikipedia-uk.xml
rename from browser/locales/searchplugins/wikipedia-ur.xml
rename to browser/components/search/searchplugins/wikipedia-ur.xml
rename from browser/locales/searchplugins/wikipedia-uz.xml
rename to browser/components/search/searchplugins/wikipedia-uz.xml
rename from browser/locales/searchplugins/wikipedia-vi.xml
rename to browser/components/search/searchplugins/wikipedia-vi.xml
rename from browser/locales/searchplugins/wikipedia-wo.xml
rename to browser/components/search/searchplugins/wikipedia-wo.xml
rename from browser/locales/searchplugins/wikipedia-zh-CN.xml
rename to browser/components/search/searchplugins/wikipedia-zh-CN.xml
rename from browser/locales/searchplugins/wikipedia-zh-TW.xml
rename to browser/components/search/searchplugins/wikipedia-zh-TW.xml
rename from browser/locales/searchplugins/wikipedia.xml
rename to browser/components/search/searchplugins/wikipedia.xml
rename from browser/locales/searchplugins/wiktionary-oc.xml
rename to browser/components/search/searchplugins/wiktionary-oc.xml
rename from browser/locales/searchplugins/wiktionary-te.xml
rename to browser/components/search/searchplugins/wiktionary-te.xml
rename from browser/locales/searchplugins/wolnelektury-pl.xml
rename to browser/components/search/searchplugins/wolnelektury-pl.xml
rename from browser/locales/searchplugins/yahoo-jp-auctions.xml
rename to browser/components/search/searchplugins/yahoo-jp-auctions.xml
rename from browser/locales/searchplugins/yahoo-jp.xml
rename to browser/components/search/searchplugins/yahoo-jp.xml
rename from browser/locales/searchplugins/yandex-az.xml
rename to browser/components/search/searchplugins/yandex-az.xml
rename from browser/locales/searchplugins/yandex-by.xml
rename to browser/components/search/searchplugins/yandex-by.xml
rename from browser/locales/searchplugins/yandex-en.xml
rename to browser/components/search/searchplugins/yandex-en.xml
rename from browser/locales/searchplugins/yandex-kk.xml
rename to browser/components/search/searchplugins/yandex-kk.xml
rename from browser/locales/searchplugins/yandex-ru.xml
rename to browser/components/search/searchplugins/yandex-ru.xml
rename from browser/locales/searchplugins/yandex-tr.xml
rename to browser/components/search/searchplugins/yandex-tr.xml
rename from browser/locales/searchplugins/zoznam-sk.xml
rename to browser/components/search/searchplugins/zoznam-sk.xml
--- a/browser/components/search/test/browser.ini
+++ b/browser/components/search/test/browser.ini
@@ -19,21 +19,18 @@ support-files =
 [browser_addEngine.js]
 [browser_amazon.js]
 [browser_bing.js]
 [browser_contextmenu.js]
 [browser_contextSearchTabPosition.js]
 skip-if = os == "mac" # bug 967013
 [browser_ddg.js]
 [browser_eBay.js]
-skip-if = artifact # bug 1315953
 [browser_google.js]
-skip-if = artifact # bug 1315953
 [browser_google_behavior.js]
-skip-if = artifact # bug 1315953
 [browser_healthreport.js]
 [browser_hiddenOneOffs_cleanup.js]
 [browser_hiddenOneOffs_diacritics.js]
 [browser_oneOffContextMenu.js]
 [browser_oneOffContextMenu_setDefault.js]
 [browser_oneOffHeader.js]
 skip-if = os == "mac" #1421238
 [browser_private_search_perwindowpb.js]
--- a/browser/components/syncedtabs/SyncedTabsDeckComponent.js
+++ b/browser/components/syncedtabs/SyncedTabsDeckComponent.js
@@ -74,16 +74,21 @@ SyncedTabsDeckComponent.prototype = {
     Services.obs.addObserver(this, FxAccountsCommon.ONLOGIN_NOTIFICATION);
     Services.obs.addObserver(this, "weave:service:login:change");
     // If the Sync service is not ready, in init() > updatePanel() we will
     // show a blank screen. If tab syncing is disabled, we will not get any other
     // ui-refreshing notifications! We listen to :ready in order to check again
     // if this engine is disabled and refresh the UI one last time.
     Services.obs.addObserver(this, "weave:service:ready");
 
+    // Add app locale change support for HTML sidebar
+    Services.obs.addObserver(this, "intl:app-locales-changed");
+    Services.prefs.addObserver("intl.uidirection", this);
+    this.updateDir();
+
     // Go ahead and trigger sync
     this._SyncedTabs.syncTabs()
                     .catch(Cu.reportError);
 
     this._deckView = new this._DeckView(this._window, this.tabListComponent, {
       onConnectDeviceClick: event => this.openConnectDevice(event),
       onSyncPrefClick: event => this.openSyncPrefs(event)
     });
@@ -96,32 +101,42 @@ SyncedTabsDeckComponent.prototype = {
     this.updatePanel();
   },
 
   uninit() {
     Services.obs.removeObserver(this, this._SyncedTabs.TOPIC_TABS_CHANGED);
     Services.obs.removeObserver(this, FxAccountsCommon.ONLOGIN_NOTIFICATION);
     Services.obs.removeObserver(this, "weave:service:login:change");
     Services.obs.removeObserver(this, "weave:service:ready");
+    Services.obs.removeObserver(this, "intl:app-locales-changed");
+    Services.prefs.removeObserver("intl.uidirection", this);
     this._deckView.destroy();
   },
 
   observe(subject, topic, data) {
     switch (topic) {
       case this._SyncedTabs.TOPIC_TABS_CHANGED:
         this._syncedTabsListStore.getData();
         this.updatePanel();
         break;
       case "weave:service:ready":
         Services.obs.removeObserver(this, "weave:service:ready");
         // Intended fallthrough.
       case FxAccountsCommon.ONLOGIN_NOTIFICATION:
       case "weave:service:login:change":
         this.updatePanel();
         break;
+      case "intl:app-locales-changed":
+        this.updateDir();
+        break;
+      case "nsPref:changed":
+        if (data == "intl.uidirection") {
+          this.updateDir();
+        }
+        break;
       default:
         break;
     }
   },
 
   // There's no good way to mock fxAccounts in browser tests where it's already
   // been instantiated, so we have this method for stubbing.
   _getSignedInUser() {
@@ -153,16 +168,27 @@ SyncedTabsDeckComponent.prototype = {
       });
     })
     .catch(err => {
       Cu.reportError(err);
       return this.PANELS.NOT_AUTHED_INFO;
     });
   },
 
+  updateDir() {
+    // If the HTML document doesn't exist, we can't update the window
+    if (!this._window.document) return;
+
+    if (Services.locale.isAppLocaleRTL) {
+      this._window.document.body.dir = "rtl";
+    } else {
+      this._window.document.body.dir = "ltr";
+    }
+  },
+
   updatePanel() {
     // return promise for tests
     return this.getPanelStatus()
       .then(panelId => this._deckStore.selectPanel(panelId))
       .catch(Cu.reportError);
   },
 
   openSyncPrefs() {
--- a/browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js
+++ b/browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js
@@ -89,30 +89,32 @@ add_task(async function testObserver() {
   sinon.stub(SyncedTabs, "syncTabs", () => Promise.resolve());
 
   sinon.spy(deckStore, "on");
   sinon.stub(deckStore, "setPanels");
 
   sinon.stub(listStore, "getData");
 
   let component = new SyncedTabsDeckComponent({
-    mockWindow,
+    window: mockWindow,
     deckStore,
     listStore,
     listComponent,
     SyncedTabs,
     DeckView: ViewMock,
   });
 
   sinon.spy(component, "observe");
   sinon.stub(component, "updatePanel");
+  sinon.stub(component, "updateDir");
 
   component.init();
   SyncedTabs.syncTabs.restore();
   Assert.ok(component.updatePanel.called, "triggers panel update during init");
+  Assert.ok(component.updateDir.called, "triggers UI direction update during init");
 
   Services.obs.notifyObservers(null, SyncedTabs.TOPIC_TABS_CHANGED);
 
   Assert.ok(component.observe.calledWith(null, SyncedTabs.TOPIC_TABS_CHANGED),
     "component is notified");
 
   Assert.ok(listStore.getData.called, "gets list data");
   Assert.ok(component.updatePanel.calledTwice, "triggers panel update");
@@ -123,16 +125,25 @@ add_task(async function testObserver() {
     "component is notified of login");
   Assert.equal(component.updatePanel.callCount, 3, "triggers panel update again");
 
   Services.obs.notifyObservers(null, "weave:service:login:change");
 
   Assert.ok(component.observe.calledWith(null, "weave:service:login:change"),
     "component is notified of login change");
   Assert.equal(component.updatePanel.callCount, 4, "triggers panel update again");
+
+  Services.locale.setAvailableLocales(["ab-CD"]);
+  Services.locale.setRequestedLocales(["ab-CD"]);
+
+  Assert.ok(component.updateDir.calledTwice, "locale change triggers UI direction update");
+
+  Services.prefs.setIntPref("intl.uidirection", 1);
+
+  Assert.equal(component.updateDir.callCount, 3, "pref change triggers UI direction update");
 });
 
 add_task(async function testPanelStatus() {
   let deckStore = new SyncedTabsDeckStore();
   let listStore = new SyncedTabsListStore();
   let listComponent = {};
   let fxAccounts = {
     getSignedInUser() {}
--- a/browser/extensions/pdfjs/content/PdfJs.jsm
+++ b/browser/extensions/pdfjs/content/PdfJs.jsm
@@ -12,18 +12,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["PdfJs"];
 
-const Cm = Components.manager;
-
 const PREF_PREFIX = "pdfjs";
 const PREF_DISABLED = PREF_PREFIX + ".disabled";
 const PREF_MIGRATION_VERSION = PREF_PREFIX + ".migrationVersion";
 const PREF_PREVIOUS_ACTION = PREF_PREFIX + ".previousHandler.preferredAction";
 const PREF_PREVIOUS_ASK = PREF_PREFIX +
                           ".previousHandler.alwaysAskBeforeHandling";
 const PREF_DISABLED_PLUGIN_TYPES = "plugin.disable_full_page_plugin_for_types";
 const PREF_ENABLED_CACHE_STATE = PREF_PREFIX + ".enabledCache.state";
@@ -46,16 +44,18 @@ XPCOMUtils.defineLazyServiceGetter(Svc, 
                                    "@mozilla.org/plugin/host;1",
                                    "nsIPluginHost");
 ChromeUtils.defineModuleGetter(this, "PdfjsChromeUtils",
                                "resource://pdf.js/PdfjsChromeUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "PdfjsContentUtils",
                                "resource://pdf.js/PdfjsContentUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "PdfJsDefaultPreferences",
   "resource://pdf.js/PdfJsDefaultPreferences.jsm");
+ChromeUtils.defineModuleGetter(this, "PdfJsRegistration",
+  "resource://pdf.js/PdfJsRegistration.jsm");
 
 function getBoolPref(aPref, aDefaultValue) {
   try {
     return Services.prefs.getBoolPref(aPref);
   } catch (ex) {
     return aDefaultValue;
   }
 }
@@ -90,50 +90,18 @@ function initializeDefaultPreferences() 
         break;
       case "string":
         defaultBranch.setCharPref(key, defaultValue);
         break;
     }
   }
 }
 
-// Register/unregister a constructor as a factory.
-function Factory() {}
-Factory.prototype = {
-  register: function register(targetConstructor) {
-    var proto = targetConstructor.prototype;
-    this._classID = proto.classID;
-
-    var factory = XPCOMUtils._getFactory(targetConstructor);
-    this._factory = factory;
-
-    var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
-    registrar.registerFactory(proto.classID, proto.classDescription,
-                              proto.contractID, factory);
-
-    if (proto.classID2) {
-      this._classID2 = proto.classID2;
-      registrar.registerFactory(proto.classID2, proto.classDescription,
-                                proto.contractID2, factory);
-    }
-  },
-
-  unregister: function unregister() {
-    var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
-    registrar.unregisterFactory(this._classID, this._factory);
-    if (this._classID2) {
-      registrar.unregisterFactory(this._classID2, this._factory);
-    }
-    this._factory = null;
-  },
-};
-
 var PdfJs = {
   QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
-  _registered: false,
   _initialized: false,
 
   init: function init(remote) {
     if (Services.appinfo.processType !==
         Services.appinfo.PROCESS_TYPE_DEFAULT) {
       throw new Error("PdfJs.init should only get called " +
                       "in the parent process.");
     }
@@ -328,30 +296,16 @@ var PdfJs = {
       }
 
       Services.prefs.setBoolPref(PREF_ENABLED_CACHE_INITIALIZED, true);
     }
     return Services.prefs.getBoolPref(PREF_ENABLED_CACHE_STATE, true);
   },
 
   ensureRegistered: function ensureRegistered() {
-    if (this._registered) {
-      return;
-    }
-    this._pdfStreamConverterFactory = new Factory();
-    ChromeUtils.import("resource://pdf.js/PdfStreamConverter.jsm");
-    this._pdfStreamConverterFactory.register(PdfStreamConverter);
-
-    this._registered = true;
+    PdfJsRegistration.ensureRegistered();
   },
 
   ensureUnregistered: function ensureUnregistered() {
-    if (!this._registered) {
-      return;
-    }
-    this._pdfStreamConverterFactory.unregister();
-    Cu.unload("resource://pdf.js/PdfStreamConverter.jsm");
-    delete this._pdfStreamConverterFactory;
-
-    this._registered = false;
+    PdfJsRegistration.ensureUnregistered();
   },
 };
 
new file mode 100644
--- /dev/null
+++ b/browser/extensions/pdfjs/content/PdfJsRegistration.jsm
@@ -0,0 +1,91 @@
+/* Copyright 2018 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+"use strict";
+
+var EXPORTED_SYMBOLS = ["PdfJsRegistration"];
+
+const Cm = Components.manager;
+
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+ChromeUtils.defineModuleGetter(this, "PdfStreamConverter",
+  "resource://pdf.js/PdfStreamConverter.jsm");
+
+// Register/unregister a constructor as a factory.
+function StreamConverterFactory() {}
+StreamConverterFactory.prototype = {
+
+  // properties required for XPCOM registration:
+  _classID: Components.ID("{d0c5195d-e798-49d4-b1d3-9324328b2291}"),
+  _classDescription: "pdf.js Component",
+  _contractID: "@mozilla.org/streamconv;1?from=application/pdf&to=*/*",
+
+  _classID2: Components.ID("{d0c5195d-e798-49d4-b1d3-9324328b2292}"),
+  _contractID2: "@mozilla.org/streamconv;1?from=application/pdf&to=text/html",
+
+  register: function register() {
+    var factory = {
+      createInstance(outer, iid) {
+        if (outer)
+          throw Cr.NS_ERROR_NO_AGGREGATION;
+        return (new PdfStreamConverter()).QueryInterface(iid);
+      },
+      QueryInterface: ChromeUtils.generateQI([Ci.nsIFactory])
+    };
+
+    this._factory = factory;
+
+    var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
+    registrar.registerFactory(this._classID, this._classDescription,
+                              this._contractID, factory);
+    registrar.registerFactory(this._classID2, this._classDescription,
+                              this._contractID2, factory);
+  },
+
+  unregister: function unregister() {
+    var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
+    registrar.unregisterFactory(this._classID, this._factory);
+    if (this._classID2) {
+      registrar.unregisterFactory(this._classID2, this._factory);
+    }
+    this._factory = null;
+  },
+};
+
+var PdfJsRegistration = {
+  _registered: false,
+
+  ensureRegistered: function ensureRegistered() {
+    if (this._registered) {
+      return;
+    }
+    this._pdfStreamConverterFactory = new StreamConverterFactory();
+    this._pdfStreamConverterFactory.register();
+
+    this._registered = true;
+  },
+
+  ensureUnregistered: function ensureUnregistered() {
+    if (!this._registered) {
+      return;
+    }
+    this._pdfStreamConverterFactory.unregister();
+    delete this._pdfStreamConverterFactory;
+
+    this._registered = false;
+  },
+
+};
--- a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
+++ b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
@@ -795,25 +795,16 @@ class FindEventManager {
     this.winmm.sendAsyncMessage("PDFJS:Parent:removeEventListener");
   }
 }
 
 function PdfStreamConverter() {
 }
 
 PdfStreamConverter.prototype = {
-
-  // properties required for XPCOM registration:
-  classID: Components.ID("{d0c5195d-e798-49d4-b1d3-9324328b2291}"),
-  classDescription: "pdf.js Component",
-  contractID: "@mozilla.org/streamconv;1?from=application/pdf&to=*/*",
-
-  classID2: Components.ID("{d0c5195d-e798-49d4-b1d3-9324328b2292}"),
-  contractID2: "@mozilla.org/streamconv;1?from=application/pdf&to=text/html",
-
   QueryInterface: ChromeUtils.generateQI([Ci.nsIStreamConverter, Ci.nsIStreamListener, Ci.nsIRequestObserver]),
 
   /*
    * This component works as such:
    * 1. asyncConvertData stores the listener
    * 2. onStartRequest creates a new channel, streams the viewer
    * 3. If range requests are supported:
    *      3.1. Leave the request open until the viewer is ready to switch to
--- a/browser/extensions/pdfjs/content/PdfjsContentUtils.jsm
+++ b/browser/extensions/pdfjs/content/PdfjsContentUtils.jsm
@@ -113,21 +113,21 @@ var PdfjsContentUtils = {
   },
 
   receiveMessage(aMsg) {
     switch (aMsg.name) {
       case "PDFJS:Child:updateSettings":
         // Only react to this if we are remote.
         if (Services.appinfo.processType ===
             Services.appinfo.PROCESS_TYPE_CONTENT) {
-          let jsm = "resource://pdf.js/PdfJs.jsm";
-          let pdfjs = ChromeUtils.import(jsm, {}).PdfJs;
+          let jsm = "resource://pdf.js/PdfJsRegistration.jsm";
+          let pdfjsr = ChromeUtils.import(jsm, {}).PdfJsRegistration;
           if (aMsg.data.enabled) {
-            pdfjs.ensureRegistered();
+            pdfjsr.ensureRegistered();
           } else {
-            pdfjs.ensureUnregistered();
+            pdfjsr.ensureUnregistered();
           }
         }
         break;
     }
   },
 };
 
--- a/browser/extensions/pdfjs/content/pdfjschildbootstrap-enabled.js
+++ b/browser/extensions/pdfjs/content/pdfjschildbootstrap-enabled.js
@@ -17,14 +17,14 @@
 
 /*
  * pdfjschildbootstrap-enabled.js loads into the content process to
  * take care of initializing our built-in version of pdfjs when
  * running remote. It will only be run when PdfJs.enable is true.
  */
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
-ChromeUtils.import("resource://pdf.js/PdfJs.jsm");
+ChromeUtils.import("resource://pdf.js/PdfJsRegistration.jsm");
 
 if (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) {
   // register various pdfjs factories that hook us into content loading.
-  PdfJs.ensureRegistered();
+  PdfJsRegistration.ensureRegistered();
 }
--- a/browser/extensions/screenshots/bootstrap.js
+++ b/browser/extensions/screenshots/bootstrap.js
@@ -116,19 +116,20 @@ const LibraryButton = {
     item.setAttribute("label", this.LABEL);
 
     parent.insertBefore(item, nextSibling);
   },
 };
 
 const APP_STARTUP = 1;
 const APP_SHUTDOWN = 2;
-let startupReason;
+let addonData, startupReason;
 
 function startup(data, reason) { // eslint-disable-line no-unused-vars
+  addonData = data;
   startupReason = reason;
   if (reason === APP_STARTUP) {
     appStartupObserver.register();
   } else {
     appStartupDone();
   }
   prefObserver.register();
   addonResourceURI = data.resourceURI;
@@ -172,17 +173,17 @@ function handleStartup() {
   if (!shouldDisable() && !webExtension.started) {
     start(webExtension);
   } else if (shouldDisable()) {
     stop(webExtension, ADDON_DISABLE);
   }
 }
 
 function start(webExtension) {
-  return webExtension.startup(startupReason).then((api) => {
+  return webExtension.startup(startupReason, addonData).then((api) => {
     api.browser.runtime.onMessage.addListener(handleMessage);
     LibraryButton.init(webExtension);
     initPhotonPageAction(api, webExtension);
   }).catch((err) => {
     // The startup() promise will be rejected if the webExtension was
     // already started (a harmless error), or if initializing the
     // WebExtension failed and threw (an important error).
     console.error(err);
--- a/browser/extensions/screenshots/webextension/manifest.json
+++ b/browser/extensions/screenshots/webextension/manifest.json
@@ -58,11 +58,13 @@
     "downloads",
     "tabs",
     "storage",
     "notifications",
     "clipboardWrite",
     "contextMenus",
     "mozillaAddons",
     "<all_urls>",
-    "https://screenshots.firefox.com/"
+    "https://screenshots.firefox.com/",
+    "resource://pdf.js/",
+    "about:reader*"
   ]
 }
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -34,58 +34,39 @@ ifneq (,$(filter cocoa,$(MOZ_WIDGET_TOOL
 MOZ_PKG_MAC_DSSTORE=$(ABS_DIST)/branding/dsstore
 MOZ_PKG_MAC_BACKGROUND=$(ABS_DIST)/branding/background.png
 MOZ_PKG_MAC_ICON=$(ABS_DIST)/branding/disk.icns
 MOZ_PKG_MAC_EXTRA=--symlink '/Applications:/ '
 endif
 
 MOZ_SFX_PACKAGE=$(topsrcdir)/other-licenses/7zstub/firefox/7zSD.sfx
 
-SEARCHPLUGINS_FILENAMES := $(or $(shell $(call py_action,output_searchplugins_list,$(srcdir)/search/list.json $(AB_CD))), $(error Missing search plugins))
-SEARCHPLUGINS_PATH := .deps/generated_$(AB_CD)
-SEARCHPLUGINS_TARGET := libs searchplugins
-SEARCHPLUGINS := $(foreach plugin,$(addsuffix .xml,$(SEARCHPLUGINS_FILENAMES)),$(or $(wildcard $(srcdir)/searchplugins/$(plugin)),$(error Missing searchplugin: $(plugin))))
-# Some locale-specific search plugins may have preprocessor directives, but the
-# default en-US ones do not.
-SEARCHPLUGINS_FLAGS := --silence-missing-directive-warnings
-PP_TARGETS += SEARCHPLUGINS
-
-list-json = $(SEARCHPLUGINS_PATH)/list.json
-GARBAGE += $(list-json)
-
-libs:: searchplugins
-
 # Required for l10n.mk - defines a list of app sub dirs that should
 # be included in langpack xpis.
 DIST_SUBDIRS = $(DIST_SUBDIR)
 
 include $(topsrcdir)/config/rules.mk
 
 include $(topsrcdir)/toolkit/locales/l10n.mk
 
-$(list-json): $(call mkdir_deps,$(SEARCHPLUGINS_PATH)) $(if $(IS_LANGUAGE_REPACK),FORCE)
-	$(call py_action,generate_searchjson,$(srcdir)/search/list.json $(AB_CD) $(list-json))
-searchplugins:: $(list-json)
-
 libs-%: AB_CD=$*
 libs-%:
 	$(if $(filter en-US,$(AB_CD)),, @$(MAKE) merge-$*)
 	$(NSINSTALL) -D $(DIST)/install
 	@$(MAKE) -C ../../toolkit/locales libs-$* XPI_ROOT_APPID='$(XPI_ROOT_APPID)'
 	@$(MAKE) -C ../../services/sync/locales AB_CD=$* XPI_NAME=locale-$*
 	@$(MAKE) -C ../../extensions/spellcheck/locales AB_CD=$* XPI_NAME=locale-$*
 ifneq (,$(wildcard ../extensions/formautofill/locales))
 	@$(MAKE) -C ../extensions/formautofill/locales AB_CD=$* XPI_NAME=locale-$*
 endif
 	@$(MAKE) -C ../extensions/onboarding/locales AB_CD=$* XPI_NAME=locale-$*
 	@$(MAKE) -C ../extensions/pocket/locale AB_CD=$* XPI_NAME=locale-$*
 	@$(MAKE) -C ../extensions/webcompat-reporter/locales AB_CD=$* XPI_NAME=locale-$*
 	@$(MAKE) -C ../../devtools/client/locales AB_CD=$* XPI_NAME=locale-$* XPI_ROOT_APPID='$(XPI_ROOT_APPID)'
 	@$(MAKE) -C ../../devtools/startup/locales AB_CD=$* XPI_NAME=locale-$* XPI_ROOT_APPID='$(XPI_ROOT_APPID)'
-	@$(MAKE) -B searchplugins AB_CD=$* XPI_NAME=locale-$*
 	@$(MAKE) libs AB_CD=$* XPI_NAME=locale-$* PREF_DIR=$(PREF_DIR)
 	@$(MAKE) multilocale.txt-$* AB_CD=$* XPI_NAME=locale-$*
 	@$(MAKE) -C $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales AB_CD=$* XPI_NAME=locale-$*
 
 chrome-%: AB_CD=$*
 chrome-%: IS_LANGUAGE_REPACK=1
 chrome-%:
 	$(if $(filter en-US,$(AB_CD)),, @$(MAKE) merge-$*)
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -55,28 +55,16 @@
     locale/browser/feeds/subscribe.dtd              (%chrome/browser/feeds/subscribe.dtd)
     locale/browser/feeds/subscribe.properties       (%chrome/browser/feeds/subscribe.properties)
     locale/browser/migration/migration.dtd         (%chrome/browser/migration/migration.dtd)
     locale/browser/migration/migration.properties  (%chrome/browser/migration/migration.properties)
     locale/browser/preferences/preferences.properties     (%chrome/browser/preferences/preferences.properties)
     locale/browser/preferences/security.dtd           (%chrome/browser/preferences/security.dtd)
     locale/browser/syncBrand.dtd                (%chrome/browser/syncBrand.dtd)
     locale/browser/syncSetup.properties         (%chrome/browser/syncSetup.properties)
-#if BUILD_FASTER
-    locale/browser/searchplugins/               (searchplugins/*.xml)
-    locale/browser/searchplugins/list.json      (search/list.json)
-#else
-    locale/browser/searchplugins/               (.deps/generated_@AB_CD@/*.xml)
-    locale/browser/searchplugins/list.json      (.deps/generated_@AB_CD@/list.json)
-#endif
-    locale/browser/searchplugins/images/amazon.ico     (searchplugins/images/amazon.ico)
-    locale/browser/searchplugins/images/ebay.ico       (searchplugins/images/ebay.ico)
-    locale/browser/searchplugins/images/wikipedia.ico  (searchplugins/images/wikipedia.ico)
-    locale/browser/searchplugins/images/yandex-en.ico  (searchplugins/images/yandex-en.ico)
-    locale/browser/searchplugins/images/yandex-ru.ico  (searchplugins/images/yandex-ru.ico)
 % locale browser-region @AB_CD@ %locale/browser-region/
     locale/browser-region/region.properties        (%chrome/browser-region/region.properties)
 # the following files are browser-specific overrides
     locale/browser/netError.dtd                (%chrome/overrides/netError.dtd)
     locale/browser/appstrings.properties       (%chrome/overrides/appstrings.properties)
     locale/browser/downloads/settingsChange.dtd  (%chrome/overrides/settingsChange.dtd)
 % locale pdf.js @AB_CD@ %locale/pdfviewer/
     locale/pdfviewer/viewer.properties             (%pdfviewer/viewer.properties)
--- a/browser/locales/moz.build
+++ b/browser/locales/moz.build
@@ -39,16 +39,10 @@ with Files("**"):
     BUG_COMPONENT = ("Firefox Build System", "General")
 
 with Files("all-locales"):
     BUG_COMPONENT = ("Core", "Localization")
 
 with Files("en-US/**"):
     BUG_COMPONENT = ("Core", "Localization")
 
-with Files("search/**"):
-    BUG_COMPONENT = ("Firefox", "Search")
-
-with Files("searchplugins/**"):
-    BUG_COMPONENT = ("Firefox", "Search")
-
 with Files("shipped-locales"):
     BUG_COMPONENT = ("Core", "Localization")
--- a/browser/modules/ContentSearch.jsm
+++ b/browser/modules/ContentSearch.jsm
@@ -102,16 +102,17 @@ var ContentSearch = {
   _destroyedPromise: null,
 
   // The current controller and browser in _onMessageGetSuggestions.  Allows
   // fetch cancellation from _cancelSuggestions.
   _currentSuggestion: null,
 
   init() {
     Services.obs.addObserver(this, "browser-search-engine-modified");
+    Services.obs.addObserver(this, "browser-search-service");
     Services.obs.addObserver(this, "shutdown-leaks-before-check");
     Services.prefs.addObserver("browser.search.hiddenOneOffs", this);
     this._stringBundle = Services.strings.createBundle("chrome://global/locale/autocomplete.properties");
   },
 
   get searchSuggestionUIStrings() {
     if (this._searchSuggestionUIStrings) {
       return this._searchSuggestionUIStrings;
@@ -128,16 +129,17 @@ var ContentSearch = {
   },
 
   destroy() {
     if (this._destroyedPromise) {
       return this._destroyedPromise;
     }
 
     Services.obs.removeObserver(this, "browser-search-engine-modified");
+    Services.obs.removeObserver(this, "browser-search-service");
     Services.obs.removeObserver(this, "shutdown-leaks-before-check");
 
     this._eventQueue.length = 0;
     this._destroyedPromise = Promise.resolve(this._currentEventPromise);
     return this._destroyedPromise;
   },
 
   /**
@@ -179,16 +181,20 @@ var ContentSearch = {
       type: "Message",
       data: msg,
     });
     this._processEventQueue();
   },
 
   observe(subj, topic, data) {
     switch (topic) {
+    case "browser-search-service":
+      if (data != "init-complete") {
+        break;
+      }
     case "nsPref:changed":
     case "browser-search-engine-modified":
       this._eventQueue.push({
         type: "Observe",
         data,
       });
       this._processEventQueue();
       break;
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -22,16 +22,21 @@
 %define panelPaletteIconSize 16px
 
 %define appmenuWarningBackgroundColor #FFEFBF
 %define appmenuWarningBackgroundColorHover #FFE8A2
 %define appmenuWarningBackgroundColorActive #FFE38F
 %define appmenuWarningColor black
 %define appmenuWarningBorderColor hsl(45,100%,77%)
 
+%define appmenuWarningBackgroundColorBrightText hsla(55,100%,50%,.1)
+%define appmenuWarningBackgroundColorHoverBrightText hsla(55,100%,50%,.15)
+%define appmenuWarningBackgroundColorActiveBrightText hsla(55,100%,50%,.2)
+%define appmenuWarningColorBrightText #F9F9FA
+
 :root:not([uidensity=compact]):not([chromehidden~="toolbar"]) #PanelUI-button {
   margin-inline-start: 3px;
   border-inline-start: 1px solid;
   border-image: linear-gradient(
     transparent 4px,
     var(--lwt-toolbar-vertical-separator, rgba(0,0,0,.1)) 4px,
     var(--lwt-toolbar-vertical-separator, rgba(0,0,0,.1)) calc(100% - 4px),
     transparent calc(100% - 4px)
@@ -94,17 +99,23 @@
 }
 
 #PanelUI-menu-button[badge-status="fxa-needs-authentication"] > .toolbarbutton-badge-stack > .toolbarbutton-badge:-moz-window-inactive {
   filter: none;
 }
 
 #PanelUI-menu-button[badge-status="addon-alert"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
   height: 13px;
-  background: #FFBF00 url(chrome://browser/skin/update-badge-failed.svg) no-repeat center;
+  background: url(chrome://browser/skin/warning.svg) no-repeat center;
+}
+
+:root[lwt-popup-brighttext] #PanelUI-menu-button[badge-status="addon-alert"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
+  -moz-context-properties: fill, stroke;
+  fill: #FFE900;
+  stroke: transparent;
 }
 
 panelview {
   -moz-box-orient: vertical;
   -moz-box-flex: 1;
   background: var(--arrowpanel-background);
   padding: 0;
 }
@@ -439,17 +450,23 @@ toolbarbutton[constrain-size="true"][cui
 }
 
 .addon-banner-item > .toolbarbutton-icon {
   width: 16px;
   height: 16px;
 }
 
 .addon-banner-item::after {
-  background: #FFBF00 url(chrome://browser/skin/update-badge-failed.svg) no-repeat center;
+  background: url(chrome://browser/skin/warning.svg) no-repeat center;
+}
+
+:root[lwt-popup-brighttext] .addon-banner-item::after {
+  -moz-context-properties: fill, stroke;
+  fill: #FFE900;
+  stroke: transparent;
 }
 
 .addon-banner-item,
 .panel-banner-item {
   margin: 0;
   padding: 11px 0;
   box-sizing: border-box;
   min-height: 40px;
@@ -635,16 +652,49 @@ toolbarbutton[constrain-size="true"][cui
 }
 
 .addon-banner-item {
   flex: 1;
   padding-inline-start: 15px;
   border-inline-start-style: none;
 }
 
+:root[lwt-popup-brighttext] .addon-banner-item {
+  color: @appmenuWarningColorBrightText@;
+  background: @appmenuWarningBackgroundColorBrightText@;
+  /* override `.addon-banner-item` border-top !important defined above */
+  border: 0 !important;
+}
+
+:root[lwt-popup-brighttext] .addon-banner-item:hover,
+:root[lwt-popup-brighttext] .addon-banner-item:focus {
+  background: @appmenuWarningBackgroundColorHoverBrightText@;
+}
+
+:root[lwt-popup-brighttext] .addon-banner-item:hover:active,
+:root[lwt-popup-brighttext] .addon-banner-item:focus:active {
+  background: @appmenuWarningBackgroundColorActiveBrightText@;
+}
+
+:root[lwt-popup-brighttext] #appMenu-fxa-container[fxastatus="login-failed"],
+:root[lwt-popup-brighttext] #appMenu-fxa-container[fxastatus="unverified"] {
+  background-color: @appmenuWarningBackgroundColorBrightText@;
+  color: @appmenuWarningColorBrightText@;
+}
+
+:root[lwt-popup-brighttext] #appMenu-fxa-container[fxastatus="login-failed"] > #appMenu-fxa-status:hover,
+:root[lwt-popup-brighttext] #appMenu-fxa-container[fxastatus="unverified"] > #appMenu-fxa-status:hover {
+  background-color: @appmenuWarningBackgroundColorHoverBrightText@;
+}
+
+:root[lwt-popup-brighttext] #appMenu-fxa-container[fxastatus="login-failed"] > #appMenu-fxa-status:hover:active,
+:root[lwt-popup-brighttext] #appMenu-fxa-container[fxastatus="unverified"] > #appMenu-fxa-status:hover:active {
+  background-color: @appmenuWarningBackgroundColorActiveBrightText@;
+}
+
 #PanelUI-remotetabs {
   --panel-ui-sync-illustration-height: 91px;
 }
 
 .PanelUI-remotetabs-instruction-label {
   /* If you change the margin here, the min-height of the synced tabs panel
     (e.g. #PanelUI-remotetabs[mainview] #PanelUI-remotetabs-setupsync, etc) may
     need adjusting (see bug 1248506) */
@@ -1234,20 +1284,16 @@ toolbarpaletteitem[place="menu-panel"] >
   max-width: calc(@menuPanelButtonWidth@ - 1px);
 }
 
 .toolbaritem-combined-buttons@inAnyPanel@ > toolbarbutton[disabled] {
   /* Override toolbarbutton.css which sets the color to GrayText */
   color: inherit;
 }
 
-#main-window:not([customizing]) .toolbaritem-combined-buttons@inAnyPanel@ > toolbarbutton[disabled] > .toolbarbutton-icon {
-  opacity: .25;
-}
-
 #zoom-controls[cui-areatype="toolbar"] > #zoom-reset-button > .toolbarbutton-text {
 %ifdef XP_MACOSX
   min-width: 6ch;
 %else
   min-width: 7ch;
 %endif
 }
 
@@ -1541,17 +1587,16 @@ toolbarpaletteitem[place="menu-panel"] >
   display: flex;
   flex: 1 auto;
   height: 40px; /* fixed item height to prevent flex sizing; height + 2*4px padding */
   padding: 4px;
 }
 
 .panel-header > label {
   flex: auto;
-  font-size: 13px;
   font-weight: 600;
   margin: 0;
   text-align: center;
 }
 
 .panel-header > .subviewbutton-back + label {
   /* Add the size of the back button to center properly. */
   margin-inline-end: 32px;
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -204,19 +204,17 @@
   skin/classic/browser/tabbrowser/tab-overflow-indicator.png   (../shared/tabbrowser/tab-overflow-indicator.png)
   skin/classic/browser/tabbrowser/badge-audio-playing.svg      (../shared/tabbrowser/badge-audio-playing.svg)
 
   skin/classic/browser/translating-16.png                      (../shared/translation/translating-16.png)
   skin/classic/browser/translating-16@2x.png                   (../shared/translation/translating-16@2x.png)
   skin/classic/browser/translation-16.png                      (../shared/translation/translation-16.png)
   skin/classic/browser/translation-16@2x.png                   (../shared/translation/translation-16@2x.png)
   skin/classic/browser/update-badge.svg                        (../shared/update-badge.svg)
-  skin/classic/browser/update-badge-failed.svg                 (../shared/update-badge-failed.svg)
   skin/classic/browser/warning.svg                             (../shared/warning.svg)
-  skin/classic/browser/warning-white.svg                       (../shared/warning-white.svg)
   skin/classic/browser/cert-error.svg                          (../shared/incontent-icons/cert-error.svg)
   skin/classic/browser/wifi.svg                                (../shared/incontent-icons/wifi.svg)
   skin/classic/browser/tab-crashed.svg                         (../shared/incontent-icons/tab-crashed.svg)
   skin/classic/browser/favicon-search-16.svg                   (../shared/favicon-search-16.svg)
   skin/classic/browser/icon-search-64.svg                      (../shared/incontent-icons/icon-search-64.svg)
   skin/classic/browser/welcome-back.svg                        (../shared/incontent-icons/welcome-back.svg)
   skin/classic/browser/readerMode.svg                          (../shared/reader/readerMode.svg)
   skin/classic/browser/panic-panel/header.png                  (../shared/panic-panel/header.png)
--- a/browser/themes/shared/notification-icons.inc.css
+++ b/browser/themes/shared/notification-icons.inc.css
@@ -148,17 +148,19 @@
 html|*#webRTC-previewVideo {
   width: 300px;
   /* If we don't set the min-width, width is ignored. */
   min-width: 300px;
   max-height: 200px;
 }
 
 #webRTC-previewWarning {
-  background: rgba(255, 217, 99, .8) url("chrome://browser/skin/warning-white.svg") no-repeat .75em .75em;
+  background: rgba(255,217,99,.8) url("chrome://browser/skin/warning.svg") no-repeat .75em .75em;
+  -moz-context-properties: fill;
+  fill: #fff;
   margin: 0;
   padding: .5em;
   padding-inline-start: calc(1.5em + 16px);
   border-top: 1px solid GrayText;
 }
 
 #webRTC-previewWarning > .text-link {
   margin-inline-start: 0;
deleted file mode 100644
--- a/browser/themes/shared/update-badge-failed.svg
+++ /dev/null
@@ -1,6 +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/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="10px" height="10px">
-  <path d="M5,6C4.2,6,3.5,6.7,3.5,7.5S4.2,9,5,9s1.5-0.7,1.5-1.5S5.8,6,5,6z M5,5L5,5c0.6,0,1-0.4,1-1l0.2-2.8 C6.2,0.5,5.7,0,5,0S3.8,0.5,3.8,1.2L4,4C4,4.6,4.4,5,5,5z" fill="#fff"/>
-</svg>
deleted file mode 100644
--- a/browser/themes/shared/warning-white.svg
+++ /dev/null
@@ -1,6 +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/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
-  <path fill="#fff" stroke="#000" stroke-opacity="0.3" d="M15.4,12.9 9.46,1.41 C9.12,0.756 8.59,0.381 8,0.381 7.41,0.381 6.88,0.756 6.54,1.41 L0.642,12.9 c-0.331,0.6 -0.348,1.3 -0.05,1.9 0.299,0.5 0.854,0.8 1.534,0.8 H13.9 c0.6,0 1.2,-0.3 1.5,-0.8 0.3,-0.6 0.3,-1.3 0,-1.9z M8.83,5.07 8.65,10.5 H7.34 L7.15,5.07 H8.83z M8,13.7 c-0.55,0 -0.99,-0.5 -0.99,-1 0,-0.6 0.44,-1 0.99,-1 0.56,0 0.99,0.4 0.99,1 0,0.5 -0.43,1 -0.99,1z"/>
-</svg>
--- a/browser/themes/shared/warning.svg
+++ b/browser/themes/shared/warning.svg
@@ -1,7 +1,6 @@
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="#ffbf00" d="M14.8,12.5L9.3,1.9C9,1.3,8.5,1,8,1C7.5,1,7,1.3,6.7,1.9L1.2,12.5c-0.3,0.6-0.3,1.2,0,1.7C1.5,14.7,2,15,2.6,15h10.8 c0.6,0,1.1-0.3,1.4-0.8C15.1,13.7,15.1,13.1,14.8,12.5z"/>
-  <path fill="#fff" d="M8,11c-0.8,0-1.5,0.7-1.5,1.5C6.5,13.3,7.2,14,8,14 c0.8,0,1.5-0.7,1.5-1.5C9.5,11.7,8.8,11,8,11z M8,10L8,10C8.6,10,9,9.6,9,9l0.2-4.2c0-0.7-0.5-1.2-1.2-1.2S6.8,4.1,6.8,4.8L7,9 C7,9.6,7.4,10,8,10z"/>
-</svg>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
+  <path fill="context-fill #FFBF00" stroke="context-stroke #fff" stroke-opacity="0.3" d="M15.4,12.9 9.46,1.41 C9.12,0.756 8.59,0.381 8,0.381 7.41,0.381 6.88,0.756 6.54,1.41 L0.642,12.9 c-0.331,0.6 -0.348,1.3 -0.05,1.9 0.299,0.5 0.854,0.8 1.534,0.8 H13.9 c0.6,0 1.2,-0.3 1.5,-0.8 0.3,-0.6 0.3,-1.3 0,-1.9z M8.83,5.07 8.65,10.5 H7.34 L7.15,5.07 H8.83z M8,13.7 c-0.55,0 -0.99,-0.5 -0.99,-1 0,-0.6 0.44,-1 0.99,-1 0.56,0 0.99,0.4 0.99,1 0,0.5 -0.43,1 -0.99,1z"/>
+</svg>
--- a/devtools/client/inspector/extensions/test/head_devtools_inspector_sidebar.js
+++ b/devtools/client/inspector/extensions/test/head_devtools_inspector_sidebar.js
@@ -35,17 +35,17 @@ function getExtensionSidebarActors(inspe
 
 // Test that the specified objectValueGrip actors have been released
 // on the remote debugging server
 // (used in browser_ext_devtools_panels_elements_sidebar.js).
 async function expectNoSuchActorIDs(client, actors) {
   info(`Test that all the objectValueGrip actors have been released`);
   for (const actor of actors) {
     await Assert.rejects(client.request({to: actor, type: "requestTypes"}),
-                         `No such actor for ID: ${actor}`);
+                         err => err.message == `No such actor for ID: ${actor}`);
   }
 }
 
 function waitForObjectInspector(panelDoc, waitForNodeWithType = "object") {
   const selector = `.object-inspector .objectBox-${waitForNodeWithType}`;
   return ContentTaskUtils.waitForCondition(() => {
     return panelDoc.querySelectorAll(selector).length > 0;
   });
--- a/devtools/client/inspector/fonts/utils/font-utils.js
+++ b/devtools/client/inspector/fonts/utils/font-utils.js
@@ -62,17 +62,20 @@ module.exports = {
 
     // Parse font-variation-settings CSS declaration into an object
     // with axis tags as keys and axis values as values.
     axes = string
       .split(",")
       .reduce((acc, pair) => {
         // Tags are always in quotes. Split by quote and filter excessive whitespace.
         pair = pair.split(/["']/).filter(part => part.trim() !== "");
-        const tag = pair[0].trim();
+        const tag = pair[0];
         const value = pair[1].trim();
-        acc[tag] = value;
+        // Axis tags shorter or longer than 4 characters are invalid. Whitespace is valid.
+        if (tag.length === 4) {
+          acc[tag] = value;
+        }
         return acc;
       }, {});
 
     return axes;
   }
 };
--- a/devtools/client/themes/animation.css
+++ b/devtools/client/themes/animation.css
@@ -246,16 +246,17 @@ select.playback-rate-selector.devtools-b
   text-overflow: ellipsis;
   white-space: nowrap;
 }
 
 .animation-target .objectBox:hover .open-inspector {
   background-color: var(--comment-node-color);
 }
 
+.animation-target .objectBox .open-inspector:hover,
 .animation-target.highlighting .objectBox .open-inspector {
   background-color: var(--theme-highlight-blue);
 }
 
 /* Summary Graph */
 .animation-summary-graph {
   cursor: pointer;
   height: 100%;
@@ -381,25 +382,36 @@ select.playback-rate-selector.devtools-b
   height: 100%;
   overflow: hidden;
   width: 100%;
   z-index: 1;
 }
 
 .animation-detail-header {
   display: flex;
+  padding-inline-end: 0;
+}
+
+/* On OSX the cursor turns into a window-resizing cursor at the edges of the
+ * window, so bring the end of the close button in. */
+:root[platform="mac"] .animation-detail-header {
+  padding-inline-end: 3px;
 }
 
 .animation-detail-title {
   flex: 1;
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
 }
 
+.animation-detail-close-button {
+  margin: 0;
+}
+
 .animation-detail-close-button::before {
   background-image: url(chrome://devtools/skin/images/close.svg);
 }
 
 /* Animated Property List Container */
 .animated-property-list-container {
   display: flex;
   flex: 1;
@@ -482,28 +494,28 @@ select.playback-rate-selector.devtools-b
   width: 0;
 }
 
 /* Animated Property List */
 .animated-property-list-background {
   border-left: var(--tick-line-style);
   border-right: var(--tick-line-style);
   bottom: 0;
-	left: var(--sidebar-width);
+  left: var(--sidebar-width);
   min-height: 100%;
-	position: sticky;
+  position: sticky;
   top: 0;
-	width: calc(100% - var(--sidebar-width) - var(--graph-right-offset));
+  width: calc(100% - var(--sidebar-width) - var(--graph-right-offset));
 }
 
 .animated-property-list-background span {
   border-left: var(--tick-line-style);
-	height: 100%;
-	left: 50%;
-	position: absolute;
+  height: 100%;
+  left: 50%;
+  position: absolute;
 }
 
 .animated-property-list {
   flex: 1;
   list-style-type: none;
   margin: 0;
   padding: 0;
   position: absolute;
--- a/devtools/server/actors/chrome.js
+++ b/devtools/server/actors/chrome.js
@@ -2,21 +2,21 @@
  * 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 { Ci } = require("chrome");
 const Services = require("Services");
 const { DebuggerServer } = require("../main");
-const { getChildDocShells, TabActor } = require("./tab");
+const { getChildDocShells, TabActor, tabPrototype } = require("./tab");
 const makeDebugger = require("./utils/make-debugger");
 
 const { extend } = require("devtools/shared/extend");
-const { ActorClassWithSpec, Actor } = require("devtools/shared/protocol");
+const { ActorClassWithSpec } = require("devtools/shared/protocol");
 const { tabSpec } = require("devtools/shared/specs/tab");
 
 /**
  * Creates a TabActor for debugging all the chrome content in the
  * current process. Most of the implementation is inherited from TabActor.
  * ChromeActor is a child of RootActor, it can be instanciated via
  * RootActor.getProcess request.
  * ChromeActor exposes all tab actors via its form() request, like TabActor.
@@ -36,22 +36,20 @@ const { tabSpec } = require("devtools/sh
  */
 
 /**
  * Protocol.js expects only the prototype object, and does not maintain the prototype
  * chain when it constructs the ActorClass. For this reason we are using `extend` to
  * maintain the properties of TabActor.prototype
  * */
 
-const chromePrototype = extend({}, TabActor.prototype);
+const chromePrototype = extend({}, tabPrototype);
 
 chromePrototype.initialize = function(connection) {
-  Actor.prototype.initialize.call(this, connection);
-  TabActor.call(this, connection);
-
+  TabActor.prototype.initialize.call(this, connection);
   // This creates a Debugger instance for chrome debugging all globals.
   this.makeDebugger = makeDebugger.bind(null, {
     findDebuggees: dbg => dbg.findAllGlobals(),
     shouldAddNewGlobalAsDebuggee: () => true
   });
 
   // Ensure catching the creation of any new content docshell
   this.listenForNewDocShells = true;
--- a/devtools/server/actors/content.js
+++ b/devtools/server/actors/content.js
@@ -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/. */
 
 "use strict";
 
 var { Cr } = require("chrome");
-var { TabActor } = require("devtools/server/actors/tab");
+var { TabActor, tabPrototype } = require("devtools/server/actors/tab");
 
 const { extend } = require("devtools/shared/extend");
-const { ActorClassWithSpec, Actor } = require("devtools/shared/protocol");
+const { ActorClassWithSpec } = require("devtools/shared/protocol");
 const { tabSpec } = require("devtools/shared/specs/tab");
 
 /**
  * Tab actor for documents living in a child process.
  *
  * Depends on TabActor, defined in tab.js.
  */
 
@@ -32,22 +32,21 @@ const { tabSpec } = require("devtools/sh
  */
 
 /**
  * Protocol.js expects only the prototype object, and does not maintain the prototype
  * chain when it constructs the ActorClass. For this reason we are using `extend` to
  * maintain the properties of TabActor.prototype
  * */
 
-const contentPrototype = extend({}, TabActor.prototype);
+const contentPrototype = extend({}, tabPrototype);
 
 contentPrototype.initialize = function(connection, chromeGlobal) {
   this._chromeGlobal = chromeGlobal;
-  Actor.prototype.initialize.call(this, connection);
-  TabActor.call(this, connection, chromeGlobal);
+  TabActor.prototype.initialize.call(this, connection, chromeGlobal);
   this.traits.reconfigure = false;
   this._sendForm = this._sendForm.bind(this);
   this._chromeGlobal.addMessageListener("debug:form", this._sendForm);
 
   Object.defineProperty(this, "docShell", {
     value: this._chromeGlobal.docShell,
     configurable: true
   });
--- a/devtools/server/actors/tab.js
+++ b/devtools/server/actors/tab.js
@@ -18,21 +18,23 @@ const ChromeUtils = require("ChromeUtils
 var {
   ActorPool, createExtraActors, appendExtraActors
 } = require("devtools/server/actors/common");
 var { DebuggerServer } = require("devtools/server/main");
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
 var { assert } = DevToolsUtils;
 var { TabSources } = require("./utils/TabSources");
 var makeDebugger = require("./utils/make-debugger");
-const EventEmitter = require("devtools/shared/event-emitter");
 const InspectorUtils = require("InspectorUtils");
 
 const EXTENSION_CONTENT_JSM = "resource://gre/modules/ExtensionContent.jsm";
 
+const { ActorClassWithSpec, Actor } = require("devtools/shared/protocol");
+const { tabSpec } = require("devtools/shared/specs/tab");
+
 loader.lazyRequireGetter(this, "ThreadActor", "devtools/server/actors/thread", true);
 loader.lazyRequireGetter(this, "unwrapDebuggerObjectGlobal", "devtools/server/actors/thread", true);
 loader.lazyRequireGetter(this, "WorkerActorList", "devtools/server/actors/worker-list", true);
 loader.lazyImporter(this, "ExtensionContent", EXTENSION_CONTENT_JSM);
 
 loader.lazyRequireGetter(this, "StyleSheetActor", "devtools/server/actors/stylesheets", true);
 loader.lazyRequireGetter(this, "getSheetText", "devtools/server/actors/stylesheets", true);
 
@@ -79,172 +81,170 @@ exports.getChildDocShells = getChildDocS
  * Browser-specific actors.
  */
 
 function getInnerId(window) {
   return window.QueryInterface(Ci.nsIInterfaceRequestor)
                .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
 }
 
-/**
- * Creates a TabActor whose main goal is to manage lifetime and
- * expose the tab actors being registered via DebuggerServer.registerModule.
- * But also track the lifetime of the document being tracked.
- *
- * ### Main requests:
- *
- * `attach`/`detach` requests:
- *  - start/stop document watching:
- *    Starts watching for new documents and emits `tabNavigated` and
- *    `frameUpdate` over RDP.
- *  - retrieve the thread actor:
- *    Instantiates a ThreadActor that can be later attached to in order to
- *    debug JS sources in the document.
- * `switchToFrame`:
- *  Change the targeted document of the whole TabActor, and its child tab actors
- *  to an iframe or back to its original document.
- *
- * Most of the TabActor properties (like `chromeEventHandler` or `docShells`)
- * are meant to be used by the various child tab actors.
- *
- * ### RDP events:
- *
- *  - `tabNavigated`:
- *    Sent when the tab is about to navigate or has just navigated to
- *    a different document.
- *    This event contains the following attributes:
- *     * url (string) The new URI being loaded.
- *     * nativeConsoleAPI (boolean) `false` if the console API of the page has
- *                                          been overridden (e.g. by Firebug),
- *                                  `true`  if the Gecko implementation is used.
- *     * state (string) `start` if we just start requesting the new URL,
- *                      `stop`  if the new URL is done loading.
- *     * isFrameSwitching (boolean) Indicates the event is dispatched when
- *                                  switching the TabActor context to
- *                                  a different frame. When we switch to
- *                                  an iframe, there is no document load.
- *                                  The targeted document is most likely
- *                                  going to be already done loading.
- *     * title (string) The document title being loaded.
- *                      (sent only on state=stop)
- *
- *  - `frameUpdate`:
- *    Sent when there was a change in the child frames contained in the document
- *    or when the tab's context was switched to another frame.
- *    This event can have four different forms depending on the type of change:
- *    * One or many frames are updated:
- *      { frames: [{ id, url, title, parentID }, ...] }
- *    * One frame got destroyed:
- *      { frames: [{ id, destroy: true }]}
- *    * All frames got destroyed:
- *      { destroyAll: true }
- *    * We switched the context of the TabActor to a specific frame:
- *      { selected: #id }
- *
- * ### Internal, non-rdp events:
- * Various events are also dispatched on the TabActor itself that are not
- * related to RDP, so, not sent to the client. They all relate to the documents
- * tracked by the TabActor (its main targeted document, but also any of its
- * iframes).
- *  - will-navigate
- *    This event fires once navigation starts.
- *    All pending user prompts are dealt with,
- *    but it is fired before the first request starts.
- *  - navigate
- *    This event is fired once the document's readyState is "complete".
- *  - window-ready
- *    This event is fired in various distinct scenarios:
- *     * When a new Window object is crafted, equivalent of `DOMWindowCreated`.
- *       It is dispatched before any page script is executed.
- *     * We will have already received a window-ready event for this window
- *       when it was created, but we received a window-destroyed event when
- *       it was frozen into the bfcache, and now the user navigated back to
- *       this page, so it's now live again and we should resume handling it.
- *     * For each existing document, when an `attach` request is received.
- *       At this point scripts in the page will be already loaded.
- *     * When `swapFrameLoaders` is used, such as with moving tabs between
- *       windows or toggling Responsive Design Mode.
- *  - window-destroyed
- *    This event is fired in two cases:
- *     * When the window object is destroyed, i.e. when the related document
- *       is garbage collected. This can happen when the tab is closed or the
- *       iframe is removed from the DOM.
- *       It is equivalent of `inner-window-destroyed` event.
- *     * When the page goes into the bfcache and gets frozen.
- *       The equivalent of `pagehide`.
- *  - changed-toplevel-document
- *    This event fires when we switch the TabActor targeted document
- *    to one of its iframes, or back to its original top document.
- *    It is dispatched between window-destroyed and window-ready.
- *  - stylesheet-added
- *    This event is fired when a StyleSheetActor is created.
- *    It contains the following attribute :
- *     * actor (StyleSheetActor) The created actor.
- *
- * Note that *all* these events are dispatched in the following order
- * when we switch the context of the TabActor to a given iframe:
- *  - will-navigate
- *  - window-destroyed
- *  - changed-toplevel-document
- *  - window-ready
- *  - navigate
- *
- * This class is subclassed by ContentActor and others.
- * Subclasses are expected to implement a getter for the docShell property.
- *
- * @param connection DebuggerServerConnection
- *        The conection to the client.
- */
-function TabActor(connection) {
-  // This usage of decorate should be removed in favor of using ES6 extends EventEmitter.
-  // See Bug 1394816.
-  EventEmitter.decorate(this);
+const tabPrototype = {
 
-  this.conn = connection;
-  this._tabActorPool = null;
-  // A map of actor names to actor instances provided by extensions.
-  this._extraActors = {};
-  this._exited = false;
-  this._sources = null;
-
-  // Map of DOM stylesheets to StyleSheetActors
-  this._styleSheetActors = new Map();
-
-  this._shouldAddNewGlobalAsDebuggee =
-    this._shouldAddNewGlobalAsDebuggee.bind(this);
-
-  this.makeDebugger = makeDebugger.bind(null, {
-    findDebuggees: () => {
-      return this.windows.concat(this.webextensionsContentScriptGlobals);
-    },
-    shouldAddNewGlobalAsDebuggee: this._shouldAddNewGlobalAsDebuggee
-  });
+  /**
+   * Creates a TabActor whose main goal is to manage lifetime and
+   * expose the tab actors being registered via DebuggerServer.registerModule.
+   * But also track the lifetime of the document being tracked.
+   *
+   * ### Main requests:
+   *
+   * `attach`/`detach` requests:
+   *  - start/stop document watching:
+   *    Starts watching for new documents and emits `tabNavigated` and
+   *    `frameUpdate` over RDP.
+   *  - retrieve the thread actor:
+   *    Instantiates a ThreadActor that can be later attached to in order to
+   *    debug JS sources in the document.
+   * `switchToFrame`:
+   *  Change the targeted document of the whole TabActor, and its child tab actors
+   *  to an iframe or back to its original document.
+   *
+   * Most of the TabActor properties (like `chromeEventHandler` or `docShells`)
+   * are meant to be used by the various child tab actors.
+   *
+   * ### RDP events:
+   *
+   *  - `tabNavigated`:
+   *    Sent when the tab is about to navigate or has just navigated to
+   *    a different document.
+   *    This event contains the following attributes:
+   *     * url (string) The new URI being loaded.
+   *     * nativeConsoleAPI (boolean) `false` if the console API of the page has
+   *                                          been overridden (e.g. by Firebug),
+   *                                  `true`  if the Gecko implementation is used.
+   *     * state (string) `start` if we just start requesting the new URL,
+   *                      `stop`  if the new URL is done loading.
+   *     * isFrameSwitching (boolean) Indicates the event is dispatched when
+   *                                  switching the TabActor context to
+   *                                  a different frame. When we switch to
+   *                                  an iframe, there is no document load.
+   *                                  The targeted document is most likely
+   *                                  going to be already done loading.
+   *     * title (string) The document title being loaded.
+   *                      (sent only on state=stop)
+   *
+   *  - `frameUpdate`:
+   *    Sent when there was a change in the child frames contained in the document
+   *    or when the tab's context was switched to another frame.
+   *    This event can have four different forms depending on the type of change:
+   *    * One or many frames are updated:
+   *      { frames: [{ id, url, title, parentID }, ...] }
+   *    * One frame got destroyed:
+   *      { frames: [{ id, destroy: true }]}
+   *    * All frames got destroyed:
+   *      { destroyAll: true }
+   *    * We switched the context of the TabActor to a specific frame:
+   *      { selected: #id }
+   *
+   * ### Internal, non-rdp events:
+   * Various events are also dispatched on the TabActor itself that are not
+   * related to RDP, so, not sent to the client. They all relate to the documents
+   * tracked by the TabActor (its main targeted document, but also any of its
+   * iframes).
+   *  - will-navigate
+   *    This event fires once navigation starts.
+   *    All pending user prompts are dealt with,
+   *    but it is fired before the first request starts.
+   *  - navigate
+   *    This event is fired once the document's readyState is "complete".
+   *  - window-ready
+   *    This event is fired in various distinct scenarios:
+   *     * When a new Window object is crafted, equivalent of `DOMWindowCreated`.
+   *       It is dispatched before any page script is executed.
+   *     * We will have already received a window-ready event for this window
+   *       when it was created, but we received a window-destroyed event when
+   *       it was frozen into the bfcache, and now the user navigated back to
+   *       this page, so it's now live again and we should resume handling it.
+   *     * For each existing document, when an `attach` request is received.
+   *       At this point scripts in the page will be already loaded.
+   *     * When `swapFrameLoaders` is used, such as with moving tabs between
+   *       windows or toggling Responsive Design Mode.
+   *  - window-destroyed
+   *    This event is fired in two cases:
+   *     * When the window object is destroyed, i.e. when the related document
+   *       is garbage collected. This can happen when the tab is closed or the
+   *       iframe is removed from the DOM.
+   *       It is equivalent of `inner-window-destroyed` event.
+   *     * When the page goes into the bfcache and gets frozen.
+   *       The equivalent of `pagehide`.
+   *  - changed-toplevel-document
+   *    This event fires when we switch the TabActor targeted document
+   *    to one of its iframes, or back to its original top document.
+   *    It is dispatched between window-destroyed and window-ready.
+   *  - stylesheet-added
+   *    This event is fired when a StyleSheetActor is created.
+   *    It contains the following attribute :
+   *     * actor (StyleSheetActor) The created actor.
+   *
+   * Note that *all* these events are dispatched in the following order
+   * when we switch the context of the TabActor to a given iframe:
+   *  - will-navigate
+   *  - window-destroyed
+   *  - changed-toplevel-document
+   *  - window-ready
+   *  - navigate
+   *
+   * This class is subclassed by ContentActor and others.
+   * Subclasses are expected to implement a getter for the docShell property.
+   *
+   * @param connection DebuggerServerConnection
+   *        The conection to the client.
+   */
+  initialize: function(connection) {
+    Actor.prototype.initialize.call(this, connection);
 
-  // Flag eventually overloaded by sub classes in order to watch new docshells
-  // Used by the ChromeActor to list all frames in the Browser Toolbox
-  this.listenForNewDocShells = false;
+    this._tabActorPool = null;
+    // A map of actor names to actor instances provided by extensions.
+    this._extraActors = {};
+    this._exited = false;
+    this._sources = null;
+
+    // Map of DOM stylesheets to StyleSheetActors
+    this._styleSheetActors = new Map();
+
+    this._shouldAddNewGlobalAsDebuggee =
+      this._shouldAddNewGlobalAsDebuggee.bind(this);
+
+    this.makeDebugger = makeDebugger.bind(null, {
+      findDebuggees: () => {
+        return this.windows.concat(this.webextensionsContentScriptGlobals);
+      },
+      shouldAddNewGlobalAsDebuggee: this._shouldAddNewGlobalAsDebuggee
+    });
 
-  this.traits = {
-    reconfigure: true,
-    // Supports frame listing via `listFrames` request and `frameUpdate` events
-    // as well as frame switching via `switchToFrame` request
-    frames: true,
-    // Do not require to send reconfigure request to reset the document state
-    // to what it was before using the TabActor
-    noTabReconfigureOnClose: true,
-    // Supports the logInPage request.
-    logInPage: true,
-  };
+    // Flag eventually overloaded by sub classes in order to watch new docshells
+    // Used by the ChromeActor to list all frames in the Browser Toolbox
+    this.listenForNewDocShells = false;
 
-  this._workerActorList = null;
-  this._workerActorPool = null;
-  this._onWorkerActorListChanged = this._onWorkerActorListChanged.bind(this);
-}
+    this.traits = {
+      reconfigure: true,
+      // Supports frame listing via `listFrames` request and `frameUpdate` events
+      // as well as frame switching via `switchToFrame` request
+      frames: true,
+      // Do not require to send reconfigure request to reset the document state
+      // to what it was before using the TabActor
+      noTabReconfigureOnClose: true,
+      // Supports the logInPage request.
+      logInPage: true,
+    };
 
-TabActor.prototype = {
+    this._workerActorList = null;
+    this._workerActorPool = null;
+    this._onWorkerActorListChanged = this._onWorkerActorListChanged.bind(this);
+  },
+
   traits: null,
 
   // Optional console API listener options (e.g. used by the WebExtensionActor to
   // filter console messages by addonID), set to an empty (no options) object by default.
   consoleAPIListenerOptions: {},
 
   // Optional TabSources filter function (e.g. used by the WebExtensionActor to filter
   // sources by addonID), allow all sources by default.
@@ -487,16 +487,17 @@ TabActor.prototype = {
     this._appendExtraActors(response);
     return response;
   },
 
   /**
    * Called when the actor is removed from the connection.
    */
   destroy() {
+    Actor.prototype.destroy.call(this);
     this.exit();
   },
 
   /**
    * Called by the root actor when the underlying tab is closed.
    */
   exit() {
     if (this.exited) {
@@ -780,17 +781,20 @@ TabActor.prototype = {
                               .getInterface(Ci.nsIWebProgress);
     const window = webProgress.DOMWindow;
     const id = window.QueryInterface(Ci.nsIInterfaceRequestor)
                    .getInterface(Ci.nsIDOMWindowUtils)
                    .outerWindowID;
     let parentID = undefined;
     // Ignore the parent of the original document on non-e10s firefox,
     // as we get the xul window as parent and don't care about it.
-    if (window.parent && window != this._originalWindow) {
+    // Furthermore, ignore setting parentID when parent window is same as
+    // current window in order to deal with front end. e.g. toolbox will be fall
+    // into infinite loop due to recursive search with by using parent id.
+    if (window.parent && window.parent != window && window != this._originalWindow) {
       parentID = window.parent
                        .QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIDOMWindowUtils)
                        .outerWindowID;
     }
 
     return {
       id,
@@ -1455,34 +1459,18 @@ TabActor.prototype = {
       if (this._tabActorPool.has(actor)) {
         this._tabActorPool.removeActor(actor);
       }
       delete this._extraActors[name];
     }
   },
 };
 
-/**
- * The request types this actor can handle.
- */
-TabActor.prototype.requestTypes = {
-  "attach": TabActor.prototype.attach,
-  "detach": TabActor.prototype.detach,
-  "focus": TabActor.prototype.focus,
-  "reload": TabActor.prototype.reload,
-  "navigateTo": TabActor.prototype.navigateTo,
-  "reconfigure": TabActor.prototype.reconfigure,
-  "ensureCSSErrorReportingEnabled": TabActor.prototype.ensureCSSErrorReportingEnabled,
-  "switchToFrame": TabActor.prototype.switchToFrame,
-  "listFrames": TabActor.prototype.listFrames,
-  "listWorkers": TabActor.prototype.listWorkers,
-  "logInPage": TabActor.prototype.logInPage,
-};
-
-exports.TabActor = TabActor;
+exports.tabPrototype = tabPrototype;
+exports.TabActor = ActorClassWithSpec(tabSpec, tabPrototype);
 
 /**
  * The DebuggerProgressListener object is an nsIWebProgressListener which
  * handles onStateChange events for the inspected browser. If the user tries to
  * navigate away from a paused page, the listener makes sure that the debuggee
  * is resumed before the navigation begins.
  *
  * @param TabActor aTabActor
--- a/devtools/server/actors/window.js
+++ b/devtools/server/actors/window.js
@@ -1,20 +1,20 @@
 /* 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 { Ci } = require("chrome");
 const Services = require("Services");
-const { TabActor } = require("./tab");
+const { TabActor, tabPrototype } = require("./tab");
 
 const { extend } = require("devtools/shared/extend");
-const { ActorClassWithSpec, Actor } = require("devtools/shared/protocol");
+const { ActorClassWithSpec } = require("devtools/shared/protocol");
 const { tabSpec } = require("devtools/shared/specs/tab");
 
 /**
  * Creates a WindowActor for debugging a single window, like a browser window in Firefox,
  * but it can be used to reach any window in the process.  (Currently this is parent
  * process only because the root actor's `onGetWindow` doesn't try to cross process
  * boundaries.)  Both chrome and content windows are supported.
  *
@@ -29,21 +29,20 @@ const { tabSpec } = require("devtools/sh
  * maintain the properties of TabActor.prototype
  *
  * @param connection DebuggerServerConnection
  *        The connection to the client.
  * @param window DOMWindow
  *        The window.
  */
 
-const windowPrototype = extend({}, TabActor.prototype);
+const windowPrototype = extend({}, tabPrototype);
 
 windowPrototype.initialize = function(connection, window) {
-  Actor.prototype.initialize.call(this, connection);
-  TabActor.call(this, connection);
+  TabActor.prototype.initialize.call(this, connection);
 
   const docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIDocShell);
   Object.defineProperty(this, "docShell", {
     value: docShell,
     configurable: true
   });
 };
--- a/devtools/shared/css/generated/generate-properties-db.js
+++ b/devtools/shared/css/generated/generate-properties-db.js
@@ -15,16 +15,17 @@ const InspectorUtils = require("Inspecto
 
 // xpcshell can output extra information, so place some delimiter text between
 // the output of the css properties database.
 dump("DEVTOOLS_CSS_DB_DELIMITER");
 
 // Output JSON
 dump(JSON.stringify({
   cssProperties: cssProperties(),
+  preferences: preferences(),
   pseudoElements: pseudoElements()
 }));
 
 dump("DEVTOOLS_CSS_DB_DELIMITER");
 
 /*
  * A list of CSS Properties and their various characteristics. This is used on the
  * client-side when the CssPropertiesActor is not found, or when the client and server
@@ -42,13 +43,25 @@ function cssProperties() {
     if (key.includes("-moz-osx-")) {
       properties[key] = undefined;
     }
   }
   return properties;
 }
 
 /**
+ * A list of preferences of CSS properties.
+ */
+function preferences() {
+  const prefs = InspectorUtils.getCSSPropertyPrefs();
+  const result = [];
+  for (const {name, pref} of prefs) {
+    result.push([name, pref]);
+  }
+  return result;
+}
+
+/**
  * The list of all CSS Pseudo Elements.
  */
 function pseudoElements() {
   return InspectorUtils.getCSSPseudoElementNames();
 }
--- a/devtools/shared/css/generated/mach_commands.py
+++ b/devtools/shared/css/generated/mach_commands.py
@@ -36,38 +36,23 @@ def stringify(obj):
 class MachCommands(MachCommandBase):
     @Command(
         'devtools-css-db', category='post-build',
         description='Rebuild the devtool\'s static css properties database.')
     def generate_css_db(self):
         """Generate the static css properties database for devtools and write it to file."""
 
         print("Re-generating the css properties database...")
-        preferences = self.get_preferences()
         db = self.get_properties_db_from_xpcshell()
 
         self.output_template({
-            'preferences': stringify(preferences),
+            'preferences': stringify(db['preferences']),
             'cssProperties': stringify(db['cssProperties']),
             'pseudoElements': stringify(db['pseudoElements'])})
 
-    def get_preferences(self):
-        """Get all of the preferences associated with enabling and disabling a property."""
-        # The data takes the following form:
-        # [ (name, prop, id, flags, pref, proptype), ... ]
-        dataPath = resolve_path(self.topobjdir, 'layout/style/ServoCSSPropList.py')
-        data = runpy.run_path(dataPath)['data']
-
-        # Map this list
-        preferences = [
-            (p.name, p.pref) for p in data
-            if 'CSSPropFlags::Internal' not in p.flags and p.pref]
-
-        return preferences
-
     def get_properties_db_from_xpcshell(self):
         """Generate the static css properties db for devtools from an xpcshell script."""
         build = MozbuildObject.from_environment()
 
         # Get the paths
         script_path = resolve_path(self.topsrcdir,
             'devtools/shared/css/generated/generate-properties-db.js')
         gre_path = resolve_path(self.topobjdir, 'dist/bin')
--- a/devtools/shared/specs/tab.js
+++ b/devtools/shared/specs/tab.js
@@ -104,12 +104,12 @@ const tabSpec = generateActorSpec({
     logInPage: {
       request: {
         text: Option(0, "string"),
         category: Option(0, "string"),
         flags: Option(0, "string")
       },
       response: {}
     }
-  },
+  }
 });
 
 exports.tabSpec = tabSpec;
--- a/devtools/shared/tests/unit/test_css-properties-db.js
+++ b/devtools/shared/tests/unit/test_css-properties-db.js
@@ -31,36 +31,34 @@ function run_test() {
                                  "assertion run `mach devtools-css-db` to re-generate " +
                                  "the client side properties.";
 
   // Check that the platform and client match for pseudo elements.
   deepEqual(PSEUDO_ELEMENTS, InspectorUtils.getCSSPseudoElementNames(),
             "The pseudo elements match on the client and platform. " +
             propertiesErrorMessage);
 
+  const prefs = InspectorUtils.getCSSPropertyPrefs();
+  deepEqual(PREFERENCES, prefs.map(({name, pref}) => [name, pref]),
+            "The preferences match on the client and platform. " +
+            propertiesErrorMessage);
+
   /**
    * Check that the platform and client match for the details on their CSS properties.
    * Enumerate each property to aid in debugging. Sometimes these properties don't
    * completely agree due to differences in preferences. Check the currently set
    * preference for that property to see if it's enabled.
    */
   const platformProperties = generateCssProperties();
 
   for (const propertyName in CSS_PROPERTIES) {
     const platformProperty = platformProperties[propertyName];
     const clientProperty = CSS_PROPERTIES[propertyName];
     const deepEqual = isJsonDeepEqual(platformProperty, clientProperty);
 
-    // The "all" property can contain information that can be turned on and off by
-    // preferences. These values can be different between OSes, so ignore the equality
-    // check for this property, since this is likely to fail.
-    if (propertyName === "all") {
-      continue;
-    }
-
     if (deepEqual) {
       ok(true, `The static database and platform match for "${propertyName}".`);
     } else {
       ok(false, `The static database and platform do not match for ` + `
         "${propertyName}". ${propertiesErrorMessage}`);
     }
   }
 
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -3635,37 +3635,49 @@ nsDOMWindowUtils::DispatchEventToChromeO
   *aRetVal = false;
   NS_ENSURE_STATE(aTarget && aEvent);
   aEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
   *aRetVal = aTarget->
     DispatchEvent(*aEvent, CallerType::System, IgnoreErrors());
   return NS_OK;
 }
 
+static Result<nsIFrame*, nsresult>
+GetTargetFrame(const Element* aElement, const nsAString& aPseudoElement)
+{
+  nsIFrame* frame = aElement->GetPrimaryFrame();
+  if (!aPseudoElement.IsEmpty()) {
+    if (aPseudoElement.EqualsLiteral("::before")) {
+      frame = nsLayoutUtils::GetBeforeFrame(aElement);
+    } else if (aPseudoElement.EqualsLiteral("::after")) {
+      frame = nsLayoutUtils::GetAfterFrame(aElement);
+    } else {
+      return Err(NS_ERROR_INVALID_ARG);
+    }
+  }
+  return frame;
+}
+
 NS_IMETHODIMP
 nsDOMWindowUtils::GetOMTAStyle(Element* aElement,
                                const nsAString& aProperty,
                                const nsAString& aPseudoElement,
                                nsAString& aResult)
 {
   if (!aElement) {
     return NS_ERROR_INVALID_ARG;
   }
 
+  auto frameOrError = GetTargetFrame(aElement, aPseudoElement);
+  if (frameOrError.isErr()) {
+    return frameOrError.unwrapErr();
+  }
+  nsIFrame* frame = frameOrError.unwrap();
+
   RefPtr<nsROCSSPrimitiveValue> cssValue = nullptr;
-  nsIFrame* frame = aElement->GetPrimaryFrame();
-  if (!aPseudoElement.IsEmpty()) {
-    if (aPseudoElement.EqualsLiteral("::before")) {
-      frame = nsLayoutUtils::GetBeforeFrame(aElement);
-    } else if (aPseudoElement.EqualsLiteral("::after")) {
-      frame = nsLayoutUtils::GetAfterFrame(aElement);
-    } else {
-      return NS_ERROR_INVALID_ARG;
-    }
-  }
   if (frame && nsLayoutUtils::AreAsyncAnimationsEnabled()) {
     RefPtr<LayerManager> widgetLayerManager;
     if (nsIWidget* widget = GetWidget()) {
       widgetLayerManager = widget->GetLayerManager();
     }
 
     if (aProperty.EqualsLiteral("opacity")) {
       float value = 0;
@@ -3728,16 +3740,77 @@ nsDOMWindowUtils::GetOMTAStyle(Element* 
     cssValue->GetCssText(text, rv);
     aResult.Assign(text);
     return rv.StealNSResult();
   }
   aResult.Truncate();
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDOMWindowUtils::GetOMTCTransform(Element* aElement,
+                                   const nsAString& aPseudoElement,
+                                   nsAString& aResult)
+{
+  if (!aElement) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  if (GetWebRenderBridge()) {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
+  auto frameOrError = GetTargetFrame(aElement, aPseudoElement);
+  if (frameOrError.isErr()) {
+    return frameOrError.unwrapErr();
+  }
+
+  nsIFrame* frame = frameOrError.unwrap();
+  aResult.Truncate();
+  if (!frame) {
+    return NS_OK;
+  }
+
+  DisplayItemType itemType = DisplayItemType::TYPE_TRANSFORM;
+  if (nsLayoutUtils::HasEffectiveAnimation(frame, eCSSProperty_opacity) &&
+      !frame->IsTransformed()) {
+    itemType = DisplayItemType::TYPE_OPACITY;
+  }
+
+  Layer* layer = FrameLayerBuilder::GetDedicatedLayer(frame, itemType);
+  if (!layer) {
+    return NS_OK;
+  }
+
+  ShadowLayerForwarder* forwarder = layer->Manager()->AsShadowForwarder();
+  if (!forwarder || !forwarder->HasShadowManager()) {
+    return NS_OK;
+  }
+
+  MaybeTransform transform;
+  forwarder->GetShadowManager()->
+    SendGetTransform(layer->AsShadowableLayer()->GetShadow(), &transform);
+  if (transform.type() != MaybeTransform::TMatrix4x4) {
+    return NS_OK;
+  }
+
+  Matrix4x4 matrix = transform.get_Matrix4x4();
+  RefPtr<nsROCSSPrimitiveValue> cssValue =
+    nsComputedDOMStyle::MatrixToCSSValue(matrix);
+  if (!cssValue) {
+    return NS_OK;
+  }
+
+  nsAutoString text;
+  ErrorResult rv;
+  cssValue->GetCssText(text, rv);
+  aResult.Assign(text);
+  return rv.StealNSResult();
+}
+
 namespace {
 
 class HandlingUserInputHelper final : public nsIJSRAIIHelper
 {
 public:
   explicit HandlingUserInputHelper(bool aHandlingUserInput);
 
   NS_DECL_ISUPPORTS
--- a/dom/chrome-webidl/InspectorUtils.webidl
+++ b/dom/chrome-webidl/InspectorUtils.webidl
@@ -28,16 +28,17 @@ namespace InspectorUtils {
                                              unsigned long selectorIndex);
   [Throws] boolean selectorMatchesElement(
       Element element,
       CSSStyleRule rule,
       unsigned long selectorIndex,
       [TreatNullAs=EmptyString] optional DOMString pseudo = "");
   boolean isInheritedProperty(DOMString property);
   sequence<DOMString> getCSSPropertyNames(optional PropertyNamesOptions options);
+  sequence<PropertyPref> getCSSPropertyPrefs();
   [Throws] sequence<DOMString> getCSSValuesForProperty(DOMString property);
   [Throws] DOMString rgbToColorName(octet r, octet g, octet b);
   InspectorRGBATuple? colorToRGBA(DOMString colorString);
   boolean isValidCSSColor(DOMString colorString);
   [Throws] sequence<DOMString> getSubpropertiesForCSSProperty(DOMString property);
   [Throws] boolean cssPropertyIsShorthand(DOMString property);
 
   // TODO: Change this to use an enum.
@@ -80,16 +81,21 @@ namespace InspectorUtils {
 };
 
 dictionary PropertyNamesOptions {
   boolean includeAliases = false;
   boolean includeShorthands = true;
   boolean includeExperimentals = false;
 };
 
+dictionary PropertyPref {
+  required DOMString name;
+  required DOMString pref;
+};
+
 dictionary InspectorRGBATuple {
   /*
    * NOTE: This tuple is in the normal 0-255-sized RGB space but can be
    * fractional and may extend outside the 0-255 range.
    *
    * a is in the range 0 - 1.
    */
   double r = 0;
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -1692,16 +1692,26 @@ interface nsIDOMWindowUtils : nsISupport
   /*
    * Returns the value of a given property animated on the compositor thread.
    * If the property is NOT currently being animated on the compositor thread,
    * returns an empty string.
    */
   AString getOMTAStyle(in Element aElement, in AString aProperty,
                        [optional] in AString aPseudoElement);
 
+  /*
+   * Returns the value of the transform value on the compositor thread.
+   * Unlike the above getOMTAStyle, the transform value returned by this
+   * includes both of animating and APZ values.
+   * Note: This function doesn't work on WebRender at all.  Also this function
+   * does work only for transform layer and opacity layer with animations.
+   */
+  AString getOMTCTransform(in Element aElement,
+                           [optional] in AString aPseudoElement);
+
   /**
    * If aHandlingInput is true, this informs the event state manager that
    * we're handling user input. Otherwise, this is a no-op (as by default
    * we're not handling user input).
    * Remember to call destruct() on the return value!
    * See also nsIDOMWindowUtils::isHandlingUserInput.
    */
   nsIJSRAIIHelper setHandlingUserInput(in boolean aHandlingInput);
--- a/dom/media/AutoplayPolicy.cpp
+++ b/dom/media/AutoplayPolicy.cpp
@@ -3,16 +3,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/. */
 
 #include "AutoplayPolicy.h"
 
 #include "mozilla/EventStateManager.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/AudioContext.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/HTMLMediaElementBinding.h"
 #include "nsContentUtils.h"
 #include "nsIDocument.h"
 #include "MediaManager.h"
 
 namespace mozilla {
 namespace dom {
@@ -63,10 +64,56 @@ AutoplayPolicy::IsMediaElementAllowedToP
   // Activated by user gesture.
   if (aElement->OwnerDoc()->HasBeenUserActivated()) {
     return true;
   }
 
   return false;
 }
 
+/* static */ bool
+AutoplayPolicy::IsAudioContextAllowedToPlay(NotNull<AudioContext*> aContext)
+{
+  if (Preferences::GetBool("media.autoplay.enabled")) {
+    return true;
+  }
+
+  if (!Preferences::GetBool("media.autoplay.enabled.user-gestures-needed", false)) {
+    return true;
+  }
+
+  // Offline context won't directly output sound to audio devices.
+  if (aContext->IsOffline()) {
+    return true;
+  }
+
+  nsPIDOMWindowInner* window = aContext->GetOwner();
+  if (!window) {
+    return false;
+  }
+
+  // Pages which have been granted permission to capture WebRTC camera or
+  // microphone are assumed to be trusted, and are allowed to autoplay.
+  MediaManager* manager = MediaManager::GetIfExists();
+  if (manager) {
+    if (manager->IsActivelyCapturingOrHasAPermission(window->WindowID())) {
+      return true;
+    }
+  }
+
+  nsCOMPtr<nsIPrincipal> principal = aContext->GetParentObject()->AsGlobal()->PrincipalOrNull();
+
+  // Whitelisted.
+  if (principal &&
+      nsContentUtils::IsExactSitePermAllow(principal, "autoplay-media")) {
+    return true;
+  }
+
+  // Activated by user gesture.
+  if (window->GetExtantDoc()->HasBeenUserActivated()) {
+    return true;
+  }
+
+  return false;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/media/AutoplayPolicy.h
+++ b/dom/media/AutoplayPolicy.h
@@ -10,16 +10,17 @@
 #include "mozilla/NotNull.h"
 
 class nsIDocument;
 
 namespace mozilla {
 namespace dom {
 
 class HTMLMediaElement;
+class AudioContext;
 
 /**
  * AutoplayPolicy is used to manage autoplay logic for all kinds of media,
  * including MediaElement, Web Audio and Web Speech.
  *
  * Autoplay could be disable by turn off the pref "media.autoplay.enabled".
  * Once user disable autoplay, media could only be played if one of following
  * conditions is true.
@@ -27,14 +28,17 @@ class HTMLMediaElement;
  *    We restrict user gestures to "mouse click", "keyboard press" and "touch".
  * 2) Muted media content or video without audio content.
  * 3) Document's origin has the "autoplay-media" permission.
  */
 class AutoplayPolicy
 {
 public:
   static bool IsMediaElementAllowedToPlay(NotNull<HTMLMediaElement*> aElement);
+  static bool IsAudioContextAllowedToPlay(NotNull<AudioContext*> aContext);
+private:
+  static bool IsDocumentAllowedToPlay(nsIDocument* aDoc);
 };
 
 } // namespace dom
 } // namespace mozilla
 
-#endif
\ No newline at end of file
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/crashtests/1429507_1.html
@@ -0,0 +1,13 @@
+<html>
+  <head>
+    <script>
+      try { o1 = window.open("") } catch (e) {}
+      try { o1.location.reload() } catch (e) {}
+      try { o2 = new RTCPeerConnection({iceServers: [{"url": "stun:d"}]}) } catch (e) {}
+      try { o1.navigator.mediaDevices.getUserMedia({video: true, fake: true}).catch((error) => {}) } catch (e) {}
+      try { o2.createOffer({offerToReceiveVideo: true}).then((offer) => {
+        try { o1.navigator.mediaDevices.getUserMedia({video: true}) } catch (e) {};
+      }) } catch (e) {}
+    </script>
+  </head>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/crashtests/1429507_2.html
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <script>
+      try { o1 = window.open("") } catch(e) { }
+      try { o1.location.reload() } catch(e) { }
+      try { o2 = o1.navigator } catch(e) { }
+      try { o3 = o2.mediaDevices } catch(e) { }
+      try { o4 = new XMLHttpRequest() } catch(e) { }
+      try { o3.getUserMedia({video: true, fake: true }).then((stream) => {}).catch((error) => {}) } catch (e) {}
+      try { o4.open("T", "aa", false) } catch(e) { }
+      try { o4.send() } catch(e) { }
+      try { o3.getUserMedia({video: true}).then((stream) => {}).catch((error) => {}) } catch (e) {}
+    </script>
+  </head>
+</html>
--- a/dom/media/tests/crashtests/crashtests.list
+++ b/dom/media/tests/crashtests/crashtests.list
@@ -1,9 +1,9 @@
-default-preferences  pref(media.peerconnection.enabled,true) pref(media.navigator.permission.disabled,true)
+default-preferences  pref(media.peerconnection.enabled,true) pref(media.navigator.permission.disabled,true) pref(dom.disable_open_during_load,false)
 
 load 780790.html
 load 791270.html
 load 791278.html
 load 791330.html
 load 799419.html
 load 802982.html
 load 812785.html
@@ -15,9 +15,11 @@ load 860143.html
 load 861958.html
 load 863929.html
 load 1185191.html
 load 1281695.html
 load 1306476.html
 load 1348381.html
 load 1367930_1.html
 load 1367930_2.html
+pref(browser.link.open_newwindow,2) load 1429507_1.html # window.open() in tab doesn't work for crashtest in e10s, this opens a new window instead
+pref(browser.link.open_newwindow,2) load 1429507_2.html # window.open() in tab doesn't work for crashtest in e10s, this opens a new window instead
 load 1453030.html
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AudioContext.h"
 
 #include "blink/PeriodicWave.h"
 
 #include "mozilla/ErrorResult.h"
+#include "mozilla/NotNull.h"
 #include "mozilla/OwningNonNull.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Preferences.h"
 
 #include "mozilla/dom/AnalyserNode.h"
 #include "mozilla/dom/AnalyserNodeBinding.h"
 #include "mozilla/dom/AudioBufferSourceNodeBinding.h"
 #include "mozilla/dom/AudioContextBinding.h"
@@ -39,16 +40,17 @@
 
 #include "AudioBuffer.h"
 #include "AudioBufferSourceNode.h"
 #include "AudioChannelService.h"
 #include "AudioDestinationNode.h"
 #include "AudioListener.h"
 #include "AudioNodeStream.h"
 #include "AudioStream.h"
+#include "AutoplayPolicy.h"
 #include "BiquadFilterNode.h"
 #include "ChannelMergerNode.h"
 #include "ChannelSplitterNode.h"
 #include "ConstantSourceNode.h"
 #include "ConvolverNode.h"
 #include "DelayNode.h"
 #include "DynamicsCompressorNode.h"
 #include "GainNode.h"
@@ -78,16 +80,17 @@ namespace dom {
 static dom::AudioContext::AudioContextId gAudioContextId = 1;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(AudioContext)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDestination)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mListener)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromiseGripArray)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingResumePromises)
   if (!tmp->mIsStarted) {
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mActiveNodes)
   }
   // mDecodeJobs owns the WebAudioDecodeJob objects whose lifetime is managed explicitly.
   // mAllNodes is an array of weak pointers, ignore it here.
   // mPannerNodes is an array of weak pointers, ignore it here.
   // mBasicWaveFormCache cannot participate in cycles, ignore it here.
 
@@ -96,16 +99,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Au
   tmp->DisconnectFromWindow();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DOMEventTargetHelper)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(AudioContext,
                                                   DOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDestination)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListener)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromiseGripArray)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingResumePromises)
   if (!tmp->mIsStarted) {
     MOZ_ASSERT(tmp->mIsOffline,
                "Online AudioContexts should always be started");
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mActiveNodes)
   }
   // mDecodeJobs owns the WebAudioDecodeJob objects whose lifetime is managed explicitly.
   // mAllNodes is an array of weak pointers, ignore it here.
   // mPannerNodes is an array of weak pointers, ignore it here.
@@ -144,23 +148,38 @@ AudioContext::AudioContext(nsPIDOMWindow
   , mCloseCalled(false)
   , mSuspendCalled(false)
   , mIsDisconnecting(false)
 {
   bool mute = aWindow->AddAudioContext(this);
 
   // Note: AudioDestinationNode needs an AudioContext that must already be
   // bound to the window.
-  mDestination = new AudioDestinationNode(this, aIsOffline,
-                                          aNumberOfChannels, aLength, aSampleRate);
+  bool allowedToStart = AutoplayPolicy::IsAudioContextAllowedToPlay(WrapNotNull(this));
+  mDestination = new AudioDestinationNode(this,
+                                          aIsOffline,
+                                          allowedToStart,
+                                          aNumberOfChannels,
+                                          aLength,
+                                          aSampleRate);
 
   // The context can't be muted until it has a destination.
   if (mute) {
     Mute();
   }
+
+  // If we won't allow audio context to start, we need to suspend all its stream
+  // in order to delay the state changing from 'suspend' to 'start'.
+  if (!allowedToStart) {
+    ErrorResult rv;
+    RefPtr<Promise> dummy = Suspend(rv);
+    MOZ_ASSERT(!rv.Failed(), "can't create promise");
+    MOZ_ASSERT(dummy->State() != Promise::PromiseState::Rejected,
+               "suspend failed");
+  }
 }
 
 nsresult
 AudioContext::Init()
 {
   if (!mIsOffline) {
     nsresult rv = mDestination->CreateAudioChannelAgent();
     if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -721,16 +740,21 @@ AudioContext::Shutdown()
       RefPtr<Promise> ignored = Close(IgnoreErrors());
     }
 
     for (auto p : mPromiseGripArray) {
       p->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
     }
 
     mPromiseGripArray.Clear();
+
+    for (const auto& p : mPendingResumePromises) {
+      p->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    }
+    mPendingResumePromises.Clear();
   }
 
   // Release references to active nodes.
   // Active AudioNodes don't unregister in destructors, at which point the
   // Node is already unregistered.
   mActiveNodes.Clear();
 
   // For offline contexts, we can destroy the MediaStreamGraph at this point.
@@ -900,16 +924,26 @@ AudioContext::OnStateChanged(void* aProm
     // already freed memory.
     if (mPromiseGripArray.Contains(promise)) {
       promise->MaybeResolveWithUndefined();
       DebugOnly<bool> rv = mPromiseGripArray.RemoveElement(promise);
       MOZ_ASSERT(rv, "Promise wasn't in the grip array?");
     }
   }
 
+  // Resolve all pending promises once the audio context has been allowed to
+  // start.
+  if (mAudioContextState == AudioContextState::Suspended &&
+      aNewState == AudioContextState::Running) {
+    for (const auto& p : mPendingResumePromises) {
+      p->MaybeResolveWithUndefined();
+    }
+    mPendingResumePromises.Clear();
+  }
+
   if (mAudioContextState != aNewState) {
     RefPtr<OnStateChangeTask> task = new OnStateChangeTask(this);
     Dispatch(task.forget());
   }
 
   mAudioContextState = aNewState;
 }
 
@@ -983,32 +1017,34 @@ AudioContext::Resume(ErrorResult& aRv)
   }
 
   if (mAudioContextState == AudioContextState::Closed ||
       mCloseCalled) {
     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
     return promise.forget();
   }
 
-  Destination()->Resume();
+  mPendingResumePromises.AppendElement(promise);
+
+  if (AutoplayPolicy::IsAudioContextAllowedToPlay(WrapNotNull(this))) {
+    Destination()->Resume();
 
-  nsTArray<MediaStream*> streams;
-  // If mSuspendCalled is false then we already resumed all our streams,
-  // so don't resume them again (since suspend(); resume(); resume(); should
-  // be OK). But we still need to do ApplyAudioContextOperation
-  // to ensure our new promise is resolved.
-  if (mSuspendCalled) {
-    streams = GetAllStreams();
+    nsTArray<MediaStream*> streams;
+    // If mSuspendCalled is false then we already resumed all our streams,
+    // so don't resume them again (since suspend(); resume(); resume(); should
+    // be OK). But we still need to do ApplyAudioContextOperation
+    // to ensure our new promise is resolved.
+    if (mSuspendCalled) {
+      streams = GetAllStreams();
+    }
+    Graph()->ApplyAudioContextOperation(DestinationStream()->AsAudioNodeStream(),
+                                        streams,
+                                        AudioContextOperation::Resume, promise);
+    mSuspendCalled = false;
   }
-  mPromiseGripArray.AppendElement(promise);
-  Graph()->ApplyAudioContextOperation(DestinationStream()->AsAudioNodeStream(),
-                                      streams,
-                                      AudioContextOperation::Resume, promise);
-
-  mSuspendCalled = false;
 
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 AudioContext::Close(ErrorResult& aRv)
 {
   nsCOMPtr<nsIGlobalObject> parentObject = do_QueryInterface(GetParentObject());
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -348,19 +348,24 @@ private:
   const AudioContextId mId;
   // Note that it's important for mSampleRate to be initialized before
   // mDestination, as mDestination's constructor needs to access it!
   const float mSampleRate;
   AudioContextState mAudioContextState;
   RefPtr<AudioDestinationNode> mDestination;
   RefPtr<AudioListener> mListener;
   nsTArray<UniquePtr<WebAudioDecodeJob> > mDecodeJobs;
-  // This array is used to keep the suspend/resume/close promises alive until
+  // This array is used to keep the suspend/close promises alive until
   // they are resolved, so we can safely pass them accross threads.
   nsTArray<RefPtr<Promise>> mPromiseGripArray;
+  // This array is used to onlly keep the resume promises alive until they are
+  // resolved, so we can safely pass them accross threads. If the audio context
+  // is not allowed to play, the promise would be pending in this array and be
+  // resolved until audio context has been allowed and user call resume() again.
+  nsTArray<RefPtr<Promise>> mPendingResumePromises;
   // See RegisterActiveNode.  These will keep the AudioContext alive while it
   // is rendering and the window remains alive.
   nsTHashtable<nsRefPtrHashKey<AudioNode> > mActiveNodes;
   // Raw (non-owning) references to all AudioNodes for this AudioContext.
   nsTHashtable<nsPtrHashKey<AudioNode> > mAllNodes;
   // Hashsets containing all the PannerNodes, to compute the doppler shift.
   // These are weak pointers.
   nsTHashtable<nsPtrHashKey<PannerNode> > mPannerNodes;
--- a/dom/media/webaudio/AudioDestinationNode.cpp
+++ b/dom/media/webaudio/AudioDestinationNode.cpp
@@ -318,18 +318,20 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)
 NS_INTERFACE_MAP_END_INHERITING(AudioNode)
 
 NS_IMPL_ADDREF_INHERITED(AudioDestinationNode, AudioNode)
 NS_IMPL_RELEASE_INHERITED(AudioDestinationNode, AudioNode)
 
 AudioDestinationNode::AudioDestinationNode(AudioContext* aContext,
                                            bool aIsOffline,
+                                           bool aAllowedToStart,
                                            uint32_t aNumberOfChannels,
-                                           uint32_t aLength, float aSampleRate)
+                                           uint32_t aLength,
+                                           float aSampleRate)
   : AudioNode(aContext, aNumberOfChannels,
               ChannelCountMode::Explicit, ChannelInterpretation::Speakers)
   , mFramesToProduce(aLength)
   , mIsOffline(aIsOffline)
   , mAudioChannelSuspended(false)
   , mCaptured(false)
   , mAudible(AudioChannelService::AudibleState::eAudible)
 {
@@ -347,17 +349,17 @@ AudioDestinationNode::AudioDestinationNo
   AudioNodeStream::Flags flags =
     AudioNodeStream::NEED_MAIN_THREAD_CURRENT_TIME |
     AudioNodeStream::NEED_MAIN_THREAD_FINISHED |
     AudioNodeStream::EXTERNAL_OUTPUT;
   mStream = AudioNodeStream::Create(aContext, engine, flags, graph);
   mStream->AddMainThreadListener(this);
   mStream->AddAudioOutput(&gWebAudioOutputKey);
 
-  if (!aIsOffline) {
+  if (!aIsOffline && aAllowedToStart) {
     graph->NotifyWhenGraphStarted(mStream);
   }
 }
 
 AudioDestinationNode::~AudioDestinationNode()
 {
 }
 
--- a/dom/media/webaudio/AudioDestinationNode.h
+++ b/dom/media/webaudio/AudioDestinationNode.h
@@ -20,16 +20,17 @@ class AudioDestinationNode final : publi
                                  , public nsIAudioChannelAgentCallback
                                  , public MainThreadMediaStreamListener
 {
 public:
   // This node type knows what MediaStreamGraph to use based on
   // whether it's in offline mode.
   AudioDestinationNode(AudioContext* aContext,
                        bool aIsOffline,
+                       bool aAllowedToStart,
                        uint32_t aNumberOfChannels = 0,
                        uint32_t aLength = 0,
                        float aSampleRate = 0.0f);
 
   void DestroyMediaStream() override;
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioDestinationNode, AudioNode)
--- a/dom/media/webaudio/test/mochitest.ini
+++ b/dom/media/webaudio/test/mochitest.ini
@@ -181,16 +181,17 @@ tags=capturestream
 [test_mediaStreamAudioSourceNodeNoGC.html]
 [test_mediaStreamAudioSourceNodePassThrough.html]
 [test_mediaStreamAudioSourceNodeResampling.html]
 tags=capturestream
 [test_mixingRules.html]
 skip-if = toolkit == 'android' # bug 1091965
 [test_nodeToParamConnection.html]
 [test_nodeCreationDocumentGone.html]
+[test_notAllowedToStartAudioContextGC.html]
 [test_OfflineAudioContext.html]
 [test_offlineDestinationChannelCountLess.html]
 [test_offlineDestinationChannelCountMore.html]
 [test_oscillatorNode.html]
 [test_oscillatorNode2.html]
 [test_oscillatorNodeNegativeFrequency.html]
 [test_oscillatorNodePassThrough.html]
 [test_oscillatorNodeStart.html]
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/test/test_notAllowedToStartAudioContextGC.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test GC for not-allow-to-start audio context</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.requestFlakyTimeout(`Checking that something does not happen`);
+
+SimpleTest.waitForExplicitFinish();
+
+var destId;
+
+function observer(subject, topic, data) {
+  let id = parseInt(data);
+  ok(id != destId, "dropping another node, not the context's destination");
+}
+
+SpecialPowers.addAsyncObserver(observer, "webaudio-node-demise", false);
+SimpleTest.registerCleanupFunction(function() {
+  SpecialPowers.removeAsyncObserver(observer, "webaudio-node-demise");
+});
+
+SpecialPowers.pushPrefEnv({"set": [["media.autoplay.enabled", false],
+                                   ["media.autoplay.enabled.user-gestures-needed", true]]},
+                          startTest);
+
+function startTest() {
+  info("- create audio context -");
+  let ac = new AudioContext();
+
+  info("- get node Id -");
+  destId = SpecialPowers.getPrivilegedProps(ac.destination, "id");
+
+  info("- trigger GCs -");
+  SpecialPowers.forceGC();
+  SpecialPowers.forceCC();
+  SpecialPowers.forceGC();
+
+  info("- after three GCs -");
+
+  // We're doing this async so that we can receive observerservice messages.
+  setTimeout(function() {
+    ok(true, `AudioContext that has been prevented
+              from starting has correctly survived GC`)
+    SimpleTest.finish();
+  }, 1);
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -7818,16 +7818,19 @@ HTMLEditRules::BustUpInlinesAtRangeEndpo
                         SplitAtEdges::eDoNotCreateEmptyContainer);
     if (NS_WARN_IF(!CanHandleEditAction())) {
       return NS_ERROR_EDITOR_DESTROYED;
     }
     if (NS_WARN_IF(splitEndInlineResult.Failed())) {
       return splitEndInlineResult.Rv();
     }
     EditorRawDOMPoint splitPointAtEnd(splitEndInlineResult.SplitPoint());
+    if (NS_WARN_IF(!splitPointAtEnd.IsSet())) {
+      return NS_ERROR_FAILURE;
+    }
     aRangeItem.mEndContainer = splitPointAtEnd.GetContainer();
     aRangeItem.mEndOffset = splitPointAtEnd.Offset();
   }
 
   nsCOMPtr<nsIContent> startInline =
     GetHighestInlineParent(*aRangeItem.mStartContainer);
 
   if (startInline) {
@@ -7842,16 +7845,19 @@ HTMLEditRules::BustUpInlinesAtRangeEndpo
     }
     if (NS_WARN_IF(splitStartInlineResult.Failed())) {
       return splitStartInlineResult.Rv();
     }
     // XXX If we split only here because of collapsed range, we're modifying
     //     only start point of aRangeItem.  Shouldn't we modify end point here
     //     if it's collapsed?
     EditorRawDOMPoint splitPointAtStart(splitStartInlineResult.SplitPoint());
+    if (NS_WARN_IF(!splitPointAtStart.IsSet())) {
+      return NS_ERROR_FAILURE;
+    }
     aRangeItem.mStartContainer = splitPointAtStart.GetContainer();
     aRangeItem.mStartOffset = splitPointAtStart.Offset();
   }
 
   return NS_OK;
 }
 
 nsresult
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -282,16 +282,22 @@ public:
    * activation of an inline table editing UI element
    * @param aUIAnonymousElement [IN] the inline table editing UI element
    */
   nsresult DoInlineTableEditingAction(const Element& aUIAnonymousElement);
 
   already_AddRefed<Element>
   GetElementOrParentByTagName(const nsAString& aTagName, nsINode* aNode);
 
+  /**
+    * Get an active editor's editing host in DOM window.  If this editor isn't
+    * active in the DOM window, this returns NULL.
+    */
+  Element* GetActiveEditingHost();
+
 protected: // May be called by friends.
   /****************************************************************************
    * Some classes like TextEditRules, HTMLEditRules, WSRunObject which are
    * part of handling edit actions are allowed to call the following protected
    * methods.  However, those methods won't prepare caches of some objects
    * which are necessary for them.  So, if you want some following methods
    * to do that for you, you need to create a wrapper method in public scope
    * and call it.
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/crashtests/1423776.html
@@ -0,0 +1,15 @@
+<script>
+function go() {
+  svgvar00002.addEventListener("DOMNodeInserted", () => {
+    svg.appendChild(svgvar00008);
+    document.execCommand("insertOrderedList", false);
+  });
+  svgvar00002.insertAdjacentHTML("afterBegin", table.outerHTML);
+}
+</script>
+<body onload=go()>
+<table id="table"></table>
+<b contenteditable="true">
+<svg id="svg">
+<feConvolveMatrix id="svgvar00002"/>
+<feConvolveMatrix id="svgvar00008"/>
--- a/editor/libeditor/crashtests/crashtests.list
+++ b/editor/libeditor/crashtests/crashtests.list
@@ -92,13 +92,14 @@ needs-focus load 1402196.html
 load 1402469.html
 load 1402526.html
 load 1402904.html
 load 1405747.html
 load 1408170.html
 load 1414581.html
 load 1415231.html
 load 1423767.html
+needs-focus load 1423776.html
 needs-focus load 1424450.html
 load 1425091.html
 load 1443664.html
 skip-if(Android) needs-focus load 1444630.html
 load 1446451.html
--- a/editor/nsIHTMLEditor.idl
+++ b/editor/nsIHTMLEditor.idl
@@ -461,16 +461,10 @@ interface nsIHTMLEditor : nsISupports
 
   /**
    * A boolean indicating if a return key pressed in a paragraph creates
    * another paragraph or just inserts a <br> at the caret
    *
    * @return    true if CR in a paragraph creates a new paragraph
    */
   attribute boolean returnInParagraphCreatesNewParagraph;
-
-  /**
-   * Get an active editor's editing host in DOM window.  If this editor isn't
-   * active in the DOM window, this returns NULL.
-   */
-  [noscript, notxpcom] Element GetActiveEditingHost();
 };
 
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/test/mochitest/helper_bug1464568_opacity.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test that opacity animation is correctly placed during asynchronous scrolling</title>
+  <script src="apz_test_utils.js"></script>
+  <script src="/tests/SimpleTest/paint_listener.js"></script>
+  <meta name="viewport" content="width=device-width"/>
+  <style>
+    #anim {
+      background: green;
+      width: 100px;
+      height: 100px;
+      animation: anim 100s step-start;
+    }
+    @keyframes anim {
+      from { opacity: 0; }
+      to { opacity: 1; }
+    }
+  </style>
+</head>
+<body>
+ <!--
+  This height should be smaller than window height, otherwise the animation
+  followed by this element will be out of view, thus the animation doesn't run
+  on the compositor.
+  -->
+ <div style="height: 500px"></div>
+ <div id="anim"></div>
+</body>
+<script>
+'use strict';
+
+const utils = SpecialPowers.getDOMWindowUtils(window);
+
+async function test_opacity() {
+  utils.setDisplayPortForElement(0, 0, 300, 1000, document.documentElement, 1);
+  await promiseAllPaintsDone();
+
+  let transform = utils.getOMTCTransform(anim);
+  is(transform, "matrix(1, 0, 0, 1, 0, 0)",
+     "The element shouldn't be moved before scrolling");
+
+  utils.setAsyncScrollOffset(document.documentElement, 0, 300);
+
+  await new Promise(resolve => waitForApzFlushedRepaints(resolve));
+
+  transform = utils.getOMTCTransform(anim);
+  is(transform, "matrix(1, 0, 0, 1, 0, -300)",
+     "Element should have been moved by the offset");
+}
+
+if (utils.layerManagerType == 'WebRender') {
+  ok(true, "This test doesn't need to run on WebRender");
+  subtestDone();
+} else {
+  waitUntilApzStable().then(test_opacity).then(subtestDone);
+}
+
+</script>
+</html>
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/test/mochitest/helper_bug1464568_transform.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test that transform animation is correctly placed during asynchronous scrolling</title>
+  <script src="apz_test_utils.js"></script>
+  <script src="/tests/SimpleTest/paint_listener.js"></script>
+  <meta name="viewport" content="width=device-width"/>
+  <style>
+    #anim {
+      background: green;
+      width: 100px;
+      height: 100px;
+      animation: anim 100s step-start;
+    }
+    @keyframes anim {
+      from { transform: translateX(100px); }
+      to { transform: translateX(200px); }
+    }
+  </style>
+</head>
+<body>
+ <!--
+  This height should be smaller than window height, otherwise the animation
+  followed by this element will be out of view, thus the animation doesn't run
+  on the compositor.
+  -->
+ <div style="height: 500px"></div>
+ <div id="anim"></div>
+</body>
+<script>
+'use strict';
+
+const utils = SpecialPowers.getDOMWindowUtils(window);
+
+async function test_transform() {
+  utils.setDisplayPortForElement(0, 0, 300, 1000, document.documentElement, 1);
+  await promiseAllPaintsDone();
+
+  let transform = utils.getOMTCTransform(anim);
+  is(transform, "matrix(1, 0, 0, 1, 200, 0)",
+     "The element shouldn't be moved before scrolling");
+
+  utils.setAsyncScrollOffset(document.documentElement, 0, 300);
+
+  await new Promise(resolve => waitForApzFlushedRepaints(resolve));
+
+  transform = utils.getOMTCTransform(anim);
+  is(transform, "matrix(1, 0, 0, 1, 200, -300)",
+     "Element should have been moved by the offset");
+}
+
+if (utils.layerManagerType == 'WebRender') {
+  ok(true, "This test doesn't need to run on WebRender");
+  subtestDone();
+} else {
+  waitUntilApzStable().then(test_transform).then(subtestDone);
+}
+
+</script>
+</html>
--- a/gfx/layers/apz/test/mochitest/mochitest.ini
+++ b/gfx/layers/apz/test/mochitest/mochitest.ini
@@ -9,16 +9,18 @@
     helper_bug1151663.html
     helper_bug1162771.html
     helper_bug1271432.html
     helper_bug1280013.html
     helper_bug1285070.html
     helper_bug1299195.html
     helper_bug1346632.html
     helper_bug1414336.html
+    helper_bug1464568_transform.html
+    helper_bug1464568_opacity.html
     helper_click.html
     helper_div_pan.html
     helper_drag_click.html
     helper_drag_scroll.html
     helper_iframe_pan.html
     helper_iframe1.html
     helper_iframe2.html
     helper_hittest_backface_hidden.html
@@ -54,16 +56,18 @@
 [test_bug1151667.html]
   skip-if = (os == 'android') || webrender # wheel events not supported on mobile, bug 1424752 for webrender
 [test_bug1253683.html]
   skip-if = (os == 'android') # wheel events not supported on mobile
 [test_bug1277814.html]
   skip-if = (os == 'android') # wheel events not supported on mobile
 [test_bug1304689.html]
 [test_bug1304689-2.html]
+[test_bug1464568.html]
+  skip-if = (toolkit == 'android') # setAsyncScrollOffset doesn't work on mobile
 [test_frame_reconstruction.html]
   skip-if = webrender # bug 1424752
 [test_group_mouseevents.html]
   skip-if = (toolkit == 'android') # mouse events not supported on mobile
 [test_group_pointerevents.html]
   skip-if = os == 'win' && os_version == '10.0' # Bug 1404836
 [test_group_touchevents.html]
   skip-if = webrender # bug 1424752
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/test/mochitest/test_bug1464568.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="apz_test_utils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+    if (isApzEnabled()) {
+      SimpleTest.waitForExplicitFinish();
+
+      const subtests = [
+        { file: 'helper_bug1464568_transform.html',
+          prefs: [["apz.test.logging_enabled", true]] },
+        { file: 'helper_bug1464568_opacity.html',
+          prefs: [["apz.test.logging_enabled", true]] },
+      ];
+      // Run the actual test in its own window, because it requires that the
+      // root APZC be scrollable. Mochitest pages themselves often run
+      // inside an iframe which means we have no control over the root APZC.
+      window.onload = () => {
+        runSubtestsSeriallyInFreshWindows(subtests)
+        .then(SimpleTest.finish, SimpleTest.finish);
+      };
+    }
+  </script>
+</head>
+<body>
+</body>
+</html>
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -704,54 +704,73 @@ SampleAnimations(Layer* aLayer,
             ApplyAnimatedValue(layer,
                                aStorage,
                                animation.property(),
                                animation.data(),
                                animationValue);
             break;
           }
           case AnimationHelper::SampleResult::Skipped:
-            // We don't need to update animation values for this layer since
-            // the values haven't changed.
-#ifdef DEBUG
-            // Sanity check that the animation value is surely unchanged.
             switch (animations[0].property()) {
-              case eCSSProperty_opacity:
+              case eCSSProperty_opacity: {
                 MOZ_ASSERT(
                   layer->AsHostLayer()->GetShadowOpacitySetByAnimation());
+#ifdef DEBUG
                 // Disable this assertion until the root cause is fixed in bug
                 // 1459775.
                 // MOZ_ASSERT(FuzzyEqualsMultiplicative(
                 //   Servo_AnimationValue_GetOpacity(animationValue),
                 //   *(aStorage->GetAnimationOpacity(layer->GetCompositorAnimationsId()))));
+#endif
+                // Even if opacity animation value has unchanged, we have to set
+                // the shadow base transform value here since the value might
+                // have been changed by APZC.
+                HostLayer* layerCompositor = layer->AsHostLayer();
+                layerCompositor->SetShadowBaseTransform(
+                  layer->GetBaseTransform());
+                layerCompositor->SetShadowTransformSetByAnimation(false);
                 break;
+              }
               case eCSSProperty_transform: {
                 MOZ_ASSERT(
                   layer->AsHostLayer()->GetShadowTransformSetByAnimation());
-
                 MOZ_ASSERT(previousValue);
-
+#ifdef DEBUG
                 const TransformData& transformData =
                   animations[0].data().get_TransformData();
                 Matrix4x4 frameTransform =
                   ServoAnimationValueToMatrix4x4(animationValue, transformData);
                 Matrix4x4 transformInDevice =
                   FrameTransformToTransformInDevice(frameTransform,
                                                     layer,
                                                     transformData);
                 MOZ_ASSERT(
                   previousValue->mTransform.mTransformInDevSpace.FuzzyEqualsMultiplicative(
                   transformInDevice));
+#endif
+                // In the case of transform we have to set the unchanged
+                // transform value again becasue APZC might have modified the
+                // previous shadow base transform value.
+                HostLayer* layerCompositor = layer->AsHostLayer();
+                layerCompositor->SetShadowBaseTransform(
+                  // FIXME: Bug 1459775: It seems possible that we somehow try
+                  // to sample animations and skip it even if the previous value
+                  // has been discarded from the animation storage when we enable
+                  // layer tree cache. So for the safety, in the case where we
+                  // have no previous animation value, we set non-animating value
+                  // instead.
+                  previousValue
+                    ? previousValue->mTransform.mTransformInDevSpace
+                    : layer->GetBaseTransform());
                 break;
               }
               default:
                 MOZ_ASSERT_UNREACHABLE("Unsupported properties");
                 break;
             }
-#endif
             break;
           case AnimationHelper::SampleResult::None: {
             HostLayer* layerCompositor = layer->AsHostLayer();
             layerCompositor->SetShadowBaseTransform(layer->GetBaseTransform());
             layerCompositor->SetShadowTransformSetByAnimation(false);
             layerCompositor->SetShadowOpacity(layer->GetOpacity());
             layerCompositor->SetShadowOpacitySetByAnimation(false);
             break;
@@ -1244,19 +1263,20 @@ AsyncCompositionManager::ApplyAsyncTrans
 void
 AsyncCompositionManager::GetFrameUniformity(FrameUniformityData* aOutData)
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   mLayerTransformRecorder.EndTest(aOutData);
 }
 
 bool
-AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame,
-                                             TimeDuration aVsyncRate,
-                                             TransformsToSkip aSkip)
+AsyncCompositionManager::TransformShadowTree(
+  TimeStamp aCurrentFrame,
+  TimeDuration aVsyncRate,
+  CompositorBridgeParentBase::TransformsToSkip aSkip)
 {
   AUTO_PROFILER_LABEL("AsyncCompositionManager::TransformShadowTree", GRAPHICS);
 
   Layer* root = mLayerManager->GetRoot();
   if (!root) {
     return false;
   }
 
@@ -1295,17 +1315,17 @@ AsyncCompositionManager::TransformShadow
   }
 #endif // defined(MOZ_WIDGET_ANDROID)
 
   // Reset the previous time stamp if we don't already have any running
   // animations to avoid using the time which is far behind for newly
   // started animations.
   mPreviousFrameTimeStamp = wantNextFrame ? aCurrentFrame : TimeStamp();
 
-  if (!(aSkip & TransformsToSkip::APZ)) {
+  if (!(aSkip & CompositorBridgeParentBase::TransformsToSkip::APZ)) {
     // FIXME/bug 775437: unify this interface with the ~native-fennec
     // derived code
     //
     // Attempt to apply an async content transform to any layer that has
     // an async pan zoom controller (which means that it is rendered
     // async using Gecko). If this fails, fall back to transforming the
     // primary scrollable layer.  "Failing" here means that we don't
     // find a frame that is async scrollable.  Note that the fallback
--- a/gfx/layers/composite/AsyncCompositionManager.h
+++ b/gfx/layers/composite/AsyncCompositionManager.h
@@ -14,16 +14,17 @@
 #include "mozilla/TimeStamp.h"          // for TimeStamp
 #include "mozilla/dom/ScreenOrientation.h"  // for ScreenOrientation
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
 #include "mozilla/layers/FrameUniformityData.h" // For FrameUniformityData
 #include "mozilla/layers/LayersMessages.h"  // for TargetConfig
 #include "mozilla/RefPtr.h"                   // for nsRefPtr
 #include "nsISupportsImpl.h"            // for LayerManager::AddRef, etc
+#include "CompositorBridgeParent.h"     // for TransformsToSkip
 
 namespace mozilla {
 namespace layers {
 
 class Layer;
 class LayerManagerComposite;
 class AutoResolveRefLayers;
 class CompositorBridgeParent;
@@ -78,20 +79,21 @@ public:
    * (or for whatever reason wants to refresh the viewport information).
    * The information refresh happens because the compositor will call
    * AndroidDynamicToolbarAnimator::FirstPaint() on the next frame of composition.
    */
   void ForceIsFirstPaint() { mIsFirstPaint = true; }
 
   // Sample transforms for layer trees.  Return true to request
   // another animation frame.
-  enum class TransformsToSkip : uint8_t { NoneOfThem = 0, APZ = 1 };
-  bool TransformShadowTree(TimeStamp aCurrentFrame,
-                           TimeDuration aVsyncRate,
-                           TransformsToSkip aSkip = TransformsToSkip::NoneOfThem);
+  bool TransformShadowTree(
+    TimeStamp aCurrentFrame,
+    TimeDuration aVsyncRate,
+    CompositorBridgeParentBase::TransformsToSkip aSkip =
+      CompositorBridgeParentBase::TransformsToSkip::NoneOfThem);
 
   // Calculates the correct rotation and applies the transform to
   // our layer manager
   void ComputeRotation();
 
   // Call after updating our layer tree.
   void Updated(bool isFirstPaint, const TargetConfig& aTargetConfig)
   {
@@ -231,18 +233,16 @@ private:
   // The following two fields are only needed on Fennec with C++ APZ, because
   // then we need to reposition the gecko scrollbar to deal with the
   // dynamic toolbar shifting content around.
   FrameMetrics::ViewID mRootScrollableId;
   ScreenMargin mFixedLayerMargins;
 #endif
 };
 
-MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AsyncCompositionManager::TransformsToSkip)
-
 class MOZ_STACK_CLASS AutoResolveRefLayers {
 public:
   explicit AutoResolveRefLayers(AsyncCompositionManager* aManager,
                                 CompositorBridgeParent* aCompositor = nullptr,
                                 bool* aHasRemoteContent = nullptr,
                                 bool* aResolvePlugins = nullptr) :
     mManager(aManager)
   {
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1387,31 +1387,31 @@ CompositorBridgeParent::SetTestSampleTim
 
 void
 CompositorBridgeParent::LeaveTestMode(const LayersId& aId)
 {
   mTestTime = Nothing();
 }
 
 void
-CompositorBridgeParent::ApplyAsyncProperties(LayerTransactionParent* aLayerTree)
+CompositorBridgeParent::ApplyAsyncProperties(LayerTransactionParent* aLayerTree,
+                                             TransformsToSkip aSkip)
 {
   // NOTE: This should only be used for testing. For example, when mTestTime is
   // non-empty, or when called from test-only methods like
   // LayerTransactionParent::RecvGetAnimationTransform.
 
   // Synchronously update the layer tree
   if (aLayerTree->GetRoot()) {
     AutoResolveRefLayers resolve(mCompositionManager);
     SetShadowProperties(mLayerManager->GetRoot());
 
     TimeStamp time = mTestTime.valueOr(mCompositorScheduler->GetLastComposeTime());
     bool requestNextFrame =
-      mCompositionManager->TransformShadowTree(time, mVsyncRate,
-        AsyncCompositionManager::TransformsToSkip::APZ);
+      mCompositionManager->TransformShadowTree(time, mVsyncRate, aSkip);
     if (!requestNextFrame) {
       CancelCurrentCompositeTask();
       // Pretend we composited in case someone is waiting for this event.
       TimeStamp now = TimeStamp::Now();
       DidComposite(now, now);
     }
   }
 }
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -108,17 +108,19 @@ public:
   virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) { return nullptr; }
 
   virtual void NotifyClearCachedResources(LayerTransactionParent* aLayerTree) { }
 
   virtual void ScheduleComposite(LayerTransactionParent* aLayerTree) { }
   virtual bool SetTestSampleTime(const LayersId& aId,
                                  const TimeStamp& aTime) { return true; }
   virtual void LeaveTestMode(const LayersId& aId) { }
-  virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree) = 0;
+  enum class TransformsToSkip : uint8_t { NoneOfThem = 0, APZ = 1 };
+  virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree,
+                                    TransformsToSkip aSkip) = 0;
   virtual void SetTestAsyncScrollOffset(const LayersId& aLayersId,
                                         const FrameMetrics::ViewID& aScrollId,
                                         const CSSPoint& aPoint) = 0;
   virtual void SetTestAsyncZoom(const LayersId& aLayersId,
                                 const FrameMetrics::ViewID& aScrollId,
                                 const LayerToParentLayerScale& aZoom) = 0;
   virtual void FlushApzRepaints(const LayersId& aLayersId) = 0;
   virtual void GetAPZTestData(const LayersId& aLayersId,
@@ -173,16 +175,18 @@ protected:
   ~CompositorBridgeParentBase() override;
 
   bool mCanSend;
 
 private:
   RefPtr<CompositorManagerParent> mCompositorManager;
 };
 
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CompositorBridgeParentBase::TransformsToSkip)
+
 class CompositorBridgeParent final : public CompositorBridgeParentBase
                                    , public CompositorController
                                    , public CompositorVsyncSchedulerOwner
 {
   friend class CompositorThreadHolder;
   friend class InProcessCompositorSession;
   friend class gfx::GPUProcessManager;
   friend class gfx::GPUParent;
@@ -232,17 +236,18 @@ public:
 
   void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
                            const TransactionInfo& aInfo,
                            bool aHitTestUpdate) override;
   void ScheduleComposite(LayerTransactionParent* aLayerTree) override;
   bool SetTestSampleTime(const LayersId& aId,
                          const TimeStamp& aTime) override;
   void LeaveTestMode(const LayersId& aId) override;
-  void ApplyAsyncProperties(LayerTransactionParent* aLayerTree) override;
+  void ApplyAsyncProperties(LayerTransactionParent* aLayerTree,
+                            TransformsToSkip aSkip) override;
   CompositorAnimationStorage* GetAnimationStorage();
   void SetTestAsyncScrollOffset(const LayersId& aLayersId,
                                 const FrameMetrics::ViewID& aScrollId,
                                 const CSSPoint& aPoint) override;
   void SetTestAsyncZoom(const LayersId& aLayersId,
                         const FrameMetrics::ViewID& aScrollId,
                         const LayerToParentLayerScale& aZoom) override;
   void FlushApzRepaints(const LayersId& aLayersId) override;
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
@@ -461,28 +461,29 @@ CrossProcessCompositorBridgeParent::Leav
   }
 
   MOZ_ASSERT(state->mParent);
   state->mParent->LeaveTestMode(aId);
 }
 
 void
 CrossProcessCompositorBridgeParent::ApplyAsyncProperties(
-    LayerTransactionParent* aLayerTree)
+    LayerTransactionParent* aLayerTree,
+    TransformsToSkip aSkip)
 {
   LayersId id = aLayerTree->GetId();
   MOZ_ASSERT(id.IsValid());
   const CompositorBridgeParent::LayerTreeState* state =
     CompositorBridgeParent::GetIndirectShadowTree(id);
   if (!state) {
     return;
   }
 
   MOZ_ASSERT(state->mParent);
-  state->mParent->ApplyAsyncProperties(aLayerTree);
+  state->mParent->ApplyAsyncProperties(aLayerTree, aSkip);
 }
 
 void
 CrossProcessCompositorBridgeParent::SetTestAsyncScrollOffset(
     const LayersId& aLayersId,
     const FrameMetrics::ViewID& aScrollId,
     const CSSPoint& aPoint)
 {
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
@@ -83,17 +83,18 @@ public:
   void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
                            const TransactionInfo& aInfo,
                            bool aHitTestUpdate) override;
   void ScheduleComposite(LayerTransactionParent* aLayerTree) override;
   void NotifyClearCachedResources(LayerTransactionParent* aLayerTree) override;
   bool SetTestSampleTime(const LayersId& aId,
                          const TimeStamp& aTime) override;
   void LeaveTestMode(const LayersId& aId) override;
-  void ApplyAsyncProperties(LayerTransactionParent* aLayerTree) override;
+  void ApplyAsyncProperties(LayerTransactionParent* aLayerTree,
+                            TransformsToSkip aSkip) override;
   void SetTestAsyncScrollOffset(const LayersId& aLayersId,
                                 const FrameMetrics::ViewID& aScrollId,
                                 const CSSPoint& aPoint) override;
   void SetTestAsyncZoom(const LayersId& aLayersId,
                         const FrameMetrics::ViewID& aScrollId,
                         const LayerToParentLayerScale& aZoom) override;
   void FlushApzRepaints(const LayersId& aLayersId) override;
   void GetAPZTestData(const LayersId& aLayersId,
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -695,17 +695,18 @@ LayerTransactionParent::RecvGetAnimation
                                                 float* aOpacity,
                                                 bool* aHasAnimationOpacity)
 {
   *aHasAnimationOpacity = false;
   if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
     return IPC_FAIL_NO_REASON(this);
   }
 
-  mCompositorBridge->ApplyAsyncProperties(this);
+  mCompositorBridge->ApplyAsyncProperties(
+    this, CompositorBridgeParentBase::TransformsToSkip::APZ);
 
   if (!mAnimStorage) {
     return IPC_FAIL_NO_REASON(this);
   }
 
   Maybe<float> opacity = mAnimStorage->GetAnimationOpacity(aCompositorAnimationsId);
   if (opacity) {
     *aOpacity = *opacity;
@@ -721,32 +722,85 @@ LayerTransactionParent::RecvGetAnimation
   if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
     return IPC_FAIL_NO_REASON(this);
   }
 
   // Make sure we apply the latest animation style or else we can end up with
   // a race between when we temporarily clear the animation transform (in
   // CompositorBridgeParent::SetShadowProperties) and when animation recalculates
   // the value.
-  mCompositorBridge->ApplyAsyncProperties(this);
+  mCompositorBridge->ApplyAsyncProperties(
+    this, CompositorBridgeParentBase::TransformsToSkip::APZ);
 
   if (!mAnimStorage) {
     return IPC_FAIL_NO_REASON(this);
   }
 
   Maybe<Matrix4x4> transform = mAnimStorage->GetAnimationTransform(aCompositorAnimationsId);
   if (transform) {
     *aTransform = *transform;
   } else {
     *aTransform = mozilla::void_t();
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
+LayerTransactionParent::RecvGetTransform(const LayerHandle& aLayerHandle,
+                                         MaybeTransform* aTransform)
+{
+  if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+
+  Layer* layer = AsLayer(aLayerHandle);
+  if (!layer) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+
+  mCompositorBridge->ApplyAsyncProperties(
+    this, CompositorBridgeParentBase::TransformsToSkip::NoneOfThem);
+
+  Matrix4x4 transform = layer->AsHostLayer()->GetShadowBaseTransform();
+  // Undo the scale transform applied by FrameTransformToTransformInDevice in
+  // AsyncCompositionManager.cpp.
+  if (ContainerLayer* c = layer->AsContainerLayer()) {
+    transform.PostScale(1.0f/c->GetInheritedXScale(),
+                        1.0f/c->GetInheritedYScale(),
+                        1.0f);
+  }
+  float scale = 1;
+  Point3D scaledOrigin;
+  Point3D transformOrigin;
+  for (uint32_t i = 0; i < layer->GetAnimations().Length(); i++) {
+    if (layer->GetAnimations()[i].data().type() == AnimationData::TTransformData) {
+      const TransformData& data = layer->GetAnimations()[i].data().get_TransformData();
+      scale = data.appUnitsPerDevPixel();
+      scaledOrigin =
+        Point3D(NS_round(NSAppUnitsToFloatPixels(data.origin().x, scale)),
+                NS_round(NSAppUnitsToFloatPixels(data.origin().y, scale)),
+                0.0f);
+      transformOrigin = data.transformOrigin();
+      break;
+    }
+  }
+
+  // If our parent isn't a perspective layer, then the offset into reference
+  // frame coordinates will have been applied to us. Add an inverse translation
+  // to cancel it out.
+  if (!layer->GetParent() || !layer->GetParent()->GetTransformIsPerspective()) {
+    transform.PostTranslate(-scaledOrigin.x, -scaledOrigin.y, -scaledOrigin.z);
+  }
+
+  *aTransform = transform;
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
 LayerTransactionParent::RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aScrollID,
                                                  const float& aX, const float& aY)
 {
   if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
     return IPC_FAIL_NO_REASON(this);
   }
 
   mCompositorBridge->SetTestAsyncScrollOffset(GetId(), aScrollID, CSSPoint(aX, aY));
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -120,16 +120,18 @@ protected:
   mozilla::ipc::IPCResult RecvScheduleComposite() override;
   mozilla::ipc::IPCResult RecvSetTestSampleTime(const TimeStamp& aTime) override;
   mozilla::ipc::IPCResult RecvLeaveTestMode() override;
   mozilla::ipc::IPCResult RecvGetAnimationOpacity(const uint64_t& aCompositorAnimationsId,
                                                   float* aOpacity,
                                                   bool* aHasAnimationOpacity) override;
   mozilla::ipc::IPCResult RecvGetAnimationTransform(const uint64_t& aCompositorAnimationsId,
                                                     MaybeTransform* aTransform) override;
+  mozilla::ipc::IPCResult RecvGetTransform(const LayerHandle& aHandle,
+                                           MaybeTransform* aTransform) override;
   mozilla::ipc::IPCResult RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aId,
                                                    const float& aX, const float& aY) override;
   mozilla::ipc::IPCResult RecvSetAsyncZoom(const FrameMetrics::ViewID& aId,
                                            const float& aValue) override;
   mozilla::ipc::IPCResult RecvFlushApzRepaints() override;
   mozilla::ipc::IPCResult RecvGetAPZTestData(APZTestData* aOutData) override;
   mozilla::ipc::IPCResult RecvRequestProperty(const nsString& aProperty, float* aValue) override;
   mozilla::ipc::IPCResult RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -83,16 +83,20 @@ parent:
 
   // Returns the value of the transform applied to the layer by animation after
   // factoring out translation components introduced to account for the offset
   // of the corresponding frame and transform origin and after converting to CSS
   // pixels. If the layer is not transformed by animation, the return value will
   // be void_t.
   sync GetAnimationTransform(uint64_t aCompositorAnimationId) returns (MaybeTransform transform);
 
+  // Returns the value of the transform applied to the layer by animation and
+  // APZC.
+  sync GetTransform(LayerHandle layer) returns (MaybeTransform transform);
+
   // The next time the layer tree is composited, add this async scroll offset in
   // CSS pixels for the given ViewID.
   // Useful for testing rendering of async scrolling.
   sync SetAsyncScrollOffset(ViewID id, float x, float y);
 
   // The next time the layer tree is composited, include this async zoom in
   // for the given ViewID.
   // Useful for testing rendering of async zooming.
--- a/intl/uconv/nsIScriptableUConv.idl
+++ b/intl/uconv/nsIScriptableUConv.idl
@@ -37,22 +37,16 @@ interface nsIScriptableUnicodeConverter 
   ACString Finish();
 
   /**
    * Converts the data from one Charset to Unicode.
    */
   AString ConvertToUnicode(in ACString aSrc);
 
   /**
-   * Converts an array of bytes to a unicode string.
-   */
-  AString convertFromByteArray([const,array,size_is(aCount)] in octet aData,
-                               in unsigned long aCount);
-
-  /**
    * Convert a unicode string to an array of bytes. Finish does not need to be
    * called.
    */
   void convertToByteArray(in AString aString,
                           [optional] out unsigned long aLen,
                           [array, size_is(aLen),retval] out octet aData);
 
   /**
--- a/intl/uconv/nsScriptableUConv.cpp
+++ b/intl/uconv/nsScriptableUConv.cpp
@@ -109,40 +109,31 @@ nsScriptableUnicodeConverter::Finish(nsA
   mDecoder->Encoding()->NewDecoderWithBOMRemovalInto(*mDecoder);
   mEncoder->Encoding()->NewEncoderInto(*mEncoder);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScriptableUnicodeConverter::ConvertToUnicode(const nsACString& aSrc, nsAString& _retval)
 {
-  return ConvertFromByteArray(
-    reinterpret_cast<const uint8_t*>(aSrc.BeginReading()),
-    aSrc.Length(),
-    _retval);
-}
-
-NS_IMETHODIMP
-nsScriptableUnicodeConverter::ConvertFromByteArray(const uint8_t* aData,
-                                                   uint32_t aCount,
-                                                   nsAString& _retval)
-{
   if (!mDecoder)
     return NS_ERROR_FAILURE;
 
-  CheckedInt<size_t> needed = mDecoder->MaxUTF16BufferLength(aCount);
+  uint32_t length = aSrc.Length();
+
+  CheckedInt<size_t> needed = mDecoder->MaxUTF16BufferLength(length);
   if (!needed.isValid() || needed.value() > UINT32_MAX) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   if (!_retval.SetLength(needed.value(), fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  auto src = MakeSpan(aData, aCount);
+  auto src = MakeSpan(reinterpret_cast<const uint8_t*>(aSrc.BeginReading()), length);
   uint32_t result;
   size_t read;
   size_t written;
   bool hadErrors;
   // The UTF-8 decoder used to throw regardless of the error behavior.
   // Simulating the old behavior for compatibility with legacy callers.
   // If callers want control over the behavior, they should switch to
   // TextDecoder.
@@ -152,17 +143,17 @@ nsScriptableUnicodeConverter::ConvertFro
     if (result != kInputEmpty) {
       return NS_ERROR_UDEC_ILLEGALINPUT;
     }
   } else {
     Tie(result, read, written, hadErrors) =
       mDecoder->DecodeToUTF16(src, _retval, false);
   }
   MOZ_ASSERT(result == kInputEmpty);
-  MOZ_ASSERT(read == aCount);
+  MOZ_ASSERT(read == length);
   MOZ_ASSERT(written <= needed.value());
   Unused << hadErrors;
   if (!_retval.SetLength(written, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }
 
--- a/ipc/glue/SharedMemoryBasic_mach.mm
+++ b/ipc/glue/SharedMemoryBasic_mach.mm
@@ -7,18 +7,16 @@
 
 #include <map>
 
 #include <mach/vm_map.h>
 #include <mach/mach_port.h>
 #if defined(XP_IOS)
 #include <mach/vm_map.h>
 #define mach_vm_address_t vm_address_t
-#define mach_vm_allocate vm_allocate
-#define mach_vm_deallocate vm_deallocate
 #define mach_vm_map vm_map
 #define mach_vm_read vm_read
 #define mach_vm_region_recurse vm_region_recurse_64
 #define mach_vm_size_t vm_size_t
 #else
 #include <mach/mach_vm.h>
 #endif
 #include <pthread.h>
@@ -530,52 +528,39 @@ toVMAddress(void* pointer)
   return static_cast<mach_vm_address_t>(reinterpret_cast<uintptr_t>(pointer));
 }
 
 bool
 SharedMemoryBasic::Create(size_t size)
 {
   MOZ_ASSERT(mPort == MACH_PORT_NULL, "already initialized");
 
-  mach_vm_address_t address;
-
-  kern_return_t kr = mach_vm_allocate(mach_task_self(), &address, round_page(size), VM_FLAGS_ANYWHERE);
-  if (kr != KERN_SUCCESS) {
-    LOG_ERROR("Failed to allocate mach_vm_allocate shared memory (%zu bytes). %s (%x)\n",
-              size, mach_error_string(kr), kr);
-    return false;
-  }
-
   memory_object_size_t memoryObjectSize = round_page(size);
 
-  kr = mach_make_memory_entry_64(mach_task_self(),
-                                 &memoryObjectSize,
-                                 address,
-                                 VM_PROT_DEFAULT,
-                                 &mPort,
-                                 MACH_PORT_NULL);
+  kern_return_t kr = mach_make_memory_entry_64(mach_task_self(),
+                                               &memoryObjectSize,
+                                               0,
+                                               MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT,
+                                               &mPort,
+                                               MACH_PORT_NULL);
   if (kr != KERN_SUCCESS || memoryObjectSize < round_page(size)) {
     LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n",
               size, mach_error_string(kr), kr);
     CloseHandle();
-    mach_vm_deallocate(mach_task_self(), address, round_page(size));
     return false;
   }
 
-  mMemory = toPointer(address);
   Mapped(size);
   return true;
 }
 
 bool
 SharedMemoryBasic::Map(size_t size)
 {
-  if (mMemory) {
-    return true;
-  }
+  MOZ_ASSERT(mMemory == nullptr);
 
   if (MACH_PORT_NULL == mPort) {
     return false;
   }
 
   kern_return_t kr;
   mach_vm_address_t address = 0;
 
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -995,16 +995,18 @@ description =
 [PLayerTransaction::SetTestSampleTime]
 description =
 [PLayerTransaction::LeaveTestMode]
 description =
 [PLayerTransaction::GetAnimationOpacity]
 description =
 [PLayerTransaction::GetAnimationTransform]
 description =
+[PLayerTransaction::GetTransform]
+description = test only
 [PLayerTransaction::SetAsyncScrollOffset]
 description =
 [PLayerTransaction::SetAsyncZoom]
 description =
 [PLayerTransaction::GetAPZTestData]
 description =
 [PLayerTransaction::RequestProperty]
 description =
--- a/js/ipc/JavaScriptBase.h
+++ b/js/ipc/JavaScriptBase.h
@@ -26,166 +26,188 @@ class JavaScriptBase : public WrapperOwn
 
     virtual void ActorDestroy(WrapperOwner::ActorDestroyReason why) override {
         WrapperOwner::ActorDestroy(why);
     }
 
     /*** IPC handlers ***/
 
     mozilla::ipc::IPCResult RecvPreventExtensions(const uint64_t& objId, ReturnStatus* rs) override {
-        if (!Answer::RecvPreventExtensions(ObjectId::deserialize(objId), rs)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvPreventExtensions(obj.value(), rs)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvGetPropertyDescriptor(const uint64_t& objId, const JSIDVariant& id,
                                                       ReturnStatus* rs,
                                                       PPropertyDescriptor* out) override {
-        if (!Answer::RecvGetPropertyDescriptor(ObjectId::deserialize(objId), id, rs, out)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvGetPropertyDescriptor(obj.value(), id, rs, out)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvGetOwnPropertyDescriptor(const uint64_t& objId,
                                                          const JSIDVariant& id,
                                                          ReturnStatus* rs,
                                                          PPropertyDescriptor* out) override {
-        if (!Answer::RecvGetOwnPropertyDescriptor(ObjectId::deserialize(objId), id, rs, out)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvGetOwnPropertyDescriptor(obj.value(), id, rs, out)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvDefineProperty(const uint64_t& objId, const JSIDVariant& id,
                                                const PPropertyDescriptor& flags, ReturnStatus* rs) override {
-        if (!Answer::RecvDefineProperty(ObjectId::deserialize(objId), id, flags, rs)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvDefineProperty(obj.value(), id, flags, rs)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvDelete(const uint64_t& objId, const JSIDVariant& id,
                                        ReturnStatus* rs) override {
-        if (!Answer::RecvDelete(ObjectId::deserialize(objId), id, rs)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvDelete(obj.value(), id, rs)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
 
     mozilla::ipc::IPCResult RecvHas(const uint64_t& objId, const JSIDVariant& id,
                                     ReturnStatus* rs, bool* bp) override {
-        if (!Answer::RecvHas(ObjectId::deserialize(objId), id, rs, bp)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvHas(obj.value(), id, rs, bp)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvHasOwn(const uint64_t& objId, const JSIDVariant& id,
                                        ReturnStatus* rs, bool* bp) override {
-        if (!Answer::RecvHasOwn(ObjectId::deserialize(objId), id, rs, bp)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvHasOwn(obj.value(), id, rs, bp)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvGet(const uint64_t& objId, const JSVariant& receiverVar, const JSIDVariant& id,
                                     ReturnStatus* rs, JSVariant* result) override {
-        if (!Answer::RecvGet(ObjectId::deserialize(objId), receiverVar, id, rs, result)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvGet(obj.value(), receiverVar, id, rs, result)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvSet(const uint64_t& objId, const JSIDVariant& id, const JSVariant& value,
                                     const JSVariant& receiverVar, ReturnStatus* rs) override {
-        if (!Answer::RecvSet(ObjectId::deserialize(objId), id, value, receiverVar, rs)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvSet(obj.value(), id, value, receiverVar, rs)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
 
     mozilla::ipc::IPCResult RecvIsExtensible(const uint64_t& objId, ReturnStatus* rs,
                                              bool* result) override {
-        if (!Answer::RecvIsExtensible(ObjectId::deserialize(objId), rs, result)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvIsExtensible(obj.value(), rs, result)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvCallOrConstruct(const uint64_t& objId, InfallibleTArray<JSParam>&& argv,
                                                 const bool& construct, ReturnStatus* rs, JSVariant* result,
                                                 nsTArray<JSParam>* outparams) override {
-        if (!Answer::RecvCallOrConstruct(ObjectId::deserialize(objId), std::move(argv), construct, rs, result, outparams)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvCallOrConstruct(obj.value(), std::move(argv), construct, rs, result, outparams)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvHasInstance(const uint64_t& objId, const JSVariant& v, ReturnStatus* rs, bool* bp) override {
-        if (!Answer::RecvHasInstance(ObjectId::deserialize(objId), v, rs, bp)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvHasInstance(obj.value(), v, rs, bp)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvGetBuiltinClass(const uint64_t& objId, ReturnStatus* rs, uint32_t* classValue) override {
-        if (!Answer::RecvGetBuiltinClass(ObjectId::deserialize(objId), rs, classValue)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvGetBuiltinClass(obj.value(), rs, classValue)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvIsArray(const uint64_t& objId, ReturnStatus* rs, uint32_t* answer) override {
-        if (!Answer::RecvIsArray(ObjectId::deserialize(objId), rs, answer)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvIsArray(obj.value(), rs, answer)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvClassName(const uint64_t& objId, nsCString* result) override {
-        if (!Answer::RecvClassName(ObjectId::deserialize(objId), result)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvClassName(obj.value(), result)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvGetPrototype(const uint64_t& objId, ReturnStatus* rs, ObjectOrNullVariant* result) override {
-        if (!Answer::RecvGetPrototype(ObjectId::deserialize(objId), rs, result)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvGetPrototype(obj.value(), rs, result)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvGetPrototypeIfOrdinary(const uint64_t& objId, ReturnStatus* rs, bool* isOrdinary,
                                                        ObjectOrNullVariant* result) override
     {
-        if (!Answer::RecvGetPrototypeIfOrdinary(ObjectId::deserialize(objId), rs, isOrdinary, result)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvGetPrototypeIfOrdinary(obj.value(), rs, isOrdinary, result)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvRegExpToShared(const uint64_t& objId, ReturnStatus* rs, nsString* source, uint32_t* flags) override {
-        if (!Answer::RecvRegExpToShared(ObjectId::deserialize(objId), rs, source, flags)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvRegExpToShared(obj.value(), rs, source, flags)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
 
     mozilla::ipc::IPCResult RecvGetPropertyKeys(const uint64_t& objId, const uint32_t& flags,
                                                 ReturnStatus* rs, nsTArray<JSIDVariant>* ids) override {
-        if (!Answer::RecvGetPropertyKeys(ObjectId::deserialize(objId), flags, rs, ids)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvGetPropertyKeys(obj.value(), flags, rs, ids)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvInstanceOf(const uint64_t& objId, const JSIID& iid,
                                            ReturnStatus* rs, bool* instanceof) override {
-        if (!Answer::RecvInstanceOf(ObjectId::deserialize(objId), iid, rs, instanceof)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvInstanceOf(obj.value(), iid, rs, instanceof)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
     mozilla::ipc::IPCResult RecvDOMInstanceOf(const uint64_t& objId, const int& prototypeID, const int& depth,
                                               ReturnStatus* rs, bool* instanceof) override {
-        if (!Answer::RecvDOMInstanceOf(ObjectId::deserialize(objId), prototypeID, depth, rs, instanceof)) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvDOMInstanceOf(obj.value(), prototypeID, depth, rs, instanceof)) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
 
     mozilla::ipc::IPCResult RecvDropObject(const uint64_t& objId) override {
-        if (!Answer::RecvDropObject(ObjectId::deserialize(objId))) {
+        Maybe<ObjectId> obj(ObjectId::deserialize(objId));
+        if (obj.isNothing() || !Answer::RecvDropObject(obj.value())) {
             return IPC_FAIL_NO_REASON(this);
         }
         return IPC_OK();
     }
 
     /*** Dummy call handlers ***/
 
     bool SendDropObject(const ObjectId& objId) override {
--- a/js/ipc/JavaScriptLogging.h
+++ b/js/ipc/JavaScriptLogging.h
@@ -163,20 +163,25 @@ class Logging
           case JSVariant::TnsString: {
               nsAutoCString tmp;
               format(value.get_nsString(), tmp);
               out = nsPrintfCString("\"%s\"", tmp.get());
               break;
           }
           case JSVariant::TObjectVariant: {
               const ObjectVariant& ovar = value.get_ObjectVariant();
-              if (ovar.type() == ObjectVariant::TLocalObject)
-                  formatObject(incoming, true, ObjectId::deserialize(ovar.get_LocalObject().serializedId()), out);
-              else
-                  formatObject(incoming, false, ObjectId::deserialize(ovar.get_RemoteObject().serializedId()), out);
+              if (ovar.type() == ObjectVariant::TLocalObject) {
+                  Maybe<ObjectId> objId(ObjectId::deserialize(ovar.get_LocalObject().serializedId()));
+                  MOZ_RELEASE_ASSERT(objId.isSome());
+                  formatObject(incoming, true, objId.value(), out);
+              } else {
+                  Maybe<ObjectId> objId(ObjectId::deserialize(ovar.get_RemoteObject().serializedId()));
+                  MOZ_RELEASE_ASSERT(objId.isSome());
+                  formatObject(incoming, false, objId.value(), out);
+              }
               break;
           }
           case JSVariant::TSymbolVariant: {
               out = "<Symbol>";
               break;
           }
           case JSVariant::Tdouble: {
               out = nsPrintfCString("%.0f", value.get_double());
--- a/js/ipc/JavaScriptShared.h
+++ b/js/ipc/JavaScriptShared.h
@@ -24,17 +24,17 @@ class ObjectId {
     // doubles. See bug 1065811 comment 12 for an explanation.
     static const size_t SERIAL_NUMBER_BITS = 47;
     static const size_t FLAG_BITS = 1;
     static const uint64_t SERIAL_NUMBER_MAX = (uint64_t(1) << SERIAL_NUMBER_BITS) - 1;
 
     explicit ObjectId(uint64_t serialNumber, bool hasXrayWaiver)
       : serialNumber_(serialNumber), hasXrayWaiver_(hasXrayWaiver)
     {
-        if (MOZ_UNLIKELY(serialNumber == 0 || serialNumber > SERIAL_NUMBER_MAX))
+        if (isInvalidSerialNumber(serialNumber))
             MOZ_CRASH("Bad CPOW Id");
     }
 
     bool operator==(const ObjectId& other) const {
         bool equal = serialNumber() == other.serialNumber();
         MOZ_ASSERT_IF(equal, hasXrayWaiver() == other.hasXrayWaiver());
         return equal;
     }
@@ -44,27 +44,34 @@ class ObjectId {
     uint64_t serialNumber() const { return serialNumber_; }
     bool hasXrayWaiver() const { return hasXrayWaiver_; }
     uint64_t serialize() const {
         MOZ_ASSERT(serialNumber(), "Don't send a null ObjectId over IPC");
         return uint64_t((serialNumber() << FLAG_BITS) | ((hasXrayWaiver() ? 1 : 0) << 0));
     }
 
     static ObjectId nullId() { return ObjectId(); }
-    static ObjectId deserialize(uint64_t data) {
-        return ObjectId(data >> FLAG_BITS, data & 1);
+    static Maybe<ObjectId> deserialize(uint64_t data) {
+        if (isInvalidSerialNumber(data >> FLAG_BITS)) {
+            return Nothing();
+        }
+        return Some(ObjectId(data >> FLAG_BITS, data & 1));
     }
 
     // For use with StructGCPolicy.
     void trace(JSTracer*) const {}
     bool needsSweep() const { return false; }
 
   private:
     ObjectId() : serialNumber_(0), hasXrayWaiver_(false) {}
 
+    static bool isInvalidSerialNumber(uint64_t aSerialNumber) {
+        return aSerialNumber == 0 || aSerialNumber > SERIAL_NUMBER_MAX;
+    }
+
     uint64_t serialNumber_ : SERIAL_NUMBER_BITS;
     bool hasXrayWaiver_ : 1;
 };
 
 class JavaScriptShared;
 
 // DefaultHasher<T> requires that T coerce to an integral type. We could make
 // ObjectId do that, but doing so would weaken our type invariants, so we just
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -1176,17 +1176,19 @@ WrapperOwner::fromObjectVariant(JSContex
     } else {
         return fromLocalObjectVariant(cx, objVar.get_LocalObject());
     }
 }
 
 JSObject*
 WrapperOwner::fromRemoteObjectVariant(JSContext* cx, const RemoteObject& objVar)
 {
-    ObjectId objId = ObjectId::deserialize(objVar.serializedId());
+    Maybe<ObjectId> maybeObjId(ObjectId::deserialize(objVar.serializedId()));
+    MOZ_RELEASE_ASSERT(maybeObjId.isSome());
+    ObjectId objId = maybeObjId.value();
     RootedObject obj(cx, findCPOWById(objId));
     if (!obj) {
 
         // All CPOWs live in the privileged junk scope.
         RootedObject junkScope(cx, xpc::PrivilegedJunkScope());
         JSAutoRealm ar(cx, junkScope);
         RootedValue v(cx, UndefinedValue());
         // We need to setLazyProto for the getPrototype/getPrototypeIfOrdinary
@@ -1222,16 +1224,17 @@ WrapperOwner::fromRemoteObjectVariant(JS
     if (!JS_WrapObject(cx, &obj))
         return nullptr;
     return obj;
 }
 
 JSObject*
 WrapperOwner::fromLocalObjectVariant(JSContext* cx, const LocalObject& objVar)
 {
-    ObjectId id = ObjectId::deserialize(objVar.serializedId());
-    Rooted<JSObject*> obj(cx, findObjectById(cx, id));
+    Maybe<ObjectId> id(ObjectId::deserialize(objVar.serializedId()));
+    MOZ_RELEASE_ASSERT(id.isSome());
+    Rooted<JSObject*> obj(cx, findObjectById(cx, id.value()));
     if (!obj)
         return nullptr;
     if (!JS_WrapObject(cx, &obj))
         return nullptr;
     return obj;
 }
--- a/layout/base/ShapeUtils.cpp
+++ b/layout/base/ShapeUtils.cpp
@@ -119,25 +119,39 @@ ShapeUtils::ComputeInsetRect(const Uniqu
                              const nsRect& aRefBox)
 {
   MOZ_ASSERT(aBasicShape->GetShapeType() == StyleBasicShapeType::Inset,
              "The basic shape must be inset()!");
 
   const nsTArray<nsStyleCoord>& coords = aBasicShape->Coordinates();
   MOZ_ASSERT(coords.Length() == 4, "wrong number of arguments");
 
-  nsMargin inset(coords[0].ComputeCoordPercentCalc(aRefBox.height),
-                 coords[1].ComputeCoordPercentCalc(aRefBox.width),
-                 coords[2].ComputeCoordPercentCalc(aRefBox.height),
-                 coords[3].ComputeCoordPercentCalc(aRefBox.width));
+  nsMargin inset(coords[0].ComputeCoordPercentCalc(aRefBox.Height()),
+                 coords[1].ComputeCoordPercentCalc(aRefBox.Width()),
+                 coords[2].ComputeCoordPercentCalc(aRefBox.Height()),
+                 coords[3].ComputeCoordPercentCalc(aRefBox.Width()));
+
+  nscoord x = aRefBox.X() + inset.left;
+  nscoord width = aRefBox.Width() - inset.LeftRight();
+  nscoord y = aRefBox.Y() + inset.top;
+  nscoord height = aRefBox.Height() - inset.TopBottom();
 
-  nsRect insetRect(aRefBox);
-  insetRect.Deflate(inset);
+  // Invert left and right, if necessary.
+  if (width < 0) {
+    width *= -1;
+    x -= width;
+  }
 
-  return insetRect;
+  // Invert top and bottom, if necessary.
+  if (height < 0) {
+    height *= -1;
+    y -= height;
+  }
+
+  return nsRect(x, y, width, height);
 }
 
 /* static */ bool
 ShapeUtils::ComputeInsetRadii(const UniquePtr<StyleBasicShape>& aBasicShape,
                               const nsRect& aInsetRect,
                               const nsRect& aRefBox,
                               nscoord aRadii[8])
 {
--- a/layout/base/ShapeUtils.h
+++ b/layout/base/ShapeUtils.h
@@ -52,17 +52,26 @@ struct ShapeUtils final
   // @param aCenter the center of the ellipse.
   // @param aRefBox the reference box of the ellipse.
   // @return The radii of the ellipse in app units. The width and height
   // represent the x-axis and y-axis radii of the ellipse.
   static nsSize ComputeEllipseRadii(
     const UniquePtr<StyleBasicShape>& aBasicShape,
     const nsPoint& aCenter, const nsRect& aRefBox);
 
-  // Compute the rect for an inset.
+  // Compute the rect for an inset. If the inset amount is larger than
+  // aRefBox itself, this will return a rect the same shape as the inverse
+  // rect that would be created by insetting aRefBox by the inset amount.
+  // This process is *not* what is called for by the current spec at
+  // https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes.
+  // The spec currently treats empty shapes, including overly-inset rects, as
+  // defining 'empty float areas' that don't affect layout. However, it is
+  // practically useful to treat empty shapes as having edges for purposes of
+  // affecting layout, and there is growing momentum for the approach we
+  // are taking here.
   // @param aRefBox the reference box of the inset.
   // @return The inset rect in app units.
   static nsRect ComputeInsetRect(
     const UniquePtr<StyleBasicShape>& aBasicShape,
     const nsRect& aRefBox);
 
   // Compute the radii for an inset.
   // @param aRefBox the reference box of the inset.
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -485,18 +485,17 @@ nsFieldSetFrame::Reflow(nsPresContext*  
         std::max(0, aReflowInput.ComputedMinBSize() - mLegendSpace);
     }
 
     if (aReflowInput.ComputedMaxBSize() != NS_UNCONSTRAINEDSIZE) {
       kidReflowInput.ComputedMaxBSize() =
         std::max(0, aReflowInput.ComputedMaxBSize() - mLegendSpace);
     }
 
-    ReflowOutput kidDesiredSize(kidReflowInput,
-                                       aDesiredSize.mFlags);
+    ReflowOutput kidDesiredSize(kidReflowInput);
     // Reflow the frame
     NS_ASSERTION(kidReflowInput.ComputedPhysicalMargin() == nsMargin(0,0,0,0),
                  "Margins on anonymous fieldset child not supported!");
     LogicalPoint pt(wm, border.IStart(wm), border.BStart(wm) + mLegendSpace);
 
     // We don't know the correct containerSize until we have reflowed |inner|,
     // so we use a dummy value for now; FinishReflowChild will fix the position
     // if necessary.
--- a/layout/generic/ReflowOutput.cpp
+++ b/layout/generic/ReflowOutput.cpp
@@ -34,23 +34,18 @@ nsOverflowAreas::SetAllTo(const nsRect& 
 {
   NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
     mRects[otype] = aRect;
   }
 }
 
 namespace mozilla {
 
-ReflowOutput::ReflowOutput(const ReflowInput& aReflowInput,
-                                         uint32_t aFlags)
-  : mISize(0)
-  , mBSize(0)
-  , mBlockStartAscent(ASK_FOR_BASELINE)
-  , mFlags(aFlags)
-  , mWritingMode(aReflowInput.GetWritingMode())
+ReflowOutput::ReflowOutput(const ReflowInput& aReflowInput)
+  : ReflowOutput(aReflowInput.GetWritingMode())
 {
 }
 
 void
 ReflowOutput::SetOverflowAreasToDesiredBounds()
 {
   NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
     mOverflowAreas.Overflow(otype).SetRect(0, 0, Width(), Height());
--- a/layout/generic/ReflowOutput.h
+++ b/layout/generic/ReflowOutput.h
@@ -14,19 +14,16 @@
 #include "nsRect.h"
 
 //----------------------------------------------------------------------
 
 namespace mozilla {
 struct ReflowInput;
 } // namespace mozilla
 
-// Option flags
-#define NS_REFLOW_CALC_BOUNDING_METRICS  0x0001
-
 /**
  * When we store overflow areas as an array of scrollable and visual
  * overflow, we use these indices.
  *
  * eOverflowType_LENGTH is needed (for gcc 4.5.*, at least) to ensure
  * that 2 is a valid value of nsOverflowType for use in
  * NS_FOR_FRAME_OVERFLOW_TYPES.
  */
@@ -198,31 +195,25 @@ namespace mozilla {
 /**
  * Reflow metrics used to return the frame's desired size and alignment
  * information.
  *
  * @see #Reflow()
  */
 class ReflowOutput {
 public:
-  // XXXldb Should |aFlags| generally be passed from parent to child?
-  // Some places do it, and some don't.  |aFlags| should perhaps go away
-  // entirely.
-  // XXX width/height/ascent are OUT parameters and so they shouldn't
-  // have to be initialized, but there are some bad frame classes that
-  // aren't properly setting them when returning from Reflow()...
-  explicit ReflowOutput(mozilla::WritingMode aWritingMode, uint32_t aFlags = 0)
+  explicit ReflowOutput(mozilla::WritingMode aWritingMode)
     : mISize(0)
     , mBSize(0)
     , mBlockStartAscent(ASK_FOR_BASELINE)
-    , mFlags(aFlags)
     , mWritingMode(aWritingMode)
-  {}
+  {
+  }
 
-  explicit ReflowOutput(const ReflowInput& aState, uint32_t aFlags = 0);
+  explicit ReflowOutput(const ReflowInput& aReflowInput);
 
   // ISize and BSize are logical-coordinate dimensions:
   // ISize is the size in the writing mode's inline direction (which equates to
   // width in horizontal writing modes, height in vertical ones), and BSize is
   // the size in the block-progression direction.
   nscoord ISize(mozilla::WritingMode aWritingMode) const {
     NS_ASSERTION(!aWritingMode.IsOrthogonalTo(mWritingMode),
                  "mismatched writing mode");
@@ -290,21 +281,16 @@ public:
   void SetBlockStartAscent(nscoord aAscent)
   {
     mBlockStartAscent = aAscent;
   }
 
   enum { ASK_FOR_BASELINE = nscoord_MAX };
 
   // Metrics that _exactly_ enclose the text to allow precise MathML placements.
-  // If the NS_REFLOW_CALC_BOUNDING_METRICS flag is set, then the caller is
-  // requesting that you also compute additional details about your inner
-  // bounding box and italic correction. For example, the bounding box of
-  // msup is the smallest rectangle that _exactly_ encloses both the text
-  // of the base and the text of the superscript.
   nsBoundingMetrics mBoundingMetrics;  // [OUT]
 
   // Carried out block-end margin values. This is the collapsed
   // (generational) block-end margin value.
   nsCollapsingMargin mCarriedOutBEndMargin;
 
   // For frames that have content that overflow their content area
   // (HasOverflowAreas() is true) these rectangles represent the total
@@ -331,19 +317,14 @@ public:
   // Union all of mOverflowAreas with (0, 0, width, height).
   void UnionOverflowAreasWithDesiredBounds();
 
   mozilla::WritingMode GetWritingMode() const { return mWritingMode; }
 
 private:
   nscoord mISize, mBSize; // [OUT] desired width and height (border-box)
   nscoord mBlockStartAscent; // [OUT] baseline (in Block direction), or ASK_FOR_BASELINE
-
-public:
-  uint32_t mFlags;
-
-private:
   mozilla::WritingMode mWritingMode;
 };
 
 } // mozilla namespace
 
 #endif // mozilla_ReflowOutput_h
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -742,17 +742,17 @@ nsColumnSetFrame::ReflowChildren(ReflowO
       // Note if the column's next in flow is not being changed by this incremental reflow.
       // This may allow the current column to avoid trying to pull lines from the next column.
       if (child->GetNextSibling() &&
           !(GetStateBits() & NS_FRAME_IS_DIRTY) &&
         !(child->GetNextSibling()->GetStateBits() & NS_FRAME_IS_DIRTY)) {
         kidReflowInput.mFlags.mNextInFlowUntouched = true;
       }
 
-      ReflowOutput kidDesiredSize(wm, aDesiredSize.mFlags);
+      ReflowOutput kidDesiredSize(wm);
 
       // XXX it would be cool to consult the float manager for the
       // previous block to figure out the region of floats from the
       // previous column that extend into this column, and subtract
       // that region from the new float manager.  So you could stick a
       // really big float in the first column and text in following
       // columns would flow around it.
 
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -725,17 +725,20 @@ public:
                     const nscoord aBEnd) const override;
   nscoord BStart() const override {
     return mCenter.y - mRadii.height - mShapeMargin;
   }
   nscoord BEnd() const override {
     return mCenter.y + mRadii.height + mShapeMargin;
   }
   bool IsEmpty() const override {
-    return mRadii.IsEmpty();
+    // An EllipseShapeInfo is never empty, because an ellipse or circle with
+    // a zero radius acts like a point, and an ellipse with one zero radius
+    // acts like a line.
+    return false;
   }
 
   void Translate(nscoord aLineLeft, nscoord aBlockStart) override
   {
     mCenter.MoveBy(aLineLeft, aBlockStart);
 
     for (nsRect& interval : mIntervals) {
       interval.MoveBy(aLineLeft, aBlockStart);
@@ -861,38 +864,46 @@ nsFloatManager::EllipseShapeInfo::Ellips
     bool bIsInExpandedRegion(b < bExpand);
     nscoord bInAppUnits = (b - bExpand) * aAppUnitsPerDevPixel;
     bool bIsMoreThanEllipseBEnd(bInAppUnits > mRadii.height);
 
     // Find the i intercept of the ellipse edge for this block row, and
     // adjust it to compensate for the expansion of the inline dimension.
     // If we're in the expanded region, or if we're using a b that's more
     // than the bEnd of the ellipse, the intercept is nscoord_MIN.
-    const int32_t iIntercept = (bIsInExpandedRegion ||
-                                bIsMoreThanEllipseBEnd) ? nscoord_MIN :
+    // We have one other special case to consider: when the ellipse has no
+    // height. In that case we treat the bInAppUnits == 0 case as
+    // intercepting at the width of the ellipse. All other cases solve
+    // the intersection mathematically.
+    const int32_t iIntercept =
+      (bIsInExpandedRegion || bIsMoreThanEllipseBEnd) ? nscoord_MIN :
       iExpand + NSAppUnitsToIntPixels(
-        XInterceptAtY(bInAppUnits, mRadii.width, mRadii.height),
+        (!!mRadii.height || bInAppUnits) ?
+        XInterceptAtY(bInAppUnits, mRadii.width, mRadii.height) :
+        mRadii.width,
         aAppUnitsPerDevPixel);
 
     // Set iMax in preparation for this block row.
     int32_t iMax = iIntercept;
 
     for (uint32_t i = 0; i < iSize; ++i) {
       const uint32_t index = i + b * iSize;
       MOZ_ASSERT(index < (iSize * bSize),
                  "Our distance field index should be in-bounds.");
 
       // Handle our three cases, in order.
       if (i < iExpand ||
           bIsInExpandedRegion) {
         // Case 1: Expanded reqion pixel.
         df[index] = MAX_MARGIN_5X;
       } else if ((int32_t)i <= iIntercept) {
-        // Case 2: Pixel within the ellipse.
-        df[index] = 0;
+        // Case 2: Pixel within the ellipse, or just outside the edge of it.
+        // Having a positive height indicates that there's an area we can
+        // be inside of.
+        df[index] = (!!mRadii.height) ? 0 : 5;
       } else {
         // Case 3: Other pixel.
 
         // Backward-looking neighborhood distance from target pixel X
         // with chamfer 5-7-11 looks like:
         //
         // +--+--+--+
         // |  |11|  |
@@ -1068,17 +1079,23 @@ public:
                       int32_t aAppUnitsPerDevPixel);
 
   nscoord LineLeft(const nscoord aBStart,
                    const nscoord aBEnd) const override;
   nscoord LineRight(const nscoord aBStart,
                     const nscoord aBEnd) const override;
   nscoord BStart() const override { return mRect.y; }
   nscoord BEnd() const override { return mRect.YMost(); }
-  bool IsEmpty() const override { return mRect.IsEmpty(); }
+  bool IsEmpty() const override {
+    // A RoundedBoxShapeInfo is never empty, because if it is collapsed to
+    // zero area, it acts like a point. If it is collapsed further, to become
+    // inside-out, it acts like a rect in the same shape as the inside-out
+    // rect.
+    return false;
+  }
 
   void Translate(nscoord aLineLeft, nscoord aBlockStart) override
   {
     mRect.MoveBy(aLineLeft, aBlockStart);
 
     if (mShapeMargin > 0) {
       MOZ_ASSERT(mLogicalTopLeftCorner && mLogicalTopRightCorner &&
                  mLogicalBottomLeftCorner && mLogicalBottomRightCorner,
@@ -1255,24 +1272,30 @@ public:
                    const nsRect& aMarginRect);
 
   nscoord LineLeft(const nscoord aBStart,
                    const nscoord aBEnd) const override;
   nscoord LineRight(const nscoord aBStart,
                     const nscoord aBEnd) const override;
   nscoord BStart() const override { return mBStart; }
   nscoord BEnd() const override { return mBEnd; }
-  bool IsEmpty() const override { return mEmpty; }
+  bool IsEmpty() const override {
+    // A PolygonShapeInfo is never empty, because the parser prevents us from
+    // creating a shape with no vertices. If we only have 1 vertex, the
+    // shape acts like a point. With 2 non-coincident vertices, the shape
+    // acts like a line.
+    return false;
+  }
 
   void Translate(nscoord aLineLeft, nscoord aBlockStart) override;
 
 private:
-  // Helper method for determining if the vertices define a float area at
-  // all, and to set mBStart and mBEnd based on the vertices' y extent.
-  void ComputeEmptinessAndExtent();
+  // Helper method for determining the mBStart and mBEnd based on the
+  // vertices' y extent.
+  void ComputeExtent();
 
   // Helper method for implementing LineLeft() and LineRight().
   nscoord ComputeLineIntercept(
     const nscoord aBStart,
     const nscoord aBEnd,
     nscoord (*aCompareOp) (std::initializer_list<nscoord>),
     const nscoord aLineInterceptInitialValue) const;
 
@@ -1290,52 +1313,41 @@ private:
   // These are only generated and used in float area calculations for
   // shape-margin > 0. Each interval is a rectangle that is one device pixel
   // deep in the block axis. The values are stored as block edges in the y
   // coordinates, and inline edges as the x coordinates.
 
   // The intervals are stored in ascending order on y.
   nsTArray<nsRect> mIntervals;
 
-  // If mEmpty is true, that means the polygon encloses no area.
-  bool mEmpty = false;
-
-  // Computed block start and block end value of the polygon shape.
-  //
-  // If mEmpty is false, their initial values nscoord_MAX and nscoord_MIN
-  // are used as sentinels for computing min() and max() in the
-  // constructor, and mBStart is guaranteed to be less than or equal to
-  // mBEnd. If mEmpty is true, their values do not matter.
+  // Computed block start and block end value of the polygon shape. These
+  // initial values are set to correct values in ComputeExtent(), which is
+  // called from all constructors. Afterwards, mBStart is guaranteed to be
+  // less than or equal to mBEnd.
   nscoord mBStart = nscoord_MAX;
   nscoord mBEnd = nscoord_MIN;
 };
 
 nsFloatManager::PolygonShapeInfo::PolygonShapeInfo(nsTArray<nsPoint>&& aVertices)
   : mVertices(aVertices)
 {
-  ComputeEmptinessAndExtent();
+  ComputeExtent();
 }
 
 nsFloatManager::PolygonShapeInfo::PolygonShapeInfo(
   nsTArray<nsPoint>&& aVertices,
   nscoord aShapeMargin,
   int32_t aAppUnitsPerDevPixel,
   const nsRect& aMarginRect)
   : mVertices(aVertices)
 {
   MOZ_ASSERT(aShapeMargin > 0, "This constructor should only be used for a "
                                "polygon with a positive shape-margin.");
 
-  ComputeEmptinessAndExtent();
-
-  // If we're empty, then the float area stays empty, even with a positive
-  // shape-margin.
-  if (mEmpty) {
-    return;
-  }
+  ComputeExtent();
 
   // With a positive aShapeMargin, we have to calculate a distance
   // field from the opaque pixels, then build intervals based on
   // them being within aShapeMargin distance to an opaque pixel.
 
   // Roughly: for each pixel in the margin box, we need to determine the
   // distance to the nearest opaque image-pixel.  If that distance is less
   // than aShapeMargin, we consider this margin-box pixel as being part of
@@ -1414,17 +1426,17 @@ nsFloatManager::PolygonShapeInfo::Polygo
     // the right edge of the polygon at one-dev-pixel-thick strip of b. We
     // have a ComputeLineIntercept function that takes and returns app unit
     // coordinates in the space of aMarginRect. So to pass in b values, we
     // first have to add the aMarginRect.y value. And for the values that we
     // get out, we have to subtract away the aMarginRect.x value before
     // converting the app units to dev pixels.
     nscoord bInAppUnitsMarginRect = bInAppUnits + aMarginRect.y;
     bool bIsLessThanPolygonBStart(bInAppUnitsMarginRect < mBStart);
-    bool bIsMoreThanPolygonBEnd(bInAppUnitsMarginRect >= mBEnd);
+    bool bIsMoreThanPolygonBEnd(bInAppUnitsMarginRect > mBEnd);
 
     const int32_t iLeftEdge = (bIsInExpandedRegion ||
                                bIsLessThanPolygonBStart ||
                                bIsMoreThanPolygonBEnd) ? nscoord_MAX :
       kiExpansionPerSide + NSAppUnitsToIntPixels(
         ComputeLineIntercept(bInAppUnitsMarginRect,
                              bInAppUnitsMarginRect + aAppUnitsPerDevPixel,
                              std::min<nscoord>, nscoord_MAX) - aMarginRect.x,
@@ -1445,19 +1457,21 @@ nsFloatManager::PolygonShapeInfo::Polygo
                  "Our distance field index should be in-bounds.");
 
       // Handle our three cases, in order.
       if (i < kiExpansionPerSide ||
           i >= iSize - kiExpansionPerSide ||
           bIsInExpandedRegion) {
         // Case 1: Expanded pixel.
         df[index] = MAX_MARGIN_5X;
-      } else if ((int32_t)i >= iLeftEdge && (int32_t)i < iRightEdge) {
-        // Case 2: Polygon pixel.
-        df[index] = 0;
+      } else if ((int32_t)i >= iLeftEdge && (int32_t)i <= iRightEdge) {
+        // Case 2: Polygon pixel, either inside or just adjacent to the right
+        // edge. We need this special distinction to detect a space between
+        // edges that is less than one dev pixel.
+        df[index] = (int32_t)i < iRightEdge ? 0 : 5;
       } else {
         // Case 3: Other pixel.
 
         // Backward-looking neighborhood distance from target pixel X
         // with chamfer 5-7-11 looks like:
         //
         // +--+--+--+--+--+
         // |  |11|  |11|  |
@@ -1600,18 +1614,16 @@ nsFloatManager::PolygonShapeInfo::Polygo
   mBStart = std::min(mBStart, mBStart - aShapeMargin);
   mBEnd = std::max(mBEnd, mBEnd + aShapeMargin);
 }
 
 nscoord
 nsFloatManager::PolygonShapeInfo::LineLeft(const nscoord aBStart,
                                            const nscoord aBEnd) const
 {
-  MOZ_ASSERT(!mEmpty, "Shouldn't be called if the polygon encloses no area.");
-
   // Use intervals if we have them.
   if (!mIntervals.IsEmpty()) {
     return LineEdge(mIntervals, aBStart, aBEnd, true);
   }
 
   // We want the line-left-most inline-axis coordinate where the
   // (block-axis) aBStart/aBEnd band crosses a line segment of the polygon.
   // To get that, we start as line-right as possible (at nscoord_MAX). Then
@@ -1623,120 +1635,117 @@ nsFloatManager::PolygonShapeInfo::LineLe
   // parameter nscoord, not the minimum value of nscoord.
   return ComputeLineIntercept(aBStart, aBEnd, std::min<nscoord>, nscoord_MAX);
 }
 
 nscoord
 nsFloatManager::PolygonShapeInfo::LineRight(const nscoord aBStart,
                                             const nscoord aBEnd) const
 {
-  MOZ_ASSERT(!mEmpty, "Shouldn't be called if the polygon encloses no area.");
-
   // Use intervals if we have them.
   if (!mIntervals.IsEmpty()) {
     return LineEdge(mIntervals, aBStart, aBEnd, false);
   }
 
   // Similar to LineLeft(). Though here, we want the line-right-most
   // inline-axis coordinate, so we instead start at nscoord_MIN and use
   // std::max() to get the biggest inline-coordinate among those
   // intersection points.
   return ComputeLineIntercept(aBStart, aBEnd, std::max<nscoord>, nscoord_MIN);
 }
 
 void
-nsFloatManager::PolygonShapeInfo::ComputeEmptinessAndExtent()
+nsFloatManager::PolygonShapeInfo::ComputeExtent()
 {
-  // Polygons with fewer than three vertices result in an empty area.
-  // https://drafts.csswg.org/css-shapes/#funcdef-polygon
-  if (mVertices.Length() < 3) {
-    mEmpty = true;
-    return;
-  }
-
-  auto Determinant = [] (const nsPoint& aP0, const nsPoint& aP1) {
-    // Returns the determinant of the 2x2 matrix [aP0 aP1].
-    // https://en.wikipedia.org/wiki/Determinant#2_.C3.97_2_matrices
-    return aP0.x * aP1.y - aP0.y * aP1.x;
-  };
-
-  // See if we have any vertices that are non-collinear with the first two.
-  // (If a polygon's vertices are all collinear, it encloses no area.)
-  bool isEntirelyCollinear = true;
-  const nsPoint& p0 = mVertices[0];
-  const nsPoint& p1 = mVertices[1];
-  for (size_t i = 2; i < mVertices.Length(); ++i) {
-    const nsPoint& p2 = mVertices[i];
-
-    // If the determinant of the matrix formed by two points is 0, that
-    // means they're collinear with respect to the origin. Here, if it's
-    // nonzero, then p1 and p2 are non-collinear with respect to p0, i.e.
-    // the three points are non-collinear.
-    if (Determinant(p2 - p0, p1 - p0) != 0) {
-      isEntirelyCollinear = false;
-      break;
-    }
-  }
-
-  if (isEntirelyCollinear) {
-    mEmpty = true;
-    return;
-  }
-
   // mBStart and mBEnd are the lower and the upper bounds of all the
   // vertex.y, respectively. The vertex.y is actually on the block-axis of
   // the float manager's writing mode.
   for (const nsPoint& vertex : mVertices) {
     mBStart = std::min(mBStart, vertex.y);
     mBEnd = std::max(mBEnd, vertex.y);
   }
+
+  MOZ_ASSERT(mBStart <= mBEnd, "Start of float area should be less than "
+                               "or equal to the end.");
 }
 
 nscoord
 nsFloatManager::PolygonShapeInfo::ComputeLineIntercept(
   const nscoord aBStart,
   const nscoord aBEnd,
   nscoord (*aCompareOp) (std::initializer_list<nscoord>),
   const nscoord aLineInterceptInitialValue) const
 {
   MOZ_ASSERT(aBStart <= aBEnd,
              "The band's block start is greater than its block end?");
 
   const size_t len = mVertices.Length();
   nscoord lineIntercept = aLineInterceptInitialValue;
 
+  // We have some special treatment of horizontal lines between vertices.
+  // Generally, we can ignore the impact of the horizontal lines since their
+  // endpoints will be included in the lines preceeding or following them.
+  // However, it's possible the polygon is entirely a horizontal line,
+  // possibly built from more than one horizontal segment. In such a case,
+  // we need to have the horizontal line(s) contribute to the line intercepts.
+  // We do this by accepting horizontal lines until we find a non-horizontal
+  // line, after which all further horizontal lines are ignored.
+  bool canIgnoreHorizontalLines = false;
+
   // Iterate each line segment {p0, p1}, {p1, p2}, ..., {pn, p0}.
   for (size_t i = 0; i < len; ++i) {
     const nsPoint* smallYVertex = &mVertices[i];
     const nsPoint* bigYVertex = &mVertices[(i + 1) % len];
 
     // Swap the two points to satisfy the requirement for calling
     // XInterceptAtY.
     if (smallYVertex->y > bigYVertex->y) {
       std::swap(smallYVertex, bigYVertex);
     }
 
-    if (aBStart >= bigYVertex->y || aBEnd <= smallYVertex->y ||
-        smallYVertex->y == bigYVertex->y) {
-      // Skip computing the intercept if a) the band doesn't intersect the
-      // line segment (even if it crosses one of two the vertices); or b)
-      // the line segment is horizontal. It's OK because the two end points
-      // forming this horizontal segment will still be considered if each of
-      // them is forming another non-horizontal segment with other points.
+    // Generally, we need to ignore line segments that either don't intersect
+    // the band, or merely touch it. However, if the polygon has no block extent
+    // (it is a point, or a horizontal line), and the band touches the line
+    // segment, we let that line segment through.
+    if ((aBStart >= bigYVertex->y || aBEnd <= smallYVertex->y) &&
+        !(mBStart == mBEnd && aBStart == bigYVertex->y)) {
+      // Skip computing the intercept if the band doesn't intersect the
+      // line segment.
       continue;
     }
 
-    nscoord bStartLineIntercept =
-      aBStart <= smallYVertex->y
-        ? smallYVertex->x
-        : XInterceptAtY(aBStart, *smallYVertex, *bigYVertex);
-    nscoord bEndLineIntercept =
-      aBEnd >= bigYVertex->y
-        ? bigYVertex->x
-        : XInterceptAtY(aBEnd, *smallYVertex, *bigYVertex);
+    nscoord bStartLineIntercept;
+    nscoord bEndLineIntercept;
+
+    if (smallYVertex->y == bigYVertex->y) {
+      // The line is horizontal; see if we can ignore it.
+      if (canIgnoreHorizontalLines) {
+        continue;
+      }
+
+      // For a horizontal line that we can't ignore, we treat the two x value
+      // ends as the bStartLineIntercept and bEndLineIntercept. It doesn't
+      // matter which is applied to which, because they'll both be applied
+      // to aCompareOp.
+      bStartLineIntercept = smallYVertex->x;
+      bEndLineIntercept = bigYVertex->x;
+    } else {
+      // This is not a horizontal line. We can now ignore all future
+      // horizontal lines.
+      canIgnoreHorizontalLines = true;
+
+      bStartLineIntercept =
+        aBStart <= smallYVertex->y
+          ? smallYVertex->x
+          : XInterceptAtY(aBStart, *smallYVertex, *bigYVertex);
+      bEndLineIntercept =
+        aBEnd >= bigYVertex->y
+          ? bigYVertex->x
+          : XInterceptAtY(aBEnd, *smallYVertex, *bigYVertex);
+    }
 
     // If either new intercept is more extreme than lineIntercept (per
     // aCompareOp), then update lineIntercept to that value.
     lineIntercept =
       aCompareOp({lineIntercept, bStartLineIntercept, bEndLineIntercept});
   }
 
   return lineIntercept;
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -567,17 +567,16 @@ FRAME_STATE_BIT(Block, 62, BULLET_FRAME_
 FRAME_STATE_BIT(Block, 63, BULLET_FRAME_IMAGE_LOADING)
 
 
 // == Frame state bits that apply to image frames =============================
 
 FRAME_STATE_GROUP(Image, nsImageFrame)
 
 FRAME_STATE_BIT(Image, 20, IMAGE_SIZECONSTRAINED)
-FRAME_STATE_BIT(Image, 21, IMAGE_GOTINITIALREFLOW)
 
 
 // == Frame state bits that apply to inline frames ============================
 
 FRAME_STATE_GROUP(Inline, nsInlineFrame)
 
 /**  In Bidi inline start (or end) margin/padding/border should be applied to
  *  first (or last) frame (or a continuation frame).
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -669,17 +669,17 @@ nsHTMLScrollFrame::InInitialReflow() con
   // assumption, because our initial reflow is no longer synchronous).
   return !mHelper.mIsRoot && (GetStateBits() & NS_FRAME_FIRST_REFLOW);
 }
 
 void
 nsHTMLScrollFrame::ReflowContents(ScrollReflowInput* aState,
                                   const ReflowOutput& aDesiredSize)
 {
-  ReflowOutput kidDesiredSize(aDesiredSize.GetWritingMode(), aDesiredSize.mFlags);
+  ReflowOutput kidDesiredSize(aDesiredSize.GetWritingMode());
   ReflowScrolledFrame(aState, GuessHScrollbarNeeded(*aState),
                       GuessVScrollbarNeeded(*aState), &kidDesiredSize, true);
 
   // There's an important special case ... if the child appears to fit
   // in the inside-border rect (but overflows the scrollport), we
   // should try laying it out without a vertical scrollbar. It will
   // usually fit because making the available-width wider will not
   // normally make the child taller. (The only situation I can think
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -370,17 +370,17 @@ nsHTMLCanvasFrame::Reflow(nsPresContext*
 
   // Reflow the single anon block child.
   nsReflowStatus childStatus;
   nsIFrame* childFrame = mFrames.FirstChild();
   WritingMode childWM = childFrame->GetWritingMode();
   LogicalSize availSize = aReflowInput.ComputedSize(childWM);
   availSize.BSize(childWM) = NS_UNCONSTRAINEDSIZE;
   NS_ASSERTION(!childFrame->GetNextSibling(), "HTML canvas should have 1 kid");
-  ReflowOutput childDesiredSize(aReflowInput.GetWritingMode(), aMetrics.mFlags);
+  ReflowOutput childDesiredSize(aReflowInput.GetWritingMode());
   ReflowInput childReflowInput(aPresContext, aReflowInput, childFrame,
                                      availSize);
   ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowInput,
               0, 0, 0, childStatus, nullptr);
   FinishReflowChild(childFrame, aPresContext, childDesiredSize,
                     &childReflowInput, 0, 0, 0);
 
   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -599,17 +599,17 @@ nsImageFrame::OnSizeAvailable(imgIReques
     mIntrinsicSize.width.SetCoordValue(0);
     mIntrinsicSize.height.SetCoordValue(0);
     mIntrinsicRatio.SizeTo(0, 0);
     intrinsicSizeChanged = true;
   }
 
   MarkNeedsDisplayItemRebuild();
 
-  if (intrinsicSizeChanged && (mState & IMAGE_GOTINITIALREFLOW)) {
+  if (intrinsicSizeChanged && GotInitialReflow()) {
     // Now we need to reflow if we have an unconstrained size and have
     // already gotten the initial reflow
     if (!(mState & IMAGE_SIZECONSTRAINED)) {
       PresShell()->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
                                     NS_FRAME_IS_DIRTY);
     } else {
       // We've already gotten the initial reflow, and our size hasn't changed,
       // so we're ready to request a decode.
@@ -622,17 +622,17 @@ nsImageFrame::OnSizeAvailable(imgIReques
   return NS_OK;
 }
 
 nsresult
 nsImageFrame::OnFrameUpdate(imgIRequest* aRequest, const nsIntRect* aRect)
 {
   NS_ENSURE_ARG_POINTER(aRect);
 
-  if (!(mState & IMAGE_GOTINITIALREFLOW)) {
+  if (!GotInitialReflow()) {
     // Don't bother to do anything; we have a reflow coming up!
     return NS_OK;
   }
 
   if (mFirstFrameComplete && !StyleVisibility()->IsVisible()) {
     return NS_OK;
   }
 
@@ -687,17 +687,17 @@ nsImageFrame::OnLoadComplete(imgIRequest
 {
   NotifyNewCurrentRequest(aRequest, aStatus);
   return NS_OK;
 }
 
 void
 nsImageFrame::ResponsiveContentDensityChanged()
 {
-  if (!(mState & IMAGE_GOTINITIALREFLOW)) {
+  if (!GotInitialReflow()) {
     return;
   }
 
   if (!mImage) {
     return;
   }
 
   if (!UpdateIntrinsicSize(mImage) && !UpdateIntrinsicRatio(mImage)) {
@@ -728,17 +728,17 @@ nsImageFrame::NotifyNewCurrentRequest(im
     mImage = mPrevImage = nullptr;
 
     // Have to size to 0,0 so that GetDesiredSize recalculates the size
     mIntrinsicSize.width.SetCoordValue(0);
     mIntrinsicSize.height.SetCoordValue(0);
     mIntrinsicRatio.SizeTo(0, 0);
   }
 
-  if (mState & IMAGE_GOTINITIALREFLOW) { // do nothing if we haven't gotten the initial reflow yet
+  if (GotInitialReflow()) {
     if (intrinsicSizeChanged) {
       if (!(mState & IMAGE_SIZECONSTRAINED)) {
         PresShell()->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
                                       NS_FRAME_IS_DIRTY);
       } else {
         // We've already gotten the initial reflow, and our size hasn't changed,
         // so we're ready to request a decode.
         MaybeDecodeForPredictedSize();
@@ -973,22 +973,16 @@ nsImageFrame::Reflow(nsPresContext*     
 
   // see if we have a frozen size (i.e. a fixed width and height)
   if (HaveFixedSize(aReflowInput)) {
     AddStateBits(IMAGE_SIZECONSTRAINED);
   } else {
     RemoveStateBits(IMAGE_SIZECONSTRAINED);
   }
 
-  // XXXldb These two bits are almost exact opposites (except in the
-  // middle of the initial reflow); remove IMAGE_GOTINITIALREFLOW.
-  if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
-    AddStateBits(IMAGE_GOTINITIALREFLOW);
-  }
-
   mComputedSize =
     nsSize(aReflowInput.ComputedWidth(), aReflowInput.ComputedHeight());
 
   aMetrics.Width() = mComputedSize.width;
   aMetrics.Height() = mComputedSize.height;
 
   // add borders and padding
   aMetrics.Width()  += aReflowInput.ComputedPhysicalBorderPadding().LeftRight();
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -186,16 +186,21 @@ private:
     : nsImageFrame(aStyle, kClassID) {}
 
 protected:
   nsImageFrame(ComputedStyle* aStyle, ClassID aID);
   virtual ~nsImageFrame();
 
   void EnsureIntrinsicSizeAndRatio();
 
+  bool GotInitialReflow() const
+  {
+    return !HasAnyStateBits(NS_FRAME_FIRST_REFLOW);
+  }
+
   virtual mozilla::LogicalSize
   ComputeSize(gfxContext *aRenderingContext,
               mozilla::WritingMode aWritingMode,
               const mozilla::LogicalSize& aCBSize,
               nscoord aAvailableISize,
               const mozilla::LogicalSize& aMargin,
               const mozilla::LogicalSize& aBorder,
               const mozilla::LogicalSize& aPadding,
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -9450,18 +9450,16 @@ nsTextFrame::ReflowText(nsLineLayout& aL
   uint32_t transformedOffset = provider.GetStart().GetSkippedOffset();
 
   // The metrics for the text go in here
   gfxTextRun::Metrics textMetrics;
   gfxFont::BoundingBoxType boundingBoxType =
     IsFloatingFirstLetterChild() || IsInitialLetterChild()
     ? gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS
     : gfxFont::LOOSE_INK_EXTENTS;
-  NS_ASSERTION(!(NS_REFLOW_CALC_BOUNDING_METRICS & aMetrics.mFlags),
-               "We shouldn't be passed NS_REFLOW_CALC_BOUNDING_METRICS anymore");
 
   int32_t limitLength = length;
   int32_t forceBreak = aLineLayout.GetForcedBreakPosition(this);
   bool forceBreakAfter = false;
   if (forceBreak >= length) {
     forceBreakAfter = forceBreak == length;
     // The break is not within the text considered for this textframe.
     forceBreak = -1;
--- a/layout/inspector/InspectorUtils.cpp
+++ b/layout/inspector/InspectorUtils.cpp
@@ -394,16 +394,29 @@ InspectorUtils::GetCSSPropertyNames(Glob
   if (aOptions.mIncludeAliases) {
     for (prop = eCSSProperty_COUNT; prop < eCSSProperty_COUNT_with_aliases; ++prop) {
       appendProperty(prop);
     }
   }
 }
 
 /* static */ void
+InspectorUtils::GetCSSPropertyPrefs(GlobalObject& aGlobalObject,
+                                    nsTArray<PropertyPref>& aResult)
+{
+  for (const auto* src = nsCSSProps::kPropertyPrefTable;
+       src->mPropID != eCSSProperty_UNKNOWN; src++) {
+    PropertyPref& dest = *aResult.AppendElement();
+    const nsCString& name = nsCSSProps::GetStringValue(src->mPropID);
+    dest.mName.Assign(NS_ConvertASCIItoUTF16(name));
+    dest.mPref.AssignASCII(src->mPref);
+  }
+}
+
+/* static */ void
 InspectorUtils::GetSubpropertiesForCSSProperty(GlobalObject& aGlobal,
                                                const nsAString& aProperty,
                                                nsTArray<nsString>& aResult,
                                                ErrorResult& aRv)
 {
   nsCSSPropertyID propertyID =
     nsCSSProps::LookupProperty(aProperty, CSSEnabledState::eForAllContent);
 
--- a/layout/inspector/InspectorUtils.h
+++ b/layout/inspector/InspectorUtils.h
@@ -3,17 +3,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/.
  */
 
 #ifndef mozilla_dom_InspectorUtils_h
 #define mozilla_dom_InspectorUtils_h
 
-#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/InspectorUtilsBinding.h"
 
 class nsAtom;
 class nsIDocument;
 class ComputedStyle;
 
 namespace mozilla {
 class StyleSheet;
 namespace css {
@@ -109,16 +109,21 @@ public:
                                   const nsAString& aPropertyName);
 
   // Get a list of all our supported property names.  Optionally
   // property aliases included.
   static void GetCSSPropertyNames(GlobalObject& aGlobal,
                                   const PropertyNamesOptions& aOptions,
                                   nsTArray<nsString>& aResult);
 
+  // Get a list of all properties controlled by preference, as well as
+  // their corresponding preference names.
+  static void GetCSSPropertyPrefs(GlobalObject& aGlobal,
+                                  nsTArray<PropertyPref>& aResult);
+
   // Get a list of all valid keywords and colors for aProperty.
   static void GetCSSValuesForProperty(GlobalObject& aGlobal,
                                       const nsAString& aPropertyName,
                                       nsTArray<nsString>& aResult,
                                       ErrorResult& aRv);
 
   // Utilities for working with CSS colors
   static void RgbToColorName(GlobalObject& aGlobal,
--- a/layout/mathml/nsMathMLContainerFrame.cpp
+++ b/layout/mathml/nsMathMLContainerFrame.cpp
@@ -877,18 +877,17 @@ nsMathMLContainerFrame::Reflow(nsPresCon
 
   /////////////
   // Reflow children
   // Asking each child to cache its bounding metrics
 
   nsReflowStatus childStatus;
   nsIFrame* childFrame = mFrames.FirstChild();
   while (childFrame) {
-    ReflowOutput childDesiredSize(aReflowInput, // ???
-                                         aDesiredSize.mFlags);
+    ReflowOutput childDesiredSize(aReflowInput);
     WritingMode wm = childFrame->GetWritingMode();
     LogicalSize availSize = aReflowInput.ComputedSize(wm);
     availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
     ReflowInput childReflowInput(aPresContext, aReflowInput,
                                        childFrame, availSize);
     ReflowChild(childFrame, aPresContext, childDesiredSize,
                 childReflowInput, childStatus);
     //NS_ASSERTION(childStatus.IsComplete(), "bad status");
--- a/layout/mathml/nsMathMLTokenFrame.cpp
+++ b/layout/mathml/nsMathMLTokenFrame.cpp
@@ -131,19 +131,17 @@ nsMathMLTokenFrame::Reflow(nsPresContext
 
   // initializations needed for empty markup like <mtag></mtag>
   aDesiredSize.ClearSize();
   aDesiredSize.SetBlockStartAscent(0);
   aDesiredSize.mBoundingMetrics = nsBoundingMetrics();
 
   for (nsIFrame* childFrame : PrincipalChildList()) {
     // ask our children to compute their bounding metrics
-    ReflowOutput childDesiredSize(aReflowInput.GetWritingMode(),
-                                         aDesiredSize.mFlags
-                                         | NS_REFLOW_CALC_BOUNDING_METRICS);
+    ReflowOutput childDesiredSize(aReflowInput.GetWritingMode());
     WritingMode wm = childFrame->GetWritingMode();
     LogicalSize availSize = aReflowInput.ComputedSize(wm);
     availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
     ReflowInput childReflowInput(aPresContext, aReflowInput,
                                        childFrame, availSize);
     ReflowChild(childFrame, aPresContext, childDesiredSize,
                 childReflowInput, aStatus);
     //NS_ASSERTION(aStatus.IsComplete(), "bad status");
--- a/layout/mathml/nsMathMLmfencedFrame.cpp
+++ b/layout/mathml/nsMathMLmfencedFrame.cpp
@@ -255,19 +255,17 @@ nsMathMLmfencedFrame::Reflow(nsPresConte
   if (firstChild || mOpenChar || mCloseChar || mSeparatorsCount > 0) {
     // We use the ASCII metrics to get our minimum height. This way,
     // if we have borders or a background, they will fit better with
     // other elements on the line.
     ascent = fm->MaxAscent();
     descent = fm->MaxDescent();
   }
   while (childFrame) {
-    ReflowOutput childDesiredSize(aReflowInput,
-                                         aDesiredSize.mFlags
-                                         | NS_REFLOW_CALC_BOUNDING_METRICS);
+    ReflowOutput childDesiredSize(aReflowInput);
     WritingMode wm = childFrame->GetWritingMode();
     LogicalSize availSize = aReflowInput.ComputedSize(wm);
     availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
     ReflowInput childReflowInput(aPresContext, aReflowInput,
                                        childFrame, availSize);
     ReflowChild(childFrame, aPresContext, childDesiredSize,
                 childReflowInput, childStatus);
     //NS_ASSERTION(childStatus.IsComplete(), "bad status");
--- a/layout/mathml/nsMathMLmrootFrame.cpp
+++ b/layout/mathml/nsMathMLmrootFrame.cpp
@@ -182,19 +182,17 @@ nsMathMLmrootFrame::Reflow(nsPresContext
   int32_t count = 0;
   nsIFrame* baseFrame = nullptr;
   nsIFrame* indexFrame = nullptr;
   ReflowOutput baseSize(aReflowInput);
   ReflowOutput indexSize(aReflowInput);
   nsIFrame* childFrame = mFrames.FirstChild();
   while (childFrame) {
     // ask our children to compute their bounding metrics
-    ReflowOutput childDesiredSize(aReflowInput,
-                                         aDesiredSize.mFlags
-                                         | NS_REFLOW_CALC_BOUNDING_METRICS);
+    ReflowOutput childDesiredSize(aReflowInput);
     WritingMode wm = childFrame->GetWritingMode();
     LogicalSize availSize = aReflowInput.ComputedSize(wm);
     availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
     ReflowInput childReflowInput(aPresContext, aReflowInput,
                                        childFrame, availSize);
     ReflowChild(childFrame, aPresContext,
                      childDesiredSize, childReflowInput, childStatus);
     //NS_ASSERTION(childStatus.IsComplete(), "bad status");
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4998,17 +4998,19 @@ nsDisplayOutline::CreateWebRenderCommand
   mozilla::Maybe<nsCSSBorderRenderer> borderRenderer =
     nsCSSRendering::CreateBorderRendererForOutline(mFrame->PresContext(),
                                                    nullptr, mFrame,
                                                    GetPaintRect(),
                                                    nsRect(offset, mFrame->GetSize()),
                                                    mFrame->Style());
 
   if (!borderRenderer) {
-    return false;
+    // No border renderer means "there is no outline".
+    // Paint nothing and return success.
+    return true;
   }
 
   borderRenderer->CreateWebRenderCommands(this, aBuilder, aResources, aSc);
   return true;
 }
 
 bool
 nsDisplayOutline::IsInvisibleInRect(const nsRect& aRect) const
--- a/layout/reftests/css-invalid/select/reftest.list
+++ b/layout/reftests/css-invalid/select/reftest.list
@@ -2,11 +2,11 @@ needs-focus == select-valid.html select-
 fuzzy-if(skiaContent,1,3) needs-focus == select-invalid.html select-ref.html
 fuzzy-if(skiaContent,2,6) needs-focus == select-disabled.html select-disabled-ref.html
 fuzzy-if(skiaContent,2,6) needs-focus == select-dyn-disabled.html select-disabled-ref.html
 fuzzy-if(skiaContent,1,3) needs-focus == select-dyn-not-disabled.html select-ref.html
 needs-focus == select-required-invalid.html select-required-ref.html
 needs-focus == select-required-valid.html select-required-ref.html
 needs-focus == select-required-multiple-still-valid.html select-required-multiple-ref.html
 fuzzy-if(skiaContent,1,250) needs-focus == select-required-multiple-valid.html select-required-multiple-ref.html
-fuzzy-if(skiaContent&&!Android,1,3) fuzzy-if(Android,8,1) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html
+fuzzy-if(skiaContent&&!Android,1,3) fuzzy-if(Android,9,1) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html
 fuzzy-if(skiaContent&&!Android,2,3) fuzzy-if(Android,8,1) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html
 fuzzy-if(skiaContent,2,5) needs-focus == select-fieldset-legend.html select-fieldset-legend-ref.html
--- a/layout/reftests/css-shapes/reftest.list
+++ b/layout/reftests/css-shapes/reftest.list
@@ -1,1 +1,33 @@
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),16,4) pref(layout.css.shape-outside.enabled,true) == dynamic-shape-outside-1.html dynamic-shape-outside-1-ref.html
+
+== shape-outside-empty-circle-1.html shape-outside-empty-point-ref.html
+== shape-outside-empty-circle-2.html shape-outside-empty-circle-ref.html
+== shape-outside-empty-circle-3.html shape-outside-empty-nothing-ref.html
+
+== shape-outside-empty-ellipse-1.html shape-outside-empty-point-ref.html
+== shape-outside-empty-ellipse-2.html shape-outside-empty-circle-ref.html
+== shape-outside-empty-ellipse-3.html shape-outside-empty-point-ref.html
+# The next test needs fuzzy due to chamfer aberration
+fuzzy(255,520) == shape-outside-empty-ellipse-4.html shape-outside-empty-circle-ref.html
+== shape-outside-empty-ellipse-5.html shape-outside-empty-line-ref.html
+== shape-outside-empty-ellipse-6.html shape-outside-empty-line-ref.html
+== shape-outside-empty-ellipse-7.html shape-outside-empty-nothing-ref.html
+== shape-outside-empty-ellipse-8.html shape-outside-empty-nothing-ref.html
+
+== shape-outside-empty-inset-1.html shape-outside-empty-point-ref.html
+== shape-outside-empty-inset-2.html shape-outside-empty-circle-ref.html
+== shape-outside-empty-inset-3.html shape-outside-empty-point-ref.html
+== shape-outside-empty-inset-4.html shape-outside-empty-circle-ref.html
+== shape-outside-empty-inset-5.html shape-outside-empty-line-ref.html
+== shape-outside-empty-inset-6.html shape-outside-empty-line-ref.html
+== shape-outside-empty-inset-7.html shape-outside-empty-nothing-ref.html
+== shape-outside-empty-inset-8.html shape-outside-empty-nothing-ref.html
+
+== shape-outside-empty-polygon-1.html shape-outside-empty-point-ref.html
+# The next test needs fuzzy due to chamfer aberration
+fuzzy(255,520) == shape-outside-empty-polygon-2.html shape-outside-empty-circle-ref.html
+== shape-outside-empty-polygon-3.html shape-outside-empty-line-ref.html
+== shape-outside-empty-polygon-4.html shape-outside-empty-line-ref.html
+== shape-outside-empty-polygon-5.html shape-outside-empty-point-ref.html
+== shape-outside-empty-polygon-6.html shape-outside-empty-nothing-ref.html
+== shape-outside-empty-polygon-7.html shape-outside-empty-nothing-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-shapes/shape-outside-empty-circle-1.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>Shape-outside empty circle, acts like a point</title>
+<style>
+  body {
+    line-height: 0;
+  }
+  .container {
+    width: 600px;
+  }
+  box {
+    display: inline-block;
+    background-color: blue;
+    width: 100px;
+    height: 20px;
+  }
+  .shape {
+    float: left;
+    width: 200px;
+    height: 180px;
+    shape-outside: circle(0px);
+  }
+</style>
+</head>
+<body>
+<div class="container">
+<div class="shape"></div>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-shapes/shape-outside-empty-circle-2.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>Shape-outside empty circle, with shape-margin acts like a circle</title>
+<style>
+  body {
+    line-height: 0;
+  }
+  .container {
+    width: 600px;
+  }
+  box {
+    display: inline-block;
+    background-color: blue;
+    width: 100px;
+    height: 20px;
+  }
+  .shape {
+    float: left;
+    width: 200px;
+    height: 180px;
+    shape-outside: circle(0px);
+    shape-margin: 90px;
+  }
+</style>
+</head>
+<body>
+<div class="container">
+<div class="shape"></div>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-shapes/shape-outside-empty-circle-3.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>Shape-outside empty circle, positioned between elements, acts like nothing</title>
+<style>
+  body {
+    line-height: 0;
+  }
+  .container {
+    width: 600px;
+  }
+  box {
+    display: inline-block;
+    background-color: blue;
+    width: 100px;
+    height: 20px;
+  }
+  .shape {
+    float: left;
+    width: 200px;
+    height: 180px;
+    shape-outside: circle(0px at 100px 20px);
+  }
+</style>
+</head>
+<body>
+<div class="container">
+<div class="shape"></div>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-shapes/shape-outside-empty-circle-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>Reference: Shape-outside empty area, float elements around a circle</title>
+<style>
+  body {
+    line-height: 0;
+  }
+  .container {
+    width: 600px;
+  }
+  box {
+    display: inline-block;
+    background-color: blue;
+    width: 100px;
+    height: 20px;
+  }
+  .shape {
+    float: left;
+    width: 200px;
+    height: 180px;
+    shape-outside: circle(90px);
+  }
+</style>
+</head>
+<body>
+<div class="container">
+<div class="shape"></div>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-shapes/shape-outside-empty-ellipse-1.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>Shape-outside empty point ellipse, acts like a point</title>
+<style>
+  body {
+    line-height: 0;
+  }
+  .container {
+    width: 600px;
+  }
+  box {
+    display: inline-block;
+    background-color: blue;
+    width: 100px;
+    height: 20px;
+  }
+  .shape {
+    float: left;
+    width: 200px;
+    height: 180px;
+    shape-outside: ellipse(0px 0px);
+  }
+</style>
+</head>
+<body>
+<div class="container">
+<div class="shape"></div>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-shapes/shape-outside-empty-ellipse-2.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>Shape-outside empty point ellipse, with shape-margin acts like a circle</title>
+<style>
+  body {
+    line-height: 0;
+  }
+  .container {
+    width: 600px;
+  }
+  box {
+    display: inline-block;
+    background-color: blue;
+    width: 100px;
+    height: 20px;
+  }
+  .shape {
+    float: left;
+    width: 200px;
+    height: 180px;
+    shape-outside: ellipse(0px 0px);
+    shape-margin: 90px;
+  }
+</style>
+</head>
+<body>
+<div class="container">
+<div class="shape"></div>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-shapes/shape-outside-empty-ellipse-3.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>Shape-outside empty horizontal ellipse, acts like a point</title>
+<style>
+  body {
+    line-height: 0;
+  }
+  .container {
+    width: 600px;
+  }
+  box {
+    display: inline-block;
+    background-color: blue;
+    width: 100px;
+    height: 20px;
+  }
+  .shape {
+    float: left;
+    width: 200px;
+    height: 180px;
+    shape-outside: ellipse(50px 0px at 50px 90px);
+  }
+</style>
+</head>
+<body>
+<div class="container">
+<div class="shape"></div>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-shapes/shape-outside-empty-ellipse-4.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>Shape-outside empty horizontal ellipse, with shape-margin acts like a circle (with some aberration)</title>
+<style>
+  body {
+    line-height: 0;
+  }
+  .container {
+    width: 600px;
+  }
+  box {
+    display: inline-block;
+    background-color: blue;
+    width: 100px;
+    height: 20px;
+  }
+  .shape {
+    float: left;
+    width: 200px;
+    height: 180px;
+    shape-outside: ellipse(50px 0px at 50px 90px);
+    shape-margin: 90px;
+  }
+</style>
+</head>
+<body>
+<div class="container">
+<div class="shape"></div>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+<box></box><br>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-shapes/shape-outside-empty-ellipse-5.html