Merge fx-team and mozilla-central
authorEd Morley <emorley@mozilla.com>
Mon, 16 Jul 2012 11:31:28 +0100
changeset 102114 38812f58ea22baac2edb13406744d6315c036280
parent 102113 21d5e58533e06ce120e35acf6a1457750def9e9d (current diff)
parent 102095 4cffe2b37d0c95dde87ec2a96f5bf8d34eb3a670 (diff)
child 102125 00405b1daf05947cc5bcd78854ce7a5594fe83c3
push id1729
push userlsblakk@mozilla.com
push dateMon, 16 Jul 2012 20:02:43 +0000
treeherdermozilla-aurora@f4e75e148951 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone16.0a1
Merge fx-team and mozilla-central
browser/extensions/pdfjs/bootstrap.js
browser/extensions/pdfjs/install.rdf.in
dom/base/nsIScriptObjectOwner.h
dom/indexedDB/test/unit/head_idb.js
mobile/android/base/resources/drawable-hdpi/abouthome_separator.9.png
mobile/android/base/resources/drawable-hdpi/tabs_normal.png
mobile/android/base/resources/drawable-hdpi/tabs_pressed.png
mobile/android/base/resources/drawable-land-hdpi-v14/tabs_normal.png
mobile/android/base/resources/drawable-land-hdpi-v14/tabs_pressed.png
mobile/android/base/resources/drawable-land-mdpi-v14/tabs_normal.png
mobile/android/base/resources/drawable-land-mdpi-v14/tabs_pressed.png
mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_normal.png
mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_pressed.png
mobile/android/base/resources/drawable-large-hdpi/address_bar_back_button_bg.png
mobile/android/base/resources/drawable-large-hdpi/address_bar_back_button_pressed_bg.png
mobile/android/base/resources/drawable-large-hdpi/address_bar_texture_tablet.png
mobile/android/base/resources/drawable-large-hdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-large-hdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-large-hdpi/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-large-hdpi/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-large-hdpi/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-large-hdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-large-hdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-large-hdpi/ic_menu_bookmark_add.png
mobile/android/base/resources/drawable-large-hdpi/ic_menu_bookmark_remove.png
mobile/android/base/resources/drawable-large-hdpi/ic_menu_forward.png
mobile/android/base/resources/drawable-large-hdpi/ic_menu_reload.png
mobile/android/base/resources/drawable-large-hdpi/menu.png
mobile/android/base/resources/drawable-large-hdpi/reader.png
mobile/android/base/resources/drawable-large-hdpi/remote_tabs_off.png
mobile/android/base/resources/drawable-large-hdpi/remote_tabs_on.png
mobile/android/base/resources/drawable-large-hdpi/site_security_identified.png
mobile/android/base/resources/drawable-large-hdpi/site_security_verified.png
mobile/android/base/resources/drawable-large-hdpi/tab_new.png
mobile/android/base/resources/drawable-large-hdpi/tabs_carat_contracted.png
mobile/android/base/resources/drawable-large-hdpi/tabs_carat_expanded.png
mobile/android/base/resources/drawable-large-hdpi/tabs_expanded_normal.png
mobile/android/base/resources/drawable-large-hdpi/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-large-hdpi/tabs_normal.png
mobile/android/base/resources/drawable-large-hdpi/tabs_pressed.png
mobile/android/base/resources/drawable-large-hdpi/urlbar_stop.png
mobile/android/base/resources/drawable-large-mdpi/address_bar_back_button_bg.png
mobile/android/base/resources/drawable-large-mdpi/address_bar_back_button_pressed_bg.png
mobile/android/base/resources/drawable-large-mdpi/address_bar_bg.xml
mobile/android/base/resources/drawable-large-mdpi/address_bar_texture_tablet.png
mobile/android/base/resources/drawable-large-mdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-large-mdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-large-mdpi/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-large-mdpi/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-large-mdpi/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-large-mdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-large-mdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-large-mdpi/ic_menu_bookmark_add.png
mobile/android/base/resources/drawable-large-mdpi/ic_menu_bookmark_remove.png
mobile/android/base/resources/drawable-large-mdpi/ic_menu_forward.png
mobile/android/base/resources/drawable-large-mdpi/ic_menu_reload.png
mobile/android/base/resources/drawable-large-mdpi/menu.png
mobile/android/base/resources/drawable-large-mdpi/reader.png
mobile/android/base/resources/drawable-large-mdpi/remote_tabs_off.png
mobile/android/base/resources/drawable-large-mdpi/remote_tabs_on.png
mobile/android/base/resources/drawable-large-mdpi/site_security_identified.png
mobile/android/base/resources/drawable-large-mdpi/site_security_verified.png
mobile/android/base/resources/drawable-large-mdpi/tab_new.png
mobile/android/base/resources/drawable-large-mdpi/tabs_button.xml
mobile/android/base/resources/drawable-large-mdpi/tabs_button_expanded.xml
mobile/android/base/resources/drawable-large-mdpi/tabs_carat_contracted.png
mobile/android/base/resources/drawable-large-mdpi/tabs_carat_expanded.png
mobile/android/base/resources/drawable-large-mdpi/tabs_expanded_normal.png
mobile/android/base/resources/drawable-large-mdpi/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-large-mdpi/tabs_level.xml
mobile/android/base/resources/drawable-large-mdpi/tabs_normal.png
mobile/android/base/resources/drawable-large-mdpi/tabs_pressed.png
mobile/android/base/resources/drawable-large-mdpi/urlbar_stop.png
mobile/android/base/resources/drawable-large-xhdpi/address_bar_back_button_bg.png
mobile/android/base/resources/drawable-large-xhdpi/address_bar_back_button_pressed_bg.png
mobile/android/base/resources/drawable-large-xhdpi/address_bar_texture_tablet.png
mobile/android/base/resources/drawable-large-xhdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-large-xhdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-large-xhdpi/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-large-xhdpi/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-large-xhdpi/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-large-xhdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-large-xhdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-large-xhdpi/ic_menu_bookmark_add.png
mobile/android/base/resources/drawable-large-xhdpi/ic_menu_bookmark_remove.png
mobile/android/base/resources/drawable-large-xhdpi/ic_menu_forward.png
mobile/android/base/resources/drawable-large-xhdpi/ic_menu_reload.png
mobile/android/base/resources/drawable-large-xhdpi/menu.png
mobile/android/base/resources/drawable-large-xhdpi/reader.png
mobile/android/base/resources/drawable-large-xhdpi/remote_tabs_off.png
mobile/android/base/resources/drawable-large-xhdpi/remote_tabs_on.png
mobile/android/base/resources/drawable-large-xhdpi/site_security_identified.png
mobile/android/base/resources/drawable-large-xhdpi/site_security_verified.png
mobile/android/base/resources/drawable-large-xhdpi/tab_new.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_carat_contracted.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_carat_expanded.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_expanded_normal.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_normal.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_pressed.png
mobile/android/base/resources/drawable-large-xhdpi/urlbar_stop.png
mobile/android/base/resources/drawable-xhdpi-v11/abouthome_icon.png
mobile/android/base/resources/drawable-xhdpi-v11/abouthome_logo.png
mobile/android/base/resources/drawable-xhdpi-v11/abouthome_separator.9.png
mobile/android/base/resources/drawable-xhdpi-v11/abouthome_sync_bg.9.png
mobile/android/base/resources/drawable-xhdpi-v11/abouthome_sync_logo.png
mobile/android/base/resources/drawable-xhdpi-v11/abouthome_sync_pressed_bg.9.png
mobile/android/base/resources/drawable-xhdpi-v11/abouthome_thumbnail.png
mobile/android/base/resources/drawable-xhdpi-v11/address_bar_bg_curve.png
mobile/android/base/resources/drawable-xhdpi-v11/address_bar_bg_shadow.png
mobile/android/base/resources/drawable-xhdpi-v11/address_bar_texture_port.png
mobile/android/base/resources/drawable-xhdpi-v11/address_bar_url_default.9.png
mobile/android/base/resources/drawable-xhdpi-v11/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-xhdpi-v11/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-xhdpi-v11/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-xhdpi-v11/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-xhdpi-v11/doorhanger_arrow.png
mobile/android/base/resources/drawable-xhdpi-v11/doorhanger_bg.9.png
mobile/android/base/resources/drawable-xhdpi-v11/doorhanger_popup_bg.9.png
mobile/android/base/resources/drawable-xhdpi-v11/doorhanger_shadow_bg.9.png
mobile/android/base/resources/drawable-xhdpi-v11/favicon.png
mobile/android/base/resources/drawable-xhdpi-v11/find_close.png
mobile/android/base/resources/drawable-xhdpi-v11/find_next.png
mobile/android/base/resources/drawable-xhdpi-v11/find_prev.png
mobile/android/base/resources/drawable-xhdpi-v11/folder.png
mobile/android/base/resources/drawable-xhdpi-v11/ic_addons_empty.png
mobile/android/base/resources/drawable-xhdpi-v11/ic_awesomebar_go.png
mobile/android/base/resources/drawable-xhdpi-v11/ic_awesomebar_reader.png
mobile/android/base/resources/drawable-xhdpi-v11/ic_awesomebar_search.png
mobile/android/base/resources/drawable-xhdpi-v11/ic_awesomebar_star.png
mobile/android/base/resources/drawable-xhdpi-v11/ic_menu_foward.png
mobile/android/base/resources/drawable-xhdpi-v11/larry_blue.png
mobile/android/base/resources/drawable-xhdpi-v11/larry_green.png
mobile/android/base/resources/drawable-xhdpi-v11/reader.png
mobile/android/base/resources/drawable-xhdpi-v11/reading_list.png
mobile/android/base/resources/drawable-xhdpi-v11/remote_tabs_off.png
mobile/android/base/resources/drawable-xhdpi-v11/remote_tabs_on.png
mobile/android/base/resources/drawable-xhdpi-v11/site_security_identified.png
mobile/android/base/resources/drawable-xhdpi-v11/site_security_verified.png
mobile/android/base/resources/drawable-xhdpi-v11/tab_close.png
mobile/android/base/resources/drawable-xhdpi-v11/tab_new.png
mobile/android/base/resources/drawable-xhdpi-v11/tab_thumbnail_default.png
mobile/android/base/resources/drawable-xhdpi-v11/tab_thumbnail_shadow.png
mobile/android/base/resources/drawable-xhdpi-v11/tabs_carat.png
mobile/android/base/resources/drawable-xhdpi-v11/tabs_normal.png
mobile/android/base/resources/drawable-xhdpi-v11/tabs_pressed.png
mobile/android/base/resources/drawable-xhdpi-v11/urlbar_stop.png
mobile/android/base/resources/drawable-xhdpi-v11/validation_arrow.png
mobile/android/base/resources/drawable-xhdpi-v11/validation_arrow_inverted.png
mobile/android/base/resources/drawable-xhdpi-v11/validation_bg.9.png
mobile/android/base/resources/drawable-xhdpi-v14/menu.png
mobile/android/base/resources/drawable-xhdpi-v14/menu_normal.png
mobile/android/base/resources/drawable-xhdpi-v14/menu_pressed.png
mobile/android/base/resources/drawable-xhdpi-v14/tab_new_normal.png
mobile/android/base/resources/drawable-xhdpi-v14/tab_new_pressed.png
mobile/android/base/resources/drawable-xhdpi-v14/tabs_normal.png
mobile/android/base/resources/drawable-xhdpi-v14/tabs_pressed.png
mobile/android/base/resources/drawable/abouthome_separator.9.png
mobile/android/base/resources/drawable/tabs_button.xml
mobile/android/base/resources/drawable/tabs_button_contracted.xml
mobile/android/base/resources/drawable/tabs_button_tail.xml
mobile/android/base/resources/drawable/tabs_expanded_pressed.png
mobile/android/base/resources/drawable/tabs_normal.png
mobile/android/base/resources/drawable/tabs_pressed.png
mobile/android/base/resources/layout-large/awesomebar_search.xml
mobile/android/base/resources/layout-large/awesomebar_tab_indicator.xml
mobile/android/base/resources/layout-large/browser_toolbar.xml
mobile/android/base/resources/layout-large/doorhangerpopup.xml
mobile/android/base/resources/layout-large/gecko_app.xml
mobile/android/base/resources/layout-large/remote_tabs_child.xml
mobile/android/base/resources/layout-large/remote_tabs_group.xml
mobile/android/base/resources/layout-large/site_identity_popup.xml
mobile/android/base/resources/layout-large/tabs_panel_toolbar.xml
mobile/android/base/resources/layout-large/tabs_row.xml
mobile/android/base/resources/layout-v14/browser_toolbar.xml
mobile/android/base/resources/layout-v14/tabs_panel_toolbar.xml
mobile/android/base/resources/menu-large-v11/gecko_menu.xml.in
mobile/android/base/resources/values-large-v14/dimens.xml
mobile/android/base/resources/values-large/dimens.xml
mobile/android/base/resources/values-large/styles.xml
--- a/accessible/src/generic/ARIAGridAccessible.h
+++ b/accessible/src/generic/ARIAGridAccessible.h
@@ -25,17 +25,17 @@ class ARIAGridAccessible : public Access
 {
 public:
   ARIAGridAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessibleTable
-  NS_DECL_OR_FORWARD_NSIACCESSIBLETABLE_WITH_XPCACCESSIBLETABLE
+  NS_FORWARD_NSIACCESSIBLETABLE(xpcAccessibleTable::)
 
   // Accessible
   virtual TableAccessible* AsTable() { return this; }
 
   // nsAccessNode
   virtual void Shutdown();
 
   // TableAccessible
--- a/accessible/src/html/HTMLTableAccessible.h
+++ b/accessible/src/html/HTMLTableAccessible.h
@@ -90,17 +90,17 @@ class HTMLTableAccessible : public Acces
                             public TableAccessible
 {
 public:
   HTMLTableAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessible Table
-  NS_DECL_OR_FORWARD_NSIACCESSIBLETABLE_WITH_XPCACCESSIBLETABLE
+  NS_FORWARD_NSIACCESSIBLETABLE(xpcAccessibleTable::)
 
   // TableAccessible
   virtual Accessible* Caption();
   virtual void Summary(nsString& aSummary);
   virtual PRUint32 ColCount();
   virtual PRUint32 RowCount();
   virtual Accessible* CellAt(PRUint32 aRowIndex, PRUint32 aColumnIndex);
   virtual PRInt32 CellIndexAt(PRUint32 aRowIdx, PRUint32 aColIdx);
--- a/accessible/src/mac/mozAccessible.mm
+++ b/accessible/src/mac/mozAccessible.mm
@@ -407,17 +407,17 @@ GetClosestInterestingAccessible(id anObj
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 - (NSString*)role
 {
   if (!mGeckoAccessible)
     return nil;
 
-#ifdef DEBUG
+#ifdef DEBUG_A11Y
   NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(mGeckoAccessible),
                "Does not support nsIAccessibleText when it should");
 #endif
 
 #define ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role) \
   case roles::geckoRole: \
     return macRole;
 
--- a/accessible/src/xpcom/xpcAccessibleTable.h
+++ b/accessible/src/xpcom/xpcAccessibleTable.h
@@ -60,70 +60,9 @@ public:
   nsresult UnselectColumn(PRInt32 aColIdx);
   nsresult UnselectRow(PRInt32 aRowIdx);
   nsresult IsProbablyForLayout(bool* aIsForLayout);
 
 protected:
   mozilla::a11y::TableAccessible* mTable;
 };
 
-#define NS_DECL_OR_FORWARD_NSIACCESSIBLETABLE_WITH_XPCACCESSIBLETABLE \
-  NS_IMETHOD GetCaption(nsIAccessible** aCaption) \
-    { return xpcAccessibleTable::GetCaption(aCaption); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSummary(nsAString & aSummary) \
-    { return xpcAccessibleTable::GetSummary(aSummary); } \
-  NS_SCRIPTABLE NS_IMETHOD GetColumnCount(PRInt32* aColumnCount) \
-    { return xpcAccessibleTable::GetColumnCount(aColumnCount); } \
-  NS_SCRIPTABLE NS_IMETHOD GetRowCount(PRInt32* aRowCount) \
-    { return xpcAccessibleTable::GetRowCount(aRowCount); } \
-  NS_SCRIPTABLE NS_IMETHOD GetCellAt(PRInt32 rowIndex, PRInt32 columnIndex, nsIAccessible** _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetCellAt(rowIndex, columnIndex, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetCellIndexAt(PRInt32 rowIndex, PRInt32 columnIndex, PRInt32 *_retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetCellIndexAt(rowIndex, columnIndex, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetColumnIndexAt(PRInt32 cellIndex, PRInt32 *_retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetColumnIndexAt(cellIndex, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetRowIndexAt(PRInt32 cellIndex, PRInt32 *_retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetRowIndexAt(cellIndex, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetRowAndColumnIndicesAt(PRInt32 cellIndex, PRInt32 *rowIndex NS_OUTPARAM, PRInt32 *columnIndex NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetRowAndColumnIndicesAt(cellIndex, rowIndex, columnIndex); } \
-  NS_SCRIPTABLE NS_IMETHOD GetColumnExtentAt(PRInt32 row, PRInt32 column, PRInt32* _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetColumnExtentAt(row, column, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetRowExtentAt(PRInt32 row, PRInt32 column, PRInt32* _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetRowExtentAt(row, column, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetColumnDescription(PRInt32 columnIndex, nsAString& _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetColumnDescription(columnIndex, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetRowDescription(PRInt32 rowIndex, nsAString& _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetRowDescription(rowIndex, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD IsColumnSelected(PRInt32 colIdx, bool* _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::IsColumnSelected(colIdx, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD IsRowSelected(PRInt32 rowIdx, bool* _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::IsRowSelected(rowIdx, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD IsCellSelected(PRInt32 rowIdx, PRInt32 colIdx, bool* _retval NS_OUTPARAM) \
-    { return xpcAccessibleTable::IsCellSelected(rowIdx, colIdx, _retval); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSelectedCellCount(PRUint32* aSelectedCellCount) \
-    { return xpcAccessibleTable::GetSelectedCellCount(aSelectedCellCount); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSelectedColumnCount(PRUint32* aSelectedColumnCount) \
-    { return xpcAccessibleTable::GetSelectedColumnCount(aSelectedColumnCount); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSelectedRowCount(PRUint32* aSelectedRowCount) \
-    { return xpcAccessibleTable::GetSelectedRowCount(aSelectedRowCount); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSelectedCells(nsIArray** aSelectedCells) \
-    { return xpcAccessibleTable::GetSelectedCells(aSelectedCells); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSelectedCellIndices(PRUint32* cellsArraySize NS_OUTPARAM, \
-                                                  PRInt32** cellsArray NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetSelectedCellIndices(cellsArraySize, cellsArray); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSelectedColumnIndices(PRUint32* colsArraySize NS_OUTPARAM, \
-                                                    PRInt32** colsArray NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetSelectedColumnIndices(colsArraySize, colsArray); } \
-  NS_SCRIPTABLE NS_IMETHOD GetSelectedRowIndices(PRUint32* rowsArraySize NS_OUTPARAM, \
-                                                 PRInt32** rowsArray NS_OUTPARAM) \
-    { return xpcAccessibleTable::GetSelectedRowIndices(rowsArraySize, rowsArray); } \
-  NS_SCRIPTABLE NS_IMETHOD SelectRow(PRInt32 aRowIdx) \
-    { return xpcAccessibleTable::SelectRow(aRowIdx); } \
-  NS_SCRIPTABLE NS_IMETHOD SelectColumn(PRInt32 aColIdx) \
-    { return xpcAccessibleTable::SelectColumn(aColIdx); } \
-  NS_SCRIPTABLE NS_IMETHOD UnselectColumn(PRInt32 aColIdx) \
-    { return xpcAccessibleTable::UnselectColumn(aColIdx); } \
-  NS_IMETHOD UnselectRow(PRInt32 aRowIdx) \
-    { return xpcAccessibleTable::UnselectRow(aRowIdx); } \
-  NS_IMETHOD IsProbablyForLayout(bool* aResult) \
-  { return xpcAccessibleTable::IsProbablyForLayout(aResult); } \
-
 #endif // MOZILLA_A11Y_XPCOM_XPACCESSIBLETABLE_H_
--- a/accessible/src/xul/XULListboxAccessible.h
+++ b/accessible/src/xul/XULListboxAccessible.h
@@ -65,17 +65,17 @@ class XULListboxAccessible : public XULS
 {
 public:
   XULListboxAccessible(nsIContent* aContent, DocAccessible* aDoc);
   virtual ~XULListboxAccessible() {}
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessibleTable
-  NS_DECL_OR_FORWARD_NSIACCESSIBLETABLE_WITH_XPCACCESSIBLETABLE
+  NS_FORWARD_NSIACCESSIBLETABLE(xpcAccessibleTable::)
 
   // TableAccessible
   virtual PRUint32 ColCount();
   virtual PRUint32 RowCount();
   virtual Accessible* CellAt(PRUint32 aRowIndex, PRUint32 aColumnIndex);
   virtual bool IsColSelected(PRUint32 aColIdx);
   virtual bool IsRowSelected(PRUint32 aRowIdx);
   virtual bool IsCellSelected(PRUint32 aRowIdx, PRUint32 aColIdx);
--- a/accessible/src/xul/XULTreeGridAccessible.h
+++ b/accessible/src/xul/XULTreeGridAccessible.h
@@ -23,17 +23,17 @@ class XULTreeGridAccessible : public XUL
 {
 public:
   XULTreeGridAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessibleTable
-  NS_DECL_OR_FORWARD_NSIACCESSIBLETABLE_WITH_XPCACCESSIBLETABLE
+  NS_FORWARD_NSIACCESSIBLETABLE(xpcAccessibleTable::)
 
   // TableAccessible
   virtual PRUint32 ColCount();
   virtual PRUint32 RowCount();
   virtual Accessible* CellAt(PRUint32 aRowIndex, PRUint32 aColumnIndex);
   virtual void ColDescription(PRUint32 aColIdx, nsString& aDescription);
   virtual bool IsColSelected(PRUint32 aColIdx);
   virtual bool IsRowSelected(PRUint32 aRowIdx);
--- a/accessible/tests/mochitest/events/test_focus_autocomplete.xul
+++ b/accessible/tests/mochitest/events/test_focus_autocomplete.xul
@@ -225,17 +225,17 @@
             var itemX = {}, itemY = {}, treeX = {}, treeY = {};
             accessible.getBounds(itemX, itemY, {}, {});
             tree.getBounds(treeX, treeY, {}, {});
             x = itemX.value - treeX.value;
             y = itemY.value - treeY.value;
           }
         }
 
-        synthesizeMouse(node, x + 1, y + 1, {}, targetWindow);
+        synthesizeMouseAtCenter(node, {}, targetWindow);
       }
 
       this.getID = function selectByClick_getID()
       {
         return "select by click " + prettyName(aIDFunc.call(null, aIDFuncArg));
       }
     }
 
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -241,16 +241,17 @@ pref("editor.singleLine.pasteNewlines", 
 // threshold where a tap becomes a drag, in 1/240" reference pixels
 // The names of the preferences are to be in sync with nsEventStateManager.cpp
 pref("ui.dragThresholdX", 25);
 pref("ui.dragThresholdY", 25);
 
 // Layers Acceleration
 pref("layers.acceleration.disabled", false);
 pref("layers.offmainthreadcomposition.enabled", false);
+pref("layers.async-video.enabled", true);
 
 // Web Notifications
 pref("notification.feature.enabled", true);
 
 // IndexedDB
 pref("indexedDB.feature.enabled", true);
 pref("dom.indexedDB.warningQuota", 5);
 
@@ -404,16 +405,26 @@ pref("b2g.remote-js.port", 9999);
 // Handle hardware buttons in the b2g chrome package
 pref("b2g.keys.menu.enabled", true);
 
 // Screen timeout in seconds
 pref("power.screen.timeout", 60);
 
 pref("full-screen-api.enabled", true);
 
+#ifndef MOZ_WIDGET_GONK
+// If we're not actually on physical hardware, don't make the top level widget
+// fullscreen when transitioning to fullscreen. This means in emulated
+// environments (like the b2g desktop client) we won't make the client window
+// fill the whole screen, we'll just make the content fill the client window,
+// i.e. it won't give the impression to content that the number of device
+// screen pixels changes!
+pref("full-screen-api.ignore-widgets", true);
+#endif
+
 pref("media.volume.steps", 10);
 
 //Enable/disable marionette server, set listening port
 pref("marionette.defaultPrefs.enabled", true);
 pref("marionette.defaultPrefs.port", 2828);
 
 #ifdef MOZ_UPDATER
 pref("app.update.enabled", true);
@@ -455,8 +466,14 @@ pref("media.plugins.enabled", true);
 // Disable printing (particularly, window.print())
 pref("dom.disable_window_print", true);
 
 // Disable window.showModalDialog
 pref("dom.disable_window_showModalDialog", true);
 
 // Turns on gralloc-based direct texturing for Gonk
 pref("gfx.gralloc.enabled", false);
+
+// XXXX REMOVE FOR PRODUCTION. Turns on GC and CC logging 
+pref("javascript.options.mem.log", true);
+
+// Increase mark slice time from 10ms to 30ms
+pref("javascript.options.mem.gc_incremental_slice_ms", 30);
--- a/b2g/chrome/content/forms.js
+++ b/b2g/chrome/content/forms.js
@@ -48,17 +48,18 @@ let FormAssistant = {
           return;
 
         let ignore = {
           button: true,
           file: true,
           checkbox: true,
           radio: true,
           reset: true,
-          submit: true
+          submit: true,
+          image: true
         };
     
         if (evt.target instanceof HTMLSelectElement) { 
           content.setTimeout(function showIMEForSelect() {
             sendAsyncMessage("Forms:Input", getJSON(evt.target));
           });
         } else if (evt.target instanceof HTMLOptionElement &&
                    evt.target.parentNode instanceof HTMLSelectElement) {
@@ -151,16 +152,20 @@ let FormAssistant = {
         Services.obs.removeObserver(this, "ime-enabled-state-changed", false);
         Services.obs.removeObserver(this, "xpcom-shutdown");
         removeMessageListener("Forms:Select:Choice", this);
         break;
     }
   },
 
   tryShowIme: function(element) {
+    if (!element) {
+      return;
+    }
+
     // FIXME/bug 729623: work around apparent bug in the IME manager
     // in gecko.
     let readonly = element.getAttribute("readonly");
     if (readonly) {
       return false;
     }
 
     sendAsyncMessage("Forms:Input", getJSON(element));
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -42,16 +42,25 @@ var SettingsListener = {
     }));
 
     this._callbacks[name] = callback;
   }
 };
 
 SettingsListener.init();
 
+// =================== Audio ====================
+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));
+});
+
 
 // =================== Languages ====================
 SettingsListener.observe('language.current', 'en-US', function(value) {
   Services.prefs.setCharPref('intl.accept_languages', value);
 });
 
 
 // =================== RIL ====================
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -38,16 +38,20 @@ XPCOMUtils.defineLazyServiceGetter(Servi
                                    '@mozilla.org/focus-manager;1',
                                    'nsIFocusManager');
 
 XPCOMUtils.defineLazyGetter(this, 'DebuggerServer', function() {
   Cu.import('resource://gre/modules/devtools/dbg-server.jsm');
   return DebuggerServer;
 });
 
+function getContentWindow() {
+  return shell.contentBrowser.contentWindow;
+}
+
 // FIXME Bug 707625
 // until we have a proper security model, add some rights to
 // the pre-installed web applications
 // XXX never grant 'content-camera' to non-gaia apps
 function addPermissions(urls) {
   let permissions = [
     'indexedDB-unlimited', 'webapps-manage', 'offline-app', 'pin-app',
     'websettings-read', 'websettings-readwrite',
@@ -167,69 +171,32 @@ var shell = {
     window.removeEventListener('sizemodechange', this);
     this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true);
 
 #ifndef MOZ_WIDGET_GONK
     delete Services.audioManager;
 #endif
   },
 
-  changeVolume: function shell_changeVolume(delta) {
-    let steps = 10;
-    try {
-      steps = Services.prefs.getIntPref("media.volume.steps");
-      if (steps <= 0)
-        steps = 1;
-    } catch(e) {}
-
-    let audioManager = Services.audioManager;
-    if (!audioManager)
-      return;
-
-    let currentVolume = audioManager.masterVolume;
-    let newStep = Math.round(steps * Math.sqrt(currentVolume)) + delta;
-    let volume = (newStep / steps) * (newStep / steps);
-
-    if (volume > 1)
-      volume = 1;
-    if (volume < 0)
-      volume = 0;
-    audioManager.masterVolume = volume;
-  },
-
   forwardKeyToContent: function shell_forwardKeyToContent(evt) {
     let content = shell.contentBrowser.contentWindow;
     let generatedEvent = content.document.createEvent('KeyboardEvent');
     generatedEvent.initKeyEvent(evt.type, true, true, evt.view, evt.ctrlKey,
                                 evt.altKey, evt.shiftKey, evt.metaKey,
                                 evt.keyCode, evt.charCode);
 
     content.document.documentElement.dispatchEvent(generatedEvent);
   },
 
   handleEvent: function shell_handleEvent(evt) {
     let content = this.contentBrowser.contentWindow;
     switch (evt.type) {
       case 'keydown':
       case 'keyup':
       case 'keypress':
-        // For debug purposes and because some of the APIs are not yet exposed
-        // to the content, let's react on some of the keyup events.
-        if (evt.type == 'keyup' && evt.eventPhase == evt.BUBBLING_PHASE) {
-          switch (evt.keyCode) {
-            case evt.DOM_VK_PAGE_DOWN:
-              this.changeVolume(-1);
-              break;
-
-            case evt.DOM_VK_PAGE_UP:
-              this.changeVolume(1);
-              break;
-          }
-        }
-
         // Redirect the HOME key to System app and stop the applications from
         // handling it.
         let rootContentEvt = (evt.target.ownerDocument.defaultView == content);
         if (!rootContentEvt && evt.eventPhase == evt.CAPTURING_PHASE &&
             evt.keyCode == evt.DOM_VK_HOME) {
           this.forwardKeyToContent(evt);
           evt.preventDefault();
           evt.stopImmediatePropagation();
--- a/b2g/components/ContentPermissionPrompt.js
+++ b/b2g/components/ContentPermissionPrompt.js
@@ -29,38 +29,43 @@ ContentPermissionPrompt.prototype = {
 
   _id: 0,
   prompt: function(request) {
     // returns true if the request was handled
     if (this.handleExistingPermission(request))
        return;
 
     let browser = Services.wm.getMostRecentWindow("navigator:browser");
-    let content = browser.content;
+    let content = browser.getContentWindow();
     if (!content)
       return;
 
     let requestId = this._id++;
     content.addEventListener("mozContentEvent", function contentEvent(evt) {
       if (evt.detail.id != requestId)
         return;
+      evt.target.removeEventListener(evt.type, contentEvent);
 
-      content.removeEventListener(evt.type, contentEvent);
       if (evt.detail.type == "permission-allow") {
         request.allow();
         return;
       }
 
       request.cancel();
     });
 
-    browser.shell.sendEvent(browser.content, "mozChromeEvent", {
-      "type": "permission-prompt", "permission": request.type,
-      "id": requestId, "url": request.uri.spec
-    });
+    let details = {
+      "type": "permission-prompt",
+      "permission": request.type,
+      "id": requestId,
+      "url": request.uri.spec
+    };
+    let event = content.document.createEvent("CustomEvent");
+    event.initCustomEvent("mozChromeEvent", true, true, details);
+    content.dispatchEvent(event);
   },
 
   classID: Components.ID("{8c719f03-afe0-4aac-91ff-6c215895d467}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt])
 };
 
 
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1341001222000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1341959296000">
   <emItems>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i86" id="{45147e67-4020-47e2-8f7a-55464fb535aa}">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
@@ -23,17 +23,17 @@
                   </emItem>
       <emItem  blockID="i43" id="supportaccessplugin@gmail.com">
                         </emItem>
       <emItem  blockID="i82" id="{8f42fb8b-b6f6-45de-81c0-d6d39f54f971}">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i107" os="WINNT" id="{ABDE892B-13A8-4d1b-88E6-365A6E755758}">
-                        <versionRange  minVersion="0" maxVersion="15.0.4" severity="1">
+                        <versionRange  minVersion="0" maxVersion="15.0.5" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i88" id="anttoolbar@ant.com">
                         <versionRange  minVersion="2.4.6.4" maxVersion="2.4.6.4" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}">
                         <versionRange  minVersion="2.2" maxVersion="2.2">
@@ -210,16 +210,20 @@
       <emItem  blockID="i109" id="{392e123b-b691-4a5e-b52f-c4c1027e749c}">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i60" id="youtb3@youtb3.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i111" os="WINNT" id="{C3949AC2-4B17-43ee-B4F1-D26B9D42404D}">
+                        <versionRange  minVersion="0" maxVersion="15.0.5" severity="1">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i38" id="{B7082FAA-CB62-4872-9106-E42DD88EDE45}">
                         <versionRange  minVersion="0.1" maxVersion="3.3.0.*">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.7a1" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                                 <versionRange  minVersion="3.3.1" maxVersion="*">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
@@ -323,17 +327,17 @@
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i77" id="{fa277cfc-1d75-4949-a1f9-4ac8e41b2dfd}">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i106" os="WINNT" id="{97E22097-9A2F-45b1-8DAF-36AD648C7EF4}">
-                        <versionRange  minVersion="0" maxVersion="15.0.4" severity="1">
+                        <versionRange  minVersion="0" maxVersion="15.0.5" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i11" id="yslow@yahoo-inc.com">
                         <versionRange  minVersion="2.0.5" maxVersion="2.0.5">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.5.7" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
--- a/browser/base/content/abouthome/aboutHome.css
+++ b/browser/base/content/abouthome/aboutHome.css
@@ -38,16 +38,17 @@ a {
 }
 
 #topSection {
   text-align: center;
 }
 
 #brandLogo {
   height: 154px;
+  width: 154px;
   margin: 22px 0 31px;
 }
 
 #searchForm,
 #snippets {
   width: 470px;
 }
 
@@ -59,16 +60,18 @@ a {
   display: -moz-box;
   -moz-box-align: center;
   padding-top: 2px;
   -moz-padding-end: 8px;
 }
 
 #searchEngineLogo {
   display: inline-block;
+  height: 28px;
+  width: 70px;
 }
 
 #searchText {
   -moz-box-flex: 1;
   padding: 6px 8px;
   background: hsla(0,0%,100%,.9) padding-box;
   border: 1px solid;
   border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
@@ -77,17 +80,18 @@ a {
               0 1px 0 hsla(0,0%,100%,.2);
   border-radius: 2.5px 0 0 2.5px;
 }
 
 body[dir=rtl] #searchText {
   border-radius: 0 2.5px 2.5px 0;
 }
 
-#searchText:focus {
+#searchText:focus,
+#searchText[autofocus] {
   border-color: hsla(206,100%,60%,.6) hsla(206,76%,52%,.6) hsla(204,100%,40%,.6);
 }
 
 #searchSubmit {
   -moz-margin-start: -1px;
   background: -moz-linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.1)) padding-box;
   padding: 0 9px;
   border: 1px solid;
@@ -101,22 +105,24 @@ body[dir=rtl] #searchText {
   transition-duration: 150ms;
 }
 
 body[dir=rtl] #searchSubmit {
   border-radius: 2.5px 0 0 2.5px;
 }
 
 #searchText:focus + #searchSubmit,
-#searchText + #searchSubmit:hover {
+#searchText + #searchSubmit:hover,
+#searchText[autofocus] + #searchSubmit {
   border-color: #59b5fc #45a3e7 #3294d5;
   color: white;
 }
 
-#searchText:focus + #searchSubmit {
+#searchText:focus + #searchSubmit,
+#searchText[autofocus] + #searchSubmit {
   background-image: -moz-linear-gradient(#4cb1ff, #1793e5);
   box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset,
               0 0 0 1px hsla(0,0%,100%,.1) inset,
               0 1px 0 hsla(210,54%,20%,.03);
 }
 
 #searchText + #searchSubmit:hover {
   background-image: -moz-linear-gradient(#66bdff, #0d9eff);
@@ -155,16 +161,22 @@ body[dir=rtl] #defaultSnippet2 {
 }
 
 #snippets {
   display: inline-block;
   text-align: start;
   margin: 12px 0;
   color: #3c3c3c;
   font-size: 75%;
+  /* 12px is the computed font size, 15px the computed line height of the snippets
+     with Segoe UI on a default Windows 7 setup. The 15/12 multiplier approximately
+     converts em from units of font-size to units of line-height. The goal is to
+     preset the height of a three-line snippet to avoid visual moving/flickering as
+     the snippets load. */
+  min-height: -moz-calc(15/12 * 3em);
 }
 
 #launcher {
   display: -moz-box;
   -moz-box-align: center;
   -moz-box-pack: center;
   width: 100%;
   background-color: hsla(0,0%,0%,.03);
@@ -251,18 +263,19 @@ body[narrow] #restorePreviousSessionSepa
 }
 
 body[narrow] #restorePreviousSession {
   font-size: 80%;
 }
 
 .launchButton::before {
   display: block;
+  width: 32px;
   height: 32px;
-  margin-bottom: 6px;
+  margin: 0 auto 6px;
   line-height: 0; /* remove extra vertical space due to non-zero font-size */
 }
 
 #downloads::before {
   content: url("chrome://browser/content/abouthome/downloads.png");
 }
 
 #bookmarks::before {
--- a/browser/base/content/abouthome/aboutHome.js
+++ b/browser/base/content/abouthome/aboutHome.js
@@ -160,16 +160,25 @@ function setupSearchEngine()
 
   // Add search engine logo.
   if (gSearchEngine.image) {
     let logoElt = document.getElementById("searchEngineLogo");
     logoElt.src = gSearchEngine.image;
     logoElt.alt = gSearchEngine.name;
   }
 
+  // The "autofocus" attribute doesn't focus the form element
+  // immediately when the element is first drawn, so the
+  // attribute is also used for styling when the page first loads.
+  let searchText = document.getElementById("searchText");
+  searchText.addEventListener("blur", function searchText_onBlur() {
+    searchText.removeEventListener("blur", searchText_onBlur);
+    searchText.removeAttribute("autofocus");
+  });
+
 }
 
 function loadSnippets()
 {
   // Check last snippets update.
   let lastUpdate = localStorage["snippets-last-update"];
   let updateURL = localStorage["snippets-update-url"];
   if (updateURL && (!lastUpdate ||
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -100,16 +100,18 @@
     <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true"/>
     <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
     <command id="Tools:Sanitize"
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing" oncommand="gPrivateBrowsingUI.toggleMode();"/>
     <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
     <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
     <command id="Browser:ToggleAddonBar" oncommand="toggleAddonBar();"/>
+    <command id="Social:SharePage" oncommand="SocialShareButton.sharePage();"/>
+    <command id="Social:UnsharePage" oncommand="SocialShareButton.unsharePage();"/>
   </commandset>
 
   <commandset id="placesCommands">
     <command id="Browser:ShowAllBookmarks"
              oncommand="PlacesCommandHook.showPlacesOrganizer('AllBookmarks');"/>
     <command id="Browser:ShowAllHistory"
              oncommand="PlacesCommandHook.showPlacesOrganizer('History');"/>
   </commandset>
@@ -332,16 +334,17 @@
     <key id="manBookmarkKb" key="&bookmarksGtkCmd.commandkey;" command="Browser:ShowAllBookmarks" modifiers="accel,shift"/>
 #endif
     <key id="viewBookmarksSidebarKb" key="&bookmarksCmd.commandkey;" command="viewBookmarksSidebar" modifiers="accel"/>
 #ifdef XP_WIN
 # Cmd+I is conventially mapped to Info on MacOS X, thus it should not be
 # overridden for other purposes there.
     <key id="viewBookmarksSidebarWinKb" key="&bookmarksWinCmd.commandkey;" command="viewBookmarksSidebar" modifiers="accel"/>
 #endif
+    <key id="sharePage" key="&sharePageCmd.commandkey;" command="Social:SharePage" modifiers="accel,shift"/>
 
 # don't use |command="Browser:Stop"|, ESC is being used to freeze animated gifs,
 # even if the stop button and menuitem are disabled (see Bug 284140)
     <key id="key_stop" keycode="VK_ESCAPE" oncommand="BrowserStop();"/>
 
 #ifdef XP_MACOSX
     <key id="key_stop_mac" modifiers="accel" key="&stopCmd.macCommandKey;" oncommand="BrowserStop();"/>
 #endif
new file mode 100644
--- /dev/null
+++ b/browser/base/content/browser-social.js
@@ -0,0 +1,108 @@
+// 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 SocialUI = {
+  // Called on delayed startup to initialize UI
+  init: function SocialUI_init() {
+    Services.obs.addObserver(this, "social:pref-changed", false);
+    Social.init(this._providerReady.bind(this));
+  },
+
+  // Called on window unload
+  uninit: function SocialUI_uninit() {
+    Services.obs.removeObserver(this, "social:pref-changed");
+  },
+
+  // Called when the social.enabled pref is changed
+  observe: function SocialUI_observe(aSubject, aTopic, aData) {
+    SocialShareButton.updateButtonEnabledState();
+  },
+
+  // Called once Social.jsm's provider has been set
+  _providerReady: function SocialUI_providerReady() {
+    SocialShareButton.init();
+  }
+}
+
+let SocialShareButton = {
+  init: function SSB_init() {
+    this.sharePopup.hidden = false;
+    this.updateButtonEnabledState();
+  },
+
+  get shareButton() {
+    return document.getElementById("share-button");
+  },
+  get sharePopup() {
+    return document.getElementById("editSharePopup");
+  },
+
+  dismissSharePopup: function SSB_dismissSharePopup() {
+    this.sharePopup.hidePopup();
+  },
+
+  updateButtonEnabledState: function SSB_updateButtonEnabledState() {
+    let shareButton = this.shareButton;
+    if (shareButton)
+      shareButton.hidden = !Social.provider || !Social.provider.enabled ||
+                           !Social.provider.port;
+  },
+
+  onClick: function SSB_onClick(aEvent) {
+    if (aEvent.button != 0)
+      return;
+
+    // Don't bubble to the textbox, to avoid unwanted selection of the address.
+    aEvent.stopPropagation();
+
+    this.sharePage();
+  },
+
+  panelShown: function SSB_panelShown(aEvent) {
+    let sharePopupOkButton = document.getElementById("editSharePopupOkButton");
+    if (sharePopupOkButton)
+      sharePopupOkButton.focus();
+  },
+
+  sharePage: function SSB_sharePage() {
+    let uri = gBrowser.currentURI;
+    if (!Social.isPageShared(uri)) {
+      Social.sharePage(uri);
+      this.updateShareState();
+    } else {
+      this.sharePopup.openPopup(this.shareButton, "bottomcenter topright");
+    }
+  },
+
+  unsharePage: function SSB_unsharePage() {
+    Social.unsharePage(gBrowser.currentURI);
+    this.updateShareState();
+    this.dismissSharePopup();
+  },
+
+  updateShareState: function SSB_updateShareState() {
+    let currentPageShared = Social.isPageShared(gBrowser.currentURI);
+
+    // Provide a11y-friendly notification of share.
+    let status = document.getElementById("share-button-status");
+    if (status) {
+      let statusString = currentPageShared ?
+                           gNavigatorBundle.getString("social.pageShared.label") : "";
+      status.setAttribute("value", statusString);
+    }
+
+    // Update the share button, if present
+    let shareButton = this.shareButton;
+    if (!shareButton)
+      return;
+
+    if (currentPageShared) {
+      shareButton.setAttribute("shared", "true");
+      shareButton.setAttribute("tooltiptext", gNavigatorBundle.getString("social.shareButton.sharedtooltip"));
+    } else {
+      shareButton.removeAttribute("shared");
+      shareButton.setAttribute("tooltiptext", gNavigatorBundle.getString("social.shareButton.tooltip"));
+    }
+  }
+};
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -136,17 +136,17 @@ let gSyncUI = {
 
   onLoginFinish: function SUI_onLoginFinish() {
     // Clear out any login failure notifications
     let title = this._stringBundle.GetStringFromName("error.login.title");
     this.clearError(title);
   },
 
   onSetupComplete: function SUI_onSetupComplete() {
-    onLoginFinish();
+    this.onLoginFinish();
   },
 
   onLoginError: function SUI_onLoginError() {
     // if login fails, any other notifications are essentially moot
     Weave.Notifications.removeAll();
 
     // if we haven't set up the client, don't show errors
     if (this._needsSetup()) {
--- a/browser/base/content/browser-tabPreviews.js
+++ b/browser/base/content/browser-tabPreviews.js
@@ -92,17 +92,16 @@ var tabPreviews = {
 
 var tabPreviewPanelHelper = {
   opening: function (host) {
     host.panel.hidden = false;
 
     var handler = this._generateHandler(host);
     host.panel.addEventListener("popupshown", handler, false);
     host.panel.addEventListener("popuphiding", handler, false);
-    host.panel.addEventListener("popuphidden", handler, false);
 
     host._prevFocus = document.commandDispatcher.focusedElement;
   },
   _generateHandler: function (host) {
     var self = this;
     return function (event) {
       if (event.target == host.panel) {
         host.panel.removeEventListener(event.type, arguments.callee, false);
@@ -125,21 +124,16 @@ var tabPreviewPanelHelper = {
       host._prevFocus = null;
     } else
       gBrowser.selectedBrowser.focus();
 
     if (host.tabToSelect) {
       gBrowser.selectedTab = host.tabToSelect;
       host.tabToSelect = null;
     }
-  },
-  _popuphidden: function (host) {
-    // Destroy the widget in order to prevent outdated content
-    // when re-opening the panel.
-    host.panel.hidden = true;
   }
 };
 
 /**
  * Ctrl-Tab panel
  */
 var ctrlTab = {
   get panel () {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -129,30 +129,37 @@ XPCOMUtils.defineLazyGetter(this, "Debug
 });
 
 XPCOMUtils.defineLazyGetter(this, "Tilt", function() {
   let tmp = {};
   Cu.import("resource:///modules/devtools/Tilt.jsm", tmp);
   return new tmp.Tilt(window);
 });
 
+XPCOMUtils.defineLazyGetter(this, "Social", function() {
+  let tmp = {};
+  Cu.import("resource:///modules/Social.jsm", tmp);
+  return tmp.Social;
+});
+
 let gInitialPages = [
   "about:blank",
   "about:newtab",
   "about:home",
   "about:privatebrowsing",
   "about:sessionrestore"
 ];
 
 #include browser-addons.js
 #include browser-feeds.js
 #include browser-fullScreen.js
 #include browser-fullZoom.js
 #include browser-places.js
 #include browser-plugins.js
+#include browser-social.js
 #include browser-tabPreviews.js
 #include browser-tabview.js
 #include browser-thumbnails.js
 
 #ifdef MOZ_SERVICES_SYNC
 #include browser-syncui.js
 #endif
 
@@ -1241,16 +1248,17 @@ var gBrowserInit = {
     Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
     Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
     Services.obs.addObserver(gFormSubmitObserver, "invalidformsubmit", false);
 
     BrowserOffline.init();
     OfflineApps.init();
     IndexedDBPromptHelper.init();
     gFormSubmitObserver.init();
+    SocialUI.init();
     AddonManager.addAddonListener(AddonsMgrListener);
 
     gBrowser.addEventListener("pageshow", function(evt) { setTimeout(pageShowEventHandlers, 0, evt); }, true);
 
     // Ensure login manager is up and running.
     Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
 
     if (mustLoadSidebar) {
@@ -1612,16 +1620,17 @@ var gBrowserInit = {
       } catch (ex) {
         Cu.reportError(ex);
       }
 
       BrowserOffline.uninit();
       OfflineApps.uninit();
       IndexedDBPromptHelper.uninit();
       AddonManager.removeAddonListener(AddonsMgrListener);
+      SocialUI.uninit();
     }
 
     // Final window teardown, do this last.
     window.XULBrowserWindow.destroy();
     window.XULBrowserWindow = null;
     window.QueryInterface(Ci.nsIInterfaceRequestor)
           .getInterface(Ci.nsIWebNavigation)
           .QueryInterface(Ci.nsIDocShellTreeItem).treeOwner
@@ -3557,16 +3566,17 @@ function BrowserToolboxCustomizeDone(aTo
   UpdateUrlbarSearchSplitterState();
   setUrlAndSearchBarWidthForConditionalForwardButton();
 
   // Update the urlbar
   if (gURLBar) {
     URLBarSetURI();
     XULBrowserWindow.asyncUpdateUI();
     PlacesStarButton.updateState();
+    SocialShareButton.updateShareState();
   }
 
   TabsInTitlebar.allowedBy("customizing-toolbars", true);
 
   // Re-enable parts of the UI we disabled during the dialog
   var menubar = document.getElementById("main-menubar");
   for (var i = 0; i < menubar.childNodes.length; ++i)
     menubar.childNodes[i].setAttribute("disabled", false);
@@ -4035,16 +4045,17 @@ var XULBrowserWindow = {
         let uri = aLocationURI;
         try {
           uri = this._uriFixup.createExposableURI(uri);
         } catch (e) {}
         URLBarSetURI(uri);
 
         // Update starring UI
         PlacesStarButton.updateState();
+        SocialShareButton.updateShareState();
       }
 
       // Show or hide browser chrome based on the whitelist
       if (this.hideChromeForLocation(location)) {
         document.documentElement.setAttribute("disablechrome", "true");
       } else {
         let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
         if (ss.getTabValue(gBrowser.selectedTab, "appOrigin"))
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -177,16 +177,55 @@
                 class="editBookmarkPanelBottomButton"
                 label="&editBookmark.done.label;"
                 default="true"
                 oncommand="StarUI.panel.hidePopup();"/>
 #endif
       </hbox>
     </panel>
 
+    <panel id="editSharePopup"
+           type="arrow"
+           orient="vertical"
+           ignorekeys="true"
+           hidden="true"
+           onpopupshown="SocialShareButton.panelShown(event);"
+           consumeoutsideclicks="true"
+           level="top">
+      <hbox id="editSharePopupBottomButtons" pack="end">
+#ifdef XP_UNIX
+        <button id="editSharePopupUndoButton"
+                class="editSharePopupBottomButton"
+                label="&social.sharePopup.undo.label;"
+                accesskey="&social.sharePopup.undo.accesskey;"
+                command="Social:UnsharePage"/>
+        <button id="editSharePopupOkButton"
+                class="editSharePopupBottomButton"
+                default="true"
+                autofocus="autofocus"
+                label="&social.sharePopup.ok.label;"
+                accesskey="&social.sharePopup.ok.accesskey;"
+                oncommand="SocialShareButton.dismissSharePopup();"/>
+#else
+        <button id="editSharePopupOkButton"
+                class="editSharePopupBottomButton"
+                default="true"
+                autofocus="autofocus"
+                label="&social.sharePopup.ok.label;"
+                accesskey="&social.sharePopup.ok.accesskey;"
+                oncommand="SocialShareButton.dismissSharePopup();"/>
+        <button id="editSharePopupUndoButton"
+                class="editSharePopupBottomButton"
+                label="&social.sharePopup.undo.label;"
+                accesskey="&social.sharePopup.undo.accesskey;"
+                command="Social:UnsharePage"/>
+#endif
+      </hbox>
+    </panel>
+
     <menupopup id="inspector-node-popup">
       <menuitem id="inspectorHTMLCopyInner"
                 label="&inspectorHTMLCopyInner.label;"
                 accesskey="&inspectorHTMLCopyInner.accesskey;"
                 command="Inspector:CopyInner"/>
       <menuitem id="inspectorHTMLCopyOuter"
                 label="&inspectorHTMLCopyOuter.label;"
                 accesskey="&inspectorHTMLCopyOuter.accesskey;"
@@ -459,16 +498,17 @@
                  autocompletesearch="urlinline history"
                  autocompletesearchparam="enable-actions"
                  autocompletepopup="PopupAutoCompleteRichResult"
                  completeselectedindex="true"
                  tabscrolling="true"
                  showcommentcolumn="true"
                  showimagecolumn="true"
                  enablehistory="true"
+                 maxrows="6"
                  newlines="stripsurroundingwhitespace"
                  oninput="gBrowser.userTypedValue = this.value;"
                  ontextentered="this.handleCommand(param);"
                  ontextreverted="return this.handleRevert();"
                  pageproxystate="invalid"
                  onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'"
                  onblur="setTimeout(function() document.getElementById('identity-box').style.MozUserFocus = '', 0);">
           <box id="notification-popup-box" hidden="true" align="center">
@@ -502,16 +542,22 @@
           </box>
           <hbox id="urlbar-icons">
             <image id="page-report-button"
                    class="urlbar-icon"
                    hidden="true"
                    tooltiptext="&pageReportIcon.tooltip;"
                    onclick="gPopupBlockerObserver.onReportButtonClick(event);"/>
 
+            <label id="share-button-status" collapsed="true" role="status"/>
+            <image id="share-button"
+                   class="urlbar-icon"
+                   hidden="true"
+                   onclick="SocialShareButton.onClick(event);"/>
+
             <image id="star-button"
                    class="urlbar-icon"
                    onclick="PlacesStarButton.onClick(event);"/>
             <image id="go-button"
                    class="urlbar-icon"
                    tooltiptext="&goEndCap.tooltip;"
                    onclick="gURLBar.handleCommand(event);"/>
           </hbox>
--- a/browser/base/content/sync/utils.js
+++ b/browser/base/content/sync/utils.js
@@ -192,18 +192,16 @@ let gSyncUtils = {
     if (!el2)
       valid = val1.length >= Weave.MIN_PASS_LENGTH;
     else if (val1 && val1 == Weave.Identity.username)
       error = "change.password.pwSameAsUsername";
     else if (val1 && val1 == Weave.Identity.account)
       error = "change.password.pwSameAsEmail";
     else if (val1 && val1 == Weave.Identity.basicPassword)
       error = "change.password.pwSameAsPassword";
-    else if (val1 && val1 == Weave.Identity.syncKey)
-      error = "change.password.pwSameAsRecoveryKey";
     else if (val1 && val2) {
       if (val1 == val2 && val1.length >= Weave.MIN_PASS_LENGTH)
         valid = true;
       else if (val1.length < Weave.MIN_PASS_LENGTH)
         error = "change.password.tooShort";
       else if (val1 != val2)
         error = "change.password.mismatch";
     }
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -57,16 +57,18 @@ endif
 # browser_sanitizeDialog_treeView.js is disabled until the tree view is added
 # back to the clear recent history dialog (sanitize.xul), if it ever is (bug
 # 480169)
 
 # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
 
 # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
 
+# browser_pageInfo.js + feed_tab.html is disabled for leaking (bug 767896)
+
 _BROWSER_FILES = \
                  head.js \
                  browser_typeAheadFind.js \
                  browser_keywordSearch.js \
                  browser_allTabsPanel.js \
                  browser_alltabslistener.js \
                  browser_bug304198.js \
                  title_test.svg \
@@ -149,16 +151,17 @@ endif
                  browser_bug710878.js \
                  browser_bug719271.js \
                  browser_bug724239.js \
                  browser_bug735471.js \
                  browser_bug743421.js \
                  browser_bug749738.js \
                  browser_bug763468.js \
                  browser_bug767836.js \
+                 browser_shareButton.js \
                  browser_canonizeURL.js \
                  browser_customize.js \
                  browser_findbarClose.js \
                  browser_homeDrop.js \
                  browser_keywordBookmarklets.js \
                  browser_contextSearchTabPosition.js \
                  browser_ctrlTab.js \
                  browser_customize_popupNotification.js \
@@ -166,17 +169,16 @@ endif
                  browser_discovery.js \
                  browser_duplicateIDs.js \
                  browser_gestureSupport.js \
                  browser_getshortcutoruri.js \
                  browser_hide_removing.js \
                  browser_overflowScroll.js \
                  browser_locationBarCommand.js \
                  browser_locationBarExternalLoad.js \
-                 browser_pageInfo.js \
                  browser_page_style_menu.js \
                  browser_pinnedTabs.js \
                  browser_plainTextLinks.js \
                  browser_pluginnotification.js \
                  browser_relatedTabs.js \
                  browser_sanitize-passwordDisabledHosts.js \
                  browser_sanitize-sitepermissions.js \
                  browser_sanitize-timespans.js \
@@ -214,17 +216,16 @@ endif
                  disablechrome.html \
                  discovery.html \
                  domplate_test.js \
                  moz.png \
                  video.ogg \
                  test_bug435035.html \
                  test_bug462673.html \
                  page_style_sample.html \
-                 feed_tab.html \
                  plugin_unknown.html \
                  plugin_test.html \
                  plugin_test2.html \
                  plugin_test3.html \
                  plugin_alternate_content.html \
                  plugin_both.html \
                  plugin_both2.html \
                  plugin_bug743421.html \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_shareButton.js
@@ -0,0 +1,160 @@
+/* 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 prefName = "social.enabled",
+    shareButton,
+    sharePopup,
+    okButton,
+    undoButton;
+
+function test() {
+  waitForExplicitFinish();
+
+  // Need to load a non-empty page for the social share button to appear
+  let tab = gBrowser.selectedTab = gBrowser.addTab("about:", {skipAnimation: true});
+  tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
+    tab.linkedBrowser.removeEventListener("load", tabLoad, true);
+    executeSoon(tabLoaded);
+  }, true);
+
+  // Enable the service to start
+  Services.prefs.setBoolPref(prefName, true);
+
+  registerCleanupFunction(function() {
+    Services.prefs.clearUserPref(prefName);
+    gBrowser.removeTab(tab);
+  });
+}
+
+function tabLoaded() {
+  ok(Social, "Social module loaded");
+
+  // If the UI is already active, run the test immediately, otherwise wait
+  // for initialization.
+  if (Social.provider) {
+    executeSoon(testInitial);
+  } else {
+    Services.obs.addObserver(function obs() {
+      Services.obs.removeObserver(obs, "test-social-ui-ready");
+      executeSoon(testInitial);
+    }, "test-social-ui-ready", false);
+  }
+}
+
+function testInitial() {
+  ok(Social.provider, "Social provider is active");
+  ok(Social.provider.enabled, "Social provider is enabled");
+  ok(Social.provider.port, "Social provider has a port to its FrameWorker");
+
+  shareButton = SocialShareButton.shareButton;
+  sharePopup = SocialShareButton.sharePopup;
+  ok(shareButton, "share button exists");
+  ok(sharePopup, "share popup exists");
+  ok(!sharePopup.hidden, "share popup is not hidden");
+
+  okButton = document.getElementById("editSharePopupOkButton");
+  undoButton = document.getElementById("editSharePopupUndoButton");
+
+  is(shareButton.hidden, false, "share button should be visible");
+
+  // Test clicking the share button
+  shareButton.addEventListener("click", function listener() {
+    shareButton.removeEventListener("click", listener);
+    is(shareButton.hasAttribute("shared"), true, "Share button should have 'shared' attribute after share button is clicked");
+    executeSoon(testSecondClick.bind(window, testPopupOKButton));
+  });
+  EventUtils.synthesizeMouseAtCenter(shareButton, {});
+}
+
+function testSecondClick(nextTest) {
+  sharePopup.addEventListener("popupshown", function listener() {
+    sharePopup.removeEventListener("popupshown", listener);
+    ok(true, "popup was shown after second click");
+    executeSoon(nextTest);
+  });
+  EventUtils.synthesizeMouseAtCenter(shareButton, {});
+}
+
+function testPopupOKButton() {
+  sharePopup.addEventListener("popuphidden", function listener() {
+    sharePopup.removeEventListener("popuphidden", listener);
+    is(shareButton.hasAttribute("shared"), true, "Share button should still have 'shared' attribute after OK button is clicked");
+    executeSoon(testSecondClick.bind(window, testPopupUndoButton));
+  });
+  EventUtils.synthesizeMouseAtCenter(okButton, {});
+}
+
+function testPopupUndoButton() {
+  sharePopup.addEventListener("popuphidden", function listener() {
+    sharePopup.removeEventListener("popuphidden", listener);
+    is(shareButton.hasAttribute("shared"), false, "Share button should not have 'shared' attribute after Undo button is clicked");
+    executeSoon(testShortcut);
+  });
+  EventUtils.synthesizeMouseAtCenter(undoButton, {});
+}
+
+function testShortcut() {
+  let keyTarget = window;
+  keyTarget.addEventListener("keyup", function listener() {
+    keyTarget.removeEventListener("keyup", listener);
+    executeSoon(checkShortcutWorked.bind(window, keyTarget));
+  });
+  EventUtils.synthesizeKey("l", {accelKey: true, shiftKey: true}, keyTarget);
+}
+
+function checkShortcutWorked(keyTarget) {
+  is(shareButton.hasAttribute("shared"), true, "Share button should be in the 'shared' state after keyboard shortcut is used");
+
+  // Test a second invocation of the shortcut
+  sharePopup.addEventListener("popupshown", function listener() {
+    sharePopup.removeEventListener("popupshown", listener);
+    ok(true, "popup was shown after second use of keyboard shortcut");
+    executeSoon(checkOKButton);
+  });
+  EventUtils.synthesizeKey("l", {accelKey: true, shiftKey: true}, keyTarget);
+}
+
+function checkOKButton() {
+  is(document.activeElement, okButton, "ok button should be focused by default");
+  checkNextInTabOrder(undoButton, function () {
+    checkNextInTabOrder(okButton, testCloseBySpace);
+  });
+}
+
+function checkNextInTabOrder(element, next) {
+  // This particular test doesn't really apply on Mac, since buttons aren't
+  // focusable by default.
+  if (navigator.platform.indexOf("Mac") != -1) {
+    executeSoon(next);
+    return;
+  }
+
+  function listener() {
+    element.removeEventListener("focus", listener);
+    is(document.activeElement, element, element.id + " should be next in tab order");
+    executeSoon(next);
+  }
+  element.addEventListener("focus", listener);
+  // Register a cleanup function to remove the listener in case this test fails
+  registerCleanupFunction(function () {
+    element.removeEventListener("focus", listener);
+  });
+  EventUtils.synthesizeKey("VK_TAB", {});
+}
+
+function testCloseBySpace() {
+  is(document.activeElement.id, okButton.id, "testCloseBySpace, the ok button should be focused");
+  sharePopup.addEventListener("popuphidden", function listener() {
+    sharePopup.removeEventListener("popuphidden", listener);
+    ok(true, "space closed the share popup");
+    executeSoon(testDisable);
+  });
+  EventUtils.synthesizeKey("VK_SPACE", {});
+}
+
+function testDisable() {
+  Services.prefs.setBoolPref(prefName, false);
+  is(shareButton.hidden, true, "Share button should be hidden when pref is disabled");
+  finish();
+}
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -620,18 +620,16 @@
             case "underflow":
               this._contentIsCropped = false;
               this._hideURLTooltip();
               break;
           }
         ]]></body>
       </method>
 
-      <property name="maxRows" onget="return this.popup.maxResults;"/>
-
       <property name="textValue"
                 onget="return this.value;">
         <setter>
           <![CDATA[
           try {
             val = losslessDecodeURI(makeURI(val));
           } catch (ex) { }
 
--- a/browser/components/shell/src/nsWindowsShellService.cpp
+++ b/browser/components/shell/src/nsWindowsShellService.cpp
@@ -189,29 +189,26 @@ static SETTING gDDESettings[] = {
   { MAKE_KEY_NAME1("Software\\Classes\\FirefoxURL", SOD) },
 
   // Protocol Handlers
   { MAKE_KEY_NAME1("Software\\Classes\\FTP", SOD) },
   { MAKE_KEY_NAME1("Software\\Classes\\HTTP", SOD) },
   { MAKE_KEY_NAME1("Software\\Classes\\HTTPS", SOD) }
 };
 
-// See Bug 770883
-#if 0
 #if defined(MOZ_MAINTENANCE_SERVICE)
 
 #define ONLY_SERVICE_LAUNCHING
 #include "updatehelper.h"
 #include "updatehelper.cpp"
 
 static const char *kPrefetchClearedPref =
   "app.update.service.lastVersionPrefetchCleared";
 static nsCOMPtr<nsIThread> sThread;
 #endif
-#endif
 
 nsresult
 GetHelperPath(nsAutoString& aPath)
 {
   nsresult rv;
   nsCOMPtr<nsIProperties> directoryService = 
     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -999,18 +996,16 @@ nsWindowsShellService::SetDesktopBackgro
   NS_ENSURE_SUCCESS(rv, rv);
 
   return regKey->Close();
 }
 
 nsWindowsShellService::nsWindowsShellService() : 
   mCheckedThisSession(false) 
 {
-// See Bug 770883
-#if 0
 #if defined(MOZ_MAINTENANCE_SERVICE)
 
   // Check to make sure the service is installed
   PRUint32 installed = 0;
   nsCOMPtr<nsIWindowsRegKey> regKey = 
     do_CreateInstance("@mozilla.org/windows-registry-key;1");
   if (!regKey || 
       NS_FAILED(regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
@@ -1045,38 +1040,32 @@ nsWindowsShellService::nsWindowsShellSer
   // service command.
   mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
   if (mTimer) {
     mTimer->InitWithFuncCallback(
       nsWindowsShellService::LaunchPrefetchClearCommand, 
       nsnull, CLEAR_PREFETCH_TIMEOUT_MS, nsITimer::TYPE_ONE_SHOT);
   }
 #endif
-#endif
 }
 
 nsWindowsShellService::~nsWindowsShellService()
 {
-// See Bug 770883
-#if 0
 #if defined(MOZ_MAINTENANCE_SERVICE)
  if (mTimer) {
     mTimer->Cancel();
     mTimer = nsnull;
   }
   if (sThread) {
     sThread->Shutdown();
     sThread = nsnull;
   }
 #endif
-#endif
 }
 
-// See Bug 770883
-#if 0
 #if defined(MOZ_MAINTENANCE_SERVICE)
 
 class ClearPrefetchEvent : public nsRunnable {
 public:
   ClearPrefetchEvent()
   {
   }
 
@@ -1089,29 +1078,26 @@ public:
     // If this command fails, it is not critical as prefetch will be cleared
     // on the next software update.
     StartServiceCommand(NS_ARRAY_LENGTH(updaterServiceArgv), 
                         updaterServiceArgv);
     return NS_OK;
   }
 };
 #endif
-#endif
 
 /**
  * For faster startup we attempt to clear the prefetch if the maintenance
  * service is installed.  Please see the definition of ClearPrefetch()
  * in toolkit/components/maintenanceservice/prefetch.cpp for more info.
  * For now the only application that gets prefetch cleaned is Firefox
  * since we have not done performance checking for other applications.
  * This is done on every update but also there is a one time operation done
  * from within the program for first time installs.
  */ 
-// See Bug 770883
-#if 0
 #if defined(MOZ_MAINTENANCE_SERVICE)
 void
 nsWindowsShellService::LaunchPrefetchClearCommand(nsITimer *aTimer, void*)
 {
   // Make sure we don't call this again from the application, it will be
   // called on each application update instead.
   nsCOMPtr<nsIPrefBranch> prefBranch;
   nsCOMPtr<nsIPrefService> prefs =
@@ -1126,17 +1112,16 @@ nsWindowsShellService::LaunchPrefetchCle
   // main thread, so start an event on another thread to handle the operation
   NS_NewThread(getter_AddRefs(sThread));
   if (sThread) {
     nsCOMPtr<nsIRunnable> prefetchEvent = new ClearPrefetchEvent();
     sThread->Dispatch(prefetchEvent, NS_DISPATCH_NORMAL);
   }
 }
 #endif
-#endif
 
 NS_IMETHODIMP
 nsWindowsShellService::OpenApplicationWithURI(nsIFile* aApplication,
                                               const nsACString& aURI)
 {
   nsresult rv;
   nsCOMPtr<nsIProcess> process = 
     do_CreateInstance("@mozilla.org/process/util;1", &rv);
--- a/browser/config/tooltool-manifests/linux32/clang.manifest
+++ b/browser/config/tooltool-manifests/linux32/clang.manifest
@@ -1,15 +1,17 @@
 [
-{"clang_version": "r159509"},
+{
+"clang_version": "r160176"
+},
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 74071397,
-"digest": "390e499161e8b5e91c179f3352ecbb07431e3d5a190298de7f338b48fe3807f3ddbeca72d8df39d11f89864fb1135f14500471faa741d3886b875b8e2b1d4416",
+"size": 74224137,
+"digest": "74963bd6531e7f39e65b50adacc2ef86ba710b6a0d68bbcba7579267bef156a0d9506e389d08483a003d0d05d5d078e7036092f928d37675b9c1f5bb518ae5ce",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/linux64/clang.manifest
+++ b/browser/config/tooltool-manifests/linux64/clang.manifest
@@ -1,15 +1,17 @@
 [
-{"clang_version": "r159509"},
+{
+"clang_version": "r160176"
+},
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 72518043,
-"digest": "447dac319a8d7fa902cc065b758440bf6d4a7a98104362162fbdb0479a44d9b84c5878506f09be4398053a6ddc07935c7fb4f71e59b178073876fb5f90a45219",
+"size": 72747617,
+"digest": "4608fd00c4dbea8d640e16bcebaf0b8bc16506ffe50fe13726e2e565d3534a3452390c63a49044748863ca94eed22a0c4f44319f6d180badd5c36de411b8722e",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx64/clang.manifest
+++ b/browser/config/tooltool-manifests/macosx64/clang.manifest
@@ -1,15 +1,17 @@
 [
-{"clang_version": "r159509"},
+{
+"clang_version": "r160176"
+},
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 63679229,
-"digest": "5257503e537b8d440b17e40aa06f0f70f1b124129c02f10e45b46ac642fc4170bfa77ae737a8bcac3ed7602ccd934a88cbe349986eb971d66a6fb553ae31f13c",
+"size": 63767767,
+"digest": "99e333756750a3bcdf9ef3cfd722e7165558e53396dabf3af2aab3f2e60a2c5b0023fb45f8b161d0f21d4281e02749f202a3f364d78de900b6d79c60aa350ba3",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- 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.3.345
+Current extension version is: 0.3.452
 
deleted file mode 100644
--- a/browser/extensions/pdfjs/bootstrap.js
+++ /dev/null
@@ -1,111 +0,0 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-'use strict';
-
-const RESOURCE_NAME = 'pdf.js';
-const EXT_PREFIX = 'extensions.uriloader@pdf.js';
-
-let Cc = Components.classes;
-let Ci = Components.interfaces;
-let Cm = Components.manager;
-let Cu = Components.utils;
-
-Cu.import('resource://gre/modules/Services.jsm');
-
-function getBoolPref(pref, def) {
-  try {
-    return Services.prefs.getBoolPref(pref);
-  } catch (ex) {
-    return def;
-  }
-}
-
-function setStringPref(pref, value) {
-  let str = Cc['@mozilla.org/supports-string;1']
-              .createInstance(Ci.nsISupportsString);
-  str.data = value;
-  Services.prefs.setComplexValue(pref, Ci.nsISupportsString, str);
-}
-
-function log(str) {
-  if (!getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false))
-    return;
-  dump(str + '\n');
-}
-
-// Register/unregister a class as a component.
-let Factory = {
-  registrar: null,
-  aClass: null,
-  register: function(aClass) {
-    if (this.aClass) {
-      log('Cannot register more than one class');
-      return;
-    }
-    this.registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
-    this.aClass = aClass;
-    var proto = aClass.prototype;
-    this.registrar.registerFactory(proto.classID, proto.classDescription,
-      proto.contractID, this);
-  },
-  unregister: function() {
-    if (!this.aClass) {
-      log('Class was never registered.');
-      return;
-    }
-    var proto = this.aClass.prototype;
-    this.registrar.unregisterFactory(proto.classID, this);
-    this.aClass = null;
-  },
-  // nsIFactory::createInstance
-  createInstance: function(outer, iid) {
-    if (outer !== null)
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    return (new (this.aClass)).QueryInterface(iid);
-  }
-};
-
-let pdfStreamConverterUrl = null;
-
-// As of Firefox 13 bootstrapped add-ons don't support automatic registering and
-// unregistering of resource urls and components/contracts. Until then we do
-// it programatically. See ManifestDirective ManifestParser.cpp for support.
-
-function startup(aData, aReason) {
-  // Setup the resource url.
-  var ioService = Services.io;
-  var resProt = ioService.getProtocolHandler('resource')
-                  .QueryInterface(Ci.nsIResProtocolHandler);
-  var aliasURI = ioService.newURI('content/', 'UTF-8', aData.resourceURI);
-  resProt.setSubstitution(RESOURCE_NAME, aliasURI);
-
-  // Load the component and register it.
-  pdfStreamConverterUrl = aData.resourceURI.spec +
-                          'components/PdfStreamConverter.js';
-  Cu.import(pdfStreamConverterUrl);
-  Factory.register(PdfStreamConverter);
-}
-
-function shutdown(aData, aReason) {
-  if (aReason == APP_SHUTDOWN)
-    return;
-  var ioService = Services.io;
-  var resProt = ioService.getProtocolHandler('resource')
-                  .QueryInterface(Ci.nsIResProtocolHandler);
-  // Remove the resource url.
-  resProt.setSubstitution(RESOURCE_NAME, null);
-  // Remove the contract/component.
-  Factory.unregister();
-  // Unload the converter
-  Cu.unload(pdfStreamConverterUrl);
-  pdfStreamConverterUrl = null;
-}
-
-function install(aData, aReason) {
-}
-
-function uninstall(aData, aReason) {
-  setStringPref(EXT_PREFIX + '.database', '{}');
-}
-
--- a/browser/extensions/pdfjs/components/PdfStreamConverter.js
+++ b/browser/extensions/pdfjs/components/PdfStreamConverter.js
@@ -123,47 +123,65 @@ function getLocalizedString(strings, id,
 }
 
 // All the priviledged actions.
 function ChromeActions(domWindow) {
   this.domWindow = domWindow;
 }
 
 ChromeActions.prototype = {
-  download: function(data) {
-    var handlerInfo = Svc.mime
-                         .getFromTypeAndExtension('application/pdf', 'pdf');
-    var uri = NetUtil.newURI(data);
-
+  download: function(data, sendResponse) {
+    var originalUrl = data.originalUrl;
+    // The data may not be downloaded so we need just retry getting the pdf with
+    // the original url.
+    var originalUri = NetUtil.newURI(data.originalUrl);
+    var blobUri = data.blobUrl ? NetUtil.newURI(data.blobUrl) : originalUri;
     var extHelperAppSvc =
           Cc['@mozilla.org/uriloader/external-helper-app-service;1'].
-            getService(Ci.nsIExternalHelperAppService);
+             getService(Ci.nsIExternalHelperAppService);
     var frontWindow = Cc['@mozilla.org/embedcomp/window-watcher;1'].
-                        getService(Ci.nsIWindowWatcher).activeWindow;
-    var ioService = Services.io;
-    var channel = ioService.newChannel(data, null, null);
-    var listener = {
-      extListener: null,
-      onStartRequest: function(aRequest, aContext) {
-        this.extListener = extHelperAppSvc.doContent('application/pdf',
-                              aRequest, frontWindow, false);
-        this.extListener.onStartRequest(aRequest, aContext);
-      },
-      onStopRequest: function(aRequest, aContext, aStatusCode) {
-        if (this.extListener)
-          this.extListener.onStopRequest(aRequest, aContext, aStatusCode);
-      },
-      onDataAvailable: function(aRequest, aContext, aInputStream, aOffset,
-                                aCount) {
-        this.extListener.onDataAvailable(aRequest, aContext, aInputStream,
-                                         aOffset, aCount);
+                         getService(Ci.nsIWindowWatcher).activeWindow;
+
+    NetUtil.asyncFetch(blobUri, function(aInputStream, aResult) {
+      if (!Components.isSuccessCode(aResult)) {
+        if (sendResponse)
+          sendResponse(true);
+        return;
       }
-    };
+      // Create a nsIInputStreamChannel so we can set the url on the channel
+      // so the filename will be correct.
+      let channel = Cc['@mozilla.org/network/input-stream-channel;1'].
+                       createInstance(Ci.nsIInputStreamChannel);
+      channel.setURI(originalUri);
+      channel.contentStream = aInputStream;
+      channel.QueryInterface(Ci.nsIChannel);
 
-    channel.asyncOpen(listener, null);
+      var listener = {
+        extListener: null,
+        onStartRequest: function(aRequest, aContext) {
+          this.extListener = extHelperAppSvc.doContent('application/pdf',
+                                aRequest, frontWindow, false);
+          this.extListener.onStartRequest(aRequest, aContext);
+        },
+        onStopRequest: function(aRequest, aContext, aStatusCode) {
+          if (this.extListener)
+            this.extListener.onStopRequest(aRequest, aContext, aStatusCode);
+          // Notify the content code we're done downloading.
+          if (sendResponse)
+            sendResponse(false);
+        },
+        onDataAvailable: function(aRequest, aContext, aInputStream, aOffset,
+                                  aCount) {
+          this.extListener.onDataAvailable(aRequest, aContext, aInputStream,
+                                           aOffset, aCount);
+        }
+      };
+
+      channel.asyncOpen(listener, null);
+    });
   },
   setDatabase: function(data) {
     if (inPrivateBrowsing)
       return;
     // Protect against something sending tons of data to setDatabase.
     if (data.length > MAX_DATABASE_LENGTH)
       return;
     setStringPref(PREF_PREFIX + '.database', data);
@@ -190,58 +208,91 @@ ChromeActions.prototype = {
     }
   },
   pdfBugEnabled: function() {
     return getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false);
   },
   searchEnabled: function() {
     return getBoolPref(PREF_PREFIX + '.searchEnabled', false);
   },
-  fallback: function(url) {
+  fallback: function(url, sendResponse) {
     var self = this;
     var domWindow = this.domWindow;
     var strings = getLocalizedStrings('chrome.properties');
     var message = getLocalizedString(strings, 'unsupported_feature');
 
     var win = Services.wm.getMostRecentWindow('navigator:browser');
     var browser = win.gBrowser.getBrowserForDocument(domWindow.top.document);
     var notificationBox = win.gBrowser.getNotificationBox(browser);
+    // Flag so we don't call the response callback twice, since if the user
+    // clicks open with different viewer both the button callback and
+    // eventCallback will be called.
+    var sentResponse = false;
     var buttons = [{
       label: getLocalizedString(strings, 'open_with_different_viewer'),
       accessKey: getLocalizedString(strings, 'open_with_different_viewer',
                                     'accessKey'),
       callback: function() {
-        self.download(url);
+        sentResponse = true;
+        sendResponse(true);
       }
     }];
     notificationBox.appendNotification(message, 'pdfjs-fallback', null,
                                        notificationBox.PRIORITY_WARNING_LOW,
-                                       buttons);
+                                       buttons,
+                                       function eventsCallback(eventType) {
+      // Currently there is only one event "removed" but if there are any other
+      // added in the future we still only care about removed at the moment.
+      if (eventType !== 'removed')
+        return;
+      // Don't send a response again if we already responded when the button was
+      // clicked.
+      if (!sentResponse)
+        sendResponse(false);
+    });
   }
 };
 
 // Event listener to trigger chrome privedged code.
 function RequestListener(actions) {
   this.actions = actions;
 }
-// Receive an event and synchronously responds.
+// Receive an event and synchronously or asynchronously responds.
 RequestListener.prototype.receive = function(event) {
   var message = event.target;
+  var doc = message.ownerDocument;
   var action = message.getUserData('action');
   var data = message.getUserData('data');
+  var sync = message.getUserData('sync');
   var actions = this.actions;
   if (!(action in actions)) {
     log('Unknown action: ' + action);
     return;
   }
-  var response = actions[action].call(this.actions, data);
-  message.setUserData('response', response, null);
+  if (sync) {
+    var response = actions[action].call(this.actions, data);
+    message.setUserData('response', response, null);
+  } else {
+    var response;
+    if (!message.getUserData('callback')) {
+      doc.documentElement.removeChild(message);
+      response = null;
+    } else {
+      response = function sendResponse(response) {
+        message.setUserData('response', response, null);
+
+        var listener = doc.createEvent('HTMLEvents');
+        listener.initEvent('pdf.js.response', true, false);
+        return message.dispatchEvent(listener);
+      }
+    }
+    actions[action].call(this.actions, data, response);
+  }
 };
 
-
 function PdfStreamConverter() {
 }
 
 PdfStreamConverter.prototype = {
 
   // properties required for XPCOM registration:
   classID: Components.ID('{d0c5195d-e798-49d4-b1d3-9324328b2291}'),
   classDescription: 'pdf.js Component',
index 12ce45f876b12eef3e5030b492d58d5fbb47ebbf..fc7023f2aafcdbb3b2412934c017225637c8bb9e
GIT binary patch
literal 417
zc$@*D0bc%zP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0004KNkl<Zc-p1X
zJxjwt7zgl^F4m=@tI(yT7>Y`u@r0Pg5(gItKS4o}g1A}g%jhT};$T7OAPy;H>flra
z2St?bnbSZL$Y+TEgF85m2n7#*aQD1j5<>Dk{}-_qVGT5BavG17$sDU1MbRrJ{zyK9
zAb6?OYC6B5c=6<(=Xqa_<9rLQ>rQ>&pH3!|N91>*sXm<;Tn)o;j2qwn@D3lU*=#mu
zy+CvXM(`|4({yNA*0pWh{VdCdY92<c7YN1SNfyWPfKqyj+y-o#rrAxBWT4iuULZR-
zJP7!h_qwhhBVLCxS8ugiCoCt|vR*OZPB0AP60tU{!UDthZ9LVLTq_T_l{nzCTgA`9
z_bxbctvujHg}5ONFp6sA0T(L7P3aZPq8c$^8;5gMqtWOfx5a3h)+wrCy+GFSx1Ax-
zRrH|G_0&A;VZA_BfWjdhF?@djHth4gny0*%lwb)euso*<?<xHPHO1-}!pO`$00000
LNkvXXu0mjf?Gd_1
--- a/browser/extensions/pdfjs/content/web/l10n.js
+++ b/browser/extensions/pdfjs/content/web/l10n.js
@@ -4,17 +4,17 @@
 'use strict';
 
 // Small subset of the webL10n API by Fabien Cazenave for pdf.js extension.
 (function(window) {
   var gLanguage = '';
 
   // fetch an l10n objects
   function getL10nData(key) {
-    var response = FirefoxCom.request('getStrings', key);
+    var response = FirefoxCom.requestSync('getStrings', key);
     var data = JSON.parse(response);
     if (!data)
       console.warn('[l10n] #' + key + ' missing for [' + gLanguage + ']');
     return data;
   }
 
   // replace {{arguments}} with their values
   function substArguments(text, args) {
@@ -73,17 +73,17 @@
       translateElement(children[i]);
 
     // translate element itself if necessary
     if (element.dataset.l10nId)
       translateElement(element);
   }
 
   window.addEventListener('DOMContentLoaded', function() {
-    gLanguage = FirefoxCom.request('getLocale', null);
+    gLanguage = FirefoxCom.requestSync('getLocale', null);
 
     translateFragment();
 
     // fire a 'localized' DOM event
     var evtObject = document.createEvent('Event');
     evtObject.initEvent('localized', false, false);
     evtObject.language = gLanguage;
     window.dispatchEvent(evtObject);
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -6,17 +6,23 @@
 html {
   height: 100%;
 }
 
 body {
   height: 100%;
   background-color: #404040;
   background-image: url(images/texture.png);
-  font-family: Segoe UI, Verdana, sans-serif;
+}
+
+body,
+input,
+button,
+select {
+  font: message-box;
 }
 
 .hidden {
   display: none;
 }
 [hidden] {
   display: none !important;
 }
@@ -49,29 +55,41 @@ html[dir='rtl'] .innerCenter {
 }
 
 #sidebarContainer {
   position: absolute;
   top: 0;
   bottom: 0;
   width: 200px;
   visibility: hidden;
-  -moz-transition-duration: 200ms;
-  -moz-transition-timing-function: ease;
   -webkit-transition-duration: 200ms;
   -webkit-transition-timing-function: ease;
+  -moz-transition-duration: 200ms;
+  -moz-transition-timing-function: ease;
+  -ms-transition-duration: 200ms;
+  -ms-transition-timing-function: ease;
+  -o-transition-duration: 200ms;
+  -o-transition-timing-function: ease;
+  transition-duration: 200ms;
+  transition-timing-function: ease;
+  
 }
 html[dir='ltr'] #sidebarContainer {
+  -webkit-transition-property: left;
   -moz-transition-property: left;
-  -webkit-transition-property: left;
+  -ms-transition-property: left;
+  -o-transition-property: left;
+  transition-property: left;
   left: -200px;
 }
 html[dir='rtl'] #sidebarContainer {
-  -moz-transition-property: right;
   -webkit-transition-property: right;
+  -ms-transition-property: right;
+  -o-transition-property: right;
+  transition-property: right;
   right: -200px;
 }
 
 #outerContainer.sidebarMoving > #sidebarContainer,
 #outerContainer.sidebarOpen > #sidebarContainer {
   visibility: visible;
 }
 html[dir='ltr'] #outerContainer.sidebarOpen > #sidebarContainer {
@@ -82,29 +100,41 @@ html[dir='rtl'] #outerContainer.sidebarO
 }
 
 #mainContainer {
   position: absolute;
   top: 0;
   right: 0;
   bottom: 0;
   left: 0;
-  -moz-transition-duration: 200ms;
-  -moz-transition-timing-function: ease;
   -webkit-transition-duration: 200ms;
   -webkit-transition-timing-function: ease;
+  -moz-transition-duration: 200ms;
+  -moz-transition-timing-function: ease;
+  -ms-transition-duration: 200ms;
+  -ms-transition-timing-function: ease;
+  -o-transition-duration: 200ms;
+  -o-transition-timing-function: ease;
+  transition-duration: 200ms;
+  transition-timing-function: ease;
 }
 html[dir='ltr'] #outerContainer.sidebarOpen > #mainContainer {
+  -webkit-transition-property: left;
   -moz-transition-property: left;
-  -webkit-transition-property: left;
+  -ms-transition-property: left;
+  -o-transition-property: left;
+  transition-property: left;
   left: 200px;
 }
 html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer {
+  -webkit-transition-property: right;
   -moz-transition-property: right;
-  -webkit-transition-property: right;
+  -ms-transition-property: right;
+  -o-transition-property: right;
+  transition-property: right;
   right: 200px;
 }
 
 #sidebarContent {
   top: 32px;
   bottom: 0;
   overflow: auto;
   position: absolute;
@@ -141,35 +171,47 @@ html[dir='rtl'] #sidebarContent {
 }
 
 #toolbarContainer {
   width: 100%;
 }
 
 #toolbarSidebar {
   width: 200px;
-  height: 32px;
+  height: 29px;
+  background-image: url(images/texture.png),
+                    -webkit-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
   background-image: url(images/texture.png),
                     -moz-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
   background-image: url(images/texture.png),
-                    -webkit-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
+                    -ms-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
+  background-image: url(images/texture.png),
+                    -o-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
+  background-image: url(images/texture.png),
+                    linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
   box-shadow: inset -2px 0 0 hsla(0,0%,100%,.08),
               inset 0 1px 1px hsla(0,0%,0%,.15),
               inset 0 -1px 0 hsla(0,0%,100%,.05),
               0 1px 0 hsla(0,0%,0%,.15),
               0 1px 1px hsla(0,0%,0%,.1);
 }
 
 #toolbarViewer {
   position: relative;
   height: 32px;
   background-image: url(images/texture.png),
+                    -webkit-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
+  background-image: url(images/texture.png),
                     -moz-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
   background-image: url(images/texture.png),
-                    -webkit-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
+                    -ms-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
+  background-image: url(images/texture.png),
+                    -o-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
+  background-image: url(images/texture.png),
+                    linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
   border-left: 1px solid hsla(0,0%,0%,.5);
   box-shadow: inset 1px 0 0 hsla(0,0%,100%,.08),
               inset 0 1px 1px hsla(0,0%,0%,.15),
               inset 0 -1px 0 hsla(0,0%,100%,.05),
               0 1px 0 hsla(0,0%,0%,.15),
               0 1px 1px hsla(0,0%,0%,.1);
 }
 html[dir='ltr'] #toolbarViewerLeft {
@@ -237,38 +279,58 @@ html[dir='rtl'] .splitToolbarButton > .t
 .toolbarButton[disabled] {
   opacity: .5;
 }
 
 .toolbarButton.group {
   margin-right:0;
 }
 
+.splitToolbarButton.toggled .toolbarButton {
+  margin: 0;
+}
+
 .splitToolbarButton:hover > .toolbarButton,
 .splitToolbarButton:focus > .toolbarButton,
-.splitToolbarButton.toggled > .toolbarButton {
+.splitToolbarButton.toggled > .toolbarButton,
+.toolbarButton.textButton {
   background-color: hsla(0,0%,0%,.12);
+  background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-  background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+  background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+  background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+  background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
   background-clip: padding-box;
   border: 1px solid hsla(0,0%,0%,.35);
   border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42);
   box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
               0 0 1px hsla(0,0%,100%,.15) inset,
               0 1px 0 hsla(0,0%,100%,.05);
+  -webkit-transition-property: background-color, border-color, box-shadow;
+  -webkit-transition-duration: 150ms;
+  -webkit-transition-timing-function: ease;
   -moz-transition-property: background-color, border-color, box-shadow;
   -moz-transition-duration: 150ms;
   -moz-transition-timing-function: ease;
-  -webkit-transition-property: background-color, border-color, box-shadow;
-  -webkit-transition-duration: 150ms;
-  -webkit-transition-timing-function: ease;
+  -ms-transition-property: background-color, border-color, box-shadow;
+  -ms-transition-duration: 150ms;
+  -ms-transition-timing-function: ease;
+  -o-transition-property: background-color, border-color, box-shadow;
+  -o-transition-duration: 150ms;
+  -o-transition-timing-function: ease;
+  transition-property: background-color, border-color, box-shadow;
+  transition-duration: 150ms;
+  transition-timing-function: ease;
+
 }
 .splitToolbarButton > .toolbarButton:hover,
 .splitToolbarButton > .toolbarButton:focus,
-.dropdownToolbarButton:hover {
+.dropdownToolbarButton:hover,
+.toolbarButton.textButton:hover,
+.toolbarButton.textButton:focus {
   background-color: hsla(0,0%,0%,.2);
   box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
               0 0 1px hsla(0,0%,100%,.15) inset,
               0 0 1px hsla(0,0%,0%,.05);
   z-index: 199;
 }
 html[dir='ltr'] .splitToolbarButton > .toolbarButton:first-child,
 html[dir='rtl'] .splitToolbarButton > .toolbarButton:last-child {
@@ -303,99 +365,146 @@ html[dir='ltr'] .splitToolbarButtonSepar
 html[dir='rtl'] .splitToolbarButtonSeparator {
   float:right;
 }
 .splitToolbarButton:hover > .splitToolbarButtonSeparator,
 .splitToolbarButton.toggled > .splitToolbarButtonSeparator {
   padding: 12px 0;
   margin: 0;
   box-shadow: 0 0 0 1px hsla(0,0%,100%,.03);
+  -webkit-transition-property: padding;
+  -webkit-transition-duration: 10ms;
+  -webkit-transition-timing-function: ease;
   -moz-transition-property: padding;
   -moz-transition-duration: 10ms;
   -moz-transition-timing-function: ease;
-  -webkit-transition-property: padding;
-  -webkit-transition-duration: 10ms;
-  -webkit-transition-timing-function: ease;
+  -ms-transition-property: padding;
+  -ms-transition-duration: 10ms;
+  -ms-transition-timing-function: ease;
+  -o-transition-property: padding;
+  -o-transition-duration: 10ms;
+  -o-transition-timing-function: ease;
+  transition-property: padding;
+  transition-duration: 10ms;
+  transition-timing-function: ease;
 }
 
 .toolbarButton,
 .dropdownToolbarButton {
   min-width: 16px;
   padding: 2px 6px 0;
   border: 1px solid transparent;
   border-radius: 2px;
   color: hsl(0,0%,95%);
   font-size: 12px;
   line-height: 14px;
+  -webkit-user-select:none;
   -moz-user-select:none;
-  -webkit-user-select:none;
+  -ms-user-select:none;
+  /* Opera does not support user-select, use <... unselectable="on"> instead */
   cursor: default;
+  -webkit-transition-property: background-color, border-color, box-shadow;
+  -webkit-transition-duration: 150ms;
+  -webkit-transition-timing-function: ease;
   -moz-transition-property: background-color, border-color, box-shadow;
   -moz-transition-duration: 150ms;
   -moz-transition-timing-function: ease;
-  -webkit-transition-property: background-color, border-color, box-shadow;
-  -webkit-transition-duration: 150ms;
-  -webkit-transition-timing-function: ease;
+  -ms-transition-property: background-color, border-color, box-shadow;
+  -ms-transition-duration: 150ms;
+  -ms-transition-timing-function: ease;
+  -o-transition-property: background-color, border-color, box-shadow;
+  -o-transition-duration: 150ms;
+  -o-transition-timing-function: ease;
+  transition-property: background-color, border-color, box-shadow;
+  transition-duration: 150ms;
+  transition-timing-function: ease;
 }
 
 html[dir='ltr'] .toolbarButton,
 html[dir='ltr'] .dropdownToolbarButton {
   margin: 3px 2px 4px 0;
 }
 html[dir='rtl'] .toolbarButton,
 html[dir='rtl'] .dropdownToolbarButton {
   margin: 3px 0 4px 2px;
 }
 
 .toolbarButton:hover,
 .toolbarButton:focus,
 .dropdownToolbarButton {
   background-color: hsla(0,0%,0%,.12);
+  background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-  background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+  background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+  background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+  background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
   background-clip: padding-box;
   border: 1px solid hsla(0,0%,0%,.35);
   border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42);
   box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
               0 0 1px hsla(0,0%,100%,.15) inset,
               0 1px 0 hsla(0,0%,100%,.05);
 }
 
 .toolbarButton:hover:active,
 .dropdownToolbarButton:hover:active {
   background-color: hsla(0,0%,0%,.2);
+  background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-  background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+  background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+  background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+  background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
   border-color: hsla(0,0%,0%,.35) hsla(0,0%,0%,.4) hsla(0,0%,0%,.45);
   box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset,
               0 0 1px hsla(0,0%,0%,.2) inset,
               0 1px 0 hsla(0,0%,100%,.05);
+  -webkit-transition-property: background-color, border-color, box-shadow;
+  -webkit-transition-duration: 10ms;
+  -webkit-transition-timing-function: linear;
   -moz-transition-property: background-color, border-color, box-shadow;
   -moz-transition-duration: 10ms;
   -moz-transition-timing-function: linear;
-  -webkit-transition-property: background-color, border-color, box-shadow;
-  -webkit-transition-duration: 10ms;
-  -webkit-transition-timing-function: linear;
+  -ms-transition-property: background-color, border-color, box-shadow;
+  -ms-transition-duration: 10ms;
+  -ms-transition-timing-function: linear;
+  -o-transition-property: background-color, border-color, box-shadow;
+  -o-transition-duration: 10ms;
+  -o-transition-timing-function: linear;
+  transition-property: background-color, border-color, box-shadow;
+  transition-duration: 10ms;
+  transition-timing-function: linear;
 }
 
 .toolbarButton.toggled,
 .splitToolbarButton.toggled > .toolbarButton.toggled {
   background-color: hsla(0,0%,0%,.3);
+  background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-  background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+  background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+  background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+  background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
   border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.45) hsla(0,0%,0%,.5);
   box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset,
               0 0 1px hsla(0,0%,0%,.2) inset,
               0 1px 0 hsla(0,0%,100%,.05);
+  -webkit-transition-property: background-color, border-color, box-shadow;
+  -webkit-transition-duration: 10ms;
+  -webkit-transition-timing-function: linear;
   -moz-transition-property: background-color, border-color, box-shadow;
   -moz-transition-duration: 10ms;
   -moz-transition-timing-function: linear;
-  -webkit-transition-property: background-color, border-color, box-shadow;
-  -webkit-transition-duration: 10ms;
-  -webkit-transition-timing-function: linear;
+  -ms-transition-property: background-color, border-color, box-shadow;
+  -ms-transition-duration: 10ms;
+  -ms-transition-timing-function: linear;
+  -o-transition-property: background-color, border-color, box-shadow;
+  -o-transition-duration: 10ms;
+  -o-transition-timing-function: linear;
+  transition-property: background-color, border-color, box-shadow;
+  transition-duration: 10ms;
+  transition-timing-function: linear;
 }
 
 .toolbarButton.toggled:hover:active,
 .splitToolbarButton.toggled > .toolbarButton.toggled:hover:active {
   background-color: hsla(0,0%,0%,.4);
   border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.5) hsla(0,0%,0%,.55);
   box-shadow: 0 1px 1px hsla(0,0%,0%,.2) inset,
               0 0 1px hsla(0,0%,0%,.3) inset,
@@ -412,18 +521,18 @@ html[dir='rtl'] .dropdownToolbarButton {
 html[dir='ltr'] .dropdownToolbarButton {
   background-position: 95%;
 }
 html[dir='rtl'] .dropdownToolbarButton {
   background-position: 5%;
 }
 
 .dropdownToolbarButton > select {
+  -webkit-appearance: none;
   -moz-appearance: none; /* in the future this might matter, see bugzilla bug #649849 */
-  -webkit-appearance: none;
   min-width: 140px;
   font-size: 12px;
   color: hsl(0,0%,95%);
   margin:0;
   padding:0;
   border:none;
   background: transparent;
 }
@@ -455,18 +564,18 @@ html[dir='rtl'] .toolbarButton:first-chi
 
 .toolbarButtonSpacer {
   width: 30px;
   display: inline-block;
   height: 1px;
 }
 
 .toolbarButtonFlexibleSpacer {
+  -webkit-box-flex: 1;
   -moz-box-flex: 1;
-  -webkit-box-flex: 1;
   min-width: 30px;
 }
 
 .toolbarButton#sidebarToggle::before {
   display: inline-block;
   content: url(images/toolbarButton-sidebarToggle.png);
 }
     
@@ -511,18 +620,18 @@ html[dir='rtl'] .toolbarButton.pageDown:
 }
 
 .toolbarButton.download::before {
   display: inline-block;
   content: url(images/toolbarButton-download.png);
 }
 
 .toolbarButton.bookmark {
+  -webkit-box-sizing: border-box;
   -moz-box-sizing: border-box;
-  -webkit-box-sizing: border-box;
   box-sizing: border-box;
   margin-top: 3px;
   padding-top: 4px;
 }
 
 .toolbarButton.bookmark::before {
   content: url(images/toolbarButton-bookmark.png);
 }
@@ -539,40 +648,39 @@ html[dir='rtl'] .toolbarButton.pageDown:
 
 #viewSearch.toolbarButton::before {
   display: inline-block;
   content: url(images/toolbarButton-search.png);
 }
 
 
 .toolbarField {
-  min-width: 16px;
-  width: 32px;
   padding: 3px 6px;
   margin: 4px 0 4px 0;
   border: 1px solid transparent;
   border-radius: 2px;
   background-color: hsla(0,0%,100%,.09);
   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
   background-clip: padding-box;
   border: 1px solid hsla(0,0%,0%,.35);
   border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42);
   box-shadow: 0 1px 0 hsla(0,0%,0%,.05) inset,
               0 1px 0 hsla(0,0%,100%,.05);
   color: hsl(0,0%,95%);
   font-size: 12px;
   line-height: 14px;
-  text-align: right;
   outline-style: none;
   -moz-transition-property: background-color, border-color, box-shadow;
   -moz-transition-duration: 150ms;
   -moz-transition-timing-function: ease;
 }
 
 .toolbarField.pageNumber {
+  min-width: 16px;
+  text-align: right;
   width: 40px;
 }
 
 .toolbarField.pageNumber::-webkit-inner-spin-button,
 .toolbarField.pageNumber::-webkit-outer-spin-button {
     -webkit-appearance: none;
     margin: 0;
 }
@@ -592,18 +700,18 @@ html[dir='rtl'] .toolbarButton.pageDown:
   padding: 3px 6px 3px 2px;
   margin: 4px 2px 4px 0;
   border: 1px solid transparent;
   border-radius: 2px;
   color: hsl(0,0%,85%);
   font-size: 12px;
   line-height: 14px;
   text-align: left;
+  -webkit-user-select:none;
   -moz-user-select:none;
-  -webkit-user-select:none;
   cursor: default;
 }
 
 #thumbnailView {
   position: fixed;
   width: 120px;
   top: 33px;
   bottom: 0;
@@ -669,197 +777,208 @@ a:focus > .thumbnail > .thumbnailSelecti
 
 #outlineView {
   position: fixed;
   width: 192px;
   top: 33px;
   bottom: 0;
   padding: 4px 4px 0;
   overflow: auto;
+  -webkit-user-select:none;
   -moz-user-select:none;
-  -webkit-user-select:none;
 }
 
 .outlineItem > .outlineItems {
   margin-left: 20px;
 }
 
-.outlineItem > a {
+.outlineItem > a,
+#searchResults > a {
   text-decoration: none;
-  display: block;
+  display: inline-block;
+  min-width: 95%;
   height: 20px;
   padding: 2px 0 0 10px;
   margin-bottom: 1px;
   border-radius: 2px;
   color: hsla(0,0%,100%,.8);
   font-size: 13px;
   line-height: 15px;
   -moz-user-select:none;
   cursor: default;
   white-space: nowrap;
 }
 
-.outlineItem > a:hover {
+.outlineItem > a:hover,
+#searchResults > a:hover {
   background-color: hsla(0,0%,100%,.02);
   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
   background-clip: padding-box;
   box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
               0 0 1px hsla(0,0%,100%,.2) inset,
               0 0 1px hsla(0,0%,0%,.2);
   color: hsla(0,0%,100%,.9);
 }
 
+.outlineItem.selected {
+  background-color: hsla(0,0%,100%,.08);
+  background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+  background-clip: padding-box;
+  box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
+              0 0 1px hsla(0,0%,100%,.1) inset,
+              0 0 1px hsla(0,0%,0%,.2);
+  color: hsla(0,0%,100%,1);
+}
+
+.noOutline,
+.noResults {
+  font-size: 12px;
+  color: hsla(0,0%,100%,.8);
+  font-style: italic;
+}
+
 #searchScrollView {
   position: absolute;
   top: 10px;
   bottom: 10px;
   left: 10px;
   width: 280px;
 }
 
 #searchToolbar {
   padding-left: 0px;
   right: 0px;
   padding-top: 0px;
   padding-bottom: 5px;
 }
 
 #searchToolbar > input {
-  margin-left: 8px;
-  width: 130px;
+  margin-left: 4px;
+  width: 124px;
+}
+
+#searchToolbar button {
+  width: auto;
+  margin: 0;
+  padding: 0 6px;
+  height: 22px;
 }
 
 #searchResults {
   overflow: auto;
-  background-color: #fff;
   position: absolute;
   top: 30px;
   bottom: 0px;
   left: 0px;
   right: 0;
+  padding: 4px 4px 0;
   font-size: smaller;
-  opacity: 0.7;
-}
-
-#searchResults a {
-  display: block;
-  white-space: pre;
-  text-decoration: none;
-  color: black;
 }
 
 #sidebarControls {
   position:absolute;
   width: 180px;
   height: 32px;
   left: 15px;
   bottom: 35px;
 }
 
-.outlineItem.selected {
-  background-color: hsla(0,0%,100%,.08);
-  background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-  background-clip: padding-box;
-  box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
-              0 0 1px hsla(0,0%,100%,.1) inset,
-              0 0 1px hsla(0,0%,0%,.2);
-  color: hsla(0,0%,100%,1);
-}
-
-.noOutline {
-  font-size: 12px;
-  color: hsla(0,0%,100%,.8);
-  font-style: italic;
-}
-
-
-
 canvas {
   margin: auto;
   display: block;
 }
 
 .page {
   direction: ltr;
   width: 816px;
   height: 1056px;
   margin: 10px auto;
   position: relative;
   overflow: hidden;
-  box-shadow: 0px 4px 10px #000;
+  -webkit-box-shadow: 0px 4px 10px #000;
   -moz-box-shadow: 0px 4px 10px #000;
-  -webkit-box-shadow: 0px 4px 10px #000;
+  box-shadow: 0px 4px 10px #000;
   background-color: white;
 }
 
 .page > a {
   display: block;
   position: absolute;
 }
 
 .page > a:hover {
   opacity: 0.2;
   background: #ff0;
-  box-shadow: 0px 2px 10px #ff0;
+  -webkit-box-shadow: 0px 2px 10px #ff0;
   -moz-box-shadow: 0px 2px 10px #ff0;
-  -webkit-box-shadow: 0px 2px 10px #ff0;
+  box-shadow: 0px 2px 10px #ff0;
 }
 
 .loadingIcon {
   position: absolute;
   display: block;
   left: 0;
   top: 0;
   right: 0;
   bottom: 0;
   background: url('images/loading-icon.gif') center no-repeat;
 }
 
 #loadingBox {
-  margin: 100px 0;
+  position: absolute;
+  top: 50%;
+  margin-top: -25px;
+  left: 0;
+  right: 0;
   text-align: center;
   color: #ddd;
   font-size: 14px;
 }
 
 #loadingBar {
-  background-color: #333;
   display: inline-block;
-  border: 1px solid black;
   clear: both;
   margin: 0px;
   margin-top: 5px;
   line-height: 0;
-  border-radius: 4px;
+  border-radius: 2px;
   width: 200px;
   height: 25px;
+
+  background-color: hsla(0,0%,0%,.3);
+  background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+  background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
+  border: 1px solid #000;
+  box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset,
+              0 0 1px hsla(0,0%,0%,.2) inset,
+              0 0 1px 1px rgba(255, 255, 255, 0.1);
 }
 
 #loadingBar .progress {
   display: inline-block;
   float: left;
 
   background: #666;
-  background: -moz-linear-gradient(top, #999 0%, #666 50%, #999 100%);
-  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#999), color-stop(50%,#666), color-stop(100%,#999));
-  background: -webkit-linear-gradient(top, #999 0%,#666 50%,#999 100%);
-  background: -o-linear-gradient(top, #999 0%,#666 50%,#999 100%);
-  background: -ms-linear-gradient(top, #999 0%,#666 50%,#999 100%);
-  background: linear-gradient(top, #999 0%,#666 50%,#999 100%);    
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b2b2b2), color-stop(100%,#898989));
+  background: -webkit-linear-gradient(top, #b2b2b2 0%,#898989 100%);
+  background: -moz-linear-gradient(top, #b2b2b2 0%,#898989 100%);
+  background: -ms-linear-gradient(top, #b2b2b2 0%,#898989 100%);
+  background: -o-linear-gradient(top, #b2b2b2 0%,#898989 100%);
+  background: linear-gradient(top, #b2b2b2 0%,#898989 100%);    
 
-  border-top-left-radius: 3px;
-  border-bottom-left-radius: 3px;
+  border-top-left-radius: 2px;
+  border-bottom-left-radius: 2px;
 
   width: 0%;
   height: 100%;
 }
 
 #loadingBar .progress.full {
-  border-top-right-radius: 3px;
-  border-bottom-right-radius: 3px;
+  border-top-right-radius: 2px;
+  border-bottom-right-radius: 2px;
 }
 
 .textLayer {
   position: absolute;
   left: 0;
   top: 0;
   right: 0;
   bottom: 0;
@@ -891,19 +1010,19 @@ canvas {
   cursor: pointer;
   opacity: 0.7;
 }
 
 .annotComment > div {
   padding: 0.2em;
   max-width: 20em;
   background-color: #F1E47B;
-  box-shadow: 0px 2px 10px #333;
+  -webkit-box-shadow: 0px 2px 10px #333;
   -moz-box-shadow: 0px 2px 10px #333;
-  -webkit-box-shadow: 0px 2px 10px #333;
+  box-shadow: 0px 2px 10px #333;
 }
 
 .annotComment > div > h1 {
   font-weight: normal;
   font-size: 1.2em;
   border-bottom: 1px solid #000000;
   margin: 0px;
 }
@@ -989,38 +1108,60 @@ canvas {
 }
 #PDFBug .stats .title {
     font-weight: bold;
 }
 #PDFBug table {
   font-size: 10px;
 }
 
+@page {
+  margin: 0;
+} 
+
+#printContainer {
+  display: none;
+}
+
 @media print {
+  /* Rules for browsers that don't support mozPrintCallback. */
   #sidebarContainer, .toolbar, #loadingBox, #errorWrapper, .textLayer {
     display: none;
   }
 
   #mainContainer, #viewerContainer, .page, .page canvas {
     position: static;
     padding: 0;
     margin: 0;
   }
 
   .page {
     float: left;
     display: none;
-    box-shadow: none;
+    -webkit-box-shadow: none;
     -moz-box-shadow: none;
-    -webkit-box-shadow: none;
+    box-shadow: none;
   }
 
   .page[data-loaded] {
     display: block;
   }
+
+  /* Rules for browsers that support mozPrintCallback */
+  body[data-mozPrintCallback] #outerContainer {
+    display: none;
+  }
+  body[data-mozPrintCallback] #printContainer {
+    display: block;
+  }
+  #printContainer canvas {
+    position: relative;
+    top: 0;
+    left: 0;
+  }
 }
 
 @media all and (max-width: 950px) {
   html[dir='ltr'] #outerContainer.sidebarMoving .outerCenter,
   html[dir='ltr'] #outerContainer.sidebarOpen .outerCenter {
     float: left;
     left: 180px;
   }
@@ -1061,8 +1202,15 @@ canvas {
   }
 }
 
 @media all and (max-width: 600px) {
   #toolbarViewerRight {
     display: none;
   }
 }
+
+@media all and (max-width: 500px) {
+  #scaleSelectContainer, #pageNumberLabel {
+    display: none;
+  }
+}
+
--- a/browser/extensions/pdfjs/content/web/viewer.html
+++ b/browser/extensions/pdfjs/content/web/viewer.html
@@ -1,12 +1,13 @@
 <!DOCTYPE html>
 <html dir="ltr">
   <head>
     <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
     <title>PDF.js viewer</title>
 <!-- This snippet is used in firefox extension, see Makefile -->
 <base href="resource://pdf.js/web/" />
 <script type="application/l10n">
 <!-- PDFJSSCRIPT_LOCALE_DATA -->
 </script>
 <script type="text/javascript" src="l10n.js"></script>
 <script type="text/javascript" id="PDFJS_SCRIPT_TAG">
@@ -17,17 +18,17 @@
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 
 var PDFJS = {};
 
 (function pdfjsWrapper() {
   // Use strict in our context only - users might not want it
   'use strict';
 
-  PDFJS.build = '121040a';
+  PDFJS.build = 'c757eed';
 
   // Files are inserted below - see Makefile
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 
 'use strict';
 
 var globalScope = (typeof window === 'undefined') ? this : window;
@@ -1182,17 +1183,19 @@ var StatTimer = (function StatTimerClosu
  *  - url   - The URL of the PDF.
  *  - data  - A typed array with PDF data.
  *  - httpHeaders - Basic authentication headers.
  *  - password - For decrypting password-protected PDFs.
  *
  * @return {Promise} A promise that is resolved with {PDFDocumentProxy} object.
  */
 PDFJS.getDocument = function getDocument(source) {
-  var url, data, headers, password, parameters = {};
+  var url, data, headers, password, parameters = {}, workerInitializedPromise,
+    workerReadyPromise, transport;
+
   if (typeof source === 'string') {
     url = source;
   } else if (isArrayBuffer(source)) {
     data = source;
   } else if (typeof source === 'object') {
     url = source.url;
     data = source.data;
     headers = source.httpHeaders;
@@ -1201,45 +1204,53 @@ PDFJS.getDocument = function getDocument
 
     if (!url && !data)
       error('Invalid parameter array, need either .data or .url');
   } else {
     error('Invalid parameter in getDocument, need either Uint8Array, ' +
           'string or a parameter object');
   }
 
-  var promise = new PDFJS.Promise();
-  var transport = new WorkerTransport(promise);
+  workerInitializedPromise = new PDFJS.Promise();
+  workerReadyPromise = new PDFJS.Promise();
+  transport = new WorkerTransport(workerInitializedPromise, workerReadyPromise);
   if (data) {
     // assuming the data is array, instantiating directly from it
     transport.sendData(data, parameters);
   } else if (url) {
     // fetch url
     PDFJS.getPdf(
       {
         url: url,
         progress: function getPDFProgress(evt) {
-          if (evt.lengthComputable)
-            promise.progress({
+          if (evt.lengthComputable) {
+            workerReadyPromise.progress({
               loaded: evt.loaded,
               total: evt.total
             });
+          }
         },
         error: function getPDFError(e) {
-          promise.reject('Unexpected server response of ' +
+          workerReadyPromise.reject('Unexpected server response of ' +
             e.target.status + '.');
         },
         headers: headers
       },
       function getPDFLoad(data) {
-        transport.sendData(data, parameters);
+        // sometimes the pdf has finished downloading before the web worker-test
+        // has finished. In that case the rendering of the final pdf would cause
+        // errors. We have to wait for the WorkerTransport to finalize worker-
+        // support detection
+        workerInitializedPromise.then(function workerInitialized() {
+          transport.sendData(data, parameters);
+        });
       });
   }
 
-  return promise;
+  return workerReadyPromise;
 };
 
 /**
  * Proxy to a PDFDocument in the worker thread. Also, contains commonly used
  * properties that can be read synchronously.
  */
 var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
   function PDFDocumentProxy(pdfInfo, transport) {
@@ -1315,16 +1326,25 @@ var PDFDocumentProxy = (function PDFDocu
       });
       return promise;
     },
     isEncrypted: function PDFDocumentProxy_isEncrypted() {
       var promise = new PDFJS.Promise();
       promise.resolve(this.pdfInfo.encrypted);
       return promise;
     },
+    /**
+     * @return {Promise} A promise that is resolved with a TypedArray that has
+     * the raw data from the PDF.
+     */
+    getData: function PDFDocumentProxy_getData() {
+      var promise = new PDFJS.Promise();
+      this.transport.getData(promise);
+      return promise;
+    },
     destroy: function PDFDocumentProxy_destroy() {
       this.transport.destroy();
     }
   };
   return PDFDocumentProxy;
 })();
 
 var PDFPageProxy = (function PDFPageProxyClosure() {
@@ -1389,17 +1409,21 @@ var PDFPageProxy = (function PDFPageProx
       return promise;
     },
     /**
      * Begins the process of rendering a page to the desired context.
      * @param {object} params A parameter object that supports:
      * {
      *   canvasContext(required): A 2D context of a DOM Canvas object.,
      *   textLayer(optional): An object that has beginLayout, endLayout, and
-     *                        appendText functions.
+     *                        appendText functions.,
+     *   continueCallback(optional): A function that will be called each time
+     *                               the rendering is paused.  To continue
+     *                               rendering call the function that is the
+     *                               first argument to the callback.
      * }.
      * @return {Promise} A promise that is resolved when the page finishes
      * rendering.
      */
     render: function PDFPageProxy_render(params) {
       this.renderInProgress = true;
 
       var promise = new Promise();
@@ -1425,29 +1449,30 @@ var PDFPageProxy = (function PDFPageProx
           delete self.displayReadyPromise;
         }
 
         if (error)
           promise.reject(error);
         else
           promise.resolve();
       };
+      var continueCallback = params.continueCallback;
 
       // Once the operatorList and fonts are loaded, do the actual rendering.
       this.displayReadyPromise.then(
         function pageDisplayReadyPromise() {
           if (self.destroyed) {
             complete();
             return;
           }
 
           var gfx = new CanvasGraphics(params.canvasContext,
             this.objs, params.textLayer);
           try {
-            this.display(gfx, params.viewport, complete);
+            this.display(gfx, params.viewport, complete, continueCallback);
           } catch (e) {
             complete(e);
           }
         }.bind(this),
         function pageDisplayReadPromiseError(reason) {
           complete(reason);
         }
       );
@@ -1495,44 +1520,51 @@ var PDFPageProxy = (function PDFPageProx
 
           callback.call(this);
         }.bind(this)
       );
     },
     /**
      * For internal use only.
      */
-    display: function PDFPageProxy_display(gfx, viewport, callback) {
+    display: function PDFPageProxy_display(gfx, viewport, callback,
+                                           continueCallback) {
       var stats = this.stats;
       stats.time('Rendering');
 
       gfx.beginDrawing(viewport);
 
       var startIdx = 0;
       var length = this.operatorList.fnArray.length;
       var operatorList = this.operatorList;
       var stepper = null;
       if (PDFJS.pdfBug && StepperManager.enabled) {
         stepper = StepperManager.create(this.pageNumber - 1);
         stepper.init(operatorList);
         stepper.nextBreakPoint = stepper.getNextBreakPoint();
       }
 
+      var continueWrapper;
+      if (continueCallback)
+        continueWrapper = function() { continueCallback(next); }
+      else
+        continueWrapper = next;
+
       var self = this;
       function next() {
-        startIdx =
-          gfx.executeOperatorList(operatorList, startIdx, next, stepper);
+        startIdx = gfx.executeOperatorList(operatorList, startIdx,
+                                           continueWrapper, stepper);
         if (startIdx == length) {
           gfx.endDrawing();
           stats.timeEnd('Rendering');
           stats.timeEnd('Overall');
           if (callback) callback();
         }
       }
-      next();
+      continueWrapper();
     },
     /**
      * @return {Promise} That is resolved with the a {string} that is the text
      * content from the page.
      */
     getTextContent: function PDFPageProxy_getTextContent() {
       var promise = new PDFJS.Promise();
       this.transport.messageHandler.send('GetTextContent', {
@@ -1569,18 +1601,18 @@ var PDFPageProxy = (function PDFPageProx
     }
   };
   return PDFPageProxy;
 })();
 /**
  * For internal use only.
  */
 var WorkerTransport = (function WorkerTransportClosure() {
-  function WorkerTransport(promise) {
-    this.workerReadyPromise = promise;
+  function WorkerTransport(workerInitializedPromise, workerReadyPromise) {
+    this.workerReadyPromise = workerReadyPromise;
     this.objs = new PDFObjects();
 
     this.pageCache = [];
     this.pagePromises = [];
     this.fontsLoading = {};
 
     // If worker support isn't disabled explicit and the browser has worker
     // support, create a new web worker and test if it/the browser fullfills
@@ -1614,31 +1646,33 @@ var WorkerTransport = (function WorkerTr
         messageHandler.on('test', function transportTest(supportTypedArray) {
           if (supportTypedArray) {
             this.worker = worker;
             this.setupMessageHandler(messageHandler);
           } else {
             globalScope.PDFJS.disableWorker = true;
             this.setupFakeWorker();
           }
+          workerInitializedPromise.resolve();
         }.bind(this));
 
         var testObj = new Uint8Array(1);
         // Some versions of Opera throw a DATA_CLONE_ERR on
         // serializing the typed array.
         messageHandler.send('test', testObj);
         return;
       } catch (e) {
         info('The worker has been disabled.');
       }
     }
     // Either workers are disabled, not supported or have thrown an exception.
     // Thus, we fallback to a faked worker.
     globalScope.PDFJS.disableWorker = true;
     this.setupFakeWorker();
+    workerInitializedPromise.resolve();
   }
   WorkerTransport.prototype = {
     destroy: function WorkerTransport_destroy() {
       if (this.worker)
         this.worker.terminate();
 
       this.pageCache = [];
       this.pagePromises = [];
@@ -1780,16 +1814,22 @@ var WorkerTransport = (function WorkerTr
         img.src = src;
       });
     },
 
     sendData: function WorkerTransport_sendData(data, params) {
       this.messageHandler.send('GetDocRequest', {data: data, params: params});
     },
 
+    getData: function WorkerTransport_sendData(promise) {
+      this.messageHandler.send('GetData', null, function(data) {
+        promise.resolve(data);
+      });
+    },
+
     getPage: function WorkerTransport_getPage(pageNumber, promise) {
       var pageIndex = pageNumber - 1;
       if (pageIndex in this.pagePromises)
         return this.pagePromises[pageIndex];
       var promise = new PDFJS.Promise('Page ' + pageNumber);
       this.pagePromises[pageIndex] = promise;
       this.messageHandler.send('GetPageRequest', { pageIndex: pageIndex });
       return promise;
@@ -2898,16 +2938,50 @@ var CanvasGraphics = (function CanvasGra
             if (!(buf & mask) == inverseDecode) {
               buffer[bufferPos] = 0;
             }
             bufferPos += 4;
             mask >>= 1;
           }
         }
       }
+      function rescaleImage(pixels, widthScale, heightScale) {
+        var scaledWidth = Math.ceil(width / widthScale);
+        var scaledHeight = Math.ceil(height / heightScale);
+
+        var itemsSum = new Uint32Array(scaledWidth * scaledHeight * 4);
+        var itemsCount = new Uint32Array(scaledWidth * scaledHeight);
+        for (var i = 0, position = 0; i < height; i++) {
+          var lineOffset = (0 | (i / heightScale)) * scaledWidth;
+          for (var j = 0; j < width; j++) {
+            var countOffset = lineOffset + (0 | (j / widthScale));
+            var sumOffset = countOffset << 2;
+            itemsSum[sumOffset] += pixels[position];
+            itemsSum[sumOffset + 1] += pixels[position + 1];
+            itemsSum[sumOffset + 2] += pixels[position + 2];
+            itemsSum[sumOffset + 3] += pixels[position + 3];
+            itemsCount[countOffset]++;
+            position += 4;
+          }
+        }
+        var tmpCanvas = createScratchCanvas(scaledWidth, scaledHeight);
+        var tmpCtx = tmpCanvas.getContext('2d');
+        var imgData = tmpCtx.getImageData(0, 0, scaledWidth, scaledHeight);
+        pixels = imgData.data;
+        for (var i = 0, j = 0, ii = scaledWidth * scaledHeight; i < ii; i++) {
+          var count = itemsCount[i];
+          pixels[j] = itemsSum[j] / count;
+          pixels[j + 1] = itemsSum[j + 1] / count;
+          pixels[j + 2] = itemsSum[j + 2] / count;
+          pixels[j + 3] = itemsSum[j + 3] / count;
+          j += 4;
+        }
+        tmpCtx.putImageData(imgData, 0, 0);
+        return tmpCanvas;
+      }
 
       this.save();
 
       var ctx = this.ctx;
       var w = width, h = height;
       // scale the image to the unit square
       ctx.scale(1 / w, -1 / h);
 
@@ -2920,18 +2994,29 @@ var CanvasGraphics = (function CanvasGra
                           fillColor.getPattern(tmpCtx) : fillColor;
       tmpCtx.fillRect(0, 0, w, h);
 
       var imgData = tmpCtx.getImageData(0, 0, w, h);
       var pixels = imgData.data;
 
       applyStencilMask(pixels, inverseDecode);
 
-      tmpCtx.putImageData(imgData, 0, 0);
-      ctx.drawImage(tmpCanvas, 0, -h);
+      var currentTransform = ctx.mozCurrentTransformInverse;
+      var widthScale = Math.max(Math.abs(currentTransform[0]), 1);
+      var heightScale = Math.max(Math.abs(currentTransform[3]), 1);
+      if (widthScale >= 2 || heightScale >= 2) {
+        // canvas does not resize well large images to small -- using simple
+        // algorithm to perform pre-scaling
+        tmpCanvas = rescaleImage(imgData.data, widthScale, heightScale);
+        ctx.scale(widthScale, heightScale);
+        ctx.drawImage(tmpCanvas, 0, -h / heightScale);
+      } else {
+        tmpCtx.putImageData(imgData, 0, 0);
+        ctx.drawImage(tmpCanvas, 0, -h);
+      }
       this.restore();
     },
 
     paintImageXObject: function CanvasGraphics_paintImageXObject(objId) {
       var imgData = this.objs.get(objId);
       if (!imgData)
         error('Dependent image isn\'t ready yet');
 
@@ -13211,18 +13296,20 @@ var PartialEvaluator = (function Partial
         }
 
         // If there is no imageMask, create the PDFImage and a lot
         // of image processing can be done here.
         var objId = 'img_' + uniquePrefix + (++self.objIdCounter);
         insertDependency([objId]);
         args = [objId, w, h];
 
-        var softMask = dict.get('SMask', 'IM') || false;
-        if (!softMask && image instanceof JpegStream &&
+        var softMask = dict.get('SMask', 'SM') || false;
+        var mask = dict.get('Mask') || false;
+
+        if (!softMask && !mask && image instanceof JpegStream &&
             image.isNativelySupported(xref, resources)) {
           // These JPEGs don't need any more processing so we can just send it.
           fn = 'paintJpegXObject';
           handler.send('obj', [objId, 'JpegStream', image.getIR()]);
           return;
         }
 
         fn = 'paintImageXObject';
@@ -14504,17 +14591,17 @@ var FontLoader = {
             document.documentElement.dispatchEvent(evt);
           },
           false);
         this.listeningForFontLoad = true;
       }
 
       // XXX we should have a time-out here too, and maybe fire
       // pdfjsFontLoadFailed?
-      var src = '<!DOCTYPE HTML><html><head>';
+      var src = '<!DOCTYPE HTML><html><head><meta charset="utf-8">';
       src += '<style type="text/css">';
       for (var i = 0, ii = rules.length; i < ii; ++i) {
         src += rules[i];
       }
       src += '</style>';
       src += '<script type="application/javascript">';
       var fontNamesArray = '';
       for (var i = 0, ii = names.length; i < ii; ++i) {
@@ -16745,24 +16832,26 @@ var Font = (function FontClosure() {
 
               newGlyphUnicodes[i] = unicode;
               if (changeCode)
                 toFontChar[code] = unicode;
               delete reverseMap[code];
             }
           }
           for (var index in newGlyphUnicodes) {
-            var unicode = newGlyphUnicodes[index];
-            if (reverseMap[unicode]) {
-              // avoiding assigning to the same unicode
-              glyphs[index].unicode = unusedUnicode++;
-              continue;
-            }
-            glyphs[index].unicode = unicode;
-            reverseMap[unicode] = index;
+            if (newGlyphUnicodes.hasOwnProperty(index)) {
+              var unicode = newGlyphUnicodes[index];
+              if (reverseMap[unicode]) {
+                // avoiding assigning to the same unicode
+                glyphs[index].unicode = unusedUnicode++;
+                continue;
+              }
+              glyphs[index].unicode = unicode;
+              reverseMap[unicode] = index;
+            }
           }
           this.useToFontChar = true;
         }
 
         // Moving all symbolic font glyphs into 0xF000 - 0xF0FF range.
         if (this.isSymbolicFont) {
           for (var i = 0, ii = glyphs.length; i < ii; i++) {
             var code = glyphs[i].unicode & 0xFF;
@@ -17076,19 +17165,23 @@ var Font = (function FontClosure() {
     bindDOM: function Font_bindDOM(data) {
       var fontName = this.loadedName;
 
       // Add the font-face rule to the document
       var url = ('url(data:' + this.mimetype + ';base64,' +
                  window.btoa(data) + ');');
       var rule = "@font-face { font-family:'" + fontName + "';src:" + url + '}';
 
-      var styleElement = document.createElement('style');
-      document.documentElement.getElementsByTagName('head')[0].appendChild(
-        styleElement);
+      var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG');
+      if (!styleElement) {
+          styleElement = document.createElement('style');
+          styleElement.id = 'PDFJS_FONT_STYLE_TAG';
+          document.documentElement.getElementsByTagName('head')[0].appendChild(
+            styleElement);
+      }
 
       var styleSheet = styleElement.sheet;
       styleSheet.insertRule(rule, styleSheet.cssRules.length);
 
       if (PDFJS.pdfBug && FontInspector.enabled)
         FontInspector.fontAdded(this, url);
 
       return rule;
@@ -18331,18 +18424,20 @@ var CFFParser = (function CFFParserClosu
       cff.charset = charset;
       cff.encoding = encoding;
 
       if (!cff.isCIDFont || !normalizeCIDData)
         return cff;
 
       // DirectWrite does not like CID fonts data. Trying to convert/flatten
       // the font data and remove CID properties.
-      if (cff.fdArray.length !== 1)
-        error('Unable to normalize CID font in CFF data');
+      if (cff.fdArray.length !== 1) {
+        warn('Unable to normalize CID font in CFF data -- using font as is');
+        return cff;
+      }
 
       var fontDict = cff.fdArray[0];
       fontDict.setByKey(17, topDict.getByName('CharStrings'));
       cff.topDict = fontDict;
       cff.isCIDFont = false;
       delete cff.fdArray;
       delete cff.fdSelect;
 
@@ -23648,17 +23743,17 @@ var PDFImage = (function PDFImageClosure
    * Decode and clamp a value. The formula is different from the spec because we
    * don't decode to float range [0,1], we decode it in the [0,max] range.
    */
   function decodeAndClamp(value, addend, coefficient, max) {
     value = addend + value * coefficient;
     // Clamp the value to the range
     return value < 0 ? 0 : value > max ? max : value;
   }
-  function PDFImage(xref, res, image, inline, smask) {
+  function PDFImage(xref, res, image, inline, smask, mask) {
     this.image = image;
     if (image.getParams) {
       // JPX/JPEG2000 streams directly contain bits per component
       // and color space mode information.
       TODO('get params from actual stream');
       // var bits = ...
       // var colorspace = ...
     }
@@ -23709,47 +23804,60 @@ var PDFImage = (function PDFImageClosure
       for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) {
         var dmin = this.decode[i];
         var dmax = this.decode[i + 1];
         this.decodeCoefficients[j] = dmax - dmin;
         this.decodeAddends[j] = max * dmin;
       }
     }
 
-    var mask = dict.get('Mask');
-
-    if (mask) {
-      TODO('masked images');
-    } else if (smask) {
+    if (smask) {
       this.smask = new PDFImage(xref, res, smask, false);
+    } else if (mask) {
+      this.mask = new PDFImage(xref, res, mask, false);
     }
   }
   /**
    * Handles processing of image data and calls the callback with an argument
    * of a PDFImage when the image is ready to be used.
    */
   PDFImage.buildImage = function PDFImage_buildImage(callback, handler, xref,
                                                      res, image, inline) {
     var imageDataPromise = new Promise();
     var smaskPromise = new Promise();
+    var maskPromise = new Promise();
     // The image data and smask data may not be ready yet, wait till both are
     // resolved.
-    Promise.all([imageDataPromise, smaskPromise]).then(function(results) {
-      var imageData = results[0], smaskData = results[1];
-      var image = new PDFImage(xref, res, imageData, inline, smaskData);
+    Promise.all([imageDataPromise, smaskPromise, maskPromise]).then(
+        function(results) {
+      var imageData = results[0], smaskData = results[1], maskData = results[2];
+      var image = new PDFImage(xref, res, imageData, inline, smaskData,
+                               maskData);
       callback(image);
     });
 
     handleImageData(handler, xref, res, image, imageDataPromise);
 
     var smask = image.dict.get('SMask');
-    if (smask)
+    var mask = image.dict.get('Mask');
+
+    if (smask) {
       handleImageData(handler, xref, res, smask, smaskPromise);
-    else
+      maskPromise.resolve(null);
+    } else {
       smaskPromise.resolve(null);
+      if (mask && isStream(mask)) {
+        handleImageData(handler, xref, res, mask, maskPromise);
+      } else if (mask) {
+        TODO('handle color key masking');
+        maskPromise.resolve(null);
+      } else {
+        maskPromise.resolve(null);
+      }
+    }
   };
 
   /**
    * Resize an image using the nearest neighbor algorithm.  Currently only
    * supports one and three component images.
    * @param {TypedArray} pixels The original image with one component.
    * @param {Number} bpc Number of bits per component.
    * @param {Number} components Number of color components, 1 or 3 is supported.
@@ -23883,27 +23991,41 @@ var PDFImage = (function PDFImageClosure
           buf = buf & ((1 << remainingBits) - 1);
           bits = remainingBits;
         }
       }
       return output;
     },
     getOpacity: function PDFImage_getOpacity(width, height) {
       var smask = this.smask;
+      var mask = this.mask;
       var originalWidth = this.width;
       var originalHeight = this.height;
       var buf;
 
       if (smask) {
         var sw = smask.width;
         var sh = smask.height;
         buf = new Uint8Array(sw * sh);
         smask.fillGrayBuffer(buf);
         if (sw != width || sh != height)
-          buf = PDFImage.resize(buf, smask.bps, 1, sw, sh, width, height);
+          buf = PDFImage.resize(buf, smask.bpc, 1, sw, sh, width, height);
+      } else if (mask) {
+        var sw = mask.width;
+        var sh = mask.height;
+        buf = new Uint8Array(sw * sh);
+        mask.numComps = 1;
+        mask.fillGrayBuffer(buf);
+
+        // Need to invert values in buffer
+        for (var i = 0, ii = sw * sh; i < ii; ++i)
+          buf[i] = 255 - buf[i];
+
+        if (sw != width || sh != height)
+          buf = PDFImage.resize(buf, mask.bpc, 1, sw, sh, width, height);
       } else {
         buf = new Uint8Array(width * height);
         for (var i = 0, ii = width * height; i < ii; ++i)
           buf[i] = 255;
       }
       return buf;
     },
     applyStencilMask: function PDFImage_applyStencilMask(buffer,
@@ -27192,17 +27314,18 @@ var Parser = (function ParserClosure() {
       }
       if (name == 'CCITTFaxDecode' || name == 'CCF') {
         return new CCITTFaxStream(stream, params);
       }
       if (name == 'RunLengthDecode' || name == 'RL') {
         return new RunLengthStream(stream);
       }
       if (name == 'JBIG2Decode') {
-        error('JBIG2 image format is not currently supprted.');
+        var bytes = stream.getBytes(length);
+        return new Jbig2Stream(bytes, stream.dict);
       }
       warn('filter "' + name + '" not supported yet');
       return stream;
     }
   };
 
   return Parser;
 })();
@@ -28879,16 +29002,60 @@ var JpxStream = (function JpxStreamClosu
   };
   JpxStream.prototype.getChar = function JpxStream_getChar() {
     error('internal error: getChar is not valid on JpxStream');
   };
 
   return JpxStream;
 })();
 
+/**
+ * For JBIG2's we use a library to decode these images and
+ * the stream behaves like all the other DecodeStreams.
+ */
+var Jbig2Stream = (function Jbig2StreamClosure() {
+  function Jbig2Stream(bytes, dict) {
+    this.dict = dict;
+    this.bytes = bytes;
+
+    DecodeStream.call(this);
+  }
+
+  Jbig2Stream.prototype = Object.create(DecodeStream.prototype);
+
+  Jbig2Stream.prototype.ensureBuffer = function Jbig2Stream_ensureBuffer(req) {
+    if (this.bufferLength)
+      return;
+
+    var jbig2Image = new Jbig2Image();
+
+    var chunks = [], decodeParams = this.dict.get('DecodeParms');
+    if (decodeParams && decodeParams.has('JBIG2Globals')) {
+      var globalsStream = decodeParams.get('JBIG2Globals');
+      var globals = globalsStream.getBytes();
+      chunks.push({data: globals, start: 0, end: globals.length});
+    }
+    chunks.push({data: this.bytes, start: 0, end: this.bytes.length});
+    var data = jbig2Image.parseChunks(chunks);
+    var dataLength = data.length;
+
+    // JBIG2 had black as 1 and white as 0, inverting the colors
+    for (var i = 0; i < dataLength; i++)
+      data[i] ^= 0xFF;
+
+    this.buffer = data;
+    this.bufferLength = dataLength;
+  };
+  Jbig2Stream.prototype.getChar = function Jbig2Stream_getChar() {
+    error('internal error: getChar is not valid on Jbig2Stream');
+  };
+
+  return Jbig2Stream;
+})();
+
 var DecryptStream = (function DecryptStreamClosure() {
   function DecryptStream(str, decrypt) {
     this.str = str;
     this.dict = str.dict;
     this.decrypt = decrypt;
 
     DecodeStream.call(this);
   }
@@ -30331,16 +30498,20 @@ var WorkerMessageHandler = {
         pageIndex: data.pageIndex,
         rotate: pdfPage.rotate,
         ref: pdfPage.ref,
         view: pdfPage.view
       };
       handler.send('GetPage', {pageInfo: page});
     });
 
+    handler.on('GetData', function wphSetupGetData(data, promise) {
+      promise.resolve(pdfModel.stream.bytes);
+    });
+
     handler.on('GetAnnotationsRequest', function wphSetupGetAnnotations(data) {
       var pdfPage = pdfModel.getPage(data.pageIndex + 1);
       handler.send('GetAnnotations', {
         pageIndex: data.pageIndex,
         annotations: pdfPage.getAnnotations()
       });
     });
 
@@ -31646,18 +31817,17 @@ var JpxImage = (function JpxImageClosure
                 }
                 cod.precinctsSizes = precinctsSizes;
               }
 
               if (cod.sopMarkerUsed || cod.ephMarkerUsed ||
                   cod.selectiveArithmeticCodingBypass ||
                   cod.resetContextProbabilities ||
                   cod.terminationOnEachCodingPass ||
-                  cod.verticalyStripe || cod.predictableTermination ||
-                  cod.segmentationSymbolUsed)
+                  cod.verticalyStripe || cod.predictableTermination)
                 throw 'Unsupported COD options: ' + uneval(cod);
 
               if (context.mainHeader)
                 context.COD = cod;
               else {
                 context.currentTile.COD = cod;
                 context.currentTile.COC = [];
               }
@@ -32224,17 +32394,18 @@ var JpxImage = (function JpxImageClosure
           codingpasses: packetItem.codingpasses
         });
         position += packetItem.dataLength;
       }
     }
     return position;
   }
   function copyCoefficients(coefficients, x0, y0, width, height,
-                            delta, mb, codeblocks, transformation) {
+                            delta, mb, codeblocks, transformation,
+                            segmentationSymbolUsed) {
     var r = 0.5; // formula (E-6)
     for (var i = 0, ii = codeblocks.length; i < ii; ++i) {
       var codeblock = codeblocks[i];
       var blockWidth = codeblock.tbx1_ - codeblock.tbx0_;
       var blockHeight = codeblock.tby1_ - codeblock.tby0_;
       if (blockWidth == 0 || blockHeight == 0)
         continue;
       if (!('data' in codeblock))
@@ -32268,16 +32439,18 @@ var JpxImage = (function JpxImageClosure
           case 0:
             bitModel.runSignificancePropogationPass();
             break;
           case 1:
             bitModel.runMagnitudeRefinementPass();
             break;
           case 2:
             bitModel.runCleanupPass();
+            if (segmentationSymbolUsed)
+              bitModel.checkSegmentationSymbol();
             break;
         }
         currentCodingpassType = (currentCodingpassType + 1) % 3;
       }
 
       var offset = (codeblock.tbx0_ - x0) + (codeblock.tby0_ - y0) * width;
       var position = 0;
       for (var j = 0; j < blockHeight; j++) {
@@ -32304,16 +32477,17 @@ var JpxImage = (function JpxImageClosure
     var codingStyleParameters = component.codingStyleParameters;
     var quantizationParameters = component.quantizationParameters;
     var decompositionLevelsCount =
       codingStyleParameters.decompositionLevelsCount;
     var spqcds = quantizationParameters.SPqcds;
     var scalarExpounded = quantizationParameters.scalarExpounded;
     var guardBits = quantizationParameters.guardBits;
     var transformation = codingStyleParameters.transformation;
+    var segmentationSymbolUsed = codingStyleParameters.segmentationSymbolUsed;
     var precision = context.components[c].precision;
 
     var subbandCoefficients = [];
     var k = 0, b = 0;
     for (var i = 0; i <= decompositionLevelsCount; i++) {
       var resolution = component.resolutions[i];
 
       for (var j = 0, jj = resolution.subbands.length; j < jj; j++) {
@@ -32334,17 +32508,18 @@ var JpxImage = (function JpxImageClosure
 
         // calulate quantization coefficient (Section E.1.1.1)
         var delta = Math.pow(2, (precision + gainLog2) - epsilon) *
           (1 + mu / 2048);
         var mb = (guardBits + epsilon - 1);
 
         var coefficients = new Float32Array(width * height);
         copyCoefficients(coefficients, subband.tbx0, subband.tby0,
-          width, height, delta, mb, subband.codeblocks, transformation);
+          width, height, delta, mb, subband.codeblocks, transformation,
+          segmentationSymbolUsed);
 
         subbandCoefficients.push({
           width: width,
           height: height,
           items: coefficients
         });
 
         b++;
@@ -33037,16 +33212,24 @@ var JpxImage = (function JpxImageClosure
                 coefficentsMagnitude[index] = 1;
                 this.setNeighborsSignificance(i, j);
                 processingFlags[index] |= firstMagnitudeBitMask;
               }
               bitsDecoded[index]++;
             }
           }
         }
+      },
+      checkSegmentationSymbol: function BitModel_checkSegmentationSymbol() {
+        var decoder = this.decoder;
+        var cx = this.uniformContext;
+        var symbol = (decoder.readBit(cx) << 3) | (decoder.readBit(cx) << 2) |
+                     (decoder.readBit(cx) << 1) | decoder.readBit(cx);
+        if (symbol != 0xA)
+          throw 'Invalid segmentation symbol';
       }
     };
 
     return BitModel;
   })();
 
   // Section F, Discrete wavelet transofrmation
   var Transform = (function TransformClosure() {
@@ -33258,16 +33441,1078 @@ var JpxImage = (function JpxImageClosure
 })();
 
 
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 
 'use strict';
 
+var Jbig2Image = (function Jbig2ImageClosure() {
+
+  // Annex E. Arithmetic Coding
+  var ArithmeticDecoder = (function ArithmeticDecoderClosure() {
+    var QeTable = [
+      {qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1},
+      {qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0},
+      {qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0},
+      {qe: 0x0AC1, nmps: 4, nlps: 12, switchFlag: 0},
+      {qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0},
+      {qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0},
+      {qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1},
+      {qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0},
+      {qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0},
+      {qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0},
+      {qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0},
+      {qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0},
+      {qe: 0x1C01, nmps: 13, nlps: 20, switchFlag: 0},
+      {qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0},
+      {qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1},
+      {qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0},
+      {qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0},
+      {qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0},
+      {qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0},
+      {qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0},
+      {qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0},
+      {qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0},
+      {qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0},
+      {qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0},
+      {qe: 0x1C01, nmps: 25, nlps: 22, switchFlag: 0},
+      {qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0},
+      {qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0},
+      {qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0},
+      {qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0},
+      {qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0},
+      {qe: 0x0AC1, nmps: 31, nlps: 28, switchFlag: 0},
+      {qe: 0x09C1, nmps: 32, nlps: 29, switchFlag: 0},
+      {qe: 0x08A1, nmps: 33, nlps: 30, switchFlag: 0},
+      {qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0},
+      {qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0},
+      {qe: 0x02A1, nmps: 36, nlps: 33, switchFlag: 0},
+      {qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0},
+      {qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0},
+      {qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0},
+      {qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0},
+      {qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0},
+      {qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0},
+      {qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0},
+      {qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0},
+      {qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0},
+      {qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0},
+      {qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0}
+    ];
+
+    function ArithmeticDecoder(data, start, end) {
+      this.data = data;
+      this.bp = start;
+      this.dataEnd = end;
+
+      this.chigh = data[start];
+      this.clow = 0;
+
+      this.byteIn();
+
+      this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F);
+      this.clow = (this.clow << 7) & 0xFFFF;
+      this.ct -= 7;
+      this.a = 0x8000;
+    }
+
+    ArithmeticDecoder.prototype = {
+      byteIn: function ArithmeticDecoder_byteIn() {
+        var data = this.data;
+        var bp = this.bp;
+        if (data[bp] == 0xFF) {
+          var b1 = data[bp + 1];
+          if (b1 > 0x8F) {
+            this.clow += 0xFF00;
+            this.ct = 8;
+          } else {
+            bp++;
+            this.clow += (data[bp] << 9);
+            this.ct = 7;
+            this.bp = bp;
+          }
+        } else {
+          bp++;
+          this.clow += bp < this.dataEnd ? (data[bp] << 8) : 0xFF00;
+          this.ct = 8;
+          this.bp = bp;
+        }
+        if (this.clow > 0xFFFF) {
+          this.chigh += (this.clow >> 16);
+          this.clow &= 0xFFFF;
+        }
+      },
+      readBit: function ArithmeticDecoder_readBit(cx) {
+        var qeIcx = QeTable[cx.index].qe;
+        this.a -= qeIcx;
+
+        if (this.chigh < qeIcx) {
+          var d = this.exchangeLps(cx);
+          this.renormD();
+          return d;
+        } else {
+          this.chigh -= qeIcx;
+          if ((this.a & 0x8000) == 0) {
+            var d = this.exchangeMps(cx);
+            this.renormD();
+            return d;
+          } else {
+            return cx.mps;
+          }
+        }
+      },
+      renormD: function ArithmeticDecoder_renormD() {
+        do {
+          if (this.ct == 0)
+            this.byteIn();
+
+          this.a <<= 1;
+          this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1);
+          this.clow = (this.clow << 1) & 0xFFFF;
+          this.ct--;
+        } while ((this.a & 0x8000) == 0);
+      },
+      exchangeMps: function ArithmeticDecoder_exchangeMps(cx) {
+        var d;
+        var qeTableIcx = QeTable[cx.index];
+        if (this.a < qeTableIcx.qe) {
+          d = 1 - cx.mps;
+
+          if (qeTableIcx.switchFlag == 1) {
+            cx.mps = 1 - cx.mps;
+          }
+          cx.index = qeTableIcx.nlps;
+        } else {
+          d = cx.mps;
+          cx.index = qeTableIcx.nmps;
+        }
+        return d;
+      },
+      exchangeLps: function ArithmeticDecoder_exchangeLps(cx) {
+        var d;
+        var qeTableIcx = QeTable[cx.index];
+        if (this.a < qeTableIcx.qe) {
+          this.a = qeTableIcx.qe;
+          d = cx.mps;
+          cx.index = qeTableIcx.nmps;
+        } else {
+          this.a = qeTableIcx.qe;
+          d = 1 - cx.mps;
+
+          if (qeTableIcx.switchFlag == 1) {
+            cx.mps = 1 - cx.mps;
+          }
+          cx.index = qeTableIcx.nlps;
+        }
+        return d;
+      }
+    };
+
+    return ArithmeticDecoder;
+  })();
+
+  // Utility data structures
+  function ContextCache() {}
+
+  ContextCache.prototype = {
+    getContexts: function(id) {
+      if (id in this)
+        return this[id];
+      return (this[id] = []);
+    }
+  };
+
+  function DecodingContext(data, start, end) {
+    this.data = data;
+    this.start = start;
+    this.end = end;
+  }
+
+  DecodingContext.prototype = {
+    get decoder() {
+      var decoder = new ArithmeticDecoder(this.data, this.start, this.end);
+      return shadow(this, 'decoder', decoder);
+    },
+    get contextCache() {
+      var cache = new ContextCache();
+      return shadow(this, 'contextCache', cache);
+    }
+  };
+
+  // Annex A. Arithmetic Integer Decoding Procedure
+  // A.2 Procedure for decoding values
+  function decodeInteger(contextCache, procedure, decoder) {
+    var contexts = contextCache.getContexts(procedure);
+
+    var prev = 1;
+    var state = 1, v = 0, s;
+    var toRead = 32, offset = 4436; // defaults for state 7
+    while (state) {
+      var cx = contexts[prev];
+      if (!cx)
+        contexts[prev] = cx = {index: 0, mps: 0};
+      var bit = decoder.readBit(cx);
+      prev = prev < 256 ? (prev << 1) | bit :
+        (((prev << 1) | bit) & 511) | 256;
+      switch (state) {
+        case 1:
+          s = !!bit;
+          break;
+        case 2:
+          if (bit) break;
+          state = 7;
+          toRead = 2;
+          offset = 0;
+          break;
+        case 3:
+          if (bit) break;
+          state = 7;
+          toRead = 4;
+          offset = 4;
+          break;
+        case 4:
+          if (bit) break;
+          state = 7;
+          toRead = 6;
+          offset = 20;
+          break;
+        case 5:
+          if (bit) break;
+          state = 7;
+          toRead = 8;
+          offset = 84;
+          break;
+        case 6:
+          if (bit) break;
+          state = 7;
+          toRead = 12;
+          offset = 340;
+          break;
+        default:
+          v = v * 2 + bit;
+          if (--toRead == 0)
+            state = 0;
+          continue;
+      }
+      state++;
+    }
+    v += offset;
+    return !s ? v : v > 0 ? -v : null;
+  }
+
+  // A.3 The IAID decoding procedure
+  function decodeIAID(contextCache, decoder, codeLength) {
+    var contexts = contextCache.getContexts('IAID');
+
+    var prev = 1;
+    for (var i = 0; i < codeLength; i++) {
+      var cx = contexts[prev];
+      if (!cx)
+        contexts[prev] = cx = {index: 0, mps: 0};
+      var bit = decoder.readBit(cx);
+      prev = (prev * 2) + bit;
+    }
+    if (codeLength < 31)
+      return prev & ((1 << codeLength) - 1);
+    else
+      return prev - Math.pow(2, codeLength);
+  }
+
+  // 7.3 Segment types
+  var SegmentTypes = [
+    'SymbolDictionary', null, null, null, 'IntermediateTextRegion', null,
+    'ImmediateTextRegion', 'ImmediateLosslessTextRegion', null, null, null,
+    null, null, null, null, null, 'patternDictionary', null, null, null,
+    'IntermediateHalftoneRegion', null, 'ImmediateHalftoneRegion',
+    'ImmediateLosslessHalftoneRegion', null, null, null, null, null, null, null,
+    null, null, null, null, null, 'IntermediateGenericRegion', null,
+    'ImmediateGenericRegion', 'ImmediateLosslessGenericRegion',
+    'IntermediateGenericRefinementRegion', null,
+    'ImmediateGenericRefinementRegion',
+    'ImmediateLosslessGenericRefinementRegion', null, null, null, null,
+    'PageInformation', 'EndOfPage', 'EndOfStripe', 'EndOfFile', 'Profiles',
+    'Tables', null, null, null, null, null, null, null, null,
+    'Extension'
+  ];
+
+  var CodingTemplates = [
+    [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: -2, y: -1},
+     {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: 2, y: -1},
+     {x: -4, y: 0}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}],
+    [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: -2, y: -1},
+     {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: 2, y: -1},
+     {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}],
+    [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: -2, y: -1},
+     {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: -2, y: 0},
+     {x: -1, y: 0}],
+    [{x: -3, y: -1}, {x: -2, y: -1}, {x: -1, y: -1}, {x: 0, y: -1},
+     {x: 1, y: -1}, {x: -4, y: 0}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}]
+  ];
+
+  var RefinementTemplates = [
+    {
+      coding: [{x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}],
+      reference: [{x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}, {x: 0, y: 0},
+                  {x: 1, y: 0}, {x: -1, y: 1}, {x: 0, y: 1}, {x: 1, y: 1}]
+    },
+    {
+      coding: [{x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}],
+      reference: [{x: 0, y: -1}, {x: -1, y: 0}, {x: 0, y: 0}, {x: 1, y: 0},
+                  {x: 0, y: 1}, {x: 1, y: 1}]
+    }
+  ];
+
+  var ReusedContexts = [
+    0x1CD3, // '00111001101' (template) + '0011' (at),
+    0x079A, // '001111001101' + '0',
+    0x00E3, // '001110001' + '1',
+    0x018B  // '011000101' + '1'
+  ];
+
+  var RefinementReusedContexts = [
+    0x0020, // '000' + '0' (coding) + '00010000' + '0' (reference)
+    0x0008  // '0000' + '001000'
+  ];
+
+  function log2(x) {
+    var n = 1, i = 0;
+    while (x > n) {
+      n <<= 1;
+      i++;
+    }
+    return i;
+  }
+
+  function readInt32(data, start) {
+    return (data[start] << 24) | (data[start + 1] << 16) |
+           (data[start + 2] << 8) | data[start + 3];
+  }
+
+  function readUint32(data, start) {
+    var value = readInt32(data, start);
+    return value & 0x80000000 ? (value + 4294967296) : value;
+  }
+
+  function readUint16(data, start) {
+    return (data[start] << 8) | data[start + 1];
+  }
+
+  function readInt8(data, start) {
+    return (data[start] << 24) >> 24;
+  }
+
+  // 6.2 Generic Region Decoding Procedure
+  function decodeBitmap(mmr, width, height, templateIndex, prediction, skip, at,
+                        decodingContext) {
+    if (mmr)
+      error('JBIG2 error: MMR encoding is not supported');
+
+    var useskip = !!skip;
+    var template = CodingTemplates[templateIndex].concat(at);
+    var templateLength = template.length;
+    var templateX = new Int32Array(templateLength);
+    var templateY = new Int32Array(templateLength);
+    for (var k = 0; k < templateLength; k++) {
+      templateX[k] = template[k].x;
+      templateY[k] = template[k].y;
+    }
+
+    var pseudoPixelContext = ReusedContexts[templateIndex];
+    var bitmap = [];
+
+    var decoder = decodingContext.decoder;
+    var contexts = decodingContext.contextCache.getContexts('GB');
+
+    var ltp = 0;
+    for (var i = 0; i < height; i++) {
+      if (prediction) {
+        var cx = contexts[pseudoPixelContext];
+        if (!cx)
+          contexts[pseudoPixelContext] = cx = {index: 0, mps: 0};
+        var sltp = decoder.readBit(cx);
+        ltp ^= sltp;
+      }
+      if (ltp) {
+        bitmap.push(bitmap[bitmap.length - 1]); // duplicate previous row
+        continue;
+      }
+      var row = new Uint8Array(width);
+      bitmap.push(row);
+      for (var j = 0; j < width; j++) {
+        if (useskip && skip[i][j]) {
+          row[j] = 0;
+          continue;
+        }
+        var contextLabel = 0;
+        for (var k = 0; k < templateLength; k++) {
+          var i0 = i + templateY[k], j0 = j + templateX[k];
+          if (i0 < 0 || j0 < 0 || j0 >= width)
+            contextLabel <<= 1; // out of bound pixel
+          else
+            contextLabel = (contextLabel << 1) | bitmap[i0][j0];
+        }
+        var cx = contexts[contextLabel];
+        if (!cx)
+          contexts[contextLabel] = cx = {index: 0, mps: 0};
+        var pixel = decoder.readBit(cx);
+        row[j] = pixel;
+      }
+    }
+    return bitmap;
+  }
+
+  // 6.3.2 Generic Refinement Region Decoding Procedure
+  function decodeRefinement(width, height, templateIndex, referenceBitmap,
+                            offsetX, offsetY, prediction, at,
+                            decodingContext) {
+    var codingTemplate = RefinementTemplates[templateIndex].coding;
+    if (templateIndex == 0)
+      codingTemplate = codingTemplate.concat([at[0]]);
+    var codingTemplateLength = codingTemplate.length;
+    var codingTemplateX = new Int32Array(codingTemplateLength);
+    var codingTemplateY = new Int32Array(codingTemplateLength);
+    for (var k = 0; k < codingTemplateLength; k++) {
+      codingTemplateX[k] = codingTemplate[k].x;
+      codingTemplateY[k] = codingTemplate[k].y;
+    }
+    var referenceTemplate = RefinementTemplates[templateIndex].reference;
+    if (templateIndex == 0)
+      referenceTemplate = referenceTemplate.concat([at[1]]);
+    var referenceTemplateLength = referenceTemplate.length;
+    var referenceTemplateX = new Int32Array(referenceTemplateLength);
+    var referenceTemplateY = new Int32Array(referenceTemplateLength);
+    for (var k = 0; k < referenceTemplateLength; k++) {
+      referenceTemplateX[k] = referenceTemplate[k].x;
+      referenceTemplateY[k] = referenceTemplate[k].y;
+    }
+    var referenceWidth = referenceBitmap[0].length;
+    var referenceHeight = referenceBitmap.length;
+
+    var pseudoPixelContext = RefinementReusedContexts[templateIndex];
+    var bitmap = [];
+
+    var decoder = decodingContext.decoder;
+    var contexts = decodingContext.contextCache.getContexts('GR');
+
+    var ltp = 0;
+    for (var i = 0; i < height; i++) {
+      if (prediction) {
+        var cx = contexts[pseudoPixelContext];
+        if (!cx)
+          contexts[pseudoPixelContext] = cx = {index: 0, mps: 0};
+        var sltp = decoder.readBit(cx);
+        ltp ^= sltp;
+      }
+      var row = new Uint8Array(width);
+      bitmap.push(row);
+      for (var j = 0; j < width; j++) {
+        if (ltp)
+          error('JBIG2 error: prediction is not supported');
+
+        var contextLabel = 0;
+        for (var k = 0; k < codingTemplateLength; k++) {
+          var i0 = i + codingTemplateY[k], j0 = j + codingTemplateX[k];
+          if (i0 < 0 || j0 < 0 || j0 >= width)
+            contextLabel <<= 1; // out of bound pixel
+          else
+            contextLabel = (contextLabel << 1) | bitmap[i0][j0];
+        }
+        for (var k = 0; k < referenceTemplateLength; k++) {
+          var i0 = i + referenceTemplateY[k] + offsetY;
+          var j0 = j + referenceTemplateX[k] + offsetX;
+          if (i0 < 0 || i0 >= referenceHeight || j0 < 0 || j0 >= referenceWidth)
+            contextLabel <<= 1; // out of bound pixel
+          else
+            contextLabel = (contextLabel << 1) | referenceBitmap[i0][j0];
+        }
+        var cx = contexts[contextLabel];
+        if (!cx)
+          contexts[contextLabel] = cx = {index: 0, mps: 0};
+        var pixel = decoder.readBit(cx);
+        row[j] = pixel;
+      }
+    }
+
+    return bitmap;
+  }
+
+  // 6.5.5 Decoding the symbol dictionary
+  function decodeSymbolDictionary(huffman, refinement, symbols,
+                                  numberOfNewSymbols, numberOfExportedSymbols,
+                                  huffmanTables, templateIndex, at,
+                                  refinementTemplateIndex, refinementAt,
+                                  decodingContext) {
+    if (huffman)
+      error('JBIG2 error: huffman is not supported');
+
+    var newSymbols = [];
+    var currentHeight = 0;
+    var symbolCodeLength = log2(symbols.length + numberOfNewSymbols);
+
+    var decoder = decodingContext.decoder;
+    var contextCache = decodingContext.contextCache;
+
+    while (newSymbols.length < numberOfNewSymbols) {
+      var deltaHeight = decodeInteger(contextCache, 'IADH', decoder); // 6.5.6
+      currentHeight += deltaHeight;
+      var currentWidth = 0;
+      var totalWidth = 0;
+      while (true) {
+        var deltaWidth = decodeInteger(contextCache, 'IADW', decoder); // 6.5.7
+        if (deltaWidth == null)
+          break; // OOB
+        currentWidth += deltaWidth;
+        totalWidth += currentWidth;
+        var bitmap;
+        if (refinement) {
+          // 6.5.8.2 Refinement/aggregate-coded symbol bitmap
+          var numberOfInstances = decodeInteger(contextCache, 'IAAI', decoder);
+          if (numberOfInstances > 1)
+            error('JBIG2 error: number of instances > 1 is not supported');
+          var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
+          var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
+          var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
+          var symbol = symbolId < symbols.length ? symbols[symbolId] :
+            newSymbols[symbolId - symbols.length];
+          bitmap = decodeRefinement(currentWidth, currentHeight,
+            refinementTemplateIndex, symbol, rdx, rdy, false, refinementAt,
+            decodingContext);
+        } else {
+          // 6.5.8.1 Direct-coded symbol bitmap
+          bitmap = decodeBitmap(false, currentWidth, currentHeight,
+            templateIndex, false, null, at, decodingContext);
+        }
+        newSymbols.push(bitmap);
+      }
+    }
+    // 6.5.10 Exported symbols
+    var exportedSymbols = [];
+    var flags = [], currentFlag = false;
+    var totalSymbolsLength = symbols.length + numberOfNewSymbols;
+    while (flags.length < totalSymbolsLength) {
+      var runLength = decodeInteger(contextCache, 'IAEX', decoder);
+      while (runLength--)
+        flags.push(currentFlag);
+      currentFlag = !currentFlag;
+    }
+    for (var i = 0, ii = symbols.length; i < ii; i++)
+      if (flags[i]) exportedSymbols.push(symbols[i]);
+    for (var j = 0; j < numberOfNewSymbols; i++, j++)
+      if (flags[i]) exportedSymbols.push(newSymbols[j]);
+    return exportedSymbols;
+  }
+
+  function decodeTextRegion(huffman, refinement, width, height,
+                            defaultPixelValue, numberOfSymbolInstances,
+                            stripSize, inputSymbols, symbolCodeLength,
+                            transposed, dsOffset, referenceCorner,
+                            combinationOperator, huffmanTables,
+                            refinementTemplateIndex, refinementAt,
+                            decodingContext) {
+    if (huffman)
+      error('JBIG2 error: huffman is not supported');
+
+    // Prepare bitmap
+    var bitmap = [];
+    for (var i = 0; i < height; i++) {
+      var row = new Uint8Array(width);
+      if (defaultPixelValue) {
+        for (var j = 0; j < width; j++)
+          row[j] = defaultPixelValue;
+      }
+      bitmap.push(row);
+    }
+
+    var decoder = decodingContext.decoder;
+    var contextCache = decodingContext.contextCache;
+
+    if (transposed)
+      error('JBIG2 error: transposed is not supported');
+
+    var stripT = -decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
+    var firstS = 0;
+    var i = 0;
+    while (i < numberOfSymbolInstances) {
+      var deltaT = decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
+      stripT += deltaT;
+
+      var deltaFirstS = decodeInteger(contextCache, 'IAFS', decoder); // 6.4.7
+      firstS += deltaFirstS;
+      var currentS = firstS;
+      do {
+        var currentT = stripSize == 1 ? 0 :
+          decodeInteger(contextCache, 'IAIT', decoder); // 6.4.9
+        var t = stripSize * stripT + currentT;
+        var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
+        var applyRefinement = refinement &&
+          decodeInteger(contextCache, 'IARI', decoder);
+        var symbolBitmap = inputSymbols[symbolId];
+        var symbolWidth = symbolBitmap[0].length;
+        var symbolHeight = symbolBitmap.length;
+        if (applyRefinement) {
+          var rdw = decodeInteger(contextCache, 'IARDW', decoder); // 6.4.11.1
+          var rdh = decodeInteger(contextCache, 'IARDH', decoder); // 6.4.11.2
+          var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
+          var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
+          symbolWidth += rdw;
+          symbolHeight += rdh;
+          symbolBitmap = decodeRefinement(symbolWidth, symbolHeight,
+            refinementTemplateIndex, symbolBitmap, (rdw >> 1) + rdx,
+            (rdh >> 1) + rdy, false, refinementAt,
+            decodingContext);
+        }
+        var offsetT = t - ((referenceCorner & 1) ? 0 : symbolHeight);
+        var offsetS = currentS - ((referenceCorner & 2) ? symbolWidth : 0);
+        for (var t2 = 0; t2 < symbolHeight; t2++) {
+          var row = bitmap[offsetT + t2];
+          if (!row) continue;
+          var symbolRow = symbolBitmap[t2];
+          switch (combinationOperator) {
+            case 0: // OR
+              for (var s2 = 0; s2 < symbolWidth; s2++)
+                row[offsetS + s2] |= symbolRow[s2];
+              break;
+            case 2: // XOR
+              for (var s2 = 0; s2 < symbolWidth; s2++)
+                row[offsetS + s2] ^= symbolRow[s2];
+              break;
+            default:
+              error('JBIG2 error: operator ' + combinationOperator +
+                    ' is not supported');
+          }
+        }
+
+        currentS += symbolWidth - 1;
+        i++;
+
+        var deltaS = decodeInteger(contextCache, 'IADS', decoder); // 6.4.8
+        if (deltaS == null)
+          break; // OOB
+        currentS += deltaS + dsOffset;
+      } while (true);
+    }
+    return bitmap;
+  }
+
+  function readSegmentHeader(data, start) {
+    var segmentHeader = {};
+    segmentHeader.number = readUint32(data, start);
+    var flags = data[start + 4];
+    var segmentType = flags & 0x3F;
+    if (!SegmentTypes[segmentType])
+      error('JBIG2 error: invalid segment type: ' + segmentType);
+    segmentHeader.type = segmentType;
+    segmentHeader.typeName = SegmentTypes[segmentType];
+    segmentHeader.deferredNonRetain = !!(flags & 0x80);
+    var pageAssociationFieldSize = !!(flags & 0x40);
+    var referredFlags = data[start + 5];
+    var referredToCount = (referredFlags >> 5) & 7;
+    var retainBits = [referredFlags & 31];
+    var position = start + 6;
+    if (referredFlags == 7) {
+      referredToCount = readInt32(data, position - 1) & 0x1FFFFFFF;
+      position += 3;
+      var bytes = (referredToCount + 7) >> 3;
+      retainBits[0] = data[position++];
+      while (--bytes > 0) {
+        retainBits.push(data[position++]);
+      }
+    } else if (referredFlags == 5 || referredFlags == 6)
+      error('JBIG2 error: invalid referred-to flags');
+    segmentHeader.retainBits = retainBits;
+    var referredToSegmentNumberSize = segmentHeader.number <= 256 ? 1 :
+      segmentHeader.number <= 65536 ? 2 : 4;
+    var referredTo = [];
+    for (var i = 0; i < referredToCount; i++) {
+      var number = referredToSegmentNumberSize == 1 ? data[position] :
+        referredToSegmentNumberSize == 2 ? readUint16(data, position) :
+        readUint32(data, position);
+      referredTo.push(number);
+      position += referredToSegmentNumberSize;
+    }
+    segmentHeader.referredTo = referredTo;
+    if (!pageAssociationFieldSize)
+      segmentHeader.pageAssociation = data[position++];
+    else {
+      segmentHeader.pageAssociation = readUint32(data, position);
+      position += 4;
+    }
+    segmentHeader.length = readUint32(data, position);
+    if (segmentHeader.length == 0xFFFFFFFF)
+      error('JBIG2 error: unknown segment length is not supported');
+    position += 4;
+    segmentHeader.headerEnd = position;
+    return segmentHeader;
+  }
+
+  function readSegments(header, data, start, end) {
+    var segments = [];
+    var position = start;
+    while (position < end) {
+      var segmentHeader = readSegmentHeader(data, position);
+      position = segmentHeader.headerEnd;
+      var segment = {
+        header: segmentHeader,
+        data: data
+      };
+      if (!header.randomAccess) {
+        segment.start = position;
+        position += segmentHeader.length;
+        segment.end = position;
+      }
+      segments.push(segment);
+      if (segmentHeader.type == 51)
+        break; // end of file is found
+    }
+    if (header.randomAccess) {
+      for (var i = 0, ii = segments.length; i < ii; i++) {
+        segments[i].start = position;
+        position += segments[i].header.length;
+        segments[i].end = position;
+      }
+    }
+    return segments;
+  }
+
+  // 7.4.1 Region segment information field
+  function readRegionSegmentInformation(data, start) {
+    return {
+      width: readUint32(data, start),
+      height: readUint32(data, start + 4),
+      x: readUint32(data, start + 8),
+      y: readUint32(data, start + 12),
+      combinationOperator: data[start + 16] & 7
+    };
+  }
+  var RegionSegmentInformationFieldLength = 17;
+
+  function processSegment(segment, visitor) {
+    var header = segment.header;
+
+    var data = segment.data, position = segment.start, end = segment.end;
+    var args;
+    switch (header.type) {
+      case 0: // SymbolDictionary
+        // 7.4.2 Symbol dictionary segment syntax
+        var dictionary = {};
+        var dictionaryFlags = readUint16(data, position); // 7.4.2.1.1
+        dictionary.huffman = !!(dictionaryFlags & 1);
+        dictionary.refinement = !!(dictionaryFlags & 2);
+        dictionary.huffmanDHSelector = (dictionaryFlags >> 2) & 3;
+        dictionary.huffmanDWSelector = (dictionaryFlags >> 4) & 3;
+        dictionary.bitmapSizeSelector = (dictionaryFlags >> 6) & 1;
+        dictionary.aggregationInstancesSelector = (dictionaryFlags >> 7) & 1;
+        dictionary.bitmapCodingContextUsed = !!(dictionaryFlags & 256);
+        dictionary.bitmapCodingContextRetained = !!(dictionaryFlags & 512);
+        dictionary.template = (dictionaryFlags >> 10) & 3;
+        dictionary.refinementTemplate = (dictionaryFlags >> 12) & 1;
+        position += 2;
+        if (!dictionary.huffman) {
+          var atLength = dictionary.template == 0 ? 4 : 1;
+          var at = [];
+          for (var i = 0; i < atLength; i++) {
+            at.push({
+              x: readInt8(data, position),
+              y: readInt8(data, position + 1)
+            });
+            position += 2;
+          }
+          dictionary.at = at;
+        }
+        if (dictionary.refinement && !dictionary.refinementTemplate) {
+          var at = [];
+          for (var i = 0; i < 2; i++) {
+            at.push({
+              x: readInt8(data, position),
+              y: readInt8(data, position + 1)
+            });
+            position += 2;
+          }
+          dictionary.refinementAt = at;
+        }
+        dictionary.numberOfExportedSymbols = readUint32(data, position);
+        position += 4;
+        dictionary.numberOfNewSymbols = readUint32(data, position);
+        position += 4;
+        args = [dictionary, header.number, header.referredTo,
+                data, position, end];
+        break;
+      case 6: // ImmediateTextRegion
+      case 7: // ImmediateLosslessTextRegion
+        var textRegion = {};
+        textRegion.info = readRegionSegmentInformation(data, position);
+        position += RegionSegmentInformationFieldLength;
+        var textRegionSegmentFlags = readUint16(data, position);
+        position += 2;
+        textRegion.huffman = !!(textRegionSegmentFlags & 1);
+        textRegion.refinement = !!(textRegionSegmentFlags & 2);
+        textRegion.stripSize = 1 << ((textRegionSegmentFlags >> 2) & 3);
+        textRegion.referenceCorner = (textRegionSegmentFlags >> 4) & 3;
+        textRegion.transposed = !!(textRegionSegmentFlags & 64);
+        textRegion.combinationOperator = (textRegionSegmentFlags >> 7) & 3;
+        textRegion.defaultPixelValue = (textRegionSegmentFlags >> 9) & 1;
+        textRegion.dsOffset = (textRegionSegmentFlags >> 10) & 31;
+        textRegion.refinementTemplate = (textRegionSegmentFlags >> 15) & 1;
+        if (textRegion.huffman) {
+          var textRegionHuffmanFlags = readUint16(data, position);
+          position += 2;
+          textRegion.huffmanFS = (textRegionHuffmanFlags) & 3;
+          textRegion.huffmanDS = (textRegionHuffmanFlags >> 2) & 3;
+          textRegion.huffmanDT = (textRegionHuffmanFlags >> 4) & 3;
+          textRegion.huffmanRefinementDW = (textRegionHuffmanFlags >> 6) & 3;
+          textRegion.huffmanRefinementDH = (textRegionHuffmanFlags >> 8) & 3;
+          textRegion.huffmanRefinementDX = (textRegionHuffmanFlags >> 10) & 3;
+          textRegion.huffmanRefinementDY = (textRegionHuffmanFlags >> 12) & 3;
+          textRegion.huffmanRefinementSizeSelector =
+            !!(textRegionHuffmanFlags & 14);
+        }
+        if (textRegion.refinement && !textRegion.refinementTemplate) {
+          var at = [];
+          for (var i = 0; i < 2; i++) {
+            at.push({
+              x: readInt8(data, position),
+              y: readInt8(data, position + 1)
+            });
+            position += 2;
+          }
+          textRegion.refinementAt = at;
+        }
+        textRegion.numberOfSymbolInstances = readUint32(data, position);
+        position += 4;
+        // TODO 7.4.3.1.7 Symbol ID Huffman table decoding
+        if (textRegion.huffman)
+          error('JBIG2 error: huffman is not supported');
+        args = [textRegion, header.referredTo, data, position, end];
+        break;
+      case 38: // ImmediateGenericRegion
+      case 39: // ImmediateLosslessGenericRegion
+        var genericRegion = {};
+        genericRegion.info = readRegionSegmentInformation(data, position);
+        position += RegionSegmentInformationFieldLength;
+        var genericRegionSegmentFlags = data[position++];
+        genericRegion.mmr = !!(genericRegionSegmentFlags & 1);
+        genericRegion.template = (genericRegionSegmentFlags >> 1) & 3;
+        genericRegion.prediction = !!(genericRegionSegmentFlags & 8);
+        if (!genericRegion.mmr) {
+          var atLength = genericRegion.template == 0 ? 4 : 1;
+          var at = [];
+          for (var i = 0; i < atLength; i++) {
+            at.push({
+              x: readInt8(data, position),
+              y: readInt8(data, position + 1)
+            });
+            position += 2;
+          }
+          genericRegion.at = at;
+        }
+        args = [genericRegion, data, position, end];
+        break;
+      case 48: // PageInformation
+        var pageInfo = {
+          width: readUint32(data, position),
+          height: readUint32(data, position + 4),
+          resolutionX: readUint32(data, position + 8),
+          resolutionY: readUint32(data, position + 12)
+        };
+        if (pageInfo.height == 0xFFFFFFFF)
+          delete pageInfo.height;
+        var pageSegmentFlags = data[position + 16];
+        var pageStripingInformatiom = readUint16(data, position + 17);
+        pageInfo.lossless = !!(pageSegmentFlags & 1);
+        pageInfo.refinement = !!(pageSegmentFlags & 2);
+        pageInfo.defaultPixelValue = (pageSegmentFlags >> 2) & 1;
+        pageInfo.combinationOperator = (pageSegmentFlags >> 3) & 3;
+        pageInfo.requiresBuffer = !!(pageSegmentFlags & 32);
+        pageInfo.combinationOperatorOverride = !!(pageSegmentFlags & 64);
+        args = [pageInfo];
+        break;
+      case 50: // EndOfStripe
+        break;
+      case 51: // EndOfFile
+        break;
+      default:
+        error('JBIG2 error: segment type ' + header.typeName + '(' +
+              header.type + ') is not implemented');
+    }
+    var callbackName = 'on' + header.typeName;
+    if (callbackName in visitor)
+      visitor[callbackName].apply(visitor, args);
+  }
+
+  function processSegments(segments, visitor) {
+    for (var i = 0, ii = segments.length; i < ii; i++)
+      processSegment(segments[i], visitor);
+  }
+
+  function parseJbig2(data, start, end) {
+    var position = start;
+    if (data[position] != 0x97 || data[position + 1] != 0x4A ||
+        data[position + 2] != 0x42 || data[position + 3] != 0x32 ||
+        data[position + 4] != 0x0D || data[position + 5] != 0x0A ||
+        data[position + 6] != 0x1A || data[position + 7] != 0x0A)
+      error('JBIG2 error: invalid header');
+    var header = {};
+    position += 8;
+    var flags = data[position++];
+    header.randomAccess = !(flags & 1);
+    if (!(flags & 2)) {
+      header.numberOfPages = readUint32(data, position);
+      position += 4;
+    }
+    var segments = readSegments(header, data, position, end);
+    error('Not implemented');
+    // processSegments(segments, new SimpleSegmentVisitor());
+  }
+
+  function parseJbig2Chunks(chunks) {
+    var visitor = new SimpleSegmentVisitor();
+    for (var i = 0, ii = chunks.length; i < ii; i++) {
+      var chunk = chunks[i];
+      var segments = readSegments({}, chunk.data, chunk.start, chunk.end);
+      processSegments(segments, visitor);
+    }
+    return visitor.buffer;
+  }
+
+  function SimpleSegmentVisitor() {}
+
+  SimpleSegmentVisitor.prototype = {
+    onPageInformation: function SimpleSegmentVisitor_onPageInformation(info) {
+      this.currentPageInfo = info;
+      var rowSize = (info.width + 7) >> 3;
+      var buffer = new Uint8Array(rowSize * info.height);
+      var fill = info.defaultPixelValue ? 0xFF : 0;
+      for (var i = 0, ii = buffer.length; i < ii; i++)
+        buffer[i] = fill;
+      this.buffer = buffer;
+    },
+    drawBitmap: function SimpleSegmentVisitor_drawBitmap(regionInfo, bitmap) {
+      var pageInfo = this.currentPageInfo;
+      var width = regionInfo.width, height = regionInfo.height;
+      var rowSize = (pageInfo.width + 7) >> 3;
+      var combinationOperator = pageInfo.combinationOperatorOverride ?
+        regionInfo.combinationOperator : pageInfo.combinationOperator;
+      var buffer = this.buffer;
+      for (var i = 0; i < height; i++) {
+        var mask = 128 >> (regionInfo.x & 7);
+        var offset = (i + regionInfo.y) * rowSize + (regionInfo.x >> 3);
+        switch (combinationOperator) {
+          case 0: // OR
+            for (var j = 0; j < width; j++) {
+              buffer[offset] |= bitmap[i][j] ? mask : 0;
+              mask >>= 1;
+              if (!mask) {
+                mask = 128;
+                offset++;
+              }
+            }
+            break;
+          case 2: // XOR
+            for (var j = 0; j < width; j++) {
+              buffer[offset] ^= bitmap[i][j] ? mask : 0;
+              mask >>= 1;
+              if (!mask) {
+                mask = 128;
+                offset++;
+              }
+            }
+            break;
+          default:
+            error('JBIG2 error: operator ' + combinationOperator +
+                  ' is not supported');
+        }
+      }
+    },
+    onImmediateGenericRegion:
+      function SimpleSegmentVisitor_onImmediateGenericRegion(region, data,
+                                                             start, end) {
+      var regionInfo = region.info;
+      var decodingContext = new DecodingContext(data, start, end);
+      var bitmap = decodeBitmap(region.mmr, regionInfo.width, regionInfo.height,
+                                region.template, region.prediction, null,
+                                region.at, decodingContext);
+      this.drawBitmap(regionInfo, bitmap);
+    },
+    onImmediateLosslessGenericRegion:
+      function SimpleSegmentVisitor_onImmediateLosslessGenericRegion() {
+      this.onImmediateGenericRegion.apply(this, arguments);
+    },
+    onSymbolDictionary:
+      function SimpleSegmentVisitor_onSymbolDictionary(dictionary,
+                                                       currentSegment,
+                                                       referredSegments,
+                                                       data, start, end) {
+      var huffmanTables;
+      if (dictionary.huffman)
+        error('JBIG2 error: huffman is not supported');
+
+      // Combines exported symbols from all referred segments
+      var symbols = this.symbols;
+      if (!symbols)
+        this.symbols = symbols = {};
+
+      var inputSymbols = [];
+      for (var i = 0, ii = referredSegments.length; i < ii; i++)
+        inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]);
+
+      var decodingContext = new DecodingContext(data, start, end);
+      symbols[currentSegment] = decodeSymbolDictionary(dictionary.huffman,
+        dictionary.refinement, inputSymbols, dictionary.numberOfNewSymbols,
+        dictionary.numberOfExportedSymbols, huffmanTables,
+        dictionary.template, dictionary.at,
+        dictionary.refinementTemplate, dictionary.refinementAt,
+        decodingContext);
+    },
+    onImmediateTextRegion:
+      function SimpleSegmentVisitor_onImmediateTextRegion(region,
+                                                          referredSegments,
+                                                          data, start, end) {
+      var regionInfo = region.info;
+      var huffmanTables;
+
+      // Combines exported symbols from all referred segments
+      var symbols = this.symbols;
+      var inputSymbols = [];
+      for (var i = 0, ii = referredSegments.length; i < ii; i++)
+        inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]);
+      var symbolCodeLength = log2(inputSymbols.length);
+
+      var decodingContext = new DecodingContext(data, start, end);
+      var bitmap = decodeTextRegion(region.huffman, region.refinement,
+        regionInfo.width, regionInfo.height, region.defaultPixelValue,
+        region.numberOfSymbolInstances, region.stripSize, inputSymbols,
+        symbolCodeLength, region.transposed, region.dsOffset,
+        region.referenceCorner, region.combinationOperator, huffmanTables,
+        region.refinementTemplate, region.refinementAt, decodingContext);
+      this.drawBitmap(regionInfo, bitmap);
+    },
+    onImmediateLosslessTextRegion:
+      function SimpleSegmentVisitor_onImmediateLosslessTextRegion() {
+        this.onImmediateTextRegion.apply(this, arguments);
+    }
+  };
+
+  function Jbig2Image() {}
+
+  Jbig2Image.prototype = {
+    parseChunks: function Jbig2Image_parseChunks(chunks) {
+      return parseJbig2Chunks(chunks);
+    }
+  };
+
+  return Jbig2Image;
+})();
+
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+'use strict';
+
 var bidi = PDFJS.bidi = (function bidiClosure() {
   // Character types for symbols from 0000 to 00FF.
   var baseTypes = [
     'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'S', 'B', 'S', 'WS',
     'B', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
     'BN', 'BN', 'B', 'B', 'B', 'S', 'WS', 'ON', 'ON', 'ET', 'ET', 'ET', 'ON',
     'ON', 'ON', 'ON', 'ON', 'ON', 'CS', 'ON', 'CS', 'ON', 'EN', 'EN', 'EN',
     'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'ON', 'ON', 'ON', 'ON', 'ON',
@@ -33794,36 +35039,36 @@ var Metadata = PDFJS.Metadata = (functio
     <script type="text/javascript" src="debugger.js"></script>
     <script type="text/javascript" src="viewer.js"></script>
   </head>
 
   <body>
     <div id="outerContainer">
 
       <div id="sidebarContainer">
-        <div id="toolbarSidebar">
+        <div id="toolbarSidebar" class="splitToolbarButton toggled">
           <button id="viewThumbnail" class="toolbarButton group toggled" title="Show Thumbnails" onclick="PDFView.switchSidebarView('thumbs')" tabindex="1" data-l10n-id="thumbs">
              <span data-l10n-id="thumbs_label">Thumbnails</span>
           </button>
           <button id="viewOutline" class="toolbarButton group" title="Show Document Outline" onclick="PDFView.switchSidebarView('outline')" tabindex="2" data-l10n-id="outline">
              <span data-l10n-id="outline_label">Document Outline</span>
           </button>
-          <button id="viewSearch" class="toolbarButton group hidden" title="Search Document" onclick="PDFView.switchSidebarView('search')" tabindex="3" data-l10n-id="search">
-             <span data-l10n-id="search_label">Search Document</span>
+          <button id="viewSearch" class="toolbarButton group hidden" title="Search Document" onclick="PDFView.switchSidebarView('search')" tabindex="3" data-l10n-id="search_panel">
+             <span data-l10n-id="search_panel_label">Search Document</span>
           </button>
         </div>
         <div id="sidebarContent">
           <div id="thumbnailView">
           </div>
           <div id="outlineView" class="hidden">
           </div>
           <div id="searchView" class="hidden">
             <div id="searchToolbar">
-              <input id="searchTermsInput" onkeydown='if (event.keyCode == 13) PDFView.search()'>
-              <button id="searchButton" onclick='PDFView.search()' data-l10n-id="search_button">Find</button>
+              <input id="searchTermsInput" class="toolbarField" onkeydown='if (event.keyCode == 13) PDFView.search()'>
+              <button id="searchButton" class="textButton toolbarButton" onclick='PDFView.search()' data-l10n-id="search">Find</button>
             </div>
             <div id="searchResults"></div>
           </div>
         </div>
       </div>  <!-- sidebarContainer -->
 
       <div id="mainContainer">
         <div class="toolbar">
@@ -33850,21 +35095,19 @@ var Metadata = PDFJS.Metadata = (functio
                 <span id="numPages" class="toolbarLabel"></span>
               </div>
               <div id="toolbarViewerRight">
                 <input id="fileInput" class="fileInput" type="file" oncontextmenu="return false;" style="visibility: hidden; position: fixed; right: 0; top: 0" />
                 <button id="openFile" class="toolbarButton openFile" title="Open File" tabindex="11" data-l10n-id="open_file" onclick="document.getElementById('fileInput').click()">
                    <span data-l10n-id="open_file_label">Open</span>
                 </button>
 
-                <!--
                 <button id="print" class="toolbarButton print" title="Print" tabindex="11" data-l10n-id="print" onclick="window.print()">
                   <span data-l10n-id="print_label">Print</span>
                 </button>
-                -->
 
                 <button id="download" class="toolbarButton download" title="Download" onclick="PDFView.download();" tabindex="12" data-l10n-id="download">
                   <span data-l10n-id="download_label">Download</span>
                 </button>
                 <!-- <div class="toolbarButtonSpacer"></div> -->
                 <a href="#" id="viewBookmark" class="toolbarButton bookmark" title="Current view (copy or open in new window)" tabindex="13" data-l10n-id="bookmark"><span data-l10n-id="bookmark_label">Current View</span></a>
               </div>
               <div class="outerCenter">
@@ -33899,18 +35142,18 @@ var Metadata = PDFJS.Metadata = (functio
           </div>
         </div>
 
         <div id="viewerContainer">
           <div id="viewer"></div>
         </div>
 
         <div id="loadingBox">
-            <div id="loading" data-l10n-id="loading" data-l10n-args='{"percent": 0}'>Loading... 0%</div>
-            <div id="loadingBar"><div class="progress"></div></div>
+          <div id="loading"></div>
+          <div id="loadingBar"><div class="progress"></div></div>
         </div>
 
         <div id="errorWrapper" hidden='true'>
           <div id="errorMessageLeft">
             <span id="errorMessage"></span>
             <button id="errorShowMore" onclick="" oncontextmenu="return false;" data-l10n-id="error_more_info">
               More Information
             </button>
@@ -33924,10 +35167,11 @@ var Metadata = PDFJS.Metadata = (functio
             </button>
           </div>
           <div class="clearBoth"></div>
           <textarea id="errorMoreInfo" hidden='true' readonly="readonly"></textarea>
         </div>
       </div> <!-- mainContainer -->
 
     </div> <!-- outerContainer -->
+    <div id="printContainer"></div>
   </body>
 </html>
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -9,16 +9,23 @@ var kDefaultScaleDelta = 1.1;
 var kUnknownScale = 0;
 var kCacheSize = 20;
 var kCssUnits = 96.0 / 72.0;
 var kScrollbarPadding = 40;
 var kMinScale = 0.25;
 var kMaxScale = 4.0;
 var kImageDirectory = './images/';
 var kSettingsMemory = 20;
+var RenderingStates = {
+  INITIAL: 0,
+  RUNNING: 1,
+  PAUSED: 2,
+  FINISHED: 3
+};
+
 
 var mozL10n = document.mozL10n || document.webL10n;
 
 function getFileName(url) {
   var anchor = url.indexOf('#');
   var query = url.indexOf('?');
   var end = Math.min(
     anchor > 0 ? anchor : url.length,
@@ -78,67 +85,73 @@ var ProgressBar = (function ProgressBarC
       this._percent = clamp(val, 0, 100);
       this.updateBar();
     }
   };
 
   return ProgressBar;
 })();
 
-var RenderingQueue = (function RenderingQueueClosure() {
-  function RenderingQueue() {
-    this.items = [];
-  }
-
-  RenderingQueue.prototype = {
-    enqueueDraw: function RenderingQueueEnqueueDraw(item) {
-      if (!item.drawingRequired())
-        return; // as no redraw required, no need for queueing.
-
-      this.items.push(item);
-      if (this.items.length > 1)
-        return; // not first item
-
-      item.draw(this.continueExecution.bind(this));
-    },
-    continueExecution: function RenderingQueueContinueExecution() {
-      var item = this.items.shift();
-
-      if (this.items.length == 0)
-        return; // queue is empty
-
-      item = this.items[0];
-      item.draw(this.continueExecution.bind(this));
-    }
-  };
-
-  return RenderingQueue;
-})();
-
 var FirefoxCom = (function FirefoxComClosure() {
   return {
     /**
-     * Creates an event that hopefully the extension is listening for and will
+     * Creates an event that the extension is listening for and will
      * synchronously respond to.
+     * NOTE: It is reccomended to use request() instead since one day we may not
+     * be able to synchronously reply.
      * @param {String} action The action to trigger.
      * @param {String} data Optional data to send.
      * @return {*} The response.
      */
-    request: function(action, data) {
+    requestSync: function(action, data) {
       var request = document.createTextNode('');
       request.setUserData('action', action, null);
       request.setUserData('data', data, null);
+      request.setUserData('sync', true, null);
       document.documentElement.appendChild(request);
 
       var sender = document.createEvent('Events');
       sender.initEvent('pdf.js.message', true, false);
       request.dispatchEvent(sender);
       var response = request.getUserData('response');
       document.documentElement.removeChild(request);
       return response;
+    },
+    /**
+     * Creates an event that the extension is listening for and will
+     * asynchronously respond by calling the callback.
+     * @param {String} action The action to trigger.
+     * @param {String} data Optional data to send.
+     * @param {Function} callback Optional response callback that will be called
+     * with one data argument.
+     */
+    request: function(action, data, callback) {
+      var request = document.createTextNode('');
+      request.setUserData('action', action, null);
+      request.setUserData('data', data, null);
+      request.setUserData('sync', false, null);
+      if (callback) {
+        request.setUserData('callback', callback, null);
+
+        document.addEventListener('pdf.js.response', function listener(event) {
+          var node = event.target,
+              callback = node.getUserData('callback'),
+              response = node.getUserData('response');
+
+          document.documentElement.removeChild(node);
+
+          document.removeEventListener('pdf.js.response', listener, false);
+          return callback(response);
+        }, false);
+      }
+      document.documentElement.appendChild(request);
+
+      var sender = document.createEvent('HTMLEvents');
+      sender.initEvent('pdf.js.message', true, false);
+      return request.dispatchEvent(sender);
     }
   };
 })();
 
 // Settings Manager - This is a utility for saving settings
 // First we see if localStorage is available
 // If not, we use FUEL in FF
 var Settings = (function SettingsClosure() {
@@ -155,17 +168,17 @@ var Settings = (function SettingsClosure
   })();
 
   var isFirefoxExtension = PDFJS.isFirefoxExtension;
 
   function Settings(fingerprint) {
     var database = null;
     var index;
     if (isFirefoxExtension)
-      database = FirefoxCom.request('getDatabase', null) || '{}';
+      database = FirefoxCom.requestSync('getDatabase', null) || '{}';
     else if (isLocalStorageEnabled)
       database = localStorage.getItem('database') || '{}';
     else
       return false;
 
     database = JSON.parse(database);
     if (!('files' in database))
       database.files = [];
@@ -188,107 +201,139 @@ var Settings = (function SettingsClosure
     set: function settingsSet(name, val) {
       if (!('file' in this))
         return false;
 
       var file = this.file;
       file[name] = val;
       var database = JSON.stringify(this.database);
       if (isFirefoxExtension)
-        FirefoxCom.request('setDatabase', database);
+        FirefoxCom.requestSync('setDatabase', database);
       else if (isLocalStorageEnabled)
         localStorage.setItem('database', database);
     },
 
     get: function settingsGet(name, defaultValue) {
       if (!('file' in this))
         return defaultValue;
 
       return this.file[name] || defaultValue;
     }
   };
 
   return Settings;
 })();
 
 var cache = new Cache(kCacheSize);
-var renderingQueue = new RenderingQueue();
 var currentPageNumber = 1;
 
 var PDFView = {
   pages: [],
   thumbnails: [],
   currentScale: kUnknownScale,
   currentScaleValue: null,
   initialBookmark: document.location.hash.substring(1),
   startedTextExtraction: false,
   pageText: [],
   container: null,
+  thumbnailContainer: null,
   initialized: false,
   fellback: false,
+  pdfDocument: null,
+  sidebarOpen: false,
+  pageViewScroll: null,
+  thumbnailViewScroll: null,
+
   // called once when the document is loaded
   initialize: function pdfViewInitialize() {
-    this.container = document.getElementById('viewerContainer');
+    var container = this.container = document.getElementById('viewerContainer');
+    this.pageViewScroll = {};
+    this.watchScroll(container, this.pageViewScroll, updateViewarea);
+
+    var thumbnailContainer = this.thumbnailContainer =
+                             document.getElementById('thumbnailView');
+    this.thumbnailViewScroll = {};
+    this.watchScroll(thumbnailContainer, this.thumbnailViewScroll,
+                     this.renderHighestPriority.bind(this));
+
     this.initialized = true;
   },
 
-  setScale: function pdfViewSetScale(val, resetAutoSettings) {
+  // Helper function to keep track whether a div was scrolled up or down and
+  // then call a callback.
+  watchScroll: function pdfViewWatchScroll(viewAreaElement, state, callback) {
+    state.down = true;
+    state.lastY = viewAreaElement.scrollTop;
+    viewAreaElement.addEventListener('scroll', function webViewerScroll(evt) {
+      var currentY = viewAreaElement.scrollTop;
+      var lastY = state.lastY;
+      if (currentY > lastY)
+        state.down = true;
+      else if (currentY < lastY)
+        state.down = false;
+      // else do nothing and use previous value
+      state.lastY = currentY;
+      callback();
+    }, true);
+  },
+
+  setScale: function pdfViewSetScale(val, resetAutoSettings, noScroll) {
     if (val == this.currentScale)
       return;
 
     var pages = this.pages;
     for (var i = 0; i < pages.length; i++)
       pages[i].update(val * kCssUnits);
 
-    if (this.currentScale != val)
+    if (!noScroll && this.currentScale != val)
       this.pages[this.page - 1].scrollIntoView();
     this.currentScale = val;
 
     var event = document.createEvent('UIEvents');
     event.initUIEvent('scalechange', false, false, window, 0);
     event.scale = val;
     event.resetAutoSettings = resetAutoSettings;
     window.dispatchEvent(event);
   },
 
-  parseScale: function pdfViewParseScale(value, resetAutoSettings) {
+  parseScale: function pdfViewParseScale(value, resetAutoSettings, noScroll) {
     if ('custom' == value)
       return;
 
     var scale = parseFloat(value);
     this.currentScaleValue = value;
     if (scale) {
-      this.setScale(scale, true);
+      this.setScale(scale, true, noScroll);
       return;
     }
 
     var container = this.container;
     var currentPage = this.pages[this.page - 1];
     var pageWidthScale = (container.clientWidth - kScrollbarPadding) /
                           currentPage.width * currentPage.scale / kCssUnits;
     var pageHeightScale = (container.clientHeight - kScrollbarPadding) /
                            currentPage.height * currentPage.scale / kCssUnits;
     switch (value) {
       case 'page-actual':
-        this.setScale(1, resetAutoSettings);
+        scale = 1;
         break;
       case 'page-width':
-        this.setScale(pageWidthScale, resetAutoSettings);
+        scale = pageWidthScale;
         break;
       case 'page-height':
-        this.setScale(pageHeightScale, resetAutoSettings);
+        scale = pageHeightScale;
         break;
       case 'page-fit':
-        this.setScale(
-            Math.min(pageWidthScale, pageHeightScale), resetAutoSettings);
+        scale = Math.min(pageWidthScale, pageHeightScale);
         break;
       case 'auto':
-        this.setScale(Math.min(1.0, pageWidthScale), resetAutoSettings);
+        scale = Math.min(1.0, pageWidthScale);
         break;
     }
+    this.setScale(scale, resetAutoSettings, noScroll);
 
     selectScaleOption(value);
   },
 
   zoomIn: function pdfViewZoomIn() {
     var newScale = (this.currentScale * kDefaultScaleDelta).toFixed(2);
     newScale = Math.min(kMaxScale, newScale);
     this.parseScale(newScale, true);
@@ -329,39 +374,51 @@ var PDFView = {
 
     pages[val - 1].scrollIntoView();
   },
 
   get page() {
     return currentPageNumber;
   },
 
+  get supportsPrinting() {
+    var canvas = document.createElement('canvas');
+    var value = 'mozPrintCallback' in canvas;
+    // shadow
+    Object.defineProperty(this, 'supportsPrinting', { value: value,
+                                                      enumerable: true,
+                                                      configurable: true,
+                                                      writable: false });
+    return value;
+  },
+
   open: function pdfViewOpen(url, scale, password) {
     var parameters = {password: password};
     if (typeof url === 'string') { // URL
       this.url = url;
       document.title = decodeURIComponent(getFileName(url)) || url;
       parameters.url = url;
     } else if (url && 'byteLength' in url) { // ArrayBuffer
       parameters.data = url;
     }
 
     if (!PDFView.loadingBar) {
       PDFView.loadingBar = new ProgressBar('#loadingBar', {});
     }
 
+    this.pdfDocument = null;
     var self = this;
     self.loading = true;
     PDFJS.getDocument(parameters).then(
       function getDocumentCallback(pdfDocument) {
         self.load(pdfDocument, scale);
         self.loading = false;
       },
       function getDocumentError(message, exception) {
-        if (exception.name === 'PasswordException') {
+        if (exception && exception.name === 'PasswordException') {
           if (exception.code === 'needpassword') {
             var promptString = mozL10n.get('request_password', null,
                                       'PDF is protected by a password:');
             password = prompt(promptString);
             if (password && password.length > 0) {
               return PDFView.open(url, scale, password);
             }
           }
@@ -379,35 +436,67 @@ var PDFView = {
       },
       function getDocumentProgress(progressData) {
         self.progress(progressData.loaded / progressData.total);
       }
     );
   },
 
   download: function pdfViewDownload() {
+    function noData() {
+      FirefoxCom.request('download', { originalUrl: url });
+    }
+
     var url = this.url.split('#')[0];
     if (PDFJS.isFirefoxExtension) {
-      FirefoxCom.request('download', url);
+      // Document isn't ready just try to download with the url.
+      if (!this.pdfDocument) {
+        noData();
+        return;
+      }
+      this.pdfDocument.getData().then(
+        function getDataSuccess(data) {
+          var bb = new MozBlobBuilder();
+          bb.append(data.buffer);
+          var blobUrl = window.URL.createObjectURL(
+                          bb.getBlob('application/pdf'));
+
+          FirefoxCom.request('download', { blobUrl: blobUrl, originalUrl: url },
+            function response(err) {
+              if (err) {
+                // This error won't really be helpful because it's likely the
+                // fallback won't work either (or is already open).
+                PDFView.error('PDF failed to download.');
+              }
+              window.URL.revokeObjectURL(blobUrl);
+            }
+          );
+        },
+        noData // Error ocurred try downloading with just the url.
+      );
     } else {
       url += '#pdfjs.action=download', '_parent';
       window.open(url, '_parent');
     }
   },
 
   fallback: function pdfViewFallback() {
     if (!PDFJS.isFirefoxExtension)
       return;
     // Only trigger the fallback once so we don't spam the user with messages
     // for one PDF.
     if (this.fellback)
       return;
     this.fellback = true;
     var url = this.url.split('#')[0];
-    FirefoxCom.request('fallback', url);
+    FirefoxCom.request('fallback', url, function response(download) {
+      if (!download)
+        return;
+      PDFView.download();
+    });
   },
 
   navigateTo: function pdfViewNavigateTo(dest) {
     if (typeof dest === 'string')
       dest = this.destinations[dest];
     if (!(dest instanceof Array))
       return; // invalid destination
     // dest array looks like that: <page-ref> </XYZ|FitXXX> <args..>
@@ -523,37 +612,36 @@ var PDFView = {
     lessInfoButton.setAttribute('hidden', 'true');
     errorMoreInfo.value = moreInfoText;
 
     errorMoreInfo.rows = moreInfoText.split('\n').length - 1;
   },
 
   progress: function pdfViewProgress(level) {
     var percent = Math.round(level * 100);
-    var loadingIndicator = document.getElementById('loading');
-    loadingIndicator.textContent = mozL10n.get('loading', {percent: percent},
-      'Loading... {{percent}}%');
-
     PDFView.loadingBar.percent = percent;
   },
 
   load: function pdfViewLoad(pdfDocument, scale) {
     function bindOnAfterDraw(pageView, thumbnailView) {
       // when page is painted, using the image as thumbnail base
       pageView.onAfterDraw = function pdfViewLoadOnAfterDraw() {
         thumbnailView.setImage(pageView.canvas);
-        preDraw();
       };
     }
 
+    this.pdfDocument = pdfDocument;
+
     var errorWrapper = document.getElementById('errorWrapper');
     errorWrapper.setAttribute('hidden', 'true');
 
     var loadingBox = document.getElementById('loadingBox');
     loadingBox.setAttribute('hidden', 'true');
+    var loadingIndicator = document.getElementById('loading');
+    loadingIndicator.textContent = '';
 
     var thumbsView = document.getElementById('thumbnailView');
     thumbsView.parentNode.scrollTop = 0;
 
     while (thumbsView.hasChildNodes())
       thumbsView.removeChild(thumbsView.lastChild);
 
     if ('_loadingInterval' in thumbsView)
@@ -658,16 +746,98 @@ var PDFView = {
 
     if (PDFView.currentScale === kUnknownScale) {
       // Scale was not initialized: invalid bookmark or scale was not specified.
       // Setting the default one.
       this.parseScale(kDefaultScale, true);
     }
   },
 
+  renderHighestPriority: function pdfViewRenderHighestPriority() {
+    // Pages have a higher priority than thumbnails, so check them first.
+    var visiblePages = this.getVisiblePages();
+    var pageView = this.getHighestPriority(visiblePages, this.pages,
+                                           this.pageViewScroll.down);
+    if (pageView) {
+      this.renderView(pageView, 'page');
+      return;
+    }
+    // No pages needed rendering so check thumbnails.
+    if (this.sidebarOpen) {
+      var visibleThumbs = this.getVisibleThumbs();
+      var thumbView = this.getHighestPriority(visibleThumbs,
+                                              this.thumbnails,
+                                              this.thumbnailViewScroll.down);
+      if (thumbView)
+        this.renderView(thumbView, 'thumbnail');
+    }
+  },
+
+  getHighestPriority: function pdfViewGetHighestPriority(visibleViews, views,
+                                                         scrolledDown) {
+    // The state has changed figure out which page has the highest priority to
+    // render next (if any).
+    // Priority:
+    // 1 visible pages
+    // 2 if last scrolled down page after the visible pages
+    // 2 if last scrolled up page before the visible pages
+    var numVisible = visibleViews.length;
+    if (numVisible === 0) {
+      info('No visible views.');
+      return false;
+    }
+    for (var i = 0; i < numVisible; ++i) {
+      var view = visibleViews[i].view;
+      if (!this.isViewFinshed(view))
+        return view;
+    }
+
+    // All the visible views have rendered, try to render next/previous pages.
+    if (scrolledDown) {
+      var lastVisible = visibleViews[visibleViews.length - 1];
+      var nextPageIndex = lastVisible.id;
+      // ID's start at 1 so no need to add 1.
+      if (views[nextPageIndex] && !this.isViewFinshed(views[nextPageIndex]))
+        return views[nextPageIndex];
+    } else {
+      var previousPageIndex = visibleViews[0].id - 2;
+      if (views[previousPageIndex] &&
+          !this.isViewFinshed(views[previousPageIndex]))
+        return views[previousPageIndex];
+    }
+    // Everything that needs to be rendered has been.
+    return false;
+  },
+
+  isViewFinshed: function pdfViewNeedsRendering(view) {
+    return view.renderingState === RenderingStates.FINISHED;
+  },
+
+  // Render a page or thumbnail view. This calls the appropriate function based
+  // on the views state. If the view is already rendered it will return false.
+  renderView: function pdfViewRender(view, type) {
+    var state = view.renderingState;
+    switch (state) {
+      case RenderingStates.FINISHED:
+        return false;
+      case RenderingStates.PAUSED:
+        PDFView.highestPriorityPage = type + view.id;
+        view.resume();
+        break;
+      case RenderingStates.RUNNING:
+        PDFView.highestPriorityPage = type + view.id;
+        break;
+      case RenderingStates.INITIAL:
+        PDFView.highestPriorityPage = type + view.id;
+        view.draw(this.renderHighestPriority.bind(this));
+        break;
+    }
+    return true;
+  },
+
   search: function pdfViewStartSearch() {
     // Limit this function to run every <SEARCH_TIMEOUT>ms.
     var SEARCH_TIMEOUT = 250;
     var lastSeach = this.lastSearch;
     var now = Date.now();
     if (lastSeach && (now - lastSeach) < SEARCH_TIMEOUT) {
       if (!this.searchTimer) {
         this.searchTimer = setTimeout(function resumeSearch() {
@@ -715,17 +885,22 @@ var PDFView = {
       var link = document.createElement('a');
       bindLink(link, pageNumber);
       link.textContent = 'Page ' + pageNumber + ': ' + textSample;
       searchResults.appendChild(link);
 
       pageFound = true;
     }
     if (!pageFound) {
-      searchResults.textContent = '(Not found)';
+      searchResults.textContent = '';
+      var noResults = document.createElement('div');
+      noResults.classList.add('noResults');
+      noResults.textContent = mozL10n.get('search_terms_not_found', null,
+                                              '(Not found)');
+      searchResults.appendChild(noResults);
     }
   },
 
   setHash: function pdfViewSetHash(hash) {
     if (!hash)
       return;
 
     if (hash.indexOf('=') >= 0) {
@@ -776,17 +951,17 @@ var PDFView = {
       case 'thumbs':
         thumbsButton.classList.add('toggled');
         outlineButton.classList.remove('toggled');
         searchButton.classList.remove('toggled');
         thumbsView.classList.remove('hidden');
         outlineView.classList.add('hidden');
         searchView.classList.add('hidden');
 
-        updateThumbViewArea();
+        PDFView.renderHighestPriority();
         break;
 
       case 'outline':
         thumbsButton.classList.remove('toggled');
         outlineButton.classList.add('toggled');
         searchButton.classList.remove('toggled');
         thumbsView.classList.add('hidden');
         outlineView.classList.remove('hidden');
@@ -826,113 +1001,115 @@ var PDFView = {
             extractPageText(pageIndex + 1);
         }
       );
     };
     extractPageText(0);
   },
 
   getVisiblePages: function pdfViewGetVisiblePages() {
-    var pages = this.pages;
-    var kBottomMargin = 10;
-    var kTopPadding = 30;
-    var visiblePages = [];
-
-    var currentHeight = kTopPadding + kBottomMargin;
-    var container = this.container;
-    // Add 1px to the scrolltop to give a little wiggle room if the math is off,
-    // this won't be needed if we calc current page number based off the middle
-    // of the screen instead of the top.
-    var containerTop = container.scrollTop + 1;
-    for (var i = 1; i <= pages.length; ++i) {
-      var page = pages[i - 1];
-      var pageHeight = page.height + kBottomMargin;
-      if (currentHeight + pageHeight > containerTop)
-        break;
-
-      currentHeight += pageHeight;
-    }
-
-    var containerBottom = containerTop + container.clientHeight;
-    for (; i <= pages.length && currentHeight < containerBottom; ++i) {
-      var singlePage = pages[i - 1];
-      visiblePages.push({ id: singlePage.id, y: currentHeight,
-                          view: singlePage });
-      currentHeight += page.height + kBottomMargin;
-    }
-    return visiblePages;
+    return this.getVisibleElements(this.container,
+                                   this.pages);
   },
 
   getVisibleThumbs: function pdfViewGetVisibleThumbs() {
-    var thumbs = this.thumbnails;
-    var kBottomMargin = 15;
-    var visibleThumbs = [];
-
-    var view = document.getElementById('thumbnailView');
-    var currentHeight = kBottomMargin;
+    return this.getVisibleElements(this.thumbnailContainer,
+                                   this.thumbnails);
+  },
 
-    var top = view.scrollTop;
-    for (var i = 1; i <= thumbs.length; ++i) {
-      var thumb = thumbs[i - 1];
-      var thumbHeight = thumb.height * thumb.scaleY + kBottomMargin;
-      if (currentHeight + thumbHeight > top)
+  // Generic helper to find out what elements are visible within a scroll pane.
+  getVisibleElements: function pdfViewGetVisibleElements(scrollEl, views) {
+    var currentHeight = 0, view;
+    var top = scrollEl.scrollTop;
+
+    for (var i = 1; i <= views.length; ++i) {
+      view = views[i - 1];
+      currentHeight = view.el.offsetTop;
+      if (currentHeight + view.el.clientHeight > top)
         break;
-
-      currentHeight += thumbHeight;
+      currentHeight += view.el.clientHeight;
     }
 
-    var bottom = top + view.clientHeight;
-    for (; i <= thumbs.length && currentHeight < bottom; ++i) {
-      var singleThumb = thumbs[i - 1];
-      visibleThumbs.push({ id: singleThumb.id, y: currentHeight,
-                          view: singleThumb });
-      currentHeight += singleThumb.height * singleThumb.scaleY + kBottomMargin;
+    var visible = [];
+    var bottom = top + scrollEl.clientHeight;
+    for (; i <= views.length && currentHeight < bottom; ++i) {
+      view = views[i - 1];
+      currentHeight = view.el.offsetTop;
+      visible.push({ id: view.id, y: currentHeight,
+                     view: view });
+      currentHeight += view.el.clientHeight;
     }
 
-    return visibleThumbs;
+    return visible;
   },
 
   // Helper function to parse query string (e.g. ?param1=value&parm2=...).
   parseQueryString: function pdfViewParseQueryString(query) {
     var parts = query.split('&');
     var params = {};
     for (var i = 0, ii = parts.length; i < parts.length; ++i) {
       var param = parts[i].split('=');
       var key = param[0];
       var value = param.length > 1 ? param[1] : null;
       params[unescape(key)] = unescape(value);
     }
     return params;
+  },
+
+  beforePrint: function pdfViewSetupBeforePrint() {
+    if (!this.supportsPrinting) {
+      var printMessage = mozL10n.get('printing_not_supported', null,
+          'Warning: Printing is not fully supported by this browser.');
+      this.error(printMessage);
+      return;
+    }
+    var body = document.querySelector('body');
+    body.setAttribute('data-mozPrintCallback', true);
+    for (var i = 0, ii = this.pages.length; i < ii; ++i) {
+      this.pages[i].beforePrint();
+    }
+  },
+
+  afterPrint: function pdfViewSetupAfterPrint() {
+    var div = document.getElementById('printContainer');
+    while (div.hasChildNodes())
+      div.removeChild(div.lastChild);
   }
 };
 
 var PageView = function pageView(container, pdfPage, id, scale,
                                  stats, navigateTo) {
   this.id = id;
   this.pdfPage = pdfPage;
 
   this.scale = scale || 1.0;
   this.viewport = this.pdfPage.getViewport(this.scale);
 
+  this.renderingState = RenderingStates.INITIAL;
+  this.resume = null;
+
   var anchor = document.createElement('a');
   anchor.name = '' + this.id;
 
-  var div = document.createElement('div');
+  var div = this.el = document.createElement('div');
   div.id = 'pageContainer' + this.id;
   div.className = 'page';
 
   container.appendChild(anchor);
   container.appendChild(div);
 
   this.destroy = function pageViewDestroy() {
     this.update();
     this.pdfPage.destroy();
   };
 
   this.update = function pageViewUpdate(scale) {
+    this.renderingState = RenderingStates.INITIAL;
+    this.resume = null;
+
     this.scale = scale || this.scale;
     var viewport = this.pdfPage.getViewport(this.scale);
 
     this.viewport = viewport;
     div.style.width = viewport.width + 'px';
     div.style.height = viewport.height + 'px';
 
     while (div.hasChildNodes())
@@ -1096,19 +1273,19 @@ var PageView = function pageView(contain
             height / kCssUnits;
           scale = Math.min(widthScale, heightScale);
           break;
         default:
           return;
       }
 
       if (scale && scale !== PDFView.currentScale)
-        PDFView.parseScale(scale, true);
+        PDFView.parseScale(scale, true, true);
       else if (PDFView.currentScale === kUnknownScale)
-        PDFView.parseScale(kDefaultScale, true);
+        PDFView.parseScale(kDefaultScale, true, true);
 
       var boundingRect = [
         this.viewport.convertToViewportPoint(x, y),
         this.viewport.convertToViewportPoint(x + width, y + height)
       ];
       setTimeout(function pageViewScrollIntoViewRelayout() {
         // letting page to re-layout before scrolling
         var scale = PDFView.currentScale;
@@ -1125,26 +1302,21 @@ var PageView = function pageView(contain
         tempDiv.style.width = Math.ceil(width) + 'px';
         tempDiv.style.height = Math.ceil(height) + 'px';
         div.appendChild(tempDiv);
         tempDiv.scrollIntoView(true);
         div.removeChild(tempDiv);
       }, 0);
   };
 
-  this.drawingRequired = function() {
-    return !div.querySelector('canvas');
-  };
+  this.draw = function pageviewDraw(callback) {
+    if (this.renderingState !== RenderingStates.INITIAL)
+      error('Must be in new state before drawing');
 
-  this.draw = function pageviewDraw(callback) {
-    if (!this.drawingRequired()) {
-      this.updateStats();
-      callback();
-      return;
-    }
+    this.renderingState = RenderingStates.RUNNING;
 
     var canvas = document.createElement('canvas');
     canvas.id = 'page' + this.id;
     canvas.mozOpaque = true;
     div.appendChild(canvas);
     this.canvas = canvas;
 
     var textLayerDiv = null;
@@ -1164,16 +1336,18 @@ var PageView = function pageView(contain
     ctx.fillStyle = 'rgb(255, 255, 255)';
     ctx.fillRect(0, 0, canvas.width, canvas.height);
     ctx.restore();
 
     // Rendering area
 
     var self = this;
     function pageViewDrawCallback(error) {
+      self.renderingState = RenderingStates.FINISHED;
+
       if (self.loadingIconDiv) {
         div.removeChild(self.loadingIconDiv);
         delete self.loadingIconDiv;
       }
 
       if (error) {
         PDFView.error(mozL10n.get('rendering_error', null,
           'An error occurred while rendering the page.'), error);
@@ -1186,31 +1360,80 @@ var PageView = function pageView(contain
 
       cache.push(self);
       callback();
     }
 
     var renderContext = {
       canvasContext: ctx,
       viewport: this.viewport,
-      textLayer: textLayer
+      textLayer: textLayer,
+      continueCallback: function pdfViewcContinueCallback(cont) {
+        if (PDFView.highestPriorityPage !== 'page' + self.id) {
+          self.renderingState = RenderingStates.PAUSED;
+          self.resume = function resumeCallback() {
+            self.renderingState = RenderingStates.RUNNING;
+            cont();
+          };
+          return;
+        }
+        cont();
+      }
     };
     this.pdfPage.render(renderContext).then(
       function pdfPageRenderCallback() {
         pageViewDrawCallback(null);
       },
       function pdfPageRenderError(error) {
         pageViewDrawCallback(error);
       }
     );
 
     setupAnnotations(this.pdfPage, this.viewport);
     div.setAttribute('data-loaded', true);
   };
 
+  this.beforePrint = function pageViewBeforePrint() {
+    var pdfPage = this.pdfPage;
+    var viewport = pdfPage.getViewport(1);
+
+    var canvas = this.canvas = document.createElement('canvas');
+    canvas.width = viewport.width;
+    canvas.height = viewport.height;
+    canvas.style.width = viewport.width + 'pt';
+    canvas.style.height = viewport.height + 'pt';
+
+    var printContainer = document.getElementById('printContainer');
+    printContainer.appendChild(canvas);
+
+    var self = this;
+    canvas.mozPrintCallback = function(obj) {
+      var ctx = obj.context;
+      var renderContext = {
+        canvasContext: ctx,
+        viewport: viewport
+      };
+
+      pdfPage.render(renderContext).then(function() {
+        // Tell the printEngine that rendering this canvas/page has finished.
+        obj.done();
+        self.pdfPage.destroy();
+      }, function(error) {
+        console.error(error);
+        // Tell the printEngine that rendering this canvas/page has failed.
+        // This will make the print proces stop.
+        if ('abort' in object)
+          obj.abort();
+        else
+          obj.done();
+        self.pdfPage.destroy();
+      });
+    };
+  };
+
   this.updateStats = function pageViewUpdateStats() {
     if (PDFJS.pdfBug && Stats.enabled) {
       var stats = this.stats;
       Stats.add(this.id, stats);
     }
   };
 };
 
@@ -1229,24 +1452,25 @@ var ThumbnailView = function thumbnailVi
   var pageRatio = pageWidth / pageHeight;
   this.id = id;
 
   var canvasWidth = 98;
   var canvasHeight = canvasWidth / this.width * this.height;
   var scaleX = this.scaleX = (canvasWidth / pageWidth);
   var scaleY = this.scaleY = (canvasHeight / pageHeight);
 
-  var div = document.createElement('div');
+  var div = this.el = document.createElement('div');
   div.id = 'thumbnailContainer' + id;
   div.className = 'thumbnail';
 
   anchor.appendChild(div);
   container.appendChild(anchor);
 
   this.hasImage = false;
+  this.renderingState = RenderingStates.INITIAL;
 
   function getPageDrawContext() {
     var canvas = document.createElement('canvas');
     canvas.id = 'thumbnail' + id;
     canvas.mozOpaque = true;
 
     canvas.width = canvasWidth;
     canvas.height = canvasHeight;
@@ -1269,42 +1493,60 @@ var ThumbnailView = function thumbnailVi
     return ctx;
   }
 
   this.drawingRequired = function thumbnailViewDrawingRequired() {
     return !this.hasImage;
   };
 
   this.draw = function thumbnailViewDraw(callback) {
+    if (this.renderingState !== RenderingStates.INITIAL)
+      error('Must be in new state before drawing');
+
+    this.renderingState = RenderingStates.RUNNING;
     if (this.hasImage) {
       callback();
       return;
     }
 
+    var self = this;
     var ctx = getPageDrawContext();
     var drawViewport = pdfPage.getViewport(scaleX);
     var renderContext = {
       canvasContext: ctx,
-      viewport: drawViewport
+      viewport: drawViewport,
+      continueCallback: function(cont) {
+        if (PDFView.highestPriorityPage !== 'thumbnail' + self.id) {
+          self.renderingState = RenderingStates.PAUSED;
+          self.resume = function() {
+            self.renderingState = RenderingStates.RUNNING;
+            cont();
+          };
+          return;
+        }
+        cont();
+      }
     };
     pdfPage.render(renderContext).then(
       function pdfPageRenderCallback() {
+        self.renderingState = RenderingStates.FINISHED;
         callback();
       },
       function pdfPageRenderError(error) {
+        self.renderingState = RenderingStates.FINISHED;
         callback();
       }
     );
     this.hasImage = true;
   };
 
   this.setImage = function thumbnailViewSetImage(img) {
     if (this.hasImage || !img)
       return;
-
+    this.renderingState = RenderingStates.FINISHED;
     var ctx = getPageDrawContext();
     ctx.drawImage(img, 0, 0, img.width, img.height,
                   0, 0, ctx.canvas.width, ctx.canvas.height);
 
     this.hasImage = true;
   };
 };
 
@@ -1515,106 +1757,70 @@ window.addEventListener('load', function
       locale = hashParams['locale'];
     mozL10n.language.code = locale;
   }
 
   if ('disableTextLayer' in hashParams)
     PDFJS.disableTextLayer = (hashParams['disableTextLayer'] === 'true');
 
   if ('pdfBug' in hashParams &&
-      (!PDFJS.isFirefoxExtension || FirefoxCom.request('pdfBugEnabled'))) {
+      (!PDFJS.isFirefoxExtension || FirefoxCom.requestSync('pdfBugEnabled'))) {
     PDFJS.pdfBug = true;
     var pdfBug = hashParams['pdfBug'];
     var enabled = pdfBug.split(',');
     PDFBug.enable(enabled);
     PDFBug.init();
   }
 
   if (!PDFJS.isFirefoxExtension ||
-    (PDFJS.isFirefoxExtension && FirefoxCom.request('searchEnabled'))) {
+    (PDFJS.isFirefoxExtension && FirefoxCom.requestSync('searchEnabled'))) {
     document.querySelector('#viewSearch').classList.remove('hidden');
   }
 
+  if (!PDFView.supportsPrinting) {
+    document.getElementById('print').classList.add('hidden');
+  }
+
   // Listen for warnings to trigger the fallback UI.  Errors should be caught
   // and call PDFView.error() so we don't need to listen for those.
   PDFJS.LogManager.addLogger({
     warn: function() {
       PDFView.fallback();
     }
   });
 
-  var thumbsView = document.getElementById('thumbnailView');
-  thumbsView.addEventListener('scroll', updateThumbViewArea, true);
-
   var mainContainer = document.getElementById('mainContainer');
   var outerContainer = document.getElementById('outerContainer');
   mainContainer.addEventListener('transitionend', function(e) {
     if (e.target == mainContainer) {
       var event = document.createEvent('UIEvents');
       event.initUIEvent('resize', false, false, window, 0);
       window.dispatchEvent(event);
       outerContainer.classList.remove('sidebarMoving');
     }
   }, true);
 
   document.getElementById('sidebarToggle').addEventListener('click',
     function() {
       this.classList.toggle('toggled');
       outerContainer.classList.add('sidebarMoving');
       outerContainer.classList.toggle('sidebarOpen');
-      updateThumbViewArea();
+      PDFView.sidebarOpen = outerContainer.classList.contains('sidebarOpen');
+      PDFView.renderHighestPriority();
     });
 
   PDFView.open(file, 0);
 }, true);
 
-/**
- * Render the next not yet visible page already such that it is
- * hopefully ready once the user scrolls to it.
- */
-function preDraw() {
-  var pages = PDFView.pages;
-  var visible = PDFView.getVisiblePages();
-  var last = visible[visible.length - 1];
-  // PageView.id is the actual page number, which is + 1 compared
-  // to the index in `pages`. That means, pages[last.id] is the next
-  // PageView instance.
-  if (pages[last.id] && pages[last.id].drawingRequired()) {
-    renderingQueue.enqueueDraw(pages[last.id]);
-    return;
-  }
-  // If there is nothing to draw on the next page, maybe the user
-  // is scrolling up, so, let's try to render the next page *before*
-  // the first visible page
-  if (pages[visible[0].id - 2]) {
-    renderingQueue.enqueueDraw(pages[visible[0].id - 2]);
-  }
-}
-
 function updateViewarea() {
   if (!PDFView.initialized)
     return;
   var visiblePages = PDFView.getVisiblePages();
-  var pageToDraw;
-  for (var i = 0; i < visiblePages.length; i++) {
-    var page = visiblePages[i];
-    var pageObj = PDFView.pages[page.id - 1];
 
-    pageToDraw |= pageObj.drawingRequired();
-    renderingQueue.enqueueDraw(pageObj);
-  }
-
-  if (!visiblePages.length)
-    return;
-
-  // If there is no need to draw a page that is currenlty visible, preDraw the
-  // next page the user might scroll to.
-  if (!pageToDraw) {
-    preDraw();
-  }
+  PDFView.renderHighestPriority();
 
   updateViewarea.inProgress = true; // used in "set page"
   var currentId = PDFView.page;
   var firstPage = visiblePages[0];
   PDFView.page = firstPage.id;
   updateViewarea.inProgress = false;
 
   var currentScale = PDFView.currentScale;
@@ -1635,39 +1841,16 @@ function updateViewarea() {
   store.set('page', pageNumber);
   store.set('zoom', normalizedScaleValue);
   store.set('scrollLeft', Math.round(topLeft[0]));
   store.set('scrollTop', Math.round(topLeft[1]));
   var href = PDFView.getAnchorUrl(pdfOpenParams);
   document.getElementById('viewBookmark').href = href;
 }
 
-window.addEventListener('scroll', function webViewerScroll(evt) {
-  updateViewarea();
-}, true);
-
-var thumbnailTimer;
-
-function updateThumbViewArea() {
-  // Only render thumbs after pausing scrolling for this amount of time
-  // (makes UI more responsive)
-  var delay = 50; // in ms
-
-  if (thumbnailTimer)
-    clearTimeout(thumbnailTimer);
-
-  thumbnailTimer = setTimeout(function() {
-    var visibleThumbs = PDFView.getVisibleThumbs();
-    for (var i = 0; i < visibleThumbs.length; i++) {
-      var thumb = visibleThumbs[i];
-      renderingQueue.enqueueDraw(PDFView.thumbnails[thumb.id - 1]);
-    }
-  }, delay);
-}
-
 window.addEventListener('resize', function webViewerResize(evt) {
   if (PDFView.initialized &&
       (document.getElementById('pageWidthOption').selected ||
       document.getElementById('pageFitOption').selected ||
       document.getElementById('pageAutoOption').selected))
       PDFView.parseScale(document.getElementById('scaleSelect').value);
   updateViewarea();
 });
@@ -1766,16 +1949,28 @@ window.addEventListener('pagechange', fu
         thumbnail.scrollIntoView();
     }
 
   }
   document.getElementById('previous').disabled = (page <= 1);
   document.getElementById('next').disabled = (page >= PDFView.pages.length);
 }, true);
 
+// Firefox specific event, so that we can prevent browser from zooming
+window.addEventListener('DOMMouseScroll', function(evt) {
+  if (evt.ctrlKey) {
+    evt.preventDefault();
+
+    var ticks = evt.detail;
+    var direction = (ticks > 0) ? 'zoomOut' : 'zoomIn';
+    for (var i = 0, length = Math.abs(ticks); i < length; i++)
+      PDFView[direction]();
+  }
+}, false);
+
 window.addEventListener('keydown', function keydown(evt) {
   var handled = false;
   var cmd = (evt.ctrlKey ? 1 : 0) |
             (evt.altKey ? 2 : 0) |
             (evt.shiftKey ? 4 : 0) |
             (evt.metaKey ? 8 : 0);
 
   // First, handle the key bindings that are independent whether an input
@@ -1833,8 +2028,16 @@ window.addEventListener('keydown', funct
         break;
     }
   }
 
   if (handled) {
     evt.preventDefault();
   }
 });
+
+window.addEventListener('beforeprint', function beforePrint(evt) {
+  PDFView.beforePrint();
+});
+
+window.addEventListener('afterprint', function afterPrint(evt) {
+  PDFView.afterPrint();
+});
deleted file mode 100644
--- a/browser/extensions/pdfjs/install.rdf.in
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0"?>
-
-#filter substitution
-
-<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
-
-  <Description about="urn:mozilla:install-manifest">
-    <em:id>uriloader@pdf.js</em:id>
-    <!-- PDFJS_LOCALIZED_METADATA -->
-    <em:name>PDF Viewer</em:name>
-    <em:version>0.3.266</em:version>
-    <em:targetApplication>
-      <Description>
-       <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
-       <em:minVersion>@FIREFOX_VERSION@</em:minVersion>
-       <em:maxVersion>@FIREFOX_VERSION@</em:maxVersion>
-     </Description>
-    </em:targetApplication>
-    <em:strictCompatibility>true</em:strictCompatibility>
-    <em:bootstrap>true</em:bootstrap>
-    <em:creator>Mozilla</em:creator>
-    <em:description>Uses HTML5 to display PDF files directly in Firefox.</em:description>
-    <em:homepageURL>https://support.mozilla.org/kb/Opening%20PDF%20files%20within%20Firefox</em:homepageURL>
-    <em:type>2</em:type>
-  </Description>
-</RDF>
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -110,16 +110,17 @@ These should match what Safari and other
 
 <!ENTITY closeWindow.label "Close Window">
 <!ENTITY closeWindow.accesskey "d">
 
 <!ENTITY bookmarksMenu.label "Bookmarks">
 <!ENTITY bookmarksMenu.accesskey "B">
 <!ENTITY bookmarkThisPageCmd.label "Bookmark This Page">
 <!ENTITY bookmarkThisPageCmd.commandkey "d">
+<!ENTITY sharePageCmd.commandkey "l">
 <!ENTITY subscribeToPageMenupopup.label "Subscribe to This Page">
 <!ENTITY subscribeToPageMenuitem.label "Subscribe to This Page…">
 <!ENTITY addCurPagesCmd.label "Bookmark All Tabs…">
 <!ENTITY showAllBookmarks2.label "Show All Bookmarks">
 <!ENTITY unsortedBookmarksCmd.label "Unsorted Bookmarks">
 <!ENTITY bookmarksToolbarChevron.tooltip "Show more bookmarks">
 
 <!ENTITY backCmd.label                "Back">
@@ -646,8 +647,13 @@ just addresses the organization to follo
 <!-- LOCALIZATION NOTE (markupButton.arialabel): The markup button is the button
 located in front of the breadcrumbs display in the inspector toolbar. The button
 doesn't display any label, but exposes a label to screen-readers with "aria-label".
 -->
 <!ENTITY markupButton.arialabel          "Markup">
 <!-- LOCALIZATION NOTE (markupButton.accesskey): The key bound to the Markup panel's
 toolbar button -->
 <!ENTITY markupButton.accesskey          "M">
+
+<!ENTITY social.sharePopup.undo.label     "Unshare">
+<!ENTITY social.sharePopup.undo.accesskey "U">
+<!ENTITY social.sharePopup.ok.label       "OK">
+<!ENTITY social.sharePopup.ok.accesskey   "O">
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -352,18 +352,23 @@ telemetryYesButtonAccessKey = Y
 telemetryNoButtonLabel = No
 telemetryNoButtonAccessKey = N
 
 # Webapps notification popup
 webapps.install = Install
 webapps.install.accesskey = I
 #LOCALIZATION NOTE (webapps.requestInstall) %1$S is the web app name, %2$S is the site from which the web app is installed
 webapps.requestInstall = Do you want to install "%1$S" from this site (%2$S)?
+webapps.install.success = Application Installed
 
 # Telemetry opt-out prompt for Aurora and Nightly
 # LOCALIZATION NOTE (telemetryOptOutPrompt): %1$S and %3$S will be replaced by
 # brandFullName, and %2$S by the value of the toolkit.telemetry.server_owner preference.
 telemetryOptOutPrompt = %1$S sends information about performance, hardware, usage and customizations back to %2$S to help improve %3$S.
 
 # LOCALIZATION NOTE (fullscreen.entered): displayed when we enter HTML5 fullscreen mode, %S is the domain name of the focused website (e.g. mozilla.com).
 fullscreen.entered=%S is now fullscreen.
 # LOCALIZATION NOTE (fullscreen.rememberDecision): displayed when we enter HTML5 fullscreen mode, %S is the domain name of the focused website (e.g. mozilla.com).
 fullscreen.rememberDecision=Remember decision for %S
+
+social.shareButton.tooltip=Share this
+social.shareButton.sharedtooltip=You shared this
+social.pageShared.label=Page shared
--- a/browser/locales/en-US/pdfviewer/chrome.properties
+++ b/browser/locales/en-US/pdfviewer/chrome.properties
@@ -1,3 +1,4 @@
 # Chrome notification bar messages and buttons
 unsupported_feature=This PDF document might not be displayed correctly.
 open_with_different_viewer=Open With Different Viewer
+open_with_different_viewer.accessKey=o
--- a/browser/locales/en-US/pdfviewer/viewer.properties
+++ b/browser/locales/en-US/pdfviewer/viewer.properties
@@ -73,19 +73,19 @@ rendering_error=An error occurred while 
 
 # Predefined zoom values
 page_scale_width=Page Width
 page_scale_fit=Page Fit
 page_scale_auto=Automatic Zoom
 page_scale_actual=Actual Size
 
 # Loading indicator messages
-# LOCALIZATION NOTE (error_line): "{{[percent}}" will be replaced with a percentage
-loading=Loading… {{percent}}%
 loading_error_indicator=Error
 loading_error=An error occurred while loading the PDF.
 
 # LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
-# "{{[type}}" will be replaced with an annotation type from a list defined in
+# "{{type}}" will be replaced with an annotation type from a list defined in
 # the PDF spec (32000-1:2008 Table 169 – Annotation types).
 # Some common types are e.g.: "Check", "Text", "Comment", "Note"
 text_annotation_type=[{{type}} Annotation]
 request_password=PDF is protected by a password:
+
+printing_not_supported=Warning: Printing is not fully supported by this browser.
--- a/browser/modules/Makefile.in
+++ b/browser/modules/Makefile.in
@@ -14,16 +14,17 @@ include $(topsrcdir)/config/config.mk
 TEST_DIRS += test
 
 EXTRA_JS_MODULES = \
 	openLocationLastURL.jsm \
 	NetworkPrioritizer.jsm \
 	NewTabUtils.jsm \
 	offlineAppCache.jsm \
 	TelemetryTimestamps.jsm \
+	Social.jsm \
 	webappsUI.jsm \
 	$(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows) 
 EXTRA_JS_MODULES += \
 	WindowsPreviewPerTab.jsm \
 	WindowsJumpLists.jsm \
 	$(NULL)
new file mode 100644
--- /dev/null
+++ b/browser/modules/Social.jsm
@@ -0,0 +1,86 @@
+/* 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";
+
+let EXPORTED_SYMBOLS = ["Social"];
+
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "SocialService",
+  "resource://gre/modules/SocialService.jsm");
+
+let Social = {
+  provider: null,
+  init: function Social_init(callback) {
+    if (this.provider) {
+      schedule(callback);
+      return;
+    }
+
+    // Eventually this might want to retrieve a specific provider, but for now
+    // just use the first available.
+    SocialService.getProviderList(function (providers) {
+      if (providers.length)
+        this.provider = providers[0];
+      callback();
+      Services.obs.notifyObservers(null, "test-social-ui-ready", "");
+    }.bind(this));
+  },
+
+  get enabled() {
+    return SocialService.enabled;
+  },
+
+  sendWorkerMessage: function Social_sendWorkerMessage(message) {
+    // Responses aren't handled yet because there is no actions to perform
+    // based on the response from the provider at this point.
+    if (this.provider && this.provider.port)
+      this.provider.port.postMessage(message);
+  },
+
+  // Sharing functionality
+  _getShareablePageUrl: function Social_getShareablePageUrl(aURI) {
+    let uri = aURI.clone();
+    try {
+      // Setting userPass on about:config throws.
+      uri.userPass = "";
+    } catch (e) {}
+    return uri.spec;
+  },
+
+  isPageShared: function Social_isPageShared(aURI) {
+    let url = this._getShareablePageUrl(aURI);
+    return this._sharedUrls.hasOwnProperty(url);
+  },
+
+  sharePage: function Social_sharePage(aURI) {
+    let url = this._getShareablePageUrl(aURI);
+    this._sharedUrls[url] = true;
+    this.sendWorkerMessage({
+      topic: "social.user-recommend",
+      data: { url: url }
+    });
+  },
+
+  unsharePage: function Social_unsharePage(aURI) {
+    let url = this._getShareablePageUrl(aURI);
+    delete this._sharedUrls[url];
+    this.sendWorkerMessage({
+      topic: "social.user-unrecommend",
+      data: { url: url }
+    });
+  },
+
+  _sharedUrls: {}
+};
+
+function schedule(callback) {
+  Services.tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL);
+}
--- a/browser/modules/webappsUI.jsm
+++ b/browser/modules/webappsUI.jsm
@@ -112,16 +112,17 @@ let webappsUI = {
         let app = WebappsInstaller.install(aData);
         if (app) {
           let localDir = null;
           if (app.appcacheDefined && app.appProfile) {
             localDir = app.appProfile.localDir;
           }
 
           DOMApplicationRegistry.confirmInstall(aData, false, localDir);
+          installationSuccessNotification(app, aWindow);
         } else {
           DOMApplicationRegistry.denyInstall(aData);
         }
       }
     };
 
     let requestingURI = aWindow.makeURI(aData.from);
     let manifest = new DOMApplicationManifest(aData.app.manifest, aData.app.origin);
@@ -136,8 +137,26 @@ let webappsUI = {
     let message = bundle.getFormattedString("webapps.requestInstall",
                                             [manifest.name, host], 2);
 
     aWindow.PopupNotifications.show(aBrowser, "webapps-install", message,
                                     "webapps-notification-icon", mainAction);
 
   }
 }
+
+function installationSuccessNotification(app, aWindow) {
+  let bundle = aWindow.gNavigatorBundle;
+
+  if (("@mozilla.org/alerts-service;1" in Cc)) {
+    let notifier;
+    try {
+      notifier = Cc["@mozilla.org/alerts-service;1"].
+                 getService(Ci.nsIAlertsService);
+
+      notifier.showAlertNotification(app.iconURI.spec,
+                                    bundle.getString("webapps.install.success"),
+                                    app.appNameAsFilename,
+                                    false, null, null);
+
+    } catch (ex) {}
+  }
+}
index bb9cdf30a0ce9f4598513ca47ea93c54eeb5f52d..433c25e1a39d85ef3c4545b7e0f6dd0c6baab724
GIT binary patch
literal 236
zc$@+302BX-P)<h;3K|Lk000e1NJLTq000mG000UI1^@s6y}sU@00029Nkl<ZC{vw~
zy$ZrG6h=EZ2)?jm27epH$=4BG9r_L;R*J=%8c47q*L=Z%f=$H>r$ag4p)?_)1h-uA
z(VS13SvsZ|aNuI&w|Fqddg)^NP)bqP!GVhny#@O2rGX%&jDmxU&DVesB1&hVs;*I5
z1McS-Yb}-KB?=t49|6w!AOwoy93=#>@d5WaLkDelo0F7x%JbviacHBiZ{Eemu||N5
mX*^o%p9ns-2xPC?KV(lIVEPvZT@;D{0000<MNUMnLSTaKI$&D>
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -1285,26 +1285,27 @@ toolbar[iconsize="small"] #feed-button {
 .ac-result-type-tag,
 .autocomplete-treebody::-moz-tree-image(tag, treecolAutoCompleteImage) {
   list-style-image: url("chrome://browser/skin/places/tag.png");
   width: 16px;
   height: 16px;
 }
 
 .ac-comment {
-  font-size: 1.15em;
+  font-size: 1.05em;
 }
 
 .ac-extra > .ac-comment {
   font-size: inherit;
 }
 
 .ac-url-text,
 .ac-action-text {
   color: -moz-nativehyperlinktext;
+  font-size: 0.9em;
 }
 
 richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
   list-style-image: url("chrome://browser/skin/actionicon-tab.png");
   padding: 0 3px;
 }
 
 .autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
@@ -1360,16 +1361,30 @@ richlistitem[type~="action"][actiontype=
   list-style-image: url("moz-icon://stock/gtk-stop?size=menu");
 }
 
 /* Popup blocker button */
 #page-report-button {
   list-style-image: url("chrome://browser/skin/Info.png");
 }
 
+/* social recommending panel */
+
+#share-button {
+  list-style-image: url(chrome://browser/skin/share-button.png);
+}
+
+#share-button:not([shared]):not([disabled]):hover {
+  list-style-image: url(chrome://browser/skin/share-button-active.png);
+}
+
+#share-button[shared] {
+  list-style-image: url(chrome://browser/skin/share-button-shared.png);
+}
+
 /* Star button */
 #star-button {
   padding: 1px;
   list-style-image: url("chrome://browser/skin/places/starPage.png");
 }
 
 #star-button[starred="true"] {
   list-style-image: url("chrome://browser/skin/places/pageStarred.png");
--- a/browser/themes/gnomestripe/jar.mn
+++ b/browser/themes/gnomestripe/jar.mn
@@ -34,16 +34,19 @@ browser.jar:
   skin/classic/browser/pageInfo.png
   skin/classic/browser/page-livemarks.png
   skin/classic/browser/Privacy-16.png
   skin/classic/browser/Privacy-48.png
   skin/classic/browser/searchbar.css                  (searchbar.css)
   skin/classic/browser/Secure.png
   skin/classic/browser/Security-broken.png
   skin/classic/browser/setDesktopBackground.css
+  skin/classic/browser/share-button.png
+  skin/classic/browser/share-button-active.png
+  skin/classic/browser/share-button-shared.png
   skin/classic/browser/Toolbar.png
   skin/classic/browser/Toolbar-small.png
   skin/classic/browser/urlbar-arrow.png
   skin/classic/browser/downloads/buttons.png          (downloads/buttons.png)
   skin/classic/browser/downloads/download-glow.png    (downloads/download-glow.png)
   skin/classic/browser/downloads/download-notification.png (downloads/download-notification.png)
   skin/classic/browser/downloads/downloads.css        (downloads/downloads.css)
   skin/classic/browser/feeds/feedIcon.png             (feeds/feedIcon.png)
new file mode 100644
index 0000000000000000000000000000000000000000..a87501e89b3112b507b9385d43d021e7700fb150
GIT binary patch
literal 1249
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!W+OlMT!a6wD0u42@09
z&CPWbj0_A7^bL&k4UKdS&8>`$tPBhkpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$
zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nB5I->~zqG_w
zNeSkK+yc0<dBxCR0tT3VMPh-zp`L+0l0si!{7Q3k;i`*Ef>P7)t1b?yEJ)Q4N-fSW
zElLJPT$(aSbAgp}QEFmIeo;t%ehw@Y12XbU@{2R_3lyA#O%;3-lQZ)`e6V_7Un|eN
z;*!L?<Wx@=TP2`~US?*Bm9e3@o2iqFsjIP*rJ<p#fs>hqvxOOuWd@Wma&d#{b;(aI
z%}vcKf$2>_=rzNs7nBqrx>JiX%TiO^it=+6z+Se>#O)Si+-`yBO~LIJ6P$YWfsWBf
zi)fe-F!g|#@MH_*z!QFI9x$~R0h9HY+tH~E42+?kE{-7;w~~JR|8LK{G9vZAx|zZ}
z&Lm^Q2^=BcYbPcD`2OEOV0q&Yoh2DzH$NZb^jPa4rhJR_l=c0o|Nj5Z7Z<qCl9Z;9
zrf`bY>vr5{hLx@kG8{*iH~df*;6C`|qtt>OKbKlfxW#cq;TNBPKEtET6IlgP3pV_l
zDL)~K>xhE*9=1moD-wAscqhbvo+0UB%2a3?^1@o+H$$POK=&h4hq9y0iWwTaom&4f
z6|xANW-R0|n|_FQLS)f(36HhST5XM93U+))%nK?-a~i%hMF%=)33uo-eB@hkc0tP~
z&JN2)3+|5Mh8t{m8QcPjT-bw(*Eb(}XmDkNa=`S)m}1_J=ma)f?`tVXW=&`is&C{}
z<?di^1iJk*^G6c}F{V>DnKIcG?3ymK8Yme44bq>)y=~u#E1w<1o6R+ub62t_l`7P+
tA9;C0RPe;EMZ)J-F&B#HRW>j%Gt6|q@oRF+pXs1N$J5o%Wt~$(697@%rp*8V
new file mode 100644
index 0000000000000000000000000000000000000000..cb8a11e81d899117cc02c924525c99182b7b8166
GIT binary patch
literal 1460
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!W+OlMT!a6wD0u42@09
z&CPWbj0_A7^bL&k4UKdS&8>`$tPBhkpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$
zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nB5I->~zqG_w
zNeSkK+yc0<dBxCR0tT3VMPh-zp`L+0l0si!{7Q3k;i`*Ef>P7)t1b?yEJ)Q4N-fSW
zElLJPT$(aSbAgp}QEFmIeo;t%ehw@Y12XbU@{2R_3lyA#O%;3-lQZ)`e6V_7Un|eN
z;*!L?<Wx@=TP2`~US?*Bm8pr7p`o#xv#YU_rJ<p#fs>hqvxOOuWoBsZX5``q)9aF-
zT$-DjR|3<Ug3#-NQ!gkfKy;@TWtOF;xE1B+DuBIgm5JLej=0?d(VK$XElxP~>H{64
zj~3A|Az<nOG2zJ;$bl#P)I4BnF9Ig(_8`;E3=B*fo-U3d6}P5LKA3&QLF8Dv+Q~Cz
zt9M+mjWAHQ75VtUQ~T)bu8tL=Ap$A=T@?ZRO()6(Uxvl*`N3Zi!gVc7C(gwsWE;Ef
z%d^cIlS|g_b}GM^GdX9{N8cMci*>fK$xWVFx!?SLP36JXrA)UDH1Br2a^u&fl(p;E
zR@eOh*8RjjG56=+PaVO<ahYvperqT49x&ussK0kB|00Jl<Jrd5C9(bAPg*7LZ;R_%
z&1NcgL*caWfkg^k!e2{OCO=y~bxyMNcXl&gnd_2En6DRFYeewAJFxG{f7bfy;M<zc
zCft+UAD*+l@%LrenZq?)MM{_WLpHsAeyyb>b!t#@$YF+dhV6`bYY%oZ&Cz>sEj;sa
z>|?fzC$@69ivFM8uOt;4zPzF@+_3*+5z}(pj)%XJZ0|>Yln*$@$5OX^)7ur5-l|dD
zN`7YQKT4RQ{9RAl96a60lw!ZRy!ni~iMOxm^iAbmECpI`Cs!zWNjwzV<A0p%$Q%o8
z=SoK5Ka48-4@j{Udjy{0KI#AIcKw0kMKdJNOgW^`^L$mqljT30CDMh2_sY+^SaJ7;
zE3cKN9QP6b<E~3)h`PRL{A@JA!}S*POe42VHj^WchbJsOB{6%;^W3WzLLqXedY_h=
z*qeQCi>nAW-0|D^Vcpy8vk~Qv@1FkP-m>@oEwSADA0{SRTY9j1YI?K>38%VmO5OkV
zI+OW_g$vJ@Jk*f=8x>i0JR_rKg{ob*cfyUZxCh<!v8Lz#>K<TVTJfhVjODO5s2ufl
L^>bP0l+XkK)?pmz
new file mode 100644
index 0000000000000000000000000000000000000000..86bd5ec70add448cfa5647e9448d9bb2ea5349a9
GIT binary patch
literal 1245
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!W+OlMT!a6wD0u42@09
z&CPWbj0_A7^bL&k4UKdS&8>`$tPBhkpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$
zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nB5I->~zqG_w
zNeSkK+yc0<dBxCR0tT3VMPh-zp`L+0l0si!{7Q3k;i`*Ef>P7)t1b?yEJ)Q4N-fSW
zElLJPT$(aSbAgp}QEFmIeo;t%ehw@Y12XbU@{2R_3lyA#O%;3-lQZ)`e6V_7Un|eN
z;*!L?<Wx@=TP2`~US?*Bm9e3@o2iqFp{uczrJ<p#fs>hqvxOOuWd@Wma&d#{b;(aI
z%}vcKf$2>_=rzKr7nBqrx>JiX%TiO^it=+6z+Se>#OW4iH{5Q4=uN@x76Y7m^?{Dj
zM~i5f5HR(CnDAr^<iHbtY927P7Xg#C@buT085kG?JzX3_DsD}=Z0~(IK&1WQl`aJi
zr-NIw?HX1$apbvbSa`6rvbS>Oxn6N}5p>c08ZX>D<(gE;ktFS=9cBs^mYq%a9R#c_
zRX^^X<k5ELf=q?Q+r8%P@sq*|W5YYW&7*5AMCVsenXz>C_sn(K$#FIBdy6-gU6ffK
z%X)p6U%<Niq8)!)_*Gp0tP_&CF2%g1IOSs#U(mn0Ck=~Vt@X-w`r;qrI^%)l%ZBDt
zXI0L&czkG;%%34-xuB$M?vmVuv(djC*;sj8`81@aYrfa?ukbcoHt|?U#HIg?)w?Wx
zvMbvEMjbT1m%9Decd7ENRp(0Q3dJQlH1~@An%K^&>Jf6Ne*VE*mMc4-UpS_$qd(K*
zbDM5YNAc<I&7BwIg`~GVwx~?Gcu?V#$3}B6`DRt$2iLzPrrJ+<kXV|jC;W>i<!J3X
r=cDFgD(#E@@0#uE?CQ7ezxDwJ`%cC;j^?6EKn0GctDnm{r-UW|0obvI
index ae2c789cbd2ecbc57ff8dbb40940a04f5f3d50d8..ab78613132887820625051be89da9a706e4b0cfe
GIT binary patch
literal 645
zc$@)+0($+4P)<h;3K|Lk000e1NJLTq001BW000&U1^@s6p;?|p0006^Nkl<ZNQuRi
z&5Ke|7{+f+?u1q?%6<EiOp#_G`L(`&3}(6za-j<sB8r<RC<rEE{sf~d6f-0<+7QvM
zAf1`Q0%>T5`CwuwsA-(l2-^D$=Ufie*twlWi=TSWeSWWx_nxaZ8jUpI_xsO;!{NJ$
zM52{SrCRB9x+#J+oI?g#?m3;#X`j!x7zhNKR)7On<AXw>(EVI4H&>}t>eXu1_!Bsn
z&*$f;#0>Y`Zuf&oBr;0{4Js-HvT)#<1>*7eLa9`$m&;{i9LP|%$vv0L<qigewPZ5+
zIFrd3G9U{Fu2`T|EEWwJkmVlmcsv(kvDnjWHfzX$EIF6pnnR+|XtPi#7&0I$7Vvt#
zCv{z4pxa}}fGjySvw+F~)gPdI2~}^Q@+MN<#LAD6>SL_@N22;iriu6Qf1ugy=Z>I*
zv&17}m-uoFyDWn&_Zr04G0t(oX_y6u!{IC~d?vR4!VYEUd4c}H0SfF$c)!hoD;C(I
z#SKZe*(IFlEWN#UcsS_N=S>U#CLFlpEkJ=!l5FuSK-e4e&vZ6e*56os{&EVgSYVy#
zNwO{!(5{AcI~}iC@YklU-#87IfB6LQk?2Z-tc@37GgdA5tK^&z3tT2X5G#_r9}EUp
zeksti;P<!(agsLR3wrMmZzSn3XHwY2@94NK;Ud#D3(#(?vBg&wX~X4%_I~Ww*__v7
z9Gq+K_xn%G0(4Mgmu1N!D{%RsTX&`}e*3=nkk*&SILpY~ynWAU7N8dgasD512>ala
f<SYlv9(g|jcN*i;D;K{P00000NkvXXu0mjf3lB0;
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -1109,17 +1109,17 @@ toolbar[mode="icons"] #zoom-in-button {
 .ac-result-type-keyword,
 .autocomplete-treebody::-moz-tree-image(keyword, treecolAutoCompleteImage) {
   list-style-image: url(chrome://global/skin/icons/search-textbox.png);
   margin: 2px;
   width: 12px;
   height: 12px;
 }
 
-richlistitem[selected="true"][current="true"] > hbox > .ac-result-type-bookmark,
+richlistitem[selected="true"][current="true"] > .ac-title-box > .ac-result-type-bookmark,
 .autocomplete-treebody::-moz-tree-image(selected, current, bookmark, treecolAutoCompleteImage) {
   list-style-image: url("chrome://browser/skin/places/star-icons.png");
   -moz-image-region: rect(0, 64px, 16px, 48px);
 }
 
 .ac-result-type-tag,
 .autocomplete-treebody::-moz-tree-image(tag, treecolAutoCompleteImage) {
   list-style-image: url("chrome://browser/skin/places/tag.png");
@@ -1134,30 +1134,30 @@ richlistitem[selected="true"][current="t
 .ac-url-text,
 .ac-action-text {
   color: -moz-nativehyperlinktext;
   font: message-box;
 }
 
 richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
   list-style-image: url("chrome://browser/skin/actionicon-tab.png");
-  -moz-image-region: rect(0, 16px, 16px, 0);
+  -moz-image-region: rect(0, 16px, 11px, 0);
   padding: 0 3px;
 }
 
 richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
-  -moz-image-region: rect(16px, 16px, 32px, 0);
+  -moz-image-region: rect(11px, 16px, 22px, 0);
 }
 
 window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
+  -moz-image-region: rect(0, 32px, 11px, 16px);
 }
 
 window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
-  -moz-image-region: rect(16px, 32px, 32px, 16px);
+  -moz-image-region: rect(11px, 32px, 22px, 16px);
 }
 
 .autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
   color: GrayText;
 }
 
 .ac-comment[selected="true"],
 .ac-url-text[selected="true"],
@@ -1237,16 +1237,30 @@ window[tabsontop="false"] richlistitem[t
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
 #page-report-button:hover:active,
 #page-report-button[open="true"] {
   -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
+/* social recommending panel */
+
+#share-button {
+  list-style-image: url(chrome://browser/skin/share-button.png);
+}
+
+#share-button:not([shared]):not([disabled]):hover {
+  list-style-image: url(chrome://browser/skin/share-button-active.png);
+}
+
+#share-button[shared] {
+  list-style-image: url(chrome://browser/skin/share-button-shared.png);
+}
+
 /* STAR BUTTON */
 #star-button {
   list-style-image: url("chrome://browser/skin/places/star-icons.png");
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
 #star-button:hover:active,
 #star-button[starred="true"] {
--- a/browser/themes/pinstripe/jar.mn
+++ b/browser/themes/pinstripe/jar.mn
@@ -63,16 +63,19 @@ browser.jar:
   skin/classic/browser/feeds/videoFeedIcon.png              (feeds/feedIcon.png)
   skin/classic/browser/feeds/videoFeedIcon16.png            (feeds/feedIcon16.png)
   skin/classic/browser/feeds/audioFeedIcon.png              (feeds/feedIcon.png)
   skin/classic/browser/feeds/audioFeedIcon16.png            (feeds/feedIcon16.png)
   skin/classic/browser/newtab/newTab.css                    (newtab/newTab.css)
   skin/classic/browser/newtab/controls.png                  (newtab/controls.png)
   skin/classic/browser/newtab/noise.png                     (newtab/noise.png)
   skin/classic/browser/setDesktopBackground.css
+  skin/classic/browser/share-button.png
+  skin/classic/browser/share-button-active.png
+  skin/classic/browser/share-button-shared.png
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
   skin/classic/browser/places/allBookmarks.png              (places/allBookmarks.png)
 * skin/classic/browser/places/places.css                    (places/places.css)
 * skin/classic/browser/places/organizer.css                 (places/organizer.css)
   skin/classic/browser/places/query.png                     (places/query.png)
   skin/classic/browser/places/bookmarksMenu.png             (places/bookmarksMenu.png)
   skin/classic/browser/places/bookmarksToolbar.png          (places/bookmarksToolbar.png)
new file mode 100644
index 0000000000000000000000000000000000000000..a87501e89b3112b507b9385d43d021e7700fb150
GIT binary patch
literal 1249
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!W+OlMT!a6wD0u42@09
z&CPWbj0_A7^bL&k4UKdS&8>`$tPBhkpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$
zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nB5I->~zqG_w
zNeSkK+yc0<dBxCR0tT3VMPh-zp`L+0l0si!{7Q3k;i`*Ef>P7)t1b?yEJ)Q4N-fSW
zElLJPT$(aSbAgp}QEFmIeo;t%ehw@Y12XbU@{2R_3lyA#O%;3-lQZ)`e6V_7Un|eN
z;*!L?<Wx@=TP2`~US?*Bm9e3@o2iqFsjIP*rJ<p#fs>hqvxOOuWd@Wma&d#{b;(aI
z%}vcKf$2>_=rzNs7nBqrx>JiX%TiO^it=+6z+Se>#O)Si+-`yBO~LIJ6P$YWfsWBf
zi)fe-F!g|#@MH_*z!QFI9x$~R0h9HY+tH~E42+?kE{-7;w~~JR|8LK{G9vZAx|zZ}
z&Lm^Q2^=BcYbPcD`2OEOV0q&Yoh2DzH$NZb^jPa4rhJR_l=c0o|Nj5Z7Z<qCl9Z;9
zrf`bY>vr5{hLx@kG8{*iH~df*;6C`|qtt>OKbKlfxW#cq;TNBPKEtET6IlgP3pV_l
zDL)~K>xhE*9=1moD-wAscqhbvo+0UB%2a3?^1@o+H$$POK=&h4hq9y0iWwTaom&4f
z6|xANW-R0|n|_FQLS)f(36HhST5XM93U+))%nK?-a~i%hMF%=)33uo-eB@hkc0tP~
z&JN2)3+|5Mh8t{m8QcPjT-bw(*Eb(}XmDkNa=`S)m}1_J=ma)f?`tVXW=&`is&C{}
z<?di^1iJk*^G6c}F{V>DnKIcG?3ymK8Yme44bq>)y=~u#E1w<1o6R+ub62t_l`7P+
tA9;C0RPe;EMZ)J-F&B#HRW>j%Gt6|q@oRF+pXs1N$J5o%Wt~$(697@%rp*8V
new file mode 100644
index 0000000000000000000000000000000000000000..cb8a11e81d899117cc02c924525c99182b7b8166
GIT binary patch
literal 1460
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!W+OlMT!a6wD0u42@09
z&CPWbj0_A7^bL&k4UKdS&8>`$tPBhkpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$
zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nB5I->~zqG_w
zNeSkK+yc0<dBxCR0tT3VMPh-zp`L+0l0si!{7Q3k;i`*Ef>P7)t1b?yEJ)Q4N-fSW
zElLJPT$(aSbAgp}QEFmIeo;t%ehw@Y12XbU@{2R_3lyA#O%;3-lQZ)`e6V_7Un|eN
z;*!L?<Wx@=TP2`~US?*Bm8pr7p`o#xv#YU_rJ<p#fs>hqvxOOuWoBsZX5``q)9aF-
zT$-DjR|3<Ug3#-NQ!gkfKy;@TWtOF;xE1B+DuBIgm5JLej=0?d(VK$XElxP~>H{64
zj~3A|Az<nOG2zJ;$bl#P)I4BnF9Ig(_8`;E3=B*fo-U3d6}P5LKA3&QLF8Dv+Q~Cz
zt9M+mjWAHQ75VtUQ~T)bu8tL=Ap$A=T@?ZRO()6(Uxvl*`N3Zi!gVc7C(gwsWE;Ef
z%d^cIlS|g_b}GM^GdX9{N8cMci*>fK$xWVFx!?SLP36JXrA)UDH1Br2a^u&fl(p;E
zR@eOh*8RjjG56=+PaVO<ahYvperqT49x&ussK0kB|00Jl<Jrd5C9(bAPg*7LZ;R_%
z&1NcgL*caWfkg^k!e2{OCO=y~bxyMNcXl&gnd_2En6DRFYeewAJFxG{f7bfy;M<zc
zCft+UAD*+l@%LrenZq?)MM{_WLpHsAeyyb>b!t#@$YF+dhV6`bYY%oZ&Cz>sEj;sa
z>|?fzC$@69ivFM8uOt;4zPzF@+_3*+5z}(pj)%XJZ0|>Yln*$@$5OX^)7ur5-l|dD
zN`7YQKT4RQ{9RAl96a60lw!ZRy!ni~iMOxm^iAbmECpI`Cs!zWNjwzV<A0p%$Q%o8
z=SoK5Ka48-4@j{Udjy{0KI#AIcKw0kMKdJNOgW^`^L$mqljT30CDMh2_sY+^SaJ7;
zE3cKN9QP6b<E~3)h`PRL{A@JA!}S*POe42VHj^WchbJsOB{6%;^W3WzLLqXedY_h=
z*qeQCi>nAW-0|D^Vcpy8vk~Qv@1FkP-m>@oEwSADA0{SRTY9j1YI?K>38%VmO5OkV
zI+OW_g$vJ@Jk*f=8x>i0JR_rKg{ob*cfyUZxCh<!v8Lz#>K<TVTJfhVjODO5s2ufl
L^>bP0l+XkK)?pmz
new file mode 100644
index 0000000000000000000000000000000000000000..86bd5ec70add448cfa5647e9448d9bb2ea5349a9
GIT binary patch
literal 1245
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!W+OlMT!a6wD0u42@09
z&CPWbj0_A7^bL&k4UKdS&8>`$tPBhkpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$
zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nB5I->~zqG_w
zNeSkK+yc0<dBxCR0tT3VMPh-zp`L+0l0si!{7Q3k;i`*Ef>P7)t1b?yEJ)Q4N-fSW
zElLJPT$(aSbAgp}QEFmIeo;t%ehw@Y12XbU@{2R_3lyA#O%;3-lQZ)`e6V_7Un|eN
z;*!L?<Wx@=TP2`~US?*Bm9e3@o2iqFp{uczrJ<p#fs>hqvxOOuWd@Wma&d#{b;(aI
z%}vcKf$2>_=rzKr7nBqrx>JiX%TiO^it=+6z+Se>#OW4iH{5Q4=uN@x76Y7m^?{Dj
zM~i5f5HR(CnDAr^<iHbtY927P7Xg#C@buT085kG?JzX3_DsD}=Z0~(IK&1WQl`aJi
zr-NIw?HX1$apbvbSa`6rvbS>Oxn6N}5p>c08ZX>D<(gE;ktFS=9cBs^mYq%a9R#c_
zRX^^X<k5ELf=q?Q+r8%P@sq*|W5YYW&7*5AMCVsenXz>C_sn(K$#FIBdy6-gU6ffK
z%X)p6U%<Niq8)!)_*Gp0tP_&CF2%g1IOSs#U(mn0Ck=~Vt@X-w`r;qrI^%)l%ZBDt
zXI0L&czkG;%%34-xuB$M?vmVuv(djC*;sj8`81@aYrfa?ukbcoHt|?U#HIg?)w?Wx
zvMbvEMjbT1m%9Decd7ENRp(0Q3dJQlH1~@An%K^&>Jf6Ne*VE*mMc4-UpS_$qd(K*
zbDM5YNAc<I&7BwIg`~GVwx~?Gcu?V#$3}B6`DRt$2iLzPrrJ+<kXV|jC;W>i<!J3X
r=cDFgD(#E@@0#uE?CQ7ezxDwJ`%cC;j^?6EKn0GctDnm{r-UW|0obvI
index f60f218e724db02776b92175919cf553ec007191..ced958ebbe39646e15fef004e6c1a5bb3f2f21f5
GIT binary patch
literal 425
zc$@*L0apHrP)<h;3K|Lk000e1NJLTq000mG000&U1^@s6$*LTD0004SNkl<ZIE|gt
zT}#4X7zW@M#E$v{=6QdiqwFZ?w{;RhK_5i1nn_}2t0sPoRf;(0&=f^5ORbO&^C%}i
zJ&&klTlLO^3+KE0zR`&c02nz8WxU51TI4)l?njggM3m|e6`*^Rq3pQF#uq|38;hpu
zpz3Y7&A-^9d(reGU{<vZ1m)sqGTQ`2YyF8b!Dz8>890**5YIeup{!-#^vVGFzRrcR
zQv+Lq;u0@)kklF%QOW~$<|YH1M~M|tG9a9&aPeanJFCNijf2?QULe&BTo>@+l(<lK
zKag%xmj;qTI5#|Wf;!Y?>$^Ad_K6BR{yRsgL*2=*Fe~PsUl_tS9wed;djCadl<`;w
z27^He58hDwAFr5|>;_tR@XV=g_Z4WM&Z%WL&_GpAji~{=aG@G{;6z#X_kkr;Mh2&n
zX`0L9|AG%6U;<xrD9b4~>iAf%X9{?sp|nF9b=gO^D~vvt?vO!UdIny!I3w>D%N<S~
T8or7A00000NkvXXu0mjf^CG#N
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -1484,57 +1484,64 @@ html|*.urlbar-input:-moz-lwtheme:-moz-pl
 .ac-result-type-tag,
 .autocomplete-treebody::-moz-tree-image(tag, treecolAutoCompleteImage) {
   list-style-image: url("chrome://browser/skin/places/tag.png");
   width: 16px;
   height: 16px;
 }
 
 .ac-comment {
-  font-size: 1.15em;
+  font-size: 1.06em;
 }
 
 .ac-extra > .ac-comment {
-  font-size: inherit;
+  font-size: 1em;
 }
 
 .ac-url-text,
 .ac-action-text {
+  font-size: 1em;
   color: -moz-nativehyperlinktext;
 }
 
 %ifndef WINSTRIPE_AERO
 @media (-moz-windows-default-theme) {
-  .ac-url-text,
-  .ac-action-text {
-    color: #006600;
+  .ac-url-text:not([selected="true"]),
+  .ac-action-text:not([selected="true"]) {
+    color: #008800;
   }
 }
 %endif
 
 richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
   list-style-image: url("chrome://browser/skin/actionicon-tab.png");
-  -moz-image-region: rect(0, 16px, 16px, 0);
+  -moz-image-region: rect(0, 16px, 11px, 0);
   padding: 0 3px;
 }
 
-richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
-  -moz-image-region: rect(16px, 16px, 32px, 0);
-}
+%ifdef WINSTRIPE_AERO
+@media not all and (-moz-windows-default-theme) {
+%endif
+  richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
+    -moz-image-region: rect(11px, 16px, 22px, 0);
+  }
+
+  .ac-comment[selected="true"],
+  .ac-url-text[selected="true"],
+  .ac-action-text[selected="true"] {
+    color: inherit !important;
+  }
+%ifdef WINSTRIPE_AERO
+}
+%endif
 
 .autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
   color: GrayText;
 }
 
-.ac-comment[selected="true"],
-.ac-url-text[selected="true"],
-.ac-action-text[selected="true"] {
-  color: inherit !important;
-}
-
 .autocomplete-treebody::-moz-tree-cell-text(suggesthint, treecolAutoCompleteComment),
 .autocomplete-treebody::-moz-tree-cell-text(suggestfirst, treecolAutoCompleteComment)
 {
   color: GrayText;
   font-size: smaller;
 }
 
 .autocomplete-treebody::-moz-tree-cell(suggesthint) {
@@ -1621,16 +1628,30 @@ richlistitem[type~="action"][actiontype=
   -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
 #page-report-button:hover:active,
 #page-report-button[open="true"] {
   -moz-image-region: rect(0, 48px, 16px, 32px);
 }
 
+/* social recommending panel */
+
+#share-button {
+  list-style-image: url(chrome://browser/skin/share-button.png);
+}
+
+#share-button:not([shared]):not([disabled]):hover {
+  list-style-image: url(chrome://browser/skin/share-button-active.png);
+}
+
+#share-button[shared] {
+  list-style-image: url(chrome://browser/skin/share-button-shared.png);
+}
+
 /* star button */
 
 #star-button {
   list-style-image: url("chrome://browser/skin/places/bookmark.png");
   -moz-image-region: rect(0px 16px 16px 0px);
 }
 
 #star-button:hover {
--- a/browser/themes/winstripe/jar.mn
+++ b/browser/themes/winstripe/jar.mn
@@ -45,16 +45,19 @@ browser.jar:
         skin/classic/browser/Secure24.png                            (Secure24.png)
         skin/classic/browser/Toolbar.png                             (Toolbar.png)
         skin/classic/browser/Toolbar-inverted.png
         skin/classic/browser/toolbarbutton-dropdown-arrow.png
         skin/classic/browser/toolbarbutton-dropdown-arrow-inverted.png
 *       skin/classic/browser/searchbar.css                           (searchbar.css)
         skin/classic/browser/searchbar-dropdown-arrow.png
         skin/classic/browser/setDesktopBackground.css
+        skin/classic/browser/share-button.png
+        skin/classic/browser/share-button-active.png
+        skin/classic/browser/share-button-shared.png
         skin/classic/browser/menu-back.png                           (menu-back.png)
         skin/classic/browser/menu-forward.png                        (menu-forward.png)
         skin/classic/browser/monitor.png
         skin/classic/browser/monitor_16-10.png
         skin/classic/browser/urlbar-arrow.png
         skin/classic/browser/urlbar-popup-blocked.png
         skin/classic/browser/urlbar-history-dropmarker.png
         skin/classic/browser/downloads/buttons.png                   (downloads/buttons.png)
@@ -243,16 +246,19 @@ browser.jar:
         skin/classic/aero/browser/Secure24.png                       (Secure24-aero.png)
         skin/classic/aero/browser/Toolbar.png
         skin/classic/aero/browser/Toolbar-inverted.png
         skin/classic/aero/browser/toolbarbutton-dropdown-arrow.png
         skin/classic/aero/browser/toolbarbutton-dropdown-arrow-inverted.png
 *       skin/classic/aero/browser/searchbar.css                      (searchbar.css)
         skin/classic/aero/browser/searchbar-dropdown-arrow.png       (searchbar-dropdown-arrow-aero.png)
         skin/classic/aero/browser/setDesktopBackground.css
+        skin/classic/aero/browser/share-button.png
+        skin/classic/aero/browser/share-button-active.png
+        skin/classic/aero/browser/share-button-shared.png
         skin/classic/aero/browser/menu-back.png                      (menu-back-aero.png)
         skin/classic/aero/browser/menu-forward.png                   (menu-forward-aero.png)
         skin/classic/aero/browser/monitor.png
         skin/classic/aero/browser/monitor_16-10.png
         skin/classic/aero/browser/urlbar-arrow.png
         skin/classic/aero/browser/urlbar-popup-blocked.png
         skin/classic/aero/browser/urlbar-history-dropmarker.png
         skin/classic/aero/browser/downloads/buttons.png              (downloads/buttons-aero.png)
new file mode 100644
index 0000000000000000000000000000000000000000..a87501e89b3112b507b9385d43d021e7700fb150
GIT binary patch
literal 1249
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!W+OlMT!a6wD0u42@09
z&CPWbj0_A7^bL&k4UKdS&8>`$tPBhkpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$
zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nB5I->~zqG_w
zNeSkK+yc0<dBxCR0tT3VMPh-zp`L+0l0si!{7Q3k;i`*Ef>P7)t1b?yEJ)Q4N-fSW
zElLJPT$(aSbAgp}QEFmIeo;t%ehw@Y12XbU@{2R_3lyA#O%;3-lQZ)`e6V_7Un|eN
z;*!L?<Wx@=TP2`~US?*Bm9e3@o2iqFsjIP*rJ<p#fs>hqvxOOuWd@Wma&d#{b;(aI
z%}vcKf$2>_=rzNs7nBqrx>JiX%TiO^it=+6z+Se>#O)Si+-`yBO~LIJ6P$YWfsWBf
zi)fe-F!g|#@MH_*z!QFI9x$~R0h9HY+tH~E42+?kE{-7;w~~JR|8LK{G9vZAx|zZ}
z&Lm^Q2^=BcYbPcD`2OEOV0q&Yoh2DzH$NZb^jPa4rhJR_l=c0o|Nj5Z7Z<qCl9Z;9
zrf`bY>vr5{hLx@kG8{*iH~df*;6C`|qtt>OKbKlfxW#cq;TNBPKEtET6IlgP3pV_l
zDL)~K>xhE*9=1moD-wAscqhbvo+0UB%2a3?^1@o+H$$POK=&h4hq9y0iWwTaom&4f
z6|xANW-R0|n|_FQLS)f(36HhST5XM93U+))%nK?-a~i%hMF%=)33uo-eB@hkc0tP~
z&JN2)3+|5Mh8t{m8QcPjT-bw(*Eb(}XmDkNa=`S)m}1_J=ma)f?`tVXW=&`is&C{}
z<?di^1iJk*^G6c}F{V>DnKIcG?3ymK8Yme44bq>)y=~u#E1w<1o6R+ub62t_l`7P+
tA9;C0RPe;EMZ)J-F&B#HRW>j%Gt6|q@oRF+pXs1N$J5o%Wt~$(697@%rp*8V
new file mode 100644
index 0000000000000000000000000000000000000000..cb8a11e81d899117cc02c924525c99182b7b8166
GIT binary patch
literal 1460
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!W+OlMT!a6wD0u42@09
z&CPWbj0_A7^bL&k4UKdS&8>`$tPBhkpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$
zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nB5I->~zqG_w
zNeSkK+yc0<dBxCR0tT3VMPh-zp`L+0l0si!{7Q3k;i`*Ef>P7)t1b?yEJ)Q4N-fSW
zElLJPT$(aSbAgp}QEFmIeo;t%ehw@Y12XbU@{2R_3lyA#O%;3-lQZ)`e6V_7Un|eN
z;*!L?<Wx@=TP2`~US?*Bm8pr7p`o#xv#YU_rJ<p#fs>hqvxOOuWoBsZX5``q)9aF-
zT$-DjR|3<Ug3#-NQ!gkfKy;@TWtOF;xE1B+DuBIgm5JLej=0?d(VK$XElxP~>H{64
zj~3A|Az<nOG2zJ;$bl#P)I4BnF9Ig(_8`;E3=B*fo-U3d6}P5LKA3&QLF8Dv+Q~Cz
zt9M+mjWAHQ75VtUQ~T)bu8tL=Ap$A=T@?ZRO()6(Uxvl*`N3Zi!gVc7C(gwsWE;Ef
z%d^cIlS|g_b}GM^GdX9{N8cMci*>fK$xWVFx!?SLP36JXrA)UDH1Br2a^u&fl(p;E
zR@eOh*8RjjG56=+PaVO<ahYvperqT49x&ussK0kB|00Jl<Jrd5C9(bAPg*7LZ;R_%
z&1NcgL*caWfkg^k!e2{OCO=y~bxyMNcXl&gnd_2En6DRFYeewAJFxG{f7bfy;M<zc
zCft+UAD*+l@%LrenZq?)MM{_WLpHsAeyyb>b!t#@$YF+dhV6`bYY%oZ&Cz>sEj;sa
z>|?fzC$@69ivFM8uOt;4zPzF@+_3*+5z}(pj)%XJZ0|>Yln*$@$5OX^)7ur5-l|dD
zN`7YQKT4RQ{9RAl96a60lw!ZRy!ni~iMOxm^iAbmECpI`Cs!zWNjwzV<A0p%$Q%o8
z=SoK5Ka48-4@j{Udjy{0KI#AIcKw0kMKdJNOgW^`^L$mqljT30CDMh2_sY+^SaJ7;
zE3cKN9QP6b<E~3)h`PRL{A@JA!}S*POe42VHj^WchbJsOB{6%;^W3WzLLqXedY_h=
z*qeQCi>nAW-0|D^Vcpy8vk~Qv@1FkP-m>@oEwSADA0{SRTY9j1YI?K>38%VmO5OkV
zI+OW_g$vJ@Jk*f=8x>i0JR_rKg{ob*cfyUZxCh<!v8Lz#>K<TVTJfhVjODO5s2ufl
L^>bP0l+XkK)?pmz
new file mode 100644
index 0000000000000000000000000000000000000000..86bd5ec70add448cfa5647e9448d9bb2ea5349a9
GIT binary patch
literal 1245
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!W+OlMT!a6wD0u42@09
z&CPWbj0_A7^bL&k4UKdS&8>`$tPBhkpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$
zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nB5I->~zqG_w
zNeSkK+yc0<dBxCR0tT3VMPh-zp`L+0l0si!{7Q3k;i`*Ef>P7)t1b?yEJ)Q4N-fSW
zElLJPT$(aSbAgp}QEFmIeo;t%ehw@Y12XbU@{2R_3lyA#O%;3-lQZ)`e6V_7Un|eN
z;*!L?<Wx@=TP2`~US?*Bm9e3@o2iqFp{uczrJ<p#fs>hqvxOOuWd@Wma&d#{b;(aI
z%}vcKf$2>_=rzKr7nBqrx>JiX%TiO^it=+6z+Se>#OW4iH{5Q4=uN@x76Y7m^?{Dj
zM~i5f5HR(CnDAr^<iHbtY927P7Xg#C@buT085kG?JzX3_DsD}=Z0~(IK&1WQl`aJi
zr-NIw?HX1$apbvbSa`6rvbS>Oxn6N}5p>c08ZX>D<(gE;ktFS=9cBs^mYq%a9R#c_
zRX^^X<k5ELf=q?Q+r8%P@sq*|W5YYW&7*5AMCVsenXz>C_sn(K$#FIBdy6-gU6ffK
z%X)p6U%<Niq8)!)_*Gp0tP_&CF2%g1IOSs#U(mn0Ck=~Vt@X-w`r;qrI^%)l%ZBDt
zXI0L&czkG;%%34-xuB$M?vmVuv(djC*;sj8`81@aYrfa?ukbcoHt|?U#HIg?)w?Wx
zvMbvEMjbT1m%9Decd7ENRp(0Q3dJQlH1~@An%K^&>Jf6Ne*VE*mMc4-UpS_$qd(K*
zbDM5YNAc<I&7BwIg`~GVwx~?Gcu?V#$3}B6`DRt$2iLzPrrJ+<kXV|jC;W>i<!J3X
r=cDFgD(#E@@0#uE?CQ7ezxDwJ`%cC;j^?6EKn0GctDnm{r-UW|0obvI
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -421,17 +421,17 @@ def wrapCommand(cmd):
   return cmd
 
 class ShutdownLeakLogger(object):
   """
   Parses the mochitest run log when running a debug build, assigns all leaked
   DOM windows (that are still around after test suite shutdown, despite running
   the GC) to the tests that created them and prints leak statistics.
   """
-  MAX_LEAK_COUNT = 7
+  MAX_LEAK_COUNT = 5
 
   def __init__(self, logger):
     self.logger = logger
     self.tests = []
     self.leakedWindows = {}
     self.leakedDocShells = set()
     self.currentTest = None
     self.seenShutdown = False
--- 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 = "160105"
+llvm_revision = "160176"
 moz_version = "moz0"
 
 ##############################################
 
 import os
 import os.path
 import shutil
 import tarfile
--- a/build/win32/autobinscope.py
+++ b/build/win32/autobinscope.py
@@ -1,75 +1,76 @@
-#!/usr/bin/env 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/.
-
-# run Microsoft's Binscope tool (http://www.microsoft.com/download/en/details.aspx?id=11910)
-# against a fresh Windows build. output a 'binscope.log' file with full details
-# of the run and appropriate strings to integrate with the buildbots
-
-# from the docs : "The error code returned when running under the command line is equal 
-# to the number of failures the tool reported plus the number of errors. BinScope will return 
-# 0 only if there are no errors or failures."
-
-# the symbol dir should point to the symbol dir hierarchy created
-# via running make buildsymbols in a windows build's objdir
-
-import sys
-import subprocess
-import os
-
-BINSCOPE_OUTPUT_LOGFILE = r".\binscope_xml_output.log"
-
-# usage
-if len(sys.argv) < 3:
-  print """usage : autobinscope.by path_to_binary path_to_symbols [log_file_path]"
-		log_file_path is optional, log will be written to .\binscope_xml_output.log by default"""
-  sys.exit(0)
-
-binary_path = sys.argv[1]
-symbol_path = sys.argv[2]
-
-if len(sys.argv) == 4:
-  log_file_path = sys.argv[3]
-else:
-  log_file_path = BINSCOPE_OUTPUT_LOGFILE
-  
-# execute binscope against the binary, using the BINSCOPE environment
-# variable as the path to binscope.exe
-try:
-  binscope_path = os.environ['BINSCOPE']
-except KeyError:
-  print "BINSCOPE environment variable is not set, can't check DEP/ASLR etc. status."
-  sys.exit(0)
-  
-try:    
-  proc = subprocess.Popen([binscope_path, "/target", binary_path,
-    "/output", log_file_path, "/sympath", symbol_path,
-    "/c", "ATLVersionCheck", "/c", "ATLVulnCheck", "/c", "FunctionPointersCheck",
-    "/c", "SharedSectionCheck", "/c", "APTCACheck", "/c", "NXCheck",
-    "/c", "GSCheck", "/c", "GSFunctionSafeBuffersCheck", "/c", "GSFriendlyInitCheck",
-    "/c", "CompilerVersionCheck", "/c", "SafeSEHCheck", "/c", "SNCheck",
-    "/c", "DBCheck"], stdout=subprocess.PIPE)
-
-except WindowsError, (errno, strerror): 
-  if errno != 2 and errno != 3:
-    print "Unexpected error ! \nError " + str(errno) + " : " + strerror + "\nExiting !\n"
-    sys.exit(0)
-  else:
-    print "Could not locate binscope at location : %s\n" % binscope_path
-    print "Binscope wasn't installed or the BINSCOPE env variable wasn't set correctly, skipping this check and exiting..."
-    sys.exit(0)
-
-proc.wait()
-
-output = proc.communicate()[0]
-
-# is this a PASS or a FAIL ? 
-if proc.returncode != 0:
-  print "TEST-UNEXPECTED-FAIL | autobinscope.py | %s is missing a needed Windows protection, such as /GS or ASLR" % binary_path
-else:
-  print "TEST-PASS | autobinscope.py | %s succeeded" % binary_path
-
-
-
+#!/usr/bin/env 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/.
+
+# run Microsoft's Binscope tool (http://www.microsoft.com/download/en/details.aspx?id=11910)
+# against a fresh Windows build. output a 'binscope.log' file with full details
+# of the run and appropriate strings to integrate with the buildbots
+
+# from the docs : "The error code returned when running under the command line is equal 
+# to the number of failures the tool reported plus the number of errors. BinScope will return 
+# 0 only if there are no errors or failures."
+
+# the symbol dir should point to the symbol dir hierarchy created
+# via running make buildsymbols in a windows build's objdir
+
+import sys
+import subprocess
+import os
+
+BINSCOPE_OUTPUT_LOGFILE = r".\binscope_xml_output.log"
+
+# usage
+if len(sys.argv) < 3:
+  print """usage : autobinscope.by path_to_binary path_to_symbols [log_file_path]"
+		log_file_path is optional, log will be written to .\binscope_xml_output.log by default"""
+  sys.exit(0)
+
+binary_path = sys.argv[1]
+symbol_path = sys.argv[2]
+
+if len(sys.argv) == 4:
+  log_file_path = sys.argv[3]
+else:
+  log_file_path = BINSCOPE_OUTPUT_LOGFILE
+  
+# execute binscope against the binary, using the BINSCOPE environment
+# variable as the path to binscope.exe
+try:
+  binscope_path = os.environ['BINSCOPE']
+except KeyError:
+  print "BINSCOPE environment variable is not set, can't check DEP/ASLR etc. status."
+  sys.exit(0)
+  
+try:    
+  proc = subprocess.Popen([binscope_path, "/target", binary_path,
+    "/output", log_file_path, "/sympath", symbol_path,
+    "/c", "ATLVersionCheck", "/c", "ATLVulnCheck", "/c", "FunctionPointersCheck",
+    "/c", "SharedSectionCheck", "/c", "APTCACheck", "/c", "NXCheck",
+    "/c", "GSCheck", "/c", "GSFunctionSafeBuffersCheck", "/c", "GSFriendlyInitCheck",
+    "/c", "CompilerVersionCheck", "/c", "SafeSEHCheck", "/c", "SNCheck",
+    "/c", "DBCheck"], stdout=subprocess.PIPE)
+
+except WindowsError, (errno, strerror): 
+  if errno != 2 and errno != 3:
+    print "Unexpected error ! \nError " + str(errno) + " : " + strerror + "\nExiting !\n"
+    sys.exit(0)
+  else:
+    print "Could not locate binscope at location : %s\n" % binscope_path
+    print "Binscope wasn't installed or the BINSCOPE env variable wasn't set correctly, skipping this check and exiting..."
+    sys.exit(0)
+
+proc.wait()
+
+output = proc.communicate()[0]
+
+# is this a PASS or a FAIL ? 
+if proc.returncode != 0:
+  print "Error count: %d" % proc.returncode
+  print "TEST-UNEXPECTED-FAIL | autobinscope.py | %s is missing a needed Windows protection, such as /GS or ASLR" % binary_path
+  logfile = open(log_file_path, "r")
+  for line in logfile:
+    print(line),
+else:
+  print "TEST-PASS | autobinscope.py | %s succeeded" % binary_path
--- a/configure.in
+++ b/configure.in
@@ -4034,17 +4034,17 @@ fi
 fi # SKIP_LIBRARY_CHECKS
 
 dnl system ZLIB support
 dnl ========================================================
 MOZ_ZLIB_CHECK([1.2.3])
 
 if test "$MOZ_NATIVE_ZLIB" != 1; then
     MOZ_ZLIB_CFLAGS=
-    MOZ_ZLIB_LIBS='$(call EXPAND_LIBNAME_PATH,mozz,'"$_objdir"'/modules/zlib/src)'
+    MOZ_ZLIB_LIBS='$(call EXPAND_LIBNAME_PATH,mozz,'"$MOZ_BUILD_ROOT"'/modules/zlib/src)'
 fi
 
 if test "$MOZ_LINKER" = 1 -a "$MOZ_NATIVE_ZLIB" != 1; then
     AC_MSG_ERROR([Custom dynamic linker requires --with-system-zlib])
 fi
 
 if test -z "$SKIP_LIBRARY_CHECKS"; then
 dnl system BZIP2 Support
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -112,17 +112,17 @@ public:
    * The style state of this element. This is the real state of the element
    * with any style locks applied for pseudo-class inspecting.
    */
   nsEventStates StyleState() const {
     if (!HasLockedStyleStates()) {
       return mState;
     }
     return StyleStateFromLocks();
-  };
+  }
 
   /**
    * The style state locks applied to this element.
    */
   nsEventStates LockedStyleStates() const;
 
   /**
    * Add a style state lock on this element.
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1626,16 +1626,21 @@ public:
   /**
    * Convert ASCII a-z to A-Z.
    * @return NS_OK on success, or NS_ERROR_OUT_OF_MEMORY if making the string
    * writable needs to allocate memory and that allocation fails.
    */
   static nsresult ASCIIToUpper(nsAString& aStr);
   static nsresult ASCIIToUpper(const nsAString& aSource, nsAString& aDest);
 
+  /**
+   * Return whether aStr contains an ASCII uppercase character.
+   */
+  static bool StringContainsASCIIUpper(const nsAString& aStr);
+
   // Returns NS_OK for same origin, error (NS_ERROR_DOM_BAD_URI) if not.
   static nsresult CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel);
   static nsIInterfaceRequestor* GetSameOriginChecker();
 
   static nsIThreadJSContextStack* ThreadJSContextStack()
   {
     return sThreadJSContextStack;
   }
--- a/content/base/src/nsAttrAndChildArray.cpp
+++ b/content/base/src/nsAttrAndChildArray.cpp
@@ -315,16 +315,49 @@ nsAttrAndChildArray::GetAttr(nsIAtom* aL
       }
     }
   }
 
   return nsnull;
 }
 
 const nsAttrValue*
+nsAttrAndChildArray::GetAttr(const nsAString& aName,
+                             nsCaseTreatment aCaseSensitive) const
+{
+  // Check whether someone is being silly and passing non-lowercase
+  // attr names.
+  if (aCaseSensitive == eIgnoreCase &&
+      nsContentUtils::StringContainsASCIIUpper(aName)) {
+    // Try again with a lowercased name, but make sure we can't reenter this
+    // block by passing eCaseSensitive for aCaseSensitive.
+    nsAutoString lowercase;
+    nsContentUtils::ASCIIToLower(aName, lowercase);
+    return GetAttr(lowercase, eCaseMatters);
+  }
+
+  PRUint32 i, slotCount = AttrSlotCount();
+  for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
+    if (ATTRS(mImpl)[i].mName.QualifiedNameEquals(aName)) {
+      return &ATTRS(mImpl)[i].mValue;
+    }
+  }
+
+  if (mImpl && mImpl->mMappedAttrs) {
+    const nsAttrValue* val =
+      mImpl->mMappedAttrs->GetAttr(aName);
+    if (val) {
+      return val;
+    }
+  }
+
+  return nsnull;
+}
+
+const nsAttrValue*
 nsAttrAndChildArray::AttrAt(PRUint32 aPos) const
 {
   NS_ASSERTION(aPos < AttrCount(),
                "out-of-bounds access in nsAttrAndChildArray");
 
   PRUint32 mapped = MappedAttrCount();
   if (aPos < mapped) {
     return mImpl->mMappedAttrs->AttrAt(aPos);
@@ -485,18 +518,18 @@ nsAttrAndChildArray::GetExistingAttrName
 
   return nsnull;
 }
 
 PRInt32
 nsAttrAndChildArray::IndexOfAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID) const
 {
   PRInt32 idx;
-  if (mImpl && mImpl->mMappedAttrs) {
-    idx = mImpl->mMappedAttrs->IndexOfAttr(aLocalName, aNamespaceID);
+  if (mImpl && mImpl->mMappedAttrs && aNamespaceID == kNameSpaceID_None) {
+    idx = mImpl->mMappedAttrs->IndexOfAttr(aLocalName);
     if (idx >= 0) {
       return idx;
     }
   }
 
   PRUint32 i;
   PRUint32 mapped = MappedAttrCount();
   PRUint32 slotCount = AttrSlotCount();
--- a/content/base/src/nsAttrAndChildArray.h
+++ b/content/base/src/nsAttrAndChildArray.h
@@ -11,16 +11,17 @@
 #ifndef nsAttrAndChildArray_h___
 #define nsAttrAndChildArray_h___
 
 #include "mozilla/Attributes.h"
 
 #include "nscore.h"
 #include "nsAttrName.h"
 #include "nsAttrValue.h"
+#include "nsCaseTreatment.h"
 
 class nsINode;
 class nsIContent;
 class nsMappedAttributes;
 class nsHTMLStyleSheet;
 class nsRuleWalker;
 class nsMappedAttributeElement;
 
@@ -66,16 +67,20 @@ public:
   void RemoveChildAt(PRUint32 aPos);
   // Like RemoveChildAt but hands the reference to the child being
   // removed back to the caller instead of just releasing it.
   already_AddRefed<nsIContent> TakeChildAt(PRUint32 aPos);
   PRInt32 IndexOfChild(nsINode* aPossibleChild) const;
 
   PRUint32 AttrCount() const;
   const nsAttrValue* GetAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID = kNameSpaceID_None) const;
+  // Get an nsAttrValue by qualified name.  Can optionally do
+  // ASCII-case-insensitive name matching.
+  const nsAttrValue* GetAttr(const nsAString& aName,
+                             nsCaseTreatment aCaseSensitive) const;
   const nsAttrValue* AttrAt(PRUint32 aPos) const;
   nsresult SetAndTakeAttr(nsIAtom* aLocalName, nsAttrValue& aValue);
   nsresult SetAndTakeAttr(nsINodeInfo* aName, nsAttrValue& aValue);
 
   // Remove the attr at position aPos.  The value of the attr is placed in
   // aValue; any value that was already in aValue is destroyed.
   nsresult RemoveAttrAt(PRUint32 aPos, nsAttrValue& aValue);
 
--- a/content/base/src/nsCSPService.cpp
+++ b/content/base/src/nsCSPService.cpp
@@ -264,17 +264,17 @@ CSPService::AsyncOnChannelRedirect(nsICh
     if (NS_SUCCEEDED(rv)) {
       return NS_OK;
     }
   }
 
   // The redirecting channel isn't a writable property bag, we won't be able
   // to enforce the load policy if it redirects again, so we stop it now.
   nsCAutoString newUriSpec;
-  newUri->GetSpec(newUriSpec);
+  rv = newUri->GetSpec(newUriSpec);
   const PRUnichar *formatParams[] = { NS_ConvertUTF8toUTF16(newUriSpec).get() };
   if (NS_SUCCEEDED(rv)) {
     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                     "Redirect Error", nsnull,
                                     nsContentUtils::eDOM_PROPERTIES,
                                     "InvalidRedirectChannelWarning",
                                     formatParams, 1);
   }
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5631,16 +5631,33 @@ nsContentUtils::EqualsLiteralIgnoreASCII
       }
     }
   }
   
   return true;
 }
 
 /* static */
+bool
+nsContentUtils::StringContainsASCIIUpper(const nsAString& aStr)
+{
+  const PRUnichar* iter = aStr.BeginReading();
+  const PRUnichar* end = aStr.EndReading();
+  while (iter != end) {
+    PRUnichar c = *iter;
+    if (c >= 'A' && c <= 'Z') {
+      return true;
+    }
+    ++iter;
+  }
+
+  return false;
+}
+
+/* static */
 nsIInterfaceRequestor*
 nsContentUtils::GetSameOriginChecker()
 {
   if (!sSameOriginChecker) {
     sSameOriginChecker = new SameOriginChecker();
     NS_IF_ADDREF(sSameOriginChecker);
   }
   return sSameOriginChecker;
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -420,18 +420,18 @@ protected:
     public:                                                                  \
       _i##Shim(nsIInterfaceRequestor* aIfreq, _i* aRealPtr)                  \
         : mIfReq(aIfreq), mRealPtr(aRealPtr)                                 \
       {                                                                      \
         NS_ASSERTION(mIfReq, "Expected non-null here");                      \
         NS_ASSERTION(mRealPtr, "Expected non-null here");                    \
       }                                                                      \
       NS_DECL_ISUPPORTS                                                      \
-      NS_FORWARD_NSIINTERFACEREQUESTOR(mIfReq->);                            \
-      NS_FORWARD_##_allcaps(mRealPtr->);                                     \
+      NS_FORWARD_NSIINTERFACEREQUESTOR(mIfReq->)                             \
+      NS_FORWARD_##_allcaps(mRealPtr->)                                      \
     private:                                                                 \
       nsCOMPtr<nsIInterfaceRequestor> mIfReq;                                \
       nsCOMPtr<_i> mRealPtr;                                                 \
     };
 
     DECL_SHIM(nsILoadContext, NSILOADCONTEXT)
     DECL_SHIM(nsIProgressEventSink, NSIPROGRESSEVENTSINK)
     DECL_SHIM(nsIChannelEventSink, NSICHANNELEVENTSINK)
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -1365,16 +1365,37 @@ nsFrameLoader::OwnerIsBrowserFrame()
   bool isBrowser = false;
   if (browserFrame) {
     browserFrame->GetReallyIsBrowser(&isBrowser);
   }
   return isBrowser;
 }
 
 bool
+nsFrameLoader::OwnerIsAppFrame()
+{
+  nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
+  bool isApp = false;
+  if (browserFrame) {
+    browserFrame->GetReallyIsApp(&isApp);
+  }
+  return isApp;
+}
+
+void
+nsFrameLoader::GetOwnerAppManifestURL(nsAString& aOut)
+{
+  aOut.Truncate();
+  nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
+  if (browserFrame) {
+    browserFrame->GetAppManifestURL(aOut);
+  }
+}
+
+bool
 nsFrameLoader::ShouldUseRemoteProcess()
 {
   if (PR_GetEnv("MOZ_DISABLE_OOP_TABS") ||
       Preferences::GetBool("dom.ipc.tabs.disabled", false)) {
     return false;
   }
 
   // If we're inside a content process, don't use a remote process for this
@@ -1911,17 +1932,22 @@ nsFrameLoader::TryRemoteBrowser()
   nsCOMPtr<nsIXULWindow> window(do_GetInterface(parentOwner));
   if (!window) {
     return false;
   }
   if (NS_FAILED(window->GetChromeFlags(&chromeFlags))) {
     return false;
   }
 
-  ContentParent* parent = ContentParent::GetNewOrUsed();
+  // If our owner has no app manifest URL, then this is equivalent to
+  // ContentParent::GetNewOrUsed().
+  nsAutoString appManifest;
+  GetOwnerAppManifestURL(appManifest);
+  ContentParent* parent = ContentParent::GetForApp(appManifest);
+
   NS_ASSERTION(parent->IsAlive(), "Process parent should be alive; something is very wrong!");
   mRemoteBrowser = parent->CreateTab(chromeFlags,
                                      /* aIsBrowserFrame = */ OwnerIsBrowserFrame());
   if (mRemoteBrowser) {
     nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mOwnerContent);
     mRemoteBrowser->SetOwnerElement(element);
 
     nsCOMPtr<nsIDocShellTreeItem> rootItem;
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -270,22 +270,35 @@ public:
 
 private:
 
   void SetOwnerContent(mozilla::dom::Element* aContent);
 
   bool ShouldUseRemoteProcess();
 
   /**
-   * Is this a frameloader for a bona fide <iframe mozbrowser>?  (I.e., does
-   * the frame return true for nsIMozBrowserFrame::GetReallyIsBrowser()?)
+   * Is this a frameloader for a bona fide <iframe mozbrowser> or
+   * <iframe mozapp>?  (I.e., does the frame return true for
+   * nsIMozBrowserFrame::GetReallyIsBrowser()?)
    */
   bool OwnerIsBrowserFrame();
 
   /**
+   * Is this a frameloader for a bona fide <iframe mozapp>?  (I.e., does the
+   * frame return true for nsIMozBrowserFrame::GetReallyIsApp()?)
+   */
+  bool OwnerIsAppFrame();
+
+  /**
+   * Get our owning element's app manifest URL, or return the empty string if
+   * our owning element doesn't have an app manifest URL.
+   */
+  void GetOwnerAppManifestURL(nsAString& aOut);
+
+  /**
    * If we are an IPC frame, set mRemoteFrame. Otherwise, create and
    * initialize mDocShell.
    */
   nsresult MaybeCreateDocShell();
   nsresult EnsureMessageManager();
   NS_HIDDEN_(void) GetURL(nsString& aURL);
 
   // Properly retrieves documentSize of any subdocument type.
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -1531,32 +1531,40 @@ nsGenericElement::GetTagName(nsAString& 
   aTagName = NodeName();
   return NS_OK;
 }
 
 nsresult
 nsGenericElement::GetAttribute(const nsAString& aName,
                                nsAString& aReturn)
 {
-  const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
-
-  if (!name) {
-    if (mNodeInfo->NamespaceID() == kNameSpaceID_XUL) {
+  // I hate XUL
+  if (IsXUL()) {
+    const nsAttrValue* val =
+      nsXULElement::FromContent(this)->GetAttrValue(aName);
+    if (val) {
+      val->ToString(aReturn);
+    }
+    else {
       // XXX should be SetDOMStringToNull(aReturn);
       // See bug 232598
       aReturn.Truncate();
     }
-    else {
-      SetDOMStringToNull(aReturn);
-    }
-
     return NS_OK;
   }
-
-  GetAttr(name->NamespaceID(), name->LocalName(), aReturn);
+  
+  const nsAttrValue* val =
+    mAttrsAndChildren.GetAttr(aName,
+                              IsHTML() && IsInHTMLDocument() ?
+                                eIgnoreCase : eCaseMatters);
+  if (val) {
+    val->ToString(aReturn);
+  } else {
+    SetDOMStringToNull(aReturn);
+  }
 
   return NS_OK;
 }
 
 nsresult
 nsGenericElement::SetAttribute(const nsAString& aName,
                                const nsAString& aValue)
 {
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1,13 +1,15 @@
 /* -*- 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/. */
 
+// IWYU pragma: private, include "nsGkAtoms.h"
+
 /*
   This file contains the list of all atoms used by gklayout;
   see nsGkAtoms for access to the atoms.
 */
 
 /*
   This file is designed to be used as inline input to nsGkAtoms.cpp and nsGkAtoms.h
   *only* through the magic of C preprocessing.
--- a/content/base/src/nsMappedAttributes.cpp
+++ b/content/base/src/nsMappedAttributes.cpp
@@ -108,19 +108,32 @@ nsMappedAttributes::SetAndTakeAttr(nsIAt
   return NS_OK;
 }
 
 const nsAttrValue*
 nsMappedAttributes::GetAttr(nsIAtom* aAttrName) const
 {
   NS_PRECONDITION(aAttrName, "null name");
 
-  PRInt32 i = IndexOfAttr(aAttrName, kNameSpaceID_None);
-  if (i >= 0) {
-    return &Attrs()[i].mValue;
+  for (PRUint32 i = 0; i < mAttrCount; ++i) {
+    if (Attrs()[i].mName.Equals(aAttrName)) {
+      return &Attrs()[i].mValue;
+    }
+  }
+
+  return nsnull;
+}
+
+const nsAttrValue*
+nsMappedAttributes::GetAttr(const nsAString& aAttrName) const
+{
+  for (PRUint32 i = 0; i < mAttrCount; ++i) {
+    if (Attrs()[i].mName.Atom()->Equals(aAttrName)) {
+      return &Attrs()[i].mValue;
+    }
   }
 
   return nsnull;
 }
 
 bool
 nsMappedAttributes::Equals(const nsMappedAttributes* aOther) const
 {
@@ -223,32 +236,22 @@ nsMappedAttributes::GetExistingAttrNameF
       }
     }
   }
 
   return nsnull;
 }
 
 PRInt32
-nsMappedAttributes::IndexOfAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID) const
+nsMappedAttributes::IndexOfAttr(nsIAtom* aLocalName) const
 {
   PRUint32 i;
-  if (aNamespaceID == kNameSpaceID_None) {
-    // This should be the common case so lets make an optimized loop
-    for (i = 0; i < mAttrCount; ++i) {
-      if (Attrs()[i].mName.Equals(aLocalName)) {
-        return i;
-      }
-    }
-  }
-  else {
-    for (i = 0; i < mAttrCount; ++i) {
-      if (Attrs()[i].mName.Equals(aLocalName, aNamespaceID)) {
-        return i;
-      }
+  for (i = 0; i < mAttrCount; ++i) {
+    if (Attrs()[i].mName.Equals(aLocalName)) {
+      return i;
     }
   }
 
   return -1;
 }
 
 size_t
 nsMappedAttributes::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
--- a/content/base/src/nsMappedAttributes.h
+++ b/content/base/src/nsMappedAttributes.h
@@ -29,16 +29,17 @@ public:
   void* operator new(size_t size, PRUint32 aAttrCount = 1) CPP_THROW_NEW;
 
   nsMappedAttributes* Clone(bool aWillAddAttr);
 
   NS_DECL_ISUPPORTS
 
   nsresult SetAndTakeAttr(nsIAtom* aAttrName, nsAttrValue& aValue);
   const nsAttrValue* GetAttr(nsIAtom* aAttrName) const;
+  const nsAttrValue* GetAttr(const nsAString& aAttrName) const;
 
   PRUint32 Count() const
   {
     return mAttrCount;
   }
 
   bool Equals(const nsMappedAttributes* aAttributes) const;
   PRUint32 HashValue() const;
@@ -62,17 +63,17 @@ public:
   {
     NS_ASSERTION(aPos < mAttrCount, "out-of-bounds");
     return &Attrs()[aPos].mValue;
   }
   // Remove the attr at position aPos.  The value of the attr is placed in
   // aValue; any value that was already in aValue is destroyed.
   void RemoveAttrAt(PRUint32 aPos, nsAttrValue& aValue);
   const nsAttrName* GetExistingAttrNameFromQName(const nsAString& aName) const;
-  PRInt32 IndexOfAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID) const;
+  PRInt32 IndexOfAttr(nsIAtom* aLocalName) const;
   
 
   // nsIStyleRule 
   virtual void MapRuleInfoInto(nsRuleData* aRuleData);
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
 #endif
 
--- a/content/base/src/nsNodeIterator.h
+++ b/content/base/src/nsNodeIterator.h
@@ -34,17 +34,17 @@ public:
     virtual ~nsNodeIterator();
 
     NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
     NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsNodeIterator, nsIDOMNodeIterator)
 
 private:
     struct NodePointer {
-        NodePointer() : mNode(nsnull) {};
+        NodePointer() : mNode(nsnull) {}
         NodePointer(nsINode *aNode, bool aBeforeNode);
 
         typedef bool (NodePointer::*MoveToMethodType)(nsINode*);
         bool MoveToNext(nsINode *aRoot);
         bool MoveToPrevious(nsINode *aRoot);
 
         bool MoveForward(nsINode *aRoot, nsINode *aNode);
         void MoveBackward(nsINode *aParent, nsINode *aNode);
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -35,17 +35,17 @@
 #include "nsIScriptSecurityManager.h"
 #include "nsDOMError.h"
 #include "nsIJSContextStack.h"
 #include "nsIDocument.h"
 #include "nsIPresShell.h"
 #include "nsMutationEvent.h"
 #include "nsIXPConnect.h"
 #include "nsDOMCID.h"
-#include "nsIScriptObjectOwner.h" // for nsIScriptEventHandlerOwner
+#include "nsIScriptEventHandlerOwner.h"
 #include "nsFocusManager.h"
 #include "nsIDOMElement.h"
 #include "nsContentUtils.h"
 #include "nsJSUtils.h"
 #include "nsContentCID.h"
 #include "nsEventDispatcher.h"
 #include "nsDOMJSUtils.h"
 #include "nsDOMScriptObjectHolder.h"
@@ -277,17 +277,19 @@ nsEventListenerManager::AddEventListener
              (aTypeAtom == nsGkAtoms::ontouchstart ||
               aTypeAtom == nsGkAtoms::ontouchend ||
               aTypeAtom == nsGkAtoms::ontouchmove ||
               aTypeAtom == nsGkAtoms::ontouchenter ||
               aTypeAtom == nsGkAtoms::ontouchleave ||
               aTypeAtom == nsGkAtoms::ontouchcancel)) {
     mMayHaveTouchEventListener = true;
     nsPIDOMWindow* window = GetInnerWindowForTarget();
-    if (window)
+    // we don't want touchevent listeners added by scrollbars to flip this flag
+    // so we ignore listeners created with system event flag
+    if (window && !(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT))
       window->SetHasTouchEventListeners();
   } else if (aTypeAtom == nsGkAtoms::onmouseenter ||
              aTypeAtom == nsGkAtoms::onmouseleave) {
     mMayHaveMouseEnterLeaveEventListener = true;
     nsPIDOMWindow* window = GetInnerWindowForTarget();
     if (window) {
 #ifdef DEBUG
       nsCOMPtr<nsIDocument> d = do_QueryInterface(window->GetExtantDocument());
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -2444,17 +2444,17 @@ void
 nsGenericHTMLElement::MapCommonAttributesInto(const nsMappedAttributes* aAttributes,
                                               nsRuleData* aData)
 {
   nsGenericHTMLElement::MapCommonAttributesExceptHiddenInto(aAttributes, aData);
 
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
     nsCSSValue* display = aData->ValueForDisplay();
     if (display->GetUnit() == eCSSUnit_Null) {
-      if (aAttributes->IndexOfAttr(nsGkAtoms::hidden, kNameSpaceID_None) >= 0) {
+      if (aAttributes->IndexOfAttr(nsGkAtoms::hidden) >= 0) {
         display->SetIntValue(NS_STYLE_DISPLAY_NONE, eCSSUnit_Enumerated);
       }
     }
   }
 }
 
 
 /* static */ const nsGenericHTMLElement::MappedAttributeEntry
--- a/content/html/content/src/nsGenericHTMLFrameElement.cpp
+++ b/content/html/content/src/nsGenericHTMLFrameElement.cpp
@@ -4,16 +4,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsGenericHTMLFrameElement.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsContentUtils.h"
 #include "mozilla/Preferences.h"
+#include "nsIAppsService.h"
+#include "nsServiceManagerUtils.h"
+#include "nsIDOMApplicationRegistry.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
                                                   nsGenericHTMLElement)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mFrameLoader, nsIFrameLoader)
@@ -260,18 +263,19 @@ nsGenericHTMLFrameElement::IsHTMLFocusab
   if (!*aIsFocusable && aTabIndex) {
     *aTabIndex = -1;
   }
 
   return false;
 }
 
 /**
- * Return true if this frame element has permission to send mozbrowser
- * events, and false otherwise.
+ * Return true if this frame element really is a mozbrowser or mozapp.  (It
+ * needs to have the right attributes, and its creator must have the right
+ * permissions.)
  */
 nsresult
 nsGenericHTMLFrameElement::GetReallyIsBrowser(bool *aOut)
 {
   *aOut = false;
 
   // Fail if browser frames are globally disabled.
   if (!Preferences::GetBool("dom.mozBrowserFramesEnabled")) {
@@ -297,16 +301,60 @@ nsGenericHTMLFrameElement::GetReallyIsBr
   }
 
   // Otherwise, succeed.
   *aOut = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsGenericHTMLFrameElement::GetReallyIsApp(bool *aOut)
+{
+  nsAutoString manifestURL;
+  GetAppManifestURL(manifestURL);
+
+  *aOut = !manifestURL.IsEmpty();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::GetAppManifestURL(nsAString& aOut)
+{
+  aOut.Truncate();
+
+  // At the moment, you can't be an app without being a browser.
+  bool isBrowser = false;
+  GetReallyIsBrowser(&isBrowser);
+  if (!isBrowser) {
+    return NS_OK;
+  }
+
+  // TODO: We surely need a permissions check here, particularly once we no
+  // longer rely on the mozbrowser permission check.
+
+  nsAutoString manifestURL;
+  GetAttr(kNameSpaceID_None, nsGkAtoms::mozapp, manifestURL);
+  if (manifestURL.IsEmpty()) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
+  NS_ENSURE_STATE(appsService);
+
+  nsCOMPtr<mozIDOMApplication> app;
+  appsService->GetAppByManifestURL(manifestURL, getter_AddRefs(app));
+
+  if (app) {
+    aOut.Assign(manifestURL);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsGenericHTMLFrameElement::DisallowCreateFrameLoader()
 {
   MOZ_ASSERT(!mFrameLoader);
   MOZ_ASSERT(!mFrameLoaderCreationDisallowed);
   mFrameLoaderCreationDisallowed = true;
   return NS_OK;
 }
 
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -2571,16 +2571,17 @@ void nsHTMLMediaElement::EndMediaStreamP
   GetMediaStream()->RemoveAudioOutput(this);
   VideoFrameContainer* container = GetVideoFrameContainer();
   if (container) {
     GetMediaStream()->RemoveVideoOutput(container);
   }
   if (mPaused) {
     GetMediaStream()->ChangeExplicitBlockerCount(-1);
   }
+  mVideoFrameContainer->GetImageContainer()->SetCurrentImage(nsnull);
   if (mPausedForInactiveDocument) {
     GetMediaStream()->ChangeExplicitBlockerCount(-1);
   }
   mStream = nsnull;
 }
 
 nsresult nsHTMLMediaElement::NewURIFromString(const nsAutoString& aURISpec, nsIURI** aURI)
 {
@@ -2987,17 +2988,18 @@ VideoFrameContainer* nsHTMLMediaElement:
     return nsnull;
 
   // Only video frames need an image container.
   nsCOMPtr<nsIDOMHTMLVideoElement> video = do_QueryObject(this);
   if (!video)
     return nsnull;
 
   mVideoFrameContainer =
-    new VideoFrameContainer(this, LayerManager::CreateImageContainer());
+    new VideoFrameContainer(this, LayerManager::CreateAsynchronousImageContainer());
+
   return mVideoFrameContainer;
 }
 
 nsresult nsHTMLMediaElement::DispatchAudioAvailableEvent(float* aFrameBuffer,
                                                          PRUint32 aFrameBufferLength,
                                                          float aTime)
 {
   // Auto manage the memory for the frame buffer. If we fail and return
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -9,16 +9,17 @@
 #include "nsCOMPtr.h"
 #include "nsIPresShell.h"
 #include "nsIView.h"
 #include "nsCaret.h"
 #include "nsEditorCID.h"
 #include "nsLayoutCID.h"
 #include "nsITextControlFrame.h" 
 #include "nsIPlaintextEditor.h"
+#include "nsIDOMCharacterData.h"
 #include "nsIDOMDocument.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsTextControlFrame.h"
 #include "nsIControllers.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMHTMLTextAreaElement.h"
 #include "nsITransactionManager.h"
 #include "nsIControllerContext.h"
@@ -1761,17 +1762,17 @@ nsTextEditorState::SetValue(const nsAStr
       mBoundFrame->GetText(currentValue);
     }
 
     nsWeakFrame weakFrame(mBoundFrame);
 
     // this is necessary to avoid infinite recursion
     if (!currentValue.Equals(aValue))
     {
-      nsTextControlFrame::ValueSetter valueSetter(mBoundFrame, mEditor);
+      nsTextControlFrame::ValueSetter valueSetter(mEditor);
 
       // \r is an illegal character in the dom, but people use them,
       // so convert windows and mac platform linebreaks to \n:
       // Unfortunately aValue is declared const, so we have to copy
       // in order to do this substitution.
       nsString newValue(aValue);
       if (aValue.FindChar(PRUnichar('\r')) != -1) {
         nsContentUtils::PlatformToDOMLineBreaks(newValue);
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -550,16 +550,17 @@ nsHTMLDocument::StartDocumentLoad(const 
     MOZ_ASSERT(false, "Bad parser command");
     return NS_ERROR_INVALID_ARG;
   }
 
   bool html = contentType.EqualsLiteral(TEXT_HTML);
   bool xhtml = !html && contentType.EqualsLiteral(APPLICATION_XHTML_XML);
   bool plainText = !html && !xhtml && (contentType.EqualsLiteral(TEXT_PLAIN) ||
     contentType.EqualsLiteral(TEXT_CSS) ||
+    contentType.EqualsLiteral(TEXT_CACHE_MANIFEST) ||
     contentType.EqualsLiteral(APPLICATION_JAVASCRIPT) ||
     contentType.EqualsLiteral(APPLICATION_XJAVASCRIPT) ||
     contentType.EqualsLiteral(TEXT_ECMASCRIPT) ||
     contentType.EqualsLiteral(APPLICATION_ECMASCRIPT) ||
     contentType.EqualsLiteral(TEXT_JAVASCRIPT) ||
     contentType.EqualsLiteral(APPLICATION_JSON));
   if (!(html || xhtml || plainText || viewSource)) {
     MOZ_ASSERT(false, "Channel with bad content type.");
--- a/content/smil/nsSMILAnimationController.cpp
+++ b/content/smil/nsSMILAnimationController.cpp
@@ -765,17 +765,18 @@ nsSMILAnimationController::GetTargetIden
     if (attributeNamespaceID == kNameSpaceID_None) {
       // width/height are special as they may be attributes or for
       // outer-<svg> elements, mapped into style.
       if (attributeName == nsGkAtoms::width ||
           attributeName == nsGkAtoms::height) {
         isCSS = targetElem->GetNameSpaceID() != kNameSpaceID_SVG;
       } else {
         nsCSSProperty prop =
-          nsCSSProps::LookupProperty(nsDependentAtomString(attributeName));
+          nsCSSProps::LookupProperty(nsDependentAtomString(attributeName),
+                                     nsCSSProps::eEnabled);
         isCSS = nsSMILCSSProperty::IsPropertyAnimatable(prop);
       }
     }
   } else {
     isCSS = (attributeType == eSMILTargetAttrType_CSS);
   }
 
   // Construct the key
--- a/content/smil/nsSMILCompositor.cpp
+++ b/content/smil/nsSMILCompositor.cpp
@@ -119,17 +119,18 @@ nsSMILCompositor::ClearAnimationEffects(
 
 // Protected Helper Functions
 // --------------------------
 nsISMILAttr*
 nsSMILCompositor::CreateSMILAttr()
 {
   if (mKey.mIsCSS) {
     nsCSSProperty propId =
-      nsCSSProps::LookupProperty(nsDependentAtomString(mKey.mAttributeName));
+      nsCSSProps::LookupProperty(nsDependentAtomString(mKey.mAttributeName),
+                                 nsCSSProps::eEnabled);
     if (nsSMILCSSProperty::IsPropertyAnimatable(propId)) {
       return new nsSMILCSSProperty(propId, mKey.mElement.get());
     }
   } else {
     return mKey.mElement->GetAnimatedAttr(mKey.mAttributeNamespaceID,
                                           mKey.mAttributeName);
   }
   return nsnull;
--- a/content/smil/nsSMILTimedElement.cpp
+++ b/content/smil/nsSMILTimedElement.cpp
@@ -1307,17 +1307,17 @@ namespace
   };
 }
 
 void
 nsSMILTimedElement::ClearSpecs(TimeValueSpecList& aSpecs,
                                InstanceTimeList& aInstances,
                                RemovalTestFunction aRemove)
 {
-  AutoIntervalUpdateBatcher(*this);
+  AutoIntervalUpdateBatcher updateBatcher(*this);
 
   for (PRUint32 i = 0; i < aSpecs.Length(); ++i) {
     aSpecs[i]->Unlink();
   }
   aSpecs.Clear();
 
   RemoveByFunction removeByFunction(aRemove);
   RemoveInstanceTimes(aInstances, removeByFunction);
--- a/content/svg/content/src/SVGAnimatedPreserveAspectRatio.h
+++ b/content/svg/content/src/SVGAnimatedPreserveAspectRatio.h
@@ -27,57 +27,57 @@ class SVGPreserveAspectRatio
 {
   friend class SVGAnimatedPreserveAspectRatio;
 
 public:
   SVGPreserveAspectRatio(PRUint16 aAlign, PRUint16 aMeetOrSlice, bool aDefer = false)
     : mAlign(aAlign)
     , mMeetOrSlice(aMeetOrSlice)
     , mDefer(aDefer)
-  {};
+  {}
 
   SVGPreserveAspectRatio()
     : mAlign(0)
     , mMeetOrSlice(0)
     , mDefer(false)
-  {};
+  {}
 
   bool operator==(const SVGPreserveAspectRatio& aOther) const;
 
   nsresult SetAlign(PRUint16 aAlign) {
     if (aAlign < nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE ||
         aAlign > nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX)
       return NS_ERROR_FAILURE;
     mAlign = static_cast<PRUint8>(aAlign);
     return NS_OK;
-  };
+  }
 
   PRUint16 GetAlign() const {
     return mAlign;
-  };
+  }
 
   nsresult SetMeetOrSlice(PRUint16 aMeetOrSlice) {
     if (aMeetOrSlice < nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET ||
         aMeetOrSlice > nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE)
       return NS_ERROR_FAILURE;
     mMeetOrSlice = static_cast<PRUint8>(aMeetOrSlice);
     return NS_OK;
-  };
+  }
 
   PRUint16 GetMeetOrSlice() const {
     return mMeetOrSlice;
-  };
+  }
 
   void SetDefer(bool aDefer) {
     mDefer = aDefer;
-  };
+  }
 
   bool GetDefer() const {
     return mDefer;
-  };
+  }
 
 private:
   PRUint8 mAlign;
   PRUint8 mMeetOrSlice;
   bool mDefer;
 };
 
 class SVGAnimatedPreserveAspectRatio
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -1126,17 +1126,18 @@ MappedAttrParser::ParseMappedAttrValue(n
 {
   if (!mDecl) {
     mDecl = new css::Declaration();
     mDecl->InitializeEmpty();
   }
 
   // Get the nsCSSProperty ID for our mapped attribute.
   nsCSSProperty propertyID =
-    nsCSSProps::LookupProperty(nsDependentAtomString(aMappedAttrName));
+    nsCSSProps::LookupProperty(nsDependentAtomString(aMappedAttrName),
+                               nsCSSProps::eEnabled);
   if (propertyID != eCSSProperty_UNKNOWN) {
     bool changed; // outparam for ParseProperty. (ignored)
     mParser.ParseProperty(propertyID, aMappedAttrValue, mDocURI, mBaseURI,
                           mNodePrincipal, mDecl, &changed, false);
     return;
   }
   NS_ABORT_IF_FALSE(aMappedAttrName == nsGkAtoms::lang,
                     "Only 'lang' should be unrecognized!");
@@ -2448,17 +2449,18 @@ nsSVGElement::GetAnimatedAttr(PRInt32 aN
     // We check mapped-into-style attributes first so that animations
     // targeting width/height on outer-<svg> don't appear to be ignored
     // because we returned a nsISMILAttr for the corresponding
     // SVGAnimatedLength.
 
     // Mapped attributes:
     if (IsAttributeMapped(aName)) {
       nsCSSProperty prop =
-        nsCSSProps::LookupProperty(nsDependentAtomString(aName));
+        nsCSSProps::LookupProperty(nsDependentAtomString(aName),
+                                   nsCSSProps::eEnabled);
       // Check IsPropertyAnimatable to avoid attributes that...
       //  - map to explicitly unanimatable properties (e.g. 'direction')
       //  - map to unsupported attributes (e.g. 'glyph-orientation-horizontal')
       if (nsSMILCSSProperty::IsPropertyAnimatable(prop)) {
         return new nsSMILMappedAttribute(prop, this);
       }
     }
 
--- a/content/xbl/src/nsXBLPrototypeBinding.cpp
+++ b/content/xbl/src/nsXBLPrototypeBinding.cpp
@@ -1843,22 +1843,16 @@ nsXBLPrototypeBinding::ReadContentNode(n
   if (namespaceID == kNameSpaceID_XUL) {
     nsIURI* documentURI = aDocument->GetDocumentURI();
 
     nsRefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
     NS_ENSURE_TRUE(prototype, NS_ERROR_OUT_OF_MEMORY);
 
     prototype->mNodeInfo = nodeInfo;
 
-    nsCOMPtr<Element> result;
-    nsresult rv =
-      nsXULElement::Create(prototype, aDocument, false, getter_AddRefs(result));
-    NS_ENSURE_SUCCESS(rv, rv);
-    content = result;
-
     nsXULPrototypeAttribute* attrs = nsnull;
     if (attrCount > 0) {
       attrs = new nsXULPrototypeAttribute[attrCount];
     }
 
     prototype->mAttributes = attrs;
     prototype->mNumAttributes = attrCount;
 
@@ -1887,16 +1881,22 @@ nsXBLPrototypeBinding::ReadContentNode(n
           aNim->GetNodeInfo(nameAtom, prefixAtom,
                             namespaceID, nsIDOMNode::ATTRIBUTE_NODE);
         attrs[i].mName.SetTo(ni);
       }
       
       rv = prototype->SetAttrAt(i, val, documentURI);
       NS_ENSURE_SUCCESS(rv, rv);
     }
+
+    nsCOMPtr<Element> result;
+    nsresult rv =
+      nsXULElement::Create(prototype, aDocument, false, getter_AddRefs(result));
+    NS_ENSURE_SUCCESS(rv, rv);
+    content = result;
   }
   else {
 #endif
     NS_NewElement(getter_AddRefs(content), nodeInfo.forget(), NOT_FROM_PARSER);
 
     for (PRUint32 i = 0; i < attrCount; i++) {
       rv = ReadNamespace(aStream, namespaceID);
       NS_ENSURE_SUCCESS(rv, rv);
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -1155,16 +1155,38 @@ nsXULElement::InternalGetExistingAttrNam
                 return attrName;
             }
         }
     }
 
     return nsnull;
 }
 
+const nsAttrValue*
+nsXULElement::GetAttrValue(const nsAString& aName)
+{
+  const nsAttrValue* val =
+      mAttrsAndChildren.GetAttr(aName, eCaseMatters);
+  if (val) {
+      return val;
+  }
+
+  if (mPrototype) {
+      PRUint32 i, count = mPrototype->mNumAttributes;
+      for (i = 0; i < count; ++i) {
+          nsXULPrototypeAttribute *protoAttr = &mPrototype->mAttributes[i];
+          if (protoAttr->mName.QualifiedNameEquals(aName)) {
+              return &protoAttr->mValue;
+          }
+      }
+  }
+
+  return nsnull;
+}
+
 bool
 nsXULElement::GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                       nsAString& aResult) const
 {
     NS_ASSERTION(nsnull != aName, "must have attribute name");
     NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
                  "must have a real namespace ID!");
 
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -20,17 +20,17 @@
 #include "nsIControllers.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMXULElement.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsEventListenerManager.h"
 #include "nsIRDFCompositeDataSource.h"
 #include "nsIRDFResource.h"
-#include "nsIScriptObjectOwner.h"
+#include "nsIScriptEventHandlerOwner.h"
 #include "nsBindingManager.h"
 #include "nsIURI.h"
 #include "nsIXULTemplateBuilder.h"
 #include "nsIBoxObject.h"
 #include "nsLayoutCID.h"
 #include "nsAttrAndChildArray.h"
 #include "nsGkAtoms.h"
 #include "nsAutoPtr.h"
@@ -483,16 +483,18 @@ public:
     // This function should ONLY be used by BindToTree implementations.
     // The function exists solely because XUL elements store the binding
     // parent as a member instead of in the slots, as nsGenericElement does.
     void SetXULBindingParent(nsIContent* aBindingParent)
     {
       mBindingParent = aBindingParent;
     }
 
+    const nsAttrValue* GetAttrValue(const nsAString& aName);
+
     /**
      * Get the attr info for the given namespace ID and attribute name.
      * The namespace ID must not be kNameSpaceID_Unknown and the name
      * must not be null.
      */
     virtual nsAttrInfo GetAttrInfo(PRInt32 aNamespaceID, nsIAtom* aName) const;
 
     virtual nsXPCClassInfo* GetClassInfo();
--- a/dom/alarm/AlarmService.jsm
+++ b/dom/alarm/AlarmService.jsm
@@ -76,26 +76,20 @@ let AlarmService = {
     debug("receiveMessage(): " + aMessage.name);
 
     let json = aMessage.json;
     switch (aMessage.name) {
       case "AlarmsManager:GetAll":
         this._db.getAll(
           function getAllSuccessCb(aAlarms) {
             debug("Callback after getting alarms from database: " + JSON.stringify(aAlarms));
-            ppmm.sendAsyncMessage(
-              "AlarmsManager:GetAll:Return:OK", 
-              { requestID: json.requestID, alarms: aAlarms }
-            ); 
+            this._sendAsyncMessage("GetAll:Return:OK", json.requestId, aAlarms);
           }.bind(this),
           function getAllErrorCb(aErrorMsg) {
-            ppmm.sendAsyncMessage(
-              "AlarmsManager:GetAll:Return:KO", 
-              { requestID: json.requestID, errorMsg: aErrorMsg }
-            );
+            this._sendAsyncMessage("GetAll:Return:KO", json.requestId, aErrorMsg);
           }.bind(this)
         );
         break;
 
       case "AlarmsManager:Add":
         // prepare a record for the new alarm to be added
         let newAlarm = {
           date: json.date, 
@@ -111,52 +105,48 @@ let AlarmService = {
             debug("Callback after adding alarm in database.");
 
             newAlarm['id'] = aNewId;
             let newAlarmTime = this._getAlarmTime(newAlarm);
 
             if (newAlarmTime <= Date.now()) {
               debug("Adding a alarm that has past time. Don't set it in system.");
               this._debugCurrentAlarm();
+              this._sendAsyncMessage("Add:Return:OK", json.requestId, aNewId);
               return;
             }
 
             // if there is no alarm being set in system, set the new alarm
             if (this._currentAlarm == null) {
               this._currentAlarm = newAlarm;
               this._debugCurrentAlarm();
+              this._sendAsyncMessage("Add:Return:OK", json.requestId, aNewId);
               return;
             }
 
             // if the new alarm is earlier than the current alarm
             // swap them and push the previous alarm back to queue
             let alarmQueue = this._alarmQueue;
             let currentAlarmTime = this._getAlarmTime(this._currentAlarm);
             if (newAlarmTime < currentAlarmTime) {
               alarmQueue.unshift(this._currentAlarm);
               this._currentAlarm = newAlarm;
               this._debugCurrentAlarm();
+              this._sendAsyncMessage("Add:Return:OK", json.requestId, aNewId);
               return;
             }
 
             //push the new alarm in the queue
             alarmQueue.push(newAlarm);
             alarmQueue.sort(this._sortAlarmByTimeStamps.bind(this));
             this._debugCurrentAlarm();
-
-            ppmm.sendAsyncMessage(
-              "AlarmsManager:Add:Return:OK", 
-              { requestID: json.requestID, id: aNewId }
-            );
+            this._sendAsyncMessage("Add:Return:OK", json.requestId, aNewId);
           }.bind(this),
           function addErrorCb(aErrorMsg) {
-            ppmm.sendAsyncMessage(
-              "AlarmsManager:Add:Return:KO", 
-              { requestID: json.requestID, errorMsg: aErrorMsg }
-            );
+            this._sendAsyncMessage("Add:Return:KO", json.requestId, aErrorMsg);
           }.bind(this)
         );
         break;
 
       case "AlarmsManager:Remove":
         this._db.remove(
           json.id,
           function removeSuccessCb() {
@@ -200,16 +190,44 @@ let AlarmService = {
         break;
 
       default:
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
         break;
     }
   },
 
+  _sendAsyncMessage: function _sendAsyncMessage(aMessageName, aRequestId, aData) {
+    debug("_sendAsyncMessage()");
+
+    let json = null;
+    switch (aMessageName)
+    {
+      case "Add:Return:OK":
+        json = { requestId: aRequestId, id: aData };
+        break;
+
+      case "GetAll:Return:OK":
+        json = { requestId: aRequestId, alarms: aData };
+        break;
+
+      case "Add:Return:KO":
+      case "GetAll:Return:KO":
+        json = { requestId: aRequestId, errorMsg: aData };
+        break;
+
+      default:
+        throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+        break;
+    }
+
+    if (aMessageName && json)
+      ppmm.sendAsyncMessage("AlarmsManager:" + aMessageName, json);
+  },
+
   _onAlarmFired: function _onAlarmFired() {
     debug("_onAlarmFired()");
 
     if (this._currentAlarm) {
       debug("Fire system intent: " + JSON.stringify(this._currentAlarm));
       if (this._currentAlarm.manifestURL)
         messenger.sendMessage("alarm", this._currentAlarm, this._currentAlarm.manifestURL);
       this._currentAlarm = null;
--- a/dom/alarm/AlarmsManager.js
+++ b/dom/alarm/AlarmsManager.js
@@ -58,17 +58,17 @@ AlarmsManager.prototype = {
       default:
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
         break;
     }
 
     let request = this.createRequest();
     this._cpmm.sendAsyncMessage(
       "AlarmsManager:Add", 
-      { requestID: this.getRequestId(request), date: aDate, ignoreTimezone: isIgnoreTimezone, data: aData, manifestURL: this._manifestURL }
+      { requestId: this.getRequestId(request), date: aDate, ignoreTimezone: isIgnoreTimezone, data: aData, manifestURL: this._manifestURL }
     );
     return request;
   },
 
   remove: function remove(aId) {
     debug("remove()");
 
     return this._cpmm.sendSyncMessage(
@@ -78,29 +78,29 @@ AlarmsManager.prototype = {
   },
 
   getAll: function getAll() {
     debug("getAll()");
 
     let request = this.createRequest();
     this._cpmm.sendAsyncMessage(
       "AlarmsManager:GetAll", 
-      { requestID: this.getRequestId(request) }
+      { requestId: this.getRequestId(request) }
     );
     return request;
   },
 
   receiveMessage: function receiveMessage(aMessage) {
     debug("receiveMessage(): " + aMessage.name);
 
     let json = aMessage.json;
-    let request = this.getRequest(json.requestID);
+    let request = this.getRequest(json.requestId);
 
     if (!request) {
-      debug("No request stored! " + json.requestID);
+      debug("No request stored! " + json.requestId);
       return;
     }
 
     switch (aMessage.name) {
       case "AlarmsManager:Add:Return:OK":
         Services.DOMRequest.fireSuccess(request, json.id);
         break;
 
@@ -115,17 +115,17 @@ AlarmsManager.prototype = {
       case "AlarmsManager:GetAll:Return:KO":
         Services.DOMRequest.fireError(request, json.errorMsg);
         break;
 
       default:
         debug("Wrong message: " + aMessage.name);
         break;
     }
-    this.removeRequest(json.requestID);
+    this.removeRequest(json.requestId);
    },
 
   // nsIDOMGlobalPropertyInitializer implementation
   init: function init(aWindow) {
     debug("init()");
 
     // Set navigator.mozAlarms to null.
     if (!Services.prefs.getBoolPref("dom.mozAlarms.enabled"))
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -9,16 +9,17 @@ const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 let EXPORTED_SYMBOLS = ["DOMApplicationRegistry", "DOMApplicationManifest"];
 
 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/WebappOSUtils.jsm");
 
 const WEBAPP_RUNTIME = Services.appinfo.ID == "webapprt@mozilla.org";
 
 XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
   Cu.import("resource://gre/modules/NetUtil.jsm");
   return NetUtil;
 });
 
@@ -166,17 +167,17 @@ let DOMApplicationRegistry = {
         break;
       case "Webapps:GetSelf":
         this.getSelf(msg);
         break;
       case "Webapps:Uninstall":
         this.uninstall(msg);
         break;
       case "Webapps:Launch":
-        Services.obs.notifyObservers(this, "webapps-launch", JSON.stringify(msg));
+        WebappOSUtils.launch(msg);
         break;
       case "Webapps:GetInstalled":
         this.getInstalled(msg);
         break;
       case "Webapps:GetNotInstalled":
         this.getNotInstalled(msg);
         break;
       case "Webapps:GetAll":
@@ -604,17 +605,17 @@ let DOMApplicationRegistry = {
   /** Added to support AITC and classic sync */
   itemExists: function(aId) {
     return !!this.webapps[aId];
   },
 
   getAppById: function(aId) {
     if (!this.webapps[aId])
       return null;
-    
+
     let app = this._cloneAppObject(this.webapps[aId]);
     return app;
   },
 
   getAppByManifestURL: function(aManifestURL) {
     // This could be O(1) if |webapps| was a dictionary indexed on manifestURL
     // which should be the unique app identifier.
     // It's currently O(n).
--- a/dom/base/ConsoleAPI.js
+++ b/dom/base/ConsoleAPI.js
@@ -102,29 +102,53 @@ ConsoleAPI.prototype = {
         self.queueCall("groupEnd", arguments);
       },
       time: function CA_time() {
         self.queueCall("time", arguments);
       },
       timeEnd: function CA_timeEnd() {
         self.queueCall("timeEnd", arguments);
       },
+      profile: function CA_profile() {
+        // Send a notification picked up by the profiler if installed.
+        // This must happen right away otherwise we will miss samples
+        let consoleEvent = {
+          action: "profile",
+          arguments: arguments
+        };
+        consoleEvent.wrappedJSObject = consoleEvent;
+        Services.obs.notifyObservers(consoleEvent, "console-api-profiler",
+                                     null);  
+      },
+      profileEnd: function CA_profileEnd() {
+        // Send a notification picked up by the profiler if installed.
+        // This must happen right away otherwise we will miss samples
+        let consoleEvent = {
+          action: "profileEnd",
+          arguments: arguments
+        };
+        consoleEvent.wrappedJSObject = consoleEvent;
+        Services.obs.notifyObservers(consoleEvent, "console-api-profiler",
+                                     null);  
+      },
       __exposedProps__: {
         log: "r",
         info: "r",
         warn: "r",
         error: "r",
         debug: "r",
         trace: "r",
         dir: "r",
         group: "r",
         groupCollapsed: "r",
         groupEnd: "r",
         time: "r",
-        timeEnd: "r"
+        timeEnd: "r",
+        profile: "r",
+        profileEnd: "r"
       }
     };
 
     // We need to return an actual content object here, instead of a wrapped
     // chrome object. This allows things like console.log.bind() to work.
     let contentObj = Cu.createObjectIn(aWindow);
     function genPropDesc(fun) {
       return { enumerable: true, configurable: true, writable: true,
@@ -138,16 +162,18 @@ ConsoleAPI.prototype = {
       debug: genPropDesc('debug'),
       trace: genPropDesc('trace'),
       dir: genPropDesc('dir'),
       group: genPropDesc('group'),
       groupCollapsed: genPropDesc('groupCollapsed'),
       groupEnd: genPropDesc('groupEnd'),
       time: genPropDesc('time'),
       timeEnd: genPropDesc('timeEnd'),
+      profile: genPropDesc('profile'),
+      profileEnd: genPropDesc('profileEnd'),
       __noSuchMethod__: { enumerable: true, configurable: true, writable: true,
                           value: function() {} },
       __mozillaConsole__: { value: true }
     };
 
     Object.defineProperties(contentObj, properties);
     Cu.makeObjectPropsNormal(contentObj);
 
--- a/dom/base/Makefile.in
+++ b/dom/base/Makefile.in
@@ -51,17 +51,17 @@ EXPORTS = \
   nsIDOMScriptObjectFactory.h \
   nsIJSEventListener.h \
   nsIJSNativeInitializer.h \
   nsIScriptContext.h	\
   nsIScriptExternalNameSet.h \
   nsIScriptGlobalObject.h \
   nsIScriptGlobalObjectOwner.h \
   nsIScriptNameSpaceManager.h \
-  nsIScriptObjectOwner.h \
+  nsIScriptEventHandlerOwner.h \
   nsIScriptObjectPrincipal.h \
   nsIScriptRuntime.h \
   nsIScriptTimeoutHandler.h \
   nsPIDOMWindow.h \
   nsPIWindowRoot.h \
   nsFocusManager.h \
   nsWrapperCache.h \
   nsContentPermissionHelper.h \
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -80,17 +80,17 @@
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeNode.h"
 #include "nsIScriptExternalNameSet.h"
 #include "nsJSUtils.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsScriptNameSpaceManager.h"
-#include "nsIScriptObjectOwner.h"
+#include "nsIScriptEventHandlerOwner.h"
 #include "nsIJSNativeInitializer.h"
 #include "nsJSEnvironment.h"
 
 // DOM base includes
 #include "nsIDOMPluginArray.h"
 #include "nsIDOMPlugin.h"
 #include "nsIDOMMimeTypeArray.h"
 #include "nsIDOMMimeType.h"
@@ -604,17 +604,19 @@ static const char kDOMStringBundleURL[] 
 #define EVENTTARGET_SCRIPTABLE_FLAGS                                          \
   (DOM_DEFAULT_SCRIPTABLE_FLAGS       |                                       \
    nsIXPCScriptable::WANT_ADDPROPERTY)
 
 #define IDBEVENTTARGET_SCRIPTABLE_FLAGS                                       \
   (EVENTTARGET_SCRIPTABLE_FLAGS)
 
 #define DOMCLASSINFO_STANDARD_FLAGS                                           \
-  (nsIClassInfo::MAIN_THREAD_ONLY | nsIClassInfo::DOM_OBJECT)
+  (nsIClassInfo::MAIN_THREAD_ONLY |                                           \
+   nsIClassInfo::DOM_OBJECT       |                                           \
+   nsIClassInfo::SINGLETON_CLASSINFO)
 
 
 #ifdef DEBUG
 #define NS_DEFINE_CLASSINFO_DATA_DEBUG(_class)                                \
     eDOMClassInfo_##_class##_id,
 #else
 #define NS_DEFINE_CLASSINFO_DATA_DEBUG(_class)                                \
   // nothing
@@ -4780,16 +4782,24 @@ nsDOMClassInfo::PostCreate(nsIXPConnectW
                            JSContext *cx, JSObject *obj)
 {
   NS_WARNING("nsDOMClassInfo::PostCreate Don't call me!");
 
   return NS_ERROR_UNEXPECTED;
 }
 
 NS_IMETHODIMP
+nsDOMClassInfo::PostTransplant(nsIXPConnectWrappedNative *wrapper,
+                               JSContext *cx, JSObject *obj)
+{
+  MOZ_NOT_REACHED("nsDOMClassInfo::PostTransplant Don't call me!");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDOMClassInfo::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                             JSObject *obj, jsid id, jsval *vp,
                             bool *_retval)
 {
   NS_WARNING("nsDOMClassInfo::AddProperty Don't call me!");
 
   return NS_ERROR_UNEXPECTED;
 }
@@ -5784,33 +5794,16 @@ BaseStubConstructor(nsIWeakReference* aW
 
         if (!ret) {
           return NS_ERROR_FAILURE;
         }
       }
     }
   }
 
-  nsCOMPtr<nsIScriptObjectOwner> owner(do_QueryInterface(native));
-  if (owner) {
-    nsIScriptContext *context = nsJSUtils::GetStaticScriptContext(cx, obj);
-    if (!context) {
-      return NS_ERROR_UNEXPECTED;
-    }
-
-    JSObject* new_obj;
-    rv = owner->GetScriptObject(context, (void**)&new_obj);
-
-    if (NS_SUCCEEDED(rv)) {
-      *rval = OBJECT_TO_JSVAL(new_obj);
-    }
-
-    return rv;
-  }
-
   return WrapNative(cx, obj, native, true, rval);
 }
 
 static nsresult
 DefineInterfaceConstants(JSContext *cx, JSObject *obj, const nsIID *aIID)
 {
   nsCOMPtr<nsIInterfaceInfoManager>
     iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
@@ -6935,33 +6928,20 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
       return NS_OK;
 
     nsCOMPtr<nsISupports> native(do_CreateInstance(name_struct->mCID, &rv));
     NS_ENSURE_SUCCESS(rv, rv);
 
     jsval prop_val = JSVAL_VOID; // Property value.
 
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-    nsCOMPtr<nsIScriptObjectOwner> owner(do_QueryInterface(native));
-    if (owner) {
-      nsIScriptContext *context = nsJSUtils::GetStaticScriptContext(cx, obj);
-      NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
-
-      JSObject *prop_obj = nsnull;
-      rv = owner->GetScriptObject(context, (void**)&prop_obj);
-      NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && prop_obj, NS_ERROR_UNEXPECTED);
-
-      prop_val = OBJECT_TO_JSVAL(prop_obj);
-    } else {
-      nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi(do_QueryInterface(native));
-
-      if (gpi) {
-        rv = gpi->Init(aWin, &prop_val);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
+    nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi(do_QueryInterface(native));
+    if (gpi) {
+      rv = gpi->Init(aWin, &prop_val);
+      NS_ENSURE_SUCCESS(rv, rv);
     }
 
     if (JSVAL_IS_PRIMITIVE(prop_val) && !JSVAL_IS_NULL(prop_val)) {
       JSObject *scope;
 
       if (aWin->IsOuterWindow()) {
         nsGlobalWindow *inner = aWin->GetCurrentInnerWindowInternal();
         NS_ENSURE_TRUE(inner, NS_ERROR_UNEXPECTED);
@@ -8190,16 +8170,25 @@ nsElementSH::PostCreate(nsIXPConnectWrap
       nsContentUtils::AddScriptRunner(
         NS_NewRunnableMethod(binding, &nsXBLBinding::ExecuteAttachedHandler));
     }
   }
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsElementSH::PostTransplant(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
+                            JSObject *obj)
+{
+  // XBL bindings are reapplied asynchronously when the node is inserted into a
+  // new document and frame construction occurs.
+  return NS_OK;
+}
+
 
 // Generic array scriptable helper.
 
 NS_IMETHODIMP
 nsGenericArraySH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                              JSObject *obj, jsid id, PRUint32 flags,
                              JSObject **objp, bool *_retval)
 {
@@ -8733,16 +8722,24 @@ nsDocumentSH::PostCreate(nsIXPConnectWra
                                JS_PropertyStub, JS_StrictPropertyStub,
                                JSPROP_READONLY | JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
   }
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDocumentSH::PostTransplant(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
+                             JSObject *obj)
+{
+  // Nothing to do here.
+  return NS_OK;
+}
+
 // HTMLDocument helper
 
 static nsresult
 ResolveImpl(JSContext *cx, nsIXPConnectWrappedNative *wrapper, jsid id,
             nsISupports **result, nsWrapperCache **aCache)
 {
   nsHTMLDocument *doc =
     static_cast<nsHTMLDocument*>(static_cast<nsINode*>(wrapper->Native()));
@@ -9857,16 +9854,30 @@ nsHTMLPluginObjElementSH::PostCreate(nsI
   nsRefPtr<nsPluginProtoChainInstallRunner> runner =
     new nsPluginProtoChainInstallRunner(wrapper, scriptContext);
   nsContentUtils::AddScriptRunner(runner);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsHTMLPluginObjElementSH::PostTransplant(nsIXPConnectWrappedNative *wrapper,
+                                         JSContext *cx, JSObject *obj)
+{
+  // Call through to PostCreate to do the prototype setup all over again. We
+  // may reuse the same prototype, in which case our prototype will be a wrapped
+  // version of the original.
+  nsresult rv = PostCreate(wrapper, cx, obj);
+  if (NS_FAILED(rv)) {
+      NS_WARNING("Calling PostCreate during PostTransplant for plugin element failed.");
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsHTMLPluginObjElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
                                       JSContext *cx, JSObject *obj, jsid id,
                                       jsval *vp, bool *_retval)
 {
   JSAutoRequest ar(cx);
 
   JSObject *pi_obj = ::JS_GetPrototype(obj);
   if (NS_UNLIKELY(!pi_obj)) {
@@ -10668,17 +10679,17 @@ nsDOMConstructorSH::HasInstance(nsIXPCon
 }
 
 NS_IMETHODIMP
 nsNonDOMObjectSH::GetFlags(PRUint32 *aFlags)
 {
   // This is NOT a DOM Object.  Use this helper class for cases when you need
   // to do something like implement nsISecurityCheckedComponent in a meaningful
   // way.
-  *aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
+  *aFlags = nsIClassInfo::MAIN_THREAD_ONLY | nsIClassInfo::SINGLETON_CLASSINFO;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAttributeSH::GetFlags(PRUint32 *aFlags)
 {
   // Just like nsNodeSH, but without CONTENT_NODE
   *aFlags = DOMCLASSINFO_STANDARD_FLAGS;
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -557,16 +557,18 @@ protected:
   {
   }
 
 public:
   NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
                        JSObject *globalObj, JSObject **parentObj);
   NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj);
+  NS_IMETHOD PostTransplant(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
+                            JSObject *obj);
 
   static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
   {
     return new nsElementSH(aData);
   }
 };
 
 
@@ -744,16 +746,18 @@ public:
 public:
   NS_IMETHOD PostCreatePrototype(JSContext * cx, JSObject * proto);
   NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj, jsid id, PRUint32 flags,
                         JSObject **objp, bool *_retval);
   NS_IMETHOD GetFlags(PRUint32* aFlags);
   NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj);
+  NS_IMETHOD  PostTransplant(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
+                             JSObject *obj);
 
   static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
   {
     return new nsDocumentSH(aData);
   }
 };
 
 
@@ -898,16 +902,18 @@ protected:
 public:
   NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj, jsid id, PRUint32 flags,
                         JSObject **objp, bool *_retval);
   NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
                        JSObject *globalObj, JSObject **parentObj);
   NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj);
+  NS_IMETHOD PostTransplant(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
+                            JSObject *obj);
   NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                          JSObject *obj, jsid id, jsval *vp, bool *_retval);
   NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                          JSObject *obj, jsid id, jsval *vp, bool *_retval);
   NS_IMETHOD Call(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                   JSObject *obj, PRUint32 argc, jsval *argv, jsval *vp,
                   bool *_retval);
 
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2021,17 +2021,18 @@ nsDOMWindowUtils::ComputeAnimationDistan
   }
 
   nsresult rv;
   nsCOMPtr<nsIContent> content = do_QueryInterface(aElement, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Convert direction-dependent properties as appropriate, e.g.,
   // border-left to border-left-value.
-  nsCSSProperty property = nsCSSProps::LookupProperty(aProperty);
+  nsCSSProperty property = nsCSSProps::LookupProperty(aProperty,
+                                                      nsCSSProps::eAny);
   if (property != eCSSProperty_UNKNOWN && nsCSSProps::IsShorthand(property)) {
     nsCSSProperty subprop0 = *nsCSSProps::SubpropertyEntryFor(property);
     if (nsCSSProps::PropHasFlags(subprop0, CSS_PROPERTY_REPORT_OTHER_NAME) &&
         nsCSSProps::OtherNameFor(subprop0) == property) {
       property = subprop0;
     } else {
       property = eCSSProperty_UNKNOWN;
     }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -4481,19 +4481,25 @@ nsGlobalWindow::SetFullScreenInternal(bo
   if (aFullScreen && xulWin) {
     xulWin->SetIntrinsicallySized(false);
   }
 
   // Set this before so if widget sends an event indicating its
   // gone full screen, the state trap above works.
   mFullScreen = aFullScreen;
 
-  nsCOMPtr<nsIWidget> widget = GetMainWidget();
-  if (widget)
-    widget->MakeFullScreen(aFullScreen);
+  // Sometimes we don't want the top-level widget to actually go fullscreen,
+  // for example in the B2G desktop client, we don't want the emulated screen
+  // dimensions to appear to increase when entering fullscreen mode; we just
+  // want the content to fill the entire client area of the emulator window.
+  if (!Preferences::GetBool("full-screen-api.ignore-widgets", false)) {
+    nsCOMPtr<nsIWidget> widget = GetMainWidget();
+    if (widget)
+      widget->MakeFullScreen(aFullScreen);
+  }
 
   if (!mFullScreen) {
     // Force exit from DOM full-screen mode. This is so that if we're in
     // DOM full-screen mode and the user exits full-screen mode with
     // the browser full-screen mode toggle keyboard-shortcut, we'll detect
     // that and leave DOM API full-screen mode too.
     nsIDocument::ExitFullScreen(false);
   }
@@ -8467,22 +8473,25 @@ private:
   PRUint32 mTimeInS;
   nsRefPtr<nsGlobalWindow> mIdleWindow;
 
   // If false then call on active
   bool mCallOnidle;
 };
 
 void
-nsGlobalWindow::NotifyIdleObserver(nsIIdleObserver* aIdleObserver,
-                                   PRUint32 aIdleObserverTimeInS,
+nsGlobalWindow::NotifyIdleObserver(IdleObserverHolder* aIdleObserverHolder,
                                    bool aCallOnidle)
 {
+  MOZ_ASSERT(aIdleObserverHolder);
+  aIdleObserverHolder->mPrevNotificationIdle = aCallOnidle;
+
   nsCOMPtr<nsIRunnable> caller =
-    new NotifyIdleObserverRunnable(aIdleObserver, aIdleObserverTimeInS,
+    new NotifyIdleObserverRunnable(aIdleObserverHolder->mIdleObserver,
+                                   aIdleObserverHolder->mTimeInS,
                                    aCallOnidle, this);
   if (NS_FAILED(NS_DispatchToCurrentThread(caller))) {
     NS_WARNING("Failed to dispatch thread for idle observer notification.");
   }
 }
 
 bool
 nsGlobalWindow::ContainsIdleObserver(nsIIdleObserver* aIdleObserver, PRUint32 aTimeInS)
@@ -8501,38 +8510,35 @@ nsGlobalWindow::ContainsIdleObserver(nsI
   return found;
 }
 
 void
 IdleActiveTimerCallback(nsITimer* aTimer, void* aClosure)
 {
   nsRefPtr<nsGlobalWindow> idleWindow = static_cast<nsGlobalWindow*>(aClosure);
   MOZ_ASSERT(idleWindow, "Idle window has not been instantiated.");
-  idleWindow->NotifyIdleObserversOfIdleActiveEvent();
+  idleWindow->HandleIdleActiveEvent();
 }
 
 void
 IdleObserverTimerCallback(nsITimer* aTimer, void* aClosure)
 {
   nsRefPtr<nsGlobalWindow> idleWindow = static_cast<nsGlobalWindow*>(aClosure);
   MOZ_ASSERT(idleWindow, "Idle window has not been instantiated.");
   idleWindow->HandleIdleObserverCallback();
 }
 
 void
 nsGlobalWindow::HandleIdleObserverCallback()
 {
   MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
   MOZ_ASSERT(static_cast<PRUint32>(mIdleCallbackIndex) < mIdleObservers.Length(),
                                   "Idle callback index exceeds array bounds!");
-  IdleObserverHolder idleObserver =
-             mIdleObservers.ElementAt(mIdleCallbackIndex);
-  NotifyIdleObserver(idleObserver.mIdleObserver,
-                     idleObserver.mTimeInS,
-                     true);
+  IdleObserverHolder& idleObserver = mIdleObservers.ElementAt(mIdleCallbackIndex);
+  NotifyIdleObserver(&idleObserver, true);
   mIdleCallbackIndex++;
   if (NS_FAILED(ScheduleNextIdleObserverCallback())) {
     NS_WARNING("Failed to set next idle observer callback.");
   }
 }
 
 nsresult
 nsGlobalWindow::ScheduleNextIdleObserverCallback()
@@ -8579,47 +8585,45 @@ nsGlobalWindow::GetFuzzTimeMS()
   PRUint32 randNum = MAX_IDLE_FUZZ_TIME_MS;
   PRSize nbytes = PR_GetRandomNoise(&randNum, sizeof(randNum));
   if (nbytes != sizeof(randNum)) {
     NS_WARNING("PR_GetRandomNoise(...) Not implemented or no available noise!");
     return MAX_IDLE_FUZZ_TIME_MS;
   }
 
   if (randNum > MAX_IDLE_FUZZ_TIME_MS) {
-    (randNum) %= MAX_IDLE_FUZZ_TIME_MS;
+    randNum %= MAX_IDLE_FUZZ_TIME_MS;
   }
 
   return randNum;
 }
 
 nsresult
 nsGlobalWindow::ScheduleActiveTimerCallback()
 {
   MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 
   if (!mAddActiveEventFuzzTime) {
-    return NotifyIdleObserversOfIdleActiveEvent();
-  }
-
-  nsRefPtr<nsGlobalWindow> kungFuDeathGrip(this);
+    return HandleIdleActiveEvent();
+  }
 
   MOZ_ASSERT(mIdleTimer);
   mIdleTimer->Cancel();
 
   PRUint32 fuzzFactorInMS = GetFuzzTimeMS();
   nsresult rv = mIdleTimer->InitWithFuncCallback(IdleActiveTimerCallback,
                                                  this,
                                                  fuzzFactorInMS,
                                                  nsITimer::TYPE_ONE_SHOT);
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 nsresult
-nsGlobalWindow::NotifyIdleObserversOfIdleActiveEvent()
+nsGlobalWindow::HandleIdleActiveEvent()
 {
   MOZ_ASSERT(IsInnerWindow(), "Must be an inner window!");
 
   if (mCurrentlyIdle) {
     mIdleCallbackIndex = 0;
     mIdleFuzzFactor = GetFuzzTimeMS();
     nsresult rv = ScheduleNextIdleObserverCallback();
     NS_ENSURE_SUCCESS(rv, rv);
@@ -8627,17 +8631,19 @@ nsGlobalWindow::NotifyIdleObserversOfIdl
   }
 
   mIdleCallbackIndex = -1;
   MOZ_ASSERT(mIdleTimer);
   mIdleTimer->Cancel();
   nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers);
   while (iter.HasMore()) {
     IdleObserverHolder& idleObserver = iter.GetNext();
-    NotifyIdleObserver(idleObserver.mIdleObserver, idleObserver.mTimeInS, false);
+    if (idleObserver.mPrevNotificationIdle) {
+      NotifyIdleObserver(&idleObserver, false);
+    }
   }
 
   return NS_OK;
 }
 
 PRUint32
 nsGlobalWindow::FindInsertionIndex(IdleObserverHolder* aIdleObserver)
 {
@@ -8709,19 +8715,18 @@ nsGlobalWindow::RegisterIdleObserver(nsI
 
   if (!mCurrentlyIdle) {
     return NS_OK;
   }
 
   MOZ_ASSERT(mIdleCallbackIndex >= 0);
 
   if (static_cast<PRInt32>(insertAtIndex) < mIdleCallbackIndex) {
-    NotifyIdleObserver(tmpIdleObserver.mIdleObserver,
-                       tmpIdleObserver.mTimeInS,
-                       true);
+    IdleObserverHolder& idleObserver = mIdleObservers.ElementAt(insertAtIndex);
+    NotifyIdleObserver(&idleObserver, true);
     mIdleCallbackIndex++;
     return NS_OK;
   }
 
   if (static_cast<PRInt32>(insertAtIndex) == mIdleCallbackIndex) {
     mIdleTimer->Cancel();
     rv = ScheduleNextIdleObserverCallback();
     NS_ENSURE_SUCCESS(rv, rv);
@@ -8791,18 +8796,16 @@ nsGlobalWindow::UnregisterIdleObserver(n
     mIdleCallbackIndex--;
     return NS_OK;
   }
 
   if (removeElementIndex != mIdleCallbackIndex) {
     return NS_OK;
   }
 
-  nsRefPtr<nsGlobalWindow> kungFuDeathGrip(this);
-
   mIdleTimer->Cancel();
 
   // If the last element in the array had been notified then decrement
   // mIdleCallbackIndex because an idle was removed from the list of
   // idle observers.
   // Example: add idle observer with time 1, 2, 3,
   // Idle notifications for idle observers with time 1, 2, 3 are complete
   // Remove idle observer with time 3 while the user is still idle.
@@ -8834,17 +8837,17 @@ nsGlobalWindow::Observe(nsISupports* aSu
 
   if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_IDLE)) {
     mCurrentlyIdle = true;
     if (IsFrozen()) {
       // need to fire only one idle event while the window is frozen.
       mNotifyIdleObserversIdleOnThaw = true;
       mNotifyIdleObserversActiveOnThaw = false;
     } else if (mOuterWindow && mOuterWindow->GetCurrentInnerWindow() == this) {
-      NotifyIdleObserversOfIdleActiveEvent();
+      HandleIdleActiveEvent();
     }
     return NS_OK;
   }
 
   if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_ACTIVE)) {
     mCurrentlyIdle = false;
     if (IsFrozen()) {
       mNotifyIdleObserversActiveOnThaw = true;
@@ -9020,17 +9023,17 @@ nsGlobalWindow::FireDelayedDOMEvents()
 
   if (mFireOfflineStatusChangeEventOnThaw) {
     mFireOfflineStatusChangeEventOnThaw = false;
     FireOfflineStatusEvent();
   }
 
   if (mNotifyIdleObserversIdleOnThaw) {
     mNotifyIdleObserversIdleOnThaw = false;
-    NotifyIdleObserversOfIdleActiveEvent();    
+    HandleIdleActiveEvent();
   }
 
   if (mNotifyIdleObserversActiveOnThaw) {
     mNotifyIdleObserversActiveOnThaw = false;
     ScheduleActiveTimerCallback();
   }
 
   nsCOMPtr<nsIDocShellTreeNode> node =
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -202,33 +202,35 @@ private:
   // reference count for shared usage
   nsAutoRefCnt mRefCnt;
 };
 
 struct IdleObserverHolder
 {
   nsCOMPtr<nsIIdleObserver> mIdleObserver;
   PRUint32 mTimeInS;
+  bool mPrevNotificationIdle;
 
   IdleObserverHolder()
-    : mTimeInS(0)
+    : mTimeInS(0), mPrevNotificationIdle(false)
   {
     MOZ_COUNT_CTOR(IdleObserverHolder);
   }
 
-  IdleObserverHolder(const IdleObserverHolder& aOtherIdleObserver)
-    : mIdleObserver(aOtherIdleObserver.mIdleObserver), mTimeInS(aOtherIdleObserver.mTimeInS)
+  IdleObserverHolder(const IdleObserverHolder& aOther)
+    : mIdleObserver(aOther.mIdleObserver), mTimeInS(aOther.mTimeInS),
+      mPrevNotificationIdle(aOther.mPrevNotificationIdle)
   {
     MOZ_COUNT_CTOR(IdleObserverHolder);
   }
 
-  bool operator==(const IdleObserverHolder& aOtherIdleObserver) const {
+  bool operator==(const IdleObserverHolder& aOther) const {
     return
-      mIdleObserver == aOtherIdleObserver.mIdleObserver &&
-      mTimeInS == aOtherIdleObserver.mTimeInS;
+      mIdleObserver == aOther.mIdleObserver &&
+      mTimeInS == aOther.mTimeInS;
   }
 
   ~IdleObserverHolder()
   {
     MOZ_COUNT_DTOR(IdleObserverHolder);
   }
 };
 
@@ -578,20 +580,19 @@ public:
 
   void SizeOfIncludingThis(nsWindowSizes* aWindowSizes) const;
 
   void UnmarkGrayTimers();