Merge last PGO-green changeset of mozilla-inbound to mozilla-central
authorEd Morley <bmo@edmorley.co.uk>
Tue, 21 Feb 2012 11:59:33 +0000
changeset 90147 4038ffaa5d820b7ee60db411517f6d3179e17f4f
parent 90098 8822243a8d6c8aabbf7846a43f8b5f765b454961 (current diff)
parent 90146 027f56e65a84cba315935f13c9a71edf6214edc0 (diff)
child 90148 7dcbce54a953090ae8e537f93c6c99ab8eb0dc62
child 90169 cb3d33c37bda18cf7f2b62e172ece51b1373b1b1
child 90189 b53f2d313802c89ed771f8b0bf905692fe2e543a
push idunknown
push userunknown
push dateunknown
milestone13.0a1
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
config/autoconf.mk.in
configure.in
content/base/src/nsXMLHttpRequest.cpp
gfx/src/nsSystemFontsAndroid.cpp
gfx/src/nsSystemFontsAndroid.h
gfx/src/nsSystemFontsGTK2.cpp
gfx/src/nsSystemFontsGTK2.h
gfx/src/nsSystemFontsMac.h
gfx/src/nsSystemFontsMac.mm
gfx/src/nsSystemFontsOS2.cpp
gfx/src/nsSystemFontsOS2.h
gfx/src/nsSystemFontsQt.cpp
gfx/src/nsSystemFontsQt.h
gfx/src/nsSystemFontsWin.cpp
gfx/src/nsSystemFontsWin.h
intl/unicharutil/src/nsUnicodeNormalizer.h
js/src/jsweakmap.cpp
testing/peptest/tests/firefox/examples/example_tests.ini
testing/peptest/tests/firefox/examples/test_contextMenu.js
testing/peptest/tests/firefox/examples/test_openBlankTab.js
testing/peptest/tests/firefox/examples/test_openBookmarksMenu.js
testing/peptest/tests/firefox/examples/test_openWindow.js
testing/peptest/tests/firefox/examples/test_resizeWindow.js
testing/peptest/tests/firefox/examples/test_searchGoogle.js
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -71,16 +71,17 @@ CPPSRCS = \
   nsEventShell.cpp \
   nsFormControlAccessible.cpp \
   nsRootAccessible.cpp \
   nsApplicationAccessible.cpp \
   nsCaretAccessible.cpp \
   nsTextAccessible.cpp \
   nsTextEquivUtils.cpp \
   nsTextAttrs.cpp \
+  StyleInfo.cpp \
   TextUpdater.cpp \
   $(NULL)
 
 EXPORTS = \
   a11yGeneric.h \
   nsAccDocManager.h \
   nsAccessibilityService.h \
   nsAccessible.h \
@@ -102,16 +103,17 @@ FORCE_STATIC_LIB = 1
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
   -I$(srcdir)/../xpcom \
   -I$(srcdir)/../html \
   -I$(srcdir)/../xul \
   -I$(srcdir)/../../../layout/generic \
+  -I$(srcdir)/../../../layout/style \
   -I$(srcdir)/../../../layout/xul/base/src \
   -I$(srcdir)/../xforms \
   $(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 LOCAL_INCLUDES += \
   -I$(srcdir)/../atk \
   $(NULL)
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/StyleInfo.cpp
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Alexander Surkov <surkov.alexander@gmail.com> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "StyleInfo.h"
+
+#include "mozilla/dom/Element.h"
+#include "nsComputedDOMStyle.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+StyleInfo::StyleInfo(dom::Element* aElement, nsIPresShell* aPresShell) :
+  mElement(aElement)
+{
+  mStyleContext =
+    nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement,
+                                                         nsnull,
+                                                         aPresShell);
+}
+
+void
+StyleInfo::Display(nsAString& aValue)
+{
+  aValue.Truncate();
+  AppendASCIItoUTF16(
+    nsCSSProps::ValueToKeyword(mStyleContext->GetStyleDisplay()->mDisplay,
+                               nsCSSProps::kDisplayKTable), aValue);
+}
+
+void
+StyleInfo::TextAlign(nsAString& aValue)
+{
+  aValue.Truncate();
+  AppendASCIItoUTF16(
+    nsCSSProps::ValueToKeyword(mStyleContext->GetStyleText()->mTextAlign,
+                               nsCSSProps::kTextAlignKTable), aValue);
+}
+
+void
+StyleInfo::TextIndent(nsAString& aValue)
+{
+  aValue.Truncate();
+
+  const nsStyleCoord& styleCoord =
+    mStyleContext->GetStyleText()->mTextIndent;
+
+  nscoord coordVal;
+  switch (styleCoord.GetUnit()) {
+    case eStyleUnit_Coord:
+      coordVal = styleCoord.GetCoordValue();
+      break;
+
+    case eStyleUnit_Percent:
+    {
+      nsIFrame* frame = mElement->GetPrimaryFrame();
+      nsIFrame* containerFrame = frame->GetContainingBlock();
+      nscoord percentageBase = containerFrame->GetContentRect().width;
+      coordVal = NSCoordSaturatingMultiply(percentageBase,
+                                           styleCoord.GetPercentValue());
+      break;
+    }
+  }
+
+  aValue.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(coordVal));
+  aValue.AppendLiteral("px");
+}
+
+void
+StyleInfo::Margin(css::Side aSide, nsAString& aValue)
+{
+  aValue.Truncate();
+
+  nscoord coordVal = mElement->GetPrimaryFrame()->GetUsedMargin().Side(aSide);
+  aValue.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(coordVal));
+  aValue.AppendLiteral("px");
+}
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/StyleInfo.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Alexander Surkov <surkov.alexander@gmail.com> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _mozilla_a11y_style_h_
+#define _mozilla_a11y_style_h_
+
+#include "mozilla/gfx/Types.h"
+#include "nsStyleContext.h"
+
+namespace mozilla {
+namespace a11y {
+
+class StyleInfo
+{
+public:
+  StyleInfo(dom::Element* aElement, nsIPresShell* aPresShell);
+  ~StyleInfo() { };
+
+  void Display(nsAString& aValue);
+  void TextAlign(nsAString& aValue);
+  void TextIndent(nsAString& aValue);
+  void MarginLeft(nsAString& aValue) { Margin(css::eSideLeft, aValue); }
+  void MarginRight(nsAString& aValue) { Margin(css::eSideRight, aValue); }
+  void MarginTop(nsAString& aValue) { Margin(css::eSideTop, aValue); }
+  void MarginBottom(nsAString& aValue) { Margin(css::eSideBottom, aValue); }
+
+private:
+  StyleInfo() MOZ_DELETE;
+  StyleInfo(const StyleInfo&) MOZ_DELETE;
+  StyleInfo& operator = (const StyleInfo&) MOZ_DELETE;
+
+  void Margin(css::Side aSide, nsAString& aValue);
+
+  dom::Element* mElement;
+  nsRefPtr<nsStyleContext> mStyleContext;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -39,29 +39,28 @@
 
 #include "nsAccessible.h"
 
 #include "nsIXBLAccessible.h"
 
 #include "AccGroupInfo.h"
 #include "AccIterator.h"
 #include "nsAccUtils.h"
-#include "nsDocAccessible.h"
-#include "nsEventShell.h"
-
 #include "nsAccEvent.h"
 #include "nsAccessibleRelation.h"
 #include "nsAccessibilityService.h"
 #include "nsAccTreeWalker.h"
 #include "nsIAccessibleRelation.h"
+#include "nsEventShell.h"
 #include "nsRootAccessible.h"
 #include "nsTextEquivUtils.h"
 #include "Relation.h"
 #include "Role.h"
 #include "States.h"
+#include "StyleInfo.h"
 
 #include "nsIDOMCSSValue.h"
 #include "nsIDOMCSSPrimitiveValue.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentXBL.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLFormElement.h"
@@ -1437,59 +1436,50 @@ nsAccessible::GetAttributesInternal(nsIP
 
     nsIDocument *parentDoc = doc->GetParentDocument();
     if (!parentDoc)
       break;
 
     startContent = parentDoc->FindContentForSubDocument(doc);      
   }
 
-  // Expose 'display' attribute.
+  if (!mContent->IsElement())
+    return NS_OK;
+
+  // CSS style based object attributes.
   nsAutoString value;
-  nsresult rv = GetComputedStyleValue(EmptyString(),
-                                      NS_LITERAL_STRING("display"),
-                                      value);
-  if (NS_SUCCEEDED(rv))
-    nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::display, value);
+  StyleInfo styleInfo(mContent->AsElement(), mDoc->PresShell());
+
+  // Expose 'display' attribute.
+  styleInfo.Display(value);
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::display, value);
 
   // Expose 'text-align' attribute.
-  rv = GetComputedStyleValue(EmptyString(), NS_LITERAL_STRING("text-align"),
-                             value);
-  if (NS_SUCCEEDED(rv))
-    nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::textAlign, value);
+  styleInfo.TextAlign(value);
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::textAlign, value);
 
   // Expose 'text-indent' attribute.
-  rv = GetComputedStyleValue(EmptyString(), NS_LITERAL_STRING("text-indent"),
-                             value);
-  if (NS_SUCCEEDED(rv))
-    nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::textIndent, value);
+  styleInfo.TextIndent(value);
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::textIndent, value);
 
   // Expose 'margin-left' attribute.
-  rv = GetComputedStyleValue(EmptyString(), NS_LITERAL_STRING("margin-left"),
-                             value);
-  if (NS_SUCCEEDED(rv))
-    nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::marginLeft, value);
+  styleInfo.MarginLeft(value);
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::marginLeft, value);
 
   // Expose 'margin-right' attribute.
-  rv = GetComputedStyleValue(EmptyString(), NS_LITERAL_STRING("margin-right"),
-                             value);
-  if (NS_SUCCEEDED(rv))
-    nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::marginRight, value);
+  styleInfo.MarginRight(value);
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::marginRight, value);
 
   // Expose 'margin-top' attribute.
-  rv = GetComputedStyleValue(EmptyString(), NS_LITERAL_STRING("margin-top"),
-                             value);
-  if (NS_SUCCEEDED(rv))
-    nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::marginTop, value);
+  styleInfo.MarginTop(value);
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::marginTop, value);
 
   // Expose 'margin-bottom' attribute.
-  rv = GetComputedStyleValue(EmptyString(), NS_LITERAL_STRING("margin-bottom"),
-                             value);
-  if (NS_SUCCEEDED(rv))
-    nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::marginBottom, value);
+  styleInfo.MarginBottom(value);
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::marginBottom, value);
 
   // Expose draggable object attribute?
   nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(mContent);
   if (htmlElement) {
     bool draggable = false;
     htmlElement->GetDraggable(&draggable);
     if (draggable) {
       nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::draggable,
--- a/accessible/tests/mochitest/attributes.js
+++ b/accessible/tests/mochitest/attributes.js
@@ -23,16 +23,36 @@ function testAttrs(aAccOrElmOrID, aAttrs
  *                              present (name/value pairs)
  */
 function testAbsentAttrs(aAccOrElmOrID, aAbsentAttrs)
 {
   testAttrsInternal(aAccOrElmOrID, {}, true, aAbsentAttrs);
 }
 
 /**
+ * Test CSS based object attributes.
+ */
+function testCSSAttrs(aID)
+{
+  var node = document.getElementById(aID);
+  var computedStyle = document.defaultView.getComputedStyle(node, "");
+
+  var attrs = {
+    "display": computedStyle.display,
+    "text-align": computedStyle.textAlign,
+    "text-indent": computedStyle.textIndent,
+    "margin-left": computedStyle.marginLeft,
+    "margin-right": computedStyle.marginRight,
+    "margin-top": computedStyle.marginTop,
+    "margin-bottom": computedStyle.marginBottom
+  };
+  testAttrs(aID, attrs, true);
+}
+
+/**
  * Test group object attributes (posinset, setsize and level) and
  * nsIAccessible::groupPosition() method.
  *
  * @param aAccOrElmOrID  [in] the ID, DOM node or accessible
  * @param aPosInSet      [in] the value of 'posinset' attribute
  * @param aSetSize       [in] the value of 'setsize' attribute
  * @param aLevel         [in, optional] the value of 'level' attribute
  */
--- a/accessible/tests/mochitest/attributes/Makefile.in
+++ b/accessible/tests/mochitest/attributes/Makefile.in
@@ -43,16 +43,17 @@ VPATH		= @srcdir@
 relativesrcdir  = accessible/attributes
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES =\
 		test_obj.html \
 		test_obj_css.html \
+		test_obj_css.xul \
 		test_obj_group.html \
 		test_obj_group.xul \
 		test_obj_group_tree.xul \
 		test_text.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)
--- a/accessible/tests/mochitest/attributes/test_obj_css.html
+++ b/accessible/tests/mochitest/attributes/test_obj_css.html
@@ -13,46 +13,75 @@ https://bugzilla.mozilla.org/show_bug.cg
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../attributes.js"></script>
 
   <script type="application/javascript">
-    function testCSSAttrs(aID)
-    {
-      var node = document.getElementById(aID);
-      var computedStyle = document.defaultView.getComputedStyle(node, "");
-
-      var attrs = {
-        "display": computedStyle.display,
-        "text-align": computedStyle.textAlign,
-        "text-indent": computedStyle.textIndent,
-        "margin-left": computedStyle.marginLeft,
-        "margin-right": computedStyle.marginRight,
-        "margin-top": computedStyle.marginTop,
-        "margin-bottom": computedStyle.marginBottom
-      };
-      testAttrs(aID, attrs, true);
-    }
-
     function doTest()
     {
+      // CSS display
+      testCSSAttrs("display_block");
+      testCSSAttrs("display_inline");
+      testCSSAttrs("display_inline-block");
+      testCSSAttrs("display_list-item");
+      testCSSAttrs("display_table");
+      testCSSAttrs("display_inline-table");
+      testCSSAttrs("display_table-row-group");
+      testCSSAttrs("display_table-column");
+      testCSSAttrs("display_table-column-group");
+      testCSSAttrs("display_table-header-group");
+      testCSSAttrs("display_table-footer-group");
+      testCSSAttrs("display_table-row");
+      testCSSAttrs("display_table-cell");
+      testCSSAttrs("display_table-caption");
+
+      // CSS text-align
+      testCSSAttrs("text-align_left");
+      testCSSAttrs("text-align_right");
+      testCSSAttrs("text-align_center");
+      testCSSAttrs("text-align_justify");
+      testCSSAttrs("text-align_inherit");
+
+      // CSS text-indent
+      testCSSAttrs("text-indent_em");
+      testCSSAttrs("text-indent_ex");
+      testCSSAttrs("text-indent_in");
+      testCSSAttrs("text-indent_cm");
+      testCSSAttrs("text-indent_mm");
+      testCSSAttrs("text-indent_pt");
+      testCSSAttrs("text-indent_pc");
+      testCSSAttrs("text-indent_px");
+      testCSSAttrs("text-indent_percent");
+      testCSSAttrs("text-indent_inherit");
+
+      // CSS margin
+      testCSSAttrs("margin_em");
+      testCSSAttrs("margin_ex");
+      testCSSAttrs("margin_in");
+      testCSSAttrs("margin_cm");
+      testCSSAttrs("margin_mm");
+      testCSSAttrs("margin_pt");
+      testCSSAttrs("margin_pc");
+      testCSSAttrs("margin_px");
+      testCSSAttrs("margin_percent");
+      testCSSAttrs("margin_auto");
+      testCSSAttrs("margin_inherit");
+
+      testCSSAttrs("margin-left");
+      testCSSAttrs("margin-right");
+      testCSSAttrs("margin-top");
+      testCSSAttrs("margin-bottom");
+
+      // Elements
       testCSSAttrs("span");
       testCSSAttrs("div");
-
       testCSSAttrs("p");
-      testCSSAttrs("p2");
-
-      testCSSAttrs("pml");
-      testCSSAttrs("pmr");
-      testCSSAttrs("pmt");
-      testCSSAttrs("pmb");
-
       testCSSAttrs("input");
       testCSSAttrs("table");
       testCSSAttrs("tr");
       testCSSAttrs("td");
 
       SimpleTest.finish();
     }
 
@@ -72,33 +101,93 @@ https://bugzilla.mozilla.org/show_bug.cg
      title="text-indent and text-align should really be object attribute">
     Mozilla Bug 460932
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=689540"
      title="Expose IA2 margin- object attributes">
     Mozilla Bug 689540
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=714579"
+     title="Don't use GetComputedStyle for object attribute calculation">
+    Mozilla Bug 714579
+  </a>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
+  <div id="display_block" role="img"
+       style="display: block;">display: block</div>
+  <div id="display_inline" role="img"
+       style="display: inline;">display: inline</div>
+  <div id="display_inline-block" role="img"
+       style="display: inline-block;">display: inline-block</div>
+  <div id="display_list-item" role="img"
+       style="display: list-item;">display: list-item</div>
+  <div id="display_table" role="img"
+       style="display: table;">display: table</div>
+  <div id="display_inline-table" role="img"
+       style="display: inline-table;">display: inline-table</div>
+  <div id="display_table-row-group" role="img"
+       style="display: table-row-group;">display: table-row-group</div>
+  <div id="display_table-column" role="img"
+       style="display: table-column;">display: table-column</div>
+  <div id="display_table-column-group" role="img"
+       style="display: table-column-group;">display: table-column-group</div>
+  <div id="display_table-header-group" role="img"
+       style="display: table-header-group;">display: table-header-group</div>
+  <div id="display_table-footer-group" role="img"
+       style="display: table-footer-group;">display: table-footer-group</div>
+  <div id="display_table-row" role="img"
+       style="display: table-row;">display: table-row</div>
+  <div id="display_table-cell" role="img"
+       style="display: table-cell;">display: table-cell</div>
+  <div id="display_table-caption" role="img"
+       style="display: table-caption;">display: table-caption</div>
+
+  <p id="text-align_left" style="text-align: left;">text-align: left</p>
+  <p id="text-align_right" style="text-align: right;">text-align: right</p>
+  <p id="text-align_center" style="text-align: center;">text-align: center</p>
+  <p id="text-align_justify" style="text-align: justify;">text-align: justify</p>
+  <p id="text-align_inherit" style="text-align: inherit;">text-align: inherit</p>
+
+  <p id="text-indent_em" style="text-indent: 0.5em;">text-indent: 0.5em</p>
+  <p id="text-indent_ex" style="text-indent: 1ex;">text-indent: 1ex</p>
+  <p id="text-indent_in" style="text-indent: 0.5in;">text-indent: 0.5in</p>
+  <p id="text-indent_cm" style="text-indent: 2cm;">text-indent: 2cm</p>
+  <p id="text-indent_mm" style="text-indent: 10mm;">text-indent: 10mm</p>
+  <p id="text-indent_pt" style="text-indent: 30pt;">text-indent: 30pt</p>
+  <p id="text-indent_pc" style="text-indent: 2pc;">text-indent: 2pc</p>
+  <p id="text-indent_px" style="text-indent: 5px;">text-indent: 5px</p>
+  <p id="text-indent_percent" style="text-indent: 10%;">text-indent: 10%</p>
+  <p id="text-indent_inherit" style="text-indent: inherit;">text-indent: inherit</p>
+
+  <p id="margin_em" style="margin: 0.5em;">margin: 0.5em</p>
+  <p id="margin_ex" style="margin: 1ex;">margin: 1ex</p>
+  <p id="margin_in" style="margin: 0.5in;">margin: 0.5in</p>
+  <p id="margin_cm" style="margin: 2cm;">margin: 2cm</p>
+  <p id="margin_mm" style="margin: 10mm;">margin: 10mm</p>
+  <p id="margin_pt" style="margin: 30pt;">margin: 30pt</p>
+  <p id="margin_pc" style="margin: 2pc;">margin: 2pc</p>
+  <p id="margin_px" style="margin: 5px;">margin: 5px</p>
+  <p id="margin_percent" style="margin: 10%;">margin: 10%</p>
+  <p id="margin_auto" style="margin: auto;">margin: auto</p>
+  <p id="margin_inherit" style="margin: inherit;">margin: inherit</p>
+
+  <p id="margin-left" style="margin-left: 11px;">margin-left: 11px</p>
+  <p id="margin-right" style="margin-right: 21px;">margin-right</p>
+  <p id="margin-top" style="margin-top: 31px;">margin-top: 31px</p>
+  <p id="margin-bottom" style="margin-bottom: 41px;">margin-bottom: 41px</p>
+
   <span id="span" role="group">It's span</span>
   <div id="div">It's div</div>
-
   <p id="p">It's paragraph"</p>
-  <p id="p2"  style="text-indent: 5px">It's another paragraph</p>
-
-  <p id="pml" style="margin-left : 11px;">It's a paragraph with left margin</p>
-  <p id="pmr" style="margin-right : 21px;">It's a paragraph with right margin</p>
-  <p id="pmt" style="margin-top : 31px;">It's a paragraph with top margin</p>
-  <p id="pmb" style="margin-bottom : 41px;">It's a paragraph with bottom margin</p>
-
   <input id="input"/>
-  <table id="table">
+  <table id="table" style="margin: 2px; text-align: center; text-indent: 10%;">
     <tr id="tr" role="group">
       <td id="td">td</td>
     </tr>
   </table>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/attributes/test_obj_css.xul
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="Accessibility CSS-based Object Attributes Test.">
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+
+  <script type="application/javascript"
+          src="../common.js" />
+  <script type="application/javascript"
+          src="../events.js" />
+  <script type="application/javascript"
+          src="../attributes.js" />
+
+  <script type="application/javascript">
+  <![CDATA[
+    function doTest()
+    {
+      // CSS display
+      testCSSAttrs("display_mozbox");
+      testCSSAttrs("display_mozinlinebox");
+      testCSSAttrs("display_mozgrid");
+      testCSSAttrs("display_mozinlinegrid");
+      testCSSAttrs("display_mozgridgroup");
+      testCSSAttrs("display_mozgridline");
+      testCSSAttrs("display_mozstack");
+      testCSSAttrs("display_mozinlinestack");
+      testCSSAttrs("display_mozdeck");
+      testCSSAttrs("display_mozpopup");
+      testCSSAttrs("display_mozgroupbox");
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  ]]>
+  </script>
+
+  <hbox flex="1" style="overflow: auto;">
+  <body xmlns="http://www.w3.org/1999/xhtml">
+    <a target="_blank"
+       href="https://bugzilla.mozilla.org/show_bug.cgi?id=714579"
+       title="Don't use GetComputedStyle for object attribute calculation">
+      Mozilla Bug 714579
+    </a><br/>
+
+    <p id="display"></p>
+    <div id="content" style="display: none">
+    </div>
+    <pre id="test">
+    </pre>
+  </body>
+
+  <vbox id="display_mozbox" style="display: -moz-box;" role="img"/>
+  <vbox id="display_mozinlinebox" style="display: -moz-inline-box;" role="img"/>
+  <vbox id="display_mozgrid" style="display: -moz-grid;" role="img"/>
+  <vbox id="display_mozinlinegrid" style="display: -moz-inline-grid;" role="img"/>
+  <vbox id="display_mozgridgroup" style="display: -moz-grid-group;" role="img"/>
+  <vbox id="display_mozgridline" style="display: -moz-grid-line;" role="img"/>
+  <vbox id="display_mozstack" style="display: -moz-stack;" role="img"/>
+  <vbox id="display_mozinlinestack" style="display: -moz-inline-stack;" role="img"/>
+  <vbox id="display_mozdeck" style="display: -moz-deck;" role="img"/>
+  <vbox id="display_mozpopup" style="display: -moz-popup;" role="img"/>
+  <vbox id="display_mozgroupbox" style="display: -moz-groupbox;" role="img"/>
+
+  </hbox>
+</window>
+
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -146,16 +146,19 @@
 @BINPATH@/components/dom.xpt
 @BINPATH@/components/dom_base.xpt
 #ifdef MOZ_B2G_RIL
 @BINPATH@/components/dom_telephony.xpt
 @BINPATH@/components/dom_wifi.xpt
 @BINPATH@/components/dom_system_b2g.xpt
 #endif
 @BINPATH@/components/dom_battery.xpt
+#ifdef MOZ_B2G_BT
+@BINPATH@/components/dom_bluetooth.xpt
+#endif
 @BINPATH@/components/dom_canvas.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_geolocation.xpt
 @BINPATH@/components/dom_network.xpt
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -145,16 +145,19 @@
 @BINPATH@/components/dom.xpt
 @BINPATH@/components/dom_base.xpt
 #ifdef MOZ_B2G_RIL
 @BINPATH@/components/dom_telephony.xpt
 @BINPATH@/components/dom_wifi.xpt
 @BINPATH@/components/dom_system_b2g.xpt
 #endif
 @BINPATH@/components/dom_battery.xpt
+#ifdef MOZ_B2G_BT
+@BINPATH@/components/dom_bluetooth.xpt
+#endif
 @BINPATH@/components/dom_canvas.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_geolocation.xpt
 @BINPATH@/components/dom_network.xpt
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -289,16 +289,17 @@ MOZ_ENABLE_GNOME_COMPONENT = @MOZ_ENABLE
 MOZ_ENABLE_GIO = @MOZ_ENABLE_GIO@
 MOZ_GIO_CFLAGS = @MOZ_GIO_CFLAGS@
 MOZ_GIO_LIBS = @MOZ_GIO_LIBS@
 
 MOZ_NATIVE_NSPR = @MOZ_NATIVE_NSPR@
 MOZ_NATIVE_NSS = @MOZ_NATIVE_NSS@
 
 MOZ_B2G_RIL = @MOZ_B2G_RIL@
+MOZ_B2G_BT = @MOZ_B2G_BT@
 
 BUILD_CTYPES = @BUILD_CTYPES@
 
 COMPILE_ENVIRONMENT = @COMPILE_ENVIRONMENT@
 CROSS_COMPILE   = @CROSS_COMPILE@
 
 WCHAR_CFLAGS	= @WCHAR_CFLAGS@
 
--- a/configure.in
+++ b/configure.in
@@ -220,24 +220,17 @@ AC_SUBST(COMPILE_ENVIRONMENT)
 
 MOZ_ARG_WITH_STRING(l10n-base,
 [  --with-l10n-base=DIR    path to l10n repositories],
     L10NBASEDIR=$withval)
 if test -n "$L10NBASEDIR"; then
     if test "$L10NBASEDIR" = "yes" -o "$L10NBASEDIR" = "no"; then
         AC_MSG_ERROR([--with-l10n-base must specify a path])
     elif test -d "$L10NBASEDIR"; then
-        case "$host_os" in
-        mingw*)
-            L10NBASEDIR=`cd "$L10NBASEDIR" && pwd -W`
-            ;;
-        *)
-            L10NBASEDIR=`cd "$L10NBASEDIR" && pwd`
-            ;;
-        esac
+        L10NBASEDIR=`cd "$L10NBASEDIR" && pwd`
     else
         AC_MSG_ERROR([Invalid value --with-l10n-base, $L10NBASEDIR doesn't exist])
     fi
 fi
 AC_SUBST(L10NBASEDIR)
 
 dnl Check for Perl first -- needed for win32 SDK checks
 MOZ_PATH_PROGS(PERL, $PERL perl5 perl )
@@ -5528,16 +5521,25 @@ AC_SUBST(MOZ_DBUS_GLIB_LIBS)
 dnl ========================================================
 dnl = Enable Android History instead of Places
 dnl ========================================================
 if test -n "$MOZ_ANDROID_HISTORY"; then
      dnl Do this if defined in confvars.sh
      AC_DEFINE(MOZ_ANDROID_HISTORY)
 fi
 
+
+dnl ========================================================
+dnl = Build with the Android Java compositor
+dnl ========================================================
+if test -n "$MOZ_JAVA_COMPOSITOR"; then
+     dnl Do this if defined in confvars.sh
+     AC_DEFINE(MOZ_JAVA_COMPOSITOR)
+fi
+
 dnl ========================================================
 dnl = Disable WebSMS backend
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(websms-backend,
 [  --disable-websms-backend
                            Disable WebSMS backend],
     MOZ_WEBSMS_BACKEND=,
     MOZ_WEBSMS_BACKEND=1)
@@ -7660,16 +7662,28 @@ MOZ_ARG_ENABLE_BOOL(b2g-ril,
     MOZ_B2G_RIL=1,
     MOZ_B2G_RIL= )
 if test -n "$MOZ_B2G_RIL"; then
    AC_DEFINE(MOZ_B2G_RIL)
 fi
 AC_SUBST(MOZ_B2G_RIL)
 
 dnl ========================================================
+dnl = Enable Bluetooth Interface for B2G (Gonk usually)
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(b2g-bt,
+[  --enable-b2g-bt      Set compile flags necessary for compiling Bluetooth API for B2G ],
+    MOZ_B2G_BT=1,
+    MOZ_B2G_BT= )
+if test -n "$MOZ_B2G_BT"; then
+   AC_DEFINE(MOZ_B2G_BT)
+fi
+AC_SUBST(MOZ_B2G_BT)
+
+dnl ========================================================
 dnl = Support for demangling undefined symbols
 dnl ========================================================
 if test -z "$SKIP_LIBRARY_CHECKS"; then
     AC_LANG_SAVE
     AC_LANG_CPLUSPLUS
     AC_CHECK_FUNCS(__cxa_demangle, HAVE_DEMANGLE=1, HAVE_DEMANGLE=)
     AC_LANG_RESTORE
 fi
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -1275,18 +1275,20 @@ nsXMLHttpRequest::CloseRequestWithError(
   if (mTimeoutTimer) {
     mTimeoutTimer->Cancel();
   }
   PRUint32 responseLength = mResponseBody.Length();
   ResetResponse();
   mState |= aFlag;
 
   // If we're in the destructor, don't risk dispatching an event.
-  if (mState & XML_HTTP_REQUEST_DELETED)
+  if (mState & XML_HTTP_REQUEST_DELETED) {
+    mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
     return;
+  }
 
   if (!(mState & (XML_HTTP_REQUEST_UNSENT |
                   XML_HTTP_REQUEST_OPENED |
                   XML_HTTP_REQUEST_DONE))) {
     ChangeState(XML_HTTP_REQUEST_DONE, true);
 
     if (!(mState & XML_HTTP_REQUEST_SYNCLOOPING)) {
       DispatchProgressEvent(this, aType, mLoadLengthComputable, responseLength,
--- a/content/canvas/src/Makefile.in
+++ b/content/canvas/src/Makefile.in
@@ -63,16 +63,17 @@ CPPSRCS	= \
 	$(NULL)
 
 ifdef MOZ_WEBGL
 
 CPPSRCS += \
 	WebGLContext.cpp \
 	WebGLContextGL.cpp \
 	WebGLContextUtils.cpp \
+	WebGLContextReporter.cpp \
 	WebGLContextValidate.cpp \
 	WebGLExtensionStandardDerivatives.cpp \
 	WebGLExtensionLoseContext.cpp \
 	$(NULL)
 
 DEFINES += -DUSE_ANGLE
 USE_ANGLE=1
 
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -70,143 +70,16 @@
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 
 using namespace mozilla;
 using namespace mozilla::gl;
 using namespace mozilla::layers;
 
-WebGLMemoryReporter* WebGLMemoryReporter::sUniqueInstance = nsnull;
-
-NS_MEMORY_REPORTER_IMPLEMENT(WebGLTextureMemoryUsed,
-                             "webgl-texture-memory",
-                             KIND_OTHER,
-                             UNITS_BYTES,
-                             WebGLMemoryReporter::GetTextureMemoryUsed,
-                             "Memory used by WebGL textures. The OpenGL implementation is free to store these textures in either video memory or main memory. This measurement is only a lower bound, actual memory usage may be higher for example if the storage is strided.")
-
-NS_MEMORY_REPORTER_IMPLEMENT(WebGLTextureCount,
-                             "webgl-texture-count",
-                             KIND_OTHER,
-                             UNITS_COUNT,
-                             WebGLMemoryReporter::GetTextureCount,
-                             "Number of WebGL textures.")
-
-NS_MEMORY_REPORTER_IMPLEMENT(WebGLBufferMemoryUsed,
-                             "webgl-buffer-memory",
-                             KIND_OTHER,
-                             UNITS_BYTES,
-                             WebGLMemoryReporter::GetBufferMemoryUsed,
-                             "Memory used by WebGL buffers. The OpenGL implementation is free to store these buffers in either video memory or main memory. This measurement is only a lower bound, actual memory usage may be higher for example if the storage is strided.")
-
-NS_MEMORY_REPORTER_IMPLEMENT(WebGLBufferCacheMemoryUsed,
-                             "explicit/webgl/buffer-cache-memory",
-                             KIND_HEAP,
-                             UNITS_BYTES,
-                             WebGLMemoryReporter::GetBufferCacheMemoryUsed,
-                             "Memory used by WebGL buffer caches. The WebGL implementation caches the contents of element array buffers only. This adds up with the webgl-buffer-memory value, but contrary to it, this one represents bytes on the heap, not managed by OpenGL.")
-
-NS_MEMORY_REPORTER_IMPLEMENT(WebGLBufferCount,
-                             "webgl-buffer-count",
-                             KIND_OTHER,
-                             UNITS_COUNT,
-                             WebGLMemoryReporter::GetBufferCount,
-                             "Number of WebGL buffers.")
-
-NS_MEMORY_REPORTER_IMPLEMENT(WebGLRenderbufferMemoryUsed,
-                             "webgl-renderbuffer-memory",
-                             KIND_OTHER,
-                             UNITS_BYTES,
-                             WebGLMemoryReporter::GetRenderbufferMemoryUsed,
-                             "Memory used by WebGL renderbuffers. The OpenGL implementation is free to store these renderbuffers in either video memory or main memory. This measurement is only a lower bound, actual memory usage may be higher for example if the storage is strided.")
-
-NS_MEMORY_REPORTER_IMPLEMENT(WebGLRenderbufferCount,
-                             "webgl-renderbuffer-count",
-                             KIND_OTHER,
-                             UNITS_COUNT,
-                             WebGLMemoryReporter::GetRenderbufferCount,
-                             "Number of WebGL renderbuffers.")
-
-NS_MEMORY_REPORTER_IMPLEMENT(WebGLShaderSourcesSize,
-                             "explicit/webgl/shader-sources-size",
-                             KIND_HEAP,
-                             UNITS_BYTES,
-                             WebGLMemoryReporter::GetShaderSourcesSize,
-                             "Combined size of WebGL shader ASCII sources, cached on the heap. This should always be at most a few kilobytes, or dozen kilobytes for very shader-intensive WebGL demos.")
-
-NS_MEMORY_REPORTER_IMPLEMENT(WebGLShaderTranslationLogsSize,
-                             "explicit/webgl/shader-translationlogs-size",
-                             KIND_HEAP,
-                             UNITS_BYTES,
-                             WebGLMemoryReporter::GetShaderTranslationLogsSize,
-                             "Combined size of WebGL shader ASCII translation logs, cached on the heap.")
-
-NS_MEMORY_REPORTER_IMPLEMENT(WebGLShaderCount,
-                             "webgl-shader-count",
-                             KIND_OTHER,
-                             UNITS_COUNT,
-                             WebGLMemoryReporter::GetShaderCount,
-                             "Number of WebGL shaders.")
-
-NS_MEMORY_REPORTER_IMPLEMENT(WebGLContextCount,
-                             "webgl-context-count",
-                             KIND_OTHER,
-                             UNITS_COUNT,
-                             WebGLMemoryReporter::GetContextCount,
-                             "Number of WebGL contexts.")
-
-WebGLMemoryReporter* WebGLMemoryReporter::UniqueInstance()
-{
-    if (!sUniqueInstance) {
-        sUniqueInstance = new WebGLMemoryReporter;
-    }
-    return sUniqueInstance;
-}
-
-WebGLMemoryReporter::WebGLMemoryReporter()
-    : mTextureMemoryUsageReporter(new NS_MEMORY_REPORTER_NAME(WebGLTextureMemoryUsed))
-    , mTextureCountReporter(new NS_MEMORY_REPORTER_NAME(WebGLTextureCount))
-    , mBufferMemoryUsageReporter(new NS_MEMORY_REPORTER_NAME(WebGLBufferMemoryUsed))
-    , mBufferCacheMemoryUsageReporter(new NS_MEMORY_REPORTER_NAME(WebGLBufferCacheMemoryUsed))
-    , mBufferCountReporter(new NS_MEMORY_REPORTER_NAME(WebGLBufferCount))
-    , mRenderbufferMemoryUsageReporter(new NS_MEMORY_REPORTER_NAME(WebGLRenderbufferMemoryUsed))
-    , mRenderbufferCountReporter(new NS_MEMORY_REPORTER_NAME(WebGLRenderbufferCount))
-    , mShaderSourcesSizeReporter(new NS_MEMORY_REPORTER_NAME(WebGLShaderSourcesSize))
-    , mShaderTranslationLogsSizeReporter(new NS_MEMORY_REPORTER_NAME(WebGLShaderTranslationLogsSize))
-    , mShaderCountReporter(new NS_MEMORY_REPORTER_NAME(WebGLShaderCount))
-    , mContextCountReporter(new NS_MEMORY_REPORTER_NAME(WebGLContextCount))
-{
-    NS_RegisterMemoryReporter(mTextureMemoryUsageReporter);
-    NS_RegisterMemoryReporter(mTextureCountReporter);
-    NS_RegisterMemoryReporter(mBufferMemoryUsageReporter);
-    NS_RegisterMemoryReporter(mBufferCacheMemoryUsageReporter);    
-    NS_RegisterMemoryReporter(mBufferCountReporter);
-    NS_RegisterMemoryReporter(mRenderbufferMemoryUsageReporter);
-    NS_RegisterMemoryReporter(mRenderbufferCountReporter);
-    NS_RegisterMemoryReporter(mShaderSourcesSizeReporter);
-    NS_RegisterMemoryReporter(mShaderTranslationLogsSizeReporter);
-    NS_RegisterMemoryReporter(mShaderCountReporter);
-    NS_RegisterMemoryReporter(mContextCountReporter);
-}
-
-WebGLMemoryReporter::~WebGLMemoryReporter()
-{
-    NS_UnregisterMemoryReporter(mTextureMemoryUsageReporter);
-    NS_UnregisterMemoryReporter(mTextureCountReporter);
-    NS_UnregisterMemoryReporter(mBufferMemoryUsageReporter);
-    NS_UnregisterMemoryReporter(mBufferCacheMemoryUsageReporter);
-    NS_UnregisterMemoryReporter(mBufferCountReporter);
-    NS_UnregisterMemoryReporter(mRenderbufferMemoryUsageReporter);
-    NS_UnregisterMemoryReporter(mRenderbufferCountReporter);
-    NS_UnregisterMemoryReporter(mShaderSourcesSizeReporter);
-    NS_UnregisterMemoryReporter(mShaderTranslationLogsSizeReporter);
-    NS_UnregisterMemoryReporter(mShaderCountReporter);
-    NS_UnregisterMemoryReporter(mContextCountReporter);
-}
 
 nsresult NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** aResult);
 
 nsresult
 NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** aResult)
 {
     Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
     nsIDOMWebGLRenderingContext* ctx = new WebGLContext();
@@ -284,31 +157,31 @@ WebGLContext::WebGLContext()
     mGLMaxVaryingVectors = 0;
     mGLMaxFragmentUniformVectors = 0;
     mGLMaxVertexUniformVectors = 0;
     
     // See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13
     mPixelStorePackAlignment = 4;
     mPixelStoreUnpackAlignment = 4;
 
-    WebGLMemoryReporter::AddWebGLContext(this);
+    WebGLMemoryMultiReporterWrapper::AddWebGLContext(this);
 
     mAllowRestore = true;
     mRobustnessTimerRunning = false;
     mDrawSinceRobustnessTimerSet = false;
     mContextRestorer = do_CreateInstance("@mozilla.org/timer;1");
     mContextStatus = ContextStable;
     mContextLostErrorSet = false;
     mContextLostDueToTest = false;
 }
 
 WebGLContext::~WebGLContext()
 {
     DestroyResourcesAndContext();
-    WebGLMemoryReporter::RemoveWebGLContext(this);
+    WebGLMemoryMultiReporterWrapper::RemoveWebGLContext(this);
     TerminateRobustnessTimer();
     mContextRestorer = nsnull;
 }
 
 void
 WebGLContext::DestroyResourcesAndContext()
 {
     if (!gl)
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -50,18 +50,18 @@
 
 #include "nsIDocShell.h"
 
 #include "nsIDOMWebGLRenderingContext.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "nsHTMLCanvasElement.h"
 #include "nsWeakReference.h"
 #include "nsIDOMHTMLElement.h"
+#include "nsIMemoryReporter.h"
 #include "nsIJSNativeInitializer.h"
-#include "nsIMemoryReporter.h"
 #include "nsContentUtils.h"
 
 #include "GLContextProvider.h"
 #include "Layers.h"
 
 #include "CheckedInt.h"
 
 /* 
@@ -509,17 +509,17 @@ struct WebGLContextOptions {
 
 class WebGLContext :
     public nsIDOMWebGLRenderingContext,
     public nsICanvasRenderingContextInternal,
     public nsSupportsWeakReference,
     public nsITimerCallback,
     public WebGLRectangleObject
 {
-    friend class WebGLMemoryReporter;
+    friend class WebGLMemoryMultiReporterWrapper;
     friend class WebGLExtensionLoseContext;
     friend class WebGLContextUserData;
 
 public:
     WebGLContext();
     virtual ~WebGLContext();
 
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -1050,16 +1050,20 @@ public:
         mContext->MakeContextCurrent();
         mContext->gl->fDeleteBuffers(1, &mGLName);
         free(mData);
         mData = nsnull;
         mByteLength = 0;
         mContext->mBuffers.RemoveElement(mMonotonicHandle);
     }
 
+    size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const {
+        return aMallocSizeOf(this) + aMallocSizeOf(mData);
+    }
+   
     bool HasEverBeenBound() { return mHasEverBeenBound; }
     void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
     GLuint GLName() const { return mGLName; }
     GLuint ByteLength() const { return mByteLength; }
     GLenum Target() const { return mTarget; }
     const void *Data() const { return mData; }
 
     void SetByteLength(GLuint byteLength) { mByteLength = byteLength; }
@@ -1622,16 +1626,22 @@ public:
         mContext->MakeContextCurrent();
         mGLName = mContext->gl->fCreateShader(mType);
         mMonotonicHandle = mContext->mShaders.AppendElement(this);
     }
 
     ~WebGLShader() {
         DeleteOnce();
     }
+    
+    size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) {
+        return aMallocSizeOf(this) +
+               mSource.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
+               mTranslationLog.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+    }
 
     void Delete() {
         mSource.Truncate();
         mTranslationLog.Truncate();
         mContext->MakeContextCurrent();
         mContext->gl->fDeleteShader(mGLName);
         mContext->mShaders.RemoveElement(mMonotonicHandle);
     }
@@ -2510,136 +2520,103 @@ WebGLContext::CanGetConcreteObject(const
                               BaseInterfaceType *aInterface,
                               bool *isNull,
                               bool *isDeleted)
 {
     ConcreteObjectType *aConcreteObject;
     return GetConcreteObject(info, aInterface, &aConcreteObject, isNull, isDeleted, false);
 }
 
-class WebGLMemoryReporter
+class WebGLMemoryMultiReporterWrapper
 {
-    WebGLMemoryReporter();
-    ~WebGLMemoryReporter();
-    static WebGLMemoryReporter* sUniqueInstance;
-
-    // here we store plain pointers, not RefPtrs: we don't want the WebGLMemoryReporter unique instance to keep alive all
+    WebGLMemoryMultiReporterWrapper();
+    ~WebGLMemoryMultiReporterWrapper();
+    static WebGLMemoryMultiReporterWrapper* sUniqueInstance;
+
+    // here we store plain pointers, not RefPtrs: we don't want the 
+    // WebGLMemoryMultiReporterWrapper unique instance to keep alive all		
     // WebGLContexts ever created.
     typedef nsTArray<const WebGLContext*> ContextsArrayType;
     ContextsArrayType mContexts;
     
-    nsCOMPtr<nsIMemoryReporter> mTextureMemoryUsageReporter;
-    nsCOMPtr<nsIMemoryReporter> mTextureCountReporter;
-    nsCOMPtr<nsIMemoryReporter> mBufferMemoryUsageReporter;
-    nsCOMPtr<nsIMemoryReporter> mBufferCacheMemoryUsageReporter;
-    nsCOMPtr<nsIMemoryReporter> mBufferCountReporter;
-    nsCOMPtr<nsIMemoryReporter> mRenderbufferMemoryUsageReporter;
-    nsCOMPtr<nsIMemoryReporter> mRenderbufferCountReporter;
-    nsCOMPtr<nsIMemoryReporter> mShaderSourcesSizeReporter;
-    nsCOMPtr<nsIMemoryReporter> mShaderTranslationLogsSizeReporter;
-    nsCOMPtr<nsIMemoryReporter> mShaderCountReporter;
-    nsCOMPtr<nsIMemoryReporter> mContextCountReporter;
-
-    static WebGLMemoryReporter* UniqueInstance();
+    nsCOMPtr<nsIMemoryMultiReporter> mReporter;
+
+    static WebGLMemoryMultiReporterWrapper* UniqueInstance();
 
     static ContextsArrayType & Contexts() { return UniqueInstance()->mContexts; }
 
   public:
 
     static void AddWebGLContext(const WebGLContext* c) {
         Contexts().AppendElement(c);
     }
 
     static void RemoveWebGLContext(const WebGLContext* c) {
         ContextsArrayType & contexts = Contexts();
         contexts.RemoveElement(c);
         if (contexts.IsEmpty()) {
-            delete sUniqueInstance;
+            delete sUniqueInstance; 
             sUniqueInstance = nsnull;
         }
     }
 
     static PRInt64 GetTextureMemoryUsed() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
         for(size_t i = 0; i < contexts.Length(); ++i)
-            for (size_t t = 0; t < contexts[i]->mTextures.Length(); ++t)
-              result += contexts[i]->mTextures[t]->MemoryUsage();
+            for (size_t j = 0; j < contexts[i]->mTextures.Length(); ++j)
+              result += contexts[i]->mTextures[j]->MemoryUsage();
         return result;
     }
 
     static PRInt64 GetTextureCount() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
         for(size_t i = 0; i < contexts.Length(); ++i)
             result += contexts[i]->mTextures.Length();
         return result;
     }
 
     static PRInt64 GetBufferMemoryUsed() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
         for(size_t i = 0; i < contexts.Length(); ++i)
-            for (size_t b = 0; b < contexts[i]->mBuffers.Length(); ++b)
-                result += contexts[i]->mBuffers[b]->ByteLength();
+            for (size_t j = 0; j < contexts[i]->mBuffers.Length(); ++j)
+                result += contexts[i]->mBuffers[j]->ByteLength();
         return result;
     }
 
-    static PRInt64 GetBufferCacheMemoryUsed() {
-        const ContextsArrayType & contexts = Contexts();
-        PRInt64 result = 0;
-        for(size_t i = 0; i < contexts.Length(); ++i)
-            for (size_t b = 0; b < contexts[i]->mBuffers.Length(); ++b)
-                if (contexts[i]->mBuffers[b]->Target() == LOCAL_GL_ELEMENT_ARRAY_BUFFER)
-                    result += contexts[i]->mBuffers[b]->ByteLength();
-        return result;
-    }
+    static PRInt64 GetBufferCacheMemoryUsed();
 
     static PRInt64 GetBufferCount() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
         for(size_t i = 0; i < contexts.Length(); ++i)
             result += contexts[i]->mBuffers.Length();
         return result;
     }
 
     static PRInt64 GetRenderbufferMemoryUsed() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
         for(size_t i = 0; i < contexts.Length(); ++i)
-            for (size_t r = 0; r < contexts[i]->mRenderbuffers.Length(); ++r)
-              result += contexts[i]->mRenderbuffers[r]->MemoryUsage();
+            for (size_t j = 0; j < contexts[i]->mRenderbuffers.Length(); ++j)
+              result += contexts[i]->mRenderbuffers[j]->MemoryUsage();
         return result;
     }
 
     static PRInt64 GetRenderbufferCount() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
         for(size_t i = 0; i < contexts.Length(); ++i)
             result += contexts[i]->mRenderbuffers.Length();
         return result;
     }
 
-    static PRInt64 GetShaderSourcesSize() {
-        const ContextsArrayType & contexts = Contexts();
-        PRInt64 result = 0;
-        for(size_t i = 0; i < contexts.Length(); ++i)
-            for (size_t s = 0; s < contexts[i]->mShaders.Length(); ++s)
-                result += contexts[i]->mShaders[s]->Source().Length();
-        return result;
-    }
-
-    static PRInt64 GetShaderTranslationLogsSize() {
-        const ContextsArrayType & contexts = Contexts();
-        PRInt64 result = 0;
-        for(size_t i = 0; i < contexts.Length(); ++i)
-            for (size_t s = 0; s < contexts[i]->mShaders.Length(); ++s)
-                result += contexts[i]->mShaders[s]->TranslationLog().Length();
-        return result;
-    }
+    static PRInt64 GetShaderSize();
 
     static PRInt64 GetShaderCount() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
         for(size_t i = 0; i < contexts.Length(); ++i)
             result += contexts[i]->mShaders.Length();
         return result;
     }
new file mode 100644
--- /dev/null
+++ b/content/canvas/src/WebGLContextReporter.cpp
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *   Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "WebGLContext.h"
+#include "nsIMemoryReporter.h"
+
+using namespace mozilla;
+
+
+class WebGLMemoryMultiReporter : public nsIMemoryMultiReporter 
+{
+  public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIMEMORYMULTIREPORTER
+};
+
+NS_IMPL_ISUPPORTS1(WebGLMemoryMultiReporter, nsIMemoryMultiReporter)
+
+NS_IMETHODIMP
+WebGLMemoryMultiReporter::GetName(nsACString &aName)
+{
+  aName.AssignLiteral("webgl");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WebGLMemoryMultiReporter::GetExplicitNonHeap(PRInt64 *aAmount)
+{
+    // WebGLMemoryMultiReporterWrapper has no KIND_NONHEAP measurements.
+    *aAmount = 0;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+WebGLMemoryMultiReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb, 
+                                         nsISupports* aClosure)
+{
+    aCb->Callback(
+        EmptyCString(), 
+        NS_LITERAL_CSTRING("webgl-texture-memory"),
+        nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_BYTES,
+        WebGLMemoryMultiReporterWrapper::GetTextureMemoryUsed(),
+        NS_LITERAL_CSTRING("Memory used by WebGL textures.The OpenGL"
+            " implementation is free to store these textures in either video"
+            " memory or main memory. This measurement is only a lower bound,"
+            " actual memory usage may be higher for example if the storage" 
+            " is strided."),  
+        aClosure);
+   
+    aCb->Callback(
+        EmptyCString(), 
+        NS_LITERAL_CSTRING("webgl-texture-count"),
+        nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
+         WebGLMemoryMultiReporterWrapper::GetTextureCount(), 
+        NS_LITERAL_CSTRING("Number of WebGL textures."), 
+        aClosure);
+
+    aCb->Callback(
+        EmptyCString(), 
+        NS_LITERAL_CSTRING("webgl-buffer-memory"),
+        nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_BYTES,
+         WebGLMemoryMultiReporterWrapper::GetBufferMemoryUsed(), 
+        NS_LITERAL_CSTRING("Memory used by WebGL buffers. The OpenGL"
+            " implementation is free to store these buffers in either video"
+            " memory or main memory. This measurement is only a lower bound,"
+            " actual memory usage may be higher for example if the storage"
+            " is strided."),
+        aClosure);
+
+    aCb->Callback(
+        EmptyCString(), 
+        NS_LITERAL_CSTRING("explicit/webgl/buffer-cache-memory"),
+        nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
+        WebGLMemoryMultiReporterWrapper::GetBufferCacheMemoryUsed(),
+        NS_LITERAL_CSTRING("Memory used by WebGL buffer caches. The WebGL"
+            " implementation caches the contents of element array buffers"
+            " only.This adds up with the webgl-buffer-memory value, but"
+            " contrary to it, this one represents bytes on the heap,"
+            " not managed by OpenGL."),
+        aClosure);
+
+    aCb->Callback(
+        EmptyCString(), NS_LITERAL_CSTRING("webgl-buffer-count"),
+        nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
+        WebGLMemoryMultiReporterWrapper::GetBufferCount(),
+        NS_LITERAL_CSTRING("Number of WebGL buffers."), 
+        aClosure);
+   
+    aCb->Callback(
+        EmptyCString(), 
+        NS_LITERAL_CSTRING("webgl-renderbuffer-memory"),
+        nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_BYTES,
+        WebGLMemoryMultiReporterWrapper::GetRenderbufferMemoryUsed(), 
+        NS_LITERAL_CSTRING("Memory used by WebGL renderbuffers. The OpenGL"
+            " implementation is free to store these renderbuffers in either"
+            " video memory or main memory. This measurement is only a lower"
+            " bound, actual memory usage may be higher for example if the"
+            " storage is strided."),
+        aClosure);
+   
+    aCb->Callback(
+        EmptyCString(),
+        NS_LITERAL_CSTRING("webgl-renderbuffer-count"),
+        nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
+        WebGLMemoryMultiReporterWrapper::GetRenderbufferCount(),
+        NS_LITERAL_CSTRING("Number of WebGL renderbuffers."),
+        aClosure);
+  
+    aCb->Callback(
+        EmptyCString(),
+        NS_LITERAL_CSTRING("explicit/webgl/shader"),
+        nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
+        WebGLMemoryMultiReporterWrapper::GetShaderSize(), 
+        NS_LITERAL_CSTRING("Combined size of WebGL shader ASCII sources and"
+            " translation logs cached on the heap."), 
+        aClosure);
+
+    aCb->Callback(
+        EmptyCString(), 
+        NS_LITERAL_CSTRING("webgl-shader-count"),
+        nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
+        WebGLMemoryMultiReporterWrapper::GetShaderCount(), 
+        NS_LITERAL_CSTRING("Number of WebGL shaders."), 
+        aClosure);
+
+    aCb->Callback(
+        EmptyCString(), 
+        NS_LITERAL_CSTRING("webgl-context-count"),
+        nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
+        WebGLMemoryMultiReporterWrapper::GetContextCount(), 
+        NS_LITERAL_CSTRING("Number of WebGL contexts."), 
+        aClosure);
+
+    return NS_OK;
+}
+
+WebGLMemoryMultiReporterWrapper* WebGLMemoryMultiReporterWrapper::sUniqueInstance = nsnull;
+
+WebGLMemoryMultiReporterWrapper* WebGLMemoryMultiReporterWrapper::UniqueInstance()
+{
+    if (!sUniqueInstance) {
+        sUniqueInstance = new WebGLMemoryMultiReporterWrapper;
+    }
+    return sUniqueInstance;     
+}
+
+WebGLMemoryMultiReporterWrapper::WebGLMemoryMultiReporterWrapper()
+{ 
+    mReporter = new WebGLMemoryMultiReporter;   
+    NS_RegisterMemoryMultiReporter(mReporter);
+}
+
+WebGLMemoryMultiReporterWrapper::~WebGLMemoryMultiReporterWrapper()
+{
+    NS_UnregisterMemoryMultiReporter(mReporter);
+}
+
+NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(WebGLBufferMallocSizeOfFun, "webgl-buffer")
+
+PRInt64 
+WebGLMemoryMultiReporterWrapper::GetBufferCacheMemoryUsed() {
+    const ContextsArrayType & contexts = Contexts();
+    PRInt64 result = 0;
+    for (size_t i = 0; i < contexts.Length(); ++i) {
+        for (size_t j = 0; j < contexts[i]->mBuffers.Length(); ++j) 
+            if (contexts[i]->mBuffers[j]->Target() == LOCAL_GL_ELEMENT_ARRAY_BUFFER)
+               result += contexts[i]->mBuffers[j]->SizeOfIncludingThis(WebGLBufferMallocSizeOfFun);
+    }
+    return result;
+}
+
+NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(WebGLShaderMallocSizeOfFun, "webgl-shader")
+
+PRInt64 
+WebGLMemoryMultiReporterWrapper::GetShaderSize() {
+    const ContextsArrayType & contexts = Contexts();
+    PRInt64 result = 0;
+    for (size_t i = 0; i < contexts.Length(); ++i) {
+        for (size_t j = 0; j < contexts[i]->mShaders.Length(); ++j) 
+            result += contexts[i]->mShaders[j]->SizeOfIncludingThis(WebGLShaderMallocSizeOfFun);
+    }
+    return result;
+}
--- a/docshell/base/nsAboutRedirector.cpp
+++ b/docshell/base/nsAboutRedirector.cpp
@@ -81,16 +81,19 @@ static RedirEntry kRedirMap[] = {
     { "buildconfig", "chrome://global/content/buildconfig.html",
       nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT },
     { "license", "chrome://global/content/license.html",
       nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT },
     { "neterror", "chrome://global/content/netError.xhtml",
       nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
       nsIAboutModule::ALLOW_SCRIPT |
       nsIAboutModule::HIDE_FROM_ABOUTABOUT },
+    // aboutMemory.xhtml implements about:compartments
+    { "compartments", "chrome://global/content/aboutMemory.xhtml",
+      nsIAboutModule::ALLOW_SCRIPT },
     { "memory", "chrome://global/content/aboutMemory.xhtml",
       nsIAboutModule::ALLOW_SCRIPT },
     { "addons", "chrome://mozapps/content/extensions/extensions.xul",
       nsIAboutModule::ALLOW_SCRIPT },
     { "newaddon", "chrome://mozapps/content/extensions/newaddon.xul",
       nsIAboutModule::ALLOW_SCRIPT |
       nsIAboutModule::HIDE_FROM_ABOUTABOUT },
     { "support", "chrome://global/content/aboutSupport.xhtml",
--- a/docshell/build/nsDocShellModule.cpp
+++ b/docshell/build/nsDocShellModule.cpp
@@ -205,16 +205,17 @@ const mozilla::Module::ContractIDEntry k
 #endif
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "credits", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "plugins", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "mozilla", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "logo", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "buildconfig", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "license", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "neterror", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
+  { NS_ABOUT_MODULE_CONTRACTID_PREFIX "compartments", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "memory", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "addons", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "newaddon", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_ABOUT_MODULE_CONTRACTID_PREFIX "support", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
   { NS_URI_LOADER_CONTRACTID, &kNS_URI_LOADER_CID },
   { NS_DOCUMENTLOADER_SERVICE_CONTRACTID, &kNS_DOCUMENTLOADER_SERVICE_CID },
   { NS_EXTERNALHELPERAPPSERVICE_CONTRACTID, &kNS_EXTERNALHELPERAPPSERVICE_CID },
   { NS_EXTERNALPROTOCOLSERVICE_CONTRACTID, &kNS_EXTERNALHELPERAPPSERVICE_CID },
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -92,14 +92,19 @@ DIRS += \
 
 ifdef MOZ_B2G_RIL
 DIRS += \
   telephony \
   wifi \
   $(NULL)
 endif
 
+ifdef MOZ_B2G_BT
+DIRS += \
+  bluetooth \
+  $(NULL)
+endif
 TEST_DIRS += tests
 ifneq (,$(filter gtk2 cocoa windows android qt os2,$(MOZ_WIDGET_TOOLKIT)))
 TEST_DIRS += plugins/test
 endif
 
 include $(topsrcdir)/config/rules.mk
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -75,16 +75,20 @@
 #include "mozilla/Hal.h"
 #include "nsIWebNavigation.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "Connection.h"
 
 #ifdef MOZ_B2G_RIL
 #include "TelephonyFactory.h"
 #endif
+#ifdef MOZ_B2G_BT
+#include "nsIDOMBluetoothAdapter.h"
+#include "BluetoothAdapter.h"
+#endif
 
 // This should not be in the namespace.
 DOMCI_DATA(Navigator, mozilla::dom::Navigator)
 
 namespace mozilla {
 namespace dom {
 
 static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
@@ -128,16 +132,19 @@ NS_INTERFACE_MAP_BEGIN(Navigator)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorGeolocation)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorBattery)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorDesktopNotification)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorSms)
 #ifdef MOZ_B2G_RIL
   NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorTelephony)
 #endif
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorNetwork)
+#ifdef MOZ_B2G_BT
+  NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorBluetooth)
+#endif
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(Navigator)
 NS_IMPL_RELEASE(Navigator)
 
 void
 Navigator::Invalidate()
@@ -177,16 +184,22 @@ Navigator::Invalidate()
     mTelephony = nsnull;
   }
 #endif
 
   if (mConnection) {
     mConnection->Shutdown();
     mConnection = nsnull;
   }
+
+#ifdef MOZ_B2G_BT
+  if (mBluetooth) {
+    mBluetooth = nsnull;
+  }
+#endif
 }
 
 nsPIDOMWindow *
 Navigator::GetWindow()
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
 
   return win;
@@ -1107,16 +1120,40 @@ Navigator::GetMozConnection(nsIDOMMozCon
     mConnection = new network::Connection();
     mConnection->Init(window, scx);
   }
 
   NS_ADDREF(*aConnection = mConnection);
   return NS_OK;
 }
 
+#ifdef MOZ_B2G_BT
+//*****************************************************************************
+//    nsNavigator::nsIDOMNavigatorBluetooth
+//*****************************************************************************
+
+NS_IMETHODIMP
+Navigator::GetMozBluetooth(nsIDOMBluetoothAdapter** aBluetooth)
+{
+  nsCOMPtr<nsIDOMBluetoothAdapter> bluetooth = mBluetooth;
+
+  if (!bluetooth) {
+    nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+    NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
+
+    mBluetooth = new bluetooth::BluetoothAdapter();
+
+    bluetooth = mBluetooth;
+  }
+
+  bluetooth.forget(aBluetooth);
+  return NS_OK;
+}
+#endif //MOZ_B2G_BT
+
 PRInt64
 Navigator::SizeOf() const
 {
   PRInt64 size = sizeof(*this);
 
   // TODO: add SizeOf() to nsMimeTypeArray, bug 674113.
   size += mMimeTypes ? sizeof(*mMimeTypes.get()) : 0;
   // TODO: add SizeOf() to nsPluginArray, bug 674114.
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -60,16 +60,21 @@ class nsDesktopNotificationCenter;
 class nsPIDOMWindow;
 class nsIDOMMozConnection;
 
 #ifdef MOZ_B2G_RIL
 #include "nsIDOMNavigatorTelephony.h"
 class nsIDOMTelephony;
 #endif
 
+#ifdef MOZ_B2G_BT
+#include "nsIDOMNavigatorBluetooth.h"
+#endif
+
+class nsIDOMAdapter;
 //*****************************************************************************
 // Navigator: Script "navigator" object
 //*****************************************************************************
 
 namespace mozilla {
 namespace dom {
 
 namespace battery {
@@ -93,16 +98,19 @@ class Navigator : public nsIDOMNavigator
                 , public nsIDOMNavigatorGeolocation
                 , public nsIDOMNavigatorDesktopNotification
                 , public nsIDOMMozNavigatorBattery
                 , public nsIDOMMozNavigatorSms
 #ifdef MOZ_B2G_RIL
                 , public nsIDOMNavigatorTelephony
 #endif
                 , public nsIDOMMozNavigatorNetwork
+#ifdef MOZ_B2G_BT
+                , public nsIDOMNavigatorBluetooth
+#endif
 {
 public:
   Navigator(nsPIDOMWindow *aInnerWindow);
   virtual ~Navigator();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMNAVIGATOR
   NS_DECL_NSIDOMCLIENTINFORMATION
@@ -110,16 +118,20 @@ public:
   NS_DECL_NSIDOMNAVIGATORDESKTOPNOTIFICATION
   NS_DECL_NSIDOMMOZNAVIGATORBATTERY
   NS_DECL_NSIDOMMOZNAVIGATORSMS
 #ifdef MOZ_B2G_RIL
   NS_DECL_NSIDOMNAVIGATORTELEPHONY
 #endif
   NS_DECL_NSIDOMMOZNAVIGATORNETWORK
 
+#ifdef MOZ_B2G_BT
+  NS_DECL_NSIDOMNAVIGATORBLUETOOTH
+#endif
+
   static void Init();
 
   void Invalidate();
   nsPIDOMWindow *GetWindow();
 
   void RefreshMIMEArray();
 
   static bool HasDesktopNotificationSupport();
@@ -141,16 +153,19 @@ private:
   nsRefPtr<nsDesktopNotificationCenter> mNotification;
   nsRefPtr<battery::BatteryManager> mBatteryManager;
   nsRefPtr<power::PowerManager> mPowerManager;
   nsRefPtr<sms::SmsManager> mSmsManager;
 #ifdef MOZ_B2G_RIL
   nsCOMPtr<nsIDOMTelephony> mTelephony;
 #endif
   nsRefPtr<network::Connection> mConnection;
+#ifdef MOZ_B2G_BT
+  nsCOMPtr<nsIDOMBluetoothAdapter> mBluetooth;
+#endif
   nsWeakPtr mWindow;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 nsresult NS_GetNavigatorUserAgent(nsAString& aUserAgent);
 nsresult NS_GetNavigatorPlatform(nsAString& aPlatform);
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -527,16 +527,20 @@ using mozilla::dom::indexedDB::IDBWrappe
 #include "mozilla/dom/network/Utils.h"
 
 #ifdef MOZ_B2G_RIL
 #include "Telephony.h"
 #include "TelephonyCall.h"
 #include "CallEvent.h"
 #endif
 
+#ifdef MOZ_B2G_BT
+#include "BluetoothAdapter.h"
+#endif
+
 #include "DOMError.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 static const char kDOMStringBundleURL[] =
@@ -1622,16 +1626,21 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(Telephony, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(TelephonyCall, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CallEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
 
+#ifdef MOZ_B2G_BT
+  NS_DEFINE_CLASSINFO_DATA(BluetoothAdapter, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+#endif
+
   NS_DEFINE_CLASSINFO_DATA(DOMError, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 };
 
 // Objects that should be constructable through |new Name();|
 struct nsContractIDMapData
 {
   PRInt32 mDOMClassInfoID;
@@ -2418,16 +2427,19 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMMozNavigatorBattery,
                                         battery::BatteryManager::HasSupport())
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozNavigatorSms)
 #ifdef MOZ_B2G_RIL
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorTelephony)
 #endif
     DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMMozNavigatorNetwork,
                                         network::IsAPIEnabled())
+#ifdef MOZ_B2G_BT
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorBluetooth)
+#endif
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(Plugin, nsIDOMPlugin)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPlugin)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(PluginArray, nsIDOMPluginArray)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPluginArray)
@@ -3148,16 +3160,22 @@ nsDOMClassInfo::Init()
 #define DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES                           \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)                          \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGElement)                           \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)                         \
     DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)                     \
     DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver,          \
                                         nsDOMTouchEvent::PrefEnabled())
 
+#define DOM_CLASSINFO_SVG_TEXT_CONTENT_ELEMENT_MAP_ENTRIES \
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTextContentElement)   \
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTests)                \
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGStylable)             \
+    DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
+
 #define DOM_CLASSINFO_SVG_GRAPHIC_ELEMENT_MAP_ENTRIES \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGLocatable)       \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTransformable)   \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGStylable)        \
     DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
 
   // XXX - the proto chain stuff is sort of hackish, because of the MI in
   // the SVG interfaces. I doubt that extending the proto on one interface
@@ -3180,22 +3198,18 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGAElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTests)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGURIReference)
     DOM_CLASSINFO_SVG_GRAPHIC_ELEMENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(SVGAltGlyphElement, nsIDOMSVGAltGlyphElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTextPositioningElement)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTextContentElement)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTests)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGURIReference)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGStylable)
-    DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
+    DOM_CLASSINFO_SVG_TEXT_CONTENT_ELEMENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(SVGAnimateElement, nsIDOMSVGAnimateElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGAnimationElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTests)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGAnimateElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMElementTimeControl)
     DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
@@ -3426,16 +3440,22 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGFilterElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTests)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGURIReference)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGStylable)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGUnitTypes)
     DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(SVGForeignObjectElement, nsIDOMSVGForeignObjectElement)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGForeignObjectElement)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTests)
+    DOM_CLASSINFO_SVG_GRAPHIC_ELEMENT_MAP_ENTRIES
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(SVGGElement, nsIDOMSVGGElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGGElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTests)
     DOM_CLASSINFO_SVG_GRAPHIC_ELEMENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(SVGImageElement, nsIDOMSVGImageElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGImageElement)
@@ -3541,17 +3561,16 @@ nsDOMClassInfo::Init()
   
   DOM_CLASSINFO_MAP_BEGIN(SVGStyleElement, nsIDOMSVGStyleElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGStyleElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMLinkStyle)
     DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(SVGSVGElement, nsIDOMSVGSVGElement)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGSVGElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGFitToViewBox)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGLocatable)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTests)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGStylable)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGZoomAndPan)
     DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
@@ -3574,37 +3593,29 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(SVGTextElement, nsIDOMSVGTextElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTextPositioningElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTextContentElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTests)
     DOM_CLASSINFO_SVG_GRAPHIC_ELEMENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(SVGTextPathElement, nsIDOMSVGTextPathElement)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTextContentElement)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTests)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGURIReference)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGStylable)
-    DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
+    DOM_CLASSINFO_SVG_TEXT_CONTENT_ELEMENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(SVGTitleElement, nsIDOMSVGTitleElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTitleElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGStylable)
     DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(SVGTSpanElement, nsIDOMSVGTSpanElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTextPositioningElement)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTextContentElement)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTests)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGStylable)
-    DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
+    DOM_CLASSINFO_SVG_TEXT_CONTENT_ELEMENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(SVGUnknownElement, nsIDOMSVGElement)
     DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(SVGUseElement, nsIDOMSVGUseElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGUseElement)
@@ -3925,21 +3936,16 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(EventSource, nsIEventSource)
     DOM_CLASSINFO_MAP_ENTRY(nsIEventSource)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(SVGForeignObjectElement, nsIDOMSVGForeignObjectElement)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGForeignObjectElement)
-    DOM_CLASSINFO_SVG_GRAPHIC_ELEMENT_MAP_ENTRIES
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(XULCommandEvent, nsIDOMXULCommandEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCommandEvent)
     DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(CommandEvent, nsIDOMCommandEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCommandEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
@@ -4360,16 +4366,22 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(CallEvent, nsIDOMCallEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCallEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
   DOM_CLASSINFO_MAP_END
 #endif
 
+#ifdef MOZ_B2G_BT
+  DOM_CLASSINFO_MAP_BEGIN(BluetoothAdapter, nsIDOMBluetoothAdapter)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothAdapter)
+  DOM_CLASSINFO_MAP_END
+#endif
+
   DOM_CLASSINFO_MAP_BEGIN(DOMError, nsIDOMDOMError)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMError)
   DOM_CLASSINFO_MAP_END
 
 #ifdef NS_DEBUG
   {
     PRUint32 i = ArrayLength(sClassInfoData);
 
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -535,9 +535,13 @@ DOMCI_CLASS(MediaQueryList)
 DOMCI_CLASS(CustomEvent)
 
 #ifdef MOZ_B2G_RIL
 DOMCI_CLASS(Telephony)
 DOMCI_CLASS(TelephonyCall)
 DOMCI_CLASS(CallEvent)
 #endif
 
+#ifdef MOZ_B2G_BT
+DOMCI_CLASS(BluetoothAdapter)
+#endif
+
 DOMCI_CLASS(DOMError)
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -0,0 +1,39 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* 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 "BluetoothAdapter.h"
+#include "nsDOMClassInfo.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+BluetoothAdapter::BluetoothAdapter() : mPower(false)
+{
+}
+
+NS_INTERFACE_MAP_BEGIN(BluetoothAdapter)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothAdapter)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothAdapter)
+NS_INTERFACE_MAP_END
+  
+NS_IMPL_ADDREF(BluetoothAdapter)
+NS_IMPL_RELEASE(BluetoothAdapter)
+
+DOMCI_DATA(BluetoothAdapter, BluetoothAdapter)
+  
+NS_IMETHODIMP
+BluetoothAdapter::GetPower(bool* aPower)
+{
+  *aPower = mPower;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::SetPower(bool aPower)
+{
+  mPower = aPower;
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothAdapter.h
@@ -0,0 +1,28 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_bluetoothadapter_h__
+#define mozilla_dom_bluetooth_bluetoothadapter_h__
+
+#include "BluetoothCommon.h"
+#include "nsIDOMBluetoothAdapter.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothAdapter : public nsIDOMBluetoothAdapter
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMBLUETOOTHADAPTER
+
+  BluetoothAdapter();
+
+protected:
+  bool mPower;
+};
+
+END_BLUETOOTH_NAMESPACE
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -0,0 +1,19 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_bluetoothcommon_h__
+#define mozilla_dom_bluetooth_bluetoothcommon_h__
+
+#define BEGIN_BLUETOOTH_NAMESPACE \
+  namespace mozilla { namespace dom { namespace bluetooth {
+#define END_BLUETOOTH_NAMESPACE \
+  } /* namespace bluetooth */ } /* namespace dom */ } /* namespace mozilla */
+#define USING_BLUETOOTH_NAMESPACE \
+  using namespace mozilla::dom::bluetooth;
+
+class nsIDOMBluetooth;
+
+#endif // mozilla_dom_bluetooth_bluetoothcommon_h__
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/Makefile.in
@@ -0,0 +1,30 @@
+# 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/.
+
+DEPTH            = ../..
+topsrcdir        = @top_srcdir@
+srcdir           = @srcdir@
+VPATH            = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE           = dom
+LIBRARY_NAME     = dombluetooth_s
+XPIDL_MODULE     = dom_bluetooth
+LIBXUL_LIBRARY   = 1
+FORCE_STATIC_LIB = 1
+
+include $(topsrcdir)/dom/dom-config.mk
+
+CPPSRCS = \
+  BluetoothAdapter.cpp \
+  $(NULL)
+
+XPIDLSRCS = \
+  nsIDOMNavigatorBluetooth.idl \
+  nsIDOMBluetoothAdapter.idl \
+  $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/nsIDOMBluetoothAdapter.idl
@@ -0,0 +1,13 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* 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 "nsISupports.idl"
+
+[scriptable, builtinclass, uuid(29689a22-45ff-4ccf-b552-5364ce3a3642)]
+interface nsIDOMBluetoothAdapter : nsISupports
+{
+  attribute boolean power;
+};
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/nsIDOMNavigatorBluetooth.idl
@@ -0,0 +1,15 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* 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 "nsISupports.idl"
+
+interface nsIDOMBluetoothAdapter;
+
+[scriptable, uuid(677f2c2d-c4d1-41ea-addc-21d30d0d3858)]
+interface nsIDOMNavigatorBluetooth : nsISupports
+{
+  readonly attribute nsIDOMBluetoothAdapter mozBluetooth;
+};
--- a/dom/dom-config.mk
+++ b/dom/dom-config.mk
@@ -26,10 +26,14 @@ DOM_SRCDIRS = \
 ifdef MOZ_B2G_RIL
 DOM_SRCDIRS += \
   dom/system/b2g \
   dom/telephony \
   dom/wifi \
   $(NULL)
 endif
 
+ifdef MOZ_B2G_BT
+DOM_SRCDIRS += dom/bluetooth
+endif
+
 LOCAL_INCLUDES += $(DOM_SRCDIRS:%=-I$(topsrcdir)/%)
 DEFINES += -D_IMPL_NS_LAYOUT
--- a/dom/indexedDB/FileManager.cpp
+++ b/dom/indexedDB/FileManager.cpp
@@ -37,17 +37,19 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "FileManager.h"
 
 #include "mozIStorageConnection.h"
 #include "mozIStorageServiceQuotaManagement.h"
 #include "mozIStorageStatement.h"
 #include "nsISimpleEnumerator.h"
+
 #include "mozStorageCID.h"
+#include "mozStorageHelper.h"
 #include "nsContentUtils.h"
 
 #include "FileInfo.h"
 #include "IndexedDatabaseManager.h"
 
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
@@ -88,16 +90,18 @@ FileManager::Init(nsIFile* aDirectory,
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ENSURE_TRUE(isDirectory, NS_ERROR_FAILURE);
   }
   else {
     rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
+  mozStorageTransaction transaction(aConnection, false);
+
   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE VIRTUAL TABLE fs USING filesystem;"
   ));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<mozIStorageStatement> stmt;
   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT name, (name IN (SELECT id FROM file)) FROM fs "
@@ -146,16 +150,17 @@ FileManager::Init(nsIFile* aDirectory,
   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "DROP TABLE fs;"
   ));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aDirectory->GetPath(mDirectoryPath);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  transaction.Commit();
   return NS_OK;
 }
 
 nsresult
 FileManager::Load(mozIStorageConnection* aConnection)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
--- a/dom/plugins/base/Makefile.in
+++ b/dom/plugins/base/Makefile.in
@@ -127,20 +127,16 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),qt)
 else
 	CPPSRCS += nsPluginNativeWindow.cpp
 endif
 endif
 endif
 endif
 endif
 
-ifdef MOZ_JAVA_COMPOSITOR
-DEFINES += -DMOZ_JAVA_COMPOSITOR
-endif
-
 LOCAL_INCLUDES += \
   -DSK_BUILD_FOR_ANDROID_NDK \
   -I$(topsrcdir)/widget/android \
   -I$(topsrcdir)/xpcom/base/ \
   -I$(topsrcdir)/gfx/skia/include/core \
   -I$(topsrcdir)/gfx/skia/include/config \
   $(MOZ_CAIRO_CFLAGS) \
   $(NULL)
--- a/dom/system/b2g/Makefile.in
+++ b/dom/system/b2g/Makefile.in
@@ -2,16 +2,18 @@
 # 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/.
 
 DEPTH            = ../../..
 topsrcdir        = @top_srcdir@
 srcdir           = @srcdir@
 VPATH            = @srcdir@
 
+relativesrcdir   = dom/system/b2g
+
 include $(DEPTH)/config/autoconf.mk
 
 MODULE           = dom
 LIBRARY_NAME     = domsystemb2g_s
 XPIDL_MODULE     = dom_system_b2g
 LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
 
@@ -48,9 +50,13 @@ EXTRA_COMPONENTS = \
   $(NULL)
 
 EXTRA_JS_MODULES = \
   ril_consts.js \
   ril_worker.js \
   systemlibs.js \
   $(NULL)
 
+ifdef ENABLE_TESTS
+XPCSHELL_TESTS = tests
+endif
+
 include $(topsrcdir)/config/rules.mk
--- a/dom/system/b2g/RadioInterfaceLayer.js
+++ b/dom/system/b2g/RadioInterfaceLayer.js
@@ -314,25 +314,25 @@ RadioInterfaceLayer.prototype = {
                                            message.sender || null,
                                            message.receiver || null,
                                            message.body || null,
                                            message.timestamp);
     Services.obs.notifyObservers(sms, kSmsReceivedObserverTopic, null);
   },
 
   handleSmsSent: function handleSmsSent(message) {
-    let message = gSmsService.createSmsMessage(-1,
-                                               DOM_SMS_DELIVERY_SENT,
-                                               message.SMSC,
-                                               message.number,
-                                               message.body,
-                                               Date.now());
+    let sms = gSmsService.createSmsMessage(-1,
+                                           DOM_SMS_DELIVERY_SENT,
+                                           null,
+                                           message.number,
+                                           message.body,
+                                           Date.now());
     //TODO At this point we should save the sms into the DB (bug 712809)
-    //TODO handle errors (bug XXX)
-    gSmsRequestManager.notifySmsSent(message.requestId, message);
+    //TODO handle errors (bug 727319)
+    gSmsRequestManager.notifySmsSent(message.requestId, sms);
   },
 
   /**
    * Handle data call state changes.
    */
   handleDataCallState: function handleDataCallState(datacall) {
     this._deliverDataCallCallback("dataCallStateChanged",
                                   [datacall.cid, datacall.ifname, datacall.state]);
--- a/dom/system/b2g/ril_worker.js
+++ b/dom/system/b2g/ril_worker.js
@@ -59,17 +59,20 @@
  * terms of object allocations. As a result, it may look more like C than
  * JavaScript, and that's intended.
  */
 
 "use strict";
 
 importScripts("ril_consts.js", "systemlibs.js");
 
-let DEBUG = false;
+// We leave this as 'undefined' instead of setting it to 'false'. That
+// way an outer scope can define it to 'true' (e.g. for testing purposes)
+// without us overriding that here.
+let DEBUG;
 
 const INT32_MAX   = 2147483647;
 const UINT8_SIZE  = 1;
 const UINT16_SIZE = 2;
 const UINT32_SIZE = 4;
 const PARCEL_SIZE_SIZE = UINT32_SIZE;
 
 let RILQUIRKS_CALLSTATE_EXTRA_UINT32 = false;
@@ -103,16 +106,19 @@ let Buf = {
     this.incomingReadIndex = 0;
 
     // Leave room for the parcel size for outgoing parcels.
     this.outgoingIndex = PARCEL_SIZE_SIZE;
 
     // How many bytes we've read for this parcel so far.
     this.readIncoming = 0;
 
+    // How many bytes available as parcel data.
+    this.readAvailable = 0;
+
     // Size of the incoming parcel. If this is zero, we're expecting a new
     // parcel.
     this.currentParcelSize = 0;
 
     // This gets incremented each time we send out a parcel.
     this.token = 1;
 
     // Maps tokens we send out with requests to the request type, so that
@@ -187,23 +193,32 @@ let Buf = {
   },
 
   /**
    * Functions for reading data from the incoming buffer.
    *
    * These are all little endian, apart from readParcelSize();
    */
 
-  readUint8: function readUint8() {
+  readUint8Unchecked: function readUint8Unchecked() {
     let value = this.incomingBytes[this.incomingReadIndex];
     this.incomingReadIndex = (this.incomingReadIndex + 1) %
                              this.INCOMING_BUFFER_LENGTH;
     return value;
   },
 
+  readUint8: function readUint8() {
+    if (!this.readAvailable) {
+      throw new Error("Trying to read data beyond the parcel end!");
+    }
+
+    this.readAvailable--;
+    return this.readUint8Unchecked();
+  },
+
   readUint16: function readUint16() {
     return this.readUint8() | this.readUint8() << 8;
   },
 
   readUint32: function readUint32() {
     return this.readUint8()       | this.readUint8() <<  8 |
            this.readUint8() << 16 | this.readUint8() << 24;
   },
@@ -246,18 +261,20 @@ let Buf = {
     let strings = [];
     for (let i = 0; i < num_strings; i++) {
       strings.push(this.readString());
     }
     return strings;
   },
 
   readParcelSize: function readParcelSize() {
-    return this.readUint8() << 24 | this.readUint8() << 16 |
-           this.readUint8() <<  8 | this.readUint8();
+    return this.readUint8Unchecked() << 24 |
+           this.readUint8Unchecked() << 16 |
+           this.readUint8Unchecked() <<  8 |
+           this.readUint8Unchecked();
   },
 
   /**
    * Functions for writing data to the outgoing buffer.
    */
 
   writeUint8: function writeUint8(value) {
     if (this.outgoingIndex >= this.OUTGOING_BUFFER_LENGTH) {
@@ -407,47 +424,47 @@ let Buf = {
           parcel = Array.slice(this.incomingBytes.subarray(
             this.incomingReadIndex, expectedAfterIndex));
         }
         debug("Parcel (size " + this.currentParcelSize + "): " + parcel);
       }
 
       if (DEBUG) debug("We have at least one complete parcel.");
       try {
+        this.readAvailable = this.currentParcelSize;
         this.processParcel();
       } catch (ex) {
         if (DEBUG) debug("Parcel handling threw " + ex + "\n" + ex.stack);
       }
 
       // Ensure that the whole parcel was consumed.
       if (this.incomingReadIndex != expectedAfterIndex) {
         if (DEBUG) {
           debug("Parcel handler didn't consume whole parcel, " +
                 Math.abs(expectedAfterIndex - this.incomingReadIndex) +
                 " bytes left over");
         }
         this.incomingReadIndex = expectedAfterIndex;
       }
       this.readIncoming -= this.currentParcelSize;
+      this.readAvailable = 0;
       this.currentParcelSize = 0;
     }
   },
 
   /**
    * Process one parcel.
    */
   processParcel: function processParcel() {
     let response_type = this.readUint32();
-    let length = this.readIncoming - UINT32_SIZE;
 
     let request_type, options;
     if (response_type == RESPONSE_TYPE_SOLICITED) {
       let token = this.readUint32();
       let error = this.readUint32();
-      length -= 2 * UINT32_SIZE;
 
       options = this.tokenRequestMap[token];
       request_type = options.rilRequestType;
       if (error) {
         //TODO
         if (DEBUG) {
           debug("Received error " + error + " for solicited parcel type " +
                 request_type);
@@ -457,24 +474,23 @@ let Buf = {
       if (DEBUG) {
         debug("Solicited response for request type " + request_type +
               ", token " + token);
       }
       delete this.tokenRequestMap[token];
       this.lastSolicitedToken = token;
     } else if (response_type == RESPONSE_TYPE_UNSOLICITED) {
       request_type = this.readUint32();
-      length -= UINT32_SIZE;
       if (DEBUG) debug("Unsolicited response for request type " + request_type);
     } else {
       if (DEBUG) debug("Unknown response type: " + response_type);
       return;
     }
 
-    RIL.handleParcel(request_type, length, options);
+    RIL.handleParcel(request_type, this.readAvailable, options);
   },
 
   /**
    * Start a new outgoing parcel.
    *
    * @param type
    *        Integer specifying the request type.
    * @param options [optional]
new file mode 100644
--- /dev/null
+++ b/dom/system/b2g/tests/header_helpers.js
@@ -0,0 +1,148 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+
+let subscriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
+                        .getService(Ci.mozIJSSubScriptLoader);
+
+/**
+ * Start a new RIL worker.
+ * 
+ * @param custom_ns
+ *        Namespace with symbols to be injected into the new worker
+ *        namespace.
+ *
+ * @return an object that represents the worker's namespace.
+ *
+ * @note that this does not start an actual worker thread. The worker
+ * is executed on the main thread, within a separate namespace object.
+ */
+function newWorker(custom_ns) {
+  let worker_ns = {
+    importScripts: function fakeImportScripts() {
+      Array.slice(arguments).forEach(function (script) {
+        subscriptLoader.loadSubScript("resource://gre/modules/" + script, this);
+      }, this);
+    },
+
+    postRILMessage: function fakePostRILMessage(message) {
+    },
+
+    postMessage: function fakepostMessage(message) {
+    },
+
+    // Define these variables inside the worker scope so ES5 strict mode
+    // doesn't flip out.
+    onmessage: undefined,
+    onerror: undefined,
+
+    DEBUG: true
+  };
+  // The 'self' variable in a worker points to the worker's own namespace.
+  worker_ns.self = worker_ns;
+
+  // Copy the custom definitions over.
+  for (let key in custom_ns) {
+    worker_ns[key] = custom_ns[key];
+  }
+
+  // Load the RIL worker itself.
+  worker_ns.importScripts("ril_worker.js");
+
+  return worker_ns;
+}
+
+/**
+ * Create a parcel suitable for postRILMessage().
+ *
+ * @param fakeParcelSize
+ *        Value to be written to parcel size field for testing
+ *        incorrect/incomplete parcel reading. Replaced with correct
+ *        one determined length of data if negative.
+ * @param response
+ *        Response code of the incoming parcel.
+ * @param request
+ *        Request code of the incoming parcel.
+ * @param data
+ *        Extra data to be appended.
+ *
+ * @return an Uint8Array carrying all parcel data.
+ */
+function newIncomingParcel(fakeParcelSize, response, request, data) {
+  const UINT32_SIZE = 4;
+  const PARCEL_SIZE_SIZE = 4;
+
+  let realParcelSize = data.length + 2 * UINT32_SIZE;
+  let buffer = new ArrayBuffer(realParcelSize + PARCEL_SIZE_SIZE);
+  let bytes = new Uint8Array(buffer);
+
+  let writeIndex = 0;
+  function writeUint8(value) {
+    bytes[writeIndex] = value;
+    ++writeIndex;
+  }
+
+  function writeUint32(value) {
+    writeUint8(value & 0xff);
+    writeUint8((value >> 8) & 0xff);
+    writeUint8((value >> 16) & 0xff);
+    writeUint8((value >> 24) & 0xff);
+  }
+
+  function writeParcelSize(value) {
+    writeUint8((value >> 24) & 0xff);
+    writeUint8((value >> 16) & 0xff);
+    writeUint8((value >> 8) & 0xff);
+    writeUint8(value & 0xff);
+  }
+
+  if (fakeParcelSize < 0) {
+    fakeParcelSize = realParcelSize;
+  }
+  writeParcelSize(fakeParcelSize);
+
+  writeUint32(response);
+  writeUint32(request);
+
+  // write parcel data
+  for (let ii = 0; ii < data.length; ++ii) {
+    writeUint8(data[ii]);
+  }
+
+  return bytes;
+}
+
+/**
+ * Test whether specified function throws exception with expected
+ * result.
+ *
+ * @param func
+ *        Function to be tested.
+ * @param result
+ *        Expected result. <code>null</code> for no throws.
+ * @param stack
+ *        Optional stack object to be printed. <code>null</code> for
+ *        Components#stack#caller.
+ */
+function do_check_throws(func, result, stack)
+{
+  if (!stack)
+    stack = Components.stack.caller;
+
+  try {
+    func();
+  } catch (exc) {
+    if (exc.result == result)
+      return;
+    do_throw("expected result " + result + ", caught " + exc, stack);
+  }
+
+  if (result) {
+    do_throw("expected result " + result + ", none thrown", stack);
+  }
+}
+
new file mode 100644
--- /dev/null
+++ b/dom/system/b2g/tests/test_ril_worker_buf.js
@@ -0,0 +1,84 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function run_test() {
+  run_next_test();
+}
+
+/**
+ * Add test function with specified parcel and request handler.
+ *
+ * @param parcel
+ *        Incoming parcel to be tested.
+ * @param handler
+ *        Handler to be invoked as RIL request handler.
+ */
+function add_test_incoming_parcel(parcel, handler) {
+  add_test(function test_incoming_parcel() {
+    let worker = newWorker({
+      postRILMessage: function fakePostRILMessage(data) {
+        // do nothing
+      },
+      postMessage: function fakePostMessage(message) {
+        // do nothing
+      }
+    });
+
+    if (!parcel) {
+      parcel = newIncomingParcel(-1,
+                                 worker.RESPONSE_TYPE_UNSOLICITED,
+                                 worker.REQUEST_REGISTRATION_STATE,
+                                 [0, 0, 0, 0]);
+    }
+
+    // supports only requests less or equal than UINT8_MAX(255).
+    let request = parcel[worker.PARCEL_SIZE_SIZE + worker.UINT32_SIZE];
+    worker.RIL[request] = function ril_request_handler() {
+      handler(worker);
+      worker.postMessage();
+    };
+
+    worker.onRILMessage(parcel);
+
+    // end of incoming parcel's trip, let's do next test.
+    run_next_test();
+  });
+}
+
+// Test normal parcel handling.
+add_test_incoming_parcel(null,
+  function test_normal_parcel_handling(worker) {
+    do_check_throws(function normal_handler(worker) {
+      // reads exactly the same size, should not throw anything.
+      worker.Buf.readUint32();
+    });
+  }
+);
+
+// Test parcel under read.
+add_test_incoming_parcel(null,
+  function test_parcel_under_read(worker) {
+    do_check_throws(function under_read_handler() {
+      // reads less than parcel size, should not throw.
+      worker.Buf.readUint16();
+    }, false);
+  }
+);
+
+// Test parcel over read.
+add_test_incoming_parcel(null,
+  function test_parcel_over_read(worker) {
+    let buf = worker.Buf;
+
+    // read all data available
+    while (buf.readAvailable > 0) {
+      buf.readUint8();
+    }
+
+    do_check_throws(function over_read_handler() {
+      // reads more than parcel size, should throw an error.
+      buf.readUint8();
+    }, new Error("Trying to read data beyond the parcel end!").result);
+  }
+);
+
new file mode 100644
--- /dev/null
+++ b/dom/system/b2g/tests/xpcshell.ini
@@ -0,0 +1,5 @@
+[DEFAULT]
+head = header_helpers.js
+tail =
+
+[test_ril_worker_buf.js]
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -553,16 +553,19 @@ GLContext::InitWithPrefix(const char *pr
     return mInitialized;
 }
 
 void
 GLContext::InitExtensions()
 {
     MakeCurrent();
     const GLubyte *extensions = fGetString(LOCAL_GL_EXTENSIONS);
+    if (!extensions)
+        return;
+
     char *exts = strdup((char *)extensions);
 
 #ifdef DEBUG
     static bool once = false;
 #else
     const bool once = true;
 #endif
 
--- a/gfx/src/Makefile.in
+++ b/gfx/src/Makefile.in
@@ -49,17 +49,17 @@ EXPORT_LIBRARY = 1
 GRE_MODULE     = 1
 LIBXUL_LIBRARY = 1
 IS_COMPONENT   = 1
 
 XPIDLSRCS = \
 	nsIFontEnumerator.idl \
 	nsIScriptableRegion.idl \
 	$(NULL)
-        
+
 EXPORTS	= \
 	gfxCore.h \
 	gfxCrashReporterUtils.h \
 	nsColor.h \
 	nsColorNames.h \
 	nsColorNameList.h \
 	nsCoord.h \
 	nsFont.h \
@@ -98,44 +98,16 @@ CPPSRCS = \
         nsFontMetrics.cpp \
         nsThebesFontEnumerator.cpp \
        $(NULL)
 
 ifdef MOZ_X11
 CPPSRCS += X11Util.cpp
 endif
 
-ifeq ($(MOZ_WIDGET_TOOLKIT),android)
-CPPSRCS += nsSystemFontsAndroid.cpp
-endif
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),gonk)
-CPPSRCS += nsSystemFontsAndroid.cpp
-endif
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
-CMMSRCS = nsSystemFontsMac.mm
-endif
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
-CPPSRCS += nsSystemFontsGTK2.cpp
-endif
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),os2)
-CPPSRCS += nsSystemFontsOS2.cpp
-endif
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),qt)
-CPPSRCS += nsSystemFontsQt.cpp
-endif
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
-CPPSRCS += nsSystemFontsWin.cpp
-endif
-
 include $(topsrcdir)/config/rules.mk
 
 CXXFLAGS += $(TK_CFLAGS) $(MOZ_CAIRO_CFLAGS)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 DEFINES += -DMOZ_ENABLE_GTK2
 CXXFLAGS += $(MOZ_GTK2_CFLAGS) $(MOZ_PANGO_CFLAGS)
 endif
--- a/gfx/src/nsDeviceContext.cpp
+++ b/gfx/src/nsDeviceContext.cpp
@@ -49,49 +49,28 @@
 #include "mozilla/Preferences.h"
 #include "nsIServiceManager.h"
 #include "nsILanguageAtomService.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
 
 #include "gfxImageSurface.h"
 
+#if !XP_MACOSX
+#include "gfxPDFSurface.h"
+#endif
+
 #ifdef MOZ_ENABLE_GTK2
-#include "nsSystemFontsGTK2.h"
-#include "gfxPDFSurface.h"
 #include "gfxPSSurface.h"
-static nsSystemFontsGTK2 *gSystemFonts = nsnull;
 #elif XP_WIN
-#include "nsSystemFontsWin.h"
 #include "gfxWindowsSurface.h"
-#include "gfxPDFSurface.h"
-static nsSystemFontsWin *gSystemFonts = nsnull;
 #elif defined(XP_OS2)
-#include "nsSystemFontsOS2.h"
 #include "gfxOS2Surface.h"
-#include "gfxPDFSurface.h"
-static nsSystemFontsOS2 *gSystemFonts = nsnull;
 #elif XP_MACOSX
-#include "nsSystemFontsMac.h"
 #include "gfxQuartzSurface.h"
-static nsSystemFontsMac *gSystemFonts = nsnull;
-#elif defined(MOZ_WIDGET_QT)
-#include "nsSystemFontsQt.h"
-#include "gfxPDFSurface.h"
-static nsSystemFontsQt *gSystemFonts = nsnull;
-#elif defined(MOZ_WIDGET_ANDROID)
-#include "nsSystemFontsAndroid.h"
-#include "gfxPDFSurface.h"
-static nsSystemFontsAndroid *gSystemFonts = nsnull;
-#elif defined(MOZ_WIDGET_GONK)
-#include "nsSystemFontsAndroid.h"
-#include "gfxPDFSurface.h"
-static nsSystemFontsAndroid *gSystemFonts = nsnull;
-#else
-#error Need to declare gSystemFonts!
 #endif
 
 using namespace mozilla;
 using mozilla::services::GetObserverService;
 
 class nsFontCache MOZ_FINAL : public nsIObserver
 {
 public:
@@ -447,65 +426,16 @@ nsDeviceContext::CreateRenderingContext(
     pContext->Init(this, mPrintingSurface);
     pContext->Scale(mPrintingScale, mPrintingScale);
     aContext = pContext;
     NS_ADDREF(aContext);
 
     return NS_OK;
 }
 
-/* static */ void
-nsDeviceContext::ClearCachedSystemFonts()
-{
-    if (gSystemFonts) {
-        delete gSystemFonts;
-        gSystemFonts = nsnull;
-    }
-}
-
-nsresult
-nsDeviceContext::GetSystemFont(nsSystemFontID aID, nsFont *aFont) const
-{
-    if (!gSystemFonts) {
-#ifdef MOZ_ENABLE_GTK2
-        gSystemFonts = new nsSystemFontsGTK2();
-#elif XP_WIN
-        gSystemFonts = new nsSystemFontsWin();
-#elif XP_OS2
-        gSystemFonts = new nsSystemFontsOS2();
-#elif XP_MACOSX
-        gSystemFonts = new nsSystemFontsMac();
-#elif defined(MOZ_WIDGET_QT)
-        gSystemFonts = new nsSystemFontsQt();
-#elif defined(ANDROID)
-        gSystemFonts = new nsSystemFontsAndroid();
-#else
-#error Need to know how to create gSystemFonts, fix me!
-#endif
-    }
-
-    nsString fontName;
-    gfxFontStyle fontStyle;
-    nsresult rv = gSystemFonts->GetSystemFont(aID, &fontName, &fontStyle);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    aFont->name = fontName;
-    aFont->style = fontStyle.style;
-    aFont->systemFont = fontStyle.systemFont;
-    aFont->variant = NS_FONT_VARIANT_NORMAL;
-    aFont->weight = fontStyle.weight;
-    aFont->stretch = fontStyle.stretch;
-    aFont->decorations = NS_FONT_DECORATION_NONE;
-    aFont->size = NSFloatPixelsToAppUnits(fontStyle.size, UnscaledAppUnitsPerDevPixel());
-    //aFont->langGroup = fontStyle.langGroup;
-    aFont->sizeAdjust = fontStyle.sizeAdjust;
-
-    return rv;
-}
-
 nsresult
 nsDeviceContext::GetDepth(PRUint32& aDepth)
 {
     if (mDepth == 0) {
         nsCOMPtr<nsIScreen> primaryScreen;
         mScreenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen));
         primaryScreen->GetColorDepth(reinterpret_cast<PRInt32 *>(&mDepth));
     }
--- a/gfx/src/nsDeviceContext.h
+++ b/gfx/src/nsDeviceContext.h
@@ -46,39 +46,16 @@
 #include "nsIWidget.h"
 #include "nsCoord.h"
 #include "gfxContext.h"
 
 class nsIAtom;
 class nsFontCache;
 class gfxUserFontSet;
 
-typedef enum {
-    eSystemFont_Caption,         // css2
-    eSystemFont_Icon,
-    eSystemFont_Menu,
-    eSystemFont_MessageBox,
-    eSystemFont_SmallCaption,
-    eSystemFont_StatusBar,
-
-    eSystemFont_Window,          // css3
-    eSystemFont_Document,
-    eSystemFont_Workspace,
-    eSystemFont_Desktop,
-    eSystemFont_Info,
-    eSystemFont_Dialog,
-    eSystemFont_Button,
-    eSystemFont_PullDownMenu,
-    eSystemFont_List,
-    eSystemFont_Field,
-
-    eSystemFont_Tooltips,        // moz
-    eSystemFont_Widget
-} nsSystemFontID;
-
 class nsDeviceContext
 {
 public:
     nsDeviceContext();
     ~nsDeviceContext();
 
     NS_INLINE_DECL_REFCOUNTING(nsDeviceContext)
 
@@ -146,32 +123,16 @@ public:
     /**
      * Get the unscaled ratio of app units to dev pixels; useful if something
      * needs to be converted from to unscaled pixels
      */
     PRInt32 UnscaledAppUnitsPerDevPixel() const
     { return mAppUnitsPerDevNotScaledPixel; }
 
     /**
-     * Fill in an nsFont based on the ID of a system font.  This function
-     * may or may not fill in the size, so the size should be set to a
-     * reasonable default before calling.
-     *
-     * @param aID    The system font ID.
-     * @param aInfo  The font structure to be filled in.
-     * @return error status
-     */
-    nsresult GetSystemFont(nsSystemFontID aID, nsFont *aFont) const;
-
-    /**
-     * Clear cached system fonts (refresh from theme when requested).
-     */
-    static void ClearCachedSystemFonts();
-
-    /**
      * Get the nsFontMetrics that describe the properties of
      * an nsFont.
      * @param aFont font description to obtain metrics for
      * @param aLanguage the language of the document
      * @param aMetrics out parameter for font metrics
      * @param aUserFontSet user font set
      * @return error status
      */
deleted file mode 100644
--- a/gfx/src/nsSystemFontsAndroid.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Android port
- *
- * The Initial Developer of the Original Code is mozilla.org.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Vladimir Vukicevic <vladimir@pobox.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsSystemFontsAndroid.h"
-#include "gfxPlatform.h"
-
-#define DEFAULT_FONT  "Droid Sans"
-
-nsSystemFontsAndroid::nsSystemFontsAndroid()
-  : mDefaultFontName(NS_LITERAL_STRING(DEFAULT_FONT))
-  , mButtonFontName(NS_LITERAL_STRING(DEFAULT_FONT))
-  , mFieldFontName(NS_LITERAL_STRING(DEFAULT_FONT))
-  , mMenuFontName(NS_LITERAL_STRING(DEFAULT_FONT))
-{
-}
-
-nsSystemFontsAndroid::~nsSystemFontsAndroid()
-{
-}
-
-nsresult
-nsSystemFontsAndroid::GetSystemFontInfo(const char *aClassName, nsString *aFontName,
-                                        gfxFontStyle *aFontStyle) const
-{
-    aFontStyle->style = FONT_STYLE_NORMAL;
-    aFontStyle->systemFont = true;
-    *aFontName = NS_LITERAL_STRING("Droid Sans");
-    aFontStyle->weight = 400;
-    aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
-    aFontStyle->size = 9.0 * 96.0f / 72.0f;
-    return NS_OK;
-}
-
-
-nsresult
-nsSystemFontsAndroid::GetSystemFont(nsSystemFontID anID, nsString *aFontName,
-                                    gfxFontStyle *aFontStyle) const
-{
-    switch (anID) {
-    case eSystemFont_Menu:         // css2
-    case eSystemFont_PullDownMenu: // css3
-        *aFontName = mMenuFontName;
-        *aFontStyle = mMenuFontStyle;
-        break;
-
-    case eSystemFont_Field:        // css3
-    case eSystemFont_List:         // css3
-        *aFontName = mFieldFontName;
-        *aFontStyle = mFieldFontStyle;
-        break;
-
-    case eSystemFont_Button:       // css3
-        *aFontName = mButtonFontName;
-        *aFontStyle = mButtonFontStyle;
-        break;
-
-    case eSystemFont_Caption:      // css2
-    case eSystemFont_Icon:         // css2
-    case eSystemFont_MessageBox:   // css2
-    case eSystemFont_SmallCaption: // css2
-    case eSystemFont_StatusBar:    // css2
-    case eSystemFont_Window:       // css3
-    case eSystemFont_Document:     // css3
-    case eSystemFont_Workspace:    // css3
-    case eSystemFont_Desktop:      // css3
-    case eSystemFont_Info:         // css3
-    case eSystemFont_Dialog:       // css3
-    case eSystemFont_Tooltips:     // moz
-    case eSystemFont_Widget:       // moz
-        *aFontName = mDefaultFontName;
-        *aFontStyle = mDefaultFontStyle;
-        break;
-    }
-
-    return NS_OK;
-}
-
deleted file mode 100644
--- a/gfx/src/nsSystemFontsAndroid.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Android port
- *
- * The Initial Developer of the Original Code is mozilla.org.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Vladimir Vukicevic <vladimir@pobox.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef _NS_SYSTEMFONTSANDROID_H_
-#define _NS_SYSTEMFONTSANDROID_H_
-
-#include "gfxFont.h"
-#include "nsDeviceContext.h"
-
-class nsSystemFontsAndroid
-{
-public:
-    nsSystemFontsAndroid();
-    ~nsSystemFontsAndroid();
-
-    nsresult GetSystemFont(nsSystemFontID anID, nsString *aFontName,
-                           gfxFontStyle *aFontStyle) const;
-
-private:
-
-    nsresult GetSystemFontInfo(const char *aClassName, nsString *aFontName,
-                               gfxFontStyle *aFontStyle) const;
-
-    /*
-     * The following system font constants exist:
-     *
-     * css2: http://www.w3.org/TR/REC-CSS2/fonts.html#x27
-     * eSystemFont_Caption, eSystemFont_Icon, eSystemFont_Menu,
-     * eSystemFont_MessageBox, eSystemFont_SmallCaption,
-     * eSystemFont_StatusBar,
-     * // css3
-     * eSystemFont_Window, eSystemFont_Document,
-     * eSystemFont_Workspace, eSystemFont_Desktop,
-     * eSystemFont_Info, eSystemFont_Dialog,
-     * eSystemFont_Button, eSystemFont_PullDownMenu,
-     * eSystemFont_List, eSystemFont_Field,
-     * // moz
-     * eSystemFont_Tooltips, eSystemFont_Widget
-     */
-    nsString mDefaultFontName, mButtonFontName, mFieldFontName, mMenuFontName;
-    gfxFontStyle mDefaultFontStyle, mButtonFontStyle, mFieldFontStyle, mMenuFontStyle;
-};
-
-#endif /* _NS_SYSTEMFONTSANDROID_H_ */
-
deleted file mode 100644
--- a/gfx/src/nsSystemFontsGTK2.cpp
+++ /dev/null
@@ -1,287 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is thebes gfx
- *
- * The Initial Developer of the Original Code is mozilla.org.
- * Portions created by the Initial Developer are Copyright (C) 2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Vladimir Vukicevic <vladimir@pobox.com>
- *   Stuart Parmenter <pavlov@pavlov.net>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-// for strtod()
-#include <stdlib.h>
-
-#include "nsSystemFontsGTK2.h"
-#include "prlink.h"
-
-#include <gtk/gtk.h>
-#include <gdk/gdk.h>
-
-#ifdef MOZ_PANGO
-#include <pango/pango.h>
-#include <pango/pango-fontmap.h>
-#endif
-
-#include <fontconfig/fontconfig.h>
-#include "gfxPlatformGtk.h"
-
-// Glue to avoid build/runtime dependencies on Pango > 1.6
-#if defined(MOZ_PANGO) && !defined(THEBES_USE_PANGO_CAIRO)
-static gboolean
-(* PTR_pango_font_description_get_size_is_absolute)(PangoFontDescription*)
-    = nsnull;
-
-static void InitPangoLib()
-{
-    static bool initialized = false;
-    if (initialized)
-        return;
-    initialized = true;
-
-    PRLibrary *pangoLib = nsnull;
-    PTR_pango_font_description_get_size_is_absolute =
-        (gboolean (*)(PangoFontDescription*))
-        PR_FindFunctionSymbolAndLibrary("pango_font_description_get_size_is_absolute",
-                                        &pangoLib);
-    if (pangoLib)
-        PR_UnloadLibrary(pangoLib);
-}
-
-static void
-ShutdownPangoLib()
-{
-}
-
-static gboolean
-MOZ_pango_font_description_get_size_is_absolute(PangoFontDescription *desc)
-{
-    if (PTR_pango_font_description_get_size_is_absolute) {
-        return PTR_pango_font_description_get_size_is_absolute(desc);
-    }
-
-    // In old versions of pango, this was always false.
-    return false;
-}
-#else
-static inline void InitPangoLib()
-{
-}
-
-static inline void ShutdownPangoLib()
-{
-}
-
-#ifdef MOZ_PANGO
-static inline gboolean
-MOZ_pango_font_description_get_size_is_absolute(PangoFontDescription *desc)
-{
-    pango_font_description_get_size_is_absolute(desc);
-}
-#endif
-#endif
-
-nsSystemFontsGTK2::nsSystemFontsGTK2()
-  : mDefaultFontName(NS_LITERAL_STRING("sans-serif"))
-  , mButtonFontName(NS_LITERAL_STRING("sans-serif"))
-  , mFieldFontName(NS_LITERAL_STRING("sans-serif"))
-  , mMenuFontName(NS_LITERAL_STRING("sans-serif"))
-{
-    InitPangoLib();
-
-    /*
-     * Much of the widget creation code here is similar to the code in
-     * nsLookAndFeel::InitColors().
-     */
-
-    // mDefaultFont
-    GtkWidget *label = gtk_label_new("M");
-    GtkWidget *parent = gtk_fixed_new();
-    GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
-
-    gtk_container_add(GTK_CONTAINER(parent), label);
-    gtk_container_add(GTK_CONTAINER(window), parent);
-
-    gtk_widget_ensure_style(label);
-
-    GetSystemFontInfo(label, &mDefaultFontName, &mDefaultFontStyle);
-
-    gtk_widget_destroy(window);  // no unref, windows are different
-
-    // mFieldFont
-    GtkWidget *entry = gtk_entry_new();
-    parent = gtk_fixed_new();
-    window = gtk_window_new(GTK_WINDOW_POPUP);
-
-    gtk_container_add(GTK_CONTAINER(parent), entry);
-    gtk_container_add(GTK_CONTAINER(window), parent);
-    gtk_widget_ensure_style(entry);
-
-    GetSystemFontInfo(entry, &mFieldFontName, &mFieldFontStyle);
-
-    gtk_widget_destroy(window);  // no unref, windows are different
-
-    // mMenuFont
-    GtkWidget *accel_label = gtk_accel_label_new("M");
-    GtkWidget *menuitem = gtk_menu_item_new();
-    GtkWidget *menu = gtk_menu_new();
-    g_object_ref_sink(GTK_OBJECT(menu));
-
-    gtk_container_add(GTK_CONTAINER(menuitem), accel_label);
-    gtk_menu_shell_append((GtkMenuShell *)GTK_MENU(menu), menuitem);
-
-    gtk_widget_ensure_style(accel_label);
-
-    GetSystemFontInfo(accel_label, &mMenuFontName, &mMenuFontStyle);
-
-    g_object_unref(menu);
-
-    // mButtonFont
-    parent = gtk_fixed_new();
-    GtkWidget *button = gtk_button_new();
-    label = gtk_label_new("M");
-    window = gtk_window_new(GTK_WINDOW_POPUP);
-          
-    gtk_container_add(GTK_CONTAINER(button), label);
-    gtk_container_add(GTK_CONTAINER(parent), button);
-    gtk_container_add(GTK_CONTAINER(window), parent);
-
-    gtk_widget_ensure_style(label);
-
-    GetSystemFontInfo(label, &mButtonFontName, &mButtonFontStyle);
-
-    gtk_widget_destroy(window);  // no unref, windows are different
-}
-
-nsSystemFontsGTK2::~nsSystemFontsGTK2()
-{
-    ShutdownPangoLib();
-}
-
-nsresult
-nsSystemFontsGTK2::GetSystemFontInfo(GtkWidget *aWidget, nsString *aFontName,
-                                     gfxFontStyle *aFontStyle) const
-{
-#ifdef MOZ_PANGO
-    GtkSettings *settings = gtk_widget_get_settings(aWidget);
-
-    aFontStyle->style       = FONT_STYLE_NORMAL;
-
-    gchar *fontname;
-    g_object_get(settings, "gtk-font-name", &fontname, NULL);
-
-    PangoFontDescription *desc;
-    desc = pango_font_description_from_string(fontname);
-
-    aFontStyle->systemFont = true;
-
-    g_free(fontname);
-
-    NS_NAMED_LITERAL_STRING(quote, "\"");
-    NS_ConvertUTF8toUTF16 family(pango_font_description_get_family(desc));
-    *aFontName = quote + family + quote;
-
-    aFontStyle->weight = pango_font_description_get_weight(desc);
-
-    // FIXME: Set aFontStyle->stretch correctly!
-    aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
-
-    float size = float(pango_font_description_get_size(desc)) / PANGO_SCALE;
-
-    // |size| is now either pixels or pango-points (not Mozilla-points!)
-
-    if (!MOZ_pango_font_description_get_size_is_absolute(desc)) {
-        // |size| is in pango-points, so convert to pixels.
-        size *= float(gfxPlatformGtk::GetDPI()) / POINTS_PER_INCH_FLOAT;
-    }
-
-    // |size| is now pixels
-
-    aFontStyle->size = size;
-  
-    pango_font_description_free(desc);
-
-#else
-    /* FIXME: DFB FT2 Hardcoding the system font info for now.. */
-    aFontStyle->style       = FONT_STYLE_NORMAL;
-    aFontStyle->systemFont = true;
-
-    NS_NAMED_LITERAL_STRING(fontname, "\"Sans\"");
-    *aFontName = fontname;
-    aFontStyle->weight = 400;
-    aFontStyle->size = 40/3;
-
-#endif
-
-    return NS_OK;
-}
-
-nsresult
-nsSystemFontsGTK2::GetSystemFont(nsSystemFontID anID, nsString *aFontName,
-                                 gfxFontStyle *aFontStyle) const
-{
-    switch (anID) {
-    case eSystemFont_Menu:         // css2
-    case eSystemFont_PullDownMenu: // css3
-        *aFontName = mMenuFontName;
-        *aFontStyle = mMenuFontStyle;
-        break;
-
-    case eSystemFont_Field:        // css3
-    case eSystemFont_List:         // css3
-        *aFontName = mFieldFontName;
-        *aFontStyle = mFieldFontStyle;
-        break;
-
-    case eSystemFont_Button:       // css3
-        *aFontName = mButtonFontName;
-        *aFontStyle = mButtonFontStyle;
-        break;
-
-    case eSystemFont_Caption:      // css2
-    case eSystemFont_Icon:         // css2
-    case eSystemFont_MessageBox:   // css2
-    case eSystemFont_SmallCaption: // css2
-    case eSystemFont_StatusBar:    // css2
-    case eSystemFont_Window:       // css3
-    case eSystemFont_Document:     // css3
-    case eSystemFont_Workspace:    // css3
-    case eSystemFont_Desktop:      // css3
-    case eSystemFont_Info:         // css3
-    case eSystemFont_Dialog:       // css3
-    case eSystemFont_Tooltips:     // moz
-    case eSystemFont_Widget:       // moz
-        *aFontName = mDefaultFontName;
-        *aFontStyle = mDefaultFontStyle;
-        break;
-    }
-
-    return NS_OK;
-}
deleted file mode 100644
--- a/gfx/src/nsSystemFontsGTK2.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is thebes gfx
- *
- * The Initial Developer of the Original Code is mozilla.org.
- * Portions created by the Initial Developer are Copyright (C) 2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Vladimir Vukicevic <vladimir@pobox.com>
- *   Stuart Parmenter <pavlov@pavlov.net>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef _NS_SYSTEMFONTSGTK2_H_
-#define _NS_SYSTEMFONTSGTK2_H_
-
-#include "gfxFont.h"
-#include "nsDeviceContext.h"
-
-typedef struct _GtkWidget GtkWidget;
-
-class nsSystemFontsGTK2
-{
-public:
-    nsSystemFontsGTK2();
-    ~nsSystemFontsGTK2();
-
-    nsresult GetSystemFont(nsSystemFontID anID, nsString *aFontName,
-                           gfxFontStyle *aFontStyle) const;
-
-private:
-
-    nsresult GetSystemFontInfo(GtkWidget *aWidget, nsString *aFontName,
-                               gfxFontStyle *aFontStyle) const;
-
-    /*
-     * The following system font constants exist:
-     *
-     * css2: http://www.w3.org/TR/REC-CSS2/fonts.html#x27
-     * eSystemFont_Caption, eSystemFont_Icon, eSystemFont_Menu,
-     * eSystemFont_MessageBox, eSystemFont_SmallCaption,
-     * eSystemFont_StatusBar,
-     * // css3
-     * eSystemFont_Window, eSystemFont_Document,
-     * eSystemFont_Workspace, eSystemFont_Desktop,
-     * eSystemFont_Info, eSystemFont_Dialog,
-     * eSystemFont_Button, eSystemFont_PullDownMenu,
-     * eSystemFont_List, eSystemFont_Field,
-     * // moz
-     * eSystemFont_Tooltips, eSystemFont_Widget
-     */
-    nsString mDefaultFontName, mButtonFontName, mFieldFontName, mMenuFontName;
-    gfxFontStyle mDefaultFontStyle, mButtonFontStyle, mFieldFontStyle, mMenuFontStyle;
-};
-
-#endif /* _NS_SYSTEMFONTSGTK2_H_ */
deleted file mode 100644
--- a/gfx/src/nsSystemFontsMac.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Corporation code.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2006
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Vladimir Vukicevic <vladimir@pobox.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef _NS_SYSTEMFONTSMAC_H_
-#define _NS_SYSTEMFONTSMAC_H_
-
-#include "gfxFont.h"
-#include "nsDeviceContext.h"
-
-class nsSystemFontsMac
-{
-public:
-    nsSystemFontsMac();
-    nsresult GetSystemFont(nsSystemFontID anID, nsString *aFontName,
-                           gfxFontStyle *aFontStyle) const;
-};
-
-#endif /* _NS_SYSTEMFONTSMAC_H_ */
deleted file mode 100644
--- a/gfx/src/nsSystemFontsMac.mm
+++ /dev/null
@@ -1,167 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Corporation code.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2006-2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Vladimir Vukicevic <vladimir@pobox.com>
- *   Jonathan Kew <jfkthame@gmail.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsSystemFontsMac.h"
-#include <Cocoa/Cocoa.h>
-
-nsSystemFontsMac::nsSystemFontsMac()
-{
-}
-
-// copied from gfxQuartzFontCache.mm, maybe should go in a Cocoa utils file somewhere
-static void GetStringForNSString(const NSString *aSrc, nsAString& aDest)
-{
-    aDest.SetLength([aSrc length]);
-    [aSrc getCharacters:aDest.BeginWriting()];
-}
-
-nsresult
-nsSystemFontsMac::GetSystemFont(nsSystemFontID aID, nsString *aFontName,
-                                gfxFontStyle *aFontStyle) const
-{
-    // hack for now
-    if (aID == eSystemFont_Window ||
-        aID == eSystemFont_Document)
-    {
-        aFontStyle->style       = FONT_STYLE_NORMAL;
-        aFontStyle->weight      = FONT_WEIGHT_NORMAL;
-        aFontStyle->stretch     = NS_FONT_STRETCH_NORMAL;
-
-        aFontName->AssignLiteral("sans-serif");
-        aFontStyle->size = 14;
-        aFontStyle->systemFont = true;
-
-        return NS_OK;
-    }
-
-/* possibilities, see NSFont Class Reference:
-    [NSFont boldSystemFontOfSize:     0.0]
-    [NSFont controlContentFontOfSize: 0.0]
-    [NSFont labelFontOfSize:          0.0]
-    [NSFont menuBarFontOfSize:        0.0]
-    [NSFont menuFontOfSize:           0.0]
-    [NSFont messageFontOfSize:        0.0]
-    [NSFont paletteFontOfSize:        0.0]
-    [NSFont systemFontOfSize:         0.0]
-    [NSFont titleBarFontOfSize:       0.0]
-    [NSFont toolTipsFontOfSize:       0.0]
-    [NSFont userFixedPitchFontOfSize: 0.0]
-    [NSFont userFontOfSize:           0.0]
-    [NSFont systemFontOfSize:         [NSFont smallSystemFontSize]]
-    [NSFont boldSystemFontOfSize:     [NSFont smallSystemFontSize]]
-*/
-
-    NSFont *font = nsnull;
-    switch (aID) {
-        // css2
-        case eSystemFont_Caption:
-            font = [NSFont systemFontOfSize:0.0];
-            break;
-        case eSystemFont_Icon: // used in urlbar; tried labelFont, but too small
-            font = [NSFont controlContentFontOfSize:0.0];
-            break;
-        case eSystemFont_Menu:
-            font = [NSFont systemFontOfSize:0.0];
-            break;
-        case eSystemFont_MessageBox:
-            font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
-            break;
-        case eSystemFont_SmallCaption:
-            font = [NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]];
-            break;
-        case eSystemFont_StatusBar:
-            font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
-            break;
-        // css3
-        //case eSystemFont_Window:     = 'sans-serif'
-        //case eSystemFont_Document:   = 'sans-serif'
-        case eSystemFont_Workspace:
-            font = [NSFont controlContentFontOfSize:0.0];
-            break;
-        case eSystemFont_Desktop:
-            font = [NSFont controlContentFontOfSize:0.0];
-            break;
-        case eSystemFont_Info:
-            font = [NSFont controlContentFontOfSize:0.0];
-            break;
-        case eSystemFont_Dialog:
-            font = [NSFont systemFontOfSize:0.0];
-            break;
-        case eSystemFont_Button:
-            font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
-            break;
-        case eSystemFont_PullDownMenu:
-            font = [NSFont menuBarFontOfSize:0.0];
-            break;
-        case eSystemFont_List:
-            font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
-            break;
-        case eSystemFont_Field:
-            font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
-            break;
-        // moz
-        case eSystemFont_Tooltips:
-            font = [NSFont toolTipsFontOfSize:0.0];
-            break;
-        case eSystemFont_Widget:
-            font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
-            break;
-        default:
-            // should never hit this
-            return NS_ERROR_FAILURE;
-    }
-
-    NS_ASSERTION(font != nsnull, "failed to find a system font!");
-
-    GetStringForNSString([font familyName], *aFontName);
-    aFontStyle->size = [font pointSize];
-
-    NSFontSymbolicTraits traits = [[font fontDescriptor] symbolicTraits];
-    if (traits & NSFontBoldTrait)
-        aFontStyle->weight = FONT_WEIGHT_BOLD;
-    if (traits & NSFontItalicTrait)
-        aFontStyle->style = FONT_STYLE_ITALIC;
-    aFontStyle->stretch =
-        (traits & NSFontExpandedTrait) ?
-            NS_FONT_STRETCH_EXPANDED : (traits & NSFontCondensedTrait) ?
-                NS_FONT_STRETCH_CONDENSED : NS_FONT_STRETCH_NORMAL;
-
-    aFontStyle->systemFont = true;
-
-    return NS_OK;
-}
deleted file mode 100644
--- a/gfx/src/nsSystemFontsOS2.cpp
+++ /dev/null
@@ -1,275 +0,0 @@
-/* vim: set sw=4 sts=4 et cin: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is OS/2 system font code in Thebes.
- *
- * The Initial Developer of the Original Code is
- * Peter Weilbacher <mozilla@Weilbacher.org>.
- * Portions created by the Initial Developer are Copyright (C) 2006
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Developers of code taken from nsDeviceContextOS2:
- *    John Fairhurst, <john_fairhurst@iname.com>
- *    Henry Sobotka <sobotka@axess.com>
- *    IBM Corp.
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsSystemFontsOS2.h"
-
-#define INCL_WINWINDOWMGR
-#define INCL_WINSHELLDATA
-#define INCL_DOSNLS
-#define INCL_DOSERRORS
-#include <os2.h>
-
-#include <stdlib.h>
-
-/************************
- *   Helper functions   *
- ************************/
-static BOOL bIsDBCS;
-static BOOL bIsDBCSSet = FALSE;
-
-/* Helper function to determine if we are running on DBCS */
-BOOL IsDBCS()
-{
-    if (!bIsDBCSSet) {
-        // the following lines of code determine whether the system is a DBCS country
-        APIRET rc;
-        COUNTRYCODE ctrycodeInfo = {0};
-        CHAR        achDBCSInfo[12] = {0};                  // DBCS environmental vector
-        ctrycodeInfo.country  = 0;                          // current country
-        ctrycodeInfo.codepage = 0;                          // current codepage
-
-        rc = DosQueryDBCSEnv(sizeof(achDBCSInfo), &ctrycodeInfo, achDBCSInfo);
-        if (rc == NO_ERROR) {
-            // Non-DBCS countries will have four bytes in the first four bytes of the
-            // DBCS environmental vector
-            if (achDBCSInfo[0] != 0 || achDBCSInfo[1] != 0 ||
-                achDBCSInfo[2] != 0 || achDBCSInfo[3] != 0)
-            {
-                bIsDBCS = TRUE;
-            } else {
-                bIsDBCS = FALSE;
-            }
-        } else {
-            bIsDBCS = FALSE;
-        } /* endif */
-        bIsDBCSSet = TRUE;
-    } /* endif */
-    return bIsDBCS;
-}
-
-/* Helper function to query font from INI file */
-void QueryFontFromINI(char* fontType, char* fontName, ULONG ulLength)
-{
-    ULONG ulMaxNameL = ulLength;
-
-    /* We had to switch to using PrfQueryProfileData because */
-    /* some users have binary font data in their INI files */
-    BOOL rc = PrfQueryProfileData(HINI_USER, (PCSZ)"PM_SystemFonts", (PCSZ)fontType,
-                                  fontName, &ulMaxNameL);
-    /* If there was no entry in the INI, default to something */
-    if (rc == FALSE) {
-        /* Different values for DBCS vs. SBCS */
-        /* WarpSans is only available on Warp 4, we exclude Warp 3 now */
-        if (!IsDBCS()) {
-            strcpy(fontName, "9.WarpSans");
-        } else {
-            strcpy(fontName, "9.WarpSans Combined");
-        }
-    } else {
-        /* null terminate fontname */
-        fontName[ulMaxNameL] = '\0';
-    }
-}
-
-/************************/
-
-nsSystemFontsOS2::nsSystemFontsOS2()
-{
-#ifdef DEBUG_thebes
-    printf("nsSystemFontsOS2::nsSystemFontsOS2()\n");
-#endif
-}
-
-/*
- * Query the font used for various CSS properties (aID) from the system.
- * For OS/2, only very few fonts are defined in the system, so most of the IDs
- * resolve to the same system font.
- * The font queried will give back a string like
- *    9.WarpSans Bold
- *    12.Times New Roman Bold Italic
- *    10.Times New Roman.Strikeout.Underline
- *    20.Bitstream Vera Sans Mono Obli
- * (always restricted to 32 chars, at least before the second dot)
- * We use the value before the dot as the font size (in pt, and convert it to
- * px using the screen resolution) and then try to use the rest of the string
- * to determine the font style from it.
- */
-nsresult nsSystemFontsOS2::GetSystemFont(nsSystemFontID aID, nsString* aFontName,
-                                         gfxFontStyle *aFontStyle) const
-{
-#ifdef DEBUG_thebes
-    printf("nsSystemFontsOS2::GetSystemFont: ");
-#endif
-    char szFontNameSize[MAXNAMEL];
-
-    switch (aID)
-    {
-    case eSystemFont_Icon:
-        QueryFontFromINI("IconText", szFontNameSize, MAXNAMEL);
-#ifdef DEBUG_thebes
-        printf("IconText ");
-#endif
-        break;
-
-    case eSystemFont_Menu:
-        QueryFontFromINI("Menus", szFontNameSize, MAXNAMEL);
-#ifdef DEBUG_thebes
-        printf("Menus ");
-#endif
-        break;
-
-    case eSystemFont_Caption:
-    case eSystemFont_MessageBox:
-    case eSystemFont_SmallCaption:
-    case eSystemFont_StatusBar:
-    case eSystemFont_Tooltips:
-    case eSystemFont_Widget:
-
-    case eSystemFont_Window:      // css3
-    case eSystemFont_Document:
-    case eSystemFont_Workspace:
-    case eSystemFont_Desktop:
-    case eSystemFont_Info:
-    case eSystemFont_Dialog:
-    case eSystemFont_Button:
-    case eSystemFont_PullDownMenu:
-    case eSystemFont_List:
-    case eSystemFont_Field:
-        QueryFontFromINI("WindowText", szFontNameSize, MAXNAMEL);
-#ifdef DEBUG_thebes
-        printf("WindowText ");
-#endif
-        break;
-
-    default:
-        NS_WARNING("None of the listed font types, using WarpSans");
-        if (!IsDBCS()) {
-            strcpy(szFontNameSize, "9.WarpSans");
-        } else {
-            strcpy(szFontNameSize, "9.WarpSans Combined");
-        }
-    } // switch
-#ifdef DEBUG_thebes
-    printf(" (%s)\n", szFontNameSize);
-#endif
-
-    char *szFacename = strchr(szFontNameSize, '.');
-    if (!szFacename || (*(szFacename++) == '\0'))
-        return NS_ERROR_FAILURE;
-
-    // local DPI for size will be taken into account below
-    aFontStyle->size = atof(szFontNameSize);
-
-    // determine DPI resolution of screen device to compare compute
-    // font size in pixels
-    HPS ps = WinGetScreenPS(HWND_DESKTOP);
-    HDC dc = GpiQueryDevice(ps);
-    // effective vertical resolution in DPI
-    LONG vertScreenRes = 120; // assume 120 dpi as default
-    DevQueryCaps(dc, CAPS_VERTICAL_FONT_RES, 1, &vertScreenRes);
-    WinReleasePS(ps);
-
-    // now scale to make pixels from points (1 pt = 1/72in)
-    aFontStyle->size *= vertScreenRes / 72.0;
-
-    NS_ConvertUTF8toUTF16 fontFace(szFacename);
-    int pos = 0;
-
-    // this is a system font in any case
-    aFontStyle->systemFont = true;
-
-    // bold fonts should have " Bold" in their names, at least we hope that they
-    // do, otherwise it's bad luck
-    NS_NAMED_LITERAL_CSTRING(spcBold, " Bold");
-    if ((pos = fontFace.Find(spcBold.get(), false, 0, -1)) > -1) {
-        aFontStyle->weight = FONT_WEIGHT_BOLD;
-        // strip the attribute, now that we have set it in the gfxFontStyle
-        fontFace.Cut(pos, spcBold.Length());
-    } else {
-        aFontStyle->weight = FONT_WEIGHT_NORMAL;
-    }
-
-    // FIXME: Set aFontStyle->stretch correctly!
-    aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
-
-    // similar hopes for italic and oblique fonts...
-    NS_NAMED_LITERAL_CSTRING(spcItalic, " Italic");
-    NS_NAMED_LITERAL_CSTRING(spcOblique, " Oblique");
-    NS_NAMED_LITERAL_CSTRING(spcObli, " Obli");
-    if ((pos = fontFace.Find(spcItalic.get(), false, 0, -1)) > -1) {
-        aFontStyle->style = FONT_STYLE_ITALIC;
-        fontFace.Cut(pos, spcItalic.Length());
-    } else if ((pos = fontFace.Find(spcOblique.get(), false, 0, -1)) > -1) {
-        // oblique fonts are rare on OS/2 and not specially supported by
-        // the GPI system, but at least we are trying...
-        aFontStyle->style = FONT_STYLE_OBLIQUE;
-        fontFace.Cut(pos, spcOblique.Length());
-    } else if ((pos = fontFace.Find(spcObli.get(), false, 0, -1)) > -1) {
-        // especially oblique often gets cut by the 32 char limit to "Obli",
-        // so search for that, too (anything shorter would be ambiguous)
-        aFontStyle->style = FONT_STYLE_OBLIQUE;
-        // In this case, assume that this is the last property in the line
-        // and cut off everything else, too
-        // This is needed in case it was really Obliq or Obliqu...
-        fontFace.Cut(pos, fontFace.Length());
-    } else {
-        aFontStyle->style = FONT_STYLE_NORMAL;
-    }
-
-    // just throw away any modifiers that are separated by dots (which are either
-    // .Strikeout, .Underline, or .Outline, none of which have a corresponding
-    // gfxFont property)
-    if ((pos = fontFace.Find(".", false, 0, -1)) > -1) {
-        fontFace.Cut(pos, fontFace.Length());
-    }
-
-#ifdef DEBUG_thebes
-    printf("  after=%s\n", NS_LossyConvertUTF16toASCII(fontFace).get());
-    printf("  style: %s %s %s\n",
-           (aFontStyle->weight == FONT_WEIGHT_BOLD) ? "BOLD" : "",
-           (aFontStyle->style == FONT_STYLE_ITALIC) ? "ITALIC" : "",
-           (aFontStyle->style == FONT_STYLE_OBLIQUE) ? "OBLIQUE" : "");
-#endif
-    NS_NAMED_LITERAL_STRING(quote, "\""); // seems like we need quotes around the font name
-    *aFontName = quote + fontFace + quote;
-
-    return NS_OK;
-}
deleted file mode 100644
--- a/gfx/src/nsSystemFontsOS2.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* vim: set sw=4 sts=4 et cin: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is OS/2 system font code in Thebes.
- *
- * The Initial Developer of the Original Code is
- * Peter Weilbacher <mozilla@Weilbacher.org>.
- * Portions created by the Initial Developer are Copyright (C) 2006
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  John Fairhurst, <john_fairhurst@iname.com> } original developers of
- *  Henry Sobotka <sobotka@axess.com>          } code taken from 
- *  IBM Corp.                                  } nsDeviceContextOS2
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef _NS_SYSTEMFONTSOS2_H_
-#define _NS_SYSTEMFONTSOS2_H_
-
-#include "gfxFont.h"
-#include "nsDeviceContext.h"
-
-class nsSystemFontsOS2
-{
-public:
-    nsSystemFontsOS2();
-    nsresult GetSystemFont(nsSystemFontID aID, nsString* aFontName,
-                           gfxFontStyle *aFontStyle) const;
-};
-
-#endif /* _NS_SYSTEMFONTSOS2_H_ */
deleted file mode 100644
--- a/gfx/src/nsSystemFontsQt.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is thebes gfx
- *
- * The Initial Developer of the Original Code is mozilla.org.
- * Portions created by the Initial Developer are Copyright (C) 2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Vladimir Vukicevic <vladimir@pobox.com>
- *   Stuart Parmenter <pavlov@pavlov.net>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-// Qt headers must be included before anything that might pull in our
-// malloc wrappers.
-#include <QApplication>
-#include <QFont>
-
-#include "nsSystemFontsQt.h"
-#include "gfxQtPlatform.h"
-
-nsSystemFontsQt::nsSystemFontsQt()
-  : mDefaultFontName(NS_LITERAL_STRING("sans-serif"))
-  , mButtonFontName(NS_LITERAL_STRING("sans-serif"))
-  , mFieldFontName(NS_LITERAL_STRING("sans-serif"))
-  , mMenuFontName(NS_LITERAL_STRING("sans-serif"))
-{
-   // What about using QFontInfo? is it faster or what?
-   GetSystemFontInfo("Qlabel", &mDefaultFontName, &mDefaultFontStyle);
-
-   GetSystemFontInfo("QlineEdit", &mFieldFontName, &mFieldFontStyle);
-
-   GetSystemFontInfo("QAction", &mMenuFontName, &mMenuFontStyle);
-
-   GetSystemFontInfo("QPushButton", &mButtonFontName, &mButtonFontStyle);
-}
-
-nsSystemFontsQt::~nsSystemFontsQt()
-{
-    // No implementation needed
-}
-
-nsresult
-nsSystemFontsQt::GetSystemFontInfo(const char *aClassName, nsString *aFontName,
-                                   gfxFontStyle *aFontStyle) const
-{
-    QFont qFont = QApplication::font(aClassName);
-
-    aFontStyle->style = FONT_STYLE_NORMAL;
-    aFontStyle->systemFont = true;
-    NS_NAMED_LITERAL_STRING(quote, "\"");
-    nsString family((PRUnichar*)qFont.family().data());
-    *aFontName = quote + family + quote;
-    aFontStyle->weight = qFont.weight();
-    // FIXME: Set aFontStyle->stretch correctly!
-    aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
-    // use pixel size directly if it is set, otherwise compute from point size
-    if (qFont.pixelSize() != -1) {
-        aFontStyle->size = qFont.pixelSize();
-    } else {
-        aFontStyle->size = qFont.pointSizeF() * 96.0f / 72.0f;
-    }
-    return NS_OK;
-}
-
-
-nsresult
-nsSystemFontsQt::GetSystemFont(nsSystemFontID anID, nsString *aFontName,
-                                 gfxFontStyle *aFontStyle) const
-{
-    switch (anID) {
-    case eSystemFont_Menu:         // css2
-    case eSystemFont_PullDownMenu: // css3
-        *aFontName = mMenuFontName;
-        *aFontStyle = mMenuFontStyle;
-        break;
-
-    case eSystemFont_Field:        // css3
-    case eSystemFont_List:         // css3
-        *aFontName = mFieldFontName;
-        *aFontStyle = mFieldFontStyle;
-        break;
-
-    case eSystemFont_Button:       // css3
-        *aFontName = mButtonFontName;
-        *aFontStyle = mButtonFontStyle;
-        break;
-
-    case eSystemFont_Caption:      // css2
-    case eSystemFont_Icon:         // css2
-    case eSystemFont_MessageBox:   // css2
-    case eSystemFont_SmallCaption: // css2
-    case eSystemFont_StatusBar:    // css2
-    case eSystemFont_Window:       // css3
-    case eSystemFont_Document:     // css3
-    case eSystemFont_Workspace:    // css3
-    case eSystemFont_Desktop:      // css3
-    case eSystemFont_Info:         // css3
-    case eSystemFont_Dialog:       // css3
-    case eSystemFont_Tooltips:     // moz
-    case eSystemFont_Widget:       // moz
-        *aFontName = mDefaultFontName;
-        *aFontStyle = mDefaultFontStyle;
-        break;
-    }
-
-    return NS_OK;
-}
-
deleted file mode 100644
--- a/gfx/src/nsSystemFontsQt.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is thebes gfx
- *
- * The Initial Developer of the Original Code is mozilla.org.
- * Portions created by the Initial Developer are Copyright (C) 2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Vladimir Vukicevic <vladimir@pobox.com>
- *   Stuart Parmenter <pavlov@pavlov.net>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef _NS_SYSTEMFONTSQT_H_
-#define _NS_SYSTEMFONTSQT_H_
-
-#include "gfxFont.h"
-#include "nsDeviceContext.h"
-
-class nsSystemFontsQt
-{
-public:
-    nsSystemFontsQt();
-    ~nsSystemFontsQt();
-
-    nsresult GetSystemFont(nsSystemFontID anID, nsString *aFontName,
-                           gfxFontStyle *aFontStyle) const;
-
-private:
-
-    nsresult GetSystemFontInfo(const char *aClassName, nsString *aFontName,
-                               gfxFontStyle *aFontStyle) const;
-
-    /*
-     * The following system font constants exist:
-     *
-     * css2: http://www.w3.org/TR/REC-CSS2/fonts.html#x27
-     * eSystemFont_Caption, eSystemFont_Icon, eSystemFont_Menu,
-     * eSystemFont_MessageBox, eSystemFont_SmallCaption,
-     * eSystemFont_StatusBar,
-     * // css3
-     * eSystemFont_Window, eSystemFont_Document,
-     * eSystemFont_Workspace, eSystemFont_Desktop,
-     * eSystemFont_Info, eSystemFont_Dialog,
-     * eSystemFont_Button, eSystemFont_PullDownMenu,
-     * eSystemFont_List, eSystemFont_Field,
-     * // moz
-     * eSystemFont_Tooltips, eSystemFont_Widget
-     */
-    nsString mDefaultFontName, mButtonFontName, mFieldFontName, mMenuFontName;
-    gfxFontStyle mDefaultFontStyle, mButtonFontStyle, mFieldFontStyle, mMenuFontStyle;
-};
-
-#endif /* _NS_SYSTEMFONTSQT_H_ */
-
deleted file mode 100644
--- a/gfx/src/nsSystemFontsWin.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is thebes gfx
- *
- * The Initial Developer of the Original Code is mozilla.org.
- * Portions created by the Initial Developer are Copyright (C) 2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Vladimir Vukicevic <vladimir@pobox.com>
- *   Stuart Parmenter <pavlov@pavlov.net>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsSystemFontsWin.h"
-#include "gfxWindowsSurface.h"
-
-nsresult nsSystemFontsWin::CopyLogFontToNSFont(HDC* aHDC, const LOGFONTW* ptrLogFont,
-                                               nsString *aFontName,
-                                               gfxFontStyle *aFontStyle) const
-{
-  PRUnichar name[LF_FACESIZE];
-  name[0] = 0;
-  memcpy(name, ptrLogFont->lfFaceName, LF_FACESIZE*sizeof(PRUnichar));
-  *aFontName = name;
-
-  // Do Style
-  aFontStyle->style = FONT_STYLE_NORMAL;
-  if (ptrLogFont->lfItalic)
-  {
-    aFontStyle->style = FONT_STYLE_ITALIC;
-  }
-  // XXX What about oblique?
-
-  // Do Weight
-  aFontStyle->weight = (ptrLogFont->lfWeight == FW_BOLD ? 
-            FONT_WEIGHT_BOLD : FONT_WEIGHT_NORMAL);
-
-  // FIXME: Set aFontStyle->stretch correctly!
-  aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
-
-  // XXX mPixelScale is currently hardcoded to 1 in thebes gfx...
-  float mPixelScale = 1.0f;
-  // Do Point Size
-  //
-  // The lfHeight is in pixel and it needs to be adjusted for the
-  // device it will be "displayed" on
-  // Screens and Printers will differe in DPI
-  //
-  // So this accounts for the difference in the DeviceContexts
-  // The mPixelScale will be a "1" for the screen and could be
-  // any value when going to a printer, for example mPixleScale is
-  // 6.25 when going to a 600dpi printer.
-  // round, but take into account whether it is negative
-  float pixelHeight = -ptrLogFont->lfHeight;
-  if (pixelHeight < 0) {
-    HFONT hFont = ::CreateFontIndirectW(ptrLogFont);
-    if (!hFont)
-      return NS_ERROR_OUT_OF_MEMORY;
-    HGDIOBJ hObject = ::SelectObject(*aHDC, hFont);
-    TEXTMETRIC tm;
-    ::GetTextMetrics(*aHDC, &tm);
-    ::SelectObject(*aHDC, hObject);
-    ::DeleteObject(hFont);
-    pixelHeight = tm.tmAscent;
-  }
-
-  pixelHeight *= mPixelScale;
-
-  // we have problem on Simplified Chinese system because the system
-  // report the default font size is 8 points. but if we use 8, the text
-  // display very ugly. force it to be at 9 points (12 pixels) on that
-  // system (cp936), but leave other sizes alone.
-  if ((pixelHeight < 12) && 
-      (936 == ::GetACP())) 
-    pixelHeight = 12;
-
-  aFontStyle->size = pixelHeight;
-  return NS_OK;
-}
-
-nsresult nsSystemFontsWin::GetSysFontInfo(HDC aHDC, nsSystemFontID anID,
-                                          nsString *aFontName,
-                                          gfxFontStyle *aFontStyle) const
-{
-  HGDIOBJ hGDI;
-
-  LOGFONTW logFont;
-  LOGFONTW* ptrLogFont = NULL;
-
-  NONCLIENTMETRICSW ncm;
-
-  BOOL status;
-  if (anID == eSystemFont_Icon) 
-  {
-    status = ::SystemParametersInfoW(SPI_GETICONTITLELOGFONT,
-                                     sizeof(logFont),
-                                     (PVOID)&logFont,
-                                     0);
-  }
-  else
-  {
-    ncm.cbSize = sizeof(NONCLIENTMETRICSW);
-    status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 
-                                     sizeof(ncm),  
-                                     (PVOID)&ncm, 
-                                     0);
-  }
-
-  if (!status)
-  {
-    return NS_ERROR_FAILURE;
-  }
-
-  switch (anID)
-  {
-    // Caption in CSS is NOT the same as Caption on Windows
-    //case eSystemFont_Caption: 
-    //  ptrLogFont = &ncm.lfCaptionFont;
-    //  break;
-
-    case eSystemFont_Icon: 
-      ptrLogFont = &logFont;
-      break;
-
-    case eSystemFont_Menu: 
-      ptrLogFont = &ncm.lfMenuFont;
-      break;
-
-    case eSystemFont_MessageBox: 
-      ptrLogFont = &ncm.lfMessageFont;
-      break;
-
-    case eSystemFont_SmallCaption: 
-      ptrLogFont = &ncm.lfSmCaptionFont;
-      break;
-
-    case eSystemFont_StatusBar: 
-    case eSystemFont_Tooltips: 
-      ptrLogFont = &ncm.lfStatusFont;
-      break;
-
-    case eSystemFont_Widget:
-
-    case eSystemFont_Window:      // css3
-    case eSystemFont_Document:
-    case eSystemFont_Workspace:
-    case eSystemFont_Desktop:
-    case eSystemFont_Info:
-    case eSystemFont_Dialog:
-    case eSystemFont_Button:
-    case eSystemFont_PullDownMenu:
-    case eSystemFont_List:
-    case eSystemFont_Field:
-    case eSystemFont_Caption: 
-      hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
-      if (hGDI != NULL)
-      {
-        if (::GetObjectW(hGDI, sizeof(logFont), &logFont) > 0)
-        { 
-          ptrLogFont = &logFont;
-        }
-      }
-      break;
-  } // switch 
-
-  if (nsnull == ptrLogFont)
-  {
-    return NS_ERROR_FAILURE;
-  }
-
-  aFontStyle->systemFont = true;
-
-  return CopyLogFontToNSFont(&aHDC, ptrLogFont, aFontName, aFontStyle);
-}
-
-nsresult nsSystemFontsWin::GetSystemFont(nsSystemFontID anID,
-                                         nsString *aFontName,
-                                         gfxFontStyle *aFontStyle) const
-{
-  nsresult status = NS_OK;
-
-  switch (anID) {
-    case eSystemFont_Caption: 
-    case eSystemFont_Icon: 
-    case eSystemFont_Menu: 
-    case eSystemFont_MessageBox: 
-    case eSystemFont_SmallCaption: 
-    case eSystemFont_StatusBar: 
-    case eSystemFont_Tooltips: 
-    case eSystemFont_Widget:
-
-    case eSystemFont_Window:      // css3
-    case eSystemFont_Document:
-    case eSystemFont_Workspace:
-    case eSystemFont_Desktop:
-    case eSystemFont_Info:
-    case eSystemFont_Dialog:
-    case eSystemFont_Button:
-    case eSystemFont_PullDownMenu:
-    case eSystemFont_List:
-    case eSystemFont_Field:
-    {
-      HWND hwnd = nsnull;
-      HDC tdc = GetDC(hwnd);
-
-      status = GetSysFontInfo(tdc, anID, aFontName, aFontStyle);
-
-      ReleaseDC(hwnd, tdc);
-
-      break;
-    }
-  }
-
-  return status;
-}
-
-nsSystemFontsWin::nsSystemFontsWin()
-{
-
-}
-
deleted file mode 100644
--- a/gfx/src/nsSystemFontsWin.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is thebes gfx
- *
- * The Initial Developer of the Original Code is mozilla.org.
- * Portions created by the Initial Developer are Copyright (C) 2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Vladimir Vukicevic <vladimir@pobox.com>
- *   Stuart Parmenter <pavlov@pavlov.net>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef _NS_SYSTEMFONTSWIN_H_
-#define _NS_SYSTEMFONTSWIN_H_
-
-#include "gfxFont.h"
-#include "nsDeviceContext.h"
-#include <windows.h> // need HDC and LOGFONTW
-
-class nsSystemFontsWin
-{
-public:
-    nsSystemFontsWin();
-
-    nsresult GetSystemFont(nsSystemFontID anID, nsString *aFontName,
-                           gfxFontStyle *aFontStyle) const;
-private:
-    nsresult CopyLogFontToNSFont(HDC* aHDC, const LOGFONTW* ptrLogFont,
-                                 nsString *aFontName, gfxFontStyle *aFontStyle) const;
-    nsresult GetSysFontInfo(HDC aHDC, nsSystemFontID anID,
-                            nsString *aFontName,
-                            gfxFontStyle *aFontStyle) const;
-};
-
-#endif /* _NS_SYSTEMFONTSWIN_H_ */
--- a/gfx/src/nsThebesGfxFactory.cpp
+++ b/gfx/src/nsThebesGfxFactory.cpp
@@ -38,17 +38,16 @@
 
 #include "mozilla/ModuleUtils.h"
 #include "nsCOMPtr.h"
 #include "nsGfxCIID.h"
 
 #include "nsThebesFontEnumerator.h"
 #include "nsScriptableRegion.h"
 
-#include "nsDeviceContext.h"
 #include "gfxPlatform.h"
 
 // This class doesn't do anything; its only purpose is to give
 // gfxPlatform::Init a way to force this component to be registered,
 // so that gfxPlatform::Shutdown will be called at an appropriate
 // time.  (Component teardown is the only shutdown hook that runs
 // late enough; see bug 651498.)
 
@@ -95,17 +94,16 @@ static const mozilla::Module::ContractID
     { "@mozilla.org/gfx/region;1", &kNS_SCRIPTABLE_REGION_CID },
     { "@mozilla.org/gfx/init;1", &kNS_GFX_INITIALIZATION_CID },
     { NULL }
 };
 
 static void
 nsThebesGfxModuleDtor()
 {
-    nsDeviceContext::ClearCachedSystemFonts();
     gfxPlatform::Shutdown();
 }
 
 static const mozilla::Module kThebesModule = {
     mozilla::Module::kVersion,
     kThebesCIDs,
     kThebesContracts,
     NULL,
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -738,35 +738,26 @@ gfxFontFamily::FindFontForChar(FontSearc
         if (rank == 0)
             continue;
             
         // omitting from original windows code -- family name, lang group, pitch
         // not available in current FontEntry implementation
 
         if (aMatchData->mFontToMatch) { 
             const gfxFontStyle *style = aMatchData->mFontToMatch->GetStyle();
-            
-            // italics
+
+            // matching italics takes precedence over weight
             bool wantItalic =
                 ((style->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0);
             if (fe->IsItalic() == wantItalic) {
-                rank += 5;
+                rank += 10;
             }
-            
-            // weight
-            PRInt32 targetWeight = style->ComputeWeight() * 100;
-
-            PRInt32 entryWeight = fe->Weight();
-            if (entryWeight == targetWeight) {
-                rank += 5;
-            } else {
-                PRUint32 diffWeight = abs(entryWeight - targetWeight);
-                if (diffWeight <= 100)  // favor faces close in weight
-                    rank += 2;
-            }
+
+            // measure of closeness of weight to the desired value
+            rank += 9 - abs(fe->Weight() / 100 - style->ComputeWeight());
         } else {
             // if no font to match, prefer non-bold, non-italic fonts
             if (!fe->IsItalic()) {
                 rank += 3;
             }
             if (!fe->IsBold()) {
                 rank += 2;
             }
@@ -1112,16 +1103,17 @@ gfxFontCache::NotifyReleased(gfxFont *aF
     // we already had a font. These fonts are added to the expiration tracker
     // anyway, even though Lookup can't resurrect them. Eventually they will
     // expire and be deleted.
 }
 
 void
 gfxFontCache::NotifyExpired(gfxFont *aFont)
 {
+    aFont->ClearCachedWords();
     RemoveObject(aFont);
     DestroyFont(aFont);
 }
 
 void
 gfxFontCache::DestroyFont(gfxFont *aFont)
 {
     Key key(aFont->GetFontEntry(), aFont->GetStyle());
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -45,23 +45,23 @@
 
 #include "gfxTypes.h"
 
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include "gfxHarfBuzzShaper.h"
 #include "gfxFontUtils.h"
 #include "gfxUnicodeProperties.h"
+#include "nsUnicodeNormalizer.h"
 
 #include "harfbuzz/hb-unicode.h"
 #include "harfbuzz/hb-ot.h"
 
 #include "cairo.h"
 
-#include "nsUnicodeRange.h"
 #include "nsCRT.h"
 
 #if defined(XP_WIN)
 #include "gfxWindowsPlatform.h"
 #endif
 
 #define FloatToFixed(f) (65536 * (f))
 #define FixedToFloat(f) ((f) * (1.0 / 65536.0))
@@ -695,16 +695,150 @@ HBGetCombiningClass(hb_unicode_funcs_t *
 }
 
 static unsigned int
 HBGetEastAsianWidth(hb_unicode_funcs_t *ufuncs, hb_codepoint_t aCh, void *user_data)
 {
     return gfxUnicodeProperties::GetEastAsianWidth(aCh);
 }
 
+// Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA;
+// note that some letters do not have a dagesh presForm encoded
+static const PRUnichar sDageshForms[0x05EA - 0x05D0 + 1] = {
+    0xFB30, // ALEF
+    0xFB31, // BET
+    0xFB32, // GIMEL
+    0xFB33, // DALET
+    0xFB34, // HE
+    0xFB35, // VAV
+    0xFB36, // ZAYIN
+    0, // HET
+    0xFB38, // TET
+    0xFB39, // YOD
+    0xFB3A, // FINAL KAF
+    0xFB3B, // KAF
+    0xFB3C, // LAMED
+    0, // FINAL MEM
+    0xFB3E, // MEM
+    0, // FINAL NUN
+    0xFB40, // NUN
+    0xFB41, // SAMEKH
+    0, // AYIN
+    0xFB43, // FINAL PE
+    0xFB44, // PE
+    0, // FINAL TSADI
+    0xFB46, // TSADI
+    0xFB47, // QOF
+    0xFB48, // RESH
+    0xFB49, // SHIN
+    0xFB4A // TAV
+};
+
+static hb_bool_t
+HBUnicodeCompose(hb_unicode_funcs_t *ufuncs,
+                 hb_codepoint_t      a,
+                 hb_codepoint_t      b,
+                 hb_codepoint_t     *ab,
+                 void               *user_data)
+{
+    hb_bool_t found = nsUnicodeNormalizer::Compose(a, b, ab);
+
+    if (!found && (b & 0x1fff80) == 0x0580) {
+        // special-case Hebrew presentation forms that are excluded from
+        // standard normalization, but wanted for old fonts
+        switch (b) {
+        case 0x05B4: // HIRIQ
+            if (a == 0x05D9) { // YOD
+                *ab = 0xFB1D;
+                found = true;
+            }
+            break;
+        case 0x05B7: // patah
+            if (a == 0x05F2) { // YIDDISH YOD YOD
+                *ab = 0xFB1F;
+                found = true;
+            } else if (a == 0x05D0) { // ALEF
+                *ab = 0xFB2E;
+                found = true;
+            }
+            break;
+        case 0x05B8: // QAMATS
+            if (a == 0x05D0) { // ALEF
+                *ab = 0xFB2F;
+                found = true;
+            }
+            break;
+        case 0x05B9: // HOLAM
+            if (a == 0x05D5) { // VAV
+                *ab = 0xFB4B;
+                found = true;
+            }
+            break;
+        case 0x05BC: // DAGESH
+            if (a >= 0x05D0 && a <= 0x05EA) {
+                *ab = sDageshForms[a - 0x05D0];
+                found = (*ab != 0);
+            } else if (a == 0xFB2A) { // SHIN WITH SHIN DOT
+                *ab = 0xFB2C;
+                found = true;
+            } else if (a == 0xFB2B) { // SHIN WITH SIN DOT
+                *ab = 0xFB2D;
+                found = true;
+            }
+            break;
+        case 0x05BF: // RAFE
+            switch (a) {
+            case 0x05D1: // BET
+                *ab = 0xFB4C;
+                found = true;
+                break;
+            case 0x05DB: // KAF
+                *ab = 0xFB4D;
+                found = true;
+                break;
+            case 0x05E4: // PE
+                *ab = 0xFB4E;
+                found = true;
+                break;
+            }
+            break;
+        case 0x05C1: // SHIN DOT
+            if (a == 0x05E9) { // SHIN
+                *ab = 0xFB2A;
+                found = true;
+            } else if (a == 0xFB49) { // SHIN WITH DAGESH
+                *ab = 0xFB2C;
+                found = true;
+            }
+            break;
+        case 0x05C2: // SIN DOT
+            if (a == 0x05E9) { // SHIN
+                *ab = 0xFB2B;
+                found = true;
+            } else if (a == 0xFB49) { // SHIN WITH DAGESH
+                *ab = 0xFB2D;
+                found = true;
+            }
+            break;
+        }
+    }
+
+    return found;
+}
+
+static hb_bool_t
+HBUnicodeDecompose(hb_unicode_funcs_t *ufuncs,
+                   hb_codepoint_t      ab,
+                   hb_codepoint_t     *a,
+                   hb_codepoint_t     *b,
+                   void               *user_data)
+{
+    return nsUnicodeNormalizer::DecomposeNonRecursively(ab, a, b);
+}
+
 /*
  * gfxFontShaper override to initialize the text run using HarfBuzz
  */
 
 static hb_font_funcs_t * sHBFontFuncs = nsnull;
 static hb_unicode_funcs_t * sHBUnicodeFuncs = nsnull;
 
 bool
@@ -748,16 +882,22 @@ gfxHarfBuzzShaper::ShapeWord(gfxContext 
                                                        HBGetGeneralCategory,
                                                        nsnull, nsnull);
             hb_unicode_funcs_set_combining_class_func(sHBUnicodeFuncs,
                                                       HBGetCombiningClass,
                                                       nsnull, nsnull);
             hb_unicode_funcs_set_eastasian_width_func(sHBUnicodeFuncs,
                                                       HBGetEastAsianWidth,
                                                       nsnull, nsnull);
+            hb_unicode_funcs_set_compose_func(sHBUnicodeFuncs,
+                                              HBUnicodeCompose,
+                                              nsnull, nsnull);
+            hb_unicode_funcs_set_decompose_func(sHBUnicodeFuncs,
+                                                HBUnicodeDecompose,
+                                                nsnull, nsnull);
         }
 
         mHBFace = hb_face_create_for_tables(HBGetTable, this, nsnull);
 
         if (!mUseFontGetGlyph) {
             // get the cmap table and find offset to our subtable
             mCmapTable = mFont->GetFontTable(TRUETYPE_TAG('c','m','a','p'));
             if (!mCmapTable) {
--- a/intl/unicharutil/public/Makefile.in
+++ b/intl/unicharutil/public/Makefile.in
@@ -43,12 +43,13 @@ VPATH		= @srcdir@
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= unicharutil
 
 EXPORTS		= \
 		nsICaseConversion.h \
 		nsIUGenCategory.h \
 		nsUnicharUtilCIID.h \
+		nsUnicodeNormalizer.h \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
rename from intl/unicharutil/src/nsUnicodeNormalizer.h
rename to intl/unicharutil/public/nsUnicodeNormalizer.h
--- a/intl/unicharutil/src/nsUnicodeNormalizer.h
+++ b/intl/unicharutil/public/nsUnicodeNormalizer.h
@@ -52,12 +52,16 @@ public:
    virtual ~nsUnicodeNormalizer();
 
    NS_DECL_ISUPPORTS 
 
    NS_IMETHOD NormalizeUnicodeNFD( const nsAString& aSrc, nsAString& aDest);
    NS_IMETHOD NormalizeUnicodeNFC( const nsAString& aSrc, nsAString& aDest);
    NS_IMETHOD NormalizeUnicodeNFKD( const nsAString& aSrc, nsAString& aDest);
    NS_IMETHOD NormalizeUnicodeNFKC( const nsAString& aSrc, nsAString& aDest);
+
+   // low-level access to the composition data needed for HarfBuzz callbacks
+   static bool Compose(PRUint32 a, PRUint32 b, PRUint32 *ab);
+   static bool DecomposeNonRecursively(PRUint32 comp, PRUint32 *c1, PRUint32 *c2);
 };
 
 #endif //nsUnicodeNormalizer_h__
 
--- a/intl/unicharutil/src/nsUnicodeNormalizer.cpp
+++ b/intl/unicharutil/src/nsUnicodeNormalizer.cpp
@@ -708,8 +708,35 @@ nsUnicodeNormalizer::NormalizeUnicodeNFK
 }
 
 nsresult  
 nsUnicodeNormalizer::NormalizeUnicodeNFKC( const nsAString& aSrc, nsAString& aDest)
 {
   return mdn_normalize(true, true, aSrc, aDest);
 }
 
+bool
+nsUnicodeNormalizer::Compose(PRUint32 a, PRUint32 b, PRUint32 *ab)
+{
+  return mdn__unicode_compose(a, b, ab) == NS_OK;
+}
+
+bool
+nsUnicodeNormalizer::DecomposeNonRecursively(PRUint32 c, PRUint32 *c1, PRUint32 *c2)
+{
+  // We can't use mdn__unicode_decompose here, because that does a recursive
+  // decomposition that may yield more than two characters, but the harfbuzz
+  // callback wants just a single-step decomp that is guaranteed to produce
+  // no more than two characters. So we do a low-level lookup in the table
+  // of decomp sequences.
+  const PRUint32 *seq;
+  PRUint32 seqidx = decompose_char(c, &seq);
+  if (seqidx == 0 || ((seqidx & DECOMP_COMPAT) != 0)) {
+    return false;
+  }
+  *c1 = *seq & ~END_BIT;
+  if (*seq & END_BIT) {
+    *c2 = 0;
+  } else {
+    *c2 = *++seq & ~END_BIT;
+  }
+  return true;
+}
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -148,16 +148,17 @@ CPPSRCS		= \
 		jswrapper.cpp \
 		jsxdrapi.cpp \
 		jsxml.cpp \
 		prmjtime.cpp \
 		sharkctl.cpp \
 		ScopeObject.cpp \
 		Debugger.cpp \
 		GlobalObject.cpp \
+		MethodGuard.cpp \
 		Stack.cpp \
 		String.cpp \
 		BytecodeCompiler.cpp \
 		BytecodeEmitter.cpp \
 		FoldConstants.cpp \
 		ParseMaps.cpp \
 		ParseNode.cpp \
 		Parser.cpp \
--- a/js/src/MemoryMetrics.cpp
+++ b/js/src/MemoryMetrics.cpp
@@ -50,77 +50,68 @@
 
 #ifdef JS_THREADSAFE
 
 namespace JS {
 
 using namespace js;
 
 static void
-CompartmentStatsCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
+StatsCompartmentCallback(JSContext *cx, void *data, JSCompartment *compartment)
 {
     // Append a new CompartmentStats to the vector.
-    RuntimeStats *rtStats = static_cast<RuntimeStats *>(vdata);
+    RuntimeStats *rtStats = static_cast<RuntimeStats *>(data);
 
     // CollectRuntimeStats reserves enough space.
     MOZ_ALWAYS_TRUE(rtStats->compartmentStatsVector.growBy(1));
     CompartmentStats &cStats = rtStats->compartmentStatsVector.back();
     cStats.init(rtStats->getNameCb(cx, compartment), rtStats->destroyNameCb);
     rtStats->currCompartmentStats = &cStats;
 
     // Get the compartment-level numbers.
 #ifdef JS_METHODJIT
     cStats.mjitCode = compartment->sizeOfMjitCode();
 #endif
     compartment->sizeOfTypeInferenceData(cx, &cStats.typeInferenceSizes, rtStats->mallocSizeOf);
     cStats.shapesCompartmentTables = compartment->sizeOfShapeTable(rtStats->mallocSizeOf);
 }
 
 static void
-ExplicitNonHeapCompartmentCallback(JSContext *cx, void *data, JSCompartment *compartment)
-{
-#ifdef JS_METHODJIT
-    size_t *n = static_cast<size_t *>(data);
-    *n += compartment->sizeOfMjitCode();
-#endif
-}
-
-static void
-ChunkCallback(JSContext *cx, void *vdata, gc::Chunk *chunk)
+StatsChunkCallback(JSContext *cx, void *data, gc::Chunk *chunk)
 {
     // Nb: This function is only called for dirty chunks, which is why we
     // increment gcHeapChunkDirtyDecommitted.
-    RuntimeStats *rtStats = static_cast<RuntimeStats *>(vdata);
+    RuntimeStats *rtStats = static_cast<RuntimeStats *>(data);
     for (size_t i = 0; i < gc::ArenasPerChunk; i++)
         if (chunk->decommittedArenas.get(i))
             rtStats->gcHeapChunkDirtyDecommitted += gc::ArenaSize;
 }
 
 static void
-ArenaCallback(JSContext *cx, void *vdata, gc::Arena *arena,
-              JSGCTraceKind traceKind, size_t thingSize)
+StatsArenaCallback(JSContext *cx, void *data, gc::Arena *arena,
+                   JSGCTraceKind traceKind, size_t thingSize)
 {
-    RuntimeStats *rtStats = static_cast<RuntimeStats *>(vdata);
+    RuntimeStats *rtStats = static_cast<RuntimeStats *>(data);
 
     rtStats->currCompartmentStats->gcHeapArenaHeaders += sizeof(gc::ArenaHeader);
     size_t allocationSpace = arena->thingsSpan(thingSize);
     rtStats->currCompartmentStats->gcHeapArenaPadding +=
         gc::ArenaSize - allocationSpace - sizeof(gc::ArenaHeader);
     // We don't call the callback on unused things.  So we compute the
     // unused space like this:  arenaUnused = maxArenaUnused - arenaUsed.
     // We do this by setting arenaUnused to maxArenaUnused here, and then
-    // subtracting thingSize for every used cell, in CellCallback().
+    // subtracting thingSize for every used cell, in StatsCellCallback().
     rtStats->currCompartmentStats->gcHeapArenaUnused += allocationSpace;
 }
 
 static void
-CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind,
-             size_t thingSize)
+StatsCellCallback(JSContext *cx, void *data, void *thing, JSGCTraceKind traceKind,
+                  size_t thingSize)
 {
-    RuntimeStats *rtStats = static_cast<RuntimeStats *>(vdata);
+    RuntimeStats *rtStats = static_cast<RuntimeStats *>(data);
     CompartmentStats *cStats = rtStats->currCompartmentStats;
     switch (traceKind) {
     case JSTRACE_OBJECT:
     {
         JSObject *obj = static_cast<JSObject *>(thing);
         if (obj->isFunction()) {
             cStats->gcHeapObjectsFunction += thingSize;
         } else {
@@ -180,17 +171,17 @@ CellCallback(JSContext *cx, void *vdata,
         break;
     }
     case JSTRACE_XML:
     {
         cStats->gcHeapXML += thingSize;
         break;
     }
     }
-    // Yes, this is a subtraction:  see ArenaCallback() for details.
+    // Yes, this is a subtraction:  see StatsArenaCallback() for details.
     cStats->gcHeapArenaUnused -= thingSize;
 }
 
 JS_PUBLIC_API(bool)
 CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats)
 {
     JSContext *cx = JS_NewContext(rt, 0);
     if (!cx)
@@ -205,19 +196,19 @@ CollectRuntimeStats(JSRuntime *rt, Runti
         rtStats->gcHeapChunkCleanDecommitted =
             rt->gcChunkPool.countCleanDecommittedArenas(rt) * gc::ArenaSize;
         rtStats->gcHeapChunkCleanUnused =
             size_t(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) * gc::ChunkSize -
             rtStats->gcHeapChunkCleanDecommitted;
         rtStats->gcHeapChunkTotal =
             size_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) * gc::ChunkSize;
 
-        IterateCompartmentsArenasCells(cx, rtStats, CompartmentStatsCallback,
-                                       ArenaCallback, CellCallback);
-        IterateChunks(cx, rtStats, ChunkCallback);
+        IterateCompartmentsArenasCells(cx, rtStats, StatsCompartmentCallback,
+                                       StatsArenaCallback, StatsCellCallback);
+        IterateChunks(cx, rtStats, StatsChunkCallback);
 
         rtStats->runtimeObject = rtStats->mallocSizeOf(rt);
 
         rt->sizeOfExcludingThis(rtStats->mallocSizeOf,
                                 &rtStats->runtimeNormal,
                                 &rtStats->runtimeTemporary,
                                 &rtStats->runtimeRegexpCode,
                                 &rtStats->runtimeStackCommitted);
@@ -303,16 +294,25 @@ CollectRuntimeStats(JSRuntime *rt, Runti
                                        rtStats->gcHeapChunkCleanDecommitted +
                                        rtStats->gcHeapChunkDirtyDecommitted +
                                        rtStats->gcHeapArenaUnused) * 10000 /
                                        rtStats->gcHeapChunkTotal;
 
     return true;
 }
 
+static void
+ExplicitNonHeapCompartmentCallback(JSContext *cx, void *data, JSCompartment *compartment)
+{
+#ifdef JS_METHODJIT
+    size_t *n = static_cast<size_t *>(data);
+    *n += compartment->sizeOfMjitCode();
+#endif
+}
+
 JS_PUBLIC_API(bool)
 GetExplicitNonHeapForRuntime(JSRuntime *rt, int64_t *amount,
                              JSMallocSizeOfFun mallocSizeOf)
 {
     JSContext *cx = JS_NewContext(rt, 0);
     if (!cx)
         return false;
 
@@ -320,17 +320,17 @@ GetExplicitNonHeapForRuntime(JSRuntime *
     *amount = int64_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
               gc::ChunkSize;
 
     {
         JSAutoRequest ar(cx);
 
         // explicit/<compartment>/mjit-code
         size_t n = 0;
-        IterateCompartments(cx, &n, ExplicitNonHeapCompartmentCallback);
+        JS_IterateCompartments(cx, &n, ExplicitNonHeapCompartmentCallback);
         *amount += n;
 
         // explicit/runtime/regexp-code
         // explicit/runtime/stack-committed
         size_t regexpCode, stackCommitted;
         rt->sizeOfExcludingThis(mallocSizeOf,
                                 NULL,
                                 NULL,
@@ -341,11 +341,33 @@ GetExplicitNonHeapForRuntime(JSRuntime *
         *amount += stackCommitted;
     }
 
     JS_DestroyContextNoGC(cx);
 
     return true;
 }
 
+JS_PUBLIC_API(size_t)
+SystemCompartmentCount(const JSRuntime *rt)
+{
+    size_t n = 0;
+    for (size_t i = 0; i < rt->compartments.length(); i++) {
+        if (rt->compartments[i]->isSystemCompartment)
+            ++n;
+    }
+    return n;
+}
+
+JS_PUBLIC_API(size_t)
+UserCompartmentCount(const JSRuntime *rt)
+{
+    size_t n = 0;
+    for (size_t i = 0; i < rt->compartments.length(); i++) {
+        if (!rt->compartments[i]->isSystemCompartment)
+            ++n;
+    }
+    return n;
+}
+
 } // namespace JS
 
 #endif // JS_THREADSAFE
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -40,16 +40,17 @@
 
 #include "builtin/MapObject.h"
 
 #include "jscntxt.h"
 #include "jsgcmark.h"
 #include "jsobj.h"
 
 #include "vm/GlobalObject.h"
+#include "vm/MethodGuard.h"
 #include "vm/Stack.h"
 
 #include "jsobjinlines.h"
 
 using namespace js;
 
 static JSObject *
 InitClass(JSContext *cx, GlobalObject *global, Class *clasp, JSProtoKey key, Native construct,
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -37,16 +37,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "jscntxt.h"
 
 #include "builtin/RegExp.h"
 
+#include "vm/MethodGuard-inl.h"
 #include "vm/RegExpObject-inl.h"
 #include "vm/RegExpStatics-inl.h"
 
 using namespace js;
 using namespace js::types;
 
 class RegExpMatchBuilder
 {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -87,16 +87,17 @@
 #include "builtin/MapObject.h"
 #include "builtin/RegExp.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "gc/Memory.h"
 #include "js/MemoryMetrics.h"
 #include "mozilla/Util.h"
 #include "yarr/BumpPointerAllocator.h"
+#include "vm/MethodGuard.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/RegExpObject-inl.h"
@@ -990,40 +991,16 @@ JS_GetRuntimePrivate(JSRuntime *rt)
 }
 
 JS_PUBLIC_API(void)
 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
 {
     rt->data = data;
 }
 
-JS_PUBLIC_API(size_t)
-JS::SystemCompartmentCount(const JSRuntime *rt)
-{
-    size_t n = 0;
-    for (size_t i = 0; i < rt->compartments.length(); i++) {
-        if (rt->compartments[i]->isSystemCompartment) {
-            ++n;
-        }
-    }
-    return n;
-}
-
-JS_PUBLIC_API(size_t)
-JS::UserCompartmentCount(const JSRuntime *rt)
-{
-    size_t n = 0;
-    for (size_t i = 0; i < rt->compartments.length(); i++) {
-        if (!rt->compartments[i]->isSystemCompartment) {
-            ++n;
-        }
-    }
-    return n;
-}
-
 #ifdef JS_THREADSAFE
 static void
 StartRequest(JSContext *cx)
 {
     JSRuntime *rt = cx->runtime;
     JS_ASSERT(rt->onOwnerThread());
 
     if (rt->requestDepth) {
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2685,16 +2685,28 @@ class JS_PUBLIC_API(JSAutoEnterCompartme
     bool entered() const { return state != STATE_UNENTERED; }
 
     ~JSAutoEnterCompartment();
 };
 
 JS_BEGIN_EXTERN_C
 #endif
 
+typedef void (*JSIterateCompartmentCallback)(JSContext *cx, void *data,
+              JSCompartment *compartment);
+
+/*
+ * This function calls |compartmentCallback| on every compartment.  Beware that
+ * there is no guarantee that the compartment will survive after the callback
+ * returns.
+ */
+extern JS_PUBLIC_API(void)
+JS_IterateCompartments(JSContext *cx, void *data,
+                       JSIterateCompartmentCallback compartmentCallback);
+
 extern JS_PUBLIC_API(JSObject *)
 JS_GetGlobalObject(JSContext *cx);
 
 extern JS_PUBLIC_API(void)
 JS_SetGlobalObject(JSContext *cx, JSObject *obj);
 
 /*
  * Initialize standard JS class constructors, prototypes, and any top-level
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -122,16 +122,17 @@
 #include "jsscope.h"
 #include "jsstr.h"
 #include "jswrapper.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/StubCalls.h"
 #include "methodjit/StubCalls-inl.h"
 
 #include "vm/ArgumentsObject.h"
+#include "vm/MethodGuard.h"
 
 #include "ds/Sort.h"
 
 #include "jsarrayinlines.h"
 #include "jsatominlines.h"
 #include "jscntxtinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -48,23 +48,25 @@
 #include "jscntxt.h"
 #include "jsinfer.h"
 #include "jsversion.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsstr.h"
 
-#include "vm/BooleanObject-inl.h"
 #include "vm/GlobalObject.h"
 
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
+#include "vm/BooleanObject-inl.h"
+#include "vm/MethodGuard-inl.h"
+
 using namespace js;
 using namespace js::types;
 
 Class js::BooleanClass = {
     "Boolean",
     JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean),    JS_PropertyStub,         /* addProperty */
     JS_PropertyStub,         /* delProperty */
     JS_PropertyStub,         /* getProperty */
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -74,16 +74,17 @@
 #include "jslibmath.h"
 
 #include "vm/GlobalObject.h"
 
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
+#include "vm/MethodGuard-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace js::types;
 
 /*
  * The JS 'Date' object is patterned after the Java 'Date' object.
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -66,18 +66,19 @@
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jsexn.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/TokenStream.h"
+#include "vm/Debugger.h"
+#include "vm/MethodGuard.h"
 #include "vm/ScopeObject.h"
-#include "vm/Debugger.h"
 
 #if JS_HAS_GENERATORS
 # include "jsiter.h"
 #endif
 
 #if JS_HAS_XDR
 # include "jsxdrapi.h"
 #endif
@@ -86,18 +87,18 @@
 #include "methodjit/MethodJIT.h"
 #endif
 
 #include "jsatominlines.h"
 #include "jsfuninlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
+#include "vm/ArgumentsObject-inl.h"
 #include "vm/ScopeObject-inl.h"
-#include "vm/ArgumentsObject-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
 JSBool
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -3785,40 +3785,18 @@ struct IterateCellCallbackOp
     IterateCellCallbackOp(JSContext *cx, void *data, IterateCellCallback callback,
                           JSGCTraceKind traceKind, size_t thingSize)
         : cx(cx), data(data), callback(callback), traceKind(traceKind), thingSize(thingSize)
     {}
     void operator()(Cell *cell) { (*callback)(cx, data, cell, traceKind, thingSize); }
 };
 
 void
-IterateCompartments(JSContext *cx, void *data,
-                    IterateCompartmentCallback compartmentCallback)
-{
-    CHECK_REQUEST(cx);
-
-    JSRuntime *rt = cx->runtime;
-    JS_ASSERT(!rt->gcRunning);
-
-    AutoLockGC lock(rt);
-    AutoHeapSession session(cx);
-#ifdef JS_THREADSAFE
-    rt->gcHelperThread.waitBackgroundSweepEnd();
-#endif
-    AutoUnlockGC unlock(rt);
-
-    AutoCopyFreeListToArenas copy(rt);
-    for (CompartmentsIter c(rt); !c.done(); c.next()) {
-        (*compartmentCallback)(cx, data, c);
-    }
-}
-
-void
 IterateCompartmentsArenasCells(JSContext *cx, void *data,
-                               IterateCompartmentCallback compartmentCallback,
+                               JSIterateCompartmentCallback compartmentCallback,
                                IterateArenaCallback arenaCallback,
                                IterateCellCallback cellCallback)
 {
     CHECK_REQUEST(cx);
 
     JSRuntime *rt = cx->runtime;
     JS_ASSERT(!rt->gcRunning);
 
@@ -4553,16 +4531,37 @@ PurgePCCounts(JSContext *cx)
         return;
     JS_ASSERT(!rt->profilingScripts);
 
     ReleaseScriptPCCounters(cx);
 }
 
 } /* namespace js */
 
+JS_PUBLIC_API(void)
+JS_IterateCompartments(JSContext *cx, void *data,
+                       JSIterateCompartmentCallback compartmentCallback)
+{
+    CHECK_REQUEST(cx);
+
+    JSRuntime *rt = cx->runtime;
+    JS_ASSERT(!rt->gcRunning);
+
+    AutoLockGC lock(rt);
+    AutoHeapSession session(cx);
+#ifdef JS_THREADSAFE
+    rt->gcHelperThread.waitBackgroundSweepEnd();
+#endif
+    AutoUnlockGC unlock(rt);
+
+    AutoCopyFreeListToArenas copy(rt);
+    for (CompartmentsIter c(rt); !c.done(); c.next())
+        (*compartmentCallback)(cx, data, c);
+}
+
 #if JS_HAS_XML_SUPPORT
 extern size_t sE4XObjectsCreated;
 
 JSXML *
 js_NewGCXML(JSContext *cx)
 {
     if (!cx->runningWithTrustedPrincipals())
         ++sE4XObjectsCreated;
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1891,37 +1891,30 @@ struct FullGCMarker : public GCMarker {
     bool init() {
         return GCMarker::init(false);
     }
 };
 
 void
 MarkStackRangeConservatively(JSTracer *trc, Value *begin, Value *end);
 
-typedef void (*IterateCompartmentCallback)(JSContext *cx, void *data, JSCompartment *compartment);
 typedef void (*IterateChunkCallback)(JSContext *cx, void *data, gc::Chunk *chunk);
 typedef void (*IterateArenaCallback)(JSContext *cx, void *data, gc::Arena *arena,
                                      JSGCTraceKind traceKind, size_t thingSize);
 typedef void (*IterateCellCallback)(JSContext *cx, void *data, void *thing,
                                     JSGCTraceKind traceKind, size_t thingSize);
 
 /*
- * This function calls |compartmentCallback| on every compartment.
- */
-extern JS_FRIEND_API(void)
-IterateCompartments(JSContext *cx, void *data,
-                    IterateCompartmentCallback compartmentCallback);
-/*
  * This function calls |compartmentCallback| on every compartment,
  * |arenaCallback| on every in-use arena, and |cellCallback| on every in-use
  * cell in the GC heap.
  */
 extern JS_FRIEND_API(void)
 IterateCompartmentsArenasCells(JSContext *cx, void *data,
-                               IterateCompartmentCallback compartmentCallback,
+                               JSIterateCompartmentCallback compartmentCallback,
                                IterateArenaCallback arenaCallback,
                                IterateCellCallback cellCallback);
 
 /*
  * Invoke chunkCallback on every in-use chunk.
  */
 extern JS_FRIEND_API(void)
 IterateChunks(JSContext *cx, void *data, IterateChunkCallback chunkCallback);
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -71,16 +71,17 @@
 
 #include "ds/Sort.h"
 #include "frontend/TokenStream.h"
 #include "vm/GlobalObject.h"
 
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
+#include "vm/MethodGuard-inl.h"
 #include "vm/Stack-inl.h"
 #include "vm/String-inl.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 
 static void iterator_finalize(JSContext *cx, JSObject *obj);
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -67,23 +67,25 @@
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsprf.h"
 #include "jsscope.h"
 #include "jsstr.h"
 #include "jslibmath.h"
 
 #include "vm/GlobalObject.h"
+#include "vm/MethodGuard.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsnuminlines.h"
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
+#include "vm/MethodGuard-inl.h"
 #include "vm/NumberObject-inl.h"
 #include "vm/String-inl.h"
 
 using namespace js;
 using namespace js::types;
 
 /*
  * If we're accumulating a decimal number and the number is >= 2^53, then the
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -85,19 +85,17 @@
 
 #include "jsarrayinlines.h"
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 #include "jsstrinlines.h"
 
-#include "vm/BooleanObject-inl.h"
-#include "vm/NumberObject-inl.h"
-#include "vm/StringObject-inl.h"
+#include "vm/MethodGuard-inl.h"
 
 #if JS_HAS_GENERATORS
 #include "jsiter.h"
 #endif
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
@@ -6356,59 +6354,16 @@ js_ReportGetterOnlyAssignment(JSContext 
 
 JS_FRIEND_API(JSBool)
 js_GetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_GETTER_ONLY);
     return JS_FALSE;
 }
 
-void
-js::ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp)
-{
-    Value &thisv = call.thisv();
-
-#ifdef DEBUG
-    if (thisv.isObject()) {
-        JS_ASSERT(thisv.toObject().getClass() != clasp ||
-                  !thisv.toObject().getProto() ||
-                  thisv.toObject().getProto()->getClass() != clasp);
-    } else if (thisv.isString()) {
-        JS_ASSERT(clasp != &StringClass);
-    } else if (thisv.isNumber()) {
-        JS_ASSERT(clasp != &NumberClass);
-    } else if (thisv.isBoolean()) {
-        JS_ASSERT(clasp != &BooleanClass);
-    } else {
-        JS_ASSERT(thisv.isUndefined() || thisv.isNull());
-    }
-#endif
-
-    if (JSFunction *fun = js_ValueToFunction(cx, &call.calleev(), 0)) {
-        JSAutoByteString funNameBytes;
-        if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
-                                 clasp->name, funName, InformalValueTypeName(thisv));
-        }
-    }
-}
-
-bool
-js::HandleNonGenericMethodClassMismatch(JSContext *cx, CallArgs args, Native native, Class *clasp)
-{
-    if (args.thisv().isObject()) {
-        JSObject &thisObj = args.thisv().toObject();
-        if (thisObj.isProxy())
-            return Proxy::nativeCall(cx, &thisObj, clasp, native, args);
-    }
-
-    ReportIncompatibleMethod(cx, args, clasp);
-    return false;
-}
-
 #ifdef DEBUG
 
 /*
  * Routines to print out values during debugging.  These are FRIEND_API to help
  * the debugger find them and to support temporarily hacking js_Dump* calls
  * into other code.
  */
 
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -2025,76 +2025,11 @@ extern JSPrincipals *
 PrincipalsForCompiledCode(const CallReceiver &call, JSContext *cx);
 
 extern JSObject *
 NonNullObject(JSContext *cx, const Value &v);
 
 extern const char *
 InformalValueTypeName(const Value &v);
 
-/*
- * Report an error if call.thisv is not compatible with the specified class.
- *
- * NB: most callers should be calling or NonGenericMethodGuard,
- * HandleNonGenericMethodClassMismatch, or BoxedPrimitiveMethodGuard (so that
- * transparent proxies are handled correctly). Thus, any caller of this
- * function better have a good explanation for why proxies are being handled
- * correctly (e.g., by IsCallable) or are not an issue (E4X).
- */
-extern void
-ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp);
-
-/*
- * A non-generic method is specified to report an error if args.thisv is not an
- * object with a specific [[Class]] internal property (ES5 8.6.2).
- * NonGenericMethodGuard performs this checking. Canonical usage is:
- *
- *   CallArgs args = ...
- *   bool ok;
- *   JSObject *thisObj = NonGenericMethodGuard(cx, args, clasp, &ok);
- *   if (!thisObj)
- *     return ok;
- *
- * Specifically: if obj is a proxy, NonGenericMethodGuard will call the
- * object's ProxyHandler's nativeCall hook (which may recursively call
- * args.callee in args.thisv's compartment). Thus, there are three possible
- * post-conditions:
- *
- *   1. thisv is an object of the given clasp: the caller may proceed;
- *
- *   2. there was an error: the caller must return 'false';
- *
- *   3. thisv wrapped an object of the given clasp and the native was reentered
- *      and completed succesfully: the caller must return 'true'.
- *
- * Case 1 is indicated by a non-NULL return value; case 2 by a NULL return
- * value with *ok == false; and case 3 by a NULL return value with *ok == true.
- *
- * NB: since this guard may reenter the native, the guard must be placed before
- * any effectful operations are performed.
- */
-inline JSObject *
-NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, bool *ok);
-
-/*
- * NonGenericMethodGuard tests args.thisv's class using 'clasp'. If more than
- * one class is acceptable (viz., isDenseArray() || isSlowArray()), the caller
- * may test the class and delegate to HandleNonGenericMethodClassMismatch to
- * handle the proxy case and error reporting. The 'clasp' argument is only used
- * for error reporting (clasp->name).
- */
-extern bool
-HandleNonGenericMethodClassMismatch(JSContext *cx, CallArgs args, Native native, Class *clasp);
-
-/*
- * Implement the extraction of a primitive from a value as needed for the
- * toString, valueOf, and a few other methods of the boxed primitives classes
- * Boolean, Number, and String (e.g., ES5 15.6.4.2). If 'true' is returned, the
- * extracted primitive is stored in |*v|. If 'false' is returned, the caller
- * must immediately 'return *ok'. For details, see NonGenericMethodGuard.
- */
-template <typename T>
-inline bool
-BoxedPrimitiveMethodGuard(JSContext *cx, CallArgs args, Native native, T *v, bool *ok);
-
 }  /* namespace js */
 
 #endif /* jsobj_h___ */
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -1910,84 +1910,16 @@ PropDesc::checkSetter(JSContext *cx)
     if (hasSet && !js_IsCallable(set) && !set.isUndefined()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GET_SET_FIELD,
                              js_setter_str);
         return false;
     }
     return true;
 }
 
-namespace detail {
-
-template<typename T> class PrimitiveBehavior { };
-
-template<>
-class PrimitiveBehavior<JSString *> {
-  public:
-    static inline bool isType(const Value &v) { return v.isString(); }
-    static inline JSString *extract(const Value &v) { return v.toString(); }
-    static inline JSString *extract(JSObject &obj) { return obj.asString().unbox(); }
-    static inline Class *getClass() { return &StringClass; }
-};
-
-template<>
-class PrimitiveBehavior<bool> {
-  public:
-    static inline bool isType(const Value &v) { return v.isBoolean(); }
-    static inline bool extract(const Value &v) { return v.toBoolean(); }
-    static inline bool extract(JSObject &obj) { return obj.asBoolean().unbox(); }
-    static inline Class *getClass() { return &BooleanClass; }
-};
-
-template<>
-class PrimitiveBehavior<double> {
-  public:
-    static inline bool isType(const Value &v) { return v.isNumber(); }
-    static inline double extract(const Value &v) { return v.toNumber(); }
-    static inline double extract(JSObject &obj) { return obj.asNumber().unbox(); }
-    static inline Class *getClass() { return &NumberClass; }
-};
-
-} /* namespace detail */
-
-inline JSObject *
-NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, bool *ok)
-{
-    const Value &thisv = args.thisv();
-    if (thisv.isObject()) {
-        JSObject &obj = thisv.toObject();
-        if (obj.getClass() == clasp) {
-            *ok = true;  /* quell gcc overwarning */
-            return &obj;
-        }
-    }
-
-    *ok = HandleNonGenericMethodClassMismatch(cx, args, native, clasp);
-    return NULL;
-}
-
-template <typename T>
-inline bool
-BoxedPrimitiveMethodGuard(JSContext *cx, CallArgs args, Native native, T *v, bool *ok)
-{
-    typedef detail::PrimitiveBehavior<T> Behavior;
-
-    const Value &thisv = args.thisv();
-    if (Behavior::isType(thisv)) {
-        *v = Behavior::extract(thisv);
-        return true;
-    }
-
-    if (!NonGenericMethodGuard(cx, args, native, Behavior::getClass(), ok))
-        return false;
-
-    *v = Behavior::extract(thisv.toObject());
-    return true;
-}
-
 inline bool
 ObjectClassIs(JSObject &obj, ESClassValue classValue, JSContext *cx)
 {
     if (JS_UNLIKELY(obj.isProxy()))
         return Proxy::objectClassIs(&obj, classValue, cx);
 
     switch (classValue) {
       case ESClass_Array: return obj.isArray();
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -45,16 +45,18 @@
 #include "jsgc.h"
 #include "jsgcmark.h"
 #include "jsprvtd.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsproxy.h"
 #include "jsscope.h"
 
+#include "vm/MethodGuard.h"
+
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::gc;
 
 static inline HeapValue &
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -76,16 +76,17 @@
 #include "builtin/RegExp.h"
 #include "vm/GlobalObject.h"
 #include "vm/RegExpObject.h"
 
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsautooplen.h"        // generated headers last
 
+#include "vm/MethodGuard-inl.h"
 #include "vm/RegExpObject-inl.h"
 #include "vm/RegExpStatics-inl.h"
 #include "vm/StringObject-inl.h"
 #include "vm/String-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -62,16 +62,18 @@
 
 #include "vm/GlobalObject.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jstypedarrayinlines.h"
 
+#include "vm/MethodGuard-inl.h"
+
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
 /*
  * Allocate array buffers with the maximum number of fixed slots marked as
  * reserved, so that the fixed slots may be used for the buffer's contents.
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -49,16 +49,18 @@
 #include "jsgcmark.h"
 #include "jsweakmap.h"
 
 #include "vm/GlobalObject.h"
 
 #include "jsgcinlines.h"
 #include "jsobjinlines.h"
 
+#include "vm/MethodGuard-inl.h"
+
 using namespace js;
 
 namespace js {
 
 bool
 WeakMapBase::markAllIteratively(JSTracer *tracer)
 {
     bool markedAny = false;
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -65,16 +65,17 @@
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jsxml.h"
 
 #include "frontend/Parser.h"
 #include "frontend/TokenStream.h"
 #include "vm/GlobalObject.h"
+#include "vm/MethodGuard.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
 #include "vm/Stack-inl.h"
 #include "vm/String-inl.h"
new file mode 100644
--- /dev/null
+++ b/js/src/vm/MethodGuard-inl.h
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is SpiderMonkey method-guard code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef MethodGuard_inl_h___
+#define MethodGuard_inl_h___
+
+#include "jsobj.h"
+
+#include "MethodGuard.h"
+
+#include "jsobjinlines.h"
+
+#include "BooleanObject-inl.h"
+#include "NumberObject-inl.h"
+#include "StringObject-inl.h"
+
+namespace js {
+
+namespace detail {
+
+template<typename T> class PrimitiveBehavior { };
+
+template<>
+class PrimitiveBehavior<bool> {
+  public:
+    static inline bool isType(const Value &v) { return v.isBoolean(); }
+    static inline bool extract(const Value &v) { return v.toBoolean(); }
+    static inline bool extract(JSObject &obj) { return obj.asBoolean().unbox(); }
+    static inline Class *getClass() { return &BooleanClass; }
+};
+
+template<>
+class PrimitiveBehavior<double> {
+  public:
+    static inline bool isType(const Value &v) { return v.isNumber(); }
+    static inline double extract(const Value &v) { return v.toNumber(); }
+    static inline double extract(JSObject &obj) { return obj.asNumber().unbox(); }
+    static inline Class *getClass() { return &NumberClass; }
+};
+
+template<>
+class PrimitiveBehavior<JSString *> {
+  public:
+    static inline bool isType(const Value &v) { return v.isString(); }
+    static inline JSString *extract(const Value &v) { return v.toString(); }
+    static inline JSString *extract(JSObject &obj) { return obj.asString().unbox(); }
+    static inline Class *getClass() { return &StringClass; }
+};
+
+} /* namespace detail */
+
+inline JSObject *
+NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, bool *ok)
+{
+    const Value &thisv = args.thisv();
+    if (thisv.isObject()) {
+        JSObject &obj = thisv.toObject();
+        if (obj.getClass() == clasp) {
+            *ok = true;  /* quell gcc overwarning */
+            return &obj;
+        }
+    }
+
+    *ok = HandleNonGenericMethodClassMismatch(cx, args, native, clasp);
+    return NULL;
+}
+
+template <typename T>
+inline bool
+BoxedPrimitiveMethodGuard(JSContext *cx, CallArgs args, Native native, T *v, bool *ok)
+{
+    typedef detail::PrimitiveBehavior<T> Behavior;
+
+    const Value &thisv = args.thisv();
+    if (Behavior::isType(thisv)) {
+        *v = Behavior::extract(thisv);
+        return true;
+    }
+
+    if (!NonGenericMethodGuard(cx, args, native, Behavior::getClass(), ok))
+        return false;
+
+    *v = Behavior::extract(thisv.toObject());
+    return true;
+}
+
+} /* namespace js */
+
+#endif /* MethodGuard_inl_h___ */
new file mode 100644
--- /dev/null
+++ b/js/src/vm/MethodGuard.cpp
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is SpiderMonkey method-guard code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "jsproxy.h"
+
+#include "MethodGuard.h"
+#include "Stack.h"
+
+#include "jsfuninlines.h"
+#include "jsobjinlines.h"
+
+using namespace js;
+
+void
+js::ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp)
+{
+    Value &thisv = call.thisv();
+
+#ifdef DEBUG
+    if (thisv.isObject()) {
+        JS_ASSERT(thisv.toObject().getClass() != clasp ||
+                  !thisv.toObject().getProto() ||
+                  thisv.toObject().getProto()->getClass() != clasp);
+    } else if (thisv.isString()) {
+        JS_ASSERT(clasp != &StringClass);
+    } else if (thisv.isNumber()) {
+        JS_ASSERT(clasp != &NumberClass);
+    } else if (thisv.isBoolean()) {
+        JS_ASSERT(clasp != &BooleanClass);
+    } else {
+        JS_ASSERT(thisv.isUndefined() || thisv.isNull());
+    }
+#endif
+
+    if (JSFunction *fun = js_ValueToFunction(cx, &call.calleev(), 0)) {
+        JSAutoByteString funNameBytes;
+        if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
+                                 clasp->name, funName, InformalValueTypeName(thisv));
+        }
+    }
+}
+
+bool
+js::HandleNonGenericMethodClassMismatch(JSContext *cx, CallArgs args, Native native, Class *clasp)
+{
+    if (args.thisv().isObject()) {
+        JSObject &thisObj = args.thisv().toObject();
+        if (thisObj.isProxy())
+            return Proxy::nativeCall(cx, &thisObj, clasp, native, args);
+    }
+
+    ReportIncompatibleMethod(cx, args, clasp);
+    return false;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/vm/MethodGuard.h
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is SpiderMonkey method-guard code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* Method prologue type-checking and unwrapping of the this parameter. */
+
+#ifndef MethodGuard_h___
+#define MethodGuard_h___
+
+#include "jsobj.h"
+
+namespace js {
+
+/*
+ * Report an error if call.thisv is not compatible with the specified class.
+ *
+ * NB: most callers should be calling or NonGenericMethodGuard,
+ * HandleNonGenericMethodClassMismatch, or BoxedPrimitiveMethodGuard (so that
+ * transparent proxies are handled correctly). Thus, any caller of this
+ * function better have a good explanation for why proxies are being handled
+ * correctly (e.g., by IsCallable) or are not an issue (E4X).
+ */
+extern void
+ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp);
+
+/*
+ * A non-generic method is specified to report an error if args.thisv is not an
+ * object with a specific [[Class]] internal property (ES5 8.6.2).
+ * NonGenericMethodGuard performs this checking. Canonical usage is:
+ *
+ *   CallArgs args = ...
+ *   bool ok;
+ *   JSObject *thisObj = NonGenericMethodGuard(cx, args, clasp, &ok);
+ *   if (!thisObj)
+ *     return ok;
+ *
+ * Specifically: if obj is a proxy, NonGenericMethodGuard will call the
+ * object's ProxyHandler's nativeCall hook (which may recursively call
+ * args.callee in args.thisv's compartment). Thus, there are three possible
+ * post-conditions:
+ *
+ *   1. thisv is an object of the given clasp: the caller may proceed;
+ *
+ *   2. there was an error: the caller must return 'false';
+ *
+ *   3. thisv wrapped an object of the given clasp and the native was reentered
+ *      and completed succesfully: the caller must return 'true'.
+ *
+ * Case 1 is indicated by a non-NULL return value; case 2 by a NULL return
+ * value with *ok == false; and case 3 by a NULL return value with *ok == true.
+ *
+ * NB: since this guard may reenter the native, the guard must be placed before
+ * any effectful operations are performed.
+ */
+inline JSObject *
+NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, bool *ok);
+
+/*
+ * NonGenericMethodGuard tests args.thisv's class using 'clasp'. If more than
+ * one class is acceptable (viz., isDenseArray() || isSlowArray()), the caller
+ * may test the class and delegate to HandleNonGenericMethodClassMismatch to
+ * handle the proxy case and error reporting. The 'clasp' argument is only used
+ * for error reporting (clasp->name).
+ */
+extern bool
+HandleNonGenericMethodClassMismatch(JSContext *cx, CallArgs args, Native native, Class *clasp);
+
+/*
+ * Implement the extraction of a primitive from a value as needed for the
+ * toString, valueOf, and a few other methods of the boxed primitives classes
+ * Boolean, Number, and String (e.g., ES5 15.6.4.2). If 'true' is returned, the
+ * extracted primitive is stored in |*v|. If 'false' is returned, the caller
+ * must immediately 'return *ok'. For details, see NonGenericMethodGuard.
+ */
+template <typename T>
+inline bool
+BoxedPrimitiveMethodGuard(JSContext *cx, CallArgs args, Native native, T *v, bool *ok);
+
+} /* namespace js */
+
+#endif /* MethodGuard_h___ */
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1206,29 +1206,29 @@ XPCJSRuntime::~XPCJSRuntime()
     }
 
     XPCPerThreadData::ShutDown();
 }
 
 namespace xpc {
 
 void*
-GetCompartmentName(JSContext *cx, JSCompartment *c)
+GetCompartmentNameHelper(JSContext *cx, JSCompartment *c, bool getAddress)
 {
     nsCString* name = new nsCString();
     if (js::IsAtomsCompartmentFor(cx, c)) {
         name->AssignLiteral("atoms");
     } else if (JSPrincipals *principals = JS_GetCompartmentPrincipals(c)) {
         if (principals->codebase) {
             name->Assign(principals->codebase);
 
-            // If it's the system compartment, append the address.
-            // This means that multiple system compartments (and there
-            // can be many) can be distinguished.
-            if (js::IsSystemCompartment(c)) {
+            // If it's the system compartment and |getAddress| is true, append
+            // the address.  This means that multiple system compartments (and
+            // there can be many) can be distinguished.
+            if (getAddress && js::IsSystemCompartment(c)) {
                 xpc::CompartmentPrivate *compartmentPrivate =
                     static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(cx, c));
                 if (compartmentPrivate &&
                     !compartmentPrivate->location.IsEmpty()) {
                     name->AppendLiteral(", ");
                     name->Append(compartmentPrivate->location);
                 }
 
@@ -1246,16 +1246,28 @@ GetCompartmentName(JSContext *cx, JSComp
             name->AssignLiteral("null-codebase");
         }
     } else {
         name->AssignLiteral("null-principal");
     }
     return name;
 }
 
+void*
+GetCompartmentName(JSContext *cx, JSCompartment *c)
+{
+    return GetCompartmentNameHelper(cx, c, /* get address = */false);
+}
+
+void*
+GetCompartmentNameAndAddress(JSContext *cx, JSCompartment *c)
+{
+    return GetCompartmentNameHelper(cx, c, /* get address = */true);
+}
+
 void
 DestroyCompartmentName(void *string)
 {
     delete static_cast<nsCString*>(string);
 }
 
 } // namespace xpc
 
@@ -1367,17 +1379,17 @@ GetJSSystemCompartmentCount()
 static PRInt64
 GetJSUserCompartmentCount()
 {
     return JS::UserCompartmentCount(nsXPConnect::GetRuntimeInstance()->GetJSRuntime());
 }
 
 // Nb: js-system-compartment-count + js-user-compartment-count could be
 // different to the number of compartments reported by
-// XPConnectJSCompartmentsMultiReporter if a garbage collection occurred
+// JSMemoryMultiReporter if a garbage collection occurred
 // between them being consulted.  We could move these reporters into
 // XPConnectJSCompartmentCount to avoid that problem, but then we couldn't
 // easily report them via telemetry, so we live with the small risk of
 // inconsistencies.
 NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSSystemCompartmentCount,
                              "js-compartments-system",
                              KIND_OTHER,
                              nsIMemoryReporter::UNITS_COUNT,
@@ -1700,26 +1712,96 @@ ReportJSRuntimeExplicitTreeStats(const J
                       NS_LITERAL_CSTRING("gc-heap-chunk-admin"),
                       &gcTotal, rtStats.gcHeapChunkAdmin,
                       "Memory on the garbage-collected JavaScript heap, within chunks, that is "
                       "used to hold internal book-keeping information.",
                       callback, closure);
 
     // gcTotal is the sum of everything we've reported for the GC heap.  It
     // should equal rtStats.gcHeapChunkTotal.
-    JS_ASSERT(gcTotal == rtStats.gcHeapChunkTotal);
+    JS_ASSERT(size_t(gcTotal) == rtStats.gcHeapChunkTotal);
 }
 
 } // namespace memory
 } // namespace xpconnect
 } // namespace mozilla
 
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsMallocSizeOf, "js")
 
-class XPConnectJSCompartmentsMultiReporter : public nsIMemoryMultiReporter
+class JSCompartmentsMultiReporter : public nsIMemoryMultiReporter
+{
+  public:
+    NS_DECL_ISUPPORTS
+
+    NS_IMETHOD GetName(nsACString &name)
+    {
+        name.AssignLiteral("compartments");
+        return NS_OK;
+    }
+
+    typedef js::Vector<nsCString, 0, js::SystemAllocPolicy> Paths; 
+
+    static void CompartmentCallback(JSContext *cx, void* data, JSCompartment *c)
+    {
+        Paths *paths = static_cast<Paths *>(data);
+        nsCString *name =
+            static_cast<nsCString *>(xpc::GetCompartmentName(cx, c));
+        nsCString path;
+        if (js::IsSystemCompartment(c))
+            path = NS_LITERAL_CSTRING("compartments/system/") + *name;
+        else
+            path = NS_LITERAL_CSTRING("compartments/user/") + *name;
+        if (!paths->append(path))
+            return;     // silent failure, but it's very unlikely
+
+        xpc::DestroyCompartmentName(name);
+    }
+
+    NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *callback,
+                              nsISupports *closure)
+    {
+        // First we collect the compartment paths.  Then we report them.  Doing
+        // the two steps interleaved is a bad idea, because calling |callback|
+        // from within CompartmentCallback() leads to all manner of assertions.
+
+        // Collect.
+        XPCJSRuntime *xpcrt = nsXPConnect::GetRuntimeInstance();
+        JSContext *cx = JS_NewContext(xpcrt->GetJSRuntime(), 0);
+        if (!cx)
+            return NS_ERROR_OUT_OF_MEMORY;
+
+        Paths paths; 
+        JS_IterateCompartments(cx, &paths, CompartmentCallback);
+        JS_DestroyContextNoGC(cx);
+
+        // Report.
+        for (size_t i = 0; i < paths.length(); i++)
+            // These ones don't need a description, hence the "".
+            ReportMemory(paths[i],
+                         nsIMemoryReporter::KIND_OTHER,
+                         nsIMemoryReporter::UNITS_COUNT,
+                         1, "", callback, closure);
+
+        return NS_OK;
+    }
+
+    NS_IMETHOD
+    GetExplicitNonHeap(PRInt64 *n)
+    {
+        // This reporter does neither "explicit" nor NONHEAP measurements.
+        *n = 0;
+        return NS_OK;
+    }
+};
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(JSCompartmentsMultiReporter
+                              , nsIMemoryMultiReporter
+                              )
+
+class JSMemoryMultiReporter : public nsIMemoryMultiReporter
 {
 public:
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD GetName(nsACString &name)
     {
         name.AssignLiteral("js");
         return NS_OK;
@@ -1730,17 +1812,17 @@ public:
     {
         XPCJSRuntime *xpcrt = nsXPConnect::GetRuntimeInstance();
 
         // In the first step we get all the stats and stash them in a local
         // data structure.  In the second step we pass all the stashed stats to
         // the callback.  Separating these steps is important because the
         // callback may be a JS function, and executing JS while getting these
         // stats seems like a bad idea.
-        JS::RuntimeStats rtStats(JsMallocSizeOf, xpc::GetCompartmentName,
+        JS::RuntimeStats rtStats(JsMallocSizeOf, xpc::GetCompartmentNameAndAddress,
                                  xpc::DestroyCompartmentName);
         if (!JS::CollectRuntimeStats(xpcrt->GetJSRuntime(), &rtStats))
             return NS_ERROR_FAILURE;
 
         size_t xpconnect =
             xpcrt->SizeOfIncludingThis(JsMallocSizeOf) +
             XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(JsMallocSizeOf);
 
@@ -1856,17 +1938,17 @@ public:
 
         if (!JS::GetExplicitNonHeapForRuntime(rt, reinterpret_cast<int64_t*>(n), JsMallocSizeOf))
             return NS_ERROR_FAILURE;
 
         return NS_OK;
     }
 };
 
-NS_IMPL_THREADSAFE_ISUPPORTS1(XPConnectJSCompartmentsMultiReporter
+NS_IMPL_THREADSAFE_ISUPPORTS1(JSMemoryMultiReporter
                               , nsIMemoryMultiReporter
                               )
 
 #ifdef MOZ_CRASHREPORTER
 static JSBool
 DiagnosticMemoryCallback(void *ptr, size_t size)
 {
     return CrashReporter::RegisterAppMemory(ptr, size) == NS_OK;
@@ -1996,17 +2078,18 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
         if (!mWatchdogWakeup)
             NS_RUNTIMEABORT("PR_NewCondVar failed.");
 
         js::SetActivityCallback(mJSRuntime, ActivityCallback, this);
 
         NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSGCHeap));
         NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSSystemCompartmentCount));
         NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSUserCompartmentCount));
-        NS_RegisterMemoryMultiReporter(new XPConnectJSCompartmentsMultiReporter);
+        NS_RegisterMemoryMultiReporter(new JSMemoryMultiReporter);
+        NS_RegisterMemoryMultiReporter(new JSCompartmentsMultiReporter);
     }
 
     if (!JS_DHashTableInit(&mJSHolders, JS_DHashGetStubOps(), nsnull,
                            sizeof(ObjectHolder), 512))
         mJSHolders.ops = nsnull;
 
     mCompartmentMap.Init();
 
@@ -2082,17 +2165,17 @@ XPCJSRuntime::OnJSContextNew(JSContext *
                 }
                 mStrJSVals[i] = STRING_TO_JSVAL(str);
             }
         }
 
         ok = mozilla::dom::binding::DefineStaticJSVals(cx);
         if (!ok)
             return false;
-        
+
         ok = DefineStaticDictionaryJSVals(cx);
     }
     if (!ok)
         return false;
 
     XPCPerThreadData* tls = XPCPerThreadData::GetData(cx);
     if (!tls)
         return false;
--- a/layout/base/nsStyleConsts.h
+++ b/layout/base/nsStyleConsts.h
@@ -470,32 +470,32 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_FONT_STRETCH_SEMI_CONDENSED    NS_FONT_STRETCH_SEMI_CONDENSED
 #define NS_STYLE_FONT_STRETCH_NORMAL            NS_FONT_STRETCH_NORMAL
 #define NS_STYLE_FONT_STRETCH_SEMI_EXPANDED     NS_FONT_STRETCH_SEMI_EXPANDED
 #define NS_STYLE_FONT_STRETCH_EXPANDED          NS_FONT_STRETCH_EXPANDED
 #define NS_STYLE_FONT_STRETCH_EXTRA_EXPANDED    NS_FONT_STRETCH_EXTRA_EXPANDED
 #define NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED    NS_FONT_STRETCH_ULTRA_EXPANDED
 
 // See nsStyleFont - system fonts
-#define NS_STYLE_FONT_CAPTION                   1		// css2
+#define NS_STYLE_FONT_CAPTION                   1   // css2
 #define NS_STYLE_FONT_ICON                      2
 #define NS_STYLE_FONT_MENU                      3
 #define NS_STYLE_FONT_MESSAGE_BOX               4
 #define NS_STYLE_FONT_SMALL_CAPTION             5
 #define NS_STYLE_FONT_STATUS_BAR                6
-#define NS_STYLE_FONT_WINDOW										7		// css3
-#define NS_STYLE_FONT_DOCUMENT									8
-#define NS_STYLE_FONT_WORKSPACE									9
-#define NS_STYLE_FONT_DESKTOP										10
-#define NS_STYLE_FONT_INFO											11
-#define NS_STYLE_FONT_DIALOG										12
-#define NS_STYLE_FONT_BUTTON										13
-#define NS_STYLE_FONT_PULL_DOWN_MENU						14
-#define NS_STYLE_FONT_LIST											15
-#define NS_STYLE_FONT_FIELD											16
+#define NS_STYLE_FONT_WINDOW                    7   // css3
+#define NS_STYLE_FONT_DOCUMENT                  8
+#define NS_STYLE_FONT_WORKSPACE                 9
+#define NS_STYLE_FONT_DESKTOP                   10
+#define NS_STYLE_FONT_INFO                      11
+#define NS_STYLE_FONT_DIALOG                    12
+#define NS_STYLE_FONT_BUTTON                    13
+#define NS_STYLE_FONT_PULL_DOWN_MENU            14
+#define NS_STYLE_FONT_LIST                      15
+#define NS_STYLE_FONT_FIELD                     16
 
 // defaults per MathML spec
 #define NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER 0.71f
 #define NS_MATHML_DEFAULT_SCRIPT_MIN_SIZE_PT 8
 
 // See nsStylePosition::mWidth, mMinWidth, mMaxWidth
 #define NS_STYLE_WIDTH_MAX_CONTENT              0
 #define NS_STYLE_WIDTH_MIN_CONTENT              1
--- a/layout/build/Makefile.in
+++ b/layout/build/Makefile.in
@@ -143,16 +143,20 @@ SHARED_LIBRARY_LIBS += \
 	$(DEPTH)/dom/plugins/base/android/$(LIB_PREFIX)gkpluginandroid_s.$(LIB_SUFFIX) \
 	$(NULL)
 LOCAL_INCLUDES	+= \
 	-I$(topsrcdir)/dom/system/android \
 	-I$(topsrcdir)/dom/system \
 	$(NULL)
 endif
 
+ifdef MOZ_B2G_BT #{
+SHARED_LIBRARY_LIBS	+= $(DEPTH)/dom/bluetooth/$(LIB_PREFIX)dombluetooth_s.$(LIB_SUFFIX)
+endif #}
+
 ifdef MOZ_B2G_RIL #{
 SHARED_LIBRARY_LIBS	+= $(DEPTH)/dom/system/b2g/$(LIB_PREFIX)domsystemb2g_s.$(LIB_SUFFIX)
 endif #}
 
 ifdef MOZ_MEDIA
 SHARED_LIBRARY_LIBS 	+= \
 	$(DEPTH)/content/media/$(LIB_PREFIX)gkconmedia_s.$(LIB_SUFFIX) \
 	$(NULL)
@@ -267,10 +271,13 @@ LOCAL_INCLUDES	+= -I$(srcdir)/../base \
 		   -I$(topsrcdir)/netwerk/base/src \
 		   -I$(topsrcdir)/content/svg/content/src \
 		   $(NULL)
 
 ifdef MOZ_B2G_RIL #{
 LOCAL_INCLUDES	+= -I$(topsrcdir)/dom/system/b2g
 endif #}
 
+ifdef MOZ_B2G_BT #{
+LOCAL_INCLUDES	+= -I$(topsrcdir)/dom/bluetooth
+endif #}
 
 DEFINES += -D_IMPL_NS_LAYOUT
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1545,32 +1545,43 @@ nsBlockFrame::MarkLineDirty(line_iterato
              static_cast<void*>(aLine.prev().get()));
     }
 #endif
   }
 
   return NS_OK;
 }
 
+/**
+ * Test whether lines are certain to be aligned left so that we can make
+ * resizing optimizations
+ */
+bool static inline IsAlignedLeft(const PRUint8 aAlignment,
+                                 const PRUint8 aDirection,
+                                 const PRUint8 aUnicodeBidi)
+{
+  return (NS_STYLE_TEXT_ALIGN_LEFT == aAlignment ||
+          ((NS_STYLE_TEXT_ALIGN_DEFAULT == aAlignment &&
+            NS_STYLE_DIRECTION_LTR == aDirection) ||
+           (NS_STYLE_TEXT_ALIGN_END == aAlignment &&
+            NS_STYLE_DIRECTION_RTL == aDirection)) &&
+          !(NS_STYLE_UNICODE_BIDI_PLAINTEXT & aUnicodeBidi));
+}
+
 nsresult
 nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
 {
   const nsStyleText* styleText = GetStyleText();
+  const nsStyleTextReset* styleTextReset = GetStyleTextReset();
   // See if we can try and avoid marking all the lines as dirty
   bool tryAndSkipLines =
       // The text must be left-aligned.
-      (NS_STYLE_TEXT_ALIGN_LEFT == styleText->mTextAlign ||
-       (NS_STYLE_TEXT_ALIGN_DEFAULT == styleText->mTextAlign &&
-        NS_STYLE_DIRECTION_LTR ==
-          aState.mReflowState.mStyleVisibility->mDirection &&
-        !(NS_STYLE_UNICODE_BIDI_PLAINTEXT &
-          GetStyleTextReset()->mUnicodeBidi)) ||
-       (NS_STYLE_TEXT_ALIGN_END == styleText->mTextAlign &&
-        NS_STYLE_DIRECTION_RTL ==
-          aState.mReflowState.mStyleVisibility->mDirection)) &&
+    IsAlignedLeft(styleText->mTextAlign, 
+                  aState.mReflowState.mStyleVisibility->mDirection,
+                  styleTextReset->mUnicodeBidi) &&
       // The left content-edge must be a constant distance from the left
       // border-edge.
       !GetStylePadding()->mPadding.GetLeft().HasPercent();
 
 #ifdef DEBUG
   if (gDisableResizeOpt) {
     tryAndSkipLines = false;
   }
@@ -1595,48 +1606,56 @@ nsBlockFrame::PrepareResizeReflow(nsBloc
 #ifdef DEBUG
     if (gNoisyReflow) {
       IndentBy(stdout, gNoiseIndent);
       ListTag(stdout);
       printf(": trying to avoid marking all lines dirty\n");
     }
 #endif
 
+    // The last line might not be aligned left even if the rest of the block is
+    bool skipLastLine = NS_STYLE_TEXT_ALIGN_AUTO == styleText->mTextAlignLast ||
+      IsAlignedLeft(styleText->mTextAlignLast,
+                    aState.mReflowState.mStyleVisibility->mDirection,
+                    styleTextReset->mUnicodeBidi);
+
     for (line_iterator line = begin_lines(), line_end = end_lines();
          line != line_end;
          ++line)
     {
       // We let child blocks make their own decisions the same
       // way we are here.
+      bool isLastLine = line == mLines.back() && !GetNextInFlow();
       if (line->IsBlock() ||
           line->HasFloats() ||
-          ((line != mLines.back() || GetNextInFlow()) // not the last line
-           && !line->HasBreakAfter()) ||
+          (!isLastLine && !line->HasBreakAfter()) ||
+          ((isLastLine || !line->IsLineWrapped()) && !skipLastLine) ||
           line->ResizeReflowOptimizationDisabled() ||
           line->IsImpactedByFloat() ||
           (line->mBounds.XMost() > newAvailWidth)) {
         line->MarkDirty();
       }
 
 #ifdef REALLY_NOISY_REFLOW
       if (!line->IsBlock()) {
         printf("PrepareResizeReflow thinks line %p is %simpacted by floats\n", 
                line.get(), line->IsImpactedByFloat() ? "" : "not ");
       }
 #endif
 #ifdef DEBUG
       if (gNoisyReflow && !line->IsDirty()) {
         IndentBy(stdout, gNoiseIndent + 1);
-        printf("skipped: line=%p next=%p %s %s%s%s breakTypeBefore/After=%d/%d xmost=%d\n",
+        printf("skipped: line=%p next=%p %s %s%s%s%s breakTypeBefore/After=%d/%d xmost=%d\n",
            static_cast<void*>(line.get()),
            static_cast<void*>((line.next() != end_lines() ? line.next().get() : nsnull)),
            line->IsBlock() ? "block" : "inline",
            line->HasBreakAfter() ? "has-break-after " : "",
            line->HasFloats() ? "has-floats " : "",
            line->IsImpactedByFloat() ? "impacted " : "",
+           skipLastLine ? "last-line-left-aligned " : "",
            line->GetBreakTypeBefore(), line->GetBreakTypeAfter(),
            line->mBounds.XMost());
       }
 #endif
     }
   }
   else {
     // Mark everything dirty
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-1-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: right 25% bottom 75% reference</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  margin-left: 72px; /** 128px - 128px * 0.25 - 32px * 0.75 **/
+  margin-top: 24px; /** 128px - 128px * 0.75 - 32px * 0.25 **/
+  width: 32px;
+  height: 32px;
+  background-image: url(aqua-32x32.png);
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+<div id="outer"><div id="inner1"></div></div>
+<div id="outer"><div id="inner1"></div></div>
+<div id="outer"><div id="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-1a.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: right 25% bottom 75%</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  width: 128px;
+  height: 128px;
+  background-position: right 25% bottom 75%;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+#inner2
+{
+  width: 128px;
+  height: 128px;
+  background-position: bottom 75% right 25%;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+#inner3
+{
+  width: 128px;
+  height: 128px;
+  background-position: right 24px bottom 72px;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+#inner4
+{
+  width: 128px;
+  height: 128px;
+  background-position: bottom 72px right 24px;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+<div id="outer"><div id="inner2"></div></div>
+<div id="outer"><div id="inner3"></div></div>
+<div id="outer"><div id="inner4"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-1b.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: left 75% top 25%</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  width: 128px;
+  height: 128px;
+  background-position: left 75% top 25%;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+#inner2
+{
+  width: 128px;
+  height: 128px;
+  background-position: top 25% left 75%;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+#inner3
+{
+  width: 128px;
+  height: 128px;
+  background-position: left 72px top 24px;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+#inner4
+{
+  width: 128px;
+  height: 128px;
+  background-position: top 24px left 72px;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+<div id="outer"><div id="inner2"></div></div>
+<div id="outer"><div id="inner3"></div></div>
+<div id="outer"><div id="inner4"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-1c.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: left 75% bottom 75%</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  width: 128px;
+  height: 128px;
+  background-position: left 75% bottom 75%;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+#inner2
+{
+  width: 128px;
+  height: 128px;
+  background-position: right 25% top 25%;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+#inner3
+{
+  width: 128px;
+  height: 128px;
+  background-position: bottom 75% left 75%;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+#inner4
+{
+  width: 128px;
+  height: 128px;
+  background-position: right 25% top 25%;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+<div id="outer"><div id="inner2"></div></div>
+<div id="outer"><div id="inner3"></div></div>
+<div id="outer"><div id="inner4"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-2-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: left 25% bottom 75% reference</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  margin-left: 24px; /** 128px * 0.25 - 32 * 0.25 **/
+  margin-top: 24px; /** 128px - 128px * 0.75 + 32px * 0.75 - 32px **/
+  width: 32px;
+  height: 32px;
+  background-image: url(aqua-32x32.png);
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-2a.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: center bottom 75%</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  width: 128px;
+  height: 128px;
+  background-position: left 25% bottom 75%;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-2b.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: 25% 25%</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  width: 128px;
+  height: 128px;
+  background-position: 25% 25%;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-3-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: center bottom 75% reference</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  margin-left: 48px; /** 128px - 128px * 0.50 - 32px * 0.50 **/
+  margin-top: 24px; /** 128px - 128px * 0.75 + 32px * 0.75 - 32px **/
+  width: 32px;
+  height: 32px;
+  background-image: url(aqua-32x32.png);
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-3a.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: center bottom 75%</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  width: 128px;
+  height: 128px;
+  background-position: center bottom 75%;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-3b.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: center 25%</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  width: 128px;
+  height: 128px;
+  background-position: center 25%;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-4-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: left center reference</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  margin-left: 0px;
+  margin-top: 48px; /** 128px - 128px * 0.50 + 32px * 0.50 - 32px **/
+  width: 32px;
+  height: 32px;
+  background-image: url(aqua-32x32.png);
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-4a.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: left center</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  width: 128px;
+  height: 128px;
+  background-position: left center;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-4b.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: left</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  width: 128px;
+  height: 128px;
+  background-position: left;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-4c.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: left bottom 50%</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  width: 128px;
+  height: 128px;
+  background-position: left bottom 50%;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-5-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background: url(aqua-32x32.png) left no-repeat reference</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  margin-left: 0px;
+  margin-top: 48px; /** 128px - 128px * 0.50 + 32px * 0.50 - 32px **/
+  width: 32px;
+  height: 32px;
+  background-image: url(aqua-32x32.png);
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-5.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background: url(aqua-32x32.png) left no-repeat reference</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  width: 128px;
+  height: 128px;
+  background: url(aqua-32x32.png) left no-repeat;
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-6-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: top, bottom reference</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  margin-left: 48px; /** 128px - 128px * 0.50 + 32px * 0.50 - 32px **/
+  margin-top: 0px;
+  width: 32px;
+  height: 32px;
+  background-image: url(aqua-32x32.png);
+}
+#inner2
+{
+  margin-left: 48px; /** 128px - 32px - 32px **/
+  margin-top: 64px; /** 128px - 128px * 0.50 + 32px * 0.50 - 32px **/
+  width: 32px;
+  height: 32px;
+  background-image: url(aqua-32x32.png);
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div><div id="inner2"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-6.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: top, bottom</title>
+  <style type="text/css">
+#outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+#inner1
+{
+  width: 128px;
+  height: 128px;
+  background-position: top, bottom;
+  background-image: url(aqua-32x32.png), url(aqua-32x32.png);
+  background-repeat: no-repeat, no-repeat;
+}
+  </style>
+</head>
+<body>
+<div id="outer"><div id="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-7-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: left 25% bottom reference</title>
+  <style type="text/css">
+.outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+.inner1
+{
+  margin-left: 24px;
+  margin-top: 96px;
+  width: 32px;
+  height: 32px;
+  background-image: url(aqua-32x32.png);
+}
+  </style>
+</head>
+<body>
+<div class="outer"><div class="inner1"></div></div>
+<div class="outer"><div class="inner1"></div></div>
+<div class="outer"><div class="inner1"></div></div>
+<div class="outer"><div class="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-7.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: left 25% bottom</title>
+  <style type="text/css">
+.outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+.outer > div
+{
+  width: 128px;
+  height: 128px;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+#inner1
+{
+  background-position: left 24px bottom;
+}
+#inner2
+{
+  background-position: left 25% bottom;
+}
+#inner3
+{
+  background-position: right 75% bottom;
+}
+#inner4
+{
+  background-position: right 72px bottom;
+}
+  </style>
+</head>
+<body>
+<div class="outer"><div id="inner1"></div></div>
+<div class="outer"><div id="inner2"></div></div>
+<div class="outer"><div id="inner3"></div></div>
+<div class="outer"><div id="inner4"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-8-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: left 25% bottom reference</title>
+  <style type="text/css">
+.outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+.inner1
+{
+  margin-left: 96px;
+  margin-top: 24px;
+  width: 32px;
+  height: 32px;
+  background-image: url(aqua-32x32.png);
+}
+  </style>
+</head>
+<body>
+<div class="outer"><div class="inner1"></div></div>
+<div class="outer"><div class="inner1"></div></div>
+<div class="outer"><div class="inner1"></div></div>
+<div class="outer"><div class="inner1"></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-position-8.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>background-position: left 25% bottom</title>
+  <style type="text/css">
+.outer
+{
+  border: 1px solid black;
+  width: 128px;
+  height: 128px;
+}
+.outer > div
+{
+  width: 128px;
+  height: 128px;
+  background-image: url(aqua-32x32.png);
+  background-repeat: no-repeat;
+}
+#inner1
+{
+  background-position: right top 25%;
+}
+#inner2
+{
+  background-position: right top 24px;
+}
+#inner3
+{
+  background-position: right bottom 75%;
+}
+#inner4
+{
+  background-position: right bottom 72px;
+}
+  </style>
+</head>
+<body>
+<div class="outer"><div id="inner1"></div></div>
+<div class="outer"><div id="inner2"></div></div>
+<div class="outer"><div id="inner3"></div></div>
+<div class="outer"><div id="inner4"></div></div>
+</body>
+</html>
--- a/layout/reftests/backgrounds/reftest.list
+++ b/layout/reftests/backgrounds/reftest.list
@@ -27,16 +27,31 @@ fails-if(Android) == viewport-translucen
 == continuous-inline-4b.html continuous-inline-4-ref.html
 == continuous-inline-5a.html continuous-inline-5-ref.html
 == continuous-inline-5b.html continuous-inline-5-ref.html
 == background-redraw-237766.html background-redraw-237766-ref.html
 
 == background-clip-1.html background-clip-1-ref.html
 == background-clip-2.html background-clip-2-ref.html
 
+== background-position-1a.html background-position-1-ref.html
+== background-position-1b.html background-position-1-ref.html
+== background-position-1c.html background-position-1-ref.html
+== background-position-2a.html background-position-2-ref.html
+== background-position-2b.html background-position-2-ref.html
+== background-position-3a.html background-position-3-ref.html
+== background-position-3b.html background-position-3-ref.html
+== background-position-4a.html background-position-4-ref.html
+== background-position-4b.html background-position-4-ref.html
+== background-position-4c.html background-position-4-ref.html
+== background-position-5.html background-position-5-ref.html
+== background-position-6.html background-position-6-ref.html
+== background-position-7.html background-position-7-ref.html
+== background-position-8.html background-position-8-ref.html
+
 == background-size-auto-auto.html background-size-auto-ref.html
 == background-size-auto.html background-size-auto-ref.html
 == background-size-contain.html background-size-contain-ref.html
 == background-size-cover.html background-size-cover-ref.html
 == background-size-auto-length.html background-size-auto-length-ref.html
 == background-size-length-auto.html background-size-auto-length-ref.html
 == background-size-length.html background-size-auto-length-ref.html
 == background-size-auto-percent.html background-size-auto-length-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/conditions-07.svg
@@ -0,0 +1,40 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg id="svg-root" width="100%" height="100%"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink" onload="runtest()">
+  <title>Test conditional processing DOM interface for foreignObject</title>
+  <defs>
+    <script>
+      function runtest() {
+        try {
+          var f1 = document.getElementById("f1");
+          var i0 = f1.requiredFeatures.getItem(0);
+
+          if(i0 != "this.is.a.bogus.feature.string") {
+            return;
+          }
+          f1.removeAttribute("requiredFeatures");
+          
+        } catch(e) {
+          var f = document.getElementById("fail");
+          f.setAttribute("fill", "red");
+        }
+      }
+    </script>
+  </defs>
+
+  <rect width="100%" height="100%" fill="lime"/>
+  <!-- background images -->
+  <rect x="100" y="100" width="100" height="100" fill="red"/>
+
+  <!-- tests -->
+  <foreignObject id="f1" x="100" y="100" width="100" height="100" requiredFeatures="this.is.a.bogus.feature.string">
+    <svg>
+      <rect width="100%" height="100%" fill="lime"/>
+    </svg>
+  </foreignObject>
+  <rect id="fail" width="100%" height="100%" fill="none"/>
+</svg>
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -37,16 +37,17 @@ include svg-integration/reftest.list
 == clipPath-winding-01.svg pass.svg
 == clip-surface-clone-01.svg clip-surface-clone-01-ref.svg
 == conditions-01.svg pass.svg
 == conditions-02.svg pass.svg
 == conditions-03.svg pass.svg
 == conditions-04.svg pass.svg
 == conditions-05.svg about:blank
 == conditions-06.svg pass.svg
+== conditions-07.svg pass.svg
 == currentColor-01.svg pass.svg
 == currentColor-02.svg pass.svg
 == currentColor-03.svg pass.svg
 == data-uri-with-filter-01.xhtml data-uri-with-filter-01-ref.svg
 == data-uri-with-gradient-01.xhtml data-uri-with-gradient-01-ref.svg
 == data-uri-with-pattern-01.xhtml pass.svg
 == dynamic-attr-removal-1.svg pass.svg
 == dynamic-attr-removal-2.svg pass.svg
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/726392-1-ref.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <meta charset="utf-8">
+  <title>Bug 726392</title>
+  <style type="text/css">
+   p { margin: 0; letter-spacing: 10px}
+   .alignLeft { text-align: left; }
+   .alignRight { text-align: right; }
+   .alignCenter { text-align: center; }
+   .alignJustify { text-align: justify; }
+   .alignStart { text-align: start; }
+   .alignEnd { text-align: end; }
+   .alignLastAuto { -moz-text-align-last: auto; }
+   .alignLastLeft { -moz-text-align-last: left; }
+   .alignLastRight { -moz-text-align-last: right; }
+   .alignLastCenter { -moz-text-align-last: center; }
+   .alignLastJustify { -moz-text-align-last: justify; }
+   .alignLastStart { -moz-text-align-last: start; }
+   .alignLastEnd { -moz-text-align-last: end; }
+  </style>
+</head>
+ <body>
+  <p class="alignLeft alignLastAuto">test</p>
+  <p class="alignLeft alignLastLeft">test</p>
+  <p class="alignLeft alignLastRight">test</p>
+  <p class="alignLeft alignLastCenter">test</p>
+  <p class="alignLeft alignLastJustify">test</p>
+  <p class="alignLeft alignLastStart">test</p>
+  <p class="alignLeft alignLastEnd">test</p>
+  <p class="alignJustify alignLastAuto">test</p>
+  <p class="alignJustify alignLastLeft">test</p>
+  <p class="alignJustify alignLastRight">test</p>
+  <p class="alignJustify alignLastCenter">test</p>
+  <p class="alignJustify alignLastJustify">test</p>
+  <p class="alignJustify alignLastStart">test</p>
+  <p class="alignJustify alignLastEnd">test</p>
+  <p class="alignStart alignLastAuto">test</p>
+  <p class="alignStart alignLastLeft">test</p>
+  <p class="alignStart alignLastRight">test</p>
+  <p class="alignStart alignLastCenter">test</p>
+  <p class="alignStart alignLastJustify">test</p>
+  <p class="alignStart alignLastStart">test</p>
+  <p class="alignStart alignLastEnd">test</p>
+  <p class="alignEnd alignLastAuto">test</p>
+  <p class="alignEnd alignLastLeft">test</p>
+  <p class="alignEnd alignLastRight">test</p>
+  <p class="alignEnd alignLastCenter">test</p>
+  <p class="alignEnd alignLastJustify">test</p>
+  <p class="alignEnd alignLastStart">test</p>
+  <p class="alignEnd alignLastEnd">test</p>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/726392-1.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+  <meta charset="utf-8">
+  <title>Bug 726392</title>
+  <style type="text/css">
+   p { margin: 0; letter-spacing: 10px}
+   .alignLeft { text-align: left; }
+   .alignRight { text-align: right; }
+   .alignCenter { text-align: center; }
+   .alignJustify { text-align: justify; }
+   .alignStart { text-align: start; }
+   .alignEnd { text-align: end; }
+   .alignLastAuto { -moz-text-align-last: auto; }
+   .alignLastLeft { -moz-text-align-last: left; }
+   .alignLastRight { -moz-text-align-last: right; }
+   .alignLastCenter { -moz-text-align-last: center; }
+   .alignLastJustify { -moz-text-align-last: justify; }
+   .alignLastStart { -moz-text-align-last: start; }
+   .alignLastEnd { -moz-text-align-last: end; }
+  </style>
+</head>
+ <body>
+ <div id="e" style="width:50%">
+  <p class="alignLeft alignLastAuto">test</p>
+  <p class="alignLeft alignLastLeft">test</p>
+  <p class="alignLeft alignLastRight">test</p>
+  <p class="alignLeft alignLastCenter">test</p>
+  <p class="alignLeft alignLastJustify">test</p>
+  <p class="alignLeft alignLastStart">test</p>
+  <p class="alignLeft alignLastEnd">test</p>
+  <p class="alignJustify alignLastAuto">test</p>
+  <p class="alignJustify alignLastLeft">test</p>
+  <p class="alignJustify alignLastRight">test</p>
+  <p class="alignJustify alignLastCenter">test</p>
+  <p class="alignJustify alignLastJustify">test</p>
+  <p class="alignJustify alignLastStart">test</p>
+  <p class="alignJustify alignLastEnd">test</p>
+  <p class="alignStart alignLastAuto">test</p>
+  <p class="alignStart alignLastLeft">test</p>
+  <p class="alignStart alignLastRight">test</p>
+  <p class="alignStart alignLastCenter">test</p>
+  <p class="alignStart alignLastJustify">test</p>
+  <p class="alignStart alignLastStart">test</p>
+  <p class="alignStart alignLastEnd">test</p>
+  <p class="alignEnd alignLastAuto">test</p>
+  <p class="alignEnd alignLastLeft">test</p>
+  <p class="alignEnd alignLastRight">test</p>
+  <p class="alignEnd alignLastCenter">test</p>
+  <p class="alignEnd alignLastJustify">test</p>
+  <p class="alignEnd alignLastStart">test</p>
+  <p class="alignEnd alignLastEnd">test</p>
+
+<script type="text/javascript">
+function resizeElements()
+{
+  var enclosingDiv = document.getElementById("e");
+  enclosingDiv.style.width = "100%";
+  document.documentElement.removeAttribute("class");
+}
+
+document.addEventListener("MozReftestInvalidate", resizeElements, false);
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/726392-2-ref.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <meta charset="utf-8">
+  <title>Bug 726392</title>
+  <style type="text/css">
+   p { margin: 0; }
+   .alignLeft { text-align: left; }
+   .alignRight { text-align: right; }
+   .alignCenter { text-align: center; }
+   .alignJustify { text-align: justify; }
+   .alignStart { text-align: start; }
+   .alignEnd { text-align: end; }
+   .alignLastAuto { -moz-text-align-last: auto; }
+   .alignLastLeft { -moz-text-align-last: left; }
+   .alignLastRight { -moz-text-align-last: right; }
+   .alignLastCenter { -moz-text-align-last: center; }
+   .alignLastJustify { -moz-text-align-last: justify; }
+   .alignLastStart { -moz-text-align-last: start; }
+   .alignLastEnd { -moz-text-align-last: end; }
+  </style>
+</head>
+ <body dir="rtl">
+  <p dir="rtl" class="alignLeft alignLastAuto">בדיקה</p>
+  <p dir="rtl" class="alignLeft alignLastLeft">בדיקה</p>
+  <p dir="rtl" class="alignLeft alignLastRight">בדיקה</p>
+  <p dir="rtl" class="alignLeft alignLastCenter">בדיקה</p>
+  <p dir="rtl" class="alignLeft alignLastJustify">בדיקה</p>
+  <p dir="rtl" class="alignLeft alignLastStart">בדיקה</p>
+  <p dir="rtl" class="alignLeft alignLastEnd">בדיקה</p>
+  <p dir="rtl" class="alignJustify alignLastAuto">בדיקה</p>
+  <p dir="rtl" class="alignJustify alignLastLeft">בדיקה</p>
+  <p dir="rtl" class="alignJustify alignLastRight">בדיקה</p>
+  <p dir="rtl" class="alignJustify alignLastCenter">בדיקה</p>
+  <p dir="rtl" class="alignJustify alignLastJustify">בדיקה</p>
+  <p dir="rtl" class="alignJustify alignLastStart">בדיקה</p>
+  <p dir="rtl" class="alignJustify alignLastEnd">בדיקה</p>
+  <p dir="rtl" class="alignStart alignLastAuto">בדיקה</p>
+  <p dir="rtl" class="alignStart alignLastLeft">בדיקה</p>
+  <p dir="rtl" class="alignStart alignLastRight">בדיקה</p>
+  <p dir="rtl" class="alignStart alignLastCenter">בדיקה</p>
+  <p dir="rtl" class="alignStart alignLastJustify">בדיקה</p>
+  <p dir="rtl" class="alignStart alignLastStart">בדיקה</p>
+  <p dir="rtl" class="alignStart alignLastEnd">בדיקה</p>
+  <p dir="rtl" class="alignEnd alignLastAuto">בדיקה</p>
+  <p dir="rtl" class="alignEnd alignLastLeft">בדיקה</p>
+  <p dir="rtl" class="alignEnd alignLastRight">בדיקה</p>
+  <p dir="rtl" class="alignEnd alignLastCenter">בדיקה</p>
+  <p dir="rtl" class="alignEnd alignLastJustify">בדיקה</p>
+  <p dir="rtl" class="alignEnd alignLastStart">בדיקה</p>
+  <p dir="rtl" class="alignEnd alignLastEnd">בדיקה</p>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/726392-2.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+  <meta charset="utf-8">
+  <title>Bug 726392</title>
+  <style type="text/css">
+   p { margin: 0; }
+   .alignLeft { text-align: left; }
+   .alignRight { text-align: right; }
+   .alignCenter { text-align: center; }
+   .alignJustify { text-align: justify; }
+   .alignStart { text-align: start; }
+   .alignEnd { text-align: end; }
+   .alignLastAuto { -moz-text-align-last: auto; }
+   .alignLastLeft { -moz-text-align-last: left; }
+   .alignLastRight { -moz-text-align-last: right; }
+   .alignLastCenter { -moz-text-align-last: center; }
+   .alignLastJustify { -moz-text-align-last: justify; }
+   .alignLastStart { -moz-text-align-last: start; }
+   .alignLastEnd { -moz-text-align-last: end; }
+  </style>
+</head>
+ <body>
+ <div id="e" style="width:50%">
+  <p dir="rtl" class="alignLeft alignLastAuto">בדיקה</p>
+  <p dir="rtl" class="alignLeft alignLastLeft">בדיקה</p>
+  <p dir="rtl" class="alignLeft alignLastRight">בדיקה</p>
+  <p dir="rtl" class="alignLeft alignLastCenter">בדיקה</p>
+  <p dir="rtl" class="alignLeft alignLastJustify">בדיקה</p>
+  <p dir="rtl" class="alignLeft alignLastStart">בדיקה</p>
+  <p dir="rtl" class="alignLeft alignLastEnd">בדיקה</p>
+  <p dir="rtl" class="alignJustify alignLastAuto">בדיקה</p>
+  <p dir="rtl" class="alignJustify alignLastLeft">בדיקה</p>
+  <p dir="rtl" class="alignJustify alignLastRight">בדיקה</p>
+  <p dir="rtl" class="alignJustify alignLastCenter">בדיקה</p>
+  <p dir="rtl" class="alignJustify alignLastJustify">בדיקה</p>
+  <p dir="rtl" class="alignJustify alignLastStart">בדיקה</p>
+  <p dir="rtl" class="alignJustify alignLastEnd">בדיקה</p>
+  <p dir="rtl" class="alignStart alignLastAuto">בדיקה</p>
+  <p dir="rtl" class="alignStart alignLastLeft">בדיקה</p>
+  <p dir="rtl" class="alignStart alignLastRight">בדיקה</p>
+  <p dir="rtl" class="alignStart alignLastCenter">בדיקה</p>
+  <p dir="rtl" class="alignStart alignLastJustify">בדיקה</p>
+  <p dir="rtl" class="alignStart alignLastStart">בדיקה</p>
+  <p dir="rtl" class="alignStart alignLastEnd">בדיקה</p>
+  <p dir="rtl" class="alignEnd alignLastAuto">בדיקה</p>
+  <p dir="rtl" class="alignEnd alignLastLeft">בדיקה</p>
+  <p dir="rtl" class="alignEnd alignLastRight">בדיקה</p>
+  <p dir="rtl" class="alignEnd alignLastCenter">בדיקה</p>
+  <p dir="rtl" class="alignEnd alignLastJustify">בדיקה</p>
+  <p dir="rtl" class="alignEnd alignLastStart">בדיקה</p>
+  <p dir="rtl" class="alignEnd alignLastEnd">בדיקה</p>
+ </div>
+<script type="text/javascript">
+function resizeElements()
+{
+  var enclosingDiv = document.getElementById("e");
+  enclosingDiv.style.width = "100%";
+  document.documentElement.removeAttribute("class");
+}
+
+document.addEventListener("MozReftestInvalidate", resizeElements, false);
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/726392-3-ref.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <meta charset="utf-8">
+  <title>Bug 726392</title>
+  <style type="text/css">
+   p { margin: 0; white-space: pre-line; letter-spacing: 10px}
+   .alignLeft { text-align: left; }
+   .alignRight { text-align: right; }
+   .alignCenter { text-align: center; }
+   .alignJustify { text-align: justify; }
+   .alignStart { text-align: start; }
+   .alignEnd { text-align: end; }
+   .alignLastAuto { -moz-text-align-last: auto; }
+   .alignLastLeft { -moz-text-align-last: left; }
+   .alignLastRight { -moz-text-align-last: right; }
+   .alignLastCenter { -moz-text-align-last: center; }
+   .alignLastJustify { -moz-text-align-last: justify; }
+   .alignLastStart { -moz-text-align-last: start; }
+   .alignLastEnd { -moz-text-align-last: end; }
+  </style>
+</head>
+ <body>
+  <div>
+  <p class="alignLeft alignLastAuto">test
+test</p>
+  <p class="alignLeft alignLastLeft">test
+test</p>
+  <p class="alignLeft alignLastRight">test
+test</p>
+  <p class="alignLeft alignLastCenter">test
+test</p>
+  <p class="alignLeft alignLastJustify">test
+test</p>
+  <p class="alignLeft alignLastStart">test
+test</p>
+  <p class="alignLeft alignLastEnd">test
+test</p>
+  <p class="alignJustify alignLastAuto">test
+test</p>
+  <p class="alignJustify alignLastLeft">test
+test</p>
+  <p class="alignJustify alignLastRight">test
+test</p>
+  <p class="alignJustify alignLastCenter">test
+test</p>
+  <p class="alignJustify alignLastJustify">test
+test</p>
+  <p class="alignJustify alignLastStart">test
+test</p>
+  <p class="alignJustify alignLastEnd">test
+test</p>
+  <p class="alignStart alignLastAuto">test
+test</p>
+  <p class="alignStart alignLastLeft">test
+test</p>
+  <p class="alignStart alignLastRight">test
+test</p>
+  <p class="alignStart alignLastCenter">test
+test</p>
+  <p class="alignStart alignLastJustify">test
+test</p>
+  <p class="alignStart alignLastStart">test
+test</p>
+  <p class="alignStart alignLastEnd">test
+test</p>
+  <p class="alignEnd alignLastAuto">test
+test</p>
+  <p class="alignEnd alignLastLeft">test
+test</p>
+  <p class="alignEnd alignLastRight">test
+test</p>
+  <p class="alignEnd alignLastCenter">test
+test</p>
+  <p class="alignEnd alignLastJustify">test
+test</p>
+  <p class="alignEnd alignLastStart">test
+test</p>
+  <p class="alignEnd alignLastEnd">test
+test</p>
+  </div>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/726392-3.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+  <meta charset="utf-8">
+  <title>Bug 726392</title>
+  <style type="text/css">
+   p { margin: 0; white-space: pre-line; letter-spacing: 10px}
+   .alignLeft { text-align: left; }
+   .alignRight { text-align: right; }
+   .alignCenter { text-align: center; }
+   .alignJustify { text-align: justify; }
+   .alignStart { text-align: start; }
+   .alignEnd { text-align: end; }
+   .alignLastAuto { -moz-text-align-last: auto; }
+   .alignLastLeft { -moz-text-align-last: left; }
+   .alignLastRight { -moz-text-align-last: right; }
+   .alignLastCenter { -moz-text-align-last: center; }
+   .alignLastJustify { -moz-text-align-last: justify; }
+   .alignLastStart { -moz-text-align-last: start; }
+   .alignLastEnd { -moz-text-align-last: end; }
+  </style>
+</head>
+ <body>
+ <div id="e" style="width:50%">
+  <p class="alignLeft alignLastAuto">test
+test</p>
+  <p class="alignLeft alignLastLeft">test
+test</p>
+  <p class="alignLeft alignLastRight">test
+test</p>
+  <p class="alignLeft alignLastCenter">test
+test</p>
+  <p class="alignLeft alignLastJustify">test
+test</p>
+  <p class="alignLeft alignLastStart">test
+test</p>
+  <p class="alignLeft alignLastEnd">test
+test</p>
+  <p class="alignJustify alignLastAuto">test
+test</p>
+  <p class="alignJustify alignLastLeft">test
+test</p>
+  <p class="alignJustify alignLastRight">test
+test</p>
+  <p class="alignJustify alignLastCenter">test
+test</p>
+  <p class="alignJustify alignLastJustify">test
+test</p>
+  <p class="alignJustify alignLastStart">test
+test</p>
+  <p class="alignJustify alignLastEnd">test
+test</p>
+  <p class="alignStart alignLastAuto">test
+test</p>
+  <p class="alignStart alignLastLeft">test
+test</p>
+  <p class="alignStart alignLastRight">test
+test</p>
+  <p class="alignStart alignLastCenter">test
+test</p>
+  <p class="alignStart alignLastJustify">test
+test</p>
+  <p class="alignStart alignLastStart">test
+test</p>
+  <p class="alignStart alignLastEnd">test
+test</p>
+  <p class="alignEnd alignLastAuto">test
+test</p>
+  <p class="alignEnd alignLastLeft">test
+test</p>
+  <p class="alignEnd alignLastRight">test
+test</p>
+  <p class="alignEnd alignLastCenter">test
+test</p>
+  <p class="alignEnd alignLastJustify">test
+test</p>
+  <p class="alignEnd alignLastStart">test
+test</p>
+  <p class="alignEnd alignLastEnd">test
+test</p>
+ </div>
+<script type="text/javascript">
+function resizeElements()
+{
+  var enclosingDiv = document.getElementById("e");
+  enclosingDiv.style.width = "100%";
+  document.documentElement.removeAttribute("class");
+}
+
+document.addEventListener("MozReftestInvalidate", resizeElements, false);
+</script>
+
+</body>
+</html>
--- a/layout/reftests/text/reftest.list
+++ b/layout/reftests/text/reftest.list
@@ -131,16 +131,20 @@ fails-if(!winWidget) HTTP(..) == 475092-
 random-if(winWidget) HTTP(..) != kerning-01.html kerning-01-notref.html
 # Test for bug 577380, support for AAT layout (on OS X only)
 random-if(!cocoaWidget) == 577380.html 577380-ref.html
 # Test for OpenType Arabic shaping support
 HTTP(..) == arabic-shaping-1.html arabic-shaping-1-ref.html
 # check ligature in Arial Bold on Windows, for bug 644184; may fail on other platforms depending on fonts
 random-if(!winWidget) == arial-bold-lam-alef-1.html arial-bold-lam-alef-1-ref.html
 
+== 726392-1.html 726392-1-ref.html
+== 726392-2.html 726392-2-ref.html
+== 726392-3.html 726392-3-ref.html
+
 # tests to compare graphite to opentype (will trivially pass when graphite not enabled)
 HTTP(..) == graphite-05-ot-only.html graphite-05-ref.html
 HTTP(..) != graphite-05-ot-only.html graphite-05-fail.html
 HTTP(..) == graphite-05-simple.html graphite-05-ref.html
 HTTP(..) == graphite-05-multipass.html graphite-05-ref.html
 HTTP(..) == graphite-05-lang.html graphite-05-ref.html
 HTTP(..) == graphite-05-badlang.html graphite-05-ref.html
 HTTP(..) == graphite-05-feat.html graphite-05-ref.html
--- a/layout/style/Declaration.cpp
+++ b/layout/style/Declaration.cpp
@@ -406,19 +406,19 @@ Declaration::GetValue(nsCSSProperty aPro
         data->ValueFor(eCSSProperty_background_image)->
         GetListValue();
       const nsCSSValueList *repeat =
         data->ValueFor(eCSSProperty_background_repeat)->
         GetListValue();
       const nsCSSValueList *attachment =
         data->ValueFor(eCSSProperty_background_attachment)->
         GetListValue();
-      const nsCSSValuePairList *position =
+      const nsCSSValueList *position =
         data->ValueFor(eCSSProperty_background_position)->
-        GetPairListValue();
+        GetListValue();
       const nsCSSValueList *clip =
         data->ValueFor(eCSSProperty_background_clip)->
         GetListValue();
       const nsCSSValueList *origin =
         data->ValueFor(eCSSProperty_background_origin)->
         GetListValue();
       const nsCSSValuePairList *size =
         data->ValueFor(eCSSProperty_background_size)->
@@ -432,21 +432,19 @@ Declaration::GetValue(nsCSSProperty aPro
         }
         image->mValue.AppendToString(eCSSProperty_background_image, aValue);
         aValue.Append(PRUnichar(' '));
         repeat->mValue.AppendToString(eCSSProperty_background_repeat, aValue);
         aValue.Append(PRUnichar(' '));
         attachment->mValue.AppendToString(eCSSProperty_background_attachment,
                                           aValue);
         aValue.Append(PRUnichar(' '));
-        position->mXValue.AppendToString(eCSSProperty_background_position,
-                                         aValue);
-        aValue.Append(PRUnichar(' '));
-        position->mYValue.AppendToString(eCSSProperty_background_position,
-                                         aValue);
+        position->mValue.AppendToString(eCSSProperty_background_position,
+                                        aValue);
+        
         NS_ABORT_IF_FALSE(clip->mValue.GetUnit() == eCSSUnit_Enumerated &&
                           origin->mValue.GetUnit() == eCSSUnit_Enumerated,
                           "should not be inherit/initial within list and "
                           "should have returned early for real inherit/initial");
         if (clip->mValue.GetIntValue() != NS_STYLE_BG_CLIP_BORDER ||
             origin->mValue.GetIntValue() != NS_STYLE_BG_ORIGIN_PADDING) {
           PR_STATIC_ASSERT(NS_STYLE_BG_CLIP_BORDER ==
                            NS_STYLE_BG_ORIGIN_BORDER);
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -455,34 +455,40 @@ protected:
 
   struct BackgroundParseState {
     nsCSSValue&  mColor;
     nsCSSValueList* mImage;
     nsCSSValueList* mRepeat;
     nsCSSValueList* mAttachment;
     nsCSSValueList* mClip;
     nsCSSValueList* mOrigin;
-    nsCSSValuePairList* mPosition;
+    nsCSSValueList* mPosition;
     nsCSSValuePairList* mSize;
     BackgroundParseState(
         nsCSSValue& aColor, nsCSSValueList* aImage, nsCSSValueList* aRepeat,
         nsCSSValueList* aAttachment, nsCSSValueList* aClip,
-        nsCSSValueList* aOrigin, nsCSSValuePairList* aPosition,
+        nsCSSValueList* aOrigin, nsCSSValueList* aPosition,
         nsCSSValuePairList* aSize) :
         mColor(aColor), mImage(aImage), mRepeat(aRepeat),
         mAttachment(aAttachment), mClip(aClip), mOrigin(aOrigin),
         mPosition(aPosition), mSize(aSize) {};
   };
 
   bool ParseBackgroundItem(BackgroundParseState& aState);
 
   bool ParseValueList(nsCSSProperty aPropID); // a single value prop-id
   bool ParseBackgroundPosition();
+
+  // ParseBoxPositionValues parses the CSS 2.1 background-position syntax,
+  // which is still used by some properties. See ParseBackgroundPositionValues
+  // for the css3-background syntax.
   bool ParseBoxPositionValues(nsCSSValuePair& aOut, bool aAcceptsInherit,
-                              bool aAllowExplicitCenter = true);
+                              bool aAllowExplicitCenter = true); // deprecated
+  bool ParseBackgroundPositionValues(nsCSSValue& aOut, bool aAcceptsInherit);
+
   bool ParseBackgroundSize();
   bool ParseBackgroundSizeValues(nsCSSValuePair& aOut);
   bool ParseBorderColor();
   bool ParseBorderColors(nsCSSProperty aProperty);
   void SetBorderImageInitialValues();
   bool ParseBorderImageRepeat(bool aAcceptsInherit);
   // If ParseBorderImageSlice returns false, aConsumedTokens indicates
   // whether or not any tokens were consumed (in other words, was the property
@@ -4941,18 +4947,16 @@ CSSParserImpl::ParseColorStop(nsCSSValue
 //
 // <gradient-shape-size> : [<gradient-shape> || <gradient-size>] ,
 // <gradient-shape> : circle | ellipse
 // <gradient-size> : closest-side | closest-corner
 //                 | farthest-side | farthest-corner
 //                 | contain | cover
 //
 // <color-stops> : <color-stop> , <color-stop> [, <color-stop>]*
-
-
 bool
 CSSParserImpl::ParseGradient(nsCSSValue& aValue, bool aIsRadial,
                              bool aIsRepeating)
 {
   nsRefPtr<nsCSSValueGradient> cssGradient
     = new nsCSSValueGradient(aIsRadial, aIsRepeating);
 
   // <gradient-line>
@@ -5641,17 +5645,19 @@ CSSParserImpl::ParsePropertyByFunction(n
 
 // Bits used in determining which background position info we have
 #define BG_CENTER  NS_STYLE_BG_POSITION_CENTER
 #define BG_TOP     NS_STYLE_BG_POSITION_TOP
 #define BG_BOTTOM  NS_STYLE_BG_POSITION_BOTTOM
 #define BG_LEFT    NS_STYLE_BG_POSITION_LEFT
 #define BG_RIGHT   NS_STYLE_BG_POSITION_RIGHT
 #define BG_CTB    (BG_CENTER | BG_TOP | BG_BOTTOM)
+#define BG_TB     (BG_TOP | BG_BOTTOM)
 #define BG_CLR    (BG_CENTER | BG_LEFT | BG_RIGHT)
+#define BG_LR     (BG_LEFT | BG_RIGHT)
 
 bool
 CSSParserImpl::ParseSingleValueProperty(nsCSSValue& aValue,
                                         nsCSSProperty aPropID)
 {
   if (aPropID == eCSSPropertyExtra_x_none_value) {
     return ParseVariant(aValue, VARIANT_NONE | VARIANT_INHERIT, nsnull);
   }
@@ -5853,17 +5859,17 @@ CSSParserImpl::ParseBackground()
       AppendValue(*subprops, color);
     }
     return true;
   }
 
   nsCSSValue image, repeat, attachment, clip, origin, position, size;
   BackgroundParseState state(color, image.SetListValue(), repeat.SetListValue(),
                              attachment.SetListValue(), clip.SetListValue(),
-                             origin.SetListValue(), position.SetPairListValue(),
+                             origin.SetListValue(), position.SetListValue(),
                              size.SetPairListValue());
 
   for (;;) {
     if (!ParseBackgroundItem(state)) {
       return false;
     }
     if (CheckEndProperty()) {
       break;
@@ -5883,17 +5889,17 @@ CSSParserImpl::ParseBackground()
     state.mRepeat->mNext = new nsCSSValueList;
     state.mRepeat = state.mRepeat->mNext;
     state.mAttachment->mNext = new nsCSSValueList;
     state.mAttachment = state.mAttachment->mNext;
     state.mClip->mNext = new nsCSSValueList;
     state.mClip = state.mClip->mNext;
     state.mOrigin->mNext = new nsCSSValueList;
     state.mOrigin = state.mOrigin->mNext;
-    state.mPosition->mNext = new nsCSSValuePairList;
+    state.mPosition->mNext = new nsCSSValueList;
     state.mPosition = state.mPosition->mNext;
     state.mSize->mNext = new nsCSSValuePairList;
     state.mSize = state.mSize->mNext;
   }
 
   // If we get to this point without seeing a color, provide a default.
   if (color.GetUnit() == eCSSUnit_Null) {
     color.SetColorValue(NS_RGBA(0,0,0,0));
@@ -5921,18 +5927,20 @@ CSSParserImpl::ParseBackgroundItem(CSSPa
   aState.mRepeat->mValue.SetIntValue(NS_STYLE_BG_REPEAT_XY,
                                      eCSSUnit_Enumerated);
   aState.mAttachment->mValue.SetIntValue(NS_STYLE_BG_ATTACHMENT_SCROLL,
                                          eCSSUnit_Enumerated);
   aState.mClip->mValue.SetIntValue(NS_STYLE_BG_CLIP_BORDER,
                                    eCSSUnit_Enumerated);
   aState.mOrigin->mValue.SetIntValue(NS_STYLE_BG_ORIGIN_PADDING,
                                      eCSSUnit_Enumerated);
-  aState.mPosition->mXValue.SetPercentValue(0.0f);
-  aState.mPosition->mYValue.SetPercentValue(0.0f);
+  nsRefPtr<nsCSSValue::Array> positionArr = nsCSSValue::Array::Create(4);
+  aState.mPosition->mValue.SetArrayValue(positionArr, eCSSUnit_Array);
+  positionArr->Item(1).SetPercentValue(0.0f);
+  positionArr->Item(3).SetPercentValue(0.0f);
   aState.mSize->mXValue.SetAutoValue();
   aState.mSize->mYValue.SetAutoValue();
 
   bool haveColor = false,
          haveImage = false,
          haveRepeat = false,
          haveAttach = false,
          havePosition = false,
@@ -5983,22 +5991,19 @@ CSSParserImpl::ParseBackgroundItem(CSSPa
           NS_NOTREACHED("should be able to parse");
           return false;
         }
       } else if (nsCSSProps::FindKeyword(keyword,
                    nsCSSProps::kBackgroundPositionKTable, dummy)) {
         if (havePosition)
           return false;
         havePosition = true;
-        nsCSSValuePair scratch;
-        if (!ParseBoxPositionValues(scratch, false)) {
+        if (!ParseBackgroundPositionValues(aState.mPosition->mValue, false)) {
           return false;
         }
-        aState.mPosition->mXValue = scratch.mXValue;
-        aState.mPosition->mYValue = scratch.mYValue;
       } else if (nsCSSProps::FindKeyword(keyword,
                    nsCSSProps::kBackgroundOriginKTable, dummy)) {
         if (haveOrigin)
           return false;
         haveOrigin = true;
         if (!ParseSingleValueProperty(aState.mOrigin->mValue,
                                       eCSSProperty_background_origin)) {
           NS_NOTREACHED("should be able to parse");
@@ -6038,22 +6043,19 @@ CSSParserImpl::ParseBackgroundItem(CSSPa
     } else if (tt == eCSSToken_Dimension ||
                tt == eCSSToken_Number ||
                tt == eCSSToken_Percentage ||
                (tt == eCSSToken_Function &&
                 mToken.mIdent.LowerCaseEqualsLiteral("-moz-calc"))) {
       if (havePosition)
         return false;
       havePosition = true;
-      nsCSSValuePair scratch;
-      if (!ParseBoxPositionValues(scratch, false)) {
+      if (!ParseBackgroundPositionValues(aState.mPosition->mValue, false)) {
         return false;
       }
-      aState.mPosition->mXValue = scratch.mXValue;
-      aState.mPosition->mYValue = scratch.mYValue;
     } else {
       if (haveColor)
         return false;
       haveColor = true;
       // Note: This parses 'inherit' and 'initial', but
       // we've already checked for them, so it's ok.
       if (!ParseSingleValueProperty(aState.mColor,
                                     eCSSProperty_background_color)) {
@@ -6104,42 +6106,47 @@ CSSParserImpl::ParseBackgroundPosition()
 {
   nsCSSValue value;
   if (ParseVariant(value, VARIANT_INHERIT, nsnull)) {
     // 'initial' and 'inherit' stand alone, no list permitted.
     if (!ExpectEndProperty()) {
       return false;
     }
   } else {
-    nsCSSValuePair valuePair;
-    if (!ParseBoxPositionValues(valuePair, false)) {
+    nsCSSValue itemValue;
+    if (!ParseBackgroundPositionValues(itemValue, false)) {
       return false;
     }
-    nsCSSValuePairList* item = value.SetPairListValue();
+    nsCSSValueList* item = value.SetListValue();
     for (;;) {
-      item->mXValue = valuePair.mXValue;
-      item->mYValue = valuePair.mYValue;
+      item->mValue = itemValue;
       if (CheckEndProperty()) {
         break;
       }
       if (!ExpectSymbol(',', true)) {
         return false;
       }
-      if (!ParseBoxPositionValues(valuePair, false)) {
+      if (!ParseBackgroundPositionValues(itemValue, false)) {
         return false;
       }
-      item->mNext = new nsCSSValuePairList;
+      item->mNext = new nsCSSValueList;
       item = item->mNext;
     }
   }
   AppendValue(eCSSProperty_background_position, value);
   return true;
 }
 
 /**
+ * BoxPositionMaskToCSSValue and ParseBoxPositionValues are used
+ * for parsing the CSS 2.1 background-position syntax (which has at
+ * most two values).  (Compare to the css3-background syntax which
+ * takes up to four values.)  Some current CSS specifications that
+ * use background-position-like syntax still use this old syntax.
+ **
  * Parses two values that correspond to positions in a box.  These can be
  * values corresponding to percentages of the box, raw offsets, or keywords
  * like "top," "left center," etc.
  *
  * @param aOut The nsCSSValuePair in which to place the result.
  * @param aAcceptsInherit If true, 'inherit' and 'initial' are legal values
  * @param aAllowExplicitCenter If true, 'center' is a legal value
  * @return Whether or not the operation succeeded.
@@ -6223,16 +6230,198 @@ bool CSSParserImpl::ParseBoxPositionValu
   }
 
   // Create style values
   xValue = BoxPositionMaskToCSSValue(mask, true);
   yValue = BoxPositionMaskToCSSValue(mask, false);
   return true;
 }
 
+bool CSSParserImpl::ParseBackgroundPositionValues(nsCSSValue& aOut,
+                                                  bool aAcceptsInherit)
+{
+  // css3-background allows positions to be defined as offsets
+  // from an edge. There can be 2 keywords and 2 offsets given. These
+  // four 'values' are stored in an array in the following order:
+  // [keyword offset keyword offset]. If a keyword or offset isn't
+  // parsed the value of the corresponding array element is set
+  // to eCSSUnit_Null by a call to nsCSSValue::Reset().
+  if (aAcceptsInherit && ParseVariant(aOut, VARIANT_INHERIT, nsnull)) {
+    return true;
+  }
+
+  nsRefPtr<nsCSSValue::Array> value = nsCSSValue::Array::Create(4);
+  aOut.SetArrayValue(value, eCSSUnit_Array);
+
+  // The following clarifies organisation of the array.
+  nsCSSValue &xEdge   = value->Item(0),
+             &xOffset = value->Item(1),
+             &yEdge   = value->Item(2),
+             &yOffset = value->Item(3);
+
+  // Parse all the values into the array.
+  PRUint32 valueCount = 0;
+  for (PRInt32 i = 0; i < 4; i++) {
+    if (!ParseVariant(value->Item(i), VARIANT_LPCALC | VARIANT_KEYWORD,
+                      nsCSSProps::kBackgroundPositionKTable)) {
+      break;
+    }
+    ++valueCount;
+  }
+
+  switch (valueCount) {
+    case 4:
+      // "If three or four values are given, then each <percentage> or <length>
+      // represents an offset and must be preceded by a keyword, which specifies
+      // from which edge the offset is given."
+      if (eCSSUnit_Enumerated != xEdge.GetUnit() ||
+          BG_CENTER == xEdge.GetIntValue() ||
+          eCSSUnit_Enumerated == xOffset.GetUnit() ||
+          eCSSUnit_Enumerated != yEdge.GetUnit() ||
+          BG_CENTER == yEdge.GetIntValue() ||
+          eCSSUnit_Enumerated == yOffset.GetUnit()) {
+        return false;
+      }
+      break;
+    case 3:
+      // "If three or four values are given, then each <percentage> or<length>
+      // represents an offset and must be preceded by a keyword, which specifies
+      // from which edge the offset is given." ... "If three values are given,
+      // the missing offset is assumed to be zero."
+      if (eCSSUnit_Enumerated != value->Item(1).GetUnit()) {
+        // keyword offset keyword
+        // Second value is non-keyword, thus first value must be a non-center
+        // keyword.
+        if (eCSSUnit_Enumerated != value->Item(0).GetUnit() ||
+            BG_CENTER == value->Item(0).GetIntValue()) {
+          return false;
+        }
+
+        // Remaining value must be a keyword.
+        if (eCSSUnit_Enumerated != value->Item(2).GetUnit()) {
+          return false;
+        }
+
+        yOffset.Reset(); // Everything else is in the correct position.
+      } else if (eCSSUnit_Enumerated != value->Item(2).GetUnit()) {
+        // keyword keyword offset
+        // Third value is non-keyword, thus second value must be non-center
+        // keyword.
+        if (BG_CENTER == value->Item(1).GetIntValue()) {
+          return false;
+        }
+
+        // Remaining value must be a keyword.
+        if (eCSSUnit_Enumerated != value->Item(0).GetUnit()) {
+          return false;
+        }
+
+        // Move the values to the correct position in the array.
+        value->Item(3) = value->Item(2); // yOffset
+        value->Item(2) = value->Item(1); // yEdge
+        value->Item(1).Reset(); // xOffset
+      } else {
+        return false;
+      }
+      break;
+    case 2:
+      // "If two values are given and at least one value is not a keyword, then
+      // the first value represents the horizontal position (or offset) and the
+      // second represents the vertical position (or offset)"
+      if (eCSSUnit_Enumerated == value->Item(0).GetUnit()) {
+        if (eCSSUnit_Enumerated == value->Item(1).GetUnit()) {
+          // keyword keyword
+          value->Item(2) = value->Item(1); // move yEdge to correct position
+          xOffset.Reset();
+          yOffset.Reset();
+        } else {
+          // keyword offset
+          // First value must represent horizontal position.
+          if ((BG_TOP | BG_BOTTOM) & value->Item(0).GetIntValue()) {
+            return false;
+          }
+          value->Item(3) = value->Item(1); // move yOffset to correct position
+          xOffset.Reset();
+          yEdge.Reset();
+        }
+      } else {
+        if (eCSSUnit_Enumerated == value->Item(1).GetUnit()) {
+          // offset keyword
+          // Second value must represent vertical position.
+          if ((BG_LEFT | BG_RIGHT) & value->Item(1).GetIntValue()) {
+            return false;
+          }
+          value->Item(2) = value->Item(1); // move yEdge to correct position
+          value->Item(1) = value->Item(0); // move xOffset to correct position
+          xEdge.Reset();
+          yOffset.Reset();
+        } else {
+          // offset offset
+          value->Item(3) = value->Item(1); // move yOffset to correct position
+          value->Item(1) = value->Item(0); // move xOffset to correct position
+          xEdge.Reset();
+          yEdge.Reset();
+        }
+      }
+      break;
+    case 1:
+      // "If only one value is specified, the second value is assumed to be
+      // center."
+      if (eCSSUnit_Enumerated == value->Item(0).GetUnit()) {
+        xOffset.Reset();
+      } else {
+        value->Item(1) = value->Item(0); // move xOffset to correct position
+        xEdge.Reset();
+      }
+      yEdge.SetIntValue(NS_STYLE_BG_POSITION_CENTER, eCSSUnit_Enumerated);
+      yOffset.Reset();
+      break;
+    default:
+      return false;
+  }
+
+  // For compatibility with CSS2.1 code the edges can be unspecified.
+  // Unspecified edges are recorded as NULL.
+  NS_ASSERTION((eCSSUnit_Enumerated == xEdge.GetUnit()  ||
+                eCSSUnit_Null       == xEdge.GetUnit()) &&
+               (eCSSUnit_Enumerated == yEdge.GetUnit()  ||
+                eCSSUnit_Null       == yEdge.GetUnit()) &&
+                eCSSUnit_Enumerated != xOffset.GetUnit()  &&
+                eCSSUnit_Enumerated != yOffset.GetUnit(),
+                "Unexpected units");
+
+  // Keywords in first and second pairs can not both be vertical or
+  // horizontal keywords. (eg. left right, bottom top). Additionally,
+  // non-center keyword can not be duplicated (eg. left left).
+  PRInt32 xEdgeEnum =
+          xEdge.GetUnit() == eCSSUnit_Enumerated ? xEdge.GetIntValue() : 0;
+  PRInt32 yEdgeEnum =
+          yEdge.GetUnit() == eCSSUnit_Enumerated ? yEdge.GetIntValue() : 0;
+  if ((xEdgeEnum | yEdgeEnum) == (BG_LEFT | BG_RIGHT) ||
+      (xEdgeEnum | yEdgeEnum) == (BG_TOP | BG_BOTTOM) ||
+      (xEdgeEnum & yEdgeEnum & ~BG_CENTER)) {
+    return false;
+  }
+
+  // The values could be in an order that is different than expected.
+  // eg. x contains vertical information, y contains horizontal information.
+  // Swap if incorrect order.
+  if (xEdgeEnum & (BG_TOP | BG_BOTTOM) ||
+      yEdgeEnum & (BG_LEFT | BG_RIGHT)) {
+    nsCSSValue swapEdge = xEdge;
+    nsCSSValue swapOffset = xOffset;
+    xEdge = yEdge;
+    xOffset = yOffset;
+    yEdge = swapEdge;
+    yOffset = swapOffset;
+  }
+
+  return true;
+}
+
 // This function is very similar to ParseBackgroundList and
 // ParseBackgroundPosition.
 bool
 CSSParserImpl::ParseBackgroundSize()
 {
   nsCSSValue value;
   if (ParseVariant(value, VARIANT_INHERIT, nsnull)) {
     // 'initial' and 'inherit' stand alone, no list permitted.
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -2676,80 +2676,83 @@ nsRuleNode::SetFont(nsPresContext* aPres
     aFont->mLanguage = do_GetAtom(lang);
   }
 
   const nsFont* defaultVariableFont =
     aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
                                  aFont->mLanguage);
 
   // -moz-system-font: enum (never inherit!)
-  nsFont systemFont;
+  PR_STATIC_ASSERT(
+    NS_STYLE_FONT_CAPTION        == LookAndFeel::eFont_Caption &&
+    NS_STYLE_FONT_ICON           == LookAndFeel::eFont_Icon &&
+    NS_STYLE_FONT_MENU           == LookAndFeel::eFont_Menu &&
+    NS_STYLE_FONT_MESSAGE_BOX    == LookAndFeel::eFont_MessageBox &&
+    NS_STYLE_FONT_SMALL_CAPTION  == LookAndFeel::eFont_SmallCaption &&
+    NS_STYLE_FONT_STATUS_BAR     == LookAndFeel::eFont_StatusBar &&
+    NS_STYLE_FONT_WINDOW         == LookAndFeel::eFont_Window &&
+    NS_STYLE_FONT_DOCUMENT       == LookAndFeel::eFont_Document &&
+    NS_STYLE_FONT_WORKSPACE      == LookAndFeel::eFont_Workspace &&
+    NS_STYLE_FONT_DESKTOP        == LookAndFeel::eFont_Desktop &&
+    NS_STYLE_FONT_INFO           == LookAndFeel::eFont_Info &&
+    NS_STYLE_FONT_DIALOG         == LookAndFeel::eFont_Dialog &&
+    NS_STYLE_FONT_BUTTON         == LookAndFeel::eFont_Button &&
+    NS_STYLE_FONT_PULL_DOWN_MENU == LookAndFeel::eFont_PullDownMenu &&
+    NS_STYLE_FONT_LIST           == LookAndFeel::eFont_List &&
+    NS_STYLE_FONT_FIELD          == LookAndFeel::eFont_Field);
+
+  // Fall back to defaultVariableFont.
+  nsFont systemFont = *defaultVariableFont;
   const nsCSSValue* systemFontValue = aRuleData->ValueForSystemFont();
   if (eCSSUnit_Enumerated == systemFontValue->GetUnit()) {
-    nsSystemFontID sysID;
-    switch (systemFontValue->GetIntValue()) {
-      case NS_STYLE_FONT_CAPTION:       sysID = eSystemFont_Caption;      break;    // css2
-      case NS_STYLE_FONT_ICON:          sysID = eSystemFont_Icon;         break;
-      case NS_STYLE_FONT_MENU:          sysID = eSystemFont_Menu;         break;
-      case NS_STYLE_FONT_MESSAGE_BOX:   sysID = eSystemFont_MessageBox;   break;
-      case NS_STYLE_FONT_SMALL_CAPTION: sysID = eSystemFont_SmallCaption; break;
-      case NS_STYLE_FONT_STATUS_BAR:    sysID = eSystemFont_StatusBar;    break;
-      case NS_STYLE_FONT_WINDOW:        sysID = eSystemFont_Window;       break;    // css3
-      case NS_STYLE_FONT_DOCUMENT:      sysID = eSystemFont_Document;     break;
-      case NS_STYLE_FONT_WORKSPACE:     sysID = eSystemFont_Workspace;    break;
-      case NS_STYLE_FONT_DESKTOP:       sysID = eSystemFont_Desktop;      break;
-      case NS_STYLE_FONT_INFO:          sysID = eSystemFont_Info;         break;
-      case NS_STYLE_FONT_DIALOG:        sysID = eSystemFont_Dialog;       break;
-      case NS_STYLE_FONT_BUTTON:        sysID = eSystemFont_Button;       break;
-      case NS_STYLE_FONT_PULL_DOWN_MENU:sysID = eSystemFont_PullDownMenu; break;
-      case NS_STYLE_FONT_LIST:          sysID = eSystemFont_List;         break;
-      case NS_STYLE_FONT_FIELD:         sysID = eSystemFont_Field;        break;
-    }
-
-    // GetSystemFont sets the font face but not necessarily the size
-    // XXX Or at least it used to -- no longer true for thebes.  Maybe
-    // it should be again, though.
-    systemFont.size = defaultVariableFont->size;
-
-    if (NS_FAILED(aPresContext->DeviceContext()->GetSystemFont(sysID,
-                                                               &systemFont))) {
-        systemFont.name = defaultVariableFont->name;
-    }
-
-    // XXXldb All of this platform-specific stuff should be in the
-    // nsDeviceContext implementations, not here.
+    gfxFontStyle fontStyle;
+    LookAndFeel::FontID fontID =
+      (LookAndFeel::FontID)systemFontValue->GetIntValue();
+    if (LookAndFeel::GetFont(fontID, systemFont.name, fontStyle)) {
+      systemFont.style = fontStyle.style;
+      systemFont.systemFont = fontStyle.systemFont;
+      systemFont.variant = NS_FONT_VARIANT_NORMAL;
+      systemFont.weight = fontStyle.weight;
+      systemFont.stretch = fontStyle.stretch;
+      systemFont.decorations = NS_FONT_DECORATION_NONE;
+      systemFont.size = NSFloatPixelsToAppUnits(fontStyle.size,
+                                                aPresContext->DeviceContext()->
+                                                UnscaledAppUnitsPerDevPixel());
+      //systemFont.langGroup = fontStyle.langGroup;
+      systemFont.sizeAdjust = fontStyle.sizeAdjust;
 
 #ifdef XP_WIN
-    //
-    // As far as I can tell the system default fonts and sizes for
-    // on MS-Windows for Buttons, Listboxes/Comboxes and Text Fields are
-    // all pre-determined and cannot be changed by either the control panel
-    // or programmtically.
-    //
-    switch (sysID) {
-      // Fields (text fields)
-      // Button and Selects (listboxes/comboboxes)
-      //    We use whatever font is defined by the system. Which it appears
-      //    (and the assumption is) it is always a proportional font. Then we
-      //    always use 2 points smaller than what the browser has defined as
-      //    the default proportional font.
-      case eSystemFont_Field:
-      case eSystemFont_Button:
-      case eSystemFont_List:
+      // XXXldb This platform-specific stuff should be in the
+      // LookAndFeel implementation, not here.
+      // XXXzw Should we even still *have* this code?  It looks to be making
+      // old, probably obsolete assumptions.
+
+      // As far as I can tell the system default fonts and sizes
+      // on MS-Windows for Buttons, Listboxes/Comboxes and Text Fields are
+      // all pre-determined and cannot be changed by either the control panel
+      // or programmtically.
+      switch (fontID) {
+        // Fields (text fields)
+        // Button and Selects (listboxes/comboboxes)
+        //    We use whatever font is defined by the system. Which it appears
+        //    (and the assumption is) it is always a proportional font. Then we
+        //    always use 2 points smaller than what the browser has defined as
+        //    the default proportional font.
+      case LookAndFeel::eFont_Field:
+      case LookAndFeel::eFont_Button:
+      case LookAndFeel::eFont_List:
         // Assumption: system defined font is proportional
         systemFont.size =
-          NS_MAX(defaultVariableFont->size - nsPresContext::CSSPointsToAppUnits(2), 0);
+          NS_MAX(defaultVariableFont->size -
+                 nsPresContext::CSSPointsToAppUnits(2), 0);
         break;
-    }
+      }
 #endif
-  } else {
-    // In case somebody explicitly used -moz-use-system-font.
-    systemFont = *defaultVariableFont;
-  }
-
+    }
+  }
 
   // font-family: string list, enum, inherit
   const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
   NS_ASSERTION(eCSSUnit_Enumerated != familyValue->GetUnit(),
                "system fonts should not be in mFamily anymore");
   if (eCSSUnit_Families == familyValue->GetUnit()) {
     // set the correct font if we are using DocumentFonts OR we are overriding for XUL
     // MJA: bug 31816
@@ -4789,72 +4792,103 @@ struct BackgroundItemComputer<nsCSSValue
                            nsStyleImage& aComputedValue,
                            bool& aCanStoreInRuleTree)
   {
     SetStyleImage(aStyleContext, aSpecifiedValue->mValue, aComputedValue,
                   aCanStoreInRuleTree);
   }
 };
 
-struct BackgroundPositionAxis {
-  nsCSSValue nsCSSValuePairList::*specified;
-  nsStyleBackground::Position::PositionCoord
-    nsStyleBackground::Position::*result;
-};
-
-static const BackgroundPositionAxis gBGPosAxes[] = {
-  { &nsCSSValuePairList::mXValue,
-    &nsStyleBackground::Position::mXPosition },
-  { &nsCSSValuePairList::mYValue,
-    &nsStyleBackground::Position::mYPosition }
-};
+/* Helper function for
+ * BackgroundItemComputer<nsCSSValue, nsStyleBackground::Position>
+ * It computes a single PositionCoord from an nsCSSValue object
+ * (contained in a list).
+ */
+typedef nsStyleBackground::Position::PositionCoord PositionCoord;
+static void
+ComputeBackgroundPositionCoord(nsStyleContext* aStyleContext,
+                               const nsCSSValue& aEdge,
+                               const nsCSSValue& aOffset,
+                               PositionCoord* aResult,
+                               bool& aCanStoreInRuleTree)
+{
+  if (eCSSUnit_Percent == aOffset.GetUnit()) {
+    aResult->mLength = 0;
+    aResult->mPercent = aOffset.GetPercentValue();
+    aResult->mHasPercent = true;
+  } else if (aOffset.IsLengthUnit()) {
+    aResult->mLength = CalcLength(aOffset, aStyleContext,
+                                  aStyleContext->PresContext(),
+                                  aCanStoreInRuleTree);
+    aResult->mPercent = 0.0f;
+    aResult->mHasPercent = false;
+  } else if (aOffset.IsCalcUnit()) {
+    LengthPercentPairCalcOps ops(aStyleContext,
+                                 aStyleContext->PresContext(),
+                                 aCanStoreInRuleTree);
+    nsRuleNode::ComputedCalc vals = ComputeCalc(aOffset, ops);
+    aResult->mLength = vals.mLength;
+    aResult->mPercent = vals.mPercent;
+    aResult->mHasPercent = ops.mHasPercent;
+  } else {
+    aResult->mLength = 0;
+    aResult->mPercent = 0.0f;
+    aResult->mHasPercent = false;
+    NS_ASSERTION(aOffset.GetUnit() == eCSSUnit_Null, "unexpected unit");
+  }
+
+  if (eCSSUnit_Enumerated == aEdge.GetUnit()) {
+    int sign;
+    if (aEdge.GetIntValue() & (NS_STYLE_BG_POSITION_BOTTOM |
+                               NS_STYLE_BG_POSITION_RIGHT)) {
+      sign = -1;
+    } else {
+      sign = 1;
+    }
+    aResult->mPercent = GetFloatFromBoxPosition(aEdge.GetIntValue()) +
+                        sign * aResult->mPercent;
+    aResult->mLength = sign * aResult->mLength;
+    aResult->mHasPercent = true;
+  } else {
+    NS_ASSERTION(eCSSUnit_Null == aEdge.GetUnit(), "unexpected unit");
+  }
+}
 
 template <>
-struct BackgroundItemComputer<nsCSSValuePairList, nsStyleBackground::Position>
+struct BackgroundItemComputer<nsCSSValueList, nsStyleBackground::Position>
 {
   static void ComputeValue(nsStyleContext* aStyleContext,
-                           const nsCSSValuePairList* aSpecifiedValue,
+                           const nsCSSValueList* aSpecifiedValue,
                            nsStyleBackground::Position& aComputedValue,
                            bool& aCanStoreInRuleTree)
   {
-    nsStyleBackground::Position &position = aComputedValue;
-    for (const BackgroundPositionAxis *axis = gBGPosAxes,
-                        *axis_end = ArrayEnd(gBGPosAxes);
-         axis < axis_end; ++axis) {
-      const nsCSSValue &specified = aSpecifiedValue->*(axis->specified);
-      if (eCSSUnit_Percent == specified.GetUnit()) {
-        (position.*(axis->result)).mLength = 0;
-        (position.*(axis->result)).mPercent = specified.GetPercentValue();
-        (position.*(axis->result)).mHasPercent = true;
-      }
-      else if (specified.IsLengthUnit()) {
-        (position.*(axis->result)).mLength =
-          CalcLength(specified, aStyleContext, aStyleContext->PresContext(),
-                     aCanStoreInRuleTree);
-        (position.*(axis->result)).mPercent = 0.0f;
-        (position.*(axis->result)).mHasPercent = false;
-      }
-      else if (specified.IsCalcUnit()) {
-        LengthPercentPairCalcOps ops(aStyleContext,
-                                     aStyleContext->PresContext(),
-                                     aCanStoreInRuleTree);
-        nsRuleNode::ComputedCalc vals = ComputeCalc(specified, ops);
-        (position.*(axis->result)).mLength = vals.mLength;
-        (position.*(axis->result)).mPercent = vals.mPercent;
-        (position.*(axis->result)).mHasPercent = ops.mHasPercent;
-      }
-      else if (eCSSUnit_Enumerated == specified.GetUnit()) {
-        (position.*(axis->result)).mLength = 0;
-        (position.*(axis->result)).mPercent =
-          GetFloatFromBoxPosition(specified.GetIntValue());
-        (position.*(axis->result)).mHasPercent = true;
-      } else {
-        NS_NOTREACHED("unexpected unit");
-      }
-    }
+    NS_ASSERTION(aSpecifiedValue->mValue.GetUnit() == eCSSUnit_Array, "bg-position not an array");
+
+    nsRefPtr<nsCSSValue::Array> bgPositionArray =
+                                  aSpecifiedValue->mValue.GetArrayValue();
+    const nsCSSValue &xEdge   = bgPositionArray->Item(0);
+    const nsCSSValue &xOffset = bgPositionArray->Item(1);
+    const nsCSSValue &yEdge   = bgPositionArray->Item(2);
+    const nsCSSValue &yOffset = bgPositionArray->Item(3);
+
+    NS_ASSERTION((eCSSUnit_Enumerated == xEdge.GetUnit()  ||
+                  eCSSUnit_Null       == xEdge.GetUnit()) &&
+                 (eCSSUnit_Enumerated == yEdge.GetUnit()  ||
+                  eCSSUnit_Null       == yEdge.GetUnit()) &&
+                  eCSSUnit_Enumerated != xOffset.GetUnit()  &&
+                  eCSSUnit_Enumerated != yOffset.GetUnit(),
+                  "Invalid background position");
+
+    ComputeBackgroundPositionCoord(aStyleContext, xEdge, xOffset,
+                                   &aComputedValue.mXPosition,
+                                   aCanStoreInRuleTree);
+
+    ComputeBackgroundPositionCoord(aStyleContext, yEdge, yOffset,
+                                   &aComputedValue.mYPosition,
+                                   aCanStoreInRuleTree);
   }
 };
 
 
 struct BackgroundSizeAxis {
   nsCSSValue nsCSSValuePairList::* specified;
   nsStyleBackground::Size::Dimension nsStyleBackground::Size::* result;
   PRUint8 nsStyleBackground::Size::* type;
@@ -5181,22 +5215,22 @@ nsRuleNode::ComputeBackgroundData(void* 
                     parentBG->mLayers, &nsStyleBackground::Layer::mOrigin,
                     PRUint8(NS_STYLE_BG_ORIGIN_PADDING), parentBG->mOriginCount,
                     bg->mOriginCount, maxItemCount, rebuild,
                     canStoreInRuleTree);
 
   // background-position: enum, length, percent (flags), inherit [pair list]
   nsStyleBackground::Position initialPosition;
   initialPosition.SetInitialValues();
-  SetBackgroundPairList(aContext, *aRuleData->ValueForBackgroundPosition(),
-                        bg->mLayers,
-                        parentBG->mLayers, &nsStyleBackground::Layer::mPosition,
-                        initialPosition, parentBG->mPositionCount,
-                        bg->mPositionCount, maxItemCount, rebuild,
-                        canStoreInRuleTree);
+  SetBackgroundList(aContext, *aRuleData->ValueForBackgroundPosition(),
+                    bg->mLayers,
+                    parentBG->mLayers, &nsStyleBackground::Layer::mPosition,
+                    initialPosition, parentBG->mPositionCount,
+                    bg->mPositionCount, maxItemCount, rebuild,
+                    canStoreInRuleTree);
 
   // background-size: enum, length, auto, inherit, initial [pair list]
   nsStyleBackground::Size initialSize;
   initialSize.SetInitialValues();
   SetBackgroundPairList(aContext, *aRuleData->ValueForBackgroundSize(),
                         bg->mLayers,
                         parentBG->mLayers, &nsStyleBackground::Layer::mSize,
                         initialSize, parentBG->mSizeCount,
--- a/layout/style/nsStyleAnimation.cpp
+++ b/layout/style/nsStyleAnimation.cpp
@@ -51,16 +51,17 @@
 #include "nsComputedDOMStyle.h"
 #include "nsCSSParser.h"
 #include "mozilla/css/Declaration.h"
 #include "mozilla/dom/Element.h"
 #include "prlog.h"
 #include <math.h>
 #include "gfxMatrix.h"
 #include "gfxQuaternion.h"
+#include "nsPrintfCString.h"
 
 using namespace mozilla;
 
 // HELPER METHODS
 // --------------
 /*
  * Given two units, this method returns a common unit that they can both be
  * converted into, if possible.  This is intended to facilitate
@@ -625,16 +626,69 @@ nsStyleAnimation::ComputeDistance(nsCSSP
         NS_ABORT_IF_FALSE(!shadow1 == !shadow2, "lists should be same length");
       }
       aDistance = sqrt(squareDistance);
       return true;
     }
     case eUnit_Transform: {
       return false;
     }
+    case eUnit_BackgroundPosition: {
+      const nsCSSValueList *position1 = aStartValue.GetCSSValueListValue();
+      const nsCSSValueList *position2 = aEndValue.GetCSSValueListValue();
+
+      double squareDistance = 0.0;
+      NS_ABORT_IF_FALSE(!position1 == !position2, "lists should be same length");
+
+      while (position1 && position2) {
+        NS_ASSERTION(position1->mValue.GetUnit() == eCSSUnit_Array &&
+                     position2->mValue.GetUnit() == eCSSUnit_Array,
+                     "Expected two arrays");
+
+        CalcValue calcVal[4];
+
+        nsCSSValue::Array* bgArray = position1->mValue.GetArrayValue();
+        NS_ABORT_IF_FALSE(bgArray->Count() == 4, "Invalid background-position");
+        NS_ASSERTION(bgArray->Item(0).GetUnit() == eCSSUnit_Null &&
+                     bgArray->Item(2).GetUnit() == eCSSUnit_Null,
+                     "Invalid list used");
+        for (int i = 0; i < 2; ++i) {
+          NS_ABORT_IF_FALSE(bgArray->Item(i*2+1).GetUnit() != eCSSUnit_Null,
+                            "Invalid background-position");
+          calcVal[i] = ExtractCalcValue(bgArray->Item(i*2+1));
+        }
+
+        bgArray = position2->mValue.GetArrayValue();
+        NS_ABORT_IF_FALSE(bgArray->Count() == 4, "Invalid background-position");
+        NS_ASSERTION(bgArray->Item(0).GetUnit() == eCSSUnit_Null &&
+                     bgArray->Item(2).GetUnit() == eCSSUnit_Null,
+                     "Invalid list used");
+        for (int i = 0; i < 2; ++i) {
+          NS_ABORT_IF_FALSE(bgArray->Item(i*2+1).GetUnit() != eCSSUnit_Null,
+                            "Invalid background-position");
+          calcVal[i+2] = ExtractCalcValue(bgArray->Item(i*2+1));
+        }
+
+        for (int i = 0; i < 2; ++i) {
+          float difflen = calcVal[i+2].mLength - calcVal[i].mLength;
+          float diffpct = calcVal[i+2].mPercent - calcVal[i].mPercent;
+          squareDistance += difflen * difflen + diffpct * diffpct;
+        }
+
+        position1 = position1->mNext;
+        position2 = position2->mNext;
+      }
+      // fail if lists differ in length.
+      if (position1 || position2) {
+        return false;
+      }
+
+      aDistance = sqrt(squareDistance);
+      return true;
+    }
     case eUnit_CSSValuePairList: {
       const nsCSSValuePairList *list1 = aStartValue.GetCSSValuePairListValue();
       const nsCSSValuePairList *list2 = aEndValue.GetCSSValuePairListValue();
       double squareDistance = 0.0;
       do {
         static nsCSSValue nsCSSValuePairList::* const pairListValues[] = {
           &nsCSSValuePairList::mXValue,
           &nsCSSValuePairList::mYValue,
@@ -798,16 +852,52 @@ AddCSSValueAngle(const nsCSSValue &aValu
                  nsCSSValue &aResult)
 {
   aResult.SetFloatValue(aCoeff1 * aValue1.GetAngleValueInRadians() +
                         aCoeff2 * aValue2.GetAngleValueInRadians(),
                         eCSSUnit_Radian);
 }
 
 static bool
+AddCSSValuePixelPercentCalc(const PRUint32 aValueRestrictions,
+                            const nsCSSUnit aCommonUnit,
+                            double aCoeff1, const nsCSSValue &aValue1,
+                            double aCoeff2, const nsCSSValue &aValue2,
+                            nsCSSValue &aResult)
+{
+  switch (aCommonUnit) {
+    case eCSSUnit_Pixel:
+      AddCSSValuePixel(aCoeff1, aValue1,
+                       aCoeff2, aValue2,
+                       aResult, aValueRestrictions);
+      break;
+    case eCSSUnit_Percent:
+      AddCSSValuePercent(aCoeff1, aValue1,
+                         aCoeff2, aValue2,
+                         aResult, aValueRestrictions);
+      break;
+    case eCSSUnit_Calc:
+      AddCSSValueCanonicalCalc(aCoeff1, aValue1,
+                               aCoeff2, aValue2,
+                               aResult);
+      break;
+    default:
+      NS_ABORT_IF_FALSE(false,
+                        nsPrintfCString(32,
+                                        "unexpected unit %d, from %d and %d",
+                                        aCommonUnit,
+                                        aValue1.GetUnit(),
+                                        aValue2.GetUnit()).get());
+      return false;
+  }
+
+  return true;
+}
+
+static bool
 AddShadowItems(double aCoeff1, const nsCSSValue &aValue1,
                double aCoeff2, const nsCSSValue &aValue2,
                nsCSSValueList **&aResultTail)
 {
   // X, Y, Radius, Spread, Color, Inset
   NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Array,
                     "wrong unit");
   NS_ABORT_IF_FALSE(aValue2.GetUnit() == eCSSUnit_Array,
@@ -1723,34 +1813,21 @@ nsStyleAnimation::AddWeighted(nsCSSPrope
 
       nsAutoPtr<nsCSSValuePair> result(new nsCSSValuePair);
       static nsCSSValue nsCSSValuePair::* const pairValues[2] = {
         &nsCSSValuePair::mXValue, &nsCSSValuePair::mYValue
       };
       PRUint32 restrictions = nsCSSProps::ValueRestrictions(aProperty);
       for (PRUint32 i = 0; i < 2; ++i) {
         nsCSSValue nsCSSValuePair::*member = pairValues[i];
-        switch (unit[i]) {
-          case eCSSUnit_Pixel:
-            AddCSSValuePixel(aCoeff1, pair1->*member, aCoeff2, pair2->*member,
-                             result->*member, restrictions);
-            break;
-          case eCSSUnit_Percent:
-            AddCSSValuePercent(aCoeff1, pair1->*member,
-                               aCoeff2, pair2->*member,
-                               result->*member, restrictions);
-            break;
-          case eCSSUnit_Calc:
-            AddCSSValueCanonicalCalc(aCoeff1, pair1->*member,
-                                     aCoeff2, pair2->*member,
-                                     result->*member);
-            break;
-          default:
-            NS_ABORT_IF_FALSE(false, "unexpected unit");
-            return false;
+        if (!AddCSSValuePixelPercentCalc(restrictions, unit[i],
+                                         aCoeff1, pair1->*member,
+                                         aCoeff2, pair2->*member,
+                                         result->*member) ) {
+          return false;
         }
       }
 
       aResultValue.SetAndAdoptCSSValuePairValue(result.forget(),
                                                 eUnit_CSSValuePair);
       return true;
     }
     case eUnit_CSSValueTriplet: {
@@ -1778,34 +1855,21 @@ nsStyleAnimation::AddWeighted(nsCSSPrope
 
       nsAutoPtr<nsCSSValueTriplet> result(new nsCSSValueTriplet);
       static nsCSSValue nsCSSValueTriplet::* const tripletValues[3] = {
         &nsCSSValueTriplet::mXValue, &nsCSSValueTriplet::mYValue, &nsCSSValueTriplet::mZValue
       };
       PRUint32 restrictions = nsCSSProps::ValueRestrictions(aProperty);
       for (PRUint32 i = 0; i < 3; ++i) {
         nsCSSValue nsCSSValueTriplet::*member = tripletValues[i];
-        switch (unit[i]) {
-          case eCSSUnit_Pixel:
-            AddCSSValuePixel(aCoeff1, &triplet1->*member, aCoeff2, &triplet2->*member,
-                             result->*member, restrictions);
-            break;
-          case eCSSUnit_Percent:
-            AddCSSValuePercent(aCoeff1, &triplet1->*member,
-                               aCoeff2, &triplet2->*member,
-                               result->*member, restrictions);
-            break;
-          case eCSSUnit_Calc:
-            AddCSSValueCanonicalCalc(aCoeff1, &triplet1->*member,
-                                     aCoeff2, &triplet2->*member,
-                                     result->*member);
-            break;
-          default:
-            NS_ABORT_IF_FALSE(false, "unexpected unit");
-            return false;
+        if (!AddCSSValuePixelPercentCalc(restrictions, unit[i],
+                                         aCoeff1, &triplet1->*member,
+                                         aCoeff2, &triplet2->*member,
+                                         result->*member) ) {
+          return false;
         }
       }
 
       if (result->mZValue.GetUnit() == eCSSUnit_Pixel &&
           result->mZValue.GetFloatValue() == 0.0f) {
         result->mZValue.Reset();
       }
 
@@ -2019,16 +2083,68 @@ nsStyleAnimation::AddWeighted(nsCSSPrope
           }
         }
       }
 
       aResultValue.SetAndAdoptCSSValueListValue(result.forget(),
                                                 eUnit_Transform);
       return true;
     }
+    case eUnit_BackgroundPosition: {
+      const nsCSSValueList *position1 = aValue1.GetCSSValueListValue();
+      const nsCSSValueList *position2 = aValue2.GetCSSValueListValue();
+      nsAutoPtr<nsCSSValueList> result;
+      nsCSSValueList **resultTail = getter_Transfers(result);
+      while (position1 && position2) {
+        nsCSSValueList *item = new nsCSSValueList;
+        if (!item) {
+          return false;
+        }
+        *resultTail = item;
+        resultTail = &item->mNext;
+
+        nsCSSValue::Array* bgPos1 = position1->mValue.GetArrayValue();
+        nsCSSValue::Array* bgPos2 = position2->mValue.GetArrayValue();
+        nsCSSValue::Array* bgPosRes = nsCSSValue::Array::Create(4);
+        item->mValue.SetArrayValue(bgPosRes, eCSSUnit_Array);
+
+        PRUint32 restrictions = nsCSSProps::ValueRestrictions(aProperty);
+
+        /* Only iterate over elements 1 and 3. The background position is
+         * 'uncomputed' to only those elements.
+         */
+        for (int i = 1; i < 4; i+=2) {
+          const nsCSSValue& v1 = bgPos1->Item(i);
+          const nsCSSValue& v2 = bgPos2->Item(i);
+          nsCSSValue& vr = bgPosRes->Item(i);
+
+          nsCSSUnit unit = GetCommonUnit(aProperty, v1.GetUnit(), v2.GetUnit());
+
+          if (!AddCSSValuePixelPercentCalc(restrictions, unit, aCoeff1, v1,
+                                           aCoeff2, v2, vr) ) {
+            if (v1 != v2) {
+              return false;
+            }
+            vr = v1;
+          }
+        }
+
+        position1 = position1->mNext;
+        position2 = position2->mNext;
+      }
+
+      // Check for different lengths
+      if (position1 || position2) {
+        return false;
+      }
+
+      aResultValue.SetAndAdoptCSSValueListValue(result.forget(),
+                                                eUnit_BackgroundPosition);
+      return true;
+    }
     case eUnit_CSSValuePairList: {
       const nsCSSValuePairList *list1 = aValue1.GetCSSValuePairListValue();
       const nsCSSValuePairList *list2 = aValue2.GetCSSValuePairListValue();
       nsAutoPtr<nsCSSValuePairList> result;
       nsCSSValuePairList **resultTail = getter_Transfers(result);
       do {
         nsCSSValuePairList *item = new nsCSSValuePairList;
         if (!item) {
@@ -2046,32 +2162,22 @@ nsStyleAnimation::AddWeighted(nsCSSPrope
           const nsCSSValue &v1 = list1->*(pairListValues[i]);
           const nsCSSValue &v2 = list2->*(pairListValues[i]);
           nsCSSValue &vr = item->*(pairListValues[i]);
           nsCSSUnit unit =
             GetCommonUnit(aProperty, v1.GetUnit(), v2.GetUnit());
           if (unit == eCSSUnit_Null) {
             return false;
           }
-          switch (unit) {
-            case eCSSUnit_Pixel:
-              AddCSSValuePixel(aCoeff1, v1, aCoeff2, v2, vr, restrictions);
-              break;
-            case eCSSUnit_Percent:
-              AddCSSValuePercent(aCoeff1, v1, aCoeff2, v2, vr, restrictions);
-              break;
-            case eCSSUnit_Calc:
-              AddCSSValueCanonicalCalc(aCoeff1, v1, aCoeff2, v2, vr);
-              break;
-            default:
-              if (v1 != v2) {
-                return false;
-              }
-              vr = v1;
-              break;
+          if (!AddCSSValuePixelPercentCalc(restrictions, unit, aCoeff1, v1,
+                                           aCoeff2, v2, vr) ) {
+            if (v1 != v2) {
+              return false;
+            }
+            vr = v1;
           }
         }
         list1 = list1->mNext;
         list2 = list2->mNext;
       } while (list1 && list2);
       if (list1 || list2) {
         // We can't interpolate lists of different lengths.
         return false;
@@ -2296,16 +2402,17 @@ nsStyleAnimation::UncomputeValue(nsCSSPr
     } break;
     case eUnit_CSSRect: {
       nsCSSRect& rect = aSpecifiedValue.SetRectValue();
       rect = *aComputedValue.GetCSSRectValue();
     } break;
     case eUnit_Dasharray:
     case eUnit_Shadow:
     case eUnit_Transform:
+    case eUnit_BackgroundPosition:
       aSpecifiedValue.
         SetDependentListValue(aComputedValue.GetCSSValueListValue());
       break;
     case eUnit_CSSValuePairList:
       aSpecifiedValue.
         SetDependentPairListValue(aComputedValue.GetCSSValuePairListValue());
       break;
     default:
@@ -2759,48 +2866,54 @@ nsStyleAnimation::ExtractComputedValue(n
             aComputedValue.SetAndAdoptCSSRectValue(vrect, eUnit_CSSRect);
           }
           break;
         }
 
         case eCSSProperty_background_position: {
           const nsStyleBackground *bg =
             static_cast<const nsStyleBackground*>(styleStruct);
-          nsAutoPtr<nsCSSValuePairList> result;
-          nsCSSValuePairList **resultTail = getter_Transfers(result);
+          nsAutoPtr<nsCSSValueList> result;
+          nsCSSValueList **resultTail = getter_Transfers(result);
           NS_ABORT_IF_FALSE(bg->mPositionCount > 0, "unexpected count");
           for (PRUint32 i = 0, i_end = bg->mPositionCount; i != i_end; ++i) {
-            nsCSSValuePairList *item = new nsCSSValuePairList;
+            nsCSSValueList *item = new nsCSSValueList;
             *resultTail = item;
             resultTail = &item->mNext;
+            nsRefPtr<nsCSSValue::Array> bgArray = nsCSSValue::Array::Create(4);
+            item->mValue.SetArrayValue(bgArray.get(), eCSSUnit_Array);
 
             const nsStyleBackground::Position &pos = bg->mLayers[i].mPosition;
             // XXXbz is there a good reason we can't just
             // SetCalcValue(&pos.mXPosition, item->mXValue) here?
+            nsCSSValue &xValue = bgArray->Item(1),
+                       &yValue = bgArray->Item(3);
             if (!pos.mXPosition.mHasPercent) {
               NS_ABORT_IF_FALSE(pos.mXPosition.mPercent == 0.0f,
                                 "Shouldn't have mPercent!");
-              nscoordToCSSValue(pos.mXPosition.mLength, item->mXValue);
+              nscoordToCSSValue(pos.mXPosition.mLength, xValue);
             } else if (pos.mXPosition.mLength == 0) {
-              item->mXValue.SetPercentValue(pos.mXPosition.mPercent);
+              xValue.SetPercentValue(pos.mXPosition.mPercent);
             } else {
-              SetCalcValue(&pos.mXPosition, item->mXValue);
+              SetCalcValue(&pos.mXPosition, xValue);
             }
+
             if (!pos.mYPosition.mHasPercent) {
               NS_ABORT_IF_FALSE(pos.mYPosition.mPercent == 0.0f,
                                 "Shouldn't have mPercent!");
-              nscoordToCSSValue(pos.mYPosition.mLength, item->mYValue);
+              nscoordToCSSValue(pos.mYPosition.mLength, yValue);
             } else if (pos.mYPosition.mLength == 0) {
-              item->mYValue.SetPercentValue(pos.mYPosition.mPercent);
+              yValue.SetPercentValue(pos.mYPosition.mPercent);
             } else {
-              SetCalcValue(&pos.mYPosition, item->mYValue);
+              SetCalcValue(&pos.mYPosition, yValue);
             }
           }
 
-          aComputedValue.SetAndAdoptCSSValuePairListValue(result.forget());
+          aComputedValue.SetAndAdoptCSSValueListValue(result.forget(),
+                                                      eUnit_BackgroundPosition);
           break;
         }
 
         case eCSSProperty_background_size: {
           const nsStyleBackground *bg =
             static_cast<const nsStyleBackground*>(styleStruct);
           nsAutoPtr<nsCSSValuePairList> result;
           nsCSSValuePairList **resultTail = getter_Transfers(result);
@@ -3141,16 +3254,17 @@ nsStyleAnimation::Value::operator=(const
       mValue.mCSSRect = new nsCSSRect(*aOther.mValue.mCSSRect);
       if (!mValue.mCSSRect) {
         mUnit = eUnit_Null;
       }
       break;
     case eUnit_Dasharray:
     case eUnit_Shadow:
     case eUnit_Transform:
+    case eUnit_BackgroundPosition:
       NS_ABORT_IF_FALSE(mUnit == eUnit_Shadow || aOther.mValue.mCSSValueList,
                         "value lists other than shadows may not be null");
       if (aOther.mValue.mCSSValueList) {
         mValue.mCSSValueList = aOther.mValue.mCSSValueList->Clone();
         if (!mValue.mCSSValueList) {
           mUnit = eUnit_Null;
         }
       } else {
@@ -3366,16 +3480,17 @@ nsStyleAnimation::Value::operator==(cons
       return *mValue.mCSSValuePair == *aOther.mValue.mCSSValuePair;
     case eUnit_CSSValueTriplet:
       return *mValue.mCSSValueTriplet == *aOther.mValue.mCSSValueTriplet;
     case eUnit_CSSRect:
       return *mValue.mCSSRect == *aOther.mValue.mCSSRect;
     case eUnit_Dasharray:
     case eUnit_Shadow:
     case eUnit_Transform:
+    case eUnit_BackgroundPosition:
       return *mValue.mCSSValueList == *aOther.mValue.mCSSValueList;
     case eUnit_CSSValuePairList:
       return *mValue.mCSSValuePairList == *aOther.mValue.mCSSValuePairList;
     case eUnit_UnparsedString:
       return (NS_strcmp(GetStringBufferValue(),
                         aOther.GetStringBufferValue()) == 0);
   }
 
--- a/layout/style/nsStyleAnimation.h
+++ b/layout/style/nsStyleAnimation.h
@@ -259,16 +259,17 @@ public:
     eUnit_Calc, // nsCSSValue* (never null), always with a single
                 // calc() expression that's either length or length+percent
     eUnit_CSSValuePair, // nsCSSValuePair* (never null)
     eUnit_CSSValueTriplet, // nsCSSValueTriplet* (never null)
     eUnit_CSSRect, // nsCSSRect* (never null)
     eUnit_Dasharray, // nsCSSValueList* (never null)
     eUnit_Shadow, // nsCSSValueList* (may be null)
     eUnit_Transform, // nsCSSValueList* (never null)
+    eUnit_BackgroundPosition, // nsCSSValueList* (never null)
     eUnit_CSSValuePairList, // nsCSSValuePairList* (never null)
     eUnit_UnparsedString // nsStringBuffer* (never null)
   };
 
   class Value {
   private:
     Unit mUnit;
     union {
@@ -416,17 +417,17 @@ public:
     static bool IsCSSValueTripletUnit(Unit aUnit) {
       return aUnit == eUnit_CSSValueTriplet;
     }
     static bool IsCSSRectUnit(Unit aUnit) {
       return aUnit == eUnit_CSSRect;
     }
     static bool IsCSSValueListUnit(Unit aUnit) {
       return aUnit == eUnit_Dasharray || aUnit == eUnit_Shadow ||
-             aUnit == eUnit_Transform;
+             aUnit == eUnit_Transform || aUnit == eUnit_BackgroundPosition;
     }
     static bool IsCSSValuePairListUnit(Unit aUnit) {
       return aUnit == eUnit_CSSValuePairList;
     }
     static bool IsStringUnit(Unit aUnit) {
       return aUnit == eUnit_UnparsedString;
     }
   };
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -1560,31 +1560,52 @@ var gCSSProperties = {
 		initial_values: [ "padding-box" ],
 		other_values: [ "border-box", "content-box", "border-box, padding-box", "padding-box, padding-box, padding-box", "border-box, border-box" ],
 		invalid_values: [ "margin-box", "padding-box padding-box" ]
 	},
 	"background-position": {
 		domProp: "backgroundPosition",
 		inherited: false,
 		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "top left", "left top", "0% 0%", "0% top", "left 0%" ],
+		initial_values: [ "top 0% left 0%", "top 0% left", "top left", "left top", "0% 0%", "0% top", "left 0%" ],
 		other_values: [ "top", "left", "right", "bottom", "center", "center bottom", "bottom center", "center right", "right center", "center top", "top center", "center left", "left center", "right bottom", "bottom right", "50%", "top left, top left", "top left, top right", "top right, top left", "left top, 0% 0%", "10% 20%, 30%, 40%", "top left, bottom right", "right bottom, left top", "0%", "0px", "30px", "0%, 10%, 20%, 30%", "top, top, top, top, top",
 			"-moz-calc(20px)",
 			"-moz-calc(20px) 10px",
 			"10px -moz-calc(20px)",
 			"-moz-calc(20px) 25%",
 			"25% -moz-calc(20px)",
 			"-moz-calc(20px) -moz-calc(20px)",
 			"-moz-calc(20px + 1em) -moz-calc(20px / 2)",
 			"-moz-calc(20px + 50%) -moz-calc(50% - 10px)",
 			"-moz-calc(-20px) -moz-calc(-50%)",
 			"-moz-calc(-20%) -moz-calc(-50%)",
-			"0px 0px"
+			"0px 0px",
+			"right 20px top 60px",
+			"right 20px bottom 60px",
+			"left 20px top 60px",
+			"left 20px bottom 60px",
+			"right -50px top -50px",
+			"left -50px bottom -50px",
+			"right 20px top -50px",
+			"right -20px top 50px",
+			"right 3em bottom 10px",
+			"bottom 3em right 10px",
+			"top 3em right 10px",
+			"left 15px",
+			"10px top",
+			"left top 15px",
+			"left 10px top",
+			"left 20%",
+			"right 20%"
 		],
-		invalid_values: [ "50% left", "top 50%" ]
+		invalid_values: [ "center 10px center 4px", "center 10px center", 
+		                  "top 20%", "bottom 20%", "50% left", "top 50%", 
+		                  "50% bottom 10%", "right 10% 50%", "left right", 
+		                  "top bottom", "left 10% right", 
+		                  "top 20px bottom 20px", "left left" ]
 	},
 	"background-repeat": {
 		domProp: "backgroundRepeat",
 		inherited: false,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "repeat" ],
 		other_values: [ "repeat-x", "repeat-y", "no-repeat",
 			"repeat-x, repeat-x",
--- a/mobile/android/base/db/BrowserContract.java.in
+++ b/mobile/android/base/db/BrowserContract.java.in
@@ -97,16 +97,18 @@ public class BrowserContract {
         public static final String URL = "url_key";
 
         public static final String FAVICON_URL = "favicon_url";
     }
 
     public static final class Bookmarks implements CommonColumns, URLColumns, ImageColumns, SyncColumns {
         private Bookmarks() {}
 
+        public static final int FIXED_ROOT_ID = 0;
+
         public static final String MOBILE_FOLDER_GUID = "mobile";
         public static final String PLACES_FOLDER_GUID = "places";
         public static final String MENU_FOLDER_GUID = "menu";
         public static final String TAGS_FOLDER_GUID = "tags";
         public static final String TOOLBAR_FOLDER_GUID = "toolbar";
         public static final String UNFILED_FOLDER_GUID = "unfiled";
 
         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "bookmarks");
--- a/mobile/android/base/db/BrowserProvider.java.in
+++ b/mobile/android/base/db/BrowserProvider.java.in
@@ -37,17 +37,19 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #filter substitution
 package @ANDROID_PACKAGE_NAME@.db;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Random;
 
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoDirProvider;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.db.BrowserContract.Bookmarks;
 import org.mozilla.gecko.db.BrowserContract.CommonColumns;
 import org.mozilla.gecko.db.BrowserContract.History;
@@ -60,43 +62,46 @@ import org.mozilla.gecko.db.DBUtils;
 import org.mozilla.gecko.sync.Utils;
 
 import android.content.ContentProvider;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.UriMatcher;
 import android.database.Cursor;
+import android.database.DatabaseUtils;
 import android.database.MatrixCursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.net.Uri;
 import android.os.Build;
 import android.text.TextUtils;
 import android.util.Log;
 
 public class BrowserProvider extends ContentProvider {
     private static final String LOGTAG = "GeckoBrowserProvider";
     private Context mContext;
 
     static final String DATABASE_NAME = "browser.db";
 
-    static final int DATABASE_VERSION = 1;
+    static final int DATABASE_VERSION = 2;
 
     // Maximum age of deleted records to be cleaned up (20 days in ms)
     static final long MAX_AGE_OF_DELETED_RECORDS = 86400000 * 20;
 
     // Number of records marked as deleted to be removed
     static final long DELETED_RECORDS_PURGE_LIMIT = 5;
 
     static final String TABLE_BOOKMARKS = "bookmarks";
     static final String TABLE_HISTORY = "history";
     static final String TABLE_IMAGES = "images";
 
+    static final String TABLE_BOOKMARKS_TMP = TABLE_BOOKMARKS + "_tmp";
+
     static final String VIEW_BOOKMARKS_WITH_IMAGES = "bookmarks_with_images";
     static final String VIEW_HISTORY_WITH_IMAGES = "history_with_images";
 
     // Bookmark matches
     static final int BOOKMARKS = 100;
     static final int BOOKMARKS_ID = 101;
     static final int BOOKMARKS_FOLDER_ID = 102;
     static final int BOOKMARKS_PARENT = 103;
@@ -239,44 +244,53 @@ public class BrowserProvider extends Con
         }
     }
 
     final class DatabaseHelper extends SQLiteOpenHelper {
         public DatabaseHelper(Context context, String databasePath) {
             super(context, databasePath, null, DATABASE_VERSION);
         }
 
-        @Override
-        public void onCreate(SQLiteDatabase db) {
-            debug("Creating browser.db: " + db.getPath());
+        private void createBookmarksTable(SQLiteDatabase db) {
+            debug("Creating " + TABLE_BOOKMARKS + " table");
 
-            debug("Creating " + TABLE_BOOKMARKS + " table");
+            // Android versions older than Froyo ship with an sqlite
+            // that doesn't support foreign keys.
+            String foreignKeyOnParent = null;
+            if (Build.VERSION.SDK_INT >= 8) {
+                foreignKeyOnParent = ", FOREIGN KEY (" + Bookmarks.PARENT +
+                    ") REFERENCES " + TABLE_BOOKMARKS + "(" + Bookmarks._ID + ")";
+            }
+
             db.execSQL("CREATE TABLE " + TABLE_BOOKMARKS + "(" +
                     Bookmarks._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
                     Bookmarks.TITLE + " TEXT," +
                     Bookmarks.URL + " TEXT," +
                     Bookmarks.IS_FOLDER + " INTEGER NOT NULL DEFAULT 0," +
                     Bookmarks.PARENT + " INTEGER," +
                     Bookmarks.POSITION + " INTEGER NOT NULL," +
                     Bookmarks.KEYWORD + " TEXT," +
                     Bookmarks.DESCRIPTION + " TEXT," +
                     Bookmarks.TAGS + " TEXT," +
                     Bookmarks.DATE_CREATED + " INTEGER," +
                     Bookmarks.DATE_MODIFIED + " INTEGER," +
                     Bookmarks.GUID + " TEXT," +
                     Bookmarks.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" +
+                    (foreignKeyOnParent != null ? foreignKeyOnParent : "") +
                     ");");
 
             db.execSQL("CREATE INDEX bookmarks_url_index ON " + TABLE_BOOKMARKS + "("
                     + Bookmarks.URL + ")");
             db.execSQL("CREATE UNIQUE INDEX bookmarks_guid_index ON " + TABLE_BOOKMARKS + "("
                     + Bookmarks.GUID + ")");
             db.execSQL("CREATE INDEX bookmarks_modified_index ON " + TABLE_BOOKMARKS + "("
                     + Bookmarks.DATE_MODIFIED + ")");
+        }
 
+        private void createHistoryTable(SQLiteDatabase db) {
             debug("Creating " + TABLE_HISTORY + " table");
             db.execSQL("CREATE TABLE " + TABLE_HISTORY + "(" +
                     History._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
                     History.TITLE + " TEXT," +
                     History.URL + " TEXT NOT NULL," +
                     History.VISITS + " INTEGER NOT NULL DEFAULT 0," +
                     History.DATE_LAST_VISITED + " INTEGER," +
                     History.DATE_CREATED + " INTEGER," +
@@ -288,17 +302,19 @@ public class BrowserProvider extends Con
             db.execSQL("CREATE INDEX history_url_index ON " + TABLE_HISTORY + "("
                     + History.URL + ")");
             db.execSQL("CREATE UNIQUE INDEX history_guid_index ON " + TABLE_HISTORY + "("
                     + History.GUID + ")");
             db.execSQL("CREATE INDEX history_modified_index ON " + TABLE_HISTORY + "("
                     + History.DATE_MODIFIED + ")");
             db.execSQL("CREATE INDEX history_visited_index ON " + TABLE_HISTORY + "("
                     + History.DATE_LAST_VISITED + ")");
+        }
 
+        private void createImagesTable(SQLiteDatabase db) {
             debug("Creating " + TABLE_IMAGES + " table");
             db.execSQL("CREATE TABLE " + TABLE_IMAGES + " (" +
                     Images._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
                     Images.URL + " TEXT UNIQUE NOT NULL," +
                     Images.FAVICON + " BLOB," +
                     Images.FAVICON_URL + " TEXT," +
                     Images.THUMBNAIL + " BLOB," +
                     Images.DATE_CREATED + " INTEGER," +
@@ -308,57 +324,243 @@ public class BrowserProvider extends Con
                     ");");
 
             db.execSQL("CREATE INDEX images_url_index ON " + TABLE_IMAGES + "("
                     + Images.URL + ")");
             db.execSQL("CREATE UNIQUE INDEX images_guid_index ON " + TABLE_IMAGES + "("
                     + Images.GUID + ")");
             db.execSQL("CREATE INDEX images_modified_index ON " + TABLE_IMAGES + "("
                     + Images.DATE_MODIFIED + ")");
+        }
 
+        private void createBookmarksWithImagesView(SQLiteDatabase db) {
             db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_BOOKMARKS_WITH_IMAGES + " AS " +
                     "SELECT " + qualifyColumn(TABLE_BOOKMARKS, "*") +
                     ", " + Images.FAVICON + ", " + Images.THUMBNAIL + " FROM " +
                     TABLE_BOOKMARKS_JOIN_IMAGES);
+        }
 
+        private void createHistoryWithImagesView(SQLiteDatabase db) {
             db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_HISTORY_WITH_IMAGES + " AS " +
                     "SELECT " + qualifyColumn(TABLE_HISTORY, "*") +
                     ", " + Images.FAVICON + ", " + Images.THUMBNAIL + " FROM " +
                     TABLE_HISTORY_JOIN_IMAGES);
+        }
 
-            createMobileBookmarksFolder(db);
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            debug("Creating browser.db: " + db.getPath());
+
+            createBookmarksTable(db);
+            createHistoryTable(db);
+            createImagesTable(db);
 
-            // FIXME: Create default bookmarks here
+            createBookmarksWithImagesView(db);
+            createHistoryWithImagesView(db);
+
+            createOrUpdateSpecialFolder(db, Bookmarks.PLACES_FOLDER_GUID,
+                R.string.bookmarks_folder_places, 0);
+
+            createOrUpdateAllSpecialFolders(db);
+
+            // FIXME: Create default bookmarks here (bug 728224)
         }
 
-        private void createMobileBookmarksFolder(SQLiteDatabase db) {
+        private void createOrUpdateAllSpecialFolders(SQLiteDatabase db) {
+            createOrUpdateSpecialFolder(db, Bookmarks.MOBILE_FOLDER_GUID,
+                R.string.bookmarks_folder_mobile, 0);
+            createOrUpdateSpecialFolder(db, Bookmarks.TOOLBAR_FOLDER_GUID,
+                R.string.bookmarks_folder_toolbar, 1);
+            createOrUpdateSpecialFolder(db, Bookmarks.MENU_FOLDER_GUID,
+                R.string.bookmarks_folder_menu, 2);
+            createOrUpdateSpecialFolder(db, Bookmarks.TAGS_FOLDER_GUID,
+                R.string.bookmarks_folder_tags, 3);
+            createOrUpdateSpecialFolder(db, Bookmarks.UNFILED_FOLDER_GUID,
+                R.string.bookmarks_folder_unfiled, 4);
+        }
+
+        private void createOrUpdateSpecialFolder(SQLiteDatabase db,
+                String guid, int titleId, int position) {
             ContentValues values = new ContentValues();
-            values.put(Bookmarks.GUID, Bookmarks.MOBILE_FOLDER_GUID);
+            values.put(Bookmarks.GUID, guid);
             values.put(Bookmarks.IS_FOLDER, 1);
-            values.put(Bookmarks.POSITION, 0);
+            values.put(Bookmarks.POSITION, position);
+
+            if (guid.equals(Bookmarks.PLACES_FOLDER_GUID))
+                values.put(Bookmarks._ID, Bookmarks.FIXED_ROOT_ID);
 
             // Set the parent to 0, which sync assumes is the root
-            values.put(Bookmarks.PARENT, 0);
+            values.put(Bookmarks.PARENT, Bookmarks.FIXED_ROOT_ID);
 
-            String title = mContext.getResources().getString(R.string.bookmarks_folder_mobile);
+            String title = mContext.getResources().getString(titleId);
             values.put(Bookmarks.TITLE, title);
 
             long now = System.currentTimeMillis();
             values.put(Bookmarks.DATE_CREATED, now);
             values.put(Bookmarks.DATE_MODIFIED, now);
 
-            db.insertOrThrow(TABLE_BOOKMARKS, Bookmarks.GUID, values);
+            int updated = db.update(TABLE_BOOKMARKS, values,
+                                    Bookmarks.GUID + " = ?",
+                                    new String[] { guid });
+
+            if (updated == 0) {
+                db.insert(TABLE_BOOKMARKS, Bookmarks.GUID, values);
+                debug("Inserted special folder: " + guid);
+            } else {
+                debug("Updated special folder: " + guid);
+            }
+        }
+
+        private boolean isSpecialFolder(ContentValues values) {
+            String guid = values.getAsString(Bookmarks.GUID);
+            if (guid == null)
+                return false;
+
+            return guid.equals(Bookmarks.MOBILE_FOLDER_GUID) ||
+                   guid.equals(Bookmarks.MENU_FOLDER_GUID) ||
+                   guid.equals(Bookmarks.TOOLBAR_FOLDER_GUID) ||
+                   guid.equals(Bookmarks.UNFILED_FOLDER_GUID) ||
+                   guid.equals(Bookmarks.TAGS_FOLDER_GUID);
+        }
+
+        private void migrateBookmarkFolder(SQLiteDatabase db, int folderId) {
+            Cursor c = null;
+
+            debug("Migrating bookmark folder with id = " + folderId);
+
+            String selection = Bookmarks.PARENT + " = " + folderId;
+            String[] selectionArgs = null;
+
+            boolean isRootFolder = (folderId == Bookmarks.FIXED_ROOT_ID);
+
+            // If we're loading the root folder, we have to account for
+            // any previously created special folder that was created without
+            // setting a parent id (e.g. mobile folder) and making sure we're
+            // not adding any infinite recursion as root's parent is root itself.
+            if (isRootFolder) {
+                selection = Bookmarks.GUID + " != ?" + " AND (" +
+                            selection + " OR " + Bookmarks.PARENT + " = NULL)";
+                selectionArgs = new String[] { Bookmarks.PLACES_FOLDER_GUID };
+            }
+
+            List<Integer> subFolders = new ArrayList<Integer>();
+            List<ContentValues> invalidSpecialEntries = new ArrayList<ContentValues>();
+
+            try {
+                c = db.query(TABLE_BOOKMARKS_TMP,
+                             null,
+                             selection,
+                             selectionArgs,
+                             null, null, null);
+
+                // The key point here is that bookmarks should be added in
+                // parent order to avoid any problems with the foreign key
+                // in Bookmarks.PARENT.
+                while (c.moveToNext()) {
+                    ContentValues values = new ContentValues();
+
+                    // We're using a null projection in the query which
+                    // means we're getting all columns from the table.
+                    // It's safe to simply transform the row into the
+                    // values to be inserted on the new table.
+                    DatabaseUtils.cursorRowToContentValues(c, values);
+
+                    boolean isSpecialFolder = isSpecialFolder(values);
+
+                    // The mobile folder used to be created with PARENT = NULL.
+                    // We want fix that here.
+                    if (values.getAsLong(Bookmarks.PARENT) == null && isSpecialFolder)
+                        values.put(Bookmarks.PARENT, Bookmarks.FIXED_ROOT_ID);
+
+                    if (isRootFolder && !isSpecialFolder) {
+                        invalidSpecialEntries.add(values);
+                        continue;
+                    }
+
+                    debug("Migrating bookmark: " + values.getAsString(Bookmarks.TITLE));
+                    db.insert(TABLE_BOOKMARKS, Bookmarks.URL, values);
+
+                    Integer isFolder = values.getAsInteger(Bookmarks.IS_FOLDER);
+                    if (isFolder != null && isFolder == 1)
+                        subFolders.add(values.getAsInteger(Bookmarks._ID));
+                }
+            } finally {
+                if (c != null)
+                    c.close();
+            }
+
+            // At this point is safe to assume that the mobile folder is
+            // in the new table given that we've always created it on
+            // database creation time.
+            final int nInvalidSpecialEntries = invalidSpecialEntries.size();
+            if (nInvalidSpecialEntries > 0) {
+                Long mobileFolderId = guidToID(db, Bookmarks.MOBILE_FOLDER_GUID);
+
+                debug("Found " + nInvalidSpecialEntries + " invalid special folder entries");
+                for (int i = 0; i < nInvalidSpecialEntries; i++) {
+                    ContentValues values = invalidSpecialEntries.get(i);
+                    values.put(Bookmarks.PARENT, mobileFolderId);
+
+                    db.insert(TABLE_BOOKMARKS, Bookmarks.URL, values);
+                }
+            }
+
+            final int nSubFolders = subFolders.size();
+            for (int i = 0; i < nSubFolders; i++) {
+                int subFolderId = subFolders.get(i);
+                migrateBookmarkFolder(db, subFolderId);
+            }
+        }
+
+        private void upgradeDatabaseFrom1to2(SQLiteDatabase db) {
+            debug("Renaming bookmarks table to " + TABLE_BOOKMARKS_TMP);
+            db.execSQL("ALTER TABLE " + TABLE_BOOKMARKS +
+                       " RENAME TO " + TABLE_BOOKMARKS_TMP);
+
+            debug("Dropping views and indexes related to " + TABLE_BOOKMARKS);
+            db.execSQL("DROP VIEW IF EXISTS " + VIEW_BOOKMARKS_WITH_IMAGES);
+
+            db.execSQL("DROP INDEX IF EXISTS bookmarks_url_index");
+            db.execSQL("DROP INDEX IF EXISTS bookmarks_guid_index");
+            db.execSQL("DROP INDEX IF EXISTS bookmarks_modified_index");
+
+            createBookmarksTable(db);
+            createBookmarksWithImagesView(db);
+
+            createOrUpdateSpecialFolder(db, Bookmarks.PLACES_FOLDER_GUID,
+                R.string.bookmarks_folder_places, 0);
+
+            migrateBookmarkFolder(db, Bookmarks.FIXED_ROOT_ID);
+
+            // Ensure all special folders exist and have the
+            // right folder hierarchy.
+            createOrUpdateAllSpecialFolders(db);
+
+            debug("Dropping bookmarks temporary table");
+            db.execSQL("DROP TABLE IF EXISTS " + TABLE_BOOKMARKS_TMP);
         }
 
         @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
             debug("Upgrading browser.db: " + db.getPath() + " from " +
                     oldVersion + " to " + newVersion);
 
-            // Do nothing for now
+            db.beginTransaction();
+
+            // We have to do incremental upgrades until we reach the current
+            // database schema version.
+            for (int v = oldVersion + 1; v <= newVersion; v++) {
+                switch(v) {
+                    case 2:
+                        upgradeDatabaseFrom1to2(db);
+                        break;
+                 }
+             }
+
+             db.endTransaction();
         }
 
         @Override
         public void onOpen(SQLiteDatabase db) {
             debug("Opening browser.db: " + db.getPath());
 
             // From Honeycomb on, it's possible to run several db
             // commands in parallel using multiple connections.
@@ -379,16 +581,36 @@ public class BrowserProvider extends Con
                 } finally {
                     if (cursor != null)
                         cursor.close();
                 }
             }
         }
     }
 
+    private Long guidToID(SQLiteDatabase db, String guid) {
+        Cursor c = null;
+
+        try {
+            c = db.query(TABLE_BOOKMARKS,
+                         new String[] { Bookmarks._ID },
+                         Bookmarks.GUID + " = ?",
+                         new String[] { guid },
+                         null, null, null);
+
+            if (c == null || !c.moveToFirst())
+                return null;
+
+            return c.getLong(c.getColumnIndex(Bookmarks._ID));
+        } finally {
+            if (c != null)
+                c.close();
+        }
+    }
+
     private DatabaseHelper getDatabaseHelperForProfile(String profile) {
         // Each profile has a separate browser.db database. The target
         // profile is provided using a URI query argument in each request
         // to our content provider.
 
         // Always fallback to default profile if none has been provided.
         if (TextUtils.isEmpty(profile)) {
             profile = BrowserContract.DEFAULT_PROFILE;
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -2082,17 +2082,17 @@ Tab.prototype = {
         viewportH = viewportW * (screenH / screenW);
     }
 
     // Make sure the viewport height is not shorter than the window when
     // the page is zoomed out to show its full width.
     let minScale = this.getPageZoomLevel(screenW);
     viewportH = Math.max(viewportH, screenH / minScale);
 
-    let oldBrowserWidth = parseInt(this.browser.style.width);
+    let oldBrowserWidth = parseInt(this.browser.style.minWidth);
     this.setBrowserSize(viewportW, viewportH);
 
     // Avoid having the scroll position jump around after device rotation.
     let win = this.browser.contentWindow;
     this.userScrollPos.x = win.scrollX;
     this.userScrollPos.y = win.scrollY;
 
     // If the browser width changes, we change the zoom proportionally. This ensures sensible
@@ -2106,32 +2106,34 @@ Tab.prototype = {
     this.updateViewport(true, newZoom);
   },
 
   getDefaultZoomLevel: function getDefaultZoomLevel() {
     let md = this.metadata;
     if ("defaultZoom" in md && md.defaultZoom)
       return md.defaultZoom;
 
-    let browserWidth = parseInt(this.browser.style.width);
+    let browserWidth = parseInt(this.browser.style.minWidth);
     return gScreenWidth / browserWidth;
   },
 
   getPageZoomLevel: function getPageZoomLevel() {
     // This may get called during a Viewport:Change message while the document
     // has not loaded yet.
     if (!this.browser.contentDocument || !this.browser.contentDocument.body)
       return 1.0;
 
     return this._viewport.width / this.browser.contentDocument.body.clientWidth;
   },
 
   setBrowserSize: function(aWidth, aHeight) {
-    this.browser.style.width = aWidth + "px";
-    this.browser.style.height = aHeight + "px";
+    // Using min width/height so as not to conflict with the fullscreen style rule.
+    // See Bug #709813.
+    this.browser.style.minWidth = aWidth + "px";
+    this.browser.style.minHeight = aHeight + "px";
   },
 
   getRequestLoadContext: function(aRequest) {
     if (aRequest && aRequest.notificationCallbacks) {
       try {