Merge m-c to inbound. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 06 Jan 2016 09:50:26 -0500
changeset 278838 d004c480a38993b00b60239e03e1f45852df3c31
parent 278837 18fedb75f8b0cbd352d12181ff3dd9299479de3c (current diff)
parent 278739 1ec3a3ff68f2d1a54e6ed33e926c28fee286bdf1 (diff)
child 278839 1d17f829b46447ddc649294aa32d2684414fa1c6
push id29860
push usercbook@mozilla.com
push dateThu, 07 Jan 2016 10:51:20 +0000
treeherdermozilla-central@e0bcd16e1d4b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone46.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to inbound. a=merge
devtools/client/fontinspector/font-inspector.css
devtools/client/fontinspector/font-inspector.js
devtools/client/fontinspector/font-inspector.xhtml
devtools/client/fontinspector/moz.build
devtools/client/fontinspector/test/.eslintrc
devtools/client/fontinspector/test/OstrichLicense.txt
devtools/client/fontinspector/test/browser.ini
devtools/client/fontinspector/test/browser_fontinspector.html
devtools/client/fontinspector/test/browser_fontinspector.js
devtools/client/fontinspector/test/browser_fontinspector_edit-previews-show-all.js
devtools/client/fontinspector/test/browser_fontinspector_edit-previews.js
devtools/client/fontinspector/test/browser_fontinspector_theme-change.js
devtools/client/fontinspector/test/head.js
devtools/client/fontinspector/test/ostrich-black.ttf
devtools/client/fontinspector/test/ostrich-regular.ttf
devtools/client/fontinspector/test/test_iframe.html
devtools/client/layoutview/moz.build
devtools/client/layoutview/test/.eslintrc
devtools/client/layoutview/test/browser.ini
devtools/client/layoutview/test/browser_layoutview.js
devtools/client/layoutview/test/browser_layoutview_editablemodel.js
devtools/client/layoutview/test/browser_layoutview_editablemodel_allproperties.js
devtools/client/layoutview/test/browser_layoutview_editablemodel_border.js
devtools/client/layoutview/test/browser_layoutview_editablemodel_stylerules.js
devtools/client/layoutview/test/browser_layoutview_guides.js
devtools/client/layoutview/test/browser_layoutview_rotate-labels-on-sides.js
devtools/client/layoutview/test/browser_layoutview_tooltips.js
devtools/client/layoutview/test/browser_layoutview_update-after-navigation.js
devtools/client/layoutview/test/browser_layoutview_update-after-reload.js
devtools/client/layoutview/test/browser_layoutview_update-in-iframes.js
devtools/client/layoutview/test/doc_layoutview_iframe1.html
devtools/client/layoutview/test/doc_layoutview_iframe2.html
devtools/client/layoutview/test/head.js
devtools/client/layoutview/view.js
devtools/client/layoutview/view.xhtml
devtools/client/styleinspector/computed-view.js
devtools/client/styleinspector/computedview.xhtml
devtools/client/styleinspector/cssruleview.xhtml
devtools/client/styleinspector/rule-view.js
devtools/client/styleinspector/ruleview.css
devtools/client/styleinspector/test/browser_computedview_browser-styles.js
devtools/client/styleinspector/test/browser_computedview_cycle_color.js
devtools/client/styleinspector/test/browser_computedview_getNodeInfo.js
devtools/client/styleinspector/test/browser_computedview_keybindings_01.js
devtools/client/styleinspector/test/browser_computedview_keybindings_02.js
devtools/client/styleinspector/test/browser_computedview_matched-selectors-toggle.js
devtools/client/styleinspector/test/browser_computedview_matched-selectors_01.js
devtools/client/styleinspector/test/browser_computedview_matched-selectors_02.js
devtools/client/styleinspector/test/browser_computedview_media-queries.js
devtools/client/styleinspector/test/browser_computedview_no-results-placeholder.js
devtools/client/styleinspector/test/browser_computedview_original-source-link.js
devtools/client/styleinspector/test/browser_computedview_pseudo-element_01.js
devtools/client/styleinspector/test/browser_computedview_refresh-on-style-change_01.js
devtools/client/styleinspector/test/browser_computedview_search-filter.js
devtools/client/styleinspector/test/browser_computedview_search-filter_clear.js
devtools/client/styleinspector/test/browser_computedview_search-filter_context-menu.js
devtools/client/styleinspector/test/browser_computedview_search-filter_escape-keypress.js
devtools/client/styleinspector/test/browser_computedview_select-and-copy-styles.js
devtools/client/styleinspector/test/browser_computedview_style-editor-link.js
devtools/client/styleinspector/test/browser_ruleview_add-property-and-reselect.js
devtools/client/styleinspector/test/browser_ruleview_add-property-cancel_01.js
devtools/client/styleinspector/test/browser_ruleview_add-property-cancel_02.js
devtools/client/styleinspector/test/browser_ruleview_add-property-cancel_03.js
devtools/client/styleinspector/test/browser_ruleview_add-property-svg.js
devtools/client/styleinspector/test/browser_ruleview_add-property_01.js
devtools/client/styleinspector/test/browser_ruleview_add-property_02.js
devtools/client/styleinspector/test/browser_ruleview_add-rule_01.js
devtools/client/styleinspector/test/browser_ruleview_add-rule_02.js
devtools/client/styleinspector/test/browser_ruleview_add-rule_03.js
devtools/client/styleinspector/test/browser_ruleview_add-rule_04.js
devtools/client/styleinspector/test/browser_ruleview_add-rule_pseudo_class.js
devtools/client/styleinspector/test/browser_ruleview_authored.js
devtools/client/styleinspector/test/browser_ruleview_colorUnit.js
devtools/client/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_01.js
devtools/client/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_02.js
devtools/client/styleinspector/test/browser_ruleview_colorpicker-appears-on-swatch-click.js
devtools/client/styleinspector/test/browser_ruleview_colorpicker-commit-on-ENTER.js
devtools/client/styleinspector/test/browser_ruleview_colorpicker-edit-gradient.js
devtools/client/styleinspector/test/browser_ruleview_colorpicker-hides-on-tooltip.js
devtools/client/styleinspector/test/browser_ruleview_colorpicker-multiple-changes.js
devtools/client/styleinspector/test/browser_ruleview_colorpicker-release-outside-frame.js
devtools/client/styleinspector/test/browser_ruleview_colorpicker-revert-on-ESC.js
devtools/client/styleinspector/test/browser_ruleview_colorpicker-swatch-displayed.js
devtools/client/styleinspector/test/browser_ruleview_completion-existing-property_01.js
devtools/client/styleinspector/test/browser_ruleview_completion-existing-property_02.js
devtools/client/styleinspector/test/browser_ruleview_completion-new-property_01.js
devtools/client/styleinspector/test/browser_ruleview_completion-new-property_02.js
devtools/client/styleinspector/test/browser_ruleview_completion-new-property_03.js
devtools/client/styleinspector/test/browser_ruleview_completion-popup-hidden-after-navigation.js
devtools/client/styleinspector/test/browser_ruleview_computed-lists_01.js
devtools/client/styleinspector/test/browser_ruleview_computed-lists_02.js
devtools/client/styleinspector/test/browser_ruleview_content_01.js
devtools/client/styleinspector/test/browser_ruleview_content_02.js
devtools/client/styleinspector/test/browser_ruleview_context-menu-show-mdn-docs-01.js
devtools/client/styleinspector/test/browser_ruleview_context-menu-show-mdn-docs-02.js
devtools/client/styleinspector/test/browser_ruleview_context-menu-show-mdn-docs-03.js
devtools/client/styleinspector/test/browser_ruleview_copy_styles.js
devtools/client/styleinspector/test/browser_ruleview_cssom.js
devtools/client/styleinspector/test/browser_ruleview_cubicbezier-appears-on-swatch-click.js
devtools/client/styleinspector/test/browser_ruleview_cubicbezier-commit-on-ENTER.js
devtools/client/styleinspector/test/browser_ruleview_cubicbezier-revert-on-ESC.js
devtools/client/styleinspector/test/browser_ruleview_custom.js
devtools/client/styleinspector/test/browser_ruleview_cycle-color.js
devtools/client/styleinspector/test/browser_ruleview_edit-property-cancel.js
devtools/client/styleinspector/test/browser_ruleview_edit-property-commit.js
devtools/client/styleinspector/test/browser_ruleview_edit-property-computed.js
devtools/client/styleinspector/test/browser_ruleview_edit-property-increments.js
devtools/client/styleinspector/test/browser_ruleview_edit-property-order.js
devtools/client/styleinspector/test/browser_ruleview_edit-property-remove_01.js
devtools/client/styleinspector/test/browser_ruleview_edit-property-remove_02.js
devtools/client/styleinspector/test/browser_ruleview_edit-property-remove_03.js
devtools/client/styleinspector/test/browser_ruleview_edit-property_01.js
devtools/client/styleinspector/test/browser_ruleview_edit-property_02.js
devtools/client/styleinspector/test/browser_ruleview_edit-property_03.js
devtools/client/styleinspector/test/browser_ruleview_edit-property_04.js
devtools/client/styleinspector/test/browser_ruleview_edit-property_05.js
devtools/client/styleinspector/test/browser_ruleview_edit-property_06.js
devtools/client/styleinspector/test/browser_ruleview_edit-property_07.js
devtools/client/styleinspector/test/browser_ruleview_edit-property_08.js
devtools/client/styleinspector/test/browser_ruleview_edit-selector-commit.js
devtools/client/styleinspector/test/browser_ruleview_edit-selector_01.js
devtools/client/styleinspector/test/browser_ruleview_edit-selector_02.js
devtools/client/styleinspector/test/browser_ruleview_edit-selector_03.js
devtools/client/styleinspector/test/browser_ruleview_edit-selector_04.js
devtools/client/styleinspector/test/browser_ruleview_edit-selector_05.js
devtools/client/styleinspector/test/browser_ruleview_edit-selector_06.js
devtools/client/styleinspector/test/browser_ruleview_editable-field-focus_01.js
devtools/client/styleinspector/test/browser_ruleview_editable-field-focus_02.js
devtools/client/styleinspector/test/browser_ruleview_eyedropper.js
devtools/client/styleinspector/test/browser_ruleview_filtereditor-appears-on-swatch-click.js
devtools/client/styleinspector/test/browser_ruleview_filtereditor-commit-on-ENTER.js
devtools/client/styleinspector/test/browser_ruleview_filtereditor-revert-on-ESC.js
devtools/client/styleinspector/test/browser_ruleview_guessIndentation.js
devtools/client/styleinspector/test/browser_ruleview_inherited-properties_01.js
devtools/client/styleinspector/test/browser_ruleview_inherited-properties_02.js
devtools/client/styleinspector/test/browser_ruleview_inherited-properties_03.js
devtools/client/styleinspector/test/browser_ruleview_keybindings.js
devtools/client/styleinspector/test/browser_ruleview_keyframeLineNumbers.js
devtools/client/styleinspector/test/browser_ruleview_keyframes-rule_01.js
devtools/client/styleinspector/test/browser_ruleview_keyframes-rule_02.js
devtools/client/styleinspector/test/browser_ruleview_lineNumbers.js
devtools/client/styleinspector/test/browser_ruleview_livepreview.js
devtools/client/styleinspector/test/browser_ruleview_mark_overridden_01.js
devtools/client/styleinspector/test/browser_ruleview_mark_overridden_02.js
devtools/client/styleinspector/test/browser_ruleview_mark_overridden_03.js
devtools/client/styleinspector/test/browser_ruleview_mark_overridden_04.js
devtools/client/styleinspector/test/browser_ruleview_mark_overridden_05.js
devtools/client/styleinspector/test/browser_ruleview_mark_overridden_06.js
devtools/client/styleinspector/test/browser_ruleview_mark_overridden_07.js
devtools/client/styleinspector/test/browser_ruleview_mathml-element.js
devtools/client/styleinspector/test/browser_ruleview_media-queries.js
devtools/client/styleinspector/test/browser_ruleview_multiple-properties-duplicates.js
devtools/client/styleinspector/test/browser_ruleview_multiple-properties-priority.js
devtools/client/styleinspector/test/browser_ruleview_multiple-properties-unfinished_01.js
devtools/client/styleinspector/test/browser_ruleview_multiple-properties-unfinished_02.js
devtools/client/styleinspector/test/browser_ruleview_multiple_properties_01.js
devtools/client/styleinspector/test/browser_ruleview_multiple_properties_02.js
devtools/client/styleinspector/test/browser_ruleview_original-source-link.js
devtools/client/styleinspector/test/browser_ruleview_pseudo-element_01.js
devtools/client/styleinspector/test/browser_ruleview_pseudo-element_02.js
devtools/client/styleinspector/test/browser_ruleview_pseudo_lock_options.js
devtools/client/styleinspector/test/browser_ruleview_refresh-no-flicker.js
devtools/client/styleinspector/test/browser_ruleview_refresh-on-attribute-change_01.js
devtools/client/styleinspector/test/browser_ruleview_refresh-on-attribute-change_02.js
devtools/client/styleinspector/test/browser_ruleview_refresh-on-style-change.js
devtools/client/styleinspector/test/browser_ruleview_search-filter-computed-list_01.js
devtools/client/styleinspector/test/browser_ruleview_search-filter-computed-list_02.js
devtools/client/styleinspector/test/browser_ruleview_search-filter-computed-list_03.js
devtools/client/styleinspector/test/browser_ruleview_search-filter-computed-list_04.js
devtools/client/styleinspector/test/browser_ruleview_search-filter-computed-list_expander.js
devtools/client/styleinspector/test/browser_ruleview_search-filter-overridden-property.js
devtools/client/styleinspector/test/browser_ruleview_search-filter_01.js
devtools/client/styleinspector/test/browser_ruleview_search-filter_02.js
devtools/client/styleinspector/test/browser_ruleview_search-filter_03.js
devtools/client/styleinspector/test/browser_ruleview_search-filter_04.js
devtools/client/styleinspector/test/browser_ruleview_search-filter_05.js
devtools/client/styleinspector/test/browser_ruleview_search-filter_06.js
devtools/client/styleinspector/test/browser_ruleview_search-filter_07.js
devtools/client/styleinspector/test/browser_ruleview_search-filter_08.js
devtools/client/styleinspector/test/browser_ruleview_search-filter_09.js
devtools/client/styleinspector/test/browser_ruleview_search-filter_10.js
devtools/client/styleinspector/test/browser_ruleview_search-filter_context-menu.js
devtools/client/styleinspector/test/browser_ruleview_search-filter_escape-keypress.js
devtools/client/styleinspector/test/browser_ruleview_select-and-copy-styles.js
devtools/client/styleinspector/test/browser_ruleview_selector-highlighter_01.js
devtools/client/styleinspector/test/browser_ruleview_selector-highlighter_02.js
devtools/client/styleinspector/test/browser_ruleview_selector-highlighter_03.js
devtools/client/styleinspector/test/browser_ruleview_selector_highlight.js
devtools/client/styleinspector/test/browser_ruleview_strict-search-filter-computed-list_01.js
devtools/client/styleinspector/test/browser_ruleview_strict-search-filter_01.js
devtools/client/styleinspector/test/browser_ruleview_strict-search-filter_02.js
devtools/client/styleinspector/test/browser_ruleview_strict-search-filter_03.js
devtools/client/styleinspector/test/browser_ruleview_style-editor-link.js
devtools/client/styleinspector/test/browser_ruleview_urls-clickable.js
devtools/client/styleinspector/test/browser_ruleview_user-agent-styles-uneditable.js
devtools/client/styleinspector/test/browser_ruleview_user-agent-styles.js
devtools/client/styleinspector/test/browser_ruleview_user-property-reset.js
devtools/client/styleinspector/test/doc_copystyles.css
devtools/client/styleinspector/test/doc_copystyles.html
devtools/client/styleinspector/test/doc_cssom.html
devtools/client/styleinspector/test/doc_custom.html
devtools/client/styleinspector/test/doc_filter.html
devtools/client/styleinspector/test/doc_keyframeLineNumbers.html
devtools/client/styleinspector/test/doc_keyframeanimation.css
devtools/client/styleinspector/test/doc_keyframeanimation.html
devtools/client/styleinspector/test/doc_matched_selectors.html
devtools/client/styleinspector/test/doc_media_queries.html
devtools/client/styleinspector/test/doc_pseudoelement.html
devtools/client/styleinspector/test/doc_ruleLineNumbers.html
devtools/client/styleinspector/test/doc_sourcemaps.css
devtools/client/styleinspector/test/doc_sourcemaps.css.map
devtools/client/styleinspector/test/doc_sourcemaps.html
devtools/client/styleinspector/test/doc_sourcemaps.scss
devtools/client/styleinspector/test/doc_style_editor_link.css
devtools/client/styleinspector/test/doc_test_image.png
devtools/client/styleinspector/test/doc_urls_clickable.css
devtools/client/styleinspector/test/doc_urls_clickable.html
devtools/client/themes/computedview.css
devtools/client/themes/font-inspector.css
devtools/client/themes/layoutview.css
devtools/client/themes/ruleview.css
modules/libpref/init/all.js
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk-specific things and forks -->
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="be4b291a90b371b41b62ade68c31ad173bb87baa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk-specific things and forks -->
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "16ebbfb6ce62c14573982b0aa87537ef8f857047", 
+        "git_revision": "81c021654c657f6995e5e70ef02ee067d4bfedbd", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "8668ab0c480334a48e1935cce440e33dff23b33a", 
+    "revision": "e651f5b571034436b7bc8eb8099033dff5623a20", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4-kk/sources.xml
+++ b/b2g/config/nexus-4-kk/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="be4b291a90b371b41b62ade68c31ad173bb87baa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/browser/components/extensions/ext-contextMenus.js
+++ b/browser/components/extensions/ext-contextMenus.js
@@ -32,32 +32,31 @@ var gMaxLabelLength = 64;
 // we populate the |xulMenu| with all the items from extensions
 // to be displayed. We always clear all the items again when
 // popuphidden fires.
 var menuBuilder = {
   build: function(contextData) {
     let xulMenu = contextData.menu;
     xulMenu.addEventListener("popuphidden", this);
     this.xulMenu = xulMenu;
-    for (let [extension, root] of rootItems) {
+    for (let [, root] of rootItems) {
       let rootElement = this.buildElementWithChildren(root, contextData);
       if (!rootElement.childNodes.length) {
         // If the root has no visible children, there is no reason to show
         // the root menu item itself either.
         continue;
       }
       rootElement.setAttribute("ext-type", "top-level-menu");
       rootElement = this.removeTopLevelMenuIfNeeded(rootElement);
       xulMenu.appendChild(rootElement);
       this.itemsToCleanUp.add(rootElement);
     }
   },
 
   buildElementWithChildren(item, contextData) {
-    let doc = contextData.menu.ownerDocument;
     let element = this.buildSingleElement(item, contextData);
     for (let child of item.children) {
       if (child.enabledForContext(contextData)) {
         let childElement = this.buildElementWithChildren(child, contextData);
         // Here element must be a menu element and its first child
         // is a menupopup, we have to append its children to this
         // menupopup.
         element.firstChild.appendChild(childElement);
@@ -101,17 +100,17 @@ var menuBuilder = {
     let menupopup = doc.createElement("menupopup");
     element.appendChild(menupopup);
     return element;
   },
 
   customizeElement(element, item, contextData) {
     let label = item.title;
     if (label) {
-      if (contextData.isTextSelected && label.indexOf('%s') > -1) {
+      if (contextData.isTextSelected && label.indexOf("%s") > -1) {
         let selection = contextData.selectionText;
         // The rendering engine will truncate the title if it's longer than 64 characters.
         // But if it makes sense let's try truncate selection text only, to handle cases like
         // 'look up "%s" in MyDictionary' more elegantly.
         let maxSelectionLength = gMaxLabelLength - label.length + 2;
         if (maxSelectionLength > 4) {
           selection = selection.substring(0, maxSelectionLength - 3) + "...";
         }
@@ -120,22 +119,22 @@ var menuBuilder = {
 
       element.setAttribute("label", label);
     }
 
     if (!item.enabled) {
       element.setAttribute("disabled", true);
     }
 
-    element.addEventListener("command", event => {
+    element.addEventListener("command", event => {  // eslint-disable-line mozilla/balanced-listeners
       item.tabManager.addActiveTabPermission();
       if (item.onclick) {
         let clickData = item.getClickData(contextData, event);
         runSafe(item.extContext, item.onclick, clickData);
-       }
+      }
     });
 
     return element;
   },
 
   handleEvent: function(event) {
     if (this.xulMenu != event.target || event.type != "popuphidden") {
       return;
@@ -232,17 +231,17 @@ MenuItem.prototype = {
     }
   },
 
   setDefaults() {
     this.setProps({
       type: "normal",
       checked: "false",
       contexts: ["all"],
-      enabled: "true"
+      enabled: "true",
     });
   },
 
   set id(id) {
     if (this.hasOwnProperty("_id")) {
       throw new Error("Id of a MenuItem cannot be changed");
     }
     let isIdUsed = contextMenuMap.get(this.extension).has(id);
@@ -387,17 +386,17 @@ MenuItem.prototype = {
     let isMedia = contextData.onImage || contextData.onAudio || contextData.onVideo;
     let targetPattern = this.targetUrlMatchPattern;
     if (isMedia && targetPattern && !targetPattern.matches(contextData.srcURL)) {
       // TODO: double check if mediaURL is always set when we need it
       return false;
     }
 
     return true;
-  }
+  },
 };
 
 var extCount = 0;
 /* eslint-disable mozilla/balanced-listeners */
 extensions.on("startup", (type, extension) => {
   contextMenuMap.set(extension, new Map());
   rootItems.delete(extension);
   if (++extCount == 1) {
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -541,21 +541,21 @@ extensions.registerSchemaAPI("tabs", nul
         let index = moveProperties.index;
         let tabsMoved = [];
         if (!Array.isArray(tabIds)) {
           tabIds = [tabIds];
         }
 
         let destinationWindow = null;
         if (moveProperties.windowId !== null) {
-           destinationWindow = WindowManager.getWindow(moveProperties.windowId);
-           // Ignore invalid window.
-           if (!destinationWindow) {
-             return;
-           }
+          destinationWindow = WindowManager.getWindow(moveProperties.windowId);
+          // Ignore invalid window.
+          if (!destinationWindow) {
+            return;
+          }
         }
 
         /*
           Indexes are maintained on a per window basis so that a call to
             move([tabA, tabB], {index: 0})
               -> tabA to 0, tabB to 1 if tabA and tabB are in the same window
             move([tabA, tabB], {index: 0})
               -> tabA to 0, tabB to 0 if tabA and tabB are in different windows
@@ -582,21 +582,22 @@ extensions.registerSchemaAPI("tabs", nul
             }
             indexMap.set(window, point + 1);
             return point;
           };
 
           if (WindowManager.getId(tab.ownerDocument.defaultView) !== windowId) {
             // If the window we are moving the tab in is different, then move the tab
             // to the new window.
-            let newTab = gBrowser.addTab('about:blank');
+            let newTab = gBrowser.addTab("about:blank");
             let newBrowser = gBrowser.getBrowserForTab(newTab);
             gBrowser.updateBrowserRemotenessByURL(newBrowser, tab.linkedBrowser.currentURI.spec);
             newBrowser.stop();
-            newBrowser.docShell;
+            // This is necessary for getter side-effects.
+            void newBrowser.docShell;
 
             if (tab.pinned) {
               gBrowser.pinTab(newTab);
             }
 
             gBrowser.moveTabTo(newTab, getInsertionPoint());
 
             tab.parentNode._finishAnimateTabMove();
--- a/browser/components/extensions/test/browser/.eslintrc
+++ b/browser/components/extensions/test/browser/.eslintrc
@@ -1,44 +1,22 @@
 {
-  "extends": "../../.eslintrc",
+  "extends": "../../../../../testing/mochitest/browser.eslintrc",
+
+  "env": {
+    "webextensions": true,
+  },
 
   "globals": {
-    // DOM window globals
-    "CustomEvent": false,
-    "document": false,
-    "ImageData": false,
-    "MouseEvent": false,
-    "setTimeout": false,
-    "window": false,
-    "XMLHttpRequest": false,
-
-    "gBrowser": false,
-
-    "sendAsyncMessage": false,
-
     "NetUtil": true,
     "XPCOMUtils": true,
     "Task": true,
 
-    "browser": false,
-
     // Test harness globals
-    "add_task": false,
-    "BrowserTestUtils": false,
-    "ContentTask": false,
-    "EventUtils": false,
     "ExtensionTestUtils": false,
-    "info": false,
-    "is": false,
-    "ok": false,
-    "registerCleanupFunction": false,
-    "SimpleTest": false,
-    "SpecialPowers": false,
-    "waitForFocus": false,
 
     "clickBrowserAction": true,
     "clickPageAction": true,
     "CustomizableUI": true,
     "focusWindow": true,
     "makeWidgetId": true,
   }
 }
--- a/browser/components/extensions/test/browser/browser_ext_contextMenus.js
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus.js
@@ -23,46 +23,46 @@ add_task(function* () {
       }
 
       browser.contextMenus.create({ contexts: ["all"], type: "separator" });
 
       let contexts = ["page", "selection", "image"];
       for (let i = 0; i < contexts.length; i++) {
         let context = contexts[i];
         let title = context;
-        var id = browser.contextMenus.create({ title: title, contexts: [context], id: "ext-" + context,
-                                               onclick: genericOnClick });
+        browser.contextMenus.create({ title: title, contexts: [context], id: "ext-" + context,
+                                      onclick: genericOnClick });
         if (context == "selection") {
           browser.contextMenus.update("ext-selection", {
             title: "selection is: '%s'",
             onclick: (info) => {
               browser.contextMenus.removeAll();
               genericOnClick(info);
-            }
+            },
           });
         }
       }
 
-      var parent = browser.contextMenus.create({ title: "parent" });
+      let parent = browser.contextMenus.create({ title: "parent" });
       browser.contextMenus.create(
         { title: "child1", parentId: parent, onclick: genericOnClick });
-      browser.contextMenus.create(
+      let child2 = browser.contextMenus.create(
         { title: "child2", parentId: parent, onclick: genericOnClick });
 
-      var parentToDel = browser.contextMenus.create({ title: "parentToDel" });
+      let parentToDel = browser.contextMenus.create({ title: "parentToDel" });
       browser.contextMenus.create(
         { title: "child1", parentId: parentToDel, onclick: genericOnClick });
       browser.contextMenus.create(
         { title: "child2", parentId: parentToDel, onclick: genericOnClick });
       browser.contextMenus.remove(parentToDel);
 
       try {
         browser.contextMenus.update(parent, { parentId: child2 });
         browser.test.notifyFail();
-      } catch(e) {
+      } catch (e) {
         browser.test.notifyPass();
       }
     },
   });
 
   let expectedClickInfo;
   function checkClickInfo(info) {
     info = JSON.parse(info);
--- a/browser/components/extensions/test/browser/browser_ext_tabs_move.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_move.js
@@ -1,115 +1,114 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 add_task(function* () {
   let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:robots");
   let tab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:config");
 
-  gBrowser.selectedTab = tab1
+  gBrowser.selectedTab = tab1;
 
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
-      "permissions": ["tabs"]
+      "permissions": ["tabs"],
     },
 
     background: function() {
       browser.tabs.query({
         lastFocusedWindow: true,
       }, function(tabs) {
-        var tab = tabs[0];
-        chrome.tabs.move(tab.id, {index: 0});
-        browser.tabs.query({
-            lastFocusedWindow: true,
-          }, function(tabs) {
+        let tab = tabs[0];
+        browser.tabs.move(tab.id, {index: 0});
+        browser.tabs.query(
+          { lastFocusedWindow: true },
+          tabs => {
             browser.test.assertEq(tabs[0].url, tab.url, "should be first tab");
             browser.test.notifyPass("tabs.move.single");
-        });
-
+          });
       });
     },
   });
 
   yield extension.startup();
   yield extension.awaitFinish("tabs.move.single");
   yield extension.unload();
 
   extension = ExtensionTestUtils.loadExtension({
     manifest: {
-      "permissions": ["tabs"]
+      "permissions": ["tabs"],
     },
 
     background: function() {
-      browser.tabs.query({
-          lastFocusedWindow: true,
-        }, function(tabs) {
+      browser.tabs.query(
+        { lastFocusedWindow: true },
+        tabs => {
           tabs.sort(function(a, b) { return a.url > b.url; });
-          chrome.tabs.move(tabs.map(tab => tab.id), {index: 0});
-          chrome.tabs.query({
-              lastFocusedWindow: true,
-            }, function(tabs) {
+          browser.tabs.move(tabs.map(tab => tab.id), {index: 0});
+          browser.tabs.query(
+            { lastFocusedWindow: true },
+            tabs => {
               browser.test.assertEq(tabs[0].url, "about:blank", "should be first tab");
               browser.test.assertEq(tabs[1].url, "about:config", "should be second tab");
               browser.test.assertEq(tabs[2].url, "about:robots", "should be third tab");
               browser.test.notifyPass("tabs.move.multiple");
+            });
         });
-      });
     },
   });
 
   yield extension.startup();
   yield extension.awaitFinish("tabs.move.multiple");
   yield extension.unload();
 
   extension = ExtensionTestUtils.loadExtension({
     manifest: {
-      "permissions": ["tabs"]
+      "permissions": ["tabs"],
     },
 
     background: function() {
-      browser.tabs.query({
-          lastFocusedWindow: true,
-        }, function(tabs) {
-          var tab = tabs[0];
+      browser.tabs.query(
+        { lastFocusedWindow: true },
+        tabs => {
+          let tab = tabs[0];
           // Assuming that tab.id of 12345 does not exist.
-          chrome.tabs.move([12345, tab.id], {index: 0});
-          chrome.tabs.query({
-              lastFocusedWindow: true,
-            }, function(tabs) {
+          browser.tabs.move([12345, tab.id], {index: 0});
+          browser.tabs.query(
+            { lastFocusedWindow: true },
+            tabs => {
               browser.test.assertEq(tabs[0].url, tab.url, "should be first tab");
               browser.test.notifyPass("tabs.move.invalid");
+            });
         });
-      });
     },
   });
 
   yield extension.startup();
   yield extension.awaitFinish("tabs.move.invalid");
   yield extension.unload();
 
   extension = ExtensionTestUtils.loadExtension({
     manifest: {
-      "permissions": ["tabs"]
+      "permissions": ["tabs"],
     },
 
     background: function() {
-      browser.tabs.query({
-          lastFocusedWindow: true,
-        }, function(tabs) {
-          var tab = tabs[0];
-          chrome.tabs.move(tab.id, {index: -1});
-          chrome.tabs.query({
-              lastFocusedWindow: true,
-            }, function(tabs) {
+      browser.tabs.query(
+        { lastFocusedWindow: true },
+        tabs => {
+          let tab = tabs[0];
+          browser.tabs.move(tab.id, {index: -1});
+          browser.tabs.query(
+            { lastFocusedWindow: true },
+            tabs => {
               browser.test.assertEq(tabs[2].url, tab.url, "should be last tab");
               browser.test.notifyPass("tabs.move.last");
             });
-      });
+        });
     },
   });
 
   yield extension.startup();
   yield extension.awaitFinish("tabs.move.last");
   yield extension.unload();
 
   yield BrowserTestUtils.removeTab(tab1);
--- a/browser/components/extensions/test/browser/browser_ext_tabs_move_window.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_move_window.js
@@ -1,119 +1,117 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 add_task(function* () {
-  let tab0 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.net/");
+  yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.net/");
   let window1 = yield BrowserTestUtils.openNewBrowserWindow();
-  let tab1 = yield BrowserTestUtils.openNewForegroundTab(window1.gBrowser, "http://example.com/");
+  yield BrowserTestUtils.openNewForegroundTab(window1.gBrowser, "http://example.com/");
 
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
-      "permissions": ["tabs"]
+      "permissions": ["tabs"],
     },
 
     background: function() {
-      chrome.tabs.query({
-        url: '<all_urls>',
+      browser.tabs.query({
+        url: "<all_urls>",
       }, function(tabs) {
         let destination = tabs[0];
         let source = tabs[1]; // skip over about:blank in window1
-        chrome.tabs.move(source.id, {windowId: destination.windowId, index: 0});
+        browser.tabs.move(source.id, {windowId: destination.windowId, index: 0});
 
-        chrome.tabs.query({
-          url: '<all_urls>',
-        }, function(tabs) {
-          browser.test.assertEq(tabs[0].url, "http://example.com/");
-          browser.test.assertEq(tabs[0].windowId, destination.windowId);
-          browser.test.notifyPass("tabs.move.window");
-        });
-
+        browser.tabs.query(
+          { url: "<all_urls>" },
+          tabs => {
+            browser.test.assertEq(tabs[0].url, "http://example.com/");
+            browser.test.assertEq(tabs[0].windowId, destination.windowId);
+            browser.test.notifyPass("tabs.move.window");
+          });
       });
     },
   });
 
   yield extension.startup();
   yield extension.awaitFinish("tabs.move.window");
   yield extension.unload();
 
   for (let tab of window.gBrowser.tabs) {
     yield BrowserTestUtils.removeTab(tab);
   }
   yield BrowserTestUtils.closeWindow(window1);
 });
 
 add_task(function* () {
-  let tab0 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.net/");
+  yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.net/");
   let window1 = yield BrowserTestUtils.openNewBrowserWindow();
   let tab1 = yield BrowserTestUtils.openNewForegroundTab(window1.gBrowser, "http://example.com/");
   window1.gBrowser.pinTab(tab1);
 
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
-      "permissions": ["tabs"]
+      "permissions": ["tabs"],
     },
 
     background: function() {
-      chrome.tabs.query({
-        url: '<all_urls>',
-      }, function(tabs) {
-        let destination = tabs[0];
-        let source = tabs[1]; // remember, pinning moves it to the left.
-        chrome.tabs.move(source.id, {windowId: destination.windowId, index: 0});
+      browser.tabs.query(
+        { url: "<all_urls>" },
+        tabs => {
+          let destination = tabs[0];
+          let source = tabs[1]; // remember, pinning moves it to the left.
+          browser.tabs.move(source.id, {windowId: destination.windowId, index: 0});
 
-        chrome.tabs.query({
-          url: '<all_urls>',
-        }, function(tabs) {
-          browser.test.assertEq(true, tabs[0].pinned);
-          browser.test.notifyPass("tabs.move.pin");
+          browser.tabs.query(
+            { url: "<all_urls>" },
+            tabs => {
+              browser.test.assertEq(true, tabs[0].pinned);
+              browser.test.notifyPass("tabs.move.pin");
+            });
         });
-      });
     },
   });
 
   yield extension.startup();
   yield extension.awaitFinish("tabs.move.pin");
   yield extension.unload();
 
   for (let tab of window.gBrowser.tabs) {
     yield BrowserTestUtils.removeTab(tab);
   }
   yield BrowserTestUtils.closeWindow(window1);
 });
 
 add_task(function* () {
   let window1 = yield BrowserTestUtils.openNewBrowserWindow();
-  let tab0 = yield BrowserTestUtils.openNewForegroundTab(window.gBrowser, "http://example.net/");
-  let tab1 = yield BrowserTestUtils.openNewForegroundTab(window.gBrowser, "http://example.com/");
-  let tab2 = yield BrowserTestUtils.openNewForegroundTab(window1.gBrowser, "http://example.net/");
-  let tab3 = yield BrowserTestUtils.openNewForegroundTab(window1.gBrowser, "http://example.com/");
+  yield BrowserTestUtils.openNewForegroundTab(window.gBrowser, "http://example.net/");
+  yield BrowserTestUtils.openNewForegroundTab(window.gBrowser, "http://example.com/");
+  yield BrowserTestUtils.openNewForegroundTab(window1.gBrowser, "http://example.net/");
+  yield BrowserTestUtils.openNewForegroundTab(window1.gBrowser, "http://example.com/");
 
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
-      "permissions": ["tabs"]
+      "permissions": ["tabs"],
     },
 
     background: function() {
-      chrome.tabs.query({
-        url: '<all_urls>',
-      }, function(tabs) {
-        let move1 = tabs[1];
-        let move3 = tabs[3];
-        chrome.tabs.move([move1.id, move3.id], {index: 0});
-        chrome.tabs.query({
-          url: '<all_urls>',
-        }, function(tabs) {
-          browser.test.assertEq(tabs[0].url, move1.url);
-          browser.test.assertEq(tabs[2].url, move3.url);
-          browser.test.notifyPass("tabs.move.multiple");
+      browser.tabs.query(
+        { url: "<all_urls>" },
+        tabs => {
+          let move1 = tabs[1];
+          let move3 = tabs[3];
+          browser.tabs.move([move1.id, move3.id], {index: 0});
+          browser.tabs.query(
+            { url: "<all_urls>" },
+            tabs => {
+              browser.test.assertEq(tabs[0].url, move1.url);
+              browser.test.assertEq(tabs[2].url, move3.url);
+              browser.test.notifyPass("tabs.move.multiple");
+            });
         });
-
-      });
     },
   });
 
   yield extension.startup();
   yield extension.awaitFinish("tabs.move.multiple");
   yield extension.unload();
 
   for (let tab of window.gBrowser.tabs) {
--- a/browser/extensions/loop/content/modules/MozLoopService.jsm
+++ b/browser/extensions/loop/content/modules/MozLoopService.jsm
@@ -47,17 +47,18 @@ const SHARING_STATE_CHANGE = {
  *
  * @type {{COPY_FROM_PANEL: Number, COPY_FROM_CONVERSATION: Number,
  *   EMAIL_FROM_CALLFAILED: Number, EMAIL_FROM_CONVERSATION: Number}}
  */
 const SHARING_ROOM_URL = {
   COPY_FROM_PANEL: 0,
   COPY_FROM_CONVERSATION: 1,
   EMAIL_FROM_CALLFAILED: 2,
-  EMAIL_FROM_CONVERSATION: 3
+  EMAIL_FROM_CONVERSATION: 3,
+  FACEBOOK_FROM_CONVERSATION: 4
 };
 
 /**
  * Values that we segment room create action telemetry probes into.
  *
  * @type {{CREATE_SUCCESS: Number, CREATE_FAIL: Number}}
  */
 const ROOM_CREATE = {
--- a/browser/extensions/loop/content/panels/js/roomStore.js
+++ b/browser/extensions/loop/content/panels/js/roomStore.js
@@ -80,16 +80,17 @@ loop.store = loop.store || {};
       "addSocialShareProvider",
       "createRoom",
       "createdRoom",
       "createRoomError",
       "copyRoomUrl",
       "deleteRoom",
       "deleteRoomError",
       "emailRoomUrl",
+      "facebookShareRoomUrl",
       "getAllRooms",
       "getAllRoomsError",
       "openRoom",
       "shareRoomUrl",
       "updateRoomContext",
       "updateRoomContextDone",
       "updateRoomContextError",
       "updateRoomList"
@@ -347,16 +348,39 @@ loop.store = loop.store || {};
         return;
       }
       loop.requestMulti(
         ["NotifyUITour", "Loop:RoomURLEmailed"],
         ["TelemetryAddValue", "LOOP_SHARING_ROOM_URL", bucket]);
     },
 
     /**
+     * Share a room url with Facebook
+     *
+     * @param  {sharedActions.FacebookShareRoomUrl} actionData The action data.
+     */
+    facebookShareRoomUrl: function(actionData) {
+      var encodedRoom = encodeURIComponent(actionData.roomUrl);
+      loop.request("GetLoopPref", "facebook.shareUrl")
+        .then(shareUrl => {
+          loop.request("OpenURL", shareUrl.replace("%ROOM_URL%", encodedRoom));
+        }).then(() => {
+          loop.request("NotifyUITour", "Loop:RoomURLShared");
+        });
+
+      var from = actionData.from;
+      var bucket = this._constants.SHARING_ROOM_URL["FACEBOOK_FROM_" + from.toUpperCase()];
+      if (typeof bucket === "undefined") {
+        console.error("No URL sharing type bucket found for '" + from + "'");
+        return;
+      }
+      loop.request("TelemetryAddValue", "LOOP_SHARING_ROOM_URL", bucket);
+    },
+
+    /**
      * Share a room url.
      *
      * @param  {sharedActions.ShareRoomUrl} actionData The action data.
      */
     shareRoomUrl: function(actionData) {
       var providerOrigin = new URL(actionData.provider.origin).hostname;
       var shareTitle = "";
       var shareBody = null;
--- a/browser/extensions/loop/content/panels/js/roomViews.js
+++ b/browser/extensions/loop/content/panels/js/roomViews.js
@@ -275,16 +275,25 @@ loop.roomViews = (function(mozL10n) {
       this.props.dispatcher.dispatch(
         new sharedActions.EmailRoomUrl({
           roomUrl: roomData.roomUrl,
           roomDescription: contextURL,
           from: "conversation"
         }));
     },
 
+    handleFacebookButtonClick: function(event) {
+      event.preventDefault();
+
+      this.props.dispatcher.dispatch(new sharedActions.FacebookShareRoomUrl({
+        from: "conversation",
+        roomUrl: this.props.roomData.roomUrl
+      }));
+    },
+
     handleCopyButtonClick: function(event) {
       event.preventDefault();
 
       this.props.dispatcher.dispatch(new sharedActions.CopyRoomUrl({
         roomUrl: this.props.roomData.roomUrl,
         from: "conversation"
       }));
 
@@ -296,30 +305,16 @@ loop.roomViews = (function(mozL10n) {
      * Reset state of triggered buttons if necessary
      */
     resetTriggeredButtons: function() {
       if (this.state.copiedUrl) {
         this.setState({ copiedUrl: false });
       }
     },
 
-    handleShareButtonClick: function(event) {
-      event.preventDefault();
-
-      var providers = this.props.socialShareProviders;
-      // If there are no providers available currently, save a click by dispatching
-      // the 'AddSocialShareProvider' right away.
-      if (!providers || !providers.length) {
-        this.props.dispatcher.dispatch(new sharedActions.AddSocialShareProvider());
-        return;
-      }
-
-      this.toggleDropdownMenu();
-    },
-
     handleEditContextClose: function() {
       if (this.props.onEditContextClose) {
         this.props.onEditContextClose();
       }
     },
 
     render: function() {
       if (!this.props.show || !this.props.roomData.roomUrl) {
@@ -349,16 +344,22 @@ loop.roomViews = (function(mozL10n) {
               React.createElement("p", null, mozL10n.get(this.state.copiedUrl ?
                 "invite_copied_link_button" : "invite_copy_link_button"))
             ), 
             React.createElement("div", {className: "btn-email invite-button", 
               onClick: this.handleEmailButtonClick, 
               onMouseOver: this.resetTriggeredButtons}, 
               React.createElement("img", {src: "shared/img/glyph-email-16x16.svg"}), 
               React.createElement("p", null, mozL10n.get("invite_email_link_button"))
+            ), 
+            React.createElement("div", {className: "btn-facebook invite-button", 
+              onClick: this.handleFacebookButtonClick, 
+              onMouseOver: this.resetTriggeredButtons}, 
+              React.createElement("img", {src: "shared/img/glyph-facebook-16x16.svg"}), 
+              React.createElement("p", null, mozL10n.get("invite_facebook_button3"))
             )
           ), 
           React.createElement(SocialShareDropdown, {
             dispatcher: this.props.dispatcher, 
             ref: "menu", 
             roomUrl: this.props.roomData.roomUrl, 
             show: this.state.showMenu, 
             socialShareProviders: this.props.socialShareProviders}), 
--- a/browser/extensions/loop/content/panels/js/roomViews.jsx
+++ b/browser/extensions/loop/content/panels/js/roomViews.jsx
@@ -275,16 +275,25 @@ loop.roomViews = (function(mozL10n) {
       this.props.dispatcher.dispatch(
         new sharedActions.EmailRoomUrl({
           roomUrl: roomData.roomUrl,
           roomDescription: contextURL,
           from: "conversation"
         }));
     },
 
+    handleFacebookButtonClick: function(event) {
+      event.preventDefault();
+
+      this.props.dispatcher.dispatch(new sharedActions.FacebookShareRoomUrl({
+        from: "conversation",
+        roomUrl: this.props.roomData.roomUrl
+      }));
+    },
+
     handleCopyButtonClick: function(event) {
       event.preventDefault();
 
       this.props.dispatcher.dispatch(new sharedActions.CopyRoomUrl({
         roomUrl: this.props.roomData.roomUrl,
         from: "conversation"
       }));
 
@@ -296,30 +305,16 @@ loop.roomViews = (function(mozL10n) {
      * Reset state of triggered buttons if necessary
      */
     resetTriggeredButtons: function() {
       if (this.state.copiedUrl) {
         this.setState({ copiedUrl: false });
       }
     },
 
-    handleShareButtonClick: function(event) {
-      event.preventDefault();
-
-      var providers = this.props.socialShareProviders;
-      // If there are no providers available currently, save a click by dispatching
-      // the 'AddSocialShareProvider' right away.
-      if (!providers || !providers.length) {
-        this.props.dispatcher.dispatch(new sharedActions.AddSocialShareProvider());
-        return;
-      }
-
-      this.toggleDropdownMenu();
-    },
-
     handleEditContextClose: function() {
       if (this.props.onEditContextClose) {
         this.props.onEditContextClose();
       }
     },
 
     render: function() {
       if (!this.props.show || !this.props.roomData.roomUrl) {
@@ -350,16 +345,22 @@ loop.roomViews = (function(mozL10n) {
                 "invite_copied_link_button" : "invite_copy_link_button")}</p>
             </div>
             <div className="btn-email invite-button"
               onClick={this.handleEmailButtonClick}
               onMouseOver={this.resetTriggeredButtons}>
               <img src="shared/img/glyph-email-16x16.svg" />
               <p>{mozL10n.get("invite_email_link_button")}</p>
             </div>
+            <div className="btn-facebook invite-button"
+              onClick={this.handleFacebookButtonClick}
+              onMouseOver={this.resetTriggeredButtons}>
+              <img src="shared/img/glyph-facebook-16x16.svg" />
+              <p>{mozL10n.get("invite_facebook_button3")}</p>
+            </div>
           </div>
           <SocialShareDropdown
             dispatcher={this.props.dispatcher}
             ref="menu"
             roomUrl={this.props.roomData.roomUrl}
             show={this.state.showMenu}
             socialShareProviders={this.props.socialShareProviders} />
           <DesktopRoomEditContextView
--- a/browser/extensions/loop/content/preferences/prefs.js
+++ b/browser/extensions/loop/content/preferences/prefs.js
@@ -1,13 +1,14 @@
 pref("loop.enabled", true);
 pref("loop.textChat.enabled", true);
 pref("loop.server", "https://loop.services.mozilla.com/v0");
 pref("loop.linkClicker.url", "https://hello.firefox.com/");
 pref("loop.gettingStarted.latestFTUVersion", 0);
+pref("loop.facebook.shareUrl", "https://www.facebook.com/sharer/sharer.php?u=%ROOM_URL%");
 pref("loop.gettingStarted.url", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/hello/start/");
 pref("loop.gettingStarted.resumeOnFirstJoin", false);
 pref("loop.learnMoreUrl", "https://www.firefox.com/hello/");
 pref("loop.legal.ToS_url", "https://www.mozilla.org/about/legal/terms/firefox-hello/");
 pref("loop.legal.privacy_url", "https://www.mozilla.org/privacy/firefox-hello/");
 pref("loop.do_not_disturb", false);
 pref("loop.ringtone", "chrome://browser/content/loop/shared/sounds/ringtone.ogg");
 pref("loop.retry_delay.start", 60000);
--- a/browser/extensions/loop/content/shared/css/conversation.css
+++ b/browser/extensions/loop/content/shared/css/conversation.css
@@ -214,16 +214,17 @@ html[dir="rtl"] .conversation-toolbar-bt
 .call-action-group > .invite-button > p {
   display: none;
   /* Position the text under the button while centering it without impacting the
    * rest of the layout */
   left: -10rem;
   margin: .5rem 0 0;
   position: absolute;
   right: -10rem;
+  font-size: 0.8rem;
 }
 
 .call-action-group > .invite-button.triggered > p,
 .call-action-group > .invite-button:hover > p {
   display: block;
 }
 
 .room-failure {
@@ -549,17 +550,17 @@ body[platform="win"] .share-service-drop
   margin: 1em 0 .5em 0;
   text-align: center;
   text-shadow: 1px 1px 0 rgba(0,0,0,.3);
 }
 
 .room-invitation-content,
 .room-context-header {
   color: #333;
-  font-size: 1.2rem;
+  font-size: 1rem;
   font-weight: bold;
   margin: 1rem auto;
 }
 
 .room-context > form {
   margin-bottom: 1rem;
   padding: .5rem;
   width: 100%;
--- a/browser/extensions/loop/content/shared/js/actions.js
+++ b/browser/extensions/loop/content/shared/js/actions.js
@@ -339,35 +339,55 @@ loop.shared.actions = (function() {
      * Updating the context data attached to a room finished successfully.
      */
     UpdateRoomContextDone: Action.define("updateRoomContextDone", {
     }),
 
     /**
      * Copy a room url into the user's clipboard.
      * XXX: should move to some roomActions module - refs bug 1079284
+     * @from: where the invitation is shared from.
+     *        Possible values ['panel', 'conversation']
+     * @roomUrl: the URL that is shared
      */
     CopyRoomUrl: Action.define("copyRoomUrl", {
       from: String,
       roomUrl: String
     }),
 
     /**
      * Email a room url.
      * XXX: should move to some roomActions module - refs bug 1079284
+     * @from: where the invitation is shared from.
+     *        Possible values ['panel', 'conversation']
+     * @roomUrl: the URL that is shared
      */
     EmailRoomUrl: Action.define("emailRoomUrl", {
       from: String,
       roomUrl: String
       // roomDescription: String, Optional.
     }),
 
     /**
+     * Share a room url with Facebook.
+     * XXX: should move to some roomActions module - refs bug 1079284
+     * @from: where the invitation is shared from.
+     *        Possible values ['panel', 'conversation']
+     * @roomUrl: the URL that is shared
+     */
+    FacebookShareRoomUrl: Action.define("facebookShareRoomUrl", {
+      from: String,
+      roomUrl: String
+    }),
+
+    /**
      * Share a room url via the Social API.
      * XXX: should move to some roomActions module - refs bug 1079284
+     * @provider: one of the share-capable Social Providers included
+     * @roomUrl: the URL that is shared
      */
     ShareRoomUrl: Action.define("shareRoomUrl", {
       provider: Object,
       roomUrl: String
     }),
 
     /**
      * Open the share panel to add a Social share provider.
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c028f51f5ec4920b6ca3703d858229605eb55fcd
GIT binary patch
literal 44332
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
--- a/browser/extensions/loop/standalone/content/index.html
+++ b/browser/extensions/loop/standalone/content/index.html
@@ -4,16 +4,24 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/.  -->
 <html>
   <head>
     <meta charset="utf-8">
     <meta name="locales" content="en-US" />
     <meta name="default_locale" content="en-US" />
     <meta name="referrer" content="origin" />
 
+    <meta property="og:image" content="https://hello.firefox.com/img/invitation.png" />
+    <meta property="og:image:height" content="630" />
+    <meta property="og:image:width" content="1200" />
+    <meta property="og:site_name" content="Firefox Hello" />
+    <meta property="og:title" content="A friend has invited you to browse the Web together on Firefox Hello" />
+    <meta property="og:description" content="Click to connect" />
+
+
     <link rel="shortcut icon" href="favicon.ico">
 
     <link rel="stylesheet" type="text/css" href="shared/css/reset.css">
     <link rel="stylesheet" type="text/css" href="shared/css/common.css">
     <link rel="stylesheet" type="text/css" href="shared/css/conversation.css">
     <link rel="stylesheet" type="text/css" href="css/webapp.css">
     <link rel="localization" href="l10n/{locale}/loop.properties">
 
--- a/browser/extensions/loop/test/desktop-local/roomStore_test.js
+++ b/browser/extensions/loop/test/desktop-local/roomStore_test.js
@@ -28,17 +28,18 @@ describe("loop.store.RoomStore", functio
 
     LoopMochaUtils.stubLoopRequest(requestStubs = {
       GetAllConstants: function() {
         return {
           SHARING_ROOM_URL: {
             COPY_FROM_PANEL: 0,
             COPY_FROM_CONVERSATION: 1,
             EMAIL_FROM_PANEL: 2,
-            EMAIL_FROM_CONVERSATION: 3
+            EMAIL_FROM_CONVERSATION: 3,
+            FACEBOOK_FROM_CONVERSATION: 4
           },
           ROOM_CREATE: {
             CREATE_SUCCESS: 0,
             CREATE_FAIL: 1
           },
           ROOM_DELETE: {
             DELETE_SUCCESS: 0,
             DELETE_FAIL: 1
@@ -51,16 +52,17 @@ describe("loop.store.RoomStore", functio
       },
       CopyString: sinon.stub(),
       GetLoopPref: function(prefName) {
         if (prefName === "debug.dispatcher") {
           return false;
         }
       },
       NotifyUITour: function() {},
+      OpenURL: sinon.stub(),
       "Rooms:Create": sinon.stub().returns({ roomToken: "fakeToken" }),
       "Rooms:Delete": sinon.stub(),
       "Rooms:GetAll": sinon.stub(),
       "Rooms:Open": sinon.stub(),
       "Rooms:Rename": sinon.stub(),
       "Rooms:PushSubscription": sinon.stub(),
       TelemetryAddValue: sinon.stub()
     });
@@ -508,16 +510,53 @@ describe("loop.store.RoomStore", functio
         }));
 
         sinon.assert.calledOnce(sharedUtils.composeCallUrlEmail);
         sinon.assert.calledWithExactly(sharedUtils.composeCallUrlEmail,
           url, null, description);
       });
     });
 
+    describe("#facebookShareRoomUrl", function() {
+      var getLoopPrefStub;
+
+      beforeEach(function() {
+        getLoopPrefStub = function() {
+          return "https://shared.site/?u=%ROOM_URL%";
+        };
+
+        LoopMochaUtils.stubLoopRequest({
+          GetLoopPref: getLoopPrefStub
+        });
+      });
+
+      it("should open the facebook url with room URL", function() {
+
+        store.facebookShareRoomUrl(new sharedActions.FacebookShareRoomUrl({
+          from: "conversation",
+          roomUrl: "http://invalid"
+        }));
+
+        sinon.assert.calledOnce(requestStubs.OpenURL);
+        sinon.assert.calledWithExactly(requestStubs.OpenURL, "https://shared.site/?u=http%3A%2F%2Finvalid");
+      });
+
+      it("should send a telemetry event for facebook share from conversation", function() {
+        store.facebookShareRoomUrl(new sharedActions.FacebookShareRoomUrl({
+          from: "conversation",
+          roomUrl: "http://invalid"
+        }));
+
+        sinon.assert.calledOnce(requestStubs.TelemetryAddValue);
+        sinon.assert.calledWithExactly(requestStubs.TelemetryAddValue,
+          "LOOP_SHARING_ROOM_URL", 4);
+      });
+
+    });
+
     describe("#shareRoomUrl", function() {
       var socialShareRoomStub;
 
       beforeEach(function() {
         socialShareRoomStub = sinon.stub();
         LoopMochaUtils.stubLoopRequest({
           SocialShareRoom: socialShareRoomStub
         });
--- a/browser/extensions/loop/test/desktop-local/roomViews_test.js
+++ b/browser/extensions/loop/test/desktop-local/roomViews_test.js
@@ -241,16 +241,37 @@ describe("loop.roomViews", function() {
         sinon.assert.calledWith(dispatcher.dispatch,
           new sharedActions.EmailRoomUrl({
             roomUrl: url,
             roomDescription: "www.mozilla.com",
             from: "conversation"
           }));
       });
 
+    it("should dispatch a FacebookShareRoomUrl action when the facebook button is clicked",
+      function() {
+        var url = "http://invalid";
+        view = mountTestComponent({
+          roomData: {
+            roomUrl: url
+          }
+        });
+
+        var facebookBtn = view.getDOMNode().querySelector(".btn-facebook");
+
+        React.addons.TestUtils.Simulate.click(facebookBtn);
+
+        sinon.assert.calledOnce(dispatcher.dispatch);
+        sinon.assert.calledWith(dispatcher.dispatch,
+          new sharedActions.FacebookShareRoomUrl({
+            from: "conversation",
+            roomUrl: url
+          }));
+    });
+
     describe("Copy Button", function() {
       beforeEach(function() {
         view = mountTestComponent();
       });
 
       it("should dispatch a CopyRoomUrl action when the copy button is pressed", function() {
         var copyBtn = view.getDOMNode().querySelector(".btn-copy");
         React.addons.TestUtils.Simulate.click(copyBtn);
--- a/browser/locales/en-US/chrome/browser/loop/loop.properties
+++ b/browser/locales/en-US/chrome/browser/loop/loop.properties
@@ -47,17 +47,17 @@ invite_header_text2=Invite a friend to j
 invite_header_text_bold=Invite someone to browse this page with you!
 invite_header_text3=It takes two to use Firefox Hello, so send a friend a link to browse the Web with you!
 ## LOCALIZATION_NOTE(invite_copy_link_button, invite_copied_link_button,
 ## invite_email_link_button, invite_facebook_button2): These labels appear under
 ## an iconic button for the invite view.
 invite_copy_link_button=Copy Link
 invite_copied_link_button=Copied!
 invite_email_link_button=Email Link
-invite_facebook_button2=Share on Facebook
+invite_facebook_button3=Facebook
 invite_your_link=Your link:
 
 # Status text
 display_name_guest=Guest
 
 # Error bars
 ## LOCALIZATION NOTE(session_expired_error_description,could_not_authenticate,password_changed_question,try_again_later,could_not_connect,check_internet_connection,login_expired,service_not_available,problem_accessing_account):
 ## These may be displayed at the top of the panel.
rename from devtools/client/styleinspector/computed-view.js
rename to devtools/client/inspector/computed/computed.js
rename from devtools/client/styleinspector/computedview.xhtml
rename to devtools/client/inspector/computed/computed.xhtml
--- a/devtools/client/styleinspector/computedview.xhtml
+++ b/devtools/client/inspector/computed/computed.xhtml
@@ -26,17 +26,17 @@
       class="theme-sidebar">
 
   <head>
 
     <title>&computedViewTitle;</title>
 
     <link rel="stylesheet" href="chrome://global/skin/global.css"  type="text/css"/>
     <link rel="stylesheet" href="chrome://devtools/skin/common.css"  type="text/css"/>
-    <link rel="stylesheet" href="chrome://devtools/skin/computedview.css"  type="text/css"/>
+    <link rel="stylesheet" href="chrome://devtools/skin/computed.css"  type="text/css"/>
 
     <script type="application/javascript;version=1.8" src="chrome://devtools/content/shared/theme-switching.js"/>
 
     <script type="application/javascript;version=1.8">
       window.setPanel = function(panel, iframe) {
         let {require} = Components.utils.import("resource://devtools/shared/Loader.jsm", {});
         let inspector = require("devtools/client/styleinspector/style-inspector");
         this.computedview = new inspector.ComputedViewTool(panel, window);
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/computed/moz.build
@@ -0,0 +1,11 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DevToolsModules(
+    'computed.js',
+)
+
+BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/computed/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/computed/test/browser.ini
@@ -0,0 +1,32 @@
+[DEFAULT]
+tags = devtools
+subsuite = devtools
+support-files =
+  doc_matched_selectors.html
+  doc_media_queries.html
+  doc_pseudoelement.html
+  doc_sourcemaps.css
+  doc_sourcemaps.css.map
+  doc_sourcemaps.html
+  doc_sourcemaps.scss
+  head.js
+
+[browser_computed_browser-styles.js]
+[browser_computed_cycle_color.js]
+[browser_computed_getNodeInfo.js]
+[browser_computed_keybindings_01.js]
+[browser_computed_keybindings_02.js]
+[browser_computed_matched-selectors-toggle.js]
+[browser_computed_matched-selectors_01.js]
+[browser_computed_matched-selectors_02.js]
+[browser_computed_media-queries.js]
+[browser_computed_no-results-placeholder.js]
+[browser_computed_original-source-link.js]
+[browser_computed_pseudo-element_01.js]
+[browser_computed_refresh-on-style-change_01.js]
+[browser_computed_search-filter.js]
+[browser_computed_search-filter_clear.js]
+[browser_computed_search-filter_context-menu.js]
+[browser_computed_search-filter_escape-keypress.js]
+[browser_computed_select-and-copy-styles.js]
+[browser_computed_style-editor-link.js]
rename from devtools/client/styleinspector/test/browser_computedview_browser-styles.js
rename to devtools/client/inspector/computed/test/browser_computed_browser-styles.js
rename from devtools/client/styleinspector/test/browser_computedview_cycle_color.js
rename to devtools/client/inspector/computed/test/browser_computed_cycle_color.js
rename from devtools/client/styleinspector/test/browser_computedview_getNodeInfo.js
rename to devtools/client/inspector/computed/test/browser_computed_getNodeInfo.js
rename from devtools/client/styleinspector/test/browser_computedview_keybindings_01.js
rename to devtools/client/inspector/computed/test/browser_computed_keybindings_01.js
rename from devtools/client/styleinspector/test/browser_computedview_keybindings_02.js
rename to devtools/client/inspector/computed/test/browser_computed_keybindings_02.js
rename from devtools/client/styleinspector/test/browser_computedview_matched-selectors-toggle.js
rename to devtools/client/inspector/computed/test/browser_computed_matched-selectors-toggle.js
rename from devtools/client/styleinspector/test/browser_computedview_matched-selectors_01.js
rename to devtools/client/inspector/computed/test/browser_computed_matched-selectors_01.js
--- a/devtools/client/styleinspector/test/browser_computedview_matched-selectors_01.js
+++ b/devtools/client/inspector/computed/test/browser_computed_matched-selectors_01.js
@@ -1,17 +1,18 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Checking selector counts, matched rules and titles in the computed-view.
 
-const {PropertyView} = require("devtools/client/styleinspector/computed-view");
+const {PropertyView} =
+      require("devtools/client/inspector/computed/computed");
 const TEST_URI = TEST_URL_ROOT + "doc_matched_selectors.html";
 
 add_task(function*() {
   yield addTab(TEST_URI);
   let {inspector, view} = yield openComputedView();
 
   yield selectNode("#test", inspector);
   yield testMatchedSelectors(view, inspector);
rename from devtools/client/styleinspector/test/browser_computedview_matched-selectors_02.js
rename to devtools/client/inspector/computed/test/browser_computed_matched-selectors_02.js
rename from devtools/client/styleinspector/test/browser_computedview_media-queries.js
rename to devtools/client/inspector/computed/test/browser_computed_media-queries.js
--- a/devtools/client/styleinspector/test/browser_computedview_media-queries.js
+++ b/devtools/client/inspector/computed/test/browser_computed_media-queries.js
@@ -4,17 +4,17 @@
 
 "use strict";
 
 // Tests that we correctly display appropriate media query titles in the
 // property view.
 
 const TEST_URI = TEST_URL_ROOT + "doc_media_queries.html";
 
-var {PropertyView} = require("devtools/client/styleinspector/computed-view");
+var {PropertyView} = require("devtools/client/inspector/computed/computed");
 var {CssLogic} = require("devtools/shared/styleinspector/css-logic");
 
 add_task(function*() {
   yield addTab(TEST_URI);
   let {inspector, view} = yield openComputedView();
   yield selectNode("div", inspector);
   yield checkPropertyView(view);
 });
rename from devtools/client/styleinspector/test/browser_computedview_no-results-placeholder.js
rename to devtools/client/inspector/computed/test/browser_computed_no-results-placeholder.js
rename from devtools/client/styleinspector/test/browser_computedview_original-source-link.js
rename to devtools/client/inspector/computed/test/browser_computed_original-source-link.js
rename from devtools/client/styleinspector/test/browser_computedview_pseudo-element_01.js
rename to devtools/client/inspector/computed/test/browser_computed_pseudo-element_01.js
rename from devtools/client/styleinspector/test/browser_computedview_refresh-on-style-change_01.js
rename to devtools/client/inspector/computed/test/browser_computed_refresh-on-style-change_01.js
rename from devtools/client/styleinspector/test/browser_computedview_search-filter.js
rename to devtools/client/inspector/computed/test/browser_computed_search-filter.js
rename from devtools/client/styleinspector/test/browser_computedview_search-filter_clear.js
rename to devtools/client/inspector/computed/test/browser_computed_search-filter_clear.js
rename from devtools/client/styleinspector/test/browser_computedview_search-filter_context-menu.js
rename to devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js
rename from devtools/client/styleinspector/test/browser_computedview_search-filter_escape-keypress.js
rename to devtools/client/inspector/computed/test/browser_computed_search-filter_escape-keypress.js
rename from devtools/client/styleinspector/test/browser_computedview_select-and-copy-styles.js
rename to devtools/client/inspector/computed/test/browser_computed_select-and-copy-styles.js
rename from devtools/client/styleinspector/test/browser_computedview_style-editor-link.js
rename to devtools/client/inspector/computed/test/browser_computed_style-editor-link.js
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/computed/test/doc_matched_selectors.html
@@ -0,0 +1,28 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+  <head>
+    <style>
+      .matched1, .matched2, .matched3, .matched4, .matched5 {
+        color: #000;
+      }
+
+      div {
+        position: absolute;
+        top: 40px;
+        left: 20px;
+        border: 1px solid #000;
+        color: #111;
+        width: 100px;
+        height: 50px;
+      }
+    </style>
+  </head>
+  <body>
+    inspectstyle($("test"));
+    <div id="test" class="matched1 matched2 matched3 matched4 matched5">Test div</div>
+    <div id="dummy">
+      <div></div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/computed/test/doc_media_queries.html
@@ -0,0 +1,24 @@
+<html>
+<head>
+  <title>test</title>
+  <script type="application/javascript;version=1.7">
+
+  </script>
+  <style>
+    div {
+      width: 1000px;
+      height: 100px;
+      background-color: #f00;
+    }
+
+    @media screen and (min-width: 1px) {
+      div {
+        width: 200px;
+      }
+    }
+  </style>
+</head>
+<body>
+<div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/computed/test/doc_pseudoelement.html
@@ -0,0 +1,131 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+  <head>
+    <style>
+
+body {
+    color: #333;
+}
+
+.box {
+    float:left;
+    width: 128px;
+    height: 128px;
+    background: #ddd;
+    padding: 32px;
+    margin: 32px;
+    position:relative;
+}
+
+.box:first-line {
+    color: orange;
+    background: red;
+}
+
+.box:first-letter {
+    color: green;
+}
+
+* {
+    cursor: default;
+}
+
+nothing {
+    cursor: pointer;
+}
+
+p::-moz-selection {
+    color: white;
+    background: black;
+}
+p::selection {
+    color: white;
+    background: black;
+}
+
+p:first-line {
+   background: blue;
+}
+p:first-letter {
+  color: red;
+  font-size: 130%;
+}
+
+.box:before {
+    background: green;
+    content: " ";
+    position: absolute;
+    height:32px;
+    width:32px;
+}
+
+.box:after {
+    background: red;
+    content: " ";
+    position: absolute;
+    border-radius: 50%;
+    height:32px;
+    width:32px;
+    top: 50%;
+    left: 50%;
+    margin-top: -16px;
+    margin-left: -16px;
+}
+
+.topleft:before {
+    top:0;
+    left:0;
+}
+
+.topleft:first-line {
+    color: orange;
+}
+.topleft::selection {
+    color: orange;
+}
+
+.topright:before {
+    top:0;
+    right:0;
+}
+
+.bottomright:before {
+    bottom:10px;
+    right:10px;
+    color: red;
+}
+
+.bottomright:before {
+    bottom:0;
+    right:0;
+}
+
+.bottomleft:before {
+    bottom:0;
+    left:0;
+}
+
+    </style>
+  </head>
+  <body>
+    <h1>ruleview pseudoelement($("test"));</h1>
+
+    <div id="topleft" class="box topleft">
+        <p>Top Left<br />Position</p>
+    </div>
+
+    <div id="topright" class="box topright">
+        <p>Top Right<br />Position</p>
+    </div>
+
+    <div id="bottomright" class="box bottomright">
+        <p>Bottom Right<br />Position</p>
+    </div>
+
+    <div id="bottomleft" class="box bottomleft">
+        <p>Bottom Left<br />Position</p>
+    </div>
+
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/computed/test/doc_sourcemaps.css
@@ -0,0 +1,7 @@
+div {
+  color: #ff0066; }
+
+span {
+  background-color: #EEE; }
+
+/*# sourceMappingURL=doc_sourcemaps.css.map */
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/computed/test/doc_sourcemaps.css.map
@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": "AAGA,GAAI;EACF,KAAK,EAHU,OAAI;;AAMrB,IAAK;EACH,gBAAgB,EAAE,IAAI",
+"sources": ["doc_sourcemaps.scss"],
+"names": [],
+"file": "doc_sourcemaps.css"
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/computed/test/doc_sourcemaps.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<html>
+<head>
+  <title>testcase for testing CSS source maps</title>
+  <link rel="stylesheet" type="text/css" href="simple.css"/>
+  <link rel="stylesheet" type="text/css" href="doc_sourcemaps.css"/>
+</head>
+<body>
+	<div>source maps <span>testcase</span></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/computed/test/doc_sourcemaps.scss
@@ -0,0 +1,10 @@
+
+$paulrougetpink: #f06;
+
+div {
+  color: $paulrougetpink;
+}
+
+span {
+  background-color: #EEE;
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/computed/test/head.js
@@ -0,0 +1,610 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+let Cu = Components.utils;
+let {gDevTools} = Cu.import("resource://devtools/client/framework/gDevTools.jsm", {});
+let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
+let {TargetFactory} = require("devtools/client/framework/target");
+let {CssComputedView} =
+    require("devtools/client/inspector/computed/computed");
+let DevToolsUtils = require("devtools/shared/DevToolsUtils");
+let promise = require("promise");
+let {console} =
+  Components.utils.import("resource://gre/modules/Console.jsm", {});
+
+// All tests are asynchronous
+waitForExplicitFinish();
+
+const TEST_URL_ROOT =
+  "http://example.com/browser/devtools/client/inspector/computed/test/";
+const TEST_URL_ROOT_SSL =
+  "https://example.com/browser/devtools/client/inspector/computed/test/";
+const ROOT_TEST_DIR = getRootDirectory(gTestPath);
+const FRAME_SCRIPT_URL = ROOT_TEST_DIR + "doc_frame_script.js";
+
+// Auto clean-up when a test ends
+registerCleanupFunction(function*() {
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  yield gDevTools.closeToolbox(target);
+
+  while (gBrowser.tabs.length > 1) {
+    gBrowser.removeCurrentTab();
+  }
+});
+
+// Uncomment this pref to dump all devtools emitted events to the console.
+// Services.prefs.setBoolPref("devtools.dump.emit", true);
+
+// Set the testing flag on gDevTools and reset it when the test ends
+DevToolsUtils.testing = true;
+registerCleanupFunction(() => DevToolsUtils.testing = false);
+
+// Clean-up all prefs that might have been changed during a test run
+// (safer here because if the test fails, then the pref is never reverted)
+registerCleanupFunction(() => {
+  Services.prefs.clearUserPref("devtools.inspector.activeSidebar");
+  Services.prefs.clearUserPref("devtools.dump.emit");
+  Services.prefs.clearUserPref("devtools.defaultColorUnit");
+});
+
+/**
+ * The functions found below are here to ease test development and maintenance.
+ * Most of these functions are stateless and will require some form of context
+ * (the instance of the current toolbox, or inspector panel for instance).
+ *
+ * Most of these functions are async too and return promises.
+ *
+ * All tests should follow the following pattern:
+ *
+ * add_task(function*() {
+ *   yield addTab(TEST_URI);
+ *   let {toolbox, inspector, view} = yield openComputedView();
+ *
+ *   yield selectNode("#test", inspector);
+ *   yield someAsyncTestFunction(view);
+ * });
+ *
+ * add_task is the way to define the testcase in the test file. It accepts
+ * a single generator-function argument.
+ * The generator function should yield any async call.
+ *
+ * There is no need to clean tabs up at the end of a test as this is done
+ * automatically.
+ *
+ * It is advised not to store any references on the global scope. There
+ * shouldn't be a need to anyway. Thanks to add_task, test steps, even
+ * though asynchronous, can be described in a nice flat way, and
+ * if/for/while/... control flow can be used as in sync code, making it
+ * possible to write the outline of the test case all in add_task, and delegate
+ * actual processing and assertions to other functions.
+ */
+
+/* *********************************************
+ * UTILS
+ * *********************************************
+ * General test utilities.
+ * Add new tabs, open the toolbox and switch to the various panels, select
+ * nodes, get node references, ...
+ */
+
+/**
+ * Add a new test tab in the browser and load the given url.
+ *
+ * @param {String} url
+ *        The url to be loaded in the new tab
+ * @return a promise that resolves to the tab object when the url is loaded
+ */
+function addTab(url) {
+  info("Adding a new tab with URL: '" + url + "'");
+  let def = promise.defer();
+
+  window.focus();
+
+  let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
+  let browser = tab.linkedBrowser;
+
+  info("Loading the helper frame script " + FRAME_SCRIPT_URL);
+  browser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false);
+
+  browser.addEventListener("load", function onload() {
+    browser.removeEventListener("load", onload, true);
+    info("URL '" + url + "' loading complete");
+
+    def.resolve(tab);
+  }, true);
+
+  return def.promise;
+}
+
+/**
+ * Simple DOM node accesor function that takes either a node or a string css
+ * selector as argument and returns the corresponding node
+ *
+ * @param {String|DOMNode} nodeOrSelector
+ * @return {DOMNode|CPOW} Note that in e10s mode a CPOW object is returned which
+ * doesn't implement *all* of the DOMNode's properties
+ */
+function getNode(nodeOrSelector) {
+  info("Getting the node for '" + nodeOrSelector + "'");
+  return typeof nodeOrSelector === "string" ?
+    content.document.querySelector(nodeOrSelector) :
+    nodeOrSelector;
+}
+
+/**
+ * Get the NodeFront for a given css selector, via the protocol
+ *
+ * @param {String} selector
+ * @param {InspectorPanel} inspector
+ *        The instance of InspectorPanel currently loaded in the toolbox
+ * @return {Promise} Resolves to the NodeFront instance
+ */
+function getNodeFront(selector, {walker}) {
+  return walker.querySelector(walker.rootNode, selector);
+}
+
+/*
+ * Set the inspector's current selection to a node or to the first match of the
+ * given css selector.
+ *
+ * @param {String|NodeFront} data
+ *        The node to select
+ * @param {InspectorPanel} inspector
+ *        The instance of InspectorPanel currently loaded in the toolbox
+ * @param {String} reason
+ *        Defaults to "test" which instructs the inspector not
+ *        to highlight the node upon selection
+ * @return {Promise} Resolves when the inspector is updated with the new node
+ */
+var selectNode = Task.async(function*(data, inspector, reason="test") {
+  info("Selecting the node for '" + data + "'");
+  let nodeFront = data;
+  if (!data._form) {
+    nodeFront = yield getNodeFront(data, inspector);
+  }
+  let updated = inspector.once("inspector-updated");
+  inspector.selection.setNodeFront(nodeFront, reason);
+  yield updated;
+});
+
+/**
+ * Open the toolbox, with the inspector tool visible.
+ *
+ * @return a promise that resolves when the inspector is ready
+ */
+var openInspector = Task.async(function*() {
+  info("Opening the inspector");
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+
+  let inspector, toolbox;
+
+  // Checking if the toolbox and the inspector are already loaded
+  // The inspector-updated event should only be waited for if the inspector
+  // isn't loaded yet
+  toolbox = gDevTools.getToolbox(target);
+  if (toolbox) {
+    inspector = toolbox.getPanel("inspector");
+    if (inspector) {
+      info("Toolbox and inspector already open");
+      return {
+        toolbox: toolbox,
+        inspector: inspector
+      };
+    }
+  }
+
+  info("Opening the toolbox");
+  toolbox = yield gDevTools.showToolbox(target, "inspector");
+  yield waitForToolboxFrameFocus(toolbox);
+  inspector = toolbox.getPanel("inspector");
+
+  info("Waiting for the inspector to update");
+  yield inspector.once("inspector-updated");
+
+  return {
+    toolbox: toolbox,
+    inspector: inspector
+  };
+});
+
+/**
+ * Wait for the toolbox frame to receive focus after it loads
+ *
+ * @param {Toolbox} toolbox
+ * @return a promise that resolves when focus has been received
+ */
+function waitForToolboxFrameFocus(toolbox) {
+  info("Making sure that the toolbox's frame is focused");
+  let def = promise.defer();
+  let win = toolbox.frame.contentWindow;
+  waitForFocus(def.resolve, win);
+  return def.promise;
+}
+
+/**
+ * Open the toolbox, with the inspector tool visible, and the sidebar that
+ * corresponds to the given id selected
+ *
+ * @return a promise that resolves when the inspector is ready and the sidebar
+ * view is visible and ready
+ */
+var openInspectorSideBar = Task.async(function*(id) {
+  let {toolbox, inspector} = yield openInspector();
+
+  if (!hasSideBarTab(inspector, id)) {
+    info("Waiting for the " + id + " sidebar to be ready");
+    yield inspector.sidebar.once(id + "-ready");
+  }
+
+  info("Selecting the " + id + " sidebar");
+  inspector.sidebar.select(id);
+
+  return {
+    toolbox: toolbox,
+    inspector: inspector,
+    view: inspector.sidebar.getWindowForTab(id)[id].view
+  };
+});
+
+/**
+ * Open the toolbox, with the inspector tool visible, and the computed-view
+ * sidebar tab selected.
+ *
+ * @return a promise that resolves when the inspector is ready and the computed
+ * view is visible and ready
+ */
+function openComputedView() {
+  return openInspectorSideBar("computedview");
+}
+
+/**
+ * Wait for eventName on target to be delivered a number of times.
+ *
+ * @param {Object} target
+ *        An observable object that either supports on/off or
+ *        addEventListener/removeEventListener
+ * @param {String} eventName
+ * @param {Number} numTimes
+ *        Number of deliveries to wait for.
+ * @param {Boolean} useCapture
+ *        Optional, for addEventListener/removeEventListener
+ * @return A promise that resolves when the event has been handled
+ */
+function waitForNEvents(target, eventName, numTimes, useCapture = false) {
+  info("Waiting for event: '" + eventName + "' on " + target + ".");
+
+  let deferred = promise.defer();
+  let count = 0;
+
+  for (let [add, remove] of [
+    ["addEventListener", "removeEventListener"],
+    ["addListener", "removeListener"],
+    ["on", "off"]
+  ]) {
+    if ((add in target) && (remove in target)) {
+      target[add](eventName, function onEvent(...aArgs) {
+        if (++count == numTimes) {
+          target[remove](eventName, onEvent, useCapture);
+          deferred.resolve.apply(deferred, aArgs);
+        }
+      }, useCapture);
+      break;
+    }
+  }
+
+  return deferred.promise;
+}
+
+/**
+ * Wait for eventName on target.
+ *
+ * @param {Object} target
+ *        An observable object that either supports on/off or
+ *        addEventListener/removeEventListener
+ * @param {String} eventName
+ * @param {Boolean} useCapture
+ *        Optional, for addEventListener/removeEventListener
+ * @return A promise that resolves when the event has been handled
+ */
+function once(target, eventName, useCapture=false) {
+  return waitForNEvents(target, eventName, 1, useCapture);
+}
+
+/**
+ * This shouldn't be used in the tests, but is useful when writing new tests or
+ * debugging existing tests in order to introduce delays in the test steps
+ *
+ * @param {Number} ms
+ *        The time to wait
+ * @return A promise that resolves when the time is passed
+ */
+function wait(ms) {
+  let def = promise.defer();
+  content.setTimeout(def.resolve, ms);
+  return def.promise;
+}
+
+/**
+ * Listen for a new tab to open and return a promise that resolves when one
+ * does and completes the load event.
+ *
+ * @return a promise that resolves to the tab object
+ */
+var waitForTab = Task.async(function*() {
+  info("Waiting for a tab to open");
+  yield once(gBrowser.tabContainer, "TabOpen");
+  let tab = gBrowser.selectedTab;
+  let browser = tab.linkedBrowser;
+  yield once(browser, "load", true);
+  info("The tab load completed");
+  return tab;
+});
+
+/**
+ * @see SimpleTest.waitForClipboard
+ *
+ * @param {Function} setup
+ *        Function to execute before checking for the
+ *        clipboard content
+ * @param {String|Boolean} expected
+ *        An expected string or validator function
+ * @return a promise that resolves when the expected string has been found or
+ * the validator function has returned true, rejects otherwise.
+ */
+function waitForClipboard(setup, expected) {
+  let def = promise.defer();
+  SimpleTest.waitForClipboard(expected, setup, def.resolve, def.reject);
+  return def.promise;
+}
+
+/**
+ * Dispatch the copy event on the given element
+ */
+function fireCopyEvent(element) {
+  let evt = element.ownerDocument.createEvent("Event");
+  evt.initEvent("copy", true, true);
+  element.dispatchEvent(evt);
+}
+
+/**
+ * Checks whether the inspector's sidebar corresponding to the given id already
+ * exists
+ *
+ * @param {InspectorPanel}
+ * @param {String}
+ * @return {Boolean}
+ */
+function hasSideBarTab(inspector, id) {
+  return !!inspector.sidebar.getWindowForTab(id);
+}
+
+/**
+ * Simulate the key input for the given input in the window.
+ *
+ * @param {String} input
+ *        The string value to input
+ * @param {Window} win
+ *        The window containing the panel
+ */
+function synthesizeKeys(input, win) {
+  for (let key of input.split("")) {
+    EventUtils.synthesizeKey(key, {}, win);
+  }
+}
+
+/* *********************************************
+ * COMPUTED-VIEW
+ * *********************************************
+ * Computed-view related utility functions.
+ * Allows to get properties, links, expand properties, ...
+ */
+
+/**
+ * Get references to the name and value span nodes corresponding to a given
+ * property name in the computed-view
+ *
+ * @param {CssComputedView} view
+ *        The instance of the computed view panel
+ * @param {String} name
+ *        The name of the property to retrieve
+ * @return an object {nameSpan, valueSpan}
+ */
+function getComputedViewProperty(view, name) {
+  let prop;
+  for (let property of view.styleDocument.querySelectorAll(".property-view")) {
+    let nameSpan = property.querySelector(".property-name");
+    let valueSpan = property.querySelector(".property-value");
+
+    if (nameSpan.textContent === name) {
+      prop = {nameSpan: nameSpan, valueSpan: valueSpan};
+      break;
+    }
+  }
+  return prop;
+}
+
+/**
+ * Get an instance of PropertyView from the computed-view.
+ *
+ * @param {CssComputedView} view
+ *        The instance of the computed view panel
+ * @param {String} name
+ *        The name of the property to retrieve
+ * @return {PropertyView}
+ */
+function getComputedViewPropertyView(view, name) {
+  let propView;
+  for (let propertyView of view.propertyViews) {
+    if (propertyView._propertyInfo.name === name) {
+      propView = propertyView;
+      break;
+    }
+  }
+  return propView;
+}
+
+/**
+ * Get a reference to the property-content element for a given property name in
+ * the computed-view.
+ * A property-content element always follows (nextSibling) the property itself
+ * and is only shown when the twisty icon is expanded on the property.
+ * A property-content element contains matched rules, with selectors,
+ * properties, values and stylesheet links
+ *
+ * @param {CssComputedView} view
+ *        The instance of the computed view panel
+ * @param {String} name
+ *        The name of the property to retrieve
+ * @return {Promise} A promise that resolves to the property matched rules
+ * container
+ */
+var getComputedViewMatchedRules = Task.async(function*(view, name) {
+  let expander;
+  let propertyContent;
+  for (let property of view.styleDocument.querySelectorAll(".property-view")) {
+    let nameSpan = property.querySelector(".property-name");
+    if (nameSpan.textContent === name) {
+      expander = property.querySelector(".expandable");
+      propertyContent = property.nextSibling;
+      break;
+    }
+  }
+
+  if (!expander.hasAttribute("open")) {
+    // Need to expand the property
+    let onExpand = view.inspector.once("computed-view-property-expanded");
+    expander.click();
+    yield onExpand;
+  }
+
+  return propertyContent;
+});
+
+/**
+ * Get the text value of the property corresponding to a given name in the
+ * computed-view
+ *
+ * @param {CssComputedView} view
+ *        The instance of the computed view panel
+ * @param {String} name
+ *        The name of the property to retrieve
+ * @return {String} The property value
+ */
+function getComputedViewPropertyValue(view, name, propertyName) {
+  return getComputedViewProperty(view, name, propertyName)
+    .valueSpan.textContent;
+}
+
+/**
+ * Expand a given property, given its index in the current property list of
+ * the computed view
+ *
+ * @param {CssComputedView} view
+ *        The instance of the computed view panel
+ * @param {Number} index
+ *        The index of the property to be expanded
+ * @return a promise that resolves when the property has been expanded, or
+ * rejects if the property was not found
+ */
+function expandComputedViewPropertyByIndex(view, index) {
+  info("Expanding property " + index + " in the computed view");
+  let expandos = view.styleDocument.querySelectorAll(".expandable");
+  if (!expandos.length || !expandos[index]) {
+    return promise.reject();
+  }
+
+  let onExpand = view.inspector.once("computed-view-property-expanded");
+  expandos[index].click();
+  return onExpand;
+}
+
+/**
+ * Get a rule-link from the computed-view given its index
+ *
+ * @param {CssComputedView} view
+ *        The instance of the computed view panel
+ * @param {Number} index
+ *        The index of the link to be retrieved
+ * @return {DOMNode} The link at the given index, if one exists, null otherwise
+ */
+function getComputedViewLinkByIndex(view, index) {
+  let links = view.styleDocument.querySelectorAll(".rule-link .link");
+  return links[index];
+}
+
+/* *********************************************
+ * STYLE-EDITOR
+ * *********************************************
+ * Style-editor related utility functions.
+ */
+
+/**
+ * Wait for the toolbox to emit the styleeditor-selected event and when done
+ * wait for the stylesheet identified by href to be loaded in the stylesheet
+ * editor
+ *
+ * @param {Toolbox} toolbox
+ * @param {String} href
+ *        Optional, if not provided, wait for the first editor to be ready
+ * @return a promise that resolves to the editor when the stylesheet editor is
+ * ready
+ */
+function waitForStyleEditor(toolbox, href) {
+  let def = promise.defer();
+
+  info("Waiting for the toolbox to switch to the styleeditor");
+  toolbox.once("styleeditor-selected").then(() => {
+    let panel = toolbox.getCurrentPanel();
+    ok(panel && panel.UI, "Styleeditor panel switched to front");
+
+    // A helper that resolves the promise once it receives an editor that
+    // matches the expected href. Returns false if the editor was not correct.
+    let gotEditor = (event, editor) => {
+      let currentHref = editor.styleSheet.href;
+      if (!href || (href && currentHref.endsWith(href))) {
+        info("Stylesheet editor selected");
+        panel.UI.off("editor-selected", gotEditor);
+
+        editor.getSourceEditor().then(sourceEditor => {
+          info("Stylesheet editor fully loaded");
+          def.resolve(sourceEditor);
+        });
+
+        return true;
+      }
+
+      info("The editor was incorrect. Waiting for editor-selected event.");
+      return false;
+    };
+
+    // The expected editor may already be selected. Check the if the currently
+    // selected editor is the expected one and if not wait for an
+    // editor-selected event.
+    if (!gotEditor("styleeditor-selected", panel.UI.selectedEditor)) {
+      // The expected editor is not selected (yet). Wait for it.
+      panel.UI.on("editor-selected", gotEditor);
+    }
+  });
+
+  return def.promise;
+}
+
+/**
+ * Reload the current page and wait for the inspector to be initialized after
+ * the navigation
+ *
+ * @param {InspectorPanel} inspector
+ *        The instance of InspectorPanel currently loaded in the toolbox
+ * @return a promise that resolves after page reload and inspector
+ * initialization
+ */
+function reloadPage(inspector) {
+  let onNewRoot = inspector.once("new-root");
+  content.location.reload();
+  return onNewRoot.then(() => {
+    inspector.markup._waitForChildren();
+  });
+}
rename from devtools/client/fontinspector/font-inspector.css
rename to devtools/client/inspector/fonts/fonts.css
rename from devtools/client/fontinspector/font-inspector.js
rename to devtools/client/inspector/fonts/fonts.js
rename from devtools/client/fontinspector/font-inspector.xhtml
rename to devtools/client/inspector/fonts/fonts.xhtml
--- a/devtools/client/fontinspector/font-inspector.xhtml
+++ b/devtools/client/inspector/fonts/fonts.xhtml
@@ -6,23 +6,23 @@
 <!ENTITY % fontinspectorDTD SYSTEM "chrome://devtools/locale/font-inspector.dtd" >
  %fontinspectorDTD;
 ]>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
     <title>&title;</title>
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
-    <link rel="stylesheet" href="font-inspector.css" type="text/css"/>
+    <link rel="stylesheet" href="fonts.css" type="text/css"/>
     <link rel="stylesheet" href="chrome://devtools/skin/common.css" type="text/css"/>
-    <link rel="stylesheet" href="chrome://devtools/skin/font-inspector.css" type="text/css"/>
+    <link rel="stylesheet" href="chrome://devtools/skin/fonts.css" type="text/css"/>
     <script type="application/javascript;version=1.8" src="chrome://devtools/content/shared/theme-switching.js"/>
   </head>
   <body class="theme-sidebar devtools-monospace" role="application">
-    <script type="application/javascript;version=1.8" src="font-inspector.js"></script>
+    <script type="application/javascript;version=1.8" src="fonts.js"></script>
     <div>
       <div class="devtools-toolbar preview-input-toolbar">
         <div class="devtools-searchbox">
           <input id="preview-text-input"
                  class="devtools-textinput"
                  placeholder="&previewHint;"/>
         </div>
       </div>
rename from devtools/client/fontinspector/moz.build
rename to devtools/client/inspector/fonts/moz.build
--- a/devtools/client/fontinspector/moz.build
+++ b/devtools/client/inspector/fonts/moz.build
@@ -1,7 +1,11 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+DevToolsModules(
+    'fonts.js',
+)
+
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
rename from devtools/client/fontinspector/test/.eslintrc
rename to devtools/client/inspector/fonts/test/.eslintrc
--- a/devtools/client/fontinspector/test/.eslintrc
+++ b/devtools/client/inspector/fonts/test/.eslintrc
@@ -1,4 +1,4 @@
 {
   // Extend from the shared list of defined globals for mochitests.
-  "extends": "../../../.eslintrc.mochitests"
+  "extends": "../../../../.eslintrc.mochitests"
 }
rename from devtools/client/fontinspector/test/OstrichLicense.txt
rename to devtools/client/inspector/fonts/test/OstrichLicense.txt
rename from devtools/client/fontinspector/test/browser.ini
rename to devtools/client/inspector/fonts/test/browser.ini
rename from devtools/client/fontinspector/test/browser_fontinspector.html
rename to devtools/client/inspector/fonts/test/browser_fontinspector.html
rename from devtools/client/fontinspector/test/browser_fontinspector.js
rename to devtools/client/inspector/fonts/test/browser_fontinspector.js
rename from devtools/client/fontinspector/test/browser_fontinspector_edit-previews-show-all.js
rename to devtools/client/inspector/fonts/test/browser_fontinspector_edit-previews-show-all.js
rename from devtools/client/fontinspector/test/browser_fontinspector_edit-previews.js
rename to devtools/client/inspector/fonts/test/browser_fontinspector_edit-previews.js
rename from devtools/client/fontinspector/test/browser_fontinspector_theme-change.js
rename to devtools/client/inspector/fonts/test/browser_fontinspector_theme-change.js
rename from devtools/client/fontinspector/test/head.js
rename to devtools/client/inspector/fonts/test/head.js
--- a/devtools/client/fontinspector/test/head.js
+++ b/devtools/client/inspector/fonts/test/head.js
@@ -1,18 +1,19 @@
  /* 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/. */
+
 "use strict";
 
 // shared-head.js handles imports, constants, and utility functions
 Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js", this);
 
-const BASE_URI = "http://mochi.test:8888/browser/devtools/client/fontinspector/test/"
+const BASE_URI = "http://mochi.test:8888/browser/devtools/client/inspector/fonts/test/";
 
 /**
  * Open the toolbox, with the inspector tool visible.
  * @param {Function} cb Optional callback, if you don't want to use the returned
  * promise
  * @return a promise that resolves when the inspector is ready
  */
 var openInspector = Task.async(function*(cb) {
rename from devtools/client/fontinspector/test/ostrich-black.ttf
rename to devtools/client/inspector/fonts/test/ostrich-black.ttf
rename from devtools/client/fontinspector/test/ostrich-regular.ttf
rename to devtools/client/inspector/fonts/test/ostrich-regular.ttf
rename from devtools/client/fontinspector/test/test_iframe.html
rename to devtools/client/inspector/fonts/test/test_iframe.html
--- a/devtools/client/inspector/inspector-panel.js
+++ b/devtools/client/inspector/inspector-panel.js
@@ -348,31 +348,31 @@ InspectorPanel.prototype = {
 
     this._setDefaultSidebar = (event, toolId) => {
       Services.prefs.setCharPref("devtools.inspector.activeSidebar", toolId);
     };
 
     this.sidebar.on("select", this._setDefaultSidebar);
 
     this.sidebar.addTab("ruleview",
-                        "chrome://devtools/content/styleinspector/cssruleview.xhtml",
+                        "chrome://devtools/content/inspector/rules/rules.xhtml",
                         "ruleview" == defaultTab);
 
     this.sidebar.addTab("computedview",
-                        "chrome://devtools/content/styleinspector/computedview.xhtml",
+                        "chrome://devtools/content/inspector/computed/computed.xhtml",
                         "computedview" == defaultTab);
 
     if (Services.prefs.getBoolPref("devtools.fontinspector.enabled") && this.canGetUsedFontFaces) {
       this.sidebar.addTab("fontinspector",
-                          "chrome://devtools/content/fontinspector/font-inspector.xhtml",
+                          "chrome://devtools/content/inspector/fonts/fonts.xhtml",
                           "fontinspector" == defaultTab);
     }
 
     this.sidebar.addTab("layoutview",
-                        "chrome://devtools/content/layoutview/view.xhtml",
+                        "chrome://devtools/content/inspector/layout/layout.xhtml",
                         "layoutview" == defaultTab);
 
     if (this.target.form.animationsActor) {
       this.sidebar.addTab("animationinspector",
                           "chrome://devtools/content/animationinspector/animation-inspector.xhtml",
                           "animationinspector" == defaultTab);
     }
 
rename from devtools/client/layoutview/view.js
rename to devtools/client/inspector/layout/layout.js
rename from devtools/client/layoutview/view.xhtml
rename to devtools/client/inspector/layout/layout.xhtml
--- a/devtools/client/layoutview/view.xhtml
+++ b/devtools/client/inspector/layout/layout.xhtml
@@ -10,20 +10,20 @@
 <html xmlns="http://www.w3.org/1999/xhtml"
       xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <head>
     <title>&title;</title>
 
     <script type="application/javascript;version=1.8"
             src="chrome://devtools/content/shared/theme-switching.js"/>
 
-    <script type="application/javascript;version=1.8" src="view.js"></script>
+    <script type="application/javascript;version=1.8" src="layout.js"></script>
 
     <link rel="stylesheet" href="chrome://devtools/skin/common.css" type="text/css"/>
-    <link rel="stylesheet" href="chrome://devtools/skin/layoutview.css" type="text/css"/>
+    <link rel="stylesheet" href="chrome://devtools/skin/layout.css" type="text/css"/>
 
   </head>
   <body class="theme-sidebar devtools-monospace">
 
     <p id="header">
       <span id="element-size"></span><span id="element-position"></span>
     </p>
 
rename from devtools/client/layoutview/moz.build
rename to devtools/client/inspector/layout/moz.build
--- a/devtools/client/layoutview/moz.build
+++ b/devtools/client/inspector/layout/moz.build
@@ -1,8 +1,11 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+DevToolsModules(
+    'layout.js',
+)
+
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
-
rename from devtools/client/layoutview/test/.eslintrc
rename to devtools/client/inspector/layout/test/.eslintrc
--- a/devtools/client/layoutview/test/.eslintrc
+++ b/devtools/client/inspector/layout/test/.eslintrc
@@ -1,4 +1,4 @@
 {
   // Extend from the shared list of defined globals for mochitests.
-  "extends": "../../../.eslintrc.mochitests"
+  "extends": "../../../../.eslintrc.mochitests"
 }
rename from devtools/client/layoutview/test/browser.ini
rename to devtools/client/inspector/layout/test/browser.ini
--- a/devtools/client/layoutview/test/browser.ini
+++ b/devtools/client/inspector/layout/test/browser.ini
@@ -1,22 +1,22 @@
 [DEFAULT]
 tags = devtools
 skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
 subsuite = devtools
 support-files =
-  doc_layoutview_iframe1.html
-  doc_layoutview_iframe2.html
+  doc_layout_iframe1.html
+  doc_layout_iframe2.html
   head.js
 
-[browser_layoutview.js]
-[browser_layoutview_editablemodel.js]
-# [browser_layoutview_editablemodel_allproperties.js]
+[browser_layout.js]
+[browser_layout_editablemodel.js]
+# [browser_layout_editablemodel_allproperties.js]
 # Disabled for too many intermittent failures (bug 1009322)
-[browser_layoutview_editablemodel_border.js]
-[browser_layoutview_editablemodel_stylerules.js]
-[browser_layoutview_guides.js]
-[browser_layoutview_rotate-labels-on-sides.js]
-[browser_layoutview_tooltips.js]
-[browser_layoutview_update-after-navigation.js]
-[browser_layoutview_update-after-reload.js]
-# [browser_layoutview_update-in-iframes.js]
+[browser_layout_editablemodel_border.js]
+[browser_layout_editablemodel_stylerules.js]
+[browser_layout_guides.js]
+[browser_layout_rotate-labels-on-sides.js]
+[browser_layout_tooltips.js]
+[browser_layout_update-after-navigation.js]
+[browser_layout_update-after-reload.js]
+# [browser_layout_update-in-iframes.js]
 # Bug 1020038 layout-view updates for iframe elements changes
rename from devtools/client/layoutview/test/browser_layoutview.js
rename to devtools/client/inspector/layout/test/browser_layout.js
rename from devtools/client/layoutview/test/browser_layoutview_editablemodel.js
rename to devtools/client/inspector/layout/test/browser_layout_editablemodel.js
rename from devtools/client/layoutview/test/browser_layoutview_editablemodel_allproperties.js
rename to devtools/client/inspector/layout/test/browser_layout_editablemodel_allproperties.js
rename from devtools/client/layoutview/test/browser_layoutview_editablemodel_border.js
rename to devtools/client/inspector/layout/test/browser_layout_editablemodel_border.js
rename from devtools/client/layoutview/test/browser_layoutview_editablemodel_stylerules.js
rename to devtools/client/inspector/layout/test/browser_layout_editablemodel_stylerules.js
rename from devtools/client/layoutview/test/browser_layoutview_guides.js
rename to devtools/client/inspector/layout/test/browser_layout_guides.js
rename from devtools/client/layoutview/test/browser_layoutview_rotate-labels-on-sides.js
rename to devtools/client/inspector/layout/test/browser_layout_rotate-labels-on-sides.js
rename from devtools/client/layoutview/test/browser_layoutview_tooltips.js
rename to devtools/client/inspector/layout/test/browser_layout_tooltips.js
rename from devtools/client/layoutview/test/browser_layoutview_update-after-navigation.js
rename to devtools/client/inspector/layout/test/browser_layout_update-after-navigation.js
--- a/devtools/client/layoutview/test/browser_layoutview_update-after-navigation.js
+++ b/devtools/client/inspector/layout/test/browser_layout_update-after-navigation.js
@@ -3,17 +3,17 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test that the layout-view continues to work after a page navigation and that
 // it also works after going back
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_layoutview_iframe1.html");
+  yield addTab(TEST_URL_ROOT + "doc_layout_iframe1.html");
   let {toolbox, inspector, view} = yield openLayoutView();
   yield runTests(inspector, view);
 });
 
 addTest("Test that the layout-view works on the first page",
 function*(inspector, view) {
   info("Selecting the test node");
   yield selectNode("p", inspector);
@@ -29,17 +29,17 @@ function*(inspector, view) {
   ok(true, "Layout-view got updated");
 
   info("Checking that the layout-view shows the right value after update");
   is(paddingElt.textContent, "20");
 });
 
 addTest("Navigate to the second page",
 function*(inspector, view) {
-  yield navigateTo(TEST_URL_ROOT + "doc_layoutview_iframe2.html");
+  yield navigateTo(TEST_URL_ROOT + "doc_layout_iframe2.html");
   yield inspector.once("markuploaded");
 });
 
 addTest("Test that the layout-view works on the second page",
 function*(inspector, view) {
   info("Selecting the test node");
   yield selectNode("p", inspector);
 
rename from devtools/client/layoutview/test/browser_layoutview_update-after-reload.js
rename to devtools/client/inspector/layout/test/browser_layout_update-after-reload.js
--- a/devtools/client/layoutview/test/browser_layoutview_update-after-reload.js
+++ b/devtools/client/inspector/layout/test/browser_layout_update-after-reload.js
@@ -2,17 +2,17 @@
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test that the layout-view continues to work after the page is reloaded
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_layoutview_iframe1.html");
+  yield addTab(TEST_URL_ROOT + "doc_layout_iframe1.html");
   let {toolbox, inspector, view} = yield openLayoutView();
 
   info("Test that the layout-view works on the first page");
   yield assertLayoutView(inspector, view);
 
   info("Reload the page");
   content.location.reload();
   yield inspector.once("markuploaded");
rename from devtools/client/layoutview/test/browser_layoutview_update-in-iframes.js
rename to devtools/client/inspector/layout/test/browser_layout_update-in-iframes.js
--- a/devtools/client/layoutview/test/browser_layoutview_update-in-iframes.js
+++ b/devtools/client/inspector/layout/test/browser_layout_update-in-iframes.js
@@ -3,17 +3,17 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test that the layout-view for elements within iframes also updates when they
 // change
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_layoutview_iframe1.html");
+  yield addTab(TEST_URL_ROOT + "doc_layout_iframe1.html");
   let iframe2 = getNode("iframe").contentDocument.querySelector("iframe");
 
   let {toolbox, inspector, view} = yield openLayoutView();
   yield runTests(inspector, view, iframe2);
 });
 
 addTest("Test that resizing an element in an iframe updates its box model",
 function*(inspector, view, iframe2) {
rename from devtools/client/layoutview/test/doc_layoutview_iframe1.html
rename to devtools/client/inspector/layout/test/doc_layout_iframe1.html
rename from devtools/client/layoutview/test/doc_layoutview_iframe2.html
rename to devtools/client/inspector/layout/test/doc_layout_iframe2.html
rename from devtools/client/layoutview/test/head.js
rename to devtools/client/inspector/layout/test/head.js
--- a/devtools/client/layoutview/test/head.js
+++ b/devtools/client/inspector/layout/test/head.js
@@ -10,17 +10,18 @@ var {require} = Cu.import("resource://de
 var {console} = Cu.import("resource://gre/modules/Console.jsm", {});
 var {TargetFactory} = require("devtools/client/framework/target");
 var promise = require("promise");
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
 
 // All test are asynchronous
 waitForExplicitFinish();
 
-const TEST_URL_ROOT = "http://example.com/browser/devtools/client/layoutview/test/";
+const TEST_URL_ROOT =
+  "http://example.com/browser/devtools/client/inspector/layout/test/";
 
 // Uncomment this pref to dump all devtools emitted events to the console.
 // Services.prefs.setBoolPref("devtools.dump.emit", true);
 
 // Services.prefs.setBoolPref("devtools.debugger.log", true);
 
 // Set the testing flag on DevToolsUtils and reset it when the test ends
 DevToolsUtils.testing = true;
@@ -95,32 +96,31 @@ function getNode(nodeOrSelector) {
  */
 function selectAndHighlightNode(nodeOrSelector, inspector) {
   info("Highlighting and selecting the node " + nodeOrSelector);
 
   let node = getNode(nodeOrSelector);
   let updated = inspector.toolbox.once("highlighter-ready");
   inspector.selection.setNode(node, "test-highlight");
   return updated;
-
 }
 
 /**
  * Set the inspector's current selection to a node or to the first match of the
  * given css selector.
  * @param {String|DOMNode} nodeOrSelector
  * @param {InspectorPanel} inspector
  *        The instance of InspectorPanel currently loaded in the toolbox
  * @param {String} reason
  *        Defaults to "test" which instructs the inspector not to highlight the
  *        node upon selection
  * @return a promise that resolves when the inspector is updated with the new
  * node
  */
-function selectNode(nodeOrSelector, inspector, reason="test") {
+function selectNode(nodeOrSelector, inspector, reason = "test") {
   info("Selecting the node " + nodeOrSelector);
 
   let node = getNode(nodeOrSelector);
   let updated = inspector.once("inspector-updated");
   inspector.selection.setNode(node, reason);
   return updated;
 }
 
@@ -134,20 +134,20 @@ var openInspector = Task.async(function*
 
   let inspector, toolbox;
 
   // The actual highligher show/hide methods are mocked in layoutview tests.
   // The highlighter is tested in devtools/inspector/test.
   function mockHighlighter({highlighter}) {
     highlighter.showBoxModel = function(nodeFront, options) {
       return promise.resolve();
-    }
+    };
     highlighter.hideBoxModel = function() {
       return promise.resolve();
-    }
+    };
   }
 
   // Checking if the toolbox and the inspector are already loaded
   // The inspector-updated event should only be waited for if the inspector
   // isn't loaded yet
   toolbox = gDevTools.getToolbox(target);
   if (toolbox) {
     inspector = toolbox.getPanel("inspector");
@@ -242,17 +242,17 @@ function waitForUpdate(inspector) {
  * addTest("what this second test does", function*() {
  *   ... actual code for the second test ...
  * });
  * runTests().then(...);
  */
 var TESTS = [];
 
 function addTest(message, func) {
-  TESTS.push([message, Task.async(func)])
+  TESTS.push([message, Task.async(func)]);
 }
 
 var runTests = Task.async(function*(...args) {
   for (let [message, test] of TESTS) {
     info("Running new test case: " + message);
     yield test.apply(null, args);
   }
 });
--- a/devtools/client/inspector/moz.build
+++ b/devtools/client/inspector/moz.build
@@ -1,12 +1,19 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+DIRS += [
+    'computed',
+    'fonts',
+    'layout',
+    'rules'
+]
+
 DevToolsModules(
     'breadcrumbs.js',
     'inspector-commands.js',
     'inspector-panel.js',
     'inspector-search.js'
 )
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/moz.build
@@ -0,0 +1,11 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DevToolsModules(
+    'rules.js',
+)
+
+BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
rename from devtools/client/styleinspector/ruleview.css
rename to devtools/client/inspector/rules/rules.css
rename from devtools/client/styleinspector/rule-view.js
rename to devtools/client/inspector/rules/rules.js
rename from devtools/client/styleinspector/cssruleview.xhtml
rename to devtools/client/inspector/rules/rules.xhtml
--- a/devtools/client/styleinspector/cssruleview.xhtml
+++ b/devtools/client/inspector/rules/rules.xhtml
@@ -12,18 +12,18 @@
 
 <html xmlns="http://www.w3.org/1999/xhtml"
       xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
       class="theme-sidebar">
   <head>
     <title>&ruleViewTitle;</title>
     <link rel="stylesheet" href="chrome://global/skin/global.css"  type="text/css"/>
     <link rel="stylesheet" href="chrome://devtools/skin/common.css"  type="text/css"/>
-    <link rel="stylesheet" href="chrome://devtools/content/styleinspector/ruleview.css"  type="text/css"/>
-    <link rel="stylesheet" href="chrome://devtools/skin/ruleview.css"  type="text/css"/>
+    <link rel="stylesheet" href="chrome://devtools/content/inspector/rules/rules.css"  type="text/css"/>
+    <link rel="stylesheet" href="chrome://devtools/skin/rules.css"  type="text/css"/>
     <script type="application/javascript;version=1.8" src="chrome://devtools/content/shared/theme-switching.js"/>
     <script type="application/javascript;version=1.8">
       window.setPanel = function(panel, iframe) {
         let {require} = Components.utils.import("resource://devtools/shared/Loader.jsm", {});
         let inspector = require("devtools/client/styleinspector/style-inspector");
         this.ruleview = new inspector.RuleViewTool(panel, window);
       }
       window.onunload = function() {
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/test/browser.ini
@@ -0,0 +1,173 @@
+[DEFAULT]
+tags = devtools
+subsuite = devtools
+support-files =
+  doc_content_stylesheet.html
+  doc_content_stylesheet_imported.css
+  doc_content_stylesheet_imported2.css
+  doc_content_stylesheet_linked.css
+  doc_content_stylesheet_script.css
+  doc_copystyles.css
+  doc_copystyles.html
+  doc_cssom.html
+  doc_custom.html
+  doc_filter.html
+  doc_frame_script.js
+  doc_keyframeanimation.css
+  doc_keyframeanimation.html
+  doc_keyframeLineNumbers.html
+  doc_media_queries.html
+  doc_pseudoelement.html
+  doc_ruleLineNumbers.html
+  doc_sourcemaps.css
+  doc_sourcemaps.css.map
+  doc_sourcemaps.html
+  doc_sourcemaps.scss
+  doc_style_editor_link.css
+  doc_test_image.png
+  doc_urls_clickable.css
+  doc_urls_clickable.html
+  head.js
+
+[browser_rules_add-property-and-reselect.js]
+[browser_rules_add-property-cancel_01.js]
+[browser_rules_add-property-cancel_02.js]
+[browser_rules_add-property-cancel_03.js]
+[browser_rules_add-property_01.js]
+[browser_rules_add-property_02.js]
+[browser_rules_add-property-svg.js]
+[browser_rules_add-rule_01.js]
+[browser_rules_add-rule_02.js]
+[browser_rules_add-rule_03.js]
+[browser_rules_add-rule_04.js]
+[browser_rules_add-rule_pseudo_class.js]
+[browser_rules_authored.js]
+[browser_rules_colorpicker-and-image-tooltip_01.js]
+[browser_rules_colorpicker-and-image-tooltip_02.js]
+[browser_rules_colorpicker-appears-on-swatch-click.js]
+[browser_rules_colorpicker-commit-on-ENTER.js]
+[browser_rules_colorpicker-edit-gradient.js]
+[browser_rules_colorpicker-hides-on-tooltip.js]
+[browser_rules_colorpicker-multiple-changes.js]
+[browser_rules_colorpicker-release-outside-frame.js]
+[browser_rules_colorpicker-revert-on-ESC.js]
+[browser_rules_colorpicker-swatch-displayed.js]
+[browser_rules_colorUnit.js]
+[browser_rules_completion-existing-property_01.js]
+[browser_rules_completion-existing-property_02.js]
+[browser_rules_completion-new-property_01.js]
+[browser_rules_completion-new-property_02.js]
+[browser_rules_completion-new-property_03.js]
+[browser_rules_computed-lists_01.js]
+[browser_rules_computed-lists_02.js]
+[browser_rules_completion-popup-hidden-after-navigation.js]
+[browser_rules_content_01.js]
+[browser_rules_content_02.js]
+skip-if = e10s # Bug 1039528: "inspect element" contextual-menu doesn't work with e10s
+[browser_rules_context-menu-show-mdn-docs-01.js]
+[browser_rules_context-menu-show-mdn-docs-02.js]
+[browser_rules_context-menu-show-mdn-docs-03.js]
+[browser_rules_copy_styles.js]
+[browser_rules_cssom.js]
+[browser_rules_cubicbezier-appears-on-swatch-click.js]
+[browser_rules_cubicbezier-commit-on-ENTER.js]
+[browser_rules_cubicbezier-revert-on-ESC.js]
+[browser_rules_custom.js]
+[browser_rules_cycle-color.js]
+[browser_rules_edit-property-cancel.js]
+[browser_rules_edit-property-commit.js]
+[browser_rules_edit-property-computed.js]
+[browser_rules_edit-property-increments.js]
+[browser_rules_edit-property-order.js]
+[browser_rules_edit-property-remove_01.js]
+[browser_rules_edit-property-remove_02.js]
+[browser_rules_edit-property-remove_03.js]
+[browser_rules_edit-property_01.js]
+[browser_rules_edit-property_02.js]
+[browser_rules_edit-property_03.js]
+[browser_rules_edit-property_04.js]
+[browser_rules_edit-property_05.js]
+[browser_rules_edit-property_06.js]
+[browser_rules_edit-property_07.js]
+[browser_rules_edit-property_08.js]
+[browser_rules_edit-selector-commit.js]
+[browser_rules_edit-selector_01.js]
+[browser_rules_edit-selector_02.js]
+[browser_rules_edit-selector_03.js]
+[browser_rules_edit-selector_04.js]
+[browser_rules_edit-selector_05.js]
+[browser_rules_edit-selector_06.js]
+[browser_rules_editable-field-focus_01.js]
+[browser_rules_editable-field-focus_02.js]
+[browser_rules_eyedropper.js]
+[browser_rules_filtereditor-appears-on-swatch-click.js]
+[browser_rules_filtereditor-commit-on-ENTER.js]
+[browser_rules_filtereditor-revert-on-ESC.js]
+skip-if = (os == "win" && debug) || e10s # bug 963492: win. bug 1040653: e10s.
+[browser_rules_guessIndentation.js]
+[browser_rules_inherited-properties_01.js]
+[browser_rules_inherited-properties_02.js]
+[browser_rules_inherited-properties_03.js]
+[browser_rules_keybindings.js]
+[browser_rules_keyframes-rule_01.js]
+[browser_rules_keyframes-rule_02.js]
+[browser_rules_keyframeLineNumbers.js]
+[browser_rules_lineNumbers.js]
+[browser_rules_livepreview.js]
+[browser_rules_mark_overridden_01.js]
+[browser_rules_mark_overridden_02.js]
+[browser_rules_mark_overridden_03.js]
+[browser_rules_mark_overridden_04.js]
+[browser_rules_mark_overridden_05.js]
+[browser_rules_mark_overridden_06.js]
+[browser_rules_mark_overridden_07.js]
+[browser_rules_mathml-element.js]
+[browser_rules_media-queries.js]
+[browser_rules_multiple-properties-duplicates.js]
+[browser_rules_multiple-properties-priority.js]
+[browser_rules_multiple-properties-unfinished_01.js]
+[browser_rules_multiple-properties-unfinished_02.js]
+[browser_rules_multiple_properties_01.js]
+[browser_rules_multiple_properties_02.js]
+[browser_rules_original-source-link.js]
+[browser_rules_pseudo-element_01.js]
+[browser_rules_pseudo-element_02.js]
+skip-if = e10s # Bug 1090340
+[browser_rules_pseudo_lock_options.js]
+[browser_rules_refresh-no-flicker.js]
+[browser_rules_refresh-on-attribute-change_01.js]
+[browser_rules_refresh-on-attribute-change_02.js]
+[browser_rules_refresh-on-style-change.js]
+[browser_rules_search-filter-computed-list_01.js]
+[browser_rules_search-filter-computed-list_02.js]
+[browser_rules_search-filter-computed-list_03.js]
+[browser_rules_search-filter-computed-list_04.js]
+[browser_rules_search-filter-computed-list_expander.js]
+[browser_rules_search-filter-overridden-property.js]
+[browser_rules_search-filter_01.js]
+[browser_rules_search-filter_02.js]
+[browser_rules_search-filter_03.js]
+[browser_rules_search-filter_04.js]
+[browser_rules_search-filter_05.js]
+[browser_rules_search-filter_06.js]
+[browser_rules_search-filter_07.js]
+[browser_rules_search-filter_08.js]
+[browser_rules_search-filter_09.js]
+[browser_rules_search-filter_10.js]
+[browser_rules_search-filter_context-menu.js]
+[browser_rules_search-filter_escape-keypress.js]
+[browser_rules_select-and-copy-styles.js]
+[browser_rules_selector-highlighter_01.js]
+[browser_rules_selector-highlighter_02.js]
+[browser_rules_selector-highlighter_03.js]
+[browser_rules_selector_highlight.js]
+[browser_rules_strict-search-filter-computed-list_01.js]
+[browser_rules_strict-search-filter_01.js]
+[browser_rules_strict-search-filter_02.js]
+[browser_rules_strict-search-filter_03.js]
+[browser_rules_style-editor-link.js]
+skip-if = e10s # bug 1040670 Cannot open inline styles in viewSourceUtils
+[browser_rules_urls-clickable.js]
+[browser_rules_user-agent-styles.js]
+[browser_rules_user-agent-styles-uneditable.js]
+[browser_rules_user-property-reset.js]
rename from devtools/client/styleinspector/test/browser_ruleview_add-property-and-reselect.js
rename to devtools/client/inspector/rules/test/browser_rules_add-property-and-reselect.js
rename from devtools/client/styleinspector/test/browser_ruleview_add-property-cancel_01.js
rename to devtools/client/inspector/rules/test/browser_rules_add-property-cancel_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_add-property-cancel_02.js
rename to devtools/client/inspector/rules/test/browser_rules_add-property-cancel_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_add-property-cancel_03.js
rename to devtools/client/inspector/rules/test/browser_rules_add-property-cancel_03.js
rename from devtools/client/styleinspector/test/browser_ruleview_add-property-svg.js
rename to devtools/client/inspector/rules/test/browser_rules_add-property-svg.js
rename from devtools/client/styleinspector/test/browser_ruleview_add-property_01.js
rename to devtools/client/inspector/rules/test/browser_rules_add-property_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_add-property_02.js
rename to devtools/client/inspector/rules/test/browser_rules_add-property_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_add-rule_01.js
rename to devtools/client/inspector/rules/test/browser_rules_add-rule_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_add-rule_02.js
rename to devtools/client/inspector/rules/test/browser_rules_add-rule_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_add-rule_03.js
rename to devtools/client/inspector/rules/test/browser_rules_add-rule_03.js
rename from devtools/client/styleinspector/test/browser_ruleview_add-rule_04.js
rename to devtools/client/inspector/rules/test/browser_rules_add-rule_04.js
rename from devtools/client/styleinspector/test/browser_ruleview_add-rule_pseudo_class.js
rename to devtools/client/inspector/rules/test/browser_rules_add-rule_pseudo_class.js
rename from devtools/client/styleinspector/test/browser_ruleview_authored.js
rename to devtools/client/inspector/rules/test/browser_rules_authored.js
rename from devtools/client/styleinspector/test/browser_ruleview_colorUnit.js
rename to devtools/client/inspector/rules/test/browser_rules_colorUnit.js
rename from devtools/client/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_01.js
rename to devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_02.js
rename to devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_colorpicker-appears-on-swatch-click.js
rename to devtools/client/inspector/rules/test/browser_rules_colorpicker-appears-on-swatch-click.js
rename from devtools/client/styleinspector/test/browser_ruleview_colorpicker-commit-on-ENTER.js
rename to devtools/client/inspector/rules/test/browser_rules_colorpicker-commit-on-ENTER.js
rename from devtools/client/styleinspector/test/browser_ruleview_colorpicker-edit-gradient.js
rename to devtools/client/inspector/rules/test/browser_rules_colorpicker-edit-gradient.js
rename from devtools/client/styleinspector/test/browser_ruleview_colorpicker-hides-on-tooltip.js
rename to devtools/client/inspector/rules/test/browser_rules_colorpicker-hides-on-tooltip.js
rename from devtools/client/styleinspector/test/browser_ruleview_colorpicker-multiple-changes.js
rename to devtools/client/inspector/rules/test/browser_rules_colorpicker-multiple-changes.js
rename from devtools/client/styleinspector/test/browser_ruleview_colorpicker-release-outside-frame.js
rename to devtools/client/inspector/rules/test/browser_rules_colorpicker-release-outside-frame.js
rename from devtools/client/styleinspector/test/browser_ruleview_colorpicker-revert-on-ESC.js
rename to devtools/client/inspector/rules/test/browser_rules_colorpicker-revert-on-ESC.js
rename from devtools/client/styleinspector/test/browser_ruleview_colorpicker-swatch-displayed.js
rename to devtools/client/inspector/rules/test/browser_rules_colorpicker-swatch-displayed.js
rename from devtools/client/styleinspector/test/browser_ruleview_completion-existing-property_01.js
rename to devtools/client/inspector/rules/test/browser_rules_completion-existing-property_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_completion-existing-property_02.js
rename to devtools/client/inspector/rules/test/browser_rules_completion-existing-property_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_completion-new-property_01.js
rename to devtools/client/inspector/rules/test/browser_rules_completion-new-property_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_completion-new-property_02.js
rename to devtools/client/inspector/rules/test/browser_rules_completion-new-property_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_completion-new-property_03.js
rename to devtools/client/inspector/rules/test/browser_rules_completion-new-property_03.js
rename from devtools/client/styleinspector/test/browser_ruleview_completion-popup-hidden-after-navigation.js
rename to devtools/client/inspector/rules/test/browser_rules_completion-popup-hidden-after-navigation.js
rename from devtools/client/styleinspector/test/browser_ruleview_computed-lists_01.js
rename to devtools/client/inspector/rules/test/browser_rules_computed-lists_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_computed-lists_02.js
rename to devtools/client/inspector/rules/test/browser_rules_computed-lists_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_content_01.js
rename to devtools/client/inspector/rules/test/browser_rules_content_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_content_02.js
rename to devtools/client/inspector/rules/test/browser_rules_content_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_context-menu-show-mdn-docs-01.js
rename to devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-01.js
rename from devtools/client/styleinspector/test/browser_ruleview_context-menu-show-mdn-docs-02.js
rename to devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-02.js
rename from devtools/client/styleinspector/test/browser_ruleview_context-menu-show-mdn-docs-03.js
rename to devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-03.js
rename from devtools/client/styleinspector/test/browser_ruleview_copy_styles.js
rename to devtools/client/inspector/rules/test/browser_rules_copy_styles.js
--- a/devtools/client/styleinspector/test/browser_ruleview_copy_styles.js
+++ b/devtools/client/inspector/rules/test/browser_rules_copy_styles.js
@@ -128,17 +128,17 @@ add_task(function*() {
         copyRule: false
       }
     },
     {
       desc: "Test Copy Location",
       node: ruleEditor.source,
       menuItem: contextmenu.menuitemCopyLocation,
       expectedPattern: "http://example.com/browser/devtools/client/" +
-                       "styleinspector/test/doc_copystyles.css",
+                       "inspector/rules/test/doc_copystyles.css",
       hidden: {
         copyLocation: false,
         copyPropertyDeclaration: true,
         copyPropertyName: true,
         copyPropertyValue: true,
         copySelector: true,
         copyRule: false
       }
rename from devtools/client/styleinspector/test/browser_ruleview_cssom.js
rename to devtools/client/inspector/rules/test/browser_rules_cssom.js
rename from devtools/client/styleinspector/test/browser_ruleview_cubicbezier-appears-on-swatch-click.js
rename to devtools/client/inspector/rules/test/browser_rules_cubicbezier-appears-on-swatch-click.js
rename from devtools/client/styleinspector/test/browser_ruleview_cubicbezier-commit-on-ENTER.js
rename to devtools/client/inspector/rules/test/browser_rules_cubicbezier-commit-on-ENTER.js
rename from devtools/client/styleinspector/test/browser_ruleview_cubicbezier-revert-on-ESC.js
rename to devtools/client/inspector/rules/test/browser_rules_cubicbezier-revert-on-ESC.js
rename from devtools/client/styleinspector/test/browser_ruleview_custom.js
rename to devtools/client/inspector/rules/test/browser_rules_custom.js
rename from devtools/client/styleinspector/test/browser_ruleview_cycle-color.js
rename to devtools/client/inspector/rules/test/browser_rules_cycle-color.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property-cancel.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property-cancel.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property-commit.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property-commit.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property-computed.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property-computed.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property-increments.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property-increments.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property-order.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property-order.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property-remove_01.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property-remove_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property-remove_02.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property-remove_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property-remove_03.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property-remove_03.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property_01.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property_02.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property_03.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property_03.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property_04.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property_04.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property_05.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property_05.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property_06.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property_06.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property_07.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property_07.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-property_08.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-property_08.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-selector-commit.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-selector-commit.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-selector_01.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-selector_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-selector_02.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-selector_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-selector_03.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-selector_03.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-selector_04.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-selector_04.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-selector_05.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-selector_05.js
rename from devtools/client/styleinspector/test/browser_ruleview_edit-selector_06.js
rename to devtools/client/inspector/rules/test/browser_rules_edit-selector_06.js
rename from devtools/client/styleinspector/test/browser_ruleview_editable-field-focus_01.js
rename to devtools/client/inspector/rules/test/browser_rules_editable-field-focus_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_editable-field-focus_02.js
rename to devtools/client/inspector/rules/test/browser_rules_editable-field-focus_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_eyedropper.js
rename to devtools/client/inspector/rules/test/browser_rules_eyedropper.js
rename from devtools/client/styleinspector/test/browser_ruleview_filtereditor-appears-on-swatch-click.js
rename to devtools/client/inspector/rules/test/browser_rules_filtereditor-appears-on-swatch-click.js
rename from devtools/client/styleinspector/test/browser_ruleview_filtereditor-commit-on-ENTER.js
rename to devtools/client/inspector/rules/test/browser_rules_filtereditor-commit-on-ENTER.js
rename from devtools/client/styleinspector/test/browser_ruleview_filtereditor-revert-on-ESC.js
rename to devtools/client/inspector/rules/test/browser_rules_filtereditor-revert-on-ESC.js
rename from devtools/client/styleinspector/test/browser_ruleview_guessIndentation.js
rename to devtools/client/inspector/rules/test/browser_rules_guessIndentation.js
rename from devtools/client/styleinspector/test/browser_ruleview_inherited-properties_01.js
rename to devtools/client/inspector/rules/test/browser_rules_inherited-properties_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_inherited-properties_02.js
rename to devtools/client/inspector/rules/test/browser_rules_inherited-properties_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_inherited-properties_03.js
rename to devtools/client/inspector/rules/test/browser_rules_inherited-properties_03.js
rename from devtools/client/styleinspector/test/browser_ruleview_keybindings.js
rename to devtools/client/inspector/rules/test/browser_rules_keybindings.js
rename from devtools/client/styleinspector/test/browser_ruleview_keyframeLineNumbers.js
rename to devtools/client/inspector/rules/test/browser_rules_keyframeLineNumbers.js
rename from devtools/client/styleinspector/test/browser_ruleview_keyframes-rule_01.js
rename to devtools/client/inspector/rules/test/browser_rules_keyframes-rule_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_keyframes-rule_02.js
rename to devtools/client/inspector/rules/test/browser_rules_keyframes-rule_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_lineNumbers.js
rename to devtools/client/inspector/rules/test/browser_rules_lineNumbers.js
rename from devtools/client/styleinspector/test/browser_ruleview_livepreview.js
rename to devtools/client/inspector/rules/test/browser_rules_livepreview.js
rename from devtools/client/styleinspector/test/browser_ruleview_mark_overridden_01.js
rename to devtools/client/inspector/rules/test/browser_rules_mark_overridden_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_mark_overridden_02.js
rename to devtools/client/inspector/rules/test/browser_rules_mark_overridden_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_mark_overridden_03.js
rename to devtools/client/inspector/rules/test/browser_rules_mark_overridden_03.js
rename from devtools/client/styleinspector/test/browser_ruleview_mark_overridden_04.js
rename to devtools/client/inspector/rules/test/browser_rules_mark_overridden_04.js
rename from devtools/client/styleinspector/test/browser_ruleview_mark_overridden_05.js
rename to devtools/client/inspector/rules/test/browser_rules_mark_overridden_05.js
rename from devtools/client/styleinspector/test/browser_ruleview_mark_overridden_06.js
rename to devtools/client/inspector/rules/test/browser_rules_mark_overridden_06.js
rename from devtools/client/styleinspector/test/browser_ruleview_mark_overridden_07.js
rename to devtools/client/inspector/rules/test/browser_rules_mark_overridden_07.js
rename from devtools/client/styleinspector/test/browser_ruleview_mathml-element.js
rename to devtools/client/inspector/rules/test/browser_rules_mathml-element.js
rename from devtools/client/styleinspector/test/browser_ruleview_media-queries.js
rename to devtools/client/inspector/rules/test/browser_rules_media-queries.js
rename from devtools/client/styleinspector/test/browser_ruleview_multiple-properties-duplicates.js
rename to devtools/client/inspector/rules/test/browser_rules_multiple-properties-duplicates.js
rename from devtools/client/styleinspector/test/browser_ruleview_multiple-properties-priority.js
rename to devtools/client/inspector/rules/test/browser_rules_multiple-properties-priority.js
rename from devtools/client/styleinspector/test/browser_ruleview_multiple-properties-unfinished_01.js
rename to devtools/client/inspector/rules/test/browser_rules_multiple-properties-unfinished_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_multiple-properties-unfinished_02.js
rename to devtools/client/inspector/rules/test/browser_rules_multiple-properties-unfinished_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_multiple_properties_01.js
rename to devtools/client/inspector/rules/test/browser_rules_multiple_properties_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_multiple_properties_02.js
rename to devtools/client/inspector/rules/test/browser_rules_multiple_properties_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_original-source-link.js
rename to devtools/client/inspector/rules/test/browser_rules_original-source-link.js
rename from devtools/client/styleinspector/test/browser_ruleview_pseudo-element_01.js
rename to devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_pseudo-element_02.js
rename to devtools/client/inspector/rules/test/browser_rules_pseudo-element_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_pseudo_lock_options.js
rename to devtools/client/inspector/rules/test/browser_rules_pseudo_lock_options.js
rename from devtools/client/styleinspector/test/browser_ruleview_refresh-no-flicker.js
rename to devtools/client/inspector/rules/test/browser_rules_refresh-no-flicker.js
rename from devtools/client/styleinspector/test/browser_ruleview_refresh-on-attribute-change_01.js
rename to devtools/client/inspector/rules/test/browser_rules_refresh-on-attribute-change_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_refresh-on-attribute-change_02.js
rename to devtools/client/inspector/rules/test/browser_rules_refresh-on-attribute-change_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_refresh-on-style-change.js
rename to devtools/client/inspector/rules/test/browser_rules_refresh-on-style-change.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter-computed-list_01.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter-computed-list_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter-computed-list_02.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter-computed-list_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter-computed-list_03.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter-computed-list_03.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter-computed-list_04.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter-computed-list_04.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter-computed-list_expander.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter-computed-list_expander.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter-overridden-property.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter-overridden-property.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter_01.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter_02.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter_03.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter_03.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter_04.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter_04.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter_05.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter_05.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter_06.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter_06.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter_07.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter_07.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter_08.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter_08.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter_09.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter_09.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter_10.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter_10.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter_context-menu.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter_context-menu.js
rename from devtools/client/styleinspector/test/browser_ruleview_search-filter_escape-keypress.js
rename to devtools/client/inspector/rules/test/browser_rules_search-filter_escape-keypress.js
rename from devtools/client/styleinspector/test/browser_ruleview_select-and-copy-styles.js
rename to devtools/client/inspector/rules/test/browser_rules_select-and-copy-styles.js
rename from devtools/client/styleinspector/test/browser_ruleview_selector-highlighter_01.js
rename to devtools/client/inspector/rules/test/browser_rules_selector-highlighter_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_selector-highlighter_02.js
rename to devtools/client/inspector/rules/test/browser_rules_selector-highlighter_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_selector-highlighter_03.js
rename to devtools/client/inspector/rules/test/browser_rules_selector-highlighter_03.js
rename from devtools/client/styleinspector/test/browser_ruleview_selector_highlight.js
rename to devtools/client/inspector/rules/test/browser_rules_selector_highlight.js
rename from devtools/client/styleinspector/test/browser_ruleview_strict-search-filter-computed-list_01.js
rename to devtools/client/inspector/rules/test/browser_rules_strict-search-filter-computed-list_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_strict-search-filter_01.js
rename to devtools/client/inspector/rules/test/browser_rules_strict-search-filter_01.js
rename from devtools/client/styleinspector/test/browser_ruleview_strict-search-filter_02.js
rename to devtools/client/inspector/rules/test/browser_rules_strict-search-filter_02.js
rename from devtools/client/styleinspector/test/browser_ruleview_strict-search-filter_03.js
rename to devtools/client/inspector/rules/test/browser_rules_strict-search-filter_03.js
rename from devtools/client/styleinspector/test/browser_ruleview_style-editor-link.js
rename to devtools/client/inspector/rules/test/browser_rules_style-editor-link.js
rename from devtools/client/styleinspector/test/browser_ruleview_urls-clickable.js
rename to devtools/client/inspector/rules/test/browser_rules_urls-clickable.js
rename from devtools/client/styleinspector/test/browser_ruleview_user-agent-styles-uneditable.js
rename to devtools/client/inspector/rules/test/browser_rules_user-agent-styles-uneditable.js
rename from devtools/client/styleinspector/test/browser_ruleview_user-agent-styles.js
rename to devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js
rename from devtools/client/styleinspector/test/browser_ruleview_user-property-reset.js
rename to devtools/client/inspector/rules/test/browser_rules_user-property-reset.js
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/test/doc_content_stylesheet.html
@@ -0,0 +1,33 @@
+<html>
+<head>
+  <title>test</title>
+
+  <link href="./doc_content_stylesheet_linked.css" rel="stylesheet" type="text/css">
+
+  <script>
+    // Load script.css
+    function loadCSS() {
+      var link = document.createElement('link');
+      link.rel = 'stylesheet';
+      link.type = 'text/css';
+      link.href = "./doc_content_stylesheet_script.css";
+      document.getElementsByTagName('head')[0].appendChild(link);
+    }
+  </script>
+
+  <style>
+    table {
+      border: 1px solid #000;
+    }
+  </style>
+</head>
+<body onload="loadCSS();">
+  <table id="target">
+    <tr>
+      <td>
+        <h3>Simple test</h3>
+      </td>
+    </tr>
+  </table>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/test/doc_content_stylesheet_imported.css
@@ -0,0 +1,5 @@
+@import url("./doc_content_stylesheet_imported2.css");
+
+#target {
+  text-decoration: underline;
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/test/doc_content_stylesheet_imported2.css
@@ -0,0 +1,3 @@
+#target {
+  text-decoration: underline;
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/test/doc_content_stylesheet_linked.css
@@ -0,0 +1,3 @@
+table  {
+  border-collapse: collapse;
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/test/doc_content_stylesheet_script.css
@@ -0,0 +1,5 @@
+@import url("./doc_content_stylesheet_imported.css");
+
+table  {
+  opacity: 1;
+}
rename from devtools/client/styleinspector/test/doc_copystyles.css
rename to devtools/client/inspector/rules/test/doc_copystyles.css
rename from devtools/client/styleinspector/test/doc_copystyles.html
rename to devtools/client/inspector/rules/test/doc_copystyles.html
rename from devtools/client/styleinspector/test/doc_cssom.html
rename to devtools/client/inspector/rules/test/doc_cssom.html
rename from devtools/client/styleinspector/test/doc_custom.html
rename to devtools/client/inspector/rules/test/doc_custom.html
rename from devtools/client/styleinspector/test/doc_filter.html
rename to devtools/client/inspector/rules/test/doc_filter.html
copy from devtools/client/styleinspector/test/doc_frame_script.js
copy to devtools/client/inspector/rules/test/doc_frame_script.js
rename from devtools/client/styleinspector/test/doc_keyframeLineNumbers.html
rename to devtools/client/inspector/rules/test/doc_keyframeLineNumbers.html
rename from devtools/client/styleinspector/test/doc_keyframeanimation.css
rename to devtools/client/inspector/rules/test/doc_keyframeanimation.css
rename from devtools/client/styleinspector/test/doc_keyframeanimation.html
rename to devtools/client/inspector/rules/test/doc_keyframeanimation.html
rename from devtools/client/styleinspector/test/doc_media_queries.html
rename to devtools/client/inspector/rules/test/doc_media_queries.html
rename from devtools/client/styleinspector/test/doc_pseudoelement.html
rename to devtools/client/inspector/rules/test/doc_pseudoelement.html
rename from devtools/client/styleinspector/test/doc_ruleLineNumbers.html
rename to devtools/client/inspector/rules/test/doc_ruleLineNumbers.html
rename from devtools/client/styleinspector/test/doc_sourcemaps.css
rename to devtools/client/inspector/rules/test/doc_sourcemaps.css
rename from devtools/client/styleinspector/test/doc_sourcemaps.css.map
rename to devtools/client/inspector/rules/test/doc_sourcemaps.css.map
rename from devtools/client/styleinspector/test/doc_sourcemaps.html
rename to devtools/client/inspector/rules/test/doc_sourcemaps.html
rename from devtools/client/styleinspector/test/doc_sourcemaps.scss
rename to devtools/client/inspector/rules/test/doc_sourcemaps.scss
rename from devtools/client/styleinspector/test/doc_style_editor_link.css
rename to devtools/client/inspector/rules/test/doc_style_editor_link.css
rename from devtools/client/styleinspector/test/doc_test_image.png
rename to devtools/client/inspector/rules/test/doc_test_image.png
rename from devtools/client/styleinspector/test/doc_urls_clickable.css
rename to devtools/client/inspector/rules/test/doc_urls_clickable.css
--- a/devtools/client/styleinspector/test/doc_urls_clickable.css
+++ b/devtools/client/inspector/rules/test/doc_urls_clickable.css
@@ -1,9 +1,9 @@
 .relative1 {
     background-image: url(./doc_test_image.png);
 }
 .absolute {
-    background: url("http://example.com/browser/devtools/client/styleinspector/test/doc_test_image.png");
+    background: url("http://example.com/browser/devtools/client/inspector/rules/test/doc_test_image.png");
 }
 .base64 {
     background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==');
-}
\ No newline at end of file
+}
rename from devtools/client/styleinspector/test/doc_urls_clickable.html
rename to devtools/client/inspector/rules/test/doc_urls_clickable.html
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/test/head.js
@@ -0,0 +1,1002 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+var Cu = Components.utils;
+var {gDevTools} = Cu.import("resource://devtools/client/framework/gDevTools.jsm", {});
+var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
+var {TargetFactory} = require("devtools/client/framework/target");
+var {CssRuleView, _ElementStyle} =
+    require("devtools/client/inspector/rules/rules");
+var {CssLogic, CssSelector} = require("devtools/shared/styleinspector/css-logic");
+var DevToolsUtils = require("devtools/shared/DevToolsUtils");
+var promise = require("promise");
+var {editableField, getInplaceEditorForSpan: inplaceEditor} =
+  require("devtools/client/shared/inplace-editor");
+var {console} =
+  Components.utils.import("resource://gre/modules/Console.jsm", {});
+
+// All tests are asynchronous
+waitForExplicitFinish();
+
+const TEST_URL_ROOT =
+  "http://example.com/browser/devtools/client/inspector/rules/test/";
+const TEST_URL_ROOT_SSL =
+  "https://example.com/browser/devtools/client/inspector/rules/test/";
+const ROOT_TEST_DIR = getRootDirectory(gTestPath);
+const FRAME_SCRIPT_URL = ROOT_TEST_DIR + "doc_frame_script.js";
+
+// Auto clean-up when a test ends
+registerCleanupFunction(function*() {
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  yield gDevTools.closeToolbox(target);
+
+  while (gBrowser.tabs.length > 1) {
+    gBrowser.removeCurrentTab();
+  }
+});
+
+// Uncomment this pref to dump all devtools emitted events to the console.
+// Services.prefs.setBoolPref("devtools.dump.emit", true);
+
+// Set the testing flag on gDevTools and reset it when the test ends
+DevToolsUtils.testing = true;
+registerCleanupFunction(() => DevToolsUtils.testing = false);
+
+// Clean-up all prefs that might have been changed during a test run
+// (safer here because if the test fails, then the pref is never reverted)
+registerCleanupFunction(() => {
+  Services.prefs.clearUserPref("devtools.inspector.activeSidebar");
+  Services.prefs.clearUserPref("devtools.dump.emit");
+  Services.prefs.clearUserPref("devtools.defaultColorUnit");
+});
+
+/**
+ * The functions found below are here to ease test development and maintenance.
+ * Most of these functions are stateless and will require some form of context
+ * (the instance of the current toolbox, or inspector panel for instance).
+ *
+ * Most of these functions are async too and return promises.
+ *
+ * All tests should follow the following pattern:
+ *
+ * add_task(function*() {
+ *   yield addTab(TEST_URI);
+ *   let {toolbox, inspector, view} = yield openComputedView();
+ *
+ *   yield selectNode("#test", inspector);
+ *   yield someAsyncTestFunction(view);
+ * });
+ *
+ * add_task is the way to define the testcase in the test file. It accepts
+ * a single generator-function argument.
+ * The generator function should yield any async call.
+ *
+ * There is no need to clean tabs up at the end of a test as this is done
+ * automatically.
+ *
+ * It is advised not to store any references on the global scope. There
+ * shouldn't be a need to anyway. Thanks to add_task, test steps, even
+ * though asynchronous, can be described in a nice flat way, and
+ * if/for/while/... control flow can be used as in sync code, making it
+ * possible to write the outline of the test case all in add_task, and delegate
+ * actual processing and assertions to other functions.
+ */
+
+/* *********************************************
+ * UTILS
+ * *********************************************
+ * General test utilities.
+ * Add new tabs, open the toolbox and switch to the various panels, select
+ * nodes, get node references, ...
+ */
+
+/**
+ * Add a new test tab in the browser and load the given url.
+ *
+ * @param {String} url
+ *        The url to be loaded in the new tab
+ * @return a promise that resolves to the tab object when the url is loaded
+ */
+function addTab(url) {
+  info("Adding a new tab with URL: '" + url + "'");
+  let def = promise.defer();
+
+  window.focus();
+
+  let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
+  let browser = tab.linkedBrowser;
+
+  info("Loading the helper frame script " + FRAME_SCRIPT_URL);
+  browser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false);
+
+  browser.addEventListener("load", function onload() {
+    browser.removeEventListener("load", onload, true);
+    info("URL '" + url + "' loading complete");
+
+    def.resolve(tab);
+  }, true);
+
+  return def.promise;
+}
+
+/**
+ * Simple DOM node accesor function that takes either a node or a string css
+ * selector as argument and returns the corresponding node
+ *
+ * @param {String|DOMNode} nodeOrSelector
+ * @return {DOMNode|CPOW} Note that in e10s mode a CPOW object is returned which
+ * doesn't implement *all* of the DOMNode's properties
+ */
+function getNode(nodeOrSelector) {
+  info("Getting the node for '" + nodeOrSelector + "'");
+  return typeof nodeOrSelector === "string" ?
+    content.document.querySelector(nodeOrSelector) :
+    nodeOrSelector;
+}
+
+/**
+ * Get the NodeFront for a given css selector, via the protocol
+ *
+ * @param {String} selector
+ * @param {InspectorPanel} inspector
+ *        The instance of InspectorPanel currently loaded in the toolbox
+ * @return {Promise} Resolves to the NodeFront instance
+ */
+function getNodeFront(selector, {walker}) {
+  return walker.querySelector(walker.rootNode, selector);
+}
+
+/*
+ * Set the inspector's current selection to a node or to the first match of the
+ * given css selector.
+ *
+ * @param {String|NodeFront} data
+ *        The node to select
+ * @param {InspectorPanel} inspector
+ *        The instance of InspectorPanel currently loaded in the toolbox
+ * @param {String} reason
+ *        Defaults to "test" which instructs the inspector not
+ *        to highlight the node upon selection
+ * @return {Promise} Resolves when the inspector is updated with the new node
+ */
+var selectNode = Task.async(function*(data, inspector, reason="test") {
+  info("Selecting the node for '" + data + "'");
+  let nodeFront = data;
+  if (!data._form) {
+    nodeFront = yield getNodeFront(data, inspector);
+  }
+  let updated = inspector.once("inspector-updated");
+  inspector.selection.setNodeFront(nodeFront, reason);
+  yield updated;
+});
+
+/**
+ * Set the inspector's current selection to null so that no node is selected
+ *
+ * @param {InspectorPanel} inspector
+ *        The instance of InspectorPanel currently loaded in the toolbox
+ * @return a promise that resolves when the inspector is updated
+ */
+function clearCurrentNodeSelection(inspector) {
+  info("Clearing the current selection");
+  let updated = inspector.once("inspector-updated");
+  inspector.selection.setNodeFront(null);
+  return updated;
+}
+
+/**
+ * Open the toolbox, with the inspector tool visible.
+ *
+ * @return a promise that resolves when the inspector is ready
+ */
+var openInspector = Task.async(function*() {
+  info("Opening the inspector");
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+
+  let inspector, toolbox;
+
+  // Checking if the toolbox and the inspector are already loaded
+  // The inspector-updated event should only be waited for if the inspector
+  // isn't loaded yet
+  toolbox = gDevTools.getToolbox(target);
+  if (toolbox) {
+    inspector = toolbox.getPanel("inspector");
+    if (inspector) {
+      info("Toolbox and inspector already open");
+      return {
+        toolbox: toolbox,
+        inspector: inspector
+      };
+    }
+  }
+
+  info("Opening the toolbox");
+  toolbox = yield gDevTools.showToolbox(target, "inspector");
+  yield waitForToolboxFrameFocus(toolbox);
+  inspector = toolbox.getPanel("inspector");
+
+  info("Waiting for the inspector to update");
+  yield inspector.once("inspector-updated");
+
+  return {
+    toolbox: toolbox,
+    inspector: inspector
+  };
+});
+
+/**
+ * Wait for the toolbox frame to receive focus after it loads
+ *
+ * @param {Toolbox} toolbox
+ * @return a promise that resolves when focus has been received
+ */
+function waitForToolboxFrameFocus(toolbox) {
+  info("Making sure that the toolbox's frame is focused");
+  let def = promise.defer();
+  let win = toolbox.frame.contentWindow;
+  waitForFocus(def.resolve, win);
+  return def.promise;
+}
+
+/**
+ * Open the toolbox, with the inspector tool visible, and the sidebar that
+ * corresponds to the given id selected
+ *
+ * @return a promise that resolves when the inspector is ready and the sidebar
+ * view is visible and ready
+ */
+var openInspectorSideBar = Task.async(function*(id) {
+  let {toolbox, inspector} = yield openInspector();
+
+  if (!hasSideBarTab(inspector, id)) {
+    info("Waiting for the " + id + " sidebar to be ready");
+    yield inspector.sidebar.once(id + "-ready");
+  }
+
+  info("Selecting the " + id + " sidebar");
+  inspector.sidebar.select(id);
+
+  return {
+    toolbox: toolbox,
+    inspector: inspector,
+    view: inspector.sidebar.getWindowForTab(id)[id].view
+  };
+});
+
+/**
+ * Open the toolbox, with the inspector tool visible, and the computed-view
+ * sidebar tab selected.
+ *
+ * @return a promise that resolves when the inspector is ready and the computed
+ * view is visible and ready
+ */
+function openComputedView() {
+  return openInspectorSideBar("computedview");
+}
+
+/**
+ * Open the toolbox, with the inspector tool visible, and the rule-view
+ * sidebar tab selected.
+ *
+ * @return a promise that resolves when the inspector is ready and the rule
+ * view is visible and ready
+ */
+function openRuleView() {
+  return openInspectorSideBar("ruleview");
+}
+
+/**
+ * Wait for eventName on target to be delivered a number of times.
+ *
+ * @param {Object} target
+ *        An observable object that either supports on/off or
+ *        addEventListener/removeEventListener
+ * @param {String} eventName
+ * @param {Number} numTimes
+ *        Number of deliveries to wait for.
+ * @param {Boolean} useCapture
+ *        Optional, for addEventListener/removeEventListener
+ * @return A promise that resolves when the event has been handled
+ */
+function waitForNEvents(target, eventName, numTimes, useCapture = false) {
+  info("Waiting for event: '" + eventName + "' on " + target + ".");
+
+  let deferred = promise.defer();
+  let count = 0;
+
+  for (let [add, remove] of [
+    ["addEventListener", "removeEventListener"],
+    ["addListener", "removeListener"],
+    ["on", "off"]
+  ]) {
+    if ((add in target) && (remove in target)) {
+      target[add](eventName, function onEvent(...aArgs) {
+        if (++count == numTimes) {
+          target[remove](eventName, onEvent, useCapture);
+          deferred.resolve.apply(deferred, aArgs);
+        }
+      }, useCapture);
+      break;
+    }
+  }
+
+  return deferred.promise;
+}
+
+/**
+ * Wait for eventName on target.
+ *
+ * @param {Object} target
+ *        An observable object that either supports on/off or
+ *        addEventListener/removeEventListener
+ * @param {String} eventName
+ * @param {Boolean} useCapture
+ *        Optional, for addEventListener/removeEventListener
+ * @return A promise that resolves when the event has been handled
+ */
+function once(target, eventName, useCapture=false) {
+  return waitForNEvents(target, eventName, 1, useCapture);
+}
+
+/**
+ * This shouldn't be used in the tests, but is useful when writing new tests or
+ * debugging existing tests in order to introduce delays in the test steps
+ *
+ * @param {Number} ms
+ *        The time to wait
+ * @return A promise that resolves when the time is passed
+ */
+function wait(ms) {
+  let def = promise.defer();
+  content.setTimeout(def.resolve, ms);
+  return def.promise;
+}
+
+/**
+ * Wait for a content -> chrome message on the message manager (the window
+ * messagemanager is used).
+ *
+ * @param {String} name
+ *        The message name
+ * @return {Promise} A promise that resolves to the response data when the
+ * message has been received
+ */
+function waitForContentMessage(name) {
+  info("Expecting message " + name + " from content");
+
+  let mm = gBrowser.selectedBrowser.messageManager;
+
+  let def = promise.defer();
+  mm.addMessageListener(name, function onMessage(msg) {
+    mm.removeMessageListener(name, onMessage);
+    def.resolve(msg.data);
+  });
+  return def.promise;
+}
+
+/**
+ * Send an async message to the frame script (chrome -> content) and wait for a
+ * response message with the same name (content -> chrome).
+ *
+ * @param {String} name
+ *        The message name. Should be one of the messages defined
+ *        in doc_frame_script.js
+ * @param {Object} data
+ *        Optional data to send along
+ * @param {Object} objects
+ *        Optional CPOW objects to send along
+ * @param {Boolean} expectResponse
+ *        If set to false, don't wait for a response with the same name
+ *        from the content script. Defaults to true.
+ * @return {Promise} Resolves to the response data if a response is expected,
+ * immediately resolves otherwise
+ */
+function executeInContent(name, data={}, objects={}, expectResponse=true) {
+  info("Sending message " + name + " to content");
+  let mm = gBrowser.selectedBrowser.messageManager;
+
+  mm.sendAsyncMessage(name, data, objects);
+  if (expectResponse) {
+    return waitForContentMessage(name);
+  }
+
+  return promise.resolve();
+}
+
+/**
+ * Send an async message to the frame script and get back the requested
+ * computed style property.
+ *
+ * @param {String} selector
+ *        The selector used to obtain the element.
+ * @param {String} pseudo
+ *        pseudo id to query, or null.
+ * @param {String} name
+ *        name of the property.
+ */
+function* getComputedStyleProperty(selector, pseudo, propName) {
+  return yield executeInContent("Test:GetComputedStylePropertyValue",
+                                {selector,
+                                pseudo,
+                                name: propName});
+}
+
+/**
+ * Send an async message to the frame script and wait until the requested
+ * computed style property has the expected value.
+ *
+ * @param {String} selector
+ *        The selector used to obtain the element.
+ * @param {String} pseudo
+ *        pseudo id to query, or null.
+ * @param {String} prop
+ *        name of the property.
+ * @param {String} expected
+ *        expected value of property
+ * @param {String} name
+ *        the name used in test message
+ */
+function* waitForComputedStyleProperty(selector, pseudo, name, expected) {
+  return yield executeInContent("Test:WaitForComputedStylePropertyValue",
+                                {selector,
+                                pseudo,
+                                expected,
+                                name});
+}
+
+/**
+ * Given an inplace editable element, click to switch it to edit mode, wait for
+ * focus
+ *
+ * @return a promise that resolves to the inplace-editor element when ready
+ */
+var focusEditableField = Task.async(function*(ruleView, editable, xOffset=1,
+    yOffset=1, options={}) {
+  let onFocus = once(editable.parentNode, "focus", true);
+  info("Clicking on editable field to turn to edit mode");
+  EventUtils.synthesizeMouse(editable, xOffset, yOffset, options,
+    editable.ownerDocument.defaultView);
+  yield onFocus;
+
+  info("Editable field gained focus, returning the input field now");
+  let onEdit = inplaceEditor(editable.ownerDocument.activeElement);
+
+  return onEdit;
+});
+
+/**
+ * Given a tooltip object instance (see Tooltip.js), checks if it is set to
+ * toggle and hover and if so, checks if the given target is a valid hover
+ * target. This won't actually show the tooltip (the less we interact with XUL
+ * panels during test runs, the better).
+ *
+ * @return a promise that resolves when the answer is known
+ */
+function isHoverTooltipTarget(tooltip, target) {
+  if (!tooltip._basedNode || !tooltip.panel) {
+    return promise.reject(new Error(
+      "The tooltip passed isn't set to toggle on hover or is not a tooltip"));
+  }
+  return tooltip.isValidHoverTarget(target);
+}
+
+/**
+ * Same as isHoverTooltipTarget except that it will fail the test if there is no
+ * tooltip defined on hover of the given element
+ *
+ * @return a promise
+ */
+function assertHoverTooltipOn(tooltip, element) {
+  return isHoverTooltipTarget(tooltip, element).then(() => {
+    ok(true, "A tooltip is defined on hover of the given element");
+  }, () => {
+    ok(false, "No tooltip is defined on hover of the given element");
+  });
+}
+
+/**
+ * Listen for a new tab to open and return a promise that resolves when one
+ * does and completes the load event.
+ *
+ * @return a promise that resolves to the tab object
+ */
+var waitForTab = Task.async(function*() {
+  info("Waiting for a tab to open");
+  yield once(gBrowser.tabContainer, "TabOpen");
+  let tab = gBrowser.selectedTab;
+  let browser = tab.linkedBrowser;
+  yield once(browser, "load", true);
+  info("The tab load completed");
+  return tab;
+});
+
+/**
+ * @see SimpleTest.waitForClipboard
+ *
+ * @param {Function} setup
+ *        Function to execute before checking for the
+ *        clipboard content
+ * @param {String|Boolean} expected
+ *        An expected string or validator function
+ * @return a promise that resolves when the expected string has been found or
+ * the validator function has returned true, rejects otherwise.
+ */
+function waitForClipboard(setup, expected) {
+  let def = promise.defer();
+  SimpleTest.waitForClipboard(expected, setup, def.resolve, def.reject);
+  return def.promise;
+}
+
+/**
+ * Polls a given function waiting for it to return true.
+ *
+ * @param {Function} validatorFn
+ *        A validator function that returns a boolean.
+ *        This is called every few milliseconds to check if the result is true.
+ *        When it is true, the promise resolves.
+ * @param {String} name
+ *        Optional name of the test. This is used to generate
+ *        the success and failure messages.
+ * @return a promise that resolves when the function returned true or rejects
+ * if the timeout is reached
+ */
+function waitForSuccess(validatorFn, name="untitled") {
+  let def = promise.defer();
+
+  function wait(validator) {
+    if (validator()) {
+      ok(true, "Validator function " + name + " returned true");
+      def.resolve();
+    } else {
+      setTimeout(() => wait(validator), 200);
+    }
+  }
+  wait(validatorFn);
+
+  return def.promise;
+}
+
+/**
+ * Create a new style tag containing the given style text and append it to the
+ * document's head node
+ *
+ * @param {Document} doc
+ * @param {String} style
+ * @return {DOMNode} The newly created style node
+ */
+function addStyle(doc, style) {
+  info("Adding a new style tag to the document with style content: " +
+    style.substring(0, 50));
+  let node = doc.createElement("style");
+  node.setAttribute("type", "text/css");
+  node.textContent = style;
+  doc.getElementsByTagName("head")[0].appendChild(node);
+  return node;
+}
+
+/**
+ * Checks whether the inspector's sidebar corresponding to the given id already
+ * exists
+ *
+ * @param {InspectorPanel}
+ * @param {String}
+ * @return {Boolean}
+ */
+function hasSideBarTab(inspector, id) {
+  return !!inspector.sidebar.getWindowForTab(id);
+}
+
+/**
+ * Get the dataURL for the font family tooltip.
+ *
+ * @param {String} font
+ *        The font family value.
+ * @param {object} nodeFront
+ *        The NodeActor that will used to retrieve the dataURL for the
+ *        font family tooltip contents.
+ */
+var getFontFamilyDataURL = Task.async(function*(font, nodeFront) {
+  let fillStyle = (Services.prefs.getCharPref("devtools.theme") === "light") ?
+      "black" : "white";
+
+  let {data} = yield nodeFront.getFontFamilyDataURL(font, fillStyle);
+  let dataURL = yield data.string();
+  return dataURL;
+});
+
+/**
+ * Simulate the key input for the given input in the window.
+ *
+ * @param {String} input
+ *        The string value to input
+ * @param {Window} win
+ *        The window containing the panel
+ */
+function synthesizeKeys(input, win) {
+  for (let key of input.split("")) {
+    EventUtils.synthesizeKey(key, {}, win);
+  }
+}
+
+/* *********************************************
+ * RULE-VIEW
+ * *********************************************
+ * Rule-view related test utility functions
+ * This object contains functions to get rules, get properties, ...
+ */
+
+/**
+ * Get the DOMNode for a css rule in the rule-view that corresponds to the given
+ * selector
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} selectorText
+ *        The selector in the rule-view for which the rule
+ *        object is wanted
+ * @return {DOMNode}
+ */
+function getRuleViewRule(view, selectorText) {
+  let rule;
+  for (let r of view.styleDocument.querySelectorAll(".ruleview-rule")) {
+    let selector = r.querySelector(".ruleview-selectorcontainer, " +
+                                   ".ruleview-selector-matched");
+    if (selector && selector.textContent === selectorText) {
+      rule = r;
+      break;
+    }
+  }
+
+  return rule;
+}
+
+/**
+ * Get references to the name and value span nodes corresponding to a given
+ * selector and property name in the rule-view
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} selectorText
+ *        The selector in the rule-view to look for the property in
+ * @param {String} propertyName
+ *        The name of the property
+ * @return {Object} An object like {nameSpan: DOMNode, valueSpan: DOMNode}
+ */
+function getRuleViewProperty(view, selectorText, propertyName) {
+  let prop;
+
+  let rule = getRuleViewRule(view, selectorText);
+  if (rule) {
+    // Look for the propertyName in that rule element
+    for (let p of rule.querySelectorAll(".ruleview-property")) {
+      let nameSpan = p.querySelector(".ruleview-propertyname");
+      let valueSpan = p.querySelector(".ruleview-propertyvalue");
+
+      if (nameSpan.textContent === propertyName) {
+        prop = {nameSpan: nameSpan, valueSpan: valueSpan};
+        break;
+      }
+    }
+  }
+  return prop;
+}
+
+/**
+ * Get the text value of the property corresponding to a given selector and name
+ * in the rule-view
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} selectorText
+ *        The selector in the rule-view to look for the property in
+ * @param {String} propertyName
+ *        The name of the property
+ * @return {String} The property value
+ */
+function getRuleViewPropertyValue(view, selectorText, propertyName) {
+  return getRuleViewProperty(view, selectorText, propertyName)
+    .valueSpan.textContent;
+}
+
+/**
+ * Get a reference to the selector DOM element corresponding to a given selector
+ * in the rule-view
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} selectorText
+ *        The selector in the rule-view to look for
+ * @return {DOMNode} The selector DOM element
+ */
+function getRuleViewSelector(view, selectorText) {
+  let rule = getRuleViewRule(view, selectorText);
+  return rule.querySelector(".ruleview-selector, .ruleview-selector-matched");
+}
+
+/**
+ * Get a reference to the selectorhighlighter icon DOM element corresponding to
+ * a given selector in the rule-view
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} selectorText
+ *        The selector in the rule-view to look for
+ * @return {DOMNode} The selectorhighlighter icon DOM element
+ */
+function getRuleViewSelectorHighlighterIcon(view, selectorText) {
+  let rule = getRuleViewRule(view, selectorText);
+  return rule.querySelector(".ruleview-selectorhighlighter");
+}
+
+/**
+ * Simulate a color change in a given color picker tooltip, and optionally wait
+ * for a given element in the page to have its style changed as a result
+ *
+ * @param {RuleView} ruleView
+ *        The related rule view instance
+ * @param {SwatchColorPickerTooltip} colorPicker
+ * @param {Array} newRgba
+ *        The new color to be set [r, g, b, a]
+ * @param {Object} expectedChange
+ *        Optional object that needs the following props:
+ *          - {DOMNode} element The element in the page that will have its
+ *            style changed.
+ *          - {String} name The style name that will be changed
+ *          - {String} value The expected style value
+ * The style will be checked like so: getComputedStyle(element)[name] === value
+ */
+var simulateColorPickerChange = Task.async(function*(ruleView, colorPicker,
+    newRgba, expectedChange) {
+  let onRuleViewChanged = ruleView.once("ruleview-changed");
+  info("Getting the spectrum colorpicker object");
+  let spectrum = yield colorPicker.spectrum;
+  info("Setting the new color");
+  spectrum.rgb = newRgba;
+  info("Applying the change");
+  spectrum.updateUI();
+  spectrum.onChange();
+  info("Waiting for rule-view to update");
+  yield onRuleViewChanged;
+
+  if (expectedChange) {
+    info("Waiting for the style to be applied on the page");
+    yield waitForSuccess(() => {
+      let {element, name, value} = expectedChange;
+      return content.getComputedStyle(element)[name] === value;
+    }, "Color picker change applied on the page");
+  }
+});
+
+/**
+ * Get a rule-link from the rule-view given its index
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {Number} index
+ *        The index of the link to get
+ * @return {DOMNode} The link if any at this index
+ */
+function getRuleViewLinkByIndex(view, index) {
+  let links = view.styleDocument.querySelectorAll(".ruleview-rule-source");
+  return links[index];
+}
+
+/**
+ * Get rule-link text from the rule-view given its index
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {Number} index
+ *        The index of the link to get
+ * @return {String} The string at this index
+ */
+function getRuleViewLinkTextByIndex(view, index) {
+  let link = getRuleViewLinkByIndex(view, index);
+  return link.querySelector(".ruleview-rule-source-label").value;
+}
+
+/**
+ * Get the rule editor from the rule-view given its index
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {Number} childrenIndex
+ *        The children index of the element to get
+ * @param {Number} nodeIndex
+ *        The child node index of the element to get
+ * @return {DOMNode} The rule editor if any at this index
+ */
+function getRuleViewRuleEditor(view, childrenIndex, nodeIndex) {
+  return nodeIndex !== undefined ?
+    view.element.children[childrenIndex].childNodes[nodeIndex]._ruleEditor :
+    view.element.children[childrenIndex]._ruleEditor;
+}
+
+/**
+ * Click on a rule-view's close brace to focus a new property name editor
+ *
+ * @param {RuleEditor} ruleEditor
+ *        An instance of RuleEditor that will receive the new property
+ * @return a promise that resolves to the newly created editor when ready and
+ * focused
+ */
+var focusNewRuleViewProperty = Task.async(function*(ruleEditor) {
+  info("Clicking on a close ruleEditor brace to start editing a new property");
+  ruleEditor.closeBrace.scrollIntoView();
+  let editor = yield focusEditableField(ruleEditor.ruleView,
+    ruleEditor.closeBrace);
+
+  is(inplaceEditor(ruleEditor.newPropSpan), editor,
+    "Focused editor is the new property editor.");
+
+  return editor;
+});
+
+/**
+ * Create a new property name in the rule-view, focusing a new property editor
+ * by clicking on the close brace, and then entering the given text.
+ * Keep in mind that the rule-view knows how to handle strings with multiple
+ * properties, so the input text may be like: "p1:v1;p2:v2;p3:v3".
+ *
+ * @param {RuleEditor} ruleEditor
+ *        The instance of RuleEditor that will receive the new property(ies)
+ * @param {String} inputValue
+ *        The text to be entered in the new property name field
+ * @return a promise that resolves when the new property name has been entered
+ * and once the value field is focused
+ */
+var createNewRuleViewProperty = Task.async(function*(ruleEditor, inputValue) {
+  info("Creating a new property editor");
+  let editor = yield focusNewRuleViewProperty(ruleEditor);
+
+  info("Entering the value " + inputValue);
+  editor.input.value = inputValue;
+
+  info("Submitting the new value and waiting for value field focus");
+  let onFocus = once(ruleEditor.element, "focus", true);
+  EventUtils.synthesizeKey("VK_RETURN", {},
+    ruleEditor.element.ownerDocument.defaultView);
+  yield onFocus;
+});
+
+/**
+ * Set the search value for the rule-view filter styles search box.
+ *
+ * @param {CssRuleView} view
+ *        The instance of the rule-view panel
+ * @param {String} searchValue
+ *        The filter search value
+ * @return a promise that resolves when the rule-view is filtered for the
+ * search term
+ */
+var setSearchFilter = Task.async(function*(view, searchValue) {
+  info("Setting filter text to \"" + searchValue + "\"");
+  let win = view.styleWindow;
+  let searchField = view.searchField;
+  searchField.focus();
+  synthesizeKeys(searchValue, win);
+  yield view.inspector.once("ruleview-filtered");
+});
+
+/* *********************************************
+ * COMPUTED-VIEW
+ * *********************************************
+ * Computed-view related utility functions.
+ * Allows to get properties, links, expand properties, ...
+ */
+
+/**
+ * Get references to the name and value span nodes corresponding to a given
+ * property name in the computed-view
+ *
+ * @param {CssComputedView} view
+ *        The instance of the computed view panel
+ * @param {String} name
+ *        The name of the property to retrieve
+ * @return an object {nameSpan, valueSpan}
+ */
+function getComputedViewProperty(view, name) {
+  let prop;
+  for (let property of view.styleDocument.querySelectorAll(".property-view")) {
+    let nameSpan = property.querySelector(".property-name");
+    let valueSpan = property.querySelector(".property-value");
+
+    if (nameSpan.textContent === name) {
+      prop = {nameSpan: nameSpan, valueSpan: valueSpan};
+      break;
+    }
+  }
+  return prop;
+}
+
+/**
+ * Get the text value of the property corresponding to a given name in the
+ * computed-view
+ *
+ * @param {CssComputedView} view
+ *        The instance of the computed view panel
+ * @param {String} name
+ *        The name of the property to retrieve
+ * @return {String} The property value
+ */
+function getComputedViewPropertyValue(view, name, propertyName) {
+  return getComputedViewProperty(view, name, propertyName)
+    .valueSpan.textContent;
+}
+
+/* *********************************************
+ * STYLE-EDITOR
+ * *********************************************
+ * Style-editor related utility functions.
+ */
+
+/**
+ * Wait for the toolbox to emit the styleeditor-selected event and when done
+ * wait for the stylesheet identified by href to be loaded in the stylesheet
+ * editor
+ *
+ * @param {Toolbox} toolbox
+ * @param {String} href
+ *        Optional, if not provided, wait for the first editor to be ready
+ * @return a promise that resolves to the editor when the stylesheet editor is
+ * ready
+ */
+function waitForStyleEditor(toolbox, href) {
+  let def = promise.defer();
+
+  info("Waiting for the toolbox to switch to the styleeditor");
+  toolbox.once("styleeditor-selected").then(() => {
+    let panel = toolbox.getCurrentPanel();
+    ok(panel && panel.UI, "Styleeditor panel switched to front");
+
+    // A helper that resolves the promise once it receives an editor that
+    // matches the expected href. Returns false if the editor was not correct.
+    let gotEditor = (event, editor) => {
+      let currentHref = editor.styleSheet.href;
+      if (!href || (href && currentHref.endsWith(href))) {
+        info("Stylesheet editor selected");
+        panel.UI.off("editor-selected", gotEditor);
+
+        editor.getSourceEditor().then(sourceEditor => {
+          info("Stylesheet editor fully loaded");
+          def.resolve(sourceEditor);
+        });
+
+        return true;
+      }
+
+      info("The editor was incorrect. Waiting for editor-selected event.");
+      return false;
+    };
+
+    // The expected editor may already be selected. Check the if the currently
+    // selected editor is the expected one and if not wait for an
+    // editor-selected event.
+    if (!gotEditor("styleeditor-selected", panel.UI.selectedEditor)) {
+      // The expected editor is not selected (yet). Wait for it.
+      panel.UI.on("editor-selected", gotEditor);
+    }
+  });
+
+  return def.promise;
+}
+
+/**
+ * Reload the current page and wait for the inspector to be initialized after
+ * the navigation
+ *
+ * @param {InspectorPanel} inspector
+ *        The instance of InspectorPanel currently loaded in the toolbox
+ * @return a promise that resolves after page reload and inspector
+ * initialization
+ */
+function reloadPage(inspector) {
+  let onNewRoot = inspector.once("new-root");
+  content.location.reload();
+  return onNewRoot.then(() => {
+    inspector.markup._waitForChildren();
+  });
+}
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -23,24 +23,24 @@ devtools.jar:
 *   content/scratchpad/scratchpad.xul (scratchpad/scratchpad.xul)
     content/scratchpad/scratchpad.js (scratchpad/scratchpad.js)
     content/shared/splitview.css (shared/splitview.css)
     content/shared/theme-switching.js (shared/theme-switching.js)
     content/shared/frame-script-utils.js (shared/frame-script-utils.js)
     content/styleeditor/styleeditor.xul (styleeditor/styleeditor.xul)
     content/styleeditor/styleeditor.css (styleeditor/styleeditor.css)
     content/storage/storage.xul (storage/storage.xul)
-    content/styleinspector/computedview.xhtml (styleinspector/computedview.xhtml)
-    content/styleinspector/cssruleview.xhtml (styleinspector/cssruleview.xhtml)
-    content/styleinspector/ruleview.css (styleinspector/ruleview.css)
-    content/layoutview/view.js (layoutview/view.js)
-    content/layoutview/view.xhtml (layoutview/view.xhtml)
-    content/fontinspector/font-inspector.js (fontinspector/font-inspector.js)
-    content/fontinspector/font-inspector.xhtml (fontinspector/font-inspector.xhtml)
-    content/fontinspector/font-inspector.css (fontinspector/font-inspector.css)
+    content/inspector/computed/computed.xhtml (inspector/computed/computed.xhtml)
+    content/inspector/rules/rules.xhtml (inspector/rules/rules.xhtml)
+    content/inspector/rules/rules.css (inspector/rules/rules.css)
+    content/inspector/layout/layout.js (inspector/layout/layout.js)
+    content/inspector/layout/layout.xhtml (inspector/layout/layout.xhtml)
+    content/inspector/fonts/fonts.js (inspector/fonts/fonts.js)
+    content/inspector/fonts/fonts.xhtml (inspector/fonts/fonts.xhtml)
+    content/inspector/fonts/fonts.css (inspector/fonts/fonts.css)
     content/animationinspector/animation-controller.js (animationinspector/animation-controller.js)
     content/animationinspector/animation-panel.js (animationinspector/animation-panel.js)
     content/animationinspector/animation-inspector.xhtml (animationinspector/animation-inspector.xhtml)
     content/sourceeditor/codemirror/addon/comment/comment.js (sourceeditor/codemirror/addon/comment/comment.js)
     content/sourceeditor/codemirror/addon/edit/trailingspace.js (sourceeditor/codemirror/addon/edit/trailingspace.js)
     content/sourceeditor/codemirror/addon/edit/matchbrackets.js (sourceeditor/codemirror/addon/edit/matchbrackets.js)
     content/sourceeditor/codemirror/addon/edit/closebrackets.js (sourceeditor/codemirror/addon/edit/closebrackets.js)
     content/sourceeditor/codemirror/addon/dialog/dialog.js (sourceeditor/codemirror/addon/dialog/dialog.js)
@@ -166,17 +166,17 @@ devtools.jar:
     skin/images/filetypes/dir-close.svg (themes/images/filetypes/dir-close.svg)
     skin/images/filetypes/dir-open.svg (themes/images/filetypes/dir-open.svg)
     skin/images/filetypes/globe.svg (themes/images/filetypes/globe.svg)
     skin/images/filetypes/store.svg (themes/images/filetypes/store.svg)
     skin/images/commandline-icon.png (themes/images/commandline-icon.png)
     skin/images/commandline-icon@2x.png (themes/images/commandline-icon@2x.png)
     skin/images/alerticon-warning.png (themes/images/alerticon-warning.png)
     skin/images/alerticon-warning@2x.png (themes/images/alerticon-warning@2x.png)
-*   skin/ruleview.css (themes/ruleview.css)
+*   skin/rules.css (themes/rules.css)
     skin/commandline.css (themes/commandline.css)
     skin/images/command-paintflashing.png (themes/images/command-paintflashing.png)
     skin/images/command-paintflashing@2x.png (themes/images/command-paintflashing@2x.png)
     skin/images/command-screenshot.png (themes/images/command-screenshot.png)
     skin/images/command-screenshot@2x.png (themes/images/command-screenshot@2x.png)
     skin/images/command-responsivemode.png (themes/images/command-responsivemode.png)
     skin/images/command-responsivemode@2x.png (themes/images/command-responsivemode@2x.png)
     skin/images/command-scratchpad.png (themes/images/command-scratchpad.png)
@@ -228,17 +228,17 @@ devtools.jar:
     skin/images/itemToggle.png (themes/images/itemToggle.png)
     skin/images/itemToggle@2x.png (themes/images/itemToggle@2x.png)
     skin/images/itemArrow-dark-rtl.svg (themes/images/itemArrow-dark-rtl.svg)
     skin/images/itemArrow-dark-ltr.svg (themes/images/itemArrow-dark-ltr.svg)
     skin/images/itemArrow-rtl.svg (themes/images/itemArrow-rtl.svg)
     skin/images/itemArrow-ltr.svg (themes/images/itemArrow-ltr.svg)
     skin/images/noise.png (themes/images/noise.png)
     skin/images/dropmarker.svg (themes/images/dropmarker.svg)
-    skin/layoutview.css (themes/layoutview.css)
+    skin/layout.css (themes/layout.css)
     skin/images/debugger-collapse.png (themes/images/debugger-collapse.png)
     skin/images/debugger-collapse@2x.png (themes/images/debugger-collapse@2x.png)
     skin/images/debugger-expand.png (themes/images/debugger-expand.png)
     skin/images/debugger-expand@2x.png (themes/images/debugger-expand@2x.png)
     skin/images/debugger-pause.png (themes/images/debugger-pause.png)
     skin/images/debugger-pause@2x.png (themes/images/debugger-pause@2x.png)
     skin/images/debugger-play.png (themes/images/debugger-play.png)
     skin/images/debugger-play@2x.png (themes/images/debugger-play@2x.png)
@@ -324,18 +324,18 @@ devtools.jar:
     skin/images/vview-lock.png (themes/images/vview-lock.png)
     skin/images/vview-lock@2x.png (themes/images/vview-lock@2x.png)
     skin/images/vview-open-inspector.png (themes/images/vview-open-inspector.png)
     skin/images/vview-open-inspector@2x.png (themes/images/vview-open-inspector@2x.png)
     skin/images/sort-arrows.svg (themes/images/sort-arrows.svg)
     skin/images/cubic-bezier-swatch.png (themes/images/cubic-bezier-swatch.png)
     skin/images/cubic-bezier-swatch@2x.png (themes/images/cubic-bezier-swatch@2x.png)
     skin/images/undock@2x.png (themes/images/undock@2x.png)
-    skin/font-inspector.css (themes/font-inspector.css)
-    skin/computedview.css (themes/computedview.css)
+    skin/fonts.css (themes/fonts.css)
+    skin/computed.css (themes/computed.css)
     skin/images/arrow-e.png (themes/images/arrow-e.png)
     skin/images/arrow-e@2x.png (themes/images/arrow-e@2x.png)
     skin/projecteditor/projecteditor.css (themes/projecteditor/projecteditor.css)
     skin/images/search-clear-failed.svg (themes/images/search-clear-failed.svg)
     skin/images/search-clear-light.svg (themes/images/search-clear-light.svg)
     skin/images/search-clear-dark.svg (themes/images/search-clear-dark.svg)
     skin/tooltip/arrow-horizontal-dark.png (themes/tooltip/arrow-horizontal-dark.png)
     skin/tooltip/arrow-horizontal-dark@2x.png (themes/tooltip/arrow-horizontal-dark@2x.png)
--- a/devtools/client/moz.build
+++ b/devtools/client/moz.build
@@ -8,21 +8,19 @@ include('../templates.mozbuild')
 
 DIRS += [
     'aboutdebugging',
     'animationinspector',
     'canvasdebugger',
     'commandline',
     'debugger',
     'eyedropper',
-    'fontinspector',
     'framework',
     'inspector',
     'jsonview',
-    'layoutview',
     'locales',
     'markupview',
     'memory',
     'netmonitor',
     'performance',
     'preferences',
     'projecteditor',
     'promisedebugger',
--- a/devtools/client/styleeditor/test/head.js
+++ b/devtools/client/styleeditor/test/head.js
@@ -9,18 +9,19 @@ const TEST_HOST = 'mochi.test:8888';
 
 var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
 var {TargetFactory} = require("devtools/client/framework/target");
 var {console} = Cu.import("resource://gre/modules/Console.jsm", {});
 var promise = require("promise");
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
 
 // Import the GCLI test helper
-var testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
-Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this);
+Services.scriptloader.loadSubScript(
+  "chrome://mochitests/content/browser/devtools/client/commandline/test/helpers.js",
+  this);
 
 DevToolsUtils.testing = true;
 SimpleTest.registerCleanupFunction(() => {
   DevToolsUtils.testing = false;
 });
 
 /**
  * Add a new test tab in the browser and load the given url.
--- a/devtools/client/styleinspector/moz.build
+++ b/devtools/client/styleinspector/moz.build
@@ -2,15 +2,13 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 
 DevToolsModules(
-    'computed-view.js',
-    'rule-view.js',
     'style-inspector-menu.js',
     'style-inspector-overlays.js',
     'style-inspector.js',
     'utils.js',
 )
--- a/devtools/client/styleinspector/style-inspector-overlays.js
+++ b/devtools/client/styleinspector/style-inspector-overlays.js
@@ -42,17 +42,17 @@ const VIEW_NODE_LOCATION_TYPE = exports.
  * Manages all highlighters in the style-inspector.
  *
  * @param {CssRuleView|CssComputedView} view
  *        Either the rule-view or computed-view panel
  */
 function HighlightersOverlay(view) {
   this.view = view;
 
-  let {CssRuleView} = require("devtools/client/styleinspector/rule-view");
+  let {CssRuleView} = require("devtools/client/inspector/rules/rules");
   this.isRuleView = view instanceof CssRuleView;
 
   this.highlighterUtils = this.view.inspector.toolbox.highlighterUtils;
 
   this._onMouseMove = this._onMouseMove.bind(this);
   this._onMouseLeave = this._onMouseLeave.bind(this);
 
   this.highlighters = {};
@@ -235,17 +235,17 @@ HighlightersOverlay.prototype = {
  * Manages all tooltips in the style-inspector.
  *
  * @param {CssRuleView|CssComputedView} view
  *        Either the rule-view or computed-view panel
  */
 function TooltipsOverlay(view) {
   this.view = view;
 
-  let {CssRuleView} = require("devtools/client/styleinspector/rule-view");
+  let {CssRuleView} = require("devtools/client/inspector/rules/rules");
   this.isRuleView = view instanceof CssRuleView;
 
   this._onNewSelection = this._onNewSelection.bind(this);
   this.view.inspector.selection.on("new-node-front", this._onNewSelection);
 }
 
 exports.TooltipsOverlay = TooltipsOverlay;
 
--- a/devtools/client/styleinspector/style-inspector.js
+++ b/devtools/client/styleinspector/style-inspector.js
@@ -10,19 +10,19 @@ const {Cu} = require("chrome");
 const promise = require("promise");
 const {Tools} = require("devtools/client/main");
 Cu.import("resource://gre/modules/Services.jsm");
 const {PREF_ORIG_SOURCES} = require("devtools/client/styleeditor/utils");
 
 loader.lazyGetter(this, "gDevTools", () =>
   Cu.import("resource://devtools/client/framework/gDevTools.jsm", {}).gDevTools);
 loader.lazyGetter(this, "RuleView",
-  () => require("devtools/client/styleinspector/rule-view"));
+  () => require("devtools/client/inspector/rules/rules"));
 loader.lazyGetter(this, "ComputedView",
-  () => require("devtools/client/styleinspector/computed-view"));
+  () => require("devtools/client/inspector/computed/computed"));
 loader.lazyGetter(this, "_strings", () => Services.strings
   .createBundle("chrome://devtools-shared/locale/styleinspector.properties"));
 
 // This module doesn't currently export any symbols directly, it only
 // registers inspector tools.
 
 function RuleViewTool(inspector, window) {
   this.inspector = inspector;
--- a/devtools/client/styleinspector/test/browser.ini
+++ b/devtools/client/styleinspector/test/browser.ini
@@ -4,200 +4,19 @@ subsuite = devtools
 support-files =
   doc_content_stylesheet.html
   doc_content_stylesheet.xul
   doc_content_stylesheet_imported.css
   doc_content_stylesheet_imported2.css
   doc_content_stylesheet_linked.css
   doc_content_stylesheet_script.css
   doc_content_stylesheet_xul.css
-  doc_copystyles.css
-  doc_copystyles.html
-  doc_cssom.html
-  doc_custom.html
-  doc_filter.html
   doc_frame_script.js
-  doc_keyframeanimation.html
-  doc_keyframeanimation.css
-  doc_keyframeLineNumbers.html
-  doc_matched_selectors.html
-  doc_media_queries.html
-  doc_pseudoelement.html
-  doc_ruleLineNumbers.html
-  doc_sourcemaps.css
-  doc_sourcemaps.css.map
-  doc_sourcemaps.html
-  doc_sourcemaps.scss
-  doc_style_editor_link.css
-  doc_test_image.png
-  doc_urls_clickable.css
-  doc_urls_clickable.html
   head.js
 
-[browser_computedview_browser-styles.js]
-[browser_computedview_cycle_color.js]
-[browser_computedview_getNodeInfo.js]
-[browser_computedview_keybindings_01.js]
-[browser_computedview_keybindings_02.js]
-[browser_computedview_matched-selectors-toggle.js]
-[browser_computedview_matched-selectors_01.js]
-[browser_computedview_matched-selectors_02.js]
-[browser_computedview_media-queries.js]
-[browser_computedview_no-results-placeholder.js]
-[browser_computedview_original-source-link.js]
-[browser_computedview_pseudo-element_01.js]
-[browser_computedview_refresh-on-style-change_01.js]
-[browser_computedview_search-filter.js]
-[browser_computedview_search-filter_clear.js]
-[browser_computedview_search-filter_context-menu.js]
-[browser_computedview_search-filter_escape-keypress.js]
-[browser_computedview_select-and-copy-styles.js]
-[browser_computedview_style-editor-link.js]
-[browser_ruleview_add-property-and-reselect.js]
-[browser_ruleview_add-property-cancel_01.js]
-[browser_ruleview_add-property-cancel_02.js]
-[browser_ruleview_add-property-cancel_03.js]
-[browser_ruleview_add-property_01.js]
-[browser_ruleview_add-property_02.js]
-[browser_ruleview_add-property-svg.js]
-[browser_ruleview_add-rule_01.js]
-[browser_ruleview_add-rule_02.js]
-[browser_ruleview_add-rule_03.js]
-[browser_ruleview_add-rule_04.js]
-[browser_ruleview_add-rule_pseudo_class.js]
-[browser_ruleview_authored.js]
-[browser_ruleview_colorpicker-and-image-tooltip_01.js]
-[browser_ruleview_colorpicker-and-image-tooltip_02.js]
-[browser_ruleview_colorpicker-appears-on-swatch-click.js]
-[browser_ruleview_colorpicker-commit-on-ENTER.js]
-[browser_ruleview_colorpicker-edit-gradient.js]
-[browser_ruleview_colorpicker-hides-on-tooltip.js]
-[browser_ruleview_colorpicker-multiple-changes.js]
-[browser_ruleview_colorpicker-release-outside-frame.js]
-[browser_ruleview_colorpicker-revert-on-ESC.js]
-[browser_ruleview_colorpicker-swatch-displayed.js]
-[browser_ruleview_colorUnit.js]
-[browser_ruleview_completion-existing-property_01.js]
-[browser_ruleview_completion-existing-property_02.js]
-[browser_ruleview_completion-new-property_01.js]
-[browser_ruleview_completion-new-property_02.js]
-[browser_ruleview_completion-new-property_03.js]
-[browser_ruleview_computed-lists_01.js]
-[browser_ruleview_computed-lists_02.js]
-[browser_ruleview_completion-popup-hidden-after-navigation.js]
-[browser_ruleview_content_01.js]
-[browser_ruleview_content_02.js]
-skip-if = e10s # Bug 1039528: "inspect element" contextual-menu doesn't work with e10s
-[browser_ruleview_context-menu-show-mdn-docs-01.js]
-[browser_ruleview_context-menu-show-mdn-docs-02.js]
-[browser_ruleview_context-menu-show-mdn-docs-03.js]
-[browser_ruleview_copy_styles.js]
-[browser_ruleview_cssom.js]
-[browser_ruleview_cubicbezier-appears-on-swatch-click.js]
-[browser_ruleview_cubicbezier-commit-on-ENTER.js]
-[browser_ruleview_cubicbezier-revert-on-ESC.js]
-[browser_ruleview_custom.js]
-[browser_ruleview_cycle-color.js]
-[browser_ruleview_edit-property-cancel.js]
-[browser_ruleview_edit-property-commit.js]
-[browser_ruleview_edit-property-computed.js]
-[browser_ruleview_edit-property-increments.js]
-[browser_ruleview_edit-property-order.js]
-[browser_ruleview_edit-property-remove_01.js]
-[browser_ruleview_edit-property-remove_02.js]
-[browser_ruleview_edit-property-remove_03.js]
-[browser_ruleview_edit-property_01.js]
-[browser_ruleview_edit-property_02.js]
-[browser_ruleview_edit-property_03.js]
-[browser_ruleview_edit-property_04.js]
-[browser_ruleview_edit-property_05.js]
-[browser_ruleview_edit-property_06.js]
-[browser_ruleview_edit-property_07.js]
-[browser_ruleview_edit-property_08.js]
-[browser_ruleview_edit-selector-commit.js]
-[browser_ruleview_edit-selector_01.js]
-[browser_ruleview_edit-selector_02.js]
-[browser_ruleview_edit-selector_03.js]
-[browser_ruleview_edit-selector_04.js]
-[browser_ruleview_edit-selector_05.js]
-[browser_ruleview_edit-selector_06.js]
-[browser_ruleview_editable-field-focus_01.js]
-[browser_ruleview_editable-field-focus_02.js]
-[browser_ruleview_eyedropper.js]
-[browser_ruleview_filtereditor-appears-on-swatch-click.js]
-[browser_ruleview_filtereditor-commit-on-ENTER.js]
-[browser_ruleview_filtereditor-revert-on-ESC.js]
-skip-if = (os == "win" && debug) || e10s # bug 963492: win. bug 1040653: e10s.
-[browser_ruleview_guessIndentation.js]
-[browser_ruleview_inherited-properties_01.js]
-[browser_ruleview_inherited-properties_02.js]
-[browser_ruleview_inherited-properties_03.js]
-[browser_ruleview_keybindings.js]
-[browser_ruleview_keyframes-rule_01.js]
-[browser_ruleview_keyframes-rule_02.js]
-[browser_ruleview_keyframeLineNumbers.js]
-[browser_ruleview_lineNumbers.js]
-[browser_ruleview_livepreview.js]
-[browser_ruleview_mark_overridden_01.js]
-[browser_ruleview_mark_overridden_02.js]
-[browser_ruleview_mark_overridden_03.js]
-[browser_ruleview_mark_overridden_04.js]
-[browser_ruleview_mark_overridden_05.js]
-[browser_ruleview_mark_overridden_06.js]
-[browser_ruleview_mark_overridden_07.js]
-[browser_ruleview_mathml-element.js]
-[browser_ruleview_media-queries.js]
-[browser_ruleview_multiple-properties-duplicates.js]
-[browser_ruleview_multiple-properties-priority.js]
-[browser_ruleview_multiple-properties-unfinished_01.js]
-[browser_ruleview_multiple-properties-unfinished_02.js]
-[browser_ruleview_multiple_properties_01.js]
-[browser_ruleview_multiple_properties_02.js]
-[browser_ruleview_original-source-link.js]
-[browser_ruleview_pseudo-element_01.js]
-[browser_ruleview_pseudo-element_02.js]
-skip-if = e10s # Bug 1090340
-[browser_ruleview_pseudo_lock_options.js]
-[browser_ruleview_refresh-no-flicker.js]
-[browser_ruleview_refresh-on-attribute-change_01.js]
-[browser_ruleview_refresh-on-attribute-change_02.js]
-[browser_ruleview_refresh-on-style-change.js]
-[browser_ruleview_search-filter-computed-list_01.js]
-[browser_ruleview_search-filter-computed-list_02.js]
-[browser_ruleview_search-filter-computed-list_03.js]
-[browser_ruleview_search-filter-computed-list_04.js]
-[browser_ruleview_search-filter-computed-list_expander.js]
-[browser_ruleview_search-filter-overridden-property.js]
-[browser_ruleview_search-filter_01.js]
-[browser_ruleview_search-filter_02.js]
-[browser_ruleview_search-filter_03.js]
-[browser_ruleview_search-filter_04.js]
-[browser_ruleview_search-filter_05.js]
-[browser_ruleview_search-filter_06.js]
-[browser_ruleview_search-filter_07.js]
-[browser_ruleview_search-filter_08.js]
-[browser_ruleview_search-filter_09.js]
-[browser_ruleview_search-filter_10.js]
-[browser_ruleview_search-filter_context-menu.js]
-[browser_ruleview_search-filter_escape-keypress.js]
-[browser_ruleview_select-and-copy-styles.js]
-[browser_ruleview_selector-highlighter_01.js]
-[browser_ruleview_selector-highlighter_02.js]
-[browser_ruleview_selector-highlighter_03.js]
-[browser_ruleview_selector_highlight.js]
-[browser_ruleview_strict-search-filter-computed-list_01.js]
-[browser_ruleview_strict-search-filter_01.js]
-[browser_ruleview_strict-search-filter_02.js]
-[browser_ruleview_strict-search-filter_03.js]
-[browser_ruleview_style-editor-link.js]
-skip-if = e10s # bug 1040670 Cannot open inline styles in viewSourceUtils
-[browser_ruleview_urls-clickable.js]
-[browser_ruleview_user-agent-styles.js]
-[browser_ruleview_user-agent-styles-uneditable.js]
-[browser_ruleview_user-property-reset.js]
 [browser_styleinspector_context-menu-copy-color_01.js]
 [browser_styleinspector_context-menu-copy-color_02.js]
 [browser_styleinspector_context-menu-copy-urls.js]
 [browser_styleinspector_csslogic-content-stylesheets.js]
 [browser_styleinspector_output-parser.js]
 [browser_styleinspector_refresh_when_active.js]
 [browser_styleinspector_tooltip-background-image.js]
 [browser_styleinspector_tooltip-closes-on-new-selection.js]
deleted file mode 100644
--- a/devtools/client/styleinspector/test/doc_matched_selectors.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!-- Any copyright is dedicated to the Public Domain.
-     http://creativecommons.org/publicdomain/zero/1.0/ -->
-<html>
-  <head>
-    <style>
-      .matched1, .matched2, .matched3, .matched4, .matched5 {
-        color: #000;
-      }
-
-      div {
-        position: absolute;
-        top: 40px;
-        left: 20px;
-        border: 1px solid #000;
-        color: #111;
-        width: 100px;
-        height: 50px;
-      }
-    </style>
-  </head>
-  <body>
-    inspectstyle($("test"));
-    <div id="test" class="matched1 matched2 matched3 matched4 matched5">Test div</div>
-    <div id="dummy">
-      <div></div>
-    </div>
-  </body>
-</html>
--- a/devtools/client/styleinspector/test/head.js
+++ b/devtools/client/styleinspector/test/head.js
@@ -3,18 +3,17 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 var Cu = Components.utils;
 var {gDevTools} = Cu.import("resource://devtools/client/framework/gDevTools.jsm", {});
 var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
 var {TargetFactory} = require("devtools/client/framework/target");
-var {CssComputedView} = require("devtools/client/styleinspector/computed-view");
-var {CssRuleView, _ElementStyle} = require("devtools/client/styleinspector/rule-view");
+var {CssRuleView, _ElementStyle} = require("devtools/client/inspector/rules/rules");
 var {CssLogic, CssSelector} = require("devtools/shared/styleinspector/css-logic");
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
 var promise = require("promise");
 var {editableField, getInplaceEditorForSpan: inplaceEditor} =
   require("devtools/client/shared/inplace-editor");
 var {console} =
   Components.utils.import("resource://gre/modules/Console.jsm", {});
 
@@ -144,34 +143,16 @@ function getNode(nodeOrSelector) {
  * @param {InspectorPanel} inspector
  *        The instance of InspectorPanel currently loaded in the toolbox
  * @return {Promise} Resolves to the NodeFront instance
  */
 function getNodeFront(selector, {walker}) {
   return walker.querySelector(walker.rootNode, selector);
 }
 
-/**
- * Highlight a node that matches the given css selector and set the inspector's
- * current selection to this node.
- *
- * @param {String} selector
- * @param {InspectorPanel} inspector
- *        The instance of InspectorPanel currently loaded in the toolbox
- * @return {Promise} Resolves when the inspector is updated with the new node
- */
-var selectAndHighlightNode = Task.async(function*(selector, inspector) {
-  info("Highlighting and selecting the node for " + selector);
-
-  let nodeFront = yield getNodeFront(selector, inspector);
-  let updated = inspector.toolbox.once("highlighter-ready");
-  inspector.selection.setNodeFront(nodeFront, "test-highlight");
-  yield updated;
-});
-
 /*
  * Set the inspector's current selection to a node or to the first match of the
  * given css selector.
  *
  * @param {String|NodeFront} data
  *        The node to select
  * @param {InspectorPanel} inspector
  *        The instance of InspectorPanel currently loaded in the toolbox
@@ -511,57 +492,16 @@ function assertHoverTooltipOn(tooltip, e
   return isHoverTooltipTarget(tooltip, element).then(() => {
     ok(true, "A tooltip is defined on hover of the given element");
   }, () => {
     ok(false, "No tooltip is defined on hover of the given element");
   });
 }
 
 /**
- * Same as assertHoverTooltipOn but fails the test if there is a tooltip defined
- * on hover of the given element
- *
- * @return a promise
- */
-function assertNoHoverTooltipOn(tooltip, element) {
-  return isHoverTooltipTarget(tooltip, element).then(() => {
-    ok(false, "A tooltip is defined on hover of the given element");
-  }, () => {
-    ok(true, "No tooltip is defined on hover of the given element");
-  });
-}
-
-/**
- * Listen for a new window to open and return a promise that resolves when one
- * does and completes its load.
- * Only resolves when the new window topic isn't domwindowopened.
- *
- * @return a promise that resolves to the window object
- */
-function waitForWindow() {
-  let def = promise.defer();
-
-  info("Waiting for a window to open");
-  Services.ww.registerNotification(function onWindow(subject, topic) {
-    if (topic != "domwindowopened") {
-      return;
-    }
-    info("A window has been opened");
-    let win = subject.QueryInterface(Ci.nsIDOMWindow);
-    once(win, "load").then(() => {
-      info("The window load completed");
-      Services.ww.unregisterNotification(onWindow);
-      def.resolve(win);
-    });
-  });
-
-  return def.promise;
-}
-
-/**
  * Listen for a new tab to open and return a promise that resolves when one
  * does and completes the load event.
  *
  * @return a promise that resolves to the tab object
  */
 var waitForTab = Task.async(function*() {
   info("Waiting for a tab to open");
   yield once(gBrowser.tabContainer, "TabOpen");
@@ -585,25 +525,16 @@ var waitForTab = Task.async(function*() 
  */
 function waitForClipboard(setup, expected) {
   let def = promise.defer();
   SimpleTest.waitForClipboard(expected, setup, def.resolve, def.reject);
   return def.promise;
 }
 
 /**
- * Dispatch the copy event on the given element
- */
-function fireCopyEvent(element) {
-  let evt = element.ownerDocument.createEvent("Event");
-  evt.initEvent("copy", true, true);
-  element.dispatchEvent(evt);
-}
-
-/**
  * Polls a given function waiting for it to return true.
  *
  * @param {Function} validatorFn
  *        A validator function that returns a boolean.
  *        This is called every few milliseconds to check if the result is true.
  *        When it is true, the promise resolves.
  * @param {String} name
  *        Optional name of the test. This is used to generate
@@ -976,124 +907,30 @@ function getComputedViewProperty(view, n
       prop = {nameSpan: nameSpan, valueSpan: valueSpan};
       break;
     }
   }
   return prop;
 }
 
 /**
- * Get an instance of PropertyView from the computed-view.
- *
- * @param {CssComputedView} view
- *        The instance of the computed view panel
- * @param {String} name
- *        The name of the property to retrieve
- * @return {PropertyView}
- */
-function getComputedViewPropertyView(view, name) {
-  let propView;
-  for (let propertyView of view.propertyViews) {
-    if (propertyView._propertyInfo.name === name) {
-      propView = propertyView;
-      break;
-    }
-  }
-  return propView;
-}
-
-/**
- * Get a reference to the property-content element for a given property name in
- * the computed-view.
- * A property-content element always follows (nextSibling) the property itself
- * and is only shown when the twisty icon is expanded on the property.
- * A property-content element contains matched rules, with selectors,
- * properties, values and stylesheet links
- *
- * @param {CssComputedView} view
- *        The instance of the computed view panel
- * @param {String} name
- *        The name of the property to retrieve
- * @return {Promise} A promise that resolves to the property matched rules
- * container
- */
-var getComputedViewMatchedRules = Task.async(function*(view, name) {
-  let expander;
-  let propertyContent;
-  for (let property of view.styleDocument.querySelectorAll(".property-view")) {
-    let nameSpan = property.querySelector(".property-name");
-    if (nameSpan.textContent === name) {
-      expander = property.querySelector(".expandable");
-      propertyContent = property.nextSibling;
-      break;
-    }
-  }
-
-  if (!expander.hasAttribute("open")) {
-    // Need to expand the property
-    let onExpand = view.inspector.once("computed-view-property-expanded");
-    expander.click();
-    yield onExpand;
-  }
-
-  return propertyContent;
-});
-
-/**
  * Get the text value of the property corresponding to a given name in the
  * computed-view
  *
  * @param {CssComputedView} view
  *        The instance of the computed view panel
  * @param {String} name
  *        The name of the property to retrieve
  * @return {String} The property value
  */
 function getComputedViewPropertyValue(view, name, propertyName) {
   return getComputedViewProperty(view, name, propertyName)
     .valueSpan.textContent;
 }
 
-/**
- * Expand a given property, given its index in the current property list of
- * the computed view
- *
- * @param {CssComputedView} view
- *        The instance of the computed view panel
- * @param {Number} index
- *        The index of the property to be expanded
- * @return a promise that resolves when the property has been expanded, or
- * rejects if the property was not found
- */
-function expandComputedViewPropertyByIndex(view, index) {
-  info("Expanding property " + index + " in the computed view");
-  let expandos = view.styleDocument.querySelectorAll(".expandable");
-  if (!expandos.length || !expandos[index]) {
-    return promise.reject();
-  }
-
-  let onExpand = view.inspector.once("computed-view-property-expanded");
-  expandos[index].click();
-  return onExpand;
-}
-
-/**
- * Get a rule-link from the computed-view given its index
- *
- * @param {CssComputedView} view
- *        The instance of the computed view panel
- * @param {Number} index
- *        The index of the link to be retrieved
- * @return {DOMNode} The link at the given index, if one exists, null otherwise
- */
-function getComputedViewLinkByIndex(view, index) {
-  let links = view.styleDocument.querySelectorAll(".rule-link .link");
-  return links[index];
-}
-
 /* *********************************************
  * STYLE-EDITOR
  * *********************************************
  * Style-editor related utility functions.
  */
 
 /**
  * Wait for the toolbox to emit the styleeditor-selected event and when done
rename from devtools/client/themes/computedview.css
rename to devtools/client/themes/computed.css
rename from devtools/client/themes/font-inspector.css
rename to devtools/client/themes/fonts.css
rename from devtools/client/themes/layoutview.css
rename to devtools/client/themes/layout.css
rename from devtools/client/themes/ruleview.css
rename to devtools/client/themes/rules.css
--- a/dom/apps/UserCustomizations.jsm
+++ b/dom/apps/UserCustomizations.jsm
@@ -75,16 +75,22 @@ this.UserCustomizations = {
       this.extensions.get(aApp.manifestURL).shutdown();
       this.extensions.delete(aApp.manifestURL);
       let uri = Services.io.newURI(aApp.origin, null, null);
       this.appId.delete(uri.host);
     }
   },
 
   isFromExtension: function(aURI) {
+    if (!aURI && Services.prefs.getBoolPref("webextensions.tests")) {
+      // That's the case in mochitests because of the packaging setup:
+      // aURI is expected to be the appURI from the jarChannel but there is
+      // no real app associated to mochitest's jar:remoteopenfile:/// uris.
+      return true;
+    }
     return this.appId.has(aURI.host);
   },
 
   // Checks that this is a valid extension manifest.
   // The format is documented at https://developer.chrome.com/extensions/manifest
   checkExtensionManifest: function(aManifest) {
     if (!aManifest) {
       return false;
--- a/gfx/layers/IPDLActor.h
+++ b/gfx/layers/IPDLActor.h
@@ -2,17 +2,16 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_LAYERS_IPDLACTOR_H
 #define MOZILLA_LAYERS_IPDLACTOR_H
 
 #include "mozilla/ipc/ProtocolUtils.h"
-#include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/unused.h"
 
 namespace mozilla {
 namespace layers {
 
 /// A base class to facilitate the deallocation of IPDL actors.
 ///
 /// This class implements a simple deallocation protocol that avoids races
@@ -44,54 +43,43 @@ public:
 
   /// Check the return of CanSend before sending any message!
   bool CanSend() const { return !mDestroyed; }
 
   /// The normal way to destroy the actor.
   ///
   /// This will asynchronously send a Destroy message to the parent actor, whom
   /// will send the delete message.
-  void Destroy(CompositableForwarder* aFwd = nullptr)
+  void Destroy()
   {
     MOZ_ASSERT(!mDestroyed);
     if (!mDestroyed) {
       mDestroyed = true;
       DestroyManagees();
-      if (!aFwd || !aFwd->DestroyInTransaction(this, false)) {
-        this->SendDestroy();
-      }
+      this->SendDestroy();
     }
   }
 
   /// The ugly and slow way to destroy the actor.
   ///
   /// This will block until the Parent actor has handled the Destroy message,
   /// and then start the asynchronous handshake (and destruction will already
   /// be done on the parent side, when the async part happens).
-  void DestroySynchronously(CompositableForwarder* aFwd = nullptr)
+  void DestroySynchronously()
   {
     MOZ_PERFORMANCE_WARNING("gfx", "IPDL actor requires synchronous deallocation");
     MOZ_ASSERT(!mDestroyed);
     if (!mDestroyed) {
       DestroyManagees();
       mDestroyed = true;
-      if (!aFwd || !aFwd->DestroyInTransaction(this, true)) {
-        this->SendDestroySync();
-        this->SendDestroy();
-      }
+      this->SendDestroySync();
+      this->SendDestroy();
     }
   }
 
-  /// If the transaction that was supposed to destroy the texture fails for
-  /// whatever reason, fallback to destroying the actor synchronously.
-  static bool DestroyFallback(Protocol* aActor)
-  {
-    return aActor->SendDestroySync();
-  }
-
   /// Override this if the protocol manages other protocols, and destroy the
   /// managees from there
   virtual void DestroyManagees() {}
 
 private:
   bool mDestroyed;
 };
 
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -639,16 +639,18 @@ ClientLayerManager::ForwardTransaction(b
 
   if (!sent) {
     // Clear the transaction id so that it doesn't get returned
     // unless we forwarded to somewhere that doesn't actually
     // have a compositor.
     mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId);
   }
 
+  mForwarder->RemoveTexturesIfNecessary();
+  mForwarder->RemoveCompositablesIfNecessary();
   mForwarder->SendPendingAsyncMessges();
   mPhase = PHASE_NONE;
 
   // this may result in Layers being deleted, which results in
   // PLayer::Send__delete__() and DeallocShmem()
   mKeepAlive.Clear();
 
   TabChild* window = mWidget->GetOwningTabChild();
--- a/gfx/layers/client/ClientTiledPaintedLayer.cpp
+++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp
@@ -407,16 +407,17 @@ void
 ClientTiledPaintedLayer::RenderLayer()
 {
   LayerManager::DrawPaintedLayerCallback callback =
     ClientManager()->GetPaintedLayerCallback();
   void *data = ClientManager()->GetPaintedLayerCallbackData();
 
   IntSize layerSize = mVisibleRegion.ToUnknownRegion().GetBounds().Size();
   if (mContentClient && !mContentClient->SupportsLayerSize(layerSize, ClientManager())) {
+    ClientManager()->AsShadowForwarder()->HoldUntilTransaction(mContentClient);
     mContentClient = nullptr;
     mValidRegion.SetEmpty();
   }
 
   if (!mContentClient) {
     if (mCreationHint == LayerManager::NONE &&
         SingleTiledContentClient::ClientSupportsLayerSize(layerSize, ClientManager()) &&
         gfxPrefs::LayersSingleTileEnabled()) {
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -175,28 +175,23 @@ CompositableClient::IsConnected() const
 }
 
 void
 CompositableClient::Destroy()
 {
   if (!IsConnected()) {
     return;
   }
-
-  mCompositableChild->mCompositableClient = nullptr;
-  mCompositableChild->Destroy(mForwarder);
-  mCompositableChild = nullptr;
-
+  // Send pending AsyncMessages before deleting CompositableChild.
+  // They might have dependency to the mCompositableChild.
   mForwarder->SendPendingAsyncMessges();
-}
-
-bool
-CompositableClient::DestroyFallback(PCompositableChild* aActor)
-{
-  return aActor->SendDestroySync();
+  // Destroy CompositableChild.
+  mCompositableChild->mCompositableClient = nullptr;
+  mCompositableChild->Destroy();
+  mCompositableChild = nullptr;
 }
 
 uint64_t
 CompositableClient::GetAsyncID() const
 {
   if (mCompositableChild) {
     return mCompositableChild->mAsyncID;
   }
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -150,18 +150,16 @@ public:
 
   /**
    * Establishes the connection with compositor side through IPDL
    */
   virtual bool Connect(ImageContainer* aImageContainer = nullptr);
 
   void Destroy();
 
-  static bool DestroyFallback(PCompositableChild* aActor);
-
   bool IsConnected() const;
 
   PCompositableChild* GetIPDLActor() const;
 
   // should only be called by a CompositableForwarder
   virtual void SetIPDLActor(CompositableChild* aChild);
 
   CompositableForwarder* GetForwarder() const
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -295,23 +295,23 @@ DeallocateTextureClient(TextureDeallocPa
     // race causing this function to be called concurrently which is bad!
     gfxCriticalError() << "Racy texture deallocation";
     return;
   }
 
   if (params.syncDeallocation) {
     MOZ_PERFORMANCE_WARNING("gfx",
       "TextureClient/Host pair requires synchronous deallocation");
-    actor->DestroySynchronously(actor->GetForwarder());
+    actor->DestroySynchronously();
     DestroyTextureData(params.data, params.allocator, params.clientDeallocation,
                        actor->mMainThreadOnly);
   } else {
     actor->mTextureData = params.data;
     actor->mOwnsTextureData = params.clientDeallocation;
-    actor->Destroy(actor->GetForwarder());
+    actor->Destroy();
     // DestroyTextureData will be called by TextureChild::ActorDestroy
   }
 }
 
 void TextureClient::Destroy(bool aForceSync)
 {
   MOZ_ASSERT(!IsLocked());
 
@@ -342,24 +342,16 @@ void TextureClient::Destroy(bool aForceS
     // client side, but having asynchronous deallocate in some of the cases will
     // be a worthwhile optimization.
     params.syncDeallocation = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT) || aForceSync;
     DeallocateTextureClient(params);
   }
 }
 
 bool
-TextureClient::DestroyFallback(PTextureChild* aActor)
-{
-  // should not end up here so crash debug builds.
-  MOZ_ASSERT(false);
-  return aActor->SendDestroySync();
-}
-
-bool
 TextureClient::Lock(OpenMode aMode)
 {
   MOZ_ASSERT(IsValid());
   MOZ_ASSERT(!mIsLocked);
   if (mIsLocked) {
     return mOpenMode == aMode;
   }
 
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -416,18 +416,16 @@ public:
    *
    * TextureChild is an implementation detail of TextureClient that is not
    * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor
    * are for use with the managing IPDL protocols only (so that they can
    * implement AllocPextureChild and DeallocPTextureChild).
    */
   static PTextureChild* CreateIPDLActor();
   static bool DestroyIPDLActor(PTextureChild* actor);
-  // call this if the transaction that was supposed to destroy the actor failed.
-  static bool DestroyFallback(PTextureChild* actor);
 
   /**
    * Get the TextureClient corresponding to the actor passed in parameter.
    */
   static TextureClient* AsTextureClient(PTextureChild* actor);
 
   gfx::IntSize GetSize() const;
 
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -222,22 +222,16 @@ CompositableHost::DumpTextureHost(std::s
   }
   RefPtr<gfx::DataSourceSurface> dSurf = aTexture->GetAsSurface();
   if (!dSurf) {
     return;
   }
   aStream << gfxUtils::GetAsDataURI(dSurf).get();
 }
 
-void
-CompositableHost::ReceivedDestroy(PCompositableParent* aActor)
-{
-  static_cast<CompositableParent*>(aActor)->RecvDestroy();
-}
-
 namespace CompositableMap {
 
 typedef std::map<uint64_t, PCompositableParent*> CompositableMap_t;
 static CompositableMap_t* sCompositableMap = nullptr;
 bool IsCreated() {
   return sCompositableMap != nullptr;
 }
 PCompositableParent* Get(uint64_t aID)
--- a/gfx/layers/composite/CompositableHost.h
+++ b/gfx/layers/composite/CompositableHost.h
@@ -171,19 +171,16 @@ public:
         aFlags & FORCE_DETACH) {
       SetLayer(nullptr);
       mAttached = false;
       mKeepAttached = false;
     }
   }
   bool IsAttached() { return mAttached; }
 
-  static void
-  ReceivedDestroy(PCompositableParent* aActor);
-
   virtual void Dump(std::stringstream& aStream,
                     const char* aPrefix="",
                     bool aDumpHtml=false) { }
   static void DumpTextureHost(std::stringstream& aStream, TextureHost* aTexture);
 
   virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() { return nullptr; }
 
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) = 0;
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -830,22 +830,16 @@ TextureParent::Destroy()
   // Clear recycle callback.
   mTextureHost->ClearRecycleCallback();
   mWaitForClientRecycle = nullptr;
 
   mTextureHost->mActor = nullptr;
   mTextureHost = nullptr;
 }
 
-void
-TextureHost::ReceivedDestroy(PTextureParent* aActor)
-{
-  static_cast<TextureParent*>(aActor)->RecvDestroy();
-}
-
 bool
 TextureParent::RecvRecycleTexture(const TextureFlags& aTextureFlags)
 {
   if (!mTextureHost) {
     return true;
   }
   mTextureHost->RecycleTexture(aTextureFlags);
   return true;
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -458,18 +458,16 @@ public:
                                          TextureFlags aFlags);
   static bool DestroyIPDLActor(PTextureParent* actor);
 
   /**
    * Destroy the TextureChild/Parent pair.
    */
   static bool SendDeleteIPDLActor(PTextureParent* actor);
 
-  static void ReceivedDestroy(PTextureParent* actor);
-
   /**
    * Get the TextureHost corresponding to the actor passed in parameter.
    */
   static TextureHost* AsTextureHost(PTextureParent* actor);
 
   /**
    * Return a pointer to the IPDLActor.
    *
--- a/gfx/layers/ipc/CompositableForwarder.h
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -79,19 +79,16 @@ public:
                                    const nsIntRegion& aUpdatedRegion) = 0;
 
 #ifdef MOZ_WIDGET_GONK
   virtual void UseOverlaySource(CompositableClient* aCompositabl,
                                 const OverlaySource& aOverlay,
                                 const gfx::IntRect& aPictureRect) = 0;
 #endif
 
-  virtual bool DestroyInTransaction(PTextureChild* aTexture, bool synchronously) = 0;
-  virtual bool DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously) = 0;
-
   /**
    * Tell the CompositableHost on the compositor side to remove the texture
    * from the CompositableHost.
    * This function does not delete the TextureHost corresponding to the
    * TextureClient passed in parameter.
    * When the TextureClient has TEXTURE_DEALLOCATE_CLIENT flag,
    * the transaction becomes synchronous.
    */
@@ -106,16 +103,50 @@ public:
    * TextureClient passed in parameter.
    * It is used when the TextureClient recycled.
    * Only ImageBridge implements it.
    */
   virtual void RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aAsyncTransactionTracker,
                                                   CompositableClient* aCompositable,
                                                   TextureClient* aTexture) {}
 
+  /**
+   * Holds a reference to a TextureClient until after the next
+   * compositor transaction, and then drops it.
+   */
+  virtual void HoldUntilTransaction(TextureClient* aClient)
+  {
+    if (aClient) {
+      mTexturesToRemove.AppendElement(aClient);
+    }
+  }
+
+  /**
+   * Forcibly remove texture data from TextureClient
+   * This function needs to be called after a tansaction with Compositor.
+   */
+  virtual void RemoveTexturesIfNecessary()
+  {
+    mTexturesToRemove.Clear();
+  }
+
+  /**
+   * The same as above, but for CompositableClients.
+   */
+  void HoldUntilTransaction(CompositableClient* aClient)
+  {
+    if (aClient) {
+      mCompositableClientsToRemove.AppendElement(aClient);
+    }
+  }
+  void RemoveCompositablesIfNecessary()
+  {
+    mCompositableClientsToRemove.Clear();
+  }
+
   struct TimedTextureClient {
     TimedTextureClient()
         : mTextureClient(nullptr), mFrameID(0), mProducerID(0) {}
 
     TextureClient* mTextureClient;
     TimeStamp mTimeStamp;
     nsIntRect mPictureRect;
     int32_t mFrameID;
--- a/gfx/layers/ipc/CompositableTransactionParent.cpp
+++ b/gfx/layers/ipc/CompositableTransactionParent.cpp
@@ -228,43 +228,18 @@ CompositableParentManager::ReceiveCompos
       MOZ_ASSERT(false, "bad type");
     }
   }
 
   return true;
 }
 
 void
-CompositableParentManager::DestroyActor(const OpDestroy& aOp)
-{
-  switch (aOp.type()) {
-    case OpDestroy::TPTextureParent: {
-      auto actor = aOp.get_PTextureParent();
-      TextureHost::ReceivedDestroy(actor);
-      break;
-    }
-    case OpDestroy::TPCompositableParent: {
-      auto actor = aOp.get_PCompositableParent();
-      CompositableHost::ReceivedDestroy(actor);
-      break;
-    }
-    default: {
-      MOZ_ASSERT(false, "unsupported type");
-    }
-  }
-}
-
-void
 CompositableParentManager::SendPendingAsyncMessages()
 {
-  for (auto& actor : mDestroyedTextures) {
-    TextureHost::SendDeleteIPDLActor(actor);
-  }
-  mDestroyedTextures.clear();
-
   if (mPendingAsyncMessage.empty()) {
     return;
   }
 
   // Some type of AsyncParentMessageData message could have
   // one file descriptor (e.g. OpDeliverFence).
   // A number of file descriptors per gecko ipc message have a limitation
   // on OS_POSIX (MACOSX or LINUX).
--- a/gfx/layers/ipc/CompositableTransactionParent.h
+++ b/gfx/layers/ipc/CompositableTransactionParent.h
@@ -41,28 +41,25 @@ public:
   virtual base::ProcessId GetChildProcessId() = 0;
 
 protected:
   /**
    * Handle the IPDL messages that affect PCompositable actors.
    */
   bool ReceiveCompositableUpdate(const CompositableOperation& aEdit,
                                  EditReplyVector& replyv);
-  void DestroyActor(const OpDestroy& aOp);
-
   bool IsOnCompositorSide() const override { return true; }
 
   /**
    * Return true if this protocol is asynchronous with respect to the content
    * thread (ImageBridge for instance).
    */
   virtual bool IsAsync() const { return false; }
 
   virtual void ReplyRemoveTexture(const OpReplyRemoveTexture& aReply) {}
 
   std::vector<AsyncParentMessageData> mPendingAsyncMessage;
-  std::vector<PTextureParent*> mDestroyedTextures;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -51,17 +51,16 @@ namespace layers {
 
 using base::Thread;
 using base::ProcessId;
 using namespace mozilla::ipc;
 using namespace mozilla::gfx;
 using namespace mozilla::media;
 
 typedef std::vector<CompositableOperation> OpVector;
-typedef nsTArray<OpDestroy> OpDestroyVector;
 
 struct CompositableTransaction
 {
   CompositableTransaction()
   : mSwapRequired(false)
   , mFinished(true)
   {}
   ~CompositableTransaction()
@@ -77,59 +76,33 @@ struct CompositableTransaction
     MOZ_ASSERT(mFinished);
     mFinished = false;
   }
   void End()
   {
     mFinished = true;
     mSwapRequired = false;
     mOperations.clear();
-    mDestroyedActors.Clear();
   }
   bool IsEmpty() const
   {
-    return mOperations.empty() && mDestroyedActors.IsEmpty();
+    return mOperations.empty();
   }
   void AddNoSwapEdit(const CompositableOperation& op)
   {
     MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
     mOperations.push_back(op);
   }
   void AddEdit(const CompositableOperation& op)
   {
     AddNoSwapEdit(op);
-    MarkSyncTransaction();
-  }
-  void MarkSyncTransaction()
-  {
     mSwapRequired = true;
   }
 
-  void FallbackDestroyActors()
-  {
-    for (auto& actor : mDestroyedActors) {
-      switch (actor.type()) {
-      case OpDestroy::TPTextureChild: {
-        DebugOnly<bool> ok = TextureClient::DestroyFallback(actor.get_PTextureChild());
-        MOZ_ASSERT(ok);
-        break;
-      }
-      case OpDestroy::TPCompositableChild: {
-        DebugOnly<bool> ok = CompositableClient::DestroyFallback(actor.get_PCompositableChild());
-        MOZ_ASSERT(ok);
-        break;
-      }
-      default: MOZ_CRASH();
-      }
-    }
-    mDestroyedActors.Clear();
-  }
-
   OpVector mOperations;
-  OpDestroyVector mDestroyedActors;
   bool mSwapRequired;
   bool mFinished;
 };
 
 struct AutoEndTransaction {
   explicit AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {}
   ~AutoEndTransaction() { mTxn->End(); }
   CompositableTransaction* mTxn;
@@ -200,22 +173,16 @@ ImageBridgeChild::UseOverlaySource(Compo
 static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton;
 static StaticRefPtr<ImageBridgeParent> sImageBridgeParentSingleton;
 static Thread *sImageBridgeChildThread = nullptr;
 
 void ReleaseImageBridgeParentSingleton() {
   sImageBridgeParentSingleton = nullptr;
 }
 
-void
-ImageBridgeChild::FallbackDestroyActors() {
-  if (mTxn && !mTxn->mDestroyedActors.IsEmpty()) {
-    mTxn->FallbackDestroyActors();
-  }
-}
 
 // dispatched function
 static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone)
 {
   ReentrantMonitorAutoEnter autoMon(*aBarrier);
 
   MOZ_ASSERT(InImageBridgeChildThread(),
              "Should be in ImageBridgeChild thread.");
@@ -232,18 +199,16 @@ static void ImageBridgeShutdownStep1(Ree
     InfallibleTArray<PTextureChild*> textures;
     sImageBridgeChildSingleton->ManagedPTextureChild(textures);
     for (int i = textures.Length() - 1; i >= 0; --i) {
       RefPtr<TextureClient> client = TextureClient::AsTextureClient(textures[i]);
       if (client) {
         client->Destroy();
       }
     }
-    sImageBridgeChildSingleton->FallbackDestroyActors();
-
     sImageBridgeChildSingleton->SendWillStop();
     sImageBridgeChildSingleton->MarkShutDown();
     // From now on, no message can be sent through the image bridge from the
     // client side except the final Stop message.
   }
 
   *aDone = true;
   aBarrier->NotifyAll();
@@ -637,23 +602,38 @@ void ImageBridgeChild::FlushAllImages(Im
 void
 ImageBridgeChild::BeginTransaction()
 {
   MOZ_ASSERT(!mShuttingDown);
   MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?");
   mTxn->Begin();
 }
 
+class MOZ_STACK_CLASS AutoRemoveTexturesFromImageBridge
+{
+public:
+  explicit AutoRemoveTexturesFromImageBridge(ImageBridgeChild* aImageBridge)
+    : mImageBridge(aImageBridge) {}
+
+  ~AutoRemoveTexturesFromImageBridge()
+  {
+    mImageBridge->RemoveTexturesIfNecessary();
+  }
+private:
+  ImageBridgeChild* mImageBridge;
+};
+
 void
 ImageBridgeChild::EndTransaction()
 {
   MOZ_ASSERT(!mShuttingDown);
   MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?");
 
   AutoEndTransaction _(mTxn);
+  AutoRemoveTexturesFromImageBridge autoRemoveTextures(this);
 
   if (mTxn->IsEmpty()) {
     return;
   }
 
   AutoInfallibleTArray<CompositableOperation, 10> cset;
   cset.SetCapacity(mTxn->mOperations.size());
   if (!mTxn->mOperations.empty()) {
@@ -662,27 +642,25 @@ ImageBridgeChild::EndTransaction()
 
   if (!IsSameProcess()) {
     ShadowLayerForwarder::PlatformSyncBeforeUpdate();
   }
 
   AutoInfallibleTArray<EditReply, 10> replies;
 
   if (mTxn->mSwapRequired) {
-    if (!SendUpdate(cset, mTxn->mDestroyedActors, &replies)) {
+    if (!SendUpdate(cset, &replies)) {
       NS_WARNING("could not send async texture transaction");
-      mTxn->FallbackDestroyActors();
       return;
     }
   } else {
     // If we don't require a swap we can call SendUpdateNoSwap which
     // assumes that aReplies is empty (DEBUG assertion)
-    if (!SendUpdateNoSwap(cset, mTxn->mDestroyedActors)) {
+    if (!SendUpdateNoSwap(cset)) {
       NS_WARNING("could not send async texture transaction (no swap)");
-      mTxn->FallbackDestroyActors();
       return;
     }
   }
   for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) {
     NS_RUNTIMEABORT("not reached");
   }
   SendPendingAsyncMessges();
 }
@@ -1113,45 +1091,16 @@ PTextureChild*
 ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
                                 LayersBackend aLayersBackend,
                                 TextureFlags aFlags)
 {
   MOZ_ASSERT(!mShuttingDown);
   return SendPTextureConstructor(aSharedData, aLayersBackend, aFlags);
 }
 
-static bool
-IBCAddOpDestroy(CompositableTransaction* aTxn, const OpDestroy& op, bool synchronously)
-{
-  if (aTxn->Finished()) {
-    return false;
-  }
-
-  aTxn->mDestroyedActors.AppendElement(op);
-
-  if (synchronously) {
-    aTxn->MarkSyncTransaction();
-  }
-
-  return true;
-}
-
-bool
-ImageBridgeChild::DestroyInTransaction(PTextureChild* aTexture, bool synchronously)
-{
-  return IBCAddOpDestroy(mTxn, OpDestroy(aTexture), synchronously);
-}
-
-bool
-ImageBridgeChild::DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously)
-{
-  return IBCAddOpDestroy(mTxn, OpDestroy(aCompositable), synchronously);
-}
-
-
 void
 ImageBridgeChild::RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                                 TextureClient* aTexture)
 {
   MOZ_ASSERT(!mShuttingDown);
   MOZ_ASSERT(aTexture);
   MOZ_ASSERT(aTexture->IsSharedWithCompositor());
   MOZ_ASSERT(aCompositable->IsConnected());
@@ -1160,16 +1109,18 @@ ImageBridgeChild::RemoveTextureFromCompo
   }
   if (aTexture->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
     mTxn->AddEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(),
                                   nullptr, aTexture->GetIPDLActor()));
   } else {
     mTxn->AddNoSwapEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(),
                                         nullptr, aTexture->GetIPDLActor()));
   }
+  // Hold texture until transaction complete.
+  HoldUntilTransaction(aTexture);
 }
 
 void
 ImageBridgeChild::RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aAsyncTransactionTracker,
                                                      CompositableClient* aCompositable,
                                                      TextureClient* aTexture)
 {
   MOZ_ASSERT(!mShuttingDown);
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -257,19 +257,16 @@ public:
                                          TextureClient* aClientOnBlack,
                                          TextureClient* aClientOnWhite) override;
 #ifdef MOZ_WIDGET_GONK
   virtual void UseOverlaySource(CompositableClient* aCompositable,
                                 const OverlaySource& aOverlay,
                                 const nsIntRect& aPictureRect) override;
 #endif
 
-  virtual bool DestroyInTransaction(PTextureChild* aTexture, bool synchronously) override;
-  virtual bool DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously) override;
-
   virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                              TextureClient* aTexture) override;
 
   virtual void RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aAsyncTransactionTracker,
                                                   CompositableClient* aCompositable,
                                                   TextureClient* aTexture) override;
 
   virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
@@ -316,18 +313,16 @@ public:
                                        LayersBackend aLayersBackend,
                                        TextureFlags aFlags) override;
 
   virtual bool IsSameProcess() const override;
 
   virtual void SendPendingAsyncMessges() override;
 
   void MarkShutDown();
-
-  void FallbackDestroyActors();
 protected:
   ImageBridgeChild();
   bool DispatchAllocShmemInternal(size_t aSize,
                                   SharedMemory::SharedMemoryType aType,
                                   Shmem* aShmem,
                                   bool aUnsafe);
 
   CompositableTransaction* mTxn;
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -124,52 +124,47 @@ public:
   {
     mImageBridge->SendPendingAsyncMessages();
   }
 private:
   ImageBridgeParent* mImageBridge;
 };
 
 bool
-ImageBridgeParent::RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
-                              EditReplyArray* aReply)
+ImageBridgeParent::RecvUpdate(EditArray&& aEdits, EditReplyArray* aReply)
 {
   AutoImageBridgeParentAsyncMessageSender autoAsyncMessageSender(this);
 
   EditReplyVector replyv;
   for (EditArray::index_type i = 0; i < aEdits.Length(); ++i) {
     if (!ReceiveCompositableUpdate(aEdits[i], replyv)) {
       return false;
     }
   }
 
-  for (const auto& op : aToDestroy) {
-    DestroyActor(op);
-  }
-
   aReply->SetCapacity(replyv.size());
   if (replyv.size() > 0) {
     aReply->AppendElements(&replyv.front(), replyv.size());
   }
 
   if (!IsSameProcess()) {
     // Ensure that any pending operations involving back and front
     // buffers have completed, so that neither process stomps on the
     // other's buffer contents.
     LayerManagerComposite::PlatformSyncBeforeReplyUpdate();
   }
 
   return true;
 }
 
 bool
-ImageBridgeParent::RecvUpdateNoSwap(EditArray&& aEdits, OpDestroyArray&& aToDestroy)
+ImageBridgeParent::RecvUpdateNoSwap(EditArray&& aEdits)
 {
   InfallibleTArray<EditReply> noReplies;
-  bool success = RecvUpdate(Move(aEdits), Move(aToDestroy), &noReplies);
+  bool success = RecvUpdate(Move(aEdits), &noReplies);
   MOZ_ASSERT(noReplies.Length() == 0, "RecvUpdateNoSwap requires a sync Update to carry Edits");
   return success;
 }
 
 static void
 ConnectImageBridgeInParentProcess(ImageBridgeParent* aBridge,
                                   Transport* aTransport,
                                   base::ProcessId aOtherPid)
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -38,17 +38,16 @@ namespace layers {
  * It's purpose is mainly to setup the IPDL connection. Most of the
  * interesting stuff is in ImageContainerParent.
  */
 class ImageBridgeParent final : public PImageBridgeParent,
                                 public CompositableParentManager
 {
 public:
   typedef InfallibleTArray<CompositableOperation> EditArray;
-  typedef InfallibleTArray<OpDestroy> OpDestroyArray;
   typedef InfallibleTArray<EditReply> EditReplyArray;
   typedef InfallibleTArray<AsyncChildMessageData> AsyncChildMessageArray;
 
   ImageBridgeParent(MessageLoop* aLoop, Transport* aTransport, ProcessId aChildProcessId);
   ~ImageBridgeParent();
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
@@ -63,19 +62,18 @@ public:
 
   virtual base::ProcessId GetChildProcessId() override
   {
     return OtherPid();
   }
 
   // PImageBridge
   virtual bool RecvImageBridgeThreadId(const PlatformThreadId& aThreadId) override;
-  virtual bool RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
-                          EditReplyArray* aReply) override;
-  virtual bool RecvUpdateNoSwap(EditArray&& aEdits, OpDestroyArray&& aToDestroy) override;
+  virtual bool RecvUpdate(EditArray&& aEdits, EditReplyArray* aReply) override;
+  virtual bool RecvUpdateNoSwap(EditArray&& aEdits) override;
 
   virtual bool IsAsync() const override { return true; }
 
   PCompositableParent* AllocPCompositableParent(const TextureInfo& aInfo,
                                                 PImageContainerParent* aImageContainer,
                                                 uint64_t*) override;
   bool DeallocPCompositableParent(PCompositableParent* aActor) override;
 
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -182,29 +182,27 @@ LayerTransactionParent::Destroy()
     RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]);
     tex->DeallocateDeviceData();
   }
   mDestroyed = true;
 }
 
 bool
 LayerTransactionParent::RecvUpdateNoSwap(InfallibleTArray<Edit>&& cset,
-                                         InfallibleTArray<OpDestroy>&& aToDestroy,
                                          const uint64_t& aTransactionId,
                                          const TargetConfig& targetConfig,
                                          PluginsArray&& aPlugins,
                                          const bool& isFirstPaint,
                                          const bool& scheduleComposite,
                                          const uint32_t& paintSequenceNumber,
                                          const bool& isRepeatTransaction,
                                          const mozilla::TimeStamp& aTransactionStart,
                                          const int32_t& aPaintSyncId)
 {
-  return RecvUpdate(Move(cset), Move(aToDestroy),
-      aTransactionId, targetConfig, Move(aPlugins), isFirstPaint,
+  return RecvUpdate(Move(cset), aTransactionId, targetConfig, Move(aPlugins), isFirstPaint,
       scheduleComposite, paintSequenceNumber, isRepeatTransaction,
       aTransactionStart, aPaintSyncId, nullptr);
 }
 
 class MOZ_STACK_CLASS AutoLayerTransactionParentAsyncMessageSender
 {
 public:
   explicit AutoLayerTransactionParentAsyncMessageSender(LayerTransactionParent* aLayerTransaction)
@@ -216,17 +214,16 @@ public:
     ImageBridgeParent::SendPendingAsyncMessages(mLayerTransaction->GetChildProcessId());
   }
 private:
   LayerTransactionParent* mLayerTransaction;
 };
 
 bool
 LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
-                                   InfallibleTArray<OpDestroy>&& aToDestroy,
                                    const uint64_t& aTransactionId,
                                    const TargetConfig& targetConfig,
                                    PluginsArray&& aPlugins,
                                    const bool& isFirstPaint,
                                    const bool& scheduleComposite,
                                    const uint32_t& paintSequenceNumber,
                                    const bool& isRepeatTransaction,
                                    const mozilla::TimeStamp& aTransactionStart,
@@ -239,20 +236,16 @@ LayerTransactionParent::RecvUpdate(Infal
 
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   TimeStamp updateStart = TimeStamp::Now();
 #endif
 
   MOZ_LAYERS_LOG(("[ParentSide] received txn with %d edits", cset.Length()));
 
   if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
-    for (const auto& op : aToDestroy) {
-      DestroyActor(op);
-    }
-
     return true;
   }
 
   EditReplyVector replyv;
   AutoLayerTransactionParentAsyncMessageSender autoAsyncMessageSender(this);
 
   {
     AutoResolveRefLayers resolve(mShadowLayersManager->GetCompositionManager(this));
@@ -595,20 +588,16 @@ LayerTransactionParent::RecvUpdate(Infal
       host->SetCompositorID(mLayerManager->GetCompositor()->GetCompositorID());
       break;
     }
     default:
       NS_RUNTIMEABORT("not reached");
     }
   }
 
-  for (const auto& op : aToDestroy) {
-    DestroyActor(op);
-  }
-
   mShadowLayersManager->ShadowLayersUpdated(this, aTransactionId, targetConfig,
                                             aPlugins, isFirstPaint, scheduleComposite,
                                             paintSequenceNumber, isRepeatTransaction,
                                             aPaintSyncId);
 
   {
     AutoResolveRefLayers resolve(mShadowLayersManager->GetCompositionManager(this));
     layer_manager()->EndTransaction(TimeStamp(), LayerManager::END_NO_IMMEDIATE_REDRAW);
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -35,17 +35,16 @@ class ShadowLayerParent;
 class CompositableParent;
 class ShadowLayersManager;
 
 class LayerTransactionParent final : public PLayerTransactionParent,
                                      public CompositableParentManager
 {
   typedef mozilla::layout::RenderFrameParent RenderFrameParent;
   typedef InfallibleTArray<Edit> EditArray;
-  typedef InfallibleTArray<OpDestroy> OpDestroyArray;
   typedef InfallibleTArray<EditReply> EditReplyArray;
   typedef InfallibleTArray<AsyncChildMessageData> AsyncChildMessageArray;
   typedef InfallibleTArray<PluginWindowData> PluginsArray;
 
 public:
   LayerTransactionParent(LayerManagerComposite* aManager,
                          ShadowLayersManager* aLayersManager,
                          uint64_t aId);
@@ -89,30 +88,28 @@ public:
   }
 
   virtual void ReplyRemoveTexture(const OpReplyRemoveTexture& aReply) override;
 
 protected:
   virtual bool RecvShutdown() override;
 
   virtual bool RecvUpdate(EditArray&& cset,
-                          OpDestroyArray&& aToDestroy,
                           const uint64_t& aTransactionId,
                           const TargetConfig& targetConfig,
                           PluginsArray&& aPlugins,
                           const bool& isFirstPaint,
                           const bool& scheduleComposite,
                           const uint32_t& paintSequenceNumber,
                           const bool& isRepeatTransaction,
                           const mozilla::TimeStamp& aTransactionStart,
                           const int32_t& aPaintSyncId,
                           EditReplyArray* reply) override;
 
   virtual bool RecvUpdateNoSwap(EditArray&& cset,
-                                OpDestroyArray&& aToDestroy,
                                 const uint64_t& aTransactionId,
                                 const TargetConfig& targetConfig,
                                 PluginsArray&& aPlugins,
                                 const bool& isFirstPaint,
                                 const bool& scheduleComposite,
                                 const uint32_t& paintSequenceNumber,
                                 const bool& isRepeatTransaction,
                                 const mozilla::TimeStamp& aTransactionStart,
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -466,22 +466,16 @@ union Edit {
   OpRaiseToTopChild;
 
   OpAttachCompositable;
   OpAttachAsyncCompositable;
 
   CompositableOperation;
 };
 
-// Operations related to destroying resources, always handled after the other
-// operations for safety.
-union OpDestroy {
-  PTexture;
-  PCompositable;
-};
 
 // Replies to operations
 
 struct OpContentBufferSwap {
   PCompositable compositable;
   nsIntRegion frontUpdatedRegion;
 };
 
--- a/gfx/layers/ipc/PImageBridge.ipdl
+++ b/gfx/layers/ipc/PImageBridge.ipdl
@@ -37,20 +37,18 @@ sync protocol PImageBridge
 child:
   async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
 
   async DidComposite(ImageCompositeNotification[] aNotifications);
 
 parent:
   async ImageBridgeThreadId(PlatformThreadId aTreahdId);
 
-  sync Update(CompositableOperation[] ops, OpDestroy[] toDestroy)
-    returns (EditReply[] reply);
-
-  async UpdateNoSwap(CompositableOperation[] ops, OpDestroy[] toDestroy);
+  sync Update(CompositableOperation[] ops) returns (EditReply[] reply);
+  async UpdateNoSwap(CompositableOperation[] ops);
 
   // First step of the destruction sequence. This puts ImageBridge
   // in a state in which it can't send asynchronous messages
   // so as to not race with the upcomming Stop message and destruction.
   // In the child side, the Stop message is not sent right after WillStop,
   // it is scheduled in the ImageBridgeChild's message queue in order to ensure
   // that all of the messages from the parent side have been received and processed
   // before sending Stop, and that after Stop returns, there is no message in
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -50,28 +50,26 @@ child:
 
 parent:
   async PLayer();
   async PCompositable(TextureInfo aTextureInfo);
   async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend, TextureFlags aTextureFlags);
 
   // The isFirstPaint flag can be used to indicate that this is the first update
   // for a particular document.
-  sync Update(Edit[] cset, OpDestroy[] toDestroy,
-              uint64_t id, TargetConfig targetConfig,
+  sync Update(Edit[] cset, uint64_t id, TargetConfig targetConfig,
               PluginWindowData[] plugins, bool isFirstPaint,
               bool scheduleComposite, uint32_t paintSequenceNumber,
               bool isRepeatTransaction, TimeStamp transactionStart,
               int32_t paintSyncId)
     returns (EditReply[] reply);
 
   // We don't need to send a sync transaction if
   // no transaction operate require a swap.
-  async UpdateNoSwap(Edit[] cset, OpDestroy[] toDestroy,
-                     uint64_t id, TargetConfig targetConfig,
+  async UpdateNoSwap(Edit[] cset, uint64_t id, TargetConfig targetConfig,
                      PluginWindowData[] plugins, bool isFirstPaint,
                      bool scheduleComposite, uint32_t paintSequenceNumber,
                      bool isRepeatTransaction, TimeStamp transactionStart,
                      int32_t paintSyncId);
 
   // Testing APIs
 
   // Enter test mode, set the sample time to sampleTime, and resample
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -12,17 +12,16 @@
 #include "ISurfaceAllocator.h"          // for IsSurfaceDescriptorValid
 #include "Layers.h"                     // for Layer
 #include "RenderTrace.h"                // for RenderTraceScope
 #include "ShadowLayerChild.h"           // for ShadowLayerChild
 #include "gfx2DGlue.h"                  // for Moz2D transition helpers
 #include "gfxPlatform.h"                // for gfxImageFormat, gfxPlatform
 #include "gfxSharedImageSurface.h"      // for gfxSharedImageSurface
 #include "ipc/IPCMessageUtils.h"        // for gfxContentType, null_t
-#include "IPDLActor.h"
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient, etc
 #include "mozilla/layers/LayersMessages.h"  // for Edit, etc
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
 #include "mozilla/layers/LayersTypes.h"  // for MOZ_LAYERS_LOG
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "ShadowLayerUtils.h"
@@ -44,17 +43,16 @@ using namespace mozilla::gfx;
 using namespace mozilla::gl;
 using namespace mozilla::ipc;
 
 class ClientTiledLayerBuffer;
 
 typedef nsTArray<SurfaceDescriptor> BufferArray;
 typedef std::vector<Edit> EditVector;
 typedef std::set<ShadowableLayer*> ShadowableLayerSet;
-typedef nsTArray<OpDestroy> OpDestroyVector;
 
 class Transaction
 {
 public:
   Transaction()
     : mTargetRotation(ROTATION_0)
     , mSwapRequired(false)
     , mOpen(false)
@@ -115,56 +113,33 @@ public:
     MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
     mMutants.insert(aLayer);
   }
   void End()
   {
     mCset.clear();
     mPaints.clear();
     mMutants.clear();
-    mDestroyedActors.Clear();
     mOpen = false;
     mSwapRequired = false;
     mRotationChanged = false;
   }
 
   bool Empty() const {
-    return mCset.empty() && mPaints.empty() && mMutants.empty()
-           && mDestroyedActors.IsEmpty();
+    return mCset.empty() && mPaints.empty() && mMutants.empty();
   }
   bool RotationChanged() const {
     return mRotationChanged;
   }
   bool Finished() const { return !mOpen && Empty(); }
 
   bool Opened() const { return mOpen; }
 
-  void FallbackDestroyActors()
-  {
-    for (auto& actor : mDestroyedActors) {
-      switch (actor.type()) {
-      case OpDestroy::TPTextureChild: {
-        DebugOnly<bool> ok = TextureClient::DestroyFallback(actor.get_PTextureChild());
-        MOZ_ASSERT(ok);
-        break;
-      }
-      case OpDestroy::TPCompositableChild: {
-        DebugOnly<bool> ok = CompositableClient::DestroyFallback(actor.get_PCompositableChild());
-        MOZ_ASSERT(ok);
-        break;
-      }
-      default: MOZ_CRASH();
-      }
-    }
-    mDestroyedActors.Clear();
-  }
-
   EditVector mCset;
   EditVector mPaints;
-  OpDestroyVector mDestroyedActors;
   ShadowableLayerSet mMutants;
   gfx::IntRect mTargetBounds;
   ScreenRotation mTargetRotation;
   dom::ScreenOrientationInternal mTargetOrientation;
   bool mSwapRequired;
 
 private:
   bool mOpen;
@@ -195,19 +170,16 @@ ShadowLayerForwarder::ShadowLayerForward
  , mPaintSyncId(0)
 {
   mTxn = new Transaction();
 }
 
 ShadowLayerForwarder::~ShadowLayerForwarder()
 {
   MOZ_ASSERT(mTxn->Finished(), "unfinished transaction?");
-  if (!mTxn->mDestroyedActors.IsEmpty()) {
-    mTxn->FallbackDestroyActors();
-  }
   delete mTxn;
   if (mShadowManager) {
     mShadowManager->SetForwarder(nullptr);
     mShadowManager->Destroy();
   }
 }
 
 void
@@ -438,43 +410,16 @@ ShadowLayerForwarder::UseOverlaySource(C
   MOZ_ASSERT(aCompositable);
   MOZ_ASSERT(aCompositable->IsConnected());
 
   mTxn->AddEdit(OpUseOverlaySource(nullptr, aCompositable->GetIPDLActor(),
       aOverlay, aPictureRect));
 }
 #endif
 
-static bool
-AddOpDestroy(Transaction* aTxn, const OpDestroy& op, bool synchronously)
-{
-  if (!aTxn->Opened()) {
-    return false;
-  }
-
-  aTxn->mDestroyedActors.AppendElement(op);
-  if (synchronously) {
-    aTxn->MarkSyncTransaction();
-  }
-
-  return true;
-}
-
-bool
-ShadowLayerForwarder::DestroyInTransaction(PTextureChild* aTexture, bool synchronously)
-{
-  return AddOpDestroy(mTxn, OpDestroy(aTexture), synchronously);
-}
-
-bool
-ShadowLayerForwarder::DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously)
-{
-  return AddOpDestroy(mTxn, OpDestroy(aCompositable), synchronously);
-}
-
 void
 ShadowLayerForwarder::RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                                     TextureClient* aTexture)
 {
   MOZ_ASSERT(aCompositable);
   MOZ_ASSERT(aTexture);
   MOZ_ASSERT(aCompositable->IsConnected());
   MOZ_ASSERT(aTexture->GetIPDLActor());
@@ -483,16 +428,18 @@ ShadowLayerForwarder::RemoveTextureFromC
     return;
   }
 
   mTxn->AddEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(),
                                 nullptr, aTexture->GetIPDLActor()));
   if (aTexture->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
     mTxn->MarkSyncTransaction();
   }
+  // Hold texture until transaction complete.
+  HoldUntilTransaction(aTexture);
 }
 
 void
 ShadowLayerForwarder::RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aAsyncTransactionTracker,
                                                      CompositableClient* aCompositable,
                                                      TextureClient* aTexture)
 {
   MOZ_ASSERT(aCompositable);
@@ -695,39 +642,35 @@ ShadowLayerForwarder::EndTransaction(Inf
   }
 
   profiler_tracing("Paint", "Rasterize", TRACING_INTERVAL_END);
   if (mTxn->mSwapRequired) {
     MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
     RenderTraceScope rendertrace3("Forward Transaction", "000093");
     if (!HasShadowManager() ||
         !mShadowManager->IPCOpen() ||
-        !mShadowManager->SendUpdate(cset, mTxn->mDestroyedActors,
-                                    aId, targetConfig, mPluginWindowData,
+        !mShadowManager->SendUpdate(cset, aId, targetConfig, mPluginWindowData,
                                     mIsFirstPaint, aScheduleComposite,
                                     aPaintSequenceNumber, aIsRepeatTransaction,
                                     aTransactionStart, mPaintSyncId, aReplies)) {
       MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
-      mTxn->FallbackDestroyActors();
       return false;
     }
   } else {
     // If we don't require a swap we can call SendUpdateNoSwap which
     // assumes that aReplies is empty (DEBUG assertion)
     MOZ_LAYERS_LOG(("[LayersForwarder] sending no swap transaction..."));
     RenderTraceScope rendertrace3("Forward NoSwap Transaction", "000093");
     if (!HasShadowManager() ||
         !mShadowManager->IPCOpen() ||
-        !mShadowManager->SendUpdateNoSwap(cset, mTxn->mDestroyedActors,
-                                          aId, targetConfig, mPluginWindowData,
+        !mShadowManager->SendUpdateNoSwap(cset, aId, targetConfig, mPluginWindowData,
                                           mIsFirstPaint, aScheduleComposite,
                                           aPaintSequenceNumber, aIsRepeatTransaction,
                                           aTransactionStart, mPaintSyncId)) {
       MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
-      mTxn->FallbackDestroyActors();
       return false;
     }
   }
 
   *aSent = true;
   mIsFirstPaint = false;
   mPaintSyncId = 0;
   MOZ_LAYERS_LOG(("[LayersForwarder] ... done"));
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -209,19 +209,16 @@ public:
                ShadowableLayer* aMaskLayer);
 
   /**
    * See CompositableForwarder::UseTiledLayerBuffer
    */
   virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
                                    const SurfaceDescriptorTiles& aTileLayerDescriptor) override;
 
-  virtual bool DestroyInTransaction(PTextureChild* aTexture, bool synchronously) override;
-  virtual bool DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously) override;
-
   virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                              TextureClient* aTexture) override;
 
   virtual void RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aAsyncTransactionTracker,
                                                   CompositableClient* aCompositable,
                                                   TextureClient* aTexture) override;
 
   /**
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -47,16 +47,17 @@ import org.mozilla.gecko.menu.GeckoMenuI
 import org.mozilla.gecko.mozglue.ContextUtils;
 import org.mozilla.gecko.mozglue.ContextUtils.SafeIntent;
 import org.mozilla.gecko.overlays.ui.ShareDialog;
 import org.mozilla.gecko.preferences.ClearOnShutdownPref;
 import org.mozilla.gecko.preferences.GeckoPreferences;
 import org.mozilla.gecko.prompts.Prompt;
 import org.mozilla.gecko.prompts.PromptListItem;
 import org.mozilla.gecko.restrictions.Restrictable;
+import org.mozilla.gecko.restrictions.RestrictedProfileConfiguration;
 import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
 import org.mozilla.gecko.tabqueue.TabQueueHelper;
 import org.mozilla.gecko.tabqueue.TabQueuePrompt;
 import org.mozilla.gecko.tabs.TabHistoryController;
 import org.mozilla.gecko.tabs.TabHistoryController.OnShowTabHistory;
 import org.mozilla.gecko.tabs.TabHistoryFragment;
 import org.mozilla.gecko.tabs.TabHistoryPage;
 import org.mozilla.gecko.tabs.TabsPanel;
@@ -1685,16 +1686,23 @@ public class BrowserApp extends GeckoApp
             Telemetry.addToHistogram("FENNEC_FAVICONS_COUNT", db.getCount(cr, "favicons"));
             Telemetry.addToHistogram("FENNEC_THUMBNAILS_COUNT", db.getCount(cr, "thumbnails"));
             Telemetry.addToHistogram("FENNEC_READING_LIST_COUNT", db.getReadingListAccessor().getCount(cr));
             Telemetry.addToHistogram("BROWSER_IS_USER_DEFAULT", (isDefaultBrowser(Intent.ACTION_VIEW) ? 1 : 0));
             Telemetry.addToHistogram("FENNEC_TABQUEUE_ENABLED", (TabQueueHelper.isTabQueueEnabled(BrowserApp.this) ? 1 : 0));
             if (Versions.feature16Plus) {
                 Telemetry.addToHistogram("BROWSER_IS_ASSIST_DEFAULT", (isDefaultBrowser(Intent.ACTION_ASSIST) ? 1 : 0));
             }
+
+            if (Restrictions.isRestrictedProfile(this)) {
+                for (Restrictable rest : RestrictedProfileConfiguration.getVisibleRestrictions()) {
+                    int value = Restrictions.isAllowed(this, rest) ? 1 : 0;
+                    Telemetry.addToKeyedHistogram("FENNEC_RESTRICTED_PROFILE_RESTRICTIONS", rest.name(), value);
+                }
+            }
         } else if ("Updater:Launch".equals(event)) {
             handleUpdaterLaunch();
         } else {
             super.handleMessage(event, message, callback);
         }
     }
 
     private void getFaviconFromCache(final EventCallback callback, final String url) {
--- a/mobile/android/base/java/org/mozilla/gecko/restrictions/RestrictedProfileConfiguration.java
+++ b/mobile/android/base/java/org/mozilla/gecko/restrictions/RestrictedProfileConfiguration.java
@@ -11,16 +11,17 @@ import org.mozilla.gecko.util.ThreadUtil
 
 import android.annotation.TargetApi;
 import android.content.Context;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.StrictMode;
 import android.os.UserManager;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
 public class RestrictedProfileConfiguration implements RestrictionConfiguration {
     // Mapping from restrictable feature to default state (on/off)
@@ -131,16 +132,29 @@ public class RestrictedProfileConfigurat
         return true;
     }
 
     @Override
     public synchronized void update() {
         isCacheInvalid = true;
     }
 
+    public static List<Restrictable> getVisibleRestrictions() {
+        final List<Restrictable> visibleList = new ArrayList<>();
+
+        for (Restrictable restrictable : configuration.keySet()) {
+            if (hiddenRestrictions.contains(restrictable)) {
+                continue;
+            }
+            visibleList.add(restrictable);
+        }
+
+        return visibleList;
+    }
+
     /**
      * This method migrates the old set of DISALLOW_ restrictions to the new restrictable feature ones (Bug 1189336).
      */
     public static void migrateRestrictionsIfNeeded(Bundle bundle) {
         if (!bundle.containsKey(Restrictable.INSTALL_EXTENSION.name) && bundle.containsKey("no_install_extensions")) {
             bundle.putBoolean(Restrictable.INSTALL_EXTENSION.name, !bundle.getBoolean("no_install_extensions"));
         }
 
--- a/mobile/android/base/resources/values/themes.xml
+++ b/mobile/android/base/resources/values/themes.xml
@@ -100,16 +100,18 @@
         <item name="menuItemShareActionButtonStyle">@style/Widget.MenuItemSecondaryActionBar</item>
         <item name="topSitesGridItemViewStyle">@style/Widget.TopSitesGridItemView</item>
         <item name="topSitesGridViewStyle">@style/Widget.TopSitesGridView</item>
         <item name="topSitesThumbnailViewStyle">@style/Widget.TopSitesThumbnailView</item>
     </style>
 
     <style name="Gecko.Preferences" parent="GeckoPreferencesBase">
         <item name="floatingHintEditTextStyle">@style/FloatingHintEditText</item>
+        <!-- This fixed bug 1233412 (Crash in GeckoPrefs due to missing colorAccent in JB) -->
+        <item name="colorAccent">@color/action_orange</item>
     </style>
 
     <!-- Make an activity appear like an overlay. -->
     <style name="OverlayActivity" parent="Gecko">
         <item name="android:windowBackground">@android:color/transparent</item>
         <item name="android:windowNoTitle">true</item>
         <item name="android:windowIsTranslucent">true</item>
         <item name="android:backgroundDimEnabled">true</item>
--- a/mobile/android/components/HelperAppDialog.js
+++ b/mobile/android/components/HelperAppDialog.js
@@ -32,27 +32,16 @@ XPCOMUtils.defineLazyGetter(this, "Conte
 });
 
 function HelperAppLauncherDialog() { }
 
 HelperAppLauncherDialog.prototype = {
   classID: Components.ID("{e9d277a0-268a-4ec2-bb8c-10fdf3e44611}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
 
-  getNativeWindow: function () {
-    try {
-      let win = Services.wm.getMostRecentWindow("navigator:browser");
-      if (win && win.NativeWindow) {
-        return win.NativeWindow;
-      }
-    } catch (e) {
-    }
-    return null;
-  },
-
   /**
    * Returns false if `url` represents a local or special URL that we don't
    * wish to ever download.
    *
    * Returns true otherwise.
    */
   _canDownload: function (url, alreadyResolved=false) {
     // The common case.
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5104,10 +5104,12 @@ pref("dom.requestcache.enabled", false);
 pref("dom.requestcontext.enabled", false);
 
 pref("dom.mozKillSwitch.enabled", false);
 
 pref("toolkit.pageThumbs.screenSizeDivisor", 7);
 pref("toolkit.pageThumbs.minWidth", 0);
 pref("toolkit.pageThumbs.minHeight", 0);
 
+pref("webextensions.tests", false);
+
 // Allow customization of the fallback directory for file uploads
 pref("dom.input.fallbackUploadDir", "");
--- a/services/sync/modules/addonutils.js
+++ b/services/sync/modules/addonutils.js
@@ -33,31 +33,20 @@ AddonUtilsInternal.prototype = {
    * an install was not found.
    *
    * @param addon
    *        AddonSearchResult to obtain install from.
    * @param cb
    *        Function to be called with result of operation.
    */
   getInstallFromSearchResult:
-    function getInstallFromSearchResult(addon, cb, requireSecureURI=true) {
+    function getInstallFromSearchResult(addon, cb) {
 
     this._log.debug("Obtaining install for " + addon.id);
 
-    // Verify that the source URI uses TLS. We don't allow installs from
-    // insecure sources for security reasons. The Addon Manager ensures that
-    // cert validation, etc is performed.
-    if (requireSecureURI) {
-      let scheme = addon.sourceURI.scheme;
-      if (scheme != "https") {
-        cb(new Error("Insecure source URI scheme: " + scheme), addon.install);
-        return;
-      }
-    }
-
     // We should theoretically be able to obtain (and use) addon.install if
     // it is available. However, the addon.sourceURI rewriting won't be
     // reflected in the AddonInstall, so we can't use it. If we ever get rid
     // of sourceURI rewriting, we can avoid having to reconstruct the
     // AddonInstall.
     AddonManager.getInstallForURL(
       addon.sourceURI.spec,
       function handleInstall(install) {
@@ -75,18 +64,16 @@ AddonUtilsInternal.prototype = {
    * Installs an add-on from an AddonSearchResult instance.
    *
    * The options argument defines extra options to control the install.
    * Recognized keys in this map are:
    *
    *   syncGUID - Sync GUID to use for the new add-on.
    *   enabled - Boolean indicating whether the add-on should be enabled upon
    *             install.
-   *   requireSecureURI - Boolean indicating whether to require a secure
-   *     URI to install from. This defaults to true.
    *
    * When complete it calls a callback with 2 arguments, error and result.
    *
    * If error is falsy, result is an object. If error is truthy, result is
    * null.
    *
    * The result object has the following keys:
    *
@@ -100,20 +87,16 @@ AddonUtilsInternal.prototype = {
    *        Object with additional metadata describing how to install add-on.
    * @param cb
    *        Function to be invoked with result of operation.
    */
   installAddonFromSearchResult:
     function installAddonFromSearchResult(addon, options, cb) {
     this._log.info("Trying to install add-on from search result: " + addon.id);
 
-    if (options.requireSecureURI === undefined) {
-      options.requireSecureURI = true;
-    }
-
     this.getInstallFromSearchResult(addon, function onResult(error, install) {
       if (error) {
         cb(error, null);
         return;
       }
 
       if (!install) {
         cb(new Error("AddonInstall not available: " + addon.id), null);
@@ -162,17 +145,17 @@ AddonUtilsInternal.prototype = {
         };
         install.addListener(listener);
         install.install();
       }
       catch (ex) {
         this._log.error("Error installing add-on: " + Utils.exceptionstr(ex));
         cb(ex, null);
       }
-    }.bind(this), options.requireSecureURI);
+    }.bind(this));
   },
 
   /**
    * Uninstalls the Addon instance and invoke a callback when it is done.
    *
    * @param addon
    *        Addon instance to uninstall.
    * @param cb
@@ -256,16 +239,17 @@ AddonUtilsInternal.prototype = {
       searchSucceeded: function searchSucceeded(addons, addonsLength, total) {
         this._log.info("Found " + addonsLength + "/" + ids.length +
                        " add-ons during repository search.");
 
         let ourResult = {
           installedIDs: [],
           installs:     [],
           addons:       [],
+          skipped:      [],
           errors:       []
         };
 
         if (!addonsLength) {
           cb(null, ourResult);
           return;
         }
 
@@ -294,24 +278,30 @@ AddonUtilsInternal.prototype = {
         let toInstall = [];
 
         // Rewrite the "src" query string parameter of the source URI to note
         // that the add-on was installed by Sync and not something else so
         // server-side metrics aren't skewed (bug 708134). The server should
         // ideally send proper URLs, but this solution was deemed too
         // complicated at the time the functionality was implemented.
         for (let addon of addons) {
-          // sourceURI presence isn't enforced by AddonRepository. So, we skip
-          // add-ons without a sourceURI.
-          if (!addon.sourceURI) {
-            this._log.info("Skipping install of add-on because missing " +
-                           "sourceURI: " + addon.id);
+          // Find the specified options for this addon.
+          let options;
+          for (let install of installs) {
+            if (install.id == addon.id) {
+              options = install;
+              break;
+            }
+          }
+          if (!this.canInstallAddon(addon, options)) {
+            ourResult.skipped.push(addon.id);
             continue;
           }
 
+          // We can go ahead and attempt to install it.
           toInstall.push(addon);
 
           // We should always be able to QI the nsIURI to nsIURL. If not, we
           // still try to install the add-on, but we don't rewrite the URL,
           // potentially skewing metrics.
           try {
             addon.sourceURI.QueryInterface(Ci.nsIURL);
           } catch (ex) {
@@ -358,19 +348,58 @@ AddonUtilsInternal.prototype = {
 
       searchFailed: function searchFailed() {
         cb(new Error("AddonRepository search failed"), null);
       },
     });
   },
 
   /**
+   * Returns true if we are able to install the specified addon, false
+   * otherwise. It is expected that this will log the reason if it returns
+   * false.
+   *
+   * @param addon
+   *        (Addon) Add-on instance to check.
+   * @param options
+   *        (object) The options specified for this addon. See installAddons()
+   *        for the valid elements.
+   */
+  canInstallAddon(addon, options) {
+    // sourceURI presence isn't enforced by AddonRepository. So, we skip
+    // add-ons without a sourceURI.
+    if (!addon.sourceURI) {
+      this._log.info("Skipping install of add-on because missing " +
+                     "sourceURI: " + addon.id);
+      return false;
+    }
+    // Verify that the source URI uses TLS. We don't allow installs from
+    // insecure sources for security reasons. The Addon Manager ensures
+    // that cert validation etc is performed.
+    let requireSecureURI = true;
+    if (options && options.requireSecureURI !== undefined) {
+      requireSecureURI = options.requireSecureURI;
+    }
+
+    if (requireSecureURI) {
+      let scheme = addon.sourceURI.scheme;
+      if (scheme != "https") {
+        this._log.info(`Skipping install of add-on "${addon.id}" because sourceURI's scheme of "${scheme}" is not trusted`);
+        return false;
+      }
+    }
+    this._log.info(`Add-on "${addon.id}" is able to be installed`);
+    return true;
+  },
+
+
+  /**
    * Update the user disabled flag for an add-on.
    *
-   * The supplied callback will ba called when the operation is
+   * The supplied callback will be called when the operation is
    * complete. If the new flag matches the existing or if the add-on
    * isn't currently active, the function will fire the callback
    * immediately. Else, the callback is invoked when the AddonManager
    * reports the change has taken effect or has been registered.
    *
    * The callback receives as arguments:
    *
    *   (Error) Encountered error during operation or null on success.
--- a/services/sync/modules/engines/addons.js
+++ b/services/sync/modules/engines/addons.js
@@ -293,16 +293,24 @@ AddonsStore.prototype = {
       enabled:          record.enabled,
       requireSecureURI: !Svc.Prefs.get("addons.ignoreRepositoryChecking", false),
     }], cb);
 
     // This will throw if there was an error. This will get caught by the sync
     // engine and the record will try to be applied later.
     let results = cb.wait();
 
+    if (results.skipped.includes(record.addonID)) {
+      this._log.info("Add-on skipped: " + record.addonID);
+      // Just early-return for skipped addons - we don't want to arrange to
+      // try again next time because the condition that caused up to skip
+      // will remain true for this addon forever.
+      return;
+    }
+
     let addon;
     for (let a of results.addons) {
       if (a.id == record.addonID) {
         addon = a;
         break;
       }
     }
 
--- a/services/sync/tests/unit/test_addon_utils.js
+++ b/services/sync/tests/unit/test_addon_utils.js
@@ -55,16 +55,19 @@ add_test(function test_handle_empty_sour
 
   let cb = Async.makeSpinningCallback();
   AddonUtils.installAddons([{id: ID, requireSecureURI: false}], cb);
   let result = cb.wait();
 
   do_check_true("installedIDs" in result);
   do_check_eq(0, result.installedIDs.length);
 
+  do_check_true("skipped" in result);
+  do_check_true(result.skipped.includes(ID));
+
   server.stop(run_next_test);
 });
 
 add_test(function test_ignore_untrusted_source_uris() {
   _("Ensures that source URIs from insecure schemes are rejected.");
 
   let ioService = Cc["@mozilla.org/network/io-service;1"]
                   .getService(Ci.nsIIOService);
@@ -74,54 +77,28 @@ add_test(function test_ignore_untrusted_
                "silly://example.com/foo.xpi"];
 
   const good = ["https://example.com/foo.xpi"];
 
   for (let s of bad) {
     let sourceURI = ioService.newURI(s, null, null);
     let addon = {sourceURI: sourceURI, name: "bad", id: "bad"};
 
-    try {
-      let cb = Async.makeSpinningCallback();
-      AddonUtils.getInstallFromSearchResult(addon, cb, true);
-      cb.wait();
-    } catch (ex) {
-      do_check_neq(null, ex);
-      do_check_eq(0, ex.message.indexOf("Insecure source URI"));
-      continue;
-    }
-
-    // We should never get here if an exception is thrown.
-    do_check_true(false);
+    let canInstall = AddonUtils.canInstallAddon(addon);
+    do_check_false(canInstall, "Correctly rejected a bad URL");
   }
 
-  let count = 0;
   for (let s of good) {
     let sourceURI = ioService.newURI(s, null, null);
     let addon = {sourceURI: sourceURI, name: "good", id: "good"};
 
-    // Despite what you might think, we don't get an error in the callback.
-    // The install won't work because the underlying Addon instance wasn't
-    // proper. But, that just results in an AddonInstall that is missing
-    // certain values. We really just care that the callback is being invoked
-    // anyway.
-    let callback = function onInstall(error, install) {
-      do_check_null(error);
-      do_check_neq(null, install);
-      do_check_eq(sourceURI.spec, install.sourceURI.spec);
-
-      count += 1;
-
-      if (count >= good.length) {
-        run_next_test();
-      }
-    };
-
-    AddonUtils.getInstallFromSearchResult(addon, callback, true);
+    let canInstall = AddonUtils.canInstallAddon(addon);
+    do_check_true(canInstall, "Correctly accepted a good URL");
   }
+  run_next_test();
 });
 
 add_test(function test_source_uri_rewrite() {
   _("Ensure that a 'src=api' query string is rewritten to 'src=sync'");
 
   // This tests for conformance with bug 708134 so server-side metrics aren't
   // skewed.
 
@@ -146,17 +123,21 @@ add_test(function test_source_uri_rewrit
 
       cb(null, {id: addon.id, addon: addon, install: install});
     }, false);
   };
 
   let server = createAndStartHTTPServer();
 
   let installCallback = Async.makeSpinningCallback();
-  AddonUtils.installAddons([{id: "rewrite@tests.mozilla.org"}], installCallback);
+  let installOptions = {
+    id: "rewrite@tests.mozilla.org",
+    requireSecureURI: false,
+  }
+  AddonUtils.installAddons([installOptions], installCallback);
 
   installCallback.wait();
   do_check_true(installCalled);
   AddonUtils.__proto__.installAddonFromSearchResult = oldFunction;
 
   Svc.Prefs.reset("addons.ignoreRepositoryChecking");
   server.stop(run_next_test);
 });
--- a/services/sync/tests/unit/test_addons_store.js
+++ b/services/sync/tests/unit/test_addons_store.js
@@ -409,19 +409,20 @@ add_test(function test_create_bad_instal
   let server = createAndStartHTTPServer(HTTP_PORT);
 
   // The handler returns a search result but the XPI will 404.
   const id = "missing-xpi@tests.mozilla.org";
   let guid = Utils.makeGUID();
   let record = createRecordForThisApp(guid, id, true, false);
 
   let failed = store.applyIncomingBatch([record]);
-  do_check_eq(1, failed.length);
-  do_check_eq(guid, failed[0]);
-  do_check_eq(sumHistogram("WEAVE_ENGINE_APPLY_FAILURES", { key: "addons" }), 1);
+  // This addon had no source URI so was skipped - but it's not treated as
+  // failure.
+  do_check_eq(0, failed.length);
+  do_check_eq(sumHistogram("WEAVE_ENGINE_APPLY_FAILURES", { key: "addons" }), 0);
 
   let addon = getAddonFromAddonManagerByID(id);
   do_check_eq(null, addon);
 
   server.stop(run_next_test);
 });
 
 add_test(function test_wipe() {
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -333,8 +333,10 @@ user_pref("media.webspeech.synth.test", 
 // connections.
 user_pref("browser.urlbar.suggest.searches", false);
 
 // Turn off the location bar search suggestions opt-in.  It interferes with
 // tests that don't expect it to be there.
 user_pref("browser.urlbar.userMadeSearchSuggestionsChoice", true);
 
 user_pref("dom.audiochannel.mutedByDefault", false);
+
+user_pref("webextensions.tests", true);
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -41,16 +41,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
                                   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
                                   "resource://gre/modules/Preferences.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
                                   "resource://gre/modules/Schemas.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
+                                  "resource://gre/modules/AppConstants.jsm");
 
 Cu.import("resource://gre/modules/ExtensionManagement.jsm");
 
 // Register built-in parts of the API. Other parts may be registered
 // in browser/, mobile/, or b2g/.
 ExtensionManagement.registerScript("chrome://extensions/content/ext-alarms.js");
 ExtensionManagement.registerScript("chrome://extensions/content/ext-backgroundPage.js");
 ExtensionManagement.registerScript("chrome://extensions/content/ext-cookies.js");
@@ -906,16 +908,20 @@ Extension.prototype = extend(Object.crea
       whiteListedHosts: this.whiteListedHosts.serialize(),
       localeData: this.localeData.serialize(),
     };
   },
 
   broadcast(msg, data) {
     return new Promise(resolve => {
       let count = Services.ppmm.childCount;
+      if (AppConstants.MOZ_NUWA_PROCESS) {
+        // The nuwa process is frozen, so don't expect it to answer.
+        count--;
+      }
       Services.ppmm.addMessageListener(msg + "Complete", function listener() {
         count--;
         if (count == 0) {
           Services.ppmm.removeMessageListener(msg + "Complete", listener);
           resolve();
         }
       });
       Services.ppmm.broadcastAsyncMessage(msg, data);
--- a/toolkit/components/extensions/ExtensionContent.jsm
+++ b/toolkit/components/extensions/ExtensionContent.jsm
@@ -175,16 +175,17 @@ Script.prototype = {
     let scheduled = this.run_at || "document_idle";
     if (shouldRun(scheduled)) {
       for (let url of this.js) {
         // On gonk we need to load the resources asynchronously because the
         // app: channels only support asyncOpen. This is safe only in the
         // `document_idle` state.
         if (AppConstants.platform == "gonk" && scheduled != "document_idle") {
           Cu.reportError(`Script injection: ignoring ${url} at ${scheduled}`);
+          continue;
         }
         url = extension.baseURI.resolve(url);
 
         let options = {
           target: sandbox,
           charset: "UTF-8",
           async: AppConstants.platform == "gonk",
         };
--- a/toolkit/components/extensions/ExtensionManagement.jsm
+++ b/toolkit/components/extensions/ExtensionManagement.jsm
@@ -8,16 +8,17 @@ this.EXPORTED_SYMBOLS = ["ExtensionManag
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/AppConstants.jsm");
 
 /*
  * This file should be kept short and simple since it's loaded even
  * when no extensions are running.
  */
 
 // Keep track of frame IDs for content windows. Mostly we can just use
 // the outer window ID as the frame ID. However, the API specifies
@@ -137,16 +138,26 @@ var Service = {
   // Called when a new extension is loaded.
   startupExtension(uuid, uri, extension) {
     if (!this.initialized) {
       this.initialized = true;
       this.init();
     }
 
     // Create the moz-extension://uuid mapping.
+    // On b2g, in content processes we can't load jar:file:/// content, so we
+    // switch to jar:remoteopenfile:/// instead
+    // This is mostly exercised by generated extensions in tests. Installed
+    // extensions in b2g get an app: uri that also maps to the right jar: uri.
+    if (AppConstants.MOZ_B2G &&
+        Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT &&
+        uri.spec.startsWith("jar:file://")) {
+      uri = Services.io.newURI("jar:remoteopen" + uri.spec.substr("jar:".length), null, null);
+    }
+
     let handler = Services.io.getProtocolHandler("moz-extension");
     handler.QueryInterface(Ci.nsISubstitutingProtocolHandler);
     handler.setSubstitution(uuid, uri);
 
     this.uuidMap.set(uuid, extension);
     this.aps.setAddonLoadURICallback(extension.id, this.checkAddonMayLoad.bind(this, extension));
     this.aps.setAddonLocalizeCallback(extension.id, extension.localize.bind(extension));
   },
--- a/toolkit/components/extensions/ExtensionUtils.jsm
+++ b/toolkit/components/extensions/ExtensionUtils.jsm
@@ -652,21 +652,20 @@ Port.prototype = {
   },
 
   close() {
     this.disconnect();
   },
 };
 
 function getMessageManager(target) {
-  if (target instanceof Ci.nsIDOMXULElement) {
-    return target.messageManager;
-  } else {
-    return target;
-  }
+  if (target instanceof Ci.nsIFrameLoaderOwner) {
+    return target.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager;
+   }
+  return target;
 }
 
 // Each extension scope gets its own Messenger object. It handles the
 // basics of sendMessage, onMessage, connect, and onConnect.
 //
 // |context| is the extension scope.
 // |broker| is a MessageBroker used to receive and send messages.
 // |sender| is an object describing the sender (usually giving its extension id, tabId, etc.)
--- a/toolkit/components/extensions/ext-alarms.js
+++ b/toolkit/components/extensions/ext-alarms.js
@@ -86,17 +86,17 @@ extensions.on("shutdown", (type, extensi
   for (let alarm of alarmsMap.get(extension)) {
     alarm.clear();
   }
   alarmsMap.delete(extension);
   alarmCallbacksMap.delete(extension);
 });
 /* eslint-enable mozilla/balanced-listeners */
 
-extensions.registerAPI((extension, context) => {
+extensions.registerPrivilegedAPI("alarms", (extension, context) => {
   return {
     alarms: {
       create: function(...args) {
         let name = "", alarmInfo;
         if (args.length == 1) {
           alarmInfo = args[0];
         } else {
           [name, alarmInfo] = args;
--- a/toolkit/components/extensions/ext-cookies.js
+++ b/toolkit/components/extensions/ext-cookies.js
@@ -1,13 +1,14 @@
 "use strict";
 
 const { interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/ExtensionUtils.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
 
 var {
   EventManager,
   runSafe,
 } = ExtensionUtils;
 
 // Cookies from private tabs currently can't be enumerated.
 var DEFAULT_STORE = "firefox-default";
--- a/toolkit/components/extensions/test/mochitest/.eslintrc
+++ b/toolkit/components/extensions/test/mochitest/.eslintrc
@@ -1,26 +1,17 @@
 {
-  "extends": "../../.eslintrc",
+  "extends": "../../../../../testing/mochitest/mochitest.eslintrc",
+
+  "env": {
+    "webextensions": true,
+  },
 
   "globals": {
     "sendAsyncMessage": false,
 
+    "waitForLoad": true,
+
     "ExtensionTestUtils": false,
     "NetUtil": true,
     "XPCOMUtils": true,
-
-    "waitForLoad": true,
-
-    // Test harness globals
-    "add_task": false,
-    "info": false,
-    "is": false,
-    "ok": false,
-    "SimpleTest": false,
-    "SpecialPowers": true,
   },
-
-  "env": {
-    "browser": true,
-    "webextensions": true,
-  }
 }
--- a/toolkit/components/extensions/test/mochitest/mochitest.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = os == 'android' || buildapp == 'b2g' || buildapp == 'mulet' || asan
+skip-if = os == 'android' || buildapp == 'mulet' || asan
 support-files =
   head.js
   file_WebRequest_page1.html
   file_WebRequest_page2.html
   file_WebNavigation_page1.html
   file_WebNavigation_page2.html
   file_WebNavigation_page3.html
   file_image_good.png
@@ -21,37 +21,47 @@ support-files =
   redirection.sjs
   file_privilege_escalation.html
   file_ext_background_api_injection.js
   file_permission_xhr.html
 
 [test_ext_simple.html]
 [test_ext_geturl.html]
 [test_ext_contentscript.html]
+skip-if = buildapp == 'b2g' # runat != document_idle is not supported.
 [test_ext_i18n_css.html]
 [test_ext_generate.html]
 [test_ext_localStorage.html]
 [test_ext_onmessage_removelistener.html]
 [test_ext_notifications.html]
 [test_ext_permission_xhr.html]
+skip-if = buildapp == 'b2g' # JavaScript error: jar:remoteopenfile:///data/local/tmp/generated-extension.xpi!/content.js, line 46: NS_ERROR_ILLEGAL_VALUE:
 [test_ext_runtime_connect.html]
+skip-if = buildapp == 'b2g' # port.sender.tab is undefined on b2g.
 [test_ext_runtime_connect2.html]
+skip-if = buildapp == 'b2g' # port.sender.tab is undefined on b2g.
 [test_ext_runtime_disconnect.html]
 [test_ext_runtime_getPlatformInfo.html]
 [test_ext_sandbox_var.html]
 [test_ext_sendmessage_reply.html]
+skip-if = buildapp == 'b2g' # sender.tab is undefined on b2g.
 [test_ext_sendmessage_reply2.html]
+skip-if = buildapp == 'b2g' # sender.tab is undefined on b2g.
 [test_ext_sendmessage_doublereply.html]
+skip-if = buildapp == 'b2g' # sender.tab is undefined on b2g.
 [test_ext_storage.html]
 [test_ext_background_runtime_connect_params.html]
 [test_ext_cookies.html]
 [test_ext_cookies_permissions.html]
-skip-if = e10s # Uses cookie service via SpecialPowers.Services, which does not support e10s.
+skip-if = e10s || buildapp == 'b2g' # Uses cookie service via SpecialPowers.Services, which does not support e10s.
 [test_ext_bookmarks.html]
+skip-if = buildapp == 'b2g' # unimplemented api.
 [test_ext_alarms.html]
 [test_ext_background_window_properties.html]
 [test_ext_background_sub_windows.html]
 [test_ext_background_api_injection.html]
 [test_ext_jsversion.html]
-skip-if = e10s # Uses a console monitor which doesn't work from a content process. The code being tested doesn't run in a tab content process in any case.
+skip-if = e10s || buildapp == 'b2g' # Uses a console monitor which doesn't work from a content process. The code being tested doesn't run in a tab content process in any case.
 [test_ext_i18n.html]
 [test_ext_webrequest.html]
+skip-if = buildapp == 'b2g' # webrequest api uninplemented (bug 1199504)
 [test_ext_webnavigation.html]
+skip-if = buildapp == 'b2g' # needs TabManager which is not yet implemented
--- a/toolkit/components/extensions/test/mochitest/test_ext_alarms.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_alarms.html
@@ -8,16 +8,41 @@
   <script type="text/javascript" src="head.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 
 <script type="text/javascript">
 "use strict";
 
+add_task(function* test_alarm_without_permissions() {
+  function backgroundScript() {
+    browser.test.log("running alarm script");
+
+    browser.test.assertTrue(!browser.alarms,
+                            "alarm API should not be available if the alarm permission is not required");
+    browser.test.notifyPass("alarms_permission");
+  }
+
+  let extensionData = {
+    background: "(" + backgroundScript.toString() + ")()",
+    manifest: {
+      permissions: [],
+    },
+  };
+
+  let extension = ExtensionTestUtils.loadExtension(extensionData);
+  yield extension.startup();
+  info("extension loaded");
+  yield extension.awaitFinish("alarms_permission");
+  yield extension.unload();
+  info("extension unloaded");
+});
+
+
 add_task(function* test_alarm_fires() {
   function backgroundScript() {
     let ALARM_NAME = "test_ext_alarms";
     browser.test.log("running alarm script");
 
     chrome.alarms.onAlarm.addListener(function(alarm) {
       browser.test.assertEq(alarm.name, ALARM_NAME, "alarm should have the correct name");
       browser.test.notifyPass("alarms");
--- a/toolkit/components/extensions/test/mochitest/test_ext_geturl.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_geturl.html
@@ -38,17 +38,17 @@ function contentScript() {
 }
 
 let extensionData = {
   background: "(" + backgroundScript.toString() + ")()",
   manifest: {
     "content_scripts": [{
       "matches": ["http://mochi.test/*/file_sample.html"],
       "js": ["content_script.js"],
-      "run_at": "document_start",
+      "run_at": "document_idle",
     }],
   },
 
   files: {
     "content_script.js": "(" + contentScript.toString() + ")()",
   },
 };
 
--- a/toolkit/components/extensions/test/mochitest/test_ext_runtime_connect2.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_runtime_connect2.html
@@ -60,17 +60,17 @@ function makeExtension() {
   let token = Math.random();
   let extensionData = {
     background: `(${backgroundScript})("${token}")`,
     manifest: {
       "permissions": ["tabs"],
       "content_scripts": [{
         "matches": ["http://mochi.test/*/file_sample.html"],
         "js": ["content_script.js"],
-        "run_at": "document_start",
+        "run_at": "document_idle",
       }],
     },
 
     files: {
       "content_script.js": `(${contentScript})("${token}")`,
     },
   };
   return extensionData;
--- a/toolkit/components/extensions/test/mochitest/test_ext_runtime_disconnect.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_runtime_disconnect.html
@@ -29,17 +29,17 @@ function contentScript() {
 
 let extensionData = {
   background: "(" + backgroundScript.toString() + ")()",
   manifest: {
     "permissions": ["tabs"],
     "content_scripts": [{
       "matches": ["http://mochi.test/*/file_sample.html"],
       "js": ["content_script.js"],
-      "run_at": "document_start",
+      "run_at": "document_idle",
     }],
   },
 
   files: {
     "content_script.js": "(" + contentScript.toString() + ")()",
   },
 };
 
--- a/toolkit/components/extensions/test/mochitest/test_ext_runtime_getPlatformInfo.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_runtime_getPlatformInfo.html
@@ -10,17 +10,17 @@
 </head>
 <body>
 
 <script type="text/javascript">
 "use strict";
 
 function backgroundScript() {
   browser.runtime.getPlatformInfo(info => {
-    let validOSs = ["mac", "win", "android", "cros", "linux", "openbsd"];
+    let validOSs = ["mac", "win", "android", "cros", "linux", "openbsd", "gonk"];
     let validArchs = ["arm", "x86-32", "x86-64"];
 
     browser.test.assertTrue(validOSs.indexOf(info.os) != -1, "OS is valid");
     browser.test.assertTrue(validArchs.indexOf(info.arch) != -1, "Architecture is valid");
     browser.test.notifyPass("runtime.getPlatformInfo");
   });
 }
 
--- a/toolkit/components/extensions/test/mochitest/test_ext_sandbox_var.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_sandbox_var.html
@@ -27,17 +27,17 @@ function contentScript() {
 }
 
 let extensionData = {
   background: "(" + backgroundScript.toString() + ")()",
   manifest: {
     "content_scripts": [{
       "matches": ["http://mochi.test/*/file_sample.html"],
       "js": ["content_script.js"],
-      "run_at": "document_start",
+      "run_at": "document_idle",
     }],
   },
 
   files: {
     "content_script.js": "(" + contentScript.toString() + ")()",
   },
 };
 
--- a/toolkit/components/extensions/test/mochitest/test_ext_sendmessage_reply.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_sendmessage_reply.html
@@ -46,17 +46,17 @@ function contentScript() {
 
 let extensionData = {
   background: "(" + backgroundScript.toString() + ")()",
   manifest: {
     "permissions": ["tabs"],
     "content_scripts": [{
       "matches": ["http://mochi.test/*/file_sample.html"],
       "js": ["content_script.js"],
-      "run_at": "document_start",
+      "run_at": "document_idle",
     }],
   },
 
   files: {
     "content_script.js": "(" + contentScript.toString() + ")()",
   },
 };
 
--- a/toolkit/components/extensions/test/xpcshell/.eslintrc
+++ b/toolkit/components/extensions/test/xpcshell/.eslintrc
@@ -1,16 +1,3 @@
 {
-  "extends": "../../.eslintrc",
-
-  "globals": {
-    "NetUtil": true,
-    "XPCOMUtils": true,
-
-    // Test harness globals
-    "add_task": false,
-    "Assert": false,
-    "do_register_cleanup": false,
-    "do_check_eq": false,
-    "equal": false,
-    "ok": false,
-  }
+  "exte