Merge m-c to oak DONTBUILD
authorRobert Strong <robert.bugzilla@gmail.com>
Tue, 05 Sep 2017 21:04:00 -0700
changeset 677681 aa95d14e66c7d623b13cb85c4e18c6547a4d7e9d
parent 677680 020d5be23c5f55a827be5d4995b40cd83b2f588a (current diff)
parent 659384 f64e2b4dcf5eec0b4ad456c149680a67b7c26dc4 (diff)
child 677682 8f6baba2e2499cfa5ebd7bc2c5a51c5ac1db33a1
push id83767
push userbmo:sledru@mozilla.com
push dateTue, 10 Oct 2017 16:25:09 +0000
milestone57.0a1
Merge m-c to oak DONTBUILD
.cron.yml
CLOBBER
browser/app/profile/firefox.js
browser/base/content/aboutDialog-appUpdater.js
browser/base/content/browser-sync.js
browser/base/content/browser.css
browser/base/content/browser.js
browser/components/customizableui/content/panelUI.inc.xul
browser/components/customizableui/content/panelUI.js
browser/components/nsBrowserGlue.js
browser/components/places/tests/browser/browser_410196_paste_into_tags.js
browser/components/places/tests/browser/browser_416459_cut.js
browser/components/places/tests/browser/browser_423515.js
browser/components/places/tests/browser/browser_425884.js
browser/components/places/tests/browser/browser_435851_copy_query.js
browser/components/places/tests/browser/browser_475045.js
browser/components/places/tests/browser/browser_555547.js
browser/components/preferences/in-content-new/containers.js
browser/components/preferences/in-content-new/containers.xul
browser/components/preferences/in-content-new/findInPage.js
browser/components/preferences/in-content-new/jar.mn
browser/components/preferences/in-content-new/main.js
browser/components/preferences/in-content-new/main.xul
browser/components/preferences/in-content-new/moz.build
browser/components/preferences/in-content-new/preferences.js
browser/components/preferences/in-content-new/preferences.xul
browser/components/preferences/in-content-new/privacy.js
browser/components/preferences/in-content-new/privacy.xul
browser/components/preferences/in-content-new/search.js
browser/components/preferences/in-content-new/search.xul
browser/components/preferences/in-content-new/searchResults.xul
browser/components/preferences/in-content-new/subdialogs.js
browser/components/preferences/in-content-new/sync.js
browser/components/preferences/in-content-new/sync.xul
browser/components/preferences/in-content-new/tests/.eslintrc.js
browser/components/preferences/in-content-new/tests/browser.ini
browser/components/preferences/in-content-new/tests/browser_advanced_update.js
browser/components/preferences/in-content-new/tests/browser_applications_selection.js
browser/components/preferences/in-content-new/tests/browser_basic_rebuild_fonts_test.js
browser/components/preferences/in-content-new/tests/browser_bug1018066_resetScrollPosition.js
browser/components/preferences/in-content-new/tests/browser_bug1020245_openPreferences_to_paneContent.js
browser/components/preferences/in-content-new/tests/browser_bug1184989_prevent_scrolling_when_preferences_flipped.js
browser/components/preferences/in-content-new/tests/browser_bug1184989_prevent_scrolling_when_preferences_flipped.xul
browser/components/preferences/in-content-new/tests/browser_bug410900.js
browser/components/preferences/in-content-new/tests/browser_bug705422.js
browser/components/preferences/in-content-new/tests/browser_bug731866.js
browser/components/preferences/in-content-new/tests/browser_bug795764_cachedisabled.js
browser/components/preferences/in-content-new/tests/browser_change_app_handler.js
browser/components/preferences/in-content-new/tests/browser_checkspelling.js
browser/components/preferences/in-content-new/tests/browser_connection.js
browser/components/preferences/in-content-new/tests/browser_connection_bug388287.js
browser/components/preferences/in-content-new/tests/browser_cookies_dialog.js
browser/components/preferences/in-content-new/tests/browser_cookies_exceptions.js
browser/components/preferences/in-content-new/tests/browser_defaultbrowser_alwayscheck.js
browser/components/preferences/in-content-new/tests/browser_engines.js
browser/components/preferences/in-content-new/tests/browser_healthreport.js
browser/components/preferences/in-content-new/tests/browser_homepages_filter_aboutpreferences.js
browser/components/preferences/in-content-new/tests/browser_layersacceleration.js
browser/components/preferences/in-content-new/tests/browser_masterpassword.js
browser/components/preferences/in-content-new/tests/browser_notifications_do_not_disturb.js
browser/components/preferences/in-content-new/tests/browser_password_management.js
browser/components/preferences/in-content-new/tests/browser_performance.js
browser/components/preferences/in-content-new/tests/browser_performance_e10srollout.js
browser/components/preferences/in-content-new/tests/browser_performance_non_e10s.js
browser/components/preferences/in-content-new/tests/browser_permissions_dialog.js
browser/components/preferences/in-content-new/tests/browser_permissions_urlFieldHidden.js
browser/components/preferences/in-content-new/tests/browser_privacypane_1.js
browser/components/preferences/in-content-new/tests/browser_privacypane_3.js
browser/components/preferences/in-content-new/tests/browser_privacypane_4.js
browser/components/preferences/in-content-new/tests/browser_privacypane_5.js
browser/components/preferences/in-content-new/tests/browser_privacypane_8.js
browser/components/preferences/in-content-new/tests/browser_proxy_backup.js
browser/components/preferences/in-content-new/tests/browser_sanitizeOnShutdown_prefLocked.js
browser/components/preferences/in-content-new/tests/browser_search_subdialogs_within_preferences_1.js
browser/components/preferences/in-content-new/tests/browser_search_subdialogs_within_preferences_2.js
browser/components/preferences/in-content-new/tests/browser_search_subdialogs_within_preferences_3.js
browser/components/preferences/in-content-new/tests/browser_search_subdialogs_within_preferences_4.js
browser/components/preferences/in-content-new/tests/browser_search_subdialogs_within_preferences_5.js
browser/components/preferences/in-content-new/tests/browser_search_subdialogs_within_preferences_6.js
browser/components/preferences/in-content-new/tests/browser_search_subdialogs_within_preferences_7.js
browser/components/preferences/in-content-new/tests/browser_search_subdialogs_within_preferences_8.js
browser/components/preferences/in-content-new/tests/browser_search_within_preferences_1.js
browser/components/preferences/in-content-new/tests/browser_search_within_preferences_2.js
browser/components/preferences/in-content-new/tests/browser_search_within_preferences_command.js
browser/components/preferences/in-content-new/tests/browser_searchsuggestions.js
browser/components/preferences/in-content-new/tests/browser_security-1.js
browser/components/preferences/in-content-new/tests/browser_security-2.js
browser/components/preferences/in-content-new/tests/browser_siteData.js
browser/components/preferences/in-content-new/tests/browser_siteData2.js
browser/components/preferences/in-content-new/tests/browser_siteData3.js
browser/components/preferences/in-content-new/tests/browser_site_login_exceptions.js
browser/components/preferences/in-content-new/tests/browser_subdialogs.js
browser/components/preferences/in-content-new/tests/browser_telemetry.js
browser/components/preferences/in-content-new/tests/head.js
browser/components/preferences/in-content-new/tests/offline/manifest.appcache
browser/components/preferences/in-content-new/tests/offline/offline.html
browser/components/preferences/in-content-new/tests/privacypane_tests_perwindow.js
browser/components/preferences/in-content-new/tests/site_data_test.html
browser/components/preferences/in-content-new/tests/subdialog.xul
browser/components/preferences/in-content-new/tests/subdialog2.xul
browser/components/preferences/in-content/advanced.js
browser/components/preferences/in-content/advanced.xul
browser/components/preferences/in-content/applications.js
browser/components/preferences/in-content/applications.xul
browser/components/preferences/in-content/content.js
browser/components/preferences/in-content/content.xul
browser/components/preferences/in-content/security.js
browser/components/preferences/in-content/security.xul
browser/components/preferences/in-content/tests/browser_security.js
browser/config/mozconfigs/linux32/devedition
browser/config/mozconfigs/linux64/devedition
browser/config/mozconfigs/macosx64/devedition
browser/config/mozconfigs/win32/devedition
browser/config/mozconfigs/win64/devedition
browser/extensions/activity-stream/lib/TelemetrySender.jsm
browser/extensions/activity-stream/test/unit/lib/TelemetrySender.test.js
browser/extensions/formautofill/skin/shared/editDialog.css
browser/extensions/onboarding/content/img/overlay-icon.svg
browser/installer/windows/nsis/stub.nsi
browser/locales/en-US/chrome/browser/aboutDialog.dtd
browser/locales/en-US/chrome/browser/browser.dtd
browser/locales/en-US/chrome/browser/browser.properties
browser/locales/en-US/chrome/browser/preferences-old/advanced.dtd
browser/locales/en-US/chrome/browser/preferences-old/applications.dtd
browser/locales/en-US/chrome/browser/preferences-old/containers.dtd
browser/locales/en-US/chrome/browser/preferences-old/containers.properties
browser/locales/en-US/chrome/browser/preferences-old/content.dtd
browser/locales/en-US/chrome/browser/preferences-old/main.dtd
browser/locales/en-US/chrome/browser/preferences-old/preferences.dtd
browser/locales/en-US/chrome/browser/preferences-old/preferences.properties
browser/locales/en-US/chrome/browser/preferences-old/privacy.dtd
browser/locales/en-US/chrome/browser/preferences-old/search.dtd
browser/locales/en-US/chrome/browser/preferences-old/security.dtd
browser/locales/en-US/chrome/browser/preferences-old/sync.dtd
browser/locales/en-US/chrome/browser/preferences-old/tabs.dtd
browser/themes/linux/preferences/in-content-new/dialog.css
browser/themes/linux/preferences/in-content-new/preferences.css
browser/themes/linux/privatebrowsing-mask.png
browser/themes/osx/preferences/in-content-new/dialog.css
browser/themes/osx/preferences/in-content-new/preferences.css
browser/themes/osx/privatebrowsing-mask-short.png
browser/themes/osx/privatebrowsing-mask-short@2x.png
browser/themes/osx/privatebrowsing-mask.png
browser/themes/osx/privatebrowsing-mask@2x.png
browser/themes/shared/customizableui/panelUI.inc.css
browser/themes/shared/fxa/android.png
browser/themes/shared/fxa/android@2x.png
browser/themes/shared/fxa/ios.png
browser/themes/shared/fxa/ios@2x.png
browser/themes/shared/fxa/logo.png
browser/themes/shared/fxa/logo@2x.png
browser/themes/shared/incontentprefs-old/containers.css
browser/themes/shared/incontentprefs-old/dialog.inc.css
browser/themes/shared/incontentprefs-old/icons.svg
browser/themes/shared/incontentprefs-old/preferences.inc.css
browser/themes/shared/incontentprefs-old/search.css
browser/themes/windows/preferences/in-content-new/dialog.css
browser/themes/windows/privatebrowsing-mask-tabstrip-win7.png
browser/themes/windows/privatebrowsing-mask-tabstrip.png
browser/themes/windows/privatebrowsing-mask-titlebar-win7-tall.png
browser/themes/windows/privatebrowsing-mask-titlebar-win7.png
browser/themes/windows/privatebrowsing-mask-titlebar.png
devtools/client/commandline/commandline.css
devtools/client/shared/css-reload.js
devtools/client/shared/devtools-file-watcher.js
devtools/client/shared/file-watcher-worker.js
devtools/client/shared/file-watcher.js
devtools/client/shared/vendor/react-proxy.js
devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_network_messages_click.js
devtools/docs/frontend/react-tips.md
devtools/docs/frontend/redux-tips.md
devtools/server/actors/profiler.js
devtools/server/tests/unit/test_profiler_activation-01.js
devtools/server/tests/unit/test_profiler_activation-02.js
devtools/server/tests/unit/test_profiler_bufferstatus.js
devtools/server/tests/unit/test_profiler_close.js
devtools/server/tests/unit/test_profiler_data.js
devtools/server/tests/unit/test_profiler_events-01.js
devtools/server/tests/unit/test_profiler_events-02.js
devtools/server/tests/unit/test_profiler_getbufferinfo.js
devtools/server/tests/unit/test_profiler_getfeatures.js
devtools/server/tests/unit/test_profiler_sharedlibraries.js
devtools/shared/fronts/profiler.js
devtools/shared/specs/profiler.js
devtools/shim/devtools-startup.js
dom/animation/Animation.cpp
dom/canvas/test/webgl-mochitest/test_webgl_disjoint_timer_query.html
dom/media/gmp/GMPCDMProxy.cpp
dom/media/gmp/GMPCDMProxy.h
dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
dom/media/gmp/widevine-adapter/WidevineAdapter.h
dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
dom/media/gmp/widevine-adapter/WidevineDecryptor.h
dom/media/gmp/widevine-adapter/WidevineDummyDecoder.cpp
dom/media/gmp/widevine-adapter/WidevineDummyDecoder.h
dom/media/gmp/widevine-adapter/WidevineVideoDecoder.cpp
dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h
dom/media/hls/HLSResource.cpp
dom/media/hls/HLSResource.h
dom/media/mediasource/MediaSourceResource.h
dom/media/platforms/agnostic/eme/EMEVideoDecoder.cpp
dom/media/platforms/agnostic/eme/EMEVideoDecoder.h
dom/media/test/bug580982.webm
dom/media/test/bug580982.webm^headers^
dom/media/test/reftest/street.mp4.15thframe-ref.html
dom/media/test/reftest/street.mp4.seek.html
gfx/webrender/res/cs_box_shadow.fs.glsl
gfx/webrender/res/cs_box_shadow.vs.glsl
gfx/webrender/res/cs_clip_rectangle.fs.glsl
gfx/webrender/res/cs_clip_rectangle.vs.glsl
gfx/webrender/res/ps_border_corner.fs.glsl
gfx/webrender/res/ps_border_corner.vs.glsl
gfx/webrender/res/ps_border_edge.fs.glsl
gfx/webrender/res/ps_border_edge.vs.glsl
ipc/glue/GeckoChildProcessHost.cpp
ipc/mscom/InterfaceRegistrationAnnotator.cpp
ipc/mscom/InterfaceRegistrationAnnotator.h
js/src/jit-test/tests/auto-regress/bug1343245.js
js/src/jit-test/tests/auto-regress/bug511836.js
js/src/jit-test/tests/auto-regress/bug561278.js
js/src/jit-test/tests/auto-regress/bug617485.js
js/src/jit-test/tests/auto-regress/bug637010.js
js/src/jit-test/tests/auto-regress/bug778557.js
js/src/jit-test/tests/baseline/bug1153458.js
js/src/jit-test/tests/basic/bug649939.js
js/src/jit-test/tests/basic/bug684922.js
js/src/jit-test/tests/basic/bug885648.js
js/src/jit-test/tests/basic/testCustomIterator.js
js/src/jit-test/tests/for-of/next-1.js
js/src/jit-test/tests/for-of/next-2.js
js/src/jit-test/tests/for-of/next-surfaces.js
js/src/jit-test/tests/ion/bug735869.js
js/src/jit-test/tests/ion/bug754718.js
js/src/jit-test/tests/ion/bug852174.js
js/src/jit-test/tests/jaeger/bug554580-1.js
js/src/jit-test/tests/jaeger/recompile/bug671943-1.js
js/src/jit/x86-shared/AtomicOperations-x86-shared.h
js/src/tests/js1_5/Regress/regress-407957.js
js/src/tests/js1_7/GC/regress-381374.js
js/src/tests/js1_7/extensions/basic-Iterator.js
js/src/tests/js1_7/extensions/iterator-ctor.js
js/src/tests/js1_7/extensions/regress-346021.js
js/src/tests/js1_7/extensions/regress-354499-01.js
js/src/tests/js1_7/extensions/regress-354499-02.js
js/src/tests/js1_7/extensions/regress-354945-01.js
js/src/tests/js1_7/extensions/regress-354945-02.js
js/src/tests/js1_7/extensions/regress-589112.js
js/src/tests/js1_7/extensions/regress-590813.js
js/src/tests/js1_7/geniter/builtin-Iterator-function.js
js/src/tests/js1_7/iterable/regress-341496.js
js/src/tests/js1_7/iterable/regress-354750-01.js
js/src/tests/js1_7/iterable/regress-355025.js
js/src/tests/js1_7/iterable/regress-355090.js
js/src/tests/js1_7/iterable/regress-568056.js
js/src/tests/js1_7/regress/regress-385393-05.js
js/src/tests/js1_7/regress/regress-407957.js
js/xpconnect/src/XPCShellImpl.cpp
layout/reftests/printing/1108104-ref.html
layout/reftests/printing/1108104.html
layout/reftests/printing/115199-1-ref.html
layout/reftests/printing/115199-1.html
layout/reftests/printing/115199-2-ref.html
layout/reftests/printing/115199-2a.html
layout/reftests/printing/115199-2b.html
layout/reftests/printing/1166147-ref.html
layout/reftests/printing/1166147.html
layout/reftests/printing/129941-1-ref.html
layout/reftests/printing/129941-1a.html
layout/reftests/printing/129941-1b.html
layout/reftests/printing/129941-1c.html
layout/reftests/printing/129941-1d.html
layout/reftests/printing/129941-1e.html
layout/reftests/printing/1321803-1-ref.html
layout/reftests/printing/1321803-1a.html
layout/reftests/printing/272830-1-ref.html
layout/reftests/printing/272830-1.html
layout/reftests/printing/318022-1-ref.html
layout/reftests/printing/318022-1.html
layout/reftests/printing/381497-f.html
layout/reftests/printing/381497-n.html
layout/reftests/printing/403669-1-ref.html
layout/reftests/printing/403669-1.html
layout/reftests/printing/577450-1-ref.html
layout/reftests/printing/577450-1.html
layout/reftests/printing/609227-1-ref.html
layout/reftests/printing/609227-1.html
layout/reftests/printing/609227-2-ref.html
layout/reftests/printing/609227-2a.html
layout/reftests/printing/609227-2b.html
layout/reftests/printing/626395-1-ref.html
layout/reftests/printing/626395-1a.html
layout/reftests/printing/626395-1b.html
layout/reftests/printing/626395-2-ref.html
layout/reftests/printing/626395-2a.html
layout/reftests/printing/626395-2b.html
layout/reftests/printing/626395-2c.html
layout/reftests/printing/626395-2d.html
layout/reftests/printing/652178-1-ref.html
layout/reftests/printing/652178-1-ref2.html
layout/reftests/printing/652178-1.html
layout/reftests/printing/745025-1-ref.html
layout/reftests/printing/745025-1.html
layout/reftests/printing/820496-1-ref.html
layout/reftests/printing/820496-1.html
layout/reftests/printing/960822-ref.html
layout/reftests/printing/960822.html
layout/reftests/printing/966419-1-ref.html
layout/reftests/printing/966419-1.html
layout/reftests/printing/966419-2-ref.html
layout/reftests/printing/966419-2.html
layout/reftests/printing/blank.html
layout/reftests/printing/test-async-paged.html
media/libcubeb/src/cubeb_utils.c
memory/build/jemalloc_config.cpp
memory/build/replace_malloc.c
mobile/android/app/src/main/res/drawable-hdpi/foxfinder.webp
mobile/android/app/src/main/res/drawable-hdpi/tab_indicator_divider.9.png
mobile/android/app/src/main/res/drawable-xhdpi/foxfinder.webp
mobile/android/app/src/main/res/drawable-xhdpi/tab_indicator_divider.9.png
mobile/android/app/src/main/res/drawable-xxhdpi/foxfinder.webp
mobile/android/app/src/main/res/layout/activity_stream_card_history_item.xml
mobile/android/app/src/main/res/layout/activity_stream_main_welcomepanel.xml
mobile/android/app/src/main/res/layout/activity_stream_main_welcomepanel_content.xml
mobile/android/app/src/photon/res/drawable-xxxhdpi/suggestedsites_twitter.png
mobile/android/base/java/org/mozilla/gecko/activitystream/homepanel/stream/WelcomePanelRow.java
mobile/android/locales/en-US/chrome/handling.properties
mobile/locales/en-US/overrides/passwordmgr.properties
modules/libjar/test/chrome/chrome.ini
modules/libjar/test/chrome/signed-added.zip
modules/libjar/test/chrome/signed-badca.zip
modules/libjar/test/chrome/signed-tampered.zip
modules/libjar/test/chrome/signed.zip
modules/libjar/test/chrome/test_bug386153.html
modules/libjar/test/chrome/unsigned.zip
python/mozbuild/mozbuild/base.py
security/nss/lib/freebl/ecl/uint128.c
security/nss/lib/freebl/ecl/uint128.h
services/common/blocklist-clients.js
services/common/tests/unit/test_blocklist_certificates.js
services/common/tests/unit/test_blocklist_clients.js
servo/components/style/cascade_info.rs
servo/components/style_derive/has_viewport_percentage.rs
servo/rust-commit-hash
servo/tests/unit/gfx/font_cache_thread.rs
servo/tests/unit/style/properties/viewport.rs
servo/tests/unit/stylo/sanity_checks.rs
taskcluster/ci/nightly-l10n/kind.yml
taskcluster/ci/test/kind.yml
taskcluster/ci/test/test-platforms.yml
taskcluster/ci/test/test-sets.yml
taskcluster/ci/test/tests.yml
taskcluster/docker/README.md
taskcluster/taskgraph/target_tasks.py
taskcluster/taskgraph/transforms/build.py
taskcluster/taskgraph/transforms/gecko_v2_whitelist.py
taskcluster/taskgraph/transforms/task.py
taskcluster/taskgraph/transforms/tests.py
testing/geckodriver/LICENSE
testing/mach_commands.py
testing/mochitest/runtests.py
testing/mozharness/mozharness/mozilla/building/buildbase.py
testing/runtimes/writeruntimes.py
testing/web-platform/meta/IndexedDB/idb-binary-key-roundtrip.htm.ini
testing/web-platform/meta/IndexedDB/idbcursor-continuePrimaryKey.htm.ini
testing/web-platform/meta/css/css-namespaces-3/syntax-013.xml.ini
testing/web-platform/meta/css/css-text-3/i18n/css3-text-line-break-baspglwj-022.html.ini
testing/web-platform/meta/cssom/escape.html.ini
testing/web-platform/meta/performance-timeline/po-callback-mutate.any.js.ini
testing/web-platform/meta/performance-timeline/po-disconnect.any.js.ini
testing/web-platform/meta/performance-timeline/po-entries-sort.any.js.ini
testing/web-platform/meta/performance-timeline/po-getentries.any.js.ini
testing/web-platform/meta/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html.ini
testing/web-platform/meta/webrtc/simplecall.html.ini
third_party/rust/bindgen/.github/ISSUE_TEMPLATE.md
third_party/rust/bindgen/.travis.yml
third_party/rust/bindgen/CONTRIBUTING.md
third_party/rust/bindgen/LICENSE
third_party/rust/bindgen/README.md
third_party/rust/bindgen/appveyor.yml
third_party/rust/bindgen/book/book.toml
third_party/rust/bindgen/book/src/SUMMARY.md
third_party/rust/bindgen/book/src/blacklisting.md
third_party/rust/bindgen/book/src/chapter_1.md
third_party/rust/bindgen/book/src/command-line-usage.md
third_party/rust/bindgen/book/src/cpp.md
third_party/rust/bindgen/book/src/customizing-generated-bindings.md
third_party/rust/bindgen/book/src/introduction.md
third_party/rust/bindgen/book/src/library-usage.md
third_party/rust/bindgen/book/src/nocopy.md
third_party/rust/bindgen/book/src/opaque.md
third_party/rust/bindgen/book/src/replacing-types.md
third_party/rust/bindgen/book/src/requirements.md
third_party/rust/bindgen/book/src/tutorial-0.md
third_party/rust/bindgen/book/src/tutorial-1.md
third_party/rust/bindgen/book/src/tutorial-2.md
third_party/rust/bindgen/book/src/tutorial-3.md
third_party/rust/bindgen/book/src/tutorial-4.md
third_party/rust/bindgen/book/src/tutorial-5.md
third_party/rust/bindgen/book/src/tutorial-6.md
third_party/rust/bindgen/book/src/using-unions.md
third_party/rust/bindgen/book/src/whitelisting.md
third_party/rust/bindgen/ci/assert-docs.sh
third_party/rust/bindgen/ci/assert-no-diff.bat
third_party/rust/bindgen/ci/assert-no-diff.sh
third_party/rust/bindgen/ci/assert-rustfmt.sh
third_party/rust/bindgen/ci/before_install.sh
third_party/rust/bindgen/ci/deploy-book.sh
third_party/rust/bindgen/ci/no-includes.sh
third_party/rust/bindgen/ci/test-book.sh
third_party/rust/bindgen/ci/test.bat
third_party/rust/bindgen/ci/test.sh
third_party/rust/bindgen/example-graphviz-ir.png
third_party/rust/bindgen/rustfmt.toml
third_party/rust/bindgen/src/uses.rs
third_party/rust/clap/appveyor.yml
third_party/rust/thread-id/license
third_party/rust/webdriver/.cargo-checksum.json
third_party/rust/webdriver/.cargo-ok
third_party/rust/webdriver/.travis.yml
third_party/rust/webdriver/Cargo.toml
third_party/rust/webdriver/LICENSE
third_party/rust/webdriver/README.md
third_party/rust/webdriver/src/capabilities.rs
third_party/rust/webdriver/src/command.rs
third_party/rust/webdriver/src/common.rs
third_party/rust/webdriver/src/error.rs
third_party/rust/webdriver/src/httpapi.rs
third_party/rust/webdriver/src/lib.rs
third_party/rust/webdriver/src/macros.rs
third_party/rust/webdriver/src/response.rs
third_party/rust/webdriver/src/server.rs
toolkit/components/telemetry/.flake8
toolkit/components/telemetry/Histograms.json
toolkit/components/url-classifier/tests/jar.mn
toolkit/components/url-classifier/tests/unittests.xul
toolkit/content/license.html
toolkit/crashreporter/CrashSubmit.jsm
toolkit/modules/RemoteController.jsm
toolkit/modules/moz.build
toolkit/mozapps/extensions/test/browser/browser_hotfix.js
toolkit/mozapps/extensions/test/browser/signed_hotfix.rdf
toolkit/mozapps/extensions/test/browser/signed_hotfix.xpi
toolkit/mozapps/extensions/test/browser/unsigned_hotfix.rdf
toolkit/mozapps/extensions/test/browser/unsigned_hotfix.xpi
toolkit/mozapps/extensions/test/xpinstall/browser_signed_no_cn.js
toolkit/mozapps/extensions/test/xpinstall/browser_signed_no_o.js
toolkit/mozapps/update/nsIUpdateService.idl
toolkit/mozapps/update/nsUpdateService.js
toolkit/mozapps/update/tests/data/shared.js
toolkit/mozapps/update/tests/data/sharedUpdateXML.js
toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js
toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForOlderAppVersion.js
toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForSameVersionAndBuildID.js
toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingIncorrectStatus.js
toolkit/mozapps/update/tests/unit_aus_update/cleanupPendingVersionFileIncorrectStatus.js
toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js
toolkit/mozapps/update/tests/unit_base_updater/invalidArgCallbackFileNotInInstallDirFailure.js
toolkit/mozapps/update/tests/unit_base_updater/invalidArgCallbackFilePathTooLongFailure.js
toolkit/mozapps/update/tests/unit_base_updater/invalidArgInstallDirPathTooLongFailure.js
toolkit/mozapps/update/tests/unit_base_updater/invalidArgInstallDirPathTraversalFailure.js
toolkit/mozapps/update/tests/unit_base_updater/invalidArgInstallWorkingDirPathNotSameFailure_win.js
toolkit/mozapps/update/tests/unit_base_updater/invalidArgPatchDirPathTraversalFailure.js
toolkit/mozapps/update/tests/unit_base_updater/invalidArgStageDirNotInInstallDirFailure_win.js
toolkit/mozapps/update/tests/unit_base_updater/invalidArgWorkingDirPathLocalUNCFailure_win.js
toolkit/mozapps/update/tests/unit_base_updater/invalidArgWorkingDirPathRelativeFailure.js
toolkit/mozapps/update/tests/unit_base_updater/marAppApplyDirLockedStageFailure_win.js
toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateAppBinInUseStageSuccess_win.js
toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageOldVersionFailure.js
toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageSuccess.js
toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateSuccess.js
toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js
toolkit/mozapps/update/tests/unit_base_updater/marAppInUseSuccessComplete.js
toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessPartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessPartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js
toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marPIDPersistsSuccessComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailurePartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessPartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js
toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js
toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js
toolkit/mozapps/update/tests/unit_base_updater/marSuccessComplete.js
toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js
toolkit/mozapps/update/tests/unit_base_updater/marVersionDowngrade.js
toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js
toolkit/mozapps/update/tests/unit_service_updater/invalidArgInstallDirPathTooLongFailureSvc.js
toolkit/mozapps/update/tests/unit_service_updater/invalidArgInstallDirPathTraversalFailureSvc.js
toolkit/mozapps/update/tests/unit_service_updater/invalidArgInstallWorkingDirPathNotSameFailureSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/invalidArgPatchDirPathSuffixFailureSvc.js
toolkit/mozapps/update/tests/unit_service_updater/invalidArgPatchDirPathTraversalFailureSvc.js
toolkit/mozapps/update/tests/unit_service_updater/invalidArgStageDirNotInInstallDirFailureSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/invalidArgWorkingDirPathLocalUNCFailureSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/invalidArgWorkingDirPathRelativeFailureSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marAppApplyDirLockedStageFailureSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateAppBinInUseStageSuccessSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateStageSuccessSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateSuccessSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marAppInUseStageFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marAppInUseSuccessCompleteSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppStageSuccessCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppStageSuccessPartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppSuccessCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppSuccessPartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFailurePartialSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailurePartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessPartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailurePartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailurePartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseStageFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseStageFailurePartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseSuccessCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseSuccessPartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marStageFailurePartialSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessCompleteSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessPartialSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marSuccessCompleteSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marSuccessPartialSvc.js
toolkit/toolkit.mozbuild
toolkit/xre/nsAppRunner.cpp
tools/lint/flake8_/__init__.py
tools/lint/flake8_/flake8_requirements.txt
xpcom/build/XPCOMInit.cpp
xpcom/ds/nsAtomService.cpp
xpcom/ds/nsAtomService.h
xpcom/ds/nsIAtomService.idl
--- a/.clang-format
+++ b/.clang-format
@@ -9,17 +9,16 @@ PointerAlignment: Left
 
 # Prevent the loss of indentation with these macros
 MacroBlockBegin: "^\
 NS_INTERFACE_MAP_BEGIN|\
 NS_INTERFACE_TABLE_HEAD|\
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION|\
 NS_IMPL_CYCLE_COLLECTION_.*_BEGIN|\
 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED|\
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED|\
 NS_INTERFACE_TABLE_BEGIN|\
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED|\
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED$"
 MacroBlockEnd: "^\
 NS_INTERFACE_MAP_END|\
 NS_IMPL_CYCLE_COLLECTION_.*_END|\
 NS_INTERFACE_TABLE_END|\
 NS_INTERFACE_MAP_END_INHERITING|\
--- a/.clang-format-ignore
+++ b/.clang-format-ignore
@@ -1,27 +1,34 @@
+# Uses the LLVM coding style
 ^build/clang-plugin/.*
+# The two templates cannot be formatted
 ^config/gcc-stl-wrapper.template.h
 ^config/msvc-stl-wrapper.template.h
 ^dom/base/test/.*
 ^dom/bindings/test/.*
 ^dom/media/gtest/.*
 ^gfx/testsd/.*
 ^image/test/.*
 ^ipc/ipdl/test/.*
 ^ipc/testshell/.*
 ^js/src/jsapi-tests/.*
+# See bug 1395584
+^js/src/vm/Opcodes.h
+# Ignored because of bug 1342657
 ^layout/style/nsCSSPropAliasList.h
+# Ignored because of bug 1342657
 ^layout/style/nsCSSPropList.h
 ^media/mtransport/test/.*
 ^mfbt/tests/.*
 ^storage/test/.*
 ^testing/gtest/.*
 ^tools/profiler/tests/.*
 ^uriloader/exthandler/tests/.*
+# JNI code is generated
 ^widget/android/GeneratedJNINatives.h
 ^widget/android/GeneratedJNIWrappers.cpp
 ^widget/android/GeneratedJNIWrappers.h
 ^widget/android/fennec/FennecJNINatives.h
 ^widget/android/fennec/FennecJNIWrappers.cpp
 ^widget/android/fennec/FennecJNIWrappers.h
 ^widget/tests/.*
 ^xpcom/glue/tests/.*
