Merge m-c to s-c.
authorRichard Newman <rnewman@mozilla.com>
Wed, 05 Dec 2012 23:59:56 -0800
changeset 117353 69a4de108bdaf6ef9e251627f27a017d21a78321
parent 117352 42bb46d1c19f799e07eea0a49af683db1c3772cc (current diff)
parent 115101 5f626f86b374315531fa35e68492d3475976c162 (diff)
child 117354 26910bf3ff350f240774eaf6fe2f50c75e3219b7
push id24098
push userrnewman@mozilla.com
push dateThu, 03 Jan 2013 03:39:06 +0000
treeherdermozilla-central@6955309291ee [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone20.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 s-c.
browser/base/content/test/browser_tabMatchesInAwesomebar.js
browser/components/privatebrowsing/test/browser/obsolete/browser_privatebrowsing_downloadmonitor.js
browser/components/privatebrowsing/test/browser/obsolete/staller.sjs
browser/components/tabview/test/browser_tabview_bug624727.js
browser/components/tabview/test/browser_tabview_bug650280.js
js/src/gc/FindSCCs.cpp
mobile/android/base/background/announcements/AnnouncementsFetchResourceDelegate.java
mobile/android/base/resources/drawable-hdpi-v11/ic_menu_close_all_tabs.png
mobile/android/base/resources/drawable-hdpi-v11/ic_menu_synced_tabs.png
mobile/android/base/resources/drawable-hdpi-v11/menu.png
mobile/android/base/resources/drawable-hdpi-v11/menu_item_check.png
mobile/android/base/resources/drawable-hdpi-v11/menu_item_more.png
mobile/android/base/resources/drawable-hdpi-v11/menu_item_uncheck.png
mobile/android/base/resources/drawable-hdpi-v11/menu_panel_bg.9.png
mobile/android/base/resources/drawable-hdpi-v11/menu_pb.png
mobile/android/base/resources/drawable-hdpi-v11/menu_popup_arrow.png
mobile/android/base/resources/drawable-hdpi-v11/menu_popup_bg.9.png
mobile/android/base/resources/drawable-mdpi-v11/ic_menu_close_all_tabs.png
mobile/android/base/resources/drawable-mdpi-v11/ic_menu_synced_tabs.png
mobile/android/base/resources/drawable-mdpi-v11/menu.png
mobile/android/base/resources/drawable-mdpi-v11/menu_item_check.png
mobile/android/base/resources/drawable-mdpi-v11/menu_item_more.png
mobile/android/base/resources/drawable-mdpi-v11/menu_item_uncheck.png
mobile/android/base/resources/drawable-mdpi-v11/menu_panel_bg.9.png
mobile/android/base/resources/drawable-mdpi-v11/menu_pb.png
mobile/android/base/resources/drawable-mdpi-v11/menu_popup_arrow.png
mobile/android/base/resources/drawable-mdpi-v11/menu_popup_bg.9.png
mobile/android/base/resources/drawable-xhdpi-v11/ic_menu_close_all_tabs.png
mobile/android/base/resources/drawable-xhdpi-v11/ic_menu_synced_tabs.png
mobile/android/base/resources/drawable-xhdpi-v11/menu.png
mobile/android/base/resources/drawable-xhdpi-v11/menu_item_check.png
mobile/android/base/resources/drawable-xhdpi-v11/menu_item_more.png
mobile/android/base/resources/drawable-xhdpi-v11/menu_item_uncheck.png
mobile/android/base/resources/drawable-xhdpi-v11/menu_panel_bg.9.png
mobile/android/base/resources/drawable-xhdpi-v11/menu_pb.png
mobile/android/base/resources/drawable-xhdpi-v11/menu_popup_arrow.png
mobile/android/base/resources/drawable-xhdpi-v11/menu_popup_bg.9.png
mobile/android/base/resources/layout-land-v14/tabs_panel_toolbar.xml
mobile/android/base/resources/layout/tabs_panel_toolbar.xml
mobile/android/base/tests/robocop_search_input.html
mobile/android/base/tests/testAddSearchEngine.java.in
toolkit/components/downloads/test/browser/browser_private_resume.js
toolkit/components/downloads/test/browser/browser_privatebrowsing.js
toolkit/components/downloads/test/browser/browser_privatebrowsing_cancel.js
toolkit/components/downloads/test/browser/head.js
toolkit/themes/pinstripe/mozapps/downloads/downloadStatusIcon.png
--- a/accessible/src/atk/AccessibleWrap.cpp
+++ b/accessible/src/atk/AccessibleWrap.cpp
@@ -136,21 +136,16 @@ struct MaiAtkObject
 
 struct MaiAtkObjectClass
 {
     AtkObjectClass parent_class;
 };
 
 static guint mai_atk_object_signals [LAST_SIGNAL] = { 0, };
 
-#ifdef MAI_LOGGING
-int32_t sMaiAtkObjCreated = 0;
-int32_t sMaiAtkObjDeleted = 0;
-#endif
-
 G_BEGIN_DECLS
 /* callbacks for MaiAtkObject */
 static void classInitCB(AtkObjectClass *aClass);
 static void initializeCB(AtkObject *aAtkObj, gpointer aData);
 static void finalizeCB(GObject *aObj);
 
 /* callbacks for AtkObject virtual functions */
 static const gchar*        getNameCB (AtkObject *aAtkObj);
@@ -227,43 +222,25 @@ mai_atk_object_get_type(void)
 
         type = g_type_register_static(ATK_TYPE_OBJECT,
                                       "MaiAtkObject", &tinfo, GTypeFlags(0));
         quark_mai_hyperlink = g_quark_from_static_string("MaiHyperlink");
     }
     return type;
 }
 
-#ifdef MAI_LOGGING
-int32_t AccessibleWrap::mAccWrapCreated = 0;
-int32_t AccessibleWrap::mAccWrapDeleted = 0;
-#endif
-
 AccessibleWrap::
   AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
   Accessible(aContent, aDoc), mAtkObject(nullptr)
 {
-#ifdef MAI_LOGGING
-  ++mAccWrapCreated;
-#endif
-  MAI_LOG_DEBUG(("==AccessibleWrap creating: this=%p,total=%d left=%d\n",
-                 (void*)this, mAccWrapCreated,
-                 (mAccWrapCreated-mAccWrapDeleted)));
 }
 
 AccessibleWrap::~AccessibleWrap()
 {
     NS_ASSERTION(!mAtkObject, "ShutdownAtkObject() is not called");
-
-#ifdef MAI_LOGGING
-    ++mAccWrapDeleted;
-#endif
-    MAI_LOG_DEBUG(("==AccessibleWrap deleting: this=%p,total=%d left=%d\n",
-                   (void*)this, mAccWrapDeleted,
-                   (mAccWrapCreated-mAccWrapDeleted)));
 }
 
 void
 AccessibleWrap::ShutdownAtkObject()
 {
     if (mAtkObject) {
         if (IS_MAI_OBJECT(mAtkObject)) {
             MAI_ATK_OBJECT(mAtkObject)->accWrap = nullptr;
@@ -477,18 +454,16 @@ GetUniqueMaiAtkTypeName(uint16_t interfa
 
     static gchar namePrefix[] = "MaiAtkType";   /* size = 10 */
     static gchar name[MAI_ATK_TYPE_NAME_LEN + 1];
 
     PR_snprintf(name, MAI_ATK_TYPE_NAME_LEN, "%s%x", namePrefix,
                 interfacesBits);
     name[MAI_ATK_TYPE_NAME_LEN] = '\0';
 
-    MAI_LOG_DEBUG(("MaiWidget::LastedTypeName=%s\n", name));
-
     return name;
 }
 
 bool
 AccessibleWrap::IsValidObject()
 {
     // to ensure we are not shut down
     return !IsDefunct();
@@ -598,39 +573,25 @@ initializeCB(AtkObject *aAtkObj, gpointe
      */
 
     if (ATK_OBJECT_CLASS(parent_class)->initialize)
         ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData);
 
   /* initialize object */
   MAI_ATK_OBJECT(aAtkObj)->accWrap =
     static_cast<AccessibleWrap*>(aData);
-
-#ifdef MAI_LOGGING
-    ++sMaiAtkObjCreated;
-#endif
-    MAI_LOG_DEBUG(("MaiAtkObj Create obj=%p for AccWrap=%p, all=%d, left=%d\n",
-                   (void*)aAtkObj, (void*)aData, sMaiAtkObjCreated,
-                   (sMaiAtkObjCreated-sMaiAtkObjDeleted)));
 }
 
 void
 finalizeCB(GObject *aObj)
 {
     if (!IS_MAI_OBJECT(aObj))
         return;
     NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == nullptr, "AccWrap NOT null");
 
-#ifdef MAI_LOGGING
-    ++sMaiAtkObjDeleted;
-#endif
-    MAI_LOG_DEBUG(("MaiAtkObj Delete obj=%p, all=%d, left=%d\n",
-                   (void*)aObj, sMaiAtkObjCreated,
-                   (sMaiAtkObjCreated-sMaiAtkObjDeleted)));
-
     // call parent finalize function
     // finalize of GObjectClass will unref the accessible parent if has
     if (G_OBJECT_CLASS (parent_class)->finalize)
         G_OBJECT_CLASS (parent_class)->finalize(aObj);
 }
 
 const gchar*
 getNameCB(AtkObject* aAtkObj)
@@ -987,17 +948,16 @@ AccessibleWrap::FirePlatformEvent(AccEve
         return FireAtkStateChangeEvent(aEvent, atkObj);
 
     case nsIAccessibleEvent::EVENT_TEXT_REMOVED:
     case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
         return FireAtkTextChangedEvent(aEvent, atkObj);
 
     case nsIAccessibleEvent::EVENT_FOCUS:
       {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_FOCUS\n"));
         a11y::RootAccessible* rootAccWrap = accWrap->RootAccessible();
         if (rootAccWrap && rootAccWrap->mActivated) {
             atk_focus_tracker_notify(atkObj);
             // Fire state change event for focus
             nsRefPtr<AccEvent> stateChangeEvent =
               new AccStateChangeEvent(accessible, states::FOCUSED, true);
             return FireAtkStateChangeEvent(stateChangeEvent, atkObj);
         }
@@ -1010,265 +970,202 @@ AccessibleWrap::FirePlatformEvent(AccEve
         NS_ConvertUTF16toUTF8 utf8Name(newName);
         if (!atkObj->name || !utf8Name.Equals(atkObj->name))
           atk_object_set_name(atkObj, utf8Name.get());
 
         break;
       }
     case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
       {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_VALUE_CHANGE\n"));
         nsCOMPtr<nsIAccessibleValue> value(do_QueryObject(accessible));
         if (value) {    // Make sure this is a numeric value
             // Don't fire for MSAA string value changes (e.g. text editing)
             // ATK values are always numeric
             g_object_notify( (GObject*)atkObj, "accessible-value" );
         }
       } break;
 
     case nsIAccessibleEvent::EVENT_SELECTION:
     case nsIAccessibleEvent::EVENT_SELECTION_ADD:
     case nsIAccessibleEvent::EVENT_SELECTION_REMOVE:
     {
       // XXX: dupe events may be fired
-      MAI_LOG_DEBUG(("\n\nReceived: EVENT_SELECTION_CHANGED\n"));
       AccSelChangeEvent* selChangeEvent = downcast_accEvent(aEvent);
       g_signal_emit_by_name(AccessibleWrap::GetAtkObject(selChangeEvent->Widget()),
                             "selection_changed");
       break;
     }
 
     case nsIAccessibleEvent::EVENT_SELECTION_WITHIN:
     {
-      MAI_LOG_DEBUG(("\n\nReceived: EVENT_SELECTION_CHANGED\n"));
       g_signal_emit_by_name(atkObj, "selection_changed");
       break;
     }
 
     case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED:
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_SELECTION_CHANGED\n"));
         g_signal_emit_by_name(atkObj, "text_selection_changed");
         break;
 
     case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED:
       {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_CARET_MOVED\n"));
-
         AccCaretMoveEvent* caretMoveEvent = downcast_accEvent(aEvent);
         NS_ASSERTION(caretMoveEvent, "Event needs event data");
         if (!caretMoveEvent)
             break;
 
         int32_t caretOffset = caretMoveEvent->GetCaretOffset();
-
-        MAI_LOG_DEBUG(("\n\nCaret postion: %d", caretOffset));
-        g_signal_emit_by_name(atkObj,
-                              "text_caret_moved",
-                              // Curent caret position
-                              caretOffset);
+        g_signal_emit_by_name(atkObj, "text_caret_moved", caretOffset);
       } break;
 
     case nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED:
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_ATTRIBUTE_CHANGED\n"));
-
-        g_signal_emit_by_name(atkObj,
-                              "text-attributes-changed");
+        g_signal_emit_by_name(atkObj, "text-attributes-changed");
         break;
 
     case nsIAccessibleEvent::EVENT_TABLE_MODEL_CHANGED:
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_MODEL_CHANGED\n"));
         g_signal_emit_by_name(atkObj, "model_changed");
         break;
 
     case nsIAccessibleEvent::EVENT_TABLE_ROW_INSERT:
       {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_ROW_INSERT\n"));
         AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
         NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
 
         int32_t rowIndex = tableEvent->GetIndex();
         int32_t numRows = tableEvent->GetCount();
 
-        g_signal_emit_by_name(atkObj,
-                              "row_inserted",
-                              // After which the rows are inserted
-                              rowIndex,
-                              // The number of the inserted
-                              numRows);
+        g_signal_emit_by_name(atkObj, "row_inserted", rowIndex, numRows);
      } break;
 
    case nsIAccessibleEvent::EVENT_TABLE_ROW_DELETE:
      {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_ROW_DELETE\n"));
         AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
         NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
 
         int32_t rowIndex = tableEvent->GetIndex();
         int32_t numRows = tableEvent->GetCount();
 
-        g_signal_emit_by_name(atkObj,
-                              "row_deleted",
-                              // After which the rows are deleted
-                              rowIndex,
-                              // The number of the deleted
-                              numRows);
+        g_signal_emit_by_name(atkObj, "row_deleted", rowIndex, numRows);
       } break;
 
     case nsIAccessibleEvent::EVENT_TABLE_ROW_REORDER:
       {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_ROW_REORDER\n"));
         g_signal_emit_by_name(atkObj, "row_reordered");
         break;
       }
 
     case nsIAccessibleEvent::EVENT_TABLE_COLUMN_INSERT:
       {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_COLUMN_INSERT\n"));
         AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
         NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
 
         int32_t colIndex = tableEvent->GetIndex();
         int32_t numCols = tableEvent->GetCount();
-
-        g_signal_emit_by_name(atkObj,
-                              "column_inserted",
-                              // After which the columns are inserted
-                              colIndex,
-                              // The number of the inserted
-                              numCols);
+        g_signal_emit_by_name(atkObj, "column_inserted", colIndex, numCols);
       } break;
 
     case nsIAccessibleEvent::EVENT_TABLE_COLUMN_DELETE:
       {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_COLUMN_DELETE\n"));
         AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
         NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
 
         int32_t colIndex = tableEvent->GetIndex();
         int32_t numCols = tableEvent->GetCount();
-
-        g_signal_emit_by_name(atkObj,
-                              "column_deleted",
-                              // After which the columns are deleted
-                              colIndex,
-                              // The number of the deleted
-                              numCols);
+        g_signal_emit_by_name(atkObj, "column_deleted", colIndex, numCols);
       } break;
 
     case nsIAccessibleEvent::EVENT_TABLE_COLUMN_REORDER:
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_COLUMN_REORDER\n"));
         g_signal_emit_by_name(atkObj, "column_reordered");
         break;
 
     case nsIAccessibleEvent::EVENT_SECTION_CHANGED:
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_SECTION_CHANGED\n"));
         g_signal_emit_by_name(atkObj, "visible_data_changed");
         break;
 
     case nsIAccessibleEvent::EVENT_SHOW:
         return FireAtkShowHideEvent(aEvent, atkObj, true);
 
     case nsIAccessibleEvent::EVENT_HIDE:
         return FireAtkShowHideEvent(aEvent, atkObj, false);
 
         /*
          * Because dealing with menu is very different between nsIAccessible
          * and ATK, and the menu activity is important, specially transfer the
          * following two event.
          * Need more verification by AT test.
          */
     case nsIAccessibleEvent::EVENT_MENU_START:
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENU_START\n"));
-        break;
-
     case nsIAccessibleEvent::EVENT_MENU_END:
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENU_END\n"));
         break;
 
     case nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE:
       {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_ACTIVATED\n"));
         accessible->AsRoot()->mActivated = true;
         guint id = g_signal_lookup ("activate", MAI_TYPE_ATK_OBJECT);
         g_signal_emit(atkObj, id, 0);
 
         // Always fire a current focus event after activation.
         FocusMgr()->ForceFocusEvent();
       } break;
 
     case nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE:
       {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_DEACTIVATED\n"));
         accessible->AsRoot()->mActivated = false;
         guint id = g_signal_lookup ("deactivate", MAI_TYPE_ATK_OBJECT);
         g_signal_emit(atkObj, id, 0);
       } break;
 
     case nsIAccessibleEvent::EVENT_WINDOW_MAXIMIZE:
       {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_MAXIMIZE\n"));
         guint id = g_signal_lookup ("maximize", MAI_TYPE_ATK_OBJECT);
         g_signal_emit(atkObj, id, 0);
       } break;
 
     case nsIAccessibleEvent::EVENT_WINDOW_MINIMIZE:
       {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_MINIMIZE\n"));
         guint id = g_signal_lookup ("minimize", MAI_TYPE_ATK_OBJECT);
         g_signal_emit(atkObj, id, 0);
       } break;
 
     case nsIAccessibleEvent::EVENT_WINDOW_RESTORE:
       {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_RESTORE\n"));
         guint id = g_signal_lookup ("restore", MAI_TYPE_ATK_OBJECT);
         g_signal_emit(atkObj, id, 0);
       } break;
 
     case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE:
-      {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_DOCUMENT_LOAD_COMPLETE\n"));
         g_signal_emit_by_name (atkObj, "load_complete");
-      } break;
+      break;
 
     case nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD:
-      {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_DOCUMENT_RELOAD\n"));
         g_signal_emit_by_name (atkObj, "reload");
-      } break;
+      break;
 
     case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED:
-      {
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_DOCUMENT_LOAD_STOPPED\n"));
         g_signal_emit_by_name (atkObj, "load_stopped");
-      } break;
+      break;
 
     case nsIAccessibleEvent::EVENT_MENUPOPUP_START:
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENUPOPUP_START\n"));
         atk_focus_tracker_notify(atkObj); // fire extra focus event
         atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, true);
         atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, true);
         break;
 
     case nsIAccessibleEvent::EVENT_MENUPOPUP_END:
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENUPOPUP_END\n"));
         atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, false);
         atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, false);
         break;
     }
 
     return NS_OK;
 }
 
 nsresult
 AccessibleWrap::FireAtkStateChangeEvent(AccEvent* aEvent,
                                         AtkObject* aObject)
 {
-    MAI_LOG_DEBUG(("\n\nReceived: EVENT_STATE_CHANGE\n"));
-
     AccStateChangeEvent* event = downcast_accEvent(aEvent);
     NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
 
     bool isEnabled = event->IsStateEnabled();
     int32_t stateIndex = AtkStateMap::GetStateIndexFor(event->GetState());
     if (stateIndex >= 0) {
         NS_ASSERTION(gAtkStateMap[stateIndex].stateMapEntryType != kNoSuchState,
                      "No such state");
@@ -1289,18 +1186,16 @@ AccessibleWrap::FireAtkStateChangeEvent(
 
     return NS_OK;
 }
 
 nsresult
 AccessibleWrap::FireAtkTextChangedEvent(AccEvent* aEvent,
                                         AtkObject* aObject)
 {
-    MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_REMOVED/INSERTED\n"));
-
     AccTextChangeEvent* event = downcast_accEvent(aEvent);
     NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
 
     int32_t start = event->GetStartOffset();
     uint32_t length = event->GetLength();
     bool isInserted = event->IsTextInserted();
     bool isFromUserInput = aEvent->IsFromUserInput();
     char* signal_name = nullptr;
@@ -1330,22 +1225,16 @@ AccessibleWrap::FireAtkTextChangedEvent(
   g_free(signal_name);
   return NS_OK;
 }
 
 nsresult
 AccessibleWrap::FireAtkShowHideEvent(AccEvent* aEvent,
                                      AtkObject* aObject, bool aIsAdded)
 {
-    if (aIsAdded) {
-        MAI_LOG_DEBUG(("\n\nReceived: Show event\n"));
-    } else {
-        MAI_LOG_DEBUG(("\n\nReceived: Hide event\n"));
-    }
-
     int32_t indexInParent = getIndexInParentCB(aObject);
     AtkObject *parentObject = getParentCB(aObject);
     NS_ENSURE_STATE(parentObject);
 
     bool isFromUserInput = aEvent->IsFromUserInput();
     char *signal_name = g_strconcat(aIsAdded ? "children_changed::add" :  "children_changed::remove",
                                     isFromUserInput ? "" : kNonUserInputEvent, NULL);
     g_signal_emit_by_name(parentObject, signal_name, indexInParent, aObject, NULL);
--- a/accessible/src/atk/AccessibleWrap.h
+++ b/accessible/src/atk/AccessibleWrap.h
@@ -4,21 +4,16 @@
  * 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 __NS_ACCESSIBLE_WRAP_H__
 #define __NS_ACCESSIBLE_WRAP_H__
 
 #include "nsCOMPtr.h"
 #include "Accessible.h"
-#include "prlog.h"
-
-#ifdef PR_LOGGING
-#define MAI_LOGGING
-#endif /* #ifdef PR_LOGGING */
 
 struct _AtkObject;
 typedef struct _AtkObject AtkObject;
 
 enum AtkProperty {
   PROP_0,           // gobject convention
   PROP_NAME,
   PROP_DESCRIPTION,
@@ -55,22 +50,16 @@ class AccessibleWrap : public Accessible
 public:
   AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc);
   virtual ~AccessibleWrap();
   void ShutdownAtkObject();
 
   // nsAccessNode
   virtual void Shutdown();
 
-#ifdef MAI_LOGGING
-  virtual void DumpAccessibleWrapInfo(int aDepth) {}
-  static int32_t mAccWrapCreated;
-  static int32_t mAccWrapDeleted;
-#endif
-
   // return the atk object for this AccessibleWrap
   NS_IMETHOD GetNativeInterface(void **aOutAccessible);
   virtual nsresult HandleAccEvent(AccEvent* aEvent);
 
   AtkObject * GetAtkObject(void);
   static AtkObject * GetAtkObject(nsIAccessible * acc);
 
   bool IsValidObject();
--- a/accessible/src/atk/ApplicationAccessibleWrap.cpp
+++ b/accessible/src/atk/ApplicationAccessibleWrap.cpp
@@ -28,536 +28,88 @@ using namespace mozilla::a11y;
 typedef GType (* AtkGetTypeType) (void);
 GType g_atk_hyperlink_impl_type = G_TYPE_INVALID;
 static bool sATKChecked = false;
 static PRLibrary *sATKLib = nullptr;
 static const char sATKLibName[] = "libatk-1.0.so.0";
 static const char sATKHyperlinkImplGetTypeSymbol[] =
   "atk_hyperlink_impl_get_type";
 
-/* gail function pointer */
-static guint (* gail_add_global_event_listener) (GSignalEmissionHook listener,
-                                                 const gchar *event_type);
-static void (* gail_remove_global_event_listener) (guint remove_listener);
-static void (* gail_remove_key_event_listener) (guint remove_listener);
-static AtkObject * (*gail_get_root) (void);
-
-/* maiutil */
-
-static guint mai_util_add_global_event_listener(GSignalEmissionHook listener,
-                                                const gchar *event_type);
-static void mai_util_remove_global_event_listener(guint remove_listener);
-static guint mai_util_add_key_event_listener(AtkKeySnoopFunc listener,
-                                             gpointer data);
-static void mai_util_remove_key_event_listener(guint remove_listener);
-static AtkObject *mai_util_get_root(void);
-static G_CONST_RETURN gchar *mai_util_get_toolkit_name(void);
-static G_CONST_RETURN gchar *mai_util_get_toolkit_version(void);
-
-
-/* Misc */
-
-static void _listener_info_destroy(gpointer data);
-static guint add_listener (GSignalEmissionHook listener,
-                           const gchar *object_type,
-                           const gchar *signal,
-                           const gchar *hook_data,
-                           guint gail_listenerid = 0);
-static AtkKeyEventStruct *atk_key_event_from_gdk_event_key(GdkEventKey *key);
-static gboolean notify_hf(gpointer key, gpointer value, gpointer data);
-static void insert_hf(gpointer key, gpointer value, gpointer data);
-static gint mai_key_snooper(GtkWidget *the_widget, GdkEventKey *event,
-                            gpointer func_data);
-
-static GHashTable* sListener_list = NULL;
-static gint sListener_idx = 1;
-
-#define MAI_TYPE_UTIL              (mai_util_get_type ())
-#define MAI_UTIL(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
-                                    MAI_TYPE_UTIL, MaiUtil))
-#define MAI_UTIL_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), \
-                                    MAI_TYPE_UTIL, MaiUtilClass))
-#define MAI_IS_UTIL(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
-                                    MAI_TYPE_UTIL))
-#define MAI_IS_UTIL_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), \
-                                    MAI_TYPE_UTIL))
-#define MAI_UTIL_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), \
-                                    MAI_TYPE_UTIL, MaiUtilClass))
-
-static GHashTable* sKey_listener_list = NULL;
-static guint sKey_snooper_id = 0;
 static bool sToplevel_event_hook_added = false;
 static gulong sToplevel_show_hook = 0;
 static gulong sToplevel_hide_hook = 0;
 
 G_BEGIN_DECLS
 typedef void (*GnomeAccessibilityInit) (void);
 typedef void (*GnomeAccessibilityShutdown) (void);
 G_END_DECLS
 
-struct MaiUtil
-{
-    AtkUtil parent;
-    GList *listener_list;
-};
-
-struct MaiKeyEventInfo
-{
-    AtkKeyEventStruct *key_event;
-    gpointer func_data;
-};
-
-union AtkKeySnoopFuncPointer
-{
-    AtkKeySnoopFunc func_ptr;
-    gpointer data;
-};
-
 struct GnomeAccessibilityModule
 {
     const char *libName;
     PRLibrary *lib;
     const char *initName;
     GnomeAccessibilityInit init;
     const char *shutdownName;
     GnomeAccessibilityShutdown shutdown;
 };
 
-struct MaiUtilClass
-{
-    AtkUtilClass parent_class;
-};
-
-GType mai_util_get_type (void);
-static void mai_util_class_init(MaiUtilClass *klass);
-
-/* supporting */
-PRLogModuleInfo *gMaiLog = NULL;
-
-#define MAI_VERSION MOZILLA_VERSION
-#define MAI_NAME "Gecko"
-
-struct MaiUtilListenerInfo
-{
-    gint key;
-    guint signal_id;
-    gulong hook_id;
-    // For window create/destory/minimize/maximize/restore/activate/deactivate
-    // events, we'll chain gail_util's add/remove_global_event_listener.
-    // So we store the listenerid returned by gail's add_global_event_listener
-    // in this structure to call gail's remove_global_event_listener later.
-    guint gail_listenerid;
-};
-
 static GnomeAccessibilityModule sAtkBridge = {
 #ifdef AIX
     "libatk-bridge.a(libatk-bridge.so.0)", NULL,
 #else
     "libatk-bridge.so", NULL,
 #endif
     "gnome_accessibility_module_init", NULL,
     "gnome_accessibility_module_shutdown", NULL
 };
 
 static GnomeAccessibilityModule sGail = {
     "libgail.so", NULL,
     "gnome_accessibility_module_init", NULL,
     "gnome_accessibility_module_shutdown", NULL
 };
 
-GType
-mai_util_get_type(void)
-{
-    static GType type = 0;
-
-    if (!type) {
-        static const GTypeInfo tinfo = {
-            sizeof(MaiUtilClass),
-            (GBaseInitFunc) NULL, /* base init */
-            (GBaseFinalizeFunc) NULL, /* base finalize */
-            (GClassInitFunc) mai_util_class_init, /* class init */
-            (GClassFinalizeFunc) NULL, /* class finalize */
-            NULL, /* class data */
-            sizeof(MaiUtil), /* instance size */
-            0, /* nb preallocs */
-            (GInstanceInitFunc) NULL, /* instance init */
-            NULL /* value table */
-        };
-
-        type = g_type_register_static(ATK_TYPE_UTIL,
-                                      "MaiUtil", &tinfo, GTypeFlags(0));
-    }
-    return type;
-}
-
-static void
-window_added (AtkObject *atk_obj,
-              guint     index,
-              AtkObject *child)
-{
-  if (!IS_MAI_OBJECT(child))
-      return;
-
-  static guint id =  g_signal_lookup ("create", MAI_TYPE_ATK_OBJECT);
-  g_signal_emit (child, id, 0);
-}
-
-static void
-window_removed (AtkObject *atk_obj,
-                guint     index,
-                AtkObject *child)
-{
-  if (!IS_MAI_OBJECT(child))
-      return;
-
-  static guint id =  g_signal_lookup ("destroy", MAI_TYPE_ATK_OBJECT);
-  g_signal_emit (child, id, 0);
-}
-
-/* intialize the the atk interface (function pointers) with MAI implementation.
- * When atk bridge get loaded, these interface can be used.
- */
-static void
-mai_util_class_init(MaiUtilClass *klass)
-{
-    AtkUtilClass *atk_class;
-    gpointer data;
-
-    data = g_type_class_peek(ATK_TYPE_UTIL);
-    atk_class = ATK_UTIL_CLASS(data);
-
-    // save gail function pointer
-    gail_add_global_event_listener = atk_class->add_global_event_listener;
-    gail_remove_global_event_listener = atk_class->remove_global_event_listener;
-    gail_remove_key_event_listener = atk_class->remove_key_event_listener;
-    gail_get_root = atk_class->get_root;
-
-    atk_class->add_global_event_listener =
-        mai_util_add_global_event_listener;
-    atk_class->remove_global_event_listener =
-        mai_util_remove_global_event_listener;
-    atk_class->add_key_event_listener = mai_util_add_key_event_listener;
-    atk_class->remove_key_event_listener = mai_util_remove_key_event_listener;
-    atk_class->get_root = mai_util_get_root;
-    atk_class->get_toolkit_name = mai_util_get_toolkit_name;
-    atk_class->get_toolkit_version = mai_util_get_toolkit_version;
-
-    sListener_list = g_hash_table_new_full(g_int_hash, g_int_equal, NULL,
-                                           _listener_info_destroy);
-    // Keep track of added/removed windows.
-    AtkObject *root = atk_get_root ();
-    g_signal_connect (root, "children-changed::add", (GCallback) window_added, NULL);
-    g_signal_connect (root, "children-changed::remove", (GCallback) window_removed, NULL);
-}
-
-static guint
-mai_util_add_global_event_listener(GSignalEmissionHook listener,
-                                   const gchar *event_type)
-{
-    guint rc = 0;
-    gchar **split_string;
-
-    split_string = g_strsplit (event_type, ":", 3);
-
-    if (split_string) {
-        if (!strcmp ("window", split_string[0])) {
-            guint gail_listenerid = 0;
-            if (gail_add_global_event_listener) {
-                // call gail's function to track gtk native window events
-                gail_listenerid =
-                    gail_add_global_event_listener(listener, event_type);
-            }
-
-            rc = add_listener (listener, "MaiAtkObject", split_string[1],
-                               event_type, gail_listenerid);
-        }
-        else {
-            rc = add_listener (listener, split_string[1], split_string[2],
-                               event_type);
-        }
-        g_strfreev(split_string);
-    }
-    return rc;
-}
-
-static void
-mai_util_remove_global_event_listener(guint remove_listener)
-{
-    if (remove_listener > 0) {
-        MaiUtilListenerInfo *listener_info;
-        gint tmp_idx = remove_listener;
-
-        listener_info = (MaiUtilListenerInfo *)
-            g_hash_table_lookup(sListener_list, &tmp_idx);
-
-        if (listener_info != NULL) {
-            if (gail_remove_global_event_listener &&
-                listener_info->gail_listenerid) {
-              gail_remove_global_event_listener(listener_info->gail_listenerid);
-            }
-
-            /* Hook id of 0 and signal id of 0 are invalid */
-            if (listener_info->hook_id != 0 && listener_info->signal_id != 0) {
-                /* Remove the emission hook */
-                g_signal_remove_emission_hook(listener_info->signal_id,
-                                              listener_info->hook_id);
-
-                /* Remove the element from the hash */
-                g_hash_table_remove(sListener_list, &tmp_idx);
-            }
-            else {
-                g_warning("Invalid listener hook_id %ld or signal_id %d\n",
-                          listener_info->hook_id, listener_info->signal_id);
-            }
-        }
-        else {
-            // atk-bridge is initialized with gail (e.g. yelp)
-            // try gail_remove_global_event_listener
-            if (gail_remove_global_event_listener) {
-                return gail_remove_global_event_listener(remove_listener);
-            }
-
-            g_warning("No listener with the specified listener id %d",
-                      remove_listener);
-        }
-    }
-    else {
-        g_warning("Invalid listener_id %d", remove_listener);
-    }
-}
-
-static AtkKeyEventStruct *
-atk_key_event_from_gdk_event_key (GdkEventKey *key)
-{
-    AtkKeyEventStruct *event = g_new0(AtkKeyEventStruct, 1);
-    switch (key->type) {
-    case GDK_KEY_PRESS:
-        event->type = ATK_KEY_EVENT_PRESS;
-        break;
-    case GDK_KEY_RELEASE:
-        event->type = ATK_KEY_EVENT_RELEASE;
-        break;
-    default:
-        g_assert_not_reached ();
-        return NULL;
-    }
-    event->state = key->state;
-    event->keyval = key->keyval;
-    event->length = key->length;
-    if (key->string && key->string [0] &&
-        (key->state & GDK_CONTROL_MASK ||
-         g_unichar_isgraph (g_utf8_get_char (key->string)))) {
-        event->string = key->string;
-    }
-    else if (key->type == GDK_KEY_PRESS ||
-             key->type == GDK_KEY_RELEASE) {
-        event->string = gdk_keyval_name (key->keyval);
-    }
-    event->keycode = key->hardware_keycode;
-    event->timestamp = key->time;
-
-    MAI_LOG_DEBUG(("MaiKey:\tsym %u\n\tmods %x\n\tcode %u\n\ttime %lx\n",
-                   (unsigned int) event->keyval,
-                   (unsigned int) event->state,
-                   (unsigned int) event->keycode,
-                   (unsigned long int) event->timestamp));
-    return event;
-}
-
-static gboolean
-notify_hf(gpointer key, gpointer value, gpointer data)
-{
-    MaiKeyEventInfo *info = (MaiKeyEventInfo *)data;
-    AtkKeySnoopFuncPointer atkKeySnoop;
-    atkKeySnoop.data = value;
-    return (atkKeySnoop.func_ptr)(info->key_event, info->func_data) ? TRUE : FALSE;
-}
-
-static void
-insert_hf(gpointer key, gpointer value, gpointer data)
-{
-    GHashTable *new_table = (GHashTable *) data;
-    g_hash_table_insert (new_table, key, value);
-}
-
-static gint
-mai_key_snooper(GtkWidget *the_widget, GdkEventKey *event, gpointer func_data)
-{
-    /* notify each AtkKeySnoopFunc in turn... */
-
-    MaiKeyEventInfo *info = g_new0(MaiKeyEventInfo, 1);
-    gint consumed = 0;
-    if (sKey_listener_list) {
-        GHashTable *new_hash = g_hash_table_new(NULL, NULL);
-        g_hash_table_foreach (sKey_listener_list, insert_hf, new_hash);
-        info->key_event = atk_key_event_from_gdk_event_key (event);
-        info->func_data = func_data;
-        consumed = g_hash_table_foreach_steal (new_hash, notify_hf, info);
-        g_hash_table_destroy (new_hash);
-        g_free(info->key_event);
-    }
-    g_free(info);
-    return (consumed ? 1 : 0);
-}
-
-static guint
-mai_util_add_key_event_listener (AtkKeySnoopFunc listener,
-                                 gpointer data)
-{
-    NS_ENSURE_TRUE(listener, 0);
-
-    static guint key=0;
-
-    if (!sKey_listener_list) {
-        sKey_listener_list = g_hash_table_new(NULL, NULL);
-        sKey_snooper_id = gtk_key_snooper_install(mai_key_snooper, data);
-    }
-    AtkKeySnoopFuncPointer atkKeySnoop;
-    atkKeySnoop.func_ptr = listener;
-    g_hash_table_insert(sKey_listener_list, GUINT_TO_POINTER (key++),
-                        atkKeySnoop.data);
-    return key;
-}
-
-static void
-mai_util_remove_key_event_listener (guint remove_listener)
-{
-    if (!sKey_listener_list) {
-        // atk-bridge is initialized with gail (e.g. yelp)
-        // try gail_remove_key_event_listener
-        return gail_remove_key_event_listener(remove_listener);
-    }
-
-    g_hash_table_remove(sKey_listener_list, GUINT_TO_POINTER (remove_listener));
-    if (g_hash_table_size(sKey_listener_list) == 0) {
-        gtk_key_snooper_remove(sKey_snooper_id);
-    }
-}
-
-AtkObject*
-mai_util_get_root(void)
-{
-  ApplicationAccessible* app = ApplicationAcc();
-  if (app)
-    return app->GetAtkObject();
-
-  // We've shutdown, try to use gail instead
-  // (to avoid assert in spi_atk_tidy_windows())
-  // XXX tbsaunde then why didn't we replace the gail atk_util impl?
-  if (gail_get_root)
-    return gail_get_root();
-
-  return nullptr;
-}
-
-G_CONST_RETURN gchar *
-mai_util_get_toolkit_name(void)
-{
-    return MAI_NAME;
-}
-
-G_CONST_RETURN gchar *
-mai_util_get_toolkit_version(void)
-{
-    return MAI_VERSION;
-}
-
-void
-_listener_info_destroy(gpointer data)
-{
-    g_free(data);
-}
-
-guint
-add_listener (GSignalEmissionHook listener,
-              const gchar *object_type,
-              const gchar *signal,
-              const gchar *hook_data,
-              guint gail_listenerid)
-{
-    GType type;
-    guint signal_id;
-    gint rc = 0;
-
-    type = g_type_from_name(object_type);
-    if (type) {
-        signal_id = g_signal_lookup(signal, type);
-        if (signal_id > 0) {
-            MaiUtilListenerInfo *listener_info;
-
-            rc = sListener_idx;
-
-            listener_info =  (MaiUtilListenerInfo *)
-                g_malloc(sizeof(MaiUtilListenerInfo));
-            listener_info->key = sListener_idx;
-            listener_info->hook_id =
-                g_signal_add_emission_hook(signal_id, 0, listener,
-                                           g_strdup(hook_data),
-                                           (GDestroyNotify)g_free);
-            listener_info->signal_id = signal_id;
-            listener_info->gail_listenerid = gail_listenerid;
-
-            g_hash_table_insert(sListener_list, &(listener_info->key),
-                                listener_info);
-            sListener_idx++;
-        }
-        else {
-            g_warning("Invalid signal type %s\n", signal);
-        }
-    }
-    else {
-        g_warning("Invalid object type %s\n", object_type);
-    }
-    return rc;
-}
-
 static nsresult LoadGtkModule(GnomeAccessibilityModule& aModule);
 
 static gboolean toplevel_event_watcher(GSignalInvocationHint*, guint,
                                        const GValue*, gpointer);
 
 // ApplicationAccessibleWrap
 
 ApplicationAccessibleWrap::ApplicationAccessibleWrap():
   ApplicationAccessible()
 {
-  MAI_LOG_DEBUG(("======Create AppRootAcc=%p\n", (void*)this));
-
   if (ShouldA11yBeEnabled()) {
       // Load and initialize gail library.
       nsresult rv = LoadGtkModule(sGail);
-      if (NS_SUCCEEDED(rv)) {
+      if (NS_SUCCEEDED(rv))
           (*sGail.init)();
-      } else {
-          MAI_LOG_DEBUG(("Fail to load lib: %s\n", sGail.libName));
-      }
   }
 }
 
 // XXX we can't do this in ApplicationAccessibleWrap's constructor because
 // a11y::ApplicationAcc() will return null then which breaks atk's attempt to
 // get the application's root accessible during initialization.  this needs to
 // be defined here because LoadGtkModule() and the library info is static.  See
 // bug 817133.
 void
 nsAccessNodeWrap::InitAccessibility()
 {
   if (!ShouldA11yBeEnabled())
     return;
 
   // Initialize the MAI Utility class, it will overwrite gail_util.
-  g_type_class_unref(g_type_class_ref(MAI_TYPE_UTIL));
+  g_type_class_unref(g_type_class_ref(mai_util_get_type()));
 
   // Init atk-bridge now
   PR_SetEnv("NO_AT_BRIDGE=0");
   nsresult rv = LoadGtkModule(sAtkBridge);
   if (NS_SUCCEEDED(rv)) {
     (*sAtkBridge.init)();
-  } else {
-    MAI_LOG_DEBUG(("Fail to load lib: %s\n", sAtkBridge.libName));
   }
 
   if (!sToplevel_event_hook_added) {
     sToplevel_event_hook_added = true;
     sToplevel_show_hook =
       g_signal_add_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
                                  0, toplevel_event_watcher,
                                  reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_SHOW),
@@ -568,17 +120,16 @@ nsAccessNodeWrap::InitAccessibility()
                                  reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_HIDE),
                                  NULL);
   }
 }
 
 
 ApplicationAccessibleWrap::~ApplicationAccessibleWrap()
 {
-  MAI_LOG_DEBUG(("======Destory AppRootAcc=%p\n", (void*)this));
   AccessibleWrap::ShutdownAtkObject();
 }
 
 static gboolean
 toplevel_event_watcher(GSignalInvocationHint* ihint,
                        guint                  n_param_values,
                        const GValue*          param_values,
                        gpointer               data)
@@ -783,64 +334,54 @@ ApplicationAccessibleWrap::PreCreate()
 }
 
 static nsresult
 LoadGtkModule(GnomeAccessibilityModule& aModule)
 {
     NS_ENSURE_ARG(aModule.libName);
 
     if (!(aModule.lib = PR_LoadLibrary(aModule.libName))) {
-
-        MAI_LOG_DEBUG(("Fail to load lib: %s in default path\n", aModule.libName));
-
         //try to load the module with "gtk-2.0/modules" appended
         char *curLibPath = PR_GetLibraryPath();
         nsAutoCString libPath(curLibPath);
 #if defined(LINUX) && defined(__x86_64__)
         libPath.Append(":/usr/lib64:/usr/lib");
 #else
         libPath.Append(":/usr/lib");
 #endif
-        MAI_LOG_DEBUG(("Current Lib path=%s\n", libPath.get()));
         PR_FreeLibraryName(curLibPath);
 
         int16_t loc1 = 0, loc2 = 0;
         int16_t subLen = 0;
         while (loc2 >= 0) {
             loc2 = libPath.FindChar(':', loc1);
             if (loc2 < 0)
                 subLen = libPath.Length() - loc1;
             else
                 subLen = loc2 - loc1;
             nsAutoCString sub(Substring(libPath, loc1, subLen));
             sub.Append("/gtk-2.0/modules/");
             sub.Append(aModule.libName);
             aModule.lib = PR_LoadLibrary(sub.get());
-            if (aModule.lib) {
-                MAI_LOG_DEBUG(("Ok, load %s from %s\n", aModule.libName, sub.get()));
+            if (aModule.lib)
                 break;
-            }
+
             loc1 = loc2+1;
         }
-        if (!aModule.lib) {
-            MAI_LOG_DEBUG(("Fail to load %s\n", aModule.libName));
+        if (!aModule.lib)
             return NS_ERROR_FAILURE;
-        }
     }
 
     //we have loaded the library, try to get the function ptrs
     if (!(aModule.init = PR_FindFunctionSymbol(aModule.lib,
                                                aModule.initName)) ||
         !(aModule.shutdown = PR_FindFunctionSymbol(aModule.lib,
                                                    aModule.shutdownName))) {
 
         //fail, :(
-        MAI_LOG_DEBUG(("Fail to find symbol %s in %s",
-                       aModule.init ? aModule.shutdownName : aModule.initName,
-                       aModule.libName));
         PR_UnloadLibrary(aModule.lib);
         aModule.lib = NULL;
         return NS_ERROR_FAILURE;
     }
     return NS_OK;
 }
 
 namespace mozilla {
--- a/accessible/src/atk/InterfaceInitFuncs.h
+++ b/accessible/src/atk/InterfaceInitFuncs.h
@@ -12,16 +12,18 @@
 namespace mozilla {
 namespace a11y {
 
 class AccessibleWrap;
 
 } // namespace a11y
 } // namespace mozilla
 
+struct MaiUtilClass;
+
 extern "C" {
 void actionInterfaceInitCB(AtkActionIface* aIface);
 void componentInterfaceInitCB(AtkComponentIface* aIface);
 void documentInterfaceInitCB(AtkDocumentIface *aIface);
 void editableTextInterfaceInitCB(AtkEditableTextIface* aIface);
 void hyperlinkImplInterfaceInitCB(AtkHyperlinkImplIface *aIface);
 void hypertextInterfaceInitCB(AtkHypertextIface* aIface);
 void imageInterfaceInitCB(AtkImageIface* aIface);
--- a/accessible/src/atk/Makefile.in
+++ b/accessible/src/atk/Makefile.in
@@ -29,16 +29,17 @@ CPPSRCS = \
   nsMaiInterfaceValue.cpp \
   nsMaiHyperlink.cpp \
   nsMaiInterfaceHypertext.cpp \
   nsMaiInterfaceHyperlinkImpl.cpp \
   nsMaiInterfaceTable.cpp \
   nsMaiInterfaceDocument.cpp \
   nsMaiInterfaceImage.cpp \
   RootAccessibleWrap.cpp \
+  UtilInterface.cpp \
   $(NULL)
 
 EXPORTS = \
   nsAccessNodeWrap.h \
   $(NULL)
 
 EXPORTS_NAMESPACES = mozilla/a11y
 
new file mode 100644
--- /dev/null
+++ b/accessible/src/atk/UtilInterface.cpp
@@ -0,0 +1,404 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "ApplicationAccessibleWrap.h"
+#include "mozilla/Likely.h"
+#include "nsAccessibilityService.h"
+#include "nsMai.h"
+
+#include <atk/atk.h>
+#include <gtk/gtk.h>
+#include <string.h>
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+typedef AtkUtil MaiUtil;
+typedef AtkUtilClass MaiUtilClass;
+
+#define MAI_VERSION MOZILLA_VERSION
+#define MAI_NAME "Gecko"
+
+extern "C" {
+static guint (*gail_add_global_event_listener)(GSignalEmissionHook listener,
+                                               const gchar* event_type);
+static void (*gail_remove_global_event_listener) (guint remove_listener);
+static void (*gail_remove_key_event_listener) (guint remove_listener);
+static AtkObject*  (*gail_get_root)();
+}
+
+struct MaiUtilListenerInfo
+{
+  gint key;
+  guint signal_id;
+  gulong hook_id;
+  // For window create/destory/minimize/maximize/restore/activate/deactivate
+  // events, we'll chain gail_util's add/remove_global_event_listener.
+  // So we store the listenerid returned by gail's add_global_event_listener
+  // in this structure to call gail's remove_global_event_listener later.
+  guint gail_listenerid;
+};
+
+static GHashTable* sListener_list = NULL;
+static gint sListener_idx = 1;
+
+extern "C" {
+static guint
+add_listener (GSignalEmissionHook listener,
+              const gchar *object_type,
+              const gchar *signal,
+              const gchar *hook_data,
+              guint gail_listenerid = 0)
+{
+    GType type;
+    guint signal_id;
+    gint rc = 0;
+
+    type = g_type_from_name(object_type);
+    if (type) {
+        signal_id = g_signal_lookup(signal, type);
+        if (signal_id > 0) {
+            MaiUtilListenerInfo *listener_info;
+
+            rc = sListener_idx;
+
+            listener_info =  (MaiUtilListenerInfo *)
+                g_malloc(sizeof(MaiUtilListenerInfo));
+            listener_info->key = sListener_idx;
+            listener_info->hook_id =
+                g_signal_add_emission_hook(signal_id, 0, listener,
+                                           g_strdup(hook_data),
+                                           (GDestroyNotify)g_free);
+            listener_info->signal_id = signal_id;
+            listener_info->gail_listenerid = gail_listenerid;
+
+            g_hash_table_insert(sListener_list, &(listener_info->key),
+                                listener_info);
+            sListener_idx++;
+        }
+        else {
+            g_warning("Invalid signal type %s\n", signal);
+        }
+    }
+    else {
+        g_warning("Invalid object type %s\n", object_type);
+    }
+    return rc;
+}
+
+static guint
+mai_util_add_global_event_listener(GSignalEmissionHook listener,
+                                   const gchar *event_type)
+{
+    guint rc = 0;
+    gchar **split_string;
+
+    split_string = g_strsplit (event_type, ":", 3);
+
+    if (split_string) {
+        if (!strcmp ("window", split_string[0])) {
+            guint gail_listenerid = 0;
+            if (gail_add_global_event_listener) {
+                // call gail's function to track gtk native window events
+                gail_listenerid =
+                    gail_add_global_event_listener(listener, event_type);
+            }
+
+            rc = add_listener (listener, "MaiAtkObject", split_string[1],
+                               event_type, gail_listenerid);
+        }
+        else {
+            rc = add_listener (listener, split_string[1], split_string[2],
+                               event_type);
+        }
+        g_strfreev(split_string);
+    }
+    return rc;
+}
+
+static void
+mai_util_remove_global_event_listener(guint remove_listener)
+{
+    if (remove_listener > 0) {
+        MaiUtilListenerInfo *listener_info;
+        gint tmp_idx = remove_listener;
+
+        listener_info = (MaiUtilListenerInfo *)
+            g_hash_table_lookup(sListener_list, &tmp_idx);
+
+        if (listener_info != NULL) {
+            if (gail_remove_global_event_listener &&
+                listener_info->gail_listenerid) {
+              gail_remove_global_event_listener(listener_info->gail_listenerid);
+            }
+
+            /* Hook id of 0 and signal id of 0 are invalid */
+            if (listener_info->hook_id != 0 && listener_info->signal_id != 0) {
+                /* Remove the emission hook */
+                g_signal_remove_emission_hook(listener_info->signal_id,
+                                              listener_info->hook_id);
+
+                /* Remove the element from the hash */
+                g_hash_table_remove(sListener_list, &tmp_idx);
+            }
+            else {
+                g_warning("Invalid listener hook_id %ld or signal_id %d\n",
+                          listener_info->hook_id, listener_info->signal_id);
+            }
+        }
+        else {
+            // atk-bridge is initialized with gail (e.g. yelp)
+            // try gail_remove_global_event_listener
+            if (gail_remove_global_event_listener) {
+                return gail_remove_global_event_listener(remove_listener);
+            }
+
+            g_warning("No listener with the specified listener id %d",
+                      remove_listener);
+        }
+    }
+    else {
+        g_warning("Invalid listener_id %d", remove_listener);
+    }
+}
+
+static AtkKeyEventStruct *
+atk_key_event_from_gdk_event_key (GdkEventKey *key)
+{
+    AtkKeyEventStruct *event = g_new0(AtkKeyEventStruct, 1);
+    switch (key->type) {
+    case GDK_KEY_PRESS:
+        event->type = ATK_KEY_EVENT_PRESS;
+        break;
+    case GDK_KEY_RELEASE:
+        event->type = ATK_KEY_EVENT_RELEASE;
+        break;
+    default:
+        g_assert_not_reached ();
+        return NULL;
+    }
+    event->state = key->state;
+    event->keyval = key->keyval;
+    event->length = key->length;
+    if (key->string && key->string [0] &&
+        (key->state & GDK_CONTROL_MASK ||
+         g_unichar_isgraph (g_utf8_get_char (key->string)))) {
+        event->string = key->string;
+    }
+    else if (key->type == GDK_KEY_PRESS ||
+             key->type == GDK_KEY_RELEASE) {
+        event->string = gdk_keyval_name (key->keyval);
+    }
+    event->keycode = key->hardware_keycode;
+    event->timestamp = key->time;
+
+    return event;
+}
+
+struct MaiKeyEventInfo
+{
+    AtkKeyEventStruct *key_event;
+    gpointer func_data;
+};
+
+union AtkKeySnoopFuncPointer
+{
+    AtkKeySnoopFunc func_ptr;
+    gpointer data;
+};
+
+static gboolean
+notify_hf(gpointer key, gpointer value, gpointer data)
+{
+    MaiKeyEventInfo *info = (MaiKeyEventInfo *)data;
+    AtkKeySnoopFuncPointer atkKeySnoop;
+    atkKeySnoop.data = value;
+    return (atkKeySnoop.func_ptr)(info->key_event, info->func_data) ? TRUE : FALSE;
+}
+
+static void
+insert_hf(gpointer key, gpointer value, gpointer data)
+{
+    GHashTable *new_table = (GHashTable *) data;
+    g_hash_table_insert (new_table, key, value);
+}
+
+static GHashTable* sKey_listener_list = NULL;
+
+static gint
+mai_key_snooper(GtkWidget *the_widget, GdkEventKey *event, gpointer func_data)
+{
+    /* notify each AtkKeySnoopFunc in turn... */
+
+    MaiKeyEventInfo *info = g_new0(MaiKeyEventInfo, 1);
+    gint consumed = 0;
+    if (sKey_listener_list) {
+        GHashTable *new_hash = g_hash_table_new(NULL, NULL);
+        g_hash_table_foreach (sKey_listener_list, insert_hf, new_hash);
+        info->key_event = atk_key_event_from_gdk_event_key (event);
+        info->func_data = func_data;
+        consumed = g_hash_table_foreach_steal (new_hash, notify_hf, info);
+        g_hash_table_destroy (new_hash);
+        g_free(info->key_event);
+    }
+    g_free(info);
+    return (consumed ? 1 : 0);
+}
+
+static guint sKey_snooper_id = 0;
+
+static guint
+mai_util_add_key_event_listener (AtkKeySnoopFunc listener,
+                                 gpointer data)
+{
+  if (MOZ_UNLIKELY(!listener))
+    return 0;
+
+    static guint key=0;
+
+    if (!sKey_listener_list) {
+        sKey_listener_list = g_hash_table_new(NULL, NULL);
+        sKey_snooper_id = gtk_key_snooper_install(mai_key_snooper, data);
+    }
+    AtkKeySnoopFuncPointer atkKeySnoop;
+    atkKeySnoop.func_ptr = listener;
+    g_hash_table_insert(sKey_listener_list, GUINT_TO_POINTER (key++),
+                        atkKeySnoop.data);
+    return key;
+}
+
+static void
+mai_util_remove_key_event_listener (guint remove_listener)
+{
+    if (!sKey_listener_list) {
+        // atk-bridge is initialized with gail (e.g. yelp)
+        // try gail_remove_key_event_listener
+        return gail_remove_key_event_listener(remove_listener);
+    }
+
+    g_hash_table_remove(sKey_listener_list, GUINT_TO_POINTER (remove_listener));
+    if (g_hash_table_size(sKey_listener_list) == 0) {
+        gtk_key_snooper_remove(sKey_snooper_id);
+    }
+}
+
+static AtkObject*
+mai_util_get_root()
+{
+  ApplicationAccessible* app = ApplicationAcc();
+  if (app)
+    return app->GetAtkObject();
+
+  // We've shutdown, try to use gail instead
+  // (to avoid assert in spi_atk_tidy_windows())
+  // XXX tbsaunde then why didn't we replace the gail atk_util impl?
+  if (gail_get_root)
+    return gail_get_root();
+
+  return nullptr;
+}
+
+static const gchar*
+mai_util_get_toolkit_name()
+{
+    return MAI_NAME;
+}
+
+static const gchar*
+mai_util_get_toolkit_version()
+{
+    return MAI_VERSION;
+}
+
+static void
+_listener_info_destroy(gpointer data)
+{
+    g_free(data);
+}
+
+static void
+window_added (AtkObject *atk_obj,
+              guint     index,
+              AtkObject *child)
+{
+  if (!IS_MAI_OBJECT(child))
+      return;
+
+  static guint id =  g_signal_lookup ("create", MAI_TYPE_ATK_OBJECT);
+  g_signal_emit (child, id, 0);
+}
+
+static void
+window_removed (AtkObject *atk_obj,
+                guint     index,
+                AtkObject *child)
+{
+  if (!IS_MAI_OBJECT(child))
+      return;
+
+  static guint id =  g_signal_lookup ("destroy", MAI_TYPE_ATK_OBJECT);
+  g_signal_emit (child, id, 0);
+}
+
+  static void
+UtilInterfaceInit(MaiUtilClass* klass)
+{
+    AtkUtilClass *atk_class;
+    gpointer data;
+
+    data = g_type_class_peek(ATK_TYPE_UTIL);
+    atk_class = ATK_UTIL_CLASS(data);
+
+    // save gail function pointer
+    gail_add_global_event_listener = atk_class->add_global_event_listener;
+    gail_remove_global_event_listener = atk_class->remove_global_event_listener;
+    gail_remove_key_event_listener = atk_class->remove_key_event_listener;
+    gail_get_root = atk_class->get_root;
+
+    atk_class->add_global_event_listener =
+        mai_util_add_global_event_listener;
+    atk_class->remove_global_event_listener =
+        mai_util_remove_global_event_listener;
+    atk_class->add_key_event_listener = mai_util_add_key_event_listener;
+    atk_class->remove_key_event_listener = mai_util_remove_key_event_listener;
+    atk_class->get_root = mai_util_get_root;
+    atk_class->get_toolkit_name = mai_util_get_toolkit_name;
+    atk_class->get_toolkit_version = mai_util_get_toolkit_version;
+
+    sListener_list = g_hash_table_new_full(g_int_hash, g_int_equal, NULL,
+                                           _listener_info_destroy);
+    // Keep track of added/removed windows.
+    AtkObject *root = atk_get_root ();
+    g_signal_connect (root, "children-changed::add", (GCallback) window_added, NULL);
+    g_signal_connect (root, "children-changed::remove", (GCallback) window_removed, NULL);
+}
+}
+
+GType
+mai_util_get_type()
+{
+    static GType type = 0;
+
+    if (!type) {
+        static const GTypeInfo tinfo = {
+            sizeof(MaiUtilClass),
+            (GBaseInitFunc) NULL, /* base init */
+            (GBaseFinalizeFunc) NULL, /* base finalize */
+            (GClassInitFunc) UtilInterfaceInit, /* class init */
+            (GClassFinalizeFunc) NULL, /* class finalize */
+            NULL, /* class data */
+            sizeof(MaiUtil), /* instance size */
+            0, /* nb preallocs */
+            (GInstanceInitFunc) NULL, /* instance init */
+            NULL /* value table */
+        };
+
+        type = g_type_register_static(ATK_TYPE_UTIL,
+                                      "MaiUtil", &tinfo, GTypeFlags(0));
+    }
+    return type;
+}
+
--- a/accessible/src/atk/nsMai.h
+++ b/accessible/src/atk/nsMai.h
@@ -8,44 +8,26 @@
 #define __NS_MAI_H__
 
 #include <atk/atk.h>
 #include <glib.h>
 #include <glib-object.h>
 
 #include "AccessibleWrap.h"
 
-extern PRLogModuleInfo *gMaiLog;
-
-#ifdef MAI_LOGGING
-#define MAI_LOG(level, args) \
-PR_BEGIN_MACRO \
-    if (!gMaiLog) { \
-        gMaiLog = PR_NewLogModule("Mai"); \
-        PR_ASSERT(gMaiLog); \
-    } \
-    PR_LOG(gMaiLog, (level), args); \
-PR_END_MACRO
-#else
-#define MAI_LOG(level, args) 
-#endif
-
-#define MAI_LOG_DEBUG(args) MAI_LOG(PR_LOG_DEBUG, args)
-#define MAI_LOG_WARNING(args) MAI_LOG(PR_LOG_WARNING, args)
-#define MAI_LOG_ERROR(args) MAI_LOG(PR_LOG_ERROR, args)
-
 #define MAI_TYPE_ATK_OBJECT             (mai_atk_object_get_type ())
 #define MAI_ATK_OBJECT(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
                                          MAI_TYPE_ATK_OBJECT, MaiAtkObject))
 #define MAI_ATK_OBJECT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), \
                                          MAI_TYPE_ATK_OBJECT, \
                                          MaiAtkObjectClass))
 #define IS_MAI_OBJECT(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
                                          MAI_TYPE_ATK_OBJECT))
 #define IS_MAI_OBJECT_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), \
                                          MAI_TYPE_ATK_OBJECT))
 #define MAI_ATK_OBJECT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), \
                                          MAI_TYPE_ATK_OBJECT, \
                                          MaiAtkObjectClass))
 GType mai_atk_object_get_type(void);
+GType mai_util_get_type();
 mozilla::a11y::AccessibleWrap* GetAccessibleWrap(AtkObject* aAtkObj);
 
 #endif /* __NS_MAI_H__ */
--- a/accessible/src/atk/nsMaiInterfaceEditableText.cpp
+++ b/accessible/src/atk/nsMaiInterfaceEditableText.cpp
@@ -21,18 +21,16 @@ setTextContentsCB(AtkEditableText *aText
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (!accWrap)
     return;
 
   HyperTextAccessible* text = accWrap->AsHyperText();
   if (!text || !text->IsTextRole())
     return;
 
-  MAI_LOG_DEBUG(("EditableText: setTextContentsCB, aString=%s", aString));
-
   NS_ConvertUTF8toUTF16 strContent(aString);
   text->SetTextContents(strContent);
 }
 
 static void
 insertTextCB(AtkEditableText *aText,
              const gchar *aString, gint aLength, gint *aPosition)
 {
@@ -41,81 +39,71 @@ insertTextCB(AtkEditableText *aText,
     return;
 
   HyperTextAccessible* text = accWrap->AsHyperText();
   if (!text || !text->IsTextRole())
     return;
 
   NS_ConvertUTF8toUTF16 strContent(aString, aLength);
   text->InsertText(strContent, *aPosition);
-
-  MAI_LOG_DEBUG(("EditableText: insert aString=%s, aLength=%d, aPosition=%d",
-                 aString, aLength, *aPosition));
 }
 
 static void
 copyTextCB(AtkEditableText *aText, gint aStartPos, gint aEndPos)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (!accWrap)
     return;
 
   HyperTextAccessible* text = accWrap->AsHyperText();
   if (!text || !text->IsTextRole())
     return;
 
-  MAI_LOG_DEBUG(("EditableText: copyTextCB, aStartPos=%d, aEndPos=%d",
-                 aStartPos, aEndPos));
   text->CopyText(aStartPos, aEndPos);
 }
 
 static void
 cutTextCB(AtkEditableText *aText, gint aStartPos, gint aEndPos)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (!accWrap)
     return;
 
   HyperTextAccessible* text = accWrap->AsHyperText();
   if (!text || !text->IsTextRole())
     return;
 
-  MAI_LOG_DEBUG(("EditableText: cutTextCB, aStartPos=%d, aEndPos=%d",
-                 aStartPos, aEndPos));
   text->CutText(aStartPos, aEndPos);
 }
 
 static void
 deleteTextCB(AtkEditableText *aText, gint aStartPos, gint aEndPos)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (!accWrap)
     return;
 
   HyperTextAccessible* text = accWrap->AsHyperText();
   if (!text || !text->IsTextRole())
     return;
 
-  MAI_LOG_DEBUG(("EditableText: deleteTextCB, aStartPos=%d, aEndPos=%d",
-                 aStartPos, aEndPos));
   text->DeleteText(aStartPos, aEndPos);
 }
 
 static void
 pasteTextCB(AtkEditableText *aText, gint aPosition)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (!accWrap)
     return;
 
   HyperTextAccessible* text = accWrap->AsHyperText();
   if (!text || !text->IsTextRole())
     return;
 
-  MAI_LOG_DEBUG(("EditableText: pasteTextCB, aPosition=%d", aPosition));
   text->PasteText(aPosition);
 }
 }
 
 void
 editableTextInterfaceInitCB(AtkEditableTextIface* aIface)
 {
   NS_ASSERTION(aIface, "Invalid aIface");
--- a/accessible/src/jsat/Makefile.in
+++ b/accessible/src/jsat/Makefile.in
@@ -7,19 +7,17 @@ topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 INSTALL_TARGETS += ACCESSFU
 
 ACCESSFU_FILES := \
-  AccessFu.css \
   AccessFu.jsm \
-  content-script.js \
   EventManager.jsm \
   jar.mn \
   Makefile.in \
   Presenters.jsm \
   TouchAdapter.jsm \
   TraversalRules.jsm \
   Utils.jsm \
   UtteranceGenerator.jsm \
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -59,46 +59,42 @@ SettingsListener.init();
 SettingsListener.observe('audio.volume.master', 0.5, function(value) {
   let audioManager = Services.audioManager;
   if (!audioManager)
     return;
 
   audioManager.masterVolume = Math.max(0.0, Math.min(value, 1.0));
 });
 
-let audioSettings = [];
+let audioChannelSettings = [];
 
 if ("nsIAudioManager" in Ci) {
   const nsIAudioManager = Ci.nsIAudioManager;
-  audioSettings = [
-    // settings name, default value, stream type
-    ['audio.volume.voice_call', 10, nsIAudioManager.STREAM_TYPE_VOICE_CALL],
-    ['audio.volume.system', 15,  nsIAudioManager.STREAM_TYPE_SYSTEM],
-    ['audio.volume.ring', 7, nsIAudioManager.STREAM_TYPE_RING],
-    ['audio.volume.music', 15, nsIAudioManager.STREAM_TYPE_MUSIC],
-    ['audio.volume.alarm', 7, nsIAudioManager.STREAM_TYPE_ALARM],
-    ['audio.volume.notification', 7, nsIAudioManager.STREAM_TYPE_NOTIFICATION],
-    ['audio.volume.bt_sco', 15, nsIAudioManager.STREAM_TYPE_BLUETOOTH_SCO],
-    ['audio.volume.enforced_audible', 7, nsIAudioManager.STREAM_TYPE_ENFORCED_AUDIBLE],
-    ['audio.volume.dtmf', 15, nsIAudioManager.STREAM_TYPE_DTMF],
-    ['audio.volume.tts', 15, nsIAudioManager.STREAM_TYPE_TTS],
-    ['audio.volume.fm', 15, nsIAudioManager.STREAM_TYPE_FM],
+  audioChannelSettings = [
+    // settings name, max value, apply to stream types
+    ['audio.volume.content', 15, [nsIAudioManager.STREAM_TYPE_SYSTEM, nsIAudioManager.STREAM_TYPE_MUSIC, nsIAudioManager.STREAM_TYPE_FM]],
+    ['audio.volume.notification', 15, [nsIAudioManager.STREAM_TYPE_RING, nsIAudioManager.STREAM_TYPE_NOTIFICATION]],
+    ['audio.volume.alarm', 15, [nsIAudioManager.STREAM_TYPE_ALARM]],
+    ['audio.volume.telephony', 5, [nsIAudioManager.STREAM_TYPE_VOICE_CALL]],
+    ['audio.volume.bt_sco', 15, [nsIAudioManager.STREAM_TYPE_BLUETOOTH_SCO]],
   ];
 }
 
-for each (let [setting, defaultValue, streamType] in audioSettings) {
-  (function AudioStreamSettings(s, d, t) {
-    SettingsListener.observe(s, d, function(value) {
+for each (let [setting, maxValue, streamTypes] in audioChannelSettings) {
+  (function AudioStreamSettings(setting, maxValue, streamTypes) {
+    SettingsListener.observe(setting, maxValue, function(value) {
       let audioManager = Services.audioManager;
       if (!audioManager)
         return;
 
-      audioManager.setStreamVolumeIndex(t, Math.min(value, d));
+      for each(let streamType in streamTypes) {
+        audioManager.setStreamVolumeIndex(streamType, Math.min(value, maxValue));
+      }
     });
-  })(setting, defaultValue, streamType);
+  })(setting, maxValue, streamTypes);
 }
 
 // =================== Console ======================
 
 SettingsListener.observe('debug.console.enabled', true, function(value) {
   Services.prefs.setBoolPref('consoleservice.enabled', value);
 });
 
@@ -152,54 +148,59 @@ SettingsListener.observe('language.curre
 //=================== DeviceInfo ====================
 Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
 Components.utils.import('resource://gre/modules/ctypes.jsm');
 (function DeviceInfoToSettings() {
   XPCOMUtils.defineLazyServiceGetter(this, 'gSettingsService',
                                      '@mozilla.org/settingsService;1',
                                      'nsISettingsService');
   let lock = gSettingsService.createLock();
-  //MOZ_B2G_VERSION is set in b2g/confvars.sh, and is outputed as a #define value
-  //from configure.in, defaults to 1.0.0 if this value is not exist
+  // MOZ_B2G_VERSION is set in b2g/confvars.sh, and is output as a #define value
+  // from configure.in, defaults to 1.0.0 if this value is not exist.
 #filter attemptSubstitution
   let os_version = '@MOZ_B2G_VERSION@';
+  let os_name = '@MOZ_B2G_OS_NAME@';
 #unfilter attemptSubstitution
   lock.set('deviceinfo.os', os_version, null, null);
+  lock.set('deviceinfo.software', os_name + ' ' + os_version, null, null);
 
   let appInfo = Cc["@mozilla.org/xre/app-info;1"]
                   .getService(Ci.nsIXULAppInfo);
   lock.set('deviceinfo.platform_version', appInfo.platformVersion, null, null);
   lock.set('deviceinfo.platform_build_id', appInfo.platformBuildID, null, null);
 
   let update_channel = Services.prefs.getCharPref('app.update.channel');
   lock.set('deviceinfo.update_channel', update_channel, null, null);
 
-  //Get the hardware info from android properties
-  let hardware_version = null;
+  // Get the hardware info and firmware revision from device properties.
+  let hardware_info = null;
+  let firmware_revision = null;
   try {
     let cutils = ctypes.open('libcutils.so');
     let cbuf = ctypes.char.array(128)();
     let c_property_get = cutils.declare('property_get', ctypes.default_abi,
                                         ctypes.int,       // return value: length
                                         ctypes.char.ptr,  // key
                                         ctypes.char.ptr,  // value
                                         ctypes.char.ptr); // default
     let property_get = function (key, defaultValue) {
       if (defaultValue === undefined) {
         defaultValue = null;
       }
       c_property_get(key, cbuf, defaultValue);
       return cbuf.readString();
     }
-    hardware_version = property_get('ro.hardware');
+    hardware_info = property_get('ro.hardware');
+    firmware_revision = property_get('ro.firmware_revision');
     cutils.close();
   } catch(e) {
-    //Error
+    // Error.
   }
-  lock.set('deviceinfo.hardware', hardware_version, null, null);
+  lock.set('deviceinfo.hardware', hardware_info, null, null);
+  lock.set('deviceinfo.firmware_revision', firmware_revision, null, null);
 })();
 
 // =================== Debugger ====================
 SettingsListener.observe('devtools.debugger.remote-enabled', false, function(value) {
   Services.prefs.setBoolPref('devtools.debugger.remote-enabled', value);
   // This preference is consulted during startup
   Services.prefs.savePrefFile(null);
   value ? startDebugger() : stopDebugger();
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -923,16 +923,25 @@ window.addEventListener('ContentStart', 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     shell.sendChromeEvent({
       type: 'headphones-status-changed',
       state: aData
     });
 }, "headphones-status-changed", false);
 })();
 
+(function audioChannelChangedTracker() {
+  Services.obs.addObserver(function(aSubject, aTopic, aData) {
+    shell.sendChromeEvent({
+      type: 'audio-channel-changed',
+      channel: aData
+    });
+}, "audio-channel-changed", false);
+})();
+
 (function recordingStatusTracker() {
   let gRecordingActiveCount = 0;
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     let oldCount = gRecordingActiveCount;
     if (aData == "starting") {
       gRecordingActiveCount += 1;
     } else if (aData == "shutdown") {
--- a/b2g/components/SignInToWebsite.jsm
+++ b/b2g/components/SignInToWebsite.jsm
@@ -71,17 +71,17 @@
 
 this.EXPORTED_SYMBOLS = ["SignInToWebsiteController"];
 
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/IdentityUtils.jsm");
+Cu.import("resource://gre/modules/identity/IdentityUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "IdentityService",
                                   "resource://gre/modules/identity/MinimalIdentity.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Logger",
                                   "resource://gre/modules/identity/LogUtils.jsm");
 
 // JS shim that contains the callback functions that
--- a/b2g/config/otoro/config.json
+++ b/b2g/config/otoro/config.json
@@ -1,24 +1,32 @@
 {
     "config_version": 1,
     "tooltool_manifest": "releng-otoro.tt",
     "mock_target": "mozilla-centos6-i386",
     "mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel"],
     "mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
     "build_targets": [],
     "upload_files": [
-        "{workdir}/out/target/product/otoro/*.img",
         "{objdir}/dist/b2g-update/*.mar",
         "{objdir}/dist/b2g-*.tar.gz",
         "{objdir}/dist/b2g-*.crashreporter-symbols.zip",
         "{workdir}/sources.xml"
     ],
+    "zip_files": [
+        ["{workdir}/out/target/product/otoro/*.img", "out/target/product/otoro/"],
+        "{workdir}/boot.img",
+        "{workdir}/flash.sh",
+        "{workdir}/load-config.sh",
+        "{workdir}/.config",
+        "{workdir}/sources.xml"
+    ],
     "env": {
         "VARIANT": "user",
+        "MOZILLA_OFFICIAL": "1",
         "B2GUPDATER": "1"
     },
     "gaia": {
         "vcs": "hgtool",
         "repo": "http://hg.mozilla.org/integration/gaia-nightly",
         "l10n": {
             "vcs": "hgtool",
             "root": "http://hg.mozilla.org/gaia-l10n"
--- a/b2g/config/otoro/releng-otoro.tt
+++ b/b2g/config/otoro/releng-otoro.tt
@@ -1,8 +1,14 @@
 [
 {
 "size": 868355892,
 "digest": "0ccae39ee8910947fe3cf51fa3a45e820d2ff11571f6ccec29d9b3e5ae7f7709c1ad657210fbfea98baadd032c3d6a58e00ddbb2e93acafd751089869a72fed6",
 "algorithm": "sha512",
 "filename": "gonk.tar.xz"
+},
+{
+"size": 4139008,
+"digest": "b1eac90cebe52708d512bbc293c507da9d93bc8c6a78cbbbd78cc9b7beb2cd335bef9bf8e4bf5a9dc38521f7080d29a743626f9e4af6c42ec211db22dc9d0fda",
+"algorithm": "sha512",
+"filename": "boot.img"
 }
 ]
new file mode 120000
--- /dev/null
+++ b/b2g/config/panda-gaia-central/README
@@ -0,0 +1,1 @@
+../panda/README
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/b2g/config/panda-gaia-central/config.json
@@ -0,0 +1,24 @@
+{
+    "config_version": 1,
+    "tooltool_manifest": "releng-pandaboard.tt",
+    "mock_target": "mozilla-centos6-i386",
+    "mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel"],
+    "mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
+    "build_targets": ["boottarball", "systemtarball", "userdatatarball"],
+    "upload_files": [
+        "{workdir}/out/target/product/panda/*.tar.bz2",
+        "{objdir}/dist/b2g-update/*.mar",
+        "{objdir}/dist/b2g-*.tar.gz",
+        "{objdir}/dist/b2g-*.crashreporter-symbols.zip",
+        "{srcdir}/b2g/config/panda/README",
+        "{workdir}/sources.xml"
+    ],
+    "gaia": {
+        "vcs": "hgtool",
+        "repo": "http://hg.mozilla.org/integration/gaia-central",
+        "l10n": {
+            "vcs": "hgtool",
+            "root": "http://hg.mozilla.org/gaia-l10n"
+        }
+    }
+}
new file mode 120000
--- /dev/null
+++ b/b2g/config/panda-gaia-central/releng-pandaboard.tt
@@ -0,0 +1,1 @@
+../panda/releng-pandaboard.tt
\ No newline at end of file
new file mode 120000
--- /dev/null
+++ b/b2g/config/panda-gaia-central/sources.xml
@@ -0,0 +1,1 @@
+../panda/sources.xml
\ No newline at end of file
--- a/b2g/config/tooltool-manifests/macosx64/releng.manifest
+++ b/b2g/config/tooltool-manifests/macosx64/releng.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r168596"
+"clang_version": "r169139"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 56147341,
-"digest": "4baed5cbe0189a509b6a328ee35ee488250677f8ea149e6d01af74c7a4a27c898a4112f78af57b33a4e788b2947813b65ab0922e06b67bd504878803dab44f5c",
+"size": 56158651,
+"digest": "38d718f20a8fa9218e22ade312e724e6c9cdd7c6650e023cfdc21b5505fe7aa3743ae41c0abd717a1bbccec4c4271be2fa82d0e2f96c91e693d70e33b4dc00d6",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/b2g/config/unagi/config.json
+++ b/b2g/config/unagi/config.json
@@ -1,24 +1,32 @@
 {
     "config_version": 1,
     "tooltool_manifest": "releng-unagi.tt",
     "mock_target": "mozilla-centos6-i386",
     "mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel"],
     "mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
     "build_targets": [],
     "upload_files": [
-        "{workdir}/out/target/product/unagi/*.img",
         "{objdir}/dist/b2g-update/*.mar",
         "{objdir}/dist/b2g-*.tar.gz",
         "{objdir}/dist/b2g-*.crashreporter-symbols.zip",
         "{workdir}/sources.xml"
     ],
+    "zip_files": [
+        ["{workdir}/out/target/product/unagi/*.img", "out/target/product/unagi/"],
+        "{workdir}/boot.img",
+        "{workdir}/flash.sh",
+        "{workdir}/load-config.sh",
+        "{workdir}/.config",
+        "{workdir}/sources.xml"
+    ],
     "env": {
         "VARIANT": "user",
+        "MOZILLA_OFFICIAL": "1",
         "B2GUPDATER": "1"
     },
     "gaia": {
         "vcs": "hgtool",
         "repo": "http://hg.mozilla.org/integration/gaia-nightly",
         "l10n": {
             "vcs": "hgtool",
             "root": "http://hg.mozilla.org/gaia-l10n"
--- a/b2g/config/unagi/releng-unagi.tt
+++ b/b2g/config/unagi/releng-unagi.tt
@@ -1,8 +1,14 @@
 [
 {
 "size": 805101852,
 "digest": "553e88831f0760ef8de039a037c91499ff9334691f0532835c73a44352750a4911752cf0d5346f5e023f64b2351ed7f49a2a833c27538ddde59ad505f50ab063",
 "algorithm": "sha512",
 "filename": "gonk.tar.xz"
+},
+{
+"size": 8859648,
+"digest": "05d4a99e0f36cd91d1b10a2b558979ea776e9a7e03b8a921af3b0bfc62e2d96cf4faa20586c39885b6f8b25089fe07726794620a3b18c4826a2f71e29d90a8ef",
+"algorithm": "sha512",
+"filename": "boot.img"
 }
 ]
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -6,16 +6,17 @@ MOZ_APP_BASENAME=B2G
 MOZ_APP_VENDOR=Mozilla
 
 MOZ_APP_VERSION=20.0a1
 MOZ_APP_UA_NAME=Firefox
 
 MOZ_UA_OS_AGNOSTIC=1
 
 MOZ_B2G_VERSION=1.0.0-prerelease
+MOZ_B2G_OS_NAME=Boot2Gecko
 
 MOZ_BRANDING_DIRECTORY=b2g/branding/unofficial
 MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/branding/official
 # MOZ_APP_DISPLAYNAME is set by branding/configure.sh
 
 MOZ_SAFE_BROWSING=
 MOZ_SERVICES_COMMON=1
 MOZ_SERVICES_HEALTHREPORT=1
--- a/browser/base/content/browser-appmenu.inc
+++ b/browser/base/content/browser-appmenu.inc
@@ -22,30 +22,30 @@
             <menuitem id="appmenu_newTab_popup"
                       label="&tabCmd.label;"
                       command="cmd_newNavigatorTab"
                       key="key_newNavigatorTab"/>
             <menuitem id="appmenu_newNavigator"
                       label="&newNavigatorCmd.label;"
                       command="cmd_newNavigator"
                       key="key_newNavigator"/>
-#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
-            <menuitem id="appmenu_newPrivateWindow"
-                      label="&newPrivateWindow.label;"
-                      command="Tools:PrivateBrowsing"
-                      key="key_privatebrowsing"/>
-#endif
             <menuseparator/>
             <menuitem id="appmenu_openFile"
                       label="&openFileCmd.label;"
                       command="Browser:OpenFile"
                       key="openFileKb"/>
           </menupopup>
       </splitmenu>
-#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+      <menuitem id="appmenu_newPrivateWindow"
+                class="menuitem-iconic menuitem-iconic-tooltip"
+                label="&newPrivateWindow.label;"
+                command="Tools:PrivateBrowsing"
+                key="key_privatebrowsing"/>
+#else
       <menuitem id="appmenu_privateBrowsing"
                 class="menuitem-iconic menuitem-iconic-tooltip"
                 label="&privateBrowsingCmd.start.label;"
                 startlabel="&privateBrowsingCmd.start.label;"
                 stoplabel="&privateBrowsingCmd.stop.label;"
                 command="Tools:PrivateBrowsing"
                 key="key_privatebrowsing"/>
 #endif
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -22,17 +22,16 @@ let SocialUI = {
     gBrowser.addEventListener("ActivateSocialFeature", this._activationEventHandler, true, true);
 
     // Called when we enter DOM full-screen mode.
     window.addEventListener("mozfullscreenchange", function () {
       SocialSidebar.update();
       SocialChatBar.update();
     });
 
-    this.updateActiveBroadcaster();
     Social.init(this._providerReady.bind(this));
   },
 
   // Called on window unload
   uninit: function SocialUI_uninit() {
     Services.obs.removeObserver(this, "social:pref-changed");
     Services.obs.removeObserver(this, "social:ambient-notification-changed");
     Services.obs.removeObserver(this, "social:profile-changed");
@@ -114,16 +113,17 @@ let SocialUI = {
     // The View->Sidebar and Menubar->Tools menu.
     for (let id of ["menu_socialSidebar", "menu_socialAmbientMenu"])
       document.getElementById(id).setAttribute("label", Social.provider.name);
 
     SocialToolbar.init();
     SocialShareButton.init();
     SocialSidebar.init();
     SocialMenu.populate();
+    this.updateActiveBroadcaster();
   },
 
   updateToggleCommand: function SocialUI_updateToggleCommand() {
     if (!Social.provider)
       return;
 
     let toggleCommand = this.toggleCommand;
     // We only need to update the command itself - all our menu items use it.
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -11,17 +11,16 @@ Cu.import("resource://gre/modules/XPCOMU
 const nsIWebNavigation = Ci.nsIWebNavigation;
 
 var gCharsetMenu = null;
 var gLastBrowserCharset = null;
 var gPrevCharset = null;
 var gProxyFavIcon = null;
 var gLastValidURLStr = "";
 var gInPrintPreviewMode = false;
-var gDownloadMgr = null;
 var gContextMenu = null; // nsContextMenu instance
 var gStartupRan = false;
 
 #ifndef XP_MACOSX
 var gEditUIVisible = true;
 #endif
 
 [
@@ -1334,18 +1333,17 @@ var gBrowserInit = {
     gPrefService.addObserver(allTabs.prefName, allTabs, false);
 
     // Initialize the download manager some time after the app starts so that
     // auto-resume downloads begin (such as after crashing or quitting with
     // active downloads) and speeds up the first-load of the download manager UI.
     // If the user manually opens the download manager before the timeout, the
     // downloads will start right away, and getting the service again won't hurt.
     setTimeout(function() {
-      gDownloadMgr = Cc["@mozilla.org/download-manager;1"].
-                     getService(Ci.nsIDownloadManager);
+      Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
 
 #ifdef XP_WIN
       if (Win7Features) {
         let tempScope = {};
         Cu.import("resource://gre/modules/DownloadTaskbarProgress.jsm",
                   tempScope);
         tempScope.DownloadTaskbarProgress.onBrowserWindowLoad(window);
       }
@@ -6866,150 +6864,16 @@ var gIdentityHandler = {
     dt.setData("text/x-moz-url", urlString);
     dt.setData("text/uri-list", value);
     dt.setData("text/plain", value);
     dt.setData("text/html", htmlString);
     dt.setDragImage(gProxyFavIcon, 16, 16);
   }
 };
 
-let DownloadMonitorPanel = {
-  //////////////////////////////////////////////////////////////////////////////
-  //// DownloadMonitorPanel Member Variables
-
-  _panel: null,
-  _activeStr: null,
-  _pausedStr: null,
-  _lastTime: Infinity,
-  _listening: false,
-
-  get DownloadUtils() {
-    delete this.DownloadUtils;
-    Cu.import("resource://gre/modules/DownloadUtils.jsm", this);
-    return this.DownloadUtils;
-  },
-
-  //////////////////////////////////////////////////////////////////////////////
-  //// DownloadMonitorPanel Public Methods
-
-  /**
-   * Initialize the status panel and member variables
-   */
-  init: function DMP_init() {
-    // Initialize "private" member variables
-    this._panel = document.getElementById("download-monitor");
-
-    // Cache the status strings
-    this._activeStr = gNavigatorBundle.getString("activeDownloads1");
-    this._pausedStr = gNavigatorBundle.getString("pausedDownloads1");
-
-    gDownloadMgr.addListener(this);
-    this._listening = true;
-
-    this.updateStatus();
-  },
-
-  uninit: function DMP_uninit() {
-    if (this._listening)
-      gDownloadMgr.removeListener(this);
-  },
-
-  inited: function DMP_inited() {
-    return this._panel != null;
-  },
-
-  /**
-   * Update status based on the number of active and paused downloads
-   */
-  updateStatus: function DMP_updateStatus() {
-    if (!this.inited())
-      return;
-
-    let numActive = gDownloadMgr.activeDownloadCount;
-
-    // Hide the panel and reset the "last time" if there's no downloads
-    if (numActive == 0) {
-      this._panel.hidden = true;
-      this._lastTime = Infinity;
-
-      return;
-    }
-
-    // Find the download with the longest remaining time
-    let numPaused = 0;
-    let maxTime = -Infinity;
-    let dls = gDownloadMgr.activeDownloads;
-    while (dls.hasMoreElements()) {
-      let dl = dls.getNext();
-      if (dl.state == gDownloadMgr.DOWNLOAD_DOWNLOADING) {
-        // Figure out if this download takes longer
-        if (dl.speed > 0 && dl.size > 0)
-          maxTime = Math.max(maxTime, (dl.size - dl.amountTransferred) / dl.speed);
-        else
-          maxTime = -1;
-      }
-      else if (dl.state == gDownloadMgr.DOWNLOAD_PAUSED)
-        numPaused++;
-    }
-
-    // Get the remaining time string and last sec for time estimation
-    let timeLeft;
-    [timeLeft, this._lastTime] =
-      this.DownloadUtils.getTimeLeft(maxTime, this._lastTime);
-
-    // Figure out how many downloads are currently downloading
-    let numDls = numActive - numPaused;
-    let status = this._activeStr;
-
-    // If all downloads are paused, show the paused message instead
-    if (numDls == 0) {
-      numDls = numPaused;
-      status = this._pausedStr;
-    }
-
-    // Get the correct plural form and insert the number of downloads and time
-    // left message if necessary
-    status = PluralForm.get(numDls, status);
-    status = status.replace("#1", numDls);
-    status = status.replace("#2", timeLeft);
-
-    // Update the panel and show it
-    this._panel.label = status;
-    this._panel.hidden = false;
-  },
-
-  //////////////////////////////////////////////////////////////////////////////
-  //// nsIDownloadProgressListener
-
-  /**
-   * Update status for download progress changes
-   */
-  onProgressChange: function() {
-    this.updateStatus();
-  },
-
-  /**
-   * Update status for download state changes
-   */
-  onDownloadStateChange: function() {
-    this.updateStatus();
-  },
-
-  onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus, aDownload) {
-  },
-
-  onSecurityChange: function(aWebProgress, aRequest, aState, aDownload) {
-  },
-
-  //////////////////////////////////////////////////////////////////////////////
-  //// nsISupports
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDownloadProgressListener]),
-};
-
 function getNotificationBox(aWindow) {
   var foundBrowser = gBrowser.getBrowserForDocument(aWindow.document);
   if (foundBrowser)
     return gBrowser.getNotificationBox(foundBrowser)
   return null;
 };
 
 function getTabModalPromptBox(aWindow) {
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -246,17 +246,16 @@ endif
                  plugin_clickToPlayDeny.html \
                  plugin_bug749455.html \
                  plugin_bug797677.html \
                  plugin_hidden_to_visible.html \
                  plugin_two_types.html \
                  alltabslistener.html \
                  zoom_test.html \
                  dummy_page.html \
-                 browser_tabMatchesInAwesomebar.js \
                  file_bug550565_popup.html \
                  file_bug550565_favicon.ico \
                  browser_aboutHome.js \
                  app_bug575561.html \
                  app_subframe_bug575561.html \
                  browser_contentAreaClick.js \
                  browser_addon_bar_close_button.js \
                  browser_addon_bar_shortcut.js \
@@ -313,22 +312,24 @@ endif
 ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
 _BROWSER_FILES += \
                 browser_bug763468_perwindowpb.js \
                 browser_bug767836_perwindowpb.js \
                 browser_bug816527.js \
                 browser_private_browsing_window.js \
                 browser_save_link-perwindowpb.js \
                 browser_save_private_link_perwindowpb.js \
+                browser_tabMatchesInAwesomebar_perwindowpb.js \
                 $(NULL)
 else
 _BROWSER_FILES += \
                 browser_bug763468.js \
                 browser_bug767836.js \
                 browser_save_link.js \
                 browser_save_private_link.js \
+                browser_tabMatchesInAwesomebar.js \
                 $(NULL)
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
--- a/browser/base/content/test/browser_bug816527.js
+++ b/browser/base/content/test/browser_bug816527.js
@@ -13,43 +13,43 @@ function test() {
       // web pages on the test. If calling executeSoon() is not necesary, then
       // call whenNewWindowLoaded() instead of testOnWindow() on your test.
       executeSoon(function() aCallback(aWin));
     });
   };
 
   testOnWindow({}, function(aNormalWindow) {
     testOnWindow({private: true}, function(aPrivateWindow) {
-      runTest(aNormalWindow, aPrivateWindow, function() {
+      runTest(aNormalWindow, aPrivateWindow, false, function() {
         aNormalWindow.close();
         aPrivateWindow.close();
         testOnWindow({}, function(aNormalWindow) {
           testOnWindow({private: true}, function(aPrivateWindow) {
-            runTest(aPrivateWindow, aNormalWindow, function() {
+            runTest(aPrivateWindow, aNormalWindow, false, function() {
               aNormalWindow.close();
               aPrivateWindow.close();
               testOnWindow({private: true}, function(aPrivateWindow) {
-                runTest(aPrivateWindow, aPrivateWindow, function() {
+                runTest(aPrivateWindow, aPrivateWindow, false, function() {
                   aPrivateWindow.close();
                   testOnWindow({}, function(aNormalWindow) {
-                    runTest(aNormalWindow, aNormalWindow, function() {
+                    runTest(aNormalWindow, aNormalWindow, true, function() {
                       aNormalWindow.close();
                       finish();
                     });
                   });
                 });
               });
             });
           });
         });
       });
     });
   });
 
-  function runTest(aSourceWindow, aDestWindow, aCallback) {
+  function runTest(aSourceWindow, aDestWindow, aExpectSuccess, aCallback) {
     // Open the base tab
     let baseTab = aSourceWindow.gBrowser.addTab(testURL);
     baseTab.linkedBrowser.addEventListener("load", function() {
       // Wait for the tab to be fully loaded so matching happens correctly
       if (baseTab.linkedBrowser.currentURI.spec == "about:blank")
         return;
       baseTab.linkedBrowser.removeEventListener("load", arguments.callee, true);
 
@@ -86,31 +86,35 @@ function test() {
         // The reason that we can't avoid the timeout here is because we are
         // trying to test something which should not happen, so we just need
         // to wait for a while and then check whether any bad things have
         // happened.
 
         function onTabClose(aEvent) {
           aDestWindow.gBrowser.tabContainer.removeEventListener("TabClose", onTabClose, false);
           aDestWindow.gBrowser.removeEventListener("load", onLoad, false);
+          clearTimeout(timeout);
           // Should only happen when we expect success
-          ok(false, "Tab closed as expected");
+          ok(aExpectSuccess, "Tab closed as expected");
           aCallback();
         }
         function onLoad(aEvent) {
           aDestWindow.gBrowser.tabContainer.removeEventListener("TabClose", onTabClose, false);
           aDestWindow.gBrowser.removeEventListener("load", onLoad, false);
+          clearTimeout(timeout);
           // Should only happen when we expect success
-          ok(false, "Tab loaded as expected");
+          ok(aExpectSuccess, "Tab loaded as expected");
           aCallback();
         }
 
         aDestWindow.gBrowser.tabContainer.addEventListener("TabClose", onTabClose, false);
         aDestWindow.gBrowser.addEventListener("load", onLoad, false);
-        setTimeout(function() {
+        let timeout = setTimeout(function() {
+          aDestWindow.gBrowser.tabContainer.removeEventListener("TabClose", onTabClose, false);
+          aDestWindow.gBrowser.removeEventListener("load", onLoad, false);
           aCallback();
         }, 500);
 
         // Press enter!
         EventUtils.synthesizeKey("VK_RETURN", {});
       }, aDestWindow);
     }, true);
   }
copy from browser/base/content/test/browser_tabMatchesInAwesomebar.js
copy to browser/base/content/test/browser_tabMatchesInAwesomebar_perwindowpb.js
--- a/browser/base/content/test/browser_tabMatchesInAwesomebar.js
+++ b/browser/base/content/test/browser_tabMatchesInAwesomebar_perwindowpb.js
@@ -4,18 +4,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const TEST_URL_BASES = [
   "http://example.org/browser/browser/base/content/test/dummy_page.html#tabmatch",
   "http://example.org/browser/browser/base/content/test/moz.png#tabmatch"
 ];
 
-var gPrivateBrowsing = Cc["@mozilla.org/privatebrowsing;1"].
-                         getService(Ci.nsIPrivateBrowsingService);
 var gController = Cc["@mozilla.org/autocomplete/controller;1"].
                   getService(Ci.nsIAutoCompleteController);
 
 var gTabWaitCount = 0;
 var gTabCounter = 0;
 
 var gTestSteps = [
   function() {
@@ -35,126 +33,53 @@ var gTestSteps = [
       loadTab(gBrowser.tabs[i], TEST_URL_BASES[1] + (++gTabCounter));
   },
   function() {
     info("Running step 3");
     for (let i = 1; i < gBrowser.tabs.length; i++)
       loadTab(gBrowser.tabs[i], TEST_URL_BASES[0] + gTabCounter);
   },
   function() {
-    info("Running step 4");
-    let ps = Services.prefs;
-    ps.setBoolPref("browser.privatebrowsing.keep_current_session", true);
-    ps.setBoolPref("browser.tabs.warnOnClose", false);
-
-    // Make sure that all restored tabs are loaded without waiting for the user
-    // to bring them to the foreground. We ensure this by resetting the
-    // related preference (see the "firefox.js" defaults file for details).
-    ps.setBoolPref("browser.sessionstore.restore_on_demand", false);
-
-    gPrivateBrowsing.privateBrowsingEnabled = true;
-
-    executeSoon(function() {
-      ensure_opentabs_match_db(nextStep);
-    });
-  },
-  function() {
-    info("Running step 5");
-    gPrivateBrowsing.privateBrowsingEnabled = false;
-
-    executeSoon(function() {
-      let ps = Services.prefs;
-      ps.clearUserPref("browser.privatebrowsing.keep_current_session");
-      ps.clearUserPref("browser.tabs.warnOnClose");
-
-      ensure_opentabs_match_db(nextStep);
-    });
-  },
-  function() {
-    info("Running step 6 - ensure we don't register subframes as open pages");
+    info("Running step 4 - ensure we don't register subframes as open pages");
     let tab = gBrowser.addTab();
     tab.linkedBrowser.addEventListener("load", function () {
       tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
       // Start the sub-document load.
       executeSoon(function () {
         tab.linkedBrowser.addEventListener("load", function (e) {
           tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
             ensure_opentabs_match_db(nextStep);
         }, true);
         tab.linkedBrowser.contentDocument.querySelector("iframe").src = "http://test2.example.org/";
       });
     }, true);
     tab.linkedBrowser.loadURI('data:text/html,<body><iframe src=""></iframe></body>');
   },
   function() {
-    info("Running step 7 - remove tab immediately");
+    info("Running step 5 - remove tab immediately");
     let tab = gBrowser.addTab("about:logo");
     gBrowser.removeTab(tab);
     ensure_opentabs_match_db(nextStep);
   },
   function() {
-    info("Running step 8 - check swapBrowsersAndCloseOther preserves registered switch-to-tab result");
+    info("Running step 6 - check swapBrowsersAndCloseOther preserves registered switch-to-tab result");
     let tabToKeep = gBrowser.addTab();
     let tab = gBrowser.addTab();
     tab.linkedBrowser.addEventListener("load", function () {
       tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
       gBrowser.swapBrowsersAndCloseOther(tabToKeep, tab);
       ensure_opentabs_match_db(function () {
         gBrowser.removeTab(tabToKeep);
         ensure_opentabs_match_db(nextStep);
       });
     }, true);
     tab.linkedBrowser.loadURI("about:mozilla");
   },
   function() {
-    info("Running step 9 - enter private browsing mode, without keeping session");
-    let ps = Services.prefs;
-    ps.setBoolPref("browser.privatebrowsing.keep_current_session", false);
-    ps.setBoolPref("browser.tabs.warnOnClose", false);
-
-    Services.obs.addObserver(function(aSubject, aTopic, aData) {
-      Services.obs.removeObserver(arguments.callee, "private-browsing-transition-complete");
-
-      for (let i = 0; i < gBrowser.tabs.length; i++)
-        waitForRestoredTab(gBrowser.tabs[i]);
-    }, "private-browsing-transition-complete", false);
-
-    gPrivateBrowsing.privateBrowsingEnabled = true;
-  },
-  function() {
-    info("Running step 10 - open tabs in private browsing mode");
-    for (let i = 0; i < 3; i++) {
-      let tab = gBrowser.addTab();
-      loadTab(tab, TEST_URL_BASES[0] + (++gTabCounter));
-    }
-  },
-  function() {
-    info("Running step 11 - close tabs in private browsing mode");
-    gBrowser.removeCurrentTab();
-    ensure_opentabs_match_db(nextStep);
-  },
-  function() {
-    info("Running step 12 - leave private browsing mode");
-
-    Services.obs.addObserver(function(aSubject, aTopic, aData) {
-      Services.obs.removeObserver(arguments.callee, "private-browsing-transition-complete");
-
-      let ps = Services.prefs;
-      ps.clearUserPref("browser.privatebrowsing.keep_current_session");
-      ps.clearUserPref("browser.tabs.warnOnClose");
-
-      for (let i = 1; i < gBrowser.tabs.length; i++)
-        waitForRestoredTab(gBrowser.tabs[i]);
-
-    }, "private-browsing-transition-complete", false);
-
-    gPrivateBrowsing.privateBrowsingEnabled = false;
-  },
-  function() {
-    info("Running step 13 - close all tabs");
+    info("Running step 7 - close all tabs");
 
     Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand");
 
     gBrowser.addTab("about:blank", {skipAnimation: true});
     while (gBrowser.tabs.length > 1) {
       info("Removing tab: " + gBrowser.tabs[0].linkedBrowser.currentURI.spec);
       gBrowser.selectTabAtIndex(0);
       gBrowser.removeCurrentTab();
@@ -167,17 +92,17 @@ var gTestSteps = [
 
 function test() {
   waitForExplicitFinish();
   nextStep();
 }
 
 function loadTab(tab, url) {
   // Because adding visits is async, we will not be notified immediately.
-  let visited = gPrivateBrowsing.privateBrowsingEnabled;
+  let visited = false;
   let loaded = false;
 
   function maybeCheckResults() {
     if (visited && loaded && --gTabWaitCount == 0) {
       ensure_opentabs_match_db(nextStep);
     }
   }
 
--- a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml
+++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml
@@ -8,37 +8,51 @@
   <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
   %htmlDTD;
   <!ENTITY % netErrorDTD SYSTEM "chrome://global/locale/netError.dtd">
   %netErrorDTD;
   <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
   %globalDTD;
   <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
   %browserDTD;
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+#ifdef XP_MACOSX
+  <!ENTITY basePBMenu.label   "&fileMenu.label;">
+#else
+  <!ENTITY basePBMenu.label   "<span class='appMenuButton'>&brandShortName;</span><span class='fileMenu'>&fileMenu.label;</span>">
+#endif
+#else
 #ifdef XP_MACOSX
   <!ENTITY basePBMenu.label   "&toolsMenu.label;">
 #else
   <!ENTITY basePBMenu.label   "<span class='appMenuButton'>&brandShortName;</span><span class='toolsMenu'>&toolsMenu.label;</span>">
 #endif
+#endif
   <!ENTITY % privatebrowsingpageDTD SYSTEM "chrome://browser/locale/aboutPrivateBrowsing.dtd">
   %privatebrowsingpageDTD;
 ]>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
     <link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all"/>
     <link rel="stylesheet" href="chrome://browser/skin/aboutPrivateBrowsing.css" type="text/css" media="all"/>
     <style type="text/css"><![CDATA[
       body.normal .showPrivate,
       body.private .showNormal {
         display: none;
       }
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+      body.appMenuButtonVisible .fileMenu {
+        display: none;
+      }
+#else
       body.appMenuButtonVisible .toolsMenu {
         display: none;
       }
+#endif
       body.appMenuButtonInvisible .appMenuButton {
         display: none;
       }
     ]]></style>
     <script type="application/javascript;version=1.7"><![CDATA[
       const Cc = Components.classes;
       const Ci = Components.interfaces;
 
@@ -88,20 +102,26 @@
 
         // Show the correct menu structure based on whether the App Menu button is
         // shown or not.
         var menuBar = mainWindow.document.getElementById("toolbar-menubar");
         var appMenuButtonIsVisible = menuBar.getAttribute("autohide") == "true";
         document.body.classList.add(appMenuButtonIsVisible ? "appMenuButtonVisible" :
                                                              "appMenuButtonInvisible");
       }, false);
-      
+
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+      function openPrivateWindow() {
+        mainWindow.OpenBrowserWindow({private: true});
+      }
+#else
       function togglePrivateBrowsing() {
         mainWindow.gPrivateBrowsingUI.toggleMode();
       }
+#endif
     ]]></script>
   </head>
 
   <body dir="&locale.dir;"
         class="private">
 
     <!-- PAGE CONTAINER (for styling purposes only) -->
     <div id="errorPageContainer">
@@ -112,37 +132,58 @@
         <h1 id="errorTitleTextNormal" class="showNormal">&privatebrowsingpage.title.normal;</h1>
       </div>
 
       <!-- LONG CONTENT (the section most likely to require scrolling) -->
       <div id="errorLongContent">
 
         <!-- Short Description -->
         <div id="errorShortDesc">
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+          <p id="errorShortDescText" class="showPrivate">&privatebrowsingpage.perwindow.issueDesc;</p>
+          <p id="errorShortDescTextNormal" class="showNormal">&privatebrowsingpage.perwindow.issueDesc.normal;</p>
+#else
           <p id="errorShortDescText" class="showPrivate">&privatebrowsingpage.issueDesc;</p>
           <p id="errorShortDescTextNormal" class="showNormal">&privatebrowsingpage.issueDesc.normal;</p>
+#endif
         </div>
 
         <!-- Long Description -->
         <div id="errorLongDesc">
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+          <p id="errorLongDescText">&privatebrowsingpage.perwindow.description;</p>
+#else
           <p id="errorLongDescText">&privatebrowsingpage.description;</p>
+#endif
         </div>
 
         <!-- Start Private Browsing -->
         <div id="startPrivateBrowsingDesc" class="showNormal">
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+          <button xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+                  id="startPrivateBrowsing" label="&privatebrowsingpage.openPrivateWindow.label;"
+                  accesskey="&privatebrowsingpage.openPrivateWindow.accesskey;"
+                  oncommand="openPrivateWindow();"/>
+#else
           <button xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
                   id="startPrivateBrowsing" label="&privatebrowsingpage.startPrivateBrowsing.label;"
                   accesskey="&privatebrowsingpage.startPrivateBrowsing.accesskey;"
                   oncommand="togglePrivateBrowsing();"/>
+#endif
         </div>
 
         <!-- Footer -->
         <div id="footerDesc">
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+          <p id="footerText" class="showPrivate">&privatebrowsingpage.howToStop3;</p>
+          <p id="footerTextNormal" class="showNormal">&privatebrowsingpage.howToStart3;</p>
+#else
           <p id="footerText" class="showPrivate">&privatebrowsingpage.howToStop2;</p>
           <p id="footerTextNormal" class="showNormal">&privatebrowsingpage.howToStart2;</p>
+#endif
         </div>
 
         <!-- More Info -->
         <div id="moreInfo" class="showPrivate">
           <p id="moreInfoText">
             &privatebrowsingpage.moreInfo;
           </p>
           <p id="moreInfoLinkContainer">
--- a/browser/components/privatebrowsing/test/browser/obsolete/Makefile.in
+++ b/browser/components/privatebrowsing/test/browser/obsolete/Makefile.in
@@ -19,20 +19,18 @@ MOCHITEST_BROWSER_FILES =  \
 		browser_privatebrowsing_forgetthissite.js \
 		browser_privatebrowsing_import.js \
 		browser_privatebrowsing_newwindow_stopcmd.js \
 		browser_privatebrowsing_pageinfo.js \
 		browser_privatebrowsing_popupmode.js \
 		browser_privatebrowsing_searchbar.js \
 		browser_privatebrowsing_sslsite_transition.js \
 		$(filter disabled-since-it-no-longer-makes-sense, browser_privatebrowsing_transition.js) \
-		$(filter disabled--bug-564934, browser_privatebrowsing_downloadmonitor.js) \
 		browser_privatebrowsing_urlbarundo.js \
 		browser_privatebrowsing_viewsource.js \
-		staller.sjs \
 		$(NULL)
 
 # Turn off private browsing tests that perma-timeout on Linux.
 ifneq (Linux,$(OS_ARCH))
 MOCHITEST_BROWSER_FILES += \
 		browser_privatebrowsing_beforeunload.js \
 		$(NULL)
 endif
deleted file mode 100644
--- a/browser/components/privatebrowsing/test/browser/obsolete/browser_privatebrowsing_downloadmonitor.js
+++ /dev/null
@@ -1,153 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// This test makes sure that the download monitor status bar panel is correctly
-// cleared when switching the private browsing mode on or off.
-
-function test() {
-  // initialization
-  let pb = Cc["@mozilla.org/privatebrowsing;1"].
-           getService(Ci.nsIPrivateBrowsingService);
-  let dm = Cc["@mozilla.org/download-manager;1"].
-           getService(Ci.nsIDownloadManager);
-  if (!gDownloadMgr)
-    gDownloadMgr = dm;
-  let panel = document.getElementById("download-monitor");
-  waitForExplicitFinish();
-
-  let acceptDialog = 0;
-  let confirmCalls = 0;
-  function promptObserver(aSubject, aTopic, aData) {
-    let dialogWin = aSubject.QueryInterface(Ci.nsIDOMWindow);
-    confirmCalls++;
-    if (acceptDialog-- > 0)
-      dialogWin.document.documentElement.getButton("accept").click();
-  }
-
-  Services.obs.addObserver(promptObserver, "common-dialog-loaded", false);
-
-  // Add a new download
-  let [file, persist] = addDownload(dm, {
-    isPrivate: PrivateBrowsingUtils.isWindowPrivate(window),
-    resultFileName: "pbtest-1",
-    downloadName: "PB Test 1"
-  });
-
-  // Make sure that the download is being displayed in the monitor panel
-  if (!DownloadMonitorPanel.inited())
-    DownloadMonitorPanel.init();
-  else
-    DownloadMonitorPanel.updateStatus();
-  ok(!panel.hidden, "The download panel should be successfully added initially");
-
-  // Enter the private browsing mode
-  acceptDialog = 1;
-  pb.privateBrowsingEnabled = true;
-  is(confirmCalls, 1, "One prompt was accepted");
-  ok(pb.privateBrowsingEnabled, "The private browsing transition was successful");
-
-  executeSoon(function () {
-    ok(panel.hidden, "The download panel should be hidden when entering the private browsing mode");
-
-    // Add a new download
-    let [file2, persist2] = addDownload(dm, {
-      isPrivate: PrivateBrowsingUtils.isWindowPrivate(window),
-      resultFileName: "pbtest-2",
-      downloadName: "PB Test 2"
-    });
-
-    // Update the panel
-    DownloadMonitorPanel.updateStatus();
-
-    // Make sure that the panel is visible
-    ok(!panel.hidden, "The download panel should show up when a new download is added");
-
-    // Exit the private browsing mode
-    acceptDialog = 1;
-    pb.privateBrowsingEnabled = false;
-    is(confirmCalls, 2, "One prompt was accepted");
-    ok(!pb.privateBrowsingEnabled, "The private browsing transition was successful");
-
-    executeSoon(function () {
-      ok(panel.hidden, "The download panel should be hidden when leaving the private browsing mode");
-
-      // cleanup
-      let dls = dm.activeDownloads;
-      while (dls.hasMoreElements()) {
-        let dl = dls.getNext().QueryInterface(Ci.nsIDownload);
-        dm.removeDownload(dl.id);
-        let file = dl.targetFile;
-        if (file.exists())
-          file.remove(false);
-      }
-      if (file.exists())
-        file.remove(false);
-
-      Services.obs.removeObserver(promptObserver, "common-dialog-loaded", false);
-      finish();
-    });
-  });
-}
-
-/**
- * Adds a download to the DM, and starts it.
- * (Copied from toolkit/componentns/downloads/test/unit/head_download_manager.js)
- * @param aParams (optional): an optional object which contains the function
- *                            parameters:
- *                              resultFileName: leaf node for the target file
- *                              targetFile: nsIFile for the target (overrides resultFileName)
- *                              sourceURI: the download source URI
- *                              downloadName: the display name of the download
- *                              runBeforeStart: a function to run before starting the download
- *                              isPrivate: whether the download is private
- */
-function addDownload(dm, aParams)
-{
-  if (!aParams)
-    aParams = {};
-  if (!("resultFileName" in aParams))
-    aParams.resultFileName = "download.result";
-  if (!("targetFile" in aParams)) {
-    let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
-                 getService(Ci.nsIProperties);
-    aParams.targetFile = dirSvc.get("ProfD", Ci.nsIFile);
-    aParams.targetFile.append(aParams.resultFileName);
-  }
-  if (!("sourceURI" in aParams))
-    aParams.sourceURI = "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/global/staller.sjs";
-  if (!("downloadName" in aParams))
-    aParams.downloadName = null;
-  if (!("runBeforeStart" in aParams))
-    aParams.runBeforeStart = function () {};
-
-  const nsIWBP = Ci.nsIWebBrowserPersist;
-  let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
-                .createInstance(Ci.nsIWebBrowserPersist);
-  persist.persistFlags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
-                         nsIWBP.PERSIST_FLAGS_BYPASS_CACHE |
-                         nsIWBP.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
-
-  let dl = dm.addDownload(Ci.nsIDownloadManager.DOWNLOAD_TYPE_DOWNLOAD,
-                          createURI(aParams.sourceURI),
-                          createURI(aParams.targetFile), aParams.downloadName, null,
-                          Math.round(Date.now() * 1000), null, persist, aParams.isPrivate);
-
-  // This will throw if it isn't found, and that would mean test failure, so no
-  // try catch block
-  let test = dm.getDownload(dl.id);
-
-  aParams.runBeforeStart.call(undefined, dl);
-  
-  persist.progressListener = dl.QueryInterface(Ci.nsIWebProgressListener);
-  persist.savePrivacyAwareURI(dl.source, null, null, null, null, dl.targetFile,
-                              aParams.isPrivate);
-
-  return [dl.targetFile, persist];
-}
-
-function createURI(aObj) {
-  let ios = Services.io;
-  return (aObj instanceof Ci.nsIFile) ? ios.newFileURI(aObj) :
-                                        ios.newURI(aObj, null, null);
-}
deleted file mode 100644
--- a/browser/components/privatebrowsing/test/browser/obsolete/staller.sjs
+++ /dev/null
@@ -1,27 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// This provides the tests with a download URL which never finishes.
-
-var timer;
-
-function handleRequest(request, response) {
-  response.setStatusLine(request.httpVersion, 200, "OK");
-  response.processAsync();
-
-  const nsITimer = Components.interfaces.nsITimer;
-
-  function stall() {
-    timer = null;
-    // This write will throw if the connection has been closed by the browser.
-    response.write("stalling...\n");
-    timer = Components.classes["@mozilla.org/timer;1"]
-                        .createInstance(nsITimer);
-    timer.initWithCallback(stall, 500, nsITimer.TYPE_ONE_SHOT);
-  }
-
-  response.setHeader("Content-Type", "text/plain", false);
-  response.setHeader("Accept-Ranges", "none", false);
-  stall();
-}
--- a/browser/components/tabview/test/Makefile.in
+++ b/browser/components/tabview/test/Makefile.in
@@ -64,17 +64,16 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug616729.js \
                  browser_tabview_bug616967.js \
                  browser_tabview_bug618816.js \
                  browser_tabview_bug618828.js \
                  browser_tabview_bug619937.js \
                  browser_tabview_bug622835.js \
                  browser_tabview_bug623768.js \
                  browser_tabview_bug624692.js \
-                 browser_tabview_bug624727.js \
                  browser_tabview_bug624847.js \
                  browser_tabview_bug624931.js \
                  browser_tabview_bug624953.js \
                  browser_tabview_bug625195.js \
                  browser_tabview_bug625269.js \
                  browser_tabview_bug625424.js \
                  browser_tabview_bug625955.js \
                  browser_tabview_bug626368.js \
@@ -102,17 +101,16 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug641802.js \
                  browser_tabview_bug642793.js \
                  browser_tabview_bug643392.js \
                  browser_tabview_bug644097.js \
                  browser_tabview_bug648882.js \
                  browser_tabview_bug649006.js \
                  browser_tabview_bug649307.js \
                  browser_tabview_bug649319.js \
-                 browser_tabview_bug650280.js \
                  browser_tabview_bug650573.js \
                  browser_tabview_bug651311.js \
                  browser_tabview_bug654295.js \
                  browser_tabview_bug654721.js \
                  browser_tabview_bug654941.js \
                  browser_tabview_bug655269.js \
                  browser_tabview_bug656778.js \
                  browser_tabview_bug656913.js \
@@ -145,17 +143,16 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_click_group.js \
                  browser_tabview_dragdrop.js \
                  browser_tabview_exit_button.js \
                  browser_tabview_expander.js \
                  browser_tabview_firstrun_pref.js \
                  browser_tabview_group.js \
                  browser_tabview_launch.js \
                  browser_tabview_multiwindow_search.js \
-                 browser_tabview_privatebrowsing.js \
                  browser_tabview_rtl.js \
                  browser_tabview_search.js \
                  browser_tabview_snapping.js \
                  browser_tabview_startup_transitions.js \
                  browser_tabview_undo_group.js \
                  dummy_page.html \
                  head.js \
                  search1.html \
@@ -163,21 +160,26 @@ include $(topsrcdir)/config/rules.mk
                  test_bug600645.html \
                  test_bug644097.html \
                  test_bug678374.html \
                  test_bug678374_icon16.png \
                  $(NULL)
 
 ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
 _BROWSER_FILES += \
-                browser_tabview_bug624265_perwindowpb.js \
-                $(NULL)
+                 browser_tabview_bug624265_perwindowpb.js \
+                 browser_tabview_bug624727_perwindowpb.js \
+                 browser_tabview_bug650280_perwindowpb.js \
+                 $(NULL)
 else
 _BROWSER_FILES += \
-                browser_tabview_bug624265.js \
-                $(NULL)
+                 browser_tabview_bug624265.js \
+                 browser_tabview_bug624727.js \
+                 browser_tabview_bug650280.js \
+                 browser_tabview_privatebrowsing.js \
+                 $(NULL)
 endif
 
 
 # browser_tabview_bug597980.js is disabled for leaking, see bug 711907
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
copy from browser/components/tabview/test/browser_tabview_bug624727.js
copy to browser/components/tabview/test/browser_tabview_bug624727_perwindowpb.js
--- a/browser/components/tabview/test/browser_tabview_bug624727.js
+++ b/browser/components/tabview/test/browser_tabview_bug624727_perwindowpb.js
@@ -1,130 +1,143 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-let pb = Cc['@mozilla.org/privatebrowsing;1'].
-         getService(Ci.nsIPrivateBrowsingService);
-
 function test() {
-  let cw;
-
-  let createGroupItem = function () {
+  let createGroupItem = function (aWindow) {
+    let cw = aWindow.TabView.getContentWindow();
     let bounds = new cw.Rect(20, 20, 400, 200);
     let groupItem = new cw.GroupItem([], {bounds: bounds, immediately: true});
     cw.UI.setActive(groupItem);
 
     let groupItemId = groupItem.id;
     registerCleanupFunction(function() {
       let groupItem = cw.GroupItems.groupItem(groupItemId);
       if (groupItem)
         groupItem.close();
     });
 
     for (let i=0; i<3; i++)
-      gBrowser.addTab('about:blank');
+      aWindow.gBrowser.addTab('about:blank');
   }
 
-  let assertTabViewIsHidden = function (prefix) {
-    ok(!TabView.isVisible(), prefix + ': tabview is hidden');
+  let assertTabViewIsHidden = function (aWindow, prefix) {
+    ok(!aWindow.TabView.isVisible(), prefix + ': tabview is hidden');
   }
 
-  let assertNumberOfTabs = function (prefix, num) {
-    is(gBrowser.tabs.length, num, prefix + ': there are ' + num + ' tabs');
+  let assertNumberOfTabs = function (aWindow, prefix, num) {
+    is(aWindow.gBrowser.tabs.length, num, prefix + ': there are ' + num + ' tabs');
   }
 
-  let assertNumberOfPinnedTabs = function (prefix, num) {
-    is(gBrowser._numPinnedTabs, num, prefix + ': there are ' + num + ' pinned tabs');
+  let assertNumberOfPinnedTabs = function (aWindow, prefix, num) {
+    is(aWindow.gBrowser._numPinnedTabs, num, prefix + ': there are ' + num + ' pinned tabs');
   }
 
-  let assertNumberOfGroups = function (prefix, num) {
-    is(cw.GroupItems.groupItems.length, num, prefix + ': there are ' + num + ' groups');
+  let assertNumberOfGroups = function (aCW, prefix, num) {
+    is(aCW.GroupItems.groupItems.length, num, prefix + ': there are ' + num + ' groups');
   }
 
   let assertOneTabInGroup = function (prefix, groupItem) {
     is(groupItem.getChildren().length, 1, prefix + ': group contains one tab');
   }
 
-  let assertValidPrerequisites = function (prefix) {
-    assertNumberOfTabs(prefix, 1);
-    assertNumberOfPinnedTabs(prefix, 0);
-    assertTabViewIsHidden(prefix);
+  let assertValidPrerequisites = function (aWindow, prefix) {
+    assertNumberOfTabs(aWindow, prefix, 1);
+    assertNumberOfPinnedTabs(aWindow, prefix, 0);
+    assertTabViewIsHidden(aWindow, prefix);
   }
 
-  let assertValidSetup = function (prefix) {
-    assertNumberOfGroups(prefix, 2);
-    assertNumberOfTabs(prefix, 4);
-    assertNumberOfPinnedTabs(prefix, 2);
+  let assertValidSetup = function (aWindow, prefix) {
+    let cw = aWindow.TabView.getContentWindow();
+    assertNumberOfGroups(cw, prefix, 2);
+    assertNumberOfTabs(aWindow, prefix, 4);
+    assertNumberOfPinnedTabs(aWindow, prefix, 2);
 
     let [group1, group2] = cw.GroupItems.groupItems;
     assertOneTabInGroup(prefix, group1);
     assertOneTabInGroup(prefix, group2);
   }
 
-  let testStateAfterEnteringPB = function () {
-    let prefix = 'enter';
-    ok(!pb.privateBrowsingEnabled, prefix + ': private browsing is disabled');
-    registerCleanupFunction(function () {
-      pb.privateBrowsingEnabled = false;
-    });
+  let testStateAfterEnteringPB = function (aWindow, aCallback) {
+    let prefix = 'window is private';
+    ok(PrivateBrowsingUtils.isWindowPrivate(aWindow), prefix);
+
+    assertTabViewIsHidden(aWindow, prefix);
 
-    togglePrivateBrowsing(function () {
-      assertTabViewIsHidden(prefix);
+    showTabView(function () {
+      let cw = aWindow.TabView.getContentWindow();
 
-      showTabView(function () {
-        assertNumberOfGroups(prefix, 1);
-        assertNumberOfTabs(prefix, 1);
-        assertOneTabInGroup(prefix, cw.GroupItems.groupItems[0]);
-        hideTabView(testStateAfterLeavingPB);
-      });
-    });
+      assertNumberOfGroups(cw, prefix, 1);
+      assertNumberOfTabs(aWindow, prefix, 1);
+      assertOneTabInGroup(prefix, cw.GroupItems.groupItems[0]);
+      aCallback();
+    }, aWindow);
   }
 
-  let testStateAfterLeavingPB = function () {
-    let prefix = 'leave';
-    ok(pb.privateBrowsingEnabled, prefix + ': private browsing is enabled');
+  let testStateAfterLeavingPB = function (aWindow) {
+    let prefix = 'window is not private';
+    ok(!PrivateBrowsingUtils.isWindowPrivate(aWindow), prefix);
 
-    togglePrivateBrowsing(function () {
-      assertTabViewIsHidden(prefix);
+    assertTabViewIsHidden(aWindow, prefix);
 
-      showTabView(function () {
-        assertValidSetup(prefix);
-        finishTest();
-      });
-    });
+    showTabView(function () {
+      assertValidSetup(aWindow, prefix);
+      finishTest(aWindow);
+    }, aWindow);
   }
 
-  let finishTest = function () {
-    // remove pinned tabs
-    gBrowser.removeTab(gBrowser.tabs[0]);
-    gBrowser.removeTab(gBrowser.tabs[0]);
+  let finishTest = function (aWindow) {
+    let cw = aWindow.TabView.getContentWindow();
+
+    // Remove pinned tabs
+    aWindow.gBrowser.removeTab(aWindow.gBrowser.tabs[0]);
+    aWindow.gBrowser.removeTab(aWindow.gBrowser.tabs[0]);
 
     cw.GroupItems.groupItems[1].closeAll();
 
     hideTabView(function () {
-      assertValidPrerequisites('exit');
-      assertNumberOfGroups('exit', 1);
+      assertValidPrerequisites(aWindow, 'exit');
+      assertNumberOfGroups(cw, 'exit', 1);
+      aWindow.close();
       finish();
-    });
+    }, aWindow);
+  }
+
+  let testOnWindow = function(aIsPrivate, aCallback) {
+    let win = OpenBrowserWindow({private: aIsPrivate});
+    win.addEventListener("load", function onLoad() {
+      win.removeEventListener("load", onLoad, false);
+      executeSoon(function() { aCallback(win) });
+    }, false);
   }
 
   waitForExplicitFinish();
-  registerCleanupFunction(function () TabView.hide());
-  assertValidPrerequisites('start');
+  testOnWindow(false, function(publicWindow) {
+    registerCleanupFunction(function () publicWindow.TabView.hide());
+    assertValidPrerequisites(publicWindow, 'start');
 
-  showTabView(function () {
-    cw = TabView.getContentWindow();
-    assertNumberOfGroups('start', 1);
-
-    createGroupItem();
+    showTabView(function () {
+      let cw = publicWindow.TabView.getContentWindow();
+      assertNumberOfGroups(cw, 'start', 1);
+      createGroupItem(publicWindow);
 
-    afterAllTabsLoaded(function () {
-      // setup
-      let groupItems = cw.GroupItems.groupItems;
-      let [tabItem1, tabItem2, ] = groupItems[1].getChildren();
-      gBrowser.pinTab(tabItem1.tab);
-      gBrowser.pinTab(tabItem2.tab);
+      afterAllTabsLoaded(function () {
+        // Setup
+        let groupItems = cw.GroupItems.groupItems;
+        let [tabItem1, tabItem2, ] = groupItems[1].getChildren();
+        publicWindow.gBrowser.pinTab(tabItem1.tab);
+        publicWindow.gBrowser.pinTab(tabItem2.tab);
 
-      assertValidSetup('setup');
-      hideTabView(testStateAfterEnteringPB);
-    });
+        assertValidSetup(publicWindow, 'setup');
+        hideTabView(function() {
+          testOnWindow(true, function(privateWindow) {
+            testStateAfterEnteringPB(privateWindow, function() {
+              privateWindow.close();
+              hideTabView(function() {
+                testStateAfterLeavingPB(publicWindow);
+              }, publicWindow);
+            });
+          });
+        }, publicWindow);
+      });
+    }, publicWindow);
   });
 }
copy from browser/components/tabview/test/browser_tabview_bug650280.js
copy to browser/components/tabview/test/browser_tabview_bug650280_perwindowpb.js
--- a/browser/components/tabview/test/browser_tabview_bug650280.js
+++ b/browser/components/tabview/test/browser_tabview_bug650280_perwindowpb.js
@@ -1,67 +1,75 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-let pb = Cc["@mozilla.org/privatebrowsing;1"].
-         getService(Ci.nsIPrivateBrowsingService);
-
 function test() {
-  let cw;
-
-  registerCleanupFunction(function() {
-    if (cw)
-      cw.Search.hide();
-
-    TabView.hide();
-    pb.privateBrowsingEnabled = false;
-  });
-
-  let enableSearch = function (callback) {
-    if (cw.Search.isEnabled()) {
-      callback();
+  let enableSearch = function (aCW, aCallback) {
+    if (aCW.Search.isEnabled()) {
+       aCallback();
       return;
     }
 
-    cw.addEventListener("tabviewsearchenabled", function onSearchEnabled() {
-      cw.removeEventListener("tabviewsearchenabled", onSearchEnabled, false);
-      executeSoon(callback);
+    aCW.addEventListener("tabviewsearchenabled", function onSearchEnabled() {
+      aCW.removeEventListener("tabviewsearchenabled", onSearchEnabled, false);
+      executeSoon(aCallback);
     }, false);
 
-    cw.Search.ensureShown();
-  };
-
-  let getSearchboxValue = function () {
-    return cw.iQ("#searchbox").val();
+    aCW.Search.ensureShown();
   };
 
-  let prepareSearchbox = function (callback) {
-    ok(!cw.Search.isEnabled(), "search is disabled");
-
-    enableSearch(function () {
-      cw.iQ("#searchbox").val("moz");
-      callback();
-    });
+  let getSearchboxValue = function (aCW) {
+    return aCW.iQ("#searchbox").val();
   };
 
-  let searchAndSwitchPBMode = function (callback) {
-    prepareSearchbox(function () {
-      togglePrivateBrowsing(function () {
-        showTabView(function () {
-          ok(!cw.Search.isEnabled(), "search is disabled");
-          is(getSearchboxValue(), "", "search box is empty");
-          callback();
-        });
+  let prepareSearchbox = function (aCW, aCallback) {
+    ok(!aCW.Search.isEnabled(), "search is disabled");
+
+    executeSoon(function() {
+      enableSearch(aCW, function() {
+        aCW.iQ("#searchbox").val("moz");
+        aCallback();
       });
     });
   };
 
+  let searchAndSwitchPBMode = function (aWindow, aCallback) {
+    showTabView(function() {
+      let cw = aWindow.TabView.getContentWindow();
+
+      prepareSearchbox(cw, function() {
+        testOnWindow(!PrivateBrowsingUtils.isWindowPrivate(aWindow), function(win) {
+          showTabView(function() {
+            let contentWindow = win.TabView.getContentWindow();
+            ok(!contentWindow.Search.isEnabled(), "search is disabled");
+            is(getSearchboxValue(contentWindow), "", "search box is empty");
+            aWindow.TabView.hide();
+            win.close();
+            hideTabView(function() {
+              aWindow.close();
+              aCallback();
+            }, aWindow);
+          }, win);
+        });
+      });
+    }, aWindow);
+  };
+
+  let testOnWindow = function(aIsPrivate, aCallback) {
+    let win = OpenBrowserWindow({private: aIsPrivate});
+    win.addEventListener("load", function onLoad() {
+      win.removeEventListener("load", onLoad, false);
+      executeSoon(function() { aCallback(win) });
+    }, false);
+  }
+
   waitForExplicitFinish();
 
-  showTabView(function () {
-    cw = TabView.getContentWindow();
-    searchAndSwitchPBMode(function () {
-      searchAndSwitchPBMode(function () {
-        hideTabView(finish);
+  testOnWindow(false, function(win) {
+    searchAndSwitchPBMode(win, function() {
+      testOnWindow(true, function(win) {
+        searchAndSwitchPBMode(win, function() {
+          finish();
+        });
       });
     });
   });
 }
--- a/browser/config/tooltool-manifests/linux32/clang.manifest
+++ b/browser/config/tooltool-manifests/linux32/clang.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r168596"
+"clang_version": "r169139"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 62525599,
-"digest": "50818d3288713821a520c3c4c5b01f0a782a5ac5b4c8f5d2a198af150323b93d07bf6b5f87d9ef4a9b49308ce788112907a211b02d7d5123338ad6a0265100b8",
+"size": 62513298,
+"digest": "1c9dfc75d4a06438da4d079282178274054e07d814ec6bc8e45c9e62589293df11858c74ce301c53b5bd758c56dc1c593a97cd5034b47ea753c518fd9af69ea4",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/linux64/clang.manifest
+++ b/browser/config/tooltool-manifests/linux64/clang.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r168596"
+"clang_version": "r169139"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 62868457,
-"digest": "f5ebd0e6a3238f309ac554f266a58e558e08dd5959579c8b9dd78ce1d88162990d850bad3164dccfced5ce2cf5aa1448baaf94878ad96c1a5fa025e567bf0d61",
+"size": 62856551,
+"digest": "3542a25815f89555f2e2b4c67fbffa432c341d824395b452698d8d90ee0216e045531adcad14bf7071be1a41c016b4652cf955270b652bcdbd7b04a02cc3c9f9",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx32/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx32/releng.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r168596"
+"clang_version": "r169139"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 56147341,
-"digest": "4baed5cbe0189a509b6a328ee35ee488250677f8ea149e6d01af74c7a4a27c898a4112f78af57b33a4e788b2947813b65ab0922e06b67bd504878803dab44f5c",
+"size": 56158651,
+"digest": "38d718f20a8fa9218e22ade312e724e6c9cdd7c6650e023cfdc21b5505fe7aa3743ae41c0abd717a1bbccec4c4271be2fa82d0e2f96c91e693d70e33b4dc00d6",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx64/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx64/releng.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r168596"
+"clang_version": "r169139"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 56147341,
-"digest": "4baed5cbe0189a509b6a328ee35ee488250677f8ea149e6d01af74c7a4a27c898a4112f78af57b33a4e788b2947813b65ab0922e06b67bd504878803dab44f5c",
+"size": 56158651,
+"digest": "38d718f20a8fa9218e22ade312e724e6c9cdd7c6650e023cfdc21b5505fe7aa3743ae41c0abd717a1bbccec4c4271be2fa82d0e2f96c91e693d70e33b4dc00d6",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/devtools/framework/Toolbox.jsm
+++ b/browser/devtools/framework/Toolbox.jsm
@@ -13,17 +13,17 @@ Cu.import("resource:///modules/devtools/
 
 XPCOMUtils.defineLazyModuleGetter(this, "Hosts",
                                   "resource:///modules/devtools/ToolboxHosts.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "CommandUtils",
                                   "resource:///modules/devtools/DeveloperToolbar.jsm");
 
 // DO NOT put Require.jsm or gcli.jsm into lazy getters as this breaks the
 // requisition import a few lines down.
-Cu.import("resource://gre/modules/devtools/gcli.jsm");
+Cu.import("resource:///modules/devtools/gcli.jsm");
 Cu.import("resource://gre/modules/devtools/Require.jsm");
 
 let Requisition = require('gcli/cli').Requisition;
 let CommandOutputManager = require('gcli/canon').CommandOutputManager;
 
 this.EXPORTED_SYMBOLS = [ "Toolbox" ];
 
 /**
--- a/browser/devtools/framework/test/head.js
+++ b/browser/devtools/framework/test/head.js
@@ -1,16 +1,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/. */
 
 let tempScope = {};
 Components.utils.import("resource:///modules/devtools/Target.jsm", tempScope);
 let TargetFactory = tempScope.TargetFactory;
-Components.utils.import("resource:///modules/devtools/Console.jsm", tempScope);
+Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
 let console = tempScope.console;
 
 /**
  * Open a new tab at a URL and call a callback on load
  */
 function addTab(aURL, aCallback)
 {
   waitForExplicitFinish();
--- a/browser/devtools/inspector/InspectorPanel.jsm
+++ b/browser/devtools/inspector/InspectorPanel.jsm
@@ -8,17 +8,17 @@ const { classes: Cc, interfaces: Ci, uti
 
 this.EXPORTED_SYMBOLS = ["InspectorPanel"];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/EventEmitter.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "MarkupView",
-  "resource://gre/modules/devtools/MarkupView.jsm");
+  "resource:///modules/devtools/MarkupView.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Selection",
   "resource:///modules/devtools/Selection.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "HTMLBreadcrumbs",
   "resource:///modules/devtools/Breadcrumbs.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Highlighter",
   "resource:///modules/devtools/Highlighter.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ToolSidebar",
   "resource:///modules/devtools/Sidebar.jsm");
--- a/browser/devtools/styleeditor/StyleEditorChrome.jsm
+++ b/browser/devtools/styleeditor/StyleEditorChrome.jsm
@@ -365,27 +365,35 @@ StyleEditorChrome.prototype = {
           // If a line or column was specified we move the caret appropriately.
           let self = this;
           aEditor.addActionListener({
             onAttach: function SEC_selectSheet_onAttach()
             {
               aEditor.removeActionListener(this);
               self.selectedStyleSheetIndex = aEditor.styleSheetIndex;
               aEditor.sourceEditor.setCaretPosition(line - 1, col - 1);
+
+              let newSheet = self._styleSheetToSelect.sheet;
+              let newLine = self._styleSheetToSelect.line;
+              let newCol = self._styleSheetToSelect.col;
+              self._styleSheetToSelect = null;
+              if (newSheet != sheet) {
+                self._window.setTimeout(self.selectStyleSheet.bind(self, newSheet, newLine, newCol), 0);
+              }
             }
           });
         } else {
           // If a line or column was specified we move the caret appropriately.
           aEditor.sourceEditor.setCaretPosition(line - 1, col - 1);
+          self._styleSheetToSelect = null;
         }
       }
 
       this._view.activeSummary = summary;
       this.selectedStyleSheetIndex = aEditor.styleSheetIndex;
-      this._styleSheetToSelect = null;
     }.bind(this);
 
     if (!this.editors.length) {
       // We are in the main initialization phase so we wait for the editor
       // containing the target stylesheet to be added and select the target
       // stylesheet, optionally moving the cursor to a selected line.
       let self = this;
       this.addChromeListener({
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js
@@ -145,11 +145,14 @@ function performLineCheck(aEditor, aLine
 
   waitForSuccess({
     name: "source editor load",
     validatorFn: function()
     {
       return aEditor.sourceEditor;
     },
     successFn: checkForCorrectState,
-    failureFn: finishTest,
+    failureFn: function() {
+      info("selectedStyleSheetIndex " + SEC.selectedStyleSheetIndex + " expected " + aEditor.styleSheetIndex);
+      finishTest();
+    },
   });
 }
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,4 +1,4 @@
 This is the pdf.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 0.6.141
+Current extension version is: 0.6.172
 
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -17,17 +17,17 @@
 
 var PDFJS = {};
 
 (function pdfjsWrapper() {
   // Use strict in our context only - users might not want it
   'use strict';
 
   PDFJS.build =
-'033545c';
+'3c7ef79';
 
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 /* Copyright 2012 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -512,16 +512,27 @@ var PDFDocument = (function PDFDocumentC
     // Find the header, remove leading garbage and setup the stream
     // starting from the header.
     checkHeader: function PDFDocument_checkHeader() {
       var stream = this.stream;
       stream.reset();
       if (find(stream, '%PDF-', 1024)) {
         // Found the header, trim off any garbage before it.
         stream.moveStart();
+        // Reading file format version
+        var MAX_VERSION_LENGTH = 12;
+        var version = '', ch;
+        while ((ch = stream.getChar()) > ' ') {
+          if (version.length >= MAX_VERSION_LENGTH) {
+            break;
+          }
+          version += ch;
+        }
+        // removing "%PDF-"-prefix
+        this.pdfFormatVersion = version.substring(5);
         return;
       }
       // May not be a PDF file, continue anyway.
     },
     setup: function PDFDocument_setup(password) {
       this.checkHeader();
       var xref = new XRef(this.stream,
                           this.startXRef,
@@ -532,21 +543,22 @@ var PDFDocument = (function PDFDocumentC
     },
     get numPages() {
       var linearization = this.linearization;
       var num = linearization ? linearization.numPages : this.catalog.numPages;
       // shadow the prototype getter
       return shadow(this, 'numPages', num);
     },
     getDocumentInfo: function PDFDocument_getDocumentInfo() {
-      var docInfo;
+      var docInfo = {
+        PDFFormatVersion: this.pdfFormatVersion
+      };
       if (this.xref.trailer.has('Info')) {
         var infoDict = this.xref.trailer.get('Info');
 
-        docInfo = {};
         var validEntries = DocumentInfoValidators.entries;
         // Only fill the document info with valid entries from the spec.
         for (var key in validEntries) {
           if (infoDict.has(key)) {
             var value = infoDict.get(key);
             // Make sure the value conforms to the spec.
             if (validEntries[key](value)) {
               docInfo[key] = typeof value !== 'string' ? value :
@@ -653,16 +665,18 @@ function backtrace() {
 function assert(cond, msg) {
   if (!cond)
     error(msg);
 }
 
 // Combines two URLs. The baseUrl shall be absolute URL. If the url is an
 // absolute URL, it will be returned as is.
 function combineUrl(baseUrl, url) {
+  if (!url)
+    return baseUrl;
   if (url.indexOf(':') >= 0)
     return url;
   if (url.charAt(0) == '/') {
     // absolute path
     var i = baseUrl.indexOf('://');
     i = baseUrl.indexOf('/', i + 3);
     return baseUrl.substring(0, i) + url;
   } else {
@@ -762,25 +776,27 @@ function stringToBytes(str) {
   return bytes;
 }
 
 var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
 
 var Util = PDFJS.Util = (function UtilClosure() {
   function Util() {}
 
-  Util.makeCssRgb = function Util_makeCssRgb(r, g, b) {
-    var ri = (255 * r) | 0, gi = (255 * g) | 0, bi = (255 * b) | 0;
-    return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
-  };
-
-  Util.makeCssCmyk = function Util_makeCssCmyk(c, m, y, k) {
-    c = (new DeviceCmykCS()).getRgb([c, m, y, k]);
-    var ri = (255 * c[0]) | 0, gi = (255 * c[1]) | 0, bi = (255 * c[2]) | 0;
-    return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
+  Util.makeCssRgb = function Util_makeCssRgb(rgb) {
+    return 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
+  };
+
+  Util.makeCssCmyk = function Util_makeCssCmyk(cmyk) {
+    var cs = new DeviceCmykCS();
+    Util.makeCssCmyk = function makeCssCmyk(cmyk) {
+      var rgb = cs.getRgb(cmyk, 0);
+      return Util.makeCssRgb(rgb);
+    };
+    return Util.makeCssCmyk(cmyk);
   };
 
   // For 2d affine transforms
   Util.applyTransform = function Util_applyTransform(p, m) {
     var xt = p[0] * m[0] + p[1] * m[2] + m[4];
     var yt = p[0] * m[1] + p[1] * m[3] + m[5];
     return [xt, yt];
   };
@@ -2894,34 +2910,30 @@ var CanvasGraphics = (function CanvasGra
     setStrokeColorSpace: function CanvasGraphics_setStrokeColorSpace(raw) {
       this.current.strokeColorSpace = ColorSpace.fromIR(raw);
     },
     setFillColorSpace: function CanvasGraphics_setFillColorSpace(raw) {
       this.current.fillColorSpace = ColorSpace.fromIR(raw);
     },
     setStrokeColor: function CanvasGraphics_setStrokeColor(/*...*/) {
       var cs = this.current.strokeColorSpace;
-      var rgbColor = cs.getRgb(arguments);
-      var color = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
+      var rgbColor = cs.getRgb(arguments, 0);
+      var color = Util.makeCssRgb(rgbColor);
       this.ctx.strokeStyle = color;
       this.current.strokeColor = color;
     },
     getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR, cs) {
       if (IR[0] == 'TilingPattern') {
         var args = IR[1];
         var base = cs.base;
         var color;
         if (base) {
           var baseComps = base.numComps;
 
-          color = [];
-          for (var i = 0; i < baseComps; ++i)
-            color.push(args[i]);
-
-          color = base.getRgb(color);
+          color = base.getRgb(args, 0);
         }
         var pattern = new TilingPattern(IR, color, this.ctx, this.objs);
       } else if (IR[0] == 'RadialAxial' || IR[0] == 'Dummy') {
         var pattern = Pattern.shadingFromIR(IR);
       } else {
         error('Unkown IR type ' + IR[0]);
       }
       return pattern;
@@ -2932,75 +2944,79 @@ var CanvasGraphics = (function CanvasGra
       if (cs.name == 'Pattern') {
         this.current.strokeColor = this.getColorN_Pattern(arguments, cs);
       } else {
         this.setStrokeColor.apply(this, arguments);
       }
     },
     setFillColor: function CanvasGraphics_setFillColor(/*...*/) {
       var cs = this.current.fillColorSpace;
-      var rgbColor = cs.getRgb(arguments);
-      var color = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
+      var rgbColor = cs.getRgb(arguments, 0);
+      var color = Util.makeCssRgb(rgbColor);
       this.ctx.fillStyle = color;
       this.current.fillColor = color;
     },
     setFillColorN: function CanvasGraphics_setFillColorN(/*...*/) {
       var cs = this.current.fillColorSpace;
 
       if (cs.name == 'Pattern') {
         this.current.fillColor = this.getColorN_Pattern(arguments, cs);
       } else {
         this.setFillColor.apply(this, arguments);
       }
     },
     setStrokeGray: function CanvasGraphics_setStrokeGray(gray) {
       if (!(this.current.strokeColorSpace instanceof DeviceGrayCS))
         this.current.strokeColorSpace = new DeviceGrayCS();
 
-      var color = Util.makeCssRgb(gray, gray, gray);
+      var rgbColor = this.current.strokeColorSpace.getRgb(arguments, 0);
+      var color = Util.makeCssRgb(rgbColor);
       this.ctx.strokeStyle = color;
       this.current.strokeColor = color;
     },
     setFillGray: function CanvasGraphics_setFillGray(gray) {
       if (!(this.current.fillColorSpace instanceof DeviceGrayCS))
         this.current.fillColorSpace = new DeviceGrayCS();
 
-      var color = Util.makeCssRgb(gray, gray, gray);
+      var rgbColor = this.current.fillColorSpace.getRgb(arguments, 0);
+      var color = Util.makeCssRgb(rgbColor);
       this.ctx.fillStyle = color;
       this.current.fillColor = color;
     },
     setStrokeRGBColor: function CanvasGraphics_setStrokeRGBColor(r, g, b) {
       if (!(this.current.strokeColorSpace instanceof DeviceRgbCS))
         this.current.strokeColorSpace = new DeviceRgbCS();
 
-      var color = Util.makeCssRgb(r, g, b);
+      var rgbColor = this.current.strokeColorSpace.getRgb(arguments, 0);
+      var color = Util.makeCssRgb(rgbColor);
       this.ctx.strokeStyle = color;
       this.current.strokeColor = color;
     },
     setFillRGBColor: function CanvasGraphics_setFillRGBColor(r, g, b) {
       if (!(this.current.fillColorSpace instanceof DeviceRgbCS))
         this.current.fillColorSpace = new DeviceRgbCS();
 
-      var color = Util.makeCssRgb(r, g, b);
+      var rgbColor = this.current.fillColorSpace.getRgb(arguments, 0);
+      var color = Util.makeCssRgb(rgbColor);
       this.ctx.fillStyle = color;
       this.current.fillColor = color;
     },
     setStrokeCMYKColor: function CanvasGraphics_setStrokeCMYKColor(c, m, y, k) {
       if (!(this.current.strokeColorSpace instanceof DeviceCmykCS))
         this.current.strokeColorSpace = new DeviceCmykCS();
 
-      var color = Util.makeCssCmyk(c, m, y, k);
+      var color = Util.makeCssCmyk(arguments);
       this.ctx.strokeStyle = color;
       this.current.strokeColor = color;
     },
     setFillCMYKColor: function CanvasGraphics_setFillCMYKColor(c, m, y, k) {
       if (!(this.current.fillColorSpace instanceof DeviceCmykCS))
         this.current.fillColorSpace = new DeviceCmykCS();
 
-      var color = Util.makeCssCmyk(c, m, y, k);
+      var color = Util.makeCssCmyk(arguments);
       this.ctx.fillStyle = color;
       this.current.fillColor = color;
     },
 
     shadingFill: function CanvasGraphics_shadingFill(patternIR) {
       var ctx = this.ctx;
 
       this.save();
@@ -3575,18 +3591,20 @@ var Catalog = (function CatalogClosure()
               if (processed.has(kid))
                 error('invalid destinations');
               queue.push(kid);
               processed.put(kid);
             }
             continue;
           }
           var names = obj.get('Names');
-          for (i = 0, n = names.length; i < n; i += 2) {
-            dests[names[i]] = fetchDestination(xref.fetchIfRef(names[i + 1]));
+          if (names) {
+            for (i = 0, n = names.length; i < n; i += 2) {
+              dests[names[i]] = fetchDestination(xref.fetchIfRef(names[i + 1]));
+            }
           }
         }
       }
       return shadow(this, 'destinations', dests);
     },
     getPage: function Catalog_getPage(n) {
       var pageCache = this.pageCache;
       if (!pageCache) {
@@ -12048,25 +12066,68 @@ var CIDToUnicodeMaps = {
 
 var ColorSpace = (function ColorSpaceClosure() {
   // Constructor should define this.numComps, this.defaultColor, this.name
   function ColorSpace() {
     error('should not call ColorSpace constructor');
   }
 
   ColorSpace.prototype = {
-    // Input: array of size numComps representing color component values
-    // Output: array of rgb values, each value ranging from [0.1]
-    getRgb: function ColorSpace_getRgb(color) {
-      error('Should not call ColorSpace.getRgb: ' + color);
-    },
-    // Input: Uint8Array of component values, each value scaled to [0,255]
-    // Output: Uint8Array of rgb values, each value scaled to [0,255]
-    getRgbBuffer: function ColorSpace_getRgbBuffer(input) {
-      error('Should not call ColorSpace.getRgbBuffer: ' + input);
+    /**
+     * Converts the color value to the RGB color. The color components are
+     * located in the src array starting from the srcOffset. Returns the array
+     * of the rgb components, each value ranging from [0,255].
+     */
+    getRgb: function ColorSpace_getRgb(src, srcOffset) {
+      error('Should not call ColorSpace.getRgb');
+    },
+    /**
+     * Converts the color value to the RGB color, similar to the getRgb method.
+     * The result placed into the dest array starting from the destOffset.
+     */
+    getRgbItem: function ColorSpace_getRgb(src, srcOffset, dest, destOffset) {
+      error('Should not call ColorSpace.getRgbItem');
+    },
+    /**
+     * Converts the specified number of the color values to the RGB colors.
+     * The colors are located in the src array starting from the srcOffset.
+     * The result is placed into the dest array starting from the destOffset.
+     * The src array items shall be in [0,2^bits) range, the dest array items
+     * will be in [0,255] range.
+     */
+    getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count,
+                                                   dest, destOffset, bits) {
+      error('Should not call ColorSpace.getRgbBuffer');
+    },
+    /**
+     * Determines amount of the bytes is required to store the reslut of the
+     * conversion that done by the getRgbBuffer method.
+     */
+    getOutputLength: function ColorSpace_getOutputLength(inputLength) {
+      error('Should not call ColorSpace.getOutputLength');
+    },
+    /**
+     * Returns true if source data will be equal the result/output data.
+     */
+    isPassthrough: function ColorSpace_isPassthrough(bits) {
+      return false;
+    },
+    /**
+     * Creates the output buffer and converts the specified number of the color
+     * values to the RGB colors, similar to the getRgbBuffer.
+     */
+    createRgbBuffer: function ColorSpace_createRgbBuffer(src, srcOffset,
+                                                         count, bits) {
+      if (this.isPassthrough(bits)) {
+        return src.subarray(srcOffset);
+      }
+      var destLength = this.getOutputLength(count * this.numComps);
+      var dest = new Uint8Array(destLength);
+      this.getRgbBuffer(src, srcOffset, count, dest, 0, bits);
+      return dest;
     }
   };
 
   ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
     var IR = ColorSpace.parseToIR(cs, xref, res);
     if (IR instanceof AlternateCS)
       return IR;
 
@@ -12240,49 +12301,76 @@ var ColorSpace = (function ColorSpaceClo
  * Separation color space is actually just a DeviceN with one color component.
  * Both color spaces use a tinting function to convert colors to a base color
  * space.
  */
 var AlternateCS = (function AlternateCSClosure() {
   function AlternateCS(numComps, base, tintFn) {
     this.name = 'Alternate';
     this.numComps = numComps;
-    this.defaultColor = [];
-    for (var i = 0; i < numComps; ++i)
-      this.defaultColor.push(1);
+    this.defaultColor = new Float32Array(numComps);
+    for (var i = 0; i < numComps; ++i) {
+      this.defaultColor[i] = 1;
+    }
     this.base = base;
     this.tintFn = tintFn;
   }
 
   AlternateCS.prototype = {
-    getRgb: function AlternateCS_getRgb(color) {
-      var tinted = this.tintFn(color);
-      return this.base.getRgb(tinted);
-    },
-    getRgbBuffer: function AlternateCS_getRgbBuffer(input, bits) {
+    getRgb: function AlternateCS_getRgb(src, srcOffset) {
+      var rgb = new Uint8Array(3);
+      this.getRgbItem(src, srcOffset, rgb, 0);
+      return rgb;
+    },
+    getRgbItem: function AlternateCS_getRgbItem(src, srcOffset,
+                                                dest, destOffset) {
+      var baseNumComps = this.base.numComps;
+      var input = 'subarray' in src ?
+        src.subarray(srcOffset, srcOffset + this.numComps) :
+        Array.prototype.slice.call(src, srcOffset, srcOffset + this.numComps);
+      var tinted = this.tintFn(input);
+      this.base.getRgbItem(tinted, 0, dest, destOffset);
+    },
+    getRgbBuffer: function AlternateCS_getRgbBuffer(src, srcOffset, count,
+                                                    dest, destOffset, bits) {
       var tintFn = this.tintFn;
       var base = this.base;
       var scale = 1 / ((1 << bits) - 1);
-      var length = input.length;
-      var pos = 0;
       var baseNumComps = base.numComps;
-      var baseBuf = new Uint8Array(baseNumComps * length);
+      var isGetRgbBufferSupported = 'getRgbBuffer' in base;
+      var isPassthrough = base.isPassthrough(8) || !isGetRgbBufferSupported;
+      var pos = isPassthrough ? destOffset : 0;
+      var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count);
       var numComps = this.numComps;
-      var scaled = [];
-
-      for (var i = 0; i < length; i += numComps) {
-        for (var z = 0; z < numComps; ++z)
-          scaled[z] = input[i + z] * scale;
-
+
+      var scaled = new Float32Array(numComps);
+      for (var i = 0; i < count; i++) {
+        for (var j = 0; j < numComps; j++) {
+          scaled[j] = src[srcOffset++] * scale;
+        }
         var tinted = tintFn(scaled);
-        for (var j = 0; j < baseNumComps; ++j)
-          baseBuf[pos++] = 255 * tinted[j];
-      }
-      return base.getRgbBuffer(baseBuf, 8);
-    },
+        if (isGetRgbBufferSupported) {
+          for (var j = 0; j < baseNumComps; j++) {
+            baseBuf[pos++] = tinted[j] * 255;
+          }
+        } else {
+          base.getRgbItem(tinted, 0, baseBuf, pos);
+          pos += baseNumComps;
+        }
+      }
+      if (!isPassthrough) {
+        base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8);
+      }
+    },
+    getOutputLength: function AlternateCS_getOutputLength(inputLength) {
+      return this.base.getOutputLength(inputLength *
+                                       this.base.numComps / this.numComps);
+    },
+    isPassthrough: ColorSpace.prototype.isPassthrough,
+    createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
     isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {
       return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
     }
   };
 
   return AlternateCS;
 })();
 
@@ -12295,17 +12383,17 @@ var PatternCS = (function PatternCSClosu
 
   return PatternCS;
 })();
 
 var IndexedCS = (function IndexedCSClosure() {
   function IndexedCS(base, highVal, lookup) {
     this.name = 'Indexed';
     this.numComps = 1;
-    this.defaultColor = [0];
+    this.defaultColor = new Uint8Array([0]);
     this.base = base;
     this.highVal = highVal;
 
     var baseNumComps = base.numComps;
     var length = baseNumComps * highVal;
     var lookupArray;
 
     if (isStream(lookup)) {
@@ -12320,102 +12408,136 @@ var IndexedCS = (function IndexedCSClosu
       lookupArray = lookup;
     } else {
       error('Unrecognized lookup table: ' + lookup);
     }
     this.lookup = lookupArray;
   }
 
   IndexedCS.prototype = {
-    getRgb: function IndexedCS_getRgb(color) {
+    getRgb: function IndexedCS_getRgb(src, srcOffset) {
       var numComps = this.base.numComps;
-      var start = color[0] * numComps;
-      var c = [];
-
-      for (var i = start, ii = start + numComps; i < ii; ++i)
-        c.push(this.lookup[i]);
-
-      return this.base.getRgb(c);
-    },
-    getRgbBuffer: function IndexedCS_getRgbBuffer(input) {
+      var start = src[srcOffset] * numComps;
+      return this.base.getRgb(this.lookup, start);
+    },
+    getRgbItem: function IndexedCS_getRgbItem(src, srcOffset,
+                                              dest, destOffset) {
+      var numComps = this.base.numComps;
+      var start = src[srcOffset] * numComps;
+      this.base.getRgbItem(this.lookup, start, dest, destOffset);
+    },
+    getRgbBuffer: function IndexedCS_getRgbBuffer(src, srcOffset, count,
+                                                  dest, destOffset) {
       var base = this.base;
       var numComps = base.numComps;
+      var outputDelta = base.getOutputLength(numComps);
       var lookup = this.lookup;
-      var length = input.length;
-      var baseBuf = new Uint8Array(length * numComps);
-      var baseBufPos = 0;
-
-      for (var i = 0; i < length; ++i) {
-        var lookupPos = input[i] * numComps;
-        for (var j = 0; j < numComps; ++j) {
-          baseBuf[baseBufPos++] = lookup[lookupPos + j];
-        }
-      }
-
-      return base.getRgbBuffer(baseBuf, 8);
-    },
+
+      for (var i = 0; i < count; ++i) {
+        var lookupPos = src[srcOffset++] * numComps;
+        base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8);
+        destOffset += outputDelta;
+      }
+    },
+    getOutputLength: function IndexedCS_getOutputLength(inputLength) {
+      return this.base.getOutputLength(inputLength * this.base.numComps);
+    },
+    isPassthrough: ColorSpace.prototype.isPassthrough,
+    createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
     isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {
       // indexed color maps shouldn't be changed
       return true;
     }
   };
   return IndexedCS;
 })();
 
 var DeviceGrayCS = (function DeviceGrayCSClosure() {
   function DeviceGrayCS() {
     this.name = 'DeviceGray';
     this.numComps = 1;
-    this.defaultColor = [0];
+    this.defaultColor = new Float32Array([0]);
   }
 
   DeviceGrayCS.prototype = {
-    getRgb: function DeviceGrayCS_getRgb(color) {
-      var c = color[0];
-      return [c, c, c];
-    },
-    getRgbBuffer: function DeviceGrayCS_getRgbBuffer(input, bits) {
+    getRgb: function DeviceGrayCS_getRgb(src, srcOffset) {
+      var rgb = new Uint8Array(3);
+      this.getRgbItem(src, srcOffset, rgb, 0);
+      return rgb;
+    },
+    getRgbItem: function DeviceGrayCS_getRgbItem(src, srcOffset,
+                                                 dest, destOffset) {
+      var c = (src[srcOffset] * 255) | 0;
+      c = c < 0 ? 0 : c > 255 ? 255 : c;
+      dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c;
+    },
+    getRgbBuffer: function DeviceGrayCS_getRgbBuffer(src, srcOffset, count,
+                                                     dest, destOffset, bits) {
       var scale = 255 / ((1 << bits) - 1);
-      var length = input.length;
-      var rgbBuf = new Uint8Array(length * 3);
-      for (var i = 0, j = 0; i < length; ++i) {
-        var c = (scale * input[i]) | 0;
-        rgbBuf[j++] = c;
-        rgbBuf[j++] = c;
-        rgbBuf[j++] = c;
-      }
-      return rgbBuf;
-    },
+      var j = srcOffset, q = destOffset;
+      for (var i = 0; i < count; ++i) {
+        var c = (scale * src[j++]) | 0;
+        dest[q++] = c;
+        dest[q++] = c;
+        dest[q++] = c;
+      }
+    },
+    getOutputLength: function DeviceGrayCS_getOutputLength(inputLength) {
+      return inputLength * 3;
+    },
+    isPassthrough: ColorSpace.prototype.isPassthrough,
+    createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
     isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
       return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
     }
   };
   return DeviceGrayCS;
 })();
 
 var DeviceRgbCS = (function DeviceRgbCSClosure() {
   function DeviceRgbCS() {
     this.name = 'DeviceRGB';
     this.numComps = 3;
-    this.defaultColor = [0, 0, 0];
+    this.defaultColor = new Float32Array([0, 0, 0]);
   }
   DeviceRgbCS.prototype = {
-    getRgb: function DeviceRgbCS_getRgb(color) {
-      return color;
-    },
-    getRgbBuffer: function DeviceRgbCS_getRgbBuffer(input, bits) {
-      if (bits == 8)
-        return input;
+    getRgb: function DeviceRgbCS_getRgb(src, srcOffset) {
+      var rgb = new Uint8Array(3);
+      this.getRgbItem(src, srcOffset, rgb, 0);
+      return rgb;
+    },
+    getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset,
+                                                dest, destOffset) {
+      var r = src[srcOffset] * 255;
+      var g = src[srcOffset + 1] * 255;
+      var b = src[srcOffset + 2] * 255;
+      dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r;
+      dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g;
+      dest[destOffset + 2] = b < 0 ? 0 : b > 255 ? 255 : b;
+    },
+    getRgbBuffer: function DeviceRgbCS_getRgbBuffer(src, srcOffset, count,
+                                                    dest, destOffset, bits) {
+      var length = count * 3;
+      if (bits == 8) {
+        dest.set(src.subarray(srcOffset, srcOffset + length), destOffset);
+        return;
+      }
       var scale = 255 / ((1 << bits) - 1);
-      var i, length = input.length;
-      var rgbBuf = new Uint8Array(length);
-      for (i = 0; i < length; ++i)
-        rgbBuf[i] = (scale * input[i]) | 0;
-      return rgbBuf;
-    },
+      var j = srcOffset, q = destOffset;
+      for (var i = 0; i < length; ++i) {
+        dest[q++] = (scale * input[j++]) | 0;
+      }
+    },
+    getOutputLength: function DeviceRgbCS_getOutputLength(inputLength) {
+      return inputLength;
+    },
+    isPassthrough: function DeviceRgbCS_isPassthrough(bits) {
+      return bits == 8;
+    },
+    createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
     isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
       return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
     }
   };
   return DeviceRgbCS;
 })();
 
 var DeviceCmykCS = (function DeviceCmykCSClosure() {
@@ -13083,98 +13205,104 @@ var DeviceCmykCS = (function DeviceCmykC
     105, 22, 33, 91, 12, 22, 76, 0, 8, 61, 0, 0, 45, 0, 1, 24, 0, 0, 0, 40, 53,
     106, 34, 43, 93, 27, 34, 80, 17, 23, 67, 5, 9, 53, 0, 0, 37, 0, 0, 16, 0, 0,
     0, 45, 53, 94, 38, 44, 82, 31, 34, 70, 20, 24, 58, 10, 11, 45, 0, 0, 29, 0,
     0, 9, 0, 0, 0, 48, 53, 81, 42, 44, 70, 34, 35, 60, 24, 24, 48, 13, 12, 36,
     0, 0, 21, 0, 0, 3, 0, 0, 0, 51, 53, 68, 45, 44, 58, 37, 35, 48, 26, 25, 37,
     15, 13, 26, 2, 1, 11, 0, 0, 0, 0, 0, 0, 54, 54, 57, 47, 44, 47, 39, 35, 39,
     28, 25, 29, 17, 13, 17, 4, 1, 3, 0, 0, 0, 0, 0, 0]);
 
+  function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
+    // using lut as in spline interpolation (see function.js)
+    var cubeVertices = 16; // 1 << number of colors
+    var cubeN = new Float32Array(cubeVertices);
+    var cubeVertex = new Uint32Array(cubeVertices);
+    for (var j = 0; j < cubeVertices; j++)
+      cubeN[j] = 1;
+
+    var k = 3, pos = 1;
+    var lutDomain = 7, lutStep = 8;
+    for (var i = 3; i >= 0; i--) {
+      var e = src[srcOffset + i] * srcScale * lutDomain;
+
+      var e0 = e < lutDomain ? Math.floor(e) : e - 1; // e1 = e0 + 1;
+      var n0 = e0 + 1 - e; // (e1 - e) / (e1 - e0);
+      var n1 = e - e0; // (e - e0) / (e1 - e0);
+      var offset0 = e0 * k;
+      var offset1 = offset0 + k; // e1 * k
+      for (var j = 0; j < cubeVertices; j++) {
+        if (j & pos) {
+          cubeN[j] *= n1;
+          cubeVertex[j] += offset1;
+        } else {
+          cubeN[j] *= n0;
+          cubeVertex[j] += offset0;
+        }
+      }
+
+      k *= lutStep;
+      pos <<= 1;
+    }
+    var y0 = 0, y1 = 0, y2 = 0;
+    for (var i = 0; i < cubeVertices; i++)
+      y0 += lut[cubeVertex[i]] * cubeN[i];
+    for (var i = 0; i < cubeVertices; i++)
+      y1 += lut[cubeVertex[i] + 1] * cubeN[i];
+    for (var i = 0; i < cubeVertices; i++)
+      y2 += lut[cubeVertex[i] + 2] * cubeN[i];
+    dest[destOffset] = y0 > 255 ? 255 : y0;
+    dest[destOffset + 1] = y1 > 255 ? 255 : y1;
+    dest[destOffset + 2] = y2 > 255 ? 255 : y2;
+  }
+
   function DeviceCmykCS() {
     this.name = 'DeviceCMYK';
     this.numComps = 4;
-    this.defaultColor = [0, 0, 0, 1];
+    this.defaultColor = new Float32Array([0, 0, 0, 1]);
   }
   DeviceCmykCS.prototype = {
-    getRgb: function DeviceCmykCS_getRgb(color) {
-      // using lut as in spline interpolation (see function.js)
-      var cubeVertices = 16; // 1 << number of colors
-      var cubeN = new Float32Array(cubeVertices);
-      var cubeVertex = new Uint32Array(cubeVertices);
-      for (var j = 0; j < cubeVertices; j++)
-        cubeN[j] = 1;
-
-      var k = 3, pos = 1;
-      var lutDomain = 7, lutStep = 8;
-      for (var i = 3; i >= 0; i--) {
-        var e = color[i] * lutDomain;
-
-        var e0 = e < lutDomain ? Math.floor(e) : e - 1; // e1 = e0 + 1;
-        var n0 = e0 + 1 - e; // (e1 - e) / (e1 - e0);
-        var n1 = e - e0; // (e - e0) / (e1 - e0);
-        var offset0 = e0 * k;
-        var offset1 = offset0 + k; // e1 * k
-        for (var j = 0; j < cubeVertices; j++) {
-          if (j & pos) {
-            cubeN[j] *= n1;
-            cubeVertex[j] += offset1;
-          } else {
-            cubeN[j] *= n0;
-            cubeVertex[j] += offset0;
-          }
-        }
-
-        k *= lutStep;
-        pos <<= 1;
-      }
-      var y = new Float32Array(3);
-      for (var j = 0; j < 3; ++j) {
-        var rj = 0;
-        for (var i = 0; i < cubeVertices; i++)
-          rj += lut[cubeVertex[i] + j] * cubeN[i];
-        y[j] = rj;
-      }
-
-      return [y[0] / 255, y[1] / 255, y[2] / 255];
-    },
-    getRgbBuffer: function DeviceCmykCS_getRgbBuffer(colorBuf, bits) {
+    getRgb: function DeviceCmykCS_getRgb(src, srcOffset) {
+      var rgb = new Uint8Array(3);
+      convertToRgb(src, srcOffset, 1, rgb, 0);
+      return rgb;
+    },
+    getRgbItem: function DeviceCmykCS_getRgbItem(src, srcOffset,
+                                                 dest, destOffset) {
+      convertToRgb(src, srcOffset, 1, dest, destOffset);
+    },
+    getRgbBuffer: function DeviceCmykCS_getRgbBuffer(src, srcOffset, count,
+                                                     dest, destOffset, bits) {
       var scale = 1 / ((1 << bits) - 1);
-      var length = colorBuf.length / 4;
-      var rgbBuf = new Uint8Array(length * 3);
-      var rgbBufPos = 0;
-      var colorBufPos = 0;
-
-      for (var i = 0; i < length; i++) {
-        var cmyk = [];
-        for (var j = 0; j < 4; ++j)
-          cmyk.push(scale * colorBuf[colorBufPos++]);
-
-        var rgb = this.getRgb(cmyk);
-        for (var j = 0; j < 3; ++j)
-          rgbBuf[rgbBufPos++] = Math.round(rgb[j] * 255);
-      }
-
-      return rgbBuf;
-    },
+      for (var i = 0; i < count; i++) {
+        convertToRgb(src, srcOffset, scale, dest, destOffset);
+        srcOffset += 4;
+        destOffset += 3;
+      }
+    },
+    getOutputLength: function DeviceCmykCS_getOutputLength(inputLength) {
+      return (inputLength >> 2) * 3;
+    },
+    isPassthrough: ColorSpace.prototype.isPassthrough,
+    createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
     isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {
       return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
     }
   };
 
   return DeviceCmykCS;
 })();
 
 //
 // LabCS: Based on "PDF Reference, Sixth Ed", p.250
 //
 var LabCS = (function LabCSClosure() {
   function LabCS(whitePoint, blackPoint, range) {
     this.name = 'Lab';
     this.numComps = 3;
-    this.defaultColor = [0, 0, 0];
+    this.defaultColor = new Float32Array([0, 0, 0]);
 
     if (!whitePoint)
       error('WhitePoint missing - required for color space Lab');
     blackPoint = blackPoint || [0, 0, 0];
     range = range || [-100, 100, -100, 100];
 
     // Translate args to spec variables
     this.XW = whitePoint[0];
@@ -13205,68 +13333,76 @@ var LabCS = (function LabCSClosure() {
       this.amin = -100;
       this.amax = 100;
       this.bmin = -100;
       this.bmax = 100;
     }
   };
 
   // Function g(x) from spec
-  function g(x) {
+  function fn_g(x) {
     if (x >= 6 / 29)
       return x * x * x;
     else
       return (108 / 841) * (x - 4 / 29);
   }
 
+  function convertToRgb(cs, src, srcOffset, dest, destOffset) {
+    // Ls,as,bs <---> L*,a*,b* in the spec
+    var Ls = src[srcOffset];
+    var as = src[srcOffset + 1];
+    var bs = src[srcOffset + 2];
+
+    // Adjust limits of 'as' and 'bs'
+    as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as;
+    bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.bmin : bs;
+
+    // Computes intermediate variables X,Y,Z as per spec
+    var M = (Ls + 16) / 116;
+    var L = M + (as / 500);
+    var N = M - (bs / 200);
+
+    var X = cs.XW * fn_g(L);
+    var Y = cs.YW * fn_g(M);
+    var Z = cs.ZW * fn_g(N);
+
+    var r, g, b;
+    // Using different conversions for D50 and D65 white points,
+    // per http://www.color.org/srgb.pdf
+    if (cs.ZW < 1) {
+      // Assuming D50 (X=0.9642, Y=1.00, Z=0.8249)
+      r = X * 3.1339 + Y * -1.6170 + Z * -0.4906;
+      g = X * -0.9785 + Y * 1.9160 + Z * 0.0333;
+      b = X * 0.0720 + Y * -0.2290 + Z * 1.4057;
+    } else {
+      // Assuming D65 (X=0.9505, Y=1.00, Z=1.0888)
+      r = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
+      g = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
+      b = X * 0.0557 + Y * -0.2040 + Z * 1.0570;
+    }
+
+    // clamp color values to [0,255] range
+    dest[destOffset] = r < 0 ? 0 : r > 1 ? 255 : r * 255;
+    dest[destOffset + 1] = g < 0 ? 0 : g > 1 ? 255 : g * 255;
+    dest[destOffset + 2] = b < 0 ? 0 : b > 1 ? 255 : b * 255;
+  }
+
   LabCS.prototype = {
-    getRgb: function LabCS_getRgb(color) {
-      // Ls,as,bs <---> L*,a*,b* in the spec
-      var Ls = color[0], as = color[1], bs = color[2];
-
-      // Adjust limits of 'as' and 'bs'
-      as = as > this.amax ? this.amax : as;
-      as = as < this.amin ? this.amin : as;
-      bs = bs > this.bmax ? this.bmax : bs;
-      bs = bs < this.bmin ? this.bmin : bs;
-
-      // Computes intermediate variables X,Y,Z as per spec
-      var M = (Ls + 16) / 116;
-      var L = M + (as / 500);
-      var N = M - (bs / 200);
-      var X = this.XW * g(L);
-      var Y = this.YW * g(M);
-      var Z = this.ZW * g(N);
-
-      // XYZ to RGB 3x3 matrix, from:
-      // http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC18
-      var XYZtoRGB = [3.240479, -1.537150, -0.498535,
-                      -0.969256, 1.875992, 0.041556,
-                      0.055648, -0.204043, 1.057311];
-
-      return Util.apply3dTransform(XYZtoRGB, [X, Y, Z]);
-    },
-    getRgbBuffer: function LabCS_getRgbBuffer(input, bits) {
-      if (bits == 8)
-        return input;
-      var scale = 255 / ((1 << bits) - 1);
-      var i, length = input.length / 3;
-      var rgbBuf = new Uint8Array(length);
-
-      var j = 0;
-      for (i = 0; i < length; ++i) {
-        // Convert L*, a*, s* into RGB
-        var rgb = this.getRgb([input[i], input[i + 1], input[i + 2]]);
-        rgbBuf[j++] = rgb[0];
-        rgbBuf[j++] = rgb[1];
-        rgbBuf[j++] = rgb[2];
-      }
-
-      return rgbBuf;
-    },
+    getRgb: function LabCS_getRgb(src, srcOffset) {
+      var rgb = new Uint8Array(3);
+      convertToRgb(this, src, srcOffset, rgb, 0);
+      return rgb;
+    },
+    getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) {
+      convertToRgb(this, src, srcOffset, dest, destOffset);
+    },
+    getOutputLength: function LabCS_getOutputLength(inputLength) {
+      return inputLength;
+    },
+    isPassthrough: ColorSpace.prototype.isPassthrough,
     isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {
       // From Table 90 in Adobe's:
       // "Document management - Portable document format", 1st ed, 2008
       if (decodeMap[0] === 0 && decodeMap[1] === 100 &&
           decodeMap[2] === this.amin && decodeMap[3] === this.amax &&
           decodeMap[4] === this.bmin && decodeMap[5] === this.bmax)
         return true;
       else
@@ -26092,18 +26228,18 @@ var PDFImage = (function PDFImageClosure
       // rows start at byte boundary;
       var rowBytes = (originalWidth * numComps * bpc + 7) >> 3;
       var imgArray = this.getImageBytes(originalHeight * rowBytes);
 
       // imgArray can be incomplete (e.g. after CCITT fax encoding)
       var actualHeight = 0 | (imgArray.length / rowBytes *
                          height / originalHeight);
 
-      var comps = this.colorSpace.getRgbBuffer(
-        this.getComponents(imgArray), bpc);
+      var comps = this.colorSpace.createRgbBuffer(this.getComponents(imgArray),
+        0, originalWidth * originalHeight, bpc);
       if (originalWidth != width || originalHeight != height)
         comps = PDFImage.resize(comps, this.bpc, 3, originalWidth,
                                 originalHeight, width, height);
       var compsPos = 0;
       var opacity = this.getOpacity(width, height, imgArray);
       var opacityPos = 0;
       var length = width * actualHeight * 4;
 
@@ -29845,21 +29981,39 @@ Shadings.RadialAxial = (function RadialA
         warn('Unsupported radial gradient.');
       }
     }
 
     this.extendStart = extendStart;
     this.extendEnd = extendEnd;
 
     var fnObj = dict.get('Function');
-    if (isArray(fnObj))
-      error('No support for array of functions');
-    if (!isPDFFunction(fnObj))
-      error('Invalid function');
-    var fn = PDFFunction.parse(xref, fnObj);
+    var fn;
+    if (isArray(fnObj)) {
+      var fnArray = [];
+      for (var j = 0, jj = fnObj.length; j < jj; j++) {
+        var obj = xref.fetchIfRef(fnObj[j]);
+        if (!isPDFFunction(obj)) {
+          error('Invalid function');
+        }
+        fnArray.push(PDFFunction.parse(xref, obj));
+      }
+      fn = function radialAxialColorFunction(arg) {
+        var out = [];
+        for (var i = 0, ii = fnArray.length; i < ii; i++) {
+          out.push(fnArray[i](arg)[0]);
+        }
+        return out;
+      };
+    } else {
+      if (!isPDFFunction(fnObj)) {
+        error('Invalid function');
+      }
+      fn = PDFFunction.parse(xref, fnObj);
+    }
 
     // 10 samples seems good enough for now, but probably won't work
     // if there are sharp color changes. Ideally, we would implement
     // the spec faithfully and add lossless optimizations.
     var diff = t1 - t0;
     var step = diff / 10;
 
     var colorStops = this.colorStops = [];
@@ -29868,25 +30022,25 @@ Shadings.RadialAxial = (function RadialA
     if (t0 >= t1 || step <= 0) {
       // Acrobat doesn't seem to handle these cases so we'll ignore for
       // now.
       info('Bad shading domain.');
       return;
     }
 
     for (var i = t0; i <= t1; i += step) {
-      var rgbColor = cs.getRgb(fn([i]));
-      var cssColor = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
+      var rgbColor = cs.getRgb(fn([i]), 0);
+      var cssColor = Util.makeCssRgb(rgbColor);
       colorStops.push([(i - t0) / diff, cssColor]);
     }
 
     var background = 'transparent';
     if (dict.has('Background')) {
-      var rgbColor = cs.getRgb(dict.get('Background'));
-      background = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
+      var rgbColor = cs.getRgb(dict.get('Background'), 0);
+      background = Util.makeCssRgb(rgbColor);
     }
 
     if (!extendStart) {
       // Insert a color stop at the front and offset the first real color stop
       // so it doesn't conflict with the one we insert.
       colorStops.unshift([0, background]);
       colorStops[1][0] += Shadings.SMALL_NUMBER;
     }
@@ -30024,17 +30178,18 @@ var TilingPattern = (function TilingPatt
     var graphics = new CanvasGraphics(tmpCtx, null, objs);
 
     switch (paintType) {
       case PaintType.COLORED:
         tmpCtx.fillStyle = ctx.fillStyle;
         tmpCtx.strokeStyle = ctx.strokeStyle;
         break;
       case PaintType.UNCOLORED:
-        var cssColor = Util.makeCssRgb(this, color[0], color[1], color[2]);
+        var rgbColor = new DeviceRgbCS().getRgb(color, 0);
+        var cssColor = Util.makeCssRgb(rgbColor);
         tmpCtx.fillStyle = cssColor;
         tmpCtx.strokeStyle = cssColor;
         break;
       default:
         error('Unsupported paint type: ' + paintType);
     }
 
     var scale = [width / xstep, height / ystep];
--- a/browser/extensions/pdfjs/content/web/viewer.html
+++ b/browser/extensions/pdfjs/content/web/viewer.html
@@ -27,17 +27,16 @@ limitations under the License.
 
 
     <link rel="stylesheet" href="viewer.css"/>
 
 
 
 
 
-
     <script type="text/javascript" src="debugger.js"></script>
     <script type="text/javascript" src="viewer.js"></script>
   </head>
 
   <body>
     <div id="outerContainer">
 
       <div id="sidebarContainer">
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -676,21 +676,21 @@ var PDFFindBar = {
 
       case FindStates.FIND_NOTFOUND:
         findMsg = mozL10n.get('find_not_found', null, 'Phrase not found');
         notFound = true;
         break;
 
       case FindStates.FIND_WRAPPED:
         if (previous) {
-          findMsg = mozL10n.get('find_wrapped_to_bottom', null,
-                                'Reached top of page, continued from bottom');
+          findMsg = mozL10n.get('find_reached_top', null,
+                      'Reached top of document, continued from bottom');
         } else {
-          findMsg = mozL10n.get('find_wrapped_to_top', null,
-                                'Reached end of page, continued from top');
+          findMsg = mozL10n.get('find_reached_bottom', null,
+                                'Reached end of document, continued from top');
         }
         break;
     }
 
     if (notFound) {
       this.findField.classList.add('notFound');
     } else {
       this.findField.classList.remove('notFound');
@@ -961,24 +961,28 @@ var PDFView = {
       }
     });
     FirefoxCom.requestSync('initPassiveLoading', null);
   },
 
   setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
     this.url = url;
     try {
-      document.title = decodeURIComponent(getFileName(url)) || url;
+      this.setTitle(decodeURIComponent(getFileName(url)) || url);
     } catch (e) {
       // decodeURIComponent may throw URIError,
       // fall back to using the unprocessed url in that case
-      document.title = url;
+      this.setTitle(url);
     }
   },
 
+  setTitle: function pdfViewSetTitle(title) {
+    document.title = title;
+  },
+
   open: function pdfViewOpen(url, scale, password) {
     var parameters = {password: password};
     if (typeof url === 'string') { // URL
       this.setTitleUsingUrl(url);
       parameters.url = url;
     } else if (url && 'byteLength' in url) { // ArrayBuffer
       parameters.data = url;
     }
@@ -1281,27 +1285,32 @@ var PDFView = {
       self.setInitialView(storedHash, scale);
     });
 
     pdfDocument.getMetadata().then(function(data) {
       var info = data.info, metadata = data.metadata;
       self.documentInfo = info;
       self.metadata = metadata;
 
+      // Provides some basic debug information
+      console.log('PDF ' + pdfDocument.fingerprint + ' [' +
+                  info.PDFFormatVersion + ' ' + (info.Producer || '-') +
+                  ' / ' + (info.Creator || '-') + ']');
+
       var pdfTitle;
       if (metadata) {
         if (metadata.has('dc:title'))
           pdfTitle = metadata.get('dc:title');
       }
 
       if (!pdfTitle && info && info['Title'])
         pdfTitle = info['Title'];
 
       if (pdfTitle)
-        document.title = pdfTitle + ' - ' + document.title;
+        self.setTitle(pdfTitle + ' - ' + document.title);
     });
   },
 
   setInitialView: function pdfViewSetInitialView(storedHash, scale) {
     // Reset the current scale, as otherwise the page's scale might not get
     // updated if the zoom level stayed the same.
     this.currentScale = 0;
     this.currentScaleValue = null;
@@ -2981,17 +2990,17 @@ function selectScaleOption(value) {
     }
     option.selected = true;
     predefinedValueFound = true;
   }
   return predefinedValueFound;
 }
 
 window.addEventListener('localized', function localized(evt) {
-  document.getElementsByTagName('html')[0].dir = mozL10n.language.direction;
+  document.getElementsByTagName('html')[0].dir = mozL10n.getDirection();
 }, true);
 
 window.addEventListener('scalechange', function scalechange(evt) {
   var customScaleOption = document.getElementById('customScaleOption');
   customScaleOption.selected = false;
 
   if (!evt.resetAutoSettings &&
        (document.getElementById('pageWidthOption').selected ||
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -699,27 +699,27 @@ searchplugins/yandex.png
 searchplugins/yandex.src
 searchplugins/zoznam-sk.gif
 searchplugins/zoznam-sk.png
 searchplugins/zoznam-sk.src
 uninstall/UninstallDeerPark.exe
 uninstall/UninstallFirefox.exe
 uninstall/uninst.exe
 uninstall/uninstall.exe
-update.locale
 #ifndef MOZ_UPDATER
   #ifdef XP_MACOSX
     updater.app/
   #else
     updater@BIN_SUFFIX@
   #endif
   updater.ini
 #endif
 xpicleanup@BIN_SUFFIX@
 #ifdef MOZ_OMNIJAR
+  update.locale
   omni.jar
   chrome/af.jar
   chrome/af.manifest
   chrome/ar.jar
   chrome/ar.manifest
   chrome/as.jar
   chrome/as.manifest
   chrome/ast.jar
--- a/browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd
@@ -3,21 +3,32 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <!ENTITY privatebrowsingpage.title                 "Private Browsing">
 <!ENTITY privatebrowsingpage.title.normal          "Would you like to start Private Browsing?">
 
 <!ENTITY privatebrowsingpage.issueDesc                 "&brandShortName; won't remember any history for this session.">
 <!ENTITY privatebrowsingpage.issueDesc.normal          "&brandShortName; is not currently in Private Browsing mode.">
 
+<!ENTITY privatebrowsingpage.perwindow.issueDesc        "&brandShortName; won't remember any history for this window.">
+<!ENTITY privatebrowsingpage.perwindow.issueDesc.normal "You are not currently in a private window.">
+
 <!ENTITY privatebrowsingpage.description               "In a Private Browsing session, &brandShortName; won't keep any browser history, search history, download history, web form history, cookies, or temporary internet files.  However, files you download and bookmarks you make will be kept.">
 
+<!ENTITY privatebrowsingpage.perwindow.description     "In a Private Browsing window, &brandShortName; won't keep any browser history, search history, download history, web form history, cookies, or temporary internet files.  However, files you download and bookmarks you make will be kept.">
 
 <!ENTITY privatebrowsingpage.startPrivateBrowsing.label "Start Private Browsing">
 <!ENTITY privatebrowsingpage.startPrivateBrowsing.accesskey "P">
 
+<!ENTITY privatebrowsingpage.openPrivateWindow.label "Open a Private Window">
+<!ENTITY privatebrowsingpage.openPrivateWindow.accesskey "P">
+
 <!-- LOCALIZATION NOTE (privatebrowsingpage.howToStop2): please leave &basePBMenu.label; intact in the translation -->
 <!-- LOCALIZATION NOTE (privatebrowsingpage.howToStart2): please leave &basePBMenu.label; intact in the translation -->
 <!ENTITY privatebrowsingpage.howToStop2                "To stop Private Browsing, select &basePBMenu.label; &gt; &privateBrowsingCmd.stop.label;, or close &brandShortName;.">
 <!ENTITY privatebrowsingpage.howToStart2               "To start Private Browsing, you can also select &basePBMenu.label; &gt; &privateBrowsingCmd.start.label;.">
 
+<!-- LOCALIZATION NOTE (privatebrowsingpage.howToStart3): please leave &basePBMenu.label; intact in the translation -->
+<!ENTITY privatebrowsingpage.howToStart3               "To start Private Browsing, you can also select &basePBMenu.label; &gt; &newPrivateWindow.label;.">
+<!ENTITY privatebrowsingpage.howToStop3                "To stop Private Browsing, you can close this window.">
+
 <!ENTITY privatebrowsingpage.moreInfo                  "While this computer won't have a record of your browsing history, your internet service provider or employer can still track the pages you visit.">
 <!ENTITY privatebrowsingpage.learnMore                 "Learn More">
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -581,18 +581,16 @@ Example Enterprises, Inc.
 The layout of the identity dialog prevents combining this into a single string with
 substitution variables.  If it is difficult to translate the sense of the string
 with that structure, consider a translation which ignores the preceding domain and
 just addresses the organization to follow, e.g. "This site is run by " -->
 <!ENTITY identity.runBy "which is run by">
 
 <!ENTITY identity.moreInfoLinkText "More Information…">
 
-<!ENTITY downloadMonitor2.tooltip "Click to open downloads window">
-
 <!ENTITY allTabs.filter.emptyText "Search Tabs">
 <!-- Name for the tabs toolbar as spoken by screen readers.
      The word "toolbar" is appended automatically and should not be contained below! -->
 <!ENTITY tabsToolbar.label "Browser tabs">
 
 <!-- LOCALIZATION NOTE (syncTabsMenu2.label): This appears in the history menu -->
 <!ENTITY syncTabsMenu2.label     "Tabs From Other Devices">
 
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -227,24 +227,16 @@ identity.identified.state_and_country=%S
 identity.encrypted=Your connection to this website is encrypted to prevent eavesdropping.
 identity.unencrypted=Your connection to this website is not encrypted.
 identity.mixed_content=Your connection to this site is only partially encrypted, and does not prevent eavesdropping.
 
 identity.unknown.tooltip=This website does not supply identity information.
 
 identity.ownerUnknown2=(unknown)
 
-# Downloads Monitor Panel
-# LOCALIZATION NOTE (activeDownloads1, pausedDownloads1): Semi-colon list of plural
-# forms. See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
-# #1 number of downloads; #2 time left
-# examples: 1 active download (2 minutes remaining); 11 paused downloads
-activeDownloads1=1 active download (#2);#1 active downloads (#2)
-pausedDownloads1=1 paused download;#1 paused downloads
-
 # Edit Bookmark UI
 editBookmarkPanel.pageBookmarkedTitle=Page Bookmarked
 editBookmarkPanel.pageBookmarkedDescription=%S will always remember this page for you.
 editBookmarkPanel.bookmarkedRemovedTitle=Bookmark Removed
 editBookmarkPanel.editBookmarkTitle=Edit This Bookmark
 
 # LOCALIZATION NOTE (editBookmark.removeBookmarks.label)
 # Semi-colon list of plural forms. Replacement for #1 is
--- a/browser/locales/en-US/pdfviewer/viewer.properties
+++ b/browser/locales/en-US/pdfviewer/viewer.properties
@@ -73,18 +73,18 @@ page_rotate_ccw.label=Rotate Countercloc
 # Find panel button title and messages
 find_label=Find:
 find_previous.title=Find the previous occurrence of the phrase
 find_previous_label=Previous
 find_next.title=Find the next occurrence of the phrase
 find_next_label=Next
 find_highlight=Highlight all
 find_match_case_label=Match case
-find_wrapped_to_bottom=Reached top of page, continued from bottom
-find_wrapped_to_top=Reached end of page, continued from top
+find_reached_top=Reached top of document, continued from bottom
+find_reached_bottom=Reached end of document, continued from top
 find_not_found=Phrase not found
 
 # Error panel labels
 error_more_info=More Information
 error_less_info=Less Information
 error_close=Close
 # LOCALIZATION NOTE (error_build): "{{build}}" will be replaced by the PDF.JS
 # build ID.
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -496,16 +496,17 @@ menuitem:not([type]):not(.menuitem-toolt
 
 #menu_pageInfo,
 #context-viewinfo,
 #context-viewframeinfo {
   list-style-image: url("moz-icon://stock/gtk-info?size=menu");
 }
 
 #appmenu_privateBrowsing,
+#appmenu_newPrivateWindow,
 #privateBrowsingItem {
   list-style-image: url("chrome://browser/skin/Privacy-16.png");
 }
 
 #placesContext_show\:info {
   list-style-image: url("moz-icon://stock/gtk-properties?size=menu");
 }
 
@@ -1785,22 +1786,16 @@ toolbarbutton.chevron > .toolbarbutton-m
 toolbarbutton.chevron > .toolbarbutton-icon {
   margin: 0;
 }
 
 toolbar[mode="text"] toolbarbutton.chevron > .toolbarbutton-icon {
   display: -moz-box; /* display chevron icon in text mode */
 }
 
-#download-monitor {
-  list-style-image: url("chrome://browser/skin/Toolbar-small.png");
-  -moz-image-region: rect(0px 16px 16px 0px);
-}
-
-
 /* ::::: Keyboard UI Panel ::::: */
 
 .KUI-panel-closebutton {
   list-style-image: url(KUI-close.png);
 }
 
 .KUI-panel-closebutton > .toolbarbutton-icon {
   margin: 0;
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -3125,20 +3125,16 @@ toolbarbutton.chevron > .toolbarbutton-m
 #identity-popup-more-info-button:focus {
   @hudButtonFocused@
 }
 
 #identity-popup-more-info-button:hover:active {
   @hudButtonPressed@
 }
 
-#download-monitor {
-  list-style-image: url("chrome://mozapps/skin/downloads/downloadStatusIcon.png");
-}
-
 /* ::::: Keyboard UI Panel ::::: */
 
 .KUI-panel {
   -moz-appearance: none;
   background: rgba(27%,27%,27%,.9) url(KUI-background.png) repeat-x;
   color: white;
   border-style: none;
   border-radius: 20px;
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -411,17 +411,18 @@
   font-style: italic;
 }
 
 #appmenu_bookmarks {
   list-style-image: url("chrome://browser/skin/places/bookmark.png");
   -moz-image-region: rect(0px 48px 16px 32px);
 }
 
-#appmenu_privateBrowsing {
+#appmenu_privateBrowsing,
+#appmenu_newPrivateWindow {
   list-style-image: url("chrome://browser/skin/Privacy-16.png");
 }
 
 #appmenu_addons {
   list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.png");
 }
 
 #BMB_bookmarkThisPage,
@@ -2402,21 +2403,16 @@ toolbarbutton.bookmark-item[dragover="tr
 #webRTC-notification-icon {
   list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png);
 }
 
 #identity-popup-container {
   min-width: 280px;
 }
 
-#download-monitor {
-  list-style-image: url("chrome://browser/skin/Toolbar.png");
-  -moz-image-region: rect(0, 108px, 18px, 90px);
-}
-
 /* Bookmarks roots menu-items */
 #appmenu_subscribeToPage:not([disabled]),
 #appmenu_subscribeToPageMenu,
 #subscribeToPageMenuitem:not([disabled]),
 #subscribeToPageMenupopup,
 #BMB_subscribeToPageMenuitem:not([disabled]),
 #BMB_subscribeToPageMenupopup {
   list-style-image: url("chrome://browser/skin/feeds/feedIcon16.png");
--- a/build/macosx/mozconfig.leopard
+++ b/build/macosx/mozconfig.leopard
@@ -7,17 +7,17 @@
 HOST_CC=$CC
 HOST_CXX=$CXX
 
 # These must be set for cross builds, and don't hurt straight builds.
 RANLIB=ranlib
 AR=ar
 AS=$CC
 LD=ld
-STRIP="strip -x -S"
+STRIP="strip"
 
 MOZ_CAN_RUN_PROGRAMS=1
 
 # We do 32 bit builds for leopard
 TARGET_CPU=i386
 CC="$CC -arch $TARGET_CPU"
 CXX="$CXX -arch $TARGET_CPU"
 
--- a/build/macosx/universal/mozconfig.common
+++ b/build/macosx/universal/mozconfig.common
@@ -34,17 +34,17 @@ if test "$MOZ_BUILD_APP" = "i386" -o "$M
   CC="$CC -arch $TARGET_CPU"
   CXX="$CXX -arch $TARGET_CPU"
 
   # These must be set for cross builds, and don't hurt straight builds.
   RANLIB=ranlib
   AR=ar
   AS=$CC
   LD=ld
-  STRIP="strip -x -S"
+  STRIP="strip"
 
   # Let configure know that we mean business.
   if test "$NATIVE_CPU" != "$TARGET_CPU" ; then
     CROSS_COMPILE=1
   fi
 
   # Each per-CPU build should be entirely oblivious to the fact that a
   # universal binary will be produced.  The exception is packager.mk, which
--- a/build/unix/build-clang/build-clang.py
+++ b/build/unix/build-clang/build-clang.py
@@ -1,14 +1,14 @@
 #!/usr/bin/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/.
 
-llvm_revision = "168596"
+llvm_revision = "169139"
 moz_version = "moz0"
 
 ##############################################
 
 import os
 import os.path
 import shutil
 import tarfile
--- a/configure.in
+++ b/configure.in
@@ -5249,32 +5249,47 @@ MOZ_ARG_DISABLE_BOOL(webrtc,
 
 if test -n "$MOZ_WEBRTC"; then
     AC_DEFINE(MOZ_WEBRTC)
     MOZ_MEDIA=1
     MOZ_RAW=1
     MOZ_VP8=1
     MOZ_VP8_ENCODER=1
     MOZ_VP8_ERROR_CONCEALMENT=1
+
+    dnl OpenSLES is only available in Android 2.3 and later; we'll change this
+    dnl hard dependency to a dynamic load with graceful runtime failure before
+    dnl we make --enable-webrtc on by default in Android (bug 815905)
+    dnl 
+    if test "$OS_TARGET" = "Android"; then
+       LDFLAGS="$LDFLAGS -lOpenSLES"
+    fi
+    case "$target" in
+    *-android*|*-linuxandroid*)
+       LDFLAGS="$LDFLAGS -lOpenSLES"
+       ;;
+    esac
+
 dnl enable once Signaling lands
     MOZ_WEBRTC_SIGNALING=1
     AC_DEFINE(MOZ_WEBRTC_SIGNALING)
     if test "${OS_TARGET}" = "WINNT"; then
         MOZ_WEBRTC_IN_LIBXUL=1
     fi
 dnl enable once PeerConnection lands
     MOZ_PEERCONNECTION=1
     AC_DEFINE(MOZ_PEERCONNECTION)
     MOZ_SCTP=1
     MOZ_SRTP=1
     AC_DEFINE(MOZ_SCTP)
     AC_DEFINE(MOZ_SRTP)
 fi
 
 AC_SUBST(MOZ_WEBRTC)
+AC_SUBST(MOZ_WEBRTC_LEAKING_TESTS)
 AC_SUBST(MOZ_WEBRTC_SIGNALING)
 AC_SUBST(MOZ_PEERCONNECTION)
 AC_SUBST(MOZ_WEBRTC_IN_LIBXUL)
 AC_SUBST(MOZ_SCTP)
 AC_SUBST(MOZ_SRTP)
 
 case "$target_cpu" in
 arm*)
@@ -8505,16 +8520,17 @@ if test -z "$IS_ALPHA"; then
   MOZ_APP_MAXVERSION=`echo $MOZ_APP_VERSION | sed "s|\(^[0-9]*.[0-9]*\).*|\1|"`.*
   changequote([,])
 else
   MOZ_APP_MAXVERSION=$MOZ_APP_VERSION
 fi
 
 MOZ_B2G_VERSION=${MOZ_B2G_VERSION:-"1.0.0"}
 AC_DEFINE_UNQUOTED(MOZ_B2G_VERSION,"$MOZ_B2G_VERSION")
+AC_DEFINE_UNQUOTED(MOZ_B2G_OS_NAME,"$MOZ_B2G_OS_NAME")
 
 AC_SUBST(MOZ_APP_NAME)
 AC_SUBST(MOZ_APP_DISPLAYNAME)
 AC_SUBST(MOZ_APP_BASENAME)
 AC_SUBST(MOZ_APP_VENDOR)
 AC_SUBST(MOZ_APP_PROFILE)
 AC_SUBST(MOZ_APP_ID)
 AC_SUBST(MAR_CHANNEL_ID)
@@ -8846,34 +8862,59 @@ dnl Load the list of Makefiles to genera
 dnl   To add new Makefiles, edit allmakefiles.sh.
 dnl   allmakefiles.sh sets the variable, MAKEFILES.
 . ${srcdir}/allmakefiles.sh
 
 echo $MAKEFILES > unallmakefiles
 
 AC_OUTPUT($MAKEFILES)
 
+# target_arch is from {ia32|x64|arm}
+case "$CPU_ARCH" in
+x86_64 | ia64)
+    WEBRTC_TARGET_ARCH=x64
+    ;;
+
+arm*)
+    WEBRTC_TARGET_ARCH=arm
+    ;;
+
+x86)
+    WEBRTC_TARGET_ARCH=ia32
+    ;;
+
+*)
+# unsupported arch for webrtc
+    WEBRTC_TARGET_ARCH=unknown
+    MOZ_WEBRTC=
+    ;;
+
+esac
+
 # Generate Makefiles for WebRTC directly from .gyp files
 if test "${OS_TARGET}" = "WINNT"; then
    if test "$HAVE_64BIT_OS"; then
       OS_BITS=64
    else
       OS_BITS=32
    fi
    EXTRA_GYP_DEFINES="-D MSVS_VERSION=${_MSVS_VERSION} -D MSVS_OS_BITS=${OS_BITS}"
+
+elif test "${OS_TARGET}" = "Android"; then
+   EXTRA_GYP_DEFINES="-D gtest_target_type=executable -D android_toolchain=${android_toolchain} -G os=android "
 fi
 
 if test -n "$MOZ_WEBRTC"; then
    AC_MSG_RESULT("generating WebRTC Makefiles...")
 
 dnl Any --include files must also appear in -D FORCED_INCLUDE_FILE= entries
 dnl so that regeneration via dependencies works correctly
    WEBRTC_CONFIG="-D build_with_mozilla=1 --include ${srcdir}/media/webrtc/webrtc_config.gypi -D FORCED_INCLUDE_FILE=${srcdir}/media/webrtc/webrtc_config.gypi"
 
-   GYP_WEBRTC_OPTIONS="--format=mozmake ${WEBRTC_CONFIG} ${EXTRA_GYP_DEFINES} --depth=${srcdir}/media/webrtc/trunk --toplevel-dir=${srcdir} -G OBJDIR=${_objdir}"
+   GYP_WEBRTC_OPTIONS="--format=mozmake ${WEBRTC_CONFIG} -D target_arch=${WEBRTC_TARGET_ARCH} ${EXTRA_GYP_DEFINES} --depth=${srcdir}/media/webrtc/trunk --toplevel-dir=${srcdir} -G OBJDIR=${_objdir}"
 
    $PYTHON ${srcdir}/media/webrtc/trunk/build/gyp_chromium \
      $GYP_WEBRTC_OPTIONS \
      --generator-output=${_objdir}/media/webrtc/trunk \
      ${srcdir}/media/webrtc/trunk/peerconnection.gyp
    if test "$?" != 0; then
       AC_MSG_ERROR([failed to generate WebRTC Makefiles])
    fi
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1280,26 +1280,26 @@ public:
 
   /**
    * Keep the JS objects held by aScriptObjectHolder alive.
    *
    * @param aScriptObjectHolder the object that holds JS objects that we want to
    *                            keep alive
    * @param aTracer the tracer for aScriptObject
    */
-  static nsresult HoldJSObjects(void* aScriptObjectHolder,
-                                nsScriptObjectTracer* aTracer);
+  static void HoldJSObjects(void* aScriptObjectHolder,
+                            nsScriptObjectTracer* aTracer);
 
   /**
    * Drop the JS objects held by aScriptObjectHolder.
    *
    * @param aScriptObjectHolder the object that holds JS objects that we want to
    *                            drop
    */
-  static nsresult DropJSObjects(void* aScriptObjectHolder);
+  static void DropJSObjects(void* aScriptObjectHolder);
 
 #ifdef DEBUG
   static bool AreJSObjectsHeld(void* aScriptObjectHolder); 
 
   static void CheckCCWrapperTraversal(void* aScriptObjectHolder,
                                       nsWrapperCache* aCache,
                                       nsScriptObjectTracer* aTracer);
 #endif
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -2555,16 +2555,18 @@ Element::MozMatchesSelector(const nsAStr
     return false;
   }
 
   OwnerDoc()->FlushPendingLinkUpdates();
   TreeMatchContext matchingContext(false,
                                    nsRuleWalker::eRelevantLinkUnvisited,
                                    OwnerDoc(),
                                    TreeMatchContext::eNeverMatchVisited);
+  matchingContext.SetHasSpecifiedScope();
+  matchingContext.AddScopeElement(this);
   return nsCSSRuleProcessor::SelectorListMatches(this, matchingContext,
                                                  selectorList);
 }
 
 static const nsAttrValue::EnumTable kCORSAttributeTable[] = {
   // Order matters here
   // See ParseCORSValue
   { "anonymous",       CORS_ANONYMOUS       },
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -4507,44 +4507,41 @@ void
 nsContentUtils::DestroyAnonymousContent(nsCOMPtr<nsIContent>* aContent)
 {
   if (*aContent) {
     AddScriptRunner(new AnonymousContentDestroyer(aContent));
   }
 }
 
 /* static */
-nsresult
+void
 nsContentUtils::HoldJSObjects(void* aScriptObjectHolder,
                               nsScriptObjectTracer* aTracer)
 {
-  NS_ENSURE_TRUE(sXPConnect, NS_ERROR_UNEXPECTED);
-
-  return sXPConnect->AddJSHolder(aScriptObjectHolder, aTracer);
+  MOZ_ASSERT(sXPConnect, "Tried to HoldJSObjects when there was no XPConnect");
+  if (sXPConnect) {
+    sXPConnect->AddJSHolder(aScriptObjectHolder, aTracer);
+  }
 }
 
 /* static */
-nsresult
+void
 nsContentUtils::DropJSObjects(void* aScriptObjectHolder)
 {
-  if (!sXPConnect) {
-    return NS_OK;
-  }
-
-  return sXPConnect->RemoveJSHolder(aScriptObjectHolder);
+  if (sXPConnect) {
+    sXPConnect->RemoveJSHolder(aScriptObjectHolder);
+  }
 }
 
 #ifdef DEBUG
 /* static */
 bool
 nsContentUtils::AreJSObjectsHeld(void* aScriptHolder)
 {
-  bool isHeld = false;
-  sXPConnect->TestJSHolder(aScriptHolder, &isHeld);
-  return isHeld;
+  return sXPConnect->TestJSHolder(aScriptHolder);
 }
 #endif
 
 /* static */
 void
 nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling)
 {
   nsIMEStateManager::OnInstalledMenuKeyboardListener(aInstalling);
--- a/content/base/src/nsDOMParser.cpp
+++ b/content/base/src/nsDOMParser.cpp
@@ -56,29 +56,39 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMParser)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMParser)
 
 already_AddRefed<nsIDocument>
 nsDOMParser::ParseFromString(const nsAString& aStr, SupportedType aType,
                              ErrorResult& rv)
 {
   nsCOMPtr<nsIDOMDocument> domDocument;
-  rv = nsDOMParser::ParseFromString(PromiseFlatString(aStr).get(),
-                                    SupportedTypeValues::strings[aType].value,
-                                    getter_AddRefs(domDocument));
+  rv = ParseFromString(aStr,
+                       SupportedTypeValues::strings[aType].value,
+                       getter_AddRefs(domDocument));
   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
   return document.forget();
 }
 
 NS_IMETHODIMP 
 nsDOMParser::ParseFromString(const PRUnichar *str, 
                              const char *contentType,
                              nsIDOMDocument **aResult)
 {
   NS_ENSURE_ARG(str);
+  // Converting a string to an enum value manually is a bit of a pain,
+  // so let's just use a helper that takes a content-type string.
+  return ParseFromString(nsDependentString(str), contentType, aResult);
+}
+
+nsresult
+nsDOMParser::ParseFromString(const nsAString& str,
+                             const char *contentType,
+                             nsIDOMDocument **aResult)
+{
   NS_ENSURE_ARG_POINTER(aResult);
 
   nsresult rv;
 
   if (!nsCRT::strcmp(contentType, "text/html")) {
     nsCOMPtr<nsIDOMDocument> domDocument;
     rv = SetUpDocument(DocumentFlavorHTML, getter_AddRefs(domDocument));
     NS_ENSURE_SUCCESS(rv, rv);
@@ -91,18 +101,17 @@ nsDOMParser::ParseFromString(const PRUni
       document->ForceEnableXULXBL();
     }
 
     // Make sure to give this document the right base URI
     document->SetBaseURI(mBaseURI);
     // And the right principal
     document->SetPrincipal(mPrincipal);
 
-    nsDependentString sourceBuffer(str);
-    rv = nsContentUtils::ParseDocumentHTML(sourceBuffer, document, false);
+    rv = nsContentUtils::ParseDocumentHTML(str, document, false);
     NS_ENSURE_SUCCESS(rv, rv);
 
     domDocument.forget(aResult);
     return rv;
   }
 
   NS_ConvertUTF16toUTF8 data(str);
 
--- a/content/base/src/nsDOMParser.h
+++ b/content/base/src/nsDOMParser.h
@@ -84,16 +84,20 @@ private:
     SetIsDOMBinding();
   }
 
   nsresult InitInternal(nsISupports* aOwner, nsIPrincipal* prin,
                         nsIURI* documentURI, nsIURI* baseURI);
 
   nsresult SetUpDocument(DocumentFlavor aFlavor, nsIDOMDocument** aResult);
 
+  // Helper for ParseFromString
+  nsresult ParseFromString(const nsAString& str, const char *contentType,
+                           nsIDOMDocument **aResult);
+
   class AttemptedInitMarker {
   public:
     AttemptedInitMarker(bool* aAttemptedInit) :
       mAttemptedInit(aAttemptedInit)
     {}
 
     ~AttemptedInitMarker() {
       *mAttemptedInit = true;
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -2103,17 +2103,17 @@ AppendAuthorSheet(nsIStyleSheet *aSheet,
   nsStyleSet *styleSet = static_cast<nsStyleSet*>(aData);
   styleSet->AppendStyleSheet(nsStyleSet::eDocSheet, aSheet);
   return true;
 }
 
 static void
 AppendSheetsToStyleSet(nsStyleSet* aStyleSet,
                        const nsCOMArray<nsIStyleSheet>& aSheets,
-                       nsStyleSet::sheetType aType) 
+                       nsStyleSet::sheetType aType)
 {
   for (int32_t i = aSheets.Count() - 1; i >= 0; --i) {
     aStyleSet->AppendStyleSheet(aType, aSheets[i]);
   }
 }
 
 
 void
@@ -7285,17 +7285,17 @@ nsDocument::CloneDocHelper(nsDocument* c
   // Set URI/principal
   clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI());
   // Must set the principal first, since SetBaseURI checks it.
   clone->SetPrincipal(NodePrincipal());
   clone->mDocumentBaseURI = mDocumentBaseURI;
 
   if (mCreatingStaticClone) {
     nsCOMPtr<nsILoadGroup> loadGroup;
-    
+
     // |mDocumentContainer| is the container of the document that is being
     // created and not the original container. See CreateStaticClone function().
     nsCOMPtr<nsIDocumentLoader> docLoader = do_QueryReferent(mDocumentContainer);
     if (docLoader) {
       docLoader->GetLoadGroup(getter_AddRefs(loadGroup));
     }
     nsCOMPtr<nsIChannel> channel = GetChannel();
     if (channel && loadGroup) {
@@ -9491,16 +9491,18 @@ nsDocument::UpdateVisibilityState()
     nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
                                          NS_LITERAL_STRING("visibilitychange"),
                                          /* bubbles = */ true,
                                          /* cancelable = */ false);
     nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
                                          NS_LITERAL_STRING("mozvisibilitychange"),
                                          /* bubbles = */ true,
                                          /* cancelable = */ false);
+
+    EnumerateFreezableElements(NotifyActivityChanged, nullptr);
   }
 }
 
 nsDocument::VisibilityState
 nsDocument::GetVisibilityState() const
 {
   // We have to check a few pieces of information here:
   // 1)  Are we in bfcache (!IsVisible())?  If so, nothing else matters.
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -565,16 +565,17 @@ GK_ATOM(mode, "mode")
 GK_ATOM(modifiers, "modifiers")
 GK_ATOM(monochrome, "monochrome")
 GK_ATOM(mousedown, "mousedown")
 GK_ATOM(mousemove, "mousemove")
 GK_ATOM(mouseout, "mouseout")
 GK_ATOM(mouseover, "mouseover")
 GK_ATOM(mousethrough, "mousethrough")
 GK_ATOM(mouseup, "mouseup")
+GK_ATOM(mozaudiochannel, "mozaudiochannel")
 GK_ATOM(mozasyncpanzoom, "mozasyncpanzoom")
 GK_ATOM(mozfullscreenchange, "mozfullscreenchange")
 GK_ATOM(mozfullscreenerror, "mozfullscreenerror")
 GK_ATOM(mozpasspointerevents, "mozpasspointerevents")
 GK_ATOM(mozpointerlockchange, "mozpointerlockchange")
 GK_ATOM(mozpointerlockerror, "mozpointerlockerror")
 GK_ATOM(moz_opaque, "moz-opaque")
 GK_ATOM(moz_action_hint, "mozactionhint")
--- a/content/base/src/nsINode.cpp
+++ b/content/base/src/nsINode.cpp
@@ -2193,16 +2193,26 @@ ParseSelectorList(nsINode* aNode,
       slot = &cur->mNext;
     }
   } while (*slot);
   *aSelectorList = selectorList;
 
   return NS_OK;
 }
 
+static void
+AddScopeElements(TreeMatchContext& aMatchContext,
+                 nsINode* aMatchContextNode)
+{
+  if (aMatchContextNode->IsElement()) {
+    aMatchContext.SetHasSpecifiedScope();
+    aMatchContext.AddScopeElement(aMatchContextNode->AsElement());
+  }
+}
+
 // Actually find elements matching aSelectorList (which must not be
 // null) and which are descendants of aRoot and put them in aList.  If
 // onlyFirstMatch, then stop once the first one is found.
 template<bool onlyFirstMatch, class T>
 inline static nsresult
 FindMatchingElements(nsINode* aRoot, const nsAString& aSelector, T &aList)
 {
   nsAutoPtr<nsCSSSelectorList> selectorList;
@@ -2213,16 +2223,17 @@ FindMatchingElements(nsINode* aRoot, con
 
   NS_ASSERTION(selectorList->mSelectors,
                "How can we not have any selectors?");
 
   nsIDocument* doc = aRoot->OwnerDoc();
   TreeMatchContext matchingContext(false, nsRuleWalker::eRelevantLinkUnvisited,
                                    doc, TreeMatchContext::eNeverMatchVisited);
   doc->FlushPendingLinkUpdates();
+  AddScopeElements(matchingContext, aRoot);
 
   // Fast-path selectors involving IDs.  We can only do this if aRoot
   // is in the document and the document is not in quirks mode, since
   // ID selectors are case-insensitive in quirks mode.  Also, only do
   // this if selectorList only has one selector, because otherwise
   // ordering the elements correctly is a pain.
   NS_ASSERTION(aRoot->IsElement() || aRoot->IsNodeOfType(nsINode::eDOCUMENT) ||
                !aRoot->IsInDoc(),
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -19,16 +19,17 @@
 #include "nsNetUtil.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptRuntime.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIPrincipal.h"
 #include "nsContentPolicyUtils.h"
 #include "nsIHttpChannel.h"
+#include "nsIHttpChannelInternal.h"
 #include "nsIScriptElement.h"
 #include "nsIDOMHTMLScriptElement.h"
 #include "nsIDocShell.h"
 #include "nsContentUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsAutoPtr.h"
 #include "nsIXPConnect.h"
 #include "nsError.h"
@@ -252,17 +253,18 @@ nsScriptLoader::ShouldLoadScript(nsIDocu
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   return NS_OK;
 }
 
 nsresult
-nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType)
+nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
+                          bool aScriptFromHead)
 {
   nsISupports *context = aRequest->mElement.get()
                          ? static_cast<nsISupports *>(aRequest->mElement.get())
                          : static_cast<nsISupports *>(mDocument);
   nsresult rv = ShouldLoadScript(mDocument, context, aRequest->mURI, aType);
   if (NS_FAILED(rv)) {
     return rv;
   }
@@ -297,16 +299,25 @@ nsScriptLoader::StartLoad(nsScriptLoadRe
 
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewChannel(getter_AddRefs(channel),
                      aRequest->mURI, nullptr, loadGroup, prompter,
                      nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI,
                      channelPolicy);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  nsIScriptElement *script = aRequest->mElement;
+  if (aScriptFromHead &&
+      !(script && (script->GetScriptAsync() || script->GetScriptDeferred()))) {
+    nsCOMPtr<nsIHttpChannelInternal>
+      internalHttpChannel(do_QueryInterface(channel));
+    if (internalHttpChannel)
+      internalHttpChannel->SetLoadAsBlocking(true);
+  }
+
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   if (httpChannel) {
     // HTTP content negotation has little value in this context.
     httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
                                   NS_LITERAL_CSTRING("*/*"),
                                   false);
     httpChannel->SetReferrer(mDocument->GetDocumentURI());
   }
@@ -513,17 +524,20 @@ nsScriptLoader::ProcessScriptElement(nsI
     }
 
     if (!request) {
       // no usable preload
       request = new nsScriptLoadRequest(aElement, version, ourCORSMode);
       request->mURI = scriptURI;
       request->mIsInline = false;
       request->mLoading = true;
-      rv = StartLoad(request, type);
+
+      // set aScriptFromHead to false so we don't treat non preloaded scripts as
+      // blockers for full page load. See bug 792438.
+      rv = StartLoad(request, type, false);
       if (NS_FAILED(rv)) {
         // Asynchronously report the load failure
         NS_DispatchToCurrentThread(
           NS_NewRunnableMethod(aElement,
                                &nsIScriptElement::FireErrorEvent));
         return false;
       }
     }
@@ -1231,30 +1245,31 @@ nsScriptLoader::ParsingComplete(bool aTe
   // Have to call this even if aTerminated so we'll correctly unblock
   // onload and all.
   ProcessPendingRequests();
 }
 
 void
 nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
                            const nsAString &aType,
-                           const nsAString &aCrossOrigin)
+                           const nsAString &aCrossOrigin,
+                           bool aScriptFromHead)
 {
   // Check to see if scripts has been turned off.
   if (!mEnabled || !mDocument->IsScriptEnabled()) {
     return;
   }
 
   nsRefPtr<nsScriptLoadRequest> request =
     new nsScriptLoadRequest(nullptr, 0,
                             Element::StringToCORSMode(aCrossOrigin));
   request->mURI = aURI;
   request->mIsInline = false;
   request->mLoading = true;
-  nsresult rv = StartLoad(request, aType);
+  nsresult rv = StartLoad(request, aType, aScriptFromHead);
   if (NS_FAILED(rv)) {
     return;
   }
 
   PreloadInfo *pi = mPreloads.AppendElement();
   pi->mRequest = request;
   pi->mCharset = aCharset;
 }
--- a/content/base/src/nsScriptLoader.h
+++ b/content/base/src/nsScriptLoader.h
@@ -195,20 +195,22 @@ public:
   /**
    * Adds aURI to the preload list and starts loading it.
    *
    * @param aURI The URI of the external script.
    * @param aCharset The charset parameter for the script.
    * @param aType The type parameter for the script.
    * @param aCrossOrigin The crossorigin attribute for the script.
    *                     Void if not present.
+   * @param aScriptFromHead Whether or not the script was a child of head
    */
   virtual void PreloadURI(nsIURI *aURI, const nsAString &aCharset,
                           const nsAString &aType,
-                          const nsAString &aCrossOrigin);
+                          const nsAString &aCrossOrigin,
+                          bool aScriptFromHead);
 
 private:
   /**
    * Unblocks the creator parser of the parser-blocking scripts.
    */
   void UnblockParser(nsScriptLoadRequest* aParserBlockingRequest);
 
   /**
@@ -223,17 +225,18 @@ private:
   static nsresult CheckContentPolicy(nsIDocument* aDocument,
                                      nsISupports *aContext,
                                      nsIURI *aURI,
                                      const nsAString &aType);
 
   /**
    * Start a load for aRequest's URI.
    */
-  nsresult StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType);
+  nsresult StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
+                     bool aScriptFromHead);
 
   /**
    * Process any pending requests asynchronously (i.e. off an event) if there
    * are any. Note that this is a no-op if there aren't any currently pending
    * requests.
    *
    * This function is virtual to allow cross-library calls to SetEnabled()
    */
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -73,16 +73,17 @@
 #include "sampler.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/dom/XMLHttpRequestBinding.h"
 #include "nsIDOMFormData.h"
 #include "DictionaryHelpers.h"
 #include "mozilla/Attributes.h"
 #include "nsIPermissionManager.h"
 #include "nsMimeTypes.h"
+#include "nsIHttpChannelInternal.h"
 
 #include "nsWrapperCacheInlines.h"
 #include "nsStreamListenerWrapper.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #define LOAD_STR "load"
@@ -2959,16 +2960,25 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
   } else {
     Telemetry::Accumulate(Telemetry::MULTIPART_XHR_RESPONSE, 0);
   }
 
   // Blocking gets are common enough out of XHR that we should mark
   // the channel slow by default for pipeline purposes
   AddLoadFlags(mChannel, nsIRequest::INHIBIT_PIPELINE);
 
+  nsCOMPtr<nsIHttpChannelInternal>
+    internalHttpChannel(do_QueryInterface(mChannel));
+  if (internalHttpChannel) {
+    // we never let XHR be blocked by head CSS/JS loads to avoid
+    // potential deadlock where server generation of CSS/JS requires
+    // an XHR signal.
+    internalHttpChannel->SetLoadUnblocked(true);
+  }
+
   if (!IsSystemXHR()) {
     // Always create a nsCORSListenerProxy here even if it's
     // a same-origin request right now, since it could be redirected.
     nsRefPtr<nsCORSListenerProxy> corsListener =
       new nsCORSListenerProxy(listener, mPrincipal, withCredentials);
     rv = corsListener->Init(mChannel, true);
     NS_ENSURE_SUCCESS(rv, rv);
     listener = corsListener;
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -262,16 +262,17 @@ MOCHITEST_FILES_A = \
 		test_meta_viewport6.html \
 		test_mutationobservers.html \
 		mutationobserver_dialog.html \
 		test_bug744830.html \
 		file_bug782342.txt \
 		test_bug782342.html \
 		test_bug282547.html \
 		bug282547.sjs \
+		test_domparser_null_char.html \
 		$(NULL)
 
 MOCHITEST_FILES_B = \
 		test_bug459424.html \
 		bug461735-redirect1.sjs \
 		bug461735-redirect2.sjs \
 		bug461735-post-redirect.js \
 		test_bug513194.html \
--- a/content/base/test/file_bug416317.xhtml
+++ b/content/base/test/file_bug416317.xhtml
@@ -95,16 +95,19 @@
     .firstChild .unitTest:first-child { background-color: lime; }
     .blox12:first-child { background-color: red; }
     .blox13:first-child { background-color: red; }
     .blox12, .blox13 { background-color: lime }
 
     /* :root tests */
     :root { background-color: green; }
 
+    /* :-moz-scope tests */
+    :-moz-scope { background-color: green; }
+
     /* :nth-child(n) tests */
     .nthchild1 > :nth-last-child(odd) { background-color: lime; }
     .nthchild1 > :nth-child(odd) { background-color: lime; }
 
     .nthchild2 > :nth-last-child(even) { background-color: lime; }
     .nthchild2 > :nth-child(even) { background-color: lime; }
 
     .nthchild3 > :nth-child(3n+2) { background-color: lime; }
@@ -264,16 +267,19 @@
 
     var root4 = root2.cloneNode(true);
     interfaceCheck(root4, "Disconnected Element");
     runTest( css, "Disconnected Element", root4, true );
     check( "Disconnected Element", root4, true, true );
     cacheCheck( "Disconnected Element", root4 );
     runTest( ecss, "SyntaxError: Disconnected Element", root4, false );
     jqTests("Disconnected Element", root3.cloneNode(true), "querySelectorAll");
+    var newRoot = document.createElement("nosuchtag");
+    newRoot.appendChild(root3.cloneNode(true));
+    jqTests("Disconnected Element scoping", newRoot, "querySelectorAll");
 
     var fragment = document.createDocumentFragment();
     fragment.appendChild( root2.cloneNode(true) );
 
     interfaceCheck(fragment, "Fragment");
     runTest( css, "Fragment", fragment, true );
     check( "Fragment", fragment, true, true );
     runTest( ecss, "SyntaxError: Fragment", fragment, false );
@@ -532,17 +538,19 @@
       function t( name, q, ids, restrict, ids2 ) {
         var pass = true;
 
         if ( restrict === false && root != document )
           return;
 
         var namespaced = /\|[^=]/.test( q );
         var prepend = namespaced ? "xHTML|*#root3 " : "#root3 ";
-        q = (restrict === false || restrict === ":root" ? "" : prepend) + q.replace(/,/g, ", " + prepend);
+        q = (restrict === false || restrict === ":root" ||
+             restrict === ":-moz-scope" ? "" : prepend) +
+            q.replace(/,/g, ", " + prepend);
         var nq = q.replace(/>/g, "&gt;").replace(/</g, "&lt;");
 
         if ( namespaced ) {
           for ( var i = 0; i < badNamespace.length; i++ ) {
             var resolver = badNamespace[i], pass = false, results = null;
 
             try {
               results = query(q, resolver);
@@ -562,17 +570,20 @@
             pass = hasPassed( results, ids );
           } catch(e) {
             pass = e.name == "SyntaxError" && e.code == DOMException.SYNTAX_ERR;
           }
   
           assert( pass, type + ": " + name + " (" + nq + ")" +
             (pass ? "" : " Expected: " + extra(ids) + " Received: " + extra(results)) );
 
-          if (results)
+          // For now, don't use checkMatchesSelector when
+          // restrict === ":-moz-scope" because we have no way to hand the
+          // right scope to it yet.
+          if (results && restrict !== ":-moz-scope")
             checkMatchesSelector( results, q );
         }
 
         function hasPassed(results, ids){
           var pass = (results && results.length == ids.length) || (!results && !ids);
   
           if ( ids && results ) {
             for ( var i = 0; ids && i < ids.length; i++ ) {
@@ -625,27 +636,35 @@
       var good = all && all.length;
       for ( var i = 0; all && i < all.length; i++ )
         if ( all[i].nodeType != 1 )
           good = false;
       assert( good, type + ": Select all elements, no comment nodes" );
 
       if ( root == document ) {
         t( ":root Selector", ":root", ["html"], false );
+        t( ":-moz-scope Selector", ":-moz-scope", ["html"], ":-moz-scope" );
       } else {
         t( ":root Selector", ":root", [], ":root" );
+        if (root.localName != "nosuchtag") {
+          t( ":-moz-scope Selector", ":-moz-scope > nosuchtag",
+             [ "outerbogustag" ], ":-moz-scope");
+        }
+        t( ":-moz-scope Selector", ":-moz-scope nosuchtag nosuchtag",
+           [ "innerbogustag" ], ":-moz-scope");
 
         if ( !root.parentNode ) {
           t( ":root All Selector", ":root *", [], ":root" );
         }
       }
 
       if ( root.parentNode || root == document ) {
         assert( query(":root *").length == query("*").length - (root == document ? 1 : 0), type + ": :root All Selector" );
       }
+      assert( query(":-moz-scope *").length == query("*").length - (root == document ? 1 : 0), type + ": :-moz-scope All Selector" );
 
       t( "Element Selector", "p", ["firstp","ap","sndp","en","sap","first"] );
       t( "Element Selector", "body", ["body"], false );
       t( "Element Selector", "html", ["html"], false );
       t( "Parent Element", "div p", ["firstp","ap","sndp","en","sap","first"] );
       var param = query("#object1 param");
       assert( param && param.length == 2, type + ": Object/param as context" );
 
@@ -1254,16 +1273,20 @@
   <h2 id="banner"></h2>
   <h2 id="userAgent"></h2>
   
   <!-- Test HTML -->
   <div id="nothiddendiv" style="height:1px;background:white;">
 
     <div id="nothiddendivchild"></div>
   </div>
+  <!-- Test for scoping -->
+  <nosuchtag id="outerbogustag">
+    <nosuchtag id="innerbogustag"></nosuchtag>
+  </nosuchtag>
   <!-- this iframe is outside the #main so it won't reload constantly wasting time, but it means the tests must be "safe" and clean up after themselves -->
   <iframe id="loadediframe" name="loadediframe" style="display:none;" src="data/iframe.html"></iframe>
   <dl id="dl" style="display:none;">
   <div id="main" style="display: none;">
     <p id="firstp">See <a id="simon1" href="http://simon.incutio.com/archive/2003/03/25/#getElementsBySelector" rel="bookmark">this blog entry</a> for more information.</p>
 
     <p id="ap">
       Here are some links in a normal paragraph: <a id="google" href="http://www.google.com/" title="Google!">Google</a>, 
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_domparser_null_char.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=817469
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 817469</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=817469">Mozilla Bug 817469</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 817469 **/
+  var doc = new DOMParser().parseFromString("\x00<div id='myElement'>", "text/html");
+  isnot(doc.getElementById("myElement"), null, "Should not stop at null");
+</script>
+</pre>
+</body>
+</html>
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -92,16 +92,18 @@
 #include "nsCCUncollectableMarker.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsJSUtils.h"
 #include "XPCQuickStubs.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "nsHTMLImageElement.h"
 #include "nsHTMLVideoElement.h"
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
+#include <cstdlib> // for std::abs(int/long)
+#include <cmath> // for std::abs(float/double)
 
 #ifdef XP_WIN
 #include "gfxWindowsPlatform.h"
 #endif
 
 // windows.h (included by chromium code) defines this, in its infinite wisdom
 #undef DrawText
 
@@ -3734,18 +3736,18 @@ CanvasRenderingContext2D::CreateImageDat
   if (!sw || !sh) {
     error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return NULL;
   }
 
   int32_t wi = JS_DoubleToInt32(sw);
   int32_t hi = JS_DoubleToInt32(sh);
 
-  uint32_t w = NS_ABS(wi);
-  uint32_t h = NS_ABS(hi);
+  uint32_t w = std::abs(wi);
+  uint32_t h = std::abs(hi);
   return mozilla::dom::CreateImageData(cx, this, w, h, error);
 }
 
 already_AddRefed<ImageData>
 CanvasRenderingContext2D::CreateImageData(JSContext* cx,
                                           ImageData& imagedata,
                                           ErrorResult& error)
 {
--- a/content/events/src/nsContentEventHandler.cpp
+++ b/content/events/src/nsContentEventHandler.cpp
@@ -217,17 +217,18 @@ static uint32_t CountNewlinesInNativeLen
       ++newlines;
       ++nativeOffset;
     }
   }
   return newlines;
 }
 #endif
 
-static uint32_t GetNativeTextLength(nsIContent* aContent, uint32_t aMaxLength = UINT32_MAX)
+/* static */ uint32_t
+nsContentEventHandler::GetNativeTextLength(nsIContent* aContent, uint32_t aMaxLength)
 {
   if (aContent->IsNodeOfType(nsINode::eTEXT)) {
     uint32_t textLengthDifference =
 #if defined(XP_MACOSX)
       // On Mac, the length of a native newline ("\r") is equal to the length of
       // the XP newline ("\n"), so the native length is the same as the XP length.
       0;
 #elif defined(XP_WIN)
@@ -364,17 +365,17 @@ nsContentEventHandler::ExpandToClusterBo
 
 nsresult
 nsContentEventHandler::SetRangeFromFlatTextOffset(
                               nsRange* aRange,
                               uint32_t aNativeOffset,
                               uint32_t aNativeLength,
                               bool aExpandToClusterBoundaries)
 {
-  nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
+  nsCOMPtr<nsIContentIterator> iter = NS_NewPreContentIterator();
   nsresult rv = iter->Init(mRootContent);
   NS_ENSURE_SUCCESS(rv, rv);
 
   uint32_t nativeOffset = 0;
   uint32_t nativeEndOffset = aNativeOffset + aNativeLength;
   bool startSet = false;
   for (; !iter->IsDone(); iter->Next()) {
     nsINode* node = iter->GetCurrentNode();
--- a/content/events/src/nsContentEventHandler.h
+++ b/content/events/src/nsContentEventHandler.h
@@ -75,16 +75,19 @@ public:
   // Get the offset in FlatText of the range. (also used by nsIMEStateManager)
   static nsresult GetFlatTextOffsetOfRange(nsIContent* aRootContent,
                                            nsINode* aNode,
                                            int32_t aNodeOffset,
                                            uint32_t* aOffset);
   static nsresult GetFlatTextOffsetOfRange(nsIContent* aRootContent,
                                            nsRange* aRange,
                                            uint32_t* aOffset);
+  // Get the native text length of a content node excluding any children
+  static uint32_t GetNativeTextLength(nsIContent* aContent,
+                                      uint32_t aMaxLength = UINT32_MAX);
 protected:
   // Make the DOM range from the offset of FlatText and the text length.
   // If aExpandToClusterBoundaries is true, the start offset and the end one are
   // expanded to nearest cluster boundaries.
   nsresult SetRangeFromFlatTextOffset(nsRange* aRange,
                                       uint32_t aNativeOffset,
                                       uint32_t aNativeLength,
                                       bool aExpandToClusterBoundaries);
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -95,16 +95,18 @@
 #include "nsHTMLLabelElement.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/Attributes.h"
 #include "sampler.h"
 
 #include "nsIDOMClientRect.h"
+#include <cstdlib> // for std::abs(int/long)
+#include <cmath> // for std::abs(float/double)
 
 #ifdef XP_MACOSX
 #import <ApplicationServices/ApplicationServices.h>
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -2065,18 +2067,18 @@ nsEventStateManager::GenerateDragGesture
       if (!pixelThresholdX)
         pixelThresholdX = 5;
       if (!pixelThresholdY)
         pixelThresholdY = 5;
     }
 
     // fire drag gesture if mouse has moved enough
     nsIntPoint pt = aEvent->refPoint + aEvent->widget->WidgetToScreenOffset();
-    if (NS_ABS(pt.x - mGestureDownPoint.x) > pixelThresholdX ||
-        NS_ABS(pt.y - mGestureDownPoint.y) > pixelThresholdY) {
+    if (std::abs(pt.x - mGestureDownPoint.x) > pixelThresholdX ||
+        std::abs(pt.y - mGestureDownPoint.y) > pixelThresholdY) {
       if (mClickHoldContextMenu) {
         // stop the click-hold before we fire off the drag gesture, in case
         // it takes a long time
         KillClickHoldTimer();
       }
 
       nsRefPtr<nsDOMDataTransfer> dataTransfer = new nsDOMDataTransfer();
       if (!dataTransfer)
@@ -2890,24 +2892,24 @@ nsEventStateManager::DoScrollText(nsIScr
   }
 
   // We shouldn't scroll more one page at once except when over one page scroll
   // is allowed for the event.
   nsSize pageSize = aScrollableFrame->GetPageScrollAmount();
   nsIntSize devPixelPageSize(pc->AppUnitsToDevPixels(pageSize.width),
                              pc->AppUnitsToDevPixels(pageSize.height));
   if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedX(aEvent) &&
-      NS_ABS(actualDevPixelScrollAmount.x) > devPixelPageSize.width) {
+      std::abs(actualDevPixelScrollAmount.x) > devPixelPageSize.width) {
     actualDevPixelScrollAmount.x =
       (actualDevPixelScrollAmount.x >= 0) ? devPixelPageSize.width :
                                             -devPixelPageSize.width;
   }
 
   if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedY(aEvent) &&
-      NS_ABS(actualDevPixelScrollAmount.y) > devPixelPageSize.height) {
+      std::abs(actualDevPixelScrollAmount.y) > devPixelPageSize.height) {
     actualDevPixelScrollAmount.y =
       (actualDevPixelScrollAmount.y >= 0) ? devPixelPageSize.height :
                                             -devPixelPageSize.height;
   }
 
   bool isDeltaModePixel =
     (aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL);
 
@@ -5551,21 +5553,21 @@ nsEventStateManager::WheelPrefs::NeedToC
 }
 
 bool
 nsEventStateManager::WheelPrefs::IsOverOnePageScrollAllowedX(
                                    widget::WheelEvent* aEvent)
 {
   Index index = GetIndexFor(aEvent);
   Init(index);
-  return NS_ABS(mMultiplierX[index]) >=
+  return std::abs(mMultiplierX[index]) >=
            MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
 }
 
 bool
 nsEventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
                                    widget::WheelEvent* aEvent)
 {
   Index index = GetIndexFor(aEvent);
   Init(index);
-  return NS_ABS(mMultiplierY[index]) >=
+  return std::abs(mMultiplierY[index]) >=
            MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
 }
--- a/content/events/src/nsIMEStateManager.cpp
+++ b/content/events/src/nsIMEStateManager.cpp
@@ -57,16 +57,18 @@ public:
     }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISELECTIONLISTENER
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
+  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
+  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
 
   void     Init(nsIWidget* aWidget,
                 nsPresContext* aPresContext,
                 nsIContent* aContent);
   void     Destroy(void);
   bool     IsManaging(nsPresContext* aPresContext, nsIContent* aContent);
 
   nsCOMPtr<nsIWidget>            mWidget;
@@ -74,16 +76,17 @@ public:
   nsCOMPtr<nsIContent>           mRootContent;
   nsCOMPtr<nsINode>              mEditableNode;
 
 private:
   void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd);
   void ObserveEditableNode();
 
   bool mObserving;
+  uint32_t mPreAttrChangeLength;
 };
 
 /******************************************************************/
 /* nsIMEStateManager                                              */
 /******************************************************************/
 
 nsIContent*    nsIMEStateManager::sContent      = nullptr;
 nsPresContext* nsIMEStateManager::sPresContext  = nullptr;
@@ -971,16 +974,60 @@ nsTextStateManager::ContentRemoved(nsIDo
     return;
 
   // fire notification
   if (childOffset)
     nsContentUtils::AddScriptRunner(
         new TextChangeEvent(this, offset, offset + childOffset, offset));
 }
 
+static nsIContent*
+GetContentBR(mozilla::dom::Element *aElement) {
+  if (!aElement->IsNodeOfType(nsINode::eCONTENT)) {
+    return nullptr;
+  }
+  nsIContent *content = static_cast<nsIContent*>(aElement);
+  return content->IsHTML(nsGkAtoms::br) ? content : nullptr;
+}
+
+void
+nsTextStateManager::AttributeWillChange(nsIDocument* aDocument,
+                                        mozilla::dom::Element* aElement,
+                                        int32_t      aNameSpaceID,
+                                        nsIAtom*     aAttribute,
+                                        int32_t      aModType)
+{
+  nsIContent *content = GetContentBR(aElement);
+  mPreAttrChangeLength = content ?
+    nsContentEventHandler::GetNativeTextLength(content) : 0;
+}
+
+void
+nsTextStateManager::AttributeChanged(nsIDocument* aDocument,
+                                     mozilla::dom::Element* aElement,
+                                     int32_t aNameSpaceID,
+                                     nsIAtom* aAttribute,
+                                     int32_t aModType)
+{
+  nsIContent *content = GetContentBR(aElement);
+  if (!content) {
+    return;
+  }
+  uint32_t postAttrChangeLength =
+    nsContentEventHandler::GetNativeTextLength(content);
+  if (postAttrChangeLength != mPreAttrChangeLength) {
+    uint32_t start;
+    if (NS_SUCCEEDED(nsContentEventHandler::GetFlatTextOffsetOfRange(
+        mRootContent, content, 0, &start))) {
+      nsContentUtils::AddScriptRunner(new TextChangeEvent(this, start,
+        start + mPreAttrChangeLength, start + postAttrChangeLength));
+    }
+  }
+}
+
 bool
 nsIMEStateManager::IsEditable(nsINode* node)
 {
   if (node->IsEditable()) {
     return true;
   }
   // |node| might be readwrite (for example, a text control)
   if (node->IsElement() && node->AsElement()->State().HasState(NS_EVENT_STATE_MOZ_READWRITE)) {
--- a/content/html/content/public/nsHTMLMediaElement.h
+++ b/content/html/content/public/nsHTMLMediaElement.h
@@ -108,17 +108,17 @@ public:
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers);
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true);
   virtual void DoneCreatingElement();
 
   /**
    * Call this to reevaluate whether we should start/stop due to our owner
-   * document being active or inactive.
+   * document being active, inactive, visible or hidden.
    */
   void NotifyOwnerDocumentActivityChanged();
 
   // Called by the video decoder object, on the main thread,
   // when it has read the metadata containing video dimensions,
   // etc.
   virtual void MetadataLoaded(int aChannels,
                               int aRate,
@@ -321,16 +321,19 @@ public:
   virtual void FireTimeUpdate(bool aPeriodic) MOZ_FINAL MOZ_OVERRIDE;
 
   MediaStream* GetSrcMediaStream()
   {
     NS_ASSERTION(mSrcStream, "Don't call this when not playing a stream");
     return mSrcStream->GetStream();
   }
 
+  // Notification from the AudioChannelService.
+   nsresult NotifyAudioChannelStateChanged();
+
 protected:
   class MediaLoadListener;
   class StreamListener;
 
   virtual void GetItemValueText(nsAString& text);
   virtual void SetItemValueText(const nsAString& text);
 
   class WakeLockBoolWrapper {
@@ -600,16 +603,25 @@ protected:
   // Return true if decoding should be paused
   virtual bool GetPaused() MOZ_FINAL MOZ_OVERRIDE
   {
     bool isPaused = false;
     GetPaused(&isPaused);
     return isPaused;
   }
 
+  // Check the permissions for audiochannel.
+  bool CheckAudioChannelPermissions(const nsAString& aType);
+
+  // This method does the check for muting/unmuting the audio channel.
+  nsresult UpdateChannelMuteState();
+
+  // Update the audio channel playing state
+  void UpdateAudioChannelPlayingState();
+
   // The current decoder. Load() has been called on this decoder.
   // At most one of mDecoder and mSrcStream can be non-null.
   nsRefPtr<MediaDecoder> mDecoder;
 
   // A reference to the VideoFrameContainer which contains the current frame
   // of video to display.
   nsRefPtr<VideoFrameContainer> mVideoFrameContainer;
 
@@ -874,11 +886,17 @@ protected:
   // and we are recreating a channel after the initial load, we need that
   // information to give it as a hint to the channel for it to bypass the
   // sniffing phase, that would fail because sniffing only works when applied to
   // the first bytes of the stream.
   nsCString mMimeType;
 
   // Audio Channel Type.
   mozilla::dom::AudioChannelType mAudioChannelType;
+
+  // The audiochannel has been muted
+  bool mChannelMuted;
+
+  // Is this media element playing?
+  bool mPlayingThroughTheAudioChannel;
 };
 
 #endif
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -62,21 +62,25 @@
 #include "nsURIHashKey.h"
 #include "nsJSUtils.h"
 #include "MediaStreamGraph.h"
 #include "nsDOMMediaStream.h"
 #include "nsIScriptError.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "MediaMetadataManager.h"
 
+#include "AudioChannelService.h"
+
 #include "nsCSSParser.h"
 #include "nsIMediaList.h"
 
 #include "ImageContainer.h"
 #include "nsIPowerManagerService.h"
+#include <cstdlib> // for std::abs(int/long)
+#include <cmath> // for std::abs(float/double)
 
 #ifdef MOZ_OGG
 #include "OggDecoder.h"
 #endif
 #ifdef MOZ_WAVE
 #include "WaveDecoder.h"
 #endif
 #ifdef MOZ_WEBM
@@ -110,16 +114,18 @@ static PRLogModuleInfo* gMediaElementEve
 #endif
 
 #include "nsIContentSecurityPolicy.h"
 #include "nsIChannelPolicy.h"
 #include "nsChannelPolicy.h"
 
 #include "mozilla/Preferences.h"
 
+#include "nsIPermissionManager.h"
+
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 
 
 // Number of milliseconds between timeupdate events as defined by spec
 #define TIMEUPDATE_MS 250
 
@@ -455,16 +461,17 @@ NS_INTERFACE_MAP_END_INHERITING(nsGeneri
 // nsIDOMHTMLMediaElement
 NS_IMPL_URI_ATTR(nsHTMLMediaElement, Src, src)
 NS_IMPL_STRING_ATTR(nsHTMLMediaElement, Crossorigin, crossorigin)
 NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, Controls, controls)
 NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, Autoplay, autoplay)
 NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, Loop, loop)
 NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, DefaultMuted, muted)
 NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLMediaElement, Preload, preload, NULL)
+NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLMediaElement, MozAudioChannelType, mozaudiochannel, "normal")
 
 NS_IMETHODIMP
 nsHTMLMediaElement::GetMozSrcObject(JSContext* aCtx, jsval *aParams)
 {
   if (mSrcAttrStream) {
     NS_ASSERTION(mSrcAttrStream->GetStream(), "MediaStream should have been set up properly");
     return nsContentUtils::WrapNative(aCtx, JS_GetGlobalForScopeChain(aCtx),
                                       mSrcAttrStream, aParams);
@@ -1544,17 +1551,18 @@ NS_IMETHODIMP nsHTMLMediaElement::GetMut
 {
   *aMuted = mMuted;
 
   return NS_OK;
 }
 
 void nsHTMLMediaElement::SetMutedInternal(bool aMuted)
 {
-  float effectiveVolume = aMuted ? 0.0f : float(mVolume);
+  float effectiveVolume = aMuted || mChannelMuted ? 0.0f : float(mVolume);
+
   if (mDecoder) {
     mDecoder->SetVolume(effectiveVolume);
   } else if (mAudioStream) {
     mAudioStream->SetVolume(effectiveVolume);
   } else if (mSrcStream) {
     GetSrcMediaStream()->SetAudioOutputVolume(this, effectiveVolume);
   }
 }
@@ -1757,17 +1765,19 @@ nsHTMLMediaElement::nsHTMLMediaElement(a
     mHasPlayedOrSeeked(false),
     mHasSelfReference(false),
     mShuttingDown(false),
     mSuspendedForPreloadNone(false),
     mMediaSecurityVerified(false),
     mCORSMode(CORS_NONE),
     mHasAudio(false),
     mDownloadSuspendedByCache(false),
-    mAudioChannelType(AUDIO_CHANNEL_NORMAL)
+    mAudioChannelType(AUDIO_CHANNEL_NORMAL),
+    mChannelMuted(false),
+    mPlayingThroughTheAudioChannel(false)
 {
 #ifdef PR_LOGGING
   if (!gMediaElementLog) {
     gMediaElementLog = PR_NewLogModule("nsMediaElement");
   }
   if (!gMediaElementEventsLog) {
     gMediaElementEventsLog = PR_NewLogModule("nsMediaElementEvents");
   }
@@ -1925,46 +1935,97 @@ nsHTMLMediaElement::WakeLockBoolWrapper&
     mWakeLock->Unlock();
     mWakeLock = NULL;
   }
   mValue = val;
   return *this;
 }
 
 bool nsHTMLMediaElement::ParseAttribute(int32_t aNamespaceID,
-                                          nsIAtom* aAttribute,
-                                          const nsAString& aValue,
-                                          nsAttrValue& aResult)
+                                        nsIAtom* aAttribute,
+                                        const nsAString& aValue,
+                                        nsAttrValue& aResult)
 {
   // Mappings from 'preload' attribute strings to an enumeration.
   static const nsAttrValue::EnumTable kPreloadTable[] = {
     { "",         nsHTMLMediaElement::PRELOAD_ATTR_EMPTY },
     { "none",     nsHTMLMediaElement::PRELOAD_ATTR_NONE },
     { "metadata", nsHTMLMediaElement::PRELOAD_ATTR_METADATA },
     { "auto",     nsHTMLMediaElement::PRELOAD_ATTR_AUTO },
     { 0 }
   };
 
+  // Mappings from 'mozaudiochannel' attribute strings to an enumeration.
+  static const nsAttrValue::EnumTable kMozAudioChannelAttributeTable[] = {
+    { "normal",             AUDIO_CHANNEL_NORMAL },
+    { "content",            AUDIO_CHANNEL_CONTENT },
+    { "notification",       AUDIO_CHANNEL_NOTIFICATION },
+    { "alarm",              AUDIO_CHANNEL_ALARM },
+    { "telephony",          AUDIO_CHANNEL_TELEPHONY },
+    { "publicnotification", AUDIO_CHANNEL_PUBLICNOTIFICATION },
+    { 0 }
+  };
+
   if (aNamespaceID == kNameSpaceID_None) {
     if (ParseImageAttribute(aAttribute, aValue, aResult)) {
       return true;
     }
     if (aAttribute == nsGkAtoms::crossorigin) {
       ParseCORSValue(aValue, aResult);
       return true;
     }
     if (aAttribute == nsGkAtoms::preload) {
       return aResult.ParseEnumValue(aValue, kPreloadTable, false);
     }
+
+    if (aAttribute == nsGkAtoms::mozaudiochannel) {
+      bool parsed = aResult.ParseEnumValue(aValue, kMozAudioChannelAttributeTable, false,
+                                           &kMozAudioChannelAttributeTable[0]);
+      if (!parsed) {
+        return false;
+      }
+
+      AudioChannelType audioChannelType = static_cast<AudioChannelType>(aResult.GetEnumValue());
+
+      if (audioChannelType != mAudioChannelType &&
+          !mDecoder &&
+          CheckAudioChannelPermissions(aValue)) {
+        mAudioChannelType = audioChannelType;
+      }
+
+      return true;
+    }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
+bool nsHTMLMediaElement::CheckAudioChannelPermissions(const nsAString& aString)
+{
+#ifdef MOZ_B2G
+  // Only normal channel doesn't need permission.
+  if (!aString.EqualsASCII("normal")) {
+    nsCOMPtr<nsIPermissionManager> permissionManager =
+      do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+    if (!permissionManager) {
+      return false;
+    }
+
+    uint32_t perm = nsIPermissionManager::UNKNOWN_ACTION;
+    permissionManager->TestExactPermissionFromPrincipal(NodePrincipal(),
+      nsCString(NS_LITERAL_CSTRING("audio-channel-") + NS_ConvertUTF16toUTF8(aString)).get(), &perm);
+    if (perm != nsIPermissionManager::ALLOW_ACTION) {
+      return false;
+    }
+  }
+#endif
+  return true;
+}
+
 void nsHTMLMediaElement::DoneCreatingElement()
 {
    if (HasAttr(kNameSpaceID_None, nsGkAtoms::muted))
      mMuted = true;
 }
 
 nsresult nsHTMLMediaElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                      nsIAtom* aPrefix, const nsAString& aValue,
@@ -2788,16 +2849,18 @@ static const char* gReadyStateToString[]
 };
 #endif
 
 void nsHTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
 {
   nsMediaReadyState oldState = mReadyState;
   mReadyState = aState;
 
+  UpdateAudioChannelPlayingState();
+
   if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY ||
       oldState == mReadyState) {
     return;
   }
 
   LOG(PR_LOG_DEBUG, ("%p Ready state changed to %s", this, gReadyStateToString[aState]));
 
   // Handle raising of "waiting" event during seek (see 4.8.10.9)
@@ -3032,16 +3095,20 @@ void nsHTMLMediaElement::NotifyOwnerDocu
         }
       } else if (mSrcStream) {
         GetSrcMediaStream()->ChangeExplicitBlockerCount(-1);
       }
       DispatchPendingMediaEvents();
     }
   }
 
+  if (mPlayingThroughTheAudioChannel) {
+    UpdateChannelMuteState();
+  }
+
   AddRemoveSelfReference();
 }
 
 void nsHTMLMediaElement::AddRemoveSelfReference()
 {
   // XXX we could release earlier here in many situations if we examined
   // which event listeners are attached. Right now we assume there is a
   // potential listener for every event. We would also have to keep the
@@ -3070,16 +3137,18 @@ void nsHTMLMediaElement::AddRemoveSelfRe
     } else {
       // Dispatch Release asynchronously so that we don't destroy this object
       // inside a call stack of method calls on this object
       nsCOMPtr<nsIRunnable> event =
         NS_NewRunnableMethod(this, &nsHTMLMediaElement::DoRemoveSelfReference);
       NS_DispatchToMainThread(event);
     }
   }
+
+  UpdateAudioChannelPlayingState();
 }
 
 void nsHTMLMediaElement::DoRemoveSelfReference()
 {
   // We don't need the shutdown observer anymore. Unregistering releases
   // its reference to us, which we were using as our self-reference.
   nsContentUtils::UnregisterShutdownObserver(this);
 }
@@ -3359,20 +3428,20 @@ void nsHTMLMediaElement::NotifyAudioAvai
   }
 }
 
 static double ClampPlaybackRate(double aPlaybackRate)
 {
   if (aPlaybackRate == 0.0) {
     return aPlaybackRate;
   }
-  if (NS_ABS(aPlaybackRate) < MIN_PLAYBACKRATE) {
+  if (std::abs(aPlaybackRate) < MIN_PLAYBACKRATE) {
     return aPlaybackRate < 0 ? -MIN_PLAYBACKRATE : MIN_PLAYBACKRATE;
   }
-  if (NS_ABS(aPlaybackRate) > MAX_PLAYBACKRATE) {
+  if (std::abs(aPlaybackRate) > MAX_PLAYBACKRATE) {
     return aPlaybackRate < 0 ? -MAX_PLAYBACKRATE : MAX_PLAYBACKRATE;
   }
   return aPlaybackRate;
 }
 
 /* attribute double defaultPlaybackRate; */
 NS_IMETHODIMP nsHTMLMediaElement::GetDefaultPlaybackRate(double* aDefaultPlaybackRate)
 {
@@ -3430,70 +3499,79 @@ NS_IMETHODIMP nsHTMLMediaElement::GetMoz
 
 NS_IMETHODIMP nsHTMLMediaElement::SetMozPreservesPitch(bool aPreservesPitch)
 {
   mPreservesPitch = aPreservesPitch;
   mDecoder->SetPreservesPitch(aPreservesPitch);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsHTMLMediaElement::GetMozAudioChannelType(nsAString& aString)
-{
-  switch (mAudioChannelType) {
-    case AUDIO_CHANNEL_NORMAL:
-      aString.AssignLiteral("normal");
-      break;
-    case AUDIO_CHANNEL_CONTENT:
-      aString.AssignLiteral("content");
-      break;
-    case AUDIO_CHANNEL_NOTIFICATION:
-      aString.AssignLiteral("notification");
-      break;
-    case AUDIO_CHANNEL_ALARM:
-      aString.AssignLiteral("alarm");
-      break;
-    case AUDIO_CHANNEL_TELEPHONY:
-      aString.AssignLiteral("telephony");
-      break;
-    case AUDIO_CHANNEL_PUBLICNOTIFICATION:
-      aString.AssignLiteral("publicnotification");
-      break;
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHTMLMediaElement::SetMozAudioChannelType(const nsAString& aString)
-{
-  AudioChannelType tmpType;
-
-  if (aString.EqualsASCII("normal")) {
-    tmpType = AUDIO_CHANNEL_NORMAL;
-  } else if (aString.EqualsASCII("content")) {
-    tmpType = AUDIO_CHANNEL_CONTENT;
-  } else if (aString.EqualsASCII("notification")) {
-    tmpType = AUDIO_CHANNEL_NOTIFICATION;
-  } else if (aString.EqualsASCII("alarm")) {
-    tmpType = AUDIO_CHANNEL_ALARM;
-  } else if (aString.EqualsASCII("telephony")) {
-    tmpType = AUDIO_CHANNEL_TELEPHONY;
-  } else if (aString.EqualsASCII("publicnotification")) {
-    tmpType = AUDIO_CHANNEL_PUBLICNOTIFICATION;
-  } else {
-    return NS_ERROR_FAILURE;
-  }
-
-  if (tmpType != mAudioChannelType && mDecoder) {
-    return NS_ERROR_FAILURE;
-  }
-
-  mAudioChannelType = tmpType;
-  return NS_OK;
-}
-
 ImageContainer* nsHTMLMediaElement::GetImageContainer()
 {
   VideoFrameContainer* container = GetVideoFrameContainer();
   return container ? container->GetImageContainer() : nullptr;
 }
 
+nsresult nsHTMLMediaElement::UpdateChannelMuteState()
+{
+  // Only on B2G we mute the nsHTMLMediaElement following the rules of
+  // AudioChannelService.
+#ifdef MOZ_B2G
+  bool hidden = false;
+  nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(OwnerDoc());
+  if (!domDoc) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv = domDoc->GetHidden(&hidden);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool mute = false;
+
+  nsRefPtr<AudioChannelService> audioChannelService = AudioChannelService::GetAudioChannelService();
+  if (audioChannelService) {
+    mute = audioChannelService->GetMuted(mAudioChannelType, hidden);
+  }
+
+  // We have to mute this channel:
+  if (mute && !mChannelMuted) {
+    mChannelMuted = true;
+    DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptbegin"));
+  } else if (!mute && mChannelMuted) {
+    mChannelMuted = false;
+    DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptend"));
+  }
+
+  SetMutedInternal(mMuted);
+#endif
+
+  return NS_OK;
+}
+
+void nsHTMLMediaElement::UpdateAudioChannelPlayingState()
+{
+  // The nsHTMLMediaElement is registered to the AudioChannelService only on B2G.
+#ifdef MOZ_B2G
+  bool playingThroughTheAudioChannel =
+     (mReadyState >= nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
+      IsPotentiallyPlaying());
+  if (playingThroughTheAudioChannel != mPlayingThroughTheAudioChannel) {
+    mPlayingThroughTheAudioChannel = playingThroughTheAudioChannel;
+
+    nsRefPtr<AudioChannelService> audioChannelService = AudioChannelService::GetAudioChannelService();
+    if (!audioChannelService) {
+      return;
+    }
+
+    if (mPlayingThroughTheAudioChannel) {
+      audioChannelService->RegisterMediaElement(this, mAudioChannelType);
+    } else {
+      audioChannelService->UnregisterMediaElement(this);
+    }
+  }
+#endif
+}
+
+nsresult nsHTMLMediaElement::NotifyAudioChannelStateChanged()
+{
+  return UpdateChannelMuteState();
+}
+
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -328,17 +328,19 @@ MOCHITEST_FILES = \
 		file_iframe_sandbox_f_if2.html^headers^ \
 		test_iframe_sandbox_workers.html \
 		file_iframe_sandbox_g_if1.html \
 		file_iframe_sandbox_worker.js \
 		test_named_options.html \
 		test_htmlcollection.html \
 		test_formelements.html \
 		test_rowscollection.html \
+		test_mozaudiochannel.html \
 		$(NULL)
 
+
 MOCHITEST_BROWSER_FILES = \
 		browser_bug649778.js \
 		file_bug649778.html \
 		file_bug649778.html^headers^ \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_mozaudiochannel.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for mozaudiochannel</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+  <audio id="audio1" />
+  <audio id="audio2" mozaudiochannel="foo" />
+  <audio id="audio3" mozaudiochannel="content" />
+</div>
+
+<pre id="test">
+<script type="application/javascript">
+
+var audio1 = document.getElementById("audio1");
+ok(audio1, "Audio Element exists");
+ok(audio1.mozAudioChannelType == "normal", "Default audio1 channel == 'normal'");
+try {
+audio1.mozAudioChannelType = "foo";
+} catch(e) {}
+ok(audio1.mozAudioChannelType == "normal", "Default audio1 channel == 'normal'");
+audio1.mozAudioChannelType = "alarm";
+ok(audio1.mozAudioChannelType == "alarm", "Default audio1 channel == 'alarm'");
+
+var audio2 = document.getElementById("audio2");
+ok(audio2, "Audio Element exists");
+ok(audio2.mozAudioChannelType == "normal", "Default audio2 channel == 'normal'");
+try {
+audio2.mozAudioChannelType = "foo";
+} catch(e) {}
+ok(audio2.mozAudioChannelType == "normal", "Default audio2 channel == 'normal'");
+audio2.mozAudioChannelType = "alarm";
+ok(audio2.mozAudioChannelType == "alarm", "Default audio2 channel == 'alarm'");
+
+var audio3 = document.getElementById("audio3");
+ok(audio3, "Audio Element exists");
+ok(audio3.mozAudioChannelType == "content", "Default audio3 channel == 'content'");
+try {
+audio3.mozAudioChannelType = "foo";
+} catch(e) {}
+ok(audio3.mozAudioChannelType == "normal", "audio3 channel == 'normal'");
+audio3.mozAudioChannelType = "alarm";
+ok(audio3.mozAudioChannelType == "alarm", "audio3 channel == 'alarm'");
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/html/document/test/Makefile.in
+++ b/content/html/document/test/Makefile.in
@@ -38,17 +38,17 @@ MOCHITEST_FILES = 	test_bug1682.html \
 		test_bug403868.html \
 		test_bug403868.xhtml \
 		$(filter disabled-for-timeouts, test_bug435128.html) \
 		test_bug463104.html \
 		test_form-parsing.html \
 		test_viewport.html \
 		test_documentAll.html \
 		test_document-element-inserted.html \
-		test_bug445004.html \
+		$(filter disabled-temporarily--bug-559932, test_bug445004.html) \
 		bug445004-inner.js \
 		bug445004-outer-rel.html \
 		bug445004-outer-abs.html \
 		bug445004-outer-write.html \
 		bug445004-inner.html \
 		test_bug446483.html \
 		bug446483-iframe.html \
 		test_bug448564.html \
--- a/content/media/MediaDecoder.cpp
+++ b/content/media/MediaDecoder.cpp
@@ -15,16 +15,18 @@
 #include "VideoUtils.h"
 #include "MediaDecoderStateMachine.h"
 #include "nsTimeRanges.h"
 #include "nsContentUtils.h"
 #include "ImageContainer.h"
 #include "MediaResource.h"
 #include "nsError.h"
 #include "mozilla/Preferences.h"
+#include <cstdlib> // for std::abs(int/long)
+#include <cmath> // for std::abs(float/double)
 
 using namespace mozilla::layers;
 using namespace mozilla::dom;
 
 namespace mozilla {
 
 // Number of milliseconds between progress events as defined by spec
 static const uint32_t PROGRESS_MS = 350;
@@ -556,21 +558,21 @@ nsresult MediaDecoder::Seek(double aTime
       // |range + 1| can't be negative, because the only possible negative value
       // for |range| is -1.
       if (uint32_t(range + 1) < length) {
         double leftBound, rightBound;
         res = seekable.End(range, &leftBound);
         NS_ENSURE_SUCCESS(res, NS_OK);
         res = seekable.Start(range + 1, &rightBound);
         NS_ENSURE_SUCCESS(res, NS_OK);
-        double distanceLeft = NS_ABS(leftBound - aTime);
-        double distanceRight = NS_ABS(rightBound - aTime);
+        double distanceLeft = std::abs(leftBound - aTime);
+        double distanceRight = std::abs(rightBound - aTime);
         if (distanceLeft == distanceRight) {
-          distanceLeft = NS_ABS(leftBound - mCurrentTime);
-          distanceRight = NS_ABS(rightBound - mCurrentTime);
+          distanceLeft = std::abs(leftBound - mCurrentTime);
+          distanceRight = std::abs(rightBound - mCurrentTime);
         } 
         aTime = (distanceLeft < distanceRight) ? leftBound : rightBound;
       } else {
         // Seek target is after the end last range in seekable data.
         // Clamp the seek target to the end of the last seekable range.
         res = seekable.End(length - 1, &aTime);
         NS_ENSURE_SUCCESS(res, NS_OK);
       }
--- a/content/media/MediaDecoder.h
+++ b/content/media/MediaDecoder.h
@@ -499,17 +499,17 @@ public:
   // Set the duration of the media resource in units of seconds.
   // This is called via a channel listener if it can pick up the duration
   // from a content header. Must be called from the main thread only.
   virtual void SetDuration(double aDuration);
 
   void SetMediaDuration(int64_t aDuration) MOZ_FINAL MOZ_OVERRIDE;
 
   // Set a flag indicating whether seeking is supported
-  virtual void SetMediaSeekable(bool aMediaSeekable) MOZ_FINAL MOZ_OVERRIDE;
+  virtual void SetMediaSeekable(bool aMediaSeekable) MOZ_OVERRIDE;
   virtual void SetTransportSeekable(bool aTransportSeekable) MOZ_FINAL MOZ_OVERRIDE;
   // Returns true if this media supports seeking. False for example for WebM
   // files without an index and chained ogg files.
   virtual bool IsMediaSeekable() MOZ_FINAL MOZ_OVERRIDE;
   // Returns true if seeking is supported on a transport level (e.g. the server
   // supports range requests, we are playing a file, etc.).
   virtual bool IsTransportSeekable();
 
--- a/content/media/plugins/MediaPluginHost.cpp
+++ b/content/media/plugins/MediaPluginHost.cpp
@@ -170,16 +170,18 @@ static const char* GetOmxLibraryName()
     return nullptr;
   }
 
   // Default libomxplugin for non-gingerbread devices
   return "lib/libomxplugin.so";
 
 #elif defined(ANDROID) && defined(MOZ_WIDGET_GONK)
   return "libomxplugin.so";
+#else
+  return nullptr;
 #endif
 }
 
 MediaPluginHost::MediaPluginHost() {
   MOZ_COUNT_CTOR(MediaPluginHost);
 
   const char* name = GetOmxLibraryName();
   ALOG("Loading OMX Plugin: %s", name ? name : "nullptr");
--- a/content/svg/content/src/nsSVGSVGElement.cpp
+++ b/content/svg/content/src/nsSVGSVGElement.cpp
@@ -1082,17 +1082,17 @@ nsSVGSVGElement::HasPreserveAspectRatio(
 
 nsSVGViewElement*
 nsSVGSVGElement::GetCurrentViewElement() const
 {
   if (mCurrentViewID) {
     nsIDocument* doc = GetCurrentDoc();
     if (doc) {
       Element *element = doc->GetElementById(*mCurrentViewID);
-      if (element && element->Tag() == nsGkAtoms::view) {
+      if (element && element->IsSVG(nsGkAtoms::view)) {
         return static_cast<nsSVGViewElement*>(element);
       }
     }
   }
   return nullptr;
 }
 
 nsSVGViewBoxRect
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -2500,21 +2500,19 @@ void
 nsXULPrototypeScript::Set(JSScript* aObject)
 {
     NS_ASSERTION(!mScriptObject.mObject, "Leaking script object.");
     if (!aObject) {
         mScriptObject.mObject = nullptr;
         return;
     }
 
-    nsresult rv = nsContentUtils::HoldJSObjects(
+    nsContentUtils::HoldJSObjects(
         this, NS_CYCLE_COLLECTION_PARTICIPANT(nsXULPrototypeNode));
-    if (NS_SUCCEEDED(rv)) {
-        mScriptObject.mObject = aObject;
-    }
+    mScriptObject.mObject = aObject;
 }
 
 //----------------------------------------------------------------------
 //
 // nsXULPrototypeText
 //
 
 nsresult
--- a/docshell/shistory/src/nsSHistory.cpp
+++ b/docshell/shistory/src/nsSHistory.cpp
@@ -29,17 +29,18 @@
 #include "mozilla/Services.h"
 #include "nsTArray.h"
 #include "nsCOMArray.h"
 #include "nsDocShell.h"
 #include "mozilla/Attributes.h"
 
 // For calculating max history entries and max cachable contentviewers
 #include "nspr.h"
-#include <math.h>  // for log()
+#include <cstdlib> // for std::abs(int/long)
+#include <cmath> // for std::abs(float/double), and std::log(double)
 
 using namespace mozilla;
 
 #define PREF_SHISTORY_SIZE "browser.sessionhistory.max_entries"
 #define PREF_SHISTORY_MAX_TOTAL_VIEWERS "browser.sessionhistory.max_total_viewers"
 
 static const char* kObservedPrefs[] = {
   PREF_SHISTORY_SIZE,
@@ -305,17 +306,17 @@ nsSHistory::CalcMaxTotalViewers()
 
   double kBytesD;
   LL_L2D(kBytesD, (int64_t) kbytes);
 
   // This is essentially the same calculation as for nsCacheService,
   // except that we divide the final memory calculation by 4, since
   // we assume each ContentViewer takes on average 4MB
   uint32_t viewers = 0;
-  double x = log(kBytesD)/log(2.0) - 14;
+  double x = std::log(kBytesD)/std::log(2.0) - 14;
   if (x > 0) {
     viewers    = (uint32_t)(x * x - x + 2.001); // add .001 for rounding
     viewers   /= 4;
   }
 
   // Cap it off at 8 max
   if (viewers > 8) {
     viewers = 8;
@@ -1083,26 +1084,26 @@ nsSHistory::GloballyEvictContentViewers(
         // have to search through shTransactions to see if we already know
         // about this content viewer.  If we find the viewer, update its
         // distance from the SHistory's index and continue.
         bool found = false;
         for (uint32_t j = 0; j < shTransactions.Length(); j++) {
           TransactionAndDistance &container = shTransactions[j];
           if (container.mViewer == contentViewer) {
             container.mDistance = NS_MIN(container.mDistance,
-                                         NS_ABS(i - shist->mIndex));
+                                         std::abs(i - shist->mIndex));
             found = true;
             break;
           }
         }
 
         // If we didn't find a TransactionAndDistance for this content viewer, make a new
         // one.
         if (!found) {
-          TransactionAndDistance container(trans, NS_ABS(i - shist->mIndex));
+          TransactionAndDistance container(trans, std::abs(i - shist->mIndex));
           shTransactions.AppendElement(container);
         }
       }
 
       nsISHTransaction *temp = trans;
       temp->GetNext(getter_AddRefs(trans));
     }
 
--- a/docshell/test/chrome/Makefile.in
+++ b/docshell/test/chrome/Makefile.in
@@ -74,17 +74,16 @@ MOCHITEST_CHROME_FILES =	\
 		bug582176_window.xul \
 		test_bug428288.html \
 		test_bug608669.xul \
 		bug608669.xul \
 		test_bug449778.xul \
 		bug449778_window.xul \
 		test_bug449780.xul \
 		bug449780_window.xul \
-		test_bug454235.xul \
 		bug454235-subframe.xul \
 		test_bug456980.xul \
 		test_bug662200.xul \
 		bug662200_window.xul \
 		662200a.html \
 		662200b.html \
 		662200c.html \
 		test_bug690056.xul \
@@ -92,16 +91,21 @@ MOCHITEST_CHROME_FILES =	\
 		test_bug311007.xul \
 		bug311007_window.xul \
 		test_principalInherit.xul \
 		test_mozFrameType.xul \
 		mozFrameType_window.xul \
 		test_bug789773.xul \
 		test_bug754029.xul \
 		bug754029_window.xul \
-		$(NULL)
-
-MOCHITEST_CHROME_FILES += \
     docshell_helpers.js \
     generic.html \
     $(NULL)
 
+ifneq ($(MOZ_WIDGET_TOOLKIT),gtk2)
+MOCHITEST_CHROME_FILES += \
+		test_bug454235.xul \
+		$(NULL)
+else
+$(filter disabled-temporarily--bug-684176, test_bug454235.xul)
+endif
+
 include $(topsrcdir)/config/rules.mk
--- a/docshell/test/navigation/Makefile.in
+++ b/docshell/test/navigation/Makefile.in
@@ -51,18 +51,25 @@ MOCHITEST_FILES = \
 
 ifneq (mobile/android,$(MOZ_BUILD_APP))
 MOCHITEST_FILES += \
 		test_bug270414.html \
 		$(NULL)
 endif
 
 MOCHITEST_BROWSER_FILES = \
-		browser_bug343515.js \
 		bug343515_pg1.html \
 		bug343515_pg2.html \
 		bug343515_pg3.html \
 		bug343515_pg3_1.html \
 		bug343515_pg3_2.html \
 		bug343515_pg3_1_1.html \
 		$(NULL)
 
+ifneq ($(OS_ARCH),WINNT)
+MOCHITEST_BROWSER_FILES += \
+		browser_bug343515.js \
+		$(NULL)
+else
+$(filter disabled-temporarily--bug-813242, browser_bug343515.js)
+endif
+
 include $(topsrcdir)/config/rules.mk
--- a/dom/apps/src/AppsUtils.jsm
+++ b/dom/apps/src/AppsUtils.jsm
@@ -179,16 +179,25 @@ this.AppsUtils = {
       if (checkAbsoluteEntryPoints(aManifest.locales[localeName].entry_points)) {
         return false;
       }
     }
 
     return true;
   },
 
+  checkManifestContentType: function
+     checkManifestContentType(installOrigin, webappOrigin, contentType) {
+    if (installOrigin != webappOrigin &&
+        contentType != "application/x-web-app-manifest+json") {
+      return false;
+    }
+    return true;
+  },
+
   /**
    * Determines whether the manifest allows installs for the given origin.
    * @param object aManifest
    * @param string aInstallOrigin
    * @return boolean
    **/
   checkInstallAllowed: function checkInstallAllowed(aManifest, aInstallOrigin) {
     if (!aManifest.installs_allowed_from) {
--- a/dom/apps/src/PermissionsInstaller.jsm
+++ b/dom/apps/src/PermissionsInstaller.jsm
@@ -9,16 +9,17 @@ const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 Cu.import("resource://gre/modules/PermissionSettings.jsm");
 
 this.EXPORTED_SYMBOLS = ["PermissionsInstaller",
                          "expandPermissions",
                          "PermissionsTable",
+                         "appendAccessToPermName"
                         ];
 const UNKNOWN_ACTION = Ci.nsIPermissionManager.UNKNOWN_ACTION;
 const ALLOW_ACTION = Ci.nsIPermissionManager.ALLOW_ACTION;
 const DENY_ACTION = Ci.nsIPermissionManager.DENY_ACTION;
 const PROMPT_ACTION = Ci.nsIPermissionManager.PROMPT_ACTION;
 
 // Permission access flags
 const READONLY = "readonly";
@@ -27,27 +28,16 @@ const READCREATE = "readcreate";
 const READWRITE = "readwrite";
 
 const PERM_TO_STRING = ["unknown", "allow", "deny", "prompt"];
 
 function debug(aMsg) {
   //dump("-*-*- PermissionsInstaller.jsm : " + aMsg + "\n");
 }
 
-/**
- * Converts ['read', 'write'] to ['contacts-read', 'contacts-write'], etc...
- * @param string aPermName
- * @param Array aSuffixes
- * @returns Array
- **/
-function mapSuffixes(aPermName, aSuffixes)
-{
-  return aSuffixes.map(function(suf) { return aPermName + "-" + suf; });
-}
-
 // Permissions Matrix: https://docs.google.com/spreadsheet/ccc?key=0Akyz_Bqjgf5pdENVekxYRjBTX0dCXzItMnRyUU1RQ0E#gid=0
 // Also, keep in sync with https://mxr.mozilla.org/mozilla-central/source/extensions/cookie/Permission.txt
 
 // Permissions that are implicit:
 // battery-status, network-information, vibration,
 // device-capabilities
 
 this.PermissionsTable =  { geolocation: {
@@ -149,17 +139,17 @@ this.PermissionsTable =  { geolocation: 
                              additional: ["indexedDB-chrome-settings"]
                            },
                            permissions: {
                              app: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
                            fmradio: {
-                             app: ALLOW_ACTION,     // Matrix indicates '?'
+                             app: ALLOW_ACTION,
                              privileged: ALLOW_ACTION,
                              certified: ALLOW_ACTION
                            },
                            attention: {
                              app: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
@@ -233,27 +223,52 @@ this.PermissionsTable =  { geolocation: 
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
                            cellbroadcast: {
                              app: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
+                           audio: {
+                             app: DENY_ACTION,
+                             privileged: ALLOW_ACTION,
+                             certified: ALLOW_ACTION,
+                             channels: ["normal", "content", "notification",
+                               "alarm", "telephony", "ringer", "publicnotification"]
+                           },
                          };
 
 /**
+ * Append access modes to the permission name as suffixes.
+ *   e.g. permission name 'contacts' with ['read', 'write'] =
+ *   ['contacts-read', contacts-write']
+ * @param string aPermName
+ * @param array aAccess
+ * @returns array containing access-appended permission names.
+ **/
+this.appendAccessToPermName = function appendAccessToPermName(aPermName, aAccess) {
+  if (aAccess.length == 0) {
+    return [aPermName];
+  }
+  return aAccess.map(function(aMode) {
+    return aPermName + "-" + aMode;
+  });
+};
+
+/**
  * Expand an access string into multiple permission names,
- *   e.g: perm 'contacts' with 'readwrite' =
- *   ['contacts-read', 'contacts-create', contacts-write']
+ *   e.g: permission name 'contacts' with 'readwrite' =
+ *   ['contacts-read', 'contacts-create', 'contacts-write']
  * @param string aPermName
  * @param string aAccess
- * @returns Array
+ * @param string array aChannels
+ * @returns array containing expanded permission names.
  **/
-this.expandPermissions = function expandPermissions(aPermName, aAccess) {
+this.expandPermissions = function expandPermissions(aPermName, aAccess, aChannels) {
   if (!PermissionsTable[aPermName]) {
     Cu.reportError("PermissionsTable.jsm: expandPermissions: Unknown Permission: " + aPermName);
     dump("PermissionsTable.jsm: expandPermissions: Unknown Permission: " + aPermName);
     return [];
   }
 
   const tableEntry = PermissionsTable[aPermName];
 
@@ -268,84 +283,99 @@ this.expandPermissions = function expand
     Cu.reportError("PermissionsTable.jsm: expandPermissions: Invalid Manifest : " +
                    aPermName + " " + aAccess + "\n");
     dump("PermissionsTable.jsm: expandPermissions: Invalid Manifest: " +
          aPermName + " " + aAccess + "\n");
     throw new Error("PermissionsTable.jsm: expandPermissions: Invalid Manifest: " +
                     aPermName + " " + aAccess + "\n");
   }
 
-  let expandedPerms = [];
+  let expandedPermNames = [];
 
   if (tableEntry.access && aAccess) {
-  let requestedSuffixes = [];
+    let requestedSuffixes = [];
     switch (aAccess) {
-  case READONLY:
-    requestedSuffixes.push("read");
-    break;
-  case CREATEONLY:
-    requestedSuffixes.push("create");
-    break;
-  case READCREATE:
-    requestedSuffixes.push("read", "create");
-    break;
-  case READWRITE:
-    requestedSuffixes.push("read", "create", "write");
-    break;
-  default:
-    return [];
-  }
+    case READONLY:
+      requestedSuffixes.push("read");
+      break;
+    case CREATEONLY:
+      requestedSuffixes.push("create");
+      break;
+    case READCREATE:
+      requestedSuffixes.push("read", "create");
+      break;
+    case READWRITE:
+      requestedSuffixes.push("read", "create", "write");
+      break;
+    default:
+      return [];
+    }
+
+    let permArr = appendAccessToPermName(aPermName, requestedSuffixes);
+
+    // Add the same suffix to each of the additions.
+    if (tableEntry.additional) {
+      for each (let additional in tableEntry.additional) {
+        permArr = permArr.concat(appendAccessToPermName(additional, requestedSuffixes));
+      }
+    }
 
-  let permArr = mapSuffixes(aPermName, requestedSuffixes);
+    // Only add the suffixed version if the suffix exisits in the table.
+    for (let idx in permArr) {
+      let suffix = requestedSuffixes[idx % requestedSuffixes.length];
+      if (tableEntry.access.indexOf(suffix) != -1) {
+        expandedPermNames.push(permArr[idx]);
+      }
+    }
+  } else if (tableEntry.substitute) {
+    expandedPermNames = expandedPermNames.concat(tableEntry.substitute);
+  } else if (tableEntry.channels) {
+    if ("audio" == aPermName && aChannels) {
+      let allowChannels = tableEntry.channels;
 
-  // Add the same suffix to each of the additions.
-  if (tableEntry.additional) {
-    for each (let additional in tableEntry.additional) {
-      permArr = permArr.concat(mapSuffixes(additional, requestedSuffixes));
+      for (let idx in aChannels) {
+        let candidate = aChannels[idx];
+        if (allowChannels.indexOf(candidate) == -1) {
+          continue;
+        }
+        let permAttr = aPermName + "-channel-" + candidate;
+        expandedPermNames.push(permAttr);
+      }
+    }
+  } else {
+    expandedPermNames.push(aPermName);
+    // Include each of the additions exactly as they appear in the table.
+    if (tableEntry.additional) {
+      expandedPermNames = expandedPermNames.concat(tableEntry.additional);
     }
   }
 
-  // Only add the suffixed version if the suffix exisits in the table.
-  for (let idx in permArr) {
-      let suffix = requestedSuffixes[idx % requestedSuffixes.length];
-      if (tableEntry.access.indexOf(suffix) != -1) {
-      expandedPerms.push(permArr[idx]);
-    }
-  }
-  } else if (tableEntry.substitute) {
-    expandedPerms = expandedPerms.concat(tableEntry.substitute);
-  } else {
-    expandedPerms.push(aPermName);
-    // Include each of the additions exactly as they appear in the table.
-    if (tableEntry.additional) {
-      expandedPerms = expandedPerms.concat(tableEntry.additional);
-    }
-  }
-
-  return expandedPerms;
+  return expandedPermNames;
 };
 
-// Sometimes all permissions (fully expanded) need to be iterated through
+// An array carring all the possible (expanded) permission names.
 let AllPossiblePermissions = [];
 for (let permName in PermissionsTable) {
   if (PermissionsTable[permName].access) {
     AllPossiblePermissions =
       AllPossiblePermissions.concat(expandPermissions(permName, READWRITE));
+  } else if (PermissionsTable[permName].channels) {
+      AllPossiblePermissions.concat(expandPermissions(permName, null, PermissionsTable[permName].channels));
   } else {
     AllPossiblePermissions =
       AllPossiblePermissions.concat(expandPermissions(permName));
   }
 }
 
 this.PermissionsInstaller = {
-/**
-   * Install permissisions or remove deprecated permissions upon re-install
+  /**
+   * Install permissisions or remove deprecated permissions upon re-install.
    * @param object aApp
    *        The just-installed app configuration.
-            The properties used are manifestURL, origin and manifest.
+   *        The properties used are manifestURL, origin and manifest.
    * @param boolean aIsReinstall
    *        Indicates the app was just re-installed
    * @param function aOnError
    *        A function called if an error occurs
    * @returns void
    **/
   installPermissions: function installPermissions(aApp, aIsReinstall, aOnError) {
     try {
@@ -354,101 +384,109 @@ this.PermissionsInstaller = {
         return;
       }
 
       if (aIsReinstall) {
         // Compare the original permissions against the new permissions
         // Remove any deprecated Permissions
 
         if (newManifest.permissions) {
-          // Expand perms
-          let newPerms = [];
-          for (let perm in newManifest.permissions) {
-            let _perms = expandPermissions(perm,
-                                           newManifest.permissions[perm].access);
-            newPerms = newPerms.concat(_perms);
+          // Expand permission names.
+          let newPermNames = [];
+          for (let permName in newManifest.permissions) {
+            let expandedPermNames =
+              expandPermissions(permName,
+                                newManifest.permissions[permName].access,
+                                newManifest.permissions[permName].channels);
+            newPermNames = newPermNames.concat(expandedPermNames);
           }
 
           for (let idx in AllPossiblePermissions) {
-            let index = newPerms.indexOf(AllPossiblePermissions[idx]);
+            let permName = AllPossiblePermissions[idx];
+            let index = newPermNames.indexOf(permName);
             if (index == -1) {
-              // See if the permission was installed previously
-              let _perm = PermissionSettingsModule.getPermission(AllPossiblePermissions[idx],
-                                           aApp.manifestURL,
-                                           aApp.origin,
-                                           false);
-              if (_perm == "unknown" || _perm == "deny") {
+              // See if the permission was installed previously.
+              let permValue =
+                PermissionSettingsModule.getPermission(permName,
+                                                       aApp.manifestURL,
+                                                       aApp.origin,
+                                                       false);
+              if (permValue == "unknown" || permValue == "deny") {
                 // All 'deny' permissions should be preserved
                 continue;
               }
               // Remove the deprecated permission
               // TODO: use PermSettings.remove, see bug 793204
-              this._setPermission(AllPossiblePermissions[idx], "unknown", aApp);
+              this._setPermission(permName, "unknown", aApp);
             }
           }
         }
       }
 
-      let installPermType;
-      // Check to see if the 'webapp' is app/priv/certified
+      // Check to see if the 'webapp' is app/privileged/certified.
+      let appStatus;
       switch (AppsUtils.getAppManifestStatus(aApp.manifest)) {
       case Ci.nsIPrincipal.APP_STATUS_CERTIFIED:
-        installPermType = "certified";
+        appStatus = "certified";
         break;
       case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED:
-        installPermType = "privileged";
+        appStatus = "privileged";
         break;
       case Ci.nsIPrincipal.APP_STATUS_INSTALLED:
-        installPermType = "app";
+        appStatus = "app";
         break;
       default:
-        // Cannot determine app type, abort install by throwing an error
-        throw new Error("PermissionsInstaller.jsm: Cannot determine app type, install cancelled");
+        // Cannot determine app type, abort install by throwing an error.
+        throw new Error("PermissionsInstaller.jsm: " +
+                        "Cannot determine the app's status. Install cancelled.");
+        break;
       }
 
       for (let permName in newManifest.permissions) {
         if (!PermissionsTable[permName]) {
           Cu.reportError("PermissionsInstaller.jsm: '" + permName + "'" +
-                         " is not a valid Webapps permission type.");
+                         " is not a valid Webapps permission name.");
           dump("PermissionsInstaller.jsm: '" + permName + "'" +
-               " is not a valid Webapps permission type.");
+               " is not a valid Webapps permission name.");
           continue;
         }
 
-        let perms = expandPermissions(permName,
-                                      newManifest.permissions[permName].access);
-        for (let idx in perms) {
-          let perm = PermissionsTable[permName][installPermType];
-          let permValue = PERM_TO_STRING[perm];
-          this._setPermission(perms[idx], permValue, aApp);
+        let expandedPermNames =
+          expandPermissions(permName,
+                            newManifest.permissions[permName].access,
+                            newManifest.permissions[permName].channels);
+        for (let idx in expandedPermNames) {
+          this._setPermission(expandedPermNames[idx],
+                              PERM_TO_STRING[PermissionsTable[permName][appStatus]],
+                              aApp);
         }
       }
     }
     catch (ex) {
       dump("Caught webapps install permissions error for " + aApp.origin);
       Cu.reportError(ex);
       if (aOnError) {
         aOnError();
       }
     }
   },
 
   /**
-   * Set a permission value
-   * @param string aPerm
+   * Set a permission value.
+   * @param string aPermName
    *        The permission name.
-   * @param string aValue
+   * @param string aPermValue
    *        The permission value.
    * @param object aApp
    *        The just-installed app configuration.
-            The properties used are manifestURL, origin and manifest.
+   *        The properties used are manifestURL and origin.
    * @returns void
    **/
-  _setPermission: function setPermission(aPerm, aValue, aApp) {
-      PermissionSettingsModule.addPermission({
-        type: aPerm,
-        origin: aApp.origin,
-        manifestURL: aApp.manifestURL,
-        value: aValue,
-        browserFlag: false
-      });
-    }
+  _setPermission: function setPermission(aPermName, aPermValue, aApp) {
+    PermissionSettingsModule.addPermission({
+      type: aPermName,
+      origin: aApp.origin,
+      manifestURL: aApp.manifestURL,
+      value: aPermValue,
+      browserFlag: false
+    });
+  }
 };
--- a/dom/apps/src/Webapps.js
+++ b/dom/apps/src/Webapps.js
@@ -100,16 +100,22 @@ WebappsRegistry.prototype = {
     let request = this.createRequest();
     let requestID = this.getRequestId(request);
     let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
     xhr.open("GET", aURL, true);
     xhr.channel.loadFlags |= Ci.nsIRequest.VALIDATE_ALWAYS;
 
     xhr.addEventListener("load", (function() {
       if (xhr.status == 200) {
+        if (!AppsUtils.checkManifestContentType(installOrigin, this._getOrigin(aURL),
+                                                xhr.getResponseHeader("content-type"))) {
+          Services.DOMRequest.fireError(request, "INVALID_MANIFEST");
+          return;
+        }
+
         let manifest;
         try {
           manifest = JSON.parse(xhr.responseText, installOrigin);
         } catch (e) {
           Services.DOMRequest.fireError(request, "MANIFEST_PARSE_ERROR");
           Cu.reportError("Error installing app from: " + installOrigin + ": " + "MANIFEST_PARSE_ERROR");
           return;
         }
@@ -209,16 +215,22 @@ WebappsRegistry.prototype = {
     let categories = (aParams && aParams.categories &&
                       Array.isArray(aParams.categories)) ? aParams.categories : [];
     let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
     xhr.open("GET", aURL, true);
     xhr.channel.loadFlags |= Ci.nsIRequest.VALIDATE_ALWAYS;
 
     xhr.addEventListener("load", (function() {
       if (xhr.status == 200) {
+        if (!AppsUtils.checkManifestContentType(installOrigin, this._getOrigin(aURL),
+                                                xhr.getResponseHeader("content-type"))) {
+          Services.DOMRequest.fireError(request, "INVALID_MANIFEST");
+          return;
+        }
+
         let manifest;
         try {
           manifest = JSON.parse(xhr.responseText, installOrigin);
         } catch(e) {
           Services.DOMRequest.fireError(request, "MANIFEST_PARSE_ERROR");
           return;
         }
         if (!(AppsUtils.checkManifest(manifest) &&
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -13,16 +13,17 @@ this.EXPORTED_SYMBOLS = ["DOMApplication
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import('resource://gre/modules/ActivitiesService.jsm');
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 Cu.import("resource://gre/modules/PermissionsInstaller.jsm");
 Cu.import("resource://gre/modules/OfflineCacheInstaller.jsm");
+Cu.import("resource://gre/modules/SystemMessagePermissionsChecker.jsm");
 
 function debug(aMsg) {
   //dump("-*-*- Webapps.jsm : " + aMsg + "\n");
 }
 
 const WEBAPP_RUNTIME = Services.appinfo.ID == "webapprt@mozilla.org";
 
 XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
@@ -38,16 +39,21 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
 XPCOMUtils.defineLazyGetter(this, "msgmgr", function() {
   return Cc["@mozilla.org/system-message-internal;1"]
          .getService(Ci.nsISystemMessagesInternal);
 });
 
+XPCOMUtils.defineLazyGetter(this, "updateSvc", function() {
+  return Cc["@mozilla.org/offlinecacheupdate-service;1"]
+           .getService(Ci.nsIOfflineCacheUpdateService);
+});
+
 #ifdef MOZ_WIDGET_GONK
   const DIRECTORY_NAME = "webappsDir";
 #elifdef ANDROID
   const DIRECTORY_NAME = "webappsDir";
 #else
   // If we're executing in the context of the webapp runtime, the data files
   // are in a different directory (currently the Firefox profile that installed
   // the webapp); otherwise, they're in the current profile.
@@ -328,17 +334,23 @@ this.DOMApplicationRegistry = {
       let href = launchPath;
       let messageName;
       if (typeof(aMessage) === "object" && Object.keys(aMessage).length === 1) {
         messageName = Object.keys(aMessage)[0];
         href = Services.io.newURI(manifest.resolveFromOrigin(aMessage[messageName]), null, null);
       } else {
         messageName = aMessage;
       }
-      msgmgr.registerPage(messageName, href, manifestURL);
+
+      if (SystemMessagePermissionsChecker
+            .isSystemMessagePermittedToRegister(messageName,
+                                                aApp.origin,
+                                                aManifest)) {
+        msgmgr.registerPage(messageName, href, manifestURL);
+      }
     });
   },
 
   _registerSystemMessages: function(aManifest, aApp) {
     this._registerSystemMessagesForEntryPoint(aManifest, aApp, null);
 
     if (!aManifest.entry_points) {
       return;
@@ -375,17 +387,23 @@ this.DOMApplicationRegistry = {
                                     "name": activity,
                                     "title": manifest.name,
                                     "icon": manifest.iconURLForSize(128),
                                     "description": description });
       }
 
       let launchPath = Services.io.newURI(description.href, null, null);
       let manifestURL = Services.io.newURI(aApp.manifestURL, null, null);
-      msgmgr.registerPage("activity", launchPath, manifestURL);
+
+      if (SystemMessagePermissionsChecker
+            .isSystemMessagePermittedToRegister("activity",
+                                                aApp.origin,
+                                                aManifest)) {
+        msgmgr.registerPage("activity", launchPath, manifestURL);
+      }
     }
     return activitiesToRegister;
   },
 
   // |aAppsToRegister| contains an array of apps to be registered, where
   // each element is an object in the format of {manifest: foo, app: bar}.
   _registerActivitiesForApps: function(aAppsToRegister, aRunUpdate) {
     // Collect the activities to be registered for root and entry_points.
@@ -913,30 +931,29 @@ this.DOMApplicationRegistry = {
 
   startOfflineCacheDownload: function startOfflineCacheDownload(aManifest, aApp,
                                                                 aProfileDir,
                                                                 aOfflineCacheObserver,
                                                                 aIsUpdate) {
     // if the manifest has an appcache_path property, use it to populate the appcache
     if (aManifest.appcache_path) {
       let appcacheURI = Services.io.newURI(aManifest.fullAppcachePath(), null, null);
-      let updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"]
-                            .getService(Ci.nsIOfflineCacheUpdateService);
       let docURI = Services.io.newURI(aManifest.fullLaunchPath(), null, null);
       // We determine the app's 'installState' according to its previous
       // state. Cancelled download should remain as 'pending'. Successfully
       // installed apps should morph to 'updating'.
       if (aIsUpdate) {
         aApp.installState = "updating";
       }
       // We set the 'downloading' flag right before starting the app
       // download/update.
       aApp.downloading = true;
-      let cacheUpdate = aProfileDir ? updateService.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
-                                    : updateService.scheduleAppUpdate(appcacheURI, docURI, aApp.localId, false);
+      let cacheUpdate = aProfileDir
+        ? updateSvc.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
+        : updateSvc.scheduleAppUpdate(appcacheURI, docURI, aApp.localId, false);
       cacheUpdate.addObserver(new AppcacheObserver(aApp), false);
       if (aOfflineCacheObserver) {
         cacheUpdate.addObserver(aOfflineCacheObserver, false);
       }
     }
   },
 
   checkForUpdate: function(aData, aMm) {
@@ -979,16 +996,17 @@ this.DOMApplicationRegistry = {
         aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
       });
     }
 
     function updateHostedApp(aManifest) {
       debug("updateHostedApp " + aData.manifestURL);
       let id = this._appId(app.origin);
 
+      // Clean up the deprecated manifest cache if needed.
       if (id in this._manifestCache) {
         delete this._manifestCache[id];
       }
 
       // Update the web apps' registration.
       this.notifyAppsRegistryStart();
 #ifdef MOZ_SYS_MSG
       this._readManifests([{ id: id }], (function unregisterManifest(aResult) {
@@ -1019,26 +1037,40 @@ this.DOMApplicationRegistry = {
       app.csp = aManifest.csp || "";
       app.updateTime = Date.now();
 
       // Update the registry.
       this.webapps[id] = app;
 
       this._saveApps(function() {
         aData.app = app;
-        aData.event = manifest.appcache_path ? "downloadavailable"
-                                             : "downloadapplied";
-        aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
+        if (!manifest.appcache_path) {
+          aData.event = "downloadapplied";
+          aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
+        } else {
+          // Check if the appcache is updatable, and send "downloadavailable" or
+          // "downloadapplied".
+          let updateObserver = {
+            observe: function(aSubject, aTopic, aData) {
+              aData.event =
+                aTopic == "offline-cache-update-available" ? "downloadavailable"
+                                                           : "downloadapplied";
+              aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
+            }
+          }
+          updateSvc.checkForUpdate(Services.io.newURI(aData.manifestURL, null, null),
+                                   app.localId, false, updateObserver);
+        }
       });
 
       // Update the permissions for this app.
       PermissionsInstaller.installPermissions({ manifest: aManifest,
                                                 origin: app.origin,
                                                 manifestURL: aData.manifestURL },
-                                                true);
+                                              true);
     }
 
     // First, we download the manifest.
     let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
                 .createInstance(Ci.nsIXMLHttpRequest);
     xhr.open("GET", aData.manifestURL, true);
     xhr.responseType = "json";
     if (app.etag) {
--- a/dom/audiochannel/AudioChannelCommon.h
+++ b/dom/audiochannel/AudioChannelCommon.h
@@ -13,16 +13,17 @@ namespace dom {
 // The audio channel. Read the nsIHTMLMediaElement.idl for a description
 // about this attribute.
 enum AudioChannelType {
   AUDIO_CHANNEL_NORMAL = 0,
   AUDIO_CHANNEL_CONTENT,
   AUDIO_CHANNEL_NOTIFICATION,
   AUDIO_CHANNEL_ALARM,
   AUDIO_CHANNEL_TELEPHONY,
-  AUDIO_CHANNEL_PUBLICNOTIFICATION
+  AUDIO_CHANNEL_PUBLICNOTIFICATION,
+  AUDIO_CHANNEL_LAST
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
 
new file mode 100644
--- /dev/null
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -0,0 +1,275 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* 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/. */
+
+#include "AudioChannelService.h"
+#include "AudioChannelServiceChild.h"
+
+#include "base/basictypes.h"
+
+#include "mozilla/Services.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/unused.h"
+#include "mozilla/Util.h"
+
+#include "mozilla/dom/ContentParent.h"
+
+#include "base/basictypes.h"
+
+#include "nsThreadUtils.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+StaticRefPtr<AudioChannelService> gAudioChannelService;
+
+// static
+AudioChannelService*
+AudioChannelService::GetAudioChannelService()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    return AudioChannelServiceChild::GetAudioChannelService();
+  }
+
+  // If we already exist, exit early
+  if (gAudioChannelService) {
+    return gAudioChannelService;
+  }
+
+  // Create new instance, register, return
+  nsRefPtr<AudioChannelService> service = new AudioChannelService();
+  NS_ENSURE_TRUE(service, nullptr);
+
+  gAudioChannelService = service;
+  return gAudioChannelService;
+}
+
+void
+AudioChannelService::Shutdown()
+{
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    return AudioChannelServiceChild::Shutdown();
+  }
+
+  if (gAudioChannelService) {
+    delete gAudioChannelService;
+    gAudioChannelService = nullptr;
+  }
+}
+
+NS_IMPL_ISUPPORTS0(AudioChannelService)
+
+AudioChannelService::AudioChannelService()
+: mCurrentHigherChannel(AUDIO_CHANNEL_NORMAL)
+{
+  mChannelCounters = new int32_t[AUDIO_CHANNEL_PUBLICNOTIFICATION+1];
+
+  for (int i = AUDIO_CHANNEL_NORMAL;
+       i <= AUDIO_CHANNEL_PUBLICNOTIFICATION;
+       ++i) {
+    mChannelCounters[i] = 0;
+  }
+
+  // Creation of the hash table.
+  mMediaElements.Init();
+}
+
+AudioChannelService::~AudioChannelService()
+{
+  delete [] mChannelCounters;
+}
+
+void
+AudioChannelService::RegisterMediaElement(nsHTMLMediaElement* aMediaElement,
+                                          AudioChannelType aType)
+{
+  mMediaElements.Put(aMediaElement, aType);
+  RegisterType(aType);
+}
+
+void
+AudioChannelService::RegisterType(AudioChannelType aType)
+{
+  mChannelCounters[aType]++;
+
+  // In order to avoid race conditions, it's safer to notify any existing
+  // media element any time a new one is registered.
+  Notify();
+}
+
+void
+AudioChannelService::UnregisterMediaElement(nsHTMLMediaElement* aMediaElement)
+{
+  AudioChannelType type;
+  if (!mMediaElements.Get(aMediaElement, &type)) {
+    return;
+  }
+
+  mMediaElements.Remove(aMediaElement);
+  UnregisterType(type);
+}
+
+void
+AudioChannelService::UnregisterType(AudioChannelType aType)
+{
+  mChannelCounters[aType]--;
+  MOZ_ASSERT(mChannelCounters[aType] >= 0);
+
+  // In order to avoid race conditions, it's safer to notify any existing
+  // media element any time a new one is registered.
+  Notify();
+}
+
+bool
+AudioChannelService::GetMuted(AudioChannelType aType, bool aElementHidden)
+{
+  // We are not visible, maybe we have to mute:
+  if (aElementHidden) {
+    switch (aType) {
+      case AUDIO_CHANNEL_NORMAL:
+        return true;
+
+      case AUDIO_CHANNEL_CONTENT:
+        // TODO: this should work per apps
+        if (mChannelCounters[AUDIO_CHANNEL_CONTENT] > 1)
+          return true;
+        break;
+
+      case AUDIO_CHANNEL_NOTIFICATION:
+      case AUDIO_CHANNEL_ALARM:
+      case AUDIO_CHANNEL_TELEPHONY:
+      case AUDIO_CHANNEL_PUBLICNOTIFICATION:
+        // Nothing to do
+        break;
+
+      case AUDIO_CHANNEL_LAST:
+        MOZ_NOT_REACHED();
+        return false;
+    }
+  }
+
+  bool muted = false;
+
+  // Priorities:
+  switch (aType) {
+    case AUDIO_CHANNEL_NORMAL:
+    case AUDIO_CHANNEL_CONTENT:
+      muted = !!mChannelCounters[AUDIO_CHANNEL_NOTIFICATION] ||
+              !!mChannelCounters[AUDIO_CHANNEL_ALARM] ||
+              !!mChannelCounters[AUDIO_CHANNEL_TELEPHONY] ||
+              !!mChannelCounters[AUDIO_CHANNEL_PUBLICNOTIFICATION];
+
+    case AUDIO_CHANNEL_NOTIFICATION:
+    case AUDIO_CHANNEL_ALARM:
+    case AUDIO_CHANNEL_TELEPHONY:
+      muted = ChannelsActiveWithHigherPriorityThan(aType);
+
+    case AUDIO_CHANNEL_PUBLICNOTIFICATION:
+      break;
+
+    case AUDIO_CHANNEL_LAST:
+      MOZ_NOT_REACHED();
+      return false;
+  }
+
+  // Notification if needed.
+  if (!muted) {
+
+    // Calculating the most important unmuted channel:
+    AudioChannelType higher = AUDIO_CHANNEL_NORMAL;
+    for (int32_t type = AUDIO_CHANNEL_NORMAL;
+         type <= AUDIO_CHANNEL_PUBLICNOTIFICATION;
+         ++type) {
+      if (mChannelCounters[type]) {
+        higher = (AudioChannelType)type;
+      }
+    }
+
+    if (higher != mCurrentHigherChannel) {
+      mCurrentHigherChannel = higher;
+
+      nsString channelName;
+      channelName.AssignASCII(ChannelName(mCurrentHigherChannel));
+
+      nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+      obs->NotifyObservers(nullptr, "audio-channel-changed", channelName.get());
+    }
+  }
+
+  return muted;
+}
+
+
+static PLDHashOperator
+NotifyEnumerator(nsHTMLMediaElement* aElement,
+                 AudioChannelType aType, void* aData)
+{
+  if (aElement) {
+    aElement->NotifyAudioChannelStateChanged();
+  }
+  return PL_DHASH_NEXT;
+}
+
+void
+AudioChannelService::Notify()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // Notify any media element for the main process.
+  mMediaElements.EnumerateRead(NotifyEnumerator, nullptr);
+
+  // Notify for the child processes.
+  nsTArray<ContentParent*> children;
+  ContentParent::GetAll(children);
+  for (uint32_t i = 0; i < children.Length(); i++) {
+    unused << children[i]->SendAudioChannelNotify();
+  }
+}
+
+bool
+AudioChannelService::ChannelsActiveWithHigherPriorityThan(AudioChannelType aType)
+{
+  for (int i = AUDIO_CHANNEL_PUBLICNOTIFICATION;
+       i != AUDIO_CHANNEL_CONTENT; --i) {
+    if (i == aType) {
+      return false;
+    }
+
+    if (mChannelCounters[i]) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+const char*
+AudioChannelService::ChannelName(AudioChannelType aType)
+{
+  static struct {
+    int32_t type;
+    const char* value;
+  } ChannelNameTable[] = {
+    { AUDIO_CHANNEL_NORMAL,             "normal" },
+    { AUDIO_CHANNEL_CONTENT,            "normal" },
+    { AUDIO_CHANNEL_NOTIFICATION,       "notification" },
+    { AUDIO_CHANNEL_ALARM,              "alarm" },
+    { AUDIO_CHANNEL_TELEPHONY,          "telephony" },
+    { AUDIO_CHANNEL_PUBLICNOTIFICATION, "publicnotification" },
+    { -1,                               "unknown" }
+  };
+
+  for (int i = AUDIO_CHANNEL_NORMAL; ; ++i) {
+    if (ChannelNameTable[i].type == aType ||
+        ChannelNameTable[i].type == -1) {
+      return ChannelNameTable[i].value;
+    }
+  }
+
+  NS_NOTREACHED("Execution should not reach here!");
+  return nullptr;
+}
new file mode 100644
--- /dev/null
+++ b/dom/audiochannel/AudioChannelService.h
@@ -0,0 +1,83 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_audiochannelservice_h__
+#define mozilla_dom_audiochannelservice_h__
+
+#include "nsAutoPtr.h"
+#include "nsISupports.h"
+
+#include "AudioChannelCommon.h"
+#include "nsHTMLMediaElement.h"
+
+namespace mozilla {
+namespace dom {
+
+class AudioChannelService : public nsISupports
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  /**
+   * Returns the AudioChannelServce singleton. Only to be called from main thread.
+   * @return NS_OK on proper assignment, NS_ERROR_FAILURE otherwise.
+   */
+  static AudioChannelService*
+  GetAudioChannelService();
+
+  /**
+   * Shutdown the singleton.
+   */
+  static void Shutdown();
+
+  /**
+   * Any MediaElement that starts playing should register itself to
+   * this service, sharing the AudioChannelType.
+   */
+  virtual void RegisterMediaElement(nsHTMLMediaElement* aMediaElement,
+                                    AudioChannelType aType);
+
+  /**
+   * Any MediaElement that stops playing should unregister itself to
+   * this service.
+   */
+  virtual void UnregisterMediaElement(nsHTMLMediaElement* aMediaElement);
+
+  /**
+   * Return true if this type should be muted.
+   */
+  virtual bool GetMuted(AudioChannelType aType, bool aElementHidden);
+
+protected:
+  void Notify();
+
+  /* Register/Unregister IPC types: */
+  void RegisterType(AudioChannelType aType);
+  void UnregisterType(AudioChannelType aType);
+
+  AudioChannelService();
+  virtual ~AudioChannelService();
+
+  bool ChannelsActiveWithHigherPriorityThan(AudioChannelType aType);
+
+  const char* ChannelName(AudioChannelType aType);
+
+  nsDataHashtable< nsPtrHashKey<nsHTMLMediaElement>, AudioChannelType > mMediaElements;
+
+  int32_t* mChannelCounters;
+
+  AudioChannelType mCurrentHigherChannel;
+
+  // This is needed for IPC comunication between
+  // AudioChannelServiceChild and this class.
+  friend class ContentParent;
+  friend class ContentChild;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/audiochannel/AudioChannelServiceChild.cpp
@@ -0,0 +1,103 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* 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/. */
+
+#include "AudioChannelServiceChild.h"
+
+#include "base/basictypes.h"
+
+#include "mozilla/Services.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/unused.h"
+#include "mozilla/Util.h"
+
+#include "mozilla/dom/ContentChild.h"
+
+#include "base/basictypes.h"
+
+#include "nsThreadUtils.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+StaticRefPtr<AudioChannelServiceChild> gAudioChannelServiceChild;
+
+// static
+AudioChannelService*
+AudioChannelServiceChild::GetAudioChannelService()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // If we already exist, exit early
+  if (gAudioChannelServiceChild) {
+    return gAudioChannelServiceChild;
+  }
+
+  // Create new instance, register, return
+  nsRefPtr<AudioChannelServiceChild> service = new AudioChannelServiceChild();
+  NS_ENSURE_TRUE(service, nullptr);
+
+  gAudioChannelServiceChild = service;
+  return gAudioChannelServiceChild;
+}
+
+void
+AudioChannelServiceChild::Shutdown()
+{
+  if (gAudioChannelServiceChild) {
+    delete gAudioChannelServiceChild;
+    gAudioChannelServiceChild = nullptr;
+  }
+}
+
+AudioChannelServiceChild::AudioChannelServiceChild()
+{
+}
+
+AudioChannelServiceChild::~AudioChannelServiceChild()
+{
+}
+
+bool
+AudioChannelServiceChild::GetMuted(AudioChannelType aType, bool aMozHidden)
+{
+  ContentChild *cc = ContentChild::GetSingleton();
+  bool muted = false;
+
+  if (cc) {
+    cc->SendAudioChannelGetMuted(aType, aMozHidden, &muted);
+  }
+
+  return muted;
+}
+
+void
+AudioChannelServiceChild::RegisterMediaElement(nsHTMLMediaElement* aMediaElement,
+                                               AudioChannelType aType)
+{
+  AudioChannelService::RegisterMediaElement(aMediaElement, aType);
+
+  ContentChild *cc = ContentChild::GetSingleton();
+  if (cc) {
+    cc->SendAudioChannelRegisterType(aType);
+  }
+}
+
+void
+AudioChannelServiceChild::UnregisterMediaElement(nsHTMLMediaElement* aMediaElement)
+{
+  AudioChannelType type;
+  if (!mMediaElements.Get(aMediaElement, &type)) {
+    return;
+  }
+
+  AudioChannelService::UnregisterMediaElement(aMediaElement);
+
+  ContentChild *cc = ContentChild::GetSingleton();
+  if (cc) {
+    cc->SendAudioChannelUnregisterType(type);
+  }
+}
+
new file mode 100644
--- /dev/null
+++ b/dom/audiochannel/AudioChannelServiceChild.h
@@ -0,0 +1,51 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_audiochannelservicechild_h__
+#define mozilla_dom_audiochannelservicechild_h__
+
+#include "nsAutoPtr.h"
+#include "nsISupports.h"
+
+#include "AudioChannelService.h"
+#include "AudioChannelCommon.h"
+#include "nsHTMLMediaElement.h"
+
+namespace mozilla {
+namespace dom {
+
+class AudioChannelServiceChild : public AudioChannelService
+{
+public:
+
+  /**
+   * Returns the AudioChannelServce singleton. Only to be called from main thread.
+   * @return NS_OK on proper assignment, NS_ERROR_FAILURE otherwise.
+   */
+  static AudioChannelService*
+  GetAudioChannelService();
+
+  static void Shutdown();
+
+  virtual void RegisterMediaElement(nsHTMLMediaElement* aMediaElement,
+                                    AudioChannelType aType);
+  virtual void UnregisterMediaElement(nsHTMLMediaElement* aMediaElement);
+
+  /**
+   * Return true if this type + this mozHidden should be muted.
+   */
+  virtual bool GetMuted(AudioChannelType aType, bool aMozHidden);
+
+protected:
+  AudioChannelServiceChild();
+  virtual ~AudioChannelServiceChild();
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
+
--- a/dom/audiochannel/Makefile.in
+++ b/dom/audiochannel/Makefile.in
@@ -26,14 +26,21 @@ LIBXUL_LIBRARY = 1
 FORCE_STATIC_LIB = 1
 EXPORT_LIBRARY = 1
 FAIL_ON_WARNINGS := 1
 
 EXPORTS_NAMESPACES = \
   mozilla/dom \
   $(NULL)
 
-EXPORTS = AudioChannelCommon.h
+EXPORTS = AudioChannelService.h \
+          AudioChannelServiceChild.h \
+          AudioChannelCommon.h
+
+CPPSRCS += \
+  AudioChannelService.cpp \
+  AudioChannelServiceChild.cpp \
+  $(NULL)
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -7029,21 +7029,17 @@ nsGlobalWindow::CacheXBLPrototypeHandler
     NS_ASSERTION(participant,
                  "Failed to QI to nsXPCOMCycleCollectionParticipant!");
 
     nsISupports* thisSupports;
     QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
                    reinterpret_cast<void**>(&thisSupports));
     NS_ASSERTION(thisSupports, "Failed to QI to nsCycleCollectionISupports!");
 
-    nsresult rv = nsContentUtils::HoldJSObjects(thisSupports, participant);
-    if (NS_FAILED(rv)) {
-      NS_ERROR("nsContentUtils::HoldJSObjects failed!");
-      return;
-    }
+    nsContentUtils::HoldJSObjects(thisSupports, participant);
   }
 
   mCachedXBLPrototypeHandlers.Put(aKey, aHandler.get());
 }
 
 /**
  * GetScriptableFrameElement is called when script reads
  * nsIGlobalWindow::frameElement.
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -4128,17 +4128,21 @@ nsJSArgArray::nsJSArgArray(JSContext *aC
 
   // Callers are allowed to pass in a null argv even for argc > 0. They can
   // then use GetArgs to initialize the values.
   if (argv) {
     for (uint32_t i = 0; i < argc; ++i)
       mArgv[i] = argv[i];
   }
 
-  *prv = argc > 0 ? NS_HOLD_JS_OBJECTS(this, nsJSArgArray) : NS_OK;
+  if (argc > 0) {
+    NS_HOLD_JS_OBJECTS(this, nsJSArgArray);
+  }
+
+  *prv = NS_OK;
 }
 
 nsJSArgArray::~nsJSArgArray()
 {
   ReleaseJSObjects();
 }
 
 void
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -255,29 +255,27 @@ nsJSScriptTimeoutHandler::Init(nsGlobalW
                             *aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
 
           // Note: Our only caller knows to turn NS_ERROR_DOM_TYPE_ERR into NS_OK.
           return NS_ERROR_DOM_TYPE_ERR;
         }
       }
     } // if there's no document, we don't have to do anything.
 
-    rv = NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
-    NS_ENSURE_SUCCESS(rv, rv);
+    NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
 
     mExpr = expr;
 
     // Get the calling location.
     const char *filename;
     if (nsJSUtils::GetCallingLocation(cx, &filename, &mLineNo)) {
       mFileName.Assign(filename);
     }
   } else if (funobj) {
-    rv = NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
-    NS_ENSURE_SUCCESS(rv, rv);
+    NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
 
     mFunObj = funobj;
 
     // Create our arg array.  argc is the number of arguments passed
     // to setTimeout or setInterval; the first two are our callback
     // and the delay, so only arguments after that need to go in our
     // array.
     nsCOMPtr<nsIJSArgArray> array;
--- a/dom/camera/CameraRecorderProfiles.h
+++ b/dom/camera/CameraRecorderProfiles.h
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef DOM_CAMERA_CAMERA_RECORDER_PROFILES_H
 #define DOM_CAMERA_CAMERA_RECORDER_PROFILES_H
 
 #include "nsISupportsImpl.h"
+#include "nsMimeTypes.h"
 #include "nsAutoPtr.h"
 #include "nsTArray.h"
 #include "jsapi.h"
 #include "DictionaryHelpers.h"
 #include "CameraCommon.h"
 
 
 namespace mozilla {
@@ -117,16 +118,24 @@ public:
   const char* GetFileFormatName() const
   {
     switch (mFileFormat) {
       case THREE_GPP: return "3gp";
       case MPEG4:     return "mp4";
       default:        return nullptr;
     }
   }
+  const char* GetFileMimeType() const
+  {
+    switch (mFileFormat) {
+      case THREE_GPP: return VIDEO_3GPP;
+      case MPEG4:     return VIDEO_MP4;
+      default:        return nullptr;
+    }
+  }
 
   virtual nsresult GetJsObject(JSContext* aCx, JSObject** aObject) = 0;
 
 protected:
   virtual ~RecorderProfile();
 
   uint32_t mCameraId;
   uint32_t mQualityIndex;
--- a/dom/camera/DOMCameraPreview.cpp
+++ b/dom/camera/DOMCameraPreview.cpp
@@ -246,25 +246,30 @@ DOMCameraPreview::StopPreview()
   NS_ASSERTION(NS_IsMainThread(), "StopPreview() not called from main thread");
   if (mState != STARTED) {
     return;
   }
 
   DOM_CAMERA_LOGI("Stopping preview stream\n");
   mState = STOPPING;
   mCameraControl->StopPreview();
+  mInput->EndTrack(TRACK_VIDEO);
+  mInput->Finish();
 }
 
 void
 DOMCameraPreview::SetStateStopped()
 {
   NS_ASSERTION(NS_IsMainThread(), "SetStateStopped() not called from main thread");
 
-  mInput->EndTrack(TRACK_VIDEO);
-  mInput->Finish();
+  // see bug 809259 and bug 817367.
+  if (mState != STOPPING) {
+    mInput->EndTrack(TRACK_VIDEO);
+    mInput->Finish();
+  }
   mState = STOPPED;
   DOM_CAMERA_LOGI("Preview stream stopped\n");
 
   /**
    * Only remove the reference added in Start() once the preview
    * has stopped completely.
    */
   NS_RELEASE_THIS();
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -26,18 +26,18 @@
 #include "nsDOMClassInfo.h"
 #include "nsMemory.h"
 #include "jsapi.h"
 #include "nsThread.h"
 #include <media/MediaProfiles.h>
 #include "mozilla/FileUtils.h"
 #include "nsAlgorithm.h"
 #include <media/mediaplayer.h>
-#include "nsDirectoryServiceDefs.h" // for NS_GetSpecialDirectory
 #include "nsPrintfCString.h"
+#include "nsIObserverService.h"
 #include "DOMCameraManager.h"
 #include "GonkCameraHwMgr.h"
 #include "DOMCameraCapabilities.h"
 #include "DOMCameraControl.h"
 #include "GonkRecorderProfiles.h"
 #include "GonkCameraControl.h"
 #include "CameraCommon.h"
 
@@ -188,19 +188,19 @@ nsGonkCameraControl::nsGonkCameraControl
   , mHeight(0)
   , mLastPictureWidth(0)
   , mLastPictureHeight(0)
   , mFormat(PREVIEW_FORMAT_UNKNOWN)
   , mFps(30)
   , mDiscardedFrameCount(0)
   , mMediaProfiles(nullptr)
   , mRecorder(nullptr)
-  , mVideoFile()
   , mProfileManager(nullptr)
   , mRecorderProfile(nullptr)
+  , mVideoFile(nullptr)
 {
   // Constructor runs on the main thread...
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   mRwLock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "GonkCameraControl.Parameters.Lock");
 
   // ...but initialization is carried out on the camera thread.
   nsCOMPtr<nsIRunnable> init = new InitGonkCameraControl(this, aDOMCameraControl, onSuccess, onError, aWindowId);
   mCameraThread->Dispatch(init, NS_DISPATCH_NORMAL);
@@ -837,21 +837,27 @@ nsGonkCameraControl::StartRecordingImpl(
    * filename to it.  The filename may include a relative subpath
    * (e.g.) "DCIM/IMG_0001.jpg".
    *
    * The camera app needs to provide the file extension '.3gp' for now.
    * See bug 795202.
    */
   nsCOMPtr<nsIFile> filename = aStartRecording->mFolder;
   filename->AppendRelativePath(aStartRecording->mFilename);
+  mVideoFile = new DeviceStorageFile(NS_LITERAL_STRING("videos"), filename);
 
   nsAutoCString nativeFilename;
   filename->GetNativePath(nativeFilename);
   DOM_CAMERA_LOGI("Video filename is '%s'\n", nativeFilename.get());
 
+  if (!mVideoFile->IsSafePath()) {
+    DOM_CAMERA_LOGE("Invalid video file name\n");
+    return NS_ERROR_INVALID_ARG;
+  }
+
   ScopedClose fd(open(nativeFilename.get(), O_RDWR | O_CREAT, 0644));
   if (fd < 0) {
     DOM_CAMERA_LOGE("Couldn't create file '%s': (%d) %s\n", nativeFilename.get(), errno, strerror(errno));
     return NS_ERROR_FAILURE;
   }
 
   nsresult rv = SetupRecording(fd, aStartRecording->mOptions.rotation, aStartRecording->mOptions.maxFileSizeBytes, aStartRecording->mOptions.maxVideoLengthMs);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -859,23 +865,53 @@ nsGonkCameraControl::StartRecordingImpl(
   if (mRecorder->start() != OK) {
     DOM_CAMERA_LOGE("mRecorder->start() failed\n");
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
+class RecordingComplete : public nsRunnable
+{
+public:
+  RecordingComplete(DeviceStorageFile* aFile, nsACString& aType)
+    : mFile(aFile)
+    , mType(aType)
+  { }
+
+  ~RecordingComplete() { }
+
+  NS_IMETHOD Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsString data;
+    CopyASCIItoUTF16(mType, data);
+    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+    obs->NotifyObservers(mFile, "file-watcher-update", data.get());
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<DeviceStorageFile> mFile;
+  nsCString mType;
+};
+
 nsresult
 nsGonkCameraControl::StopRecordingImpl(StopRecordingTask* aStopRecording)
 {
   mRecorder->stop();
   delete mRecorder;
   mRecorder = nullptr;
-  return NS_OK;
+
+  // notify DeviceStorage that the new video file is closed and ready
+  nsCString type(mRecorderProfile->GetFileMimeType());
+  nsCOMPtr<nsIRunnable> recordingComplete = new RecordingComplete(mVideoFile, type);
+  return NS_DispatchToMainThread(recordingComplete, NS_DISPATCH_NORMAL);
 }
 
 void
 nsGonkCameraControl::AutoFocusComplete(bool aSuccess)
 {
   /**
    * Auto focusing can change some of the camera's parameters, so
    * we need to pull a new set before sending the result to the
--- a/dom/camera/GonkCameraControl.h
+++ b/dom/camera/GonkCameraControl.h
@@ -15,23 +15,23 @@
  */
 
 #ifndef DOM_CAMERA_GONKCAMERACONTROL_H
 #define DOM_CAMERA_GONKCAMERACONTROL_H
 
 #include "base/basictypes.h"
 #include "prrwlock.h"
 #include <media/MediaProfiles.h>
+#include "DeviceStorage.h"
 #include "nsIDOMCameraManager.h"
 #include "DOMCameraControl.h"
 #include "CameraControlImpl.h"
 #include "CameraCommon.h"
 #include "GonkRecorder.h"
 
-
 namespace mozilla {
 
 namespace layers {
 class GraphicBufferLocked;
 }
 
 class GonkRecorderProfile;
 class GonkRecorderProfileManager;
@@ -101,22 +101,22 @@ protected:
   uint32_t                  mFormat;
 
   uint32_t                  mFps;
   uint32_t                  mDiscardedFrameCount;
 
   android::MediaProfiles*   mMediaProfiles;
   android::GonkRecorder*    mRecorder;
 
-  nsString                  mVideoFile;
-
   // camcorder profile settings for the desired quality level
   nsRefPtr<GonkRecorderProfileManager> mProfileManager;
   nsRefPtr<GonkRecorderProfile> mRecorderProfile;
 
+  nsRefPtr<DeviceStorageFile> mVideoFile;
+
 private:
   nsGonkCameraControl(const nsGonkCameraControl&) MOZ_DELETE;
   nsGonkCameraControl& operator=(const nsGonkCameraControl&) MOZ_DELETE;
 };
 
 // camera driver callbacks
 void ReceiveImage(nsGonkCameraControl* gc, uint8_t* aData, uint32_t aLength);
 void AutoFocusComplete(nsGonkCameraControl* gc, bool aSuccess);
--- a/dom/devicestorage/DeviceStorage.h
+++ b/dom/devicestorage/DeviceStorage.h
@@ -6,16 +6,48 @@
 #define DeviceStorage_h
 
 #include "nsIDOMDeviceStorage.h"
 #include "nsIFile.h"
 #include "nsIPrincipal.h"
 #include "nsIObserver.h"
 #include "nsDOMEventTargetHelper.h"
 
+class DeviceStorageFile MOZ_FINAL
+  : public nsISupports {
+public:
+  nsCOMPtr<nsIFile> mFile;
+  nsString mPath;
+  nsString mStorageType;
+  bool mEditable;
+
+  DeviceStorageFile(const nsAString& aStorageType, nsIFile* aFile, const nsAString& aPath);
+  DeviceStorageFile(const nsAString& aStorageType, nsIFile* aFile);
+  void SetPath(const nsAString& aPath);
+  void SetEditable(bool aEditable);
+
+  NS_DECL_ISUPPORTS
+
+  // we want to make sure that the names of file can't reach
+  // outside of the type of storage the user asked for.
+  bool IsSafePath();
+
+  nsresult Remove();
+  nsresult Write(nsIInputStream* aInputStream);
+  nsresult Write(InfallibleTArray<uint8_t>& bits);
+  void CollectFiles(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, PRTime aSince = 0);
+  void collectFilesInternal(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, PRTime aSince, nsAString& aRootPath);
+
+  static void DirectoryDiskUsage(nsIFile* aFile, uint64_t* aSoFar, const nsAString& aStorageType);
+
+private:
+  void NormalizeFilePath();
+  void AppendRelativePath();
+};
+
 class nsDOMDeviceStorage MOZ_FINAL
   : public nsIDOMDeviceStorage
   , public nsDOMEventTargetHelper
   , public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMDEVICESTORAGE
--- a/dom/devicestorage/nsDeviceStorage.h
+++ b/dom/devicestorage/nsDeviceStorage.h
@@ -67,48 +67,16 @@ public:
 private:
   nsString mPicturesExtensions;
   nsString mVideosExtensions;
   nsString mMusicExtensions;
 
   static nsAutoPtr<DeviceStorageTypeChecker> sDeviceStorageTypeChecker;
 };
 
-class DeviceStorageFile MOZ_FINAL
-  : public nsISupports {
-public:
-  nsCOMPtr<nsIFile> mFile;
-  nsString mPath;
-  nsString mStorageType;
-  bool mEditable;
-
-  DeviceStorageFile(const nsAString& aStorageType, nsIFile* aFile, const nsAString& aPath);
-  DeviceStorageFile(const nsAString& aStorageType, nsIFile* aFile);
-  void SetPath(const nsAString& aPath);
-  void SetEditable(bool aEditable);
-
-  NS_DECL_ISUPPORTS
-
-  // we want to make sure that the names of file can't reach
-  // outside of the type of storage the user asked for.
-  bool IsSafePath();
-
-  nsresult Remove();
-  nsresult Write(nsIInputStream* aInputStream);
-  nsresult Write(InfallibleTArray<uint8_t>& bits);
-  void CollectFiles(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, PRTime aSince = 0);
-  void collectFilesInternal(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, PRTime aSince, nsAString& aRootPath);
-
-  static void DirectoryDiskUsage(nsIFile* aFile, uint64_t* aSoFar, const nsAString& aStorageType);
-
-private:
-  void NormalizeFilePath();
-  void AppendRelativePath();
-};
-
 class ContinueCursorEvent MOZ_FINAL : public nsRunnable
 {
 public:
   ContinueCursorEvent(nsRefPtr<mozilla::dom::DOMRequest>& aRequest);
   ContinueCursorEvent(mozilla::dom::DOMRequest* aRequest);
   ~ContinueCursorEvent();
   void Continue();
 
--- a/dom/identity/DOMIdentity.jsm
+++ b/dom/identity/DOMIdentity.jsm
@@ -6,17 +6,17 @@
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 // This is the parent process corresponding to nsDOMIdentity.
 this.EXPORTED_SYMBOLS = ["DOMIdentity"];
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/IdentityUtils.jsm");
+Cu.import("resource://gre/modules/identity/IdentityUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "IdentityService",
 #ifdef MOZ_B2G_VERSION
                                   "resource://gre/modules/identity/MinimalIdentity.jsm");
 #else
                                   "resource://gre/modules/identity/Identity.jsm");
 #endif
 
--- a/dom/identity/nsDOMIdentity.js
+++ b/dom/identity/nsDOMIdentity.js
@@ -11,17 +11,17 @@ const PREF_ENABLED = "dom.identity.enabl
 
 // Maximum length of a string that will go through IPC
 const MAX_STRING_LENGTH = 2048;
 // Maximum number of times navigator.id.request can be called for a document
 const MAX_RP_CALLS = 100;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/IdentityUtils.jsm");
+Cu.import("resource://gre/modules/identity/IdentityUtils.jsm");
 
 // This is the child process corresponding to nsIDOMIdentity
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
 function nsDOMIdentity(aIdentityInternal) {
   this._identityInternal = aIdentityInternal;
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -316,20 +316,17 @@ IDBCursor::CreateCommon(IDBRequest* aReq
                "Empty query!");
 
   nsRefPtr<IDBCursor> cursor = new IDBCursor();
 
   IDBDatabase* database = aTransaction->Database();
   cursor->mScriptOwner = database->GetScriptOwner();
 
   if (cursor->mScriptOwner) {
-    if (NS_FAILED(NS_HOLD_JS_OBJECTS(cursor, IDBCursor))) {
-      return nullptr;
-    }
-
+    NS_HOLD_JS_OBJECTS(cursor, IDBCursor);
     cursor->mRooted = true;
   }
 
   cursor->mRequest = aRequest;
   cursor->mTransaction = aTransaction;
   cursor->mObjectStore = aObjectStore;
   cursor->mDirection = aDirection;
   cursor->mContinueQuery = aContinueQuery;
--- a/dom/indexedDB/IDBWrapperCache.cpp
+++ b/dom/indexedDB/IDBWrapperCache.cpp
@@ -50,22 +50,17 @@ IDBWrapperCache::SetScriptOwner(JSObject
 {
   NS_ASSERTION(aScriptOwner, "This should never be null!");
 
   mScriptOwner = aScriptOwner;
 
   nsISupports* thisSupports = NS_CYCLE_COLLECTION_UPCAST(this, IDBWrapperCache);
   nsXPCOMCycleCollectionParticipant* participant;
   CallQueryInterface(this, &participant);
-  nsresult rv = nsContentUtils::HoldJSObjects(thisSupports, participant);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("nsContentUtils::HoldJSObjects failed.");
-    mScriptOwner = nullptr;
-    return false;
-  }
+  nsContentUtils::HoldJSObjects(thisSupports, participant);
 
   return true;
 }
 
 #ifdef DEBUG
 void
 IDBWrapperCache::AssertIsRooted() const
 {
--- a/dom/interfaces/html/nsIDOMHTMLMediaElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLMediaElement.idl
@@ -22,17 +22,17 @@ interface nsIDOMMediaStream;
 
 // undef the GetCurrentTime macro defined in WinBase.h from the MS Platform SDK
 %{C++
 #ifdef GetCurrentTime
 #undef GetCurrentTime
 #endif
 %}
 
-[scriptable, uuid(efa52d52-a876-486f-8739-87e1a13bc42d)]
+[scriptable, uuid(75ccaaec-6920-43ae-a56f-ee7a693f3d31)]
 interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
 {
   // error state
   readonly attribute nsIDOMMediaError error;
 
   // network state
            attribute DOMString src;
   [implicit_jscontext] attribute jsval mozSrcObject;
@@ -136,11 +136,15 @@ interface nsIDOMHTMLMediaElement : nsIDO
    //   played.
    //   User case: Alarm clock, calendar alarms
    // * telephony
    //   Automatically paused if "publicnotification" or higher priority
    //   channel is played.
    //   Use case: dialer, voip
    // * publicnotification
    //   Always plays in speaker, even when headphones are plugged in.
+   attribute DOMString mozAudioChannelType;
 
-   attribute DOMString mozAudioChannelType;
+  // In addition the media element has this new events:
+  // * onmozinterruptbegin - called when the media element is interrupted
+  //   because of the audiochannel manager.
+  // * onmozinterruptend - called when the interruption is concluded
 };
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -93,16 +93,17 @@
 #include "nsIRemoteBlob.h"
 #include "ProcessUtils.h"
 #include "StructuredCloneUtils.h"
 #include "URIUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsContentUtils.h"
 #include "nsIPrincipal.h"
 #include "nsDeviceStorage.h"
+#include "AudioChannelService.h"
 
 using namespace base;
 using namespace mozilla::docshell;
 using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::sms;
 using namespace mozilla::dom::indexedDB;
 using namespace mozilla::hal_sandbox;
@@ -427,16 +428,27 @@ ContentChild::RecvPMemoryReportRequestCo
       r->CollectReports(cb, wrappedReports);
     }
 
     child->Send__delete__(child, reports);
     return true;
 }
 
 bool
+ContentChild::RecvAudioChannelNotify()
+{
+    nsRefPtr<AudioChannelService> service =
+        AudioChannelService::GetAudioChannelService();
+    if (service) {
+        service->Notify();
+    }
+    return true;
+}
+
+bool
 ContentChild::DeallocPMemoryReportRequest(PMemoryReportRequestChild* actor)
 {
     delete actor;
     return true;
 }
 
 bool
 ContentChild::RecvDumpMemoryReportsToFile(const nsString& aIdentifier,
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -107,16 +107,19 @@ public:
 
     virtual bool
     DeallocPMemoryReportRequest(PMemoryReportRequestChild* actor);
 
     virtual bool
     RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* child);
 
     virtual bool
+    RecvAudioChannelNotify();
+
+    virtual bool
     RecvDumpMemoryReportsToFile(const nsString& aIdentifier,
                                 const bool& aMinimizeMemoryUsage,
                                 const bool& aDumpChildProcesses);
     virtual bool
     RecvDumpGCAndCCLogsToFile(const nsString& aIdentifier,
                               const bool& aDumpChildProcesses);
 
     virtual PTestShellChild* AllocPTestShell();
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -11,16 +11,17 @@
 #if defined(ANDROID) || defined(LINUX)
 # include <sys/time.h>
 # include <sys/resource.h>
 #endif
 
 #include "chrome/common/process_watcher.h"
 
 #include "AppProcessPermissions.h"
+#include "AudioChannelService.h"
 #include "CrashReporterParent.h"
 #include "IHistory.h"
 #include "IDBFactory.h"
 #include "IndexedDBParent.h"
 #include "IndexedDatabaseManager.h"
 #include "mozIApplication.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/ExternalHelperAppParent.h"
@@ -1006,16 +1007,52 @@ ContentParent::RecvFirstIdle()
     // When the ContentChild goes idle, it sends us a FirstIdle message
     // which we use as a good time to prelaunch another process. If we
     // prelaunch any sooner than this, then we'll be competing with the
     // child process and slowing it down.
     ScheduleDelayedPreallocateAppProcess();
     return true;
 }
 
+bool
+ContentParent::RecvAudioChannelGetMuted(const AudioChannelType& aType,
+                                        const bool& aMozHidden,
+                                        bool* aValue)
+{
+    nsRefPtr<AudioChannelService> service =
+        AudioChannelService::GetAudioChannelService();
+    *aValue = false;
+    if (service) {
+        *aValue = service->GetMuted(aType, aMozHidden);
+    }
+    return true;
+}
+
+bool
+ContentParent::RecvAudioChannelRegisterType(const AudioChannelType& aType)
+{
+    nsRefPtr<AudioChannelService> service =
+        AudioChannelService::GetAudioChannelService();
+    if (service) {
+        service->RegisterType(aType);
+    }
+    return true;
+}
+
+bool
+ContentParent::RecvAudioChannelUnregisterType(const AudioChannelType& aType)
+{
+    nsRefPtr<AudioChannelService> service =
+        AudioChannelService::GetAudioChannelService();
+    if (service) {
+        service->UnregisterType(aType);
+    }
+    return true;
+}
+
 NS_IMPL_THREADSAFE_ISUPPORTS3(ContentParent,
                               nsIObserver,
                               nsIThreadObserver,
                               nsIDOMGeoPositionCallback)
 
 NS_IMETHODIMP
 ContentParent::Observe(nsISupports* aSubject,
                        const char* aTopic,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -256,29 +256,29 @@ private:
     virtual bool RecvStartVisitedQuery(const URIParams& uri);
 
     virtual bool RecvVisitURI(const URIParams& uri,
                               const OptionalURIParams& referrer,
                               const uint32_t& flags);
 
     virtual bool RecvSetURITitle(const URIParams& uri,
                                  const nsString& title);
-    
+
     virtual bool RecvShowFilePicker(const int16_t& mode,
                                     const int16_t& selectedType,
                                     const bool& addToRecentDocs,
                                     const nsString& title,
                                     const nsString& defaultFile,
                                     const nsString& defaultExtension,
                                     const InfallibleTArray<nsString>& filters,
                                     const InfallibleTArray<nsString>& filterNames,
                                     InfallibleTArray<nsString>* files,
                                     int16_t* retValue,
                                     nsresult* result);
- 
+
     virtual bool RecvShowAlertNotification(const nsString& aImageUrl, const nsString& aTitle,
                                            const nsString& aText, const bool& aTextClickable,
                                            const nsString& aCookie, const nsString& aName);
 
     virtual bool RecvLoadURIExternal(const URIParams& uri);
 
     virtual bool RecvSyncMessage(const nsString& aMsg,
                                  const ClonedMessageData& aData,
@@ -297,16 +297,23 @@ private:
                                  const uint32_t& aColNumber,
                                  const uint32_t& aFlags,
                                  const nsCString& aCategory);
 
     virtual bool RecvPrivateDocShellsExist(const bool& aExist);
 
     virtual bool RecvFirstIdle();
 
+    virtual bool RecvAudioChannelGetMuted(const AudioChannelType& aType,
+                                          const bool& aMozHidden,
+                                          bool* aValue);
+
+    virtual bool RecvAudioChannelRegisterType(const AudioChannelType& aType);
+    virtual bool RecvAudioChannelUnregisterType(const AudioChannelType& aType);
+
     virtual void ProcessingError(Result what) MOZ_OVERRIDE;
 
     GeckoChildProcessHost* mSubprocess;
     ChildOSPrivileges mOSPrivileges;
 
     uint64_t mChildID;
     int32_t mGeolocationWatchID;
     int mRunToCompletionDepth;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -33,16 +33,17 @@ using GeoPosition;
 using PrefTuple;
 
 using ChromePackage;
 using ResourceMapping;
 using OverrideMapping;
 using IPC::Permission;
 using mozilla::null_t;
 using mozilla::void_t;
+using mozilla::dom::AudioChannelType;
 using mozilla::dom::NativeThreadId;
 using mozilla::layout::ScrollingBehavior;
 using gfxIntSize;
 
 namespace mozilla {
 namespace dom {
 
 // Data required to clone an existing DOMStorageImpl in the parent
@@ -260,16 +261,21 @@ both:
     async PBrowser(IPCTabContext context, uint32_t chromeFlags);
 
     async PBlob(BlobConstructorParams params);
 
 child:
     PMemoryReportRequest();
 
     /**
+     * Notify the AudioChannelService in the child processes.
+     */
+    async AudioChannelNotify();
+
+    /**
      * Dump the contents of about:memory to a file in our temp directory.
      *
      * For documentation on the args, see
      * MemoryInfoDumper::dumpMemoryReportsToFile.
      */
     async DumpMemoryReportsToFile(nsString identifier,
                                   bool minimizeMemoryUsage,
                                   bool dumpChildProcesses);
@@ -419,14 +425,21 @@ parent:
         returns (bool showPassword);
 
     // Notify the parent of the presence or absence of private docshells
     PrivateDocShellsExist(bool aExist);
 
     // Tell the parent that the child has gone idle for the first time
     async FirstIdle();
 
+    // Get Muted from the main AudioChannelService.
+    sync AudioChannelGetMuted(AudioChannelType aType, bool aMozHidden)
+        returns (bool value);
+
+    async AudioChannelRegisterType(AudioChannelType aType);
+    async AudioChannelUnregisterType(AudioChannelType aType);
+
 both:
      AsyncMessage(nsString aMessage, ClonedMessageData aData);
 };
 
 }
 }
--- a/dom/ipc/TabMessageUtils.h
+++ b/dom/ipc/TabMessageUtils.h
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 TABMESSAGE_UTILS_H
 #define TABMESSAGE_UTILS_H
 
+#include "AudioChannelCommon.h"
 #include "ipc/IPCMessageUtils.h"
 #include "nsIDOMEvent.h"
 #include "nsCOMPtr.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
@@ -51,12 +52,19 @@ struct ParamTraits<mozilla::dom::RemoteD
     return mozilla::dom::ReadRemoteEvent(aMsg, aIter, aResult);
   }
 
   static void Log(const paramType& aParam, std::wstring* aLog)
   {
   }
 };
 
+template <>
+struct ParamTraits<mozilla::dom::AudioChannelType>
+  : public EnumSerializer<mozilla::dom::AudioChannelType,
+                          mozilla::dom::AUDIO_CHANNEL_NORMAL,
+                          mozilla::dom::AUDIO_CHANNEL_LAST>
+{ };
+
 }
 
 
 #endif
--- a/dom/locales/en-US/chrome/nsWebBrowserPersist.properties
+++ b/dom/locales/en-US/chrome/nsWebBrowserPersist.properties
@@ -3,13 +3,14 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 readError=%S could not be saved, because the source file could not be read.\n\nTry again later, or contact the server administrator.
 writeError=%S could not be saved, because an unknown error occurred.\n\nTry saving to a different location.
 launchError=%S could not be opened, because an unknown error occurred.\n\nTry saving to disk first and then opening the file.
 diskFull=There is not enough room on the disk to save %S.\n\nRemove unnecessary files from the disk and try again, or try saving in a different location.
 readOnly=%S could not be saved, because the disk, folder, or file is write-protected.\n\nWrite-enable the disk and try again, or try saving in a different location.
 accessError=%S could not be saved, because you cannot change the contents of that folder.\n\nChange the folder properties and try again, or try saving in a different location.
+accessErrorSD=No SD card.\n\nAn SD card is required to download %S.
 helperAppNotFound=%S could not be opened, because the associated helper application does not exist. Change the association in your preferences.
 noMemory=There is not sufficient memory to complete the action you requested.\n\nQuit some applications and try again.
 title=Downloading %S
 fileAlreadyExistsError=%S could not be saved, because a file already exists with the same name as the '_files' directory.\n\nTry saving to a different location.
 fileNameTooLongError=%S could not be saved, because the file name was too long.\n\nTry saving with a shorter file name.
--- a/dom/media/tests/mochitest/Makefile.in
+++ b/dom/media/tests/mochitest/Makefile.in
@@ -5,19 +5,25 @@
 DEPTH = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 relativesrcdir = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-# TODO: When bug 814718 and bug 814721 are fixed, add the following files:
-#          test_getUserMedia_basicVideo.html
-#          test_getUserMedia_basicAudio.thml
-#          test_getUserMedia_basicVideoAudio.html
-#          mediaStreamPlayback.js
 MOCHITEST_FILES = \
   test_getUserMedia_exceptions.html \
   head.js \
   $(NULL)
 
+# The following tests are leaking and cannot be run by default yet
+ifdef MOZ_WEBRTC_LEAKING_TESTS
+MOCHITEST_FILES += \
+# Bug 814718 and bug 818466 prevent us from running the following tests:
+#  test_getUserMedia_basicVideo.html \
+#  test_getUserMedia_basicAudio.html \
+#  test_getUserMedia_basicVideoAudio.html \
+#  mediaStreamPlayback.js \
+  $(NULL)
+endif
+
 include $(topsrcdir)/config/rules.mk
--- a/dom/messages/Makefile.in
+++ b/dom/messages/Makefile.in
@@ -14,9 +14,13 @@ include $(DEPTH)/config/autoconf.mk
 PARALLEL_DIRS = interfaces
 
 EXTRA_COMPONENTS = \
   SystemMessageManager.js \
   SystemMessageInternal.js \
   SystemMessageManager.manifest \
   $(NULL)
 
+EXTRA_JS_MODULES += \
+  SystemMessagePermissionsChecker.jsm \
+  $(NULL)
+
 include $(topsrcdir)/config/rules.mk
--- a/dom/messages/SystemMessageInternal.js
+++ b/dom/messages/SystemMessageInternal.js
@@ -6,16 +6,17 @@
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 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/SystemMessagePermissionsChecker.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIMessageBroadcaster");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
                                    "@mozilla.org/uuid-generator;1",
                                    "nsIUUIDGenerator");
@@ -76,26 +77,25 @@ SystemMessageInternal.prototype = {
     }
 
     // Give this message an ID so that we can identify the message and
     // clean it up from the pending message queue when apps receive it.
     let messageID = gUUIDGenerator.generateUUID().toString();
 
     debug("Sending " + aType + " " + JSON.stringify(aMessage) +
       " for " + aPageURI.spec + " @ " + aManifestURI.spec);
-    if (this._listeners[aManifestURI.spec]) {
-      let manifest = this._listeners[aManifestURI.spec];
-      for (let winID in manifest) {
-        manifest[winID].sendAsyncMessage("SystemMessageManager:Message",
-                                         { type: aType,
-                                           msg: aMessage,
-                                           manifest: aManifestURI.spec,
-                                           uri: aPageURI.spec,
-                                           msgID: messageID });
-      }
+
+    // Don't need to open the pages and queue the system message
+    // which was not allowed to be sent.
+    if (!this._sendMessageCommon(aType,
+                                 aMessage,
+                                 messageID,
+                                 aPageURI.spec,
+                                 aManifestURI.spec)) {
+      return;
     }
 
     let pagesToOpen = {};
     this._pages.forEach(function(aPage) {
       if (!this._isPageMatched(aPage, aType, aPageURI.spec, aManifestURI.spec)) {
         return;
       }
 
@@ -126,27 +126,26 @@ SystemMessageInternal.prototype = {
     // clean it up from the pending message queue when apps receive it.
     let messageID = gUUIDGenerator.generateUUID().toString();
 
     debug("Broadcasting " + aType + " " + JSON.stringify(aMessage));
     // Find pages that registered an handler for this type.
     let pagesToOpen = {};
     this._pages.forEach(function(aPage) {
       if (aPage.type == aType) {
-        if (this._listeners[aPage.manifest]) {
-          let manifest = this._listeners[aPage.manifest];
-          for (let winID in manifest) {
-            manifest[winID].sendAsyncMessage("SystemMessageManager:Message",
-                                             { type: aType,
-                                               msg: aMessage,
-                                               manifest: aPage.manifest,
-                                               uri: aPage.uri,
-                                               msgID: messageID });
-          }
+        // Don't need to open the pages and queue the system message
+        // which was not allowed to be sent.
+        if (!this._sendMessageCommon(aType,
+                                     aMessage,
+                                     messageID,
+                                     aPage.uri,
+                                     aPage.manifest)) {
+          return;
         }
+
         // Queue this message in the corresponding pages.
         this._queueMessage(aPage, aMessage, messageID);
 
         // Open app pages to handle their pending messages.
         // Note that we only need to open each app page once.
         let key = this._createKeyForPage(aPage);
         if (!pagesToOpen.hasOwnProperty(key)) {
           this._openAppPage(aPage, aMessage);
@@ -337,20 +336,20 @@ SystemMessageInternal.prototype = {
     let page = { uri: aPage.uri,
                  manifest: aPage.manifest,
                  type: aPage.type,
                  target: aMessage.target };
     debug("Asking to open " + JSON.stringify(page));
     Services.obs.notifyObservers(this, "system-messages-open-app", JSON.stringify(page));
   },
 
-  _isPageMatched: function _isPageMatched(aPage, aType, aUri, aManifest) {
+  _isPageMatched: function _isPageMatched(aPage, aType, aPageURI, aManifestURI) {
     return (aPage.type === aType &&
-            aPage.manifest === aManifest &&
-            aPage.uri === aUri)
+            aPage.manifest === aManifestURI &&
+            aPage.uri === aPageURI)
   },
 
   _createKeyForPage: function _createKeyForPage(aPage) {
     let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
                       .createInstance(Ci.nsIScriptableUnicodeConverter);
     converter.charset = "UTF-8";
 
     let hasher = Cc["@mozilla.org/security/hash;1"]
@@ -361,14 +360,39 @@ SystemMessageInternal.prototype = {
     ["type", "manifest", "uri"].forEach(function(aProp) {
       let data = converter.convertToByteArray(aPage[aProp], {});
       hasher.update(data, data.length);
     });
 
     return hasher.finish(true);
   },
 
+  _sendMessageCommon:
+    function _sendMessageCommon(aType, aMessage, aMessageID, aPageURI, aManifestURI) {
+    // Don't send the system message not granted by the app's permissions.
+    if (!SystemMessagePermissionsChecker
+          .isSystemMessagePermittedToSend(aType,
+                                          aPageURI,
+                                          aManifestURI)) {
+      return false;
+    }
+
+    let winTargets = this._listeners[aManifestURI];
+    if (winTargets) {
+      for (let winID in winTargets) {
+        winTargets[winID].sendAsyncMessage("SystemMessageManager:Message",
+                                           { type: aType,
+                                             msg: aMessage,
+                                             manifest: aManifestURI,
+                                             uri: aPageURI,
+                                             msgID: aMessageID });
+      }
+    }
+
+    return true;
+  },
+
   classID: Components.ID("{70589ca5-91ac-4b9e-b839-d6a88167d714}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesInternal, Ci.nsIObserver])
 }
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SystemMessageInternal]);
--- a/dom/messages/SystemMessageManager.js
+++ b/dom/messages/SystemMessageManager.js
@@ -198,17 +198,17 @@ SystemMessageManager.prototype = {
 
     debug("done");
   },
 
   observe: function sysMessMgr_observe(aSubject, aTopic, aData) {
     if (aTopic === kSystemMessageInternalReady) {
       this._registerManifest();
     }
-    //call the DOMRequestIpcHelper.observe method
+    // Call the DOMRequestIpcHelper.observe method.
     this.__proto__.__proto__.observe.call(this, aSubject, aTopic, aData);
   },
 
   _registerManifest: function sysMessMgr_registerManifest() {
     if (!this._registerManifestReady) {
       cpmm.sendAsyncMessage("SystemMessageManager:Register",
                             { manifest: this._manifest,
                               innerWindowID: this.innerWindowID
new file mode 100644
--- /dev/null
+++ b/dom/messages/SystemMessagePermissionsChecker.jsm
@@ -0,0 +1,254 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/AppsUtils.jsm");
+Cu.import("resource://gre/modules/PermissionsInstaller.jsm");
+Cu.import("resource://gre/modules/PermissionSettings.jsm");
+
+this.EXPORTED_SYMBOLS = ["SystemMessagePermissionsChecker",
+                         "SystemMessagePermissionsTable"];
+
+function debug(aStr) {
+  // dump("SystemMessagePermissionsChecker.jsm: " + aStr + "\n");
+}
+
+// This table maps system message to permission(s), indicating only
+// the system messages granted by the page's permissions are allowed
+// to be registered or sent to that page. Note the empty permission
+// set means this type of system message is always permitted.
+
+this.SystemMessagePermissionsTable = {
+  "activity": { },
+  "alarm": {
+    "alarms": []
+  },
+  "bluetooth-dialer-command": {
+    "telephony": []
+  },
+  "bluetooth-requestconfirmation": {
+    "bluetooth": []
+  },
+  "bluetooth-requestpasskey": {
+    "bluetooth": []
+  },
+  "bluetooth-requestpincode": {
+    "bluetooth": []
+  },
+  "bluetooth-authorize": {
+    "bluetooth": []
+  },
+  "bluetooth-cancel": {
+    "bluetooth": []
+  },
+  "bluetooth-pairedstatuschanged": {
+    "bluetooth": []
+  },
+  "bluetooth-hfp-status-changed": {
+    "bluetooth": []
+  },
+  "bluetooth-opp-transfer-complete": {
+    "bluetooth": []
+  },
+  "bluetooth-opp-update-progress": {
+    "bluetooth": []
+  },
+  "bluetooth-opp-receiving-file-confirmation": {
+    "bluetooth": []
+  },
+  "bluetooth-opp-transfer-start": {
+    "bluetooth": []
+  },
+  "headset-button": { },
+  "icc-stkcommand": {
+    "settings": ["read", "write"]
+  },
+  "notification": {
+    "desktop-notification": []
+  },
+  "sms-received": {
+    "sms": []
+  },
+  "telephony-new-call": {
+    "telephony": []
+  }
+};
+
+this.SystemMessagePermissionsChecker = {
+  /**
+   * Return all the needed permission names for the given system message.
+   * @param string aSysMsgName
+   *        The system messsage name.
+   * @returns object
+   *        Format: { permName (string): permNamesWithAccess (string array), ... }
+   *        Ex, { "settings": ["settings-read", "settings-write"], ... }.
+   *        Note: an empty object will be returned if it's always permitted.
+   * @returns null
+   *        Return and report error when any unexpected error is ecountered.
+   *        Ex, when the system message we want to search is not included.
+   **/
+  getSystemMessagePermissions: function getSystemMessagePermissions(aSysMsgName) {
+    debug("getSystemMessagePermissions(): aSysMsgName: " + aSysMsgName);
+
+    let permNames = SystemMessagePermissionsTable[aSysMsgName];
+    if (permNames === undefined) {
+      debug("'" + aSysMsgName + "' is not associated with permissions. " +
+            "Please add them to the SystemMessagePermissionsTable.");
+      return null;
+    }
+
+    let object = { };
+    for (let permName in permNames) {
+      if (PermissionsTable[permName] === undefined) {
+        debug("'" + permName + "' for '" + aSysMsgName + "' is invalid. " +
+              "Please correct it in the SystemMessagePermissionsTable.");
+        return null;
+      }
+
+      // Construct a new permission name array by adding the access suffixes.
+      let access = permNames[permName];
+      if (!access || !Array.isArray(access)) {
+        debug("'" + permName + "' is not associated with access array. " +
+              "Please correct it in the SystemMessagePermissionsTable.");
+        return null;
+      }
+      object[permName] = appendAccessToPermName(permName, access);
+    }
+    return object
+  },
+
+  /**
+   * Check if the system message is permitted to be registered for the given
+   * app at start-up based on the permissions claimed in the app's manifest.
+   * @param string aSysMsgName
+   *        The system messsage name.
+   * @param string aOrigin
+   *        The app's origin.
+   * @param object aManifest
+   *        The app's manifest.
+   * @returns bool
+   *        Is permitted or not.
+   **/
+  isSystemMessagePermittedToRegister:
+    function isSystemMessagePermittedToRegister(aSysMsgName, aOrigin, aManifest) {
+    debug("isSystemMessagePermittedToRegister(): " +
+          "aSysMsgName: " + aSysMsgName + ", " +
+          "aOrigin: " + aOrigin + ", " +
+          "aManifest: " + JSON.stringify(aManifest));
+
+    let permNames = this.getSystemMessagePermissions(aSysMsgName);
+    if (permNames === null) {
+      return false;
+    }
+
+    // Check to see if the 'webapp' is app/privileged/certified.
+    let appStatus;
+    switch (AppsUtils.getAppManifestStatus(aManifest)) {
+    case Ci.nsIPrincipal.APP_STATUS_CERTIFIED:
+      appStatus = "certified";
+      break;
+    case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED:
+      appStatus = "privileged";
+      break;
+    case Ci.nsIPrincipal.APP_STATUS_INSTALLED:
+      appStatus = "app";
+      break;
+    default:
+      throw new Error("SystemMessagePermissionsChecker.jsm: " +
+                      "Cannot decide the app's status. Install cancelled.");
+      break;
+    }
+
+    let newManifest = new ManifestHelper(aManifest, aOrigin);
+
+    for (let permName in permNames) {
+      // The app doesn't claim valid permissions for this sytem message.
+      if (!newManifest.permissions || !newManifest.permissions[permName]) {
+        debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " +
+              "Please add the permission for app: '" + aOrigin + "'.");
+        return false;
+      }
+      let permValue = PermissionsTable[permName][appStatus];
+      if (permValue != Ci.nsIPermissionManager.PROMPT_ACTION &&
+          permValue != Ci.nsIPermissionManager.ALLOW_ACTION) {
+        debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " +
+              "Please add the permission for app: '" + aOrigin + "'.");
+        return false;
+      }
+
+      // Compare the expanded permission names between the ones in
+      // app's manifest and the ones needed for system message.
+      let expandedPermNames =
+        expandPermissions(permName,
+                          newManifest.permissions[permName].access,
+                          newManifest.permissions[permName].channels);
+
+      let permNamesWithAccess = permNames[permName];
+
+      // Early return false as soon as any permission is not matched.
+      for (let idx in permNamesWithAccess) {
+        let index = expandedPermNames.indexOf(permNamesWithAccess[idx]);
+        if (index == -1) {
+          debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " +
+                "Please add the permission for app: '" + aOrigin + "'.");
+          return false;
+        }
+      }
+    }
+
+    // All the permissions needed for this system message are matched.
+    return true;
+  },
+
+  /**
+   * Check if the system message is permitted to be sent to the given
+   * app's page at run-time based on the current app's permissions.
+   * @param string aSysMsgName
+   *        The system messsage name.
+   * @param string aPageURI
+   *        The app's page URI.
+   * @param string aManifestURL
+   *        The app's manifest URL.
+   * @returns bool
+   *        Is permitted or not.
+   **/
+  isSystemMessagePermittedToSend:
+    function isSystemMessagePermittedToSend(aSysMsgName, aPageURI, aManifestURL) {
+    debug("isSystemMessagePermittedToSend(): " +
+          "aSysMsgName: " + aSysMsgName + ", " +
+          "aPageURI: " + aPageURI + ", " +
+          "aManifestURL: " + aManifestURL);
+
+    let permNames = this.getSystemMessagePermissions(aSysMsgName);
+    if (permNames === null) {
+      return false;
+    }
+
+    let pageURI = Services.io.newURI(aPageURI, null, null);
+    for (let permName in permNames) {
+      let permNamesWithAccess = permNames[permName];
+
+      // Early return false as soon as any permission is not matched.
+      for (let idx in permNamesWithAccess) {
+        if(PermissionSettingsModule.getPermission(permNamesWithAccess[idx],
+                                                  aManifestURL,
+                                                  pageURI.prePath,
+                                                  false) != "allow") {
+          debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " +
+                "Please add the permission for app: '" + pageURI.prePath + "'.");
+          return false;
+        }
+      }
+    }
+
+    // All the permissions needed for this system message are matched.
+    return true;
+  }
+};
--- a/dom/network/tests/marionette/test_mobile_iccinfo.js
+++ b/dom/network/tests/marionette/test_mobile_iccinfo.js
@@ -73,10 +73,10 @@ function testSPN(mcc, mnc, expectedIsDis
        expectedIsDisplaySpnRequired);
     window.setTimeout(callback, 0);
   });
   setEmulatorMccMnc(mcc, mnc);
 }
 
 testDisplayConditionChange(testSPN, [
   [123, 456, false, true], // Not in HPLMN.
-  [310, 260, true, false], // inside HPLMN.
+  [310, 260, true, true], // inside HPLMN.
 ], finalize);
--- a/dom/permission/PermissionPromptHelper.jsm
+++ b/dom/permission/PermissionPromptHelper.jsm
@@ -44,98 +44,102 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "@mozilla.org/permission-prompt-service;1",
                                    "nsIPermissionPromptService");
 
 var permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
 var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
 var appsService = Cc["@mozilla.org/AppsService;1"].getService(Ci.nsIAppsService);
 
 this.PermissionPromptHelper = {
-  init: function() {
+  init: function init() {
     debug("Init");
     ppmm.addMessageListener("PermissionPromptHelper:AskPermission", this);
     Services.obs.addObserver(this, "profile-before-change", false);
   },
 
-  askPermission: function(aMessage, aCallbacks) {
+  askPermission: function askPermission(aMessage, aCallbacks) {
     let msg = aMessage.json;
 
     let access;
     if (PermissionsTable[msg.type].access) {
       access = "readwrite"; // XXXddahl: Not sure if this should be set to READWRITE
     }
-    // expand Permissions:
-    var expandedPerms = expandPermissions(msg.type, access);
-    let installedPerms = [];
+    // Expand permission names.
+    var expandedPermNames = expandPermissions(msg.type, access);
+    let installedPermValues = [];
     let principal;
 
-    for (let idx in expandedPerms) {
+    for (let idx in expandedPermNames) {
       let uri = Services.io.newURI(msg.origin, null, null);
       principal =
         secMan.getAppCodebasePrincipal(uri, msg.appID, msg.browserFlag);
       let access = msg.access ? msg.type + "-" + msg.access : msg.type;
-      let perm =
+      let permValue =
         permissionManager.testExactPermissionFromPrincipal(principal, access);
-      installedPerms.push(perm);
+      installedPermValues.push(permValue);
     }
 
     // TODO: see bug 804623, We are preventing "read" operations
     // even if just "write" has been set to DENY_ACTION
-    for (let idx in installedPerms) {
-      // if any of the installedPerms are deny, run aCallbacks.cancel
-      if (installedPerms[idx] == Ci.nsIPermissionManager.DENY_ACTION ||
-          installedPerms[idx] == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
+    for (let idx in installedPermValues) {
+      // if any of the installedPermValues are deny, run aCallbacks.cancel
+      if (installedPermValues[idx] == Ci.nsIPermissionManager.DENY_ACTION ||
+          installedPermValues[idx] == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
         aCallbacks.cancel();
         return;
       }
     }
 
-    for (let idx in installedPerms) {
-      if (installedPerms[idx] == Ci.nsIPermissionManager.PROMPT_ACTION) {
+    for (let idx in installedPermValues) {
+      if (installedPermValues[idx] == Ci.nsIPermissionManager.PROMPT_ACTION) {
         // create a nsIContentPermissionRequest
         let request = {
           type: msg.type,
           principal: principal,
           QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
           allow: aCallbacks.allow,
           cancel: aCallbacks.cancel,
           window: Services.wm.getMostRecentWindow("navigator:browser")
         };
 
         permissionPromptService.getPermission(request);
         return;
       }
     }
 
-    for (let idx in installedPerms) {
-      if (installedPerms[idx] == Ci.nsIPermissionManager.ALLOW_ACTION) {
+    for (let idx in installedPermValues) {
+      if (installedPermValues[idx] == Ci.nsIPermissionManager.ALLOW_ACTION) {
         aCallbacks.allow();
         return;
       }
     }
   },
 
-  observe: function(aSubject, aTopic, aData) {
+  observe: function observe(aSubject, aTopic, aData) {
     ppmm.removeMessageListener("PermissionPromptHelper:AskPermission", this);
     Services.obs.removeObserver(this, "profile-before-change");
     ppmm = null;
   },
 
-  receiveMessage: function(aMessage) {
+  receiveMessage: function receiveMessage(aMessage) {
     debug("PermissionPromptHelper::receiveMessage " + aMessage.name);
     let mm = aMessage.target;
     let msg = aMessage.data;
 
     let result;
     if (aMessage.name == "PermissionPromptHelper:AskPermission") {
       this.askPermission(aMessage, {
         cancel: function() {
-          mm.sendAsyncMessage("PermissionPromptHelper:AskPermission:OK", {result: Ci.nsIPermissionManager.DENY_ACTION, requestID: msg.requestID});
+          mm.sendAsyncMessage("PermissionPromptHelper:AskPermission:OK",
+                              { result: Ci.nsIPermissionManager.DENY_ACTION,
+                                requestID: msg.requestID });
         },
         allow: function() {
-          mm.sendAsyncMessage("PermissionPromptHelper:AskPermission:OK", {result: Ci.nsIPermissionManager.ALLOW_ACTION, requestID: msg.requestID});
+          mm.sendAsyncMessage("PermissionPromptHelper:AskPermission:OK",
+                              { result: Ci.nsIPermissionManager.ALLOW_ACTION,
+                                requestID: msg.requestID });
         }
       });
     }
   }
 }
 
 PermissionPromptHelper.init();
--- a/dom/permission/PermissionSettings.js
+++ b/dom/permission/PermissionSettings.js
@@ -39,22 +39,22 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "nsIScriptSecurityManager");
 
 XPCOMUtils.defineLazyServiceGetter(this,
                                    "appsService",
                                    "@mozilla.org/AppsService;1",
                                    "nsIAppsService");
 
 PermissionSettings.prototype = {
-  get: function get(aPermission, aManifestURL, aOrigin, aBrowserFlag) {
-    debug("Get called with: " + aPermission + ", " + aManifestURL + ", " + aOrigin + ", " + aBrowserFlag);
+  get: function get(aPermName, aManifestURL, aOrigin, aBrowserFlag) {
+    debug("Get called with: " + aPermName + ", " + aManifestURL + ", " + aOrigin + ", " + aBrowserFlag);
     let uri = Services.io.newURI(aOrigin, null, null);
     let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
     let principal = secMan.getAppCodebasePrincipal(uri, appID, aBrowserFlag);
-    let result = permissionManager.testExactPermissionFromPrincipal(principal, aPermission);
+    let result = permissionManager.testExactPermissionFromPrincipal(principal, aPermName);
 
     switch (result)
     {
       case Ci.nsIPermissionManager.UNKNOWN_ACTION:
         return "unknown";
       case Ci.nsIPermissionManager.ALLOW_ACTION:
         return "allow";
       case Ci.nsIPermissionManager.DENY_ACTION:
@@ -62,29 +62,29 @@ PermissionSettings.prototype = {
       case Ci.nsIPermissionManager.PROMPT_ACTION:
         return "prompt";
       default:
         dump("Unsupported PermissionSettings Action!\n");
         return "unknown";
     }
   },
 
-  set: function set(aPermission, aValue, aManifestURL, aOrigin, aBrowserFlag) {
-    debug("Set called with: " + aPermission + ", " + aManifestURL + ", " + aOrigin + ",  " + aValue + ", " + aBrowserFlag);
+  set: function set(aPermName, aPermValue, aManifestURL, aOrigin, aBrowserFlag) {
+    debug("Set called with: " + aPermName + ", " + aManifestURL + ", " + aOrigin + ",  " + aPermValue + ", " + aBrowserFlag);
     let action;
     cpm.sendSyncMessage("PermissionSettings:AddPermission", {
-      type: aPermission,
+      type: aPermName,
       origin: aOrigin,
       manifestURL: aManifestURL,
-      value: aValue,
+      value: aPermValue,
       browserFlag: aBrowserFlag
     });
   },
 
-  init: function(aWindow) {
+  init: function init(aWindow) {
     debug("init");
 
     // Set navigator.mozPermissionSettings to null.
     let perm = Services.perms.testExactPermissionFromPrincipal(aWindow.document.nodePrincipal, "permissions");
     if (!Services.prefs.getBoolPref("dom.mozPermissionSettings.enabled")
         || perm != Ci.nsIPermissionManager.ALLOW_ACTION) {
       return null;
     }
--- a/dom/permission/PermissionSettings.jsm
+++ b/dom/permission/PermissionSettings.jsm
@@ -32,23 +32,23 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "nsIScriptSecurityManager");
 
 XPCOMUtils.defineLazyServiceGetter(this,
                                    "appsService",
                                    "@mozilla.org/AppsService;1",
                                    "nsIAppsService");
 
 this.PermissionSettingsModule = {
-  init: function() {
+  init: function init() {
     debug("Init");
     ppmm.addMessageListener("PermissionSettings:AddPermission", this);
     Services.obs.addObserver(this, "profile-before-change", false);
   },
 
-  addPermission: function(aData, aCallbacks) {
+  addPermission: function addPermission(aData, aCallbacks) {
     let uri = Services.io.newURI(aData.origin, null, null);
     let appID = appsService.getAppLocalIdByManifestURL(aData.manifestURL);
     let principal = secMan.getAppCodebasePrincipal(uri, appID, aData.browserFlag);
 
     let action;
     switch (aData.value)
     {
       case "unknown":
@@ -66,22 +66,22 @@ this.PermissionSettingsModule = {
       default:
         dump("Unsupported PermisionSettings Action: " + aData.value +"\n");
         action = Ci.nsIPermissionManager.UNKNOWN_ACTION;
     }
     debug("add: " + aData.origin + " " + appID + " " + action);
     permissionManager.addFromPrincipal(principal, aData.type, action);
   },
 
-  getPermission: function getPermission(aPermission, aManifestURL, aOrigin, aBrowserFlag) {
-    debug("getPermission: " + aPermission + ", " + aManifestURL + ", " + aOrigin);
+  getPermission: function getPermission(aPermName, aManifestURL, aOrigin, aBrowserFlag) {
+    debug("getPermission: " + aPermName + ", " + aManifestURL + ", " + aOrigin);
     let uri = Services.io.newURI(aOrigin, null, null);
     let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
     let principal = secMan.getAppCodebasePrincipal(uri, appID, aBrowserFlag);
-    let result = permissionManager.testExactPermissionFromPrincipal(principal, aPermission);
+    let result = permissionManager.testExactPermissionFromPrincipal(principal, aPermName);
 
     switch (result)
     {
       case Ci.nsIPermissionManager.UNKNOWN_ACTION:
         return "unknown";
       case Ci.nsIPermissionManager.ALLOW_ACTION:
         return "allow";
       case Ci.nsIPermissionManager.DENY_ACTION:
@@ -89,23 +89,23 @@ this.PermissionSettingsModule = {
       case Ci.nsIPermissionManager.PROMPT_ACTION:
         return "prompt";
       default:
         dump("Unsupported PermissionSettings Action!\n");
         return "unknown";
     }
   },
 
-  observe: function(aSubject, aTopic, aData) {
+  observe: function observe(aSubject, aTopic, aData) {
     ppmm.removeMessageListener("PermissionSettings:AddPermission", this);
     Services.obs.removeObserver(this, "profile-before-change");
     ppmm = null;
   },
 
-  receiveMessage: function(aMessage) {
+  receiveMessage: function receiveMessage(aMessage) {
     debug("PermissionSettings::receiveMessage " + aMessage.name);
     let mm = aMessage.target;
     let msg = aMessage.data;
 
     let result;
     switch (aMessage.name) {
       case "PermissionSettings:AddPermission":
         this.addPermission(msg);
--- a/dom/phonenumberutils/PhoneNumber.jsm
+++ b/dom/phonenumberutils/PhoneNumber.jsm
@@ -189,17 +189,18 @@ this.PhoneNumber = (function (dataBase) 
     // (949) 726-2896
     get nationalFormat() {
       var value = FormatNumber(this.regionMetaData, this.nationalNumber, false);
       Object.defineProperty(this, "nationalFormat", { value: value, enumerable: true });
       return value;
     },
     // +19497262896
     get internationalNumber() {
-      var value = this.internationalFormat.replace(NON_DIALABLE_CHARS, "");
+      var value = this.internationalFormat ? this.internationalFormat.replace(NON_DIALABLE_CHARS, "")
+                                           : null;
       Object.defineProperty(this, "nationalNumber", { value: value, enumerable: true });
       return value;
     }
   };
 
   // Normalize a number by converting unicode numbers and symbols to their
   // ASCII equivalents and removing all non-dialable characters.
   function NormalizeNumber(number) {
--- a/dom/phonenumberutils/tests/test_phonenumber.xul
+++ b/dom/phonenumberutils/tests/test_phonenumber.xul
@@ -128,17 +128,17 @@ Parse("045 33 1234-5678", "MX");
 Parse("0 3   3 3 1   6 0 0 5", "NZ");
 
 // Test omitting the current region. This is only valid when the number starts
 // with a '+'.
 Parse("+64 3 331 6005");
 Parse("+64 3 331 6005", null);
 
 // US numbers
-Format("19497262896", "US", "9497262896", "US", "(949) 726-2896", "+1 949-726-2896");
+Format("19497261234", "US", "9497261234", "US", "(949) 726-1234", "+1 949-726-1234");
 
 // Try a couple german numbers from the US with various access codes.
 Format("49451491934", "US", "451491934", "DE", "0451 491934", "+49 451 491934");
 Format("+49451491934", "US", "451491934", "DE", "0451 491934", "+49 451 491934");
 Format("01149451491934", "US", "451491934", "DE", "0451 491934", "+49 451 491934");
 
 // Now try dialing the same number from within the German region.
 Format("451491934", "DE", "451491934", "DE", "0451 491934", "+49 451 491934");
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -3087,38 +3087,36 @@ nsresult nsPluginHost::NewPluginURLStrea
 {
   nsCOMPtr<nsIURI> url;
   nsAutoString absUrl;
   nsresult rv;
 
   if (aURL.Length() <= 0)
     return NS_OK;
 
-  // get the full URL of the document that the plugin is embedded
-  //   in to create an absolute url in case aURL is relative
-  nsCOMPtr<nsIDocument> doc;
+  // get the base URI for the plugin to create an absolute url 
+  // in case aURL is relative
   nsRefPtr<nsPluginInstanceOwner> owner = aInstance->GetOwner();
   if (owner) {
-    rv = owner->GetDocument(getter_AddRefs(doc));
-    if (NS_SUCCEEDED(rv) && doc) {
-      // Create an absolute URL
-      rv = NS_MakeAbsoluteURI(absUrl, aURL, doc->GetDocBaseURI());
-    }
+    rv = NS_MakeAbsoluteURI(absUrl, aURL, nsCOMPtr<nsIURI>(owner->GetBaseURI()));
   }
 
   if (absUrl.IsEmpty())
     absUrl.Assign(aURL);
 
   rv = NS_NewURI(getter_AddRefs(url), absUrl);
   if (NS_FAILED(rv))
     return rv;
 
   nsCOMPtr<nsIDOMElement> element;
-  if (owner)
+  nsCOMPtr<nsIDocument> doc;
+  if (owner) {
     owner->GetDOMElement(getter_AddRefs(element));
+    owner->GetDocument(getter_AddRefs(doc));
+  }
 
   int16_t shouldLoad = nsIContentPolicy::ACCEPT;
   rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OBJECT_SUBREQUEST,
                                  url,
                                  (doc ? doc->NodePrincipal() : nullptr),
                                  element,
                                  EmptyCString(), //mime guess
                                  nullptr,         //extra
@@ -3170,18 +3168,22 @@ nsresult nsPluginHost::NewPluginURLStrea
       // bug 724465.
       nsCOMPtr<nsIURI> referer;
 
       nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(element);
       if (olc)
         olc->GetSrcURI(getter_AddRefs(referer));
 
 
-      if (!referer)
+      if (!referer) {
+        if (!doc) {
+          return NS_ERROR_FAILURE;
+        }
         referer = doc->GetDocumentURI();
+      }
 
       rv = httpChannel->SetReferrer(referer);
       NS_ENSURE_SUCCESS(rv,rv);
     }
       
     if (aPostStream) {
       // XXX it's a bit of a hack to rewind the postdata stream
       // here but it has to be done in case the post data is
@@ -3211,32 +3213,36 @@ nsresult nsPluginHost::NewPluginURLStrea
 // Called by GetURL and PostURL
 nsresult
 nsPluginHost::DoURLLoadSecurityCheck(nsNPAPIPluginInstance *aInstance,
                                      const char* aURL)
 {
   if (!aURL || *aURL == '\0')
     return NS_OK;
 
-  // get the URL of the document that loaded the