Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Tue, 27 Dec 2011 14:02:22 -0800
changeset 105497 0cfb7c3645ee2bcac477c4382395753b7d7f49f9
parent 105495 3319e30a2c00ee32252c2d9b4527fc374f1158f7 (current diff)
parent 83410 7e28cce342a6deb1d18e6382bd76baf61ae955ae (diff)
child 105498 eaaf33ed43c0c418af4fa16ea6e08fa49a3cc909
push id14706
push usereakhgari@mozilla.com
push dateTue, 11 Sep 2012 20:39:52 +0000
treeherdermozilla-inbound@d50bf1edaabe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge 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(nsInsertPlaintextComman