Merge fx-team to m-c a=merge
authorWes Kocher <wkocher@mozilla.com>
Thu, 05 Jun 2014 19:06:34 -0700
changeset 206189 4a552fb1ca38e5eabb53d59db9f8568f7f67676b
parent 206175 78513fddd45e92556760a891777d1681c9a0736c (current diff)
parent 206188 e88f77d8db9207ef695c9669f9111434a28f7ad9 (diff)
child 206190 7297cfffd91c930525a9f2acfcd084ad5ae7decf
child 206227 f3d257065b3371878d0cf1b79e9800ebfc029925
child 206328 b7d259bda94a1a0075fad7a964c7df97537b14f2
child 206396 648e1e91997d594048c288fe202bdb3e2bcd5d91
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone32.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 fx-team to m-c a=merge
mobile/android/base/resources/drawable-hdpi/close_edit_mode.png
mobile/android/base/resources/drawable-mdpi/close_edit_mode.png
mobile/android/base/resources/drawable-xhdpi/close_edit_mode.png
--- a/browser/components/customizableui/test/browser_962069_drag_to_overflow_chevron.js
+++ b/browser/components/customizableui/test/browser_962069_drag_to_overflow_chevron.js
@@ -16,22 +16,26 @@ add_task(function*() {
   window.resizeTo(400, window.outerHeight);
   yield waitForCondition(() => navbar.hasAttribute("overflowing"));
   ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
 
   let widgetOverflowPanel = document.getElementById("widget-overflow");
   let panelShownPromise = promisePanelElementShown(window, widgetOverflowPanel);
   let identityBox = document.getElementById("identity-box");
   let overflowChevron = document.getElementById("nav-bar-overflow-button");
+
+  // Listen for hiding immediately so we don't miss the event because of the
+  // async-ness of the 'shown' yield...
+  let panelHiddenPromise = promisePanelElementHidden(window, widgetOverflowPanel);
+
   ChromeUtils.synthesizeDrop(identityBox, overflowChevron, [], null);
   yield panelShownPromise;
 
   info("Overflow panel is shown.");
 
-  let panelHiddenPromise = promisePanelElementHidden(window, widgetOverflowPanel);
   widgetOverflowPanel.hidePopup();
   yield panelHiddenPromise;
 });
 
 add_task(function*() {
   window.resizeTo(originalWindowWidth, window.outerHeight);
   let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
   yield waitForCondition(() => !navbar.hasAttribute("overflowing"));
--- a/browser/components/translation/Translation.jsm
+++ b/browser/components/translation/Translation.jsm
@@ -15,16 +15,17 @@ const TRANSLATION_PREF_SHOWUI = "browser
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Metrics.jsm", this);
 Cu.import("resource://gre/modules/Task.jsm", this);
 
 const DAILY_COUNTER_FIELD = {type: Metrics.Storage.FIELD_DAILY_COUNTER};
 const DAILY_LAST_TEXT_FIELD = {type: Metrics.Storage.FIELD_DAILY_LAST_TEXT};
+const DAILY_LAST_NUMERIC_FIELD = {type: Metrics.Storage.FIELD_DAILY_LAST_NUMERIC};
 
 
 this.Translation = {
   supportedSourceLanguages: ["en", "zh", "ja", "es", "de", "fr", "ru", "ar", "ko", "pt"],
   supportedTargetLanguages: ["en", "pl", "tr", "vi"],
 
   _defaultTargetLanguage: "",
   get defaultTargetLanguage() {
@@ -295,16 +296,18 @@ TranslationMeasurement1.prototype = Obje
   fields: {
     translationOpportunityCount: DAILY_COUNTER_FIELD,
     pageTranslatedCount: DAILY_COUNTER_FIELD,
     charactersTranslatedCount: DAILY_COUNTER_FIELD,
     translationOpportunityCountsByLanguage: DAILY_LAST_TEXT_FIELD,
     pageTranslatedCountsByLanguage: DAILY_LAST_TEXT_FIELD,
     detectedLanguageChangedBefore: DAILY_COUNTER_FIELD,
     detectedLanguageChangedAfter: DAILY_COUNTER_FIELD,
+    detectLanguageEnabled: DAILY_LAST_NUMERIC_FIELD,
+    showTranslationUI: DAILY_LAST_NUMERIC_FIELD,
   },
 
   shouldIncludeField: function (field) {
     if (!Services.prefs.getBoolPref("toolkit.telemetry.enabled")) {
       // This measurement should only be included when telemetry is
       // enabled, so we will not include any fields.
       return false;
     }
@@ -319,17 +322,17 @@ TranslationMeasurement1.prototype = Obje
       if (data.hasDay(date)) {
         data = JSON.parse(data.getDay(date));
       } else {
         data = {};
       }
 
       return data;
     });
-},
+  },
 
   _wrapJSONSerializer: function (serializer) {
     let _parseInPlace = function(o, k) {
       if (k in o) {
         o[k] = JSON.parse(o[k]);
       }
     };
 
@@ -409,16 +412,29 @@ TranslationProvider.prototype = Object.f
       if (beforeFirstTranslation) {
           yield m.incrementDailyCounter("detectedLanguageChangedBefore");
         } else {
           yield m.incrementDailyCounter("detectedLanguageChangedAfter");
         }
     }.bind(this));
   },
 