--- a/.eslintignore
+++ b/.eslintignore
@@ -170,16 +170,17 @@ devtools/client/debugger/test/mochitest/
 devtools/client/debugger/test/mochitest/code_math.min.js
 devtools/client/debugger/test/mochitest/code_math_bogus_map.js
 devtools/client/debugger/test/mochitest/code_ugly*
 devtools/client/debugger/test/mochitest/code_worker-source-map.js
 devtools/client/framework/test/code_ugly*
 devtools/client/inspector/markup/test/events_bundle.js
 devtools/client/netmonitor/test/xhr_bundle.js
 devtools/client/webconsole/new-console-output/test/mochitest/code_bundle_nosource.js
+devtools/client/webconsole/new-console-output/test/mochitest/code_bundle_invalidmap.js
 devtools/server/tests/unit/babel_and_browserify_script_with_source_map.js
 devtools/server/tests/unit/setBreakpoint*
 devtools/server/tests/unit/sourcemapped.js
 
 # dom/ exclusions
 dom/animation/**
 dom/archivereader/**
 dom/asmjscache/**
@@ -343,17 +344,16 @@ toolkit/modules/tests/xpcshell/test_task
 # External code:
 toolkit/components/microformats/test/**
 toolkit/components/microformats/microformat-shiv.js
 toolkit/components/reader/Readability.js
 toolkit/components/reader/JSDOMParser.js
 
 # Uses preprocessing
 toolkit/content/widgets/wizard.xml
-toolkit/components/jsdownloads/src/DownloadIntegration.jsm
 toolkit/components/osfile/osfile.jsm
 toolkit/components/urlformatter/nsURLFormatter.js
 toolkit/modules/AppConstants.jsm
 toolkit/mozapps/downloads/nsHelperAppDlg.js
 toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js
 
 # Third party
 toolkit/modules/third_party/**
--- a/.flake8
+++ b/.flake8
@@ -1,4 +1,6 @@
 [flake8]
 # See http://pep8.readthedocs.io/en/latest/intro.html#configuration
 ignore = E121, E123, E126, E129, E133, E226, E241, E242, E704, W503, E402
 max-line-length = 99
+exclude =
+    testing/mochitest/pywebsocket,
--- a/.taskcluster.yml
+++ b/.taskcluster.yml
@@ -67,68 +67,68 @@ tasks:
       env:
         # checkout-gecko uses these to check out the source; the inputs
         # to `mach taskgraph decision` are all on the command line.
         GECKO_BASE_REPOSITORY: 'https://hg.mozilla.org/mozilla-unified'
         GECKO_HEAD_REPOSITORY: '${repoUrl}'
         GECKO_HEAD_REF: '${push.revision}'
         GECKO_HEAD_REV: '${push.revision}'
         GECKO_COMMIT_MSG: '${push.comment}'
-        HG_STORE_PATH: /home/worker/checkouts/hg-store
-        TASKCLUSTER_CACHES: /home/worker/checkouts
+        HG_STORE_PATH: /builds/worker/checkouts/hg-store
+        TASKCLUSTER_CACHES: /builds/worker/checkouts
 
       cache:
-        level-${repository.level}-checkouts-sparse-v1: /home/worker/checkouts
+        level-${repository.level}-checkouts-sparse-v1: /builds/worker/checkouts
 
       features:
         taskclusterProxy: true
         chainOfTrust: true
 
       # Note: This task is built server side without the context or tooling that
       # exist in tree so we must hard code the hash
       # XXX Changing this will break Chain of Trust without an associated puppet and
       # scriptworker patch!
-      image: 'taskcluster/decision:0.1.10@sha256:c5451ee6c655b3d97d4baa3b0e29a5115f23e0991d4f7f36d2a8f793076d6854'
+      image: 'taskcluster/decision:2.0.0@sha256:4039fd878e5700b326d4a636e28c595c053fbcb53909c1db84ad1f513cf644ef'
 
       maxRunTime: 1800
 
       # TODO use mozilla-unified for the base repository once the tc-vcs
       # tar.gz archives are created or tc-vcs isn't being used.
       command:
-        - /home/worker/bin/run-task
-        - '--vcs-checkout=/home/worker/checkouts/gecko'
+        - /builds/worker/bin/run-task
+        - '--vcs-checkout=/builds/worker/checkouts/gecko'
         - '--sparse-profile=build/sparse-profiles/taskgraph'
         - '--'
         - bash
         - -cx
         - $let:
             extraArgs: {$if: 'tasks_for == "hg-push"', then: '', else: '${cron.quoted_args}'}
           # NOTE: the explicit reference to mozilla-central below is required because android-stuff
           # still uses tc-vcs, which does not support mozilla-unified
           # https://bugzilla.mozilla.org/show_bug.cgi?id=1383973
           in: >
-            cd /home/worker/checkouts/gecko &&
-            ln -s /home/worker/artifacts artifacts &&
+            cd /builds/worker/checkouts/gecko &&
+            ln -s /builds/worker/artifacts artifacts &&
             ./mach --log-no-times taskgraph decision
             --pushlog-id='${push.pushlog_id}'
             --pushdate='${push.pushdate}'
             --project='${repository.project}'
             --message="$GECKO_COMMIT_MSG"
             --owner='${ownerEmail}'
             --level='${repository.level}'
             --base-repository='https://hg.mozilla.org/mozilla-central'
             --head-repository="$GECKO_HEAD_REPOSITORY"
             --head-ref="$GECKO_HEAD_REF"
             --head-rev="$GECKO_HEAD_REV"
             ${extraArgs}
 
       artifacts:
         'public':
           type: 'directory'
-          path: '/home/worker/artifacts'
+          path: '/builds/worker/artifacts'
           expires: {$fromNow: '1 year'}
 
     extra:
       treeherder:
         $merge:
           - machine:
               platform: gecko-decision
           - $if: 'tasks_for == "hg-push"'
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1340910 - clobber required for Brotli 0.6.0 update due to changes in exported headers.
+Bug 1395486 - Moving files to content-accessible requires a clobber so as not to break Android packaging.
--- a/accessible/base/MarkupMap.h
+++ b/accessible/base/MarkupMap.h
@@ -59,22 +59,22 @@ MARKUPMAP(figure,
           roles::FIGURE,
           Attr(xmlroles, figure))
 
 MARKUPMAP(form,
           New_HyperText,
           roles::FORM)
 
 MARKUPMAP(footer,
-          New_HyperText,
-          roles::FOOTER)
+          New_HTMLHeaderOrFooter,
+          0)
 
 MARKUPMAP(header,
-          New_HyperText,
-          roles::HEADER)
+          New_HTMLHeaderOrFooter,
+          0)
 
 MARKUPMAP(h1,
           New_HyperText,
           roles::HEADING)
 
 MARKUPMAP(h2,
           New_HyperText,
           roles::HEADING)
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -156,16 +156,19 @@ static Accessible* New_HyperText(nsICont
   { return new HyperTextAccessibleWrap(aContent, aContext->Document()); }
 
 static Accessible* New_HTMLFigcaption(nsIContent* aContent, Accessible* aContext)
   { return new HTMLFigcaptionAccessible(aContent, aContext->Document()); }
 
 static Accessible* New_HTMLFigure(nsIContent* aContent, Accessible* aContext)
   { return new HTMLFigureAccessible(aContent, aContext->Document()); }
 
+static Accessible* New_HTMLHeaderOrFooter(nsIContent* aContent, Accessible* aContext)
+  { return new HTMLHeaderOrFooterAccessible(aContent, aContext->Document()); }
+
 static Accessible* New_HTMLLegend(nsIContent* aContent, Accessible* aContext)
   { return new HTMLLegendAccessible(aContent, aContext->Document()); }
 
 static Accessible* New_HTMLOption(nsIContent* aContent, Accessible* aContext)
   { return new HTMLSelectOptionAccessible(aContent, aContext->Document()); }
 
 static Accessible* New_HTMLOptgroup(nsIContent* aContent, Accessible* aContext)
   { return new HTMLSelectOptGroupAccessible(aContent, aContext->Document()); }
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -843,18 +843,20 @@ Accessible::XULElmName(DocAccessible* aD
 nsresult
 Accessible::HandleAccEvent(AccEvent* aEvent)
 {
   NS_ENSURE_ARG_POINTER(aEvent);
 
   if (profiler_is_active()) {
     nsAutoCString strEventType;
     GetAccService()->GetStringEventType(aEvent->GetEventType(), strEventType);
-
-    profiler_tracing("A11y Event", strEventType.get());
+    nsAutoCString strMarker;
+    strMarker.AppendLiteral("A11y Event - ");
+    strMarker.Append(strEventType);
+    profiler_add_marker(strMarker.get());
   }
 
   if (IPCAccessibilityActive() && Document()) {
     DocAccessibleChild* ipcDoc = mDoc->IPCDoc();
     MOZ_ASSERT(ipcDoc);
     if (ipcDoc) {
       uint64_t id = aEvent->GetAccessible()->IsDoc() ? 0 :
         reinterpret_cast<uintptr_t>(aEvent->GetAccessible());
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -158,17 +158,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_IN
   tmp->mDependentIDsHash.Clear();
   tmp->mNodeToAccessibleMap.Clear();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAccessibleCache)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnchorJumpElm)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mInvalidationList)
   tmp->mARIAOwnsHash.Clear();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DocAccessible)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DocAccessible)
   NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY(nsIAccessiblePivotObserver)
 NS_INTERFACE_MAP_END_INHERITING(HyperTextAccessible)
 
 NS_IMPL_ADDREF_INHERITED(DocAccessible, HyperTextAccessible)
--- a/accessible/generic/HyperTextAccessible.cpp
+++ b/accessible/generic/HyperTextAccessible.cpp
@@ -1137,41 +1137,16 @@ HyperTextAccessible::LandmarkRole() cons
     return nullptr;
 
   // For the html landmark elements we expose them like we do ARIA landmarks to
   // make AT navigation schemes "just work".
   if (mContent->IsHTMLElement(nsGkAtoms::nav)) {
     return nsGkAtoms::navigation;
   }
 
-  if (mContent->IsAnyOfHTMLElements(nsGkAtoms::header,
-                                    nsGkAtoms::footer)) {
-    // Only map header and footer if they are not descendants of an article
-    // or section tag.
-    nsIContent* parent = mContent->GetParent();
-    while (parent) {
-      if (parent->IsAnyOfHTMLElements(nsGkAtoms::article, nsGkAtoms::section)) {
-        break;
-      }
-      parent = parent->GetParent();
-    }
-
-    // No article or section elements found.
-    if (!parent) {
-      if (mContent->IsHTMLElement(nsGkAtoms::header)) {
-        return nsGkAtoms::banner;
-      }
-
-      if (mContent->IsHTMLElement(nsGkAtoms::footer)) {
-        return nsGkAtoms::contentinfo;
-      }
-    }
-    return nullptr;
-  }
-
   if (mContent->IsHTMLElement(nsGkAtoms::aside)) {
     return nsGkAtoms::complementary;
   }
 
   if (mContent->IsHTMLElement(nsGkAtoms::main)) {
     return nsGkAtoms::main;
   }
 
--- a/accessible/html/HTMLElementAccessibles.cpp
+++ b/accessible/html/HTMLElementAccessibles.cpp
@@ -197,8 +197,64 @@ HTMLSummaryAccessible::NativeState()
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLSummaryAccessible: Widgets
 
 bool
 HTMLSummaryAccessible::IsWidget() const
 {
   return true;
 }
+
+
+////////////////////////////////////////////////////////////////////////////////
+// HTMLHeaderOrFooterAccessible
+////////////////////////////////////////////////////////////////////////////////
+
+NS_IMPL_ISUPPORTS_INHERITED0(HTMLHeaderOrFooterAccessible, HyperTextAccessible)
+
+role
+HTMLHeaderOrFooterAccessible::NativeRole()
+{
+  // Only map header and footer if they are direct descendants of the body tag.
+  // If other sectioning or sectioning root elements, they become sections.
+  nsIContent* parent = mContent->GetParent();
+  while (parent) {
+    if (parent->IsAnyOfHTMLElements(nsGkAtoms::article, nsGkAtoms::aside,
+                             nsGkAtoms::nav, nsGkAtoms::section,
+                             nsGkAtoms::blockquote, nsGkAtoms::details,
+                             nsGkAtoms::dialog, nsGkAtoms::fieldset,
+                             nsGkAtoms::figure, nsGkAtoms::td)) {
+      break;
+    }
+    parent = parent->GetParent();
+  }
+
+  // No sectioning or sectioning root elements found.
+  if (!parent) {
+    if (mContent->IsHTMLElement(nsGkAtoms::header)) {
+      return roles::HEADER;
+    }
+
+    if (mContent->IsHTMLElement(nsGkAtoms::footer)) {
+      return roles::FOOTER;
+    }
+  }
+
+  return roles::SECTION;
+}
+
+nsIAtom*
+HTMLHeaderOrFooterAccessible::LandmarkRole() const
+{
+  if (!HasOwnContent())
+    return nullptr;
+
+  a11y::role r = const_cast<HTMLHeaderOrFooterAccessible*>(this)->Role();
+  if (r == roles::HEADER) {
+    return nsGkAtoms::banner;
+  }
+
+  if (r == roles::FOOTER) {
+    return nsGkAtoms::contentinfo;
+  }
+
+  return nullptr;
+}
--- a/accessible/html/HTMLElementAccessibles.h
+++ b/accessible/html/HTMLElementAccessibles.h
@@ -109,12 +109,32 @@ public:
   virtual uint8_t ActionCount() override;
   virtual void ActionNameAt(uint8_t aIndex, nsAString& aName) override;
   virtual bool DoAction(uint8_t aIndex) override;
 
   // Widgets
   virtual bool IsWidget() const override;
 };
 
+/**
+ * Used for HTML header and footer elements.
+ */
+class HTMLHeaderOrFooterAccessible : public HyperTextAccessibleWrap
+{
+public:
+
+  HTMLHeaderOrFooterAccessible(nsIContent* aContent, DocAccessible* aDoc) :
+    HyperTextAccessibleWrap(aContent, aDoc) {}
+
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // Accessible
+  virtual nsIAtom* LandmarkRole() const override;
+  virtual a11y::role NativeRole() override;
+
+protected:
+  virtual ~HTMLHeaderOrFooterAccessible() {}
+};
+
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/tests/browser/.eslintrc.js
+++ b/accessible/tests/browser/.eslintrc.js
@@ -17,17 +17,16 @@ module.exports = {
     "consistent-this": "off",
     "curly": ["error", "multi-line"],
     "default-case": "off",
     "dot-location": ["error", "property"],
 
     "eqeqeq": "off",
     "func-names": "off",
     "func-style": "off",
-    "generator-star-spacing": "off",
     "handle-callback-err": ["error", "er"],
     "indent": ["error", 2, {"SwitchCase": 1}],
     "max-nested-callbacks": ["error", 4],
     "max-params": "off",
     "max-statements": "off",
     "new-cap": ["error", {"capIsNew": false}],
     "new-parens": "error",
     "no-bitwise": "off",
--- a/accessible/tests/mochitest/elm/test_HTMLSpec.html
+++ b/accessible/tests/mochitest/elm/test_HTMLSpec.html
@@ -519,22 +519,30 @@
       obj = {
         role: ROLE_FOOTER,
         attributes: { "xml-roles": "contentinfo" },
         interfaces: [ nsIAccessibleText, nsIAccessibleHyperText ]
       };
       testElm("footer", obj);
 
       obj = {
-        role: ROLE_FOOTER,
+        role: ROLE_SECTION,
         absentAttributes: { "xml-roles": "contentinfo" },
         interfaces: [ nsIAccessibleText, nsIAccessibleHyperText ]
       };
       testElm("footer_in_article", obj);
+      testElm("footer_in_aside", obj);
+      testElm("footer_in_nav", obj);
       testElm("footer_in_section", obj);
+      testElm("footer_in_blockquote", obj);
+      testElm("footer_in_details", obj);
+      testElm("footer_in_dialog", obj);
+      testElm("footer_in_fieldset", obj);
+      testElm("footer_in_figure", obj);
+      testElm("footer_in_td", obj);
 
       // ////////////////////////////////////////////////////////////////////////
       // HTML:form
 
       obj = {
         role: ROLE_FORM
       };
       testElm("form", obj);
@@ -604,22 +612,30 @@
       obj = {
         role: ROLE_HEADER,
         attributes: { "xml-roles": "banner" },
         interfaces: [ nsIAccessibleText, nsIAccessibleHyperText ]
       };
       testElm("header", obj);
 
       obj = {
-        role: ROLE_HEADER,
+        role: ROLE_SECTION,
         absentAttributes: { "xml-roles": "banner" },
         interfaces: [ nsIAccessibleText, nsIAccessibleHyperText ]
       };
       testElm("header_in_article", obj);
+      testElm("header_in_aside", obj);
+      testElm("header_in_nav", obj);
       testElm("header_in_section", obj);
+      testElm("header_in_blockquote", obj);
+      testElm("header_in_details", obj);
+      testElm("header_in_dialog", obj);
+      testElm("header_in_fieldset", obj);
+      testElm("header_in_figure", obj);
+      testElm("header_in_td", obj);
 
       // ////////////////////////////////////////////////////////////////////////
       // HTML:hr
 
       obj = {
         role: ROLE_SEPARATOR,
       };
       testElm("hr", obj);
@@ -1466,19 +1482,43 @@
     <img src="../moz.png" alt="An awesome picture">
     <figcaption id="figcaption">Caption for the awesome picture</figcaption>
   </figure>
 
   <footer id="footer">Some copyright info</footer>
   <article>
     <footer id="footer_in_article">Some copyright info</footer>
   </article>
+  <aside>
+    <footer id="footer_in_aside">Some copyright info</footer>
+  </aside>
+  <nav>
+    <footer id="footer_in_nav">Some copyright info</footer>
+  </nav>
   <section>
     <footer id="footer_in_section">Some copyright info</footer>
   </section>
+  <blockquote>
+    <footer id="footer_in_blockquote">Some copyright info</footer>
+  </blockquote>
+  <details open="true">
+    <footer id="footer_in_details">Some copyright info</footer>
+  </details>
+  <dialog open="true">
+    <footer id="footer_in_dialog">Some copyright info</footer>
+  </dialog>
+  <fieldset>
+    <footer id="footer_in_fieldset">Some copyright info</footer>
+  </fieldset>
+  <figure>
+    <footer id="footer_in_figure">Some copyright info</footer>
+  </figure>
+  <table><tr><td>
+    <footer id="footer_in_td">Some copyright info</footer>
+  </td></tr></table>
 
   <form id="form"></form>
 
   <iframe id="frameset_container"
           src="data:text/html,<html><frameset><frame src='data:text/html,hi'></frame></frameset></html>">
   </iframe>
 
   <h1 id="h1">heading1</h1>
@@ -1487,19 +1527,43 @@
   <h4 id="h4">heading4</h4>
   <h5 id="h5">heading5</h5>
   <h6 id="h6">heading6</h6>
 
   <header id="header">A logo</header>
   <article>
     <header id="header_in_article">Not logo</header>
   </article>
+  <aside>
+    <header id="header_in_aside">Not logo</header>
+  </aside>
+  <nav>
+    <header id="header_in_nav">Not logo</header>
+  </nav>
   <section>
     <header id="header_in_section">Not logo</header>
   </section>
+  <blockquote>
+    <header id="header_in_blockquote">Not logo</header>
+  </blockquote>
+  <details open="true">
+    <header id="header_in_details">Not logo</header>
+  </details>
+  <dialog open="true">
+    <header id="header_in_dialog">Not logo</header>
+  </dialog>
+  <fieldset>
+    <header id="header_in_fieldset">Not logo</header>
+  </fieldset>
+  <figure>
+    <header id="header_in_figure">Not logo</header>
+  </figure>
+  <table><tr><td>
+    <header id="header_in_td">Not logo</header>
+  </td></tr></table>
 
   <hr id="hr">
   <p id="i_container">normal<i>italic</i></p>
   <img id="img" src="../moz.png">
 
   <input id="input_button" type="button" value="Button">
   <input id="input_checkbox" type="checkbox">
   <input id="input_checkbox_true" type="checkbox" checked>
--- a/accessible/tests/mochitest/jsat/jsatcommon.js
+++ b/accessible/tests/mochitest/jsat/jsatcommon.js
@@ -127,17 +127,17 @@ var AccessFuTest = {
   runTests: function AccessFuTest_runTests(aAdditionalPrefs) {
     if (gTestFuncs.length === 0) {
       ok(false, "No tests specified!");
       SimpleTest.finish();
       return;
     }
 
     // Create an Iterator for gTestFuncs array.
-    gIterator = (function*() {
+    gIterator = (function* () {
       for (var testFunc of gTestFuncs) {
         yield testFunc;
       }
     })();
 
     // Start AccessFu and put it in stand-by.
     Components.utils.import("resource://gre/modules/accessibility/AccessFu.jsm");
 
--- a/accessible/tests/mochitest/jsat/test_landmarks.html
+++ b/accessible/tests/mochitest/jsat/test_landmarks.html
@@ -42,44 +42,44 @@
           [{"string": "contentinfo"}, {"string": "footer"}, "a footer"],
           ["a footer", {"string": "footer"}, {"string": "contentinfo"}]],
         expectedBraille: [
           [{"string": "contentinfo"}, {"string": "footerAbbr"}, "a footer"],
           ["a footer", {"string": "footerAbbr"}, {"string": "contentinfo"}]]
       }, {
         accOrElmOrID: "article_header",
         expectedUtterance: [
-          [{"string": "header"}, "a header within an article"],
-          ["a header within an article", {"string": "header"}]],
+          ["a header within an article"],
+          ["a header within an article"]],
         expectedBraille: [
-          [{"string": "headerAbbr"}, "a header within an article"],
-          ["a header within an article", {"string": "headerAbbr"}]],
+          ["a header within an article"],
+          ["a header within an article"]],
       }, {
         accOrElmOrID: "article_footer",
         expectedUtterance: [
-          [{"string": "footer"}, "a footer within an article"],
-          ["a footer within an article", {"string": "footer"}]],
+          ["a footer within an article"],
+          ["a footer within an article"]],
         expectedBraille: [
-          [{"string": "footerAbbr"}, "a footer within an article"],
-          ["a footer within an article", {"string": "footerAbbr"}]]
+          ["a footer within an article"],
+          ["a footer within an article"]]
       }, {
         accOrElmOrID: "section_header",
-        expectedUtterance: [[{"string": "header"}, "a header within a section"],
-                            ["a header within a section", {"string": "header"}]],
+        expectedUtterance: [["a header within a section"],
+                            ["a header within a section"]],
         expectedBraille: [
-          [{"string": "headerAbbr"}, "a header within a section"],
-          ["a header within a section", {"string": "headerAbbr"}]]
+          ["a header within a section"],
+          ["a header within a section"]]
       }, {
         accOrElmOrID: "section_footer",
         expectedUtterance: [
-          [{"string": "footer"}, "a footer within a section"],
-          ["a footer within a section", {"string": "footer"}]],
+          ["a footer within a section"],
+          ["a footer within a section"]],
         expectedBraille: [
-          [{"string": "footerAbbr"}, "a footer within a section"],
-          ["a footer within a section", {"string": "footerAbbr"}]]
+          ["a footer within a section"],
+          ["a footer within a section"]]
       }, {
         accOrElmOrID: "aside",
         expectedUtterance: [
           [{"string": "complementary"}, "by the way I am an aside"],
           ["by the way I am an aside", {"string": "complementary"}]],
         expectedBraille: [
           [{"string": "complementary"}, "by the way I am an aside"],
           ["by the way I am an aside", {"string": "complementary"}]]
--- a/accessible/tests/mochitest/role/test_general.html
+++ b/accessible/tests/mochitest/role/test_general.html
@@ -27,19 +27,19 @@
       testRole("article", ROLE_ARTICLE);
       testRole("aside", ROLE_NOTE);
       testRole("section", ROLE_SECTION);
 
       // Bug 996821
       // Check that landmark elements get accessibles with styled overflow.
       testRole("section_overflow", ROLE_SECTION);
       testRole("nav_overflow", ROLE_SECTION);
-      testRole("header_overflow", ROLE_HEADER);
+      testRole("header_overflow", ROLE_SECTION);
       testRole("aside_overflow", ROLE_NOTE);
-      testRole("footer_overflow", ROLE_FOOTER);
+      testRole("footer_overflow", ROLE_SECTION);
       testRole("article_overflow", ROLE_ARTICLE);
 
       // test html:div
       testRole("sec", ROLE_SECTION);
 
       // Test html:blockquote
       testRole("quote", ROLE_SECTION);
 
--- a/accessible/windows/msaa/Compatibility.cpp
+++ b/accessible/windows/msaa/Compatibility.cpp
@@ -19,16 +19,35 @@
 #include "mozilla/Preferences.h"
 
 #include <shlobj.h>
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 /**
+ * String versions of consumer flags. See GetHumanReadableConsumersStr.
+ */
+static const wchar_t* ConsumerStringMap[CONSUMERS_ENUM_LEN+1] = {
+  L"NVDA",
+  L"JAWS",
+  L"OLDJAWS",
+  L"WE",
+  L"DOLPHIN",
+  L"SEROTEK",
+  L"COBRA",
+  L"ZOOMTEXT",
+  L"KAZAGURU",
+  L"YOUDAO",
+  L"UNKNOWN",
+  L"UIAUTOMATION",
+  L"\0"
+};
+
+/**
  * Return true if module version is lesser than the given version.
  */
 bool
 IsModuleVersionLessThan(HMODULE aModuleHandle, DWORD aMajor, DWORD aMinor)
 {
   wchar_t fileName[MAX_PATH];
   ::GetModuleFileNameW(aModuleHandle, fileName, MAX_PATH);
 
@@ -393,8 +412,27 @@ Compatibility::GetActCtxResourceId()
       UseIAccessibleProxyStub()) {
     return 64;
   }
 
   return 32;
 #endif // defined(HAVE_64BIT_BUILD)
 }
 
+// static
+void
+Compatibility::GetHumanReadableConsumersStr(nsAString &aResult)
+{
+  bool appened = false;
+  uint32_t index = 0;
+  for (uint32_t consumers = sConsumers; consumers; consumers = consumers >> 1) {
+    if (consumers & 0x1) {
+      if (appened) {
+        aResult.AppendLiteral(",");
+      }
+      aResult.Append(ConsumerStringMap[index]);
+      appened = true;
+    }
+    if (++index > CONSUMERS_ENUM_LEN) {
+      break;
+    }
+  }
+}
--- a/accessible/windows/msaa/Compatibility.h
+++ b/accessible/windows/msaa/Compatibility.h
@@ -2,16 +2,17 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef COMPATIBILITY_MANAGER_H
 #define COMPATIBILITY_MANAGER_H
 
