Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Tue, 27 Dec 2011 14:02:22 -0800
changeset 105463 0cfb7c3645ee2bcac477c4382395753b7d7f49f9
parent 105461 3319e30a2c00ee32252c2d9b4527fc374f1158f7 (current diff)
parent 83415 7e28cce342a6deb1d18e6382bd76baf61ae955ae (diff)
child 105464 eaaf33ed43c0c418af4fa16ea6e08fa49a3cc909
push id1075
push uservporof@mozilla.com
push dateThu, 13 Sep 2012 10:46:49 +0000
treeherderfx-team@f39786e8364d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
Merge from mozilla-central.
accessible/src/base/nsOuterDocAccessible.cpp
accessible/src/mac/nsAccessibleWrap.h
accessible/src/mac/nsAccessibleWrap.mm
browser/base/content/browser.js
config/autoconf.mk.in
configure.in
content/base/src/nsContentUtils.cpp
content/base/src/nsDOMFileReader.cpp
content/base/src/nsGenericElement.cpp
content/base/src/nsRange.cpp
content/base/src/nsRange.h
content/base/src/nsXMLHttpRequest.cpp
content/canvas/src/CustomQS_Canvas2D.h
content/events/src/nsDOMCloseEvent.cpp
content/events/src/nsDOMCloseEvent.h
content/events/src/nsDOMCustomEvent.cpp
content/events/src/nsDOMEvent.cpp
content/events/src/nsDOMEvent.h
content/events/src/nsDOMHashChangeEvent.cpp
content/events/src/nsDOMMouseEvent.cpp
content/events/src/nsDOMPageTransitionEvent.cpp
content/events/src/nsDOMPageTransitionEvent.h
content/events/src/nsDOMPopStateEvent.cpp
content/events/src/nsDOMUIEvent.cpp
content/events/src/nsDOMUIEvent.h
content/events/src/nsEventStateManager.cpp
content/events/test/Makefile.in
content/html/content/src/nsHTMLInputElement.cpp
content/html/content/src/nsHTMLTextAreaElement.cpp
content/html/content/src/nsTextEditorState.cpp
content/media/nsBuiltinDecoderStateMachine.cpp
content/svg/content/src/nsSVGElement.cpp
content/svg/content/src/nsSVGElement.h
content/svg/content/src/nsSVGLength2.h
content/svg/content/src/nsSVGSVGElement.cpp
docshell/base/nsDSURIContentListener.cpp
docshell/base/nsDocShell.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMWindowUtils.cpp
dom/base/nsFocusManager.cpp
dom/base/nsGlobalWindowCommands.cpp
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBIndex.cpp
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IndexedDatabaseManager.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
dom/interfaces/css/nsIDOMCSS2Properties.idl
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/workers/File.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerScope.cpp
editor/composer/src/nsEditingSession.cpp
editor/libeditor/base/nsEditor.cpp
editor/libeditor/base/nsEditor.h
editor/libeditor/html/nsHTMLEditorStyle.cpp
embedding/android/Makefile.in
embedding/android/locales/jar.mn
extensions/spellcheck/hunspell/src/mozHunspell.cpp
js/jetpack/Handle.h
js/jetpack/JetpackActorCommon.cpp
js/jetpack/JetpackActorCommon.h
js/jetpack/JetpackChild.cpp
js/jetpack/JetpackChild.h
js/jetpack/JetpackParent.cpp
js/jetpack/JetpackParent.h
js/jetpack/JetpackProcessChild.cpp
js/jetpack/JetpackProcessChild.h
js/jetpack/JetpackProcessParent.cpp
js/jetpack/JetpackProcessParent.h
js/jetpack/JetpackService.cpp
js/jetpack/JetpackService.h
js/jetpack/Makefile.in
js/jetpack/PHandle.ipdl
js/jetpack/PJetpack.ipdl
js/jetpack/ipdl.mk
js/jetpack/nsIJetpack.idl
js/jetpack/nsIJetpackService.idl
js/jetpack/tests/Makefile.in
js/jetpack/tests/test_jetpack_crash.xul
js/jetpack/tests/unit/handle_tests.js
js/jetpack/tests/unit/head_jetpack.js
js/jetpack/tests/unit/impl.js
js/jetpack/tests/unit/impl_jetpack_ctypes.js
js/jetpack/tests/unit/impl_rooting.js
js/jetpack/tests/unit/test_jetpack.js
js/jetpack/tests/unit/test_jetpack_ctypes.js
js/jetpack/tests/unit/test_jetpack_sandbox.js
js/jetpack/tests/unit/test_rooting.js
js/jetpack/tests/unit/xpcshell.ini
js/src/Makefile.in
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/ion/IonBuilder.cpp
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsapi.cpp
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsexn.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsgc.h
js/src/jsgcmark.cpp
js/src/jsinfer.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsopcode.cpp
js/src/jsopcode.h
js/src/jsopcode.tbl
js/src/jsreflect.cpp
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsxdrapi.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/LoopState.cpp
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
js/src/shell/js.cpp
js/src/tests/js1_5/extensions/regress-371636.js
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
js/src/vm/StackSpace.h
js/xpconnect/public/xpc_map_end.h
js/xpconnect/src/Makefile.in
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCInlines.h
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCQuickStubs.cpp
js/xpconnect/src/XPCQuickStubs.h
js/xpconnect/src/XPCVariant.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeProto.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/qsgen.py
js/xpconnect/src/xpcprivate.h
js/xpconnect/src/xpcpublic.h
js/xpconnect/wrappers/WrapperFactory.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSRendering.cpp
layout/base/nsDisplayList.cpp
layout/base/nsDocumentViewer.cpp
layout/base/nsIPresShell.h
layout/base/nsImageLoader.cpp
layout/base/nsImageLoader.h
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
layout/base/nsRefreshDriver.cpp
layout/base/nsRefreshDriver.h
layout/base/tests/Makefile.in
layout/base/tests/test_bug445810.html
layout/build/nsLayoutModule.cpp
layout/forms/nsComboboxControlFrame.cpp
layout/generic/crashtests/crashtests.list
layout/generic/nsBulletFrame.cpp
layout/generic/nsBulletFrame.h
layout/generic/nsColumnSetFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsFrameSetFrame.cpp
layout/generic/nsSelection.cpp
layout/reftests/bugs/reftest.list
layout/reftests/selection/reftest.list
layout/reftests/svg/sizing/dynamic--inline-resize-cb-height.xhtml
layout/reftests/svg/sizing/dynamic--inline-resize-cb-width.xhtml
layout/style/Declaration.cpp
layout/style/nsCSSParser.cpp
layout/style/nsCSSProps.cpp
layout/style/nsCSSProps.h
layout/style/nsCSSRuleProcessor.h
layout/style/nsCSSValue.cpp
layout/style/nsCSSValue.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/nsStyleStructInlines.h
layout/style/test/property_database.js
layout/tables/nsCellMap.cpp
layout/tables/nsTableRowFrame.cpp
layout/tables/nsTableRowGroupFrame.cpp
layout/tools/layout-debug/src/nsLayoutDebuggingTools.cpp
layout/xul/base/src/nsListBoxBodyFrame.cpp
mobile/android/base/Makefile.in
mobile/android/base/locales/l10n.ini
mobile/android/locales/en-US/chrome/overrides/appstrings.properties
mobile/android/locales/en-US/chrome/overrides/netError.dtd
mobile/android/locales/en-US/chrome/overrides/passwordmgr.properties
mobile/android/locales/en-US/chrome/region.properties
mobile/android/locales/en-US/crashreporter/crashreporter-override.ini
mobile/android/locales/en-US/installer/setup.ini
mobile/android/locales/en-US/profile/bookmarks.inc
mobile/android/locales/en-US/searchplugins/amazondotcom.xml
mobile/android/locales/en-US/searchplugins/google.xml
mobile/android/locales/en-US/searchplugins/list.txt
mobile/android/locales/en-US/searchplugins/twitter.xml
mobile/android/locales/en-US/searchplugins/wikipedia.xml
mobile/android/locales/en-US/searchplugins/yahoo.xml
mobile/android/locales/en-US/updater/updater.ini
mobile/android/locales/generic/profile/bookmarks.json.in
mobile/xul/locales/en-US/chrome/overrides/appstrings.properties
mobile/xul/locales/en-US/chrome/overrides/netError.dtd
mobile/xul/locales/en-US/chrome/overrides/passwordmgr.properties
mobile/xul/locales/en-US/chrome/region.properties
mobile/xul/locales/en-US/installer/setup.ini
mobile/xul/locales/en-US/profile/bookmarks.inc
mobile/xul/locales/en-US/searchplugins/amazondotcom.xml
mobile/xul/locales/en-US/searchplugins/google.xml
mobile/xul/locales/en-US/searchplugins/list.txt
mobile/xul/locales/en-US/searchplugins/twitter.xml
mobile/xul/locales/en-US/searchplugins/wikipedia.xml
mobile/xul/locales/en-US/searchplugins/yahoo.xml
netwerk/base/public/nsNetUtil.h
netwerk/cache/nsCacheService.cpp
netwerk/cache/nsCacheService.h
netwerk/cache/nsDiskCacheDevice.cpp
netwerk/cache/nsDiskCacheDevice.h
netwerk/cache/nsMemoryCacheDevice.cpp
netwerk/protocol/http/nsHttpHandler.cpp
testing/xpcshell/xpcshell.ini
toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsEmbedFunctions.cpp
view/public/nsIViewManager.h
view/src/nsView.cpp
view/src/nsView.h
view/src/nsViewManager.cpp
view/src/nsViewManager.h
widget/public/nsGUIEvent.h
widget/public/nsIWidget.h
widget/src/android/nsAppShell.cpp
widget/src/android/nsAppShell.h
widget/src/android/nsWindow.cpp
widget/src/android/nsWindow.h
widget/src/cocoa/nsChildView.h
widget/src/cocoa/nsChildView.mm
widget/src/cocoa/nsCocoaWindow.h
widget/src/cocoa/nsCocoaWindow.mm
widget/src/gtk2/nsNativeThemeGTK.cpp
widget/src/gtk2/nsWindow.cpp
widget/src/gtk2/nsWindow.h
widget/src/os2/nsWindow.cpp
widget/src/os2/nsWindow.h
widget/src/qt/nsWindow.cpp
widget/src/qt/nsWindow.h
widget/src/windows/nsWindow.cpp
widget/src/windows/nsWindow.h
widget/src/windows/nsWindowGfx.cpp
widget/src/xpwidgets/PuppetWidget.cpp
widget/src/xpwidgets/PuppetWidget.h
widget/src/xpwidgets/nsBaseWidget.cpp
widget/src/xpwidgets/nsBaseWidget.h
xpcom/base/nsStackWalk.cpp
xpcom/build/nsXULAppAPI.h
xpcom/glue/pldhash.cpp
xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm.cpp
--- a/accessible/src/base/nsOuterDocAccessible.cpp
+++ b/accessible/src/base/nsOuterDocAccessible.cpp
@@ -182,17 +182,17 @@ nsOuterDocAccessible::AppendChild(nsAcce
   // We keep showing the old document for a bit after creating the new one,
   // and while building the new DOM and frame tree. That's done on purpose
   // to avoid weird flashes of default background color.
   // The old viewer will be destroyed after the new one is created.
   // For a11y, it should be safe to shut down the old document now.
   if (mChildren.Length())
     mChildren[0]->Shutdown();
 
-  if (!nsAccessible::AppendChild(aAccessible))
+  if (!nsAccessibleWrap::AppendChild(aAccessible))
     return false;
 
   NS_LOG_ACCDOCCREATE("append document to outerdoc",
                       aAccessible->GetDocumentNode())
   NS_LOG_ACCDOCCREATE_ACCADDRESS("outerdoc", this)
 
   return true;
 }
@@ -205,17 +205,17 @@ nsOuterDocAccessible::RemoveChild(nsAcce
     NS_ERROR("Wrong child to remove!");
     return false;
   }
 
   NS_LOG_ACCDOCDESTROY_FOR("remove document from outerdoc",
                            child->GetDocumentNode(), child)
   NS_LOG_ACCDOCDESTROY_ACCADDRESS("outerdoc", this)
 
-  bool wasRemoved = nsAccessible::RemoveChild(child);
+  bool wasRemoved = nsAccessibleWrap::RemoveChild(child);
 
   NS_ASSERTION(!mChildren.Length(),
                "This child document of outerdoc accessible wasn't removed!");
 
   return wasRemoved;
 }
 
 
--- a/accessible/src/mac/mozAccessible.h
+++ b/accessible/src/mac/mozAccessible.h
@@ -125,16 +125,21 @@
 - (void)didReceiveFocus;
 - (void)valueDidChange;
 
 #pragma mark -
 
 // invalidates and removes all our children from our cached array.
 - (void)invalidateChildren;
 
+/** 
+ * Append a child if they are already cached.
+ */
+- (void)appendChild:(nsAccessible*)aAccessible;
+
 // invalidates the cached parent, used by invalidateChildren.
 - (void)invalidateParent;
 
 // makes ourselves "expired". after this point, we might be around if someone
 // has retained us (e.g., a third-party), but we really contain no information.
 - (void)expire;
 - (BOOL)isExpired;
 
--- a/accessible/src/mac/mozAccessible.mm
+++ b/accessible/src/mac/mozAccessible.mm
@@ -610,16 +610,27 @@ GetNativeFromGeckoAccessible(nsIAccessib
 
   // make room for new children
   [mChildren release];
   mChildren = nil;
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
+- (void)appendChild:(nsAccessible*)aAccessible
+{
+  // if mChildren is nil, then we don't even need to bother
+  if (!mChildren)
+    return;
+    
+  mozAccessible *curNative = GetNativeFromGeckoAccessible(aAccessible);
+  if (curNative)
+    [mChildren addObject:GetObjectOrRepresentedView(curNative)];
+}
+
 - (void)invalidateParent
 {
   mParent = nil;
 }
 
 - (void)expire
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
--- a/accessible/src/mac/nsAccessibleWrap.h
+++ b/accessible/src/mac/nsAccessibleWrap.h
@@ -56,44 +56,56 @@
 #include "nsAutoPtr.h"
 
 #if defined(__OBJC__)
 @class mozAccessible;
 #endif
 
 class nsAccessibleWrap : public nsAccessible
 {
-  public: // construction, destruction
-    nsAccessibleWrap(nsIContent *aContent, nsIWeakReference *aShell);
-    virtual ~nsAccessibleWrap();
+public: // construction, destruction
+  nsAccessibleWrap(nsIContent* aContent, nsIWeakReference* aShell);
+  virtual ~nsAccessibleWrap();
     
-    // get the native obj-c object (mozAccessible)
-    NS_IMETHOD GetNativeInterface (void **aOutAccessible);
-    
-    // the objective-c |Class| type that this accessible's native object
-    // should be instantied with.   used on runtime to determine the
-    // right type for this accessible's associated native object.
-    virtual Class GetNativeType ();
+  /**
+   * Get the native Obj-C object (mozAccessible).
+   */
+  NS_IMETHOD GetNativeInterface (void** aOutAccessible);
+  
+  /**
+   * The objective-c |Class| type that this accessible's native object
+   * should be instantied with.   used on runtime to determine the
+   * right type for this accessible's associated native object.
+   */
+  virtual Class GetNativeType ();
+
+  virtual void Shutdown ();
+  virtual void InvalidateChildren();
 
-    virtual void Shutdown ();
-    virtual void InvalidateChildren();
+  virtual bool AppendChild(nsAccessible* aAccessible);
+  virtual bool RemoveChild(nsAccessible* aAccessible);
 
-    virtual nsresult HandleAccEvent(AccEvent* aEvent);
+  virtual nsresult HandleAccEvent(AccEvent* aEvent);
 
-    // ignored means that the accessible might still have children, but is not displayed
-    // to the user. it also has no native accessible object represented for it.
-    bool IsIgnored();
-    
-    bool HasPopup () {
-      return (NativeState() & mozilla::a11y::states::HASPOPUP);
-    }
-    
-    // return this accessible's all children, adhering to "flat" accessibles by not returning their children.
-    void GetUnignoredChildren(nsTArray<nsRefPtr<nsAccessibleWrap> > &aChildrenArray);
-    virtual already_AddRefed<nsIAccessible> GetUnignoredParent();
+  /**
+   * Ignored means that the accessible might still have children, but is not
+   * displayed to the user. it also has no native accessible object represented
+   * for it.
+   */
+  bool IsIgnored();
+  
+  inline bool HasPopup () 
+    { return (NativeState() & mozilla::a11y::states::HASPOPUP); }
+  
+  /**
+   * Returns this accessible's all children, adhering to "flat" accessibles by 
+   * not returning their children.
+   */
+  void GetUnignoredChildren(nsTArray<nsRefPtr<nsAccessibleWrap> >& aChildrenArray);
+  virtual already_AddRefed<nsIAccessible> GetUnignoredParent();
     
 protected:
 
   virtual nsresult FirePlatformEvent(AccEvent* aEvent);
 
   /**
    * Return true if the parent doesn't have children to expose to AT.
    */
@@ -107,17 +119,18 @@ protected:
 #else
   id GetNativeObject();
 #endif
 
 private:
 
   /**
    * Our native object. Private because its creation is done lazily.
-   * Don't access it directly. Ever. Unless you are GetNativeObject() or Shutdown()
+   * Don't access it directly. Ever. Unless you are GetNativeObject() or 
+   * Shutdown()
    */
 #if defined(__OBJC__)
   // if we are in Objective-C, we use the actual Obj-C class.
   mozAccessible* mNativeObject;
 #else
   id mNativeObject;
 #endif
 
--- a/accessible/src/mac/nsAccessibleWrap.mm
+++ b/accessible/src/mac/nsAccessibleWrap.mm
@@ -203,16 +203,38 @@ nsAccessibleWrap::InvalidateChildren()
 
   [GetNativeObject() invalidateChildren];
 
   nsAccessible::InvalidateChildren();
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
+bool
+nsAccessibleWrap::AppendChild(nsAccessible *aAccessible)
+{
+  bool appended = nsAccessible::AppendChild(aAccessible);
+  
+  if (appended && mNativeObject)
+    [mNativeObject appendChild:aAccessible];
+
+  return appended;
+}
+
+bool
+nsAccessibleWrap::RemoveChild(nsAccessible *aAccessible)
+{
+  bool removed = nsAccessible::RemoveChild(aAccessible);
+
+  if (removed && mNativeObject)
+    [mNativeObject invalidateChildren];
+
+  return removed;
+}
+
 // if we for some reason have no native accessible, we should be skipped over (and traversed)
 // when fetching all unignored children, etc.  when counting unignored children, we will not be counted.
 bool 
 nsAccessibleWrap::IsIgnored() 
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
   
   mozAccessible* nativeObject = GetNativeObject();
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -385,8 +385,11 @@ pref("security.fileuri.strict_origin_pol
 // Temporarily force-enable GL compositing.  This is default-disabled
 // deep within the bowels of the widgetry system.  Remove me when GL
 // compositing isn't default disabled in widget/src/android.
 pref("layers.acceleration.force-enabled", true);
 
 // screen.enabled and screen.brightness properties.
 pref("dom.screenEnabledProperty.enabled", true);
 pref("dom.screenBrightnessProperty.enabled", true);
+
+// Ignore X-Frame-Options headers.
+pref("b2g.ignoreXFrameOptions", true);
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -71,17 +71,19 @@ function startupHttpd(baseDir, port) {
   server.registerContentType('appcache', 'text/cache-manifest');
   server.start(port);
 }
 
 // FIXME Bug 707625
 // until we have a proper security model, add some rights to
 // the pre-installed web applications 
 function addPermissions(urls) {
-  let permissions = ['indexedDB', 'webapps-manage', 'offline-app'];
+  let permissions = [
+    'indexedDB', 'indexedDB-unlimited', 'webapps-manage', 'offline-app'
+  ];
   urls.forEach(function(url) {
     let uri = Services.io.newURI(url, null, null);
     let allow = Ci.nsIPermissionManager.ALLOW_ACTION;
     
     permissions.forEach(function(permission) {
       Services.perms.add(uri, permission, allow);
     });
   });
@@ -305,17 +307,19 @@ var shell = {
   });
 })();
 
 
 function MozKeyboard() {
 }
 
 MozKeyboard.prototype = {
-  sendKey: function mozKeyboardSendKey(keyCode) {
+  sendKey: function mozKeyboardSendKey(keyCode, charCode) {
+    charCode = (charCode == undefined) ? keyCode : charCode;
+
     var utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
                       .getInterface(Ci.nsIDOMWindowUtils);
     ['keydown', 'keypress', 'keyup'].forEach(function sendKeyEvents(type) {
-      utils.sendKeyEvent(type, keyCode, keyCode, null);
+      utils.sendKeyEvent(type, keyCode, charCode, null);
     });
   }
 };
 
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1321712096000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1324588296000">
   <emItems>
       <emItem  blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i8" id="{B13721C7-F507-4982-B2E5-502A71474FED}">
                         <versionRange  minVersion=" " severity="1">
                     </versionRange>
@@ -65,23 +65,37 @@
                               <versionRange  minVersion="3.0a1" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
       <emItem  blockID="i40" id="{28387537-e3f9-4ed7-860c-11e69af4a8a0}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i46" id="{841468a1-d7f4-4bd3-84e6-bb0f13a06c64}">
+                        <versionRange  minVersion="0.1" maxVersion="*">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="9.0a1" maxVersion="9.0" />
+                          </targetApplication>
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i23" id="firefox@bandoo.com">
                         <versionRange  minVersion="5.0" maxVersion="5.0" severity="1">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.7a1pre" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i11" id="yslow@yahoo-inc.com">
+                        <versionRange  minVersion="2.0.5" maxVersion="2.0.5">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="3.5.7" maxVersion="*" />
+                          </targetApplication>
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i22" id="ShopperReports@ShopperReports.com">
                         <versionRange  minVersion="3.1.22.0" maxVersion="3.1.22.0">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i2" id="fdm_ffext@freedownloadmanager.org">
                         <versionRange  minVersion="1.0" maxVersion="1.3.1">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.0a1" maxVersion="*" />
@@ -101,23 +115,18 @@
       <emItem  blockID="i12" id="masterfiler@gmail.com">
                         <versionRange  severity="3">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i20" id="{AB2CE124-6272-4b12-94A9-7303C7397BD1}">
                         <versionRange  minVersion="0.1" maxVersion="5.2.0.7164" severity="1">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i11" id="yslow@yahoo-inc.com">
-                        <versionRange  minVersion="2.0.5" maxVersion="2.0.5">
-                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
-                              <versionRange  minVersion="3.5.7" maxVersion="*" />
-                          </targetApplication>
-                    </versionRange>
-                  </emItem>
+      <emItem  blockID="i47" id="youtube@youtube2.com">
+                        </emItem>
       <emItem  blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}">
                         <versionRange  minVersion="2.2" maxVersion="2.2">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i45" id="{22119944-ED35-4ab1-910B-E619EA06A115}">
                         <versionRange  minVersion="0.1" maxVersion="7.6.1">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="8.0a1" maxVersion="*" />
--- a/browser/app/profile/extensions/testpilot@labs.mozilla.com/content/browser.css
+++ b/browser/app/profile/extensions/testpilot@labs.mozilla.com/content/browser.css
@@ -30,26 +30,30 @@
   -moz-window-shadow: none;
   background-color: transparent;
   margin-top: -6px;
   margin-right: -3px;
   width: 480px;
 }
 
 .tail-up {
- -moz-border-image: url(chrome://testpilot-os/skin/notification-tail-up.png) 26 56 22 18 / 26px 56px 22px 18px round stretch;
+ border-width: 26px 56px 22px 18px;
+ border-style: solid;
+ -moz-border-image: url(chrome://testpilot-os/skin/notification-tail-up.png) 26 56 22 18 fill round stretch;
 }
 
 /* tail-down uses the old styling; it doesn't look as good as the new styling,
    but the new styling doesn't work on 3.6.
    TODO: If someone is using 3.7.* or 4.* but is NOT on the beta channel and
    installed Test Pilot from AMO, they should get the new styling, similar
    to .tail-up! */
 .tail-down {
- -moz-border-image: url(chrome://testpilot/skin/notification-tail-down.png) 26 50 22 18 / 26px 50px 22px 18px repeat;
+ border-width: 26px 50px 22px 18px;
+ border-style: solid;
+ -moz-border-image: url(chrome://testpilot/skin/notification-tail-down.png) 26 50 22 18 fill repeat;
  color: white;
 }
 
 .pilot-notification-popup-container {
   -moz-appearance: none;
   margin-right: -42px;
   padding: 0px 5px 5px 5px;
   font-size: 14px;
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -111,16 +111,17 @@
     </command>
     <command id="Browser:ReloadSkipCache" oncommand="BrowserReloadSkipCache()" disabled="true">
       <observes element="Browser:Reload" attribute="disabled"/>
     </command>
     <command id="Browser:NextTab" oncommand="gBrowser.tabContainer.advanceSelectedTab(1, true);"/>
     <command id="Browser:PrevTab" oncommand="gBrowser.tabContainer.advanceSelectedTab(-1, true);"/>
     <command id="Browser:ShowAllTabs" oncommand="allTabs.open();"/>
     <command id="Browser:ToggleTabView" oncommand="TabView.toggle();"/>
+    <command id="Browser:FocusNextFrame" oncommand="focusNextFrame(event);"/>
     <command id="cmd_fullZoomReduce"  oncommand="FullZoom.reduce()"/>
     <command id="cmd_fullZoomEnlarge" oncommand="FullZoom.enlarge()"/>
     <command id="cmd_fullZoomReset"   oncommand="FullZoom.reset()"/>
     <command id="cmd_fullZoomToggle"  oncommand="ZoomManager.toggleZoom();"/>
     <command id="Browser:OpenLocation" oncommand="openLocation();"/>
 
     <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
     <command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
@@ -299,16 +300,17 @@
     <key id="goBackKb2" key="&goBackCmd.commandKey;" command="Browser:Back" modifiers="accel"/>
     <key id="goForwardKb2" key="&goForwardCmd.commandKey;" command="Browser:Forward" modifiers="accel"/>
 #endif
     <key id="goHome" keycode="VK_HOME" command="Browser:Home" modifiers="alt"/>
     <key keycode="VK_F5" command="Browser:Reload"/>
 #ifndef XP_MACOSX
     <key id="showAllHistoryKb" key="&showAllHistoryCmd.commandkey;" command="Browser:ShowAllHistory" modifiers="accel,shift"/>
     <key keycode="VK_F5" command="Browser:ReloadSkipCache" modifiers="accel"/>
+    <key keycode="VK_F6" command="Browser:FocusNextFrame"/>
     <key id="key_fullScreen" keycode="VK_F11" command="View:FullScreen"/>
 #else
     <key id="key_fullScreen" key="&fullScreenCmd.macCommandKey;" command="View:FullScreen" modifiers="accel,shift"/>
     <key keycode="VK_F11" command="View:FullScreen"/>
 #endif
     <key key="&reloadCmd.commandkey;" command="Browser:Reload" modifiers="accel" id="key_reload"/>
     <key key="&reloadCmd.commandkey;" command="Browser:ReloadSkipCache" modifiers="accel,shift"/>
     <key id="key_viewSource" key="&pageSourceCmd.commandkey;" command="View:PageSource" modifiers="accel"/>
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -9014,8 +9014,15 @@ XPCOMUtils.defineLazyGetter(window, "gSh
   let sysInfo = Components.classes["@mozilla.org/system-info;1"]
                           .getService(Components.interfaces.nsIPropertyBag2);
   return parseFloat(sysInfo.getProperty("version")) < 6;
 #else
   return false;
 #endif
 });
 
+function focusNextFrame(event) {
+  let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
+  let dir = event.shiftKey ? fm.MOVEFOCUS_BACKWARDDOC : fm.MOVEFOCUS_FORWARDDOC;
+  let element = fm.moveFocus(window, null, dir, fm.FLAG_BYKEY);
+  if (element.ownerDocument == document)
+    focusAndSelectUrlBar();
+}
--- a/browser/base/content/test/browser_save_video.js
+++ b/browser/base/content/test/browser_save_video.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 var MockFilePicker = SpecialPowers.MockFilePicker;
-MockFilePicker.reset();
+MockFilePicker.init();
 
 /**
  * TestCase for bug 564387
  * <https://bugzilla.mozilla.org/show_bug.cgi?id=564387>
  */
 function test() {
   waitForExplicitFinish();
   var fileName;
@@ -49,17 +49,17 @@ function test() {
       MockFilePicker.filterIndex = 1; // kSaveAsType_URL
     };
 
     mockTransferCallback = onTransferComplete;
     mockTransferRegisterer.register();
 
     registerCleanupFunction(function () {
       mockTransferRegisterer.unregister();
-      MockFilePicker.reset();
+      MockFilePicker.cleanup();
       destDir.remove(true);
     });
 
     // Select "Save Video As" option from context menu
     var saveVideoCommand = document.getElementById("context-savevideo");
     saveVideoCommand.doCommand();
 
     event.target.hidePopup();
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -9,17 +9,16 @@
 ;
 
 #filter substitution
 
 #ifdef XP_MACOSX
 ; Mac bundle stuff
 @APPNAME@/Contents/Info.plist
 @APPNAME@/Contents/PkgInfo
-@APPNAME@/Contents/Plug-Ins/
 @APPNAME@/Contents/Resources/
 #endif
 
 [@AB_CD@]
 @BINPATH@/chrome/@AB_CD@@JAREXT@
 @BINPATH@/chrome/@AB_CD@.manifest
 @BINPATH@/@PREF_DIR@/firefox-l10n.js
 @BINPATH@/searchplugins/*
@@ -152,17 +151,16 @@
 @BINPATH@/components/dom_indexeddb.xpt
 @BINPATH@/components/dom_offline.xpt
 @BINPATH@/components/dom_json.xpt
 @BINPATH@/components/dom_range.xpt
 @BINPATH@/components/dom_sidebar.xpt
 @BINPATH@/components/dom_sms.xpt
 @BINPATH@/components/dom_storage.xpt
 @BINPATH@/components/dom_stylesheets.xpt
-@BINPATH@/components/dom_threads.xpt
 @BINPATH@/components/dom_traversal.xpt
 @BINPATH@/components/dom_xbl.xpt
 @BINPATH@/components/dom_xpath.xpt
 @BINPATH@/components/dom_xul.xpt
 @BINPATH@/components/dom_loadsave.xpt
 @BINPATH@/components/downloads.xpt
 @BINPATH@/components/editor.xpt
 @BINPATH@/components/embed_base.xpt
@@ -178,17 +176,16 @@
 @BINPATH@/components/fuel.xpt
 @BINPATH@/components/gfx.xpt
 @BINPATH@/components/htmlparser.xpt
 @BINPATH@/components/imglib2.xpt
 @BINPATH@/components/imgicon.xpt
 @BINPATH@/components/inspector.xpt
 @BINPATH@/components/intl.xpt
 @BINPATH@/components/jar.xpt
-@BINPATH@/components/jetpack.xpt
 @BINPATH@/components/jsdservice.xpt
 @BINPATH@/components/jsdebugger.xpt
 @BINPATH@/components/layout_base.xpt
 @BINPATH@/components/layout_forms.xpt
 #ifdef NS_PRINTING
 @BINPATH@/components/layout_printing.xpt
 #endif
 @BINPATH@/components/layout_xul_tree.xpt
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -1234,17 +1234,19 @@ toolbar[iconsize="small"] #feed-button {
 
 /* Notification icon box */
 #notification-popup-box {
   position: relative;
   background-color: #fff;
   background-clip: padding-box;
   padding-left: 4px;
   border-radius: 2.5px 0 0 2.5px;
-  -moz-border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 / 0 8px 0 0;
+  border-width: 0 8px 0 0;
+  border-style: solid;
+  -moz-border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 fill;
   -moz-margin-end: -8px;
   margin-top: -1px;
   margin-bottom: -1px;
 }
 
 #notification-popup-box:not([hidden]) + #identity-box {
   -moz-padding-start: 10px;
   border-radius: 0;
@@ -1493,17 +1495,19 @@ richlistitem[type~="action"][actiontype=
   background: -moz-linear-gradient(hsla(0,0%,100%,.2), hsla(0,0%,45%,.2) 2px, hsla(0,0%,32%,.2) 80%);
   background-origin: border-box;
   background-position: 1px 2px;
   background-size: 100% -moz-calc(100% - 2px);
   background-repeat: no-repeat;
   color: inherit;
   margin: 0;
   padding: 0;
-  -moz-border-image: url(tabbrowser/tab.png) 4 5 3 6 / 4px 5px 3px 6px repeat stretch;
+  border-width: 4px 5px 3px 6px;
+  border-style: solid;
+  -moz-border-image: url(tabbrowser/tab.png) 4 5 3 6 fill repeat stretch;
   border-radius: 10px 8px 0 0;
   min-height: 25px; /* reserve space for the sometimes hidden close button */
 }
 
 .tabbrowser-tab:hover,
 .tabs-newtab-button:hover {
   background-image: -moz-linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.2) 4px, hsla(0,0%,75%,.2) 80%);
 }
@@ -1665,22 +1669,26 @@ richlistitem[type~="action"][actiontype=
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down[notifybgtab] {
   box-shadow: 0 0 5px 5px Highlight inset;
   -moz-transition: none;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]):-moz-locale-dir(ltr),
 .tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]):-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/tabbrowser/tab-overflow-border.png") 0 2 0 2 / 0 2px 0 0;
+  border-width: 0 2px 0 0;
+  border-style: solid;
+  -moz-border-image: url("chrome://browser/skin/tabbrowser/tab-overflow-border.png") 0 2 0 2 fill;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]):-moz-locale-dir(ltr),
 .tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]):-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/tabbrowser/tab-overflow-border.png") 0 2 0 2 / 0 0 0 2px;