+  collectDailyData: function () {
+    let m = this.getMeasurement(TranslationMeasurement1.prototype.name,
+                                TranslationMeasurement1.prototype.version);
+
+    return this._enqueueTelemetryStorageTask(function* recordTask() {
+      let detectLanguageEnabled = Services.prefs.getBoolPref("browser.translation.detectLanguage");
+      yield m.setDailyLastNumeric("detectLanguageEnabled", detectLanguageEnabled ? 1 : 0);
+
+      let showTranslationUI = Services.prefs.getBoolPref("browser.translation.ui.show");
+      yield m.setDailyLastNumeric("showTranslationUI", showTranslationUI ? 1 : 0);
+    }.bind(this));
+  },
+
   _enqueueTelemetryStorageTask: function (task) {
     if (!Services.prefs.getBoolPref("toolkit.telemetry.enabled")) {
       // This measurement should only be included when telemetry is
       // enabled, so don't record any data.
       return Promise.resolve(null);
     }
 
     return this.enqueueStorageOperation(() => {
--- a/browser/components/translation/test/unit/test_healthreport.js
+++ b/browser/components/translation/test/unit/test_healthreport.js
@@ -165,16 +165,54 @@ add_task(function* test_record_translati
   Assert.equal(day.get("detectedLanguageChangedBefore"), 1);
   Assert.ok(day.has("detectedLanguageChangedAfter"));
   Assert.equal(day.get("detectedLanguageChangedAfter"), 2);
 
   yield provider.shutdown();
   yield storage.close();
 });
 
+add_task(function* test_collect_daily() {
+  let storage = yield Metrics.Storage("translation");
+  let provider = new TranslationProvider();
+  yield provider.init(storage);
+  let now = new Date();
+
+  // Set the prefs we test here to `false` initially.
+  const kPrefDetectLanguage = "browser.translation.detectLanguage";
+  const kPrefShowUI = "browser.translation.ui.show";
+  Services.prefs.setBoolPref(kPrefDetectLanguage, false);
+  Services.prefs.setBoolPref(kPrefShowUI, false);
+
+  // Initially nothing should be configured.
+  yield provider.collectDailyData();
+
+  let m = provider.getMeasurement("translation", 1);
+  let values = yield m.getValues();
+  Assert.equal(values.days.size, 1);
+  Assert.ok(values.days.hasDay(now));
+  let day = values.days.getDay(now);
+  Assert.ok(day.has("detectLanguageEnabled"));
+  Assert.ok(day.has("showTranslationUI"));
+
+  // Changes to the repective prefs should be picked up.
+  Services.prefs.setBoolPref(kPrefDetectLanguage, true);
+  Services.prefs.setBoolPref(kPrefShowUI, true);
+
+  yield provider.collectDailyData();
+
+  values = yield m.getValues();
+  day = values.days.getDay(now);
+  Assert.equal(day.get("detectLanguageEnabled"), 1);
+  Assert.equal(day.get("showTranslationUI"), 1);
+
+  yield provider.shutdown();
+  yield storage.close();
+});
+
 // Test the payload after recording with telemetry enabled.
 add_task(function* test_healthreporter_json() {
   Services.prefs.setBoolPref("toolkit.telemetry.enabled", true);
 
   let reporter = yield getHealthReporter("healthreporter_json");
   yield reporter.init();
   try {
     let now = new Date();
@@ -222,17 +260,17 @@ add_task(function* test_healthreporter_j
     Assert.ok("detectedLanguageChangedAfter" in translations);
     Assert.equal(translations["detectedLanguageChangedAfter"], 1);
   } finally {
     reporter._shutdown();
   }
 });
 
 // Test the payload after recording with telemetry disabled.
-add_task(function* test_healthreporter_json() {
+add_task(function* test_healthreporter_json2() {
   Services.prefs.setBoolPref("toolkit.telemetry.enabled", false);
 
   let reporter = yield getHealthReporter("healthreporter_json");
   yield reporter.init();
   try {
     let now = new Date();
     let provider = new TranslationProvider();
     yield reporter._providerManager.registerProvider(provider);
--- a/browser/devtools/markupview/markup-view.js
+++ b/browser/devtools/markupview/markup-view.js
@@ -80,16 +80,19 @@ function MarkupView(aInspector, aFrame, 
   this.undo = new UndoStack();
   this.undo.installController(aControllerWindow);
 
   this._containers = new Map();
 
   this._boundMutationObserver = this._mutationObserver.bind(this);
   this.walker.on("mutations", this._boundMutationObserver);
 
+  this._boundOnDisplayChange = this._onDisplayChange.bind(this);
+  this.walker.on("display-change", this._boundOnDisplayChange);
+
   this._boundOnNewSelection = this._onNewSelection.bind(this);
   this._inspector.selection.on("new-node-front", this._boundOnNewSelection);
   this._onNewSelection();
 
   this._boundKeyDown = this._onKeyDown.bind(this);
   this._frame.contentWindow.addEventListener("keydown", this._boundKeyDown, false);
 
   this._boundFocus = this._onFocus.bind(this);
@@ -610,16 +613,29 @@ MarkupView.prototype = {
           }
         });
 
       }
     });
   },
 
   /**
+   * React to display-change events from the walker
+   * @param {Array} nodes An array of nodeFronts
+   */
+  _onDisplayChange: function(nodes) {
+    for (let node of nodes) {
+      let container = this._containers.get(node);
+      if (container) {
+        container.isDisplayed = node.isDisplayed;
+      }
+    }
+  },
+
+  /**
    * Given a list of mutations returned by the mutation observer, flash the
    * corresponding containers to attract attention.
    */
   _flashMutatedNodes: function(aMutations) {
     let addedOrEditedContainers = new Set();
     let removedContainers = new Set();
 
     for (let {type, target, added, removed} of aMutations) {
@@ -1105,16 +1121,19 @@ MarkupView.prototype = {
     this._boundKeyDown = null;
 
     this._inspector.selection.off("new-node-front", this._boundOnNewSelection);
     this._boundOnNewSelection = null;
 
     this.walker.off("mutations", this._boundMutationObserver)
     this._boundMutationObserver = null;
 
+    this.walker.off("display-change", this._boundOnDisplayChange);
+    this._boundOnDisplayChange = null;
+
     this._elt.removeEventListener("mousemove", this._onMouseMove, false);
     this._elt.removeEventListener("mouseleave", this._onMouseLeave, false);
     this._elt = null;
 
     for (let [key, container] of this._containers) {
       container.destroy();
     }
     this._containers = null;
@@ -1263,16 +1282,19 @@ function MarkupContainer(aMarkupView, aN
   // Appending the editor element and attaching event listeners
   this.tagLine.appendChild(this.editor.elt);
 
   this._onMouseDown = this._onMouseDown.bind(this);
   this.elt.addEventListener("mousedown", this._onMouseDown, false);
 
   // Prepare the image preview tooltip data if any
   this._prepareImagePreview();
+
+  // Marking the node as shown or hidden
+  this.isDisplayed = this.node.isDisplayed;
 }
 
 MarkupContainer.prototype = {
   toString: function() {
     return "[MarkupContainer for " + this.node + "]";
   },
 
   isPreviewable: function() {
@@ -1337,16 +1359,26 @@ MarkupContainer.prototype = {
 
     return this.tooltipData.data.then(({data, size}) => {
       tooltip.setImageContent(data, size);
     }, () => {
       tooltip.setBrokenImageContent();
     });
   },
 
+  /**
+   * Show the element has displayed or not
+   */
+  set isDisplayed(isDisplayed) {
+    this.elt.classList.remove("not-displayed");
+    if (!isDisplayed) {
+      this.elt.classList.add("not-displayed");
+    }
+  },
+
   copyImageDataUri: function() {
     // We need to send again a request to gettooltipData even if one was sent for
     // the tooltip, because we want the full-size image
     this.node.getImageData().then(data => {
       data.data.string().then(str => {
         clipboardHelper.copyString(str, this.markup.doc);
       });
     });
--- a/browser/devtools/markupview/test/browser.ini
+++ b/browser/devtools/markupview/test/browser.ini
@@ -1,16 +1,17 @@
 [DEFAULT]
 skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
 subsuite = devtools
 support-files =
   doc_markup_edit.html
   doc_markup_flashing.html
   doc_markup_mutation.html
   doc_markup_navigation.html
+  doc_markup_not_displayed.html
   doc_markup_pagesize_01.html
   doc_markup_pagesize_02.html
   doc_markup_search.html
   doc_markup_toggle.html
   doc_markup_tooltip.png
   head.js
   helper_attributes_test_runner.js
   helper_outerhtml_test_runner.js
@@ -21,16 +22,18 @@ support-files =
 [browser_markupview_highlight_hover_02.js]
 [browser_markupview_html_edit_01.js]
 [browser_markupview_html_edit_02.js]
 [browser_markupview_html_edit_03.js]
 [browser_markupview_image_tooltip.js]
 [browser_markupview_mutation_01.js]
 [browser_markupview_mutation_02.js]
 [browser_markupview_navigation.js]
+[browser_markupview_node_not_displayed_01.js]
+[browser_markupview_node_not_displayed_02.js]
 [browser_markupview_pagesize_01.js]
 [browser_markupview_pagesize_02.js]
 [browser_markupview_search_01.js]
 [browser_markupview_tag_edit_01.js]
 [browser_markupview_tag_edit_02.js]
 [browser_markupview_tag_edit_03.js]
 [browser_markupview_tag_edit_04.js]
 [browser_markupview_tag_edit_05.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/markupview/test/browser_markupview_node_not_displayed_01.js
@@ -0,0 +1,33 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that nodes that are not displayed appear differently in the markup-view
+// when these nodes are imported in the view.
+
+// Note that nodes inside a display:none parent are obviously not displayed too
+// but the markup-view uses css inheritance to mark those as hidden instead of
+// having to visit each and every child of a hidden node. So there's no sense
+// testing children nodes.
+
+const TEST_URL = TEST_URL_ROOT + "doc_markup_not_displayed.html";
+const TEST_DATA = [
+  {selector: "#normal-div", isDisplayed: true},
+  {selector: "head", isDisplayed: false},
+  {selector: "#display-none", isDisplayed: false},
+  {selector: "#hidden-true", isDisplayed: false},
+  {selector: "#visibility-hidden", isDisplayed: true}
+];
+
+let test = asyncTest(function*() {
+  let {inspector} = yield addTab(TEST_URL).then(openInspector);
+
+  for (let {selector, isDisplayed} of TEST_DATA) {
+    info("Getting node " + selector);
+    let container = getContainerForRawNode(selector, inspector);
+    is(!container.elt.classList.contains("not-displayed"), isDisplayed,
+      "The container for " + selector + " is marked as displayed " + isDisplayed);
+  }
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/markupview/test/browser_markupview_node_not_displayed_02.js
@@ -0,0 +1,132 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that nodes are marked as displayed and not-displayed dynamically, when
+// their display changes
+
+const TEST_URL = TEST_URL_ROOT + "doc_markup_not_displayed.html";
+const TEST_DATA = [
+  {
+    desc: "Hiding a node by creating a new stylesheet",
+    selector: "#normal-div",
+    before: true,
+    changeStyle: (doc, node) => {
+      let div = doc.createElement("div");
+      div.id = "new-style";
+      div.innerHTML = "<style>#normal-div {display:none;}</style>";
+      doc.body.appendChild(div);
+    },
+    after: false
+  },
+  {
+    desc: "Showing a node by deleting an existing stylesheet",
+    selector: "#normal-div",
+    before: false,
+    changeStyle: (doc, node) => {
+      doc.getElementById("new-style").remove();
+    },
+    after: true
+  },
+  {
+    desc: "Hiding a node by changing its style property",
+    selector: "#display-none",
+    before: false,
+    changeStyle: (doc, node) => {
+      node.style.display = "block";
+    },
+    after: true
+  },
+  {
+    desc: "Showing a node by removing its hidden attribute",
+    selector: "#hidden-true",
+    before: false,
+    changeStyle: (doc, node) => {
+      node.removeAttribute("hidden");
+    },
+    after: true
+  },
+  {
+    desc: "Hiding a node by adding a hidden attribute",
+    selector: "#hidden-true",
+    before: true,
+    changeStyle: (doc, node) => {
+      node.setAttribute("hidden", "true");
+    },
+    after: false
+  },
+  {
+    desc: "Showing a node by changin a stylesheet's rule",
+    selector: "#hidden-via-stylesheet",
+    before: false,
+    changeStyle: (doc, node) => {
+      doc.styleSheets[0].cssRules[0].style.setProperty("display", "inline");
+    },
+    after: true
+  },
+  {
+    desc: "Hiding a node by adding a new rule to a stylesheet",
+    selector: "#hidden-via-stylesheet",
+    before: true,
+    changeStyle: (doc, node) => {
+      doc.styleSheets[0].insertRule(
+        "#hidden-via-stylesheet {display: none;}", 1);
+    },
+    after: false
+  },
+  {
+    desc: "Hiding a node by adding a class that matches an existing rule",
+    selector: "#normal-div",
+    before: true,
+    changeStyle: (doc, node) => {
+      doc.styleSheets[0].insertRule(
+        ".a-new-class {display: none;}", 2);
+      node.classList.add("a-new-class");
+    },
+    after: false
+  }
+];
+
+let test = asyncTest(function*() {
+  let {inspector} = yield addTab(TEST_URL).then(openInspector);
+
+  for (let data of TEST_DATA) {
+    info("Running test case: " + data.desc);
+    yield runTestData(inspector, data);
+  }
+});
+
+function runTestData(inspector, {selector, before, changeStyle, after}) {
+  let def = promise.defer();
+
+  info("Getting the " + selector + " test node");
+  let container = getContainerForRawNode(selector, inspector);
+  is(!container.elt.classList.contains("not-displayed"), before,
+    "The container is marked as " + (before ? "shown" : "hidden"));
+
+  info("Listening for the display-change event");
+  inspector.markup.walker.once("display-change", nodes => {
+    info("Verifying that the list of changed nodes include our container");
+
+    ok(nodes.length, "The display-change event was received with a nodes");
+    let foundContainer = false;
+    for (let node of nodes) {
+      if (inspector.markup.getContainer(node) === container) {
+        foundContainer = true;
+        break;
+      }
+    }
+    ok(foundContainer, "Container is part of the list of changed nodes");
+
+    is(!container.elt.classList.contains("not-displayed"), after,
+      "The container is marked as " + (after ? "shown" : "hidden"));
+    def.resolve();
+  });
+
+  info("Making style changes");
+  changeStyle(content.document, getNode(selector));
+
+  return def.promise;
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/markupview/test/doc_markup_not_displayed.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <style>
+    #hidden-via-stylesheet {
+      display: none;
+    }
+  </style>
+</head>
+<body>
+  <div id="normal-div"></div>
+  <div id="display-none" style="display:none;"></div>
+  <div id="hidden-true" hidden="true"></div>
+  <div id="visibility-hidden" style="visibility:hidden;"></div>
+  <div id="hidden-via-stylesheet"></div>
+</body>
+</html>
\ No newline at end of file
--- a/browser/devtools/styleinspector/rule-view.js
+++ b/browser/devtools/styleinspector/rule-view.js
@@ -1464,34 +1464,36 @@ CssRuleView.prototype = {
         };
       }
     }).then(null, console.error);
   },
 
   /**
    * Update the rules for the currently highlighted element.
    */
-  nodeChanged: function() {
+  refreshPanel: function() {
     // Ignore refreshes during editing or when no element is selected.
     if (this.isEditing || !this._elementStyle) {
       return;
     }
 
-    this._clearRules();
-
     // Repopulate the element style.
-    this._populate();
+    this._populate(true);
   },
 
-  _populate: function() {
+  _populate: function(clearRules = false) {
     let elementStyle = this._elementStyle;
     return this._elementStyle.populate().then(() => {
       if (this._elementStyle != elementStyle) {
         return;
       }
+
+      if (clearRules) {
+        this._clearRules();
+      }
       this._createEditors();
 
       // Notify anyone that cares that we refreshed.
       var evt = this.doc.createEvent("Events");
       evt.initEvent("CssRuleViewRefreshed", true, false);
       this.element.dispatchEvent(evt);
       return undefined;
     }).then(null, promiseWarn);
--- a/browser/devtools/styleinspector/style-inspector.js
+++ b/browser/devtools/styleinspector/style-inspector.js
@@ -104,17 +104,17 @@ RuleViewTool.prototype = {
 
     if (!aEvent || aEvent == "new-node-front") {
       let done = this.inspector.updating("rule-view");
       this.view.highlight(this.inspector.selection.nodeFront).then(done, done);
     }
   },
 
   refresh: function RVT_refresh() {
-    this.view.nodeChanged();
+    this.view.refreshPanel();
   },
 
   destroy: function RVT_destroy() {
     this.inspector.off("layout-change", this.refresh);
     this.inspector.selection.off("pseudoclass", this.refresh);
     this.inspector.selection.off("new-node-front", this._onSelect);
 
     this.view.element.removeEventListener("CssRuleViewCSSLinkClicked",
--- a/browser/themes/shared/devtools/markup-view.css
+++ b/browser/themes/shared/devtools/markup-view.css
@@ -25,16 +25,22 @@
 .theme-selected ~ .editor .theme-fg-color3,
 .theme-selected ~ .editor .theme-fg-color4,
 .theme-selected ~ .editor .theme-fg-color5,
 .theme-selected ~ .editor .theme-fg-color6,
 .theme-selected ~ .editor .theme-fg-color7 {
   color: #f5f7fa; /* Light foreground text */
 }
 
+/* In case a node isn't displayed in the page, we fade the syntax highlighting */
+.not-displayed .open,
+.not-displayed .close {
+  opacity: .7;
+}
+
 .tag-line {
   padding-left: 2px;
 }
 
 /* Preview */
 
 #previewbar {
   position: fixed;
--- a/mobile/android/base/home/TopSitesThumbnailView.java
+++ b/mobile/android/base/home/TopSitesThumbnailView.java
@@ -21,17 +21,17 @@ import android.widget.ImageView;
  */
 public class TopSitesThumbnailView extends ImageView {
     private static final String LOGTAG = "GeckoTopSitesThumbnailView";
 
     // 27.34% opacity filter for the dominant color.
     private static final int COLOR_FILTER = 0x46FFFFFF;
 
     // Default filter color for "Add a bookmark" views.
-    private static final int DEFAULT_COLOR = 0x46ECF0F3;
+    private static final int DEFAULT_COLOR = 0xFFECF0F3;
 
     // Stroke width for the border.
     private final float mStrokeWidth = getResources().getDisplayMetrics().density * 2;
 
     // Paint for drawing the border.
     private static Paint sBorderPaint;
 
     // Initializing the static border paint.
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..14765da7ef5dacd273d90cdec2b9b5a82b150fa0
GIT binary patch
literal 480
zc%17D@N?(olHy`uVBq!ia0vp^Y9P$P0wkGC6jgx~OS+@4BLl<6e(pbstU$g(vPY0F
z149*1VM7Z8!!Mvv!wUw6QUeBtR|yOZRx=nF#0%!^3bX+kk>u^}!tlSn|IB_M@3*Im
zV~EG`r_*eOS`>KPHp?{$<=SpDzHzg{p)&f#yEOuWcT1KfsnmJOJ#>E}`0W?Z1v@dH
z&-rD+ad(!6%=r-#;Uds7Z)Rg(NzhsDg~<ua+yy_MaZyT~x>!f0ghgqh<os?+Hl+;$
z8U9D3n79Qb3!-M;eYU|s?sRU@<7bj0I!lVOHkQU!ohf^NV&8$Jf115Lv6b7l_(kT-
zz3M5P`f>Ywp|D(EbGgl{Q<sYEUOsu_Dv{tDzCP0<L~pJwYrWcd=Zom<b4zAfC%$|3
zwSHzBcfu{HHs9=RbA8NrJrqnSvzR4!`<i&y%h2>H&e?YS*WSdubxU-8T)*0&HpuqK
zy@fY~tDMhSiU5N_wZt`|BqgyV)hf9t6-Y4{85o-A8kp%C7>5{|Ss9pF85-&um|Gbb
iG-to{LD7(#pOTqYiCe=bv(OJf4Gf;HelF{r5}E)X`L7ZH
rename from mobile/android/base/resources/drawable-hdpi/close_edit_mode.png
rename to mobile/android/base/resources/drawable-hdpi/close_edit_mode_light.png
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fd57fe4604d2c4ac45563ab21fa59b07eb31f238
GIT binary patch
literal 1186
zc$@*E1YP@yP)<h;3K|Lk000e1NJLTq003qH003PG1^@s6S7H+k000DONkl<Zc-rmV
zZD>_>0LSq&r(4?6<?ty*#Ik~#$kIR)TV`gIp}hzevBJVyHmnt!5*2$BMbVHl3~~e&
z;d%tgR+{*t%xYL@ENUn&)^Kgk*=A{O_uu#Qq8EeRd(Ziw|GnpSe_!~#9S44Ib{?;1
zjESr9xEeQMEpEXIT#oVZ{?FoeKo_G1t@s0Dbq2e!8Iv`PI|X<Qrx3JLs7IlOiPjW+
z4%>F4NW(;<2wx(qUez$sXhf7HP_AL@l;JF*ZkvX&vjHwTs$uLj!9_zF#?Cu%l7_L<
z3>Wok7(36xMXegf&aH4!wT7`%gl<Gx8wxdyy*fnI0It!Qe>4iQAGQtSc3s4b)-?PK
zo1WHXe>WCj0AcDuv4(NyL4;|SZj`w-2Vr_m!?<-B!t}O=ajOPl>cJ!p<HmZ+doypL
zNW<7E#4J>z0S6I9zhEn_$FzJIW)hll68#~aMy5N5{s`>HqBsuovQgc*C~m`a8|8Oh
z+=dx2%5Qnxh8Z#{hQlZgqhU0RhS4w@Chvwx80EKI=P?>a!)O={qhU0RhRNzM=Zw;M
zjD|^nm@`HN8D=^*<0G`A4`(rg9vnbD%4~;eH_C4vyd<V#C;mn{4dNl2VLmp>uLa&1
zu0SWk)D(7@I)p8Oqj(>$V<$eqG2~*k@J6``U9jolFvHBl2!eDT+b}oD-@O)}AlKT1
zJFp0w&<EQFF)P?Gz<Wry!&n&L13&K?<<}HunAzw+vU>3(Ccq2eQk}&9TR)0}4FgQX
z19%hr@GV-g163%27t$L>`K=B%jC=PP<<}UuVU`-@_hH<InQN5a;kXSm)hNGXaT})8
zD8J6Q4Kv>;zaw!QX0=g%du)c8iM7~(ji^F}<#$}3Gb;4I%ZpRIn%9TtQ5xc_<XuMj
z-3Tw}D1QccllZm(f4dgB)CHVC7e)|O9T*pMm_rEC2%bU#yd-W0gXc_JM!oVk12171
zw%s4}B4!1`whxQpjZ%Vo{DoYp1Kt=`p%-EM6a_(t*#g@-u@^1)0)xo4UP<HX#X$t^
zJ4^|DqfGZp{_Bx6zhm$yP9jyqco7rB-dg_3D8Kda(li0<upNhR9R2te2hfNGwol0%
zG0Jac+@32tVN@(1`0F!D50z^e4WnTKmcU-rVHxJ36vdc{N^He98YXkK2mF}M3jC;H
z-1a-B!wcvVv}qW}_aZ`CsA1f-2A+j>4HM5Z>(Ah_8}fCSDtH#!;Ii_39p(kg4{Be~
zFm5^?@|VX8&;p}j+*KR)ryDhl+lFu@yfi%nqhT`B*BA#cg;hvsn9Nq4?vpzjCbNB?
z&TAVQCOgeYa!hM9O!kIZn&g=7)-c%{W?7PBs?;#q8)i<5Oa13HOqSk7Okq1R*^+!8
zW;o3&&6Dv%KHpmY37P6N?h5$s<}PHS`EeWO9*n?M!)QYT%HV~t1Uv8>T+|%bACD`?
zCNx-j0vl0{J5hlWcoCY7mADr*mdE=zD&b|)KVJWj4MTd{SO5S307*qoM6N<$f~lG!
Ax&QzG
index b20454542a596644d3004dcc5db0b940abc0135e..fbc3b4a37f998126280d20aeb472fe758d61f095
GIT binary patch
literal 1369
zc$@)Q1*ZCmP)<h;3K|Lk000e1NJLTq003hE003GD1^@s6tWN0g000FbNkl<Zc-rlq
zeP~r>9LMigEnli7*|4HH8Z&wsHHz9KZ6WkRO`+1r)KqGJXfI<Rvq1(SZrPixvX%=H
z+=3XbER-l|(F<tng+)q5TZZX$x_n{E+}gMAAN%9<<2-lU+2uUH=icW7pMQ4lVVCo{
zJ1@_9&Rqh4SBV+F0ep=AJBvO*t7we{m(kgDa;C<}q1Ch-dg!Muv^bMu6w+UzmqA*c
z2{H2N-*AJfbdRwU?r??{rE844;2y1U#_)d?qaQ!=(=A3G{TI<VM3>Vm=(KTq37t)M
zAUd__7UOZt`|Yd=1lf~rF+M;vnp5~5$`OrWIz3%tWYa!G<E4~d=|^W#y2Q8@(b;2Z
zS1H+&E-^M>VysKSd$^t+L3DcPxvs~^p$9Q>I%s`_LBMsig$`iiEOI?Y4bq2w^gLH%
z+(`S8UcBgHjH~GZq$kxb#aKxDklr-Wi?qf#e<VUXGKa(TS(=~f7?0BW5#OMVV{|M1
zik?PhvyZmY#&NhYu+66gV>H8K4H;uIJhnJ1cT@FnlVQ4pzDbY4O^(VKwQ!FU^zOg`
z@KQ%lAi89XC*T$Xw3H@<ljttE#g8(^Qn<x3nlLzxcEKIKlra`SBhiPmOX(2Y;A0u%
z4!FSqnrjFkeHCu7O~$whZm=L(0O3^H4gGAEF^Zs{_6S1^k3c_lGDe;Q*ArzC@4x>9
z-8>^>OoDFOXd<HbK{u;p42l8hrF4{AyE8_aGxZDfvLq}<FLct8WJBkUEI&gllFkg#
z%lxnye>ix7*A{r)DOzZF-DJfdw%fyE{GfCYEyu8d@1&BQNy2S{PD;XJv_l`S8;=9#
zv!pqOb;_WV!mt?Ip^rHcp7m%o1ys5#o*ouso5Fj{*@g}KVc?<2Uiv5PqXYCTz09y)
z9rTeSVyL{^_byEsyn$Y9xX8;7ER)^_U7QZSKh2+-hiM|ko<omA4?U(BYoUuPGvINy
z-%K%9K@W|o3?M95H0|^|Q;a3hK?BW7WdOsm;{@!p%M@ci>{Cw@F?kE^(=-4o{(P<S
zTuc$<O!*@k&KPBk64+x6O<3|8dJuMKFvTdebkk@xO<1;w?nnHrH^s<D{5(bzN}Oq7
ziq8g9jB61yN+Q@Ch1g_@akGyRdyKbDG3NRhvBzjO#kkkUh&{%3Q;dgvjM!s*Zi=zO
z$A~?~x271YeT>*+bQ*`yeT>*+bem$V_c3CRao7~&6(1w^7^h4z-clYTJIcgo<uPE2
z(X2Q|0o_X<9LGAB(+*mxJjR7#F+NfnV;21@Fv{CR7mnhS^k`t6rxeG?3yblY!Wh@l
zLr4uZN@Em+#rQ^9j1t<5)bhN-7{y^RIu*qzrT-wD_XDr{UM!nA^7DIOW+Tl~6r(IG
zMwgNpbLmN#SsOT08WhX!A6YhI3=^uel*E`97NZC8(<t0BhB-|u15YdsC;3vxAtdKh
z`TH$B;ZzY8<0KqFoZjvh_tUQmEIST2SR4|=8CDt|p4=+t)DFN6DrJld;0`Z~{ruCk
zjZP6?D(nhXE<Fb>*(+j%xdsB4o&zs{Ta=G79`!rip-#pqhFg4{<XT|`+@e9oD1&=c
z8UEYZF}OvOj4==HF(kfaCy#c*Jz8Xp3b@H2eSt2e-EfmnWQ@h|*y0NrqY@rl?3OXA
z;IYNeGDa;tw%9LY)WKtmUK!&xcx=%xW4r^8HDrwU;IT<=FvfCP@3rPsjKuIN(8usG
bye9txn2_eg=)<2I00000NkvXXu0mjfHb;W>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d43991dd7a060f19271e0af7d6699ad2d66390e8
GIT binary patch
literal 1929
zc$@)=2X^?0P)<h;3K|Lk000e1NJLTq007be001fo1^@s6##jY5000M2Nkl<Zc-rlp
zZHQD=9LC+3wt}RtX|9NAlS!J2Iud@!Qo3cBCMJW>mQlfoAM6FPkqV>;nlDSxi!~Wy
zg=UiwnSr#3x{@zBA1bp#nbNWn%gJ7h%-KCXA5QG$;XmizyZ5eFXU+q^54-1opS^ST
zJolb+UuKX}%3`rZq~SZjVzEK8SZt6i78@js#bSdLno9!KU8-zf*&sC#)4(3^JJ<?F
zQ~OAe0WW|O_*3v`0aL+pumKzeuQd9AvO#Jb+QBK{)j`nWsreMJhLX=@z<R&Y2b2v`
z<B(Odrg~~V0<5daX9QqvY4ibQgVZ=Ypk&?Pso4-9NNs@C-RJ|Vj&VT&ltIo0NvR>=
z1O;FpX!6vo_Y0DSwM*FnSFhw$pIjRx04D0`+aa)4SpTfEL9*B&MQ61Ql7;9B8>GQt
zw&&+oFcT~R3qiZEO*5Dd?gJg*M*Ta%U)**YxF2M}-C#0JwWNJ?LUJ*Aw1RP9f#zHV
zsR>Ncef1bv4i-_r1|<XXpi5H#Igm2U^D_Z_9pI8r3b@+erP>V0Y0~T$*~6c7-?rp!
zCe3~2*}qJGf;0*|1$Kh7x_CTT%IgW;{vv48+s+4v0qa{Z$7euwfFnxQVZ%RtmkO_C
zp6&O7Gjz3Wpo264bQ(Ty57-1o1RMY*WmXpr$iCnAZwlkGhpw#vR*Az9qX+wym8^>P
z7O&iT{${?fPrY7x+hEH5Z#+gE$YyN>kAq%A&6ygV(Mk(?limO=F$d`sQ0FK}V|74!
zltI+*j?YoOLIW<RDSFx}z=<(P4tW%mSrz)<NB7_`$On&#5J<--&>6r=g$R=4HUCKs
zj0!?0tO@Dy@`W2D?0a}UV;JZ~K57yU$WmM6AZb_?no6c=|0v9{dAQV`71~S2G1#Xv
z9elc|-WB{@4{2T_?N_pPfK_0%;iy^$ouDAp?4b`Z3$T6!cY<~>m!?0`KXp2ACG>u<
z{smJK3eqs}o2RA<w&^~77<>R&yV*w`0NlpJA0$4~hYx#n51N9d4ePveh=W2d=*0%9
z-E@>c1?JKQ+o`4so(8R+n%z`$fIL11EdD#U0@hBdkr)n+1J)`qD3Krm9hhFQ4qVG?
zMPV9!glfboNrFKt`%OQoHZBkDgF=YUQlvI9MDYhn9u%)r%@;z=MyfgLX&Wk>u}*?!
zVQ~FSb-iGS&&7)mYb;tXN;pWZV1{AeH<QmVhKmfzpOO4M_^gqN!-MyargX+Iasc@E
z=Q>EM0|aTkAxI0PsUv$B&RlmGKIk&Q`iCC<Nh(N8GZ+QN>u_u#pJM?BR}rMn(;#(`
zPh=01uL0$=AEgU1NGp7vn3jF~k3iRh(}1;t>XHo7P_Pp01%E4&q0g9%xJKoBNXZ8&
zPgAE@Jb2v`G5}d=KQ6=|Jr7uK8lNuk4@Mg(0oEs=<va<}U39@gg$xpt4R8-Bm0*zA
zCl`xH^eI`co`dwZZev~rtd&BY<oOr4j_Q&M(hP7`h0|B$A&~-kP%_<vsq-MYjT)pJ
zU~SfI%sYU!lxl7PRlr(Kb#Vk~Oh1FP9kBL;#b5#$0lIzr)gKq+`OH*@K`PlG;W@ex
z)1e)Jb(^RCiW>Kuwt=Pr2-2i}1jzwC!kJ<)-(ZdqB*rDLR6;>2l205SJfJgv9vr-S
z3DR)kk)l6@wM;WODLmtMIsYB@qVHcA=peCAiP|UmU8Rg3B>%yaP>@O-=I9>sS;_<-
zRO%u~nyr8}i)!Wp*1Mkedz7q)bbHhwbpqD(06t$*`&7U>Xc{nDKg9URe=5Y~UI$c+
zL1GV?6xGJ*kq+UJ;rnj&6r|b0S?PN)9}EL7I7aPN&%$|hjVoY>fNNk<h#)-+SWgI_
z^*gFL4cck?*#lS|o^K+01XK-YK*D!j;LzYP-P~k~rp3JY45hzMHf|5Tq#f{#mWwe+
zPGUhKUQ^-p98Ep?qenvoX(3=$K^a^|Pb5gw%a=Sg-AdNi;8#^!pM!P|5k0XigsA4?
zx<E&AS9-{k&PaLk_j^?%1&Vye7yys7@Q9B?9$oAaF-QfWUlR{f8+cCz(;8YstyJOF
z14f1jQX42sM)VTkOzAZe9gt>EO;!1eAOAlA#_~~G9Ecj9qkTHyK4b!1LN9CRXY!&m
zUt|yedue6EYZOs~l$H8j`==8LlBNkP0SA<<&%olo`ba_Q4zflf#({kSUg_unCw<mb
z^T2T>t5^5yRp1-Xdt5ge{-GtGFystthO*%%u0v;i4kOnVg4_^}(SvbyT`lD)M4^Jj
z81^+wg^6(un5%;`2aG<?zLoVsa4)!7`dVWByW4f$A{|2MYmYOa6TAi1f+xX5PtBFO
ztt0sB;Nf4frtPvd25c_i;7ft5@ip=IJ(x6YpP>N7Ns9U|ZNL1)5&{lEbPxLlkro>y
z8zdVfiw%+ulEnte2FYTBWP@a}*dW;;S)$^(#O}o5VS{9`SZt6imbm#3%_^;L5WLm@
P00000NkvXXu0mjf?8$P)
index 795644794500ac735d1fad19e515ff3d59879929..2d0b9cb505503e1845341222135769c7396ed9e5
GIT binary patch
literal 2086
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
QZ2$lO07*qoM6N<$f{R@tq5uE@
index 5703bfbe90a0f244e9caee6928a33eaa41bfa804..de1df25fc945e8e01a3e06f80a79471f73ff3f70
GIT binary patch
literal 151
zc%17D@N?(olHy`uVBq!ia0vp^HXzK%3?vzhybXb*WQl7;NpOBzNqJ&XDuZK6ep0G}
zXKrG8YEWuoN@d~6RFDp~0G|+7AbsKTwYT26hkz``k|4ie28U-i(tsQ(PZ!4!jq}L~
p2iTstvn~E-FCnAQWmwe2%Es{DS}W^$V?-RtLQhvemvv4FO#t<IDn9@K
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b0eea2e7704d40178a1c399a9128b2023b83e5a1
GIT binary patch
literal 437
zc%17D@N?(olHy`uVBq!ia0vp^QXtI10wkH8TU>z@OS+@4BLl<6e(pbstU$g(vPY0F
z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a><Y92N-!mPySp&_Z|^^|AIQ7l
z>Eak-ar*3JYraDU0xs+>FHe~t*r_5btM1wOL?g9tveI^ijbAi+oQ}+5x||XdvHSJM
zH$Rl$O10Z025aZM-Eq?5=XuxcCr^764izq5>X?&ZxoF|jw!;%_bUQr^mN=+fe5C7X
z;v!_5zC|*<O33hgf~V4j$uBlXX)adMeSdrJ9@CQOw@laeT8k+)I;1T8y(s9zHUonV
zB718>r5PknX}SOHpMQI`MMszN`dxQ!rGGixY`gYr<m7j|vP{a{W4~Njvh&Hwhq=$!
ztJ%JbUHR*s^>JZ|2KPz64Ng%&zp0kEMwFx^mZVxG7o`Fz1|tJQ6I}x{T?69~Lo+J_
sGb=+wT?2C~1B2%5w>~Hua`RI%(<*Um_+%FP0jPn&)78&qol`;+0DtD79smFU
rename from mobile/android/base/resources/drawable-mdpi/close_edit_mode.png
rename to mobile/android/base/resources/drawable-mdpi/close_edit_mode_light.png
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..60ac5531ae19ba9ac65cf64ee185e1fa7c84e683
GIT binary patch
literal 781
zc$@(Z1M>WdP)<h;3K|Lk000e1NJLTq002Y)002G+1^@s6lB&HG0008iNkl<Zc-rmS
zT}V@59LMozl3_WgNRUJ?5DqE`y;&+=1=2+q5d;wg5`@%6kT)W2cu^N23Q|`^L^r(<
z7GaS>%NogwNF|A0Bn_P1HEILVWx3Y(dYpEib2d*t=Q%(4T%K+Gb~rre|2!g>%Q;~K
zcA*&!*a{!STC<uT?!!^U@Duq-;x-y}D5M6XkjWoJ++0XGUcqV(xwViE*vT8W7BUJu
z$)d`Qh0MWjw!5*AsUq$WzZ(m=1v?pb>ocScR<n#oH?KnmVI?QrzA)Q}*O18_U6$@U
zune;t)T0n!8fFRUQb-*#FiV%)3-RMHK0zi+I0gS&FJvF0n6O|TE3lJan8T#S?|g_o
zP89MUswCz>Axh<)SBO`LSBO`LSBO`LSBO`LSBOT1EJBrhfcS@IT*eq?@C9$tkDYFP
zmsv!O!PM>^3MGT%vV~le+&YM306pkO6j?Z(M+iWm8ZRsixLaikX-1)pV{d_LQ*b&z
z@El24$s~L-1EPq*Tr`2RSZ8u=Csay{?8Gd9ChSKLLegfalwK!>%t@${5of0E>SV%+
zLOw#3OgVAJECp5aRJM>1BDjR}Xh$uCi3X^YKAA$U7T8M(qs;VJg!5T|orKI6X66~j
zrZut#89)UD>JhbiHpQ%vE09SF*U^PA;`krgmiPP1a6#fVVg_4e3V8`tvS9KIypJV=
zox&Tam3_HOK$RpQOjII-HnbvObsq8^s^qg11ERDyF<ae2X7L1r7{NEy3dx`p8A5%5
z#oLfhL*_B~B$oI$bt$A1Lc(rc3OOlzj8m6F`XD5<=u*g6R7f1s8`q!^sk@{c&ve_$
z%%TaxKv>tk-Nz6H=5;M34Uwlx_uYSyXFXPQEo2tLKuo1Vexp=rhcM8Hv?_(fQEaAh
z45EM_9u)Zp+;yUmI&`AjqBA&xAcO_gIDpgW#yRwwxQGr^LX^T^54(3tlZ}!V00000
LNkvXXu0mjfb)`;%
index 029fbfd19a16a4d4e395864fc5805cfe9cebd803..6733fa579c8e70cd1185477cfd407dd51c2fc410
GIT binary patch
literal 945
zc$@*T15W&jP)<h;3K|Lk000e1NJLTq002S&002A)1^@s6(tK=L000AcNkl<Zc-rlo
zOGp(_9EZnBiHywbWtosYD2%8qBCwzcB*fGpdqD)QY7z8U*rtMvtSD$vLA0q<N~JQg
zqO3$~(Tkq+F3^Z5D%47`hrfP{S^Sv}&8TzE42&OqAm<KeIN!a_%$?y{0D7g751=zd
z9L=VCXc?{W$#Q$n9NItZA?DLY=%<k`3~Pv)v>oQ?pqXI|aR=skOk=_nBC`wc;sp=K
zgBscfZ!8E?hy!q^l}_oxoawX`?i>hHh?j7usvGl`!JXG(36TnK)OTa<T6kl87(#4<
zclOd0n&@H*ErEBo1RWxtzC-YQq)9=A=u68G9!}G~rb8stYJ`t!n%t8RBWaq8=`@!f
zqRj{|-{=vVN2hpL*GL(n64B+H3~>~}(LsMBI7(%R{RoB{I+PBlXAuksWr*!CPd$xu
zoQ1B!JiBCwjRBnZhf~X8B7G0D6v+^UFv~I-z+oQDvQ~yz3Uky^%f-tu$0`{j3+9;P
zA;b*Y2{Yu#5OZLL>rh{%j#i9cf*Iz?5a}>Ou4A#oXcPTJ$B1#0pVDbEL<;oNMEf`v
zd;C8)Zer+b=x3}9F$ntE<5=h<`bWIpNvAuuDTaQML<p*%nT|znqxb0*+uO9*vCUNI
zC)OFF8T$Av{w=!d2k7I6>V8BM^ifHzZh8Xx_@D~$7<zb0NA)1Y2>J+mc%ce$6aMo+
ze5dG%N%SuK=e8=uMGZR{LM@+6(C}u}szRKCe>BhpYWeIydJX<@MirvM$0Kn(wKO?^
zeuqDtSA^i8KQwC!pyO0urwY*!y%6ey<-G`oc%lmNEP^2#RUsN97~+d6L~{f~w5vk=
zG!$YYjd9yXa|lTv86pnEK!`=OjaJdwG{fO6T24FYVnZPkWQf5ALgdj7c;_cAFc4yt
z43Vli#0vV$aW`ru-7Us;(&h3wsQve9%^}9i5R>5_Ei_SBsCdZx*52<1F}B_wdk*4=
zw$?Fc3;biM43Pn|+_Cq&M2zLzV>e)yOc`P>%<{_KZ!CRCZ_$3@!p<aFGDJ4a(kbp*
z4HVy2htfYVOTG+I0P}38mct?lf_V112Il$UxNsUrTS0<+8omy}@P<yHY4jO_VY3WT
zgy8sP8x&h*h#iP7B{IZ5M3+M{#9>62V=_b;qD!R=QA)o?)RVnGfbIPy@W1{ABuqjK
THd3L@00000NkvXXu0mjfR1vd!
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..202a5b59d415ac8c53e73ec7c14b57cce6046e85
GIT binary patch
literal 1347
zc$@)41-$x+P)<h;3K|Lk000e1NJLTq004{t000~a1^@s6v!+*l000FFNkl<Zc-rln
zZ-`V?7{<r8UD?%?*^F9@p(b4<F_N*OO^M(x6n<C;CXteqXz)|8gj@x)BB+4~A;P)@
zlJu8_>O=Ht%05U%G!_I=m?IVav*Ie$x>?cme0T;PUOM;e$PBx2&kH|>dCoiMoVo9F
z&pr3f6x!`}ATV!oe*gl(FoB#K=5jE_SJel>O<<Giqy+BFdvWt<m@#k~v=J$|lKP|I
z9QEfV|61@J^?$%n-V2;J!)yl{+o>NE?PbXyH~A~`Uf{eLW-U0+;?IFK)Sqw|rW6d*
z6Dpty8vn;V%yr;Fz7{-&xhxo_Cqz7cvCA+QgPXx97~%)+0ToFe09&X}f~C|g7lB*A
zz2I)J&ao-2co=5xN^Wj<aZHC{nCmyp0Ke-Fa38os#>yfh#k?El0dSTHhrubJ@gj@<
ziP66W<JuVu`z5gPE+|RfA>fM*4g*}MVaC9d+(g^>fhH;#il7c`G(lCC?}k0Nj<zaD
zLCm%p>2t=Mpk>ek4bCG0sU6=!y=nT5Ois+4vYAJj<6&F`$0t$8Fgt-S{&eVv&81^j
z+RlLA<$ViWx`2i`<{9rBu8svE(SuH6ewQfgY;?3m(qAeCVS%BkX=o0TO7S{TGvn3d
zSl3BvbEzZv%5m7{GEA{!n62`mzrf=x);^$dge%A+qP;JZcu(}#cxk%?d?fnQ%(aYw
z&rQDrJvPi1-fDjgwsAu}MXeK8=^3sE(oOe<F`6xQLo{6_ie}|X33Z(>HR@uTGPPLe
zVe;ATz9iiyA3i3H>qY-i^i86FM(rA)p=ZesU3KIvR-Tod-`HQFmxdvm!4ji=udA9C
zyN`xZQz$KS{22e4n@HcfYE(7Pt|-P3iR8@NFq<8QDLM2F)-c@MYK$0zX{<4mm@@76
zQ}2gi2EkUYqOb7GowbG$QaNztJ{v|&Q1cmvIa>6lt|E$#YYnkbhM5K$1(UCFgS4#%
zze?L%)cawWb>IXrk!j|dX-{dgYF`Yah4LFl`|{^97K>qa1C7Cq6=uEMejgS67jQ)%
z4fCn!r@?dJAuuO;iMdJ{#4JoIx%FU}3pdOp&=`~a+eQByET_H~NXU<cegixv+Uu@-
zG2q&aJ=R%|VHCSzEcVGTwJuDM*!@pNZn{_uvkaUOeVgPzCHe={ZZx;*FG#-6FxG5u
zJMz^46AmNMFy@lvr@{P)=!&CMyEIJ0x#{&6btYreTU}Ip81k^_Ke4C>z<K%gc#@Z^
zuYkrOP&bTc7-qK_Yl8Zaxx~a^6%C?sgx@<c`m}v;=ee6Hx=g^fro%8T?VD7jjT!@O
zwr`n3*=~Y8o9RVkm_hJH+k}{9kE{Z|m;);^40AR3!(8e{+4d&T*hl?U$5^xSEapeB
zObU>KglA|(W@JTi-A&o2t%(|jkupExYpUiT8VPf2pyeoNQ|CcqYR&l=!aiWMCr^RP
za6<M-!l*-EE&2g7&=PPL?{>bRp<V(Lk~0hv57Um^Ve=sF9q=_c4z8!Z0z3mwf)g^w
z5pWRvEG9b&HiG>$;H`Sb>*IJ^=&ZXbDNu#QP3>yLJ|y(%F=5bvscR0Vs13(lid`6{
zsN?CSjtRMAIaq46Ri2;wBQ2=wZi-a(v&6NBiKN}YkiI-~(7c%V^WCPYb-qvdPwxU?
z4daCo{y-HB6ATjwh6(hZ3e8gM;(1R!7$y+@1Rlr-{{m-MARqu#k+c8+002ovPDHLk
FV1lxwgjWCn
index f210937303a7ba60cc543629938a117ec6c17323..b465addc7e8e6e2dc4e13bf305ac129087c2378b
GIT binary patch
literal 1378
zc$@)Z1)chdP)<h;3K|Lk000e1NJLTq004df001Hg1^@s6nQv_b000FkNkl<Zc-rmT
zZA_JQ9LDkgQKSqMLTrW)EoOo`w-}mpb4+Hd*47&91x=fdO<Xy{<!WU{o38L7v)R-n
zpPHphCQJuy0xw!>O%Mxg5wsYg*ld<!3kZQj-xs{N_uub#pL26)-e;U^`@CV-{$pHl
zpL3scFhfH_F=Nn}{{e()9M<6*e2dpGUg;)a88)K|7ekyq4SCpsbJ!Id-ak&kPKD6B
zfPSmjqntSpZLm`r8{Qw5Lrad;?NoXR!nqkr_k3)4e|Q60Hdx*7m0pr?ZmQC)j}7k+
ztDz;|>Yn#7d_d`5i4E@$lkq$3bl?H2TMH@ErL$wh``-dIImT%~hR~~mlv&ETeX-%A
z!%U=EUyEe;uGsKVE&7Mg#CjY+00v1Yz)_sVX>7$D;lOyjfKpTs_m7|ei7*~4!TYF0
zJ-$OZim?F3MGDqNV1;#F5*A?<N>G9Fdpvvqi?JDHs6!JPP=QUD<2L+bIE<@sW+@7B
z8&djFf`H?Gw+&kUz*8_GWZ?orr52g$V{&Bau+Hm{2D(SXr(hF)MW_UE42jb4sThD2
z4h}CLV2yQ#mTqLgDAu4K;pQJaJ4S|2#x8WjYtA7~y3{veqzQWLm%<405QNwCVd)qc
zejg%9p)`CY+;SJ~9)8<ypbt_Sl{YH>l**1bMK+>d>9k|A<Gkr84dIZ>)uq9Q!%xF)
zmn+{-Xu+V;sgZ_1u9W{m5t4^{6Y+!69mFS&Clr&=rkrUk2O#A*0@k}^WlDDkj0eRo
z&s`S#^fA83`aX{#*Sd@^RQ~9$Ny8r!ioMD=yj8g(JR@{Vg>JX-jJZeX4IouG^AY8@
z`WEgF`;I|>PO=5Yr^CnLN1VZ<F1;Gq>5_)uuN4IwJao4~inEjN_K={s0x8SG7(EH?
zka7tVd^|jcufFb%!cH*K;a?f$;rA$=BQT1Skn$Ex2qz$=2XkS3JG?F)Q;<IF3)s2i
zx8ZA)&Ndjuhmf)t#>FaVDT0ZT;U{4wzC>%7x4>O~8@@^DY=TjgK+5MZirM%ZQfd*1
zlHu3lCagr?@GVN`RT#xPkW#MnC!h{eZea#Y6b%0nMw-rO`HR;duk~|}sC_*vVWMF8
z{4id{Y{O;c+z!7DU+Z>TrPvE8yM=Bp29^Fvn5Y<DfBmEmPa@9xK72p?$4ci@7{zHw
zS#R~Gpi}8yM~V-JZxvs)lk+bg68c{W-DbZH|DyU*tv<wWkg_n$UyvZ4h8gAIPmRLx
z9pVd4axM#9?X!PB`)hdpmAgJ9dwA!q9pfCmmqGN~zEK}uf9ZR^a&Bjs!!LuB1`oqu
z_t)_5uhk#4ZnNTDo)f%o{j);1(rZP+|1|tTNXhYVZZG1j-h7ug&t_WPROQ@3Jm|OK
z)6nH|IeQy#x_oZE*?OJ65n6shZ5U>ZVEA_-r5aBNAG5Ag`a6;3xPryG{Cpabi%b;Y
zDzv=kui=3_48Uu;gpXoHnwAm%#pghXdW*UpZdqi#;T36u*yyj}ffeXQxVecX!a0#<
z%Ls=LpblET7CyCm2U?09-G_0_%g;s`{(1im56ngdg3vO6!<Z_b5qUDa4sQ)q@A8<O
zBwQtKDE*68cP^R{DwmLkL(&z;Is7bSTONlIO!d&6j%<MmLps)BH;$tWdr*Kh7#G<Q
z$dc|Pgx<Um|5p7R_Mr-u*oT)eQRpY45TBtM<=Cm*a^8p4ID_lB>-Y;livq`!!|~XT
ke(aBZu72!ExBs92KkmY%CV#ViI{*Lx07*qoM6N<$f>w5z)c^nh
index 0ef98f83618965f093a6c71827ce85a65bbd62a9..4bf658f8f621313460f8ac883b6e1028d6c604fe
GIT binary patch
literal 136
zc%17D@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dE{+=$5Ar-gYUf#&bpupqm_<g>g
zK#Y1*>kZ9_6$M9M+dZ7Mq@!ZjQ-$ffqJ5SgW?+N?_6_p&x(6=Xa4JB-gX0H&|7Ff8
X4Y0QV*!bEDXf%VTtDnm{r-UW|pG7PF
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a6297a75e1a3050cdaf47de0d4c902f35525d0d1
GIT binary patch
literal 574
zc%17D@N?(olHy`uVBq!ia0vp^#vshW0wgD__^}X3v7|ftIx;Y9?C1WI$O_~uBzpw;
zGB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHrx4R3&|Mvbf`xzJ*
zBRyRlLn02po#ETpY{27YTg;Hr*Kmcm{1k5$hlQy61Dh4A99}J}+T7r1A|O=v#P_xA
zp=aHHoi+&myw!gD{1>MCy&0cvAC^Cx)GexfDB5EVi;|MtnkVa)JU%wHt8G%sd>&3!
zUeWNdlp?J-hwZT$A}<@nMR&#@yL2Ji`=n|dhvSZbOMD-BujwbZUH!wol;abRhfVdw
z5~WLlN!M<u2tPMlS2Fu?8lzy(y%|Sz`zm{xd;a`ul<Fy+XIN!1uRm2S^U1N!wO`|=
zz3!P4s+YF+Z7jF(t+Oig1dq=+Vr+Hd$n1%`Umevczpb>msppZwWQE1nrr(8Uut*jP
z3H!Spo#8q^v@l9-@7=0}JylA<lNC?AwUL~f6LLf2jmgsQZcjx5EH8`rWh{N)d+K`d
zQt^NnIa7X_OkEeevi+McOQ6wgHKwIM-7=$sXW9Pl(Mdah(e8+}&Q9s|U*aER%jeh6
z{lJ}Yx$#^dFvwL)Tq8<S5=&C8l8aJ-6oZk0p^2`6nXZ9xh@qL4fti(|p{{|sm4QKX
h_FEqm4Y~O#nQ4`{HGDD){Q%U!;OXk;vd$@?2>=yD;1vJ>
rename from mobile/android/base/resources/drawable-xhdpi/close_edit_mode.png
rename to mobile/android/base/resources/drawable-xhdpi/close_edit_mode_light.png
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..813ed14fb454c58d344191cd8f6aa434de763824
GIT binary patch
literal 1711
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
FV1fmw0$Bh6
index 25dcfec47dbf0d8c7ca6c2763e0f5f63f52d3ead..f8d201f052552b0135001634a33f026cbc519193
GIT binary patch
literal 1844
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f28a62f53a7f896b9434df91d5fd62f4624468e8
GIT binary patch
literal 2643
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
B%yj?&
index 3b66dd61ff371df1bf2da59b193b7526ab045461..3fabf236a680465186c9a9ce9cf4c83e734d8fee
GIT binary patch
literal 2751
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
FV1k}bR(1dY
index 0fab5b669160c83b16a775ac6a2d9a31a58af32e..811f9658db3dd9b3a6bd89195314ad98d3f90bde
GIT binary patch
literal 156
zc%17D@N?(olHy`uVBq!ia0vp^0U*rC3?#SQPk0BUBuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrH1%u?6^qxB}@5m#@9`&OHQVF_r}R1v5B2yO9Ru$a}gthG?8m
xPEcUmU@wt+X}acrd9Jz%r)79gHYPn{X4s=zyq%%Dd?!#TgQu&X%Q~loCIAmmFLM9@
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ef989768432535edad0d10a7a64bf37133cc6c59
GIT binary patch
literal 2642
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f518916e814a9e3c9ec9441036c8cb89fc529775
GIT binary patch
literal 2915
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
I27fx?zjaDoZ2$lO
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..acb641a950b5e4a64bcc61ed658da2601e617bc8
GIT binary patch
literal 4012
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
NfR%-<c?B9D`#*a~VVwW~
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7143b9361fab6bd8ab7c55b8a10989945f14512f
GIT binary patch
literal 4308
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
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/drawable/close_edit_mode_selector.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:gecko="http://schemas.android.com/apk/res-auto">
+
+    <item gecko:state_dark="true"
+          android:drawable="@drawable/close_edit_mode_dark"/>
+
+    <item android:drawable="@drawable/close_edit_mode_light"/>
+
+</selector>
--- a/mobile/android/base/resources/layout-large-v11/browser_toolbar.xml
+++ b/mobile/android/base/resources/layout-large-v11/browser_toolbar.xml
@@ -104,18 +104,19 @@
                android:layout_width="fill_parent"
                android:layout_height="2dp"
                android:layout_alignParentBottom="true"
                android:background="@color/url_bar_shadow"
                android:contentDescription="@null"/>
 
     <!-- We draw after the menu items so when they are hidden, the cancel button,
          which is thus drawn on top, may be pressed. -->
-    <ImageView android:id="@+id/edit_cancel"
-               style="@style/UrlBar.ImageButton.Icon"
-               android:layout_alignParentRight="true"
-               android:src="@drawable/close_edit_mode"
-               android:paddingLeft="2dp"
-               android:paddingRight="2dp"
-               android:contentDescription="@string/edit_mode_cancel"
-               android:visibility="gone"/>
+    <org.mozilla.gecko.widget.ThemedImageView
+            android:id="@+id/edit_cancel"
+            style="@style/UrlBar.ImageButton.Icon"
+            android:layout_alignParentRight="true"
+            android:src="@drawable/close_edit_mode_selector"
+            android:paddingLeft="2dp"
+            android:paddingRight="2dp"
+            android:contentDescription="@string/edit_mode_cancel"
+            android:visibility="gone"/>
 
 </merge>
--- a/mobile/android/base/resources/layout/browser_toolbar.xml
+++ b/mobile/android/base/resources/layout/browser_toolbar.xml
@@ -92,24 +92,25 @@
                         android:layout_height="24dip"
                         android:layout_marginLeft="40dip"
                         android:layout_marginRight="8dip"
                         android:layout_marginTop="12dip"
                         android:layout_alignRight="@id/tabs"/>
 
     <!-- Note that the edit components are invisible so that the views
          depending on their location can properly layout. -->
-    <ImageView android:id="@+id/edit_cancel"
-               style="@style/UrlBar.ImageButton.Icon"
-               android:layout_alignParentRight="true"
-               android:src="@drawable/close_edit_mode"
-               android:paddingLeft="2dp"
-               android:paddingRight="2dp"
-               android:contentDescription="@string/edit_mode_cancel"
-               android:visibility="invisible"/>
+    <org.mozilla.gecko.widget.ThemedImageView
+            android:id="@+id/edit_cancel"
+            style="@style/UrlBar.ImageButton.Icon"
+            android:layout_alignParentRight="true"
+            android:src="@drawable/close_edit_mode_selector"
+            android:paddingLeft="2dp"
+            android:paddingRight="2dp"
+            android:contentDescription="@string/edit_mode_cancel"
+            android:visibility="invisible"/>
 
     <!-- The space to the left of the cancel button would be larger than the right because
          the url bar drawable contains some whitespace, so we compensate by removing
          some padding from the right (value determined through experimentation). -->
     <org.mozilla.gecko.toolbar.ToolbarEditLayout android:id="@+id/edit_layout"
                   style="@style/UrlBar.Button"
                   android:layout_toLeftOf="@id/edit_cancel"
                   android:paddingLeft="12dp"
--- a/mobile/android/base/toolbar/BrowserToolbar.java
+++ b/mobile/android/base/toolbar/BrowserToolbar.java
@@ -136,17 +136,17 @@ public class BrowserToolbar extends Them
     private ToolbarProgressView progressBar;
     private TabCounter tabsCounter;
     private ThemedImageButton menuButton;
     private ThemedImageView menuIcon;
     private LinearLayout actionItemBar;
     private MenuPopup menuPopup;
     private List<View> focusOrder;
 
-    private final ImageView editCancel;
+    private final ThemedImageView editCancel;
 
     private final View[] tabletDisplayModeViews;
     private boolean hidForwardButtonOnStartEditing = false;
 
     private boolean shouldShrinkURLBar = false;
 
     private OnActivateListener activateListener;
     private OnFocusChangeListener focusChangeListener;
@@ -229,17 +229,17 @@ public class BrowserToolbar extends Them
         forwardButton = (ImageButton) findViewById(R.id.forward);
         setButtonEnabled(forwardButton, false);
 
         menuButton = (ThemedImageButton) findViewById(R.id.menu);
         menuIcon = (ThemedImageView) findViewById(R.id.menu_icon);
         actionItemBar = (LinearLayout) findViewById(R.id.menu_items);
         hasSoftMenuButton = !HardwareUtils.hasMenuButton();
 
-        editCancel = (ImageView) findViewById(R.id.edit_cancel);
+        editCancel = (ThemedImageView) findViewById(R.id.edit_cancel);
 
         // We use different layouts on phones and tablets, so adjust the focus
         // order appropriately.
         focusOrder = new ArrayList<View>();
         if (HardwareUtils.isTablet()) {
             focusOrder.addAll(Arrays.asList(tabsButton, backButton, forwardButton, this));
             focusOrder.addAll(urlDisplayLayout.getFocusOrder());
             focusOrder.addAll(Arrays.asList(actionItemBar, menuButton));
@@ -1450,15 +1450,18 @@ public class BrowserToolbar extends Them
         if (drawable == null)
             return;
 
         StateListDrawable stateList = new StateListDrawable();
         stateList.addState(PRIVATE_STATE_SET, getColorDrawable(R.color.background_private));
         stateList.addState(EMPTY_STATE_SET, drawable);
 
         setBackgroundDrawable(stateList);
+
+        editCancel.onLightweightThemeChanged();
     }
 
     @Override
     public void onLightweightThemeReset() {
         setBackgroundResource(R.drawable.url_bar_bg);
+        editCancel.onLightweightThemeReset();
     }
 }
--- a/mobile/android/base/webapp/EventListener.java
+++ b/mobile/android/base/webapp/EventListener.java
@@ -178,17 +178,17 @@ public class EventListener implements Na
                 if (proc.processName.equals(targetProcessName)) {
                     android.os.Process.killProcess(proc.pid);
                     break;
                 }
             }
         }
     }
 
-    public static void installApk(final Activity context, NativeJSObject message, EventCallback callback) {
+    public static void installApk(final Activity context, NativeJSObject message, final EventCallback callback) {
         final JSONObject messageData;
 
         // We get the manifest url out of javascript here so we can use it as a checksum
         // in a minute, when a package has been installed.
         String manifestUrl = null;
         String filePath = null;
 
         try {
@@ -232,16 +232,17 @@ public class EventListener implements Na
                         receiver.cleanup();
                     } catch (java.lang.IllegalArgumentException e) {
                         // IllegalArgumentException happens because resultCode is RESULT_CANCELED
                         // when the user presses the Done button in the install confirmation dialog,
                         // even though the install has been successful (and InstallListener already
                         // unregistered the receiver).
                         Log.e(LOGTAG, "error unregistering install receiver: ", e);
                     }
+                    callback.sendError("APK installation cancelled by user");
                 }
             }
         });
     }
 
     private static final int DEFAULT_VERSION_CODE = -1;
 
     public static JSONObject getApkVersions(Activity context, String[] packageNames) {
--- a/mobile/android/base/widget/ActivityChooserModel.java
+++ b/mobile/android/base/widget/ActivityChooserModel.java
@@ -1043,45 +1043,57 @@ public class ActivityChooserModel extend
             }
         }
     }
 
     /**
      * Command for reading the historical records from a file off the UI thread.
      */
     private void readHistoricalDataImpl() {
-        FileInputStream fis = null;
         try {
             GeckoProfile profile = GeckoProfile.get(mContext);
             File f = profile.getFile(mHistoryFileName);
             if (!f.exists()) {
                 // Fall back to the non-profile aware file if it exists...
                 File oldFile = new File(mHistoryFileName);
                 oldFile.renameTo(f);
             }
-            fis = new FileInputStream(f);
+            readHistoricalDataFromStream(new FileInputStream(f));
         } catch (FileNotFoundException fnfe) {
-            try {
-                Distribution dist = new Distribution(mContext);
-                File distFile = dist.getDistributionFile("quickshare/" + mHistoryFileName);
-                if (distFile == null) {
-                    if (DEBUG) {
-                        Log.i(LOG_TAG, "Could not open historical records file: " + mHistoryFileName);
+            final Distribution dist = Distribution.getInstance(mContext);
+            dist.addOnDistributionReadyCallback(new Runnable() {
+                @Override
+                public void run() {
+                    Log.d(LOGTAG, "Running post-distribution task: quickshare.");
+
+                    if (!dist.exists()) {
+                        return;
                     }
-                    return;
+
+                    try {
+                        File distFile = dist.getDistributionFile("quickshare/" + mHistoryFileName);
+                        if (distFile == null) {
+                            if (DEBUG) {
+                                Log.i(LOG_TAG, "Could not open historical records file: " + mHistoryFileName);
+                            }
+                            return;
+                        }
+                        readHistoricalDataFromStream(new FileInputStream(distFile));
+                    } catch (Exception ex) {
+                        if (DEBUG) {
+                            Log.i(LOG_TAG, "Could not open historical records file: " + mHistoryFileName);
+                        }
+                        return;
+                    }
                 }
-                fis = new FileInputStream(distFile);
-            } catch(Exception ex) {
-                if (DEBUG) {
-                    Log.i(LOG_TAG, "Could not open historical records file: " + mHistoryFileName);
-                }
-                return;
-            }
+            });
         }
+    }
 
+    private void readHistoricalDataFromStream(FileInputStream fis) {
         try {
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(fis, null);
 
             int type = XmlPullParser.START_DOCUMENT;
             while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
                 type = parser.next();
             }
@@ -1119,19 +1131,19 @@ public class ActivityChooserModel extend
                     Log.i(LOG_TAG, "Read " + readRecord.toString());
                 }
             }
 
             if (DEBUG) {
                 Log.i(LOG_TAG, "Read " + historicalRecords.size() + " historical records.");
             }
         } catch (XmlPullParserException xppe) {
-            Log.e(LOG_TAG, "Error reading historical recrod file: " + mHistoryFileName, xppe);
+            Log.e(LOG_TAG, "Error reading historical record file: " + mHistoryFileName, xppe);
         } catch (IOException ioe) {
-            Log.e(LOG_TAG, "Error reading historical recrod file: " + mHistoryFileName, ioe);
+            Log.e(LOG_TAG, "Error reading historical record file: " + mHistoryFileName, ioe);
         } finally {
             if (fis != null) {
                 try {
                     fis.close();
                 } catch (IOException ioe) {
                     /* ignore */
                 }
             }
@@ -1184,21 +1196,21 @@ public class ActivityChooserModel extend
 
                 serializer.endTag(null, TAG_HISTORICAL_RECORDS);
                 serializer.endDocument();
 
                 if (DEBUG) {
                     Log.i(LOG_TAG, "Wrote " + recordCount + " historical records.");
                 }
             } catch (IllegalArgumentException iae) {
-                Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, iae);
+                Log.e(LOG_TAG, "Error writing historical record file: " + mHistoryFileName, iae);
             } catch (IllegalStateException ise) {
-                Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, ise);
+                Log.e(LOG_TAG, "Error writing historical record file: " + mHistoryFileName, ise);
             } catch (IOException ioe) {
-                Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, ioe);
+                Log.e(LOG_TAG, "Error writing historical record file: " + mHistoryFileName, ioe);
             } finally {
                 mCanReadHistoricalData = true;
                 if (fos != null) {
                     try {
                         fos.close();
                     } catch (IOException e) {
                         /* ignore */
                     }
--- a/mobile/android/modules/WebappManager.jsm
+++ b/mobile/android/modules/WebappManager.jsm
@@ -495,16 +495,22 @@ this.WebappManager = {
           app: apk.app,
           // TODO: figure out why Webapps:InstallApk needs the "from" property.
           from: apk.app.installOrigin,
         };
         sendMessageToJava({
           type: "Webapps:InstallApk",
           filePath: apk.filePath,
           data: msg,
+        }, (data, error) => {
+          if (!!error) {
+            // There's no page to report back to so drop the error.
+            // TODO: we should notify the user about this failure.
+            debug("APK install failed : " + returnError);
+          }
         });
       }
     } else {
       // The user cancelled the notification, so remove the downloaded APKs.
       for (let apk of downloadedApks) {
         try {
           yield OS.file.remove(apk.filePath);
         } catch(ex) {
--- a/mobile/locales/en-US/chrome/region.properties
+++ b/mobile/locales/en-US/chrome/region.properties
@@ -36,16 +36,26 @@ browser.contentHandlers.types.0.uri=http
 # Values for these keys must correspond to the name used in the keys that
 # define each suggested website's details. For example:
 # browser.suggestedsites.list.0=NAME
 # browser.suggestedsites.NAME.title=Displayed name
 # browser.suggestedsites.NAME.url=Website URL
 # browser.suggestedsites.NAME.bgcolor= Color (hex format)
 browser.suggestedsites.list.0=mozilla
 browser.suggestedsites.list.1=fxmarketplace
+browser.suggestedsites.list.2=fxaddons
+browser.suggestedsites.list.3=fxsupport
 
-browser.suggestedsites.mozilla.title=Mozilla
+browser.suggestedsites.mozilla.title=The Mozilla Project
 browser.suggestedsites.mozilla.url=https://www.mozilla.org/en-US/
-browser.suggestedsites.mozilla.bgcolor=#c13832
+browser.suggestedsites.mozilla.bgcolor=#ce4e41
 
 browser.suggestedsites.fxmarketplace.title=Firefox Marketplace
 browser.suggestedsites.fxmarketplace.url=https://marketplace.firefox.com/
-browser.suggestedsites.fxmarketplace.bgcolor=#0095dd
\ No newline at end of file
+browser.suggestedsites.fxmarketplace.bgcolor=#0096dd
+
+browser.suggestedsites.fxaddons.title=Add-ons: Customize Firefox
+browser.suggestedsites.fxaddons.url=https://addons.mozilla.org/en-US/android/
+browser.suggestedsites.fxaddons.bgcolor=#62be06
+
+browser.suggestedsites.fxsupport.title=Firefox Help and Support
+browser.suggestedsites.fxsupport.url=https://support.mozilla.org/en-US/products/mobile
+browser.suggestedsites.fxsupport.bgcolor=#f37c00
--- a/services/healthreport/docs/dataformat.rst
+++ b/services/healthreport/docs/dataformat.rst
@@ -1559,23 +1559,32 @@ properties:
 translationOpportunityCountsByLanguage
     A mapping from language to count of opportunities to translate that
     language.
 pageTranslatedCountsByLanguage
     A mapping from language to the counts of pages translated from that
     language. Each language entry will be an object containing a "total" member
     along with individual counts for each language translated to.
 
+Other properties:
+
+detectLanguageEnabled
+    Whether automatic language detection is enabled. This is an integer, 0 or 1.
+showTranslationUI
+    Whether the translation feature UI will be shown. This is an integer, 0 or 1.
+
 Example
 ^^^^^^^
 
 ::
 
     "org.mozilla.translation.translation": {
       "_v": 1,
+      "detectLanguageEnabled": 1,
+      "showTranslationUI": 1,
       "translationOpportunityCount": 134,
       "pageTranslatedCount": 6,
       "charactersTranslatedCount": "1126",
       "detectedLanguageChangedBefore": 1,
       "detectedLanguageChangedAfter": 2,
       "translationOpportunityCountsByLanguage": {
         "fr": 100,
         "es": 34
--- a/toolkit/components/passwordmgr/LoginImport.jsm
+++ b/toolkit/components/passwordmgr/LoginImport.jsm
@@ -160,20 +160,17 @@ this.LoginImport.prototype = {
       }
 
       rows = yield connection.execute("SELECT * FROM moz_disabledHosts");
       for (let row of rows) {
         try {
           let id = row.getResultByName("id");
           let hostname = row.getResultByName("hostname");
 
-          this.store.data.disabledHosts.push({
-            id: this.store.data.nextId++,
-            hostname: hostname,
-          });
+          this.store.data.disabledHosts.push(hostname);
         } catch (ex) {
           Cu.reportError("Error importing disabled host: " + ex);
         }
       }
     } finally {
       yield connection.close();
     }
   }),
--- a/toolkit/components/passwordmgr/LoginStore.jsm
+++ b/toolkit/components/passwordmgr/LoginStore.jsm
@@ -262,16 +262,41 @@ LoginStore.prototype = {
     }
     if (!this.data.disabledHosts) {
       this.data.disabledHosts = [];
     }
 
     // Indicate that the current version of the code has touched the file.
     this.data.version = kDataVersion;
 
+    // Due to bug 1019885, invalid data was created by the import process in
+    // Nightly.  This automated procedure fixes the error.  This is provided as
+    // a convenience to Nightly users and can be safely removed after Nightly
+    // users are updated to the new version.
+    let originalDisabledHosts = this.data.disabledHosts;
+    if (originalDisabledHosts.some(hostItem => typeof hostItem != "string")) {
+
+      this.data.disabledHosts = [];
+
+      for (let hostItem of originalDisabledHosts) {
+        // Fix each item if it is in the broken format.
+        if (typeof hostItem != "string") {
+          hostItem = hostItem.hostname;
+        }
+
+        // Ensure we don't create duplicates in the process.
+        if (this.data.disabledHosts.indexOf(hostItem) == -1) {
+          this.data.disabledHosts.push(hostItem);
+        }
+      }
+
+      // Ensure the updated data is saved.
+      this.saveSoon();
+    }
+
     this.dataReady = true;
   },
 
   /**
    * Called when the data changed, this triggers asynchronous serialization.
    */
   saveSoon: function () this._saver.arm(),
 
--- a/toolkit/components/passwordmgr/test/unit/test_module_LoginImport.js
+++ b/toolkit/components/passwordmgr/test/unit/test_module_LoginImport.js
@@ -165,20 +165,18 @@ add_task(function test_import()
              loginDataItem.timeLastUsed == loginInfo.timeLastUsed &&
              loginDataItem.timePasswordChanged == loginInfo.timePasswordChanged &&
              loginDataItem.timesUsed == loginInfo.timesUsed;
     });
   }));
 
   // Verify that disabled hosts have been imported.
   do_check_eq(store.data.disabledHosts.length, 2);
-  do_check_true(store.data.disabledHosts.some(
-                dataItem => dataItem.hostname == "http://www.example.com"));
-  do_check_true(store.data.disabledHosts.some(
-                dataItem => dataItem.hostname == "https://www.example.org"));
+  do_check_true(store.data.disabledHosts.indexOf("http://www.example.com") != -1);
+  do_check_true(store.data.disabledHosts.indexOf("https://www.example.org") != -1);
 });
 
 /**
  * Tests imports of NULL values due to a downgraded database.
  */
 add_task(function test_import_downgraded()
 {
   let store = new LoginStore(getTempFile("test-import-downgraded.json").path);
--- a/toolkit/content/tests/browser/browser_bug295977_autoscroll_overflow.js
+++ b/toolkit/content/tests/browser/browser_bug295977_autoscroll_overflow.js
@@ -4,44 +4,44 @@ function test()
   Services.prefs.setBoolPref(kPrefName_AutoScroll, true);
 
   const expectScrollNone = 0;
   const expectScrollVert = 1;
   const expectScrollHori = 2;
   const expectScrollBoth = 3;
 
   var allTests = [
-    {dataUri: 'data:text/html,<body><style type="text/css">div { display: inline-block; }</style>\
+    {dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><body><style type="text/css">div { display: inline-block; }</style>\
       <div id="a" style="width: 100px; height: 100px; overflow: hidden;"><div style="width: 200px; height: 200px;"></div></div>\
       <div id="b" style="width: 100px; height: 100px; overflow: auto;"><div style="width: 200px; height: 200px;"></div></div>\
       <div id="c" style="width: 100px; height: 100px; overflow-x: auto; overflow-y: hidden;"><div style="width: 200px; height: 200px;"></div></div>\
       <div id="d" style="width: 100px; height: 100px; overflow-y: auto; overflow-x: hidden;"><div style="width: 200px; height: 200px;"></div></div>\
       <select id="e" style="width: 100px; height: 100px;" multiple="multiple"><option>aaaaaaaaaaaaaaaaaaaaaaaa</option><option>a</option><option>a</option>\
       <option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option>\
       <option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option></select>\
       <select id="f" style="width: 100px; height: 100px;"><option>a</option><option>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</option><option>a</option>\
       <option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option>\
       <option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option></select>\
       <div id="g" style="width: 99px; height: 99px; border: 10px solid black; margin: 10px; overflow: auto;"><div style="width: 100px; height: 100px;"></div></div>\
       <div id="h" style="width: 100px; height: 100px; overflow: -moz-hidden-unscrollable;"><div style="width: 200px; height: 200px;"></div></div>\
       <iframe id="iframe" style="display: none;"></iframe>\
-      </body>'},
+      </body></html>'},
     {elem: 'a', expected: expectScrollNone},
     {elem: 'b', expected: expectScrollBoth},
     {elem: 'c', expected: expectScrollHori},
     {elem: 'd', expected: expectScrollVert},
     {elem: 'e', expected: expectScrollVert},
     {elem: 'f', expected: expectScrollNone},
     {elem: 'g', expected: expectScrollBoth},
     {elem: 'h', expected: expectScrollNone},
-    {dataUri: 'data:text/html,<html><body id="i" style="overflow-y: scroll"><div style="height: 2000px"></div>\
+    {dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><body id="i" style="overflow-y: scroll"><div style="height: 2000px"></div>\
       <iframe id="iframe" style="display: none;"></iframe>\
       </body></html>'},
     {elem: 'i', expected: expectScrollVert}, // bug 695121
-    {dataUri: 'data:text/html,<html><style>html, body { width: 100%; height: 100%; overflow-x: hidden; overflow-y: scroll; }</style>\
+    {dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><style>html, body { width: 100%; height: 100%; overflow-x: hidden; overflow-y: scroll; }</style>\
       <body id="j"><div style="height: 2000px"></div>\
       <iframe id="iframe" style="display: none;"></iframe>\
       </body></html>'},
     {elem: 'j', expected: expectScrollVert}  // bug 914251
   ];
 
   var doc;
 
@@ -53,24 +53,45 @@ function test()
     }
 
     if (test.dataUri) {
       startLoad(test.dataUri);
       return;
     }
 
     var elem = doc.getElementById(test.elem);
-    // Skip the first callback as it's the same callback that the browser
-    // uses to kick off the scrolling.
-    var skipFrames = 1;
-    var checkScroll = function () {
-      if (skipFrames--) {
+
+    let firstTimestamp = undefined;
+    function checkScroll(timestamp) {
+      if (firstTimestamp === undefined) {
+        firstTimestamp = timestamp;
+      }
+
+      // This value is calculated similarly to the value of the same name in
+      // ClickEventHandler.autoscrollLoop, except here it's cumulative across
+      // all frames after the first one instead of being based only on the
+      // current frame.
+      let timeCompensation = (timestamp - firstTimestamp) / 20;
+      info("timestamp=" + timestamp + " firstTimestamp=" + firstTimestamp +
+           " timeCompensation=" + timeCompensation);
+
+      // Try to wait until enough time has passed to allow the scroll to happen.
+      // autoscrollLoop incrementally scrolls during each animation frame, but
+      // due to how its calculations work, when a frame is very close to the
+      // previous frame, no scrolling may actually occur during that frame.
+      // After 20ms's worth of frames, timeCompensation will be 1, making it
+      // more likely that the accumulated scroll in autoscrollLoop will be >= 1,
+      // although it also depends on acceleration, which here in this test
+      // should be > 1 due to how it synthesizes mouse events below.
+      if (timeCompensation < 1) {
         window.mozRequestAnimationFrame(checkScroll);
         return;
       }
+
+      // Close the autoscroll popup by synthesizing Esc.
       EventUtils.synthesizeKey("VK_ESCAPE", {}, gBrowser.contentWindow);
       var scrollVert = test.expected & expectScrollVert;
       ok((scrollVert && elem.scrollTop > 0) ||
          (!scrollVert && elem.scrollTop == 0),
          test.elem+' should'+(scrollVert ? '' : ' not')+' have scrolled vertically');
       var scrollHori = test.expected & expectScrollHori;
       ok((scrollHori && elem.scrollLeft > 0) ||
          (!scrollHori && elem.scrollLeft == 0),
@@ -78,30 +99,29 @@ function test()
 
       // Before continuing the test, we need to ensure that the IPC
       // message that stops autoscrolling has had time to arrive.
       executeSoon(nextTest);
     };
     EventUtils.synthesizeMouse(elem, 50, 50, { button: 1 },
                                gBrowser.contentWindow);
 
+    // This ensures bug 605127 is fixed: pagehide in an unrelated document
+    // should not cancel the autoscroll.
     var iframe = gBrowser.contentDocument.getElementById("iframe");
     var e = iframe.contentDocument.createEvent("pagetransition");
     e.initPageTransitionEvent("pagehide", true, true, false);
     iframe.contentDocument.dispatchEvent(e);
     iframe.contentDocument.documentElement.dispatchEvent(e);
 
     EventUtils.synthesizeMouse(elem, 100, 100,
                                { type: "mousemove", clickCount: "0" },
                                gBrowser.contentWindow);
-    /*
-     * if scrolling didn’t work, we wouldn’t do any redraws and thus time out.
-     * so request and force redraws to get the chance to check for scrolling at
-     * all.
-     */
+
+    // Start checking for the scroll.
     window.mozRequestAnimationFrame(checkScroll);
   }
 
   waitForExplicitFinish();
 
   nextTest();
 
   function startLoad(dataUri) {
--- a/toolkit/devtools/pretty-fast/pretty-fast.js
+++ b/toolkit/devtools/pretty-fast/pretty-fast.js
@@ -1,8 +1,9 @@
+/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2; fill-column: 80 -*- */
 /*
  * Copyright 2013 Mozilla Foundation and contributors
  * Licensed under the New BSD license. See LICENSE.md or:
  * http://opensource.org/licenses/BSD-2-Clause
  */
 (function (root, factory) {
   if (typeof define === 'function' && define.amd) {
     define(factory);
@@ -319,33 +320,34 @@
         return true;
       }
       if (ltt == ";") {
         return true;
       }
 
       var ltk = lastToken.type.keyword;
       if (ltk != null) {
-        if (ltk == "break" || ltk == "continue") {
+        if (ltk == "break" || ltk == "continue" || ltk == "return") {
           return token.type.type != ";";
         }
         if (ltk != "debugger"
             && ltk != "null"
             && ltk != "true"
             && ltk != "false"
             && ltk != "this"
             && ltk != "default") {
           return true;
         }
       }
 
       if (ltt == ")" && (token.type.type != ")"
                          && token.type.type != "]"
                          && token.type.type != ";"
-                         && token.type.type != ",")) {
+                         && token.type.type != ","
+                         && token.type.type != ".")) {
         return true;
       }
     }
 
     if (token.type.isAssign) {
       return true;
     }
     if (token.type.binop != null) {
@@ -552,16 +554,17 @@
   function belongsOnStack(token) {
     var ttt = token.type.type;
     var ttk = token.type.keyword;
     return ttt == "{"
       || ttt == "("
       || ttt == "["
       || ttt == "?"
       || ttk == "do"
+      || ttk == "switch"
       || ttk == "case"
       || ttk == "default";
   }
 
   /**
    * Returns true if the given token should cause us to pop the stack.
    */
   function shouldStackPop(token, stack) {
@@ -584,17 +587,19 @@
       || (tokenType == "]" && stack[stack.length - 1] == "[\n")
   }
 
   /**
    * Returns true if the given token should cause us to increment the indent
    * level.
    */
   function incrementsIndent(token) {
-    return token.type.type == "{" || token.isArrayLiteral;
+    return token.type.type == "{"
+      || token.isArrayLiteral
+      || token.type.keyword == "switch";
   }
 
   /**
    * Add a comment to the pretty printed code.
    *
    * @param Function write
    *        The function to write pretty printed code to the result SourceNode.
    * @param Number indentLevel
@@ -719,16 +724,17 @@
     // Strings that go on the stack:
     //
     //   - "{"
     //   - "("
     //   - "["
     //   - "[\n"
     //   - "do"
     //   - "?"
+    //   - "switch"
     //   - "case"
     //   - "default"
     //
     // The difference between "[" and "[\n" is that "[\n" is used when we are
     // treating "[" and "]" tokens as line delimiters and should increment and
     // decrement the indent level when we find them.
     var stack = [];
 
@@ -751,17 +757,18 @@
       locations: true,
       sourceFile: options.url,
       onComment: function (block, text, start, end, startLoc, endLoc) {
         if (lastToken) {
           commentQueue.push({
             block: block,
             text: text,
             line: startLoc.line,
-            column: startLoc.column
+            column: startLoc.column,
+            trailing: lastToken.endLoc.line == startLoc.line
           });
         } else {
           addComment(write, indentLevel, options, block, text, startLoc.line,
                      startLoc.column);
           addedNewline = true;
         }
       }
     });
@@ -786,25 +793,36 @@
           stack.push("[\n");
         } else {
           stack.push(ttt || ttk);
         }
       }
 
       if (decrementsIndent(ttt, stack)) {
         indentLevel--;
+        if (ttt == "}"
+            && stack.length > 1
+            && stack[stack.length - 2] == "switch") {
+          indentLevel--;
+        }
       }
 
       prependWhiteSpace(token, lastToken, addedNewline, write, options,
                         indentLevel, stack);
       addToken(token, write, options);
-      addedNewline = appendNewline(token, write, stack);
+      if (commentQueue.length == 0 || !commentQueue[0].trailing) {
+        addedNewline = appendNewline(token, write, stack);
+      }
 
       if (shouldStackPop(token, stack)) {
         stack.pop();
+        if (token == "}" && stack.length
+            && stack[stack.length - 1] == "switch") {
+          stack.pop();
+        }
       }
 
       if (incrementsIndent(token)) {
         indentLevel++;
       }
 
       // Acorn's tokenizer re-uses tokens, so we have to copy the last token on
       // every iteration. We follow acorn's lead here, and reuse the lastToken
@@ -820,23 +838,27 @@
       lastToken.endLoc.line = token.endLoc.line;
       lastToken.endLoc.column = token.endLoc.column;
       lastToken.type = token.type;
       lastToken.value = token.value;
       lastToken.isArrayLiteral = token.isArrayLiteral;
 
       // Apply all the comments that have been queued up.
       if (commentQueue.length) {
-        if (!addedNewline) {
+        if (!addedNewline && !commentQueue[0].trailing) {
           write("\n");
         }
+        if (commentQueue[0].trailing) {
+          write(" ");
+        }
         for (var i = 0, n = commentQueue.length; i < n; i++) {
           var comment = commentQueue[i];
-          addComment(write, indentLevel, options, comment.block, comment.text,
-                     comment.line, comment.column);
+          var commentIndentLevel = commentQueue[i].trailing ? 0 : indentLevel;
+          addComment(write, commentIndentLevel, options, comment.block,
+                     comment.text, comment.line, comment.column);
         }
         addedNewline = true;
         commentQueue.splice(0, commentQueue.length);
       }
     }
 
     return result.toStringWithSourceMap({ file: options.url });
   };
--- a/toolkit/devtools/pretty-fast/tests/unit/test.js
+++ b/toolkit/devtools/pretty-fast/tests/unit/test.js
@@ -1,8 +1,12 @@
+/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2; fill-column: 80 -*- */
+
+"use strict";
+
 /*
  * Copyright 2013 Mozilla Foundation and contributors
  * Licensed under the New BSD license. See LICENSE.md or:
  * http://opensource.org/licenses/BSD-2-Clause
  */
 var prettyFast = this.prettyFast || require("./pretty-fast");
 
 var testCases = [
@@ -341,21 +345,21 @@ var testCases = [
     input: "bar?baz:bang;",
     output: "bar ? baz : bang;\n"
   },
 
   {
     name: "Switch statements",
     input: "switch(x){case a:foo();break;default:bar()}",
     output: "switch (x) {\n" +
-            "case a:\n" +
-            "  foo();\n" +
-            "  break;\n" +
-            "default:\n" +
-            "  bar()\n" +
+            "  case a:\n" +
+            "    foo();\n" +
+            "    break;\n" +
+            "  default:\n" +
+            "    bar()\n" +
             "}\n"
   },
 
   {
     name: "Multiple single line comments",
     input: "function f() {\n" +
            "  // a\n" +
            "  // b\n" +
@@ -476,16 +480,54 @@ var testCases = [
   },
 
   {
     name: "Escaping null character in strings",
     input: "'\\0'\n",
     output: "'\\0'\n"
   },
 
+  {
+    name: "Bug 977082 - space between grouping operator and dot notation",
+    input: "JSON.stringify(3).length;\n" +
+           "([1,2,3]).length;\n" +
+           "(new Date()).toLocaleString();\n",
+    output: "JSON.stringify(3).length;\n" +
+            "([1,\n" +
+            "2,\n" +
+            "3]).length;\n" +
+            "(new Date()).toLocaleString();\n"
+  },
+
+  {
+    name: "Bug 975477 don't move end of line comments to next line",
+    input: "switch (request.action) {\n" +
+           "  case 'show': //$NON-NLS-0$\n" +
+           "    if (localStorage.hideicon !== 'true') { //$NON-NLS-0$\n" +
+           "      chrome.pageAction.show(sender.tab.id);\n" +
+           "    }\n" +
+           "    break;\n" +
+           "  default:\n" +
+           "    console.warn('unknown request'); //$NON-NLS-0$\n" +
+           "    // don't respond if you don't understand the message.\n" +
+           "    return;\n" +
+           "}\n",
+    output: "switch (request.action) {\n" +
+            "  case 'show': //$NON-NLS-0$\n" +
+            "    if (localStorage.hideicon !== 'true') { //$NON-NLS-0$\n" +
+            "      chrome.pageAction.show(sender.tab.id);\n" +
+            "    }\n" +
+            "    break;\n" +
+            "  default:\n" +
+            "    console.warn('unknown request'); //$NON-NLS-0$\n" +
+            "    // don't respond if you don't understand the message.\n" +
+            "    return;\n" +
+            "}\n"
+  }
+
 ];
 
 var sourceMap = this.sourceMap || require("source-map");
 
 function run_test() {
   testCases.forEach(function (test) {
     console.log(test.name);
 
--- a/toolkit/devtools/server/actors/inspector.js
+++ b/toolkit/devtools/server/actors/inspector.js
@@ -57,16 +57,18 @@ const {Arg, Option, method, RetVal, type
 const {LongStringActor, ShortLongString} = require("devtools/server/actors/string");
 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 const object = require("sdk/util/object");
 const events = require("sdk/event/core");
 const {Unknown} = require("sdk/platform/xpcom");
 const {Class} = require("sdk/core/heritage");
 const {PageStyleActor} = require("devtools/server/actors/styles");
 const {HighlighterActor} = require("devtools/server/actors/highlighter");
+const {getLayoutChangesObserver, releaseLayoutChangesObserver} =
+  require("devtools/server/actors/layout");
 
 const FONT_FAMILY_PREVIEW_TEXT = "The quick brown fox jumps over the lazy dog";
 const FONT_FAMILY_PREVIEW_TEXT_SIZE = 20;
 const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
 const HIDDEN_CLASS = "__fx-devtools-hide-shortcut__";
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 const IMAGE_FETCHING_TIMEOUT = 500;
 // The possible completions to a ':' with added score to give certain values
@@ -172,16 +174,20 @@ exports.setValueSummaryLength = function
  */
 var NodeActor = exports.NodeActor = protocol.ActorClass({
   typeName: "domnode",
 
   initialize: function(walker, node) {
     protocol.Actor.prototype.initialize.call(this, null);
     this.walker = walker;
     this.rawNode = node;
+
+    // Storing the original display of the node, to track changes when reflows
+    // occur
+    this.wasDisplayed = this.isDisplayed;
   },
 
   toString: function() {
     return "[NodeActor " + this.actorID + " for " + this.rawNode.toString() + "]";
   },
 
   /**
    * Instead of storing a connection object, the NodeActor gets its connection
@@ -222,16 +228,18 @@ var NodeActor = exports.NodeActor = prot
       // doctype attributes
       name: this.rawNode.name,
       publicId: this.rawNode.publicId,
       systemId: this.rawNode.systemId,
 
       attrs: this.writeAttrs(),
 
       pseudoClassLocks: this.writePseudoClassLocks(),
+
+      isDisplayed: this.isDisplayed,
     };
 
     if (this.isDocumentElement()) {
       form.isDocumentElement = true;
     }
 
     if (this.rawNode.nodeValue) {
       // We only include a short version of the value if it's longer than
@@ -242,16 +250,39 @@ var NodeActor = exports.NodeActor = prot
       } else {
         form.shortValue = this.rawNode.nodeValue;
       }
     }
 
     return form;
   },
 
+  get computedStyle() {
+    if (Cu.isDeadWrapper(this.rawNode) ||
+        this.rawNode.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE ||
+        !this.rawNode.ownerDocument ||
+        !this.rawNode.ownerDocument.defaultView) {
+      return null;
+    }
+    return this.rawNode.ownerDocument.defaultView.getComputedStyle(this.rawNode);
+  },
+
+  /**
+   * Is the node's display computed style value other than "none"
+   */
+  get isDisplayed() {
+    let style = this.computedStyle;
+    if (!style) {
+      // Consider all non-element nodes as displayed
+      return true;
+    } else {
+      return style.display !== "none";
+    }
+  },
+
   writeAttrs: function() {
     if (!this.rawNode.attributes) {
       return undefined;
     }
     return [{namespace: attr.namespace, name: attr.name, value: attr.value }
             for (attr of this.rawNode.attributes)];
   },
 
@@ -543,16 +574,22 @@ let NodeFront = protocol.FrontClass(Node
 
   get attributes() this._form.attrs,
 
   get pseudoClassLocks() this._form.pseudoClassLocks || [],
   hasPseudoClassLock: function(pseudo) {
     return this.pseudoClassLocks.some(locked => locked === pseudo);
   },
 
+  get isDisplayed() {
+    // The NodeActor's form contains the isDisplayed information as a boolean
+    // starting from FF32. Before that, the property is missing
+    return "isDisplayed" in this._form ? this._form.isDisplayed : true;
+  },
+
   getNodeValue: protocol.custom(function() {
     if (!this.incompleteValue) {
       return delayedResolve(new ShortLongString(this.shortValue));
     } else {
       return this._getNodeValue();
     }
   }, {
     impl: "_getNodeValue"
@@ -831,16 +868,20 @@ var WalkerActor = protocol.ActorClass({
       type: "pickerNodeHovered",
       node: Arg(0, "disconnectedNode")
     },
     "highlighter-ready" : {
       type: "highlighter-ready"
     },
     "highlighter-hide" : {
       type: "highlighter-hide"
+    },
+    "display-change" : {
+      type: "display-change",
+      nodes: Arg(0, "array:domnode")
     }
   },
 
   /**
    * Create the WalkerActor
    * @param DebuggerServerConnection conn
    *    The server connection.
    */
@@ -870,16 +911,20 @@ var WalkerActor = protocol.ActorClass({
     this.onFrameUnload = this.onFrameUnload.bind(this);
 
     events.on(tabActor, "will-navigate", this.onFrameUnload);
     events.on(tabActor, "navigate", this.onFrameLoad);
 
     // Ensure that the root document node actor is ready and
     // managed.
     this.rootNode = this.document();
+
+    this.reflowObserver = getLayoutChangesObserver(this.tabActor);
+    this._onReflows = this._onReflows.bind(this);
+    this.reflowObserver.on("reflows", this._onReflows);
   },
 
   // Returns the JSON representation of this object over the wire.
   form: function() {
     return {
       actor: this.actorID,
       root: this.rootNode.form()
     }
@@ -889,27 +934,32 @@ var WalkerActor = protocol.ActorClass({
     return "[WalkerActor " + this.actorID + "]";
   },
 
   destroy: function() {
     this._hoveredNode = null;
     this.clearPseudoClassLocks();
     this._activePseudoClassLocks = null;
     this.rootDoc = null;
+
+    this.reflowObserver.off("reflows", this._onReflows);
+    this.reflowObserver = null;
+    releaseLayoutChangesObserver(this.tabActor);
+
     events.emit(this, "destroyed");
     protocol.Actor.prototype.destroy.call(this);
   },
 
   release: method(function() {}, { release: true }),
 
   unmanage: function(actor) {
     if (actor instanceof NodeActor) {
       if (this._activePseudoClassLocks &&
           this._activePseudoClassLocks.has(actor)) {
-        this.clearPsuedoClassLocks(actor);
+        this.clearPseudoClassLocks(actor);
       }
       this._refMap.delete(actor.rawNode);
     }
     protocol.Actor.prototype.unmanage.call(this, actor);
   },
 
   _ref: function(node) {
     let actor = this._refMap.get(node);
@@ -923,16 +973,34 @@ var WalkerActor = protocol.ActorClass({
     this._refMap.set(node, actor);
 
     if (node.nodeType === Ci.nsIDOMNode.DOCUMENT_NODE) {
       this._watchDocument(actor);
     }
     return actor;
   },
 
+  _onReflows: function(reflows) {
+    // Going through the nodes the walker knows about, see which ones have
+    // had their display changed and send a display-change event if any
+    let changes = [];
+    for (let [node, actor] of this._refMap) {
+      let isDisplayed = actor.isDisplayed;
+      if (isDisplayed !== actor.wasDisplayed) {
+        changes.push(actor);
+        // Updating the original value
+        actor.wasDisplayed = isDisplayed;
+      }
+    }
+
+    if (changes.length) {
+      events.emit(this, "display-change", changes);
+    }
+  },
+
   /**
    * This is kept for backward-compatibility reasons with older remote targets.
    * Targets prior to bug 916443.
    *
    * pick/cancelPick are used to pick a node on click on the content
    * document. But in their implementation prior to bug 916443, they don't allow
    * highlighting on hover.
    * The client-side now uses the highlighter actor's pick and cancelPick