+#include "nsString.h"
 #include <stdint.h>
 
 namespace mozilla {
 namespace a11y {
 
 /**
  * Used to get compatibility modes. Note, modes are computed at accessibility
  * start up time and aren't changed during lifetime.
@@ -40,16 +41,22 @@ public:
   static bool IsDolphin() { return !!(sConsumers & DOLPHIN); }
 
   /**
    * @return ID of a11y manifest resource to be passed to
    * mscom::ActivationContext
    */
   static uint16_t GetActCtxResourceId();
 
+  /**
+   * Return a string describing sConsumers suitable for about:support.
+   * Exposed through nsIXULRuntime.accessibilityInstantiator.
+   */
+  static void GetHumanReadableConsumersStr(nsAString &aResult);
+
 private:
   Compatibility();
   Compatibility(const Compatibility&);
   Compatibility& operator = (const Compatibility&);
 
   /**
    * Initialize compatibility mode. Called by platform (see Platform.h) during
    * accessibility initialization.
@@ -69,16 +76,17 @@ private:
     SEROTEK = 1 << 5,
     COBRA = 1 << 6,
     ZOOMTEXT = 1 << 7,
     KAZAGURU = 1 << 8,
     YOUDAO = 1 << 9,
     UNKNOWN = 1 << 10,
     UIAUTOMATION = 1 << 11
   };
+  #define CONSUMERS_ENUM_LEN 12
 
 private:
   static uint32_t sConsumers;
 };
 
 } // a11y namespace
 } // mozilla namespace
 
--- a/accessible/windows/msaa/Platform.cpp
+++ b/accessible/windows/msaa/Platform.cpp
@@ -192,24 +192,25 @@ a11y::IsHandlerRegistered()
 {
   nsresult rv;
   nsCOMPtr<nsIWindowsRegKey> regKey =
     do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
   if (NS_FAILED(rv)) {
     return false;
   }
 
+  nsAutoString clsid;
+  GUIDToString(CLSID_AccessibleHandler, clsid);
+
   nsAutoString subKey;
-  subKey.AppendLiteral("CLSID\\");
-  nsAutoString iid;
-  GUIDToString(CLSID_AccessibleHandler, iid);
-  subKey.Append(iid);
-  subKey.AppendLiteral("\\InprocHandler32");
+  subKey.AppendLiteral(u"SOFTWARE\\Classes\\CLSID\\");
+  subKey.Append(clsid);
+  subKey.AppendLiteral(u"\\InprocHandler32");
 
-  rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, subKey,
+  rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, subKey,
                     nsIWindowsRegKey::ACCESS_READ);
   if (NS_FAILED(rv)) {
     return false;
   }
 
   return true;
 }
 
--- a/accessible/xul/XULTreeAccessible.cpp
+++ b/accessible/xul/XULTreeAccessible.cpp
@@ -69,17 +69,17 @@ XULTreeAccessible::~XULTreeAccessible()
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeAccessible: nsISupports and cycle collection implementation
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeAccessible, Accessible,
                                    mTree, mAccessibleCache)
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XULTreeAccessible)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULTreeAccessible)
 NS_INTERFACE_MAP_END_INHERITING(Accessible)
 
 NS_IMPL_ADDREF_INHERITED(XULTreeAccessible, Accessible)
 NS_IMPL_RELEASE_INHERITED(XULTreeAccessible, Accessible)
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeAccessible: Accessible implementation
 
@@ -705,22 +705,19 @@ XULTreeItemAccessibleBase::~XULTreeItemA
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeItemAccessibleBase: nsISupports implementation
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase, Accessible,
                                    mTree)
 
-NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase)
-  NS_INTERFACE_TABLE_INHERITED(XULTreeItemAccessibleBase,
-                               XULTreeItemAccessibleBase)
-NS_INTERFACE_TABLE_TAIL_INHERITING(Accessible)
-NS_IMPL_ADDREF_INHERITED(XULTreeItemAccessibleBase, Accessible)
-NS_IMPL_RELEASE_INHERITED(XULTreeItemAccessibleBase, Accessible)
+NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase,
+                                             Accessible,
+                                             XULTreeItemAccessibleBase)
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeItemAccessibleBase: Accessible
 
 Accessible*
 XULTreeItemAccessibleBase::FocusedChild()
 {
   return FocusMgr()->FocusedAccessible() == this ? this : nullptr;
@@ -1081,17 +1078,17 @@ XULTreeItemAccessible::~XULTreeItemAcces
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeItemAccessible: nsISupports implementation
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessible,
                                    XULTreeItemAccessibleBase,
                                    mColumn)
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessible)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULTreeItemAccessible)
 NS_INTERFACE_MAP_END_INHERITING(XULTreeItemAccessibleBase)
 NS_IMPL_ADDREF_INHERITED(XULTreeItemAccessible, XULTreeItemAccessibleBase)
 NS_IMPL_RELEASE_INHERITED(XULTreeItemAccessible, XULTreeItemAccessibleBase)
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeItemAccessible: nsIAccessible implementation
 
 ENameValueFlag
--- a/accessible/xul/XULTreeGridAccessible.cpp
+++ b/accessible/xul/XULTreeGridAccessible.cpp
@@ -258,17 +258,17 @@ XULTreeGridRowAccessible::~XULTreeGridRo
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeGridRowAccessible: nsISupports and cycle collection implementation
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeGridRowAccessible,
                                    XULTreeItemAccessibleBase,
                                    mAccessibleCache)
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XULTreeGridRowAccessible)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULTreeGridRowAccessible)
 NS_INTERFACE_MAP_END_INHERITING(XULTreeItemAccessibleBase)
 
 NS_IMPL_ADDREF_INHERITED(XULTreeGridRowAccessible,
                          XULTreeItemAccessibleBase)
 NS_IMPL_RELEASE_INHERITED(XULTreeGridRowAccessible,
                           XULTreeItemAccessibleBase)
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -442,17 +442,17 @@ XULTreeGridCellAccessible::~XULTreeGridC
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeGridCellAccessible: nsISupports implementation
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeGridCellAccessible, LeafAccessible,
                                    mTree, mColumn)
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XULTreeGridCellAccessible)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULTreeGridCellAccessible)
 NS_INTERFACE_MAP_END_INHERITING(LeafAccessible)
 NS_IMPL_ADDREF_INHERITED(XULTreeGridCellAccessible, LeafAccessible)
 NS_IMPL_RELEASE_INHERITED(XULTreeGridCellAccessible, LeafAccessible)
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeGridCellAccessible: Accessible
 
 void
--- a/addon-sdk/source/test/fixtures/native-addon-test/dir/test.jsm
+++ b/addon-sdk/source/test/fixtures/native-addon-test/dir/test.jsm
@@ -1,6 +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/. */
 
 this['EXPORTED_SYMBOLS'] = ['test'];
-test = 'this is a jsm';
+var test = 'this is a jsm';
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -455,16 +455,17 @@ pref("browser.tabs.insertRelatedAfterCur
 pref("browser.tabs.warnOnClose", true);
 pref("browser.tabs.warnOnCloseOtherTabs", true);
 pref("browser.tabs.warnOnOpen", true);
 pref("browser.tabs.maxOpenBeforeWarn", 15);
 pref("browser.tabs.loadInBackground", true);
 pref("browser.tabs.opentabfor.middleclick", true);
 pref("browser.tabs.loadDivertedInBackground", false);
 pref("browser.tabs.loadBookmarksInBackground", false);
+pref("browser.tabs.loadBookmarksInTabs", false);
 pref("browser.tabs.tabClipWidth", 140);
 #ifdef UNIX_BUT_NOT_MAC
 pref("browser.tabs.drawInTitlebar", false);
 #else
 pref("browser.tabs.drawInTitlebar", true);
 #endif
 
 // 0 - Disable the tabbar session restore button.
@@ -669,16 +670,20 @@ pref("network.protocol-handler.expose.ne
 pref("network.protocol-handler.expose.snews", false);
 pref("network.protocol-handler.expose.nntp", false);
 
 pref("accessibility.typeaheadfind", false);
 pref("accessibility.typeaheadfind.timeout", 5000);
 pref("accessibility.typeaheadfind.linksonly", false);
 pref("accessibility.typeaheadfind.flashBar", 1);
 
+// Accessibility indicator preferences such as support URL, enabled flag.
+pref("accessibility.support.url", "https://support.mozilla.org/%LOCALE%/kb/accessibility-services");
+pref("accessibility.indicator.enabled", true);
+
 // Tracks when accessibility is loaded into the previous session.
 pref("accessibility.loadedInLastSession", false);
 
 pref("plugins.click_to_play", true);
 pref("plugins.testmode", false);
 
 // Should plugins that are hidden show the infobar UI?
 pref("plugins.show_infobar", false);
@@ -719,19 +724,16 @@ pref("plugins.favorfallback.rules", "nos
 pref("browser.preferences.instantApply", false);
 #else
 pref("browser.preferences.instantApply", true);
 #endif
 
 // Toggling Search bar on and off in about:preferences
 pref("browser.preferences.search", true);
 
-// Use the new in-content about:preferences in Nightly only for now
-pref("browser.preferences.useOldOrganization", false);
-
 // Once the Storage Management is completed.
 // (The Storage Management-related prefs are browser.storageManager.* )
 // The Offline(Appcache) Group section in about:preferences will be hidden.
 // And the task to clear appcache will be done by Storage Management.
 #if defined(NIGHTLY_BUILD)
 pref("browser.preferences.offlineGroup.enabled", false);
 #else
 pref("browser.preferences.offlineGroup.enabled", true);
@@ -1043,17 +1045,17 @@ pref("dom.ipc.plugins.sandbox-level.flas
 #endif
 
 #if defined(MOZ_CONTENT_SANDBOX)
 // This controls the strength of the Windows content process sandbox for testing
 // purposes. This will require a restart.
 // On windows these levels are:
 // See - security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
 // SetSecurityLevelForContentProcess() for what the different settings mean.
-pref("security.sandbox.content.level", 3);
+pref("security.sandbox.content.level", 4);
 
 // This controls the depth of stack trace that is logged when Windows sandbox
 // logging is turned on.  This is only currently available for the content
 // process because the only other sandbox (for GMP) has too strict a policy to
 // allow stack tracing.  This does not require a restart to take effect.
 pref("security.sandbox.windows.log.stackTraceDepth", 0);
 #endif
 
@@ -1512,21 +1514,17 @@ pref("toolkit.telemetry.bhrPing.enabled"
 // Telemetry experiments settings.
 pref("experiments.enabled", true);
 pref("experiments.manifest.fetchIntervalSeconds", 86400);
 pref("experiments.manifest.uri", "https://telemetry-experiment.cdn.mozilla.net/manifest/v1/firefox/%VERSION%/%CHANNEL%");
 // Whether experiments are supported by the current application profile.
 pref("experiments.supported", true);
 
 // Ping Centre Telemetry settings.
-#ifdef NIGHTLY_BUILD
 pref("browser.ping-centre.telemetry", true);
-#else
-pref("browser.ping-centre.telemetry", false);
-#endif
 pref("browser.ping-centre.log", false);
 pref("browser.ping-centre.staging.endpoint", "https://onyx_tiles.stage.mozaws.net/v3/links/ping-centre");
 pref("browser.ping-centre.production.endpoint", "https://tiles.services.mozilla.com/v3/links/ping-centre");
 
 // Enable GMP support in the addon manager.
 pref("media.gmp-provider.enabled", true);
 
 #ifdef NIGHTLY_BUILD
@@ -1717,17 +1715,17 @@ pref("extensions.formautofill.creditCard
 pref("extensions.formautofill.firstTimeUse", true);
 pref("extensions.formautofill.heuristics.enabled", true);
 pref("extensions.formautofill.loglevel", "Warn");
 
 // Whether or not to restore a session with lazy-browser tabs.
 pref("browser.sessionstore.restore_tabs_lazily", true);
 
 // Enable safebrowsing v4 tables (suffixed by "-proto") update.
-pref("urlclassifier.malwareTable", "goog-malware-proto,goog-unwanted-proto,test-malware-simple,test-unwanted-simple,test-harmful-simple");
+pref("urlclassifier.malwareTable", "goog-malware-proto,goog-unwanted-proto,test-harmful-simple,test-malware-simple,test-unwanted-simple");
 #ifdef MOZILLA_OFFICIAL
 pref("urlclassifier.phishTable", "goog-phish-proto,test-phish-simple");
 #else
 pref("urlclassifier.phishTable", "googpub-phish-proto,test-phish-simple");
 #endif
 
 pref("urlclassifier.downloadAllowTable", "goog-downloadwhite-proto");
 pref("urlclassifier.downloadBlockTable", "goog-badbinurl-proto");
--- a/browser/base/content/aboutDialog-appUpdater.js
+++ b/browser/base/content/aboutDialog-appUpdater.js
@@ -22,27 +22,28 @@ function onUnload(aEvent) {
   if (gAppUpdater.isChecking)
     gAppUpdater.checker.stopChecking(Components.interfaces.nsIUpdateChecker.CURRENT_CHECK);
   // Safe to call even when there isn't a download in progress.
   gAppUpdater.removeDownloadListener();
   gAppUpdater = null;
 }
 
 
-function appUpdater() {
+function appUpdater(options = {}) {
   XPCOMUtils.defineLazyServiceGetter(this, "aus",
                                      "@mozilla.org/updates/update-service;1",
                                      "nsIApplicationUpdateService");
   XPCOMUtils.defineLazyServiceGetter(this, "checker",
                                      "@mozilla.org/updates/update-checker;1",
                                      "nsIUpdateChecker");
   XPCOMUtils.defineLazyServiceGetter(this, "um",
                                      "@mozilla.org/updates/update-manager;1",
                                      "nsIUpdateManager");
 
+  this.options = options;
   this.updateDeck = document.getElementById("updateDeck");
 
   // Hide the update deck when the update window is already open and it's not
   // already applied, to avoid syncing issues between them. Applied updates
   // don't have any information to sync between the windows as they both just
   // show the "Restart to continue"-type button.
   if (Services.wm.getMostRecentWindow("Update:Wizard") &&
       !this.isApplied) {
@@ -181,19 +182,25 @@ appUpdater.prototype =
           let year = buildID.slice(0, 4);
           let month = buildID.slice(4, 6);
           let day = buildID.slice(6, 8);
           updateVersion += ` (${year}-${month}-${day})`;
         }
         button.label = this.bundle.formatStringFromName("update.downloadAndInstallButton.label", [updateVersion], 1);
         button.accessKey = this.bundle.GetStringFromName("update.downloadAndInstallButton.accesskey");
       }
+      this.updateDeck.selectedPanel = panel;
+      if (this.options.buttonAutoFocus &&
+          (!document.commandDispatcher.focusedElement || // don't steal the focus
+           document.commandDispatcher.focusedElement.localName == "button")) { // except from the other buttons
+        button.focus();
+      }
+    } else {
+      this.updateDeck.selectedPanel = panel;
     }
-
-    this.updateDeck.selectedPanel = panel;
   },
 
   /**
    * Check for updates
    */
   checkForUpdates() {
     // Clear prefs that could prevent a user from discovering available updates.
     if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CANCELATIONS_OSX)) {
--- a/browser/base/content/aboutDialog.js
+++ b/browser/base/content/aboutDialog.js
@@ -59,23 +59,17 @@ function init(aEvent) {
     let relNotesURL = Services.urlFormatter.formatURLPref("app.releaseNotesURL");
     if (relNotesURL != "about:blank") {
       relNotesLink.href = relNotesURL;
       relNotesLink.hidden = false;
     }
   }
 
   if (AppConstants.MOZ_UPDATER) {
-    gAppUpdater = new appUpdater();
-
-    let button = gAppUpdater.updateDeck.selectedPanel.querySelector("button");
-    if (button && (!document.commandDispatcher.focusedElement || // don't steal the focus
-                   document.commandDispatcher.focusedElement.localName == "button")) { // except from the other buttons
-      button.focus();
-    }
+    gAppUpdater = new appUpdater({ buttonAutoFocus: true });
 
     let channelLabel = document.getElementById("currentChannel");
     let currentChannelText = document.getElementById("currentChannelText");
     channelLabel.value = UpdateUtils.UpdateChannel;
     if (/^release($|\-)/.test(channelLabel.value))
         currentChannelText.hidden = true;
   }
 
--- a/browser/base/content/browser-data-submission-info-bar.js
+++ b/browser/base/content/browser-data-submission-info-bar.js
@@ -58,23 +58,17 @@ var gDataNotificationInfoBar = {
     this._actionTaken = false;
 
     let buttons = [{
       label: gNavigatorBundle.getString("dataReportingNotification.button.label"),
       accessKey: gNavigatorBundle.getString("dataReportingNotification.button.accessKey"),
       popup: null,
       callback: () => {
         this._actionTaken = true;
-        // The advanced subpanes are only supported in the old organization, which will
-        // be removed by bug 1349689.
-        if (Services.prefs.getBoolPref("browser.preferences.useOldOrganization")) {
-          window.openAdvancedPreferences("dataChoicesTab", {origin: "dataReporting"});
-        } else {
-          window.openPreferences("privacy-reports", {origin: "dataReporting"});
-        }
+        window.openPreferences("privacy-reports", {origin: "dataReporting"});
       },
     }];
 
     this._log.info("Creating data reporting policy notification.");
     this._notificationBox.appendNotification(
       message,
       this._DATA_REPORTING_NOTIFICATION,
       null,
--- a/browser/base/content/browser-media.js
+++ b/browser/base/content/browser-media.js
@@ -164,21 +164,17 @@ var gEMEHandler = {
     } else {
       document.getElementById(anchorId).removeAttribute("firstplay");
     }
 
     let mainAction = {
       label: gNavigatorBundle.getString(btnLabelId),
       accessKey: gNavigatorBundle.getString(btnAccessKeyId),
       callback() {
-        if (Services.prefs.getBoolPref("browser.preferences.useOldOrganization")) {
-          openPreferences("paneContent", {origin: "browserMedia"});
-        } else {
-          openPreferences("general-drm", {origin: "browserMedia"});
-        }
+        openPreferences("general-drm", {origin: "browserMedia"});
       },
       dismiss: true
     };
     let options = {
       dismissed: true,
       eventCallback: aTopic => aTopic == "swapping",
       learnMoreURL: Services.urlFormatter.formatURLPref("app.support.baseURL") + "drm-content",
     };
--- a/browser/base/content/browser-pageActions.js
+++ b/browser/base/content/browser-pageActions.js
@@ -42,51 +42,64 @@ var BrowserPageActions = {
     delete this.mainViewBodyNode;
     return this.mainViewBodyNode = this.mainViewNode.querySelector(".panel-subview-body");
   },
 
   /**
    * Inits.  Call to init.
    */
   init() {
+    this.placeAllActions();
+  },
+
+  /**
+   * Places all registered actions.
+   */
+  placeAllActions() {
+    // Place actions in the panel.  Notify of onBeforePlacedInWindow too.
     for (let action of PageActions.actions) {
-      this.placeAction(action,
-                       PageActions.insertBeforeActionIDInPanel(action),
-                       PageActions.insertBeforeActionIDInUrlbar(action));
+      action.onBeforePlacedInWindow(window);
+      this.placeActionInPanel(action);
+    }
+
+    // Place actions in the urlbar.  Do this in reverse order.  The reason is
+    // subtle.  If there were no urlbar nodes already in markup (like the
+    // bookmark star button), then doing this in forward order would be fine.
+    // Forward order means that the insert-before relationship is always broken:
+    // there's never a next-sibling node before which to insert a new node, so
+    // node.insertBefore() is always passed null, and nodes are always appended.
+    // That will break the position of nodes that should be inserted before
+    // nodes that are in markup, which in turn can break other nodes.
+    let actionsInUrlbar = PageActions.actionsInUrlbar;
+    for (let i = actionsInUrlbar.length - 1; i >= 0; i--) {
+      let action = actionsInUrlbar[i];
+      this.placeActionInUrlbar(action);
     }
   },
 
   /**
    * Adds or removes as necessary DOM nodes for the given action.
    *
    * @param  action (PageActions.Action, required)
    *         The action to place.
-   * @param  panelInsertBeforeID (string, required)
-   *         The ID of the action in the panel before which the given action
-   *         action should be inserted.
-   * @param  urlbarInsertBeforeID (string, required)
-   *         If the action is shown in the urlbar, then this is ID of the action
-   *         in the urlbar before which the given action should be inserted.
    */
-  placeAction(action, panelInsertBeforeID, urlbarInsertBeforeID) {
+  placeAction(action) {
     action.onBeforePlacedInWindow(window);
-    this.placeActionInPanel(action, panelInsertBeforeID);
-    this.placeActionInUrlbar(action, urlbarInsertBeforeID);
+    this.placeActionInPanel(action);
+    this.placeActionInUrlbar(action);
   },
 
   /**
    * Adds or removes as necessary DOM nodes for the action in the panel.
    *
    * @param  action (PageActions.Action, required)
    *         The action to place.
-   * @param  insertBeforeID (string, required)
-   *         The ID of the action in the panel before which the given action
-   *         action should be inserted.  Pass null to append.
    */
-  placeActionInPanel(action, insertBeforeID) {
+  placeActionInPanel(action) {
+    let insertBeforeID = PageActions.nextActionID(action, PageActions.actions);
     let id = this._panelButtonNodeIDForActionID(action.id);
     let node = document.getElementById(id);
     if (!node) {
       let panelViewNode;
       [node, panelViewNode] = this._makePanelButtonNodeForAction(action);
       node.id = id;
       let insertBeforeNode = null;
       if (insertBeforeID) {
@@ -177,55 +190,36 @@ var BrowserPageActions = {
 
   _toggleActivatedActionPanelForAction(action) {
     let panelNode = this.activatedActionPanelNode;
     if (panelNode) {
       panelNode.hidePopup();
       return null;
     }
 
-    // Before creating the panel, find the best anchor node for it because we'll
-    // bail if there isn't one.  Try each of the following nodes in order, using
-    // the first that's visible.
-    let anchorNode = null;
-    let potentialAnchorNodeIDs = [
-      action.anchorIDOverride || null,
-      this._urlbarButtonNodeIDForActionID(action.id),
-      this.mainButtonNode.id,
-      "identity-icon",
-    ];
-    let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindowUtils);
-    for (let id of potentialAnchorNodeIDs) {
-      if (id) {
-        let node = document.getElementById(id);
-        if (node && !node.hidden) {
-          let bounds = dwu.getBoundsWithoutFlushing(node);
-          if (bounds.height > 0 && bounds.width > 0) {
-            anchorNode = node;
-            break;
-          }
-        }
-      }
-    }
-    if (!anchorNode) {
-      throw new Error(`PageActions: No anchor node for '${action.id}'`);
-    }
+    // Before creating the panel, get the anchor node for it because it'll throw
+    // if there isn't one (which shouldn't happen, but still).
+    let anchorNode = this.panelAnchorNodeForAction(action);
 
     panelNode = document.createElement("panel");
     panelNode.id = this._activatedActionPanelID;
     panelNode.classList.add("cui-widget-panel");
     panelNode.setAttribute("actionID", action.id);
     panelNode.setAttribute("role", "group");
     panelNode.setAttribute("type", "arrow");
     panelNode.setAttribute("flip", "slide");
     panelNode.setAttribute("noautofocus", "true");
     panelNode.setAttribute("tabspecific", "true");
     panelNode.setAttribute("photon", "true");
 
+    // For tests.
+    if (this._disableActivatedActionPanelAnimation) {
+      panelNode.setAttribute("animate", "false");
+    }
+
     let panelViewNode = null;
     let iframeNode = null;
 
     if (action.subview) {
       let multiViewNode = document.createElement("photonpanelmultiview");
       panelViewNode = this._makePanelViewNodeForAction(action, true);
       multiViewNode.appendChild(panelViewNode);
       panelNode.appendChild(multiViewNode);
@@ -262,34 +256,57 @@ var BrowserPageActions = {
 
     if (iframeNode) {
       action.onIframeShown(iframeNode, panelNode);
     }
 
     return panelNode;
   },
 
+  panelAnchorNodeForAction(action) {
+    // Try each of the following nodes in order, using the first that's visible.
+    let potentialAnchorNodeIDs = [
+      action.anchorIDOverride || null,
+      this._urlbarButtonNodeIDForActionID(action.id),
+      this.mainButtonNode.id,
+      "identity-icon",
+    ];
+    let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                    .getInterface(Ci.nsIDOMWindowUtils);
+    for (let id of potentialAnchorNodeIDs) {
+      if (id) {
+        let node = document.getElementById(id);
+        if (node && !node.hidden) {
+          let bounds = dwu.getBoundsWithoutFlushing(node);
+          if (bounds.height > 0 && bounds.width > 0) {
+            return node;
+          }
+        }
+      }
+    }
+    throw new Error(`PageActions: No anchor node for '${action.id}'`);
+  },
+
   get activatedActionPanelNode() {
     return document.getElementById(this._activatedActionPanelID);
   },
 
   get _activatedActionPanelID() {
     return "pageActionActivatedActionPanel";
   },
 
   /**
    * Adds or removes as necessary a DOM node for the given action in the urlbar.
    *
    * @param  action (PageActions.Action, required)
    *         The action to place.
-   * @param  insertBeforeID (string, required)
-   *         If the action is shown in the urlbar, then this is ID of the action
-   *         in the urlbar before which the given action should be inserted.
    */
-  placeActionInUrlbar(action, insertBeforeID) {
+  placeActionInUrlbar(action) {
+    let insertBeforeID =
+      PageActions.nextActionID(action, PageActions.actionsInUrlbar);
     let id = this._urlbarButtonNodeIDForActionID(action.id);
     let node = document.getElementById(id);
 
     if (!action.shownInUrlbar) {
       if (node) {
         if (action.__urlbarNodeInMarkup) {
           node.hidden = true;
         } else {
@@ -334,16 +351,17 @@ var BrowserPageActions = {
     }
 
     return node;
   },
 
   _makeUrlbarButtonNode(action) {
     let buttonNode = document.createElement("image");
     buttonNode.classList.add("urlbar-icon", "urlbar-page-action");
+    buttonNode.setAttribute("role", "button");
     if (action.tooltip) {
       buttonNode.setAttribute("tooltiptext", action.tooltip);
     }
     if (action.iconURL) {
       buttonNode.style.listStyleImage = `url('${action.iconURL}')`;
     }
     buttonNode.setAttribute("context", "pageActionPanelContextMenu");
     buttonNode.addEventListener("contextmenu", event => {
@@ -689,44 +707,36 @@ var BrowserPageActionFeedback = {
   },
 
   get feedbackLabel() {
     delete this.feedbackLabel;
     return this.feedbackLabel = document.getElementById("pageActionFeedbackMessage");
   },
 
   show(action, event) {
-    this.feedbackLabel.textContent = this.panelNode.getAttribute(action + "Feedback");
+    this.feedbackLabel.textContent = this.panelNode.getAttribute(action.id + "Feedback");
     this.panelNode.hidden = false;
 
-    let anchor = BrowserPageActions.mainButtonNode;
-    if (event.target.classList.contains("urlbar-icon")) {
-      let id = BrowserPageActions._urlbarButtonNodeIDForActionID(action);
-      let node = document.getElementById(id);
-      if (node) {
-        anchor = node;
-      }
-    }
-
+    let anchor = BrowserPageActions.panelAnchorNodeForAction(action);
     this.panelNode.openPopup(anchor, {
       position: "bottomcenter topright",
       triggerEvent: event,
     });
 
     this.panelNode.addEventListener("popupshown", () => {
       this.feedbackAnimationBox.setAttribute("animate", "true");
     }, {once: true});
     this.panelNode.addEventListener("popuphidden", () => {
       this.feedbackAnimationBox.removeAttribute("animate");
     }, {once: true});
 
     // The timeout value used here allows the panel to stay open for
     // 1 second after the text transition (duration=120ms) has finished.
     setTimeout(() => {
-      this.panelNode.hidePopup();
+      this.panelNode.hidePopup(true);
     }, Services.prefs.getIntPref("browser.pageActions.feedbackTimeoutMS", 1120));
   },
 };
 
 // built-in actions below //////////////////////////////////////////////////////
 
 // bookmark
 BrowserPageActions.bookmark = {
@@ -754,17 +764,18 @@ BrowserPageActions.copyURL = {
     BrowserPageActions.takeNodeAttributeFromPanel(buttonNode, "title");
   },
 
   onCommand(event, buttonNode) {
     BrowserPageActions.panelNode.hidePopup();
     Cc["@mozilla.org/widget/clipboardhelper;1"]
       .getService(Ci.nsIClipboardHelper)
       .copyString(gURLBar.makeURIReadable(gBrowser.selectedBrowser.currentURI).displaySpec);
-    BrowserPageActionFeedback.show("copyURL", event);
+    let action = PageActions.actionForID("copyURL");
+    BrowserPageActionFeedback.show(action, event);
   },
 };
 
 // email link
 BrowserPageActions.emailLink = {
   onPlacedInPanel(buttonNode) {
     BrowserPageActions.takeNodeAttributeFromPanel(buttonNode, "title");
   },
@@ -800,31 +811,40 @@ BrowserPageActions.sendToDevice = {
   },
 
   onShowingSubview(panelViewNode) {
     let browser = gBrowser.selectedBrowser;
     let url = browser.currentURI.spec;
     let title = browser.contentTitle;
 
     let bodyNode = panelViewNode.firstChild;
+    let panelNode = panelViewNode.closest("panel");
 
     // This is on top because it also clears the device list between state
     // changes.
     gSync.populateSendTabToDevicesMenu(bodyNode, url, title, (clientId, name, clientType) => {
       if (!name) {
         return document.createElement("toolbarseparator");
       }
       let item = document.createElement("toolbarbutton");
       item.classList.add("pageAction-sendToDevice-device", "subviewbutton");
       if (clientId) {
         item.classList.add("subviewbutton-iconic");
       }
       item.setAttribute("tooltiptext", name);
       item.addEventListener("command", event => {
-        BrowserPageActionFeedback.show("sendToDevice", event);
+        if (panelNode) {
+          panelNode.hidePopup();
+        }
+        // There are items in the subview that don't represent devices: "Sign
+        // in", "Learn about Sync", etc.  Device items will be .sendtab-target.
+        if (event.target.classList.contains("sendtab-target")) {
+          let action = PageActions.actionForID("sendToDevice");
+          BrowserPageActionFeedback.show(action, event);
+        }
       });
       return item;
     });
 
     bodyNode.removeAttribute("state");
     // In the first ~10 sec after startup, Sync may not be loaded and the list
     // of devices will be empty.
     if (gSync.syncConfiguredAndLoading) {
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -73,31 +73,16 @@ var StarUI = {
         elt.removeAttribute("disabled");
       elt.removeAttribute("wasDisabled");
     });
   },
 
   // nsIDOMEventListener
   handleEvent(aEvent) {
     switch (aEvent.type) {
-      case "animationend": {
-        let animatableBox = document.getElementById("library-animatable-box");
-        if (aEvent.animationName.startsWith("library-bookmark-animation")) {
-          animatableBox.setAttribute("fade", "true");
-        } else if (aEvent.animationName == "library-bookmark-fade") {
-          animatableBox.removeEventListener("animationend", this);
-          animatableBox.removeAttribute("animate");
-          animatableBox.removeAttribute("fade");
-          let libraryButton = document.getElementById("library-button");
-          // Put the 'fill' back in the normal icon.
-          libraryButton.removeAttribute("animate");
-          gNavToolbox.removeAttribute("animate");
-        }
-        break;
-      }
       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) {
@@ -115,17 +100,16 @@ var StarUI = {
           let guidsForRemoval = this._itemGuids;
           this._itemGuids = null;
           this._itemIdsMap = null;
 
           if (this._batching) {
             this.endBatch();
           }
 
-          let libraryButton;
           if (removeBookmarksOnPopupHidden && guidsForRemoval) {
             if (this._isNewBookmark) {
               if (!PlacesUIUtils.useAsyncTransactions) {
                 PlacesUtils.transactionManager.undoTransaction();
                 break;
               }
               PlacesTransactions.undo().catch(Cu.reportError);
               break;
@@ -139,42 +123,18 @@ var StarUI = {
                   PlacesUtils.transactionManager.doTransaction(txn);
                 }
               }
               break;
             }
 
             PlacesTransactions.Remove(guidsForRemoval)
                               .transact().catch(Cu.reportError);
-          } else if (this._isNewBookmark &&
-                     Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled") &&
-                     (libraryButton = document.getElementById("library-button")) &&
-                     libraryButton.getAttribute("cui-areatype") != "menu-panel" &&
-                     libraryButton.getAttribute("overflowedItem") != "true" &&
-                     libraryButton.closest("#nav-bar")) {
-            let animatableBox = document.getElementById("library-animatable-box");
-            let navBar = document.getElementById("nav-bar");
-            let libraryIcon = document.getAnonymousElementByAttribute(libraryButton, "class", "toolbarbutton-icon");
-            let dwu = window.getInterface(Ci.nsIDOMWindowUtils);
-            let iconBounds = dwu.getBoundsWithoutFlushing(libraryIcon);
-            let libraryBounds = dwu.getBoundsWithoutFlushing(libraryButton);
-
-            animatableBox.style.setProperty("--library-button-y", libraryBounds.y + "px");
-            animatableBox.style.setProperty("--library-button-height", libraryBounds.height + "px");
-            animatableBox.style.setProperty("--library-icon-x", iconBounds.x + "px");
-            if (navBar.hasAttribute("brighttext")) {
-              animatableBox.setAttribute("brighttext", "true");
-            } else {
-              animatableBox.removeAttribute("brighttext");
-            }
-            animatableBox.removeAttribute("fade");
-            gNavToolbox.setAttribute("animate", "bookmark");
-            libraryButton.setAttribute("animate", "bookmark");
-            animatableBox.setAttribute("animate", "bookmark");
-            animatableBox.addEventListener("animationend", this);
+          } else if (this._isNewBookmark) {
+            LibraryUI.triggerLibraryAnimation("bookmark");
           }
         }
         break;
       }
       case "keypress":
         clearTimeout(this._autoCloseTimer);
         this._autoCloseTimerEnabled = false;
 
@@ -245,17 +205,17 @@ var StarUI = {
           // browser/extensions/pocket/content/panels/js/saved.js
           let delay = 3500;
           if (this._closePanelQuickForTesting) {
             delay /= 10;
           }
           clearTimeout(this._autoCloseTimer);
           this._autoCloseTimer = setTimeout(() => {
             if (!this.panel.mozMatchesSelector(":hover")) {
-              this.panel.hidePopup();
+              this.panel.hidePopup(true);
             }
           }, delay);
           this._autoCloseTimerEnabled = true;
         }
         break;
     }
   },
 
@@ -1537,16 +1497,78 @@ var RecentBookmarksMenuUI = {
   onEndUpdateBatch() {},
   onItemAdded() {},
   onItemChanged() {},
   onItemVisited() {},
   onItemMoved() {},
 }
 
 /**
+ * Handles the Library button in the toolbar.
+ */
+var LibraryUI = {
+  triggerLibraryAnimation(animation) {
+    if (!this.hasOwnProperty("COSMETIC_ANIMATIONS_ENABLED")) {
+      XPCOMUtils.defineLazyPreferenceGetter(this, "COSMETIC_ANIMATIONS_ENABLED",
+        "toolkit.cosmeticAnimations.enabled", true);
+    }
+
+    let libraryButton = document.getElementById("library-button");
+    if (!libraryButton ||
+        libraryButton.getAttribute("cui-areatype") == "menu-panel" ||
+        libraryButton.getAttribute("overflowedItem") == "true" ||
+        !libraryButton.closest("#nav-bar") ||
+        !this.COSMETIC_ANIMATIONS_ENABLED) {
+      return;
+    }
+    let animatableBox = document.getElementById("library-animatable-box");
+    let navBar = document.getElementById("nav-bar");
+    let libraryIcon = document.getAnonymousElementByAttribute(libraryButton, "class", "toolbarbutton-icon");
+    let dwu = window.getInterface(Ci.nsIDOMWindowUtils);
+    let iconBounds = dwu.getBoundsWithoutFlushing(libraryIcon);
+    let libraryBounds = dwu.getBoundsWithoutFlushing(libraryButton);
+
+    animatableBox.style.setProperty("--library-button-y", libraryBounds.y + "px");
+    animatableBox.style.setProperty("--library-button-height", libraryBounds.height + "px");
+    animatableBox.style.setProperty("--library-icon-x", iconBounds.x + "px");
+    if (navBar.hasAttribute("brighttext")) {
+      animatableBox.setAttribute("brighttext", "true");
+    } else {
+      animatableBox.removeAttribute("brighttext");
+    }
+    animatableBox.removeAttribute("fade");
+    gNavToolbox.setAttribute("animate", animation);
+    libraryButton.setAttribute("animate", animation);
+    animatableBox.setAttribute("animate", animation);
+    if (!this._libraryButtonAnimationEndListeners[animation]) {
+      this._libraryButtonAnimationEndListeners[animation] = event => {
+        this._libraryButtonAnimationEndListener(event, animation);
+      }
+    }
+    animatableBox.addEventListener("animationend", this._libraryButtonAnimationEndListeners[animation]);
+  },
+
+  _libraryButtonAnimationEndListeners: {},
+  _libraryButtonAnimationEndListener(aEvent, animation) {
+    let animatableBox = document.getElementById("library-animatable-box");
+    if (aEvent.animationName.startsWith(`library-${animation}-animation`)) {
+      animatableBox.setAttribute("fade", "true");
+    } else if (aEvent.animationName == `library-${animation}-fade`) {
+      animatableBox.removeEventListener("animationend", LibraryUI._libraryButtonAnimationEndListeners[animation]);
+      animatableBox.removeAttribute("animate");
+      animatableBox.removeAttribute("fade");
+      let libraryButton = document.getElementById("library-button");
+      // Put the 'fill' back in the normal icon.
+      libraryButton.removeAttribute("animate");
+      gNavToolbox.removeAttribute("animate");
+    }
+  },
+};
+
+/**
  * Handles the bookmarks menu-button in the toolbar.
  */
 
 var BookmarkingUI = {
   STAR_ID: "star-button",
   BOOKMARK_BUTTON_ID: "bookmarks-menu-button",
   BOOKMARK_BUTTON_SHORTCUT: "addBookmarkAsKb",
   get button() {
--- a/browser/base/content/browser-sidebar.js
+++ b/browser/base/content/browser-sidebar.js
@@ -10,18 +10,18 @@
  * xul:broadcaster element with the specified ID.
  * The following attributes on that element may be used and/or modified:
  *  - id           (required) the string to match commandID. The convention
  *                 is to use this naming scheme: 'view<sidebar-name>Sidebar'.
  *  - sidebarurl   (required) specifies the URL to load in this sidebar.
  *  - sidebartitle or label (in that order) specify the title to
  *                 display on the sidebar.
  *  - checked      indicates whether the sidebar is currently displayed.
- *                 Note that toggleSidebar updates this attribute when
- *                 it changes the sidebar's visibility.
+ *                 Note that this attribute is updated when
+ *                 the sidebar's visibility is changed.
  *  - group        this attribute must be set to "sidebar".
  */
 var SidebarUI = {
   // Avoid getting the browser element from init() to avoid triggering the
   // <browser> constructor during startup if the sidebar is hidden.
   get browser() {
     if (this._browser)
       return this._browser;
@@ -251,19 +251,16 @@ var SidebarUI = {
    * Fire a "SidebarFocused" event on the sidebar's |window| to give the sidebar
    * a chance to adjust focus as needed. An additional event is needed, because
    * we don't want to focus the sidebar when it's opened on startup or in a new
    * window, only when the user opens the sidebar.
    */
   _fireFocusedEvent() {
     let event = new CustomEvent("SidebarFocused", {bubbles: true});
     this.browser.contentWindow.dispatchEvent(event);
-
-    // Run the original function for backwards compatibility.
-    fireSidebarFocusedEvent();
   },
 
   /**
    * True if the sidebar is currently open.
    */
   get isOpen() {
     return !this._box.hidden;
   },
@@ -388,19 +385,16 @@ var SidebarUI = {
       if (this.browser.contentDocument.location.href != url) {
         this.browser.addEventListener("load", event => {
 
           // We're handling the 'load' event before it bubbles up to the usual
           // (non-capturing) event handlers. Let it bubble up before firing the
           // SidebarFocused event.
           setTimeout(() => this._fireFocusedEvent(), 0);
 
-          // Run the original function for backwards compatibility.
-          sidebarOnLoad(event);
-
           resolve();
 
           // Now that the currentId is updated, fire a show event.
           this._fireShowEvent();
         }, {capture: true, once: true});
       } else {
         // Older code handled this case, so we do it too.
         this._fireFocusedEvent();
@@ -464,42 +458,8 @@ var SidebarUI = {
 
 // Add getters related to the position here, since we will want them
 // available for both startDelayedLoad and init.
 XPCOMUtils.defineLazyPreferenceGetter(SidebarUI, "_positionStart",
   SidebarUI.POSITION_START_PREF, true, SidebarUI.setPosition.bind(SidebarUI));
 XPCOMUtils.defineLazyGetter(SidebarUI, "isRTL", () => {
   return getComputedStyle(document.documentElement).direction == "rtl";
 });
-
-/**
- * This exists for backwards compatibility - it will be called once a sidebar is
- * ready, following any request to show it.
- *
- * @deprecated
- */
-function fireSidebarFocusedEvent() {}
-
-/**
- * This exists for backwards compatibility - it gets called when a sidebar has
- * been loaded.
- *
- * @deprecated
- */
-function sidebarOnLoad(event) {}
-
-/**
- * This exists for backwards compatibility, and is equivilent to
- * SidebarUI.toggle() without the forceOpen param. With forceOpen set to true,
- * it is equivalent to SidebarUI.show().
- *
- * @deprecated
- */
-function toggleSidebar(commandID, forceOpen = false) {
-  Deprecated.warning("toggleSidebar() is deprecated, please use SidebarUI.toggle() or SidebarUI.show() instead",
-                     "https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Sidebar");
-
-  if (forceOpen) {
-    SidebarUI.show(commandID);
-  } else {
-    SidebarUI.toggle(commandID);
-  }
-}
--- a/browser/base/content/browser-sync.js
+++ b/browser/base/content/browser-sync.js
@@ -335,32 +335,33 @@ var gSync = {
 
   _appendSendTabDeviceList(fragment, createDeviceNodeFn, url, title) {
     const onTargetDeviceCommand = (event) => {
       let clients = event.target.getAttribute("clientId") ?
         [event.target.getAttribute("clientId")] :
         this.remoteClients.map(client => client.id);
 
       clients.forEach(clientId => this.sendTabToDevice(url, clientId, title));
-      BrowserPageActions.panelNode.hidePopup();
     }
 
     function addTargetDevice(clientId, name, clientType) {
       const targetDevice = createDeviceNodeFn(clientId, name, clientType);
       targetDevice.addEventListener("command", onTargetDeviceCommand, true);
       targetDevice.classList.add("sync-menuitem", "sendtab-target");
       targetDevice.setAttribute("clientId", clientId);
       targetDevice.setAttribute("clientType", clientType);
       targetDevice.setAttribute("label", name);
       fragment.appendChild(targetDevice);
     }
 
     const clients = this.remoteClients;
     for (let client of clients) {
-      addTargetDevice(client.id, client.name, client.type);
+      const type = client.formfactor && client.formfactor.includes("tablet") ?
+                   "tablet" : client.type;
+      addTargetDevice(client.id, client.name, type);
     }
 
     // "Send to All Devices" menu item
     if (clients.length > 1) {
       const separator = createDeviceNodeFn();
       separator.classList.add("sync-menuitem");
       fragment.appendChild(separator);
       const allDevicesLabel = this.fxaStrings.GetStringFromName("sendToAllDevices.menuitem");
@@ -368,49 +369,45 @@ var gSync = {
     }
   },
 
   _appendSendTabSingleDevice(fragment, createDeviceNodeFn) {
     const noDevices = this.fxaStrings.GetStringFromName("sendTabToDevice.singledevice.status");
     const learnMore = this.fxaStrings.GetStringFromName("sendTabToDevice.singledevice");
     this._appendSendTabInfoItems(fragment, createDeviceNodeFn, noDevices, learnMore, () => {
       this.openSendToDevicePromo();
-      BrowserPageActions.panelNode.hidePopup();
     });
   },
 
   _appendSendTabVerify(fragment, createDeviceNodeFn) {
     const notVerified = this.fxaStrings.GetStringFromName("sendTabToDevice.verify.status");
     const verifyAccount = this.fxaStrings.GetStringFromName("sendTabToDevice.verify");
     this._appendSendTabInfoItems(fragment, createDeviceNodeFn, notVerified, verifyAccount, () => {
       this.openPrefs("sendtab");
-      BrowserPageActions.panelNode.hidePopup();
     });
   },
 
   _appendSendTabUnconfigured(fragment, createDeviceNodeFn) {
     const notConnected = this.fxaStrings.GetStringFromName("sendTabToDevice.unconfigured.status");
     const learnMore = this.fxaStrings.GetStringFromName("sendTabToDevice.unconfigured");
     this._appendSendTabInfoItems(fragment, createDeviceNodeFn, notConnected, learnMore, () => {
       this.openSendToDevicePromo();
-      BrowserPageActions.panelNode.hidePopup();
     });
 
     // Now add a 'sign in to sync' item above the 'learn more' item.
     const signInToSync = this.fxaStrings.GetStringFromName("sendTabToDevice.signintosync");
     let signInItem = createDeviceNodeFn(null, signInToSync, null);
     signInItem.classList.add("sync-menuitem");
     signInItem.setAttribute("label", signInToSync);
     // Show an icon if opened in the page action panel:
     if (signInItem.classList.contains("subviewbutton")) {
       signInItem.classList.add("subviewbutton-iconic", "signintosync");
     }
     signInItem.addEventListener("command", () => {
       this.openPrefs("sendtab");
-      BrowserPageActions.panelNode.hidePopup();
     });
     fragment.insertBefore(signInItem, fragment.lastChild);
   },
 
   _appendSendTabInfoItems(fragment, createDeviceNodeFn, statusLabel, actionLabel, actionCommand) {
     const status = createDeviceNodeFn(null, statusLabel, null);
     status.setAttribute("label", statusLabel);
     status.setAttribute("disabled", true);
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -268,17 +268,18 @@ toolbarpaletteitem {
 %else
 /* On non-OSX, these should be start-aligned */
 #titlebar-buttonbox-container {
   -moz-box-align: start;
 }
 %endif
 
 %if !defined(MOZ_WIDGET_GTK)
-#TabsToolbar > .private-browsing-indicator {
+#TabsToolbar > .private-browsing-indicator,
+#TabsToolbar > .accessibility-indicator {
   -moz-box-ordinal-group: 1000;
 }
 %endif
 
 %ifdef XP_WIN
 #main-window[sizemode="maximized"] #titlebar-buttonbox {
   -moz-appearance: -moz-window-button-box-maximized;
 }
@@ -322,16 +323,17 @@ toolbarpaletteitem:-moz-any([place="pale
   display: -moz-box;
 }
 
 toolbarpaletteitem > toolbaritem[sdkstylewidget="true"][cui-areatype="toolbar"] > .toolbarbutton-text {
   display: -moz-box;
 }
 
 .webextension-browser-action > .toolbarbutton-badge-stack > .toolbarbutton-icon {
+  height: 16px;
   width: 16px;
 }
 
 @media not all and (min-resolution: 1.1dppx) {
   .webextension-browser-action {
     list-style-image: var(--webextension-toolbar-image, inherit);
   }
 
@@ -446,17 +448,17 @@ toolbar:not(#TabsToolbar) > #personal-bo
 }
 
 #zoom-controls[cui-areatype="toolbar"]:not([overflowedItem=true]) > #zoom-reset-button > .toolbarbutton-text {
   display: -moz-box;
 }
 
 #reload-button:not([displaystop]) + #stop-button,
 #reload-button[displaystop] {
-  visibility: collapse;
+  display: none;
 }
 
 /* The reload-button is only disabled temporarily when it becomes visible
    to prevent users from accidentally clicking it. We don't however need
    to show this disabled state, as the flicker that it generates is short
    enough to be visible but not long enough to explain anything to users. */
 #reload-button[disabled]:not(:-moz-window-inactive) > .toolbarbutton-icon {
   opacity: 1 !important;
@@ -662,22 +664,23 @@ html|input.urlbar-input[textoverflow]:no
 }
 
 #DateTimePickerPanel[active="true"] {
   -moz-binding: url("chrome://global/content/bindings/datetimepopup.xml#datetime-popup");
 }
 
 #urlbar[pageproxystate=invalid] > #page-action-buttons > .urlbar-page-action,
 #identity-box.chromeUI ~ #page-action-buttons > .urlbar-page-action,
+#urlbar[usertyping] > .urlbar-textbox-container > .urlbar-history-dropmarker,
 .urlbar-go-button[pageproxystate="valid"],
 .urlbar-go-button:not([parentfocused="true"]),
 #urlbar[pageproxystate="invalid"] > #identity-box > #blocked-permissions-container,
 #urlbar[pageproxystate="invalid"] > #identity-box > #notification-popup-box,
 #urlbar[pageproxystate="invalid"] > #identity-box > #identity-icon-labels {
-  visibility: collapse;
+  display: none;
 }
 
 #identity-box {
   -moz-user-focus: normal;
 }
 
 #urlbar[pageproxystate="invalid"] > #identity-box {
   pointer-events: none;
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -123,16 +123,17 @@ XPCOMUtils.defineLazyScriptGetter(this, 
 // lazy service getters
 
 XPCOMUtils.defineLazyServiceGetters(this, {
   Favicons: ["@mozilla.org/browser/favicon-service;1", "mozIAsyncFavicons"],
   gAboutNewTabService: ["@mozilla.org/browser/aboutnewtab-service;1", "nsIAboutNewTabService"],
   gDNSService: ["@mozilla.org/network/dns-service;1", "nsIDNSService"],
   gSerializationHelper: ["@mozilla.org/network/serialization-helper;1", "nsISerializationHelper"],
   Marionette: ["@mozilla.org/remote/marionette;1", "nsIMarionette"],
+  SessionStartup: ["@mozilla.org/browser/sessionstartup;1", "nsISessionStartup"],
   WindowsUIUtils: ["@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils"],
 });
 
 if (AppConstants.MOZ_CRASHREPORTER) {
   XPCOMUtils.defineLazyServiceGetter(this, "gCrashReporter",
                                      "@mozilla.org/xre/app-info;1",
                                      "nsICrashReporter");
 }
@@ -543,21 +544,17 @@ const gStoragePressureObserver = {
       msg = prefStrBundle.getFormattedString(descriptionStringID, [brandShortName]);
       buttons.push({
         label: prefStrBundle.getString(prefButtonLabelStringID),
         accessKey: prefStrBundle.getString(prefButtonAccesskeyStringID),
         callback(notificationBar, button) {
           // The advanced subpanes are only supported in the old organization, which will
           // be removed by bug 1349689.
           let win = gBrowser.ownerGlobal;
-          if (Services.prefs.getBoolPref("browser.preferences.useOldOrganization")) {
-            win.openAdvancedPreferences("networkTab", {origin: "storagePressure"});
-          } else {
-            win.openPreferences("panePrivacy", {origin: "storagePressure"});
-          }
+          win.openPreferences("panePrivacy", { origin: "storagePressure" });
         }
       });
     }
 
     notificationBox.appendNotification(
       msg, NOTIFICATION_VALUE, null, notificationBox.PRIORITY_WARNING_HIGH, buttons, null);
   }
 };
@@ -1359,34 +1356,50 @@ var gBrowserInit = {
       gURLBar.setAttribute("enablehistory", "false");
     }
 
     // Misc. inits.
     TabletModeUpdater.init();
     CombinedStopReload.init();
     gPrivateBrowsingUI.init();
     BrowserPageActions.init();
+    gAccessibilityServiceIndicator.init();
 
     if (window.matchMedia("(-moz-os-version: windows-win8)").matches &&
         window.matchMedia("(-moz-windows-default-theme)").matches) {
       let windowFrameColor = new Color(...Cu.import("resource:///modules/Windows8WindowFrameColor.jsm", {})
                                             .Windows8WindowFrameColor.get());
       // Default to black for foreground text.
       if (!windowFrameColor.isContrastRatioAcceptable(new Color(0, 0, 0))) {
         document.documentElement.setAttribute("darkwindowframe", "true");
       }
     }
 
     ToolbarIconColor.init();
 
     gRemoteControl.updateVisualCue(Marionette.running);
 
-    this._uriToLoadPromise.then(uriToLoad => {
-      gIdentityHandler.initIdentityBlock(uriToLoad);
-    });
+    // If we are given a tab to swap in, take care of it before first paint to
+    // avoid an about:blank flash.
+    let tabToOpen = window.arguments && window.arguments[0];
+    if (tabToOpen instanceof XULElement) {
+      // Clear the reference to the tab from the arguments array.
+      window.arguments[0] = null;
+
+      // Stop the about:blank load
+      gBrowser.stop();
+      // make sure it has a docshell
+      gBrowser.docShell;
+
+      try {
+        gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, tabToOpen);
+      } catch (e) {
+        Cu.reportError(e);
+      }
+    }
 
     // Wait until chrome is painted before executing code not critical to making the window visible
     this._boundDelayedStartup = this._delayedStartup.bind(this);
     window.addEventListener("MozAfterPaint", this._boundDelayedStartup);
 
     this._loadHandled = true;
   },
 
@@ -1604,16 +1617,18 @@ var gBrowserInit = {
       firstBrowserPaintDeferred.resolve();
     });
 
     this._uriToLoadPromise.then(uriToLoad => {
       if (!uriToLoad || uriToLoad == "about:blank") {
         return;
       }
 
+      // We don't check if uriToLoad is a XULElement because this case has
+      // already been handled before first paint, and the argument cleared.
       if (uriToLoad instanceof Ci.nsIArray) {
         let count = uriToLoad.length;
         let specs = [];
         for (let i = 0; i < count; i++) {
           let urisstring = uriToLoad.queryElementAt(i, Ci.nsISupportsString);
           specs.push(urisstring.data);
         }
 
@@ -1621,49 +1636,16 @@ var gBrowserInit = {
         // so that we don't disrupt startup
         try {
           gBrowser.loadTabs(specs, {
             inBackground: false,
             replace: true,
             triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
           });
         } catch (e) {}
-      } else if (uriToLoad instanceof XULElement) {
-        // swap the given tab with the default about:blank tab and then close
-        // the original tab in the other window.
-        let tabToOpen = uriToLoad;
-
-        // If this tab was passed as a window argument, clear the
-        // reference to it from the arguments array.
-        if (window.arguments[0] == tabToOpen) {
-          window.arguments[0] = null;
-        }
-
-        // Stop the about:blank load
-        gBrowser.stop();
-        // make sure it has a docshell
-        gBrowser.docShell;
-
-        // We must set usercontextid before updateBrowserRemoteness()
-        // so that the newly created remote tab child has correct usercontextid
-        if (tabToOpen.hasAttribute("usercontextid")) {
-          let usercontextid = tabToOpen.getAttribute("usercontextid");
-          gBrowser.selectedBrowser.setAttribute("usercontextid", usercontextid);
-        }
-
-        try {
-          // Make sure selectedBrowser has the same remote settings as the one
-          // we are swapping in.
-          gBrowser.updateBrowserRemoteness(gBrowser.selectedBrowser,
-                                           tabToOpen.linkedBrowser.isRemoteBrowser,
-                                           { remoteType: tabToOpen.linkedBrowser.remoteType });
-          gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, tabToOpen);
-        } catch (e) {
-          Cu.reportError(e);
-        }
       } else if (window.arguments.length >= 3) {
         // window.arguments[2]: referrer (nsIURI | string)
         //                 [3]: postData (nsIInputStream)
         //                 [4]: allowThirdPartyFixup (bool)
         //                 [5]: referrerPolicy (int)
         //                 [6]: userContextId (int)
         //                 [7]: originPrincipal (nsIPrincipal)
         //                 [8]: triggeringPrincipal (nsIPrincipal)
@@ -1799,19 +1781,17 @@ var gBrowserInit = {
       // If the given URI is different from the homepage, we want to load it.
       if (uri != defaultArgs) {
         resolve(uri);
         return;
       }
 
       // The URI appears to be the the homepage. We want to load it only if
       // session restore isn't about to override the homepage.
-      let sessionStartup = Cc["@mozilla.org/browser/sessionstartup;1"]
-                             .getService(Ci.nsISessionStartup);
-      sessionStartup.willOverrideHomepagePromise.then(willOverrideHomepage => {
+      SessionStartup.willOverrideHomepagePromise.then(willOverrideHomepage => {
         resolve(willOverrideHomepage ? null : uri);
       });
     });
   },
 
   onUnload() {
     // In certain scenarios it's possible for unload to be fired before onload,
     // (e.g. if the window is being closed after browser.js loads but before the
@@ -1863,16 +1843,18 @@ var gBrowserInit = {
     CompactTheme.uninit();
 
     TrackingProtection.uninit();
 
     CaptivePortalWatcher.uninit();
 
     SidebarUI.uninit();
 
+    gAccessibilityServiceIndicator.uninit();
+
     // Now either cancel delayedStartup, or clean up the services initialized from
     // it.
     if (this._boundDelayedStartup) {
       this._cancelDelayedStartup();
     } else {
       if (Win7Features)
         Win7Features.onCloseWindow();
 
@@ -2252,43 +2234,56 @@ function loadOneOrMoreURIs(aURIString, a
       inBackground: false,
       replace: true,
       triggeringPrincipal: aTriggeringPrincipal,
     });
   } catch (e) {
   }
 }
 
-function focusAndSelectUrlBar() {
+/**
+ * Focuses the location bar input field and selects its contents.
+ *
+ * @param [optional] userInitiatedFocus
+ *        Whether this focus is caused by an user interaction whose intention
+ *        was to use the location bar. For example, using a shortcut to go to
+ *        the location bar, or a contextual menu to search from it.
+ *        The default is false and should be used in all those cases where the
+ *        code focuses the location bar but that's not the primary user
+ *        intention, like when opening a new tab.
+ */
+function focusAndSelectUrlBar(userInitiatedFocus = false) {
   // In customize mode, the url bar is disabled. If a new tab is opened or the
   // user switches to a different tab, this function gets called before we've
   // finished leaving customize mode, and the url bar will still be disabled.
   // We can't focus it when it's disabled, so we need to re-run ourselves when
   // we've finished leaving customize mode.
   if (CustomizationHandler.isExitingCustomizeMode) {
     gNavToolbox.addEventListener("aftercustomization", function() {
-      focusAndSelectUrlBar();
+      focusAndSelectUrlBar(userInitiatedFocus);
     }, {once: true});
 
     return true;
   }
 
   if (gURLBar) {
     if (window.fullScreen)
       FullScreen.showNavToolbox();
 
+    gURLBar.userInitiatedFocus = userInitiatedFocus;
     gURLBar.select();
+    gURLBar.userInitiatedFocus = false;
     if (document.activeElement == gURLBar.inputField)
       return true;
   }
   return false;
 }
 
 function openLocation() {
-  if (focusAndSelectUrlBar())
+  if (focusAndSelectUrlBar(true))
     return;
 
   if (window.location.href != getBrowserURL()) {
     var win = getTopWin();
     if (win) {
       // If there's an open browser window, it should handle this command
       win.focus()
       win.openLocation();
@@ -2764,22 +2759,23 @@ function URLBarSetURI(aURI) {
       // We should deal with losslessDecodeURI throwing for exotic URIs
       try {
         value = losslessDecodeURI(uri);
       } catch (ex) {
         value = "about:blank";
       }
     }
 
-    valid = !isBlankPageURL(uri.spec);
+    valid = !isBlankPageURL(uri.spec) || uri.schemeIs("moz-extension");
   }
 
   let isDifferentValidValue = valid && value != gURLBar.value;
   gURLBar.value = value;
   gURLBar.valueIsTyped = !valid;
+  gURLBar.removeAttribute("usertyping");
   if (isDifferentValidValue) {
     gURLBar.selectionStart = gURLBar.selectionEnd = 0;
   }
 
   SetPageProxyState(valid ? "valid" : "invalid");
 }
 
 function losslessDecodeURI(aURI) {
@@ -3827,17 +3823,17 @@ const BrowserSearch = {
                                 "chrome,all,dialog=no", "about:blank");
         Services.obs.addObserver(observer, "browser-delayed-startup-finished");
       }
       return;
     }
 
     let focusUrlBarIfSearchFieldIsNotActive = function(aSearchBar) {
       if (!aSearchBar || document.activeElement != aSearchBar.textbox.inputField) {
-        focusAndSelectUrlBar();
+        focusAndSelectUrlBar(true);
       }
     };
 
     let searchBar = this.searchBar;
     let placement = CustomizableUI.getPlacementOfWidget("search-container");
     let focusSearchBar = () => {
       searchBar = this.searchBar;
       searchBar.select();
@@ -4176,38 +4172,16 @@ function toOpenWindowByType(inType, uri,
   else
     window.open(uri, "_blank", "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar");
 }
 
 function OpenBrowserWindow(options) {
   var telemetryObj = {};
   TelemetryStopwatch.start("FX_NEW_WINDOW_MS", telemetryObj);
 
-  function newDocumentShown(doc, topic, data) {
-    if (topic == "document-shown" &&
-        doc != document &&
-        doc.defaultView == win) {
-      Services.obs.removeObserver(newDocumentShown, "document-shown");
-      Services.obs.removeObserver(windowClosed, "domwindowclosed");
-      TelemetryStopwatch.finish("FX_NEW_WINDOW_MS", telemetryObj);
-    }
-  }
-
-  function windowClosed(subject) {
-    if (subject == win) {
-      Services.obs.removeObserver(newDocumentShown, "document-shown");
-      Services.obs.removeObserver(windowClosed, "domwindowclosed");
-    }
-  }
-
-  // Make sure to remove the 'document-shown' observer in case the window
-  // is being closed right after it was opened to avoid leaking.
-  Services.obs.addObserver(newDocumentShown, "document-shown");
-  Services.obs.addObserver(windowClosed, "domwindowclosed");
-
   var handler = Components.classes["@mozilla.org/browser/clh;1"]
                           .getService(Components.interfaces.nsIBrowserHandler);
   var defaultArgs = handler.defaultArgs;
   var wintype = document.documentElement.getAttribute("windowtype");
 
   var extraFeatures = "";
   if (options && options.private) {
     extraFeatures = ",private";
@@ -4242,16 +4216,20 @@ function OpenBrowserWindow(options) {
 
     // we should "inherit" the charset menu setting in a new window
     win = window.openDialog("chrome://browser/content/", "_blank", "chrome,all,dialog=no" + extraFeatures, defaultArgs, charsetArg);
   } else {
     // forget about the charset information.
     win = window.openDialog("chrome://browser/content/", "_blank", "chrome,all,dialog=no" + extraFeatures, defaultArgs);
   }
 
+  win.addEventListener("MozAfterPaint", () => {
+    TelemetryStopwatch.finish("FX_NEW_WINDOW_MS", telemetryObj);
+  }, {once: true});
+
   return win;
 }
 
 /**
  * Update the global flag that tracks whether or not any edit UI (the Edit menu,
  * edit-related items in the context menu, and edit-related toolbar buttons
  * is visible, then update the edit commands' enabled state accordingly.  We use
  * this flag to skip updating the edit commands on focus or selection changes
@@ -6530,23 +6508,17 @@ var OfflineApps = {
     if (browser && browser.messageManager) {
       browser.messageManager.sendAsyncMessage("OfflineApps:StartFetching", {
         docId,
       });
     }
   },
 
   manage() {
-    // The advanced subpanes are only supported in the old organization, which will
-    // be removed by bug 1349689.
-    if (Services.prefs.getBoolPref("browser.preferences.useOldOrganization")) {
-      openAdvancedPreferences("networkTab", {origin: "offlineApps"});
-    } else {
-      openPreferences("panePrivacy", {origin: "offlineApps"});
-    }
+    openPreferences("panePrivacy", { origin: "offlineApps" });
   },
 
   receiveMessage(msg) {
     switch (msg.name) {
       case "OfflineApps:CheckUsage":
         let uri = makeURI(msg.data.uri);
         if (this._usedMoreThanWarnQuota(uri)) {
           this.warnUsage(msg.target, uri);
@@ -7077,17 +7049,17 @@ var gIdentityHandler = {
    * to be able to focus it on the popupshown event.
    */
   _popupTriggeredByKeyboard: false,
 
   /**
    * RegExp used to decide if an about url should be shown as being part of
    * the browser UI.
    */
-  _secureInternalUIWhitelist: /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|home|license|newaddon|permissions|preferences|privatebrowsing|rights|searchreset|sessionrestore|support|welcomeback)(?:[?#]|$)/i,
+  _secureInternalUIWhitelist: /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|license|newaddon|permissions|preferences|rights|searchreset|sessionrestore|support|welcomeback)(?:[?#]|$)/i,
 
   get _isBroken() {
     return this._state & Ci.nsIWebProgressListener.STATE_IS_BROKEN;
   },
 
   get _isSecure() {
     // If a <browser> is included within a chrome document, then this._state
     // will refer to the security state for the <browser> and not the top level
@@ -7707,24 +7679,16 @@ var gIdentityHandler = {
     this._identityPopupContentSupp.textContent = supplemental;
     this._identityPopupContentVerif.textContent = verifier;
 
     // Update per-site permissions section.
     this.updateSitePermissions();
   },
 
   setURI(uri) {
-    // Ignore about:blank loads until the window's initial URL has loaded,
-    // to avoid hiding the UI that initIdentityBlock could have prepared.
-    if (this._ignoreAboutBlankUntilFirstLoad) {
-      if (uri.spec == "about:blank")
-        return;
-      this._ignoreAboutBlankUntilFirstLoad = false;
-    }
-
     this._uri = uri;
 
     try {
       this._uri.host;
       this._uriHasHost = true;
     } catch (ex) {
       this._uriHasHost = false;
     }
@@ -7749,40 +7713,16 @@ var gIdentityHandler = {
       // Check the URI again after resolving.
       this._isURILoadedFromFile = resolvedURI.schemeIs("file");
     } catch (ex) {
       // NetUtil's methods will throw for malformed URIs and the like
     }
   },
 
   /**
-   * Used to initialize the identity block before first paint to avoid
-   * flickering when opening a new window showing a secure internal page
-   * (eg. about:home)
-   */
-  initIdentityBlock(initialURI) {
-    if (this._uri) {
-      // Apparently we already loaded something, so there's nothing to do here.
-      return;
-    }
-
-    if ((typeof initialURI != "string") || !initialURI.startsWith("about:"))
-      return;
-
-    let uri = Services.io.newURI(initialURI);
-    if (this._secureInternalUIWhitelist.test(uri.pathQueryRef)) {
-      this._isSecureInternalUI = true;
-      this._ignoreAboutBlankUntilFirstLoad = true;
-      this.refreshIdentityBlock();
-      // The identity label won't be visible without setting this.
-      gURLBar.setAttribute("pageproxystate", "valid");
-    }
-  },
-
-  /**
    * Click handler for the identity-box element in primary chrome.
    */
   handleIdentityButtonEvent(event) {
     event.stopPropagation();
 
     if ((event.type == "click" && event.button != 0) ||
         (event.type == "keypress" && event.charCode != KeyEvent.DOM_VK_SPACE &&
          event.keyCode != KeyEvent.DOM_VK_RETURN)) {
@@ -8076,16 +8016,73 @@ function getTabModalPromptBox(aWindow) {
   return null;
 }
 
 /* DEPRECATED */
 function getBrowser() {
   return gBrowser;
 }
 
+const gAccessibilityServiceIndicator = {
+  init() {
+    // Pref to enable accessibility service indicator.
+    gPrefService.addObserver("accessibility.indicator.enabled", this);
+    // Accessibility service init/shutdown event.
+    Services.obs.addObserver(this, "a11y-init-or-shutdown");
+    this.update(Services.appinfo.accessibilityEnabled);
+  },
+
+  update(accessibilityEnabled = false) {
+    if (this.enabled && accessibilityEnabled) {
+      this._active = true;
+      document.documentElement.setAttribute("accessibilitymode", "true");
+      [...document.querySelectorAll(".accessibility-indicator")].forEach(
+        indicator => ["click", "keypress"].forEach(type =>
+          indicator.addEventListener(type, this)));
+      TabsInTitlebar.updateAppearance(true);
+    } else if (this._active) {
+      this._active = false;
+      document.documentElement.removeAttribute("accessibilitymode");
+      [...document.querySelectorAll(".accessibility-indicator")].forEach(
+        indicator => ["click", "keypress"].forEach(type =>
+          indicator.removeEventListener(type, this)));
+      TabsInTitlebar.updateAppearance(true);
+    }
+  },
+
+  observe(subject, topic, data) {
+    if (topic == "nsPref:changed" && data === "accessibility.indicator.enabled") {
+      this.update(Services.appinfo.accessibilityEnabled);
+    } else if (topic === "a11y-init-or-shutdown") {
+      // When "a11y-init-or-shutdown" event is fired, "1" indicates that
+      // accessibility service is started and "0" that it is shut down.
+      this.update(data === "1");
+    }
+  },
+
+  get enabled() {
+    return gPrefService.getBoolPref("accessibility.indicator.enabled");
+  },
+
+  handleEvent({ key, type }) {
+    if ((type === "keypress" && [" ", "Enter"].includes(key)) ||
+         type === "click") {
+      let a11yServicesSupportURL =
+        Services.urlFormatter.formatURLPref("accessibility.support.url");
+      gBrowser.selectedTab = gBrowser.addTab(a11yServicesSupportURL);
+    }
+  },
+
+  uninit() {
+    gPrefService.removeObserver("accessibility.indicator.enabled", this);
+    Services.obs.removeObserver(this, "a11y-init-or-shutdown");
+    this.update();
+  }
+};
+
 var gPrivateBrowsingUI = {
   init: function PBUI_init() {
     // Do nothing for normal windows
     if (!PrivateBrowsingUtils.isWindowPrivate(window)) {
       return;
     }
 
     // Disable the Clear Recent History... menu item when in PB mode
@@ -8299,16 +8296,18 @@ var RestoreLastSessionObserver = {
         gBrowser.tabContainer.addEventListener("TabOpen", this);
         Services.telemetry.scalarSet("browser.session.restore.tabbar_restore_available", true);
         restoreTabsButton.addEventListener("click", () => {
           Services.telemetry.scalarSet("browser.session.restore.tabbar_restore_clicked", true);
         });
       }
       Services.obs.addObserver(this, "sessionstore-last-session-cleared", true);
       goSetCommandEnabled("Browser:RestoreLastSession", true);
+    } else if (SessionStartup.isAutomaticRestoreEnabled()) {
+      document.getElementById("Browser:RestoreLastSession").setAttribute("hidden", true);
     }
   },
 
   handleEvent(event) {
     switch (event.type) {
      case "TabOpen":
         this.removeRestoreButton();
         break;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -84,16 +84,19 @@
       <menuitem id="context_toggleMuteTab" oncommand="TabContextMenu.contextTab.toggleMuteAudio();"/>
       <menuseparator/>
       <menuitem id="context_pinTab" label="&pinTab.label;"
                 accesskey="&pinTab.accesskey;"
                 oncommand="gBrowser.pinTab(TabContextMenu.contextTab);"/>
       <menuitem id="context_unpinTab" label="&unpinTab.label;" hidden="true"
                 accesskey="&unpinTab.accesskey;"
                 oncommand="gBrowser.unpinTab(TabContextMenu.contextTab);"/>
+      <menuitem id="context_duplicateTab" label="&duplicateTab.label;"
+                accesskey="&duplicateTab.accesskey;"
+                oncommand="duplicateTabIn(TabContextMenu.contextTab, 'tab');"/>
       <menuitem id="context_openTabInWindow" label="&moveToNewWindow.label;"
                 accesskey="&moveToNewWindow.accesskey;"
                 tbattr="tabbrowser-multiple"
                 oncommand="gBrowser.replaceTabWithWindow(TabContextMenu.contextTab);"/>
 #ifdef E10S_TESTING_ONLY
       <menuitem id="context_openNonRemoteWindow" label="Open in new non-e10s window"
                 tbattr="tabbrowser-remote"
                 hidden="true"
@@ -425,22 +428,23 @@
     </panel>
 
     <panel id="pageActionPanel"
            class="cui-widget-panel"
            role="group"
            type="arrow"
            hidden="true"
            flip="slide"
+           photon="true"
            position="bottomcenter topright"
            tabspecific="true"
            noautofocus="true"
-           copyURL-title="&copyURLCmd.label;"
+           copyURL-title="&copyLinkCmd.label;"
            emailLink-title="&emailPageCmd.label;"
-           sendToDevice-title="&sendToDevice.label3;"
+           sendToDevice-title="&sendTabToDevice.label;"
            sendToDevice-notReadyTitle="&sendToDevice.syncNotReady.label;">
       <photonpanelmultiview id="pageActionPanelMultiView"
                             mainViewId="pageActionPanelMainView"
                             viewCacheId="appMenu-viewCache">
         <panelview id="pageActionPanelMainView"
                    context="pageActionPanelContextMenu"
                    oncontextmenu="BrowserPageActions.onContextMenu(event);"
                    class="PanelUI-subView">
@@ -582,30 +586,30 @@
   <box id="appMenu-viewCache" hidden="true"/>
 
 #ifdef CAN_DRAW_IN_TITLEBAR
 <vbox id="titlebar">
   <hbox id="titlebar-content">
     <spacer id="titlebar-spacer" flex="1"/>
     <hbox id="titlebar-buttonbox-container">
 #ifdef XP_WIN
-      <hbox id="private-browsing-indicator-titlebar">
-        <hbox class="private-browsing-indicator"/>
-      </hbox>
+      <button class="accessibility-indicator" tooltiptext="&accessibilityIndicator.tooltip;" aria-live="polite"/>
+      <hbox class="private-browsing-indicator"/>
 #endif
       <hbox id="titlebar-buttonbox">
         <toolbarbutton class="titlebar-button" id="titlebar-min" oncommand="window.minimize();"/>
         <toolbarbutton class="titlebar-button" id="titlebar-max" oncommand="onTitlebarMaxClick();"/>
         <toolbarbutton class="titlebar-button" id="titlebar-close" command="cmd_closeWindow"/>
       </hbox>
     </hbox>
 #ifdef XP_MACOSX
     <!-- OS X does not natively support RTL for its titlebar items, so we prevent this secondary
          buttonbox from reversing order in RTL by forcing an LTR direction. -->
     <hbox id="titlebar-secondary-buttonbox" dir="ltr">
+      <button class="accessibility-indicator" tooltiptext="&accessibilityIndicator.tooltip;" aria-live="polite"/>
       <hbox class="private-browsing-indicator"/>
       <hbox id="titlebar-fullscreen-button"/>
     </hbox>
 #endif
   </hbox>
 </vbox>
 #endif
 
@@ -642,18 +646,22 @@
              customizable="true"
              mode="icons"
              iconsize="small"
              aria-label="&tabsToolbar.label;"
              context="toolbar-context-menu"
              collapsed="true">
 
 #if defined(MOZ_WIDGET_GTK)
-      <hbox id="private-browsing-indicator"
+      <hbox class="private-browsing-indicator"
             skipintoolbarset="true"/>
+      <button class="accessibility-indicator"
+              tooltiptext="&accessibilityIndicator.tooltip;"
+              aria-live="polite"
+              skipintoolbarset="true"/>
 #endif
 
       <tabs id="tabbrowser-tabs"
             class="tabbrowser-tabs"
             tabbrowser="content"
             flex="1"
             setfocus="false"
             tooltip="tabbrowser-tab-tooltip"
@@ -691,16 +699,18 @@
                 label="&newUserContext.label;">
             <menupopup id="alltabs_containersMenuTab" />
           </menu>
           <menuseparator id="alltabs-popup-separator-2"/>
         </menupopup>
       </toolbarbutton>
 
 #if !defined(MOZ_WIDGET_GTK)
+      <button class="accessibility-indicator" tooltiptext="&accessibilityIndicator.tooltip;"
+              aria-live="polite" skipintoolbarset="true"/>
       <hbox class="private-browsing-indicator" skipintoolbarset="true"/>
 #endif
 #ifdef CAN_DRAW_IN_TITLEBAR
       <hbox class="titlebar-placeholder" type="caption-buttons"
             id="titlebar-placeholder-on-TabsToolbar-for-captions-buttons" persist="width"
 #ifndef XP_MACOSX
             ordinal="1000"
 #endif
@@ -876,43 +886,49 @@
               </box>
               <hbox id="page-action-buttons">
                 <hbox id="userContext-icons" hidden="true">
                   <label id="userContext-label"/>
                   <image id="userContext-indicator"/>
                 </hbox>
                 <image id="page-report-button"
                        class="urlbar-icon urlbar-page-action"
+                       role="button"
                        hidden="true"
                        tooltiptext="&pageReportIcon.tooltip;"
                        onmousedown="gPopupBlockerObserver.onReportButtonMousedown(event);"/>
                 <image id="reader-mode-button"
                        class="urlbar-icon urlbar-page-action"
+                       role="button"
                        hidden="true"
                        onclick="ReaderParent.buttonClick(event);"/>
                 <toolbarbutton id="urlbar-zoom-button"
                        onclick="FullZoom.reset();"
                        tooltip="dynamic-shortcut-tooltip"
                        hidden="true"/>
                 <box id="pageActionSeparator" class="urlbar-page-action"/>
                 <image id="pageActionButton"
                        class="urlbar-icon urlbar-page-action"
+                       role="button"
                        tooltiptext="&pageActionButton.tooltip;"
                        onclick="BrowserPageActions.mainButtonClicked(event);"/>
                 <hbox id="star-button-box"
                       hidden="true"
                       class="urlbar-icon-wrapper urlbar-page-action"
+                      role="button"
                       context="pageActionPanelContextMenu"
                       oncontextmenu="BrowserPageActions.onContextMenu(event);"
                       onclick="BrowserPageActions.bookmark.onUrlbarNodeClicked(event);">
                   <image id="star-button"
                          class="urlbar-icon"
+                         role="button"
                          observes="bookmarkThisPageBroadcaster"/>
                   <hbox id="star-button-animatable-box">
                     <image id="star-button-animatable-image"
+                           role="button"
                            observes="bookmarkThisPageBroadcaster"/>
                   </hbox>
                 </hbox>
               </hbox>
             </textbox>
         </toolbaritem>
 
         <toolbaritem id="search-container" title="&searchItem.title;"
--- a/browser/base/content/tabbrowser.css
+++ b/browser/base/content/tabbrowser.css
@@ -1,16 +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/. */
 
-.tabbrowser-tabbox {
-  -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tabbox");
-}
-
 .tabbrowser-tabpanels {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tabpanels");
 }
 
 .tabbrowser-arrowscrollbox {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-arrowscrollbox");
 }
 
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -14,17 +14,17 @@
   <binding id="tabbrowser">
     <resources>
       <stylesheet src="chrome://browser/content/tabbrowser.css"/>
     </resources>
 
     <content>
       <xul:stringbundle anonid="tbstringbundle" src="chrome://browser/locale/tabbrowser.properties"/>
       <xul:tabbox anonid="tabbox" class="tabbrowser-tabbox"
-                  flex="1" eventnode="document" xbl:inherits="handleCtrlPageUpDown"
+                  flex="1" eventnode="document" xbl:inherits="handleCtrlPageUpDown,tabcontainer"
                   onselect="if (event.target.localName == 'tabpanels') this.parentNode.updateCurrentBrowser();">
         <xul:tabpanels flex="1" class="plain" selectedIndex="0" anonid="panelcontainer">
           <xul:notificationbox flex="1" notificationside="top">
             <xul:hbox flex="1" class="browserSidebarContainer">
               <xul:vbox flex="1" class="browserContainer">
                 <xul:stack flex="1" class="browserStack" anonid="browserStack">
                   <xul:browser anonid="initialBrowser" type="content" message="true" messagemanagergroup="browsers"
                                primary="true"
@@ -612,16 +612,60 @@
                   !aLocation) {
                 return true;
               }
 
               let location = aLocation ? aLocation.spec : "";
               return location == "about:blank";
             },
 
+            _syncThrobberAnimations() {
+              const originalTab = this.mTab;
+              BrowserUtils.promiseLayoutFlushed(this.mTab.ownerDocument, "style", () => {
+                if (!originalTab.parentNode) {
+                  return;
+                }
+
+                const animations =
+                  Array.from(originalTab.parentNode.getElementsByTagName("tab"))
+                  .map(tab => {
+                    const throbber =
+                      document.getAnonymousElementByAttribute(tab, "anonid", "tab-throbber");
+                    return throbber ? throbber.getAnimations({ subtree: true }) : [];
+                  })
+                  .reduce((a, b) => a.concat(b))
+                  .filter(anim =>
+                    anim instanceof CSSAnimation &&
+                    (anim.animationName === "tab-throbber-animation" ||
+                     anim.animationName === "tab-throbber-animation-rtl") &&
+                    (anim.playState === "running" || anim.playState === "pending"));
+
+                // Synchronize with the oldest running animation, if any.
+                const firstStartTime = Math.min(
+                  ...animations.map(anim => anim.startTime === null ? Infinity : anim.startTime)
+                );
+                if (firstStartTime === Infinity) {
+                  return;
+                }
+                requestAnimationFrame(() => {
+                  for (let animation of animations) {
+                    // If |animation| has been cancelled since this rAF callback
+                    // was scheduled we don't want to set its startTime since
+                    // that would restart it. We check for a cancelled animation
+                    // by looking for a null currentTime rather than checking
+                    // the playState, since reading the playState of
+                    // a CSSAnimation object will flush style.
+                    if (animation.currentTime !== null) {
+                      animation.startTime = firstStartTime;
+                    }
+                  }
+                });
+              });
+            },
+
             onProgressChange(aWebProgress, aRequest,
                              aCurSelfProgress, aMaxSelfProgress,
                              aCurTotalProgress, aMaxTotalProgress) {
               this.mTotalProgress = aMaxTotalProgress ? aCurTotalProgress / aMaxTotalProgress : 0;
 
               if (!this._shouldShowProgress(aRequest))
                 return;
 
@@ -709,31 +753,33 @@
                   delete this.mBrowser.initialPageLoadedFromURLBar;
                   // If the browser is loading it must not be crashed anymore
                   this.mTab.removeAttribute("crashed");
                 }
 
                 if (this._shouldShowProgress(aRequest)) {
                   if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING)) {
                     this.mTab.setAttribute("busy", "true");
+                    this._syncThrobberAnimations();
                   }
 
                   if (this.mTab.selected) {
                     this.mTabBrowser.mIsBusy = true;
                   }
                 }
               } else if (aStateFlags & nsIWebProgressListener.STATE_STOP &&
                          aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
 
                 if (this.mTab.hasAttribute("busy")) {
                   this.mTab.removeAttribute("busy");
 
                   // Only animate the "burst" indicating the page has loaded if
                   // the top-level page is the one that finished loading.
                   if (aWebProgress.isTopLevel && !aWebProgress.isLoadingDocument &&
+                      Components.isSuccessCode(aStatus) &&
                       !this.mTabBrowser.tabAnimationsInProgress &&
                       Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled")) {
                     this.mTab.setAttribute("bursting", "true");
                   }
 
                   this.mTabBrowser._tabAttrModified(this.mTab, ["busy"]);
                   if (!this.mTab.selected)
                     this.mTab.setAttribute("unread", "true");
@@ -2220,17 +2266,18 @@
         "goHome", "homePage", "gotoIndex", "currentURI", "documentURI",
         "preferences", "imageDocument", "isRemoteBrowser", "messageManager",
         "getTabBrowser", "finder", "fastFind", "sessionHistory", "contentTitle",
         "characterSet", "fullZoom", "textZoom", "webProgress",
         "addProgressListener", "removeProgressListener", "audioPlaybackStarted",
         "audioPlaybackStopped", "pauseMedia", "stopMedia",
         "resumeMedia", "mute", "unmute", "blockedPopups", "lastURI",
         "purgeSessionHistory", "stopScroll", "startScroll",
-        "userTypedValue", "userTypedClear", "mediaBlocked"
+        "userTypedValue", "userTypedClear", "mediaBlocked",
+        "didStartLoadSinceLastUserTyping"
       ]</field>
 
       <method name="_createLazyBrowser">
         <parameter name="aTab"/>
         <body>
           <![CDATA[
             let browser = aTab.linkedBrowser;
 
@@ -2248,16 +2295,19 @@
                   getter = () => SessionStore.getLazyTabValue(aTab, "title");
                   break;
                 case "currentURI":
                   getter = () => {
                     let url = SessionStore.getLazyTabValue(aTab, "url");
                     return Services.io.newURI(url);
                   };
                   break;
+                case "didStartLoadSinceLastUserTyping":
+                  getter = () => () => false;
+                  break;
                 case "fullZoom":
                 case "textZoom":
                   getter = () => 1;
                   break;
                 case "getTabBrowser":
                   getter = () => () => this;
                   break;
                 case "isRemoteBrowser":
@@ -2321,16 +2371,17 @@
               });
             }
           ]]>
         </body>
       </method>
 
       <method name="_insertBrowser">
         <parameter name="aTab"/>
+        <parameter name="aInsertedOnTabCreation"/>
         <body>
           <![CDATA[
             "use strict";
 
             // If browser is already inserted or window is closed don't do anything.
             if (aTab.linkedPanel || window.closed) {
               return;
             }
@@ -2382,22 +2433,73 @@
             // set the "nodefaultsrc" attribute that prevents a frameLoader
             // from being created as soon as the linked <browser> is inserted
             // into the DOM. We thus have to register the new outerWindowID
             // for non-remote browsers after we have called browser.loadURI().
             if (remoteType == E10SUtils.NOT_REMOTE) {
               this._outerWindowIDBrowserMap.set(browser.outerWindowID, browser);
             }
 
-            var evt = new CustomEvent("TabBrowserInserted", { bubbles: true, detail: {} });
+            var evt = new CustomEvent("TabBrowserInserted",
+              { bubbles: true, detail: { insertedOnTabCreation: aInsertedOnTabCreation } });
             aTab.dispatchEvent(evt);
           ]]>
         </body>
       </method>
 
+      <method name="discardBrowser">
+        <parameter name="aBrowser"/>
+        <body>
+          <![CDATA[
+            "use strict";
+
+            let tab = this.getTabForBrowser(aBrowser);
+
+            if (!tab ||
+                tab.selected ||
+                tab.closing ||
+                this._windowIsClosing ||
+                !aBrowser.isConnected ||
+                !aBrowser.isRemoteBrowser ||
+                aBrowser.frameLoader.tabParent.hasBeforeUnload) {
+              return;
+            }
+
+            // Set browser parameters for when browser is restored.  Also remove
+            // listeners and set up lazy restore data in SessionStore. This must
+            // be done before aBrowser is destroyed and removed from the document.
+            tab._browserParams = { uriIsAboutBlank: aBrowser.currentURI.spec == "about:blank",
+                                   remoteType: aBrowser.remoteType,
+                                   usingPreloadedContent: false };
+
+            SessionStore.resetBrowserToLazyState(tab);
+
+            this._outerWindowIDBrowserMap.delete(aBrowser.outerWindowID);
+
+            // Remove the tab's filter and progress listener.
+            let filter = this._tabFilters.get(tab);
+            let listener = this._tabListeners.get(tab);
+            aBrowser.webProgress.removeProgressListener(filter);
+            filter.removeProgressListener(listener);
+            listener.destroy();
+
+            this._tabListeners.delete(tab);
+            this._tabFilters.delete(tab);
+
+            aBrowser.destroy();
+
+            let notificationbox = this.getNotificationBox(aBrowser);
+            this.mPanelContainer.removeChild(notificationbox);
+            tab.removeAttribute("linkedpanel");
+
+            this._createLazyBrowser(tab);
+          ]]>
+        </body>
+      </method>
+
       <method name="addTab">
         <parameter name="aURI"/>
         <parameter name="aReferrerURI"/>
         <parameter name="aCharset"/>
         <parameter name="aPostData"/>
         <parameter name="aOwner"/>
         <parameter name="aAllowThirdPartyFixup"/>
         <body>
@@ -2633,17 +2735,17 @@
 
               if (lazyBrowserURI) {
                 // Lazy browser must be explicitly registered so tab will appear as
                 // a switch-to-tab candidate in autocomplete.
                 this._unifiedComplete.registerOpenPage(lazyBrowserURI, aUserContextId);
                 b.registeredOpenURI = lazyBrowserURI;
               }
             } else {
-              this._insertBrowser(t);
+              this._insertBrowser(t, true);
             }
 
             // Dispatch a new tab notification.  We do this once we're
             // entirely done, so that things are in a consistent state
             // even if the event listener opens or closes tabs.
             var detail = aEventDetail || {};
             var evt = new CustomEvent("TabOpen", { bubbles: true, detail });
             t.dispatchEvent(evt);
@@ -3003,16 +3105,26 @@
                 // This call actually closes the window, unless the user
                 // cancels the operation.  We are finished here in both cases.
                 this._windowIsClosing = window.closeWindow(true, window.warnAboutClosingWindow);
                 return false;
               }
 
               newTab = true;
             }
+            aTab._endRemoveArgs = [closeWindow, newTab];
+
+            // swapBrowsersAndCloseOther will take care of closing the window without animation.
+            if (closeWindow && aAdoptedByTab) {
+              // Remove the tab's filter to avoid leaking.
+              if (aTab.linkedPanel) {
+                this._tabFilters.delete(aTab);
+              }
+              return true;
+            }
 
             if (!aTab._fullyOpen) {
               // If the opening tab animation hasn't finished before we start closing the
               // tab, decrement the animation count since _handleNewTab will not get called.
               this.tabAnimationsInProgress--;
             }
 
             this.tabAnimationsInProgress++;
@@ -3073,17 +3185,16 @@
 
             // Remove this tab as the owner of any other tabs, since it's going away.
             for (let tab of this.tabs) {
               if ("owner" in tab && tab.owner == aTab)
                 // |tab| is a child of the tab we're removing, make it an orphan
                 tab.owner = null;
             }
 
-            aTab._endRemoveArgs = [closeWindow, newTab];
             return true;
           ]]>
         </body>
       </method>
 
       <method name="_endRemoveTab">
         <parameter name="aTab"/>
         <body>
@@ -3291,16 +3402,35 @@
             }
 
             // First, start teardown of the other browser.  Make sure to not
             // fire the beforeunload event in the process.  Close the other
             // window if this was its last tab.
             if (!remoteBrowser._beginRemoveTab(aOtherTab, aOurTab, true))
               return;
 
+            // If this is the last tab of the window, hide the window
+            // immediately without animation before the docshell swap, to avoid
+            // about:blank being painted.
+            let [closeWindow] = aOtherTab._endRemoveArgs;
+            if (closeWindow) {
+              let win = aOtherTab.ownerGlobal;
+              let dwu = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                           .getInterface(Ci.nsIDOMWindowUtils);
+              dwu.suppressAnimation(true);
+              // Only suppressing window animations isn't enough to avoid
+              // an empty content area being painted.
+              let baseWin = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                               .getInterface(Ci.nsIDocShell)
+                               .QueryInterface(Ci.nsIDocShellTreeItem)
+                               .treeOwner
+                               .QueryInterface(Ci.nsIBaseWindow);
+              baseWin.visibility = false;
+            }
+
             let modifiedAttrs = [];
             if (aOtherTab.hasAttribute("muted")) {
               aOurTab.setAttribute("muted", "true");
               aOurTab.muteReason = aOtherTab.muteReason;
               ourBrowser.mute();
               modifiedAttrs.push("muted");
             }
             if (aOtherTab.hasAttribute("soundplaying")) {
@@ -3357,17 +3487,21 @@
                 otherFindBar.findMode == otherFindBar.FIND_NORMAL) {
               let ourFindBar = this.getFindBar(aOurTab);
               ourFindBar._findField.value = otherFindBar._findField.value;
               if (!otherFindBar.hidden)
                 ourFindBar.onFindCommand();
             }
 
             // Finish tearing down the tab that's going away.
-            remoteBrowser._endRemoveTab(aOtherTab);
+            if (closeWindow) {
+              aOtherTab.ownerGlobal.close();
+            } else {
+              remoteBrowser._endRemoveTab(aOtherTab);
+            }
 
             this.setTabTitle(aOurTab);
 
             // If the tab was already selected (this happpens in the scenario
             // of replaceTabWithWindow), notify onLocationChange, etc.
             if (aOurTab.selected)
               this.updateCurrentBrowser(true);
 
@@ -3723,16 +3857,24 @@
           <![CDATA[
             if (this.tabs.length == 1)
               return null;
 
             var options = "chrome,dialog=no,all";
             for (var name in aOptions)
               options += "," + name + "=" + aOptions[name];
 
+            // Play the tab closing animation to give immediate feedback while
+            // waiting for the new window to appear.
+            // content area when the docshells are swapped.
+            if (this.animationsEnabled) {
+              aTab.style.maxWidth = ""; // ensure that fade-out transition happens
+              aTab.removeAttribute("fadein");
+            }
+
             // tell a new window to take the "dropped" tab
             return window.openDialog(getBrowserURL(), "_blank", options, aTab);
           ]]>
         </body>
       </method>
 
       <!-- Opens a given tab to a non-remote window. -->
       <method name="openNonRemoteWindow">
@@ -3845,17 +3987,18 @@
           // Swap the dropped tab with a new one we create and then close
           // it in the other window (making it seem to have moved between
           // windows). We also ensure that the tab we create to swap into has
           // the same remote type and process as the one we're swapping in.
           // This makes sure we don't get a short-lived process for the new tab.
           let linkedBrowser = aTab.linkedBrowser;
           let params = { eventDetail: { adoptedTab: aTab },
                          preferredRemoteType: linkedBrowser.remoteType,
-                         sameProcessAsFrameLoader: linkedBrowser.frameLoader };
+                         sameProcessAsFrameLoader: linkedBrowser.frameLoader,
+                         skipAnimation: true };
           if (aTab.hasAttribute("usercontextid")) {
             // new tab must have the same usercontextid as the old one
             params.userContextId = aTab.getAttribute("usercontextid");
           }
           let newTab = this.addTab("about:blank", params);
           let newBrowser = this.getBrowserForTab(newTab);
 
           // Stop the about:blank load.
@@ -5983,24 +6126,16 @@
             hist.add(2 /* unblockByVisitingTab */);
             tab.finishMediaBlockTimer();
           }
         ]]>
       </handler>
     </handlers>
   </binding>
 
-  <binding id="tabbrowser-tabbox"
-           extends="chrome://global/content/bindings/tabbox.xml#tabbox">
-    <implementation>
-      <property name="tabs" readonly="true"
-                onget="return document.getBindingParent(this).tabContainer;"/>
-    </implementation>
-  </binding>
-
   <binding id="tabbrowser-arrowscrollbox" extends="chrome://global/content/bindings/scrollbox.xml#arrowscrollbox-clicktoscroll">
     <implementation>
       <!-- Override scrollbox.xml method, since our scrollbox's children are
            inherited from the binding parent -->
       <method name="_getScrollableElements">
         <body><![CDATA[
           return Array.filter(document.getBindingParent(this).childNodes,
                               this._canScrollToElement, this);
@@ -7401,17 +7536,17 @@
         if (this.tabbrowser.tabs.length == 1) {
           // resize _before_ move to ensure the window fits the new screen.  if
           // the window is too large for its screen, the window manager may do
           // automatic repositioning.
           window.resizeTo(winWidth, winHeight);
           window.moveTo(left, top);
           window.focus();
         } else {
-          let props = { screenX: left, screenY: top };
+          let props = { screenX: left, screenY: top, suppressanimation: 1 };
           if (AppConstants.platform != "win") {
             props.outerWidth = winWidth;
             props.outerHeight = winHeight;
           }
           this.tabbrowser.replaceTabWithWindow(draggedTab, props);
         }
         event.stopPropagation();
       ]]></handler>
@@ -7477,16 +7612,17 @@
           <xul:hbox class="tab-bottom-line"/>
         </xul:vbox>
         <xul:hbox xbl:inherits="pinned,bursting"
                   anonid="tab-loading-burst"
                   class="tab-loading-burst"/>
         <xul:hbox xbl:inherits="pinned,selected=visuallyselected,titlechanged,attention"
                   class="tab-content" align="center">
           <xul:hbox xbl:inherits="fadein,pinned,busy,progress,selected=visuallyselected"
+                    anonid="tab-throbber"
                     class="tab-throbber"
                     layer="true"/>
           <xul:image xbl:inherits="src=image,loadingprincipal=iconLoadingPrincipal,fadein,pinned,selected=visuallyselected,busy,crashed,sharing"
                      anonid="tab-icon-image"
                      class="tab-icon-image"
                      validate="never"
                      role="presentation"/>
           <xul:image xbl:inherits="sharing,selected=visuallyselected,pinned"
--- a/browser/base/content/test/about/browser_aboutHome.js
+++ b/browser/base/content/test/about/browser_aboutHome.js
@@ -523,28 +523,27 @@ add_task(async function() {
 
   // Skip this test on Mac, because Space doesn't activate the button there.
   if (AppConstants.platform == "macosx") {
     return;
   }
 
   await BrowserTestUtils.withNewTab({ gBrowser, url: "about:home" }, async function(browser) {
     info("Waiting for about:addons tab to open...");
-    let promiseTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, "about:addons");
+    let promiseTabLoaded = BrowserTestUtils.browserLoaded(browser, false, "about:addons");
 
     await ContentTask.spawn(browser, null, async function() {
       let addOnsButton = content.document.getElementById("addons");
       addOnsButton.focus();
     });
     await BrowserTestUtils.synthesizeKey(" ", {}, browser);
 
-    let tab = await promiseTabOpened;
-    is(tab.linkedBrowser.currentURI.spec, "about:addons",
+    await promiseTabLoaded;
+    is(browser.currentURI.spec, "about:addons",
       "Should have seen the about:addons tab");
-    await BrowserTestUtils.removeTab(tab);
   });
 });
 
 /**
  * Cleans up snippets and ensures that by default we don't try to check for
  * remote snippets since that may cause network bustage or slowness.
  *
  * @param aSetupFn
--- a/browser/base/content/test/about/browser_aboutHome_wrapsCorrectly.js
+++ b/browser/base/content/test/about/browser_aboutHome_wrapsCorrectly.js
@@ -1,9 +1,14 @@
 add_task(async function() {
+  // When about:home is set to Activity Stream, there are no 'narrow' attributes
+  // therefore for this test, we want to ensure we're using the original about:home
+  await SpecialPowers.pushPrefEnv({set: [
+    ["browser.newtabpage.activity-stream.aboutHome.enabled", false]
+  ]});
   let newWindow = await BrowserTestUtils.openNewBrowserWindow();
 
   let resizedPromise = BrowserTestUtils.waitForEvent(newWindow, "resize");
   newWindow.resizeTo(300, 300);
   await resizedPromise;
 
   await BrowserTestUtils.openNewForegroundTab(newWindow.gBrowser, "about:home");
 
--- a/browser/base/content/test/alerts/browser_notification_open_settings.js
+++ b/browser/base/content/test/alerts/browser_notification_open_settings.js
@@ -1,58 +1,40 @@
 "use strict";
 
 var notificationURL = "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
-var useOldPrefs = Services.prefs.getBoolPref("browser.preferences.useOldOrganization");
-var expectedURL = useOldPrefs ? "about:preferences#content"
-                              : "about:preferences#privacy";
-
+var expectedURL = "about:preferences#privacy";
 
 add_task(async function test_settingsOpen_observer() {
   info("Opening a dummy tab so openPreferences=>switchToTabHavingURI doesn't use the blank tab.");
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: "about:robots"
   }, async function dummyTabTask(aBrowser) {
-    // Ensure preferences is loaded before removing the tab. In the "new prefs", all categories
-    // get initialized on page load since we need to be able to search them. Sync is *very*
-    // slow to load and therefore we need to wait for it to load when testing the "new prefs".
-    // For "old prefs" we only load the actual visited categories so we don't have this problem,
-    // as well, the "sync-pane-loaded" notification is not sent on "old prefs".
-    let syncPaneLoadedPromise = useOldPrefs || TestUtils.topicObserved("sync-pane-loaded", () => true);
-
     let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, expectedURL);
     info("simulate a notifications-open-settings notification");
     let uri = NetUtil.newURI("https://example.com");
     let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
     Services.obs.notifyObservers(principal, "notifications-open-settings");
     let tab = await tabPromise;
     ok(tab, "The notification settings tab opened");
-    await syncPaneLoadedPromise;
     await BrowserTestUtils.removeTab(tab);
   });
 });
 
 add_task(async function test_settingsOpen_button() {
   let pm = Services.perms;
   info("Adding notification permission");
   pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION);
 
   try {
     await BrowserTestUtils.withNewTab({
       gBrowser,
       url: notificationURL
     }, async function tabTask(aBrowser) {
-      // Ensure preferences is loaded before removing the tab. In the "new prefs", all categories
-      // get initialized on page load since we need to be able to search them. Sync is *very*
-      // slow to load and therefore we need to wait for it to load when testing the "new prefs".
-      // For "old prefs" we only load the actual visited categories so we don't have this problem,
-      // as well, the "sync-pane-loaded" notification is not sent on "old prefs".
-      let syncPaneLoadedPromise = useOldPrefs || TestUtils.topicObserved("sync-pane-loaded", () => true);
-
       info("Waiting for notification");
       await openNotification(aBrowser, "showNotification2");
 
       let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
       if (!alertWindow) {
         ok(true, "Notifications don't use XUL windows on all platforms.");
         await closeNotification(aBrowser);
         return;
@@ -62,17 +44,16 @@ add_task(async function test_settingsOpe
       let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, expectedURL);
       let openSettingsMenuItem = alertWindow.document.getElementById("openSettingsMenuItem");
       openSettingsMenuItem.click();
 
       info("Waiting for notification settings tab");
       let tab = await tabPromise;
       ok(tab, "The notification settings tab opened");
 
-      await syncPaneLoadedPromise;
       await closePromise;
       await BrowserTestUtils.removeTab(tab);
     });
   } finally {
     info("Removing notification permission");
     pm.remove(makeURI(notificationURL), "desktop-notification");
   }
 });
--- a/browser/base/content/test/general/browser_bug882977.js
+++ b/browser/base/content/test/general/browser_bug882977.js
@@ -1,16 +1,16 @@
 "use strict";
 
 /**
  * Tests that the identity-box shows the chromeUI styling
- * when viewing about:home in a new window.
+ * when viewing such a page in a new window.
  */
 add_task(async function() {
-  let homepage = "about:home";
+  let homepage = "about:preferences";
   await SpecialPowers.pushPrefEnv({
     "set": [
       ["browser.startup.homepage", homepage],
       ["browser.startup.page", 1],
     ]
   });
 
   let win = OpenBrowserWindow();
--- a/browser/base/content/test/general/browser_datachoices_notification.js
+++ b/browser/base/content/test/general/browser_datachoices_notification.js
@@ -78,25 +78,20 @@ function triggerInfoBar(expectedTimeoutM
 }
 
 var checkInfobarButton = async function(aNotification) {
   // Check that the button on the data choices infobar does the right thing.
   let buttons = aNotification.getElementsByTagName("button");
   Assert.equal(buttons.length, 1, "There is 1 button in the data reporting notification.");
   let button = buttons[0];
 
-  // Add an observer to ensure the "advanced" pane opened (but don't bother
-  // closing it - we close the entire window when done.)
-  let paneLoadedPromise = promiseTopicObserved("advanced-pane-loaded");
-
   // Click on the button.
   button.click();
 
   // Wait for the preferences panel to open.
-  await paneLoadedPromise;
   await promiseNextTick();
 };
 
 add_task(async function setup() {
   const bypassNotification = Preferences.get(PREF_BYPASS_NOTIFICATION, true);
   const currentPolicyVersion = Preferences.get(PREF_CURRENT_POLICY_VERSION, 1);
 
   // Register a cleanup function to reset our preferences.
--- a/browser/base/content/test/general/browser_offlineQuotaNotification.js
+++ b/browser/base/content/test/general/browser_offlineQuotaNotification.js
@@ -10,17 +10,16 @@ const URL = "http://mochi.test:8888/brow
 
 registerCleanupFunction(function() {
   // Clean up after ourself
   let uri = Services.io.newURI(URL);
   let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
   Services.perms.removeFromPrincipal(principal, "offline-app");
   Services.prefs.clearUserPref("offline-apps.quota.warn");
   Services.prefs.clearUserPref("offline-apps.allow_by_default");
-  Services.prefs.clearUserPref("browser.preferences.useOldOrganization");
   let {OfflineAppCacheHelper} = Components.utils.import("resource:///modules/offlineAppCache.jsm", {});
   OfflineAppCacheHelper.clear();
 });
 
 // Same as the other one, but for in-content preferences
 function checkInContentPreferences(win) {
   let doc = win.document;
   let sel = doc.getElementById("categories").selectedItems[0].id;
@@ -29,17 +28,16 @@ function checkInContentPreferences(win) 
   // all good, we are done.
   win.close();
   finish();
 }
 
 function test() {
   waitForExplicitFinish();
 
-  Services.prefs.setBoolPref("browser.preferences.useOldOrganization", false);
   Services.prefs.setBoolPref("offline-apps.allow_by_default", false);
 
   // Open a new tab.
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, URL);
   registerCleanupFunction(() => gBrowser.removeCurrentTab());
 
 
   Promise.all([
--- a/browser/base/content/test/general/browser_storagePressure_notification.js
+++ b/browser/base/content/test/general/browser_storagePressure_notification.js
@@ -8,50 +8,23 @@ function notifyStoragePressure(usage = 1
   let usageWrapper = Cc["@mozilla.org/supports-PRUint64;1"]
                      .createInstance(Ci.nsISupportsPRUint64);
   usageWrapper.data = usage;
   Services.obs.notifyObservers(usageWrapper, "QuotaManager::StoragePressure");
   return notifyPromise;
 }
 
 function openAboutPrefPromise() {
-  let useOldOrganization = Services.prefs.getBoolPref("browser.preferences.useOldOrganization");
-  let targetURL = useOldOrganization ? "about:preferences#advanced" : "about:preferences#privacy";
   let promises = [
-    BrowserTestUtils.waitForLocationChange(gBrowser, targetURL),
-    TestUtils.topicObserved("advanced-pane-loaded", () => true)
+    BrowserTestUtils.waitForLocationChange(gBrowser, "about:preferences#privacy"),
+    TestUtils.topicObserved("privacy-pane-loaded", () => true)
   ];
   return Promise.all(promises);
 }
 
-async function testOverUsageThresholdNotification() {
-  await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
-  await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.pressureNotification.minIntervalMS", 0]]});
-  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "https://example.com");
-
-  const BYTES_IN_GIGABYTE = 1073741824;
-  const USAGE_THRESHOLD_BYTES = BYTES_IN_GIGABYTE *
-    Services.prefs.getIntPref("browser.storageManager.pressureNotification.usageThresholdGB");
-  await notifyStoragePressure(USAGE_THRESHOLD_BYTES);
-  let notificationbox = document.getElementById("high-priority-global-notificationbox");
-  let notification = notificationbox.getNotificationWithValue("storage-pressure-notification");
-  ok(notification instanceof XULElement, "Should display storage pressure notification");
-
-  let prefBtn = notification.getElementsByTagName("button")[1];
-  let aboutPrefPromise = openAboutPrefPromise();
-  prefBtn.doCommand();
-  await aboutPrefPromise;
-  let aboutPrefTab = gBrowser.selectedTab;
-  let prefDoc = gBrowser.selectedBrowser.contentDocument;
-  let siteDataGroup = prefDoc.getElementById("siteDataGroup");
-  is_element_visible(siteDataGroup, "Should open to the siteDataGroup section in about:preferences");
-  await BrowserTestUtils.removeTab(aboutPrefTab);
-  await BrowserTestUtils.removeTab(tab);
-}
-
 // Test only displaying notification once within the given interval
 add_task(async function() {
   const TEST_NOTIFICATION_INTERVAL_MS = 2000;
   await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
   await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.pressureNotification.minIntervalMS", TEST_NOTIFICATION_INTERVAL_MS]]});
 
   await notifyStoragePressure();
   let notificationbox = document.getElementById("high-priority-global-notificationbox");
@@ -67,22 +40,38 @@ add_task(async function() {
   await notifyStoragePressure();
   notification = notificationbox.getNotificationWithValue("storage-pressure-notification");
   ok(notification instanceof XULElement, "Should display storage pressure notification after the given interval");
   notification.close();
 });
 
 // Test guiding user to the about:preferences when usage exceeds the given threshold
 add_task(async function() {
-  // Test for the old about:preferences
-  await SpecialPowers.pushPrefEnv({set: [["browser.preferences.useOldOrganization", true]]});
-  await testOverUsageThresholdNotification();
-  // Test for the new about:preferences
-  await SpecialPowers.pushPrefEnv({set: [["browser.preferences.useOldOrganization", false]]});
-  await testOverUsageThresholdNotification();
+  await SpecialPowers.pushPrefEnv({ set: [["browser.storageManager.enabled", true]] });
+  await SpecialPowers.pushPrefEnv({ set: [["browser.storageManager.pressureNotification.minIntervalMS", 0]] });
+  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "https://example.com");
+
+  const BYTES_IN_GIGABYTE = 1073741824;
+  const USAGE_THRESHOLD_BYTES = BYTES_IN_GIGABYTE *
+    Services.prefs.getIntPref("browser.storageManager.pressureNotification.usageThresholdGB");
+  await notifyStoragePressure(USAGE_THRESHOLD_BYTES);
+  let notificationbox = document.getElementById("high-priority-global-notificationbox");
+  let notification = notificationbox.getNotificationWithValue("storage-pressure-notification");
+  ok(notification instanceof XULElement, "Should display storage pressure notification");
+
+  let prefBtn = notification.getElementsByTagName("button")[1];
+  let aboutPrefPromise = openAboutPrefPromise();
+  prefBtn.doCommand();
+  await aboutPrefPromise;
+  let aboutPrefTab = gBrowser.selectedTab;
+  let prefDoc = gBrowser.selectedBrowser.contentDocument;
+  let siteDataGroup = prefDoc.getElementById("siteDataGroup");
+  is_element_visible(siteDataGroup, "Should open to the siteDataGroup section in about:preferences");
+  await BrowserTestUtils.removeTab(aboutPrefTab);
+  await BrowserTestUtils.removeTab(tab);
 });
 
 // Test not displaying the 2nd notification if one is already being displayed
 add_task(async function() {
   const TEST_NOTIFICATION_INTERVAL_MS = 0;
   await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
   await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.pressureNotification.minIntervalMS", TEST_NOTIFICATION_INTERVAL_MS]]});
 
--- a/browser/base/content/test/performance/browser_startup_images.js
+++ b/browser/base/content/test/performance/browser_startup_images.js
@@ -12,51 +12,25 @@
  *  - platforms: An array of the platforms where the issue is occurring.
  *               Possible values are linux, win, macosx.
  *  - intermittentNotLoaded: an array of platforms where this image is
  *                           intermittently not loaded, e.g. because it is
  *                           loaded during the time we stop recording.
  *  - intermittentShown: An array of platforms where this image is
  *                       intermittently shown, contrary to what our
  *                       whitelist says.
- *  - photon: If true, this entry only applies for builds with the Photon theme.
- *            If false, this entry only applies for builds without the Photon theme.
- *            If undefined, this entry applies for both Photon and non-Photon builds.
  *
  * Please don't add items to this list. Please remove items from this list.
  */
 const whitelist = [
-  // Photon-only entries
-  {
-    file: "chrome://browser/skin/stop.svg",
-    platforms: ["linux", "win", "macosx"],
-  },
-  {
-    file: "chrome://browser/skin/bookmark-hollow.svg",
-    platforms: ["linux", "win", "macosx"],
-  },
-  {
-    file: "chrome://browser/skin/page-action.svg",
-    platforms: ["linux", "win", "macosx"],
-  },
-  {
-    file: "chrome://pocket-shared/skin/pocket.svg",
-    platforms: ["linux", "win", "macosx"],
-  },
-
-  // Shared entries
   {
     file: "chrome://browser/skin/arrow-left.svg",
     platforms: ["linux", "win", "macosx"],
   },
   {
-    file: "chrome://browser/skin/fxa/sync-illustration.svg",
-    platforms: ["linux", "win", "macosx"],
-  },
-  {
     file: "chrome://browser/skin/tabbrowser/tab-overflow-indicator.png",
     platforms: ["linux", "win", "macosx"],
   },
 
   {
     file: "chrome://browser/skin/places/toolbarDropMarker.png",
     platforms: ["linux", "win", "macosx"],
   },
--- a/browser/base/content/test/performance/browser_urlbar_keyed_search_reflows.js
+++ b/browser/base/content/test/performance/browser_urlbar_keyed_search_reflows.js
@@ -62,17 +62,17 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
     stack: [
       "_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
       "handleOverUnderflow@chrome://global/content/bindings/autocomplete.xml",
       "_reuseAcItem@chrome://global/content/bindings/autocomplete.xml",
       "_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
       "_invalidate@chrome://global/content/bindings/autocomplete.xml",
       "invalidate@chrome://global/content/bindings/autocomplete.xml"
     ],
-    times: 1584, // This number should only ever go down - never up.
+    times: 1344, // This number should only ever go down - never up.
   },
 
   {
     stack: [
       "_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
       "handleOverUnderflow@chrome://global/content/bindings/autocomplete.xml",
       "_onChanged@chrome://global/content/bindings/autocomplete.xml",
       "_appendCurrentResult/<@chrome://global/content/bindings/autocomplete.xml",
--- a/browser/base/content/test/performance/browser_urlbar_search_reflows.js
+++ b/browser/base/content/test/performance/browser_urlbar_search_reflows.js
@@ -62,17 +62,17 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
     stack: [
       "_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
       "handleOverUnderflow@chrome://global/content/bindings/autocomplete.xml",
       "_reuseAcItem@chrome://global/content/bindings/autocomplete.xml",
       "_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
       "_invalidate@chrome://global/content/bindings/autocomplete.xml",
       "invalidate@chrome://global/content/bindings/autocomplete.xml"
     ],
-    times: 390, // This number should only ever go down - never up.
+    times: 330, // This number should only ever go down - never up.
   },
 
   {
     stack: [
       "_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openPopup@chrome://global/content/bindings/autocomplete.xml",
       "set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
@@ -114,17 +114,17 @@ const EXPECTED_REFLOWS_SECOND_OPEN = [
     stack: [
       "_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
       "handleOverUnderflow@chrome://global/content/bindings/autocomplete.xml",
       "_reuseAcItem@chrome://global/content/bindings/autocomplete.xml",
       "_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
       "_invalidate@chrome://global/content/bindings/autocomplete.xml",
       "invalidate@chrome://global/content/bindings/autocomplete.xml"
     ],
-    times: 444, // This number should only ever go down - never up.
+    times: 384, // This number should only ever go down - never up.
   },
 
   // Bug 1384256
   {
     stack: [
       "_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openPopup@chrome://global/content/bindings/autocomplete.xml",
--- a/browser/base/content/test/static/browser_all_files_referenced.js
+++ b/browser/base/content/test/static/browser_all_files_referenced.js
@@ -82,19 +82,16 @@ var whitelist = [
 
   // Add-on API introduced in bug 1118285
   {file: "resource://app/modules/NewTabURL.jsm"},
 
   // browser/components/newtab bug 1355166
   {file: "resource://app/modules/NewTabSearchProvider.jsm"},
   {file: "resource://app/modules/NewTabWebChannel.jsm"},
 
-  // browser/modules/PingCentre.jsm will soon be used (bug 1393604)
-  {file: "resource://app/modules/PingCentre.jsm"},
-
   // layout/mathml/nsMathMLChar.cpp
   {file: "resource://gre/res/fonts/mathfontSTIXGeneral.properties"},
   {file: "resource://gre/res/fonts/mathfontUnicode.properties"},
 
   // toolkit/components/places/ColorAnalyzer_worker.js
   {file: "resource://gre/modules/ClusterLib.js"},
   {file: "resource://gre/modules/ColorConversion.js"},
 
@@ -121,30 +118,26 @@ var whitelist = [
   // browser/extensions/pdfjs/content/web/viewer.js#7450
   {file: "resource://pdf.js/web/debugger.js"},
 
   // These are used in content processes. They are actually referenced.
   {file: "resource://shield-recipe-client-content/shield-content-frame.js"},
   {file: "resource://shield-recipe-client-content/shield-content-process.js"},
 
   // New L10n API that is not yet used in production
-  {file: "resource://gre/modules/Localization.jsm"},
+  {file: "resource://gre/modules/DOMLocalization.jsm"},
 
   // Starting from here, files in the whitelist are bugs that need fixing.
-  // Bug 1339420
-  {file: "chrome://branding/content/icon128.png"},
   // Bug 1339424 (wontfix?)
   {file: "chrome://browser/locale/taskbar.properties",
    platforms: ["linux", "macosx"]},
   // Bug 1316187
   {file: "chrome://global/content/customizeToolbar.xul"},
   // Bug 1343837
   {file: "chrome://global/content/findUtils.js"},
-  // Bug 1343843
-  {file: "chrome://global/content/url-classifier/unittests.xul"},
   // Bug 1348362
   {file: "chrome://global/skin/icons/warning-64.png", platforms: ["linux", "win"]},
   // Bug 1348525
   {file: "chrome://global/skin/splitter/grip-bottom.gif", platforms: ["linux"]},
   {file: "chrome://global/skin/splitter/grip-left.gif", platforms: ["linux"]},
   {file: "chrome://global/skin/splitter/grip-right.gif", platforms: ["linux"]},
   {file: "chrome://global/skin/splitter/grip-top.gif", platforms: ["linux"]},
   // Bug 1348526
--- a/browser/base/content/test/tabs/browser.ini
+++ b/browser/base/content/test/tabs/browser.ini
@@ -1,14 +1,15 @@
 [DEFAULT]
 support-files =
   dummy_page.html
   test_bug1358314.html
 
 [browser_abandonment_telemetry.js]
+[browser_accessibility_indicator.js]
 [browser_allow_process_switches_despite_related_browser.js]
 [browser_contextmenu_openlink_after_tabnavigated.js]
 [browser_isLocalAboutURI.js]
 [browser_tabCloseProbes.js]
 [browser_tabSpinnerProbe.js]
 skip-if = !e10s # Tab spinner is e10s only.
 [browser_tabSwitchPrintPreview.js]
 skip-if = os == 'mac'
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabs/browser_accessibility_indicator.js
@@ -0,0 +1,124 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const A11Y_INDICATOR_ENABLED_PREF = "accessibility.indicator.enabled";
+
+/**
+ * Test various pref and UI properties based on whether the accessibility
+ * indicator is enabled and the accessibility service is initialized.
+ * @param  {Object}  win      browser window to check the indicator in.
+ * @param  {Boolean} enabled  pref flag for accessibility indicator.
+ * @param  {Boolean} active   whether accessibility service is started or not.
+ */
+function testIndicatorState(win, enabled, active) {
+  is(Services.prefs.getBoolPref(A11Y_INDICATOR_ENABLED_PREF), enabled,
+    `Indicator is ${enabled ? "enabled" : "disabled"}.`);
+  is(Services.appinfo.accessibilityEnabled, active,
+    `Accessibility service is ${active ? "enabled" : "disabled"}.`);
+
+  let visible = enabled && active;
+  is(win.document.documentElement.hasAttribute("accessibilitymode"), visible,
+    `accessibilitymode flag is ${visible ? "set" : "unset"}.`);
+
+  // Browser UI has 2 indicators in markup for OSX and Windows but only 1 is
+  // shown depending on whether the titlebar is enabled.
+  let expectedVisibleCount = visible ? 1 : 0;
+  let visibleCount = 0;
+  [...win.document.querySelectorAll(".accessibility-indicator")].forEach(indicator =>
+    win.getComputedStyle(indicator).getPropertyValue("display") !== "none" &&
+    visibleCount++);
+  is(expectedVisibleCount, visibleCount,
+    `Indicator is ${visible ? "visible" : "invisible"}.`);
+}
+
+/**
+ * Instantiate accessibility service and wait for event associated with its
+ * startup, if necessary.
+ */
+async function initAccessibilityService() {
+  let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
+    Ci.nsIAccessibilityService);
+
+  if (!Services.appinfo.accessibilityEnabled) {
+    await new Promise(resolve => {
+      let observe = (subject, topic, data) => {
+        Services.obs.removeObserver(observe, "a11y-init-or-shutdown");
+        // "1" indicates that the accessibility service is initialized.
+        data === "1" && resolve();
+      };
+      Services.obs.addObserver(observe, "a11y-init-or-shutdown");
+    })
+  }
+
+  return accService;
+}
+
+/**
+ * If accessibility service is not yet disabled, wait for the event associated
+ * with its shutdown.
+ */
+async function shutdownAccessibilityService() {
+  if (Services.appinfo.accessibilityEnabled) {
+    await new Promise(resolve => {
+      let observe = (subject, topic, data) => {
+        Services.obs.removeObserver(observe, "a11y-init-or-shutdown");
+        // "1" indicates that the accessibility service is shutdown.
+        data === "0" && resolve();
+      };
+      Services.obs.addObserver(observe, "a11y-init-or-shutdown");
+    })
+  }
+}
+
+/**
+ * Force garbage collection.
+ */
+function forceGC() {
+  SpecialPowers.gc();
+  SpecialPowers.forceShrinkingGC();
+  SpecialPowers.forceCC();
+}
+
+add_task(async function test_accessibility_indicator() {
+  info("Test default accessibility indicator state.");
+  let newWin = await BrowserTestUtils.openNewBrowserWindow();
+  testIndicatorState(window, true, false);
+  testIndicatorState(newWin, true, false);
+
+  info("Enable accessibility and ensure the indicator is shown in all windows.");
+  let accService = await initAccessibilityService(); // eslint-disable-line no-unused-vars
+  testIndicatorState(window, true, true);
+  testIndicatorState(newWin, true, true);
+
+  info("Open a new window and ensure the indicator is shown there by default.");
+  let dynamicWin = await BrowserTestUtils.openNewBrowserWindow({ private: true });
+  testIndicatorState(dynamicWin, true, true);
+  await BrowserTestUtils.closeWindow(dynamicWin);
+
+  info("Preff off accessibility indicator.");
+  Services.prefs.setBoolPref(A11Y_INDICATOR_ENABLED_PREF, false);
+  testIndicatorState(window, false, true);
+  testIndicatorState(newWin, false, true);
+  dynamicWin = await BrowserTestUtils.openNewBrowserWindow({ private: true });
+  testIndicatorState(dynamicWin, false, true);
+
+  info("Preff on accessibility indicator.");
+  Services.prefs.setBoolPref(A11Y_INDICATOR_ENABLED_PREF, true);
+  testIndicatorState(window, true, true);
+  testIndicatorState(newWin, true, true);
+  testIndicatorState(dynamicWin, true, true);
+
+  info("Disable accessibility and ensure the indicator is hidden in all windows.");
+  accService = undefined;
+  forceGC();
+  await shutdownAccessibilityService();
+  testIndicatorState(window, true, false);
+  testIndicatorState(newWin, true, false);
+  testIndicatorState(dynamicWin, true, false);
+
+  Services.prefs.clearUserPref(A11Y_INDICATOR_ENABLED_PREF);
+  await BrowserTestUtils.closeWindow(newWin);
+  await BrowserTestUtils.closeWindow(dynamicWin);
+});
--- a/browser/base/content/test/urlbar/browser_page_action_menu.js
+++ b/browser/base/content/test/urlbar/browser_page_action_menu.js
@@ -118,32 +118,32 @@ add_task(async function sendToDevice_non
   // Open a tab that's not sendable.  An about: page like about:home is
   // convenient.
   await BrowserTestUtils.withNewTab("about:home", async () => {
     // ... but the page actions should be hidden on about:home, including the
     // main button.  (It's not easy to load a page that's both actionable and
     // not sendable.)  So first check that that's the case, and then unhide the
     // main button so that this test can continue.
     Assert.equal(
-      window.getComputedStyle(BrowserPageActions.mainButtonNode).visibility,
-      "collapse",
+      window.getComputedStyle(BrowserPageActions.mainButtonNode).display,
+      "none",
       "Main button should be hidden on about:home"
     );
-    BrowserPageActions.mainButtonNode.style.visibility = "visible";
+    BrowserPageActions.mainButtonNode.style.display = "-moz-box";
     await promiseSyncReady();
     // Open the panel.  Send to Device should be disabled.
     await promisePageActionPanelOpen();
     let sendToDeviceButton =
       document.getElementById("pageAction-panel-sendToDevice");
     Assert.ok(sendToDeviceButton.disabled);
     let hiddenPromise = promisePageActionPanelHidden();
     BrowserPageActions.panelNode.hidePopup();
     await hiddenPromise;
-    // Remove the `visibility` style set above.
-    BrowserPageActions.mainButtonNode.style.removeProperty("visibility");
+    // Remove the `display` style set above.
+    BrowserPageActions.mainButtonNode.style.removeProperty("display");
   });
 });
 
 add_task(async function sendToDevice_syncNotReady_other_states() {
   // Open a tab that's sendable.
   await BrowserTestUtils.withNewTab("http://example.com/", async () => {
     await promiseSyncReady();
     const sandbox = sinon.sandbox.create();
@@ -457,16 +457,120 @@ add_task(async function sendToDevice_dev
     let hiddenPromise = promisePageActionPanelHidden();
     BrowserPageActions.panelNode.hidePopup();
     await hiddenPromise;
 
     cleanUp();
   });
 });
 
+add_task(async function sendToDevice_inUrlbar() {
+  // Open a tab that's sendable.
+  await BrowserTestUtils.withNewTab("http://example.com/", async () => {
+    await promiseSyncReady();
+    const sandbox = sinon.sandbox.create();
+    sandbox.stub(gSync, "syncReady").get(() => true);
+    sandbox.stub(Weave.Service.clientsEngine, "lastSync").get(() => Date.now());
+    sandbox.stub(UIState, "get").returns({ status: UIState.STATUS_SIGNED_IN });
+    sandbox.stub(gSync, "isSendableURI").returns(true);
+    sandbox.stub(gSync, "remoteClients").get(() => mockRemoteClients);
+
+    let cleanUp = () => {
+      sandbox.restore();
+    };
+    registerCleanupFunction(cleanUp);
+
+    // Disable the activated-action panel animation when it opens.  Otherwise
+    // it's necessary to wait a moment before trying to click the device menu
+    // item below.
+    BrowserPageActions._disableActivatedActionPanelAnimation = true;
+
+    // Add Send to Device to the urlbar.
+    let action = PageActions.actionForID("sendToDevice");
+    action.shownInUrlbar = true;
+
+    // Click it to open its panel.
+    let urlbarButton = document.getElementById(
+      BrowserPageActions._urlbarButtonNodeIDForActionID(action.id)
+    );
+    Assert.ok(!urlbarButton.disabled);
+    let panelPromise =
+      promisePanelShown(BrowserPageActions._activatedActionPanelID);
+    EventUtils.synthesizeMouseAtCenter(urlbarButton, {});
+    await panelPromise;
+
+    // The devices should be shown in the subview.
+    let expectedItems = [
+      {
+        id: "pageAction-urlbar-sendToDevice-notReady",
+        display: "none",
+        disabled: true,
+      },
+    ];
+    for (let client of mockRemoteClients) {
+      expectedItems.push({
+        attrs: {
+          clientId: client.id,
+          label: client.name,
+          clientType: client.type,
+        },
+      });
+    }
+    expectedItems.push(
+      null,
+      {
+        attrs: {
+          label: "Send to All Devices"
+        }
+      }
+    );
+    checkSendToDeviceItems(expectedItems, true);
+
+    // Get the first device menu item in the panel.
+    let bodyID =
+      BrowserPageActions._panelViewNodeIDForActionID("sendToDevice", true) +
+      "-body";
+    let body = document.getElementById(bodyID);
+    let deviceMenuItem = body.querySelector(".sendtab-target");
+    Assert.notEqual(deviceMenuItem, null);
+
+    // For good measure, wait until it's visible.
+    let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                    .getInterface(Ci.nsIDOMWindowUtils);
+    await BrowserTestUtils.waitForCondition(() => {
+      let bounds = dwu.getBoundsWithoutFlushing(deviceMenuItem);
+      return bounds.height > 0 && bounds.width > 0;
+    }, "Waiting for first device menu item to appear");
+
+    // Click it, which should cause the panel to close.
+    let hiddenPromise =
+      promisePanelHidden(BrowserPageActions._activatedActionPanelID);
+    EventUtils.synthesizeMouseAtCenter(deviceMenuItem, {});
+    info("Waiting for Send to Device panel to close after clicking a device");
+    await hiddenPromise;
+
+    // And then the "Sent!" notification panel should open and close by itself
+    // after a moment.
+    info("Waiting for the Sent! notification panel to open");
+    await promisePanelShown(BrowserPageActionFeedback.panelNode.id);
+    Assert.equal(
+      BrowserPageActionFeedback.panelNode.anchorNode.id,
+      urlbarButton.id
+    );
+    info("Waiting for the Sent! notification panel to close");
+    await promisePanelHidden(BrowserPageActionFeedback.panelNode.id);
+
+    // Remove Send to Device from the urlbar.
+    action.shownInUrlbar = false;
+    BrowserPageActions._disableActivatedActionPanelAnimation = false;
+
+    cleanUp();
+  });
+});
+
 add_task(async function contextMenu() {
   // Open an actionable page so that the main page action button appears.
   let url = "http://example.com/";
   await BrowserTestUtils.withNewTab(url, async () => {
     // Open the panel and then open the context menu on the bookmark button.
     await promisePageActionPanelOpen();
     let bookmarkButton = document.getElementById("pageAction-panel-bookmark");
     let contextMenuPromise = promisePanelShown("pageActionPanelContextMenu");
@@ -572,19 +676,21 @@ function promiseSyncReady() {
                   .getService(Components.interfaces.nsISupports)
                   .wrappedJSObject;
   return service.whenLoaded().then(() => {
     UIState.isReady();
     return UIState.refresh();
   });
 }
 
-function checkSendToDeviceItems(expectedItems) {
-  let body =
-    document.getElementById("pageAction-panel-sendToDevice-subview-body");
+function checkSendToDeviceItems(expectedItems, forUrlbar = false) {
+  let bodyID =
+    BrowserPageActions._panelViewNodeIDForActionID("sendToDevice", forUrlbar) +
+    "-body";
+  let body = document.getElementById(bodyID);
   Assert.equal(body.childNodes.length, expectedItems.length);
   for (let i = 0; i < expectedItems.length; i++) {
     let expected = expectedItems[i];
     let actual = body.childNodes[i];
     if (!expected) {
       Assert.equal(actual.localName, "toolbarseparator");
       continue;
     }
--- a/browser/base/content/test/urlbar/browser_urlbarAboutHomeLoading.js
+++ b/browser/base/content/test/urlbar/browser_urlbarAboutHomeLoading.js
@@ -6,17 +6,17 @@ const {TabStateFlusher} = Cu.import("res
 /**
  * Test what happens if loading a URL that should clear the
  * location bar after a parent process URL.
  */
 add_task(async function clearURLBarAfterParentProcessURL() {
   let tab = await new Promise(resolve => {
     gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:preferences");
     let newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
-    newTabBrowser.addEventListener("Initialized", function() {
+    newTabBrowser.addEventListener("Initialized", async function() {
       resolve(gBrowser.selectedTab);
     }, {capture: true, once: true});
   });
   document.getElementById("home-button").click();
   await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
   is(gURLBar.value, "", "URL bar should be empty");
   is(tab.linkedBrowser.userTypedValue, null, "The browser should have no recorded userTypedValue");
   await BrowserTestUtils.removeTab(tab);
@@ -25,17 +25,17 @@ add_task(async function clearURLBarAfter
 /**
  * Same as above, but open the tab without passing the URL immediately
  * which changes behaviour in tabbrowser.xml.
  */
 add_task(async function clearURLBarAfterParentProcessURLInExistingTab() {
   let tab = await new Promise(resolve => {
     gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
     let newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
-    newTabBrowser.addEventListener("Initialized", function() {
+    newTabBrowser.addEventListener("Initialized", async function() {
       resolve(gBrowser.selectedTab);
     }, {capture: true, once: true});
     newTabBrowser.loadURI("about:preferences");
   });
   document.getElementById("home-button").click();
   await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
   is(gURLBar.value, "", "URL bar should be empty");
   is(tab.linkedBrowser.userTypedValue, null, "The browser should have no recorded userTypedValue");
--- a/browser/base/content/test/urlbar/browser_urlbarSearchSuggestions_opt-out.js
+++ b/browser/base/content/test/urlbar/browser_urlbarSearchSuggestions_opt-out.js
@@ -1,8 +1,9 @@
+/* eslint-disable mozilla/no-arbitrary-setTimeout */
 // The order of the tests here matters!
 
 const SUGGEST_ALL_PREF = "browser.search.suggest.enabled";
 const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
 const CHOICE_PREF = "browser.urlbar.userMadeSearchSuggestionsChoice";
 const TIMES_PREF = "browser.urlbar.timesBeforeHidingSuggestionsHint";
 const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
 const ONEOFF_PREF = "browser.urlbar.oneOffSearches";
@@ -33,17 +34,17 @@ add_task(async function prepare() {
 });
 
 add_task(async function focus() {
   // Focusing the urlbar should open the popup in order to show the
   // notification.
   setupVisibleHint();
   gURLBar.blur();
   let popupPromise = promisePopupShown(gURLBar.popup);
-  gURLBar.focus();
+  focusAndSelectUrlBar(true);
   await popupPromise;
   Assert.ok(gURLBar.popup.popupOpen, "popup should be open");
   assertVisible(true);
   assertFooterVisible(false);
   Assert.equal(gURLBar.popup._matchCount, 0, "popup should have no results");
 
   // Start searching.
   EventUtils.synthesizeKey("r", {});
@@ -59,31 +60,48 @@ add_task(async function focus() {
   let prefsPromise = BrowserTestUtils.waitForLocationChange(gBrowser, "about:preferences#search");
   changeOptionsLink.click();
   await prefsPromise;
   Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
   // The preferences page does fancy stuff with focus, ensure to unload it.
   await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "about:blank");
 });
 
-add_task(async function new_tab() {
-  // Opening a new tab when the urlbar is unfocused, should focusing it and thus
-  // open the popup in order to show the notification.
+add_task(async function click_on_focused() {
+  // Even if the location bar is already focused, we should still show the popup
+  // and the notification on click.
   setupVisibleHint();
   gURLBar.blur();
+  // Won't show the hint since it's not user initiated.
+  gURLBar.focus();
+  await new Promise(resolve => setTimeout(resolve, 500));
+  Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
+
   let popupPromise = promisePopupShown(gURLBar.popup);
-  // openNewForegroundTab doesn't focus the urlbar.
-  await BrowserTestUtils.synthesizeKey("t", { accelKey: true }, gBrowser.selectedBrowser);
+  EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, { button: 0, type: "mousedown" });
   await popupPromise;
+
   Assert.ok(gURLBar.popup.popupOpen, "popup should be open");
   assertVisible(true);
   assertFooterVisible(false);
   Assert.equal(gURLBar.popup._matchCount, 0, "popup should have no results");
+  gURLBar.blur();
+  Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
+});
+
+add_task(async function new_tab() {
+  // Opening a new tab when the urlbar is unfocused, should focus it but not
+  // open the popup.
+  setupVisibleHint();
+  gURLBar.blur();
+  // openNewForegroundTab doesn't focus the urlbar.
+  await BrowserTestUtils.synthesizeKey("t", { accelKey: true }, gBrowser.selectedBrowser);
+  await new Promise(resolve => setTimeout(resolve, 500));
+  Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
-  Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
 });
 
 add_task(async function privateWindow() {
   // Since suggestions are disabled in private windows, the notification should
   // not appear even when suggestions are otherwise enabled.
   setupVisibleHint();
   let win = await BrowserTestUtils.openNewBrowserWindow({ private: true });
   await promiseAutocompleteResultPopup("foo", win);
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -180,16 +180,22 @@ file, You can obtain one at http://mozil
 
       <!--
         Since we never want scrollbars, we always use the maxResults value.
       -->
       <property name="maxRows"
                 onget="return this.popup.maxResults;"/>
 
       <!--
+        Set by focusAndSelectUrlBar to indicate whether the next focus event was
+        initiated by an explicit user action. See the "focus" handler below.
+      -->
+      <field name="userInitiatedFocus">false</field>
+
+      <!--
         onBeforeValueGet is called by the base-binding's .value getter.
         It can return an object with a "value" property, to override the
         return value of the getter.
       -->
       <method name="onBeforeValueGet">
         <body><![CDATA[
           return { value: this._value };
         ]]></body>
@@ -1295,16 +1301,21 @@ file, You can obtain one at http://mozil
 
       <method name="onInput">
         <parameter name="aEvent"/>
         <body><![CDATA[
           if (!this.mIgnoreInput && this.mController.input == this) {
             this._value = this.inputField.value;
             gBrowser.userTypedValue = this.value;
             this.valueIsTyped = true;
+            if (this.inputField.value) {
+              this.setAttribute("usertyping", "true");
+            } else {
+              this.removeAttribute("usertyping");
+            }
             // Only wait for a result when we are sure to get one.  In some
             // cases, like when pasting the same exact text, we may not fire
             // a new search and we won't get a result.
             if (this.mController.handleText()) {
               this.gotResultForCurrentQuery = false;
               this._searchStartDate = Date.now();
               this._deferredKeyEventQueue = [];
               if (this._deferredKeyEventTimeout) {
@@ -1435,16 +1446,37 @@ file, You can obtain one at http://mozil
           let previousDate = this._prefs.getIntPref("lastSuggestionsPromptDate");
           if (!useDays || previousDate != date) {
             this._prefs.setIntPref(prefName, remaining - 1);
           }
           this._prefs.setIntPref("lastSuggestionsPromptDate", date);
         ]]></body>
       </method>
 
+      <method name="maybeShowSearchSuggestionsNotificationOnFocus">
+        <parameter name="mouseFocused"/>
+        <body><![CDATA[
+          let whichNotification = this.whichSearchSuggestionsNotification;
+          if (this._showSearchSuggestionNotificationOnMouseFocus &&
+              mouseFocused) {
+            // Force showing the opt-out notification.
+            this._whichSearchSuggestionsNotification = whichNotification = "opt-out";
+          }
+          if (whichNotification == "opt-out") {
+            try {
+              this.popup.openAutocompletePopup(this, this);
+            } finally {
+              if (mouseFocused) {
+                delete this._whichSearchSuggestionsNotification;
+                this._showSearchSuggestionNotificationOnMouseFocus = false;
+              }
+            }
+          }
+        ]]></body>
+      </method>
     </implementation>
 
     <handlers>
       <handler event="keydown"><![CDATA[
         if (this._noActionKeys.has(event.keyCode) &&
             this.popup.selectedIndex >= 0 &&
             !this._pressedNoActionKeys.has(event.keyCode)) {
           if (this._pressedNoActionKeys.size == 0) {
@@ -1459,52 +1491,51 @@ file, You can obtain one at http://mozil
         if (this._noActionKeys.has(event.keyCode) &&
             this._pressedNoActionKeys.has(event.keyCode)) {
           this._pressedNoActionKeys.delete(event.keyCode);
           if (this._pressedNoActionKeys.size == 0)
             this._clearNoActions();
         }
       ]]></handler>
 
+      <handler event="mousedown"><![CDATA[
+        // Eventually show the opt-out notification even if the location bar is
+        // empty, focused, and the user clicks on it.
+        if (event.button == 0 && this.focused && this.textValue == "") {
+          this.maybeShowSearchSuggestionsNotificationOnFocus(true);
+        }
+      ]]></handler>
+
       <handler event="focus"><![CDATA[
         if (event.originalTarget == this.inputField) {
           this._hideURLTooltip();
           this.formatValue();
           if (this.getAttribute("pageproxystate") != "valid") {
             UpdatePopupNotificationsVisibility();
           }
 
-          // We show the opt-out notification on every kind of focus to the urlbar
-          // included opening a new tab, but we want to enforce at least one
+          // We show the opt-out notification when the mouse/keyboard focus the
+          // urlbar, but in any case we want to enforce at least one
           // notification when the user focuses it with the mouse.
           let whichNotification = this.whichSearchSuggestionsNotification;
           if (whichNotification == "opt-out" &&
               this._showSearchSuggestionNotificationOnMouseFocus === undefined) {
             this._showSearchSuggestionNotificationOnMouseFocus = true;
           }
 
-          // Check whether the focus change came from a user mouse action.
+          // Check whether the focus change came from a keyboard/mouse action.
           let focusMethod = Services.focus.getLastFocusMethod(window);
-          let mouseFocused = !!(focusMethod & Services.focus.FLAG_BYMOUSE);
-          if (this._showSearchSuggestionNotificationOnMouseFocus &&
-              mouseFocused) {
-            // Force showing the opt-out notification.
-            this._whichSearchSuggestionsNotification = whichNotification = "opt-out";
+          // If it's a focus started by code and the primary user intention was
+          // not to go to the location bar, don't show a notification.
+          if (!focusMethod && !this.userInitiatedFocus) {
+            return;
           }
 
-          if (whichNotification == "opt-out") {
-            try {
-              this.popup.openAutocompletePopup(this, this);
-            } finally {
-              if (mouseFocused) {
-                delete this._whichSearchSuggestionsNotification;
-                this._showSearchSuggestionNotificationOnMouseFocus = false;
-              }
-            }
-          }
+          let mouseFocused = !!(focusMethod & Services.focus.FLAG_BYMOUSE);
+          this.maybeShowSearchSuggestionsNotificationOnFocus(mouseFocused);
         }
       ]]></handler>
 
       <handler event="blur"><![CDATA[
         if (event.originalTarget == this.inputField) {
           this._clearNoActions();
           this.formatValue();
           if (this.getAttribute("pageproxystate") != "valid") {
@@ -1961,16 +1992,17 @@ file, You can obtain one at http://mozil
           // around that problem by disabling the listbox animation.
           this.richlistbox.flex = 0;
           this.setAttribute("dontanimate", "true");
 
           this.classList.add("showSearchSuggestionsNotification");
           // Don't show the one-off buttons if we are showing onboarding and
           // there's no result, since it would be ugly and pointless.
           this.footer.collapsed = this._matchCount == 0;
+          this.input.tabScrolling = this._matchCount != 0;
 
           // This event allows accessibility APIs to see the notification.
           if (!this.popupOpen) {
             let event = document.createEvent("Events");
             event.initEvent("AlertActive", true, true);
             this.searchSuggestionsNotification.dispatchEvent(event);
           }
           ]]>
@@ -2179,16 +2211,17 @@ file, You can obtain one at http://mozil
                 let engine = Services.search.currentEngine;
                 engine.speculativeConnect({window,
                                            originAttributes: gBrowser.contentPrincipal.originAttributes});
               }
             }
 
             // When a result is present the footer should always be visible.
             this.footer.collapsed = false;
+            this.input.tabScrolling = true;
 
             this.input.gotResultForCurrentQuery = true;
             this.input.maybeReplayDeferredKeyEvents();
           ]]>
         </body>
       </method>
 
       <method name="_onSearchBegin">
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -38,17 +38,19 @@ Object.defineProperty(this, "BROWSER_NEW
 var TAB_DROP_TYPE = "application/x-moz-tabbrowser-tab";
 
 var gBidiUI = false;
 
 /**
  * Determines whether the given url is considered a special URL for new tabs.
  */
 function isBlankPageURL(aURL) {
-  return aURL == "about:blank" || aURL == BROWSER_NEW_TAB_URL;
+  return aURL == "about:blank" ||
+         aURL == "about:home" ||
+         aURL == BROWSER_NEW_TAB_URL;
 }
 
 function getBrowserURL() {
   return "chrome://browser/content/browser.xul";
 }
 
 function getTopWin(skipPopups) {
   // If this is called in a browser window, use that window regardless of
@@ -729,27 +731,16 @@ function openAboutDialog() {
 
 function openPreferences(paneID, extraArgs) {
   let histogram = Services.telemetry.getHistogramById("FX_PREFERENCES_OPENED_VIA");
   if (extraArgs && extraArgs.origin) {
     histogram.add(extraArgs.origin);
   } else {
     histogram.add("other");
   }
-  function switchToAdvancedSubPane(doc) {
-    if (extraArgs && extraArgs.advancedTab) {
-      // After the Preferences reorg works in Bug 1335907, no more advancedPrefs element.
-      // The old Preference is pref-off behind `browser.preferences.useOldOrganization` on Nightly.
-      // During the transition between the old and new Preferences, should do checking before proceeding.
-      let advancedPaneTabs = doc.getElementById("advancedPrefs");
-      if (advancedPaneTabs) {
-        advancedPaneTabs.selectedTab = doc.getElementById(extraArgs.advancedTab);
-      }
-    }
-  }
 
   // This function is duplicated from preferences.js.
   function internalPrefCategoryNameToFriendlyName(aName) {
     return (aName || "").replace(/^pane./, function(toReplace) { return toReplace[4].toLowerCase(); });
   }
 
   let win = Services.wm.getMostRecentWindow("navigator:browser");
   let friendlyCategoryName = internalPrefCategoryNameToFriendlyName(paneID);
@@ -759,64 +750,56 @@ function openPreferences(paneID, extraAr
     let urlParams = extraArgs.urlParams;
     for (let name in urlParams) {
       if (urlParams[name] !== undefined) {
         params.set(name, urlParams[name]);
       }
     }
   }
   let preferencesURL = "about:preferences" + (params ? "?" + params : "") +
-                       (friendlyCategoryName ? "#" + friendlyCategoryName : "");
+    (friendlyCategoryName ? "#" + friendlyCategoryName : "");
   let newLoad = true;
   let browser = null;
   if (!win) {
     const Cc = Components.classes;
     const Ci = Components.interfaces;
     let windowArguments = Cc["@mozilla.org/array;1"]
-                            .createInstance(Ci.nsIMutableArray);
+      .createInstance(Ci.nsIMutableArray);
     let supportsStringPrefURL = Cc["@mozilla.org/supports-string;1"]
-                                  .createInstance(Ci.nsISupportsString);
+      .createInstance(Ci.nsISupportsString);
     supportsStringPrefURL.data = preferencesURL;
     windowArguments.appendElement(supportsStringPrefURL);
 
     win = Services.ww.openWindow(null, Services.prefs.getCharPref("browser.chromeURL"),
-                                 "_blank", "chrome,dialog=no,all", windowArguments);
+      "_blank", "chrome,dialog=no,all", windowArguments);
   } else {
     let shouldReplaceFragment = friendlyCategoryName ? "whenComparingAndReplace" : "whenComparing";
     newLoad = !win.switchToTabHavingURI(preferencesURL, true, {
       ignoreFragment: shouldReplaceFragment,
       replaceQueryString: true,
       triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
     });
     browser = win.gBrowser.selectedBrowser;
   }
 
   if (newLoad) {
-    Services.obs.addObserver(function advancedPaneLoadedObs(prefWin, topic, data) {
+    Services.obs.addObserver(function panesLoadedObs(prefWin, topic, data) {
       if (!browser) {
         browser = win.gBrowser.selectedBrowser;
       }
       if (prefWin != browser.contentWindow) {
         return;
       }
-      Services.obs.removeObserver(advancedPaneLoadedObs, "advanced-pane-loaded");
-      switchToAdvancedSubPane(browser.contentDocument);
-    }, "advanced-pane-loaded");
-  } else {
-    if (paneID) {
-      browser.contentWindow.gotoPref(paneID);
-    }
-    switchToAdvancedSubPane(browser.contentDocument);
+      Services.obs.removeObserver(panesLoadedObs, "sync-pane-loaded");
+    }, "sync-pane-loaded");
+  } else if (paneID) {
+    browser.contentWindow.gotoPref(paneID);
   }
 }
 
-function openAdvancedPreferences(tabID, origin) {
-  openPreferences("paneAdvanced", { "advancedTab": tabID, origin });
-}
-
 /**
  * Opens the troubleshooting information (about:support) page for this version
  * of the application.
  */
 function openTroubleshootingPage() {
   openUILinkIn("about:support", "tab");
 }
 
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -16,17 +16,16 @@
 #include "mozilla/Preferences.h"
 #include "nsServiceManagerUtils.h"
 
 namespace mozilla {
 namespace browser {
 
 NS_IMPL_ISUPPORTS(AboutRedirector, nsIAboutModule)
 
-bool AboutRedirector::sUseOldPreferences = false;
 bool AboutRedirector::sActivityStreamEnabled = false;
 bool AboutRedirector::sActivityStreamAboutHomeEnabled = false;
 
 struct RedirEntry {
   const char* id;
   const char* url;
   uint32_t flags;
 };
@@ -68,19 +67,21 @@ static const RedirEntry kRedirMap[] = {
     nsIAboutModule::ALLOW_SCRIPT },
   { "robots", "chrome://browser/content/aboutRobots.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT },
   { "searchreset", "chrome://browser/content/search/searchReset.xhtml",
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT },
   { "sessionrestore", "chrome://browser/content/aboutSessionRestore.xhtml",
-    nsIAboutModule::ALLOW_SCRIPT },
+    nsIAboutModule::ALLOW_SCRIPT |
+    nsIAboutModule::HIDE_FROM_ABOUTABOUT },
   { "welcomeback", "chrome://browser/content/aboutWelcomeBack.xhtml",
-    nsIAboutModule::ALLOW_SCRIPT },
+    nsIAboutModule::ALLOW_SCRIPT |
+    nsIAboutModule::HIDE_FROM_ABOUTABOUT },
   // Linkable because of indexeddb use (bug 1228118)
   { "home", "chrome://browser/content/abouthome/aboutHome.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::MAKE_LINKABLE |
     nsIAboutModule::ENABLE_INDEXED_DB },
   // the newtab's actual URL will be determined when the channel is created
@@ -145,38 +146,30 @@ AboutRedirector::NewChannel(nsIURI* aURI
   NS_ASSERTION(result, "must not be null");
 
   nsAutoCString path = GetAboutModuleName(aURI);
 
   nsresult rv;
   nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  static bool sPrefCacheInited = false;
-  if (!sPrefCacheInited) {
-    Preferences::AddBoolVarCache(&sUseOldPreferences,
-                                 "browser.preferences.useOldOrganization");
-    sPrefCacheInited = true;
-  }
   LoadActivityStreamPrefs();
 
   for (auto & redir : kRedirMap) {
     if (!strcmp(path.get(), redir.id)) {
       nsAutoCString url;
 
       if (path.EqualsLiteral("newtab") ||
           (path.EqualsLiteral("home") && sActivityStreamEnabled && sActivityStreamAboutHomeEnabled)) {
         // let the aboutNewTabService decide where to redirect
         nsCOMPtr<nsIAboutNewTabService> aboutNewTabService =
           do_GetService("@mozilla.org/browser/aboutnewtab-service;1", &rv);
         NS_ENSURE_SUCCESS(rv, rv);
         rv = aboutNewTabService->GetDefaultURL(url);
         NS_ENSURE_SUCCESS(rv, rv);
-      } else if (path.EqualsLiteral("preferences") && !sUseOldPreferences) {
-        url.AssignASCII("chrome://browser/content/preferences/in-content-new/preferences.xul");
       }
       // fall back to the specified url in the map
       if (url.IsEmpty()) {
         url.AssignASCII(redir.url);
       }
 
       nsCOMPtr<nsIChannel> tempChannel;
       nsCOMPtr<nsIURI> tempURI;
--- a/browser/components/about/AboutRedirector.h
+++ b/browser/components/about/AboutRedirector.h
@@ -21,17 +21,16 @@ public:
 
   static nsresult
     Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
 
 protected:
   virtual ~AboutRedirector() {}
 
 private:
-  static bool sUseOldPreferences;
   static bool sActivityStreamEnabled;
   static bool sActivityStreamAboutHomeEnabled;
 
   static void LoadActivityStreamPrefs();
 };
 
 } // namespace browser
 } // namespace mozilla
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -2962,17 +2962,17 @@ this.CustomizableUI = {
 
 
   /**
    * An iteratable property of windows managed by CustomizableUI.
    * Note that this can *only* be used as an iterator. ie:
    *     for (let window of CustomizableUI.windows) { ... }
    */
   windows: {
-    *[Symbol.iterator]() {
+    * [Symbol.iterator]() {
       for (let [window, ] of gBuildWindows)
         yield window;
     }
   },
 
   /**
    * Add a listener object that will get fired for various events regarding
    * customization.
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -87,20 +87,16 @@
                        key="key_gotoHistory"
                        oncommand="SidebarUI.toggle('viewHistorySidebar'); PanelUI.hide();">
           <observes element="viewHistorySidebar" attribute="checked"/>
         </toolbarbutton>
         <toolbarbutton id="appMenuClearRecentHistory"
                        label="&appMenuHistory.clearRecent.label;"
                        class="subviewbutton subviewbutton-iconic"
                        command="Tools:Sanitize"/>
-        <toolbarbutton id="appMenuRestoreLastSession"
-                       label="&appMenuHistory.restoreSession.label;"
-                       class="subviewbutton subviewbutton-iconic"
-                       command="Browser:RestoreLastSession"/>
         <toolbarseparator/>
         <toolbarbutton id="appMenuRecentlyClosedTabs"
                        label="&historyUndoMenu.label;"
                        class="subviewbutton subviewbutton-iconic subviewbutton-nav"
                        closemenu="none"
                        oncommand="PanelUI.showSubView('appMenu-library-recentlyClosedTabs', this)"/>
         <toolbarbutton id="appMenuRecentlyClosedWindows"
                        label="&historyUndoWindowMenu.label;"
@@ -159,17 +155,17 @@
                     showMoreTooltipText="&appMenuRemoteTabs.showMore.tooltip;"
                     notabsforclientlabel="&appMenuRemoteTabs.notabs.label;"
                     />
             </vbox>
             <!-- Sync is ready to Sync but the "tabs" engine isn't enabled-->
             <hbox id="PanelUI-remotetabs-tabsdisabledpane" pack="center" flex="1">
               <vbox class="PanelUI-remotetabs-instruction-box" align="center">
                 <hbox pack="center">
-                  <html:img class="fxaSyncIllustration" src="chrome://browser/skin/fxa/sync-illustration.svg"/>
+                  <image class="fxaSyncIllustration"/>
                 </hbox>
                 <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.tabsnotsyncing.label;</label>
                 <hbox pack="center">
                   <toolbarbutton class="PanelUI-remotetabs-prefs-button"
                                  label="&appMenuRemoteTabs.openprefs.label;"
                                  oncommand="gSync.openPrefs('synced-tabs');"/>
                 </hbox>
               </vbox>
@@ -177,17 +173,17 @@
             <!-- Sync is ready to Sync but we are still fetching the tabs to show -->
             <vbox id="PanelUI-remotetabs-fetching">
               <!-- Show intentionally blank panel, see bug 1239845 -->
             </vbox>
             <!-- Sync has only 1 (ie, this) device connected -->
             <hbox id="PanelUI-remotetabs-nodevicespane" pack="center" flex="1">
               <vbox class="PanelUI-remotetabs-instruction-box">
                 <hbox pack="center">
-                  <html:img class="fxaSyncIllustration" src="chrome://browser/skin/fxa/sync-illustration.svg"/>
+                  <image class="fxaSyncIllustration"/>
                 </hbox>
                 <label class="PanelUI-remotetabs-instruction-title">&appMenuRemoteTabs.noclients.title;</label>
                 <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.noclients.subtitle;</label>
                 <!-- The inner HTML for PanelUI-remotetabs-mobile-promo is built at runtime -->
                 <label id="PanelUI-remotetabs-mobile-promo" fxAccountsBrand="&syncBrand.fxAccount.label;"/>
               </vbox>
             </hbox>
           </deck>
@@ -195,31 +191,31 @@
         <!-- a box to ensure contained boxes are centered horizonally -->
         <hbox pack="center" flex="1">
           <!-- When Sync is not configured -->
           <vbox id="PanelUI-remotetabs-setupsync"
                 flex="1"
                 align="center"
                 class="PanelUI-remotetabs-instruction-box"
                 observes="sync-setup-state">
-            <html:img class="fxaSyncIllustration" src="chrome://browser/skin/fxa/sync-illustration.svg"/>
+            <image class="fxaSyncIllustration"/>
             <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.notsignedin.label;</label>
             <toolbarbutton class="PanelUI-remotetabs-prefs-button"
                            label="&appMenuRemoteTabs.signin.label;"
                            oncommand="gSync.openPrefs('synced-tabs');"/>
           </vbox>
           <!-- When Sync needs re-authentication. This uses the exact same messaging
                as "Sync is not configured" but remains a separate box so we get
                the goodness of observing broadcasters to manage the hidden states -->
           <vbox id="PanelUI-remotetabs-reauthsync"
                 flex="1"
                 align="center"
                 class="PanelUI-remotetabs-instruction-box"
                 observes="sync-reauth-state">
-            <html:img class="fxaSyncIllustration" src="chrome://browser/skin/fxa/sync-illustration.svg"/>
+            <image class="fxaSyncIllustration"/>
             <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.notsignedin.label;</label>
             <toolbarbutton class="PanelUI-remotetabs-prefs-button"
                            label="&appMenuRemoteTabs.signin.label;"
                            oncommand="gSync.openPrefs('synced-tabs');"/>
           </vbox>
         </hbox>
       </vbox>
     </panelview>
@@ -329,16 +325,17 @@
 
 </panel>
 
 <panel id="widget-overflow"
        role="group"
        type="arrow"
        noautofocus="true"
        position="bottomcenter topright"
+       photon="true"
        hidden="true">
   <photonpanelmultiview mainViewId="widget-overflow-mainView">
     <panelview id="widget-overflow-mainView"
                context="toolbar-context-menu">
       <vbox class="panel-subview-body">
         <vbox id="widget-overflow-list" class="widget-overflow-list"
               overflowfortoolbar="nav-bar"/>
         <toolbarseparator id="widget-overflow-fixed-separator" hidden="true"/>
@@ -551,16 +548,20 @@
                        label="&newNavigatorCmd.label;"
                        key="key_newNavigator"
                        command="cmd_newNavigator"/>
         <toolbarbutton id="appMenu-private-window-button"
                        class="subviewbutton subviewbutton-iconic"
                        label="&newPrivateWindow.label;"
                        key="key_privatebrowsing"
                        command="Tools:PrivateBrowsing"/>
+        <toolbarbutton id="appMenuRestoreLastSession"
+                       label="&appMenuHistory.restoreSession.label;"
+                       class="subviewbutton subviewbutton-iconic"
+                       command="Browser:RestoreLastSession"/>
         <toolbarseparator/>
         <toolbaritem id="appMenu-zoom-controls" class="toolbaritem-combined-buttons">
           <label value="&fullZoom.label;"/>
           <toolbarbutton id="appMenu-zoomReduce-button"
                          class="subviewbutton subviewbutton-iconic"
                          command="cmd_fullZoomReduce"
                          closemenu="none"
                          tooltip="dynamic-shortcut-tooltip"/>
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -313,25 +313,25 @@ const PanelUI = {
    * by the user.
    *
    * @param aCustomizing (optional) set to true if this was called while entering
    *        customization mode. If that's the case, we trust that customization
    *        mode will handle calling beginBatchUpdate and endBatchUpdate.
    *
    * @return a Promise that resolves once the panel is ready to roll.
    */
-  ensureReady() {
-    if (this._readyPromise) {
-      return this._readyPromise;
+  async ensureReady() {
+    if (this._isReady) {
+      return;
     }
+
+    await window.delayedStartupPromise;
     this._ensureEventListenersAdded();
     this.panel.hidden = false;
-    this._readyPromise = Promise.resolve();
     this._isReady = true;
-    return this._readyPromise;
   },
 
   /**
    * Switch the panel to the main view if it's not already
    * in that view.
    */
   showMainView() {
     this._ensureEventListenersAdded();
--- a/browser/components/customizableui/test/browser_1087303_button_preferences.js
+++ b/browser/components/customizableui/test/browser_1087303_button_preferences.js
@@ -39,17 +39,18 @@ add_task(function asyncCleanup() {
 function waitForPageLoad(aTab) {
   return new Promise((resolve, reject) => {
 
     let timeoutId = setTimeout(() => {
       aTab.linkedBrowser.removeEventListener("load", onTabLoad, true);
       reject("Page didn't load within " + 20000 + "ms");
     }, 20000);
 
-    function onTabLoad(event) {
+    async function onTabLoad(event) {
       clearTimeout(timeoutId);
       aTab.linkedBrowser.removeEventListener("load", onTabLoad, true);
       info("Tab event received: load");
       resolve();
-   }
+    }
+
     aTab.linkedBrowser.addEventListener("load", onTabLoad, true, true);
   });
 }
--- a/browser/components/customizableui/test/browser_synced_tabs_menu.js
+++ b/browser/components/customizableui/test/browser_synced_tabs_menu.js
@@ -87,17 +87,17 @@ async function openPrefsFromMenuPanel(ex
   let subpanel = document.getElementById(expectedPanelId)
   ok(!subpanel.hidden, "sync setup element is visible");
 
   // Find and click the "setup" button.
   let setupButton = subpanel.querySelector(".PanelUI-remotetabs-prefs-button");
   setupButton.click();
 
   await new Promise(resolve => {
-    let handler = (e) => {
+    let handler = async(e) => {
       if (e.originalTarget != gBrowser.selectedBrowser.contentDocument ||
           e.target.location.href == "about:blank") {
         info("Skipping spurious 'load' event for " + e.target.location.href);
         return;
       }
       gBrowser.selectedBrowser.removeEventListener("load", handler, true);
       resolve();
     }
--- a/browser/components/extensions/ext-bookmarks.js
+++ b/browser/components/extensions/ext-bookmarks.js
@@ -3,52 +3,82 @@
 "use strict";
 
 // The ext-* files are imported into the same scopes.
 /* import-globals-from ext-browserAction.js */
 
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 
+const {
+  TYPE_BOOKMARK,
+  TYPE_FOLDER,
+  TYPE_SEPARATOR,
+} = PlacesUtils.bookmarks;
+
+const BOOKMARKS_TYPES_TO_API_TYPES_MAP = new Map([
+  [TYPE_BOOKMARK, "bookmark"],
+  [TYPE_FOLDER, "folder"],
+  [TYPE_SEPARATOR, "separator"],
+]);
+
+const BOOKMARK_SEPERATOR_URL = "data:";
+
+XPCOMUtils.defineLazyGetter(this, "API_TYPES_TO_BOOKMARKS_TYPES_MAP", () => {
+  let theMap = new Map();
+
+  for (let [code, name] of BOOKMARKS_TYPES_TO_API_TYPES_MAP) {
+    theMap.set(name, code);
+  }
+  return theMap;
+});
+
 let listenerCount = 0;
 
+function getUrl(type, url) {
+  switch (type) {
+    case TYPE_BOOKMARK:
+      return url;
+    case TYPE_SEPARATOR:
+      return BOOKMARK_SEPERATOR_URL;
+    default:
+      return undefined;
+  }
+}
+
 const getTree = (rootGuid, onlyChildren) => {
   function convert(node, parent) {
     let treenode = {
       id: node.guid,
       title: node.title || "",
       index: node.index,
       dateAdded: node.dateAdded / 1000,
+      type: BOOKMARKS_TYPES_TO_API_TYPES_MAP.get(node.typeCode),
+      url: getUrl(node.typeCode, node.uri),
     };
 
     if (parent && node.guid != PlacesUtils.bookmarks.rootGuid) {
       treenode.parentId = parent.guid;
     }
 
-    if (node.type == PlacesUtils.TYPE_X_MOZ_PLACE) {
-      // This isn't quite correct. Recently Bookmarked ends up here ...
-      treenode.url = node.uri;
-    } else {
+    if (node.typeCode == TYPE_FOLDER) {
       treenode.dateGroupModified = node.lastModified / 1000;
 
       if (!onlyChildren) {
         treenode.children = node.children
           ? node.children.map(child => convert(child, node))
           : [];
       }
     }
 
     return treenode;
   }
 
   return PlacesUtils.promiseBookmarksTree(rootGuid, {
     excludeItemsCallback: item => {
-      if (item.type == PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR) {
-        return true;
-      }
       return item.annos &&
              item.annos.find(a => a.name == PlacesUtils.EXCLUDE_FROM_BACKUP_ANNO);
     },
   }).then(root => {
     if (onlyChildren) {
       let children = root.children || [];
       return children.map(child => convert(child, root));
     }
@@ -60,25 +90,25 @@ const getTree = (rootGuid, onlyChildren)
 };
 
 const convertBookmarks = result => {
   let node = {
     id: result.guid,
     title: result.title || "",
     index: result.index,
     dateAdded: result.dateAdded.getTime(),
+    type: BOOKMARKS_TYPES_TO_API_TYPES_MAP.get(result.type),
+    url: getUrl(result.type, result.url && result.url.href),
   };
 
   if (result.guid != PlacesUtils.bookmarks.rootGuid) {
     node.parentId = result.parentGuid;
   }
 
-  if (result.type == PlacesUtils.bookmarks.TYPE_BOOKMARK) {
-    node.url = result.url.href; // Output is always URL object.
-  } else {
+  if (result.type == TYPE_FOLDER) {
     node.dateGroupModified = result.lastModified.getTime();
   }
 
   return node;
 };
 
 let observer = new class extends EventEmitter {
   constructor() {
@@ -87,76 +117,58 @@ let observer = new class extends EventEm
     this.skipTags = true;
     this.skipDescendantsOnItemRemoval = true;
   }
 
   onBeginUpdateBatch() {}
   onEndUpdateBatch() {}
 
   onItemAdded(id, parentId, index, itemType, uri, title, dateAdded, guid, parentGuid, source) {
-    if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
-      return;
-    }
-
     let bookmark = {
       id: guid,
       parentId: parentGuid,
       index,
       title,
       dateAdded: dateAdded / 1000,
+      type: BOOKMARKS_TYPES_TO_API_TYPES_MAP.get(itemType),
+      url: getUrl(itemType, uri && uri.spec),
     };
 
-    if (itemType == PlacesUtils.bookmarks.TYPE_BOOKMARK) {
-      bookmark.url = uri.spec;
-    } else {
+    if (itemType == TYPE_FOLDER) {
       bookmark.dateGroupModified = bookmark.dateAdded;
     }
 
     this.emit("created", bookmark);
   }
 
   onItemVisited() {}
 
   onItemMoved(id, oldParentId, oldIndex, newParentId, newIndex, itemType, guid, oldParentGuid, newParentGuid, source) {
-    if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
-      return;
-    }
-
     let info = {
       parentId: newParentGuid,
       index: newIndex,
       oldParentId: oldParentGuid,
       oldIndex,
     };
     this.emit("moved", {guid, info});
   }
 
   onItemRemoved(id, parentId, index, itemType, uri, guid, parentGuid, source) {
-    if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
-      return;
-    }
-
     let node = {
       id: guid,
       parentId: parentGuid,
       index,
+      type: BOOKMARKS_TYPES_TO_API_TYPES_MAP.get(itemType),
+      url: getUrl(itemType, uri && uri.spec),
     };
 
-    if (itemType == PlacesUtils.bookmarks.TYPE_BOOKMARK) {
-      node.url = uri.spec;
-    }
-
     this.emit("removed", {guid, info: {parentId: parentGuid, index, node}});
   }
 
   onItemChanged(id, prop, isAnno, val, lastMod, itemType, parentId, guid, parentGuid, oldVal, source) {
-    if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
-      return;
-    }
-
     let info = {};
     if (prop == "title") {
       info.title = val;
     } else if (prop == "uri") {
       info.url = val;
     } else {
       // Not defined yet.
       return;
@@ -223,22 +235,28 @@ this.bookmarks = class extends Extension
           return PlacesUtils.bookmarks.getRecent(numberOfItems).then(result => result.map(convertBookmarks));
         },
 
         create: function(bookmark) {
           let info = {
             title: bookmark.title || "",
           };
 
-          // If url is NULL or missing, it will be a folder.
-          if (bookmark.url !== null) {
-            info.type = PlacesUtils.bookmarks.TYPE_BOOKMARK;
+          info.type = API_TYPES_TO_BOOKMARKS_TYPES_MAP.get(bookmark.type);
+          if (!info.type) {
+            // If url is NULL or missing, it will be a folder.
+            if (bookmark.url !== null) {
+              info.type = TYPE_BOOKMARK;
+            } else {
+              info.type = TYPE_FOLDER;
+            }
+          }
+
+          if (info.type === TYPE_BOOKMARK) {
             info.url = bookmark.url || "";
-          } else {
-            info.type = PlacesUtils.bookmarks.TYPE_FOLDER;
           }
 
           if (bookmark.index !== null) {
             info.index = bookmark.index;
           }
 
           if (bookmark.parentId !== null) {
             info.parentGuid = bookmark.parentId;
--- a/browser/components/extensions/ext-browser.js
+++ b/browser/components/extensions/ext-browser.js
@@ -564,16 +564,20 @@ class Tab extends TabBase {
   get audible() {
     return this.nativeTab.soundPlaying;
   }
 
   get browser() {
     return this.nativeTab.linkedBrowser;
   }
 
+  get discarded() {
+    return !this.nativeTab.linkedPanel;
+  }
+
   get frameLoader() {
     // If we don't have a frameLoader yet, just return a dummy with no width and
     // height.
     return super.frameLoader || {lazyWidth: 0, lazyHeight: 0};
   }
 
   get cookieStoreId() {
     return getCookieStoreIdForTab(this, this.nativeTab);
@@ -714,17 +718,17 @@ class Window extends WindowBase {
 
     if (options.width !== null || options.height !== null) {
       let width = options.width !== null ? options.width : window.outerWidth;
       let height = options.height !== null ? options.height : window.outerHeight;
       window.resizeTo(width, height);
     }
   }
 
-  get title() {
+  get _title() {
     return this.window.document.title;
   }
 
   setTitlePreface(titlePreface) {
     this.window.document.documentElement.setAttribute("titlepreface", titlePreface);
   }
 
   get focused() {
@@ -819,16 +823,22 @@ class Window extends WindowBase {
   * getTabs() {
     let {tabManager} = this.extension;
 
     for (let nativeTab of this.window.gBrowser.tabs) {
       yield tabManager.getWrapper(nativeTab);
     }
   }
 
+  get activeTab() {
+    let {tabManager} = this.extension;
+
+    return tabManager.getWrapper(this.window.gBrowser.selectedTab);
+  }
+
   /**
    * Converts session store data to an object compatible with the return value
    * of the convert() method, representing that data.
    *
    * @param {Extension} extension
    *        The extension for which to convert the data.
    * @param {Object} windowData
    *        Session store data for a closed window, as returned by
--- a/browser/components/extensions/ext-sidebarAction.js
+++ b/browser/components/extensions/ext-sidebarAction.js
@@ -60,19 +60,16 @@ this.sidebarAction = class extends Exten
       icon: IconDetails.normalize({path: options.default_icon}, extension),
       panel: options.default_panel || "",
     };
 
     this.tabContext = new TabContext(tab => Object.create(this.defaults),
                                      extension);
 
     // We need to ensure our elements are available before session restore.
-    for (let window of windowTracker.browserWindows()) {
-      this.createMenuItem(window, this.defaults);
-    }
     this.windowOpenListener = (window) => {
       this.createMenuItem(window, this.defaults);
     };
     windowTracker.addOpenListener(this.windowOpenListener);
 
     this.updateHeader = (event) => {
       let window = event.target.ownerGlobal;
       let details = this.tabContext.get(window.gBrowser.selectedTab);
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -257,16 +257,19 @@ this.tabs = class extends ExtensionAPI {
               }
               if (changed.includes("label")) {
                 needed.push("title");
               }
             } else if (event.type == "TabPinned") {
               needed.push("pinned");
             } else if (event.type == "TabUnpinned") {
               needed.push("pinned");
+            } else if (event.type == "TabBrowserInserted" &&
+                       !event.detail.insertedOnTabCreation) {
+              needed.push("discarded");
             }
 
             let tab = tabManager.getWrapper(event.originalTarget);
             let changeInfo = {};
             for (let prop of needed) {
               changeInfo[prop] = tab[prop];
             }
 
@@ -285,22 +288,24 @@ this.tabs = class extends ExtensionAPI {
               fireForTab(tabManager.wrapTab(tabElem), changed);
             }
           };
 
           windowTracker.addListener("status", statusListener);
           windowTracker.addListener("TabAttrModified", listener);
           windowTracker.addListener("TabPinned", listener);
           windowTracker.addListener("TabUnpinned", listener);
+          windowTracker.addListener("TabBrowserInserted", listener);
 
           return () => {
             windowTracker.removeListener("status", statusListener);
             windowTracker.removeListener("TabAttrModified", listener);
             windowTracker.removeListener("TabPinned", listener);
             windowTracker.removeListener("TabUnpinned", listener);
+            windowTracker.removeListener("TabBrowserInserted", listener);
           };
         }).api(),
 
         create(createProperties) {
           return new Promise((resolve, reject) => {
             let window = createProperties.windowId !== null ?
               windowTracker.getWindow(createProperties.windowId, context) :
               windowTracker.topWindow;
@@ -440,17 +445,17 @@ this.tabs = class extends ExtensionAPI {
             if (updateProperties.active) {
               tabbrowser.selectedTab = nativeTab;
             } else {
               // Not sure what to do here? Which tab should we select?
             }
           }
           if (updateProperties.muted !== null) {
             if (nativeTab.muted != updateProperties.muted) {
-              nativeTab.toggleMuteAudio(extension.uuid);
+              nativeTab.toggleMuteAudio(extension.id);
             }
           }
           if (updateProperties.pinned !== null) {
             if (updateProperties.pinned) {
               tabbrowser.pinTab(nativeTab);
             } else {
               tabbrowser.unpinTab(nativeTab);
             }
--- a/browser/components/extensions/schemas/bookmarks.json
+++ b/browser/components/extensions/schemas/bookmarks.json
@@ -24,16 +24,22 @@
     "types": [
       {
         "id": "BookmarkTreeNodeUnmodifiable",
         "type": "string",
         "enum": ["managed"],
         "description": "Indicates the reason why this node is unmodifiable. The <var>managed</var> value indicates that this node was configured by the system administrator or by the custodian of a supervised user. Omitted if the node can be modified by the user and the extension (default)."
       },
       {
+        "id": "BookmarkTreeNodeType",
+        "type": "string",
+        "enum": ["bookmark", "folder", "separator"],
+        "description": "Indicates the type of a BookmarkTreeNode, which can be one of bookmark, folder or separator."
+      },
+      {
         "id": "BookmarkTreeNode",
         "type": "object",
         "description": "A node (either a bookmark or a folder) in the bookmark tree.  Child nodes are ordered within their parent folder.",
         "properties": {
           "id": {
             "type": "string",
             "description": "The unique identifier for the node. IDs are unique within the current profile, and they remain valid even after the browser is restarted."
           },
@@ -66,16 +72,21 @@
             "optional": true,
             "description": "When the contents of this folder last changed, in milliseconds since the epoch."
           },
           "unmodifiable": {
             "$ref": "BookmarkTreeNodeUnmodifiable",
             "optional": true,
             "description": "Indicates the reason why this node is unmodifiable. The <var>managed</var> value indicates that this node was configured by the system administrator or by the custodian of a supervised user. Omitted if the node can be modified by the user and the extension (default)."
           },
+          "type": {
+            "$ref": "BookmarkTreeNodeType",
+            "optional": true,
+            "description": "Indicates the type of the BookmarkTreeNode, which can be one of bookmark, folder or separator."
+          },
           "children": {
             "type": "array",
             "optional": true,
             "items": { "$ref": "BookmarkTreeNode" },
             "description": "An ordered list of children of this node."
           }
         }
       },
@@ -96,16 +107,21 @@
           },
           "title": {
             "type": "string",
             "optional": true
           },
           "url": {
             "type": "string",
             "optional": true
+          },
+          "type": {
+            "$ref": "BookmarkTreeNodeType",
+            "optional": true,
+            "description": "Indicates the type of BookmarkTreeNode to create, which can be one of bookmark, folder or separator."
           }
         }
       }
     ],
     "functions": [
       {
         "name": "get",
         "type": "function",
--- a/browser/components/extensions/schemas/tabs.json
+++ b/browser/components/extensions/schemas/tabs.json
@@ -66,16 +66,17 @@
           "pinned": {"type": "boolean", "description": "Whether the tab is pinned."},
           "lastAccessed": {"type": "integer", "optional": true, "description": "The last time the tab was accessed as the number of milliseconds since epoch."},
           "audible": {"type": "boolean", "optional": true, "description": "Whether the tab has produced sound over the past couple of seconds (but it might not be heard if also muted). Equivalent to whether the speaker audio indicator is showing."},
           "mutedInfo": {"$ref": "MutedInfo", "optional": true, "description": "Current tab muted state and the reason for the last state change."},
           "url": {"type": "string", "optional": true, "permissions": ["tabs"], "description": "The URL the tab is displaying. This property is only present if the extension's manifest includes the <code>\"tabs\"</code> permission."},
           "title": {"type": "string", "optional": true, "permissions": ["tabs"], "description": "The title of the tab. This property is only present if the extension's manifest includes the <code>\"tabs\"</code> permission."},
           "favIconUrl": {"type": "string", "optional": true, "permissions": ["tabs"], "description": "The URL of the tab's favicon. This property is only present if the extension's manifest includes the <code>\"tabs\"</code> permission. It may also be an empty string if the tab is loading."},
           "status": {"type": "string", "optional": true, "description": "Either <em>loading</em> or <em>complete</em>."},
+          "discarded": {"type": "boolean", "optional": true, "description": "True while the tab is not loaded with content."},
           "incognito": {"type": "boolean", "description": "Whether the tab is in an incognito window."},
           "width": {"type": "integer", "optional": true, "description": "The width of the tab in pixels."},
           "height": {"type": "integer", "optional": true, "description": "The height of the tab in pixels."},
           "sessionId": {"type": "string", "optional": true, "description": "The session ID used to uniquely identify a Tab obtained from the $(ref:sessions) API."},
           "cookieStoreId": {"type": "string", "optional": true, "description": "The CookieStoreId used for the tab."}
         }
       },
       {
@@ -584,16 +585,21 @@
                 "optional": true,
                 "description": "Whether the tabs are in the last focused window."
               },
               "status": {
                 "$ref": "TabStatus",
                 "optional": true,
                 "description": "Whether the tabs have completed loading."
               },
+              "discarded": {
+                "type": "boolean",
+                "optional": true,
+                "description": "True while the tabs are not loaded with content."
+              },
               "title": {
                 "type": "string",
                 "optional": true,
                 "description": "Match page titles against a pattern."
               },
               "url": {
                 "choices": [
                   {"type": "string"},
@@ -1190,16 +1196,21 @@
             "name": "changeInfo",
             "description": "Lists the changes to the state of the tab that was updated.",
             "properties": {
               "status": {
                 "type": "string",
                 "optional": true,
                 "description": "The status of the tab. Can be either <em>loading</em> or <em>complete</em>."
               },
+              "discarded": {
+                "type": "boolean",
+                "optional": true,
+                "description": "True while the tab is not loaded with content."
+              },
               "url": {
                 "type": "string",
                 "optional": true,
                 "description": "The tab's URL if it has changed."
               },
               "pinned": {
                 "type": "boolean",
                 "optional": true,
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -36,16 +36,17 @@ support-files =
 [browser_ext_browserAction_context.js]
 [browser_ext_browserAction_contextMenu.js]
 # bug 1369197
 skip-if = os == 'linux'
 [browser_ext_browserAction_disabled.js]
 [browser_ext_browserAction_pageAction_icon.js]
 [browser_ext_browserAction_pageAction_icon_permissions.js]
 [browser_ext_browserAction_popup.js]
+skip-if = debug && (os == 'linux' && bits == 32) # Bug 1313372
 [browser_ext_browserAction_popup_preload.js]
 skip-if = (os == 'win' && !debug) # bug 1352668
 [browser_ext_browserAction_popup_resize.js]
 [browser_ext_browserAction_simple.js]
 [browser_ext_browserAction_telemetry.js]
 [browser_ext_browserAction_theme_icons.js]
 [browser_ext_browsingData_formData.js]
 [browser_ext_browsingData_history.js]
@@ -121,16 +122,17 @@ skip-if = debug || asan # Bug 1354681
 [browser_ext_sidebarAction_windows.js]
 [browser_ext_simple.js]
 [browser_ext_tab_runtimeConnect.js]
 [browser_ext_tabs_audio.js]
 [browser_ext_tabs_captureVisibleTab.js]
 [browser_ext_tabs_create.js]
 [browser_ext_tabs_create_invalid_url.js]
 [browser_ext_tabs_detectLanguage.js]
+[browser_ext_tabs_discarded.js]
 [browser_ext_tabs_duplicate.js]
 [browser_ext_tabs_events.js]
 [browser_ext_tabs_executeScript.js]
 [browser_ext_tabs_executeScript_good.js]
 [browser_ext_tabs_executeScript_bad.js]
 [browser_ext_tabs_executeScript_multiple.js]
 [browser_ext_tabs_executeScript_no_create.js]
 [browser_ext_tabs_executeScript_runAt.js]
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_popup_resize.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_popup_resize.js
@@ -247,17 +247,19 @@ async function testPopupSize(standardsMo
 
   dims = await alterContent(browser, setClass, "huge");
   win = dims.window;
 
   ok(getHeight() > height, `Browser height should increase (${getHeight()} > ${height})`);
 
   is(win.innerWidth, innerWidth, "Window width should not change");
   ok(win.innerHeight > innerHeight, `Window height should increase (${win.innerHeight} > ${innerHeight})`);
-  ok(win.innerHeight < screen.height, `Window height be less than the screen height (${win.innerHeight} < ${screen.height})`);
+  // Commented out check for the window height here which mysteriously breaks
+  // on infra but not locally. bug 1396843 covers re-enabling this.
+  // ok(win.innerHeight < screen.height, `Window height be less than the screen height (${win.innerHeight} < ${screen.height})`);
   ok(win.scrollMaxY > 0, `Document should be vertically scrollable (${win.scrollMaxY} > 0)`);
 
   checkPanelPosition();
 
 
   info("Restore original styling. Expect original dimensions.");
   dims = await alterContent(browser, setClass, "");
   win = dims.window;
--- a/browser/components/extensions/test/browser/browser_ext_identity_indication.js
+++ b/browser/components/extensions/test/browser/browser_ext_identity_indication.js
@@ -54,8 +54,44 @@ add_task(async function testIdentityIndi
   await BrowserTestUtils.withNewTab({gBrowser, url}, async function() {
     confirmExtensionPage();
   });
 
   await extension.unload();
 
   confirmDefaults();
 });
+
+add_task(async function testIdentityIndicationNewTab() {
+  let extension = ExtensionTestUtils.loadExtension({
+    background() {
+      browser.test.sendMessage("url", browser.extension.getURL("newtab.html"));
+    },
+    manifest: {
+      name: "Test Extension",
+      applications: {
+        gecko: {
+          id: "@newtab",
+        },
+      },
+      chrome_url_overrides: {
+        newtab: "newtab.html",
+      },
+    },
+    files: {
+      "newtab.html": "<h1>New tab!</h1>",
+    },
+    useAddonManager: "temporary",
+  });
+
+  await extension.startup();
+
+  confirmDefaults();
+
+  let url = await extension.awaitMessage("url");
+  await BrowserTestUtils.withNewTab({gBrowser, url}, async function() {
+    confirmExtensionPage();
+  });
+
+  await extension.unload();
+
+  confirmDefaults();
+});
--- a/browser/components/extensions/test/browser/browser_ext_tabs_audio.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_audio.js
@@ -110,31 +110,29 @@ add_task(async function() {
       }
       for (let obj of [muted.changeInfo, muted.tab]) {
         browser.test.assertEq(true, obj.mutedInfo.muted, "Tab is muted");
       }
 
       for (let obj of [nonMuted.changeInfo, nonMuted.tab, muted.changeInfo, muted.tab]) {
         browser.test.assertEq("extension", obj.mutedInfo.reason, "Mute state changed by extension");
 
-        // FIXME: browser.runtime.id is currently broken.
-        browser.test.assertEq(browser.i18n.getMessage("@@extension_id"),
+        browser.test.assertEq(browser.runtime.id,
                               obj.mutedInfo.extensionId,
                               "Mute state changed by extension");
       }
 
       browser.test.log("Test that mutedInfo is preserved by sessionstore");
       let tab = await changeTab(tabIds[1], "duplicate").then(browser.tabs.get);
 
       browser.test.assertEq(true, tab.mutedInfo.muted, "Tab is muted");
 
       browser.test.assertEq("extension", tab.mutedInfo.reason, "Mute state changed by extension");
 
-      // FIXME: browser.runtime.id is currently broken.
-      browser.test.assertEq(browser.i18n.getMessage("@@extension_id"),
+      browser.test.assertEq(browser.runtime.id,
                             tab.mutedInfo.extensionId,
                             "Mute state changed by extension");
 
       browser.test.log("Unmute externally, and check results");
       [nonMuted] = await Promise.all([
         promiseUpdated(tabIds[1], "mutedInfo"),
         changeTab(tabIds[1], "muted", false),
         browser.tabs.remove(tab.id),
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_discarded.js
@@ -0,0 +1,66 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+/* global gBrowser SessionStore */
+"use strict";
+
+let lazyTabState = {entries: [{url: "http://example.com/", title: "Example Domain"}]};
+
+add_task(async function test_discarded() {
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "permissions": ["tabs"],
+    },
+
+    background: async function() {
+      let onCreatedTabData = [];
+      let discardedEventData = [];
+
+      async function finishTest() {
+        browser.test.assertEq(0, discardedEventData.length, "number of discarded events fired");
+
+        onCreatedTabData.sort((data1, data2) => data1.index - data2.index);
+        browser.test.assertEq(false, onCreatedTabData[0].discarded, "non-lazy tab onCreated discard property");
+        browser.test.assertEq(true, onCreatedTabData[1].discarded, "lazy tab onCreated discard property");
+
+        let tabs = await browser.tabs.query({currentWindow: true});
+        tabs.sort((tab1, tab2) => tab1.index - tab2.index);
+
+        browser.test.assertEq(false, tabs[1].discarded, "non-lazy tab query discard property");
+        browser.test.assertEq(true, tabs[2].discarded, "lazy tab query discard property");
+
+        let updatedTab = await browser.tabs.update(tabs[2].id, {active: true});
+        browser.test.assertEq(false, updatedTab.discarded, "lazy to non-lazy update discard property");
+        browser.test.assertEq(false, discardedEventData[0], "lazy to non-lazy onUpdated discard property");
+
+        browser.test.notifyPass("test-finished");
+      }
+
+      browser.tabs.onUpdated.addListener(function(tabId, updatedInfo) {
+        if ("discarded" in updatedInfo) {
+          discardedEventData.push(updatedInfo.discarded);
+        }
+      });
+
+      browser.tabs.onCreated.addListener(function(tab) {
+        onCreatedTabData.push({discarded: tab.discarded, index: tab.index});
+        if (onCreatedTabData.length == 2) {
+          finishTest();
+        }
+      });
+    },
+  });
+
+  await extension.startup();
+
+  let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com");
+
+  let tab2 = BrowserTestUtils.addTab(gBrowser, "about:blank", {createLazyBrowser: true});
+  SessionStore.setTabState(tab2, JSON.stringify(lazyTabState));
+
+  await extension.awaitFinish("test-finished");
+  await extension.unload();
+
+  await BrowserTestUtils.removeTab(tab1);
+  await BrowserTestUtils.removeTab(tab2);
+});
+
--- a/browser/components/extensions/test/browser/browser_ext_windows.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows.js
@@ -59,16 +59,19 @@ add_task(async function testWindowTitle(
                               "Window has the expected title text after update.");
         browser.test.sendMessage("updated", win);
       }
     });
   }
 
   let extension = ExtensionTestUtils.loadExtension({
     background,
+    manifest: {
+      permissions: ["tabs"],
+    },
   });
 
   await extension.startup();
   let {Management: {global: {windowTracker}}} = Cu.import("resource://gre/modules/Extension.jsm", {});
 
   async function createApiWin(options) {
     let promiseLoaded = BrowserTestUtils.waitForNewWindow(true, START_URL);
     extension.sendMessage("create", options);
@@ -134,16 +137,67 @@ add_task(async function testWindowTitle(
       text: NEW_TITLE,
     },
   };
   await updateWindow({titlePreface: PREFACE2}, apiWin, expected);
 
   await extension.unload();
 });
 
+// Test that the window title is only available with the correct tab
+// permissions.
+add_task(async function testWindowTitlePermissions() {
+  let tab = await BrowserTestUtils.openNewForegroundTab(window.gBrowser, "http://example.com/");
+
+  let extension = ExtensionTestUtils.loadExtension({
+    async background() {
+      function awaitMessage(name) {
+        return new Promise(resolve => {
+          browser.test.onMessage.addListener(function listener(...msg) {
+            if (msg[0] === name) {
+              browser.test.onMessage.removeListener(listener);
+              resolve(msg[1]);
+            }
+          });
+        });
+      }
+
+      let window = await browser.windows.getCurrent();
+
+      browser.test.assertEq(undefined, window.title,
+                            "Window title should be null without tab permission");
+
+      browser.test.sendMessage("grant-activeTab");
+      let expectedTitle = await awaitMessage("title");
+
+      window = await browser.windows.getCurrent();
+      browser.test.assertEq(expectedTitle, window.title,
+                            "Window should have the expected title with tab permission granted");
+
+      await browser.test.notifyPass("window-title-permissions");
+    },
+    manifest: {
+      permissions: ["activeTab"],
+      browser_action: {},
+    },
+  });
+
+  await extension.startup();
+
+  await extension.awaitMessage("grant-activeTab");
+  await clickBrowserAction(extension);
+  extension.sendMessage("title", document.title);
+
+  await extension.awaitFinish("window-title-permissions");
+
+  await extension.unload();
+
+  await BrowserTestUtils.removeTab(tab);
+});
+
 add_task(async function testInvalidWindowId() {
   let extension = ExtensionTestUtils.loadExtension({
     async background() {
       await browser.test.assertRejects(
         // Assuming that this windowId does not exist.
         browser.windows.get(123456789),
         /Invalid window/,
         "Should receive invalid window");
--- a/browser/components/extensions/test/xpcshell/test_ext_bookmarks.js
+++ b/browser/components/extensions/test/xpcshell/test_ext_bookmarks.js
@@ -6,16 +6,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/PlacesUtils.jsm");
 
 add_task(async function test_bookmarks() {
   function background() {
     let unsortedId, ourId;
     let initialBookmarkCount = 0;
     let createdBookmarks = new Set();
     let createdFolderId;
+    let createdSeparatorId;
     let collectedEvents = [];
     const nonExistentId = "000000000000";
     const bookmarkGuids = {
       menuGuid:    "menu________",
       toolbarGuid: "toolbar_____",
       unfiledGuid: "unfiled_____",
     };
 
@@ -23,42 +24,45 @@ add_task(async function test_bookmarks()
       browser.test.assertEq(ourId, bookmark.id, "Bookmark has the expected Id");
       browser.test.assertTrue("parentId" in bookmark, "Bookmark has a parentId");
       browser.test.assertEq(0, bookmark.index, "Bookmark has the expected index"); // We assume there are no other bookmarks.
       browser.test.assertEq("http://example.org/", bookmark.url, "Bookmark has the expected url");
       browser.test.assertEq("test bookmark", bookmark.title, "Bookmark has the expected title");
       browser.test.assertTrue("dateAdded" in bookmark, "Bookmark has a dateAdded");
       browser.test.assertFalse("dateGroupModified" in bookmark, "Bookmark does not have a dateGroupModified");
       browser.test.assertFalse("unmodifiable" in bookmark, "Bookmark is not unmodifiable");
+      browser.test.assertEq("bookmark", bookmark.type, "Bookmark is of type bookmark");
     }
 
     function checkBookmark(expected, bookmark) {
       browser.test.assertEq(expected.url, bookmark.url, "Bookmark has the expected url");
       browser.test.assertEq(expected.title, bookmark.title, "Bookmark has the expected title");
       browser.test.assertEq(expected.index, bookmark.index, "Bookmark has expected index");
+      browser.test.assertEq("bookmark", bookmark.type, "Bookmark is of type bookmark");
       if ("parentId" in expected) {
         browser.test.assertEq(expected.parentId, bookmark.parentId, "Bookmark has the expected parentId");
       }
     }
 
     function expectedError() {
       browser.test.fail("Did not get expected error");
     }
 
-    function checkOnCreated(id, parentId, index, title, url, dateAdded) {
+    function checkOnCreated(id, parentId, index, title, url, dateAdded, type = "bookmark") {
       let createdData = collectedEvents.pop();
       browser.test.assertEq("onCreated", createdData.event, "onCreated was the last event received");
       browser.test.assertEq(id, createdData.id, "onCreated event received the expected id");
       let bookmark = createdData.bookmark;
       browser.test.assertEq(id, bookmark.id, "onCreated event received the expected bookmark id");
       browser.test.assertEq(parentId, bookmark.parentId, "onCreated event received the expected bookmark parentId");
       browser.test.assertEq(index, bookmark.index, "onCreated event received the expected bookmark index");
       browser.test.assertEq(title, bookmark.title, "onCreated event received the expected bookmark title");
       browser.test.assertEq(url, bookmark.url, "onCreated event received the expected bookmark url");
       browser.test.assertEq(dateAdded, bookmark.dateAdded, "onCreated event received the expected bookmark dateAdded");
+      browser.test.assertEq(type, bookmark.type, "onCreated event received the expected bookmark type");
     }
 
     function checkOnChanged(id, url, title) {
       // If both url and title are changed, then url is fired last.
       let changedData = collectedEvents.pop();
       browser.test.assertEq("onChanged", changedData.event, "onChanged was the last event received");
       browser.test.assertEq(id, changedData.id, "onChanged event received the expected id");
       browser.test.assertEq(url, changedData.info.url, "onChanged event received the expected url");
@@ -75,28 +79,29 @@ add_task(async function test_bookmarks()
       browser.test.assertEq(id, movedData.id, "onMoved event received the expected id");
       let info = movedData.info;
       browser.test.assertEq(parentId, info.parentId, "onMoved event received the expected parentId");
       browser.test.assertEq(oldParentId, info.oldParentId, "onMoved event received the expected oldParentId");
       browser.test.assertEq(index, info.index, "onMoved event received the expected index");
       browser.test.assertEq(oldIndex, info.oldIndex, "onMoved event received the expected oldIndex");
     }
 
-    function checkOnRemoved(id, parentId, index, url) {
+    function checkOnRemoved(id, parentId, index, url, type = "folder") {
       let removedData = collectedEvents.pop();
       browser.test.assertEq("onRemoved", removedData.event, "onRemoved was the last event received");
       browser.test.assertEq(id, removedData.id, "onRemoved event received the expected id");
       let info = removedData.info;
       browser.test.assertEq(parentId, removedData.info.parentId, "onRemoved event received the expected parentId");
       browser.test.assertEq(index, removedData.info.index, "onRemoved event received the expected index");
       let node = info.node;
       browser.test.assertEq(id, node.id, "onRemoved event received the expected node id");
       browser.test.assertEq(parentId, node.parentId, "onRemoved event received the expected node parentId");
       browser.test.assertEq(index, node.index, "onRemoved event received the expected node index");
       browser.test.assertEq(url, node.url, "onRemoved event received the expected node url");
+      browser.test.assertEq(type, node.type, "onRemoved event received the expected node type");
     }
 
     browser.bookmarks.onChanged.addListener((id, info) => {
       collectedEvents.push({event: "onChanged", id, info});
     });
 
     browser.bookmarks.onCreated.addListener((id, bookmark) => {
       collectedEvents.push({event: "onCreated", id, bookmark});
@@ -121,17 +126,17 @@ add_task(async function test_bookmarks()
           nonExistentIdError.message.includes("Bookmark not found"),
           "Expected error thrown when trying to get a bookmark using a non-existent Id"
         );
       });
     }).then(() => {
       return browser.bookmarks.search({});
     }).then(results => {
       initialBookmarkCount = results.length;
-      return browser.bookmarks.create({title: "test bookmark", url: "http://example.org"});
+      return browser.bookmarks.create({title: "test bookmark", url: "http://example.org", type: "bookmark"});
     }).then(result => {
       ourId = result.id;
       checkOurBookmark(result);
       browser.test.assertEq(1, collectedEvents.length, "1 expected event received");
       checkOnCreated(ourId, bookmarkGuids.unfiledGuid, 0, "test bookmark", "http://example.org/", result.dateAdded);
 
       return browser.bookmarks.get(ourId);
     }).then(results => {
@@ -142,21 +147,22 @@ add_task(async function test_bookmarks()
       return browser.bookmarks.get(unsortedId);
     }).then(results => {
       let folder = results[0];
       browser.test.assertEq(1, results.length, "1 bookmark was returned");
 
       browser.test.assertEq(unsortedId, folder.id, "Folder has the expected id");
       browser.test.assertTrue("parentId" in folder, "Folder has a parentId");
       browser.test.assertTrue("index" in folder, "Folder has an index");
-      browser.test.assertFalse("url" in folder, "Folder does not have a url");
+      browser.test.assertEq(undefined, folder.url, "Folder does not have a url");
       browser.test.assertEq("Other Bookmarks", folder.title, "Folder has the expected title");
       browser.test.assertTrue("dateAdded" in folder, "Folder has a dateAdded");
       browser.test.assertTrue("dateGroupModified" in folder, "Folder has a dateGroupModified");
       browser.test.assertFalse("unmodifiable" in folder, "Folder is not unmodifiable"); // TODO: Do we want to enable this?
+      browser.test.assertEq("folder", folder.type, "Folder has a type of folder");
 
       return browser.bookmarks.getChildren(unsortedId);
     }).then(results => {
       browser.test.assertEq(1, results.length, "The folder has one child");
       checkOurBookmark(results[0]);
 
       return browser.bookmarks.update(nonExistentId, {title: "new test title"}).then(expectedError, error => {
         browser.test.assertTrue(
@@ -165,16 +171,17 @@ add_task(async function test_bookmarks()
         );
 
         return browser.bookmarks.update(ourId, {title: "new test title", url: "http://example.com/"});
       });
     }).then(result => {
       browser.test.assertEq("new test title", result.title, "Updated bookmark has the expected title");
       browser.test.assertEq("http://example.com/", result.url, "Updated bookmark has the expected URL");
       browser.test.assertEq(ourId, result.id, "Updated bookmark has the expected id");
+      browser.test.assertEq("bookmark", result.type, "Updated bookmark has a type of bookmark");
 
       browser.test.assertEq(2, collectedEvents.length, "2 expected events received");
       checkOnChanged(ourId, "http://example.com/", "new test title");
 
       return Promise.resolve().then(() => {
         return browser.bookmarks.update(ourId, {url: "this is not a valid url"});
       }).then(expectedError, error => {
         browser.test.assertTrue(
@@ -186,16 +193,18 @@ add_task(async function test_bookmarks()
     }).then(results => {
       browser.test.assertEq(1, results.length, "getTree returns one result");
       let bookmark = results[0].children.find(bookmarkItem => bookmarkItem.id == unsortedId);
       browser.test.assertEq(
           "Other Bookmarks",
           bookmark.title,
           "Folder returned from getTree has the expected title"
       );
+      browser.test.assertEq("folder", bookmark.type,
+                            "Folder returned from getTree has the expected type");
 
       return browser.bookmarks.create({parentId: "invalid"}).then(expectedError, error => {
         browser.test.assertTrue(
           error.message.includes("Invalid bookmark"),
           "Expected error thrown when trying to create a bookmark with an invalid parentId"
         );
         browser.test.assertTrue(
             error.message.includes(`"parentGuid":"invalid"`),
@@ -203,17 +212,17 @@ add_task(async function test_bookmarks()
         );
       });
     }).then(() => {
       return browser.bookmarks.remove(ourId);
     }).then(result => {
       browser.test.assertEq(undefined, result, "Removing a bookmark returns undefined");
 
       browser.test.assertEq(1, collectedEvents.length, "1 expected events received");
-      checkOnRemoved(ourId, bookmarkGuids.unfiledGuid, 0, "http://example.com/");
+      checkOnRemoved(ourId, bookmarkGuids.unfiledGuid, 0, "http://example.com/", "bookmark");
 
       return browser.bookmarks.get(ourId).then(expectedError, error => {
         browser.test.assertTrue(
           error.message.includes("Bookmark not found"),
           "Expected error thrown when trying to get a removed bookmark"
         );
       });
     }).then(() => {
@@ -223,83 +232,91 @@ add_task(async function test_bookmarks()
           "Expected error thrown when trying removed a non-existent bookmark"
         );
       });
     }).then(() => {
       // test bookmarks.search
       return Promise.all([
         browser.bookmarks.create({title: "MØzillä", url: "http://møzîllä.örg/"}),
         browser.bookmarks.create({title: "Example", url: "http://example.org/"}),
-        browser.bookmarks.create({title: "Mozilla Folder"}),
+        browser.bookmarks.create({title: "Mozilla Folder", type: "folder"}),
         browser.bookmarks.create({title: "EFF", url: "http://eff.org/"}),
         browser.bookmarks.create({title: "Menu Item", url: "http://menu.org/", parentId: bookmarkGuids.menuGuid}),
         browser.bookmarks.create({title: "Toolbar Item", url: "http://toolbar.org/", parentId: bookmarkGuids.toolbarGuid}),
       ]);
     }).then(results => {
       browser.test.assertEq(6, collectedEvents.length, "6 expected events received");
       checkOnCreated(results[5].id, bookmarkGuids.toolbarGuid, 0, "Toolbar Item", "http://toolbar.org/", results[5].dateAdded);
       checkOnCreated(results[4].id, bookmarkGuids.menuGuid, 0, "Menu Item", "http://menu.org/", results[4].dateAdded);
       checkOnCreated(results[3].id, bookmarkGuids.unfiledGuid, 0, "EFF", "http://eff.org/", results[3].dateAdded);
-      checkOnCreated(results[2].id, bookmarkGuids.unfiledGuid, 0, "Mozilla Folder", undefined, results[2].dateAdded);
+      checkOnCreated(results[2].id, bookmarkGuids.unfiledGuid, 0, "Mozilla Folder", undefined, results[2].dateAdded, "folder");
       checkOnCreated(results[1].id, bookmarkGuids.unfiledGuid, 0, "Example", "http://example.org/", results[1].dateAdded);
       checkOnCreated(results[0].id, bookmarkGuids.unfiledGuid, 0, "MØzillä", "http://xn--mzll-ooa1dud.xn--rg-eka/", results[0].dateAdded);
 
       for (let result of results) {
         if (result.title !== "Mozilla Folder") {
           createdBookmarks.add(result.id);
         }
       }
       let folderResult = results[2];
       createdFolderId = folderResult.id;
       return Promise.all([
         browser.bookmarks.create({title: "Mozilla", url: "http://allizom.org/", parentId: createdFolderId}),
+        browser.bookmarks.create({parentId: createdFolderId, type: "separator"}),