+  border-width: 0 0 0 2px;
+  border-style: solid;
+  -moz-border-image: url("chrome://browser/skin/tabbrowser/tab-overflow-border.png") 0 2 0 2 fill;
 }
 
 #TabsToolbar .toolbarbutton-1 > .toolbarbutton-icon,
 #TabsToolbar .toolbarbutton-1 > .toolbarbutton-menu-dropmarker,
 #TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
   margin-top: -2px;
   margin-bottom: -2px;
 }
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -1851,40 +1851,40 @@ toolbarbutton.chevron > .toolbarbutton-m
 .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start:-moz-lwtheme-darktext:not([selected="true"]),
 .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle:-moz-lwtheme-darktext:not([selected="true"]),
 .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end:-moz-lwtheme-darktext:not([selected="true"]) {
   background-image: -moz-linear-gradient(hsla(0,0%,60%,.5), hsla(0,0%,45%,.5) 50%);
 }
 
 @TABSONTOP_TAB_STACK@ > .tab-content,
 @TABSONTOP_NEWTAB_BUTTON@ > .toolbarbutton-icon {
-  -moz-border-image: url(chrome://browser/skin/tabbrowser/tab-top-normal-active.png) 0 11 repeat stretch;
+  -moz-border-image: url(chrome://browser/skin/tabbrowser/tab-top-normal-active.png) 0 11 fill repeat stretch;
 }
 
 @TABSONTOP_TAB@:hover > .tab-stack > .tab-content:not([selected="true"]),
 @TABSONTOP_NEWTAB_BUTTON@:hover > .toolbarbutton-icon {
-  -moz-border-image: url(chrome://browser/skin/tabbrowser/tab-top-hover-active.png) 0 11 repeat stretch;
+  -moz-border-image: url(chrome://browser/skin/tabbrowser/tab-top-hover-active.png) 0 11 fill repeat stretch;
 }
 
 @TABSONTOP_TAB_STACK@ > .tab-content[selected="true"] {
-  -moz-border-image: url(chrome://browser/skin/tabbrowser/tab-top-selected-active.png) 0 11 repeat stretch;
+  -moz-border-image: url(chrome://browser/skin/tabbrowser/tab-top-selected-active.png) 0 11 fill repeat stretch;
 }
 
 @TABSONBOTTOM_TAB_STACK@ > .tab-content,
 @TABSONBOTTOM_NEWTAB_BUTTON@ > .toolbarbutton-icon {
-  -moz-border-image: url(chrome://browser/skin/tabbrowser/tab-bottom-normal-active.png) 0 11 repeat stretch;
+  -moz-border-image: url(chrome://browser/skin/tabbrowser/tab-bottom-normal-active.png) 0 11 fill repeat stretch;
 }
 
 @TABSONBOTTOM_TAB@:hover > .tab-stack > .tab-content:not([selected="true"]),
 @TABSONBOTTOM_NEWTAB_BUTTON@:hover > .toolbarbutton-icon {
-  -moz-border-image: url(chrome://browser/skin/tabbrowser/tab-bottom-hover-active.png) 0 11 repeat stretch;
+  -moz-border-image: url(chrome://browser/skin/tabbrowser/tab-bottom-hover-active.png) 0 11 fill repeat stretch;
 }
 
 @TABSONBOTTOM_TAB_STACK@ > .tab-content[selected="true"] {
-  -moz-border-image: url(chrome://browser/skin/tabbrowser/tab-bottom-selected-active.png) 0 11 repeat stretch;
+  -moz-border-image: url(chrome://browser/skin/tabbrowser/tab-bottom-selected-active.png) 0 11 fill repeat stretch;
 }
 
 /* preloading hack */
 #TabsToolbar::after {
   content: '';
   display: block;
   background-image:
     url(chrome://browser/skin/tabbrowser/tab-top-normal-active.png),
@@ -2085,22 +2085,26 @@ toolbarbutton.chevron > .toolbarbutton-m
 .tabbrowser-arrowscrollbox > .scrollbutton-up[disabled] > .toolbarbutton-icon,
 .tabbrowser-arrowscrollbox > .scrollbutton-down[disabled] > .toolbarbutton-icon {
   -moz-image-region: rect(0, 13px, 20px, 0) !important;
   opacity: .5;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]):-moz-locale-dir(ltr),
 .tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]):-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/tabbrowser/tab-overflow-border.png") 0 2 0 2 / 0 2px 0 0;
+  border-width: 0 2px 0 0;
+  border-style: solid;
+  -moz-border-image: url("chrome://browser/skin/tabbrowser/tab-overflow-border.png") 0 2 0 2 fill;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]):-moz-locale-dir(ltr),
 .tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]):-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/tabbrowser/tab-overflow-border.png") 0 2 0 2 / 0 0 0 2px;
+  border-width: 0 0 0 2px;
+  border-style: solid;
+  -moz-border-image: url("chrome://browser/skin/tabbrowser/tab-overflow-border.png") 0 2 0 2 fill;
 }
 
 /**
  * Tabstrip & add-on bar toolbar buttons
  */
 
 :-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1,
 :-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button,
@@ -2305,17 +2309,19 @@ toolbarbutton.chevron > .toolbarbutton-m
 }
 
 #notification-popup-box {
   position: relative;
   background-color: #fff;
   background-clip: padding-box;
   padding-left: 3px;
   border-radius: 2px 0 0 2px;
-  -moz-border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 / 0 8px 0 0;
+  border-width: 0 8px 0 0;
+  border-style: solid;
+  -moz-border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 fill;
   -moz-margin-end: -8px;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box {
   padding-left: 7px;
 }
 
 #notification-popup-box:-moz-locale-dir(rtl),
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -1814,17 +1814,19 @@ richlistitem[type~="action"][actiontype=
   background: @toolbarShadowOnTab@, @bgTabTexture@,
               -moz-linear-gradient(-moz-dialog, -moz-dialog);
   background-origin: border-box;
   background-position: 1px 2px;
   background-size: -moz-calc(100% - 2px) -moz-calc(100% - 2px);
   background-repeat: no-repeat;
   margin: 0;
   padding: 2px 0 4px;
-  -moz-border-image: url(tabbrowser/tab.png) 4 3 0 / 4px 3px 0 repeat stretch;
+  border-width: 4px 3px 0;
+  border-style: solid;
+  -moz-border-image: url(tabbrowser/tab.png) 4 3 0 fill repeat stretch;
   border-radius: 0;
 }
 
 .tabbrowser-tab:hover,
 .tabs-newtab-button:hover {
   background-image: @toolbarShadowOnTab@, @bgTabTextureHover@,
                     -moz-linear-gradient(-moz-dialog, -moz-dialog);
 }
@@ -2009,17 +2011,19 @@ richlistitem[type~="action"][actiontype=
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down[notifybgtab] {
   background-color: Highlight;
   -moz-transition: none;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]),
 .tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]) {
-  -moz-border-image: url("chrome://browser/skin/tabbrowser/tab-overflow-border.png") 0 2 0 2 / 0 2px 0 0;
+  border-width: 0 2px 0 0;
+  border-style: solid;
+  -moz-border-image: url("chrome://browser/skin/tabbrowser/tab-overflow-border.png") 0 2 0 2 fill;
 }
 
 .tabs-newtab-button > .toolbarbutton-icon {
   margin-top: -1px;
   margin-bottom: -1px;
 }
 
 .tabs-newtab-button,
@@ -2307,17 +2311,19 @@ toolbarbutton.bookmark-item[dragover="tr
 
 /* Notification icon box */
 #notification-popup-box {
   position: relative;
   background-color: #fff;
   background-clip: padding-box;
   padding-left: 3px;
   border-radius: 2.5px 0 0 2.5px;
-  -moz-border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 / 0 8px 0 0;
+  border-width: 0 8px 0 0;
+  border-style: solid;
+  -moz-border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 fill;
   -moz-margin-end: -8px;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box {
   padding-left: 5px;
 }
 
 #notification-popup-box:-moz-locale-dir(rtl),
@@ -2607,24 +2613,28 @@ panel[dimmed="true"] {
   border-top-style: solid;
   color: #333;
   text-shadow: none;
 }
 
 .statuspanel-label:-moz-locale-dir(ltr):not([mirror]),
 .statuspanel-label:-moz-locale-dir(rtl)[mirror] {
   border-right-style: solid;
+  /* disabled for triggering grayscale AA (bug 659213)
   border-top-right-radius: .3em;
+  */
   margin-right: 1em;
 }
 
 .statuspanel-label:-moz-locale-dir(rtl):not([mirror]),
 .statuspanel-label:-moz-locale-dir(ltr)[mirror] {
   border-left-style: solid;
+  /* disabled for triggering grayscale AA (bug 659213)
   border-top-left-radius: .3em;
+  */
   margin-left: 1em;
 }
 
 /* Highlighter */
 
 .highlighter-veil {
   background-color: rgba(25, 25, 25, 0.5);
 }
new file mode 100644
--- /dev/null
+++ b/build/mobile/robocop/Actions.java.in
@@ -0,0 +1,60 @@
+#filter substitution
+/* ***** 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 Firefox Mobile Test Framework.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Trevor Fairey <tnfairey@gmail.com>
+ * David Burns <dburns@mozilla.com>
+ * Joel Maher <joel.maher@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 ***** */
+
+package @ANDROID_PACKAGE_NAME@;
+import java.util.List;
+
+public interface Actions {
+  public enum SpecialKey {
+    DOWN, UP, LEFT, RIGHT, ENTER
+  }
+  /**
+   * Waits for a gecko event to be sent from the Gecko instance.
+   * 
+   * @param geckoEvent The geckoEvent JSONObject's type
+   */
+
+  void waitForGeckoEvent(String geckoEvent);
+  // Send the string kewsToSend to the application 
+  void sendKeys(String keysToSend);
+  //Send any of the above keys to the element
+  void sendSpecialKey(SpecialKey button);
+
+  void drag(int startingX, int endingX, int startingY, int endingY);
+}
new file mode 100644
--- /dev/null
+++ b/build/mobile/robocop/AndroidManifest.xml.in
@@ -0,0 +1,19 @@
+#filter substitution
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.mozilla.roboexample.test"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk android:minSdkVersion="8" />
+
+    <instrumentation
+        android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="@ANDROID_PACKAGE_NAME@" />
+
+    <application
+        android:label="@string/app_name" >
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+</manifest>
new file mode 100644
--- /dev/null
+++ b/build/mobile/robocop/Driver.java.in
@@ -0,0 +1,78 @@
+#filter substitution
+/* ***** 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 Firefox Mobile Test Framework.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Trevor Fairey <tnfairey@gmail.com>
+ * David Burns <dburns@mozilla.com>
+ * Joel Maher <joel.maher@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 ***** */
+
+package @ANDROID_PACKAGE_NAME@;
+import java.util.List;
+
+public interface Driver {
+  /**
+   * Find the first Element using the given method.
+   * 
+   * @param name The name of the element
+   * @return The first matching element on the current context
+   * @throws RoboCopException If no matching elements are found
+   */
+  Element findElement(String name);
+
+  /**
+   * Sets up scroll handling so that data is received from the extension.
+   */
+  void setupScrollHandling();
+
+  int getPageHeight();
+  int getScrollHeight();
+  int getHeight();
+  int getGeckoTop();
+  int getGeckoLeft();
+  int getGeckoWidth();
+  int getGeckoHeight();
+
+  void startFrameRecording();
+  int stopFrameRecording();
+  void dumpLog(String message);
+  void setLogFile(String filename);
+
+  void ok(boolean condition, String name, String diag);
+  void is(Object a, Object b, String name);
+  void isnot(Object a, Object b, String name);
+  void todo(boolean condition, String name, String diag);
+  void todo_is(Object a, Object b, String name);
+  void todo_isnot(Object a, Object b, String name);
+  void info(String name, String message);
+}
new file mode 100644
--- /dev/null
+++ b/build/mobile/robocop/Element.java.in
@@ -0,0 +1,49 @@
+#filter substitution
+/* ***** 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 Firefox Mobile Test Framework.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Trevor Fairey <tnfairey@gmail.com>
+ * David Burns <dburns@mozilla.com>
+ * Joel Maher <joel.maher@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 ***** */
+
+package @ANDROID_PACKAGE_NAME@;
+
+public interface Element {
+  //Click on the element
+  void click();
+  //Returns true if the element is currently displayed
+  boolean isDisplayed();
+  //Returns the text currently displayed on the element.
+  String getText();
+}
new file mode 100644
--- /dev/null
+++ b/build/mobile/robocop/FennecNativeActions.java.in
@@ -0,0 +1,197 @@
+#filter substitution
+/* ***** 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 Firefox Mobile Test Framework.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Trevor Fairey <tnfairey@gmail.com>
+ * David Burns <dburns@mozilla.com>
+ * Joel Maher <joel.maher@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 ***** */
+
+package @ANDROID_PACKAGE_NAME@;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.HashMap;
+import java.util.List;
+
+import java.lang.Class;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.InvocationHandler;
+import java.lang.Long;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.util.Log;
+import android.view.View;
+import android.view.KeyEvent;
+
+import java.util.concurrent.SynchronousQueue;
+
+import org.json.*;
+
+import com.jayway.android.robotium.solo.Solo;
+
+public class FennecNativeActions implements Actions {
+  // Map of IDs to element names.
+  private Solo solo;
+  private Instrumentation instr;
+
+  // Objects for reflexive access of fennec classes.
+  private ClassLoader classLoader;
+  private Class gel;
+  private Class ge;
+  private Class gas;
+  private Method registerGEL;
+  private Method unregisterGEL;
+  private Method sendGE;
+
+
+  // If waiting for an event.
+  private SynchronousQueue waitqueue = new SynchronousQueue<Boolean>();
+
+  public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation){
+    this.solo = robocop;
+    this.instr = instrumentation;
+    // Set up reflexive access of java classes and methods.
+    try {
+      classLoader = activity.getClassLoader();
+      gel = classLoader.loadClass("org.mozilla.gecko.GeckoEventListener");
+      ge = classLoader.loadClass("org.mozilla.gecko.GeckoEvent");
+      gas = classLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
+      Class [] parameters = new Class[2];
+      parameters[0] = String.class;
+      parameters[1] = gel;
+      registerGEL = gas.getMethod("registerGeckoEventListener", parameters);
+      unregisterGEL = gas.getMethod("unregisterGeckoEventListener", parameters);
+      parameters = new Class[1];
+      parameters[0] = ge;
+      sendGE = gas.getMethod("sendEventToGecko", parameters);
+     } catch (ClassNotFoundException e) {
+       e.printStackTrace();
+     } catch (SecurityException e) {
+       e.printStackTrace();
+     } catch (NoSuchMethodException e) {
+       e.printStackTrace();
+     } catch (IllegalArgumentException e) {
+       e.printStackTrace();
+     }
+  }
+
+  class wakeInvocationHandler implements InvocationHandler {
+    public wakeInvocationHandler(){};
+    public Object invoke(Object proxy, Method method, Object[] args) {
+      String methodName = method.getName();
+      //Depending on the method, return a completely different type.
+      if(methodName.equals("toString")) {
+        return "wakeInvocationHandler";
+      }
+      if(methodName.equals("equals")) {
+        return this == args[0];
+      }
+      if(methodName.equals("clone")) {
+        return this;
+      }
+      if(methodName.equals("hashCode")) {
+        return 314;
+      }
+      Log.i("Robocop", "Waking up on "+methodName);
+      waitqueue.offer(new Boolean(true));
+      return null;
+    }
+  }
+  
+  public void waitForGeckoEvent(String geckoEvent) {
+    Log.i("Robocop", "waiting for "+geckoEvent);
+    try {
+      Class [] interfaces = new Class[1];
+      interfaces[0] = gel;
+      Object[] finalParams = new Object[2];
+      finalParams[0] = geckoEvent;
+     
+      wakeInvocationHandler wIH = new wakeInvocationHandler();
+      Object proxy = Proxy.newProxyInstance(classLoader, interfaces, wIH);
+      finalParams[1] = proxy;
+      registerGEL.invoke(null, finalParams);
+      
+      waitqueue.take();
+      unregisterGEL.invoke(null, finalParams);
+    } catch (IllegalAccessException e) {
+      e.printStackTrace();
+    } catch (InvocationTargetException e) {
+      e.printStackTrace();
+    } catch (InterruptedException e) {
+      e.printStackTrace();
+    }
+    Log.i("Robocop", "wait ends for: "+geckoEvent);
+  }
+
+  public void sendSpecialKey(SpecialKey button) {
+    switch( button) {
+      case DOWN:
+        instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
+        break;
+      case UP:
+        instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_UP);
+        break;
+      case LEFT:
+        instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_LEFT);
+        break;
+      case RIGHT:
+        instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_RIGHT);
+        break;
+      case ENTER:
+        instr.sendCharacterSync(KeyEvent.KEYCODE_ENTER);
+        break;
+      default:
+        break;
+    }
+  }
+
+  @Override
+  public void sendKeys(String input) {
+    instr.sendStringSync(input);
+  }
+
+
+  public void drag(int startingX, int endingX, int startingY, int endingY) {
+    solo.drag(startingX, endingX, startingY, endingY, 10);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/build/mobile/robocop/FennecNativeDriver.java.in
@@ -0,0 +1,425 @@
+#filter substitution
+/* ***** 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 Firefox Mobile Test Framework.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Trevor Fairey <tnfairey@gmail.com>
+ * David Burns <dburns@mozilla.com>
+ * Joel Maher <joel.maher@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 ***** */
+
+package @ANDROID_PACKAGE_NAME@;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.HashMap;
+import java.util.List;
+
+import java.lang.Class;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.InvocationHandler;
+import java.lang.Long;
+
+import android.app.Activity;
+import android.util.Log;
+import android.view.View;
+
+import org.json.*;
+
+import com.jayway.android.robotium.solo.Solo;
+
+public class FennecNativeDriver implements Driver {
+  // Map of IDs to element names.
+  private HashMap locators = null;
+  private Activity activity;
+  private Solo solo;
+  private String logFile;
+
+  // Objects for reflexive access of fennec classes.
+  private ClassLoader classLoader;
+  private Class gel;
+  private Class ge;
+  private Class gas;
+  private Method registerGEL;
+  private Method unregisterGEL;
+  private Method sendGE;
+  private Method _startFrameRecording;
+  private Method _stopFrameRecording;
+
+
+  private LinkedList<testInfo> testList = new LinkedList<testInfo>();
+
+  public FennecNativeDriver(Activity activity, Solo robocop){
+    this.activity = activity;
+    this.solo = robocop;
+
+    // Set up table of fennec_ids.
+    locators = convertTextToTable(getFile("/mnt/sdcard/fennec_ids.txt"));
+
+    // Set up reflexive access of java classes and methods.
+    try {
+      classLoader = activity.getClassLoader();
+      gel = classLoader.loadClass("org.mozilla.gecko.GeckoEventListener");
+      ge = classLoader.loadClass("org.mozilla.gecko.GeckoEvent");
+      gas = classLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
+      Class [] parameters = new Class[2];
+      parameters[0] = String.class;
+      parameters[1] = gel;
+      registerGEL = gas.getMethod("registerGeckoEventListener", parameters);
+      unregisterGEL = gas.getMethod("unregisterGeckoEventListener", parameters);
+      parameters = new Class[1];
+      parameters[0] = ge;
+      sendGE = gas.getMethod("sendEventToGecko", parameters);
+
+      Class gfx = classLoader.loadClass("org.mozilla.gecko.gfx.PanningPerfAPI");
+      _startFrameRecording = gfx.getDeclaredMethod("startFrameTimeRecording");
+      _stopFrameRecording = gfx.getDeclaredMethod("stopFrameTimeRecording");
+     } catch (ClassNotFoundException e) {
+       e.printStackTrace();
+     } catch (SecurityException e) {
+       e.printStackTrace();
+     } catch (NoSuchMethodException e) {
+       e.printStackTrace();
+     } catch (IllegalArgumentException e) {
+       e.printStackTrace();
+     }
+  }
+
+  //Information on the location of the Gecko Frame.
+  private boolean geckoInfo = false;
+  private int geckoTop = 100;
+  private int geckoLeft = 0;
+  private int geckoHeight= 700;
+  private int geckoWidth = 1024;
+
+  private void getGeckoInfo() {
+    View geckoLayout = activity.findViewById(Integer.decode((String)locators.get("gecko_layout")));
+    if (geckoLayout != null) {
+      geckoTop = geckoLayout.getTop();
+      geckoLeft = geckoLayout.getLeft();
+      geckoWidth = geckoLayout.getWidth();
+      geckoHeight = geckoLayout.getHeight();
+      geckoInfo = true;
+    }
+  }
+
+  public int getGeckoTop() {
+    if(!geckoInfo) {
+      getGeckoInfo();
+    }
+    return geckoTop;
+  }
+
+  public int getGeckoLeft() {
+    if(!geckoInfo) {
+      getGeckoInfo();
+    }
+    return geckoLeft;
+  }
+
+  public int getGeckoHeight() {
+    if(!geckoInfo) {
+      getGeckoInfo();
+    }
+    return geckoHeight;
+  }
+  public int getGeckoWidth() {
+    if(!geckoInfo) {
+      getGeckoInfo();
+    }
+    return geckoWidth;
+  }
+
+  @Override
+  public Element findElement(String name) {
+    if (name == null)
+      throw new IllegalArgumentException("Can not findElements when passed a null");
+    if (locators.containsKey(name)){
+      return new FennecNativeElement(Integer.decode((String)locators.get(name)), activity, solo);
+    }
+    throw new RoboCopException("Element does not exist in the list");
+  }
+
+  public void startFrameRecording() {
+    try {
+      Object [] params = null;
+      _startFrameRecording.invoke(null, params);
+    } catch (IllegalAccessException e) {
+      e.printStackTrace();
+    } catch (InvocationTargetException e) {
+      e.printStackTrace();
+    }
+  }
+
+  public int stopFrameRecording() {
+    Class [] parameters = new Class[1];
+    parameters[0] = null;
+    List frames;
+
+    try {
+      Object [] params = null;
+      frames = (List)_stopFrameRecording.invoke(null, params);
+      Object [] framearray = frames.toArray();
+      Long last = new Long(0);
+      Long threshold = new Long(17);
+      int numDelays = 0;
+      for (int i=0; i < framearray.length; i++) {
+        Long val = (Long)framearray[i];
+        if ((val - last) > threshold) {
+          numDelays++;
+        }
+        last = val;
+      }
+      return numDelays;
+    } catch (IllegalAccessException e) {
+      e.printStackTrace();
+    } catch (InvocationTargetException e) {
+      e.printStackTrace();
+    }
+
+    return 0;
+  }
+
+  class scrollHandler implements InvocationHandler {
+    public scrollHandler(){};
+    public Object invoke(Object proxy, Method method, Object[] args) {
+      try{
+        //Disect the JSON object into the appropriate variables 
+        JSONObject jo = ((JSONObject)args[1]);
+        scrollHeight = jo.getInt("y");
+        height = jo.getInt("cheight");
+        //We don't want a height of 0. That means it's a bad response.
+        if( height > 0) {
+          pageHeight = jo.getInt("height");
+        }
+
+      } catch( Throwable e) {
+        Log.i("Robocop", "WARNING: ScrollReceived, but read wrong!");
+      }
+      return null;
+    }
+  }
+  public int getScrollHeight() {
+    return scrollHeight;
+  }
+  public int getPageHeight() {
+    return pageHeight;
+  }
+  public int getHeight() {
+    return height;
+  }
+
+  public int height=0;
+  public int scrollHeight=0;
+  public int pageHeight=10;
+  public void setupScrollHandling() {
+    //Setup scrollHandler to catch "robocop:scroll" events. 
+    try {
+      Class [] interfaces = new Class[1];
+      interfaces[0] = gel;
+      Object[] finalParams = new Object[2];
+      finalParams[0] = "robocop:scroll";
+      finalParams[1] = Proxy.newProxyInstance(classLoader, interfaces, new scrollHandler());
+      registerGEL.invoke(null, finalParams);
+    } catch (IllegalAccessException e) {
+      e.printStackTrace();
+    } catch (InvocationTargetException e) {
+      e.printStackTrace();
+    }
+
+  }
+
+  //Takes a filename, loads the file, 
+  //  and returns a string version of the entire file.
+  public static String getFile(String filename)
+  {
+    File file = new File(filename);
+    StringBuilder text = new StringBuilder();
+
+    try {
+      BufferedReader br = new BufferedReader(new FileReader(file));
+      String line;
+
+      while ((line = br.readLine()) != null) {
+        text.append(line);
+        text.append('\n');
+      }
+    } catch(IOException e) {
+      e.printStackTrace();
+    }
+    return text.toString();  
+  }
+
+  // Write information to a logfile and logcat
+  public void dumpLog(String message)
+  {
+    File file = new File(logFile);
+    BufferedWriter bw = null;
+
+    try {
+      bw = new BufferedWriter(new FileWriter(logFile, true));
+      bw.write(message);
+      bw.newLine();
+    } catch(IOException e) {
+      e.printStackTrace();
+    } finally {
+      try {
+        if (bw != null) {
+          bw.flush();
+          bw.close();
+        }
+      } catch (IOException ex) {
+        ex.printStackTrace();
+      }
+    }
+
+    Log.i("Robocop", message);
+  }
+
+  // Set the filename used for dumpLog.
+  public void setLogFile(String filename)
+  {
+    logFile = filename;
+  }
+
+  // Takes a string of "key=value" pairs split by \n and creates a hash table.
+  public static HashMap convertTextToTable(String data)
+  {
+    HashMap retVal = new HashMap();
+
+    String[] lines = data.split("\n");
+    for (int i = 0; i < lines.length; i++) {
+      String[] parts = lines[i].split("=");
+      retVal.put(parts[0].trim(), parts[1].trim());
+    }
+    return retVal;
+  }
+
+  class testInfo {
+    public boolean result;
+    public String name;
+    public String diag;
+    public boolean todo;
+    public testInfo(boolean r, String n, String d, boolean t) {
+      result = r;
+      name = n;
+      diag = d;
+      todo = t;
+    }
+
+  }
+
+
+  private void _logResult(testInfo test, String passString, String failString)
+  {
+    boolean isError = true;
+    String resultString = failString;
+    if(test.result || test.todo){
+      isError = false;
+    }
+    if(test.result)
+    {
+      resultString = passString;
+    }
+    String diag= test.name;
+    if(test.diag!=null) diag+= " - " + test.diag;
+
+    String message = resultString + " | " + "ROBOCOP" + " | " + diag;
+    if(isError) {
+      dumpLog(message);
+    }
+    else {
+      dumpLog(message);
+    }
+  }
+
+  public void ok(boolean condition, String name, String diag) {
+    testInfo test = new testInfo(condition, name, diag, false);
+    _logResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL");
+    testList.add(test);
+  }
+
+  public void is(Object a, Object b, String name) {
+    boolean pass = a.equals(b);
+    String diag = "got " + a.toString() + ", expected " + b.toString();
+    if(pass) {
+      diag = a.toString() + " should equal " + b.toString();
+    }
+    ok(pass, name, diag);
+  }
+  
+  public void isnot(Object a, Object b, String name) {
+    boolean pass = !a.equals(b);
+    String diag = "didn't expect " + a.toString() + ", but got it";
+    if(pass) {
+      diag = a.toString() + " should not equal " + b.toString();
+    }
+    ok(pass, name, diag);
+  }
+
+  public void todo(boolean condition, String name, String diag) {
+    testInfo test = new testInfo(condition, name, diag, true);
+    _logResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL");
+    testList.add(test);
+  }
+
+  public void todo_is(Object a, Object b, String name) {
+    boolean pass = a.equals(b);
+    String diag = "got " + a.toString() + ", expected " + b.toString();
+    if(pass) {
+      diag = a.toString() + " should equal " + b.toString();
+    }
+    todo(pass, name, diag);
+  }
+  
+  public void todo_isnot(Object a, Object b, String name) {
+    boolean pass = !a.equals(b);
+    String diag = "didn't expect " + a.toString() + ", but got it";
+    if(pass) {
+      diag = a.toString() + " should not equal " + b.toString();
+    }
+    todo(pass, name, diag);
+  }
+
+  public void info(String name, String message) {
+    testInfo test = new testInfo(true, name, message, false);
+    _logResult(test, "TEST-INFO", "INFO FAILED?");
+  }
+}
new file mode 100644
--- /dev/null
+++ b/build/mobile/robocop/FennecNativeElement.java.in
@@ -0,0 +1,149 @@
+#filter substitution
+/* ***** 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 Firefox Mobile Test Framework.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Trevor Fairey <tnfairey@gmail.com>
+ * David Burns <dburns@mozilla.com>
+ * Joel Maher <joel.maher@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 ***** */
+
+package @ANDROID_PACKAGE_NAME@;
+
+import java.util.List;
+
+import android.app.Activity;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.TextSwitcher;
+import android.app.Instrumentation;
+import android.util.Log;
+import com.jayway.android.robotium.solo.Solo;
+import java.util.concurrent.SynchronousQueue;
+
+public class FennecNativeElement implements Element {
+  private Integer id;
+  private Activity currentActivity;
+  private Solo robocop;
+
+  public FennecNativeElement(Integer id, Activity activity, Solo solo){
+    this.id = id;
+    robocop = solo;
+    currentActivity = activity;
+  }
+
+  public Integer getId() {
+    return id;
+  }
+
+  @Override
+  public void click() {
+    final SynchronousQueue syncQueue = new SynchronousQueue();
+    currentActivity = robocop.getCurrentActivity();
+    currentActivity.runOnUiThread(
+        new Runnable() {
+          public void run() {
+            View view = (View)currentActivity.findViewById(id);
+            if(view != null) {
+              view.performClick();
+            } else {
+              throw new RoboCopException("click: unable to find view "+id); 
+            }
+            syncQueue.offer(new Object());
+          }
+        });
+    try {
+      syncQueue.take();
+    } catch (InterruptedException e) {
+      e.printStackTrace();
+    }
+  }
+
+  private Object text;
+  private Activity elementActivity;
+
+  @Override
+  public String getText() {
+    elementActivity = robocop.getCurrentActivity();
+    final SynchronousQueue syncQueue = new SynchronousQueue();
+    elementActivity.runOnUiThread(
+        new Runnable() {
+          public void run() {
+            View v = elementActivity.findViewById(id);
+            if(v instanceof EditText) {
+              EditText et = (EditText)v;
+              text = et.getEditableText();
+            }else if(v instanceof TextSwitcher) {
+              TextSwitcher ts = (TextSwitcher)v;
+              ts.getNextView();
+              text = ((TextView)ts.getCurrentView()).getText();
+            }else if(v instanceof ViewGroup) {
+              ViewGroup vg = (ViewGroup)v;
+              for(int i = 0; i < vg.getChildCount(); i++) {
+                if(vg.getChildAt(i) instanceof TextView) {
+                  text = ((TextView)vg.getChildAt(i)).getText();
+                }
+              } //end of for
+            } else if(v instanceof TextView) {
+              text = ((TextView)v).getText(); 
+            } else if(v == null) {
+              throw new RoboCopException("getText: unable to find view "+id); 
+            } else {
+              throw new RoboCopException("getText: unhandled type for view "+id); 
+            }
+            syncQueue.offer(new Object());
+          } // end of run() method definition
+        } // end of anonymous Runnable object instantiation
+    );
+    try {   
+      //Wait for the UiThread code to finish running
+      syncQueue.take();
+    } catch (InterruptedException e) {
+      e.printStackTrace();
+    }
+    if(text == null) {
+      throw new RoboCopException("getText: Text is null for view "+id);
+    }
+    return text.toString();
+  }
+
+  @Override
+  public boolean isDisplayed() {
+    // TODO Auto-generated method stub
+    return false;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/build/mobile/robocop/Makefile.in
@@ -0,0 +1,136 @@
+# ***** 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 the Android sutagent for testing.
+#
+# The Initial Developer of the Original Code is
+#   Mozilla Foundation
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Clint Talbert <ctalbert@mozilla.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 *****
+
+DEPTH       = ../../..
+topsrcdir   = @top_srcdir@
+srcdir      = @srcdir@
+VPATH       = @srcdir@
+TESTPATH    = $(topsrcdir)/mobile/android/base/tests
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = robocop
+
+ROBOTIUM_PATH = $(srcdir)/robotium-solo-3.0.jar
+
+JAVAFILES = \
+  R.java \
+
+_JAVA_HARNESS = \
+  Driver.java \
+  Element.java \
+  Actions.java \
+  FennecNativeElement.java \
+  RoboCopException.java \
+  FennecNativeDriver.java \
+  FennecNativeActions.java \
+
+_JAVA_TESTS = $(patsubst $(TESTPATH)/%.in,%,$(wildcard $(TESTPATH)/*.java.in))
+
+_ROBOCOP_TOOLS = \
+  $(TESTPATH)/robocop.ini \
+  parse_ids.py \
+  $(NULL)
+
+GARBAGE += \
+  AndroidManifest.xml \
+  _JAVA_TESTS \
+  _JAVA_HARNESS \
+  classes.dex \
+  robocop.apk \
+  robocop.ap_ \
+  robocop-unsigned-unaligned.apk \
+  robocop-unaligned.apk \
+  $(NULL)
+
+DEFINES += \
+  -DANDROID_PACKAGE_NAME=$(ANDROID_PACKAGE_NAME) \
+  $(NULL)
+
+GARBAGE_DIRS += res
+
+JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar:$(ROBOTIUM_PATH)
+
+include $(topsrcdir)/config/rules.mk
+
+# Override rules.mk java flags with the android specific ones
+include $(topsrcdir)/config/android-common.mk
+
+$(_JAVA_HARNESS): % : %.in
+	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $< > $@
+
+AndroidManifest.xml: % : %.in
+	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $< > $@
+
+$(_JAVA_TESTS): % : $(TESTPATH)/%.in
+	$(NSINSTALL) -D $(DEPTH)/mobile/android/base/tests
+	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $< > $(DEPTH)/mobile/android/base/tests/$@
+
+$(_ROBOCOP_TOOLS):
+	cp $(TESTPATH)/robocop.ini robocop.ini
+	cp $(srcdir)/parse_ids.txt parse_ids.txt
+
+tools:: robocop.apk
+
+classes.dex: robocop.ap_
+classes.dex: $(_ROBOCOP_TOOLS)
+classes.dex: $(_JAVA_HARNESS)
+classes.dex: $(_JAVA_TESTS)
+classes.dex: $(TEST_FILES)
+	$(NSINSTALL) -D classes
+	$(JAVAC) $(JAVAC_FLAGS) -d classes $(JAVAFILES) $(_JAVA_HARNESS) $(addprefix $(DEPTH)/mobile/android/base/tests/,$(_JAVA_TESTS))
+	$(DX) --dex --output=$@ classes $(ROBOTIUM_PATH)
+
+robocop.ap_: AndroidManifest.xml
+	$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -I . -S res -F $@ -J ./
+
+robocop-unsigned-unaligned.apk: robocop.ap_ classes.dex
+	$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z robocop.ap_ -f classes.dex
+
+robocop-unaligned.apk: robocop-unsigned-unaligned.apk
+	cp robocop-unsigned-unaligned.apk $@
+	jarsigner -keystore ~/.android/debug.keystore -storepass android -keypass android $@ androiddebugkey
+
+robocop.apk: robocop-unaligned.apk
+	$(ZIPALIGN) -f -v 4 robocop-unaligned.apk $@
+	cp $(TESTPATH)/robocop.ini robocop.ini
+	cp $(srcdir)/parse_ids.py parse_ids.py
+
+export::
+	$(NSINSTALL) -D res
+	@(cd $(srcdir)/res && tar $(TAR_CREATE_FLAGS) - *) | (cd $(DEPTH)/build/mobile/robocop/res && tar -xf -)
+
new file mode 100644
--- /dev/null
+++ b/build/mobile/robocop/RoboCopException.java.in
@@ -0,0 +1,59 @@
+#filter substitution
+/* ***** 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 Firefox Mobile Test Framework.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Trevor Fairey <tnfairey@gmail.com>
+ * David Burns <dburns@mozilla.com>
+ * Joel Maher <joel.maher@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 ***** */
+
+package @ANDROID_PACKAGE_NAME@;
+
+public class RoboCopException extends RuntimeException {
+  
+  public RoboCopException(){
+    super();
+  }
+  
+  public RoboCopException(String message){
+    super(message);
+  }
+  
+  public RoboCopException(Throwable cause){
+    super(cause);
+  }
+  
+  public RoboCopException(String message, Throwable cause){
+    super(message, cause);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/build/mobile/robocop/parse_ids.py
@@ -0,0 +1,60 @@
+import re
+import os
+import sys
+import optparse
+
+def getFile(filename):
+  fHandle = open(filename, 'r')
+  data = fHandle.read()
+  fHandle.close()
+  return data
+  
+def findIDs(data):
+  start_function = False
+  reID = re.compile('.*public static final class id {.*')
+  reEnd = re.compile('.*}.*')
+  idlist = []
+  
+  for line in data.split('\n'):
+    if reEnd.match(line):
+      start_function = False
+      
+    if start_function:
+      id_value = line.split(' ')[-1]
+      idlist.append(id_value.split(';')[0].split('='))
+      
+    if reID.match(line):
+      start_function = True
+      
+  return idlist
+  
+  
+def printIDs(outputFile, idlist):
+  fOutput = open(outputFile, 'w')
+  for item in idlist:
+    fOutput.write("%s=%s\n" % (item[0], item[1]))
+  fOutput.close()
+
+def main(args=sys.argv[1:]):
+  parser = optparse.OptionParser()
+  parser.add_option('-o', '--output', dest='outputFile', default='',
+                    help="output file with the id=value pairs")
+  parser.add_option('-i', '--input', dest='inputFile', default='',
+                    help="filename of the input R.java file")
+  options, args = parser.parse_args(args)
+  
+  if options.inputFile == '':
+    print "Error: please provide input file: -i <filename>"
+    sys.exit(1)
+
+  if options.outputFile == '':
+    print "Error: please provide output file: -o <filename>"
+    sys.exit(1)
+
+  data = getFile(os.path.abspath(options.inputFile));
+  idlist = findIDs(data)
+  printIDs(os.path.abspath(options.outputFile), idlist)
+
+if __name__ == "__main__":
+    main()
+
new file mode 100644
--- /dev/null
+++ b/build/mobile/robocop/res/values/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">Roboexample</string>
+
+</resources>
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -174,17 +174,18 @@ VPX_NEED_OBJ_INT_EXTRACT = @VPX_NEED_OBJ
 LIBJPEG_TURBO_AS = @LIBJPEG_TURBO_AS@
 LIBJPEG_TURBO_ASFLAGS = @LIBJPEG_TURBO_ASFLAGS@
 LIBJPEG_TURBO_X86_ASM = @LIBJPEG_TURBO_X86_ASM@
 LIBJPEG_TURBO_X64_ASM = @LIBJPEG_TURBO_X64_ASM@
 NS_PRINTING = @NS_PRINTING@
 MOZ_PDF_PRINTING = @MOZ_PDF_PRINTING@
 MOZ_CRASHREPORTER = @MOZ_CRASHREPORTER@
 MOZ_HELP_VIEWER = @MOZ_HELP_VIEWER@
-MOC= @MOC@
+MOC = @MOC@
+RCC = @RCC@
 MOZ_NSS_PATCH = @MOZ_NSS_PATCH@
 MOZ_WEBGL = @MOZ_WEBGL@
 MOZ_ANGLE = @MOZ_ANGLE@
 MOZ_DIRECTX_SDK_PATH = @MOZ_DIRECTX_SDK_PATH@
 MOZ_DIRECTX_SDK_CPU_SUFFIX = @MOZ_DIRECTX_SDK_CPU_SUFFIX@
 MOZ_D3DX9_VERSION = @MOZ_D3DX9_VERSION@
 MOZ_D3DX9_CAB = @MOZ_D3DX9_CAB@
 MOZ_D3DCOMPILER_CAB = @MOZ_D3DCOMPILER_CAB@
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -368,16 +368,23 @@ ifdef DEFFILE
 OS_LDFLAGS += -DEF:$(call normalizepath,$(DEFFILE))
 EXTRA_DEPS += $(DEFFILE)
 endif
 
 ifdef MAPFILE
 OS_LDFLAGS += -MAP:$(MAPFILE)
 endif
 
+else #!GNU_CC
+
+ifdef DEFFILE
+OS_LDFLAGS += $(call normalizepath,$(DEFFILE))
+EXTRA_DEPS += $(DEFFILE)
+endif
+
 endif # !GNU_CC
 
 endif # WINNT
 
 ifeq ($(SOLARIS_SUNPRO_CXX),1)
 ifeq (86,$(findstring 86,$(OS_TEST)))
 OS_LDFLAGS += -M $(topsrcdir)/config/solaris_ia32.map
 endif # x86
@@ -442,16 +449,17 @@ ALL_TRASH = \
 	$(PROGRAM:$(BIN_SUFFIX)=.lib) $(SIMPLE_PROGRAMS:$(BIN_SUFFIX)=.lib) \
 	$(SIMPLE_PROGRAMS:$(BIN_SUFFIX)=.$(OBJ_SUFFIX)) \
 	$(wildcard gts_tmp_*) $(LIBRARY:%.a=.%.timestamp)
 ALL_TRASH_DIRS = \
 	$(GARBAGE_DIRS) /no-such-file
 
 ifdef QTDIR
 GARBAGE                 += $(MOCSRCS)
+GARBAGE                 += $(RCCSRCS)
 endif
 
 ifdef SIMPLE_PROGRAMS
 GARBAGE			+= $(SIMPLE_PROGRAMS:%=%.$(OBJ_SUFFIX))
 endif
 
 ifdef HOST_SIMPLE_PROGRAMS
 GARBAGE			+= $(HOST_SIMPLE_PROGRAMS:%=%.$(OBJ_SUFFIX))
@@ -1178,22 +1186,24 @@ host_%.$(OBJ_SUFFIX): %.mm $(GLOBAL_DEPS
 	$(REPORT_BUILD)
 	@$(MAKE_DEPS_AUTO_CC)
 	$(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(_VPATH_SRCS)
 
 # DEFINES and ACDEFINES are needed here to enable conditional compilation of Q_OBJECTs:
 # 'moc' only knows about #defines it gets on the command line (-D...), not in
 # included headers like mozilla-config.h
 moc_%.cpp: %.h $(GLOBAL_DEPS)
-	$(MOC) $(DEFINES) $(ACDEFINES) $< $(OUTOPTION)$@
+	$(ELOG) $(MOC) $(DEFINES) $(ACDEFINES) $< $(OUTOPTION)$@
 
 moc_%.cc: %.cc $(GLOBAL_DEPS)
-	$(REPORT_BUILD)
 	$(ELOG) $(MOC) $(DEFINES) $(ACDEFINES) $(_VPATH_SRCS:.cc=.h) $(OUTOPTION)$@
 
+qrc_%.cpp: %.qrc $(GLOBAL_DEPS)
+	$(ELOG) $(RCC) -name $* $< $(OUTOPTION)$@
+
 ifdef ASFILES
 # The AS_DASH_C_FLAG is needed cause not all assemblers (Solaris) accept
 # a '-c' flag.
 %.$(OBJ_SUFFIX): %.$(ASM_SUFFIX) $(GLOBAL_DEPS)
 	$(AS) $(ASOUTOPTION)$@ $(ASFLAGS) $(AS_DASH_C_FLAG) $(_VPATH_SRCS)
 endif
 
 %.$(OBJ_SUFFIX): %.S $(GLOBAL_DEPS)
--- a/configure.in
+++ b/configure.in
@@ -5032,33 +5032,41 @@ if test "$MOZ_ENABLE_QT"
 then
     MOZ_ARG_WITH_STRING(qtdir,
     [  --with-qtdir=\$dir       Specify Qt directory ],
     [ QTDIR=$withval])
 
     if test -z "$QTDIR"; then
         PKG_CHECK_MODULES(MOZ_QT, QtGui QtNetwork QtCore QtOpenGL)
         AC_CHECK_PROGS(HOST_MOC, $MOC moc, "")
+        AC_CHECK_PROGS(HOST_RCC, $RCC rcc, "")
     else
         MOZ_QT_LIBS="-L$QTDIR/lib/ -lQtGui -lQtNetwork -lQtCore -lQtXml -lQtOpenGL"
 
         MOZ_QT_CFLAGS="-DQT_SHARED"
         MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I$QTDIR/include"
         MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I$QTDIR/include/Qt"
         MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I$QTDIR/include/QtGui"
         MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I$QTDIR/include/QtCore"
         MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I$QTDIR/include/QtNetwork"
         MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I$QTDIR/include/QtXml"
         HOST_MOC="$QTDIR/bin/moc"
+        HOST_RCC="$QTDIR/bin/rcc"
     fi
     if test -z "$HOST_MOC"; then
         AC_MSG_ERROR([No acceptable moc preprocessor found. Qt SDK is not installed or --with-qt is
 incorrect])
     fi
+    if test -z "$HOST_RCC"; then
+        AC_MSG_ERROR([No acceptable rcc preprocessor found. Qt SDK is not installed or --with-qt is
+incorrect])
+    fi
+
     MOC=$HOST_MOC
+    RCC=$HOST_RCC
 
     MOZ_ENABLE_QMSYSTEM2=
     PKG_CHECK_MODULES(_QMSYSTEM2, qmsystem2,
                       MOZ_ENABLE_QMSYSTEM2=1,
                       MOZ_ENABLE_QMSYSTEM2=)
 
     if test "$MOZ_ENABLE_QMSYSTEM2"; then
       MOZ_ENABLE_QMSYSTEM2=1
@@ -5111,16 +5119,17 @@ AC_SUBST(MOZ_ENABLE_QMSYSTEM2)
 AC_SUBST(MOZ_ENABLE_QTMOBILITY)
 AC_SUBST(MOZ_ENABLE_XREMOTE)
 AC_SUBST(MOZ_GTK2_CFLAGS)
 AC_SUBST(MOZ_GTK2_LIBS)
 AC_SUBST(MOZ_QT_CFLAGS)
 AC_SUBST(MOZ_QT_LIBS)
 
 AC_SUBST(MOC)
+AC_SUBST(RCC)
 
 AC_SUBST(MOZ_DFB)
 AC_SUBST(MOZ_X11)
 
 dnl ========================================================
 dnl =
 dnl = Components & Features
 dnl =
@@ -8016,17 +8025,17 @@ fi
 AC_SUBST(GLIB_CFLAGS)
 AC_SUBST(GLIB_LIBS)
 AC_SUBST(GLIB_GMODULE_LIBS)
 
 dnl ========================================================
 dnl Graphics checks.
 dnl ========================================================
 
-if test "${OS_ARCH}" = "Darwin" -o "${OS_TARGET}" = "Android"; then
+if test "${OS_ARCH}" = "Darwin" -o "${MOZ_WIDGET_TOOLKIT}" = "android"; then
 MOZ_ENABLE_SKIA=1
 else
 MOZ_ENABLE_SKIA=
 fi
 
 MOZ_ARG_ENABLE_BOOL(skia,
 [  --enable-skia   Enable use of Skia],
 MOZ_ENABLE_SKIA=1,
new file mode 100644
--- /dev/null
+++ b/content/base/crashtests/713417-2.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+function boom()
+{
+  var f = document.getElementById("f");
+  var w = f.contentWindow;
+  var d = w.document;
+  var range = d.createRange();
+  w.getSelection().removeAllRanges();
+  w.getSelection().addRange(range);
+  var r = d.documentElement;
+  d.removeChild(r);
+  w.getSelection().collapse(r,0);
+  document.adoptNode(r);
+  f.parentNode.removeChild(f);
+}
+
+</script>
+</head>
+<body onload="boom();">
+<iframe src="data:text/html,1" id="f"></iframe>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/crashtests/713417.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+function boom()
+{
+  var f = document.getElementById("f");
+  var w = f.contentWindow;
+  var d = w.document;
+  d.designMode = 'on';
+  var r = d.documentElement;
+  d.removeChild(r);
+  document.adoptNode(r);
+  f.parentNode.removeChild(f);
+}
+
+</script>
+</head>
+<body onload="boom();">
+<iframe src="data:text/html,1" id="f"></iframe>
+</body>
+</html>
--- a/content/base/crashtests/crashtests.list
+++ b/content/base/crashtests/crashtests.list
@@ -98,8 +98,10 @@ load 679689-1.html
 load 682463.html
 load 693212.xhtml
 load 698974-1.html
 load 700090-1.html
 load 700090-2.html
 load 700512.html
 load xhr_html_nullresponse.html
 load 709384.html
+load 713417.html
+load 713417-2.html
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -4963,28 +4963,26 @@ nsContentUtils::GetASCIIOrigin(nsIURI* a
   nsCString host;
   nsresult rv = uri->GetAsciiHost(host);
 
   if (NS_SUCCEEDED(rv) && !host.IsEmpty()) {
     nsCString scheme;
     rv = uri->GetScheme(scheme);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    aOrigin = scheme + NS_LITERAL_CSTRING("://") + host;
-
-    // If needed, append the port
-    PRInt32 port;
+    PRInt32 port = -1;
     uri->GetPort(&port);
-    if (port != -1) {
-      PRInt32 defaultPort = NS_GetDefaultPort(scheme.get());
-      if (port != defaultPort) {
-        aOrigin.Append(':');
-        aOrigin.AppendInt(port);
-      }
-    }
+    if (port != -1 && port == NS_GetDefaultPort(scheme.get()))
+      port = -1;
+
+    nsCString hostPort;
+    rv = NS_GenerateHostPort(host, port, hostPort);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    aOrigin = scheme + NS_LITERAL_CSTRING("://") + hostPort;
   }
   else {
     aOrigin.AssignLiteral("null");
   }
 
   return NS_OK;
 }
 
@@ -5023,28 +5021,27 @@ nsContentUtils::GetUTFOrigin(nsIURI* aUR
   nsCString host;
   nsresult rv = uri->GetHost(host);
 
   if (NS_SUCCEEDED(rv) && !host.IsEmpty()) {
     nsCString scheme;
     rv = uri->GetScheme(scheme);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    aOrigin = NS_ConvertUTF8toUTF16(scheme + NS_LITERAL_CSTRING("://") + host);
-
-    // If needed, append the port
-    PRInt32 port;
+    PRInt32 port = -1;
     uri->GetPort(&port);
-    if (port != -1) {
-      PRInt32 defaultPort = NS_GetDefaultPort(scheme.get());
-      if (port != defaultPort) {
-        aOrigin.Append(':');
-        aOrigin.AppendInt(port);
-      }
-    }
+    if (port != -1 && port == NS_GetDefaultPort(scheme.get()))
+      port = -1;
+
+    nsCString hostPort;
+    rv = NS_GenerateHostPort(host, port, hostPort);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    aOrigin = NS_ConvertUTF8toUTF16(
+      scheme + NS_LITERAL_CSTRING("://") + hostPort);
   }
   else {
     aOrigin.AssignLiteral("null");
   }
   
   return NS_OK;
 }
 
--- a/content/base/src/nsDOMFileReader.cpp
+++ b/content/base/src/nsDOMFileReader.cpp
@@ -71,21 +71,21 @@
 #include "nsIScriptGlobalObject.h"
 #include "nsCExternalHandlerService.h"
 #include "nsIStreamConverterService.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsLayoutStatics.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsFileDataProtocolHandler.h"
 #include "mozilla/Preferences.h"
-#include "xpcprivate.h"
 #include "xpcpublic.h"
-#include "XPCQuickStubs.h"
+#include "nsIScriptSecurityManager.h"
+#include "nsDOMJSUtils.h"
+
 #include "jstypedarray.h"
-#include "nsDOMJSUtils.h"
 
 using namespace mozilla;
 
 #define LOAD_STR "load"
 #define LOADSTART_STR "loadstart"
 #define LOADEND_STR "loadend"
 
 using mozilla::dom::FileIOObject;
@@ -242,17 +242,17 @@ nsDOMFileReader::GetResult(JSContext* aC
       *aResult = OBJECT_TO_JSVAL(tmp);
     } else {
       *aResult = JSVAL_NULL;
     }
     return NS_OK;
   }
  
   nsString tmpResult = mResult;
-  if (!xpc_qsStringToJsval(aCx, tmpResult, aResult)) {
+  if (!xpc::StringToJsval(aCx, tmpResult, aResult)) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMFileReader::GetError(nsIDOMFileError** aError)
 {
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -1202,26 +1202,68 @@ nsINode::GetContextForEventHandlers(nsre
 
 /* static */
 void
 nsINode::Trace(nsINode *tmp, TraceCallback cb, void *closure)
 {
   nsContentUtils::TraceWrapper(tmp, cb, closure);
 }
 
+static bool
+IsBlackNode(nsINode* aNode)
+{
+  JSObject* o = aNode->GetWrapperPreserveColor();
+  return o && !xpc_IsGrayGCThing(o);
+}
+
+static bool
+IsXBL(nsINode* aNode)
+{
+  return aNode->IsElement() &&
+         aNode->AsElement()->IsInNamespace(kNameSpaceID_XBL);
+}
+
 /* static */
 bool
 nsINode::Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb)
 {
   nsIDocument *currentDoc = tmp->GetCurrentDoc();
   if (currentDoc &&
       nsCCUncollectableMarker::InGeneration(cb, currentDoc->GetMarkedCCGeneration())) {
     return false;
   }
 
+  if (nsCCUncollectableMarker::sGeneration) {
+    // If we're black no need to traverse.
+    if (IsBlackNode(tmp)) {
+      return false;
+    }
+
+    const PtrBits problematicFlags =
+      (NODE_IS_ANONYMOUS |
+       NODE_IS_IN_ANONYMOUS_SUBTREE |
+       NODE_IS_NATIVE_ANONYMOUS_ROOT |
+       NODE_MAY_BE_IN_BINDING_MNGR |
+       NODE_IS_INSERTION_PARENT);
+
+    if (!tmp->HasFlag(problematicFlags) && !IsXBL(tmp)) {
+      // If we're in a black document, return early.
+      if ((currentDoc && IsBlackNode(currentDoc))) {
+        return false;
+      }
+      // If we're not in anonymous content and we have a black parent,
+      // return early.
+      nsIContent* parent = tmp->GetParent();
+      if (parent && !IsXBL(parent) && IsBlackNode(parent)) {
+        NS_ABORT_IF_FALSE(parent->IndexOf(tmp) >= 0, "Parent doesn't own us?");
+        return false;
+      }
+    }
+  }
+
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNodeInfo)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(GetParent())
 
   nsSlots *slots = tmp->GetExistingSlots();
   if (slots) {
     slots->Traverse(cb);
   }
 
--- a/content/base/src/nsRange.cpp
+++ b/content/base/src/nsRange.cpp
@@ -79,16 +79,42 @@ nsresult NS_NewContentSubtreeIterator(ns
     if (!nsContentUtils::CanCallerAccess(node_)) {                                 \
       return NS_ERROR_DOM_SECURITY_ERR;                                            \
     }                                                                              \
     if (mIsDetached) {                                                             \
       return NS_ERROR_DOM_INVALID_STATE_ERR;                                       \
     }                                                                              \
   PR_END_MACRO
 
+static void InvalidateAllFrames(nsINode* aNode)
+{
+  NS_PRECONDITION(aNode, "bad arg");
+
+  nsIFrame* frame = nsnull;
+  switch (aNode->NodeType()) {
+    case nsIDOMNode::TEXT_NODE:
+    case nsIDOMNode::ELEMENT_NODE:
+    {
+      nsIContent* content = static_cast<nsIContent*>(aNode);
+      frame = content->GetPrimaryFrame();
+      break;
+    }
+    case nsIDOMNode::DOCUMENT_NODE:
+    {
+      nsIDocument* doc = static_cast<nsIDocument*>(aNode);
+      nsIPresShell* shell = doc ? doc->GetShell() : nsnull;
+      frame = shell ? shell->GetRootFrame() : nsnull;
+      break;
+    }
+  }
+  for (nsIFrame* f = frame; f; f = f->GetNextContinuation()) {
+    f->InvalidateFrameSubtree();
+  }
+}
+
 // Utility routine to detect if a content node is completely contained in a range
 // If outNodeBefore is returned true, then the node starts before the range does.
 // If outNodeAfter is returned true, then the node ends after the range does.
 // Note that both of the above might be true.
 // If neither are true, the node is contained inside of the range.
 // XXX - callers responsibility to ensure node in same doc as range! 
 
 // static
@@ -385,17 +411,17 @@ nsIRange::RegisterCommonAncestor(nsINode
 
   MarkDescendants(aNode);
 
   RangeHashTable* ranges =
     static_cast<RangeHashTable*>(aNode->GetProperty(nsGkAtoms::range));
   if (!ranges) {
     ranges = new RangeHashTable;
     ranges->Init();
-    aNode->SetProperty(nsGkAtoms::range, ranges, RangeHashTableDtor);
+    aNode->SetProperty(nsGkAtoms::range, ranges, RangeHashTableDtor, true);
   }
   ranges->PutEntry(this);
   aNode->SetCommonAncestorForRangeInSelection();
 }
 
 void
 nsIRange::UnregisterCommonAncestor(nsINode* aNode)
 {
@@ -934,16 +960,17 @@ nsINode* nsIRange::IsValidBoundary(nsINo
 }
 
 NS_IMETHODIMP
 nsRange::SetStart(nsIDOMNode* aParent, PRInt32 aOffset)
 {
   VALIDATE_ACCESS(aParent);
 
   nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
+  AutoInvalidateSelection atEndOfBlock(this);
   return SetStart(parent, aOffset);
 }
 
 /* virtual */ nsresult
 nsRange::SetStart(nsINode* aParent, PRInt32 aOffset)
 {
   nsINode* newRoot = IsValidBoundary(aParent);
   NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_RANGE_INVALID_NODE_TYPE_ERR);
@@ -995,16 +1022,17 @@ nsRange::SetStartAfter(nsIDOMNode* aSibl
   return SetStart(nParent, IndexOf(aSibling) + 1);
 }
 
 NS_IMETHODIMP
 nsRange::SetEnd(nsIDOMNode* aParent, PRInt32 aOffset)
 {
   VALIDATE_ACCESS(aParent);
 
+  AutoInvalidateSelection atEndOfBlock(this);
   nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
   return SetEnd(parent, aOffset);
 }
 
 
 /* virtual */ nsresult
 nsRange::SetEnd(nsINode* aParent, PRInt32 aOffset)
 {
@@ -1062,16 +1090,17 @@ nsRange::SetEndAfter(nsIDOMNode* aSiblin
 NS_IMETHODIMP
 nsRange::Collapse(bool aToStart)
 {
   if(mIsDetached)
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   if (!mIsPositioned)
     return NS_ERROR_NOT_INITIALIZED;
 
+  AutoInvalidateSelection atEndOfBlock(this);
   if (aToStart)
     DoSetRange(mStartParent, mStartOffset, mStartParent, mStartOffset, mRoot);
   else
     DoSetRange(mEndParent, mEndOffset, mEndParent, mEndOffset, mRoot);
 
   return NS_OK;
 }
 
@@ -1087,30 +1116,32 @@ nsRange::SelectNode(nsIDOMNode* aN)
   nsINode* newRoot = IsValidBoundary(parent);
   NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_RANGE_INVALID_NODE_TYPE_ERR);
 
   PRInt32 index = parent->IndexOf(node);
   if (index < 0) {
     return NS_ERROR_DOM_RANGE_INVALID_NODE_TYPE_ERR;
   }
 
+  AutoInvalidateSelection atEndOfBlock(this);
   DoSetRange(parent, index, parent, index + 1, newRoot);
   
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsRange::SelectNodeContents(nsIDOMNode* aN)
 {
   VALIDATE_ACCESS(aN);
 
   nsCOMPtr<nsINode> node = do_QueryInterface(aN);
   nsINode* newRoot = IsValidBoundary(node);
   NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_RANGE_INVALID_NODE_TYPE_ERR);
   
+  AutoInvalidateSelection atEndOfBlock(this);
   DoSetRange(node, 0, node, GetNodeLength(node), newRoot);
   
   return NS_OK;
 }
 
 // The Subtree Content Iterator only returns subtrees that are
 // completely within a given range. It doesn't return a CharacterData
 // node that contains either the start or end point of the range.,
@@ -2330,16 +2361,20 @@ nsRange::ToString(nsAString& aReturn)
 
 
 NS_IMETHODIMP
 nsRange::Detach()
 {
   if(mIsDetached)
     return NS_ERROR_DOM_INVALID_STATE_ERR;
 
+  if (IsInSelection()) {
+    ::InvalidateAllFrames(GetRegisteredCommonAncestor());
+  }
+
   mIsDetached = true;
 
   DoSetRange(nsnull, 0, nsnull, 0, nsnull);
   
   return NS_OK;
 }
 
 // nsIDOMNSRange interface
@@ -2586,8 +2621,43 @@ nsRange::GetUsedFontFaces(nsIDOMFontFace
     }
 
     nsLayoutUtils::GetFontFacesForFrames(frame, fontFaceList);
   }
 
   fontFaceList.forget(aResult);
   return NS_OK;
 }
+
+nsINode*
+nsRange::GetRegisteredCommonAncestor()
+{
+  NS_ASSERTION(IsInSelection(),
+               "GetRegisteredCommonAncestor only valid for range in selection");
+  nsINode* ancestor = GetNextRangeCommonAncestor(mStartParent);
+  while (ancestor) {
+    RangeHashTable* ranges =
+      static_cast<RangeHashTable*>(ancestor->GetProperty(nsGkAtoms::range));
+    if (ranges->GetEntry(this)) {
+      break;
+    }
+    ancestor = GetNextRangeCommonAncestor(ancestor->GetNodeParent());
+  }
+  NS_ASSERTION(ancestor, "can't find common ancestor for selected range");
+  return ancestor;
+}
+
+/* static */ bool nsRange::AutoInvalidateSelection::mIsNested;
+
+nsRange::AutoInvalidateSelection::~AutoInvalidateSelection()
+{
+  NS_ASSERTION(mWasInSelection == mRange->IsInSelection(),
+               "Range got unselected in AutoInvalidateSelection block");
+  if (!mCommonAncestor) {
+    return;
+  }
+  mIsNested = false;
+  ::InvalidateAllFrames(mCommonAncestor);
+  nsINode* commonAncestor = mRange->GetRegisteredCommonAncestor();
+  if (commonAncestor != mCommonAncestor) {
+    ::InvalidateAllFrames(commonAncestor);
+  }
+}
--- a/content/base/src/nsRange.h
+++ b/content/base/src/nsRange.h
@@ -160,16 +160,50 @@ public:
 protected:
   // CharacterDataChanged set aNotInsertedYet to true to disable an assertion
   // and suppress re-registering a range common ancestor node since
   // the new text node of a splitText hasn't been inserted yet.
   // CharacterDataChanged does the re-registering when needed.
   void DoSetRange(nsINode* aStartN, PRInt32 aStartOffset,
                   nsINode* aEndN, PRInt32 aEndOffset,
                   nsINode* aRoot, bool aNotInsertedYet = false);
+
+  /**
+   * For a range for which IsInSelection() is true, return the common
+   * ancestor for the range.  This method uses the selection bits and
+   * nsGkAtoms::range property on the nodes to quickly find the ancestor.
+   * That is, it's a faster version of GetCommonAncestor that only works
+   * for ranges in a Selection.  The method will assert and the behavior
+   * is undefined if called on a range where IsInSelection() is false.
+   */
+  nsINode* GetRegisteredCommonAncestor();
+
+  struct NS_STACK_CLASS AutoInvalidateSelection
+  {
+    AutoInvalidateSelection(nsRange* aRange) : mRange(aRange)
+    {
+#ifdef DEBUG
+      mWasInSelection = mRange->IsInSelection();
+#endif
+      if (!mRange->IsInSelection() || mIsNested) {
+        return;
+      }
+      mIsNested = true;
+      NS_ASSERTION(!mRange->IsDetached(), "detached range in selection");
+      mCommonAncestor = mRange->GetRegisteredCommonAncestor();
+    }
+    ~AutoInvalidateSelection();
+    nsRange* mRange;
+    nsRefPtr<nsINode> mCommonAncestor;
+#ifdef DEBUG
+    bool mWasInSelection;
+#endif
+    static bool mIsNested;
+  };
+  
 };
 
 // Make a new nsIDOMRange object
 nsresult NS_NewRange(nsIDOMRange** aInstancePtrResult);
 
 // Make a new nsIRangeUtils object
 nsresult NS_NewRangeUtils(nsIRangeUtils** aInstancePtrResult);
 
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -64,18 +64,19 @@
 #include "nsICharsetAlias.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMWindow.h"
 #include "nsIMIMEService.h"
 #include "nsCExternalHandlerService.h"
 #include "nsIVariant.h"
-#include "xpcprivate.h"
-#include "XPCQuickStubs.h"
+#include "nsVariant.h"
+#include "nsIScriptError.h"
+#include "xpcpublic.h"
 #include "nsStringStream.h"
 #include "nsIStreamConverterService.h"
 #include "nsICachingChannel.h"
 #include "nsContentUtils.h"
 #include "nsEventDispatcher.h"
 #include "nsDOMJSUtils.h"
 #include "nsCOMArray.h"
 #include "nsIScriptableUConv.h"
@@ -1031,17 +1032,17 @@ NS_IMETHODIMP nsXMLHttpRequest::GetRespo
   switch (mResponseType) {
   case XML_HTTP_RESPONSE_TYPE_DEFAULT:
   case XML_HTTP_RESPONSE_TYPE_TEXT:
   case XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT:
     {
       nsString str;
       rv = GetResponseText(str);
       if (NS_FAILED(rv)) return rv;
-      NS_ENSURE_TRUE(xpc_qsStringToJsval(aCx, str, aResult),
+      NS_ENSURE_TRUE(xpc::StringToJsval(aCx, str, aResult),
                      NS_ERROR_OUT_OF_MEMORY);
     }
     break;
 
   case XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER:
   case XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER:
     if ((mResponseType == XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER &&
          mState & XML_HTTP_REQUEST_DONE) ||
--- a/content/canvas/src/CustomQS_Canvas2D.h
+++ b/content/canvas/src/CustomQS_Canvas2D.h
@@ -102,17 +102,17 @@ Canvas2D_GetStyleHelper(JSContext *cx, J
     nsCOMPtr<nsISupports> resultInterface;
     PRInt32 resultType;
     rv = (self->*getfunc)(resultString, getter_AddRefs(resultInterface), &resultType);
     if (NS_FAILED(rv))
         return xpc_qsThrowGetterSetterFailed(cx, rv, JSVAL_TO_OBJECT(*vp), id);
 
     switch (resultType) {
     case nsIDOMCanvasRenderingContext2D::CMG_STYLE_STRING:
-        return xpc_qsStringToJsval(cx, resultString, vp);
+        return xpc::StringToJsval(cx, resultString, vp);
 
     case nsIDOMCanvasRenderingContext2D::CMG_STYLE_PATTERN:
     {
         qsObjectHelper helper(resultInterface,
                               xpc_qsGetWrapperCache(resultInterface));
         return xpc_qsXPCOMObjectToJsval(lccx, helper,
                                         &NS_GET_IID(nsIDOMCanvasPattern),
                                         &interfaces[k_nsIDOMCanvasPattern], vp);
@@ -151,21 +151,21 @@ nsIDOMCanvasRenderingContext2D_SetFillSt
 static JSBool
 nsIDOMCanvasRenderingContext2D_GetFillStyle(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     return Canvas2D_GetStyleHelper(cx, obj, id, vp, &nsIDOMCanvasRenderingContext2D::GetFillStyle_multi);
 }
 
 static bool
 CreateImageData(JSContext* cx,
-                uint32 w,
-                uint32 h,
+                uint32_t w,
+                uint32_t h,
                 nsIDOMCanvasRenderingContext2D* self,
-                int32 x,
-                int32 y,
+                int32_t x,
+                int32_t y,
                 jsval* vp)
 {
     using mozilla::CheckedInt;
 
     if (w == 0)
         w = 1;
     if (h == 0)
         h = 1;
@@ -276,21 +276,21 @@ nsIDOMCanvasRenderingContext2D_CreateIma
         return false;
 
     if (!NS_finite(width) || !NS_finite(height))
         return xpc_qsThrow(cx, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 
     if (!width || !height)
         return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
 
-    int32 wi = JS_DoubleToInt32(width);
-    int32 hi = JS_DoubleToInt32(height);
+    int32_t wi = JS_DoubleToInt32(width);
+    int32_t hi = JS_DoubleToInt32(height);
 
-    uint32 w = NS_ABS(wi);
-    uint32 h = NS_ABS(hi);
+    uint32_t w = NS_ABS(wi);
+    uint32_t h = NS_ABS(hi);
     return CreateImageData(cx, w, h, NULL, 0, 0, vp);
 }
 
 static JSBool
 nsIDOMCanvasRenderingContext2D_GetImageData(JSContext *cx, uintN argc, jsval *vp)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
 
@@ -318,24 +318,24 @@ nsIDOMCanvasRenderingContext2D_GetImageD
 
     if (!NS_finite(xd) || !NS_finite(yd) ||
         !NS_finite(width) || !NS_finite(height))
         return xpc_qsThrow(cx, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 
     if (!width || !height)
         return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
 
-    int32 x = JS_DoubleToInt32(xd);
-    int32 y = JS_DoubleToInt32(yd);
-    int32 wi = JS_DoubleToInt32(width);
-    int32 hi = JS_DoubleToInt32(height);
+    int32_t x = JS_DoubleToInt32(xd);
+    int32_t y = JS_DoubleToInt32(yd);
+    int32_t wi = JS_DoubleToInt32(width);
+    int32_t hi = JS_DoubleToInt32(height);
 
     // Handle negative width and height by flipping the rectangle over in the
     // relevant direction.
-    uint32 w, h;
+    uint32_t w, h;
     if (width < 0) {
         w = -wi;
         x -= w;
     } else {
         w = wi;
     }
     if (height < 0) {
         h = -hi;
@@ -378,32 +378,32 @@ nsIDOMCanvasRenderingContext2D_PutImageD
         !JS_ValueToNumber(cx, argv[2], &yd)) {
         return false;
     }
 
     if (!NS_finite(xd) || !NS_finite(yd)) {
         return xpc_qsThrow(cx, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     }
 
-    int32 x = JS_DoubleToInt32(xd);
-    int32 y = JS_DoubleToInt32(yd);
+    int32_t x = JS_DoubleToInt32(xd);
+    int32_t y = JS_DoubleToInt32(yd);
 
     // Grab width, height, and the dense array from the dataObject.
     js::AutoValueRooter tv(cx);
 
     uint32_t w, h;
     if (!GetImageDataDimensions(cx, dataObject, &w, &h))
         return JS_FALSE;
 
     // the optional dirty rect
     bool hasDirtyRect = false;
-    int32 dirtyX = 0,
-          dirtyY = 0,
-          dirtyWidth = w,
-          dirtyHeight = h;
+    int32_t dirtyX = 0,
+            dirtyY = 0,
+            dirtyWidth = w,
+            dirtyHeight = h;
 
     if (argc >= 7) {
         double dx, dy, dw, dh;
         if (!JS_ValueToNumber(cx, argv[3], &dx) ||
             !JS_ValueToNumber(cx, argv[4], &dy) ||
             !JS_ValueToNumber(cx, argv[5], &dw) ||
             !JS_ValueToNumber(cx, argv[6], &dh)) {
             return false;
--- a/content/events/src/nsDOMCloseEvent.cpp
+++ b/content/events/src/nsDOMCloseEvent.cpp
@@ -33,16 +33,17 @@
  * 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 "nsDOMCloseEvent.h"
 #include "nsContentUtils.h"
+#include "DictionaryHelpers.h"
 
 NS_IMPL_ADDREF_INHERITED(nsDOMCloseEvent, nsDOMEvent)
 NS_IMPL_RELEASE_INHERITED(nsDOMCloseEvent, nsDOMEvent)
 
 DOMCI_DATA(CloseEvent, nsDOMCloseEvent)
 
 NS_INTERFACE_MAP_BEGIN(nsDOMCloseEvent)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCloseEvent)
@@ -84,41 +85,24 @@ nsDOMCloseEvent::InitCloseEvent(const ns
   mWasClean = aWasClean;
   mReasonCode = aReasonCode;
   mReason = aReason;
 
   return NS_OK;
 }
 
 nsresult
-nsDOMCloseEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                              JSContext* aCx, JSObject* aObj)
+nsDOMCloseEvent::InitFromCtor(const nsAString& aType,
+                              JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsICloseEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  bool wasClean = false;
-  PRUint16 code = 0;
-  nsAutoString reason;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetWasClean(&wasClean);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCode(&code);
-    NS_ENSURE_SUCCESS(rv, rv);
-    JSBool found = JS_FALSE;
-    if (JS_HasProperty(aCx, aObj, "reason", &found) && found) {
-      rv = eventInit->GetReason(reason);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-  }
-  return InitCloseEvent(aType, bubbles, cancelable, wasClean, code, reason);
+  mozilla::dom::CloseEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitCloseEvent(aType, d.bubbles, d.cancelable, d.wasClean, d.code,
+                        d.reason);
 }
 
 nsresult
 NS_NewDOMCloseEvent(nsIDOMEvent** aInstancePtrResult,
                     nsPresContext* aPresContext,
                     nsEvent* aEvent) 
 {
   nsDOMCloseEvent* it = new nsDOMCloseEvent(aPresContext, aEvent);
--- a/content/events/src/nsDOMCloseEvent.h
+++ b/content/events/src/nsDOMCloseEvent.h
@@ -59,18 +59,17 @@ public:
                      
   NS_DECL_ISUPPORTS_INHERITED
 
   // Forward to base class
   NS_FORWARD_TO_NSDOMEVENT
 
   NS_DECL_NSIDOMCLOSEEVENT
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsICloseEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 private:
   bool mWasClean;
   PRUint16 mReasonCode;
   nsString mReason;
 };
 
 #endif // nsDOMCloseEvent_h__
--- a/content/events/src/nsDOMCustomEvent.cpp
+++ b/content/events/src/nsDOMCustomEvent.cpp
@@ -32,16 +32,17 @@
  * 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 "nsDOMCustomEvent.h"
 #include "nsContentUtils.h"
+#include "DictionaryHelpers.h"
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMCustomEvent)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMCustomEvent, nsDOMEvent)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDetail)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMCustomEvent, nsDOMEvent)
@@ -74,32 +75,23 @@ nsDOMCustomEvent::InitCustomEvent(const 
   nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mDetail = aDetail;
   return NS_OK;
 }
 
 nsresult
-nsDOMCustomEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                               JSContext* aCx, JSObject* aObj)
+nsDOMCustomEvent::InitFromCtor(const nsAString& aType,
+                               JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsICustomEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  nsCOMPtr<nsIVariant> detail;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetDetail(getter_AddRefs(detail));
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return InitCustomEvent(aType, bubbles, cancelable, detail);
+  mozilla::dom::CustomEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitCustomEvent(aType, d.bubbles, d.cancelable, d.detail);
 }
 
 nsresult
 NS_NewDOMCustomEvent(nsIDOMEvent** aInstancePtrResult,
                      nsPresContext* aPresContext,
                      nsEvent* aEvent) 
 {
   nsDOMCustomEvent* e = new nsDOMCustomEvent(aPresContext, aEvent);
--- a/content/events/src/nsDOMCustomEvent.h
+++ b/content/events/src/nsDOMCustomEvent.h
@@ -54,16 +54,15 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMCustomEvent, nsDOMEvent)
 
   NS_DECL_NSIDOMCUSTOMEVENT
 
   // Forward to base class
   NS_FORWARD_TO_NSDOMEVENT
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsICustomEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 private:
   nsCOMPtr<nsIVariant> mDetail;
 };
 
 #endif // nsDOMCustomEvent_h__
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -57,16 +57,17 @@
 #include "nsMutationEvent.h"
 #include "nsContentUtils.h"
 #include "nsIURI.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScriptError.h"
 #include "nsDOMPopStateEvent.h"
 #include "mozilla/Preferences.h"
 #include "nsJSUtils.h"
+#include "DictionaryHelpers.h"
 
 using namespace mozilla;
 
 static const char* const sEventNames[] = {
   "mousedown", "mouseup", "click", "dblclick", "mouseenter", "mouseleave", "mouseover",
   "mouseout", "MozMouseHittest", "mousemove", "contextmenu", "keydown", "keyup", "keypress",
   "focus", "blur", "load", "popstate", "beforescriptexecute",
   "afterscriptexecute", "beforeunload", "unload",
@@ -404,46 +405,32 @@ nsDOMEvent::Initialize(nsISupports* aOwn
   if (!jsstr) {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
   JS::Anchor<JSString*> deleteProtector(jsstr);
 
   nsDependentJSString type;
   NS_ENSURE_STATE(type.init(aCx, jsstr));
-  
-  nsCOMPtr<nsISupports> dict;
-  JSObject* obj = nsnull;
-  if (aArgc >= 2 && !JSVAL_IS_PRIMITIVE(aArgv[1])) {
-    obj = JSVAL_TO_OBJECT(aArgv[1]);
-    nsContentUtils::XPConnect()->WrapJS(aCx, obj,
-                                        EventInitIID(),
-                                        getter_AddRefs(dict));
-  }
-  nsresult rv = InitFromCtor(type, dict, aCx, obj);
+
+  nsresult rv = InitFromCtor(type, aCx, aArgc >= 2 ? &(aArgv[1]) : nsnull);
   NS_ENSURE_SUCCESS(rv, rv);
 
   SetTrusted(trusted);
   return NS_OK;
 }
 
 nsresult
-nsDOMEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                         JSContext* aCx, JSObject* aObj)
+nsDOMEvent::InitFromCtor(const nsAString& aType,
+                         JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsIEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return InitEvent(aType, bubbles, cancelable);
+  mozilla::dom::EventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitEvent(aType, d.bubbles, d.cancelable);
 }
 
 NS_IMETHODIMP
 nsDOMEvent::GetEventPhase(PRUint16* aEventPhase)
 {
   // Note, remember to check that this works also
   // if or when Bug 235441 is fixed.
   if (mEvent->currentTarget == mEvent->target ||
--- a/content/events/src/nsDOMEvent.h
+++ b/content/events/src/nsDOMEvent.h
@@ -222,19 +222,18 @@ public:
   NS_IMETHOD_(bool)    IsDispatchStopped();
   NS_IMETHOD_(nsEvent*)    GetInternalNSEvent();
   NS_IMETHOD    SetTrusted(bool aTrusted);
 
   // nsIJSNativeInitializer
   NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
                         PRUint32 aArgc, jsval* aArgv);
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsIEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 
   void InitPresContextData(nsPresContext* aPresContext);
 
   virtual void Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType);
   virtual bool Deserialize(const IPC::Message* aMsg, void** aIter);
 
   static PopupControlState GetEventPopupControlState(nsEvent *aEvent);
 
--- a/content/events/src/nsDOMHashChangeEvent.cpp
+++ b/content/events/src/nsDOMHashChangeEvent.cpp
@@ -29,16 +29,17 @@
  * 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 "nsDOMHashChangeEvent.h"
 #include "nsContentUtils.h"
+#include "DictionaryHelpers.h"
 
 NS_IMPL_ADDREF_INHERITED(nsDOMHashChangeEvent, nsDOMEvent)
 NS_IMPL_RELEASE_INHERITED(nsDOMHashChangeEvent, nsDOMEvent)
 
 DOMCI_DATA(HashChangeEvent, nsDOMHashChangeEvent)
 
 NS_INTERFACE_MAP_BEGIN(nsDOMHashChangeEvent)
   NS_INTERFACE_MAP_ENTRY(nsIDOMHashChangeEvent)
@@ -74,41 +75,23 @@ nsDOMHashChangeEvent::InitHashChangeEven
   NS_ENSURE_SUCCESS(rv, rv);
 
   mOldURL.Assign(aOldURL);
   mNewURL.Assign(aNewURL);
   return NS_OK;
 }
 
 nsresult
-nsDOMHashChangeEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                   JSContext* aCx, JSObject* aObj)
+nsDOMHashChangeEvent::InitFromCtor(const nsAString& aType,
+                                   JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsIHashChangeEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  nsAutoString oldURL;
-  nsAutoString newURL;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-    JSBool found = JS_FALSE;
-    if (JS_HasProperty(aCx, aObj, "oldURL", &found) && found) {
-      rv = eventInit->GetOldURL(oldURL);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-    found = JS_FALSE;
-    if (JS_HasProperty(aCx, aObj, "newURL", &found) && found) {
-      rv = eventInit->GetNewURL(newURL);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-  }
-  return InitHashChangeEvent(aType, bubbles, cancelable, oldURL, newURL);
+  mozilla::dom::HashChangeEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitHashChangeEvent(aType, d.bubbles, d.cancelable, d.oldURL, d.newURL);
 }
 
 nsresult NS_NewDOMHashChangeEvent(nsIDOMEvent** aInstancePtrResult,
                                 nsPresContext* aPresContext,
                                 nsEvent* aEvent)
 {
   nsDOMHashChangeEvent* event =
     new nsDOMHashChangeEvent(aPresContext, aEvent);
--- a/content/events/src/nsDOMHashChangeEvent.h
+++ b/content/events/src/nsDOMHashChangeEvent.h
@@ -53,17 +53,16 @@ public:
 
   virtual ~nsDOMHashChangeEvent();
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMHASHCHANGEEVENT
 
   NS_FORWARD_TO_NSDOMEVENT
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsIHashChangeEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 protected:
   nsString mOldURL;
   nsString mNewURL;
 };
 
 #endif // nsDOMHashChangeEvent_h__
--- a/content/events/src/nsDOMMouseEvent.cpp
+++ b/content/events/src/nsDOMMouseEvent.cpp
@@ -36,16 +36,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsDOMMouseEvent.h"
 #include "nsGUIEvent.h"
 #include "nsIContent.h"
 #include "nsContentUtils.h"
+#include "DictionaryHelpers.h"
 
 nsDOMMouseEvent::nsDOMMouseEvent(nsPresContext* aPresContext,
                                  nsInputEvent* aEvent)
   : nsDOMUIEvent(aPresContext, aEvent ? aEvent :
                  new nsMouseEvent(false, 0, nsnull,
                                   nsMouseEvent::eReal))
 {
   // There's no way to make this class' ctor allocate an nsMouseScrollEvent.
@@ -140,68 +141,27 @@ nsDOMMouseEvent::InitMouseEvent(const ns
     default:
        break;
   }
 
   return NS_OK;
 }   
 
 nsresult
-nsDOMMouseEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                              JSContext* aCx, JSObject* aObj)
+nsDOMMouseEvent::InitFromCtor(const nsAString& aType,
+                              JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsIMouseEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  nsCOMPtr<nsIDOMWindow> view;
-  PRInt32 detail = 0;
-  PRInt32 screenX = 0;
-  PRInt32 screenY = 0;
-  PRInt32 clientX = 0;
-  PRInt32 clientY = 0;
-  bool ctrl = false;
-  bool alt = false;
-  bool shift = false;
-  bool meta = false;
-  PRUint16 button = 0;
-  nsCOMPtr<nsIDOMEventTarget> relatedTarget;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetView(getter_AddRefs(view));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetDetail(&detail);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetScreenX(&screenX);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetScreenY(&screenY);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetClientX(&clientX);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetClientY(&clientY);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCtrlKey(&ctrl);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetShiftKey(&shift);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetAltKey(&alt);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetMetaKey(&meta);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetButton(&button);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetRelatedTarget(getter_AddRefs(relatedTarget));
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return InitMouseEvent(aType, bubbles, cancelable,
-                        view, detail, screenX, screenY, clientX, clientY, 
-                        ctrl, alt, shift, meta,
-                        button, relatedTarget);
+  mozilla::dom::MouseEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitMouseEvent(aType, d.bubbles, d.cancelable,
+                        d.view, d.detail, d.screenX, d.screenY,
+                        d.clientX, d.clientY, 
+                        d.ctrlKey, d.altKey, d.shiftKey, d.metaKey,
+                        d.button, d.relatedTarget);
 }
 
 NS_IMETHODIMP
 nsDOMMouseEvent::InitNSMouseEvent(const nsAString & aType, bool aCanBubble, bool aCancelable,
                                   nsIDOMWindow *aView, PRInt32 aDetail, PRInt32 aScreenX,
                                   PRInt32 aScreenY, PRInt32 aClientX, PRInt32 aClientY,
                                   bool aCtrlKey, bool aAltKey, bool aShiftKey,
                                   bool aMetaKey, PRUint16 aButton, nsIDOMEventTarget *aRelatedTarget,
--- a/content/events/src/nsDOMMouseEvent.h
+++ b/content/events/src/nsDOMMouseEvent.h
@@ -55,19 +55,18 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMMouseEvent Interface
   NS_DECL_NSIDOMMOUSEEVENT
 
   // Forward to base class
   NS_FORWARD_TO_NSDOMUIEVENT
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsIMouseEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 protected:
   // Specific implementation for a mouse event.
   virtual nsresult Which(PRUint32* aWhich);
 };
 
 #define NS_FORWARD_TO_NSDOMMOUSEEVENT         \
   NS_FORWARD_NSIDOMMOUSEEVENT(nsDOMMouseEvent::) \
   NS_FORWARD_TO_NSDOMUIEVENT
--- a/content/events/src/nsDOMPageTransitionEvent.cpp
+++ b/content/events/src/nsDOMPageTransitionEvent.cpp
@@ -33,16 +33,17 @@
  * 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 "nsDOMPageTransitionEvent.h"
 #include "nsContentUtils.h"
+#include "DictionaryHelpers.h"
 
 DOMCI_DATA(PageTransitionEvent, nsDOMPageTransitionEvent)
 
 NS_INTERFACE_MAP_BEGIN(nsDOMPageTransitionEvent)
   NS_INTERFACE_MAP_ENTRY(nsIDOMPageTransitionEvent)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(PageTransitionEvent)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
 
@@ -65,32 +66,23 @@ nsDOMPageTransitionEvent::InitPageTransi
   nsresult rv = nsDOMEvent::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mPersisted = aPersisted;
   return NS_OK;
 }
 
 nsresult
-nsDOMPageTransitionEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                       JSContext* aCx, JSObject* aObj)
+nsDOMPageTransitionEvent::InitFromCtor(const nsAString& aType,
+                                       JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsIPageTransitionEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  bool persisted = false;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetPersisted(&persisted);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return InitPageTransitionEvent(aType, bubbles, cancelable, persisted);
+  mozilla::dom::PageTransitionEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitPageTransitionEvent(aType, d.bubbles, d.cancelable, d.persisted);
 }
 
 nsresult NS_NewDOMPageTransitionEvent(nsIDOMEvent** aInstancePtrResult,
                                       nsPresContext* aPresContext,
                                       nsEvent *aEvent) 
 {
   nsDOMPageTransitionEvent* it =
     new nsDOMPageTransitionEvent(aPresContext, aEvent);
--- a/content/events/src/nsDOMPageTransitionEvent.h
+++ b/content/events/src/nsDOMPageTransitionEvent.h
@@ -51,16 +51,15 @@ public:
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMPAGETRANSITIONEVENT
 
   // Forward to base class
   NS_FORWARD_TO_NSDOMEVENT
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsIPageTransitionEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 protected:
   bool mPersisted;
 };
 
 #endif // nsDOMPageTransitionEvent_h__
--- a/content/events/src/nsDOMPopStateEvent.cpp
+++ b/content/events/src/nsDOMPopStateEvent.cpp
@@ -32,16 +32,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsDOMPopStateEvent.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIClassInfo.h"
 #include "nsIXPCScriptable.h"
+#include "DictionaryHelpers.h"
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMPopStateEvent)
 
 NS_IMPL_ADDREF_INHERITED(nsDOMPopStateEvent, nsDOMEvent)
 NS_IMPL_RELEASE_INHERITED(nsDOMPopStateEvent, nsDOMEvent)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMPopStateEvent, nsDOMEvent)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mState)
@@ -79,32 +80,23 @@ nsDOMPopStateEvent::InitPopStateEvent(co
   nsresult rv = nsDOMEvent::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mState = aStateArg;
   return NS_OK;
 }
 
 nsresult
-nsDOMPopStateEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                 JSContext* aCx, JSObject* aObj)
+nsDOMPopStateEvent::InitFromCtor(const nsAString& aType,
+                                 JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsIPopStateEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  nsCOMPtr<nsIVariant> state;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetState(getter_AddRefs(state));
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return InitPopStateEvent(aType, bubbles, cancelable, state);
+  mozilla::dom::PopStateEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitPopStateEvent(aType, d.bubbles, d.cancelable, d.state);
 }
 
 nsresult NS_NewDOMPopStateEvent(nsIDOMEvent** aInstancePtrResult,
                                 nsPresContext* aPresContext,
                                 nsEvent* aEvent)
 {
   nsDOMPopStateEvent* event =
     new nsDOMPopStateEvent(aPresContext, aEvent);
--- a/content/events/src/nsDOMPopStateEvent.h
+++ b/content/events/src/nsDOMPopStateEvent.h
@@ -55,16 +55,15 @@ public:
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMPopStateEvent, nsDOMEvent)
 
   NS_DECL_NSIDOMPOPSTATEEVENT
 
   NS_FORWARD_TO_NSDOMEVENT
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsIPopStateEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 protected:
   nsCOMPtr<nsIVariant> mState;
 };
 
 #endif // nsDOMPopStateEvent_h__
--- a/content/events/src/nsDOMUIEvent.cpp
+++ b/content/events/src/nsDOMUIEvent.cpp
@@ -46,16 +46,17 @@
 #include "nsIDOMWindow.h"
 #include "nsIDOMNode.h"
 #include "nsIContent.h"
 #include "nsContentUtils.h"
 #include "nsEventStateManager.h"
 #include "nsIFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsIScrollableFrame.h"
+#include "DictionaryHelpers.h"
 
 nsDOMUIEvent::nsDOMUIEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent)
   : nsDOMEvent(aPresContext, aEvent ?
                static_cast<nsEvent *>(aEvent) :
                static_cast<nsEvent *>(new nsUIEvent(false, 0, 0)))
   , mClientPoint(0, 0), mLayerPoint(0, 0), mPagePoint(0, 0)
 {
   if (aEvent) {
@@ -201,35 +202,23 @@ nsDOMUIEvent::InitUIEvent(const nsAStrin
   
   mDetail = detailArg;
   mView = viewArg;
 
   return NS_OK;
 }
 
 nsresult
-nsDOMUIEvent::InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                           JSContext* aCx, JSObject* aObj)
+nsDOMUIEvent::InitFromCtor(const nsAString& aType,
+                           JSContext* aCx, jsval* aVal)
 {
-  nsCOMPtr<nsIUIEventInit> eventInit = do_QueryInterface(aDict);
-  bool bubbles = false;
-  bool cancelable = false;
-  nsCOMPtr<nsIDOMWindow> view;
-  PRInt32 detail = 0;
-  if (eventInit) {
-    nsresult rv = eventInit->GetBubbles(&bubbles);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetCancelable(&cancelable);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetView(getter_AddRefs(view));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = eventInit->GetDetail(&detail);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return InitUIEvent(aType, bubbles, cancelable, view, detail);
+  mozilla::dom::UIEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitUIEvent(aType, d.bubbles, d.cancelable, d.view, d.detail);
 }
 
 // ---- nsDOMNSUIEvent implementation -------------------
 nsIntPoint
 nsDOMUIEvent::GetPagePoint()
 {
   if (mPrivateDataDuplicated) {
     return mPagePoint;
--- a/content/events/src/nsDOMUIEvent.h
+++ b/content/events/src/nsDOMUIEvent.h
@@ -59,19 +59,18 @@ public:
   virtual void Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType);
   virtual bool Deserialize(const IPC::Message* aMsg, void** aIter);
   
   // Forward to nsDOMEvent
   NS_FORWARD_TO_NSDOMEVENT
 
   NS_FORWARD_NSIDOMNSEVENT(nsDOMEvent::)
 
-  virtual const nsIID& EventInitIID() { return NS_GET_IID(nsIUIEventInit); }
-  virtual nsresult InitFromCtor(const nsAString& aType, nsISupports* aDict,
-                                JSContext* aCx, JSObject* aObj);
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 protected:
   // Internal helper functions
   nsIntPoint GetClientPoint();
   nsIntPoint GetScreenPoint();
   nsIntPoint GetLayerPoint();
   nsIntPoint GetPagePoint();
 
   // Allow specializations.
--- a/content/events/test/test_eventctors.html
+++ b/content/events/test/test_eventctors.html
@@ -28,16 +28,42 @@ var ex = false;
 try {
   e = new Event();
 } catch(exp) {
   ex = true;
 }
 ok(ex, "First parameter is required!");
 ex = false;
 
+try {
+  e = new Event("foo", 123);
+} catch(exp) {
+  ex = true;
+}
+ok(ex, "2nd parameter should be an object!");
+ex = false;
+
+try {
+  e = new Event("foo", "asdf");
+} catch(exp) {
+  ex = true;
+}
+ok(ex, "2nd parameter should be an object!");
+ex = false;
+
+
+try {
+  e = new Event("foo", false);
+} catch(exp) {
+  ex = true;
+}
+ok(ex, "2nd parameter should be an object!");
+ex = false;
+
+
 e = new Event("hello");
 ok(e.type, "hello", "Wrong event type!");
 ok(!e.isTrusted, "Event shouldn't be trusted!");
 ok(!e.bubbles, "Event shouldn't bubble!");
 ok(!e.cancelable, "Event shouldn't be cancelable!");
 document.dispatchEvent(e);
 is(receivedEvent, e, "Wrong event!");
 
@@ -89,21 +115,16 @@ ok(!e.bubbles, "Event shouldn't bubble!"
 ok(!e.cancelable, "Event shouldn't be cancelable!");
 
 var dict = { get detail() { return document.body } };
 e = new CustomEvent("hello", dict);
 is(e.detail, dict.detail, "Wrong event.detail!");
 ok(!e.bubbles, "Event shouldn't bubble!");
 ok(!e.cancelable, "Event shouldn't be cancelable!");
 
-e = new CustomEvent("hello", 1234);
-is(e.detail, null, "Wrong event.detail!");
-ok(!e.bubbles, "Event shouldn't bubble!");
-ok(!e.cancelable, "Event shouldn't be cancelable!");
-
 var dict = { get detail() { throw "foo"; } };
 
 try {
   e = new CustomEvent("hello", dict);
 } catch (exp) {
   ex = true;
 }
 ok(ex, "Should have thrown an exception!");
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -2620,16 +2620,22 @@ nsHTMLInputElement::GetControllers(nsICo
       NS_ENSURE_SUCCESS(rv, rv);
 
       nsCOMPtr<nsIController>
         controller(do_CreateInstance("@mozilla.org/editor/editorcontroller;1",
                                      &rv));
       NS_ENSURE_SUCCESS(rv, rv);
 
       mControllers->AppendController(controller);
+
+      controller = do_CreateInstance("@mozilla.org/editor/editingcontroller;1",
+                                     &rv);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      mControllers->AppendController(controller);
     }
   }
 
   *aResult = mControllers;
   NS_IF_ADDREF(*aResult);
 
   return NS_OK;
 }
--- a/content/html/content/src/nsHTMLTextAreaElement.cpp
+++ b/content/html/content/src/nsHTMLTextAreaElement.cpp
@@ -811,16 +811,22 @@ nsHTMLTextAreaElement::GetControllers(ns
     mControllers = do_CreateInstance(kXULControllersCID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIController> controller = do_CreateInstance("@mozilla.org/editor/editorcontroller;1", &rv);
     if (NS_FAILED(rv))
       return rv;
 
     mControllers->AppendController(controller);
+
+    controller = do_CreateInstance("@mozilla.org/editor/editingcontroller;1", &rv);
+    if (NS_FAILED(rv))
+      return rv;
+
+    mControllers->AppendController(controller);
   }
 
   *aResult = mControllers;
   NS_IF_ADDREF(*aResult);
 
   return NS_OK;
 }
 
--- a/content/html/content/test/test_bug500885.html
+++ b/content/html/content/test/test_bug500885.html
@@ -13,17 +13,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=500885">Mozilla Bug 500885</a>
 <div>
   <input id="file" type="file" />
 </div>
 <script type="text/javascript">
 
 var MockFilePicker = SpecialPowers.MockFilePicker;
-MockFilePicker.reset();
+MockFilePicker.init();
 MockFilePicker.returnValue = MockFilePicker.returnOK;
 
 function test() {
   // SpecialPowers.DOMWindowUtils doesn't appear to fire mouseEvents correctly
   var wu = SpecialPowers.getDOMWindowUtils(window);
 
   try {
     var domActivateEvents;
@@ -42,17 +42,20 @@ function test() {
     is(domActivateEvents, 1, "click on text field should fire 1 DOMActivate event");
 
     domActivateEvents = 0;
     wu.sendMouseEvent("mousedown", rect.right - 5, rect.top + 5, 0, 1, 0);
     wu.sendMouseEvent("mouseup", rect.right - 5, rect.top + 5, 0, 1, 0);
     is(domActivateEvents, 1, "click on button should fire 1 DOMActivate event");
 
   } finally {
-    SimpleTest.executeSoon(SimpleTest.finish);
+    SimpleTest.executeSoon(function() {
+      MockFilePicker.cleanup();
+      SimpleTest.finish();
+    });
   }
 }
 
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(test);
 
 </script>
 </body>
--- a/content/html/content/test/test_bug592802.html
+++ b/content/html/content/test/test_bug592802.html
@@ -21,33 +21,34 @@ https://bugzilla.mozilla.org/show_bug.cg
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 592802 **/
 
 SimpleTest.waitForExplicitFinish();
 
 var MockFilePicker = SpecialPowers.MockFilePicker;
-MockFilePicker.reset();
+MockFilePicker.init();
 
 var testData = [
 /* visibility | display | multiple */
   [ "",       "",     false ],
   [ "hidden", "",     false ],
   [ "",       "none", false ],
   [ "",       "",     true ],
   [ "hidden", "",     true ],
   [ "",       "none", true ],
 ];
 
 var testCounter = 0;
 var testNb = testData.length;
 
 function finished()
 {
+  MockFilePicker.cleanup();
   SimpleTest.finish();
 }
 
 SimpleTest.waitForFocus(function() {
   // mockFilePicker will simulate a cancel for the first time the file picker will be shown.
   MockFilePicker.returnValue = MockFilePicker.returnCancel;
 
   var b2 = document.getElementById('b2');
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -1107,16 +1107,34 @@ nsSVGElement::UpdateContentStyleRule()
   MappedAttrParser mappedAttrParser(doc->CSSLoader(), doc->GetDocumentURI(),
                                     GetBaseURI(), NodePrincipal());
 
   for (PRUint32 i = 0; i < attrCount; ++i) {
     const nsAttrName* attrName = mAttrsAndChildren.AttrNameAt(i);
     if (!attrName->IsAtom() || !IsAttributeMapped(attrName->Atom()))
       continue;
 
+    if (Tag() == nsGkAtoms::svg) {
+      // Special case: we don't want <svg> 'width'/'height' mapped into style
+      // if the attribute value isn't a valid <length> according to SVG (which
+      // only supports a subset of the CSS <length> values). We don't enforce
+      // this by checking the attribute value in nsSVGSVGElement::
+      // IsAttributeMapped since we don't want that method to depend on the
+      // value of the attribute that is being checked. Rather we just prevent
+      // the actual mapping here, as necessary.
+      if (attrName->Atom() == nsGkAtoms::width &&
+          !GetAnimatedLength(nsGkAtoms::width)->HasBaseVal()) {
+        continue;
+      }
+      if (attrName->Atom() == nsGkAtoms::height &&
+          !GetAnimatedLength(nsGkAtoms::height)->HasBaseVal()) {
+        continue;
+      }
+    }
+
     nsAutoString value;
     mAttrsAndChildren.AttrAt(i)->ToString(value);
     mappedAttrParser.ParseMappedAttrValue(attrName->Atom(), value);
   }
   mContentStyleRule = mappedAttrParser.CreateStyleRule();
 }
 
 static void
@@ -1309,16 +1327,30 @@ nsSVGElement::DidAnimateLength(PRUint8 a
   if (frame) {
     LengthAttributesInfo info = GetLengthInfo();
     frame->AttributeChanged(kNameSpaceID_None,
                             *info.mLengthInfo[aAttrEnum].mName,
                             nsIDOMMutationEvent::MODIFICATION);
   }
 }
 
+nsSVGLength2*
+nsSVGElement::GetAnimatedLength(const nsIAtom *aAttrName)
+{
+  LengthAttributesInfo lengthInfo = GetLengthInfo();
+
+  for (PRUint32 i = 0; i < lengthInfo.mLengthCount; i++) {
+    if (aAttrName == *lengthInfo.mLengthInfo[i].mName) {
+      return &lengthInfo.mLengths[i];
+    }
+  }
+  NS_ABORT_IF_FALSE(false, "no matching length found");
+  return nsnull;
+}
+
 void
 nsSVGElement::GetAnimatedLengthValues(float *aFirst, ...)
 {
   LengthAttributesInfo info = GetLengthInfo();
 
   NS_ASSERTION(info.mLengthCount > 0,
                "GetAnimatedLengthValues on element with no length attribs");
 
--- a/content/svg/content/src/nsSVGElement.h
+++ b/content/svg/content/src/nsSVGElement.h
@@ -190,16 +190,17 @@ public:
   virtual void DidAnimatePreserveAspectRatio();
   virtual void DidAnimateNumberList(PRUint8 aAttrEnum);
   virtual void DidAnimateLengthList(PRUint8 aAttrEnum);
   virtual void DidAnimatePointList();
   virtual void DidAnimatePathSegList();
   virtual void DidAnimateTransformList();
   virtual void DidAnimateString(PRUint8 aAttrEnum);
 
+  nsSVGLength2* GetAnimatedLength(const nsIAtom *aAttrName);
   void GetAnimatedLengthValues(float *aFirst, ...);
   void GetAnimatedNumberValues(float *aFirst, ...);
   void GetAnimatedIntegerValues(PRInt32 *aFirst, ...);
   SVGAnimatedNumberList* GetAnimatedNumberList(PRUint8 aAttrEnum);
   SVGAnimatedNumberList* GetAnimatedNumberList(nsIAtom *aAttrName);
   void GetAnimatedLengthListValues(SVGUserUnitList *aFirst, ...);
   SVGAnimatedLengthList* GetAnimatedLengthList(PRUint8 aAttrEnum);
   virtual SVGAnimatedPointList* GetAnimatedPointList() {
--- a/content/svg/content/src/nsSVGLength2.h
+++ b/content/svg/content/src/nsSVGLength2.h
@@ -95,16 +95,19 @@ public:
   float GetAnimValInSpecifiedUnits() const { return mAnimVal; }
   float GetBaseValInSpecifiedUnits() const { return mBaseVal; }
 
   float GetBaseValue(nsSVGSVGElement* aCtx) const
     { return mBaseVal / GetUnitScaleFactor(aCtx, mSpecifiedUnitType); }
   float GetAnimValue(nsSVGSVGElement* aCtx) const
     { return mAnimVal / GetUnitScaleFactor(aCtx, mSpecifiedUnitType); }
 
+  bool HasBaseVal() const {
+    return mIsBaseSet;
+  }
   // Returns true if the animated value of this length has been explicitly
   // set (either by animation, or by taking on the base value which has been
   // explicitly set by markup or a DOM call), false otherwise.
   // If this returns false, the animated value is still valid, that is,
   // useable, and represents the default base value of the attribute.
   bool IsExplicitlySet() const
     { return mIsAnimated || mIsBaseSet; }
   
--- a/content/svg/content/src/nsSVGSVGElement.cpp
+++ b/content/svg/content/src/nsSVGSVGElement.cpp
@@ -878,16 +878,30 @@ nsSVGSVGElement::GetTimedDocumentRoot()
 }
 
 //----------------------------------------------------------------------
 // nsIContent methods
 
 NS_IMETHODIMP_(bool)
 nsSVGSVGElement::IsAttributeMapped(const nsIAtom* name) const
 {
+  // We want to map the 'width' and 'height' attributes into style for
+  // outer-<svg>, except when the attributes aren't set (since their default
+  // values of '100%' can cause unexpected and undesirable behaviour for SVG
+  // inline in HTML). We rely on nsSVGElement::UpdateContentStyleRule() to
+  // prevent mapping of the default values into style (it only maps attributes
+  // that are set). We also rely on a check in nsSVGElement::
+  // UpdateContentStyleRule() to prevent us mapping the attributes when they're
+  // given a <length> value that is not currently recognized by the SVG
+  // specification.
+
+  if (!IsInner() && (name == nsGkAtoms::width || name == nsGkAtoms::height)) {
+    return true;
+  }
+
   static const MappedAttributeEntry* const map[] = {
     sColorMap,
     sFEFloodMap,
     sFillStrokeMap,
     sFiltersMap,
     sFontSpecificationMap,
     sGradientStopMap,
     sGraphicsMap,
--- a/content/xbl/builtin/browser-base.inc
+++ b/content/xbl/builtin/browser-base.inc
@@ -1,15 +1,15 @@
       <handler event="keypress" key=" " modifiers="shift" command="cmd_scrollPageUp" />
       <handler event="keypress" key=" " command="cmd_scrollPageDown" />
 
-      <handler event="keypress" keycode="VK_UP" command="cmd_scrollLineUp" />
-      <handler event="keypress" keycode="VK_DOWN" command="cmd_scrollLineDown" />
-      <handler event="keypress" keycode="VK_LEFT" command="cmd_scrollLeft" />
-      <handler event="keypress" keycode="VK_RIGHT" command="cmd_scrollRight" />
+      <handler event="keypress" keycode="VK_UP" command="cmd_linePrevious" />
+      <handler event="keypress" keycode="VK_DOWN" command="cmd_lineNext" />
+      <handler event="keypress" keycode="VK_LEFT" command="cmd_charPrevious" />
+      <handler event="keypress" keycode="VK_RIGHT" command="cmd_charNext" />
 
       <handler event="keypress" key="x" command="cmd_cut" modifiers="accel"/>
       <handler event="keypress" key="c" command="cmd_copy" modifiers="accel"/>
       <handler event="keypress" key="v" command="cmd_paste" modifiers="accel"/>
       <handler event="keypress" key="z" command="cmd_undo" modifiers="accel"/>
       <handler event="keypress" key="z" command="cmd_redo" modifiers="accel,shift" />
       <handler event="keypress" key="a" command="cmd_selectAll" modifiers="accel"/>
 
--- a/content/xbl/builtin/emacs/platformHTMLBindings.xml
+++ b/content/xbl/builtin/emacs/platformHTMLBindings.xml
@@ -164,18 +164,18 @@
       <handler event="keypress" keycode="VK_PAGE_UP" modifiers="shift" command="cmd_selectPageUp"/>
       <handler event="keypress" keycode="VK_PAGE_DOWN" modifiers="shift" command="cmd_selectPageDown"/>
 
       <handler event="keypress" keycode="VK_DELETE" modifiers="shift" command="cmd_cut" /> 
       <handler event="keypress" keycode="VK_DELETE" modifiers="control" command="cmd_copy" /> 
       <handler event="keypress" keycode="VK_INSERT" modifiers="control" command="cmd_copy" /> 
       <handler event="keypress" keycode="VK_HOME" command="cmd_beginLine"/>
       <handler event="keypress" keycode="VK_END" command="cmd_endLine"/>
-      <handler event="keypress" keycode="VK_HOME" modifiers="control" command="cmd_scrollTop"/>
-      <handler event="keypress" keycode="VK_END" modifiers="control" command="cmd_scrollBottom"/>
+      <handler event="keypress" keycode="VK_HOME" modifiers="control" command="cmd_moveTop"/>
+      <handler event="keypress" keycode="VK_END" modifiers="control" command="cmd_moveBottom"/>
       <handler event="keypress" keycode="VK_HOME" modifiers="shift,control" command="cmd_selectTop" /> 
       <handler event="keypress" keycode="VK_END" modifiers="shift,control" command="cmd_selectBottom" /> 
 
       <handler event="keypress" keycode="VK_LEFT" modifiers="control" command="cmd_wordPrevious" />
       <handler event="keypress" keycode="VK_RIGHT" modifiers="control" command="cmd_wordNext" />
       <handler event="keypress" keycode="VK_LEFT" modifiers="control,shift" command="cmd_selectWordPrevious" />
       <handler event="keypress" keycode="VK_RIGHT" modifiers="control,shift" command="cmd_selectWordNext" />
       <handler event="keypress" keycode="VK_LEFT" modifiers="shift" command="cmd_selectCharPrevious" />
--- a/content/xbl/builtin/mac/platformHTMLBindings.xml
+++ b/content/xbl/builtin/mac/platformHTMLBindings.xml
@@ -101,18 +101,18 @@
       <handler event="keypress" keycode="VK_LEFT" modifiers="alt" command="cmd_wordPrevious" />
       <handler event="keypress" keycode="VK_RIGHT" modifiers="alt" command="cmd_wordNext" />
       <handler event="keypress" keycode="VK_LEFT" modifiers="alt,shift" command="cmd_selectWordPrevious" />
       <handler event="keypress" keycode="VK_RIGHT" modifiers="alt,shift" command="cmd_selectWordNext" />
       <handler event="keypress" keycode="VK_LEFT" modifiers="shift" command="cmd_selectCharPrevious" />
       <handler event="keypress" keycode="VK_RIGHT" modifiers="shift" command="cmd_selectCharNext" />
       <handler event="keypress" keycode="VK_UP" modifiers="shift" command="cmd_selectLinePrevious" />
       <handler event="keypress" keycode="VK_DOWN" modifiers="shift" command="cmd_selectLineNext" />
-      <handler event="keypress" keycode="VK_UP" modifiers="accel" command="cmd_scrollTop"/>
-      <handler event="keypress" keycode="VK_DOWN" modifiers="accel" command="cmd_scrollBottom"/>      
+      <handler event="keypress" keycode="VK_UP" modifiers="accel" command="cmd_moveTop"/>
+      <handler event="keypress" keycode="VK_DOWN" modifiers="accel" command="cmd_moveBottom"/>
 	</handlers>
   </binding>
 
   <binding id="editor">
     <handlers>
 #include ../editor-base.inc
       <handler event="keypress" key="a" command="cmd_selectAll" modifiers="accel"/>
       <handler event="keypress" keycode="VK_HOME" command="cmd_scrollTop" /> 
--- a/content/xbl/builtin/unix/platformHTMLBindings.xml
+++ b/content/xbl/builtin/unix/platformHTMLBindings.xml
@@ -36,18 +36,18 @@
       <handler event="keypress" keycode="VK_PAGE_UP" modifiers="shift" command="cmd_selectPageUp"/>
       <handler event="keypress" keycode="VK_PAGE_DOWN" modifiers="shift" command="cmd_selectPageDown"/>
 
       <handler event="keypress" keycode="VK_DELETE" modifiers="shift" command="cmd_cut" /> 
       <handler event="keypress" keycode="VK_DELETE" modifiers="control" command="cmd_copy" /> 
       <handler event="keypress" keycode="VK_INSERT" modifiers="control" command="cmd_copy" /> 
       <handler event="keypress" keycode="VK_HOME" command="cmd_beginLine"/>
       <handler event="keypress" keycode="VK_END" command="cmd_endLine"/>
-      <handler event="keypress" keycode="VK_HOME" modifiers="control" command="cmd_scrollTop"/>
-      <handler event="keypress" keycode="VK_END" modifiers="control" command="cmd_scrollBottom"/>
+      <handler event="keypress" keycode="VK_HOME" modifiers="control" command="cmd_moveTop"/>
+      <handler event="keypress" keycode="VK_END" modifiers="control" command="cmd_moveBottom"/>
       <handler event="keypress" keycode="VK_HOME" modifiers="shift,control" command="cmd_selectTop" /> 
       <handler event="keypress" keycode="VK_END" modifiers="shift,control" command="cmd_selectBottom" /> 
 
       <handler event="keypress" keycode="VK_LEFT" modifiers="control" command="cmd_wordPrevious" />
       <handler event="keypress" keycode="VK_RIGHT" modifiers="control" command="cmd_wordNext" />
       <handler event="keypress" keycode="VK_LEFT" modifiers="control,shift" command="cmd_selectWordPrevious" />
       <handler event="keypress" keycode="VK_RIGHT" modifiers="control,shift" command="cmd_selectWordNext" />
       <handler event="keypress" keycode="VK_LEFT" modifiers="shift" command="cmd_selectCharPrevious" />
--- a/content/xbl/builtin/win/platformHTMLBindings.xml
+++ b/content/xbl/builtin/win/platformHTMLBindings.xml
@@ -96,18 +96,18 @@
       <handler event="keypress" keycode="VK_PAGE_UP" modifiers="shift" command="cmd_selectPageUp"/>
       <handler event="keypress" keycode="VK_PAGE_DOWN" modifiers="shift" command="cmd_selectPageDown"/>
 
       <handler event="keypress" keycode="VK_DELETE" modifiers="shift" command="cmd_cut"/>
       <handler event="keypress" keycode="VK_DELETE" modifiers="control" command="cmd_deleteWordForward"/>
       <handler event="keypress" keycode="VK_INSERT" modifiers="control" command="cmd_copy"/>
       <handler event="keypress" keycode="VK_HOME" command="cmd_beginLine"/>
       <handler event="keypress" keycode="VK_END" command="cmd_endLine"/>
-      <handler event="keypress" keycode="VK_HOME" modifiers="control" command="cmd_scrollTop"/>
-      <handler event="keypress" keycode="VK_END" modifiers="control" command="cmd_scrollBottom"/>
+      <handler event="keypress" keycode="VK_HOME" modifiers="control" command="cmd_moveTop"/>
+      <handler event="keypress" keycode="VK_END" modifiers="control" command="cmd_moveBottom"/>
       <handler event="keypress" keycode="VK_HOME" modifiers="shift,control" command="cmd_selectTop" />
       <handler event="keypress" keycode="VK_END" modifiers="shift,control" command="cmd_selectBottom" />
 
       <handler event="keypress" keycode="VK_LEFT" modifiers="control" command="cmd_wordPrevious" />
       <handler event="keypress" keycode="VK_RIGHT" modifiers="control" command="cmd_wordNext" />
       <handler event="keypress" keycode="VK_LEFT" modifiers="control,shift" command="cmd_selectWordPrevious" />
       <handler event="keypress" keycode="VK_RIGHT" modifiers="control,shift" command="cmd_selectWordNext" />
       <handler event="keypress" keycode="VK_LEFT" modifiers="shift" command="cmd_selectCharPrevious" />
--- a/docshell/base/nsDSURIContentListener.cpp
+++ b/docshell/base/nsDSURIContentListener.cpp
@@ -43,25 +43,41 @@
 #include "nsXPIDLString.h"
 #include "nsDocShellCID.h"
 #include "nsIWebNavigationInfo.h"
 #include "nsIDOMWindow.h"
 #include "nsAutoPtr.h"
 #include "nsIHttpChannel.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsNetError.h"
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
+
+static bool sIgnoreXFrameOptions = false;
 
 //*****************************************************************************
 //***    nsDSURIContentListener: Object Management
 //*****************************************************************************
 
 nsDSURIContentListener::nsDSURIContentListener(nsDocShell* aDocShell)
     : mDocShell(aDocShell), 
       mParentContentListener(nsnull)
 {
+  static bool initializedPrefCache = false;
+
+  // Set up a pref cache for sIgnoreXFrameOptions, if we haven't already.
+  if (NS_UNLIKELY(!initializedPrefCache)) {
+    // Lock the pref so that the user's changes to it, if any, are ignored.
+    nsIPrefBranch2 *root = Preferences::GetRootBranch();
+    root->LockPref("b2g.ignoreXFrameOptions");
+
+    Preferences::AddBoolVarCache(&sIgnoreXFrameOptions, "b2g.ignoreXFrameOptions");
+    initializedPrefCache = true;
+  }
 }
 
 nsDSURIContentListener::~nsDSURIContentListener()
 {
 }
 
 nsresult
 nsDSURIContentListener::Init() 
@@ -116,17 +132,18 @@ nsDSURIContentListener::DoContent(const 
                                   nsIStreamListener** aContentHandler,
                                   bool* aAbortProcess)
 {
     nsresult rv;
     NS_ENSURE_ARG_POINTER(aContentHandler);
     NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
 
     // Check whether X-Frame-Options permits us to load this content in an
-    // iframe
+    // iframe and abort the load (unless we've disabled x-frame-options
+    // checking).
     if (!CheckFrameOptions(request)) {
         *aAbortProcess = true;
         return NS_OK;
     }
 
     *aAbortProcess = false;
 
     // determine if the channel has just been retargeted to us...
@@ -282,16 +299,21 @@ nsDSURIContentListener::SetParentContent
         mParentContentListener = nsnull;
     }
     return NS_OK;
 }
 
 // Check if X-Frame-Options permits this document to be loaded as a subdocument.
 bool nsDSURIContentListener::CheckFrameOptions(nsIRequest* request)
 {
+    // If X-Frame-Options checking is disabled, return true unconditionally.
+    if (sIgnoreXFrameOptions) {
+        return true;
+    }
+
     nsCAutoString xfoHeaderValue;
 
     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
     if (!httpChannel) {
         return true;
     }
 
     httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-Frame-Options"),
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1674,35 +1674,16 @@ jsid nsDOMClassInfo::sWrappedJSObject_id
 jsid nsDOMClassInfo::sURL_id             = JSID_VOID;
 jsid nsDOMClassInfo::sKeyPath_id         = JSID_VOID;
 jsid nsDOMClassInfo::sAutoIncrement_id   = JSID_VOID;
 jsid nsDOMClassInfo::sUnique_id          = JSID_VOID;
 jsid nsDOMClassInfo::sMultiEntry_id      = JSID_VOID;
 jsid nsDOMClassInfo::sOnload_id          = JSID_VOID;
 jsid nsDOMClassInfo::sOnerror_id         = JSID_VOID;
 
-static const JSClass *sObjectClass = nsnull;
-
-/**
- * Set our JSClass pointer for the Object class
- */
-static void
-FindObjectClass(JSObject* aGlobalObject)
-{
-  NS_ASSERTION(!sObjectClass,
-               "Double set of sObjectClass");
-  JSObject *obj, *proto = aGlobalObject;
-  do {
-    obj = proto;
-    proto = js::GetObjectProto(obj);
-  } while (proto);
-
-  sObjectClass = js::GetObjectJSClass(obj);
-}
-
 static void
 PrintWarningOnConsole(JSContext *cx, const char *stringBundleProperty)
 {
   nsCOMPtr<nsIStringBundleService> stringService =
     mozilla::services::GetStringBundleService();
   if (!stringService) {
     return;
   }
@@ -4716,16 +4697,62 @@ GetExternalClassInfo(nsScriptNameSpaceMa
 static nsresult
 ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
                  JSObject *obj, const PRUnichar *name,
                  const nsDOMClassInfoData *ci_data,
                  const nsGlobalNameStruct *name_struct,
                  nsScriptNameSpaceManager *nameSpaceManager,
                  JSObject *dot_prototype, bool install, bool *did_resolve);
 
+static nsresult
+LookupPrototypeProto(JSContext *cx, JSObject *winobj,
+                     const nsDOMClassInfoData *ci_data,
+                     const nsGlobalNameStruct *name_struct,
+                     JSObject **aProtoProto);
+
+
+static nsGlobalWindow*
+FindUsableInnerWindow(nsIXPConnect *xpc, JSContext *cx, JSObject *global)
+{
+  // Only do this if the global object is a window.
+  // XXX Is there a better way to check this?
+  nsISupports *globalNative = xpc->GetNativeOfWrapper(cx, global);
+  nsCOMPtr<nsPIDOMWindow> piwin = do_QueryInterface(globalNative);
+  if (!piwin) {
+    return nsnull;
+  }
+
+  nsGlobalWindow *win = nsGlobalWindow::FromSupports(globalNative);
+  if (win->IsClosedOrClosing()) {
+    return nsnull;
+  }
+  
+  // If the window is in a different compartment than the global object, then
+  // it's likely that global is a sandbox object whose prototype is a window.
+  // Don't do anything in this case.
+  if (win->FastGetGlobalJSObject() &&
+      js::GetObjectCompartment(global) != js::GetObjectCompartment(win->FastGetGlobalJSObject())) {
+    return nsnull;
+  }
+
+  if (win->IsOuterWindow()) {
+    // XXXjst: Do security checks here when we remove the security
+    // checks on the inner window.
+
+    win = win->GetCurrentInnerWindowInternal();
+
+    JSObject* global;
+    if (!win || !(global = win->GetGlobalJSObject()) ||
+        win->IsClosedOrClosing()) {
+      return nsnull;
+    }
+  }
+
+  return win;
+}
 
 NS_IMETHODIMP
 nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * proto)
 {
   PRUint32 flags = (mData->mScriptableFlags & DONT_ENUM_STATIC_PROPS)
                    ? 0
                    : JSPROP_ENUMERATE;
 
@@ -4734,29 +4761,16 @@ nsDOMClassInfo::PostCreatePrototype(JSCo
     count++;
   }
 
   if (!sXPConnect->DefineDOMQuickStubs(cx, proto, flags,
                                        count, mData->mInterfaces)) {
     JS_ClearPendingException(cx);
   }
 
-  // This is called before any other location that requires
-  // sObjectClass, so compute it here. We assume that nobody has had a
-  // chance to monkey around with proto's prototype chain before this.
-  if (!sObjectClass) {
-    FindObjectClass(proto);
-    NS_ASSERTION(sObjectClass && !strcmp(sObjectClass->name, "Object"),
-                 "Incorrect object class!");
-  }
-
-  NS_ASSERTION(::JS_GetPrototype(cx, proto) &&
-               JS_GET_CLASS(cx, ::JS_GetPrototype(cx, proto)) == sObjectClass,
-               "Hmm, somebody did something evil?");
-
 #ifdef DEBUG
   if (mData->mHasClassInterface && mData->mProtoChainInterface &&
       mData->mProtoChainInterface != &NS_GET_IID(nsISupports)) {
     nsCOMPtr<nsIInterfaceInfoManager>
       iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
 
     if (iim) {
       nsCOMPtr<nsIInterfaceInfo> if_info;
@@ -4774,48 +4788,22 @@ nsDOMClassInfo::PostCreatePrototype(JSCo
 #endif
 
   // Make prototype delegation work correctly. Consider if a site sets
   // HTMLElement.prototype.foopy = function () { ... } Now, calling
   // document.body.foopy() needs to ensure that looking up foopy on
   // document.body's prototype will find the right function.
   JSObject *global = ::JS_GetGlobalForObject(cx, proto);
 
-  // Only do this if the global object is a window.
-  // XXX Is there a better way to check this?
-  nsISupports *globalNative = XPConnect()->GetNativeOfWrapper(cx, global);
-  nsCOMPtr<nsPIDOMWindow> piwin = do_QueryInterface(globalNative);
-  if (!piwin) {
-    return NS_OK;
-  }
-
-  nsGlobalWindow *win = nsGlobalWindow::FromSupports(globalNative);
-  if (win->IsClosedOrClosing()) {
+  nsGlobalWindow *win = FindUsableInnerWindow(XPConnect(), cx, global);
+  if (!win) {
     return NS_OK;
   }
 
-  // If the window is in a different compartment than the global object, then
-  // it's likely that global is a sandbox object whose prototype is a window.
-  // Don't do anything in this case.
-  if (win->FastGetGlobalJSObject() &&
-      js::GetObjectCompartment(global) != js::GetObjectCompartment(win->FastGetGlobalJSObject())) {
-    return NS_OK;
-  }
-
-  if (win->IsOuterWindow()) {
-    // XXXjst: Do security checks here when we remove the security
-    // checks on the inner window.
-
-    win = win->GetCurrentInnerWindowInternal();
-
-    if (!win || !(global = win->GetGlobalJSObject()) ||
-        win->IsClosedOrClosing()) {
-      return NS_OK;
-    }
-  }
+  global = win->FastGetGlobalJSObject();
 
   // Don't overwrite a property set by content.
   JSBool found;
   if (!::JS_AlreadyHasOwnUCProperty(cx, global, reinterpret_cast<const jschar*>(mData->mNameUTF16),
                                     nsCRT::strlen(mData->mNameUTF16), &found)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -4824,16 +4812,33 @@ nsDOMClassInfo::PostCreatePrototype(JSCo
   NS_ENSURE_TRUE(nameSpaceManager, NS_OK);
 
   bool unused;
   return ResolvePrototype(sXPConnect, win, cx, global, mData->mNameUTF16,
                           mData, nsnull, nameSpaceManager, proto, !found,
                           &unused);
 }
 
+NS_IMETHODIMP
+nsDOMClassInfo::PreCreatePrototype(JSContext * cx, JSObject * global,
+                                   JSObject **protoProto)
+{
+  *protoProto = nsnull;
+  
+  nsGlobalWindow *win = FindUsableInnerWindow(XPConnect(), cx, global);
+  if (!win) {
+    return NS_OK;
+  }
+
+  JSObject *winObj = win->FastGetGlobalJSObject();
+  
+  return LookupPrototypeProto(cx, winObj, mData, nsnull, protoProto);
+}
+
+
 // static
 nsIClassInfo *
 NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID)
 {
   if (aID >= eDOMClassInfoIDCount) {
     NS_ERROR("Bad ID!");
 
     return nsnull;
@@ -5176,17 +5181,17 @@ nsWindowSH::InstallGlobalScopePolluter(J
   }
 
   JSObject *o = obj, *proto;
 
   // Find the place in the prototype chain where we want this global
   // scope polluter (right before Object.prototype).
 
   while ((proto = ::JS_GetPrototype(cx, o))) {
-    if (JS_GET_CLASS(cx, proto) == sObjectClass) {
+    if (js::GetObjectClass(proto) == &js::ObjectClass) {
       // Set the global scope polluters prototype to Object.prototype
       ::JS_SplicePrototype(cx, gsp, proto);
 
       break;
     }
 
     o = proto;
   }
@@ -5998,16 +6003,115 @@ GetXPCProto(nsIXPConnect *aXPConnect, JS
   if (!JS_WrapObject(cx, &proto_obj)) {
     return NS_ERROR_FAILURE;
   }
 
   NS_IF_RELEASE(*aProto);
   return aXPConnect->HoldObject(cx, proto_obj, aProto);
 }
 
+static nsresult
+LookupPrototypeProto(JSContext *cx, JSObject *winobj,
+                     const nsDOMClassInfoData *ci_data,
+                     const nsGlobalNameStruct *name_struct,
+                     JSObject **aProtoProto)
+{
+  NS_ASSERTION(ci_data ||
+               (name_struct &&
+                name_struct->mType == nsGlobalNameStruct::eTypeClassProto),
+               "Wrong type or missing ci_data!");
+
+  const nsIID *primary_iid = &NS_GET_IID(nsISupports);
+
+  if (!ci_data) {
+    primary_iid = &name_struct->mIID;
+  } else if (ci_data->mProtoChainInterface) {
+    primary_iid = ci_data->mProtoChainInterface;
+  }
+
+  if (primary_iid->Equals(NS_GET_IID(nsISupports))) {
+    *aProtoProto = nsnull;
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIInterfaceInfoManager>
+    iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
+  NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
+
+  nsCOMPtr<nsIInterfaceInfo> if_info;
+  iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info));
+  NS_ENSURE_TRUE(if_info, NS_ERROR_UNEXPECTED);
+
+  const nsIID *iid = nsnull;
+
+  nsCOMPtr<nsIInterfaceInfo> parent;
+  if (ci_data && !ci_data->mHasClassInterface) {
+    if_info->GetIIDShared(&iid);
+  } else {
+    if_info->GetParent(getter_AddRefs(parent));
+    NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
+
+    parent->GetIIDShared(&iid);
+  }
+
+  if (!iid || iid->Equals(NS_GET_IID(nsISupports))) {
+    *aProtoProto = nsnull;
+    return NS_OK;
+  }
+
+  const char *class_parent_name = nsnull;
+  if (ci_data && !ci_data->mHasClassInterface) {
+    // If the class doesn't have a class interface the primary
+    // interface is the interface that should be
+    // constructor.prototype.__proto__.
+
+    if_info->GetNameShared(&class_parent_name);
+  } else {
+    // If the class does have a class interface (or there's no
+    // real class for this name) then the parent of the
+    // primary interface is what we want on
+    // constructor.prototype.__proto__.
+
+    NS_ASSERTION(parent, "Whoa, this is bad, null parent here!");
+
+    parent->GetNameShared(&class_parent_name);
+  }
+
+  JSObject *protoProto = nsnull;
+
+  // Get class_parent_name here
+  if (class_parent_name) {
+    jsval val;
+
+    JSAutoEnterCompartment ac;
+    if (!ac.enter(cx, winobj)) {
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    if (!::JS_LookupProperty(cx, winobj, CutPrefix(class_parent_name), &val)) {
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    JSObject *tmp = JSVAL_IS_OBJECT(val) ? JSVAL_TO_OBJECT(val) : nsnull;
+
+    if (tmp) {
+      if (!::JS_LookupProperty(cx, tmp, "prototype", &val)) {
+        return NS_ERROR_UNEXPECTED;
+      }
+
+      if (JSVAL_IS_OBJECT(val)) {
+        protoProto = JSVAL_TO_OBJECT(val);
+      }
+    }
+  }
+
+  *aProtoProto = protoProto;
+  return NS_OK;
+}
+
 // Either ci_data must be non-null or name_struct must be non-null and of type
 // eTypeClassProto.
 static nsresult
 ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
                  JSObject *obj, const PRUnichar *name,
                  const nsDOMClassInfoData *ci_data,
                  const nsGlobalNameStruct *name_struct,
                  nsScriptNameSpaceManager *nameSpaceManager,
@@ -6043,20 +6147,16 @@ ResolvePrototype(nsIXPConnect *aXPConnec
 
   if (!ci_data) {
     primary_iid = &name_struct->mIID;
   }
   else if (ci_data->mProtoChainInterface) {
     primary_iid = ci_data->mProtoChainInterface;
   }
 
-  nsCOMPtr<nsIInterfaceInfo> if_info;
-  nsCOMPtr<nsIInterfaceInfo> parent;
-  const char *class_parent_name = nsnull;
-
   if (!primary_iid->Equals(NS_GET_IID(nsISupports))) {
     JSAutoEnterCompartment ac;
 
     if (!ac.enter(cx, class_obj)) {
       return NS_ERROR_FAILURE;
     }
 
     rv = DefineInterfaceConstants(cx, class_obj, primary_iid);
@@ -6070,98 +6170,36 @@ ResolvePrototype(nsIXPConnect *aXPConnec
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     // Special case for |IDBKeyRange| which gets funny "static" functions.
     if (primary_iid->Equals(NS_GET_IID(nsIIDBKeyRange)) &&
         !indexedDB::IDBKeyRange::DefineConstructors(cx, class_obj)) {
       return NS_ERROR_FAILURE;
     }
-
-    nsCOMPtr<nsIInterfaceInfoManager>
-      iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
-    NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
-
-    iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info));
-    NS_ENSURE_TRUE(if_info, NS_ERROR_UNEXPECTED);
-
-    const nsIID *iid = nsnull;
-
-    if (ci_data && !ci_data->mHasClassInterface) {
-      if_info->GetIIDShared(&iid);
-    } else {
-      if_info->GetParent(getter_AddRefs(parent));
-      NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
-
-      parent->GetIIDShared(&iid);
-    }
-
-    if (iid) {
-      if (!iid->Equals(NS_GET_IID(nsISupports))) {
-        if (ci_data && !ci_data->mHasClassInterface) {
-          // If the class doesn't have a class interface the primary
-          // interface is the interface that should be
-          // constructor.prototype.__proto__.
-
-          if_info->GetNameShared(&class_parent_name);
-        } else {
-          // If the class does have a class interface (or there's no
-          // real class for this name) then the parent of the
-          // primary interface is what we want on
-          // constructor.prototype.__proto__.
-
-          NS_ASSERTION(parent, "Whoa, this is bad, null parent here!");
-
-          parent->GetNameShared(&class_parent_name);
-        }
-      }
-    }
   }
 
   {
     JSObject *winobj = aWin->FastGetGlobalJSObject();
 
-    JSObject *proto = nsnull;
-
-    if (class_parent_name) {
-      jsval val;
-
-      JSAutoEnterCompartment ac;
-      if (!ac.enter(cx, winobj)) {
-        return NS_ERROR_UNEXPECTED;
-      }
-
-      if (!::JS_LookupProperty(cx, winobj, CutPrefix(class_parent_name), &val)) {
-        return NS_ERROR_UNEXPECTED;
-      }
-
-      JSObject *tmp = JSVAL_IS_OBJECT(val) ? JSVAL_TO_OBJECT(val) : nsnull;
-
-      if (tmp) {
-        if (!::JS_LookupProperty(cx, tmp, "prototype", &val)) {
-          return NS_ERROR_UNEXPECTED;
-        }
-
-        if (JSVAL_IS_OBJECT(val)) {
-          proto = JSVAL_TO_OBJECT(val);
-        }
-      }
-    }
+    JSObject *proto;
+    rv = LookupPrototypeProto(cx, winobj, ci_data, name_struct, &proto);
+    NS_ENSURE_SUCCESS(rv, rv);
 
     if (dot_prototype) {
       JSAutoEnterCompartment ac;
       if (!ac.enter(cx, dot_prototype)) {
         return NS_ERROR_UNEXPECTED;
       }
 
       JSObject *xpc_proto_proto = ::JS_GetPrototype(cx, dot_prototype);
 
       if (proto &&
           (!xpc_proto_proto ||
-           JS_GET_CLASS(cx, xpc_proto_proto) == sObjectClass)) {
+           js::GetObjectClass(xpc_proto_proto) == &js::ObjectClass)) {
         if (!JS_WrapObject(cx, &proto) ||
             !JS_SetPrototype(cx, dot_prototype, proto)) {
           return NS_ERROR_UNEXPECTED;
         }
       }
     } else {
       JSAutoEnterCompartment ac;
       if (!ac.enter(cx, winobj)) {
@@ -9538,17 +9576,17 @@ nsHTMLPluginObjElementSH::SetupProtoChai
   rv = wrapper->GetJSObjectPrototype(&my_proto);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Set 'this.__proto__' to pi
   if (!::JS_SetPrototype(cx, obj, pi_obj)) {
     return NS_ERROR_UNEXPECTED;
   }
 
-  if (pi_proto && JS_GET_CLASS(cx, pi_proto) != sObjectClass) {
+  if (pi_proto && js::GetObjectClass(pi_proto) != &js::ObjectClass) {
     // The plugin wrapper has a proto that's not Object.prototype, set
     // 'pi.__proto__.__proto__' to the original 'this.__proto__'
     if (pi_proto != my_proto && !::JS_SetPrototype(cx, pi_proto, my_proto)) {
       return NS_ERROR_UNEXPECTED;
     }
   } else {
     // 'pi' didn't have a prototype, or pi's proto was
     // 'Object.prototype' (i.e. pi is an NPRuntime wrapped JS object)
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1977,106 +1977,62 @@ nsDOMWindowUtils::GetFileReferences(cons
     }
   }
 
   *aRefCnt = *aDBRefCnt = *aSliceRefCnt = -1;
   *aResult = false;
   return NS_OK;
 }
 
-static inline JSContext *
-GetJSContext()
+NS_IMETHODIMP
+nsDOMWindowUtils::StartPCCountProfiling(JSContext* cx)
 {
-  nsCOMPtr<nsIXPConnect> xpc = nsContentUtils::XPConnect();
-
-  // get the xpconnect native call context
-  nsAXPCNativeCallContext *cc = nsnull;
-  xpc->GetCurrentNativeCallContext(&cc);
-  if(!cc)
-    return NULL;
-
-  // Get JSContext of current call
-  JSContext* cx;
-  nsresult rv = cc->GetJSContext(&cx);
-  if(NS_FAILED(rv) || !cx)
-    return NULL;
-
-  return cx;
-}
-
-NS_IMETHODIMP
-nsDOMWindowUtils::StartPCCountProfiling()
-{
-  JSContext *cx = GetJSContext();
-  if (!cx)
-    return NS_ERROR_FAILURE;
-
   js::StartPCCountProfiling(cx);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMWindowUtils::StopPCCountProfiling()
+nsDOMWindowUtils::StopPCCountProfiling(JSContext* cx)
 {
-  JSContext *cx = GetJSContext();
-  if (!cx)
-    return NS_ERROR_FAILURE;
-
   js::StopPCCountProfiling(cx);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMWindowUtils::PurgePCCounts()
+nsDOMWindowUtils::PurgePCCounts(JSContext* cx)
 {
-  JSContext *cx = GetJSContext();
-  if (!cx)
-    return NS_ERROR_FAILURE;
-
   js::PurgePCCounts(cx);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMWindowUtils::GetPCCountScriptCount(PRInt32 *result)
+nsDOMWindowUtils::GetPCCountScriptCount(JSContext* cx, PRInt32 *result)
 {
-  JSContext *cx = GetJSContext();
-  if (!cx)
-    return NS_ERROR_FAILURE;
-
   *result = js::GetPCCountScriptCount(cx);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMWindowUtils::GetPCCountScriptSummary(PRInt32 script, nsAString& result)
+nsDOMWindowUtils::GetPCCountScriptSummary(PRInt32 script, JSContext* cx, nsAString& result)
 {
-  JSContext *cx = GetJSContext();
-  if (!cx)
-    return NS_ERROR_FAILURE;
-
   JSString *text = js::GetPCCountScriptSummary(cx, script);
   if (!text)
     return NS_ERROR_FAILURE;
 
   nsDependentJSString str;
   if (!str.init(cx, text))
     return NS_ERROR_FAILURE;
 
   result = str;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMWindowUtils::GetPCCountScriptContents(PRInt32 script, nsAString& result)
+nsDOMWindowUtils::GetPCCountScriptContents(PRInt32 script, JSContext* cx, nsAString& result)
 {
-  JSContext *cx = GetJSContext();
-  if (!cx)
-    return NS_ERROR_FAILURE;
-
   JSString *text = js::GetPCCountScriptContents(cx, script);
   if (!text)
     return NS_ERROR_FAILURE;
 
   nsDependentJSString str;
   if (!str.init(cx, text))
     return NS_ERROR_FAILURE;
 
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -2452,24 +2452,16 @@ nsFocusManager::DetermineElementToMoveFo
         nsCOMPtr<nsIContent> endSelectionContent;
         GetSelectionLocation(doc, presShell,
                              getter_AddRefs(startContent),
                              getter_AddRefs(endSelectionContent));
         // If the selection is on the rootContent, then there is no selection
         if (startContent == rootContent) {
           startContent = nsnull;
         }
-        else if (startContent && startContent->HasFlag(NODE_IS_EDITABLE)) {
-          // Don't start from the selection if the selection is in a
-          // contentEditable region.
-          nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(doc);
-          if (htmlDoc &&
-              htmlDoc->GetEditingState() == nsIHTMLDocument::eContentEditable)
-            startContent = nsnull;
-        }
 
         if (aType == MOVEFOCUS_CARET) {
           // GetFocusInSelection finds a focusable link near the caret.
           // If there is no start content though, don't do this to avoid
           // focusing something unexpected.
           if (startContent) {
             GetFocusInSelection(aWindow, startContent,
                                 endSelectionContent, aNextContent);
--- a/dom/base/nsGlobalWindowCommands.cpp
+++ b/dom/base/nsGlobalWindowCommands.cpp
@@ -71,22 +71,24 @@ const char * const sSelectNoneString = "
 const char * const sCopyImageLocationString = "cmd_copyImageLocation";
 const char * const sCopyImageContentsString = "cmd_copyImageContents";
 const char * const sCopyImageString = "cmd_copyImage";
 
 const char * const sScrollTopString = "cmd_scrollTop";
 const char * const sScrollBottomString = "cmd_scrollBottom";
 const char * const sScrollPageUpString = "cmd_scrollPageUp";
 const char * const sScrollPageDownString = "cmd_scrollPageDown";
+const char * const sMoveTopString = "cmd_moveTop";
+const char * const sMoveBottomString = "cmd_moveBottom";
 const char * const sMovePageUpString = "cmd_movePageUp";
 const char * const sMovePageDownString = "cmd_movePageDown";
-const char * const sScrollLineUpString = "cmd_scrollLineUp";
-const char * const sScrollLineDownString = "cmd_scrollLineDown";
-const char * const sScrollLeftString = "cmd_scrollLeft";
-const char * const sScrollRightString = "cmd_scrollRight";
+const char * const sLinePreviousString = "cmd_linePrevious";
+const char * const sLineNextString = "cmd_lineNext";
+const char * const sCharPreviousString = "cmd_charPrevious";
+const char * const sCharNextString = "cmd_charNext";
 
 // These are so the browser can use editor navigation key bindings
 // helps with accessibility (boolean pref accessibility.browsewithcaret)
 
 const char * const sSelectCharPreviousString = "cmd_selectCharPrevious";
 const char * const sSelectCharNextString = "cmd_selectCharNext";
 
 const char * const sWordPreviousString = "cmd_wordPrevious";
@@ -97,18 +99,18 @@ const char * const sSelectWordNextString
 const char * const sBeginLineString = "cmd_beginLine";
 const char * const sEndLineString = "cmd_endLine";
 const char * const sSelectBeginLineString = "cmd_selectBeginLine";
 const char * const sSelectEndLineString = "cmd_selectEndLine";
 
 const char * const sSelectLinePreviousString = "cmd_selectLinePrevious";
 const char * const sSelectLineNextString = "cmd_selectLineNext";
 
-const char * const sSelectPagePreviousString = "cmd_selectPagePrevious";
-const char * const sSelectPageNextString = "cmd_selectPageNext";
+const char * const sSelectPageUpString = "cmd_selectPageUp";
+const char * const sSelectPageDownString = "cmd_selectPageDown";
 
 const char * const sSelectTopString = "cmd_selectTop";
 const char * const sSelectBottomString = "cmd_selectBottom";
 
 
 #if 0
 #pragma mark -
 #endif
@@ -272,43 +274,51 @@ nsSelectMoveScrollCommand::DoSelectComma
 }
 
 nsresult
 nsSelectMoveScrollCommand::DoCommandBrowseWithCaretOn(const char *aCommandName,
                   nsIDOMWindow *aWindow, nsISelectionController *aSelectionController)
 {
   nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
 
-  if (!nsCRT::strcmp(aCommandName, sScrollTopString))
+  // cmd_MoveTop/Bottom are used on Window/Unix. They move the caret
+  // in caret browsing mode.
+  if (!nsCRT::strcmp(aCommandName, sMoveTopString))
     rv = aSelectionController->CompleteMove(false, false);
+  else if (!nsCRT::strcmp(aCommandName,sMoveBottomString))
+    rv = aSelectionController->CompleteMove(true, false);
+  // cmd_ScrollTop/Bottom are used on Mac. They do not move the
+  // caret in caret browsing mode.
+  else if (!nsCRT::strcmp(aCommandName, sScrollTopString))
+    rv = aSelectionController->CompleteScroll(false);
   else if (!nsCRT::strcmp(aCommandName,sScrollBottomString))
-    rv = aSelectionController->CompleteMove(true, false);
+    rv = aSelectionController->CompleteScroll(true);
   // cmd_MovePageUp/Down are used on Window/Unix. They move the caret
   // in caret browsing mode.
   else if (!nsCRT::strcmp(aCommandName, sMovePageUpString))
     rv = aSelectionController->PageMove(false, false);
   else if (!nsCRT::strcmp(aCommandName, sMovePageDownString))
     rv = aSelectionController->PageMove(true, false);
   // cmd_ScrollPageUp/Down are used on Mac, and for the spacebar on all platforms.
   // They do not move the caret in caret browsing mode.
   else if (!nsCRT::strcmp(aCommandName, sScrollPageUpString))
     rv = aSelectionController->ScrollPage(false);
   else if (!nsCRT::strcmp(aCommandName, sScrollPageDownString))
     rv = aSelectionController->ScrollPage(true);
-  else if (!nsCRT::strcmp(aCommandName, sScrollLineUpString))
+  else if (!nsCRT::strcmp(aCommandName, sLinePreviousString))
     rv = aSelectionController->LineMove(false, false);
-  else if (!nsCRT::strcmp(aCommandName, sScrollLineDownString))
+  else if (!nsCRT::strcmp(aCommandName, sLineNextString))
     rv = aSelectionController->LineMove(true, false);
   else if (!nsCRT::strcmp(aCommandName, sWordPreviousString))
     rv = aSelectionController->WordMove(false, false);
   else if (!nsCRT::strcmp(aCommandName, sWordNextString))
     rv = aSelectionController->WordMove(true, false);
-  else if (!nsCRT::strcmp(aCommandName, sScrollLeftString))
+  else if (!nsCRT::strcmp(aCommandName, sCharPreviousString))
     rv = aSelectionController->CharacterMove(false, false);
-  else if (!nsCRT::strcmp(aCommandName, sScrollRightString))
+  else if (!nsCRT::strcmp(aCommandName, sCharNextString))
     rv = aSelectionController->CharacterMove(true, false);
   else if (!nsCRT::strcmp(aCommandName, sBeginLineString))
     rv = aSelectionController->IntraLineMove(false, false);
   else if (!nsCRT::strcmp(aCommandName, sEndLineString))
     rv = aSelectionController->IntraLineMove(true, false);
 
   if (NS_SUCCEEDED(rv))
   {
@@ -325,17 +335,25 @@ nsSelectMoveScrollCommand::DoCommandBrow
   return rv;
 }
 
 nsresult
 nsSelectMoveScrollCommand::DoCommandBrowseWithCaretOff(const char *aCommandName, nsISelectionController *aSelectionController)
 {
   nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
 
-  if (!nsCRT::strcmp(aCommandName, sScrollTopString))   
+  // cmd_MoveTop/Bottom are used on Window/Unix. They move the caret
+  // in caret browsing mode.
+  if (!nsCRT::strcmp(aCommandName, sMoveTopString))
+    rv = aSelectionController->CompleteScroll(false);
+  else if (!nsCRT::strcmp(aCommandName,sMoveBottomString))
+    rv = aSelectionController->CompleteScroll(true);
+  // cmd_ScrollTop/Bottom are used on Mac. They do not move the
+  // caret in caret browsing mode.
+  else if (!nsCRT::strcmp(aCommandName, sScrollTopString))
     rv = aSelectionController->CompleteScroll(false);
   else if (!nsCRT::strcmp(aCommandName,sScrollBottomString))
     rv = aSelectionController->CompleteScroll(true);
 
   // cmd_MovePageUp/Down are used on Window/Unix. They move the caret
   // in caret browsing mode.
   else if (!nsCRT::strcmp(aCommandName, sMovePageUpString))
     rv = aSelectionController->ScrollPage(false);
@@ -343,26 +361,26 @@ nsSelectMoveScrollCommand::DoCommandBrow
     rv = aSelectionController->ScrollPage(true);
   // cmd_ScrollPageUp/Down are used on Mac. They do not move the
   // caret in caret browsing mode.
   else if (!nsCRT::strcmp(aCommandName, sScrollPageUpString))
     rv = aSelectionController->ScrollPage(false);
   else if (!nsCRT::strcmp(aCommandName, sScrollPageDownString))
     rv = aSelectionController->ScrollPage(true);
 
-  else if (!nsCRT::strcmp(aCommandName, sScrollLineUpString))
+  else if (!nsCRT::strcmp(aCommandName, sLinePreviousString))
     rv = aSelectionController->ScrollLine(false);
-  else if (!nsCRT::strcmp(aCommandName, sScrollLineDownString))
+  else if (!nsCRT::strcmp(aCommandName, sLineNextString))
     rv = aSelectionController->ScrollLine(true);
-  else if (!nsCRT::strcmp(aCommandName, sScrollLeftString))
+  else if (!nsCRT::strcmp(aCommandName, sCharPreviousString))
     rv = aSelectionController->ScrollHorizontal(true);
-  else if (!nsCRT::strcmp(aCommandName, sScrollRightString))
+  else if (!nsCRT::strcmp(aCommandName, sCharNextString))
     rv = aSelectionController->ScrollHorizontal(false);
   // cmd_beginLine/endLine with caret browsing off
-  // will act as cmd_scrollTop/Bottom
+  // will act as cmd_moveTop/Bottom
   else if (!nsCRT::strcmp(aCommandName, sBeginLineString))
     rv = aSelectionController->CompleteScroll(false);
   else if (!nsCRT::strcmp(aCommandName, sEndLineString))
     rv = aSelectionController->CompleteScroll(true);
 
   return rv;
 }
 
@@ -393,16 +411,20 @@ nsSelectCommand::DoSelectCommand(const c
   else if (!nsCRT::strcmp(aCommandName, sSelectBeginLineString))
     rv = selCont->IntraLineMove(false, true);
   else if (!nsCRT::strcmp(aCommandName, sSelectEndLineString))
     rv = selCont->IntraLineMove(true, true);
   else if (!nsCRT::strcmp(aCommandName, sSelectLinePreviousString))
     rv = selCont->LineMove(false, true);
   else if (!nsCRT::strcmp(aCommandName, sSelectLineNextString))
     rv = selCont->LineMove(true, true);
+  else if (!nsCRT::strcmp(aCommandName, sSelectPageUpString))
+    rv = selCont->PageMove(false, true);
+  else if (!nsCRT::strcmp(aCommandName, sSelectPageDownString))
+    rv = selCont->PageMove(true, true);
   else if (!nsCRT::strcmp(aCommandName, sSelectTopString))
     rv = selCont->CompleteMove(false, true);
   else if (!nsCRT::strcmp(aCommandName, sSelectBottomString))
     rv = selCont->CompleteMove(true, true);
 
   return rv;
 }
 
@@ -941,40 +963,41 @@ nsWindowCommandRegistration::RegisterWin
 {
   nsresult rv;
 
   // XXX rework the macros to use a loop is possible, reducing code size
   
   // this set of commands is affected by the 'browse with caret' setting
   NS_REGISTER_FIRST_COMMAND(nsSelectMoveScrollCommand, sScrollTopString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sScrollBottomString);
+  NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sMoveTopString);
+  NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sMoveBottomString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sWordPreviousString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sWordNextString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sBeginLineString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sEndLineString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sMovePageUpString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sMovePageDownString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sScrollPageUpString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sScrollPageDownString);
-  NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sScrollLineUpString);
-  NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sScrollLineDownString);
-  NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sScrollLeftString);
-  NS_REGISTER_LAST_COMMAND(nsSelectMoveScrollCommand, sScrollRightString);
+  NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sLinePreviousString);
+  NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sLineNextString);
+  NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sCharPreviousString);
+  NS_REGISTER_LAST_COMMAND(nsSelectMoveScrollCommand, sCharNextString);
 
   NS_REGISTER_FIRST_COMMAND(nsSelectCommand, sSelectCharPreviousString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectCharNextString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectWordPreviousString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectWordNextString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectBeginLineString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectEndLineString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectLinePreviousString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectLineNextString);
-  // XXX these commands were never implemented. fix me.
-  // NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectPagePreviousString);
-  // NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectPageNextString);
+  NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectPageUpString);
+  NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectPageDownString);
   NS_REGISTER_NEXT_COMMAND(nsSelectCommand, sSelectTopString);
   NS_REGISTER_LAST_COMMAND(nsSelectCommand, sSelectBottomString);
 
   NS_REGISTER_ONE_COMMAND(nsClipboardCommand, "cmd_cut");
   NS_REGISTER_ONE_COMMAND(nsClipboardCommand, "cmd_copy");
   NS_REGISTER_ONE_COMMAND(nsClipboardCommand, "cmd_paste");
   NS_REGISTER_ONE_COMMAND(nsClipboardCopyLinkCommand, "cmd_copyLink");
   NS_REGISTER_FIRST_COMMAND(nsClipboardImageCommands, sCopyImageLocationString);
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -55,16 +55,17 @@
 #include "IDBEvents.h"
 #include "IDBIndex.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
 #include "IDBFactory.h"
 #include "IndexedDatabaseManager.h"
 #include "LazyIdleThread.h"
 #include "TransactionThreadPool.h"
+#include "DictionaryHelpers.h"
 
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
 class CreateObjectStoreHelper : public AsyncConnectionHelper
 {
 public:
@@ -381,37 +382,27 @@ IDBDatabase::CreateObjectStore(const nsA
 
   if (!transaction ||
       transaction->Mode() != nsIIDBTransaction::VERSION_CHANGE) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   DatabaseInfo* databaseInfo = transaction->DBInfo();
 
+  mozilla::dom::IDBObjectStoreParameters params;
   nsString keyPath;
   keyPath.SetIsVoid(true);
   nsTArray<nsString> keyPathArray;
-  bool autoIncrement = false;
 
   if (!JSVAL_IS_VOID(aOptions) && !JSVAL_IS_NULL(aOptions)) {
-    if (JSVAL_IS_PRIMITIVE(aOptions)) {
-      // XXX This isn't the right error
-      return NS_ERROR_DOM_TYPE_ERR;
-    }
-
-    NS_ASSERTION(JSVAL_IS_OBJECT(aOptions), "Huh?!");
-    JSObject* options = JSVAL_TO_OBJECT(aOptions);
+    nsresult rv = params.Init(aCx, &aOptions);
+    NS_ENSURE_SUCCESS(rv, rv);
 
     // Get keyPath
-    jsval val;
-    if (!JS_GetPropertyById(aCx, options, nsDOMClassInfo::sKeyPath_id, &val)) {
-      NS_WARNING("JS_GetPropertyById failed!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
-
+    jsval val = params.keyPath;
     if (!JSVAL_IS_VOID(val) && !JSVAL_IS_NULL(val)) {
       if (!JSVAL_IS_PRIMITIVE(val) &&
           JS_IsArrayObject(aCx, JSVAL_TO_OBJECT(val))) {
     
         JSObject* obj = JSVAL_TO_OBJECT(val);
     
         jsuint length;
         if (!JS_GetArrayLength(aCx, obj, &length)) {
@@ -453,47 +444,34 @@ IDBDatabase::CreateObjectStore(const nsA
     
         if (!IDBObjectStore::IsValidKeyPath(aCx, str)) {
           return NS_ERROR_DOM_SYNTAX_ERR;
         }
     
         keyPath = str;
       }
     }
-
-    if (!JS_GetPropertyById(aCx, options, nsDOMClassInfo::sAutoIncrement_id,
-                            &val)) {
-      NS_WARNING("JS_GetPropertyById failed!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
-
-    JSBool boolVal;
-    if (!JS_ValueToBoolean(aCx, val, &boolVal)) {
-      NS_WARNING("JS_ValueToBoolean failed!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
-    autoIncrement = !!boolVal;
   }
 
   if (databaseInfo->ContainsStoreName(aName)) {
     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
   }
 
-  if (autoIncrement &&
+  if (params.autoIncrement &&
       ((!keyPath.IsVoid() && keyPath.IsEmpty()) || !keyPathArray.IsEmpty())) {
     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
 
   nsRefPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo());
 
   newInfo->name = aName;
   newInfo->id = databaseInfo->nextObjectStoreId++;
   newInfo->keyPath = keyPath;
   newInfo->keyPathArray = keyPathArray;
-  newInfo->nextAutoIncrementId = autoIncrement ? 1 : 0;
+  newInfo->nextAutoIncrementId = params.autoIncrement ? 1 : 0;
   newInfo->comittedAutoIncrementId = newInfo->nextAutoIncrementId;
 
   if (!databaseInfo->PutObjectStore(newInfo)) {
     NS_WARNING("Put failed!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   // Don't leave this in the hash if we fail below!
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -43,18 +43,17 @@
 
 #include "nsIIDBKeyRange.h"
 #include "nsIJSContextStack.h"
 
 #include "nsDOMClassInfoID.h"
 #include "nsEventDispatcher.h"
 #include "nsThreadUtils.h"
 #include "mozilla/storage.h"
-#include "xpcprivate.h"
-#include "XPCQuickStubs.h"
+#include "xpcpublic.h"
 
 #include "AsyncConnectionHelper.h"
 #include "IDBCursor.h"
 #include "IDBEvents.h"
 #include "IDBKeyRange.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
 #include "DatabaseInfo.h"
@@ -393,30 +392,30 @@ IDBIndex::GetKeyPath(JSContext* aCx,
     if (!array) {
       NS_WARNING("Failed to make array!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     for (PRUint32 i = 0; i < mKeyPathArray.Length(); ++i) {
       jsval val;
       nsString tmp(mKeyPathArray[i]);
-      if (!xpc_qsStringToJsval(aCx, tmp, &val)) {
+      if (!xpc::StringToJsval(aCx, tmp, &val)) {
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
       if (!JS_SetElement(aCx, array, i, &val)) {
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
 
     *aVal = OBJECT_TO_JSVAL(array);
   }
   else {
     nsString tmp(mKeyPath);
-    if (!xpc_qsStringToJsval(aCx, tmp, aVal)) {
+    if (!xpc::StringToJsval(aCx, tmp, aVal)) {
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBIndex::GetUnique(bool* aUnique)
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -50,26 +50,26 @@
 #include "nsDOMFile.h"
 #include "nsDOMLists.h"
 #include "nsEventDispatcher.h"
 #include "nsJSUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "snappy/snappy.h"
 #include "test_quota.h"
-#include "xpcprivate.h"
-#include "XPCQuickStubs.h"
+#include "xpcpublic.h"
 
 #include "AsyncConnectionHelper.h"
 #include "IDBCursor.h"
 #include "IDBEvents.h"
 #include "IDBIndex.h"
 #include "IDBKeyRange.h"
 #include "IDBTransaction.h"
 #include "DatabaseInfo.h"
+#include "DictionaryHelpers.h"
 
 #define FILE_COPY_BUFFER_SIZE 32768
 
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
 class AddHelper : public AsyncConnectionHelper
@@ -559,17 +559,17 @@ IDBObjectStore::IsValidKeyPath(JSContext
   while (tokenizer.hasMoreTokens()) {
     nsString token(tokenizer.nextToken());
 
     if (!token.Length()) {
       return false;
     }
 
     jsval stringVal;
-    if (!xpc_qsStringToJsval(aCx, token, &stringVal)) {
+    if (!xpc::StringToJsval(aCx, token, &stringVal)) {
       return false;
     }
 
     NS_ASSERTION(JSVAL_IS_STRING(stringVal), "This should never happen");
     JSString* str = JSVAL_TO_STRING(stringVal);
 
     JSBool isIdentifier = JS_FALSE;
     if (!JS_IsIdentifier(aCx, str, &isIdentifier) || !isIdentifier) {
@@ -1424,30 +1424,30 @@ IDBObjectStore::GetKeyPath(JSContext* aC
     if (!array) {
       NS_WARNING("Failed to make array!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     for (PRUint32 i = 0; i < mKeyPathArray.Length(); ++i) {
       jsval val;
       nsString tmp(mKeyPathArray[i]);
-      if (!xpc_qsStringToJsval(aCx, tmp, &val)) {
+      if (!xpc::StringToJsval(aCx, tmp, &val)) {
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
       if (!JS_SetElement(aCx, array, i, &val)) {
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
 
     *aVal = OBJECT_TO_JSVAL(array);
   }
   else {
     nsString tmp(mKeyPath);
-    if (!xpc_qsStringToJsval(aCx, tmp, aVal)) {
+    if (!xpc::StringToJsval(aCx, tmp, aVal)) {
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBObjectStore::GetTransaction(nsIIDBTransaction** aTransaction)
@@ -1771,67 +1771,37 @@ IDBObjectStore::CreateIndex(const nsAStr
   }
 
   if (found) {
     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
   }
 
   NS_ASSERTION(mTransaction->IsOpen(), "Impossible!");
 
-  bool unique = false;
-  bool multiEntry = false;
+  mozilla::dom::IDBIndexParameters params;
 
   // Get optional arguments.
   if (!JSVAL_IS_VOID(aOptions) && !JSVAL_IS_NULL(aOptions)) {
-    if (JSVAL_IS_PRIMITIVE(aOptions)) {
-      // XXX Update spec for a real code here
-      return NS_ERROR_DOM_TYPE_ERR;
-    }
-
-    NS_ASSERTION(JSVAL_IS_OBJECT(aOptions), "Huh?!");
-    JSObject* options = JSVAL_TO_OBJECT(aOptions);
-
-    jsval val;
-    if (!JS_GetPropertyById(aCx, options, nsDOMClassInfo::sUnique_id, &val)) {
-      NS_WARNING("JS_GetPropertyById failed!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
-
-    JSBool boolVal;
-    if (!JS_ValueToBoolean(aCx, val, &boolVal)) {
-      NS_WARNING("JS_ValueToBoolean failed!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
-    unique = !!boolVal;
-
-    if (!JS_GetPropertyById(aCx, options, nsDOMClassInfo::sMultiEntry_id, &val)) {
-      NS_WARNING("JS_GetPropertyById failed!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
-
-    if (!JS_ValueToBoolean(aCx, val, &boolVal)) {
-      NS_WARNING("JS_ValueToBoolean failed!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
-    multiEntry = !!boolVal;
+    nsresult rv = params.Init(aCx, &aOptions);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  if (multiEntry && !keyPathArray.IsEmpty()) {
+  if (params.multiEntry && !keyPathArray.IsEmpty()) {
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
 
   DatabaseInfo* databaseInfo = mTransaction->DBInfo();
 
   IndexInfo* indexInfo = mInfo->indexes.AppendElement();
   indexInfo->id = databaseInfo->nextIndexId++;
   indexInfo->name = aName;
   indexInfo->keyPath = keyPath;
   indexInfo->keyPathArray.SwapElements(keyPathArray);
-  indexInfo->unique = unique;
-  indexInfo->multiEntry = multiEntry;
+  indexInfo->unique = params.unique;
+  indexInfo->multiEntry = params.multiEntry;
 
   // Don't leave this in the list if we fail below!
   AutoRemoveIndex autoRemove(mInfo, aName);
 
 #ifdef DEBUG
   for (PRUint32 index = 0; index < mCreatedIndexes.Length(); index++) {
     if (mCreatedIndexes[index]->Name() == aName) {
       NS_ERROR("Already created this one!");
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -51,17 +51,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/storage.h"
 #include "nsContentUtils.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
 #include "test_quota.h"
-#include "xpcprivate.h"
+#include "xpcpublic.h"
 
 #include "AsyncConnectionHelper.h"
 #include "CheckQuotaHelper.h"
 #include "IDBDatabase.h"
 #include "IDBEvents.h"
 #include "IDBFactory.h"
 #include "LazyIdleThread.h"
 #include "OpenDatabaseHelper.h"
--- a/dom/indexedDB/Key.cpp
+++ b/dom/indexedDB/Key.cpp
@@ -37,18 +37,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "Key.h"
 #include "nsIStreamBufferAccess.h"
 #include "jsdate.h"
 #include "nsContentUtils.h"
 #include "nsJSUtils.h"
-#include "xpcprivate.h"
-#include "XPCQuickStubs.h"
+#include "xpcpublic.h"
 
 USING_INDEXEDDB_NAMESPACE
 
 /*
  Here's how we encode keys:
 
  Basic strategy is the following
 
@@ -238,17 +237,17 @@ Key::DecodeJSVal(const unsigned char*& a
                  "Should have found end-of-array marker");
     ++aPos;
 
     *aVal = OBJECT_TO_JSVAL(array);
   }
   else if (*aPos - aTypeOffset == eString) {
     nsString key;
     DecodeString(aPos, aEnd, key);
-    if (!xpc_qsStringToJsval(aCx, key, aVal)) {
+    if (!xpc::StringToJsval(aCx, key, aVal)) {
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
   }
   else if (*aPos - aTypeOffset == eDate) {
     jsdouble msec = static_cast<jsdouble>(DecodeNumber(aPos, aEnd));
     JSObject* date = JS_NewDateObjectMsec(aCx, msec);
     if (!date) {
       NS_WARNING("Failed to make date!");
--- a/dom/indexedDB/Makefile.in
+++ b/dom/indexedDB/Makefile.in
@@ -94,17 +94,16 @@ EXPORTS_mozilla/dom/indexedDB = \
 
 LOCAL_INCLUDES = \
   -I$(topsrcdir)/db/sqlite3/src \
   -I$(topsrcdir)/xpcom/build \
   -I$(topsrcdir)/dom/base \
   -I$(topsrcdir)/dom/src/storage \
   -I$(topsrcdir)/content/base/src \
   -I$(topsrcdir)/content/events/src \
-  -I$(topsrcdir)/js/xpconnect/src \
   $(NULL)
 
 DEFINES += -D_IMPL_NS_LAYOUT
 
 # Make sure to quickstub as much as possible here! See
 # js/xpconnect/src/dom_quickstubs.qsconf.
 XPIDLSRCS = \
   nsIIDBCursor.idl \
--- a/dom/indexedDB/nsIIDBDatabase.idl
+++ b/dom/indexedDB/nsIIDBDatabase.idl
@@ -40,41 +40,41 @@
 #include "nsISupports.idl"
 
 interface nsIIDBObjectStore;
 interface nsIIDBRequest;
 interface nsIIDBTransaction;
 interface nsIDOMDOMStringList;
 interface nsIDOMEventListener;
 
+[scriptable, uuid(fb143548-08d1-43b4-95f2-a1cd58f8db76)]
+interface nsIIDBObjectStoreParameters : nsISupports
+{
+  attribute jsval keyPath;
+  attribute boolean autoIncrement;
+};
+
 /**
  * IDBDatabase interface.  See
  * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBDatabase
  * for more information.
  */
 [scriptable, builtinclass, uuid(bb877dff-ab5b-4ebb-9b3c-a7fa97cd4b51)]
 interface nsIIDBDatabase : nsISupports
 {
   readonly attribute DOMString name;
 
   readonly attribute unsigned long long version;
 
   readonly attribute nsIDOMDOMStringList objectStoreNames;
 
-  /**
-   * Optional arguments:
-   *   - keyPath (string):
-   *       Specifies key path on objects in the objectStore. Defaults to no key
-   *       path.
-   *   - autoIncrement (boolean):
-   *       Specifies if the objectStore has a key generator. Defaults to false.
-   */
   [implicit_jscontext]
   nsIIDBObjectStore
   createObjectStore([Null(Stringify)] in DOMString name,
+                    /* nsIIDBObjectStoreParameters */
                     [optional /* none */] in jsval options);
 
   void
   deleteObjectStore([Null(Stringify)] in DOMString name);
 
   [optional_argc, implicit_jscontext]
   nsIIDBTransaction
   transaction(in jsval storeNames, // js array of strings
--- a/dom/indexedDB/nsIIDBObjectStore.idl
+++ b/dom/indexedDB/nsIIDBObjectStore.idl
@@ -40,16 +40,23 @@
 #include "nsISupports.idl"
 
 interface nsIIDBIndex;
 interface nsIIDBKeyRange;
 interface nsIIDBRequest;
 interface nsIIDBTransaction;
 interface nsIDOMDOMStringList;
 
+[scriptable, uuid(450e02fd-a87a-47d4-beaf-321417dad781)]
+interface nsIIDBIndexParameters : nsISupports
+{
+  attribute boolean unique;
+  attribute boolean multiEntry;
+};
+
 /**
  * nsIIDBObjectStore interface.  See
  * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-nsIIDBObjectStore
  * for more information.
  */
 [scriptable, builtinclass, uuid(e0d308ea-b804-4962-918a-28ec0aa4e42b)]
 interface nsIIDBObjectStore : nsISupports
 {
@@ -98,26 +105,21 @@ interface nsIIDBObjectStore : nsISupport
 
   // Success fires IDBTransactionEvent, result == IDBCursor or result == null if
   // no match.
   [implicit_jscontext, optional_argc]
   nsIIDBRequest
   openCursor([optional /* null */] in jsval range,
              [optional /* NEXT */] in unsigned short direction);
 
-  /**
-   * Optional arguments:
-   *   - unique (boolean):
-   *       Specifies whether values in the index must be unique. Defaults to
-   *       false.
-   */
   [implicit_jscontext]
   nsIIDBIndex
   createIndex([Null(Stringify)] in DOMString name,
               in jsval keyPath,
+              /* nsIIDBIndexParameters */
               [optional /* none */] in jsval options);
 
   // Returns object immediately
   nsIIDBIndex
   index([Null(Stringify)] in DOMString name);
 
   void
   deleteIndex([Null(Stringify)] in DOMString name);
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -64,17 +64,17 @@ interface nsIDOMHTMLCanvasElement;
 interface nsIDOMEvent;
 interface nsITransferable;
 interface nsIQueryContentEventResult;
 interface nsIDOMWindow;
 interface nsIDOMBlob;
 interface nsIDOMFile;
 interface nsIFile;
 
-[scriptable, uuid(3af3c5ce-6f2a-47e7-acd0-555ed576fa82)]
+[scriptable, uuid(9df58cf3-7094-4c8d-96f2-bebd765099fe)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -940,39 +940,45 @@ interface nsIDOMWindowUtils : nsISupport
                             [optional] out long aRefCnt,
                             [optional] out long aDBRefCnt,
                             [optional] out long aSliceRefCnt);
 
   /**
    * Begin opcode-level profiling of all JavaScript execution in the window's
    * runtime.
    */
+  [implicit_jscontext]
   void startPCCountProfiling();
 
   /**
    * Stop opcode-level profiling of JavaScript execution in the runtime, and
    * collect all counts for use by getPCCount methods.
    */
+  [implicit_jscontext]
   void stopPCCountProfiling();
 
   /**
    * Purge collected PC counters.
    */
+  [implicit_jscontext]
   void purgePCCounts();
 
   /**
    * Get the number of scripts with opcode-level profiling information.
    */
+  [implicit_jscontext]
   long getPCCountScriptCount();
 
   /**
    * Get a JSON string for a short summary of a script and the PC counts
    * accumulated for it.
    */
+  [implicit_jscontext]
   AString getPCCountScriptSummary(in long script);
 
   /**
    * Get a JSON string with full information about a profiled script,
    * including the decompilation of the script and placement of decompiled
    * operations within it, and PC counts for each operation.
    */
+  [implicit_jscontext]
   AString getPCCountScriptContents(in long script);
 };
--- a/dom/interfaces/css/nsIDOMCSS2Properties.idl
+++ b/dom/interfaces/css/nsIDOMCSS2Properties.idl
@@ -46,17 +46,17 @@
  * The nsIDOMCSS2Properties interface is a datatype for additional
  * reflection of data already provided in nsIDOMCSSStyleDeclaration in
  * the Document Object Model.
  *
  * For more information on this interface please see
  * http://www.w3.org/TR/DOM-Level-2-Style
  */
 
-[builtinclass, scriptable, uuid(0a6fc4c6-a62a-4f52-9ab6-3d398b958843)]
+[builtinclass, scriptable, uuid(b4afb8f4-d9ab-44d9-9d0c-f765c47d57c2)]
 interface nsIDOMCSS2Properties : nsISupports
 {
            attribute DOMString        background;
                                         // raises(DOMException) on setting
 
            attribute DOMString        backgroundAttachment;
                                         // raises(DOMException) on setting
 
@@ -527,16 +527,19 @@ interface nsIDOMCSS2Properties : nsISupp
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozColumnCount;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozColumnWidth;
                                         // raises(DOMException) on setting
 
+           attribute DOMString        MozColumnFill;
+                                        // raises(DOMException) on setting
+
            attribute DOMString        MozColumnGap;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozFloatEdge;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozFontFeatureSettings;
                                         // raises(DOMException) on setting
@@ -762,9 +765,24 @@ interface nsIDOMCSS2Properties : nsISupp
            attribute DOMString        MozAnimationPlayState;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozAnimation;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozTextSizeAdjust;
                                         // raises(DOMException) on setting
+
+           attribute DOMString        MozBorderImageSource;
+                                        // raises(DOMException) on setting
+
+           attribute DOMString        MozBorderImageSlice;
+                                        // raises(DOMException) on setting
+
+           attribute DOMString        MozBorderImageWidth;
+                                        // raises(DOMException) on setting
+
+           attribute DOMString        MozBorderImageOutset;
+                                        // raises(DOMException) on setting
+
+           attribute DOMString        MozBorderImageRepeat;
+                                        // raises(DOMException) on setting
 };
--- a/dom/sms/Makefile.in
+++ b/dom/sms/Makefile.in
@@ -34,17 +34,20 @@
 #
 # ***** END LICENSE BLOCK *****
 
 DEPTH            = ../..
 topsrcdir        = @top_srcdir@
 srcdir           = @srcdir@
 VPATH            = @srcdir@
 
+relativesrcdir   = dom/sms
+
 include $(DEPTH)/config/autoconf.mk
 
 PARALLEL_DIRS = interfaces src
 
 ifdef ENABLE_TESTS
 DIRS += tests
+XPCSHELL_TESTS = tests
 endif
 
 include $(topsrcdir)/config/rules.mk
--- a/dom/sms/interfaces/nsIDOMSmsMessage.idl
+++ b/dom/sms/interfaces/nsIDOMSmsMessage.idl
@@ -14,16 +14,17 @@
  * The Original Code is mozilla.org.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation
  * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *  Philipp von Weitershausen <philipp@weitershausen.de>
  *
  * 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
@@ -31,17 +32,17 @@
  * 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 "nsISupports.idl"
 
-[scriptable, function, uuid(0a0037ba-585e-41f4-b0a5-1d0224353105)]
+[scriptable, builtinclass, uuid(20da0c51-2224-49ae-afe9-4b309c6d8f84)]
 interface nsIDOMMozSmsMessage : nsISupports
 {
   // TODO: we should add SENT and RECEIVED DOMString constants, see bug 443316.
 
   readonly attribute long      id;
   readonly attribute DOMString delivery;  // Should be "sent" or "received".
   readonly attribute DOMString sender;
   readonly attribute DOMString receiver;
--- a/dom/sms/interfaces/nsISmsService.idl
+++ b/dom/sms/interfaces/nsISmsService.idl
@@ -14,16 +14,17 @@
  * The Original Code is mozilla.org.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation
  * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *  Philipp von Weitershausen <philipp@weitershausen.de>
  *
  * 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
@@ -31,20 +32,30 @@
  * 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 "nsISupports.idl"
 
+interface nsIDOMMozSmsMessage;
+
 %{C++
 #define NS_SMSSERVICE_CID { 0xbada3cb8, 0xa568, 0x4dff, { 0xb5, 0x43, 0x52, 0xbb, 0xb3, 0x14, 0x31, 0x21 } }
 #define SMSSERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1"
 %}
 
-[scriptable, function, uuid(24edea1d-130a-4ae3-9522-0e2a7ee2885d)]
+[scriptable, builtinclass, uuid(a0fbbe74-5d61-4b7e-b7ab-9b5224f9e5e9)]
 interface nsISmsService : nsISupports
 {
   boolean        hasSupport();
   unsigned short getNumberOfMessagesForText(in DOMString text);
             void send(in DOMString number, in DOMString message);
+
+  [implicit_jscontext]
+  nsIDOMMozSmsMessage createSmsMessage(in long      id,
+                                       in DOMString delivery,
+                                       in DOMString sender,
+                                       in DOMString receiver,
+                                       in DOMString body,
+                                       in jsval     timestamp);
 };
--- a/dom/sms/src/Constants.h
+++ b/dom/sms/src/Constants.h
@@ -39,13 +39,16 @@
 #define mozilla_dom_sms_Constants_h
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 extern const char* kSmsReceivedObserverTopic; // Defined in the .cpp.
 
+#define DELIVERY_RECEIVED NS_LITERAL_STRING("received")
+#define DELIVERY_SENT     NS_LITERAL_STRING("sent")
+
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_sms_Constants_h
--- a/dom/sms/src/Makefile.in
+++ b/dom/sms/src/Makefile.in
@@ -41,16 +41,18 @@ VPATH            = \
   $(srcdir) \
   $(srcdir)/ipc \
   $(NULL)
 
 include $(DEPTH)/config/autoconf.mk
 
 ifeq (android,$(MOZ_WIDGET_TOOLKIT))
 VPATH += $(srcdir)/android
+else ifdef MOZ_B2G_RIL
+VPATH += $(srcdir)/ril
 else
 VPATH += $(srcdir)/fallback
 endif
 
 LIBRARY_NAME     = dom_sms_s
 LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
 
@@ -82,11 +84,18 @@ CPPSRCS = \
 LOCAL_INCLUDES = \
   -I$(topsrcdir)/content/events/src \
   $(NULL)
 
 # Add VPATH to LOCAL_INCLUDES so we are going to include the correct backend
 # subdirectory (and the ipc one).
 LOCAL_INCLUDES += $(VPATH:%=-I%)
 
+ifdef MOZ_B2G_RIL
+LOCAL_INCLUDES += \
+  -I$(topsrcdir)/dom/telephony \
+  -I$(topsrcdir)/dom/system/b2g \
+  $(NULL)
+endif
+
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
--- a/dom/sms/src/SmsMessage.cpp
+++ b/dom/sms/src/SmsMessage.cpp
@@ -15,16 +15,17 @@
  * 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) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *   Philipp von Weitershausen <philipp@weitershausen.de>
  *
  * 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
@@ -33,16 +34,17 @@
  * 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 "SmsMessage.h"
 #include "nsIDOMClassInfo.h"
 #include "jsapi.h" // For OBJECT_TO_JSVAL and JS_NewDateObjectMsec
+#include "jsdate.h" // For js_DateGetMsecSinceEpoch
 #include "Constants.h"
 
 DOMCI_DATA(MozSmsMessage, mozilla::dom::sms::SmsMessage)
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
@@ -55,16 +57,67 @@ NS_INTERFACE_MAP_END
 NS_IMPL_ADDREF(SmsMessage)
 NS_IMPL_RELEASE(SmsMessage)
 
 SmsMessage::SmsMessage(const SmsMessageData& aData)
   : mData(aData)
 {
 }
 
+/* static */ nsresult
+SmsMessage::Create(PRInt32 aId,
+                   const nsAString& aDelivery,
+                   const nsAString& aSender,
+                   const nsAString& aReceiver,
+                   const nsAString& aBody,
+                   const jsval& aTimestamp,
+                   JSContext* aCx,
+                   nsIDOMMozSmsMessage** aMessage)
+{
+  *aMessage = nsnull;
+
+  // SmsMessageData exposes these as references, so we can simply assign
+  // to them.
+  SmsMessageData data;
+  data.id() = aId;
+  data.sender() = nsString(aSender);
+  data.receiver() = nsString(aReceiver);
+  data.body() = nsString(aBody);
+
+  if (aDelivery.Equals(DELIVERY_RECEIVED)) {
+    data.delivery() = eDeliveryState_Received;
+  } else if (aDelivery.Equals(DELIVERY_SENT)) {
+    data.delivery() = eDeliveryState_Sent;
+  } else {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  // We support both a Date object and a millisecond timestamp as a number.
+  if (aTimestamp.isObject()) {
+    JSObject& obj = aTimestamp.toObject();
+    if (!JS_ObjectIsDate(aCx, &obj)) {
+      return NS_ERROR_INVALID_ARG;
+    }
+    data.timestamp() = js_DateGetMsecSinceEpoch(aCx, &obj);
+  } else {
+    if (!aTimestamp.isNumber()) {
+      return NS_ERROR_INVALID_ARG;
+    }
+    jsdouble number = aTimestamp.toNumber();
+    if (static_cast<PRUint64>(number) != number) {
+      return NS_ERROR_INVALID_ARG;
+    }
+    data.timestamp() = static_cast<PRUint64>(number);
+  }
+
+  nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(data);
+  message.swap(*aMessage);
+  return NS_OK;
+}
+
 const SmsMessageData&
 SmsMessage::GetData() const
 {
   return mData;
 }
 
 NS_IMETHODIMP
 SmsMessage::GetId(PRInt32* aId)
--- a/dom/sms/src/SmsMessage.h
+++ b/dom/sms/src/SmsMessage.h
@@ -36,29 +36,38 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_sms_SmsMessage_h
 #define mozilla_dom_sms_SmsMessage_h
 
 #include "mozilla/dom/sms/PSms.h"
 #include "nsIDOMSmsMessage.h"
 #include "nsString.h"
+#include "jspubtd.h"
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 class SmsMessage : public nsIDOMMozSmsMessage
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMMOZSMSMESSAGE
 
   SmsMessage(const SmsMessageData& aData);
 
+  static nsresult Create(PRInt32 aId,
+                         const nsAString& aDelivery,
+                         const nsAString& aSender,
+                         const nsAString& aReceiver,
+                         const nsAString& aBody,
+                         const JS::Value& aTimestamp,
+                         JSContext* aCx,
+                         nsIDOMMozSmsMessage** aMessage);
   const SmsMessageData& GetData() const;
 
 private:
   // Don't try to use the default constructor.
   SmsMessage();
 
   SmsMessageData mData;
 };
--- a/dom/sms/src/android/SmsService.cpp
+++ b/dom/sms/src/android/SmsService.cpp
@@ -15,33 +15,36 @@
  * 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) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *   Philipp von Weitershausen <philipp@weitershausen.de>
  *
  * 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 "mozilla/dom/sms/SmsMessage.h"
 #include "SmsService.h"
 #include "AndroidBridge.h"
+#include "jsapi.h"
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 NS_IMPL_ISUPPORTS1(SmsService, nsISmsService)
 
 NS_IMETHODIMP
@@ -69,11 +72,25 @@ SmsService::Send(const nsAString& aNumbe
   if (!AndroidBridge::Bridge()) {
     return NS_OK;
   }
 
   AndroidBridge::Bridge()->SendMessage(aNumber, aMessage);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+SmsService::CreateSmsMessage(PRInt32 aId,
+                             const nsAString& aDelivery,
+                             const nsAString& aSender,
+                             const nsAString& aReceiver,
+                             const nsAString& aBody,
+                             const jsval& aTimestamp,
+                             JSContext* aCx,
+                             nsIDOMMozSmsMessage** aMessage)
+{
+  return SmsMessage::Create(
+    aId, aDelivery, aSender, aReceiver, aBody, aTimestamp, aCx, aMessage);
+}
+
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
--- a/dom/sms/src/fallback/SmsService.cpp
+++ b/dom/sms/src/fallback/SmsService.cpp
@@ -15,32 +15,35 @@
  * 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) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *   Philipp von Weitershausen <philipp@weitershausen.de>
  *
  * 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 "mozilla/dom/sms/SmsMessage.h"
 #include "SmsService.h"
+#include "jsapi.h"
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 NS_IMPL_ISUPPORTS1(SmsService, nsISmsService)
 
 NS_IMETHODIMP
@@ -60,11 +63,25 @@ SmsService::GetNumberOfMessagesForText(c
 
 NS_IMETHODIMP
 SmsService::Send(const nsAString& aNumber, const nsAString& aMessage)
 {
   NS_ERROR("We should not be here!");
   return NS_OK;
 }
 
+NS_IMETHODIMP
+SmsService::CreateSmsMessage(PRInt32 aId,
+                             const nsAString& aDelivery,
+                             const nsAString& aSender,
+                             const nsAString& aReceiver,
+                             const nsAString& aBody,
+                             const jsval& aTimestamp,
+                             JSContext* aCx,
+                             nsIDOMMozSmsMessage** aMessage)
+{
+  return SmsMessage::Create(
+    aId, aDelivery, aSender, aReceiver, aBody, aTimestamp, aCx, aMessage);
+}
+
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
--- a/dom/sms/src/ipc/SmsIPCService.cpp
+++ b/dom/sms/src/ipc/SmsIPCService.cpp
@@ -33,17 +33,19 @@
  * 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 "mozilla/dom/ContentChild.h"
 #include "SmsIPCService.h"
 #include "nsXULAppAPI.h"
+#include "jsapi.h"
 #include "mozilla/dom/sms/SmsChild.h"
+#include "mozilla/dom/sms/SmsMessage.h"
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 PSmsChild* SmsIPCService::sSmsChild = nsnull;
 
 NS_IMPL_ISUPPORTS1(SmsIPCService, nsISmsService)
@@ -77,11 +79,25 @@ SmsIPCService::GetNumberOfMessagesForTex
 NS_IMETHODIMP
 SmsIPCService::Send(const nsAString& aNumber, const nsAString& aMessage)
 {
   GetSmsChild()->SendSendMessage(nsString(aNumber), nsString(aMessage));
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+SmsIPCService::CreateSmsMessage(PRInt32 aId,
+                                const nsAString& aDelivery,
+                                const nsAString& aSender,
+                                const nsAString& aReceiver,
+                                const nsAString& aBody,
+                                const jsval& aTimestamp,
+                                JSContext* aCx,
+                                nsIDOMMozSmsMessage** aMessage)
+{
+  return SmsMessage::Create(
+    aId, aDelivery, aSender, aReceiver, aBody, aTimestamp, aCx, aMessage);
+}
+
 } // namespace sms
 } // namespace dom
 } // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/ril/SmsService.cpp
@@ -0,0 +1,102 @@
+/* ***** 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 SMS DOM API.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Philipp von Weitershausen <philipp@weitershausen.de>
+ *
+ * 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 "mozilla/dom/sms/SmsMessage.h"
+#include "SmsService.h"
+#include "RadioManager.h"
+#include "jsapi.h"
+
+using mozilla::dom::telephony::RadioManager;
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+NS_IMPL_ISUPPORTS1(SmsService, nsISmsService)
+
+SmsService::SmsService()
+  : mRIL(RadioManager::GetTelephone())
+{
+}
+
+NS_IMETHODIMP
+SmsService::HasSupport(bool* aHasSupport)
+{
+  *aHasSupport = true;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsService::GetNumberOfMessagesForText(const nsAString& aText, PRUint16* aResult)
+{
+  if (!mRIL) {
+    *aResult = 0;
+    return NS_OK;
+  }
+
+  mRIL->GetNumberOfMessagesForText(aText, aResult);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsService::Send(const nsAString& aNumber, const nsAString& aMessage)
+{
+  if (!mRIL) {
+    return NS_OK;
+  }
+
+  mRIL->SendSMS(aNumber, aMessage);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SmsService::CreateSmsMessage(PRInt32 aId,
+                             const nsAString& aDelivery,
+                             const nsAString& aSender,
+                             const nsAString& aReceiver,
+                             const nsAString& aBody,
+                             const jsval& aTimestamp,
+                             JSContext* aCx,
+                             nsIDOMMozSmsMessage** aMessage)
+{
+  return SmsMessage::Create(
+    aId, aDelivery, aSender, aReceiver, aBody, aTimestamp, aCx, aMessage);
+}
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/sms/src/ril/SmsService.h
@@ -0,0 +1,64 @@
+/* ***** 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 SMS DOM API.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Philipp von Weitershausen <philipp@weitershausen.de>
+ *
+ * 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 mozilla_dom_sms_SmsService_h
+#define mozilla_dom_sms_SmsService_h
+
+#include "nsISmsService.h"
+#include "nsCOMPtr.h"
+#include "nsITelephone.h"
+
+namespace mozilla {
+namespace dom {
+namespace sms {
+
+class SmsService : public nsISmsService
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISMSSERVICE
+  SmsService();
+
+protected:
+  nsCOMPtr<nsITelephone> mRIL;
+};
+
+} // namespace sms
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_sms_SmsService_h
new file mode 100644
--- /dev/null
+++ b/dom/sms/tests/test_smsservice_createsmsmessage.js
@@ -0,0 +1,165 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+function do_check_throws(f, result, stack) {
+  if (!stack) {
+    stack = Components.stack.caller;
+  }
+
+  try {
+    f();
+  } catch (exc) {
+    if (exc.result == result)
+      return;
+    do_throw("expected result " + result + ", caught " + exc, stack);
+  }
+  do_throw("expected result " + result + ", none thrown", stack);
+}
+
+let gSmsService = Cc["@mozilla.org/sms/smsservice;1"]
+                    .getService(Ci.nsISmsService);
+function newMessage() {
+  return gSmsService.createSmsMessage.apply(gSmsService, arguments);
+}
+
+function run_test() {
+  run_next_test();
+}
+
+/**
+ * Ensure an SmsMessage object created has sensible initial values.
+ */
+add_test(function test_interface() {
+  let sms = newMessage(null, "sent", null, null, null, new Date());
+  do_check_true(sms instanceof Ci.nsIDOMMozSmsMessage);
+  do_check_eq(sms.id, 0);
+  do_check_eq(sms.delivery, "sent");
+  do_check_eq(sms.receiver, null);
+  do_check_eq(sms.sender, null);
+  do_check_eq(sms.body, null);
+  do_check_true(sms.timestamp instanceof Date);
+  run_next_test();
+});
+
+/**
+ * Verify that attributes are read-only.
+ */
+add_test(function test_readonly_attributes() {
+  let sms = newMessage(null, "received", null, null, null, new Date());
+
+  sms.id = 1;
+  do_check_eq(sms.id, 0);
+
+  sms.delivery = "sent";
+  do_check_eq(sms.delivery, "received");
+
+  sms.receiver = "a receiver";
+  do_check_eq(sms.receiver, null);
+
+  sms.sender = "a sender";
+  do_check_eq(sms.sender, null);
+
+  sms.body = "a body";
+  do_check_eq(sms.body, null);
+
+  let oldTimestamp = sms.timestamp.getTime();
+  sms.timestamp = new Date();
+  do_check_eq(sms.timestamp.getTime(), oldTimestamp);
+
+  run_next_test();
+});
+
+/**
+ * Test supplying the timestamp as a number of milliseconds.
+ */
+add_test(function test_timestamp_number() {
+  let ts = Date.now();
+  let sms = newMessage(42, "sent", "the sender", "the receiver", "the body", ts);
+  do_check_eq(sms.id, 42);
+  do_check_eq(sms.delivery, "sent");
+  do_check_eq(sms.sender, "the sender");
+  do_check_eq(sms.receiver, "the receiver");
+  do_check_eq(sms.body, "the body");
+  do_check_true(sms.timestamp instanceof Date);
+  do_check_eq(sms.timestamp.getTime(), ts);
+  run_next_test();
+});
+
+/**
+ * Test supplying the timestamp as a Date object.
+ */
+add_test(function test_timestamp_date() {
+  let date = new Date();
+  let sms = newMessage(42, "sent", "the sender", "the receiver", "the body", date);
+  do_check_eq(sms.id, 42);
+  do_check_eq(sms.delivery, "sent");
+  do_check_eq(sms.sender, "the sender");
+  do_check_eq(sms.receiver, "the receiver");
+  do_check_eq(sms.body, "the body");
+  do_check_true(sms.timestamp instanceof Date);
+  do_check_eq(sms.timestamp.getTime(), date.getTime());
+  run_next_test();
+});
+
+/**
+ * Test that a floating point number for the timestamp is not allowed.
+ */
+add_test(function test_invalid_timestamp_float() {
+  do_check_throws(function() {
+    newMessage(42, "sent", "the sender", "the receiver", "the body", 3.1415);
+  }, Cr.NS_ERROR_INVALID_ARG);
+  run_next_test();
+});
+
+/**
+ * Test that a null value for the timestamp is not allowed.
+ */
+add_test(function test_invalid_timestamp_null() {
+  do_check_throws(function() {
+    newMessage(42, "sent", "the sender", "the receiver", "the body", null);
+  }, Cr.NS_ERROR_INVALID_ARG);
+  run_next_test();
+});
+
+/**
+ * Test that undefined for the timestamp is not allowed.
+ */
+add_test(function test_invalid_timestamp_undefined() {
+  do_check_throws(function() {
+    newMessage(42, "sent", "the sender", "the receiver", "the body", undefined);
+  }, Cr.NS_ERROR_INVALID_ARG);
+  run_next_test();
+});
+
+/**
+ * Test that a random object for the timestamp is not allowed.
+ */
+add_test(function test_invalid_timestamp_object() {
+  do_check_throws(function() {
+    newMessage(42, "sent", "the sender", "the receiver", "the body", {});
+  }, Cr.NS_ERROR_INVALID_ARG);
+  run_next_test();
+});
+
+/**
+ * Test that an invalid delivery string is not accepted.
+ */
+add_test(function test_invalid_delivery_string() {
+  do_check_throws(function() {
+    newMessage(42, "this is invalid", "the sender", "the receiver", "the body",
+               new Date());
+  }, Cr.NS_ERROR_INVALID_ARG);
+  run_next_test();
+});
+
+/**
+ * Test that a number is not accepted for the 'delivery' argument.
+ */
+add_test(function test_invalid_delivery_string() {
+  do_check_throws(function() {
+    newMessage(42, 1, "the sender", "the receiver", "the body", new Date());
+  }, Cr.NS_ERROR_INVALID_ARG);
+  run_next_test();
+});
new file mode 100644
--- /dev/null
+++ b/dom/sms/tests/xpcshell.ini
@@ -0,0 +1,5 @@
+[DEFAULT]
+head = 
+tail = 
+
+[test_smsservice_createsmsmessage.js]
--- a/dom/telephony/nsITelephone.idl
+++ b/dom/telephony/nsITelephone.idl
@@ -33,35 +33,44 @@
  * 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 "nsISupports.idl"
 
 [scriptable, uuid(9b7e3a01-9c45-4af3-81bb-1bf08a842226)]
-interface nsITelephoneCallback : nsISupports {
+interface nsITelephoneCallback : nsISupports
+{
   void oncallstatechange(in jsval event);
 
   //XXX philikon's additions
   void onoperatorchange(in jsval event);
   void onradiostatechange(in jsval event);
   void oncardstatechange(in jsval event);
   void onsignalstrengthchange(in jsval event);
 };
 
-[scriptable, uuid(f6baa721-665e-403e-8a98-acaa0d8bf267)]
-interface nsITelephone : nsISupports {
+[scriptable, uuid(5be6e41d-3aee-4f5c-8284-95cf529dd6fe)]
+interface nsITelephone : nsISupports
+{
+  readonly attribute jsval currentState;
+  void registerCallback(in nsITelephoneCallback callback);
+  void unregisterCallback(in nsITelephoneCallback callback);
 
-  readonly attribute jsval currentState;
-
+  /**
+   * Functionality for making and managing phone calls.
+   */
   void dial(in DOMString number);
   void hangUp(in long callIndex);
   void startTone(in DOMString dtmfChar);
   void stopTone();
   void answerCall();
   void rejectCall();
   attribute bool microphoneMuted;
   attribute bool speakerEnabled;
 
-  void registerCallback(in nsITelephoneCallback callback);
-  void unregisterCallback(in nsITelephoneCallback callback);
+  /**
+   * SMS-related functionality.
+   */
+  unsigned short getNumberOfMessagesForText(in DOMString text);
+  void sendSMS(in DOMString number, in DOMString message);
 };
--- a/dom/telephony/nsTelephonyWorker.js
+++ b/dom/telephony/nsTelephonyWorker.js
@@ -34,16 +34,17 @@
  * 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 ***** */
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
 
 const DEBUG = true; // set to false to suppress debug messages
 
 const TELEPHONYWORKER_CONTRACTID = "@mozilla.org/telephony/worker;1";
 const TELEPHONYWORKER_CID        = Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
 
 const DOM_CALL_READYSTATE_DIALING        = "dialing";
 const DOM_CALL_READYSTATE_RINGING        = "ringing";
@@ -51,16 +52,22 @@ const DOM_CALL_READYSTATE_BUSY          
 const DOM_CALL_READYSTATE_CONNECTING     = "connecting";
 const DOM_CALL_READYSTATE_CONNECTED      = "connected";
 const DOM_CALL_READYSTATE_DISCONNECTING  = "disconnecting";
 const DOM_CALL_READYSTATE_DISCONNECTED   = "disconnected";
 const DOM_CALL_READYSTATE_INCOMING       = "incoming";
 const DOM_CALL_READYSTATE_HOLDING        = "holding";
 const DOM_CALL_READYSTATE_HELD           = "held";
 
+const kSmsReceivedObserverTopic          = "sms-received";
+const DOM_SMS_DELIVERY_RECEIVED          = "received";
+
+XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
+                                   "@mozilla.org/sms/smsservice;1",
+                                   "nsISmsService");
 
 /**
  * Fake nsIAudioManager implementation so that we can run the telephony
  * code in a non-Gonk build.
  */
 let FakeAudioManager = {
   microphoneMuted: false,
   masterVolume: 1.0,
@@ -151,16 +158,19 @@ nsTelephonyWorker.prototype = {
         this.currentState.radioState = message.radioState;
         break;
       case "cardstatechange":
         this.currentState.cardState = message.cardState;
         break;
       case "callstatechange":
         this.handleCallState(message);
         break;
+      case "sms-received":
+        this.handleSmsReceived(message);
+        break;
       default:
         // Got some message from the RIL worker that we don't know about.
         return;
     }
     let methodname = "on" + message.type;
     this._callbacks.forEach(function (callback) {
       let method = callback[methodname];
       if (typeof method != "function") {
@@ -211,16 +221,27 @@ nsTelephonyWorker.prototype = {
         break;
       case DOM_CALL_READYSTATE_DISCONNECTED:
         this.worker.postMessage({type: "setMute", mute: true});
         gAudioManager.phoneState = Ci.nsIAudioManager.PHONE_STATE_NORMAL;
         break;
     }
   },
 
+  handleSmsReceived: function handleSmsReceived(message) {
+    //TODO: put the sms into a database, assign it a proper id, yada yada
+    let sms = gSmsService.createSmsMessage(-1,
+                                           DOM_SMS_DELIVERY_RECEIVED,
+                                           message.sender || null,
+                                           message.receiver || null,
+                                           message.body || null,
+                                           message.timestamp);
+    Services.obs.notifyObservers(sms, kSmsReceivedObserverTopic, null);
+  },
+
   // nsIRadioWorker
 
   worker: null,
 
   // nsITelephone
 
   currentState: null,
 
@@ -274,16 +295,29 @@ nsTelephonyWorker.prototype = {
       return;
     }
     gAudioManager.phoneState = Ci.nsIAudioManager.PHONE_STATE_IN_CALL; // XXX why is this needed?
     let force = value ? Ci.nsIAudioManager.FORCE_SPEAKER :
                         Ci.nsIAudioManager.FORCE_NONE;
     gAudioManager.setForceUse(Ci.nsIAudioManager.USE_COMMUNICATION, force);
   },
 
+  getNumberOfMessagesForText: function getNumberOfMessagesForText(text) {
+    //TODO: this assumes 7bit encoding, which is incorrect. Need to look
+    // for characters not supported by 7bit alphabets and then calculate
+    // length in UCS2 encoding.
+    return Math.ceil(text.length / 160);
+  },
+
+  sendSMS: function sendSMS(number, message) {
+    this.worker.postMessage({type: "sendSMS",
+                             number: number,
+                             body: message});
+  },
+
   _callbacks: null,
 
   registerCallback: function registerCallback(callback) {
     this._callbacks.push(callback);
   },
 
   unregisterCallback: function unregisterCallback(callback) {
     let index = this._callbacks.indexOf(callback);
--- a/dom/telephony/ril_consts.js
+++ b/dom/telephony/ril_consts.js
@@ -16,16 +16,17 @@
  * The Initial Developer of the Original Code is
  * the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Kyle Machulis <kyle@nonpolynomial.com>
  *   Philipp von Weitershausen <philipp@weitershausen.de>
+ *   Fernando Jimenez <ferjmoreno@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
@@ -200,16 +201,18 @@ const CALL_STATE_WAITING = 5;
 const TOA_INTERNATIONAL = 0x91;
 const TOA_UNKNOWN = 0x81;
 
 const CALL_PRESENTATION_ALLOWED = 0;
 const CALL_PRESENTATION_RESTRICTED = 1;
 const CALL_PRESENTATION_UNKNOWN = 2;
 const CALL_PRESENTATION_PAYPHONE = 3;
 
+const SMS_HANDLED = 0;
+
 
 /**
  * DOM constants
  */
 
 const DOM_RADIOSTATE_UNAVAILABLE   = "unavailable";
 const DOM_RADIOSTATE_OFF           = "off";
 const DOM_RADIOSTATE_READY         = "ready";
@@ -236,8 +239,177 @@ const DOM_CALL_READYSTATE_HELD          
 const RIL_TO_DOM_CALL_STATE = [
   DOM_CALL_READYSTATE_CONNECTED, // CALL_READYSTATE_ACTIVE
   DOM_CALL_READYSTATE_HELD,      // CALL_READYSTATE_HOLDING
   DOM_CALL_READYSTATE_DIALING,   // CALL_READYSTATE_DIALING
   DOM_CALL_READYSTATE_RINGING,   // CALL_READYSTATE_ALERTING
   DOM_CALL_READYSTATE_INCOMING,  // CALL_READYSTATE_INCOMING
   DOM_CALL_READYSTATE_HELD       // CALL_READYSTATE_WAITING (XXX is this right?)
 ];
+
+
+/**
+ * GSM PDU constants
+ */
+
+// PDU TYPE-OF-ADDRESS
+const PDU_TOA_UNKNOWN       = 0x80; // Unknown. This is used when the user or
+                                    // network has no a priori information
+                                    // about the numbering plan.
+const PDU_TOA_ISDN          = 0x81; // ISDN/Telephone numbering
+const PDU_TOA_DATA_NUM      = 0x83; // Data numbering plan
+const PDU_TOA_TELEX_NUM     = 0x84; // Telex numbering plan
+const PDU_TOA_NATIONAL_NUM  = 0x88; // National numbering plan
+const PDU_TOA_PRIVATE_NUM   = 0x89; // Private numbering plan
+const PDU_TOA_ERMES_NUM     = 0x8A; // Ermes numbering plan
+const PDU_TOA_INTERNATIONAL = 0x90; // International number
+const PDU_TOA_NATIONAL      = 0xA0; // National number. Prefix or escape digits
+                                    // shall not be included
+const PDU_TOA_NETWORK_SPEC  = 0xB0; // Network specific number This is used to
+                                    // indicate administration/service number
+                                    // specific to the serving network
+const PDU_TOA_SUSCRIBER     = 0xC0; // Suscriber number. This is used when a
+                                    // specific short number representation is
+                                    // stored in one or more SCs as part of a
+                                    // higher layer application
+const PDU_TOA_ALPHANUMERIC  = 0xD0; // Alphanumeric, (coded according to GSM TS
+                                    // 03.38 7-bit default alphabet)
+const PDU_TOA_ABBREVIATED   = 0xE0; // Abbreviated number
+
+/**
+ * First octet of the SMS-DELIVER PDU
+ *
+ * RP:     0   Reply Path parameter is not set in this PDU
+ *         1   Reply Path parameter is set in this PDU
+ *
+ * UDHI:   0   The UD field contains only the short message
+ *         1   The beginning of the UD field contains a header in addition of
+ *             the short message
+ *
+ * SRI: (is only set by the SMSC)
+ *         0    A status report will not be returned to the SME
+ *         1    A status report will be returned to the SME
+ *
+ * MMS: (is only set by the SMSC)
+ *         0    More messages are waiting for the MS in the SMSC
+ *         1    No more messages are waiting for the MS in the SMSC
+ *
+ * MTI:   bit1    bit0    Message type
+ *         0       0       SMS-DELIVER (SMSC ==> MS)
+ *         0       0       SMS-DELIVER REPORT (MS ==> SMSC, is generated
+ *                         automatically by the M20, after receiving a
+ *                         SMS-DELIVER)
+ *         0       1       SMS-SUBMIT (MS ==> SMSC)
+ *         0       1       SMS-SUBMIT REPORT (SMSC ==> MS)
+ *         1       0       SMS-STATUS REPORT (SMSC ==> MS)
+ *         1       0       SMS-COMMAND (MS ==> SMSC)
+ *         1       1       Reserved
+ */
+const PDU_RP    = 0x80;       // Reply path. Parameter indicating that
+                              // reply path exists.
+const PDU_UDHI  = 0x40;       // User data header indicator. This bit is
+                              // set to 1 if the User Data field starts
+                              // with a header
+const PDU_SRI_SRR = 0x20;     // Status report indication (SMS-DELIVER)
+                              // or request (SMS-SUBMIT)
+const PDU_VPF_ABSOLUTE = 0x18;// Validity period aboslute format
+                              // (SMS-SUBMIT only)
+const PDU_VPF_RELATIVE = 0x10;// Validity period relative format
+                              // (SMS-SUBMIT only)
+const PDU_VPF_ENHANCED = 0x8; // Validity period enhance format
+                              // (SMS-SUBMIT only)
+const PDU_MMS_RD       = 0x04;// More messages to send. (SMS-DELIVER only) or
+                              // Reject duplicates (SMS-SUBMIT only)
+
+// MTI - Message Type Indicator
+const PDU_MTI_SMS_STATUS_COMMAND  = 0x02;
+const PDU_MTI_SMS_SUBMIT          = 0x01;
+const PDU_MTI_SMS_DELIVER         = 0x00;
+
+// User Data max length in octets
+const PDU_MAX_USER_DATA_7BIT = 160;
+
+// DCS - Data Coding Scheme
+const PDU_DCS_MSG_CODING_7BITS_ALPHABET = 0x00;
+const PDU_DCS_MSG_CODING_8BITS_ALPHABET = 0x04;
+const PDU_DCS_MSG_CODING_16BITS_ALPHABET= 0x08;
+const PDU_DCS_MSG_CLASS_ME_SPECIFIC     = 0xF1;
+const PDU_DCS_MSG_CLASS_SIM_SPECIFIC    = 0xF2;
+const PDU_DCS_MSG_CLASS_TE_SPECIFIC     = 0xF3;
+
+// Because service center timestamp omit the century. Yay.
+const PDU_TIMESTAMP_YEAR_OFFSET = 2000;
+
+// 7bit Default Alphabet
+//TODO: maybe convert this to a string? might be faster/cheaper
+const PDU_ALPHABET_7BIT_DEFAULT = [
+  "@",      // COMMERCIAL AT
+  "\xa3",   // POUND SIGN
+  "$",      // DOLLAR SIGN
+  "\xa5",   // YEN SIGN
+  "\xe8",   // LATIN SMALL LETTER E WITH GRAVE
+  "\xe9",   // LATIN SMALL LETTER E WITH ACUTE
+  "\xf9",   // LATIN SMALL LETTER U WITH GRAVE
+  "\xec",   // LATIN SMALL LETTER I WITH GRAVE
+  "\xf2",   // LATIN SMALL LETTER O WITH GRAVE
+  "\xc7",   // LATIN CAPITAL LETTER C WITH CEDILLA
+  "\n",     // LINE FEED
+  "\xd8",   // LATIN CAPITAL LETTER O WITH STROKE
+  "\xf8",   // LATIN SMALL LETTER O WITH STROKE
+  "\r",     // CARRIAGE RETURN
+  "\xc5",   // LATIN CAPITAL LETTER A WITH RING ABOVE
+  "\xe5",   // LATIN SMALL LETTER A WITH RING ABOVE
+  "\u0394", // GREEK CAPITAL LETTER DELTA
+  "_",      // LOW LINE
+  "\u03a6", // GREEK CAPITAL LETTER PHI
+  "\u0393", // GREEK CAPITAL LETTER GAMMA
+  "\u039b", // GREEK CAPITAL LETTER LAMBDA
+  "\u03a9", // GREEK CAPITAL LETTER OMEGA
+  "\u03a0", // GREEK CAPITAL LETTER PI
+  "\u03a8", // GREEK CAPITAL LETTER PSI
+  "\u03a3", // GREEK CAPITAL LETTER SIGMA
+  "\u0398", // GREEK CAPITAL LETTER THETA
+  "\u039e", // GREEK CAPITAL LETTER XI
+  "\u20ac", // (escape to extension table)
+  "\xc6",   // LATIN CAPITAL LETTER AE
+  "\xe6",   // LATIN SMALL LETTER AE
+  "\xdf",   // LATIN SMALL LETTER SHARP S (German)
+  "\xc9",   // LATIN CAPITAL LETTER E WITH ACUTE
+  " ",      // SPACE
+  "!",      // EXCLAMATION MARK
+  "\"",     // QUOTATION MARK
+  "#",      // NUMBER SIGN
+  "\xa4",   // CURRENCY SIGN
+  "%",      // PERCENT SIGN
+  "&",      // AMPERSAND
+  "'",      // APOSTROPHE
+  "(",      // LEFT PARENTHESIS
+  ")",      // RIGHT PARENTHESIS
+  "*",      // ASTERISK
+  "+",      // PLUS SIGN
+  ",",      // COMMA
+  "-",      // HYPHEN-MINUS
+  ".",      // FULL STOP
+  "/",      // SOLIDUS (SLASH)
+  "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
+  ":",      // COLON
+  ";",      // SEMICOLON
+  "<",      // LESS-THAN SIGN
+  "=",      // EQUALS SIGN
+  ">",      // GREATER-THAN SIGN
+  "?",      // QUESTION MARK
+  "\xa1",   // INVERTED EXCLAMATION MARK
+  "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
+  "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
+  "\xc4",   // LATIN CAPITAL LETTER A WITH DIAERESIS
+  "\xd6",   // LATIN CAPITAL LETTER O WITH DIAERESIS
+  "\xd1",   // LATIN CAPITAL LETTER N WITH TILDE
+  "\xdc",   // LATIN CAPITAL LETTER U WITH DIAERESIS
+  "\xa7",   // SECTION SIGN
+  "\xbf",   // INVERTED QUESTION MARK
+  "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
+  "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
+  "\xe4",   // LATIN SMALL LETTER A WITH DIAERESIS
+  "\xf6",   // LATIN SMALL LETTER O WITH DIAERESIS
+  "\xf1",   // LATIN SMALL LETTER N WITH TILDE
+  "\xfc",   // LATIN SMALL LETTER U WITH DIAERESIS
+  "\xe0"    // LATIN SMALL LETTER A WITH GRAVE
+];
--- a/dom/telephony/ril_worker.js
+++ b/dom/telephony/ril_worker.js
@@ -16,16 +16,17 @@
  * The Initial Developer of the Original Code is
  * the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Kyle Machulis <kyle@nonpolynomial.com>
  *   Philipp von Weitershausen <philipp@weitershausen.de>
+ *   Fernando Jimenez <ferjmoreno@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
@@ -403,17 +404,17 @@ let Buf = {
         }
         debug("Parcel (size " + this.currentParcelSize + "): " + parcel);
       }
 
       if (DEBUG) debug("We have at least one complete parcel.");
       try {
         this.processParcel();
       } catch (ex) {
-        if (DEBUG) debug("Parcel handling threw " + 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");
@@ -664,28 +665,51 @@ let RIL = {
     Buf.simpleRequest(REQUEST_UDUB);
   },
 
   /**
    * Send an SMS.
    *
    * @param smscPDU
    *        String containing the SMSC PDU in hex format.
-   * @param pdu
-   *        String containing the PDU in hex format.
+   * @param address
+   *        String containing the recipients address.
+   * @param body
+   *        String containing the message body.
+   * @param dcs
+   *        Data coding scheme. One of the PDU_DCS_MSG_CODING_*BITS_ALPHABET
+   *        constants.
+   * @param bodyLengthInOctets
+   *        Byte length of the message body when encoded with the given DCS.
    */
-  sendSMS: function sendSMS(smscPDU, pdu) {
+  sendSMS: function sendSMS(smscPDU, address, body, dcs, bodyLengthInOctets) {
     let token = Buf.newParcel(REQUEST_SEND_SMS);
     //TODO we want to map token to the input values so that on the
     // response from the RIL device we know which SMS request was successful
     // or not. Maybe we should build that functionality into newParcel() and
     // handle it within tokenRequestMap[].
     Buf.writeUint32(2);
     Buf.writeString(smscPDU);
-    Buf.writeString(pdu);
+    GsmPDUHelper.writeMessage(address, body, dcs, bodyLengthInOctets);
+    Buf.sendParcel();
+  },
+
+  /**
+   * Acknowledge the receipt and handling of an SMS.
+   *
+   * @param success
+   *        Boolean indicating whether the message was successfuly handled.
+   * @param cause
+   *        SMS_* constant indicating the reason for unsuccessful handling.
+   */
+  acknowledgeSMS: function acknowledgeSMS(success, cause) {
+    let token = Buf.newParcel(REQUEST_SMS_ACKNOWLEDGE);
+    Buf.writeUint32(2);
+    Buf.writeUint32(success ? 1 : 0);
+    Buf.writeUint32(cause);
     Buf.sendParcel();
   },
 
   /**
    * Start a DTMF Tone.
    *
    * @param dtmfChar
    *        DTMF signal to send, 0-9, *, +
@@ -703,16 +727,35 @@ let RIL = {
 
   sendTone: function sendTone(dtmfChar) {
     Buf.newParcel(REQUEST_DTMF);
     Buf.writeString(dtmfChar);
     Buf.sendParcel();
   },
 
   /**
+   * Get the Short Message Service Center address.
+   */
+  getSMSCAddress: function getSMSCAddress() {
+    Buf.simpleRequest(REQUEST_GET_SMSC_ADDRESS);
+  },
+
+  /**
+   * Set the Short Message Service Center address.
+   *
+   * @param smsc
+   *        Short Message Service Center address in PDU format.
+   */
+   setSMSCAddress: function setSMSCAddress(smsc) {
+     Buf.newParcel(REQUEST_SET_SMSC_ADDRESS);
+     Buf.writeString(smsc);
+     Buf.sendParcel();
+   },
+
+  /**
    * Handle incoming requests from the RIL. We find the method that
    * corresponds to the request type. Incidentally, the request type
    * _is_ the method name, so that's easy.
    */
 
   handleParcel: function handleParcel(request_type, length) {
     let method = this[request_type];
     if (typeof method == "function") {
@@ -855,32 +898,34 @@ RIL[REQUEST_OPERATOR] = function REQUEST
   Phone.onOperator(operator);
 };
 RIL[REQUEST_RADIO_POWER] = null;
 RIL[REQUEST_DTMF] = function REQUEST_DTMF() {
   Phone.onSendTone();
 };
 RIL[REQUEST_SEND_SMS] = function REQUEST_SEND_SMS() {
   let messageRef = Buf.readUint32();
-  let ackPDU = p.readString();
-  let errorCode = p.readUint32();
+  let ackPDU = Buf.readString();
+  let errorCode = Buf.readUint32();
   Phone.onSendSMS(messageRef, ackPDU, errorCode);
 };
 RIL[REQUEST_SEND_SMS_EXPECT_MORE] = null;
 RIL[REQUEST_SETUP_DATA_CALL] = null;
 RIL[REQUEST_SIM_IO] = null;
 RIL[REQUEST_SEND_USSD] = null;
 RIL[REQUEST_CANCEL_USSD] = null;
 RIL[REQUEST_GET_CLIR] = null;
 RIL[REQUEST_SET_CLIR] = null;
 RIL[REQUEST_QUERY_CALL_FORWARD_STATUS] = null;
 RIL[REQUEST_SET_CALL_FORWARD] = null;
 RIL[REQUEST_QUERY_CALL_WAITING] = null;
 RIL[REQUEST_SET_CALL_WAITING] = null;
-RIL[REQUEST_SMS_ACKNOWLEDGE] = null;
+RIL[REQUEST_SMS_ACKNOWLEDGE] = function REQUEST_SMS_ACKNOWLEDGE() {
+  Phone.onAcknowledgeSMS();
+};
 RIL[REQUEST_GET_IMEI] = function REQUEST_GET_IMEI() {
   let imei = Buf.readString();
   Phone.onIMEI(imei);
 };
 RIL[REQUEST_GET_IMEISV] = function REQUEST_GET_IMEISV() {
   let imeiSV = Buf.readString();
   Phone.onIMEISV(imeiSV);
 };
@@ -953,33 +998,46 @@ RIL[REQUEST_GSM_SMS_BROADCAST_ACTIVATION
 RIL[REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG] = null;
 RIL[REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG] = null;
 RIL[REQUEST_CDMA_SMS_BROADCAST_ACTIVATION] = null;
 RIL[REQUEST_CDMA_SUBSCRIPTION] = null;
 RIL[REQUEST_CDMA_WRITE_SMS_TO_RUIM] = null;
 RIL[REQUEST_CDMA_DELETE_SMS_ON_RUIM] = null;
 RIL[REQUEST_DEVICE_IDENTITY] = null;
 RIL[REQUEST_EXIT_EMERGENCY_CALLBACK_MODE] = null;
-RIL[REQUEST_GET_SMSC_ADDRESS] = null;
-RIL[REQUEST_SET_SMSC_ADDRESS] = null;
+RIL[REQUEST_GET_SMSC_ADDRESS] = function REQUEST_GET_SMSC_ADDRESS() {
+  let smsc = Buf.readString();
+  Phone.onGetSMSCAddress(smsc);
+};
+RIL[REQUEST_SET_SMSC_ADDRESS] = function REQUEST_SET_SMSC_ADDRESS() {
+  Phone.onSetSMSCAddress();
+};
 RIL[REQUEST_REPORT_SMS_MEMORY_STATUS] = null;
 RIL[REQUEST_REPORT_STK_SERVICE_IS_RUNNING] = null;
 RIL[UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED] = function UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED() {
   let newState = Buf.readUint32();
   Phone.onRadioStateChanged(newState);
 };
 RIL[UNSOLICITED_RESPONSE_CALL_STATE_CHANGED] = function UNSOLICITED_RESPONSE_CALL_STATE_CHANGED() {
   Phone.onCallStateChanged();
 };
 RIL[UNSOLICITED_RESPONSE_NETWORK_STATE_CHANGED] = function UNSOLICITED_RESPONSE_NETWORK_STATE_CHANGED() {
   Phone.onNetworkStateChanged();
 };
-RIL[UNSOLICITED_RESPONSE_NEW_SMS] = null;
-RIL[UNSOLICITED_RESPONSE_NEW_SMS_STATUS_REPORT] = null;
-RIL[UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM] = null;
+RIL[UNSOLICITED_RESPONSE_NEW_SMS] = function UNSOLICITED_RESPONSE_NEW_SMS(length) {
+  Phone.onNewSMS(length);
+};
+RIL[UNSOLICITED_RESPONSE_NEW_SMS_STATUS_REPORT] = function UNSOLICITED_RESPONSE_NEW_SMS_STATUS_REPORT(length) {
+  let info = Buf.readStringList();
+  Phone.onNewSMSStatusReport(info);
+};
+RIL[UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM] = function UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM(length) {
+  let info = Buf.readUint32List();
+  Phone.onNewSMSOnSIM(message);
+};
 RIL[UNSOLICITED_ON_USSD] = null;
 RIL[UNSOLICITED_ON_USSD_REQUEST] = null;
 RIL[UNSOLICITED_NITZ_TIME_RECEIVED] = null;
 RIL[UNSOLICITED_SIGNAL_STRENGTH] = function UNSOLICITED_SIGNAL_STRENGTH() {
   this[REQUEST_SIGNAL_STRENGTH]();
 };
 RIL[UNSOLICITED_DATA_CALL_LIST_CHANGED] = null;
 RIL[UNSOLICITED_SUPP_SVC_NOTIFICATION] = null;
@@ -1032,16 +1090,17 @@ let Phone = {
   radioState: RADIO_STATE_UNAVAILABLE,
 
   /**
    * Strings
    */
   IMEI: null,
   IMEISV: null,
   IMSI: null,
+  SMSC: null,
 
   /**
    * List of strings identifying the network operator.
    */
   operator: null,
 
   /**
    * String containing the baseband version.
@@ -1124,16 +1183,17 @@ let Phone = {
 
     if (newState == RADIO_STATE_SIM_READY  ||
         newState == RADIO_STATE_RUIM_READY ||
         newState == RADIO_STATE_NV_READY) {
       // The ICC card has become available. Get all the things.
       RIL.getICCStatus();
       this.requestNetworkInfo();
       RIL.getSignalStrength();
+      RIL.getSMSCAddress();
       this.sendDOMMessage({type: "cardstatechange",
                            cardState: DOM_CARDSTATE_READY});
     }
     if (newState == RADIO_STATE_SIM_LOCKED_OR_ABSENT  ||
         newState == RADIO_STATE_RUIM_LOCKED_OR_ABSENT) {
       RIL.getICCStatus();
       this.sendDOMMessage({type: "cardstatechange",
                            cardState: DOM_CARDSTATE_UNAVAILABLE});
@@ -1303,20 +1363,71 @@ let Phone = {
   },
 
   onStartTone: function onStartTone() {
   },
 
   onStopTone: function onStopTone() {
   },
 
+  onGetSMSCAddress: function onGetSMSCAddress(smsc) {
+    this.SMSC = smsc;
+  },
+
+  onSetSMSCAddress: function onSetSMSCAddress() {
+  },
+
   onSendSMS: function onSendSMS(messageRef, ackPDU, errorCode) {
     //TODO
   },
 
+  onNewSMS: function onNewSMS(payloadLength) {
+    if (!payloadLength) {
+      if (DEBUG) debug("Received empty SMS!");
+      //TODO: should we acknowledge the SMS here? maybe only after multiple
+      //failures.
+      return;
+    }
+    // An SMS is a string, but we won't read it as such, so let's read the
+    // string length and then defer to PDU parsing helper.
+    let messageStringLength = Buf.readUint32();
+    debug("Got new SMS, length " + messageStringLength);
+    let message = GsmPDUHelper.readMessage();
+    debug(message);
+
+    // Read string delimiters. See Buf.readString().
+    let delimiter = Buf.readUint16();
+    if (!(messageStringLength & 1)) {
+      delimiter |= Buf.readUint16();
+    }
+    if (DEBUG) {
+      if (delimiter != 0) {
+        debug("Something's wrong, found string delimiter: " + delimiter);
+      }
+    }
+
+    message.type = "sms-received";
+    this.sendDOMMessage(message);
+
+    //TODO: this might be a lie? do we want to wait for the mainthread to
+    // report back?
+    RIL.acknowledgeSMS(true, SMS_HANDLED);
+  },
+
+  onNewSMSStatusReport: function onNewSMSStatusReport(info) {
+    //TODO
+  },
+
+  onNewSMSOnSIM: function onNewSMSOnSIM(info) {
+    //TODO
+  },
+
+  onAcknowledgeSMS: function onAcknowledgeSMS() {
+  },
+
   /**
    * Outgoing requests to the RIL. These can be triggered from the
    * main thread via messages that look like this:
    *
    *   {type:  "methodName",
    *    extra: "parameters",
    *    go:    "here"}
    *
@@ -1411,24 +1522,34 @@ let Phone = {
     RIL.rejectCall();
   },
 
   /**
    * Send an SMS.
    *
    * @param number
    *        String containing the recipient number.
-   * @param message
+   * @param body
    *        String containing the message text.
    */
   sendSMS: function sendSMS(options) {
-    //TODO munge options.number and options.message into PDU format
-    let smscPDU = "";
-    let pdu = "";
-    RIL.sendSMS(smscPDU, pdu);
+    // Get the SMS Center address
+    if (!this.SMSC) {
+      //TODO: we shouldn't get here, but if we do, we might want to hold on
+      // to the message and retry once we know the SMSC... or just notify an
+      // error to the mainthread and let them deal with retrying?
+      debug("Cannot send the SMS. Need to get the SMSC address first.");
+      return;
+    }
+    //TODO: verify values on 'options'
+    //TODO: the data encoding and length in octets should eventually be
+    // computed on the mainthread and passed down to us.
+    RIL.sendSMS(this.SMSC, options.number, options.body,
+                PDU_DCS_MSG_CODING_7BITS_ALPHABET, //TODO: hard-coded for now,
+                Math.ceil(options.body.length * 7 / 8)); //TODO: ditto
   },
 
   /**
    * Handle incoming messages from the main UI thread.
    *
    * @param message
    *        Object containing the message. Messages are supposed
    */
@@ -1448,16 +1569,540 @@ let Phone = {
   sendDOMMessage: function sendDOMMessage(message) {
     postMessage(message, "*");
   }
 
 };
 
 
 /**
+ * This object exposes the functionality to parse and serialize PDU strings
+ *
+ * A PDU is a string containing a series of hexadecimally encoded octets
+ * or nibble-swapped binary-coded decimals (BCDs). It contains not only the
+ * message text but information about the sender, the SMS service center,
+ * timestamp, etc.
+ */
+let GsmPDUHelper = {
+
+  /**
+   * Read one character (2 bytes) from a RIL string and decode as hex.
+   *
+   * @return the nibble as a number.
+   */
+  readHexNibble: function readHexNibble() {
+    let nibble = Buf.readUint16();
+    if (nibble >= 48 && nibble <= 57) {
+      nibble -= 48; // ASCII '0'..'9'
+    } else if (nibble >= 65 && nibble <= 70) {
+      nibble -= 55; // ASCII 'A'..'F'
+    } else if (nibble >= 97 && nibble <= 102) {
+      nibble -= 87; // ASCII 'a'..'f'
+    } else {
+      throw "Found invalid nibble during PDU parsing: " +
+            String.fromCharCode(nibble);
+    }
+    return nibble;
+  },
+
+  /**
+   * Encode a nibble as one hex character in a RIL string (2 bytes).
+   *
+   * @param nibble
+   *        The nibble to encode (represented as a number)
+   */
+  writeHexNibble: function writeHexNibble(nibble) {
+    nibble &= 0x0f;
+    if (nibble < 10) {
+      nibble += 48; // ASCII '0'
+    } else {
+      nibble += 55; // ASCII 'A'
+    }
+    Buf.writeUint16(nibble);
+  },
+
+  /**
+   * Read a hex-encoded octet (two nibbles).
+   *
+   * @return the octet as a number.
+   */
+  readHexOctet: function readHexOctet() {
+    return (this.readHexNibble() << 4) | this.readHexNibble();
+  },
+
+  /**
+   * Write an octet as two hex-encoded nibbles.
+   *
+   * @param octet
+   *        The octet (represented as a number) to encode.
+   */
+  writeHexOctet: function writeHexOctet(octet) {
+    this.writeHexNibble(octet >> 4);
+    this.writeHexNibble(octet);
+  },
+
+  /**
+   * Convert an octet (number) to a BCD number.
+   *
+   * Any nibbles that are not in the BCD range count as 0.
+   *
+   * @param octet
+   *        The octet (a number, as returned by getOctet())
+   *
+   * @return the corresponding BCD number.
+   */
+  octetToBCD: function octetToBCD(octet) {
+    return ((octet & 0xf0) <= 0x90) * ((octet >> 4) & 0x0f) +
+           ((octet & 0x0f) <= 0x09) * (octet & 0x0f) * 10;
+  },
+
+  /**
+   * Read a *swapped nibble* binary coded decimal (BCD)
+   *
+   * @param length
+   *        Number of nibble *pairs* to read.
+   *
+   * @return the decimal as a number.
+   */
+  readSwappedNibbleBCD: function readSwappedNibbleBCD(length) {
+    let number = 0;
+    for (let i = 0; i < length; i++) {
+      let octet = this.readHexOctet();
+      // If the first nibble is an "F" , only the second nibble is to be taken
+      // into account.
+      if ((octet & 0xf0) == 0xf0) {
+        number *= 10;
+        number += octet & 0x0f;
+        continue;
+      }
+      number *= 100;
+      number += this.octetToBCD(octet);
+    }
+    return number;
+  },
+
+  /**
+   * Write numerical data as swapped nibble BCD.
+   * 
+   * @param data
+   *        Data to write (as a string or a number)
+   */
+  writeSwappedNibbleBCD: function writeSwappedNibbleBCD(data) {
+    data = data.toString();
+    if (data.length % 2) {
+      data += "F";
+    }
+    for (let i = 0; i < data.length; i += 2) {
+      Buf.writeUint16(data.charCodeAt(i + 1));
+      Buf.writeUint16(data.charCodeAt(i));
+    }
+  },
+
+  /**
+   * Read user data, convert to septets, look up relevant characters in a
+   * 7-bit alphabet, and construct string.
+   *
+   * @param length
+   *        Number of septets to read (*not* octets)
+   *
+   * @return a string.
+   *
+   * TODO: support other alphabets
+   * TODO: support escape chars
+   */
+  readSeptetsToString: function readSeptetsToString(length) {
+    let ret = "";
+    let byteLength = Math.ceil(length * 7 / 8);
+
+    let leftOver = 0;
+    for (let i = 0; i < byteLength; i++) {
+      let octet = this.readHexOctet();
+      let shift = (i % 7);
+      let leftOver_mask = (0xff << (7 - shift)) & 0xff;
+      let septet_mask = (0xff >> (shift + 1));
+
+      let septet = ((octet & septet_mask) << shift) | leftOver;
+      ret += PDU_ALPHABET_7BIT_DEFAULT[septet];
+      leftOver = (octet & leftOver_mask) >> (7 - shift);
+
+      // Every 7th byte we have a whole septet left over that we can apply.
+      if (shift == 6) {
+        ret += PDU_ALPHABET_7BIT_DEFAULT[leftOver];
+        leftOver = 0;
+      }
+    }
+    if (ret.length != length) {
+      ret = ret.slice(0, length);
+    }
+    return ret;
+  },
+
+  writeStringAsSeptets: function writeStringAsSeptets(message) {
+    let right = 0;
+    for (let i = 0; i < message.length + 1; i++) {
+      let shift = (i % 8);
+      let septet;
+      if (i < message.length) {
+        septet = PDU_ALPHABET_7BIT_DEFAULT.indexOf(message[i]);
+      } else {
+        septet = 0;
+      }
+      if (septet == -1) {
+        if (DEBUG) debug("Fffff, "  + message[i] + " not in 7 bit alphabet!");
+        septet = 0;
+      }
+      if (shift == 0) {
+        // We're at the beginning of a cycle, but we need two septet values
+        // to make an octet. So we're going to have to sit this one out.
+        right = septet;
+        continue;
+      }
+
+      let left_mask = 0xff >> (8 - shift);
+      let right_mask = (0xff << shift) & 0xff;
+      let left = (septet & left_mask) << (8 - shift);
+      let octet = left | right;
+      this.writeHexOctet(left | right);
+      right = (septet & right_mask) >> shift;
+    }
+  },
+
+  /**
+   * Read user data and decode as a UCS2 string.
+   *
+   * @param length
+   *        XXX TODO
+   *
+   * @return a string.
+   */
+  readUCS2String: function readUCS2String(length) {
+    //TODO bug 712804
+  },
+
+  /**
+   * Write user data as a UCS2 string.
+   *
+   * @param message
+   *        Message string to encode as UCS2 in hex-encoded octets.
+   */
+  writeUCS2String: function writeUCS2String(message) {
+    //TODO bug 712804
+  },
+
+  /**
+   * User data can be 7 bit (default alphabet) data, 8 bit data, or 16 bit
+   * (UCS2) data.
+   *
+   * TODO: This function currently supports only the default alphabet.
+   */
+  readUserData: function readUserData(length, codingScheme) {
+    if (DEBUG) {
+      debug("Reading " + length + " bytes of user data.");
+      debug("Coding scheme: " + codingScheme);
+    }
+    // 7 bit is the default fallback encoding.
+    let encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET;
+    switch (codingScheme & 0xC0) {
+      case 0x0:
+        // bits 7..4 = 00xx
+        switch (codingScheme & 0x0C) {
+          case 0x4:
+            encoding = PDU_DCS_MSG_CODING_8BITS_ALPHABET;
+            break;
+          case 0x8:
+            encoding = PDU_DCS_MSG_CODING_16BITS_ALPHABET;
+            break;
+        }
+        break;
+      case 0xC0:
+        // bits 7..4 = 11xx
+        switch (codingScheme & 0x30) {
+          case 0x20:
+            encoding = PDU_DCS_MSG_CODING_16BITS_ALPHABET;
+            break;
+          case 0x30:
+            if (!codingScheme & 0x04) {
+              encoding = PDU_DCS_MSG_CODING_8BITS_ALPHABET;
+            }
+            break;
+        }
+        break;
+      default:
+        // Falling back to default encoding.
+        break;
+    }
+
+    if (DEBUG) debug("PDU: message encoding is " + encoding + " bit.");
+    switch (encoding) {
+      case PDU_DCS_MSG_CODING_7BITS_ALPHABET:
+        // 7 bit encoding allows 140 octets, which means 160 characters
+        // ((140x8) / 7 = 160 chars)
+        if (length > PDU_MAX_USER_DATA_7BIT) {
+          if (DEBUG) debug("PDU error: user data is too long: " + length);
+          return null;
+        }
+        return this.readSeptetsToString(length);
+      case PDU_DCS_MSG_CODING_8BITS_ALPHABET:
+        // Unsupported.
+        return null;
+      case PDU_DCS_MSG_CODING_16BITS_ALPHABET:
+        return this.readUCS2String(length);
+    }
+    return null;
+  },
+
+  /**
+   * Read and decode a PDU-encoded message from the stream.
+   *
+   * TODO: add some basic sanity checks like:
+   * - do we have the minimum number of chars available
+   */
+  readMessage: function readMessage() {
+    // An empty message object. This gets filled below and then returned.
+    let msg = {
+      SMSC:      null,
+      reference: null,
+      sender:    null,
+      body:      null,
+      validity:  null,
+      timestamp: null
+    };
+
+    // SMSC info
+    let smscLength = this.readHexOctet();
+    if (smscLength > 0) {
+      let smscTypeOfAddress = this.readHexOctet();
+      // Subtract the type-of-address octet we just read from the length.
+      msg.SMSC = this.readSwappedNibbleBCD(smscLength - 1).toString();
+      if ((smscTypeOfAddress >> 4) == (PDU_TOA_INTERNATIONAL >> 4)) {
+        msg.SMSC = '+' + msg.SMSC;
+      }
+    }
+
+    // First octet of this SMS-DELIVER or SMS-SUBMIT message
+    let firstOctet = this.readHexOctet();
+    // if the sms is of SMS-SUBMIT type it would contain a TP-MR
+    let isSmsSubmit = firstOctet & PDU_MTI_SMS_SUBMIT;
+    if (isSmsSubmit) {
+      msg.reference = this.readHexOctet(); // TP-Message-Reference
+    }
+
+    // - Sender Address info -
+    // Address length
+    let senderAddressLength = this.readHexOctet();
+    if (senderAddressLength <= 0) {
+      if (DEBUG) debug("PDU error: invalid sender address length: " + senderAddressLength);
+      return null;
+    }
+    // Type-of-Address
+    let senderTypeOfAddress = this.readHexOctet();
+    if (senderAddressLength % 2 == 1) {
+      senderAddressLength += 1;
+    }
+    if (DEBUG) debug("PDU: Going to read sender address: " + senderAddressLength);
+    msg.sender = this.readSwappedNibbleBCD(senderAddressLength / 2).toString();
+    if (msg.sender.length <= 0) {
+      if (DEBUG) debug("PDU error: no sender number provided");
+      return null;
+    }
+    if ((senderTypeOfAddress >> 4) == (PDU_TOA_INTERNATIONAL >> 4)) {
+      msg.sender = '+' + msg.sender;
+    }
+
+    // - TP-Protocolo-Identifier -
+    let protocolIdentifier = this.readHexOctet();
+
+    // - TP-Data-Coding-Scheme -
+    let dataCodingScheme = this.readHexOctet();
+
+    // SMS of SMS-SUBMIT type contains a TP-Service-Center-Time-Stamp field
+    // SMS of SMS-DELIVER type contains a TP-Validity-Period octet
+    if (isSmsSubmit) {
+      //  - TP-Validity-Period -
+      //  The Validity Period octet is optional. Depends on the SMS-SUBMIT
+      //  first octet
+      //  Validity Period Format. Bit4 and Bit3 specify the TP-VP field
+      //  according to this table:
+      //  bit4 bit3
+      //    0   0 : TP-VP field not present
+      //    1   0 : TP-VP field present. Relative format (one octet)
+      //    0   1 : TP-VP field present. Enhanced format (7 octets)
+      //    1   1 : TP-VP field present. Absolute format (7 octets)
+      if (firstOctet & (PDU_VPF_ABSOLUTE | PDU_VPF_RELATIVE | PDU_VPF_ENHANCED)) {
+        msg.validity = this.readHexOctet();
+      }
+      //TODO: check validity period
+    } else {
+      // - TP-Service-Center-Time-Stamp -
+      let year   = this.readSwappedNibbleBCD(1) + PDU_TIMESTAMP_YEAR_OFFSET;
+      let month  = this.readSwappedNibbleBCD(1) - 1;
+      let day    = this.readSwappedNibbleBCD(1) - 1;
+      let hour   = this.readSwappedNibbleBCD(1) - 1;
+      let minute = this.readSwappedNibbleBCD(1) - 1;
+      let second = this.readSwappedNibbleBCD(1) - 1;
+      msg.timestamp = Date.UTC(year, month, day, hour, minute, second);
+
+      // If the most significant bit of the least significant nibble is 1,
+      // the timezone offset is negative (fourth bit from the right => 0x08).
+      let tzOctet = this.readHexOctet();
+      let tzOffset = this.octetToBCD(tzOctet & ~0x08) * 15 * 60 * 1000;
+      if (tzOctet & 0x08) {
+        msg.timestamp -= tzOffset;
+      } else {
+        msg.timestamp += tzOffset;
+      }
+    }
+
+    // - TP-User-Data-Length -
+    let userDataLength = this.readHexOctet();
+
+    // - TP-User-Data -
+    if (userDataLength > 0) {
+      msg.body = this.readUserData(userDataLength, dataCodingScheme);
+    }
+
+    return msg;
+  },
+
+  /**
+   * Serialize a SMS-SUBMIT PDU message and write it to the output stream.
+   *
+   * This method expects that a data coding scheme has been chosen already
+   * and that the length of the user data payload in that encoding is known,
+   * too. Both go hand in hand together anyway.
+   *
+   * @param address
+   *        String containing the address (number) of the SMS receiver
+   * @param userData
+   *        String containing the message to be sent as user data
+   * @param dcs
+   *        Data coding scheme. One of the PDU_DCS_MSG_CODING_*BITS_ALPHABET
+   *        constants.
+   * @param userDataLengthInOctets
+   *        Byte length of the user data when encoded with the given DCS.
+   */
+  writeMessage: function writeMessage(address,
+                                      userData,
+                                      dcs,
+                                      userDataLengthInOctets) {
+    // SMS-SUBMIT Format:
+    //
+    // PDU Type - 1 octet
+    // Message Reference - 1 octet
+    // DA - Destination Address - 2 to 12 octets
+    // PID - Protocol Identifier - 1 octet
+    // DCS - Data Coding Scheme - 1 octet
+    // VP - Validity Period - 0, 1 or 7 octets
+    // UDL - User Data Length - 1 octet
+    // UD - User Data - 140 octets
+
+    let addressFormat = PDU_TOA_ISDN; // 81
+    if (address[0] == '+') {
+      addressFormat = PDU_TOA_INTERNATIONAL | PDU_TOA_ISDN; // 91
+      address = address.substring(1);
+    }
+    //TODO validity is unsupported for now
+    let validity = 0;
+
+    let pduOctetLength = 4 + // PDU Type, Message Ref, address length + format
+                         Math.ceil(address.length / 2) +
+                         3 + // PID, DCS, UDL
+                         userDataLengthInOctets;
+    if (validity) {
+      //TODO: add more to pduOctetLength
+    }
+
+    // Start the string. Since octets are represented in hex, we will need
+    // twice as many characters as octets.
+    Buf.writeUint32(pduOctetLength * 2);
+
+    // - PDU-TYPE-
+
+    // +--------+----------+---------+---------+--------+---------+
+    // | RP (1) | UDHI (1) | SRR (1) | VPF (2) | RD (1) | MTI (2) |
+    // +--------+----------+---------+---------+--------+---------+
+    // RP:    0   Reply path parameter is not set
+    //        1   Reply path parameter is set
+    // UDHI:  0   The UD Field contains only the short message
+    //        1   The beginning of the UD field contains a header in addition
+    //            of the short message
+    // SRR:   0   A status report is not requested
+    //        1   A status report is requested
+    // VPF:   bit4  bit3
+    //        0     0     VP field is not present
+    //        0     1     Reserved
+    //        1     0     VP field present an integer represented (relative)
+    //        1     1     VP field present a semi-octet represented (absolute)
+    // RD:        Instruct the SMSC to accept(0) or reject(1) an SMS-SUBMIT
+    //            for a short message still held in the SMSC which has the same
+    //            MR and DA as a previously submitted short message from the
+    //            same OA
+    // MTI:   bit1  bit0    Message Type
+    //        0     0       SMS-DELIVER (SMSC ==> MS)
+    //        0     1       SMS-SUBMIT (MS ==> SMSC)
+
+    // PDU type. MTI is set to SMS-SUBMIT
+    let firstOctet = PDU_MTI_SMS_SUBMIT;
+
+    // Validity period
+    if (validity) {
+      //TODO: not supported yet, OR with one of PDU_VPF_*
+    }
+    let udhi = ""; //TODO: for now this is unsupported
+    if (udhi) {
+      firstOctet |= PDU_UDHI;
+    }
+    this.writeHexOctet(firstOctet);
+
+    // Message reference 00
+    this.writeHexOctet(0x00);
+
+    // - Destination Address -
+    this.writeHexOctet(address.length);
+    this.writeHexOctet(addressFormat);
+    this.writeSwappedNibbleBCD(address);
+
+    // - Protocol Identifier -
+    this.writeHexOctet(0x00);
+
+    // - Data coding scheme -
+    // For now it assumes bits 7..4 = 1111 except for the 16 bits use case
+    this.writeHexOctet(dcs);
+
+    // - Validity Period -
+    if (validity) {
+      this.writeHexOctet(validity);
+    }
+
+    // - User Data -
+    let userDataLength = userData.length;
+    if (dcs == PDU_DCS_MSG_CODING_16BITS_ALPHABET) {
+      userDataLength = userData.length * 2;
+    }
+    this.writeHexOctet(userDataLength);
+    switch (dcs) {
+      case PDU_DCS_MSG_CODING_7BITS_ALPHABET:
+        this.writeStringAsSeptets(userData);
+        break;
+      case PDU_DCS_MSG_CODING_8BITS_ALPHABET:
+        // Unsupported.
+        break;
+      case PDU_DCS_MSG_CODING_16BITS_ALPHABET:
+        this.writeUCS2String(userData);
+        break;
+    }
+
+    // End of the string. The string length is always even by definition, so
+    // we write two \0 delimiters.
+    Buf.writeUint16(0);
+    Buf.writeUint16(0);
+  }
+};
+
+/**
  * Global stuff.
  */
 
 if (!this.debug) {
   // Debugging stub that goes nowhere.
   this.debug = function debug(message) {
     dump("RIL Worker: " + message + "\n");
   };
--- a/dom/workers/File.cpp
+++ b/dom/workers/File.cpp
@@ -43,18 +43,16 @@
 
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsfriendapi.h"
 #include "nsCOMPtr.h"
 #include "nsJSUtils.h"
 #include "nsStringGlue.h"
-#include "xpcprivate.h"
-#include "XPCQuickStubs.h"
 
 #include "Exceptions.h"
 #include "WorkerInlines.h"
 #include "WorkerPrivate.h"
 
 #define PROPERTY_FLAGS \
   JSPROP_ENUMERATE | JSPROP_SHARED
 
@@ -203,18 +201,18 @@ private:
 
     nsDependentJSString contentType;
     if (!contentType.init(aCx, jsContentType)) {
       return false;
     }
 
     PRUint8 optionalArgc = aArgc;
     nsCOMPtr<nsIDOMBlob> rtnBlob;
-    if (NS_FAILED(blob->MozSlice(xpc_qsDoubleToUint64(start),
-                                 xpc_qsDoubleToUint64(end),
+    if (NS_FAILED(blob->MozSlice(static_cast<PRUint64>(start),
+                                 static_cast<PRUint64>(end),
                                  contentType, optionalArgc,
                                  getter_AddRefs(rtnBlob)))) {
       ThrowFileExceptionForCode(aCx, FILE_NOT_READABLE_ERR);
       return false;
     }
 
     JSObject* rtnObj = file::CreateBlob(aCx, rtnBlob);
     if (!rtnObj) {
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -74,16 +74,19 @@
 #include "Exceptions.h"
 #include "File.h"
 #include "Principal.h"
 #include "RuntimeService.h"
 #include "ScriptLoader.h"
 #include "Worker.h"
 #include "WorkerFeature.h"
 #include "WorkerScope.h"
+#ifdef ANDROID
+#include <android/log.h>
+#endif
 
 #include "WorkerInlines.h"
 
 #if 0 // Define to run GC more often.
 #define EXTRA_GC
 #endif
 
 using mozilla::MutexAutoLock;
@@ -1144,17 +1147,21 @@ public:
         logged = true;
       }
       else {
         NS_WARNING("Failed to log script error!");
       }
     }
 
     if (!logged) {
-      fputs(NS_ConvertUTF16toUTF8(aMessage).get(), stderr);
+      NS_ConvertUTF16toUTF8 msg(aMessage);
+#ifdef ANDROID
+      __android_log_print(ANDROID_LOG_INFO, "Gecko", msg.get());
+#endif
+      fputs(msg.get(), stderr);
       fflush(stderr);
     }
 
     return true;
   }
 };
 
 class TimerRunnable : public WorkerRunnable
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -56,16 +56,19 @@
 #include "ListenerManager.h"
 #include "Location.h"
 #include "Navigator.h"
 #include "Principal.h"
 #include "ScriptLoader.h"
 #include "Worker.h"
 #include "WorkerPrivate.h"
 #include "XMLHttpRequest.h"
+#ifdef ANDROID
+#include <android/log.h>
+#endif
 
 #include "WorkerInlines.h"
 
 #define PROPERTY_FLAGS \
   JSPROP_ENUMERATE | JSPROP_SHARED
 
 #define FUNCTION_FLAGS \
   JSPROP_ENUMERATE
@@ -512,16 +515,19 @@ private:
         return false;
       }
 
       JSAutoByteString buffer(aCx, str);
       if (!buffer) {
         return false;
       }
 
+#ifdef ANDROID
+      __android_log_print(ANDROID_LOG_INFO, "Gecko", buffer.ptr());
+#endif
       fputs(buffer.ptr(), stderr);
       fflush(stderr);
     }
 
     return true;
   }
 
   static JSBool
--- a/editor/composer/src/nsComposerController.cpp
+++ b/editor/composer/src/nsComposerController.cpp
@@ -40,61 +40,55 @@
 
 #include "nsIControllerCommandTable.h"
 #include "nsComposerController.h"
 #include "nsComposerCommands.h"
 
 #define NS_REGISTER_ONE_COMMAND(_cmdClass, _cmdName)                    \
   {                                                                     \
     _cmdClass* theCmd = new _cmdClass();                                \
-    NS_ENSURE_TRUE(theCmd, NS_ERROR_OUT_OF_MEMORY);                         \
-    rv = inCommandTable->RegisterCommand(_cmdName,                      \
+    inCommandTable->RegisterCommand(_cmdName,                           \
                        static_cast<nsIControllerCommand *>(theCmd));    \
   }
 
 #define NS_REGISTER_FIRST_COMMAND(_cmdClass, _cmdName)                  \
   {                                                                     \
     _cmdClass* theCmd = new _cmdClass();                                \
-    NS_ENSURE_TRUE(theCmd, NS_ERROR_OUT_OF_MEMORY);                         \
-    rv = inCommandTable->RegisterCommand(_cmdName,                      \
+    inCommandTable->RegisterCommand(_cmdName,                           \
                        static_cast<nsIControllerCommand *>(theCmd));
 
 #define NS_REGISTER_NEXT_COMMAND(_cmdClass, _cmdName)                   \
-    rv = inCommandTable->RegisterCommand(_cmdName,                      \
+    inCommandTable->RegisterCommand(_cmdName,                           \
                         static_cast<nsIControllerCommand *>(theCmd));
 
 #define NS_REGISTER_LAST_COMMAND(_cmdClass, _cmdName)                   \
-    rv = inCommandTable->RegisterCommand(_cmdName,                      \
+    inCommandTable->RegisterCommand(_cmdName,                           \
                        static_cast<nsIControllerCommand *>(theCmd));    \
   }
 
 #define NS_REGISTER_STYLE_COMMAND(_cmdClass, _cmdName, _styleTag)       \
   {                                                                     \
     _cmdClass* theCmd = new _cmdClass(_styleTag);                       \
-    NS_ENSURE_TRUE(theCmd, NS_ERROR_OUT_OF_MEMORY);                         \
-    rv = inCommandTable->RegisterCommand(_cmdName,                      \
+    inCommandTable->RegisterCommand(_cmdName,                           \
                        static_cast<nsIControllerCommand *>(theCmd));    \
   }
   
 #define NS_REGISTER_TAG_COMMAND(_cmdClass, _cmdName, _tagName)          \
   {                                                                     \
     _cmdClass* theCmd = new _cmdClass(_tagName);                        \
-    NS_ENSURE_TRUE(theCmd, NS_ERROR_OUT_OF_MEMORY);                         \
-    rv = inCommandTable->RegisterCommand(_cmdName,                      \
+    inCommandTable->RegisterCommand(_cmdName,                           \
                        static_cast<nsIControllerCommand *>(theCmd));    \
   }
   
 
 // static
 nsresult
 nsComposerController::RegisterEditorDocStateCommands(
                         nsIControllerCommandTable *inCommandTable)
 {
-  nsresult rv;
-
   // observer commands for document state
   NS_REGISTER_FIRST_COMMAND(nsDocumentStateCommand, "obs_documentCreated")
   NS_REGISTER_NEXT_COMMAND(nsDocumentStateCommand, "obs_documentWillBeDestroyed")
   NS_REGISTER_LAST_COMMAND(nsDocumentStateCommand, "obs_documentLocationChanged")
 
   // commands that may get or change state
   NS_REGISTER_FIRST_COMMAND(nsSetDocumentStateCommand, "cmd_setDocumentModified")
   NS_REGISTER_NEXT_COMMAND(nsSetDocumentStateCommand, "cmd_setDocumentUseCSS")
@@ -108,18 +102,16 @@ nsComposerController::RegisterEditorDocS
   return NS_OK;
 }
 
 // static
 nsresult
 nsComposerController::RegisterHTMLEditorCommands(
                         nsIControllerCommandTable *inCommandTable)
 {
-  nsresult rv;
-  
   // Edit menu
   NS_REGISTER_ONE_COMMAND(nsPasteNoFormattingCommand, "cmd_pasteNoFormatting");
 
   // indent/outdent
   NS_REGISTER_ONE_COMMAND(nsIndentCommand, "cmd_indent");
   NS_REGISTER_ONE_COMMAND(nsOutdentCommand, "cmd_outdent");
 
   // Styles
--- a/editor/composer/src/nsEditingSession.cpp
+++ b/editor/composer/src/nsEditingSession.cpp
@@ -179,18 +179,18 @@ nsEditingSession::MakeWindowEditable(nsI
   NS_ENSURE_SUCCESS(rv, rv);  
   
   // set the flag on the docShell to say that it's editable
   rv = editorDocShell->MakeEditable(aDoAfterUriLoad);
   NS_ENSURE_SUCCESS(rv, rv);  
 
   // Setup commands common to plaintext and html editors,
   //  including the document creation observers
-  // the first is an editor controller
-  rv = SetupEditorCommandController("@mozilla.org/editor/editorcontroller;1",
+  // the first is an editing controller
+  rv = SetupEditorCommandController("@mozilla.org/editor/editingcontroller;1",
                                     aWindow,
                                     static_cast<nsIEditingSession*>(this),
                                     &mBaseCommandControllerId);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // The second is a controller to monitor doc state,
   // such as creation and "dirty flag"
   rv = SetupEditorCommandController("@mozilla.org/editor/editordocstatecontroller;1",
@@ -1430,17 +1430,17 @@ nsEditingSession::ReattachToWindow(nsIDO
   // Tells embedder that startup is in progress.
   mEditorStatus = eEditorCreationInProgress;
 
   // Adds back web progress listener.
   rv = PrepareForEditing(aWindow);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Setup the command controllers again.
-  rv = SetupEditorCommandController("@mozilla.org/editor/editorcontroller;1",
+  rv = SetupEditorCommandController("@mozilla.org/editor/editingcontroller;1",
                                     aWindow,
                                     static_cast<nsIEditingSession*>(this),
                                     &mBaseCommandControllerId);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = SetupEditorCommandController("@mozilla.org/editor/editordocstatecontroller;1",
                                     aWindow,
                                     static_cast<nsIEditingSession*>(this),
--- a/editor/libeditor/base/nsEditorController.cpp
+++ b/editor/libeditor/base/nsEditorController.cpp
@@ -43,69 +43,82 @@
 #include "nsEditorCommands.h"
 #include "nsIControllerCommandTable.h"
 
 
 
 #define NS_REGISTER_ONE_COMMAND(_cmdClass, _cmdName)                                      \
   {                                                                                       \
     _cmdClass* theCmd = new _cmdClass();                                                  \
-    NS_ENSURE_TRUE(theCmd, NS_ERROR_OUT_OF_MEMORY);                                           \
-    rv = inCommandTable->RegisterCommand(_cmdName,                                        \
+    NS_ENSURE_TRUE(theCmd, NS_ERROR_OUT_OF_MEMORY);                                       \
+    inCommandTable->RegisterCommand(_cmdName,                                             \
                                    static_cast<nsIControllerCommand *>(theCmd));          \
   }
 
 #define NS_REGISTER_FIRST_COMMAND(_cmdClass, _cmdName)                                    \
   {                                                                                       \
     _cmdClass* theCmd = new _cmdClass();                                                  \
-    NS_ENSURE_TRUE(theCmd, NS_ERROR_OUT_OF_MEMORY);                                           \
-    rv = inCommandTable->RegisterCommand(_cmdName,                                        \
+    NS_ENSURE_TRUE(theCmd, NS_ERROR_OUT_OF_MEMORY);                                       \
+    inCommandTable->RegisterCommand(_cmdName,                                             \
                                    static_cast<nsIControllerCommand *>(theCmd));
 
 #define NS_REGISTER_NEXT_COMMAND(_cmdClass, _cmdName)                                     \
-    rv = inCommandTable->RegisterCommand(_cmdName,                                        \
+    inCommandTable->RegisterCommand(_cmdName,                                             \
                                    static_cast<nsIControllerCommand *>(theCmd));
 
 #define NS_REGISTER_LAST_COMMAND(_cmdClass, _cmdName)                                     \
-    rv = inCommandTable->RegisterCommand(_cmdName,                                        \
+    inCommandTable->RegisterCommand(_cmdName,                                             \
                                    static_cast<nsIControllerCommand *>(theCmd));          \
   }
 
 
 // static
-nsresult nsEditorController::RegisterEditorCommands(nsIControllerCommandTable *inCommandTable)
+nsresult nsEditorController::RegisterEditingCommands(nsIControllerCommandTable *inCommandTable)
 {
-  nsresult rv;
- 
   // now register all our commands
   // These are commands that will be used in text widgets, and in composer
-  
+
   NS_REGISTER_ONE_COMMAND(nsUndoCommand, "cmd_undo");
   NS_REGISTER_ONE_COMMAND(nsRedoCommand, "cmd_redo");
   NS_REGISTER_ONE_COMMAND(nsClearUndoCommand, "cmd_clearUndo");
 
   NS_REGISTER_ONE_COMMAND(nsCutCommand, "cmd_cut");
   NS_REGISTER_ONE_COMMAND(nsCutOrDeleteCommand, "cmd_cutOrDelete");
   NS_REGISTER_ONE_COMMAND(nsCopyCommand, "cmd_copy");
   NS_REGISTER_ONE_COMMAND(nsCopyOrDeleteCommand, "cmd_copyOrDelete");
   NS_REGISTER_ONE_COMMAND(nsSelectAllCommand, "cmd_selectAll");
-  
+
   NS_REGISTER_ONE_COMMAND(nsPasteCommand, "cmd_paste");
   NS_REGISTER_ONE_COMMAND(nsPasteTransferableCommand, "cmd_pasteTransferable");
 
   NS_REGISTER_ONE_COMMAND(nsSwitchTextDirectionCommand, "cmd_switchTextDirection");
-  
+
   NS_REGISTER_FIRST_COMMAND(nsDeleteCommand, "cmd_delete");
   NS_REGISTER_NEXT_COMMAND(nsDeleteCommand, "cmd_deleteCharBackward");
   NS_REGISTER_NEXT_COMMAND(nsDeleteCommand, "cmd_deleteCharForward");
   NS_REGISTER_NEXT_COMMAND(nsDeleteCommand, "cmd_deleteWordBackward");
   NS_REGISTER_NEXT_COMMAND(nsDeleteCommand, "cmd_deleteWordForward");
   NS_REGISTER_NEXT_COMMAND(nsDeleteCommand, "cmd_deleteToBeginningOfLine");
   NS_REGISTER_LAST_COMMAND(nsDeleteCommand, "cmd_deleteToEndOfLine");
 
+  // Insert content
+  NS_REGISTER_ONE_COMMAND(nsInsertPlaintextCommand, "cmd_insertText");
+  NS_REGISTER_ONE_COMMAND(nsPasteQuotationCommand,  "cmd_pasteQuote");
+
+  return NS_OK;
+}
+
+
+// static
+nsresult nsEditorController::RegisterEditorCommands(nsIControllerCommandTable *inCommandTable)
+{
+  nsresult rv;
+
+  // These are commands that will be used in text widgets only.
+
   NS_REGISTER_FIRST_COMMAND(nsSelectionMoveCommands, "cmd_scrollTop");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_scrollBottom");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_moveTop");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_moveBottom");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_selectTop");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_selectBottom");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_lineNext");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_linePrevious");
@@ -126,17 +139,12 @@ nsresult nsEditorController::RegisterEdi
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_scrollPageUp");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_scrollPageDown");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_scrollLineUp");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_scrollLineDown");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_movePageUp");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_movePageDown");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_selectPageUp");
   NS_REGISTER_LAST_COMMAND(nsSelectionMoveCommands, "cmd_selectPageDown");
-    
-  // Insert content
-  NS_REGISTER_ONE_COMMAND(nsInsertPlaintextCommand, "cmd_insertText");
-  NS_REGISTER_ONE_COMMAND(nsPasteQuotationCommand,  "cmd_pasteQuote");
-
 
   return NS_OK;
 }
 
--- a/editor/libeditor/base/nsEditorController.h
+++ b/editor/libeditor/base/nsEditorController.h
@@ -36,22 +36,26 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsEditorController_h__
 #define nsEditorController_h__
 
 #define NS_EDITORCONTROLLER_CID \
 { 0x26fb965c, 0x9de6, 0x11d3, { 0xbc, 0xcc, 0x0, 0x60, 0xb0, 0xfc, 0x76, 0xbd } }
 
+#define NS_EDITINGCONTROLLER_CID \
+{ 0x2c5a5cdd, 0xe742, 0x4dfe, { 0x86, 0xb8, 0x06, 0x93, 0x09, 0xbf, 0x6c, 0x91 } }
+
 class nsIControllerCommandTable;
 
 
 // the editor controller is used for both text widgets, and basic text editing
 // commands in composer. The refCon that gets passed to its commands is an nsIEditor.
 
 class nsEditorController 
 {
 public:
   static nsresult RegisterEditorCommands(nsIControllerCommandTable* inCommandTable);
+  static nsresult RegisterEditingCommands(nsIControllerCommandTable* inCommandTable);
 };
 
 #endif /* nsEditorController_h__ */
 
--- a/editor/libeditor/base/tests/test_selection_move_commands.xul
+++ b/editor/libeditor/base/tests/test_selection_move_commands.xul
@@ -33,16 +33,17 @@ function execTests() {
   body.style.padding='0px';
   body.style.margin='0px';
   body.style.borderSize='0px';
 
   var sel = win.getSelection();
   doc.designMode='on';
   body.innerHTML = "1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>10<br>11<br>12<br>";
   win.focus();
+  yield;
 
   function doCommand(cmd) {
     var controller = document.commandDispatcher.getControllerForCommand(cmd);
     if (controller) {
       controller.doCommand(cmd);
     }
   }
 
@@ -117,26 +118,16 @@ function execTests() {
   var pageHeight = -root.getBoundingClientRect().top;
   ok(pageHeight > 0, "cmd_scrollPageDown works");
   ok(pageHeight <= 100, "cmd_scrollPageDown doesn't scroll too much");
   doCommand("cmd_scrollBottom");
   doCommand("cmd_scrollPageUp");
   yield;
   testScrollCommand("cmd_scrollPageUp", root.scrollHeight - 100 - pageHeight);
 
-  doCommand("cmd_scrollTop");
-  doCommand("cmd_scrollLineDown");
-  yield;
-  var lineHeight = -root.getBoundingClientRect().top;
-  ok(lineHeight > 0, "Can scroll by lines");
-  doCommand("cmd_scrollBottom");
-  doCommand("cmd_scrollLineUp");
-  yield;
-  testScrollCommand("cmd_scrollLineUp", root.scrollHeight - 100 - lineHeight);
-
   var runSelectionTests = function(selectWordNextNode, selectWordNextOffset) {
     testMoveCommand("cmd_moveBottom", body, 23);
     testMoveCommand("cmd_moveTop", node(0), 0);
     testSelectCommand("cmd_selectBottom", body, 23);
     doCommand("cmd_moveBottom");
     testSelectCommand("cmd_selectTop", node(0), 0);
 
     doCommand("cmd_moveTop");
--- a/editor/libeditor/html/nsHTMLEditorStyle.cpp
+++ b/editor/libeditor/html/nsHTMLEditorStyle.cpp
@@ -534,41 +534,40 @@ nsHTMLEditor::SetInlinePropertyOnNode( n
 
 nsresult nsHTMLEditor::SplitStyleAboveRange(nsIDOMRange *inRange, 
                                             nsIAtom *aProperty, 
                                             const nsAString *aAttribute)
 {
   NS_ENSURE_TRUE(inRange, NS_ERROR_NULL_POINTER);
   nsresult res;
   nsCOMPtr<nsIDOMNode> startNode, endNode, origStartNode;
-  PRInt32 startOffset, endOffset, origStartOffset;
-  
+  PRInt32 startOffset, endOffset;
+
   res = inRange->GetStartContainer(getter_AddRefs(startNode));
   NS_ENSURE_SUCCESS(res, res);
   res = inRange->GetStartOffset(&startOffset);
   NS_ENSURE_SUCCESS(res, res);
   res = inRange->GetEndContainer(getter_AddRefs(endNode));
   NS_ENSURE_SUCCESS(res, res);
   res = inRange->GetEndOffset(&endOffset);
   NS_ENSURE_SUCCESS(res, res);
-  
+
   origStartNode = startNode;
-  origStartOffset = startOffset;
-  
+
   // split any matching style nodes above the start of range
   {
     nsAutoTrackDOMPoint tracker(mRangeUpdater, address_of(endNode), &endOffset);
     res = SplitStyleAbovePoint(address_of(startNode), &startOffset, aProperty, aAttribute);
     NS_ENSURE_SUCCESS(res, res);
   }
 
   // second verse, same as the first...
   res = SplitStyleAbovePoint(address_of(endNode), &endOffset, aProperty, aAttribute);
   NS_ENSURE_SUCCESS(res, res);
-  
+
   // reset the range
   res = inRange->SetStart(startNode, startOffset);
   NS_ENSURE_SUCCESS(res, res);
   res = inRange->SetEnd(endNode, endOffset);
   return res;
 }
 
 nsresult nsHTMLEditor::SplitStyleAbovePoint(nsCOMPtr<nsIDOMNode> *aNode,
@@ -661,20 +660,20 @@ nsresult nsHTMLEditor::RemoveStyleInside
     // cache next sibling since we might remove child
     child->GetNextSibling(getter_AddRefs(tmp));
     res = RemoveStyleInside(child, aProperty, aAttribute);
     NS_ENSURE_SUCCESS(res, res);
     child = tmp;
   }
 
   // then process the node itself
-  if ( !aChildrenOnly && 
-        (aProperty && NodeIsType(aNode, aProperty) || // node is prop we asked for