Merge from TM
authorLuke Wagner <lw@mozilla.com>
Sun, 04 Jul 2010 14:49:39 -0700
changeset 53063 95dc54180c543b4674c6cb4761f84baa29eb2820
parent 53062 63fe1945af8c06ab94565bc933417bb2e4dffff9 (current diff)
parent 47589 9749ef55a16bbee5ad59ca37f70d887b8b6222c6 (diff)
child 53064 5571e48bb47b5df16f358def9a915775e08299f0
push id15660
push userrsayre@mozilla.com
push dateSat, 11 Sep 2010 19:16:24 +0000
treeherdermozilla-central@f1bd314e64ac [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone2.0b2pre
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 TM
browser/components/places/public/Makefile.in
browser/components/places/public/nsIPlacesTransactionsService.idl
browser/components/places/src/nsPlacesTransactionsService.js
browser/themes/gnomestripe/browser/Geo.png
browser/themes/pinstripe/browser/Geo.png
browser/themes/winstripe/browser/Geo-aero.png
browser/themes/winstripe/browser/Geo.png
caps/src/nsScriptSecurityManager.cpp
chrome/src/nsChromeFactory.cpp
content/base/public/nsContentUtils.h
content/base/public/nsIChromeRegistry.idl
content/base/src/nsContentUtils.cpp
content/base/src/nsFrameMessageManager.cpp
content/canvas/src/CustomQS_WebGL.h
content/html/document/src/nsHTMLDocument.cpp
content/html/document/src/nsHTMLDocument.h
docshell/base/nsGlobalHistory2Adapter.cpp
docshell/base/nsGlobalHistory2Adapter.h
docshell/base/nsGlobalHistoryAdapter.cpp
docshell/base/nsGlobalHistoryAdapter.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsJSEnvironment.cpp
extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
gfx/thebes/cairo-xlib-utils.c
js/jsd/jsd_xpc.cpp
js/src/Makefile.in
js/src/config/rules.mk
js/src/configure.in
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsbuiltins.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsemit.cpp
js/src/jsfun.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsopcode.cpp
js/src/jsparse.cpp
js/src/jsparse.h
js/src/jsproxy.cpp
js/src/jsproxy.h
js/src/jsprvtd.h
js/src/jspubtd.h
js/src/jsregexp.cpp
js/src/jsregexp.h
js/src/jsscope.h
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsstr.cpp
js/src/jsstr.h
js/src/jstl.h
js/src/jstracer.cpp
js/src/jstypedarray.cpp
js/src/jsvector.h
js/src/jswrapper.cpp
js/src/jswrapper.h
js/src/jsxml.cpp
js/src/shell/js.cpp
js/src/xpconnect/idl/nsIXPConnect.idl
js/src/xpconnect/loader/mozJSComponentLoader.cpp
js/src/xpconnect/shell/xpcshell.cpp
js/src/xpconnect/src/Makefile.in
js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
js/src/xpconnect/src/dom_quickstubs.qsconf
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/qsgen.py
js/src/xpconnect/src/wrappers/AccessCheck.cpp
js/src/xpconnect/src/wrappers/AccessCheck.h
js/src/xpconnect/src/wrappers/ChromeWrapper.cpp
js/src/xpconnect/src/wrappers/ChromeWrapper.h
js/src/xpconnect/src/wrappers/ContentWrapper.cpp
js/src/xpconnect/src/wrappers/ContentWrapper.h
js/src/xpconnect/src/wrappers/Makefile.in
js/src/xpconnect/src/wrappers/WrapperFactory.cpp
js/src/xpconnect/src/wrappers/WrapperFactory.h
js/src/xpconnect/src/xpccomponents.cpp
js/src/xpconnect/src/xpcconvert.cpp
js/src/xpconnect/src/xpcjsid.cpp
js/src/xpconnect/src/xpcprivate.h
js/src/xpconnect/src/xpcquickstubs.cpp
js/src/xpconnect/src/xpcquickstubs.h
js/src/xpconnect/src/xpcthreadcontext.cpp
js/src/xpconnect/src/xpcvariant.cpp
js/src/xpconnect/src/xpcwrappednative.cpp
js/src/xpconnect/src/xpcwrappednativejsops.cpp
js/src/xpconnect/src/xpcwrappednativescope.cpp
js/src/xpconnect/tests/TestXPC.cpp
js/src/xpconnect/tests/unit/CatRegistrationComponents.js
js/src/xpconnect/wrappers/AccessCheck.cpp
modules/libjar/nsXPTZipLoader.cpp
modules/libjar/nsXPTZipLoader.h
modules/plugin/base/src/nsJSNPRuntime.cpp
rdf/build/nsRDFModule.h
storage/src/mozStorageStatementParams.cpp
toolkit/components/filepicker/src/nsFilePicker.js.in
toolkit/mozapps/plugins/pluginGlue.js
xpcom/base/nsrootidl.idl
xpcom/components/nsIComponentManagerObsolete.idl
xpcom/components/nsIModuleLoader.idl
xpcom/components/nsIServiceManagerObsolete.h
xpcom/components/nsModule.h
xpcom/components/nsObsoleteModuleLoading.h
xpcom/components/nsServiceManagerObsolete.cpp
xpcom/components/nsStaticComponentLoader.cpp
xpcom/components/nsStaticComponentLoader.h
xpcom/ds/nsINIProcessor.js
xpcom/glue/nsGenericFactory.cpp
xpcom/glue/nsGenericFactory.h
xpcom/glue/nsIGenericFactory.h
xpcom/reflect/xptinfo/public/nsIXPTLoader.idl
xpcom/reflect/xptinfo/src/xptiMisc.cpp
xpcom/tests/TestFactory.cpp
xpcom/tests/TestFactory.h
xpcom/tests/TestServMgr.cpp
xpcom/tests/dynamic/Makefile.in
xpcom/tests/dynamic/TestDynamic.cpp
xpcom/tests/regorder/core/componentDeferred.js
xpcom/tests/regorder/extension/extComponentDeferred.js
xpcom/tests/services/Makefile.in
xpcom/tests/services/MyService.cpp
xpcom/tests/services/MyService.h
--- a/.hgtags
+++ b/.hgtags
@@ -30,11 +30,25 @@ 8a601ed6bc4c7b3d1e35aa9e81f257512d984bd5
 d7d64f68423b68a671f623f123e90057ebc49dac UPDATE_PACKAGING_R7
 fb32f6e1859c07846a01b4478a7b1678019e0b45 UPDATE_PACKAGING_R7
 f817a4378f32b1ad0a7c4b5a9949586dba816da5 FENNEC_M11
 5c1e7c779b6edc8ff912001990edc579f80597f4 FENNEC_B1
 fe9cc55b8db7f56f7e68a246acba363743854979 UPDATE_PACKAGING_R8
 6fd4bb500d425c406c1b52f66e5b195b20ae5e0a chromium-import-r15462
 6fd4bb500d425c406c1b52f66e5b195b20ae5e0a chromium-import-latest
 376b78fc72230aaf2ca4e279a8f4ef1efd4a1d9f GECKO_1_9_2_BASE
+941ad9d7d079246481f365c3cfbfc75a5bbefc94 last-mozilla-central
+2bae3bbf866e7de2a4b2377e7c2f52cc9ac14a22 last-mozilla-central
+2bae3bbf866e7de2a4b2377e7c2f52cc9ac14a22 last-mozilla-central
+65c1582465efe99899189519fccaf7b2826fcb2e last-mozilla-central
+65c1582465efe99899189519fccaf7b2826fcb2e last-mozilla-central
+27937722da69ad0e8fd140a00671413068226a5b last-mozilla-central
+27937722da69ad0e8fd140a00671413068226a5b last-mozilla-central
+a732c6d3c078f80635255c78bfaadffa5828a8a5 last-mozilla-central
+a732c6d3c078f80635255c78bfaadffa5828a8a5 last-mozilla-central
+925595f3c08634cc42e33158ea6858bb55623ef7 last-mozilla-central
+dba2abb7db57078c5a4810884834d3056a5d56c2 last-mozilla-central
 138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R9
 138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R10
 138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R11
+0327e126ea245112c0aa7283fee154e084866fb5 bsmedberg-static-xpcom-registration-base
+0327e126ea245112c0aa7283fee154e084866fb5 bsmedberg-static-xpcom-registration-base
+2f83edbbeef0de7dd901411d270da61106c8afae bsmedberg-static-xpcom-registration-base
--- a/accessible/build/nsAccessibilityFactory.cpp
+++ b/accessible/build/nsAccessibilityFactory.cpp
@@ -31,52 +31,56 @@
  * 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 "nsCOMPtr.h"
-#include "nsIModule.h"
-#include "nsIGenericFactory.h"
+#include "mozilla/ModuleUtils.h"
 
 #include "nsIServiceManager.h"
 #include "nsIComponentManager.h"
 #include "nsIAccessibilityService.h"
 #include "nsIAccessibleRetrieval.h"
 #include "nscore.h"
 
-static NS_IMETHODIMP
+static nsresult
 NS_ConstructAccessibilityService(nsISupports *aOuter, REFNSIID aIID, void **aResult)
 {
     nsresult rv;
     NS_ASSERTION(aOuter == nsnull, "no aggregation");
     nsIAccessibilityService* accessibility;
     rv = NS_GetAccessibilityService(&accessibility);
     if (NS_FAILED(rv)) {
         NS_ERROR("Unable to construct accessibility service");
         return rv;
     }
     rv = accessibility->QueryInterface(aIID, aResult);
     NS_ASSERTION(NS_SUCCEEDED(rv), "unable to find correct interface");
     NS_RELEASE(accessibility);
     return rv;
 }
 
-// The list of components we register
-static const nsModuleComponentInfo components[] = 
-{
-    { "AccessibilityService", 
-      NS_ACCESSIBILITY_SERVICE_CID,
-      "@mozilla.org/accessibilityService;1", 
-      NS_ConstructAccessibilityService
-    },
-    { "AccessibleRetrieval", 
-      NS_ACCESSIBLE_RETRIEVAL_CID,
-      "@mozilla.org/accessibleRetrieval;1", 
-      NS_ConstructAccessibilityService
-    },
+NS_DEFINE_NAMED_CID(NS_ACCESSIBILITY_SERVICE_CID);
+NS_DEFINE_NAMED_CID(NS_ACCESSIBLE_RETRIEVAL_CID);
+
+static const mozilla::Module::CIDEntry kA11yCIDs[] = {
+    { &kNS_ACCESSIBILITY_SERVICE_CID, false, NULL, NS_ConstructAccessibilityService },
+    { NULL }
 };
 
-NS_IMPL_NSGETMODULE(nsAccessibilityModule, components)
+static const mozilla::Module::ContractIDEntry kA11yContracts[] = {
+    { "@mozilla.org/accessibilityService;1", &kNS_ACCESSIBILITY_SERVICE_CID },
+    { "@mozilla.org/accessibleRetrieval;1", &kNS_ACCESSIBILITY_SERVICE_CID },
+    { NULL }
+};
+
+static const mozilla::Module kA11yModule = {
+    mozilla::Module::kVersion,
+    kA11yCIDs,
+    kA11yContracts
+};
+
+NSMODULE_DEFN(nsAccessibilityModule) = &kA11yModule;
 
 
--- a/accessible/public/msaa/ISimpleDOMDocument.idl
+++ b/accessible/public/msaa/ISimpleDOMDocument.idl
@@ -34,18 +34,16 @@
  * 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 ***** */
 
 cpp_quote("///////////////////////////////////////////////////////////////////////////////////////////////////////")
 cpp_quote("//")
 cpp_quote("// ISimpleDOMDocument")
-cpp_quote("//")
-cpp_quote("// @STATUS UNDER_REVIEW")
 cpp_quote("// ---------------------------------------------------------------------------------------------------=")
 cpp_quote("//")
 cpp_quote("// get_URL(out] BSTR *url)")
 cpp_quote("// ---------------------------------------------------------------------------------------------------=")
 cpp_quote("// Get the internet URL associated with this document.")
 cpp_quote("//")
 cpp_quote("// get_title([out BSTR *title")
 cpp_quote("// ---------------------------------------------------------------------------------------------------=")
--- a/accessible/public/msaa/ISimpleDOMNode.idl
+++ b/accessible/public/msaa/ISimpleDOMNode.idl
@@ -37,18 +37,16 @@
  * ***** END LICENSE BLOCK ***** */
 
 cpp_quote("///////////////////////////////////////////////////////////////////////////////////////////////////////")
 cpp_quote("//")
 cpp_quote("// ISimpleDOMNode")
 cpp_quote("// ---------------------------------------------------------------------------------------------------=")
 cpp_quote("// An interface that extends MSAA's IAccessible to provide readonly DOM node information via cross-process COM.")
 cpp_quote("//")
-cpp_quote("// @STATUS UNDER_REVIEW")
-cpp_quote("//")
 cpp_quote("// get_nodeInfo(")
 cpp_quote("//  /* [out] */ BSTR  *nodeName,   // For elements, this is the tag name")
 cpp_quote("//  /* [out] */ short  *nameSpaceID,")
 cpp_quote("//  /* [out] */ BSTR  *nodeValue, ")
 cpp_quote("//  /* [out] */ unsigned int    *numChildren); ") 
 cpp_quote("//  /* [out] */ unsigned int    *uniqueID;  // In Win32 accessible events we generate, the target's childID matches to this")
 cpp_quote("//  /* [out] */ unsigned short  *nodeType,")
 cpp_quote("// ---------------------------------------------------------------------------------------------------=")
--- a/accessible/public/msaa/ISimpleDOMText.idl
+++ b/accessible/public/msaa/ISimpleDOMText.idl
@@ -40,18 +40,16 @@ import "objidl.idl";
 import "oaidl.idl";
         
 cpp_quote("///////////////////////////////////////////////////////////////////////////////////////////////////////")
 cpp_quote("//")
 cpp_quote("// ISimpleDOMText")
 cpp_quote("// ---------------------------------------------------------------------------------------------------=")
 cpp_quote("// An interface that extends MSAA's IAccessible to provide important additional capabilities on text nodes")
 cpp_quote("//")
-cpp_quote("// @STATUS UNDER_REVIEW")
-cpp_quote("//")
 cpp_quote("// [propget] domText(/* out,retval */ BSTR *domText")
 cpp_quote("// ---------------------------------------------------------------------------------------------------=")
 cpp_quote("// Similar to IAccessible::get_accName, but does not strip out whitespace characters.")
 cpp_quote("// Important for retrieving the correct start/end substring indices to use with other")
 cpp_quote("// methods in ISimpleDOMText.")
 cpp_quote("//")
 cpp_quote("//")
 cpp_quote("// get_[un]clippedSubstringBounds(")
--- a/accessible/public/nsIAccessNode.idl
+++ b/accessible/public/nsIAccessNode.idl
@@ -48,18 +48,16 @@ interface nsIDOMCSSPrimitiveValue;
  * a DOM node. When accessibility is active in Gecko,
  * every DOM node can have one nsIAccessNode for each
  * pres shell the DOM node is rendered in.
  * The nsIAccessNode implementations are instantiated lazily.
  * The nsIAccessNode tree for a given dom window
  * has a one to one relationship to the DOM tree.
  * If the DOM node for this access node is "accessible",
  * then a QueryInterface to nsIAccessible will succeed.
- *
- * @status UNDER_REVIEW
  */
 [scriptable, uuid(ef16ff42-0256-4b48-ae87-b18a95b7f7d6)]
 interface nsIAccessNode : nsISupports
 {
   /**
    * The DOM node this nsIAccessNode is associated with.
    */
   readonly attribute nsIDOMNode DOMNode;
--- a/accessible/public/nsIAccessible.idl
+++ b/accessible/public/nsIAccessible.idl
@@ -50,18 +50,16 @@ interface nsIAccessibleRelation;
  * A cross-platform interface that supports platform-specific 
  * accessibility APIs like MSAA and ATK. Contains the sum of what's needed
  * to support IAccessible as well as ATK's generic accessibility objects.
  * Can also be used by in-process accessibility clients to get information
  * about objects in the accessible tree. The accessible tree is a subset of 
  * nodes in the DOM tree -- such as documents, focusable elements and text.
  * Mozilla creates the implementations of nsIAccessible on demand.
  * See http://www.mozilla.org/projects/ui/accessibility for more information.
- *
- * @status UNDER_REVIEW
  */
 [scriptable, uuid(c81d8f8c-8585-4094-bc7c-71dd01494906)]
 interface nsIAccessible : nsISupports
 {
   /**
    * Parent node in accessible tree.
    */
   readonly attribute nsIAccessible parent;
--- a/accessible/public/nsIAccessibleDocument.idl
+++ b/accessible/public/nsIAccessibleDocument.idl
@@ -50,18 +50,16 @@ interface nsIDOMWindow;
  * When accessibility is turned on in Gecko,
  * there is an nsIAccessibleDocument for each document
  * whether it is XUL, HTML or whatever.
  * You can QueryInterface to nsIAccessibleDocument from
  * the nsIAccessible or nsIAccessNode for the root node
  * of a document. You can also get one from 
  * nsIAccessNode::GetAccessibleDocument() or 
  * nsIAccessibleEvent::GetAccessibleDocument()
- *
- * @status UNDER_REVIEW
  */
 [scriptable, uuid(03c6ce8a-aa40-4484-9282-e6579c56e054)]
 interface nsIAccessibleDocument : nsISupports
 {
   /**
    * The URL of the document
    */
   readonly attribute AString URL;
--- a/accessible/public/nsIAccessibleEvent.idl
+++ b/accessible/public/nsIAccessibleEvent.idl
@@ -53,18 +53,16 @@ interface nsIDOMNode;
  * to find out how to get accessibility and DOM interfaces for
  * the event and its target. To listen to in-process accessibility invents,
  * make your object an nsIObserver, and listen for accessible-event by 
  * using code something like this:
  *   nsCOMPtr<nsIObserverService> observerService = 
  *     do_GetService("@mozilla.org/observer-service;1", &rv);
  *   if (NS_SUCCEEDED(rv)) 
  *     rv = observerService->AddObserver(this, "accessible-event", PR_TRUE);
- *
- * @status UNDER_REVIEW
  */
 [scriptable, uuid(c68b4386-dca7-4b88-8988-7a95ce7be92f)]
 interface nsIAccessibleEvent : nsISupports
 {
   /**
    * An object has been created.
    */
   const unsigned long EVENT_SHOW = 0x0001;
--- a/accessible/public/nsIAccessibleImage.idl
+++ b/accessible/public/nsIAccessibleImage.idl
@@ -31,20 +31,16 @@
  * 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"
 
-/**
- *
- * @status UNDER_REVIEW
- */
 [scriptable, uuid(09086623-0f09-4310-ac56-c2cda7c29648)]
 interface nsIAccessibleImage : nsISupports
 {
   /**
    * Returns the coordinates of the image.
    *
    * @param coordType  specifies coordinates origin (for available constants
    *                   refer to nsIAccessibleCoordinateType)
--- a/accessible/public/nsIAccessibleRetrieval.idl
+++ b/accessible/public/nsIAccessibleRetrieval.idl
@@ -48,60 +48,34 @@ interface nsIDOMDOMStringList;
 
 
 /**
  * An interface for in-process accessibility clients
  * wishing to get an nsIAccessible or nsIAccessNode for
  * a given DOM node.
  * More documentation at:
  *   http://www.mozilla.org/projects/ui/accessibility
- *
- * @status UNDER_REVIEW
  */
-[scriptable, uuid(420f0f49-27c1-4ac1-b509-5aba4353909b)]
+[scriptable, uuid(310ce77d-c92b-4761-82e8-77e1a728e8d4)]
 interface nsIAccessibleRetrieval : nsISupports
 {
   /**
    * Return application accessible.
    */
   nsIAccessible getApplicationAccessible();
 
   /**
    * Return an nsIAccessible for a DOM node in pres shell 0.
    * Create a new accessible of the appropriate type if necessary,
    * or use one from the accessibility cache if it already exists.
    * @param aNode The DOM node to get an accessible for.
    * @return The nsIAccessible for the given DOM node.
    */
   nsIAccessible getAccessibleFor(in nsIDOMNode aNode);
 
-  /**
-   * The same like getAccessibleFor method except it returns accessible only if
-   * it is attached, i.e. accessible is certified to be a descendent of the root
-   * accessible.
-   *
-   * @param aNode - the DOM node to get an accessible for.
-   *
-   * @return - the accessible for the given DOM node.
-   */
-  nsIAccessible getAttachedAccessibleFor(in nsIDOMNode aNode);
-
-  /**
-   * Return an DOM node that is relevant to attached accesible check. This
-   * node is either from bindings chain if given node is anonymous and owner
-   * binding denies accessible in anonymous content or given node (it's not
-   * important whether it is accessible or not). This method doesn't create
-   * accessible object for returned node.
-   *
-   * @param aNode - the DOM node to get relevant content node.
-   *
-   * @return - the DOM node for parent attached accessible
-   */
-  nsIDOMNode getRelevantContentNodeFor(in nsIDOMNode aNode);
-
    /**
     * Returns accessible role as a string.
     *
     * @param aRole - the accessible role constants.
     */
   AString getStringRole(in unsigned long aRole);
 
    /**
--- a/accessible/public/nsIAccessibleSelectable.idl
+++ b/accessible/public/nsIAccessibleSelectable.idl
@@ -41,18 +41,16 @@
  * ***** END LICENSE BLOCK ***** */
 #include "nsISupports.idl"
 #include "nsIAccessible.idl"
 #include "nsIArray.idl"
 
 /**
  * An interface for the accessibility module and in-process accessibility clients
  * for dealing with getting and changing the selection of accessible nodes.
- *
- * @status UNDER_REVIEW
  */
 [scriptable, uuid(34d268d6-1dd2-11b2-9d63-83a5e0ada290)]
 interface nsIAccessibleSelectable : nsISupports
 {
     const unsigned long eSelection_Add = 0;
     const unsigned long eSelection_Remove = 1;
     const unsigned long eSelection_GetState = 2;
 
--- a/accessible/src/atk/nsAccessibleWrap.cpp
+++ b/accessible/src/atk/nsAccessibleWrap.cpp
@@ -924,17 +924,17 @@ getIndexInParentCB(AtkObject *aAtkObj)
         return -1; // No parent
     }
 
     // Links within hypertext accessible play role of accessible children in
     // ATK since every embedded object is a link and text accessibles are
     // ignored.
     nsRefPtr<nsHyperTextAccessible> hyperTextParent(do_QueryObject(parent));
     return hyperTextParent ?
-        hyperTextParent->GetLinkIndex(accWrap) : parent->GetIndexOf(accWrap);
+        hyperTextParent->GetLinkIndex(accWrap) : accWrap->GetIndexInParent();
 }
 
 static void TranslateStates(PRUint32 aState, const AtkStateMap *aStateMap,
                             AtkStateSet *aStateSet)
 {
   NS_ASSERTION(aStateSet, "Can't pass in null state set");
 
   // Convert every state to an entry in AtkStateMap
--- a/accessible/src/base/nsAccDocManager.cpp
+++ b/accessible/src/base/nsAccDocManager.cpp
@@ -35,16 +35,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsAccDocManager.h"
 
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
+#include "nsApplicationAccessible.h"
 #include "nsOuterDocAccessible.h"
 #include "nsRootAccessibleWrap.h"
 
 #include "nsCURILoader.h"
 #include "nsDocShellLoadTypes.h"
 #include "nsIChannel.h"
 #include "nsIContentViewer.h"
 #include "nsIDOMDocument.h"
@@ -449,62 +450,60 @@ nsAccDocManager::CreateDocOrRootAccessib
   if (!rootElm)
     return nsnull;
 
   PRBool isRootDoc = nsCoreUtils::IsRootDocument(aDocument);
 
   // Ensure the document container node is accessible, otherwise do not create
   // document accessible.
   nsAccessible *outerDocAcc = nsnull;
-  if (!isRootDoc) {
+  if (isRootDoc) {
+    outerDocAcc = nsAccessNode::GetApplicationAccessible();
+
+  } else {
     nsIDocument* parentDoc = aDocument->GetParentDocument();
     if (!parentDoc)
       return nsnull;
 
     nsIContent* ownerContent = parentDoc->FindContentForSubDocument(aDocument);
     if (!ownerContent)
       return nsnull;
 
     // XXXaaronl: ideally we would traverse the presshell chain. Since there's
     // no easy way to do that, we cheat and use the document hierarchy.
     // GetAccessible() is bad because it doesn't support our concept of multiple
     // presshells per doc. It should be changed to use
     // GetAccessibleInWeakShell().
     outerDocAcc = GetAccService()->GetAccessible(ownerContent);
-    if (!outerDocAcc)
-      return nsnull;
   }
 
-  nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(presShell));
+  if (!outerDocAcc)
+    return nsnull;
 
   // We only create root accessibles for the true root, otherwise create a
   // doc accessible.
+  nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(presShell));
   nsDocAccessible *docAcc = isRootDoc ?
     new nsRootAccessibleWrap(aDocument, rootElm, weakShell) :
     new nsDocAccessibleWrap(aDocument, rootElm, weakShell);
 
   if (!docAcc)
     return nsnull;
 
   // Cache and addref document accessible.
   if (!mDocAccessibleCache.Put(static_cast<void*>(aDocument), docAcc)) {
     delete docAcc;
     return nsnull;
   }
 
   // XXX: ideally we should initialize an accessible and then put it into tree,
-  // also this code should be shared between doc and root accessibles.
-  if (outerDocAcc) {
-    // Root document accessible doesn't have associated outerdoc accessible, it
-    // adds itself to application accessible instead.
-    outerDocAcc->AppendChild(docAcc);
-  }
-
-  if (!GetAccService()->InitAccessible(docAcc,
-                                       nsAccUtils::GetRoleMapEntry(aDocument))) {
+  // we can't since document accessible fires reorder event on its container
+  // while initialized.
+  if (!outerDocAcc->AppendChild(docAcc) ||
+      !GetAccService()->InitAccessible(docAcc, nsAccUtils::GetRoleMapEntry(aDocument))) {
     mDocAccessibleCache.Remove(static_cast<void*>(aDocument));
     return nsnull;
   }
 
   NS_LOG_ACCDOCCREATE("document creation finished", aDocument)
 
   AddListeners(aDocument, isRootDoc);
   return docAcc;
--- a/accessible/src/base/nsAccEvent.cpp
+++ b/accessible/src/base/nsAccEvent.cpp
@@ -295,16 +295,17 @@ nsAccReorderEvent::HasAccessibleInReason
 {
   if (!mReasonNode)
     return PR_FALSE;
 
   nsAccessible *accessible = GetAccService()->GetAccessible(mReasonNode);
   return accessible || nsAccUtils::HasAccessibleChildren(mReasonNode);
 }
 
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccStateChangeEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_ISUPPORTS_INHERITED1(nsAccStateChangeEvent, nsAccEvent,
                              nsIAccessibleStateChangeEvent)
 
 // Note: we pass in eAllowDupes to the base class because we don't currently
@@ -382,40 +383,38 @@ NS_IMPL_ISUPPORTS_INHERITED1(nsAccTextCh
 // events coalescence. We fire delayed text change events in nsDocAccessible but
 // we continue to base the event off the accessible object rather than just the
 // node. This means we won't try to create an accessible based on the node when
 // we are ready to fire the event and so we will no longer assert at that point
 // if the node was removed from the document. Either way, the AT won't work with
 // a defunct accessible so the behaviour should be equivalent.
 // XXX revisit this when coalescence is faster (eCoalesceFromSameSubtree)
 nsAccTextChangeEvent::
-  nsAccTextChangeEvent(nsAccessible *aAccessible,
-                       PRInt32 aStart, PRUint32 aLength,
+  nsAccTextChangeEvent(nsAccessible *aAccessible, PRInt32 aStart,
                        nsAString& aModifiedText, PRBool aIsInserted,
                        PRBool aIsAsynch, EIsFromUserInput aIsFromUserInput) :
   nsAccEvent(aIsInserted ? nsIAccessibleEvent::EVENT_TEXT_INSERTED : nsIAccessibleEvent::EVENT_TEXT_REMOVED,
              aAccessible, aIsAsynch, aIsFromUserInput, eAllowDupes),
-  mStart(aStart), mLength(aLength), mIsInserted(aIsInserted),
-  mModifiedText(aModifiedText)
+  mStart(aStart), mIsInserted(aIsInserted), mModifiedText(aModifiedText)
 {
 }
 
 NS_IMETHODIMP
 nsAccTextChangeEvent::GetStart(PRInt32 *aStart)
 {
   NS_ENSURE_ARG_POINTER(aStart);
   *aStart = mStart;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccTextChangeEvent::GetLength(PRUint32 *aLength)
 {
   NS_ENSURE_ARG_POINTER(aLength);
-  *aLength = mLength;
+  *aLength = GetLength();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccTextChangeEvent::IsInserted(PRBool *aIsInserted)
 {
   NS_ENSURE_ARG_POINTER(aIsInserted);
   *aIsInserted = mIsInserted;
@@ -424,16 +423,34 @@ nsAccTextChangeEvent::IsInserted(PRBool 
 
 NS_IMETHODIMP
 nsAccTextChangeEvent::GetModifiedText(nsAString& aModifiedText)
 {
   aModifiedText = mModifiedText;
   return NS_OK;
 }
 
+
+////////////////////////////////////////////////////////////////////////////////
+// AccHideEvent
+////////////////////////////////////////////////////////////////////////////////
+
+AccHideEvent::
+  AccHideEvent(nsAccessible* aTarget, nsINode* aTargetNode,
+               PRBool aIsAsynch, EIsFromUserInput aIsFromUserInput) :
+  nsAccEvent(nsIAccessibleEvent::EVENT_HIDE, aTarget, aIsAsynch,
+             aIsFromUserInput, eCoalesceFromSameSubtree)
+{
+  mNode = aTargetNode;
+  mParent = mAccessible->GetCachedParent();
+  mNextSibling = mAccessible->GetCachedNextSibling();
+  mPrevSibling = mAccessible->GetCachedPrevSibling();
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccCaretMoveEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_ISUPPORTS_INHERITED1(nsAccCaretMoveEvent, nsAccEvent,
                              nsIAccessibleCaretMoveEvent)
 
 nsAccCaretMoveEvent::
--- a/accessible/src/base/nsAccEvent.h
+++ b/accessible/src/base/nsAccEvent.h
@@ -107,24 +107,25 @@ public:
 
   // nsAccEvent
   PRUint32 GetEventType() const { return mEventType; }
   EEventRule GetEventRule() const { return mEventRule; }
   PRBool IsAsync() const { return mIsAsync; }
   PRBool IsFromUserInput() const { return mIsFromUserInput; }
 
   nsAccessible *GetAccessible();
+  nsDocAccessible* GetDocAccessible();
   nsINode* GetNode();
-  nsDocAccessible* GetDocAccessible();
 
   enum EventGroup {
     eGenericEvent,
     eReorderEvent,
     eStateChangeEvent,
     eTextChangeEvent,
+    eHideEvent,
     eCaretMoveEvent,
     eTableChangeEvent
   };
 
   static const EventGroup kEventGroup = eGenericEvent;
   virtual unsigned int GetEventGroups() const
   {
     return 1U << eGenericEvent;
@@ -231,40 +232,67 @@ private:
 /**
  * Accessible text change event.
  */
 class nsAccTextChangeEvent: public nsAccEvent,
                             public nsIAccessibleTextChangeEvent
 {
 public:
   nsAccTextChangeEvent(nsAccessible *aAccessible, PRInt32 aStart,
-                       PRUint32 aLength, nsAString& aModifiedText,
+                       nsAString& aModifiedText,
                        PRBool aIsInserted, PRBool aIsAsynch = PR_FALSE,
                        EIsFromUserInput aIsFromUserInput = eAutoDetect);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIACCESSIBLETEXTCHANGEEVENT
 
   // nsAccEvent
   static const EventGroup kEventGroup = eTextChangeEvent;
   virtual unsigned int GetEventGroups() const
   {
     return nsAccEvent::GetEventGroups() | (1U << eTextChangeEvent);
   }
 
   // nsAccTextChangeEvent
   PRInt32 GetStartOffset() const { return mStart; }
-  PRUint32 GetLength() const { return mLength; }
+  PRUint32 GetLength() const { return mModifiedText.Length(); }
   PRBool IsTextInserted() const { return mIsInserted; }
 
 private:
   PRInt32 mStart;
-  PRUint32 mLength;
   PRBool mIsInserted;
   nsString mModifiedText;
+
+  friend class nsAccEventQueue;
+};
+
+
+/**
+ * Accessible hide events.
+ */
+class AccHideEvent : public nsAccEvent
+{
+public:
+  AccHideEvent(nsAccessible* aTarget, nsINode* aTargetNode,
+               PRBool aIsAsynch, EIsFromUserInput aIsFromUserInput);
+
+  // nsAccEvent
+  static const EventGroup kEventGroup = eHideEvent;
+  virtual unsigned int GetEventGroups() const
+  {
+    return nsAccEvent::GetEventGroups() | (1U << eHideEvent);
+  }
+
+protected:
+  nsRefPtr<nsAccessible> mParent;
+  nsRefPtr<nsAccessible> mNextSibling;
+  nsRefPtr<nsAccessible> mPrevSibling;
+  nsRefPtr<nsAccTextChangeEvent> mTextChangeEvent;
+
+  friend class nsAccEventQueue;
 };
 
 
 /**
  * Accessible caret move event.
  */
 class nsAccCaretMoveEvent: public nsAccEvent,
                            public nsIAccessibleCaretMoveEvent
--- a/accessible/src/base/nsAccTreeWalker.cpp
+++ b/accessible/src/base/nsAccTreeWalker.cpp
@@ -108,18 +108,18 @@ nsAccTreeWalker::GetNextChildInternal(PR
     mState->childList->GetLength(&length);
 
   while (mState->childIdx < length) {
     nsIContent* childNode = mState->childList->GetNodeAt(mState->childIdx);
     mState->childIdx++;
 
     PRBool isHidden = PR_FALSE;
     nsRefPtr<nsAccessible> accessible =
-      GetAccService()->GetAccessible(childNode, presShell, mWeakShell,
-                                     &isHidden);
+      GetAccService()->GetOrCreateAccessible(childNode, presShell, mWeakShell,
+                                             &isHidden);
 
     if (accessible)
       return accessible.forget();
 
     // Walk down into subtree to find accessibles.
     if (!isHidden) {
       if (!PushState(childNode))
         break;
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -522,41 +522,38 @@ nsAccUtils::GetTextAccessibleFromSelecti
     return nsnull;
 
   PRInt32 focusOffset = 0;
   aSelection->GetFocusOffset(&focusOffset);
 
   nsCOMPtr<nsINode> focusNode(do_QueryInterface(focusDOMNode));
   nsCOMPtr<nsINode> resultNode =
     nsCoreUtils::GetDOMNodeFromDOMPoint(focusNode, focusOffset);
+  nsCOMPtr<nsIWeakReference> weakShell(nsCoreUtils::GetWeakShellFor(resultNode));
 
   // Get text accessible containing the result node.
-  while (resultNode) {
-    // Make sure to get the correct starting node for selection events inside
-    // XBL content trees.
-    resultNode = GetAccService()->GetRelevantContentNodeFor(resultNode);
-    if (!resultNode->IsNodeOfType(nsINode::eTEXT)) {
-      nsAccessible *accessible = GetAccService()->GetAccessible(resultNode);
-      if (accessible) {
-        nsHyperTextAccessible *textAcc = nsnull;
-        CallQueryInterface(accessible, &textAcc);
-        if (textAcc) {
-          if (aNode)
-            NS_ADDREF(*aNode = resultNode);
-
-          return textAcc;
-        }
-      }
-    }
-
-    resultNode = resultNode->GetNodeParent();
+  nsAccessible* accessible =
+    GetAccService()->GetAccessibleOrContainer(resultNode, weakShell);
+  if (!accessible) {
+    NS_NOTREACHED("No nsIAccessibleText for selection change event!");
+    return nsnull;
   }
 
-  NS_NOTREACHED("No nsIAccessibleText for selection change event!");
+  do {
+    nsHyperTextAccessible* textAcc = nsnull;
+    CallQueryInterface(accessible, &textAcc);
+    if (textAcc) {
+      if (aNode)
+        NS_ADDREF(*aNode = accessible->GetNode());
 
+      return textAcc;
+    }
+  } while (accessible = accessible->GetParent());
+
+  NS_NOTREACHED("We must reach document accessible implementing nsIAccessibleText!");
   return nsnull;
 }
 
 nsresult
 nsAccUtils::ConvertToScreenCoords(PRInt32 aX, PRInt32 aY,
                                   PRUint32 aCoordinateType,
                                   nsAccessNode *aAccessNode,
                                   nsIntPoint *aCoords)
@@ -629,17 +626,18 @@ nsAccUtils::GetScreenCoordsForWindow(nsA
 {
   return nsCoreUtils::GetScreenCoordsForWindow(aAccessNode->GetNode());
 }
 
 nsIntPoint
 nsAccUtils::GetScreenCoordsForParent(nsAccessNode *aAccessNode)
 {
   nsAccessible *parent =
-    GetAccService()->GetContainerAccessible(aAccessNode->GetNode(), PR_TRUE);
+    GetAccService()->GetContainerAccessible(aAccessNode->GetNode(),
+                                            aAccessNode->GetWeakShell());
   if (!parent)
     return nsIntPoint(0, 0);
 
   nsIFrame *parentFrame = parent->GetFrame();
   if (!parentFrame)
     return nsIntPoint(0, 0);
 
   nsIntRect parentRect = parentFrame->GetScreenRectExternal();
@@ -810,22 +808,16 @@ nsAccUtils::MustPrune(nsIAccessible *aAc
     role == nsIAccessibleRole::ROLE_PASSWORD_TEXT ||
     role == nsIAccessibleRole::ROLE_TOGGLE_BUTTON ||
     role == nsIAccessibleRole::ROLE_GRAPHIC ||
     role == nsIAccessibleRole::ROLE_SLIDER ||
     role == nsIAccessibleRole::ROLE_PROGRESSBAR ||
     role == nsIAccessibleRole::ROLE_SEPARATOR;
 }
 
-PRBool
-nsAccUtils::IsNodeRelevant(nsINode *aNode)
-{
-  return aNode == GetAccService()->GetRelevantContentNodeFor(aNode);
-}
-
 nsresult
 nsAccUtils::GetHeaderCellsFor(nsIAccessibleTable *aTable,
                               nsIAccessibleTableCell *aCell,
                               PRInt32 aRowOrColHeaderCells, nsIArray **aCells)
 {
   nsresult rv = NS_OK;
   nsCOMPtr<nsIMutableArray> cells = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/accessible/src/base/nsAccUtils.h
+++ b/accessible/src/base/nsAccUtils.h
@@ -406,22 +406,16 @@ public:
 
   /**
    * Return true if the given accessible can't have children. Used when exposing
    * to platform accessibility APIs, should the children be pruned off?
    */
   static PRBool MustPrune(nsIAccessible *aAccessible);
 
   /**
-   * Return true if the given node can be accessible and attached to
-   * the document's accessible tree.
-   */
-  static PRBool IsNodeRelevant(nsINode *aNode);
-
-  /**
    * Search hint enum constants. Used by GetHeaderCellsFor() method.
    */
   enum {
     // search for row header cells, left direction
     eRowHeaderCells,
     // search for column header cells, top direction
     eColumnHeaderCells
   };
--- a/accessible/src/base/nsAccessNode.h
+++ b/accessible/src/base/nsAccessNode.h
@@ -171,16 +171,21 @@ public:
     return GetNode() && GetNode()->IsNodeOfType(nsINode::eDOCUMENT);
   }
 
   /**
    * Return the corresponding press shell for this accessible.
    */
   already_AddRefed<nsIPresShell> GetPresShell();
 
+  /**
+   * Return presentation shell for the accessible.
+   */
+  nsIWeakReference* GetWeakShell() const { return mWeakShell; }
+
 protected:
     nsPresContext* GetPresContext();
 
     void LastRelease();
 
   nsCOMPtr<nsIContent> mContent;
   nsCOMPtr<nsIWeakReference> mWeakShell;
 
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -143,40 +143,28 @@ nsAccessibilityService::Observe(nsISuppo
 // nsIAccessibilityService
 void
 nsAccessibilityService::NotifyOfAnchorJumpTo(nsIContent *aTarget)
 {
   nsIDocument *document = aTarget->GetCurrentDoc();
   if (!document)
     return;
 
-  nsINode *targetNode = aTarget;
-  nsAccessible *targetAcc = GetAccessible(targetNode);
-
-  // Getting the targetAcc above will have ensured accessible doc creation.
-  // XXX Bug 561683
-  nsDocAccessible *docAccessible = GetDocAccessible(document);
-  if (!docAccessible)
+  // If the jump target is not accessible then fire an event for nearest
+  // accessible in parent chain.
+  nsCOMPtr<nsIWeakReference> weakShell(nsCoreUtils::GetWeakShellFor(aTarget));
+  nsAccessible* targetAcc = GetAccessibleOrContainer(aTarget, weakShell);
+  if (!targetAcc)
     return;
 
-  // If the jump target is not accessible then fire an event for nearest
-  // accessible in parent chain.
-  if (!targetAcc) {
-    targetAcc = GetContainerAccessible(targetNode, PR_TRUE);
-    targetNode = targetAcc->GetNode();
-  }
-
-  NS_ASSERTION(targetNode,
-      "No accessible in parent chain!? Expect at least a document accessible.");
-  if (!targetNode)
-    return;
+  nsINode* targetNode = targetAcc->GetNode();
 
   // XXX note in rare cases the node could go away before we flush the queue,
   // for example if the node becomes inaccessible, or is removed from the DOM.
-  docAccessible->
+  GetDocAccessible(document)->
     FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_SCROLLING_START,
                                targetNode);
 }
 
 // nsIAccessibilityService
 nsresult
 nsAccessibilityService::FireAccessibleEvent(PRUint32 aEvent,
                                             nsIAccessible *aTarget)
@@ -509,41 +497,16 @@ nsAccessibilityService::GetAccessibleFor
   NS_ENSURE_ARG_POINTER(aAccessible);
 
   nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
   NS_IF_ADDREF(*aAccessible = GetAccessible(node));
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsAccessibilityService::GetAttachedAccessibleFor(nsIDOMNode *aDOMNode,
-                                                 nsIAccessible **aAccessible)
-{
-  NS_ENSURE_ARG(aDOMNode);
-  NS_ENSURE_ARG_POINTER(aAccessible);
-
-  nsCOMPtr<nsINode> node(do_QueryInterface(aDOMNode));
-  NS_IF_ADDREF(*aAccessible = GetAttachedAccessibleFor(node));
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsAccessibilityService::GetRelevantContentNodeFor(nsIDOMNode *aNode,
-                                                  nsIDOMNode **aRelevantNode)
-{
-  NS_ENSURE_ARG(aNode);
-  NS_ENSURE_ARG_POINTER(aRelevantNode);
-
-  nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
-  nsINode *relevantNode = GetRelevantContentNodeFor(node);
-  CallQueryInterface(relevantNode, aRelevantNode);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsAccessibilityService::GetStringRole(PRUint32 aRole, nsAString& aString)
 {
   if ( aRole >= NS_ARRAY_LENGTH(kRoleNames)) {
     aString.AssignLiteral("unknown");
     return NS_OK;
   }
 
   CopyUTF8toUTF16(kRoleNames[aRole], aString);
@@ -725,98 +688,57 @@ nsAccessibilityService::GetAccessibleFro
 nsAccessible*
 nsAccessibilityService::GetAccessibleInShell(nsINode* aNode,
                                              nsIPresShell* aPresShell)
 {
   if (!aNode || !aPresShell)
     return nsnull;
 
   nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(aPresShell));
-  nsRefPtr<nsAccessible> accessible =
-    GetAccessible(aNode, aPresShell, weakShell);
-  return accessible;
+  return GetAccessibleByRule(aNode, weakShell, eGetAccForNode);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibilityService public
 
-nsAccessible *
-nsAccessibilityService::GetAccessible(nsINode *aNode)
+nsAccessible*
+nsAccessibilityService::GetAccessible(nsINode* aNode)
 {
-  if (!aNode)
-    return nsnull;
-
-  nsIPresShell *presShell = nsCoreUtils::GetPresShellFor(aNode);
-  if (!presShell)
-    return nsnull;
-
-  nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(presShell));
-  nsRefPtr<nsAccessible> accessible = GetAccessible(aNode, presShell,
-                                                    weakShell);
-  return accessible;
+  if (aNode) {
+    nsCOMPtr<nsIWeakReference> weakShell(nsCoreUtils::GetWeakShellFor(aNode));
+    if (weakShell)
+      return GetAccessibleByRule(aNode, weakShell, eGetAccForNode);
+  }
+  return nsnull;
 }
 
-nsAccessible *
-nsAccessibilityService::GetAccessibleInWeakShell(nsINode *aNode,
-                                                 nsIWeakReference *aWeakShell) 
-{
-  if (!aNode || !aWeakShell)
-    return nsnull;
-
-  nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(aWeakShell));
-  nsRefPtr<nsAccessible> accessible = GetAccessible(aNode, presShell,
-                                                    aWeakShell);
-  return accessible;
-}
-
-nsAccessible *
-nsAccessibilityService::GetContainerAccessible(nsINode *aNode,
-                                               PRBool aCanCreate)
+nsAccessible*
+nsAccessibilityService::GetCachedContainerAccessible(nsINode* aNode)
 {
   if (!aNode)
     return nsnull;
 
   nsIDocument *document = aNode->GetCurrentDoc();
   if (!document)
     return nsnull;
 
   nsIPresShell *presShell = document->GetShell();
   if (!presShell)
     return nsnull;
 
   nsINode *currNode = aNode;
   nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(presShell));
 
   nsAccessible *accessible = nsnull;
-  while (!accessible && (currNode = currNode->GetNodeParent())) {
-    currNode = GetAccService()->GetRelevantContentNodeFor(currNode);
-
-    if (aCanCreate) {
-      accessible = GetAccService()->GetAccessibleInWeakShell(currNode,
-                                                             weakShell);
-
-    } else {
-      // Only return cached accessible, don't create anything.
-      accessible = GetCachedAccessible(currNode, weakShell);
-    }
-  }
+  while ((currNode = currNode->GetNodeParent()) &&
+         !(accessible = GetCachedAccessible(currNode, weakShell)));
 
   return accessible;
 }
 
-nsAccessible *
-nsAccessibilityService::GetAttachedAccessibleFor(nsINode *aNode)
-{
-  nsINode *relevantNode = GetRelevantContentNodeFor(aNode);
-  if (relevantNode != aNode)
-    return nsnull;
-
-  return GetAccessible(relevantNode);
-}
-
 PRBool
 nsAccessibilityService::InitAccessible(nsAccessible *aAccessible,
                                        nsRoleMapEntry *aRoleMapEntry)
 {
   if (!aAccessible)
     return PR_FALSE;
 
   // Add to cache an accessible, etc.
@@ -858,20 +780,20 @@ static PRBool HasRelatedContent(nsIConte
       return PR_TRUE;
     }
   }
 
   return PR_FALSE;
 }
 
 already_AddRefed<nsAccessible>
-nsAccessibilityService::GetAccessible(nsINode *aNode,
-                                      nsIPresShell *aPresShell,
-                                      nsIWeakReference *aWeakShell,
-                                      PRBool *aIsHidden)
+nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
+                                              nsIPresShell* aPresShell,
+                                              nsIWeakReference* aWeakShell,
+                                              PRBool* aIsHidden)
 {
   if (!aPresShell || !aWeakShell || !aNode || gIsShutdown)
     return nsnull;
 
   if (aIsHidden)
     *aIsHidden = PR_FALSE;
 
   // Check to see if we already have an accessible for this node in the cache.
@@ -1239,81 +1161,83 @@ nsAccessibilityService::HasUniversalAria
          nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_invalid) ||
          aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_label) ||
          aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_labelledby) ||
          nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_live) ||
          nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_owns) ||
          nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_relevant);
 }
 
-nsINode *
-nsAccessibilityService::GetRelevantContentNodeFor(nsINode *aNode)
+nsAccessible*
+nsAccessibilityService::GetAccessibleByRule(nsINode* aNode,
+                                            nsIWeakReference* aWeakShell,
+                                            EWhatAccToGet aWhatToGet)
 {
-  // The method returns node that is relevant for attached accessible check.
-  // Sometimes element that is XBL widget hasn't accessible children in
-  // anonymous content. This method check whether given node can be accessible
-  // by looking through all nested bindings that given node is anonymous for. If
-  // there is XBL widget that deniedes to be accessible for given node then the
-  // method returns that XBL widget otherwise it returns given node.
-
-  // For example, the algorithm allows us to handle following cases:
-  // 1. xul:dialog element has buttons (like 'ok' and 'cancel') in anonymous
-  // content. When node is dialog's button then we dialog's button since button
-  // of xul:dialog is accessible anonymous node.
-  // 2. xul:texbox has html:input in anonymous content. When given node is
-  // html:input elmement then we return xul:textbox since xul:textbox doesn't
-  // allow accessible nodes in anonymous content.
-  // 3. xforms:input that is hosted in xul document contains xul:textbox
-  // element. When given node is html:input or xul:textbox then we return
-  // xforms:input element since xforms:input hasn't accessible anonymous
-  // children.
-
-  if (!aNode)
+  if (!aNode || !aWeakShell)
     return nsnull;
 
-  nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
-  if (content) {
-    // Build stack of binding parents so we can walk it in reverse.
-    nsIContent *bindingParent;
-    nsCOMArray<nsIContent> bindingsStack;
+  nsAccessible* cachedAcc = GetCachedAccessible(aNode, aWeakShell);
+  if (cachedAcc) {
+    if (aWhatToGet & eGetAccForNode)
+      return cachedAcc;
 
-    for (bindingParent = content->GetBindingParent(); bindingParent != nsnull &&
-         bindingParent != bindingParent->GetBindingParent();
-         bindingParent = bindingParent->GetBindingParent()) {
-      bindingsStack.AppendObject(bindingParent);
-    }
+    // XXX: while nsAccessible::GetParent() tries to repair broken tree and
+    // may not return cached parent then we use GetAccessibleOrContainer().
+    return GetAccessibleByRule(aNode->GetNodeParent(), aWeakShell,
+                               eGetAccForNodeOrContainer);
+  }
 
-    PRInt32 bindingsCount = bindingsStack.Count();
-    for (PRInt32 index = bindingsCount - 1; index >= 0 ; index--) {
-      bindingParent = bindingsStack[index];
+  // Go up looking for the nearest accessible container stored in cache.
+  nsTArray<nsINode*> nodes;
+  nsINode* node = aNode;
+  while ((node = node->GetNodeParent()) &&
+         !(cachedAcc = GetCachedAccessible(node, aWeakShell)))
+    nodes.AppendElement(node);
 
-      // Try to get an accessible by type since XBL widget can be accessible
-      // only if it implements nsIAccessibleProvider interface.
-      nsCOMPtr<nsIWeakReference> weakShell =
-        nsCoreUtils::GetWeakShellFor(bindingParent);
+  // Node is not in accessible document.
+  if (!cachedAcc)
+    return nsnull;
 
-      // XXX: it's a hack we should try the cache before, otherwise to cache
-      // the accessible.
-      nsRefPtr<nsAccessible> accessible =
-        CreateAccessibleByType(bindingParent, weakShell);
-
-      if (accessible) {
-        if (!accessible->GetAllowsAnonChildAccessibles())
-          return bindingParent;
+  // If children of the cached accessible weren't initialized then go down to
+  // the given node and create accessible tree.
+  nsAccessible* containerAcc = cachedAcc;
+  if (!cachedAcc->AreChildrenCached()) {
+    cachedAcc->EnsureChildren();
+    for (PRInt32 idx = nodes.Length() - 1; idx >= 0; idx--) {
+      cachedAcc = GetCachedAccessible(nodes[idx], aWeakShell);
+      if (cachedAcc) {
+        cachedAcc->EnsureChildren();
+        containerAcc = cachedAcc;
       }
     }
   }
 
-  return aNode;
+  // If the given node is accessible then it should be cached at this point.
+  // Exception is an area element because area and imagemap nodes aren't in
+  // the same parent chain.
+  cachedAcc = GetCachedAccessible(aNode, aWeakShell);
+  if (!cachedAcc && aNode->IsElement()) {
+    nsIFrame* frame = aNode->AsElement()->GetPrimaryFrame();
+    if (frame && frame->GetContent() != aNode)
+      cachedAcc = GetAreaAccessible(frame, aNode, aWeakShell, &containerAcc);
+  }
+
+  if ((aWhatToGet & eGetAccForNode) && cachedAcc)
+    return cachedAcc;
+  else if (aWhatToGet & eGetAccForContainer)
+    return containerAcc;
+
+  return nsnull;
 }
 
 nsAccessible*
-nsAccessibilityService::GetAreaAccessible(nsIFrame *aImageFrame,
-                                          nsINode *aAreaNode,
-                                          nsIWeakReference *aWeakShell)
+nsAccessibilityService::GetAreaAccessible(nsIFrame* aImageFrame,
+                                          nsINode* aAreaNode,
+                                          nsIWeakReference* aWeakShell,
+                                          nsAccessible** aImageAccessible)
 {
   // Check if frame is an image frame, and content is <area>.
   nsIImageFrame *imageFrame = do_QueryFrame(aImageFrame);
   if (!imageFrame)
     return nsnull;
 
   nsCOMPtr<nsIDOMHTMLAreaElement> areaElmt = do_QueryInterface(aAreaNode);
   if (!areaElmt)
@@ -1326,16 +1250,19 @@ nsAccessibilityService::GetAreaAccessibl
   if (!imageAcc) {
     imageAcc = CreateHTMLImageAccessible(aImageFrame->GetContent(),
                                          aImageFrame->PresContext()->PresShell());
 
     if (!InitAccessible(imageAcc, nsnull))
       return nsnull;
   }
 
+  if (aImageAccessible)
+    *aImageAccessible = imageAcc;
+
   // Make sure <area> accessible children of the image map are cached so
   // that they should be available in global cache.
   imageAcc->EnsureChildren();
 
   return GetCachedAccessible(aAreaNode, aWeakShell);
 }
 
 already_AddRefed<nsAccessible>
--- a/accessible/src/base/nsAccessibilityService.h
+++ b/accessible/src/base/nsAccessibilityService.h
@@ -122,76 +122,72 @@ public:
   // nsAccessibiltiyService
 
   /**
    * Return true if accessibility service has been shutdown.
    */
   static PRBool IsShutdown() { return gIsShutdown; }
 
   /**
-   * Return an accessible for the given DOM node.
+   * Return an accessible for the given DOM node from the cache or create new
+   * one.
    *
    * @param  aNode       [in] the given node
    * @param  aPresShell  [in] the pres shell of the node
    * @param  aWeakShell  [in] the weak shell for the pres shell
    * @param  aIsHidden   [out, optional] indicates whether the node's frame is
    *                       hidden
    */
   already_AddRefed<nsAccessible>
-    GetAccessible(nsINode *aNode, nsIPresShell *aPresShell,
-                  nsIWeakReference *aWeakShell, PRBool *aIsHidden = nsnull);
+    GetOrCreateAccessible(nsINode* aNode, nsIPresShell* aPresShell,
+                          nsIWeakReference* aWeakShell,
+                          PRBool* aIsHidden = nsnull);
 
   /**
    * Return an accessible for the given DOM node.
    */
-  nsAccessible *GetAccessible(nsINode *aNode);
+  nsAccessible* GetAccessible(nsINode* aNode);
 
   /**
-   * Return an accessible for a DOM node in the given pres shell.
-   * 
-   * @param aNode       [in] the given node.
-   * @param aPresShell  [in] the presentation shell of the given node.
+   * Return an accessible for a DOM node in the given presshell.
+   *
+   * @param aNode       [in] the given node
+   * @param aWeakShell  [in] the presentation shell for the given node
    */
-  nsAccessible *GetAccessibleInWeakShell(nsINode *aNode,
-                                         nsIWeakReference *aPresShell);
-
-  /**
-   * Return the first accessible parent of a DOM node.
-   *
-   * @param aDOMNode    [in] the DOM node to get an accessible for
-   * @param aCanCreate  [in] specifies if accessible can be created if it didn't
-   *                     exist
-   */
-  nsAccessible *GetContainerAccessible(nsINode *aNode, PRBool aCanCreate);
+  inline nsAccessible* GetAccessibleInWeakShell(nsINode* aNode,
+                                                nsIWeakReference* aWeakShell)
+  {
+    return GetAccessibleByRule(aNode, aWeakShell, eGetAccForNode);
+  }
 
   /**
-   * The same as getAccessibleFor method except it returns accessible only if
-   * it is attached, i.e. accessible is certified to be a descendant of the root
-   * accessible.
-   *
-   * XXX: this method must go away once we'll implement correct accessible tree.
-   *
-   * @param  aNode  [in] the DOM node to get an accessible for
-   * @return         the accessible for the given DOM node
+   * Return an accessible for the given DOM node or container accessible if
+   * the node is not accessible.
    */
-  nsAccessible *GetAttachedAccessibleFor(nsINode *aNode);
+  inline nsAccessible* GetAccessibleOrContainer(nsINode* aNode,
+                                                nsIWeakReference* aWeakShell)
+  {
+    return GetAccessibleByRule(aNode, aWeakShell, eGetAccForNodeOrContainer);
+  }
 
   /**
-   * Return an DOM node that is relevant to attached accessible check. This
-   * node is either from bindings chain if given node is anonymous and owner
-   * binding denies accessible in anonymous content or given node (it's not
-   * important whether it is accessible or not). This method doesn't create
-   * accessible object for returned node.
+   * Return a container accessible for the given DOM node.
+   */
+  inline nsAccessible* GetContainerAccessible(nsINode* aNode,
+                                              nsIWeakReference* aWeakShell)
+  {
+    return GetAccessibleByRule(aNode, aWeakShell, eGetAccForContainer);
+  }
+
+  /**
+   * Return the first cached accessible parent of a DOM node.
    *
-   * XXX: this method must go away once we'll implement correct accessible tree.
-   *
-   * @param  aNode  [in] the DOM node to get relevant content node
-   * @return         the DOM node for parent attached accessible
+   * @param aDOMNode    [in] the DOM node to get an accessible for
    */
-  nsINode *GetRelevantContentNodeFor(nsINode *aNode);
+  nsAccessible* GetCachedContainerAccessible(nsINode *aNode);
 
   /**
    * Initialize an accessible and cache it. The method should be called for
    * every created accessible.
    *
    * @param  aAccessible    [in] accessible to initialize.
    * @param  aRoleMapEntry  [in] the role map entry role the ARIA role or nsnull
    *                          if none
@@ -226,21 +222,40 @@ private:
    */
   PRBool Init();
 
   /**
    * Shutdowns accessibility service.
    */
   void Shutdown();
 
+  enum EWhatAccToGet {
+    eGetAccForNode = 0x1,
+    eGetAccForContainer = 0x2,
+    eGetAccForNodeOrContainer = eGetAccForNode | eGetAccForContainer
+  };
+
+  /**
+   * Return accessible or accessible container for the given node in presshell.
+   */
+  nsAccessible* GetAccessibleByRule(nsINode* aNode,
+                                    nsIWeakReference* aWeakShell,
+                                    EWhatAccToGet aWhatToGet);
+
   /**
    * Return accessible for HTML area element associated with an image map.
+   *
+   * @param  aImageFrame       [in] image frame
+   * @param  aAreaNode         [in] area node
+   * @param  aWeakShell        [in] presshell of image frame
+   * @param  aImageAccessible  [out, optional] image accessible, isn't addrefed
    */
   nsAccessible* GetAreaAccessible(nsIFrame* aImageFrame, nsINode* aAreaNode,
-                                  nsIWeakReference* aWeakShell);
+                                  nsIWeakReference* aWeakShell,
+                                  nsAccessible** aImageAccessible = nsnull);
 
   /**
    * Create accessible for the element implementing nsIAccessibleProvider
    * interface.
    */
   already_AddRefed<nsAccessible>
     CreateAccessibleByType(nsIContent* aContent, nsIWeakReference* aWeakShell);
 
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -187,17 +187,18 @@ nsresult nsAccessible::QueryInterface(RE
     return NS_ERROR_NO_INTERFACE;
   }
 
   return nsAccessNodeWrap::QueryInterface(aIID, aInstancePtr);
 }
 
 nsAccessible::nsAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
   nsAccessNodeWrap(aContent, aShell),
-  mParent(nsnull), mAreChildrenInitialized(PR_FALSE), mRoleMapEntry(nsnull)
+  mParent(nsnull), mAreChildrenInitialized(PR_FALSE), mIndexInParent(-1),
+  mRoleMapEntry(nsnull)
 {
 #ifdef NS_DEBUG_X
    {
      nsCOMPtr<nsIPresShell> shell(do_QueryReferent(aShell));
      printf(">>> %p Created Acc - DOM: %p  PS: %p", 
             (void*)static_cast<nsIAccessible*>(this), (void*)aNode,
             (void*)shell.get());
     nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
@@ -808,26 +809,23 @@ nsAccessible::GetChildAtPoint(PRInt32 aX
   nsIFrame *foundFrame = presShell->GetFrameForPoint(frame, offset);
 
   nsIContent* content = nsnull;
   if (!foundFrame || !(content = foundFrame->GetContent())) {
     NS_IF_ADDREF(*aChild = fallbackAnswer);
     return NS_OK;
   }
 
-  nsINode *relevantNode = GetAccService()->GetRelevantContentNodeFor(content);
-  nsAccessible *accessible = GetAccService()->GetAccessible(relevantNode);
+  // Get accessible for the node with the point or the first accessible in
+  // the DOM parent chain.
+  nsAccessible* accessible =
+   GetAccService()->GetAccessibleOrContainer(content, mWeakShell);
   if (!accessible) {
-    // No accessible for the node with the point, so find the first
-    // accessible in the DOM parent chain
-    accessible = GetAccService()->GetContainerAccessible(relevantNode, PR_TRUE);
-    if (!accessible) {
-      NS_IF_ADDREF(*aChild = fallbackAnswer);
-      return NS_OK;
-    }
+    NS_IF_ADDREF(*aChild = fallbackAnswer);
+    return NS_OK;
   }
 
   if (accessible == this) {
     // Manually walk through accessible children and see if the are within this
     // point. Skip offscreen or invisible accessibles. This takes care of cases
     // where layout won't walk into things for us, such as image map areas and
     // sub documents (XXX: subdocuments should be handled by methods of
     // nsOuterDocAccessibles).
@@ -1237,18 +1235,16 @@ nsAccessible::GetXULName(nsAString& aLab
 
   return nsTextEquivUtils::GetNameFromSubtree(this, aLabel);
 }
 
 nsresult
 nsAccessible::HandleAccEvent(nsAccEvent *aEvent)
 {
   NS_ENSURE_ARG_POINTER(aEvent);
-  NS_ENSURE_TRUE(nsAccUtils::IsNodeRelevant(aEvent->GetNode()),
-                 NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIObserverService> obsService =
     mozilla::services::GetObserverService();
   NS_ENSURE_TRUE(obsService, NS_ERROR_FAILURE);
 
   return obsService->NotifyObservers(aEvent, NS_ACCESSIBLE_EVENT_TOPIC, nsnull);
 }
 
@@ -2670,43 +2666,28 @@ nsAccessible::Init()
     GetAccService()->GetDocAccessible(mContent->GetOwnerDoc());
   NS_ASSERTION(docAcc, "Cannot cache new nsAccessible!");
   if (!docAcc)
     return PR_FALSE;
 
   void *uniqueID = nsnull;
   GetUniqueID(&uniqueID);
 
-  if (!docAcc->CacheAccessible(uniqueID, this))
-    return PR_FALSE;
-
-  // Make sure an ancestor in real content is cached so that
-  // nsDocAccessible::RefreshNodes() can find the anonymous subtree to release
-  // when the root node goes away. /Specific examples of where this is used:
-  // <input type="file"> and <xul:findbar>.
-  // XXX: remove this once we create correct accessible tree.
-  if (mContent && mContent->IsInAnonymousSubtree()) {
-    nsAccessible *parent = GetAccService()->GetContainerAccessible(mContent,
-                                                                   PR_TRUE);
-    if (parent)
-      parent->EnsureChildren();
-  }
-
-  return PR_TRUE;
+  return docAcc->CacheAccessible(uniqueID, this);
 }
 
 void
 nsAccessible::Shutdown()
 {
   // Invalidate the child count and pointers to other accessibles, also make
   // sure none of its children point to this parent
   InvalidateChildren();
   if (mParent) {
     mParent->InvalidateChildren();
-    mParent = nsnull;
+    UnbindFromParent();
   }
 
   nsAccessNodeWrap::Shutdown();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible public methods
 
@@ -2740,75 +2721,116 @@ nsAccessible::GetNameInternal(nsAString&
     return GetHTMLName(aName);
 
   if (mContent->IsXUL())
     return GetXULName(aName);
 
   return NS_OK;
 }
 
+// nsAccessible protected
 void
-nsAccessible::SetParent(nsAccessible *aParent)
+nsAccessible::BindToParent(nsAccessible* aParent, PRUint32 aIndexInParent)
 {
   NS_PRECONDITION(aParent, "This method isn't used to set null parent!");
 
   if (mParent && mParent != aParent) {
     // Adopt a child -- we allow this now. the new parent
     // may be a dom node which wasn't previously accessible but now is.
     // The old parent's children now need to be invalidated, since 
     // it no longer owns the child, the new parent does
     NS_ASSERTION(PR_FALSE, "Adopting child!");
     if (mParent)
       mParent->InvalidateChildren();
   }
 
   mParent = aParent;
+  mIndexInParent = aIndexInParent;
 }
 
 void
 nsAccessible::InvalidateChildren()
 {
   PRInt32 childCount = mChildren.Length();
   for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
     nsAccessible* child = mChildren.ElementAt(childIdx);
-    child->mParent = nsnull;
+    child->UnbindFromParent();
   }
 
   mChildren.Clear();
   mAreChildrenInitialized = PR_FALSE;
 }
 
+PRBool
+nsAccessible::AppendChild(nsAccessible* aChild)
+{
+  if (!mChildren.AppendElement(aChild))
+    return PR_FALSE;
+
+  aChild->BindToParent(this, mChildren.Length() - 1);
+  return PR_TRUE;
+}
+
+PRBool
+nsAccessible::InsertChildAt(PRUint32 aIndex, nsAccessible* aChild)
+{
+  if (!mChildren.InsertElementAt(aIndex, aChild))
+    return PR_FALSE;
+
+  for (PRUint32 idx = aIndex + 1; idx < mChildren.Length(); idx++)
+    mChildren[idx]->mIndexInParent++;
+
+  aChild->BindToParent(this, aIndex);
+  return PR_TRUE;
+}
+
+PRBool
+nsAccessible::RemoveChild(nsAccessible* aChild)
+{
+  if (aChild->mParent != this || aChild->mIndexInParent == -1)
+    return PR_FALSE;
+
+  for (PRUint32 idx = aChild->mIndexInParent + 1; idx < mChildren.Length(); idx++)
+    mChildren[idx]->mIndexInParent--;
+
+  mChildren.RemoveElementAt(aChild->mIndexInParent);
+  aChild->UnbindFromParent();
+  return PR_TRUE;
+}
+
 nsAccessible*
 nsAccessible::GetParent()
 {
+  if (mParent)
+    return mParent;
+
   if (IsDefunct())
     return nsnull;
 
-  if (mParent)
-    return mParent;
+  // XXX: mParent can be null randomly because supposedly we get layout
+  // notification and invalidate parent-child relations, this accessible stays
+  // unattached. This should gone after bug 572951. Other reason is bug 574588
+  // since CacheChildren() implementation calls nsAccessible::GetRole() what
+  // can need to get a parent and we are here as result.
+  NS_WARNING("Bad accessible tree!");
 
 #ifdef DEBUG
   nsDocAccessible *docAccessible = GetDocAccessible();
   NS_ASSERTION(docAccessible, "No document accessible for valid accessible!");
 #endif
 
-  nsAccessible *parent = GetAccService()->GetContainerAccessible(mContent,
-                                                                 PR_TRUE);
+  nsAccessible* parent = GetAccService()->GetContainerAccessible(mContent,
+                                                                 mWeakShell);
   NS_ASSERTION(parent, "No accessible parent for valid accessible!");
   if (!parent)
     return nsnull;
 
-#ifdef DEBUG
-  NS_ASSERTION(!parent->IsDefunct(), "Defunct parent!");
-
+  // Repair parent-child relations.
   parent->EnsureChildren();
-  if (parent != mParent)
-    NS_WARNING("Bad accessible tree!");
-#endif
-
+  NS_ASSERTION(parent == mParent, "Wrong children repair!");
   return parent;
 }
 
 nsAccessible*
 nsAccessible::GetChildAt(PRUint32 aIndex)
 {
   if (EnsureChildren())
     return nsnull;
@@ -2828,47 +2850,30 @@ nsAccessible::GetChildAt(PRUint32 aIndex
 
 PRInt32
 nsAccessible::GetChildCount()
 {
   return EnsureChildren() ? -1 : mChildren.Length();
 }
 
 PRInt32
-nsAccessible::GetIndexOf(nsIAccessible *aChild)
+nsAccessible::GetIndexOf(nsAccessible* aChild)
 {
-  return EnsureChildren() ? -1 : mChildren.IndexOf(aChild);
+  return EnsureChildren() || (aChild->mParent != this) ?
+    -1 : aChild->GetIndexInParent();
 }
 
 PRInt32
 nsAccessible::GetIndexInParent()
 {
-  nsAccessible *parent = GetParent();
-  return parent ? parent->GetIndexOf(this) : -1;
+  // XXX: call GetParent() to repair the tree if it's broken.
+  nsAccessible* parent = GetParent();
+  return mIndexInParent;
 }
 
-nsAccessible*
-nsAccessible::GetCachedParent()
-{
-  if (IsDefunct())
-    return nsnull;
-
-  return mParent;
-}
-
-nsAccessible*
-nsAccessible::GetCachedFirstChild()
-{
-  if (IsDefunct())
-    return nsnull;
-
-  return mChildren.SafeElementAt(0, nsnull);
-}
-
-
 #ifdef DEBUG
 PRBool
 nsAccessible::IsInCache()
 {
   nsDocAccessible *docAccessible =
     GetAccService()->GetDocAccessible(mContent->GetOwnerDoc());
   if (!docAccessible)
     return nsnull;
@@ -2885,20 +2890,17 @@ nsAccessible::IsInCache()
 // nsAccessible protected methods
 
 void
 nsAccessible::CacheChildren()
 {
   nsAccTreeWalker walker(mWeakShell, mContent, GetAllowsAnonChildAccessibles());
 
   nsRefPtr<nsAccessible> child;
-  while ((child = walker.GetNextChild())) {
-    mChildren.AppendElement(child);
-    child->SetParent(this);
-  }
+  while ((child = walker.GetNextChild()) && AppendChild(child));
 }
 
 void
 nsAccessible::TestChildCache(nsAccessible *aCachedChild)
 {
 #ifdef DEBUG
   PRInt32 childCount = mChildren.Length();
   if (childCount == 0) {
@@ -2949,33 +2951,32 @@ nsAccessible::GetSiblingAtOffset(PRInt32
   nsAccessible *parent = GetParent();
   if (!parent) {
     if (aError)
       *aError = NS_ERROR_UNEXPECTED;
 
     return nsnull;
   }
 
-  PRInt32 indexInParent = parent->GetIndexOf(this);
-  if (indexInParent == -1) {
+  if (mIndexInParent == -1) {
     if (aError)
       *aError = NS_ERROR_UNEXPECTED;
 
     return nsnull;
   }
 
   if (aError) {
     PRInt32 childCount = parent->GetChildCount();
-    if (indexInParent + aOffset >= childCount) {
+    if (mIndexInParent + aOffset >= childCount) {
       *aError = NS_OK; // fail peacefully
       return nsnull;
     }
   }
 
-  nsAccessible *child = parent->GetChildAt(indexInParent + aOffset);
+  nsAccessible* child = parent->GetChildAt(mIndexInParent + aOffset);
   if (aError && !child)
     *aError = NS_ERROR_UNEXPECTED;
 
   return child;
 }
 
 nsAccessible *
 nsAccessible::GetFirstAvailableAccessible(nsINode *aStartNode) const
@@ -3109,22 +3110,21 @@ nsAccessible::GetPositionAndSizeInternal
   PRUint32 baseRole = role;
   if (role == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
       role == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM)
     baseRole = nsIAccessibleRole::ROLE_MENUITEM;
 
   nsAccessible* parent = GetParent();
   NS_ENSURE_TRUE(parent,);
 
-  PRInt32 indexInParent = parent->GetIndexOf(this);
   PRInt32 level = nsAccUtils::GetARIAOrDefaultLevel(this);
 
   // Compute 'posinset'.
   PRInt32 positionInGroup = 1;
-  for (PRInt32 idx = indexInParent - 1; idx >= 0; idx--) {
+  for (PRInt32 idx = mIndexInParent - 1; idx >= 0; idx--) {
     nsAccessible* sibling = parent->GetChildAt(idx);
 
     PRUint32 siblingRole = nsAccUtils::Role(sibling);
 
     // If the sibling is separator then the group is ended.
     if (siblingRole == nsIAccessibleRole::ROLE_SEPARATOR)
       break;
 
@@ -3148,17 +3148,17 @@ nsAccessible::GetPositionAndSizeInternal
         ++ positionInGroup;
     }
   }
 
   // Compute 'setsize'.
   PRInt32 setSize = positionInGroup;
 
   PRInt32 siblingCount = parent->GetChildCount();
-  for (PRInt32 idx = indexInParent + 1; idx < siblingCount; idx++) {
+  for (PRInt32 idx = mIndexInParent + 1; idx < siblingCount; idx++) {
     nsAccessible* sibling = parent->GetChildAt(idx);
     NS_ENSURE_TRUE(sibling,);
 
     PRUint32 siblingRole = nsAccUtils::Role(sibling);
 
     // If the sibling is separator then the group is ended.
     if (siblingRole == nsIAccessibleRole::ROLE_SEPARATOR)
       break;
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -198,84 +198,84 @@ public:
    * For a newly created accessible, specify which role map entry should be used.
    *
    * @param aRoleMapEntry The ARIA nsRoleMapEntry* for the accessible, or 
    *                      nsnull if none.
    */
   virtual void SetRoleMapEntry(nsRoleMapEntry *aRoleMapEntry);
 
   /**
-   * Set accessible parent.
-   */
-  void SetParent(nsAccessible *aParent);
-
-  /**
    * Cache children if necessary. Return true if the accessible is defunct.
    */
   PRBool EnsureChildren();
 
   /**
    * Set the child count to -1 (unknown) and null out cached child pointers.
    * Should be called when accessible tree is changed because document has
-   * transformed.
+   * transformed. Note, if accessible cares about its parent relation chain
+   * itself should override this method to do nothing.
    */
   virtual void InvalidateChildren();
 
   /**
-   * Append/remove a child. Alternative approach of children handling than
-   * CacheChildren/InvalidateChildren.
-   *
-   * @param  aAccessible  [in] child to append/remove
-   * @return true          if child was successfully appended/removed
+   * Append/insert/remove a child. Return true if operation was successful.
    */
-  virtual PRBool AppendChild(nsAccessible *aAccessible) { return PR_FALSE; }
-  virtual PRBool RemoveChild(nsAccessible *aAccessible) { return PR_FALSE; }
+  virtual PRBool AppendChild(nsAccessible* aChild);
+  virtual PRBool InsertChildAt(PRUint32 aIndex, nsAccessible* aChild);
+  virtual PRBool RemoveChild(nsAccessible* aChild);
 
   //////////////////////////////////////////////////////////////////////////////
   // Accessible tree traverse methods
 
   /**
    * Return parent accessible.
    */
-  virtual nsAccessible* GetParent();
+  nsAccessible* GetParent();
 
   /**
    * Return child accessible at the given index.
    */
   virtual nsAccessible* GetChildAt(PRUint32 aIndex);
 
   /**
    * Return child accessible count.
    */
   virtual PRInt32 GetChildCount();
 
   /**
    * Return index of the given child accessible.
    */
-  virtual PRInt32 GetIndexOf(nsIAccessible *aChild);
+  virtual PRInt32 GetIndexOf(nsAccessible* aChild);
 
   /**
    * Return index in parent accessible.
    */
-  PRInt32 GetIndexInParent();
+  virtual PRInt32 GetIndexInParent();
 
   /**
    * Return true if accessible has children;
    */
   PRBool HasChildren() { return !!GetChildAt(0); }
 
   /**
-   * Return parent accessible only if cached.
+   * Return cached accessible of parent-child relatives.
    */
-  nsAccessible* GetCachedParent();
-
-  /**
-   * Return first child accessible only if cached.
-   */
-  nsAccessible* GetCachedFirstChild();
+  nsAccessible* GetCachedParent() const { return mParent; }
+  nsAccessible* GetCachedNextSibling() const
+  {
+    return mParent ?
+      mParent->mChildren.SafeElementAt(mIndexInParent + 1, nsnull).get() : nsnull;
+  }
+  nsAccessible* GetCachedPrevSibling() const
+  {
+    return mParent ?
+      mParent->mChildren.SafeElementAt(mIndexInParent - 1, nsnull).get() : nsnull;
+  }
+  PRUint32 GetCachedChildCount() const { return mChildren.Length(); }
+  PRBool AreChildrenCached() const { return mAreChildrenInitialized; }
 
 #ifdef DEBUG
   /**
    * Return true if the access node is cached.
    */
   PRBool IsInCache();
 #endif
 
@@ -316,16 +316,22 @@ protected:
   // Initializing, cache and tree traverse methods
 
   /**
    * Cache accessible children.
    */
   virtual void CacheChildren();
 
   /**
+   * Set accessible parent and index in parent.
+   */
+  void BindToParent(nsAccessible* aParent, PRUint32 aIndexInParent);
+  void UnbindFromParent() { mParent = nsnull; mIndexInParent = -1; }
+
+  /**
    * Return sibling accessible at the given offset.
    */
   virtual nsAccessible* GetSiblingAtOffset(PRInt32 aOffset,
                                            nsresult *aError = nsnull);
 
   //////////////////////////////////////////////////////////////////////////////
   // Miscellaneous helpers
 
@@ -427,16 +433,17 @@ protected:
    * @param aEvent  the accessible event to fire.
    */
   virtual nsresult FirePlatformEvent(nsAccEvent *aEvent) = 0;
 
   // Data Members
   nsRefPtr<nsAccessible> mParent;
   nsTArray<nsRefPtr<nsAccessible> > mChildren;
   PRBool mAreChildrenInitialized;
+  PRInt32 mIndexInParent;
 
   nsRoleMapEntry *mRoleMapEntry; // Non-null indicates author-supplied role; possibly state & value as well
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsAccessible,
                               NS_ACCESSIBLE_IMPL_IID)
 
 #endif  
--- a/accessible/src/base/nsApplicationAccessible.cpp
+++ b/accessible/src/base/nsApplicationAccessible.cpp
@@ -400,22 +400,16 @@ nsApplicationAccessible::GetStateInterna
   }
 
   if (aExtraState)
     *aExtraState = 0;
 
   return NS_OK;
 }
 
-nsAccessible*
-nsApplicationAccessible::GetParent()
-{
-  return nsnull;
-}
-
 void
 nsApplicationAccessible::InvalidateChildren()
 {
   // Do nothing because application children are kept updated by AppendChild()
   // and RemoveChild() method calls.
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -473,37 +467,16 @@ nsApplicationAccessible::GetSiblingAtOff
 
   if (aError)
     *aError = NS_OK; // fail peacefully
 
   return nsnull;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// Public methods
-
-PRBool
-nsApplicationAccessible::AppendChild(nsAccessible* aChild)
-{
-  if (!mChildren.AppendElement(aChild))
-    return PR_FALSE;
-
-  aChild->SetParent(this);
-  return PR_TRUE;
-}
-
-PRBool
-nsApplicationAccessible::RemoveChild(nsAccessible* aChild)
-{
-  // It's not needed to unbind root accessible from parent because this method
-  // is called when root accessible is shutdown and it'll be unbound properly.
-  return mChildren.RemoveElement(aChild);
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // nsIAccessNode
 
 NS_IMETHODIMP
 nsApplicationAccessible::GetDOMNode(nsIDOMNode **aDOMNode)
 {
   NS_ENSURE_ARG_POINTER(aDOMNode);
   *aDOMNode = nsnull;
   return NS_OK;
--- a/accessible/src/base/nsApplicationAccessible.h
+++ b/accessible/src/base/nsApplicationAccessible.h
@@ -108,21 +108,18 @@ public:
   virtual PRBool IsDefunct();
   virtual PRBool Init();
   virtual void Shutdown();
 
   // nsAccessible
   virtual nsresult GetARIAState(PRUint32 *aState, PRUint32 *aExtraState);
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
-  virtual nsAccessible* GetParent();
 
   virtual void InvalidateChildren();
-  virtual PRBool AppendChild(nsAccessible* aChild);
-  virtual PRBool RemoveChild(nsAccessible* aChild);
 
 protected:
 
   // nsAccessible
   virtual void CacheChildren();
   virtual nsAccessible* GetSiblingAtOffset(PRInt32 aOffset,
                                            nsresult *aError = nsnull);
 
--- a/accessible/src/base/nsCaretAccessible.cpp
+++ b/accessible/src/base/nsCaretAccessible.cpp
@@ -325,17 +325,17 @@ nsCaretAccessible::GetCaretRect(nsIWidge
 
   nsRect rect;
   nsIFrame* frame = caret->GetGeometry(caretSelection, &rect);
   if (!frame || rect.IsEmpty()) {
     return nsIntRect(); // Return empty rect
   }
 
   nsPoint offset;
-  *aOutWidget = frame->GetWindowOffset(offset);
+  *aOutWidget = frame->GetNearestWidget(offset);
   NS_ENSURE_TRUE(*aOutWidget, nsIntRect());
   rect.MoveBy(offset);
 
   caretRect = rect.ToOutsidePixels(frame->PresContext()->AppUnitsPerDevPixel());
   caretRect.MoveBy((*aOutWidget)->WidgetToScreenOffset());
 
   // Correct for character size, so that caret always matches the size of the character
   // This is important for font size transitions, and is necessary because the Gecko caret uses the
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -162,17 +162,17 @@ nsCoreUtils::DispatchMouseEvent(PRUint32
   nsIFrame *frame = aContent->GetPrimaryFrame();
   if (!frame)
     return PR_FALSE;
 
   nsIFrame* rootFrame = aPresShell->GetRootFrame();
   if (!rootFrame)
     return PR_FALSE;
 
-  nsCOMPtr<nsIWidget> rootWidget = rootFrame->GetWindow();
+  nsCOMPtr<nsIWidget> rootWidget = rootFrame->GetNearestWidget();
   if (!rootWidget)
     return PR_FALSE;
 
   // Compute x and y coordinates.
   nsPoint point = frame->GetOffsetToExternal(rootFrame);
   nsSize size = frame->GetSize();
 
   nsPresContext* presContext = aPresShell->GetPresContext();
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -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 ***** */
 
 #include "nsAccCache.h"
 #include "nsAccessibilityAtoms.h"
 #include "nsAccessibilityService.h"
+#include "nsAccTreeWalker.h"
 #include "nsAccUtils.h"
 #include "nsRootAccessible.h"
 #include "nsTextEquivUtils.h"
 
 #include "nsIMutableArray.h"
 #include "nsICommandManager.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
@@ -626,20 +627,18 @@ nsDocAccessible::Shutdown()
 
   if (mEventQueue) {
     mEventQueue->Shutdown();
     mEventQueue = nsnull;
   }
 
   RemoveEventListeners();
 
-  if (mParent) {
+  if (mParent)
     mParent->RemoveChild(this);
-    mParent = nsnull;
-  }
 
   mWeakShell = nsnull;  // Avoid reentrancy
 
   ClearCache(mAccessibleCache);
 
   nsCOMPtr<nsIDocument> kungFuDeathGripDoc = mDocument;
   mDocument = nsnull;
 
@@ -950,18 +949,16 @@ nsDocAccessible::AttributeChangedImpl(ns
     return; // Still loading, ignore setting of initial attributes
 
   nsCOMPtr<nsIPresShell> shell = GetPresShell();
   if (!shell) {
     return; // Document has been shut down
   }
 
   NS_ASSERTION(aContent, "No node for attr modified");
-  if (!aContent || !nsAccUtils::IsNodeRelevant(aContent))
-    return;
 
   // Universal boolean properties that don't require a role. Fire the state
   // change when disabled or aria-disabled attribute is set.
   if (aAttribute == nsAccessibilityAtoms::disabled ||
       aAttribute == nsAccessibilityAtoms::aria_disabled) {
 
     // Note. Checking the XUL or HTML namespace would not seem to gain us
     // anything, because disabled attribute really is going to mean the same
@@ -1267,22 +1264,16 @@ void
 nsDocAccessible::ParentChainChanged(nsIContent *aContent)
 {
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible
 
-nsAccessible*
-nsDocAccessible::GetParent()
-{
-  return IsDefunct() ? nsnull : mParent.get();
-}
-
 #ifdef DEBUG_ACCDOCMGR
 nsresult
 nsDocAccessible::HandleAccEvent(nsAccEvent *aAccEvent)
 {
   NS_LOG_ACCDOCLOAD_HANDLEEVENT(aAccEvent)
 
   return nsHyperTextAccessible::HandleAccEvent(aAccEvent);
 
@@ -1329,124 +1320,120 @@ nsDocAccessible::FireTextChangeEventForT
   if (!accessible)
     return;
 
   nsRefPtr<nsHyperTextAccessible> textAccessible =
     do_QueryObject(accessible->GetParent());
   if (!textAccessible)
     return;
 
-  // Get offset within hypertext accessible.
-  PRInt32 offset = 0;
-  textAccessible->DOMPointToHypertextOffset(aContent, contentOffset, &offset);
+  // Get offset within hypertext accessible and invalidate cached offsets after
+  // this child accessible.
+  PRInt32 offset = textAccessible->GetChildOffset(accessible, PR_TRUE);
 
+  // Get added or removed text.
   nsIFrame* frame = aContent->GetPrimaryFrame();
   if (!frame)
     return;
 
-  // Get added or removed text.
   PRUint32 textOffset = 0;
   nsresult rv = textAccessible->ContentToRenderedOffset(frame, contentOffset,
                                                         &textOffset);
   if (NS_FAILED(rv))
     return;
 
   nsAutoString text;
   rv = accessible->AppendTextTo(text, textOffset, contentLength);
   if (NS_FAILED(rv))
     return;
 
-  // Get text length.
-  PRUint32 length = text.Length();
-  if (length == 0)
+  if (text.IsEmpty())
     return;
 
   // Normally we only fire delayed events created from the node, not an
   // accessible object. See the nsAccTextChangeEvent constructor for details
   // about this exceptional case.
   nsRefPtr<nsAccEvent> event =
-      new nsAccTextChangeEvent(textAccessible, offset, length, text,
-                               aIsInserted, PR_FALSE);
+    new nsAccTextChangeEvent(textAccessible, offset + textOffset, text,
+                             aIsInserted, PR_FALSE);
   FireDelayedAccessibleEvent(event);
 
   FireValueChangeForTextFields(textAccessible);
 }
 
 already_AddRefed<nsAccEvent>
 nsDocAccessible::CreateTextChangeEventForNode(nsAccessible *aContainerAccessible,
                                               nsIContent *aChangeNode,
-                                              nsAccessible *aAccessibleForChangeNode,
+                                              nsAccessible *aChangeChild,
                                               PRBool aIsInserting,
                                               PRBool aIsAsynch,
                                               EIsFromUserInput aIsFromUserInput)
 {
   nsRefPtr<nsHyperTextAccessible> textAccessible =
     do_QueryObject(aContainerAccessible);
   if (!textAccessible) {
     return nsnull;
   }
 
+  nsAutoString text;
   PRInt32 offset = 0;
-  nsAccessible *changeAcc =
-    textAccessible->DOMPointToHypertextOffset(aChangeNode, -1, &offset);
-
-  nsAutoString text;
-  if (!aAccessibleForChangeNode) {
-    // A span-level object or something else without an accessible is being removed, where
-    // it has no accessible but it has descendant content which is aggregated as text
-    // into the parent hypertext.
-    // In this case, accessibleToBeRemoved may just be the first
-    // accessible that is removed, which affects the text in the hypertext container
-    if (!changeAcc)
-      return nsnull; // No descendant content that represents any text in the hypertext parent
-
-    nsAccessible *parent = changeAcc->GetParent();
-    nsINode *parentNode = parent->GetNode();
-    PRInt32 childCount = parent->GetChildCount();
-    PRInt32 changeAccIdx = parent->GetIndexOf(changeAcc);
-
-    for (PRInt32 idx = changeAccIdx; idx < childCount; idx++) {
-      nsAccessible *child = parent->GetChildAt(idx);
-      nsINode *childNode = child->GetNode();
-
-      if (!nsCoreUtils::IsAncestorOf(aChangeNode, childNode, parentNode)) {
-        // We only want accessibles with DOM nodes as children of this node
-        break;
-      }
-
-      child->AppendTextTo(text, 0, PR_UINT32_MAX);
-    }
-  }
-  else {
-    NS_ASSERTION(!changeAcc || changeAcc == aAccessibleForChangeNode,
-                 "Hypertext is reporting a different accessible for this node");
-
-    if (nsAccUtils::Role(aAccessibleForChangeNode) == nsIAccessibleRole::ROLE_WHITESPACE) {  // newline
-      // Don't fire event for the first html:br in an editor.
+  if (aChangeChild) {
+    // Don't fire event for the first html:br in an editor.
+    if (nsAccUtils::Role(aChangeChild) == nsIAccessibleRole::ROLE_WHITESPACE) {
       nsCOMPtr<nsIEditor> editor;
       textAccessible->GetAssociatedEditor(getter_AddRefs(editor));
       if (editor) {
         PRBool isEmpty = PR_FALSE;
         editor->GetDocumentIsEmpty(&isEmpty);
         if (isEmpty) {
           return nsnull;
         }
       }
     }
 
-    aAccessibleForChangeNode->AppendTextTo(text, 0, PR_UINT32_MAX);
+    offset = textAccessible->GetChildOffset(aChangeChild);
+    aChangeChild->AppendTextTo(text, 0, PR_UINT32_MAX);
+
+  } else {
+    // A span-level object or something else without an accessible is being
+    // added, where it has no accessible but it has descendant content which is
+    // aggregated as text into the parent hypertext. In this case, changed text
+    // is compounded from all accessible contained in changed node.
+    nsAccTreeWalker walker(mWeakShell, aChangeNode,
+                           GetAllowsAnonChildAccessibles());
+    nsRefPtr<nsAccessible> child = walker.GetNextChild();
+
+    // No descendant content that represents any text in the hypertext parent.
+    if (!child)
+      return nsnull;
+
+    offset = textAccessible->GetChildOffset(child);
+    child->AppendTextTo(text, 0, PR_UINT32_MAX);
+
+    nsINode* containerNode = textAccessible->GetNode();
+    PRInt32 childCount = textAccessible->GetChildCount();
+    PRInt32 childIdx = child->GetIndexInParent();
+
+    for (PRInt32 idx = childIdx + 1; idx < childCount; idx++) {
+      nsAccessible* nextChild = textAccessible->GetChildAt(idx);
+      // We only want accessibles with DOM nodes as children of this node.
+      if (!nsCoreUtils::IsAncestorOf(aChangeNode, nextChild->GetNode(),
+                                     containerNode))
+        break;
+
+      nextChild->AppendTextTo(text, 0, PR_UINT32_MAX);
+    }
   }
 
-  PRUint32 length = text.Length();
-  if (length == 0)
+  if (text.IsEmpty())
     return nsnull;
 
   nsAccEvent *event =
-      new nsAccTextChangeEvent(aContainerAccessible, offset, length, text,
-                               aIsInserting, aIsAsynch, aIsFromUserInput);
+    new nsAccTextChangeEvent(aContainerAccessible, offset, text,
+                             aIsInserting, aIsAsynch, aIsFromUserInput);
   NS_IF_ADDREF(event);
 
   return event;
 }
 
 // nsDocAccessible public member
 nsresult
 nsDocAccessible::FireDelayedAccessibleEvent(PRUint32 aEventType, nsINode *aNode,
@@ -1499,35 +1486,36 @@ nsDocAccessible::ProcessPendingEvent(nsA
       nsIAtom *newFrameType =
         (focusFrame && focusFrame->GetStyleVisibility()->IsVisible()) ?
         focusFrame->GetType() : nsnull;
 
       if (newFrameType == gLastFocusedFrameType) {
         // Don't need to invalidate this current accessible, but can
         // just invalidate the children instead
         FireShowHideEvents(node, PR_TRUE, eventType, eNormalEvent,
-                           isAsync, isFromUserInput); 
+                           isAsync, isFromUserInput);
         return;
       }
       gLastFocusedFrameType = newFrameType;
     }
   }
 
   if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
 
-    nsAccessible *containerAccessible = nsnull;
-    if (accessible)
+    nsAccessible* containerAccessible = nsnull;
+    if (accessible) {
       containerAccessible = accessible->GetParent();
+    } else {
+      nsCOMPtr<nsIWeakReference> weakShell(nsCoreUtils::GetWeakShellFor(node));
+      containerAccessible = GetAccService()->GetContainerAccessible(node,
+                                                                    weakShell);
+    }
 
-    if (!containerAccessible) {
-      containerAccessible = GetAccService()->GetContainerAccessible(node,
-                                                                    PR_TRUE);
-      if (!containerAccessible)
-        containerAccessible = this;
-    }
+    if (!containerAccessible)
+      containerAccessible = this;
 
     if (isAsync) {
       // For asynch show, delayed invalidatation of parent's children
       containerAccessible->InvalidateChildren();
 
       // Some show events in the subtree may have been removed to 
       // avoid firing redundant events. But, we still need to make sure any
       // accessibles parenting those shown nodes lose their child references.
@@ -1649,17 +1637,17 @@ nsDocAccessible::RefreshNodes(nsINode *a
         // handling in nsRootAccessible::HandleEvent
         nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
                                 accessible);
       }
     }
 
     // We only need to shutdown the accessibles here if one of them has been
     // created.
-    if (accessible->GetCachedFirstChild()) {
+    if (accessible->GetCachedChildCount() > 0) {
       nsCOMPtr<nsIArray> children;
       // use GetChildren() to fetch all children at once, because after shutdown
       // the child references are cleared.
       accessible->GetChildren(getter_AddRefs(children));
       PRUint32 childCount =0;
       if (children)
         children->GetLength(&childCount);
       nsINode *possibleAnonNode = nsnull;
@@ -1764,17 +1752,17 @@ nsDocAccessible::InvalidateCacheSubtree(
     nsIEventStateManager *esm = presShell->GetPresContext()->EventStateManager();
     NS_ENSURE_TRUE(esm,);
 
     if (!esm->IsHandlingUserInputExternal()) {
       // Changes during page load, but not caused by user input
       // Just invalidate accessible hierarchy and return,
       // otherwise the page load time slows down way too much
       nsAccessible *containerAccessible =
-        GetAccService()->GetContainerAccessible(childNode, PR_FALSE);
+        GetAccService()->GetCachedContainerAccessible(childNode);
       if (!containerAccessible) {
         containerAccessible = this;
       }
 
       containerAccessible->InvalidateChildren();
       return;
     }     
     // else: user input, so we must fall through and for full handling,
@@ -1800,17 +1788,17 @@ nsDocAccessible::InvalidateCacheSubtree(
     printf("[Create %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
   else if (aChangeType == nsIAccessibilityService::NODE_REMOVE)
     printf("[Destroy  %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
   else if (aChangeType == nsIAccessibilityService::NODE_SIGNIFICANT_CHANGE)
     printf("[Type change %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
 #endif
 
   nsAccessible *containerAccessible =
-    GetAccService()->GetContainerAccessible(childNode, PR_TRUE);
+    GetAccService()->GetCachedContainerAccessible(childNode);
   if (!containerAccessible) {
     containerAccessible = this;
   }
 
   if (!isShowing) {
     // Fire EVENT_HIDE.
     if (isHiding) {
       if (aChild) {
@@ -1832,34 +1820,16 @@ nsDocAccessible::InvalidateCacheSubtree(
     // Fire an event if the accessible existed for node being hidden, otherwise
     // for the first line accessible descendants. Fire before the accessible(s)
     // away.
     nsresult rv = FireShowHideEvents(childNode, PR_FALSE,
                                      nsIAccessibleEvent::EVENT_HIDE,
                                      eDelayedEvent, isAsynch);
     if (NS_FAILED(rv))
       return;
-
-    if (aChild) {
-      // Fire text change unless the node being removed is for this doc.
-      // When a node is hidden or removed, the text in an ancestor hyper text will lose characters
-      // At this point we still have the frame and accessible for this node if there was one
-      // XXX Collate events when a range is deleted
-      // XXX We need a way to ignore SplitNode and JoinNode() when they
-      // do not affect the text within the hypertext
-      // Normally we only fire delayed events created from the node, not an
-      // accessible object. See the nsAccTextChangeEvent constructor for details
-      // about this exceptional case.
-      nsRefPtr<nsAccEvent> textChangeEvent =
-        CreateTextChangeEventForNode(containerAccessible, aChild, childAccessible,
-                                     PR_FALSE, isAsynch);
-      if (textChangeEvent) {
-        FireDelayedAccessibleEvent(textChangeEvent);
-      }
-    }
   }
 
   // We need to get an accessible for the mutation event's container node
   // If there is no accessible for that node, we need to keep moving up the parent
   // chain so there is some accessible.
   // We will use this accessible to fire the accessible mutation event.
   // We're guaranteed success, because we will eventually end up at the doc accessible,
   // and there is always one of those.
@@ -1945,26 +1915,36 @@ nsDocAccessible::FireShowHideEvents(nsIN
 
   nsAccessible *accessible = nsnull;
   if (!aAvoidOnThisNode) {
     if (aEventType == nsIAccessibleEvent::EVENT_HIDE) {
       // Don't allow creation for accessibles when nodes going away
       accessible = GetCachedAccessible(aNode);
     } else {
       // Allow creation of new accessibles for show events
-      accessible = GetAccService()->GetAttachedAccessibleFor(aNode);
+      accessible = GetAccService()->GetAccessible(aNode);
     }
   }
 
   if (accessible) {
     // Found an accessible, so fire the show/hide on it and don't look further
     // into this subtree.
-    nsRefPtr<nsAccEvent> event =
-      new nsAccEvent(aEventType, accessible, aIsAsyncChange, aIsFromUserInput,
-                     nsAccEvent::eCoalesceFromSameSubtree);
+    nsRefPtr<nsAccEvent> event;
+    if (aDelayedOrNormal == eDelayedEvent &&
+        aEventType == nsIAccessibleEvent::EVENT_HIDE) {
+      // Use AccHideEvent for delayed hide events to coalesce text change events
+      // caused by these hide events.
+      event = new AccHideEvent(accessible, accessible->GetNode(),
+                               aIsAsyncChange, aIsFromUserInput);
+
+    } else {
+      event = new nsAccEvent(aEventType, accessible, aIsAsyncChange,
+                             aIsFromUserInput,
+                             nsAccEvent::eCoalesceFromSameSubtree);
+    }
     NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
 
     if (aDelayedOrNormal == eDelayedEvent)
       return FireDelayedAccessibleEvent(event);
 
     nsEventShell::FireEvent(event);
     return NS_OK;
   }
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -108,17 +108,16 @@ public:
   virtual nsINode* GetNode() const { return mDocument; }
 
   // nsAccessible
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
   virtual nsresult GetARIAState(PRUint32 *aState, PRUint32 *aExtraState);
 
   virtual void SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry);
-  virtual nsAccessible* GetParent();
 
 #ifdef DEBUG_ACCDOCMGR
   virtual nsresult HandleAccEvent(nsAccEvent *aAccEvent);
 #endif
 
   // nsIAccessibleText
   NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
 
--- a/accessible/src/base/nsEventShell.cpp
+++ b/accessible/src/base/nsEventShell.cpp
@@ -141,20 +141,26 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAccEv
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccEventQueue: public
 
 void
 nsAccEventQueue::Push(nsAccEvent *aEvent)
 {
   mEvents.AppendElement(aEvent);
-  
+
   // Filter events.
   CoalesceEvents();
-  
+
+  // Associate text change with hide event if it wasn't stolen from hiding
+  // siblings during coalescence.
+  AccHideEvent* hideEvent = downcast_accEvent(aEvent);
+  if (hideEvent && !hideEvent->mTextChangeEvent)
+    CreateTextChangeEventFor(hideEvent);
+
   // Process events.
   PrepareFlush();
 }
 
 void
 nsAccEventQueue::Shutdown()
 {
   if (mObservingRefresh) {
@@ -200,19 +206,26 @@ nsAccEventQueue::WillRefresh(mozilla::Ti
   nsTArray < nsRefPtr<nsAccEvent> > events;
   events.SwapElements(mEvents);
   PRUint32 length = events.Length();
   NS_ASSERTION(length, "How did we get here without events to fire?");
 
   for (PRUint32 index = 0; index < length; index ++) {
 
     nsAccEvent *accEvent = events[index];
-    if (accEvent->mEventRule != nsAccEvent::eDoNotEmit)
+    if (accEvent->mEventRule != nsAccEvent::eDoNotEmit) {
       mDocument->ProcessPendingEvent(accEvent);
 
+      AccHideEvent* hideEvent = downcast_accEvent(accEvent);
+      if (hideEvent) {
+        if (hideEvent->mTextChangeEvent)
+          mDocument->ProcessPendingEvent(hideEvent->mTextChangeEvent);
+      }
+    }
+
     // No document means it was shut down during event handling by AT
     if (!mDocument)
       return;
   }
 
   if (mEvents.Length() == 0) {
     nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
     if (!shell ||
@@ -239,25 +252,51 @@ nsAccEventQueue::CoalesceEvents()
     {
       for (PRInt32 index = tail - 1; index >= 0; index--) {
         nsAccEvent* thisEvent = mEvents[index];
 
         if (thisEvent->mEventType != tailEvent->mEventType)
           continue; // Different type
 
         // Skip event for application accessible since no coalescence for it
-        // is supported. Ignore events unattached from DOM and events from
-        // different documents since we can't coalesce them.
-        if (!thisEvent->mNode || !thisEvent->mNode->IsInDoc() ||
+        // is supported. Ignore events from different documents since we don't
+        // coalesce them.
+        if (!thisEvent->mNode ||
             thisEvent->mNode->GetOwnerDoc() != tailEvent->mNode->GetOwnerDoc())
           continue;
 
         // If event queue contains an event of the same type and having target
         // that is sibling of target of newly appended event then apply its
         // event rule to the newly appended event.
+
+        // XXX: deal with show events separately because they can't be
+        // coalesced by accessible tree the same as hide events since target
+        // accessibles can't be created at this point because of lazy frame
+        // construction (bug 570275).
+
+        // Coalesce hide events for sibling targets.
+        if (tailEvent->mEventType == nsIAccessibleEvent::EVENT_HIDE) {
+          AccHideEvent* tailHideEvent = downcast_accEvent(tailEvent);
+          AccHideEvent* thisHideEvent = downcast_accEvent(thisEvent);
+          if (thisHideEvent->mParent == tailHideEvent->mParent) {
+            tailEvent->mEventRule = thisEvent->mEventRule;
+
+            // Coalesce text change events for hide events.
+            if (tailEvent->mEventRule != nsAccEvent::eDoNotEmit)
+              CoalesceTextChangeEventsFor(tailHideEvent, thisHideEvent);
+
+            return;
+          }
+        }
+
+        // Ignore events unattached from DOM since we don't coalesce them.
+        if (!thisEvent->mNode->IsInDoc())
+          continue;
+
+        // Coalesce show and reorder events by sibling targets.
         if (thisEvent->mNode->GetNodeParent() ==
             tailEvent->mNode->GetNodeParent()) {
           tailEvent->mEventRule = thisEvent->mEventRule;
           return;
         }
 
         // Specifies if this event target can be descendant of tail node.
         PRBool thisCanBeDescendantOfTail = PR_FALSE;
@@ -457,8 +496,68 @@ void
 nsAccEventQueue::CoalesceReorderEventsFromSameTree(nsAccEvent *aAccEvent,
                                                    nsAccEvent *aDescendantAccEvent)
 {
   // Do not emit descendant event if this event is unconditional.
   nsAccReorderEvent *reorderEvent = downcast_accEvent(aAccEvent);
   if (reorderEvent->IsUnconditionalEvent())
     aDescendantAccEvent->mEventRule = nsAccEvent::eDoNotEmit;
 }
+
+void
+nsAccEventQueue::CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
+                                             AccHideEvent* aThisEvent)
+{
+  // XXX: we need a way to ignore SplitNode and JoinNode() when they do not
+  // affect the text within the hypertext.
+
+  nsAccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent;
+  if (!textEvent)
+    return;
+
+  if (aThisEvent->mNextSibling == aTailEvent->mAccessible) {
+    aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText,
+                                          0, PR_UINT32_MAX);
+
+  } else if (aThisEvent->mPrevSibling == aTailEvent->mAccessible) {
+    PRUint32 oldLen = textEvent->GetLength();
+    aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText,
+                                          0, PR_UINT32_MAX);
+    textEvent->mStart -= textEvent->GetLength() - oldLen;
+  }
+
+  aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent);
+}
+
+void
+nsAccEventQueue::CreateTextChangeEventFor(AccHideEvent* aEvent)
+{
+  nsRefPtr<nsHyperTextAccessible> textAccessible = do_QueryObject(
+    GetAccService()->GetContainerAccessible(aEvent->mNode,
+                                            aEvent->mAccessible->GetWeakShell()));
+  if (!textAccessible)
+    return;
+
+  // Don't fire event for the first html:br in an editor.
+  if (nsAccUtils::Role(aEvent->mAccessible) ==
+      nsIAccessibleRole::ROLE_WHITESPACE) {
+    nsCOMPtr<nsIEditor> editor;
+    textAccessible->GetAssociatedEditor(getter_AddRefs(editor));
+    if (editor) {
+      PRBool isEmpty = PR_FALSE;
+      editor->GetDocumentIsEmpty(&isEmpty);
+      if (isEmpty)
+        return;
+    }
+  }
+
+  PRInt32 offset = textAccessible->GetChildOffset(aEvent->mAccessible);
+
+  nsAutoString text;
+  aEvent->mAccessible->AppendTextTo(text, 0, PR_UINT32_MAX);
+  if (text.IsEmpty())
+    return;
+
+  aEvent->mTextChangeEvent =
+    new nsAccTextChangeEvent(textAccessible, offset, text, PR_FALSE,
+                             aEvent->mIsAsync,
+                             aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput);
+}
--- a/accessible/src/base/nsEventShell.h
+++ b/accessible/src/base/nsEventShell.h
@@ -153,16 +153,30 @@ private:
   /**
    * Do not emit one of two given reorder events fired for DOM nodes in the case
    * when one DOM node is in parent chain of second one.
    */
   void CoalesceReorderEventsFromSameTree(nsAccEvent *aAccEvent,
                                          nsAccEvent *aDescendantAccEvent);
 
   /**
+   * Coalesce text change events caused by sibling hide events.
+   */
+  void CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
+                                   AccHideEvent* aThisEvent);
+
+  /**
+   * Create text change event caused by hide event. When a node is hidden or
+   * removed, the text in an ancestor hyper text will lose characters. Create
+   * text change event unless the node is being removed or frame is being
+   * destroyed.
+   */
+  void CreateTextChangeEventFor(AccHideEvent* aEvent);
+
+  /**
    * Indicates whether we're waiting on a refresh notification from our
    * presshell to flush events
    */
   PRBool mObservingRefresh;
 
   /**
    * The document accessible reference owning this queue.
    */
--- a/accessible/src/base/nsOuterDocAccessible.cpp
+++ b/accessible/src/base/nsOuterDocAccessible.cpp
@@ -195,21 +195,19 @@ nsOuterDocAccessible::InvalidateChildren
 }
 
 PRBool
 nsOuterDocAccessible::AppendChild(nsAccessible *aAccessible)
 {
   NS_ASSERTION(!mChildren.Length(),
                "Previous child document of outerdoc accessible wasn't removed!");
 
-  if (!mChildren.AppendElement(aAccessible))
+  if (!nsAccessible::AppendChild(aAccessible))
     return PR_FALSE;
 
-  aAccessible->SetParent(this);
-
   NS_LOG_ACCDOCCREATE("append document to outerdoc",
                       aAccessible->GetDocumentNode())
   NS_LOG_ACCDOCCREATE_ACCADDRESS("outerdoc", this)
 
   return PR_TRUE;
 }
 
 PRBool
@@ -220,22 +218,22 @@ nsOuterDocAccessible::RemoveChild(nsAcce
     NS_ERROR("Wrong child to remove!");
     return PR_FALSE;
   }
 
   NS_LOG_ACCDOCDESTROY("remove document from outerdoc",
                        child->GetDocumentNode())
   NS_LOG_ACCDOCDESTROY_ACCADDRESS("outerdoc", this)
 
-  mChildren.RemoveElement(child);
+  PRBool wasRemoved = nsAccessible::RemoveChild(child);
 
   NS_ASSERTION(!mChildren.Length(),
                "This child document of outerdoc accessible wasn't removed!");
 
-  return PR_TRUE;
+  return wasRemoved;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible protected
 
 void
 nsOuterDocAccessible::CacheChildren()
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -453,109 +453,77 @@ nsRootAccessible::FireAccessibleFocusEve
 }
 
 void
 nsRootAccessible::FireCurrentFocusEvent()
 {
   if (IsDefunct())
     return;
 
+  // Simulate a focus event so that we can reuse code that fires focus for
+  // container children like treeitems.
   nsCOMPtr<nsINode> focusedNode = GetCurrentFocus();
   if (!focusedNode) {
     return; // No current focus
   }
 
-  // Simulate a focus event so that we can reuse code that fires focus for container children like treeitems
   nsCOMPtr<nsIDOMDocumentEvent> docEvent = do_QueryInterface(mDocument);
   if (docEvent) {
     nsCOMPtr<nsIDOMEvent> event;
     if (NS_SUCCEEDED(docEvent->CreateEvent(NS_LITERAL_STRING("Events"),
                                            getter_AddRefs(event))) &&
         NS_SUCCEEDED(event->InitEvent(NS_LITERAL_STRING("focus"), PR_TRUE, PR_TRUE))) {
-      // Get the target node we really want for the event.
 
-      nsINode *targetNode =
-        GetAccService()->GetRelevantContentNodeFor(focusedNode);
-      if (targetNode) {
-        // If the focused element is document element or HTML body element
-        // then simulate the focus event for the document.
-        nsINode *document = targetNode->GetOwnerDoc();
-        if (targetNode == nsCoreUtils::GetRoleContent(document)) {
-          HandleEventWithTarget(event, document);
-          return;
-        }
-
-        // Otherwise simulate the focus event for currently focused node.
-        nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
-        nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(focusedNode));
-        privateEvent->SetTarget(target);
-        HandleEventWithTarget(event, targetNode);
-      }
+      nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
+      nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(focusedNode));
+      privateEvent->SetTarget(target);
+      HandleEvent(event);
     }
   }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIDOMEventListener
 
-NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
+NS_IMETHODIMP
+nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
 {
-  // Turn DOM events in accessibility events
-  // Get info about event and target
-  nsCOMPtr<nsIDOMNode> targetNode;
-  GetTargetNode(aEvent, getter_AddRefs(targetNode));
-  if (!targetNode)
-    return NS_ERROR_FAILURE;
+  nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aEvent));
+  NS_ENSURE_STATE(nsevent);
 
-  nsCOMPtr<nsINode> node(do_QueryInterface(targetNode));
-  return HandleEventWithTarget(aEvent, node);
-}
-
+  nsCOMPtr<nsIDOMEventTarget> domEventTarget;
+  nsevent->GetOriginalTarget(getter_AddRefs(domEventTarget));
+  nsCOMPtr<nsINode> origTarget(do_QueryInterface(domEventTarget));
+  NS_ENSURE_STATE(origTarget);
 
-// nsRootAccessible protected member
-nsresult nsRootAccessible::HandleEventWithTarget(nsIDOMEvent* aEvent,
-                                                 nsINode* aTargetNode)
-{
   nsAutoString eventType;
   aEvent->GetType(eventType);
-  nsAutoString localName;
-  nsCOMPtr<nsIContent> targetContent(do_QueryInterface(aTargetNode));
-  if (targetContent)
-    targetContent->NodeInfo()->GetName(localName);
-#ifdef MOZ_XUL
-  PRBool isTree = localName.EqualsLiteral("tree");
-#endif
-#ifdef DEBUG_A11Y
-  // Very useful for debugging, please leave this here.
-  if (eventType.EqualsLiteral("AlertActive")) {
-    printf("\ndebugging %s events for %s", NS_ConvertUTF16toUTF8(eventType).get(), NS_ConvertUTF16toUTF8(localName).get());
-  }
-  if (localName.LowerCaseEqualsLiteral("textbox")) {
-    printf("\ndebugging %s events for %s", NS_ConvertUTF16toUTF8(eventType).get(), NS_ConvertUTF16toUTF8(localName).get());
-  }
-#endif
-
-  nsAccessibilityService *accService = GetAccService();
-  NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIWeakReference> weakShell =
-    nsCoreUtils::GetWeakShellFor(aTargetNode);
+    nsCoreUtils::GetWeakShellFor(origTarget);
   if (!weakShell)
     return NS_OK;
 
-  nsAccessible *accessible =
-    accService->GetAccessibleInWeakShell(aTargetNode, weakShell);
+  nsAccessible* accessible =
+    GetAccService()->GetAccessibleOrContainer(origTarget, weakShell);
 
   if (eventType.EqualsLiteral("popuphiding"))
-    return HandlePopupHidingEvent(aTargetNode, accessible);
+    return HandlePopupHidingEvent(origTarget, accessible);
 
   if (!accessible)
     return NS_OK;
 
+  nsINode* targetNode = accessible->GetNode();
+  nsIContent* targetContent = targetNode->IsElement() ?
+    targetNode->AsElement() : nsnull;
 #ifdef MOZ_XUL
+  PRBool isTree = targetContent ?
+    targetContent->NodeInfo()->Equals(nsAccessibilityAtoms::tree,
+                                      kNameSpaceID_XUL) : PR_FALSE;
+
   if (isTree) {
     nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(accessible);
     NS_ASSERTION(treeAcc,
                  "Accessible for xul:tree isn't nsXULTreeAccessible.");
 
     if (treeAcc) {
       if (eventType.EqualsLiteral("TreeViewChanged")) {
         treeAcc->TreeViewChanged();
@@ -582,17 +550,17 @@ nsresult nsRootAccessible::HandleEventWi
                         nsIAccessibleStates::STATE_SELECTED)) != 0;
 
     nsRefPtr<nsAccEvent> accEvent =
       new nsAccStateChangeEvent(accessible, nsIAccessibleStates::STATE_CHECKED,
                                 PR_FALSE, isEnabled);
     nsEventShell::FireEvent(accEvent);
 
     if (isEnabled)
-      FireAccessibleFocusEvent(accessible, aTargetNode, aEvent);
+      FireAccessibleFocusEvent(accessible, targetNode, aEvent);
 
     return NS_OK;
   }
 
   if (eventType.EqualsLiteral("CheckboxStateChange")) {
     PRUint32 state = nsAccUtils::State(accessible);
 
     PRBool isEnabled = !!(state & nsIAccessibleStates::STATE_CHECKED);
@@ -606,17 +574,17 @@ nsresult nsRootAccessible::HandleEventWi
     return NS_OK;
   }
 
   nsAccessible *treeItemAccessible = nsnull;
 #ifdef MOZ_XUL
   // If it's a tree element, need the currently selected item
   if (isTree) {
     nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelect =
-      do_QueryInterface(aTargetNode);
+      do_QueryInterface(targetNode);
     if (multiSelect) {
       PRInt32 treeIndex = -1;
       multiSelect->GetCurrentIndex(&treeIndex);
       if (treeIndex >= 0) {
         nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(accessible);
         if (treeAcc) {
           treeItemAccessible = treeAcc->GetTreeItemAccessible(treeIndex);
           if (treeItemAccessible)
@@ -636,19 +604,19 @@ nsresult nsRootAccessible::HandleEventWi
       new nsAccStateChangeEvent(accessible, nsIAccessibleStates::STATE_EXPANDED,
                                 PR_FALSE, isEnabled);
     nsEventShell::FireEvent(accEvent);
     return NS_OK;
   }
 
   if (treeItemAccessible && eventType.EqualsLiteral("select")) {
     // If multiselect tree, we should fire selectionadd or selection removed
-    if (gLastFocusedNode == aTargetNode) {
+    if (gLastFocusedNode == targetNode) {
       nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSel =
-        do_QueryInterface(aTargetNode);
+        do_QueryInterface(targetNode);
       nsAutoString selType;
       multiSel->GetSelType(selType);
       if (selType.IsEmpty() || !selType.EqualsLiteral("single")) {
         // XXX: We need to fire EVENT_SELECTION_ADD and EVENT_SELECTION_REMOVE
         // for each tree item. Perhaps each tree item will need to cache its
         // selection state and fire an event after a DOM "select" event when
         // that state changes. nsXULTreeAccessible::UpdateTreeSelection();
         nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN,
@@ -659,47 +627,46 @@ nsresult nsRootAccessible::HandleEventWi
       nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION,
                               treeItemAccessible);
       return NS_OK;
     }
   }
   else
 #endif
   if (eventType.EqualsLiteral("focus")) {
-    if (aTargetNode == mDocument && mDocument != gLastFocusedNode) {
+    if (targetNode == mDocument && mDocument != gLastFocusedNode) {
       // Got focus event for the window, we will make sure that an accessible
       // focus event for initial focus is fired. We do this on a short timer
       // because the initial focus may not have been set yet.
       NS_DISPATCH_RUNNABLEMETHOD(FireCurrentFocusEvent, this)
     }
 
     // Keep a reference to the target node. We might want to change
     // it to the individual radio button or selected item, and send
     // the focus event to that.
-    nsCOMPtr<nsINode> focusedItem(aTargetNode);
-
+    nsCOMPtr<nsINode> focusedItem = targetNode;
     if (!treeItemAccessible) {
       nsCOMPtr<nsIDOMXULSelectControlElement> selectControl =
-        do_QueryInterface(aTargetNode);
+        do_QueryInterface(targetNode);
       if (selectControl) {
         nsCOMPtr<nsIDOMXULMenuListElement> menuList =
-          do_QueryInterface(aTargetNode);
+          do_QueryInterface(targetNode);
         if (!menuList) {
           // Don't do this for menu lists, the items only get focused
           // when the list is open, based on DOMMenuitemActive events
           nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem;
           selectControl->GetSelectedItem(getter_AddRefs(selectedItem));
           if (selectedItem)
             focusedItem = do_QueryInterface(selectedItem);
 
           if (!focusedItem)
             return NS_OK;
 
-          accessible = accService->GetAccessibleInWeakShell(focusedItem,
-                                                            weakShell);
+          accessible = GetAccService()->GetAccessibleInWeakShell(focusedItem,
+                                                                 weakShell);
           if (!accessible)
             return NS_OK;
         }
       }
     }
     FireAccessibleFocusEvent(accessible, focusedItem, aEvent);
   }
   else if (eventType.EqualsLiteral("blur")) {
@@ -751,110 +718,68 @@ nsresult nsRootAccessible::HandleEventWi
           if (nsAccUtils::Role(containerParent) != nsIAccessibleRole::ROLE_COMBOBOX) {
             return NS_OK;
           }
         }
       }
     }
     if (!fireFocus) {
       nsCOMPtr<nsINode> realFocusedNode = GetCurrentFocus();
-      nsCOMPtr<nsIContent> realFocusedContent = do_QueryInterface(realFocusedNode);
-      nsCOMPtr<nsIContent> targetContent = do_QueryInterface(aTargetNode);
-      nsIContent *containerContent = targetContent;
+      nsIContent* realFocusedContent = realFocusedNode->AsElement();
+      nsIContent* containerContent = targetContent;
       while (containerContent) {
         nsCOMPtr<nsIDOMXULPopupElement> popup = do_QueryInterface(containerContent);
         if (popup || containerContent == realFocusedContent) { 
           // If we're inside the focus or a popup we can fire focus events
           // for the changed active item
           fireFocus = PR_TRUE;
           break;
         }
         containerContent = containerContent->GetParent();
       }
     }
     if (fireFocus) {
       // Always asynch, always from user input.
-      FireAccessibleFocusEvent(accessible, aTargetNode, aEvent, PR_TRUE,
+      FireAccessibleFocusEvent(accessible, targetNode, aEvent, PR_TRUE,
                                PR_TRUE, eFromUserInput);
     }
   }
   else if (eventType.EqualsLiteral("DOMMenuBarActive")) {  // Always asynch, always from user input
     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_START,
                             accessible, PR_TRUE, eFromUserInput);
   }
   else if (eventType.EqualsLiteral("DOMMenuBarInactive")) {  // Always asynch, always from user input
     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_END,
                             accessible, PR_TRUE, eFromUserInput);
     FireCurrentFocusEvent();
   }
   else if (eventType.EqualsLiteral("ValueChange")) {
     FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
-                               aTargetNode, nsAccEvent::eRemoveDupes);
+                               targetNode, nsAccEvent::eRemoveDupes);
   }
 #ifdef DEBUG
   else if (eventType.EqualsLiteral("mouseover")) {
     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_DRAGDROP_START,
                             accessible);
   }
 #endif
   return NS_OK;
 }
 
-void nsRootAccessible::GetTargetNode(nsIDOMEvent *aEvent, nsIDOMNode **aTargetNode)
-{
-  *aTargetNode = nsnull;
-
-  nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aEvent));
-
-  if (!nsevent)
-    return;
-
-  nsCOMPtr<nsIDOMEventTarget> domEventTarget;
-  nsevent->GetOriginalTarget(getter_AddRefs(domEventTarget));
-  nsCOMPtr<nsIDOMNode> eventTarget(do_QueryInterface(domEventTarget));
-  if (!eventTarget)
-    return;
-
-  nsIAccessibilityService* accService = GetAccService();
-  if (accService) {
-    nsresult rv = accService->GetRelevantContentNodeFor(eventTarget,
-                                                        aTargetNode);
-    if (NS_SUCCEEDED(rv) && *aTargetNode)
-      return;
-  }
-
-  NS_ADDREF(*aTargetNode = eventTarget);
-}
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNode
 
-PRBool
-nsRootAccessible::Init()
-{
-  nsApplicationAccessible *applicationAcc = GetApplicationAccessible();
-  if (!applicationAcc || !applicationAcc->AppendChild(this))
-    return PR_FALSE;
-
-  return nsDocAccessibleWrap::Init();
-}
-
 void
 nsRootAccessible::Shutdown()
 {
   // Called manually or by nsAccessNode::LastRelease()
   if (!mWeakShell)
     return;  // Already shutdown
 
-  nsApplicationAccessible *applicationAcc = GetApplicationAccessible();
-  if (!applicationAcc)
-    return;
-
-  applicationAcc->RemoveChild(this);
-
   mCurrentARIAMenubar = nsnull;
 
   nsDocAccessibleWrap::Shutdown();
 }
 
 // nsRootAccessible protected member
 already_AddRefed<nsIDocShellTreeItem>
 nsRootAccessible::GetContentDocShell(nsIDocShellTreeItem *aStart)
@@ -928,27 +853,16 @@ nsRootAccessible::GetRelationByType(PRUi
     nsDocAccessible *accDoc = nsAccUtils::GetDocAccessibleFor(contentTreeItem);
     return nsRelUtils::AddTarget(aRelationType, aRelation, accDoc);
   }
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsAccessible
-
-nsAccessible*
-nsRootAccessible::GetParent()
-{
-  // Parent has been set in nsApplicationAccesible::AppendChild() when root
-  // accessible was initialized.
-  return mParent;
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // Protected members
 
 nsresult
 nsRootAccessible::HandlePopupShownEvent(nsAccessible *aAccessible)
 {
   PRUint32 role = nsAccUtils::Role(aAccessible);
 
   if (role == nsIAccessibleRole::ROLE_MENUPOPUP) {
--- a/accessible/src/base/nsRootAccessible.h
+++ b/accessible/src/base/nsRootAccessible.h
@@ -76,23 +76,21 @@ public:
   NS_IMETHOD GetName(nsAString& aName);
   NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
                                nsIAccessibleRelation **aRelation);
 
   // nsIDOMEventListener
   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
 
   // nsAccessNode
-  virtual PRBool Init();
   virtual void Shutdown();
 
   // nsAccessible
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
-  virtual nsAccessible* GetParent();
 
   // nsRootAccessible
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ROOTACCESSIBLE_IMPL_CID)
 
   /**
    * Fire an accessible focus event for the current focusAccssible
    * and attach a new selection listener, if necessary.
    *
@@ -121,29 +119,22 @@ public:
 
 protected:
   NS_DECL_RUNNABLEMETHOD(nsRootAccessible, FireCurrentFocusEvent)
 
     nsresult AddEventListeners();
     nsresult RemoveEventListeners();
 
   /**
-   * Process DOM events.
-   */
-  nsresult HandleEventWithTarget(nsIDOMEvent* aEvent, nsINode* aTargetNode);
-
-    static void GetTargetNode(nsIDOMEvent *aEvent, nsIDOMNode **aTargetNode);
-
-  /**
-   * Process "popupshown" event. Used by HandleEventWithTarget().
+   * Process "popupshown" event. Used by HandleEvent().
    */
 
   nsresult HandlePopupShownEvent(nsAccessible *aAccessible);
   /*
-   * Process "popuphiding" event. Used by HandleEventWithTarget().
+   * Process "popuphiding" event. Used by HandleEvent().
    */
   nsresult HandlePopupHidingEvent(nsINode *aNode, nsAccessible *aAccessible);
 
 #ifdef MOZ_XUL
     nsresult HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
                                             nsXULTreeAccessible *aAccessible);
     nsresult HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
                                         nsXULTreeAccessible *aAccessible);
--- a/accessible/src/html/nsHTMLImageMapAccessible.cpp
+++ b/accessible/src/html/nsHTMLImageMapAccessible.cpp
@@ -152,18 +152,18 @@ nsHTMLImageMapAccessible::CacheChildren(
     if (!areaAcc->Init()) {
       areaAcc->Shutdown();
       return;
     }
 
     // We must respect ARIA on area elements (for the canvas map technique)
     areaAcc->SetRoleMapEntry(nsAccUtils::GetRoleMapEntry(areaContent));
 
-    mChildren.AppendElement(areaAcc);
-    areaAcc->SetParent(this);
+    if (!AppendChild(areaAcc))
+      return;
   }
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLAreaAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
--- a/accessible/src/html/nsHTMLSelectAccessible.cpp
+++ b/accessible/src/html/nsHTMLSelectAccessible.cpp
@@ -366,34 +366,34 @@ nsHTMLSelectListAccessible::CacheChildre
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLSelectListAccessible protected
 
 void
 nsHTMLSelectListAccessible::CacheOptSiblings(nsIContent *aParentContent)
 {
+  nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
   PRUint32 numChildren = aParentContent->GetChildCount();
   for (PRUint32 count = 0; count < numChildren; count ++) {
     nsIContent *childContent = aParentContent->GetChildAt(count);
     if (!childContent->IsHTML()) {
       continue;
     }
 
     nsCOMPtr<nsIAtom> tag = childContent->Tag();
     if (tag == nsAccessibilityAtoms::option ||
         tag == nsAccessibilityAtoms::optgroup) {
 
       // Get an accessible for option or optgroup and cache it.
-      nsAccessible *accessible =
-        GetAccService()->GetAccessibleInWeakShell(childContent, mWeakShell);
-      if (accessible) {
-        mChildren.AppendElement(accessible);
-        accessible->SetParent(this);
-      }
+      nsRefPtr<nsAccessible> accessible =
+        GetAccService()->GetOrCreateAccessible(childContent, presShell,
+                                               mWeakShell);
+      if (accessible)
+        AppendChild(accessible);
 
       // Deep down into optgroup element.
       if (tag == nsAccessibilityAtoms::optgroup)
         CacheOptSiblings(childContent);
     }
   }
 }
 
@@ -401,36 +401,16 @@ nsHTMLSelectListAccessible::CacheOptSibl
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLSelectOptionAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsHTMLSelectOptionAccessible::
   nsHTMLSelectOptionAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
   nsHyperTextAccessibleWrap(aContent, aShell)
 {
-  nsIContent *parentContent = aContent->GetParent();
-  if (!parentContent)
-    return;
-
-  // If the parent node is a Combobox, then the option's accessible parent
-  // is nsHTMLComboboxListAccessible, not the nsHTMLComboboxAccessible that
-  // GetParent would normally return. This is because the 
-  // nsHTMLComboboxListAccessible is inserted into the accessible hierarchy
-  // where there is no DOM node for it.
-  nsAccessible *parentAcc =
-    GetAccService()->GetAccessibleInWeakShell(parentContent, mWeakShell);
-  if (!parentAcc)
-    return;
-
-  if (nsAccUtils::RoleInternal(parentAcc) == nsIAccessibleRole::ROLE_COMBOBOX) {
-    PRInt32 childCount = parentAcc->GetChildCount();
-    parentAcc = parentAcc->GetChildAt(childCount - 1);
-  }
-
-  SetParent(parentAcc);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLSelectOptionAccessible: nsAccessible public
 
 nsresult
 nsHTMLSelectOptionAccessible::GetRoleInternal(PRUint32 *aRole)
 {
@@ -467,16 +447,17 @@ nsHTMLSelectOptionAccessible::GetNameInt
     txtValue.CompressWhitespace();
     aName.Assign(txtValue);
     return NS_OK;
   }
 
   return NS_OK;
 }
 
+// nsAccessible protected
 nsIFrame* nsHTMLSelectOptionAccessible::GetBoundsFrame()
 {
   PRUint32 state = 0;
   nsCOMPtr<nsIContent> content = GetSelectState(&state);
   if (state & nsIAccessibleStates::STATE_COLLAPSED) {
     if (content) {
       return content->GetPrimaryFrame();
     }
@@ -927,21 +908,28 @@ nsHTMLComboboxAccessible::CacheChildren(
     return;
 
   if (!mListAccessible) {
     mListAccessible = 
       new nsHTMLComboboxListAccessible(mParent, mContent, mWeakShell);
     if (!mListAccessible)
       return;
 
-    mListAccessible->Init();
+    // Initialize and put into cache.
+    if (!mListAccessible->Init()) {
+      mListAccessible->Shutdown();
+      return;
+    }
   }
 
-  mChildren.AppendElement(mListAccessible);
-  mListAccessible->SetParent(this);
+  AppendChild(mListAccessible);
+
+  // Cache combobox option accessibles so that we build complete accessible tree
+  // for combobox.
+  mListAccessible->EnsureChildren();
 }
 
 void
 nsHTMLComboboxAccessible::Shutdown()
 {
   nsAccessibleWrap::Shutdown();
 
   if (mListAccessible) {
@@ -1166,15 +1154,8 @@ void nsHTMLComboboxListAccessible::GetBo
   if (!frame) {
     *aBoundingFrame = nsnull;
     return;
   }
 
   *aBoundingFrame = frame->GetParent();
   aBounds = (*aBoundingFrame)->GetRect();
 }
-
-// nsHTMLComboboxListAccessible. nsAccessible public mehtod
-nsAccessible*
-nsHTMLComboboxListAccessible::GetParent()
-{
-  return mParent;
-}
--- a/accessible/src/html/nsHTMLSelectAccessible.h
+++ b/accessible/src/html/nsHTMLSelectAccessible.h
@@ -158,25 +158,27 @@ public:
   virtual nsresult GetNameInternal(nsAString& aName);
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
 
   virtual PRInt32 GetLevelInternal();
   virtual void GetPositionAndSizeInternal(PRInt32 *aPosInSet,
                                           PRInt32 *aSetSize);
 
-  nsIFrame*  GetBoundsFrame();
-
   /**
    * Return focused option if any.
    */
   static already_AddRefed<nsIContent> GetFocusedOption(nsIContent *aListNode);
 
   static void SelectionChangedIfOption(nsIContent *aPossibleOption);
 
+protected:
+  // nsAccessible
+  virtual nsIFrame* GetBoundsFrame();
+
 private:
   
   /**
    * Get Select element's accessible state
    * @param aState, Select element state
    * @param aExtraState, Select element extra state
    * @return Select element content, returns null if not avaliable
    */ 
@@ -271,12 +273,11 @@ public:
   NS_IMETHOD GetUniqueID(void **aUniqueID);
 
   // nsAccessNode
   virtual nsIFrame* GetFrame();
 
   // nsAccessible
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
   virtual void GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame);
-  virtual nsAccessible* GetParent();
 };
 
 #endif
--- a/accessible/src/html/nsHTMLTableAccessible.cpp
+++ b/accessible/src/html/nsHTMLTableAccessible.cpp
@@ -35,16 +35,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 "nsHTMLTableAccessible.h"
 
 #include "nsAccessibilityService.h"
+#include "nsAccTreeWalker.h"
 #include "nsAccUtils.h"
 #include "nsDocAccessible.h"
 #include "nsRelUtils.h"
 #include "nsTextEquivUtils.h"
 
 #include "nsIDOMElement.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentRange.h"
@@ -447,35 +448,30 @@ NS_IMPL_ISUPPORTS_INHERITED2(nsHTMLTable
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLTableAccessible: nsAccessible implementation
 
 void
 nsHTMLTableAccessible::CacheChildren()
 {
-  nsAccessible::CacheChildren();
-
-  // Move caption accessible so that it's the first child.
-  PRInt32 length = mChildren.Length();
-  for (PRInt32 idx = 0; idx < length; idx++) {
-    // Check for the first caption, because nsAccessibilityService ensures we
-    // don't create accessibles for the other captions, since only the first is
-    // actually visible.
+  // Move caption accessible so that it's the first child. Check for the first
+  // caption only, because nsAccessibilityService ensures we don't create
+  // accessibles for the other captions, since only the first is actually
+  // visible.
+  nsAccTreeWalker walker(mWeakShell, mContent, GetAllowsAnonChildAccessibles());
 
-    nsAccessible* child = mChildren.ElementAt(idx);
+  nsRefPtr<nsAccessible> child;
+  while ((child = walker.GetNextChild())) {
     if (nsAccUtils::Role(child) == nsIAccessibleRole::ROLE_CAPTION) {
-      if (idx == 0)
-        break;
-
-      nsRefPtr<nsAccessible> tmp = mChildren[0];
-      mChildren[0] = child;
-      mChildren[idx] = tmp;
+      InsertChildAt(0, child);
+      while ((child = walker.GetNextChild()) && AppendChild(child));
       break;
     }
+    AppendChild(child);
   }
 }
 
 nsresult
 nsHTMLTableAccessible::GetRoleInternal(PRUint32 *aResult)
 {
   *aResult = nsIAccessibleRole::ROLE_TABLE;
   return NS_OK;
--- a/accessible/src/html/nsHTMLTextAccessible.cpp
+++ b/accessible/src/html/nsHTMLTextAccessible.cpp
@@ -267,20 +267,18 @@ NS_IMETHODIMP nsHTMLLIAccessible::GetBou
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLLIAccessible: nsAccessible protected
 
 void
 nsHTMLLIAccessible::CacheChildren()
 {
-  if (mBulletAccessible) {
-    mChildren.AppendElement(mBulletAccessible);
-    mBulletAccessible->SetParent(this);
-  }
+  if (mBulletAccessible)
+    AppendChild(mBulletAccessible);
 
   // Cache children from subtree.
   nsAccessibleWrap::CacheChildren();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLListBulletAccessible
 ////////////////////////////////////////////////////////////////////////////////
@@ -342,22 +340,16 @@ nsHTMLListBulletAccessible::AppendTextTo
   PRUint32 maxLength = mBulletText.Length() - aStartOffset;
   if (aLength > maxLength) {
     aLength = maxLength;
   }
   aText += Substring(mBulletText, aStartOffset, aLength);
   return NS_OK;
 }
 
-nsAccessible*
-nsHTMLListBulletAccessible::GetParent()
-{
-  return mParent;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLListAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsHTMLListAccessible::
   nsHTMLListAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
   nsHyperTextAccessibleWrap(aContent, aShell)
 {
--- a/accessible/src/html/nsHTMLTextAccessible.h
+++ b/accessible/src/html/nsHTMLTextAccessible.h
@@ -124,18 +124,16 @@ public:
   virtual void Shutdown();
 
   // nsAccessible
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
   virtual nsresult AppendTextTo(nsAString& aText, PRUint32 aStartOffset,
                                 PRUint32 aLength);
 
-  virtual nsAccessible* GetParent();
-
 protected:
   // XXX: Ideally we'd get the bullet text directly from the bullet frame via
   // nsBulletFrame::GetListItemText(), but we'd need an interface for getting
   // text from contentless anonymous frames. Perhaps something like
   // nsIAnonymousFrame::GetText() ? However, in practice storing the bullet text
   // here should not be a problem if we invalidate the right parts of
   // the accessibility cache when mutation events occur.
   nsString mBulletText;
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -2039,16 +2039,18 @@ nsHyperTextAccessible::ScrollSubstringTo
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible public
 
 void
 nsHyperTextAccessible::InvalidateChildren()
 {
   mLinks = nsnull;
+  mOffsets.Clear();
+
   nsAccessibleWrap::InvalidateChildren();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHyperTextAccessible public static
 
 nsresult nsHyperTextAccessible::ContentToRenderedOffset(nsIFrame *aFrame, PRInt32 aContentOffset,
                                                         PRUint32 *aRenderedOffset)
@@ -2100,16 +2102,47 @@ nsresult nsHyperTextAccessible::Rendered
   PRInt32 ourContentStart = iter.GetOriginalOffset();
 
   *aContentOffset = iter.ConvertSkippedToOriginal(aRenderedOffset + ourRenderedStart) - ourContentStart;
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// nsHyperTextAccessible public
+
+PRInt32
+nsHyperTextAccessible::GetChildOffset(nsAccessible* aChild,
+                                      PRBool aInvalidateAfter)
+{
+  PRInt32 index = GetIndexOf(aChild);
+  if (index == -1 || index == 0)
+    return index;
+
+  PRInt32 count = mOffsets.Length() - index;
+  if (count > 0) {
+    if (aInvalidateAfter)
+      mOffsets.RemoveElementsAt(index, count);
+
+    return mOffsets[index - 1];
+  }
+
+  PRUint32 lastOffset = mOffsets.IsEmpty() ?
+    0 : mOffsets[mOffsets.Length() - 1];
+
+  EnsureChildren();
+  while (mOffsets.Length() < index) {
+    nsAccessible* child = mChildren[mOffsets.Length()];
+    lastOffset += nsAccUtils::TextLength(child);
+    mOffsets.AppendElement(lastOffset);
+  }
+
+  return mOffsets[index - 1];
+}
+////////////////////////////////////////////////////////////////////////////////
 // nsHyperTextAccessible protected
 
 AccCollector*
 nsHyperTextAccessible::GetLinkCollector()
 {
   if (IsDefunct())
     return nsnull;
 
--- a/accessible/src/html/nsHyperTextAccessible.h
+++ b/accessible/src/html/nsHyperTextAccessible.h
@@ -181,16 +181,26 @@ public:
    */
   nsresult HypertextOffsetsToDOMRange(PRInt32 aStartHTOffset,
                                       PRInt32 aEndHTOffset,
                                       nsIDOMNode **aStartNode,
                                       PRInt32 *aStartOffset,
                                       nsIDOMNode **aEndNode,
                                       PRInt32 *aEndOffset);
 
+  /**
+   * Return text offset the given child accessible of hypertext accessible.
+   *
+   * @param  aChild           [in] accessible child to get text offset for
+   * @param  aInvalidateAfter [in, optional] indicates whether invalidate
+   *                           cached offsets for next siblings of the child
+   */
+  PRInt32 GetChildOffset(nsAccessible* aChild,
+                         PRBool aInvalidateAfter = PR_FALSE);
+
 protected:
   // nsHyperTextAccessible
 
   /**
    * Return link collection, create it if necessary.
    */
   AccCollector* GetLinkCollector();
 
@@ -339,16 +349,24 @@ protected:
    * @param aAttributes       [out, optional] result attributes
    */
   nsresult GetSpellTextAttribute(nsIDOMNode *aNode, PRInt32 aNodeOffset,
                                  PRInt32 *aStartOffset,
                                  PRInt32 *aEndOffset,
                                  nsIPersistentProperties *aAttributes);
 
 private:
+  /**
+   * Embedded objects collector.
+   */
   nsAutoPtr<AccCollector> mLinks;
+
+  /**
+   * End text offsets array.
+   */
+  nsTArray<PRUint32> mOffsets;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsHyperTextAccessible,
                               NS_HYPERTEXTACCESSIBLE_IMPL_CID)
 
 #endif  // _nsHyperTextAccessible_H_
 
--- a/accessible/src/msaa/nsAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsAccessibleWrap.cpp
@@ -226,17 +226,17 @@ STDMETHODIMP nsAccessibleWrap::get_accPa
           NS_ASSERTION(hwnd, "No window handle for window");
         }
       }
       else {
         // If a frame is a scrollable frame, then it has one window for the client area,
         // not an extra parent window for just the scrollbars
         nsIScrollableFrame *scrollFrame = do_QueryFrame(frame);
         if (scrollFrame) {
-          hwnd = (HWND)scrollFrame->GetScrolledFrame()->GetWindow()->GetNativeData(NS_NATIVE_WINDOW);
+          hwnd = (HWND)scrollFrame->GetScrolledFrame()->GetNearestWidget()->GetNativeData(NS_NATIVE_WINDOW);
           NS_ASSERTION(hwnd, "No window handle for window");
         }
       }
     }
 
     if (hwnd && SUCCEEDED(AccessibleObjectFromWindow(hwnd, OBJID_WINDOW, IID_IAccessible,
                                               (void**)ppdispParent))) {
       return S_OK;
@@ -1676,17 +1676,17 @@ nsAccessibleWrap::FirePlatformEvent(nsAc
   if (!childID)
     return NS_OK; // Can't fire an event without a child ID
 
   // See if we're in a scrollable area with its own window
   nsAccessible *newAccessible = nsnull;
   if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
     // Don't use frame from current accessible when we're hiding that
     // accessible.
-    newAccessible = accessible->GetParent();
+    newAccessible = accessible->GetCachedParent();
   } else {
     newAccessible = accessible;
   }
 
   HWND hWnd = GetHWNDFor(newAccessible);
   NS_ENSURE_TRUE(hWnd, NS_ERROR_FAILURE);
 
   // Gecko uses two windows for every scrollable area. One window contains
@@ -1730,17 +1730,17 @@ HWND
 nsAccessibleWrap::GetHWNDFor(nsAccessible *aAccessible)
 {
   HWND hWnd = 0;
   if (!aAccessible)
     return hWnd;
 
   nsIFrame *frame = aAccessible->GetFrame();
   if (frame) {
-    nsIWidget *window = frame->GetWindow();
+    nsIWidget *window = frame->GetNearestWidget();
     PRBool isVisible;
     window->IsVisible(isVisible);
     if (isVisible) {
       // Short explanation:
       // If HWND for frame is inside a hidden window, fire the event on the
       // containing document's visible window.
       //
       // Long explanation:
@@ -1748,17 +1748,17 @@ nsAccessibleWrap::GetHWNDFor(nsAccessibl
       // worked with combo boxes because they use the value change event in
       // the closed combo box case. JAWS will only pay attention to the focus
       // events on the list items. The JAWS developers haven't fixed that, so
       // we'll use the focus events to make JAWS work. However, JAWS is
       // ignoring events on a hidden window. So, in order to fix the bug where
       // JAWS doesn't echo the current option as it changes in a closed
       // combo box, we need to use an ensure that we never fire an event with
       // an HWND for a hidden window.
-      hWnd = (HWND)frame->GetWindow()->GetNativeData(NS_NATIVE_WINDOW);
+      hWnd = (HWND)frame->GetNearestWidget()->GetNativeData(NS_NATIVE_WINDOW);
     }
   }
 
   if (!hWnd) {
     void* handle = nsnull;
     nsDocAccessible *accessibleDoc = aAccessible->GetDocAccessible();
     if (!accessibleDoc)
       return 0;
--- a/accessible/src/msaa/nsHTMLWin32ObjectAccessible.cpp
+++ b/accessible/src/msaa/nsHTMLWin32ObjectAccessible.cpp
@@ -90,20 +90,18 @@ nsHTMLWin32ObjectOwnerAccessible::GetSta
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLWin32ObjectOwnerAccessible: nsAccessible protected implementation
 
 void
 nsHTMLWin32ObjectOwnerAccessible::CacheChildren()
 {
-  if (mNativeAccessible) {
-    mChildren.AppendElement(mNativeAccessible);
-    mNativeAccessible->SetParent(this);
-  }
+  if (mNativeAccessible)
+    AppendChild(mNativeAccessible);
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLWin32ObjectAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsHTMLWin32ObjectAccessible::nsHTMLWin32ObjectAccessible(void* aHwnd):
--- a/accessible/src/xforms/nsXFormsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsAccessible.cpp
@@ -113,32 +113,34 @@ nsXFormsAccessible::CacheSelectChildren(
     container = do_QueryInterface(mContent);
 
   nsCOMPtr<nsIDOMNodeList> children;
   sXFormsService->GetSelectChildrenFor(container, getter_AddRefs(children));
 
   if (!children)
     return;
 
+  nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
+
   PRUint32 length = 0;
   children->GetLength(&length);
 
   for (PRUint32 index = 0; index < length; index++) {
     nsCOMPtr<nsIDOMNode> DOMChild;
     children->Item(index, getter_AddRefs(DOMChild));
     if (!DOMChild)
       continue;
 
     nsCOMPtr<nsIContent> child(do_QueryInterface(DOMChild));
-    nsAccessible *accessible = GetAccService()->GetAttachedAccessibleFor(child);
+    nsRefPtr<nsAccessible> accessible =
+      GetAccService()->GetOrCreateAccessible(child, presShell, mWeakShell);
     if (!accessible)
       continue;
 
-    mChildren.AppendElement(accessible);
-    accessible->SetParent(this);
+    AppendChild(accessible);
   }
 }
 
 // nsIAccessible
 
 NS_IMETHODIMP
 nsXFormsAccessible::GetValue(nsAString& aValue)
 {
--- a/accessible/src/xul/nsXULColorPickerAccessible.cpp
+++ b/accessible/src/xul/nsXULColorPickerAccessible.cpp
@@ -161,19 +161,19 @@ nsXULColorPickerAccessible::GetRoleInter
 
 void
 nsXULColorPickerAccessible::CacheChildren()
 {
   nsAccTreeWalker walker(mWeakShell, mContent, PR_TRUE);
 
   nsRefPtr<nsAccessible> child;
   while ((child = walker.GetNextChild())) {
+    // XXX: do not call nsAccessible::GetRole() while accessible not in tree
+    // (bug 574588).
     PRUint32 role = nsAccUtils::Role(child);
 
     // Get an accessbile for menupopup or panel elements.
     if (role == nsIAccessibleRole::ROLE_ALERT) {
-      mChildren.AppendElement(child);
-      child->SetParent(this);
-
+      AppendChild(child);
       return;
     }
   }
 }
--- a/accessible/src/xul/nsXULFormControlAccessible.cpp
+++ b/accessible/src/xul/nsXULFormControlAccessible.cpp
@@ -207,16 +207,18 @@ nsXULButtonAccessible::CacheChildren()
 
   nsRefPtr<nsAccessible> menupopupAccessible;
   nsRefPtr<nsAccessible> buttonAccessible;
 
   nsAccTreeWalker walker(mWeakShell, mContent, PR_TRUE);
 
   nsRefPtr<nsAccessible> child;
   while ((child = walker.GetNextChild())) {
+    // XXX: do not call nsAccessible::GetRole() while accessible not in tree
+    // (bug 574588).
     PRUint32 role = nsAccUtils::Role(child);
 
     if (role == nsIAccessibleRole::ROLE_MENUPOPUP) {
       // Get an accessbile for menupopup or panel elements.
       menupopupAccessible.swap(child);
 
     } else if (isMenuButton && role == nsIAccessibleRole::ROLE_PUSHBUTTON) {
       // Button type="menu-button" contains a real button. Get an accessible
@@ -224,23 +226,19 @@ nsXULButtonAccessible::CacheChildren()
       buttonAccessible.swap(child);
       break;
     }
   }
 
   if (!menupopupAccessible)
     return;
 
-  mChildren.AppendElement(menupopupAccessible);
-  menupopupAccessible->SetParent(this);
-
-  if (buttonAccessible) {
-    mChildren.AppendElement(buttonAccessible);
-    buttonAccessible->SetParent(this);
-  }
+  AppendChild(menupopupAccessible);
+  if (buttonAccessible)
+    AppendChild(buttonAccessible);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULButtonAccessible protected
 
 PRBool
 nsXULButtonAccessible::ContainsMenu()
 {
@@ -1055,20 +1053,17 @@ nsXULTextFieldAccessible::CacheChildren(
   // input element.
   nsCOMPtr<nsIContent> inputContent(GetInputField());
   if (!inputContent)
     return;
 
   nsAccTreeWalker walker(mWeakShell, inputContent, PR_FALSE);
 
   nsRefPtr<nsAccessible> child;
-  while ((child = walker.GetNextChild())) {
-    mChildren.AppendElement(child);
-    child->SetParent(this);
-  }
+  while ((child = walker.GetNextChild()) && AppendChild(child));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTextFieldAccessible protected
 
 already_AddRefed<nsIContent>
 nsXULTextFieldAccessible::GetInputField() const
 {
--- a/accessible/src/xul/nsXULTreeAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeAccessible.cpp
@@ -465,32 +465,16 @@ nsXULTreeAccessible::GetChildCount()
 
   PRInt32 rowCount = 0;
   mTreeView->GetRowCount(&rowCount);
   childCount += rowCount;
 
   return childCount;
 }
 
-PRInt32
-nsXULTreeAccessible::GetIndexOf(nsIAccessible *aChild)
-{
-  if (IsDefunct())
-    return -1;
-
-  nsRefPtr<nsXULTreeItemAccessibleBase> item = do_QueryObject(aChild);
-
-  // If the given child is not treeitem then it should be treecols accessible.
-  if (!item)
-    return nsAccessible::GetIndexOf(aChild);
-
-  return nsAccessible::GetChildCount() + item->GetRowIndex();
-}
-
-
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeAccessible: public implementation
 
 nsAccessible*
 nsXULTreeAccessible::GetTreeItemAccessible(PRInt32 aRow)
 {
   if (aRow < 0 || IsDefunct())
     return nsnull;
@@ -1035,22 +1019,16 @@ nsXULTreeItemAccessibleBase::GetStateInt
   mTree->GetFirstVisibleRow(&firstVisibleRow);
   mTree->GetLastVisibleRow(&lastVisibleRow);
   if (mRow < firstVisibleRow || mRow > lastVisibleRow)
     *aState |= nsIAccessibleStates::STATE_INVISIBLE;
 
   return NS_OK;
 }
 
-nsAccessible*
-nsXULTreeItemAccessibleBase::GetParent()
-{
-  return IsDefunct() ? nsnull : mParent.get();
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeItemAccessibleBase: nsAccessible protected methods
 
 void
 nsXULTreeItemAccessibleBase::DispatchClickEvent(nsIContent *aContent,
                                                 PRUint32 aActionIndex)
 {
   if (IsDefunct())
@@ -1077,39 +1055,27 @@ nsXULTreeItemAccessibleBase::DispatchCli
   if (column)
     nsCoreUtils::DispatchClickEvent(mTree, mRow, column, pseudoElm);
 }
 
 nsAccessible*
 nsXULTreeItemAccessibleBase::GetSiblingAtOffset(PRInt32 aOffset,
                                                 nsresult* aError)
 {
-  if (mRow + aOffset < 0)
-    return nsAccessible::GetSiblingAtOffset(mRow + aOffset, aError);
-
   if (IsDefunct()) {
     if (aError)
       *aError = NS_ERROR_FAILURE;
 
     return nsnull;
   }
 
   if (aError)
     *aError = NS_OK; // fail peacefully
 
-  nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(mParent);
-  if (!treeAcc)
-    return nsnull;
-
-  PRInt32 rowCount = 0;
-  mTreeView->GetRowCount(&rowCount);
-  if (mRow + aOffset >= rowCount)
-    return nsnull;
-
-  return treeAcc->GetTreeItemAccessible(mRow + aOffset);
+  return mParent->GetChildAt(GetIndexInParent() + aOffset);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeItemAccessibleBase: protected implementation
 
 PRBool
 nsXULTreeItemAccessibleBase::IsExpandable()
 {
--- a/accessible/src/xul/nsXULTreeAccessible.h
+++ b/accessible/src/xul/nsXULTreeAccessible.h
@@ -86,17 +86,16 @@ public:
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
   virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY,
                                    PRBool aDeepestChild,
                                    nsIAccessible **aChild);
 
   virtual nsAccessible* GetChildAt(PRUint32 aIndex);
   virtual PRInt32 GetChildCount();
-  virtual PRInt32 GetIndexOf(nsIAccessible *aChild);
 
   // nsXULTreeAccessible
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_XULTREEACCESSIBLE_IMPL_CID)
 
   /**
    * Return tree item accessible at the givem row. If accessible doesn't exist
    * in the cache then create and cache it.
@@ -194,17 +193,18 @@ public:
   NS_IMETHOD DoAction(PRUint8 aIndex);
 
   // nsAccessNode
   virtual PRBool IsDefunct();
   virtual void Shutdown();
 
   // nsAccessible
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
-  virtual nsAccessible* GetParent();
+  virtual PRInt32 GetIndexInParent()
+    { return mParent ? mParent->GetCachedChildCount() + mRow : -1; }
 
   // nsXULTreeItemAccessibleBase
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_XULTREEITEMBASEACCESSIBLE_IMPL_CID)
 
   /**
    * Return row index associated with the accessible.
    */
   PRInt32 GetRowIndex() const { return mRow; }
--- a/accessible/src/xul/nsXULTreeGridAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeGridAccessible.cpp
@@ -693,27 +693,16 @@ PRInt32
 nsXULTreeGridRowAccessible::GetChildCount()
 {
   if (IsDefunct())
     return -1;
 
   return nsCoreUtils::GetSensibleColumnCount(mTree);
 }
 
-PRInt32
-nsXULTreeGridRowAccessible::GetIndexOf(nsIAccessible *aChild)
-{
-  if (IsDefunct())
-    return -1;
-
-  nsRefPtr<nsXULTreeGridCellAccessible> cell = do_QueryObject(aChild);
-
-  return cell ? cell->GetColumnIndex() : -1;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeGridRowAccessible: nsXULTreeItemAccessibleBase implementation
 
 nsAccessible*
 nsXULTreeGridRowAccessible::GetCellAccessible(nsITreeColumn* aColumn)
 {
   NS_PRECONDITION(aColumn, "No tree column!");
 
@@ -1197,22 +1186,16 @@ nsXULTreeGridCellAccessible::GetStateInt
     mTreeView->GetCellValue(mRow, mColumn, checked);
     if (checked.EqualsIgnoreCase("true"))
       *aStates |= nsIAccessibleStates::STATE_CHECKED;
   }
 
   return NS_OK;
 }
 
-nsAccessible*
-nsXULTreeGridCellAccessible::GetParent()
-{
-  return IsDefunct() ? nsnull : mParent.get();
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeGridCellAccessible: public implementation
 
 PRInt32
 nsXULTreeGridCellAccessible::GetColumnIndex() const
 {
   PRInt32 index = 0;
   nsCOMPtr<nsITreeColumn> column = mColumn;
--- a/accessible/src/xul/nsXULTreeGridAccessible.h
+++ b/accessible/src/xul/nsXULTreeGridAccessible.h
@@ -90,17 +90,16 @@ public:
   // nsAccessible
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY,
                                    PRBool aDeepestChild,
                                    nsIAccessible **aChild);
 
   virtual nsAccessible* GetChildAt(PRUint32 aIndex);
   virtual PRInt32 GetChildCount();
-  virtual PRInt32 GetIndexOf(nsIAccessible *aChild);
 
   // nsXULTreeItemAccessibleBase
   virtual nsAccessible* GetCellAccessible(nsITreeColumn *aColumn);
   virtual void RowInvalidated(PRInt32 aStartColIdx, PRInt32 aEndColIdx);
 
 protected:
 
   // nsAccessible
@@ -156,18 +155,17 @@ public:
   // nsAccessNode
   virtual PRBool IsDefunct();
   virtual PRBool Init();
 
   // nsAccessible
   virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
-
-  virtual nsAccessible* GetParent();
+  virtual PRInt32 GetIndexInParent() { return GetColumnIndex(); }
 
   // nsXULTreeGridCellAccessible
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_XULTREEGRIDCELLACCESSIBLE_IMPL_CID)
 
   /**
    * Return index of the column.
    */
   PRInt32 GetColumnIndex() const;
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -91,16 +91,18 @@ const EXT_STATE_VERTICAL = nsIAccessible
 const MAC = (navigator.platform.indexOf("Mac") != -1)? true : false;
 const LINUX = (navigator.platform.indexOf("Linux") != -1)? true : false;
 const SOLARIS = (navigator.platform.indexOf("SunOS") != -1)? true : false;
 const WIN = (navigator.platform.indexOf("Win") != -1)? true : false;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Accessible general
 
+const kEmbedChar = String.fromCharCode(0xfffc);
+
 /**
  * nsIAccessibleRetrieval, initialized when test is loaded.
  */
 var gAccRetrieval = null;
 
 /**
  * Invokes the given function when document is loaded and focused. Preferable
  * to mochitests 'addLoadEvent' function -- additionally ensures state of the
--- a/accessible/tests/mochitest/events.js
+++ b/accessible/tests/mochitest/events.js
@@ -9,16 +9,17 @@ const EVENT_FOCUS = nsIAccessibleEvent.E
 const EVENT_NAME_CHANGE = nsIAccessibleEvent.EVENT_NAME_CHANGE;
 const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER;
 const EVENT_SCROLLING_START = nsIAccessibleEvent.EVENT_SCROLLING_START;
 const EVENT_SELECTION_ADD = nsIAccessibleEvent.EVENT_SELECTION_ADD;
 const EVENT_SELECTION_WITHIN = nsIAccessibleEvent.EVENT_SELECTION_WITHIN;
 const EVENT_SHOW = nsIAccessibleEvent.EVENT_SHOW;
 const EVENT_STATE_CHANGE = nsIAccessibleEvent.EVENT_STATE_CHANGE;
 const EVENT_TEXT_CARET_MOVED = nsIAccessibleEvent.EVENT_TEXT_CARET_MOVED;
+const EVENT_TEXT_INSERTED = nsIAccessibleEvent.EVENT_TEXT_INSERTED;
 const EVENT_TEXT_REMOVED = nsIAccessibleEvent.EVENT_TEXT_REMOVED;
 const EVENT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_VALUE_CHANGE;
 
 ////////////////////////////////////////////////////////////////////////////////
 // General
 
 /**
  * Set up this variable to dump events into DOM.
@@ -901,16 +902,23 @@ var gA11yEventObserver =
 
       var parent = target;
       while (parent && parent != dumpElm)
         parent = parent.parentNode;
 
       if (parent != dumpElm) {
         var type = eventTypeToString(event.eventType);
         var info = "Event type: " + type;
+
+        if (event instanceof nsIAccessibleTextChangeEvent) {
+          info += ", start: " + event.start + ", length: " + event.length +
+            ", " + (event.isInserted() ? "inserted" : "removed") +
+            " text: " + event.modifiedText;
+        }
+
         info += ". Target: " + prettyName(event.accessible);
 
         if (listenersArray)
           info += ". Listeners count: " + listenersArray.length;
 
         eventFromDumpArea = false;
         dumpInfoToDOM(info);
       }
--- a/accessible/tests/mochitest/events/test_docload.html
+++ b/accessible/tests/mochitest/events/test_docload.html
@@ -122,16 +122,21 @@
     {
       // Get application root accessible.
       var docAcc = getAccessible(document);
       while (docAcc) {
         this.mRootAcc = docAcc;
         try {
           docAcc = docAcc.parent;
         } catch (e) {
+          // XXX: it may randomaly fail on propertypage accessible of browser's
+          // tabbbrowser if nsIAccessible::parent returns cached parent only.
+          // This should gone after bug 572951.
+          // Error: failed | Can't get parent for [ 'panel1277435313424' ,
+          // role: propertypage]
           ok(false, "Can't get parent for " + prettyName(docAcc));
           throw e;
         }
       }
 
       this.eventSeq = [
         new invokerChecker(EVENT_REORDER, this.mRootAcc)
       ];
--- a/accessible/tests/mochitest/events/test_text.html
+++ b/accessible/tests/mochitest/events/test_text.html
@@ -20,88 +20,174 @@
 
   <script type="application/javascript">
     ////////////////////////////////////////////////////////////////////////////
     // Invokers
 
     /**
      * Base text remove invoker and checker.
      */
-    function textRemoveChecker(aID, aStart, aEnd, aText)
+    function textChangeChecker(aID, aStart, aEnd, aText, aIsInserted)
     {
       this.target = getNode(aID);
-      this.type = EVENT_TEXT_REMOVED;
+      this.type = aIsInserted ? EVENT_TEXT_INSERTED : EVENT_TEXT_REMOVED;
 
       this.check = function textRemoveChecker_check(aEvent)
       {
         aEvent.QueryInterface(nsIAccessibleTextChangeEvent);
         is(aEvent.start, aStart, "Wrong start offset for " + prettyName(aID));
-        is(aEvent.length, aEnd - aStart, "Wrong length for" + prettyName(aID));
-        is(aEvent.isInserted(), false,
-           "Text was removed for " + prettyName(aID));
+        is(aEvent.length, aEnd - aStart, "Wrong length for " + prettyName(aID));
+        var changeInfo = (aIsInserted ? "inserted" : "removed");
+        is(aEvent.isInserted(), aIsInserted,
+           "Text was " + changeInfo + " for " + prettyName(aID));
         is(aEvent.modifiedText, aText,
-           "Wrong removed text " + prettyName(aID));
+           "Wrong " + changeInfo + " text for " + prettyName(aID));
       }
     }
 
     function textRemoveInvoker(aID, aStart, aEnd, aText)
     {
       this.DOMNode = getNode(aID);
 
       this.eventSeq = [
-        new textRemoveChecker(aID, aStart, aEnd, aText)
+        new textChangeChecker(aID, aStart, aEnd, aText, false)
+      ];
+    }
+
+    function textInsertInvoker(aID, aStart, aEnd, aText)
+    {
+      this.DOMNode = getNode(aID);
+
+      this.eventSeq = [
+        new textChangeChecker(aID, aStart, aEnd, aText, true)
       ];
     }
 
     /**
-     * Remove inaccessible child node containing text accessibles.
+     * Remove inaccessible child node containing accessibles.
      */
     function removeChildSpan(aID)
     {
       this.__proto__ = new textRemoveInvoker(aID, 0, 5, "33322");
 
       this.invoke = function removeChildSpan_invoke()
       {
         // remove HTML span, a first child of the node
+        ensureAccessibleTree(this.DOMNode);
         this.DOMNode.removeChild(this.DOMNode.firstChild);
       }
 
       this.getID = function removeChildSpan_getID()
       {
         return "Remove inaccessible span containing accessible nodes" + prettyName(aID);
       }
     }
 
     /**
+     * Insert inaccessible child node containing accessibles.
+     */
+    function insertChildSpan(aID)
+    {
+      this.__proto__ = new textInsertInvoker(aID, 0, 5, "33322");
+
+      this.invoke = function insertChildSpan_invoke()
+      {
+        // <span><span>333</span><span>22</span></span>
+        var topSpan = document.createElement("span");
+        var fSpan = document.createElement("span");
+        fSpan.textContent = "333";
+        topSpan.appendChild(fSpan);
+        var sSpan = document.createElement("span");
+        sSpan.textContent = "22";
+        topSpan.appendChild(sSpan);
+
+        this.DOMNode.insertBefore(topSpan, this.DOMNode.childNodes[0]);
+      }
+
+      this.getID = function insertChildSpan_getID()
+      {
+       return "Insert inaccessible span containing accessibles" +
+          prettyName(aID);
+      }
+    }
+
+    /**
      * Remove child embedded accessible.
      */
-    function removeChildDiv(aID, aChildId)
+    function removeChildDiv(aID)
     {
-      this.__proto__ = new textRemoveInvoker(aID, 5, 6,
-                                             String.fromCharCode(0xfffc));
+      this.__proto__ = new textRemoveInvoker(aID, 5, 6, kEmbedChar);
 
       this.invoke = function removeChildDiv_invoke()
       {
-        var childDiv = this.DOMNode.childNodes[aChildId];
+        var childDiv = this.DOMNode.childNodes[1];
 
         // Ensure accessible is created to get text remove event when it's
         // removed.
         getAccessible(childDiv);
 
         this.DOMNode.removeChild(childDiv);
       }
 
       this.getID = function removeChildDiv_getID()
       {
         return "Remove accessible div from the middle of text accessible " +
           prettyName(aID);
       }
     }
 
     /**
+     * Insert child embedded accessible.
+     */
+    function insertChildDiv(aID)
+    {
+      this.__proto__ = new textInsertInvoker(aID, 5, 6, kEmbedChar);
+
+      this.invoke = function insertChildDiv_invoke()
+      {
+        var childDiv = document.createElement("div");
+        this.DOMNode.insertBefore(childDiv, this.DOMNode.childNodes[1]);
+      }
+
+      this.getID = function insertChildDiv_getID()
+      {
+        return "Insert accessible div into the middle of text accessible " +
+          prettyName(aID);
+      }
+    }
+
+    /**
+     * Remove children from text container from first to last child or vice
+     * versa.
+     */
+    function removeChildren(aID, aLastToFirst, aStart, aEnd, aText)
+    {
+      this.__proto__ = new textRemoveInvoker(aID, aStart, aEnd, aText);
+
+      this.invoke = function removeChildren_invoke()
+      {
+        ensureAccessibleTree(this.DOMNode);
+
+        if (aLastToFirst) {
+          while (this.DOMNode.firstChild)
+            this.DOMNode.removeChild(this.DOMNode.lastChild);
+        } else {
+          while (this.DOMNode.firstChild)
+            this.DOMNode.removeChild(this.DOMNode.firstChild);
+        }
+      }
+
+      this.getID = function removeChildren_getID()
+      {
+        return "remove children of " + prettyName(aID) +
+          (aLastToFirst ? " from last to first" : " from first to last");
+      }
+    }
+
+    /**
      * Remove text from HTML input.
      */
     function removeTextFromInput(aID, aStart, aEnd, aText)
     {
       this.__proto__ = new textRemoveInvoker(aID, aStart, aEnd, aText);
 
       this.eventSeq.push(new invokerChecker(EVENT_VALUE_CHANGE, this.DOMNode));
 
@@ -119,16 +205,37 @@
       this.getID = function removeTextFromInput_getID()
       {
         return "Remove text from " + aStart + " to " + aEnd + " for " +
           prettyName(aID);
       }
     }
 
     /**
+     * Add text into HTML input.
+     */
+    function insertTextIntoInput(aID, aStart, aEnd, aText)
+    {
+      this.__proto__ = new textInsertInvoker(aID, aStart, aEnd, aText);
+
+      this.eventSeq.push(new invokerChecker(EVENT_VALUE_CHANGE, this.DOMNode));
+
+      this.invoke = function insertTextIntoInput_invoke()
+      {
+        this.DOMNode.focus();
+        synthesizeKey("a", {});
+      }
+
+      this.getID = function insertTextIntoInput_getID()
+      {
+        return "Insert text to " + aStart + " for " + prettyName(aID);
+      }
+    }
+
+    /**
      * Remove text data from text node of editable area.
      */
     function removeTextFromEditable(aID, aStart, aEnd, aText, aTextNode)
     {
       this.__proto__ = new textRemoveInvoker(aID, aStart, aEnd, aText);
 
       this.invoke = function removeTextFromEditable_invoke()
       {
@@ -150,31 +257,39 @@
       }
 
       this.textNode = getNode(aTextNode);
     }
 
     ////////////////////////////////////////////////////////////////////////////
     // Do tests
     var gQueue = null;
-    // gA11yEventDumpID = "eventdump"; // debug stuff
+    //gA11yEventDumpID = "eventdump"; // debug stuff
 
     function doTests()
     {
       gQueue = new eventQueue();
 
       // Text remove event on inaccessible child HTML span removal containing
       // accessible text nodes.
       gQueue.push(new removeChildSpan("p"));
+      gQueue.push(new insertChildSpan("p"));
 
       // Remove embedded character.
-      gQueue.push(new removeChildDiv("div", 1));
+      gQueue.push(new removeChildDiv("div"));
+      gQueue.push(new insertChildDiv("div"));
+
+      // Remove all children.
+      var text = kEmbedChar + "txt" + kEmbedChar;
+      gQueue.push(new removeChildren("div2", true, 0, 5, text));
+      gQueue.push(new removeChildren("div3", false, 0, 5, text));
 
       // Text remove from text node within hypertext accessible.
       gQueue.push(new removeTextFromInput("input", 1, 3, "al"));
+      gQueue.push(new insertTextIntoInput("input", 1, 2, "a"));
 
       // bug 570691
       todo(false, "Fix text change events from editable area, see bug 570691");
       //var textNode = getNode("editable").firstChild;
       //gQueue.push(new removeTextFromEditable("editable", 1, 3, "al", textNode));
       //textNode = getNode("editable2").firstChild.firstChild;
       //gQueue.push(new removeTextFromEditable("editable2", 1, 3, "al", textNode));
 
@@ -187,28 +302,40 @@
 </head>
 
 <body>
 
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=566293"
      title=" wrong length of text remove event when inaccessible node containing accessible nodes is removed">
     Mozilla Bug 566293
-  </a>
+  </a><br>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=570710"
      title="Avoid extra array traversal during text event creation">
     Mozilla Bug 570710
+  </a><br>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=574003"
+     title="Coalesce text events on nodes removal">
+    Mozilla Bug 574003
+  </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=575052"
+     title="Cache text offsets within hypertext accessible">
+    Mozilla Bug 575052
   </a>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
   <div id="eventdump"></div>
 
   <p id="p"><span><span>333</span><span>22</span></span>1111</p>
   <div id="div">hello<div>hello</div>hello</div>
+  <div id="div2"><div>txt</div>txt<div>txt</div></div>
+  <div id="div3"><div>txt</div>txt<div>txt</div></div>
   <input id="input" value="value">
   <div contentEditable="true" id="editable">value</div>
   <div contentEditable="true" id="editable2"><span>value</span></div>
 </body>
 </html>
--- a/browser/app/profile/extensions/testpilot@labs.mozilla.com/modules/setup.js
+++ b/browser/app/profile/extensions/testpilot@labs.mozilla.com/modules/setup.js
@@ -57,17 +57,17 @@ const POPUP_REMINDER_INTERVAL = "extensi
 const ALWAYS_SUBMIT_DATA = "extensions.testpilot.alwaysSubmitData";
 const LOG_FILE_NAME = "TestPilotErrorLog.log";
 
 let TestPilotSetup = {
   didReminderAfterStartup: false,
   startupComplete: false,
   _shortTimer: null,
   _longTimer: null,
-  _remoteExperimentLoader: null,
+  _remoteExperimentLoader: null, // TODO make this a lazy initializer too?
   taskList: [],
   version: "",
 
   // Lazy initializers:
   __application: null,
   get _application() {
     if (this.__application == null) {
       this.__application = Cc["@mozilla.org/fuel/application;1"]
@@ -367,20 +367,26 @@ let TestPilotSetup = {
     // exists.  No excuse to ever be running two copies of the same task.
     this.taskList.push(testPilotTask);
   },
 
   _showNotification: function TPS__showNotification(task, fragile, text, title,
                                                     iconClass, showSubmit,
 						    showAlwaysSubmitCheckbox,
                                                     linkText, linkUrl,
-						    isExtensionUpdate) {
+						    isExtensionUpdate,
+                                                    onCloseCallback) {
+    /* TODO: Refactor the arguments of this function, it's getting really
+     * unweildly.... maybe pass in an object, or even make a notification an
+     * object that you create and then call .show() on. */
+
     // If there are multiple windows, show notifications in the frontmost
     // window.
-    let doc = this._getFrontBrowserWindow().document;
+    let window = this._getFrontBrowserWindow();
+    let doc = window.document;
     let popup = doc.getElementById("pilot-notification-popup");
 
     let anchor;
     if (this._isFfx4BetaVersion()) {
       /* If we're in the Ffx4Beta version, popups come down from feedback
        * button, but if we're in the standalone extension version, they
        * come up from status bar icon. */
       anchor = doc.getElementById("feedback-menu-button");
@@ -417,24 +423,24 @@ let TestPilotSetup = {
     alwaysSubmitCheckbox.setAttribute("hidden", !showAlwaysSubmitCheckbox);
     if (showSubmit) {
       if (isExtensionUpdate) {
         submitBtn.setAttribute("label",
 	  this._stringBundle.GetStringFromName(
 	    "testpilot.notification.update"));
 	submitBtn.onclick = function() {
           this._extensionUpdater.check(EXTENSION_ID);
-          self._hideNotification();
+          self._hideNotification(window, onCloseCallback);
 	};
       } else {
         submitBtn.setAttribute("label",
 	  this._stringBundle.GetStringFromName("testpilot.submit"));
         // Functionality for submit button:
         submitBtn.onclick = function() {
-          self._hideNotification();
+          self._hideNotification(window, onCloseCallback);
           if (showAlwaysSubmitCheckbox && alwaysSubmitCheckbox.checked) {
             self._prefs.setValue(ALWAYS_SUBMIT_DATA, true);
           }
           task.upload( function(success) {
             if (success) {
               self._showNotification(
 		task, true,
                 self._stringBundle.GetStringFromName(
@@ -459,46 +465,52 @@ let TestPilotSetup = {
       link.setAttribute("class", "notification-link");
       link.onclick = function(event) {
         if (event.button == 0) {
 	  if (task) {
             task.loadPage();
 	  } else {
             self._openChromeless(linkUrl);
 	  }
-          self._hideNotification();
+          self._hideNotification(window, onCloseCallback);
         }
       };
       link.setAttribute("hidden", false);
     } else {
       link.setAttribute("hidden", true);
     }
 
     closeBtn.onclick = function() {
-      self._hideNotification();
+      self._hideNotification(window, onCloseCallback);
     };
 
     // Show the popup:
     popup.hidden = false;
     popup.setAttribute("open", "true");
     popup.openPopup( anchor, "after_end");
   },
 
   _openChromeless: function TPS__openChromeless(url) {
     let window = this._getFrontBrowserWindow();
     window.TestPilotWindowUtils.openChromeless(url);
   },
 
-  _hideNotification: function TPS__hideNotification() {
-    let window = this._getFrontBrowserWindow();
+  _hideNotification: function TPS__hideNotification(window, onCloseCallback) {
+    /* Note - we take window as an argument instead of just using the frontmost
+     * window because the window order might have changed since the notification
+     * appeared and we want to be sure we close the notification in the same
+     * window as we opened it in! */
     let popup = window.document.getElementById("pilot-notification-popup");
     popup.hidden = true;
     popup.setAttribute("open", "false");
     popup.removeAttribute("tpisextensionupdate");
     popup.hidePopup();
+    if (onCloseCallback) {
+      onCloseCallback();
+    }
   },
 
   _isShowingUpdateNotification : function() {
     let window = this._getFrontBrowserWindow();
     let popup = window.document.getElementById("pilot-notification-popup");
 
     return popup.hasAttribute("tpisextensionupdate");
   },
@@ -538,36 +550,38 @@ let TestPilotSetup = {
       }
     }
 
     // If there's no finished test, next highest priority is new tests that
     // are starting...
     if (this._prefs.getValue(POPUP_SHOW_ON_NEW, false)) {
       for (i = 0; i < this.taskList.length; i++) {
         task = this.taskList[i];
-        if (task.status == TaskConstants.STATUS_STARTING ||
+        if (task.status == TaskConstants.STATUS_PENDING ||
             task.status == TaskConstants.STATUS_NEW) {
           if (task.taskType == TaskConstants.TYPE_EXPERIMENT) {
 	    this._showNotification(
-	      task, true,
+	      task, false,
 	      this._stringBundle.formatStringFromName(
 		"testpilot.notification.newTestPilotStudy.message",
 		[task.title], 1),
 	      this._stringBundle.GetStringFromName(
 		"testpilot.notification.newTestPilotStudy"),
 	      "new-study", false, false,
 	      this._stringBundle.GetStringFromName("testpilot.moreInfo"),
-	      task.defaultUrl);
-            // Having shown the notification, update task status so that this
-            // notification won't be shown again.
-            task.changeStatus(TaskConstants.STATUS_IN_PROGRESS, true);
+	      task.defaultUrl, false, function() {
+                /* on close callback (Bug 575767) -- when the "new study
+                 * starting" popup is dismissed, then the study can start. */
+                task.changeStatus(TaskConstants.STATUS_IN_PROGRESS, true);
+                TestPilotSetup.reloadRemoteExperiments();
+              });
             return;
           } else if (task.taskType == TaskConstants.TYPE_SURVEY) {
 	    this._showNotification(
-	      task, true,
+	      task, false,
 	      this._stringBundle.formatStringFromName(
 		"testpilot.notification.newTestPilotSurvey.message",
 		[task.title], 1),
               this._stringBundle.GetStringFromName(
 		"testpilot.notification.newTestPilotSurvey"),
 	      "new-study", false, false,
 	      this._stringBundle.GetStringFromName("testpilot.moreInfo"),
 	      task.defaultUrl);
--- a/browser/app/profile/extensions/testpilot@labs.mozilla.com/modules/tasks.js
+++ b/browser/app/profile/extensions/testpilot@labs.mozilla.com/modules/tasks.js
@@ -198,16 +198,17 @@ var TestPilotTask = {
 
   onWindowClosed: function TestPilotTask_onWindowClosed(window) {
   },
 
   onUrlLoad: function TestPilotTask_onUrlLoad(url) {
   },
 
   onDetailPageOpened: function TestPilotTask_onDetailPageOpened(){
+    // TODO fold this into loadPage()?
   },
 
   checkDate: function TestPilotTask_checkDate() {
   },
 
   changeStatus: function TPS_changeStatus(newStatus, suppressNotification) {
     // TODO we always suppress notifications except when new status is
     // "finished"; maybe remove that argument and only fire notification
@@ -439,24 +440,19 @@ TestPilotExperiment.prototype = {
       break;
     }
     if (!waitForData) {
       callback(content);
     }
   },
 
   experimentIsRunning: function TestPilotExperiment_isRunning() {
-    if (this._optInRequired) {
-      return (this._status == TaskConstants.STATUS_STARTING ||
-              this._status == TaskConstants.STATUS_IN_PROGRESS);
-    } else {
-      // Tests that don't require extra opt-in should start running even
-      // if you haven't seen them yet.
-      return (this._status < TaskConstants.STATUS_FINISHED);
-    }
+    // bug 575767
+    return (this._status == TaskConstants.STATUS_STARTING ||
+            this._status == TaskConstants.STATUS_IN_PROGRESS);
   },
 
   // Pass events along to handlers:
   onNewWindow: function TestPilotExperiment_onNewWindow(window) {
     this._logger.trace("Experiment.onNewWindow called.");
     if (this.experimentIsRunning()) {
       this._handlers.onNewWindow(window);
     }
@@ -594,21 +590,33 @@ TestPilotExperiment.prototype = {
         numTimesRun++;
         this._logger.trace("Test recurring... incrementing " + RECUR_TIMES_PREF_PREFIX + this._id + " to " + numTimesRun);
         Application.prefs.setValue( RECUR_TIMES_PREF_PREFIX + this._id,
                                     numTimesRun );
         this._logger.trace("Incremented it.");
       }
     }
 
-    // No-opt-in required tests skip PENDING and go straight to STARTING.
+    // If the notify-on-new-study pref is turned off, and the test doesn't
+    // require opt-in, then it can jump straight ahead to STARTING.
     if (!this._optInRequired &&
-        this._status < TaskConstants.STATUS_STARTING &&
+        !Application.prefs.getValue("extensions.testpilot.popup.showOnNewStudy",
+                                    false) &&
+        (this._status == TaskConstants.STATUS_NEW ||
+         this._status == TaskConstants.STATUS_PENDING)) {
+      this._logger.info("Skipping pending and going straight to starting.");
+      this.changeStatus(TaskConstants.STATUS_STARTING, true);
+    }
+
+    // If a study is STARTING, and we're in the right date range,
+    // then start it, and move it to IN_PROGRESS.
+    if ( this._status == TaskConstants.STATUS_STARTING &&
         currentDate >= this._startDate &&
         currentDate <= this._endDate) {
+      this._logger.info("Study now starting.");
       let uuidGenerator =
         Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
       let uuid = uuidGenerator.generateUUID().toString();
       // remove the brackets from the generated UUID
       if (uuid.indexOf("{") == 0) {
         uuid = uuid.substring(1, (uuid.length - 1));
       }
       // clear the data before starting.
--- a/browser/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf.in
+++ b/browser/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf.in
@@ -18,26 +18,19 @@
         <em:maxVersion>@FIREFOX_VERSION@</em:maxVersion>
       </Description>
     </em:targetApplication>
 
     <!-- Front End MetaData -->
     <em:name>Default</em:name>
     <em:description>The default theme.</em:description>
 
-    <!-- EXTENSION AUTHORS!
-         DO NOT COPY THIS PROPERTY INTO YOUR INSTALL RDF FILES
-         It will cause users not to be informed of incompatibilities 
-         with your extension when they are updated with Software Update
-         and your extension will become unavailable to them!
-         -->
-    <em:appManaged>true</em:appManaged>
-
-    <em:locked>true</em:locked>
-
     <!-- Front End Integration Hooks (used by Theme Manager)-->
     <em:creator>Mozilla</em:creator>
     <em:contributor>Mozilla Contributors</em:contributor>
 
+    <!-- Allow lightweight themes to apply to this theme -->
+    <em:skinnable>true</em:skinnable>
+
     <em:internalName>classic/1.0</em:internalName>
   </Description>      
 
 </RDF>
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -247,26 +247,22 @@ window[chromehidden~="toolbar"] toolbar:
 #identity-popup-content-box.unknownIdentity > #identity-popup-content-host ,
 #identity-popup-content-box.unknownIdentity > #identity-popup-content-owner ,
 #identity-popup-content-box.verifiedIdentity > #identity-popup-connectedToLabel2 ,
 #identity-popup-content-box.verifiedDomain > #identity-popup-connectedToLabel2 {
   display: none;
 }
 
 /*  Full Screen UI */
+
 #fullscr-toggler {
-  display: none;
-  min-height: 1px;
   height: 1px;
   background: black;
-  border-style: none;
-  -moz-appearance: none;
 }
 
-#navigator-toolbox[inFullscreen="true"] > #fullscr-toggler,
 #nav-bar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-icon {
   display: -moz-box;
 }
 
 #nav-bar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-text {
   display: none;
 }
 
@@ -322,11 +318,12 @@ window[chromehidden~="toolbar"] toolbar:
 }
 
 /* notification anchors should only be visible when their associated
    notifications are */
 .notification-anchor-icon {
   display: none;
 }
 
-#notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon {
+#notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon,
+#notification-popup-box[anchorid="addons-notification-icon"] > #addons-notification-icon {
   display: -moz-box;
 }
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -125,16 +125,25 @@ XPCOMUtils.defineLazyGetter(window, "gFi
   return findbar;
 });
 
 __defineGetter__("gPrefService", function() {
   delete this.gPrefService;
   return this.gPrefService = Services.prefs;
 });
 
+__defineGetter__("AddonManager", function() {
+  Cu.import("resource://gre/modules/AddonManager.jsm");
+  return this.AddonManager;
+});
+__defineSetter__("AddonManager", function (val) {
+  delete this.AddonManager;
+  return this.AddonManager = val;
+});
+
 __defineGetter__("PluralForm", function() {
   Cu.import("resource://gre/modules/PluralForm.jsm");
   return this.PluralForm;
 });
 __defineSetter__("PluralForm", function (val) {
   delete this.PluralForm;
   return this.PluralForm = val;
 });
@@ -618,79 +627,152 @@ const gXPInstallObserver = {
         return browser;
     }
     return null;
   },
 
   observe: function (aSubject, aTopic, aData)
   {
     var brandBundle = document.getElementById("bundle_brand");
+    var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo);
+    var win = installInfo.originatingWindow;
+    var shell = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                   .getInterface(Components.interfaces.nsIWebNavigation)
+                   .QueryInterface(Components.interfaces.nsIDocShell);
+    var browser = this._getBrowser(shell);
+    if (!browser)
+      return;
+    const anchorID = "addons-notification-icon";
+    var messageString, action;
+    var brandShortName = brandBundle.getString("brandShortName");
+    var host = installInfo.originatingURI ? installInfo.originatingURI.host : browser.currentURI.host;
+
+    var notificationID = aTopic;
+
     switch (aTopic) {
     case "addon-install-blocked":
-      var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo);
-      var win = installInfo.originatingWindow;
-      var shell = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                     .getInterface(Components.interfaces.nsIWebNavigation)
-                     .QueryInterface(Components.interfaces.nsIDocShell);
-      var browser = this._getBrowser(shell);
-      if (browser) {
-        var host = installInfo.originatingURI.host;
-        var brandShortName = brandBundle.getString("brandShortName");
-        var notificationName, messageString, buttons;
-        var enabled = true;
-        try {
-          enabled = gPrefService.getBoolPref("xpinstall.enabled");
-        }
-        catch (e) {
-        }
-        if (!enabled) {
-          notificationName = "xpinstall-disabled"
-          if (gPrefService.prefIsLocked("xpinstall.enabled")) {
-            messageString = gNavigatorBundle.getString("xpinstallDisabledMessageLocked");
-            buttons = [];
-          }
-          else {
-            messageString = gNavigatorBundle.getFormattedString("xpinstallDisabledMessage",
-                                                                [brandShortName, host]);
-
-            buttons = [{
-              label: gNavigatorBundle.getString("xpinstallDisabledButton"),
-              accessKey: gNavigatorBundle.getString("xpinstallDisabledButton.accesskey"),
-              popup: null,
-              callback: function editPrefs() {
-                gPrefService.setBoolPref("xpinstall.enabled", true);
-                return false;
-              }
-            }];
-          }
+      var enabled = true;
+      try {
+        enabled = gPrefService.getBoolPref("xpinstall.enabled");
+      }
+      catch (e) {
+      }
+
+      if (!enabled) {
+        notificationID = "xpinstall-disabled"
+        if (PopupNotifications.getNotification(notificationID, browser))
+          return;
+
+        if (gPrefService.prefIsLocked("xpinstall.enabled")) {
+          messageString = gNavigatorBundle.getString("xpinstallDisabledMessageLocked");
+          buttons = [];
         }
         else {
-          notificationName = "xpinstall"
-          messageString = gNavigatorBundle.getFormattedString("xpinstallPromptWarning",
+          messageString = gNavigatorBundle.getFormattedString("xpinstallDisabledMessage",
                                                               [brandShortName, host]);
 
-          buttons = [{
-            label: gNavigatorBundle.getString("xpinstallPromptAllowButton"),
-            accessKey: gNavigatorBundle.getString("xpinstallPromptAllowButton.accesskey"),
-            popup: null,
-            callback: function() {
-              installInfo.install();
-              return false;
+          action = {
+            label: gNavigatorBundle.getString("xpinstallDisabledButton"),
+            accessKey: gNavigatorBundle.getString("xpinstallDisabledButton.accesskey"),
+            callback: function editPrefs() {
+              gPrefService.setBoolPref("xpinstall.enabled", true);
             }
-          }];
-        }
-
-        var notificationBox = gBrowser.getNotificationBox(browser);
-        if (!notificationBox.getNotificationWithValue(notificationName)) {
-          const priority = notificationBox.PRIORITY_WARNING_MEDIUM;
-          const iconURL = "chrome://mozapps/skin/update/update.png";
-          notificationBox.appendNotification(messageString, notificationName,
-                                             iconURL, priority, buttons);
+          };
         }
       }
+      else {
+        if (PopupNotifications.getNotification(notificationID, browser))
+          return;
+
+        messageString = gNavigatorBundle.getFormattedString("xpinstallPromptWarning",
+                                                            [brandShortName, host]);
+
+        action = {
+          label: gNavigatorBundle.getString("xpinstallPromptAllowButton"),
+          accessKey: gNavigatorBundle.getString("xpinstallPromptAllowButton.accesskey"),
+          callback: function() {
+            installInfo.install();
+          }
+        };
+      }
+
+      PopupNotifications.show(browser, notificationID, messageString, anchorID,
+                              action);
+      break;
+    case "addon-install-failed":
+      // TODO This isn't terribly ideal for the multiple failure case
+      installInfo.installs.forEach(function(aInstall) {
+        var error = "addonError";
+        if (aInstall.error != 0)
+          error += aInstall.error;
+        else if (aInstall.addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
+          error += "Blocklisted";
+        else
+          error += "Incompatible";
+
+        messageString = gNavigatorBundle.getString(error);
+        messageString = messageString.replace("#1", aInstall.name);
+        messageString = messageString.replace("#2", host);
+        messageString = messageString.replace("#3", brandShortName);
+        messageString = messageString.replace("#4", Services.appinfo.version);
+
+        PopupNotifications.show(browser, notificationID, messageString, anchorID,
+                                action);
+      });
+      break;
+    case "addon-install-complete":
+      var notification = PopupNotifications.getNotification(notificationID, browser);
+      if (notification)
+        PopupNotifications.remove(notification);
+
+      var needsRestart = installInfo.installs.some(function(i) {
+        return (i.addon.pendingOperations & AddonManager.PENDING_INSTALL) != 0;
+      });
+
+      if (needsRestart) {
+        messageString = gNavigatorBundle.getString("addonsInstalledNeedsRestart");
+        action = {
+          label: gNavigatorBundle.getString("addonInstallRestartButton"),
+          accessKey: gNavigatorBundle.getString("addonInstallRestartButton.accesskey"),
+          callback: function() {
+            Application.restart();
+          }
+        };
+      }
+      else {
+        messageString = gNavigatorBundle.getString("addonsInstalled");
+        action = {
+          label: gNavigatorBundle.getString("addonInstallManage"),
+          accessKey: gNavigatorBundle.getString("addonInstallManage.accesskey"),
+          callback: function() {
+            // Calculate the add-on type that is most popular in the list of
+            // installs
+            var types = {};
+            var bestType = null;
+            installInfo.installs.forEach(function(aInstall) {
+              if (aInstall.type in types)
+                types[aInstall.type]++;
+              else
+                types[aInstall.type] = 1;
+              if (!bestType || types[aInstall.type] > types[bestType])
+                bestType = aInstall.type;
+            });
+
+            BrowserOpenAddonsMgr("addons://list/" + bestType);
+          }
+        };
+      }
+
+      messageString = PluralForm.get(installInfo.installs.length, messageString);
+      messageString = messageString.replace("#1", installInfo.installs[0].name);
+      messageString = messageString.replace("#2", installInfo.installs.length);
+      messageString = messageString.replace("#3", brandShortName);
+
+      PopupNotifications.show(browser, notificationID, messageString, anchorID,
+                              action);
       break;
     }
   }
 };
 
 // Simple gestures support
 //
 // As per bug #412486, web content must not be allowed to receive any
@@ -1213,16 +1295,18 @@ function prepareForStartup() {
 
   // setup simple gestures support
   gGestureSupport.init(true);
 }
 
 function delayedStartup(isLoadingBlank, mustLoadSidebar) {
   Services.obs.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);
   Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked", false);
+  Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
+  Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
 
   BrowserOffline.init();
   OfflineApps.init();
 
   gBrowser.addEventListener("pageshow", function(evt) { setTimeout(pageShowEventHandlers, 0, evt); }, true);
 
   // Ensure login manager is up and running.
   Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
@@ -1433,16 +1517,18 @@ function BrowserShutdown()
     FullZoom.destroy();
   }
   catch(ex) {
     Components.utils.reportError(ex);
   }
 
   Services.obs.removeObserver(gSessionHistoryObserver, "browser:purge-session-history");
   Services.obs.removeObserver(gXPInstallObserver, "addon-install-blocked");
+  Services.obs.removeObserver(gXPInstallObserver, "addon-install-failed");
+  Services.obs.removeObserver(gXPInstallObserver, "addon-install-complete");
   Services.obs.removeObserver(gPluginHandler.pluginCrashed, "plugin-crashed");
 
   try {
     gBrowser.removeProgressListener(window.XULBrowserWindow);
     gBrowser.removeTabsProgressListener(window.TabsProgressListener);
   } catch (ex) {
   }
 
@@ -3513,22 +3599,20 @@ var FullScreen =
     document.getElementById("View:FullScreen").setAttribute("checked", !window.fullScreen);
 
     if (!window.fullScreen) {
       // Add a tiny toolbar to receive mouseover and dragenter events, and provide affordance.
       // This will help simulate the "collapse" metaphor while also requiring less code and
       // events than raw listening of mouse coords.
       let fullScrToggler = document.getElementById("fullscr-toggler");
       if (!fullScrToggler) {
-        fullScrToggler = document.createElement("toolbar");
+        fullScrToggler = document.createElement("hbox");
         fullScrToggler.id = "fullscr-toggler";
-        fullScrToggler.setAttribute("customizable", "false");
-        fullScrToggler.setAttribute("moz-collapsed", "true");
-        var navBar = document.getElementById("nav-bar");
-        navBar.parentNode.insertBefore(fullScrToggler, navBar);
+        fullScrToggler.collapsed = true;
+        gNavToolbox.parentNode.insertBefore(fullScrToggler, gNavToolbox.nextSibling);
       }
       fullScrToggler.addEventListener("mouseover", this._expandCallback, false);
       fullScrToggler.addEventListener("dragenter", this._expandCallback, false);
 
       if (gPrefService.getBoolPref("browser.fullscreen.autohide"))
         gBrowser.mPanelContainer.addEventListener("mousemove",
                                                   this._collapseCallback, false);
 
@@ -3719,22 +3803,21 @@ var FullScreen =
       gBrowser.mPanelContainer.addEventListener("mousemove",
                                                 this._collapseCallback, false);
     }
     else {
       gBrowser.mPanelContainer.removeEventListener("mousemove",
                                                    this._collapseCallback, false);
     }
 
-    var allFSToolbars = document.getElementsByTagNameNS(this._XULNS, "toolbar");
-    for (var i = 0; i < allFSToolbars.length; i++) {
-      if (allFSToolbars[i].getAttribute("fullscreentoolbar") == "true")
-        allFSToolbars[i].setAttribute("moz-collapsed", !aShow);
-    }
-    document.getElementById("fullscr-toggler").setAttribute("moz-collapsed", aShow);
+    // Hiding/collapsing the toolbox interferes with the tab bar's scrollbox,
+    // so we just move it off-screen instead. See bug 430687.
+    gNavToolbox.style.marginTop = aShow ? "" : -gNavToolbox.clientHeight + "px";
+
+    document.getElementById("fullscr-toggler").collapsed = aShow;
     this._isChromeCollapsed = !aShow;
     if (gPrefService.getIntPref("browser.fullscreen.animateUp") == 2)
       this._shouldAnimate = true;
   },
 
   showXULChrome: function(aTag, aShow)
   {
     var els = document.getElementsByTagNameNS(this._XULNS, aTag);
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -603,16 +603,17 @@
                  ontextreverted="return this.handleRevert();"
                  pageproxystate="invalid"
                  onsearchbegin="LocationBarHelpers._searchBegin();"
                  onsearchcomplete="LocationBarHelpers._searchComplete();"
                  onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'"
                  onblur="setTimeout(function() document.getElementById('identity-box').style.MozUserFocus = '', 0);">
           <box id="notification-popup-box" hidden="true" align="center">
             <image id="geo-notification-icon" class="notification-anchor-icon"/>
+            <image id="addons-notification-icon" class="notification-anchor-icon"/>
           </box>
           <!-- Use onclick instead of normal popup= syntax since the popup
                code fires onmousedown, and hence eats our favicon drag events.
                We only add the identity-box button to the tab order when the location bar
                has focus, otherwise pressing F6 focuses it instead of the location bar -->
           <box id="identity-box" role="button"
                onclick="gIdentityHandler.handleIdentityButtonEvent(event);"
                onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);">
--- a/browser/base/content/safeMode.js
+++ b/browser/base/content/safeMode.js
@@ -16,32 +16,34 @@
 #
 # The Initial Developer of the Original Code is
 # Mike Connor.
 # Portions created by the Initial Developer are Copyright (C) 2005
 # the Initial Developer. All Rights Reserved.
 #
 # Contributor(s):
 #   Mike Connor <mconnor@steelgryphon.com>
-#   Asaf Romano <mozilla.mano@sent.com>
+#   Asaf Romano <mano@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 *****
 
+Components.utils.import("resource://gre/modules/AddonManager.jsm");
+
 function restartApp() {
   var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
                              .getService(Components.interfaces.nsIAppStartup);
   appStartup.quit(appStartup.eForceQuit | appStartup.eRestart);
 }
 
 function clearAllPrefs() {
   var prefService = Components.classes["@mozilla.org/preferences-service;1"]
@@ -73,37 +75,31 @@ function deleteLocalstore() {
   var directoryService =  Components.classes[nsIDirectoryServiceContractID]
                                     .getService(nsIProperties);
   var localstoreFile = directoryService.get("LStoreS", Components.interfaces.nsIFile);
   if (localstoreFile.exists())
     localstoreFile.remove(false);
 }
 
 function disableAddons() {
-  // Disable addons
-  const nsIUpdateItem = Components.interfaces.nsIUpdateItem;
-  var em = Components.classes["@mozilla.org/extensions/manager;1"]
-                     .getService(Components.interfaces.nsIExtensionManager);
-  var type = nsIUpdateItem.TYPE_EXTENSION + nsIUpdateItem.TYPE_LOCALE;
-  var items = em.getItemList(type);
-  for (var i = 0; i < items.length; ++i)
-    em.disableItem(items[i].id);
-
-  // Select the default theme
-  var prefB = Components.classes["@mozilla.org/preferences-service;1"]
-                        .getService(Components.interfaces.nsIPrefBranch);
-  if (prefB.prefHasUserValue("general.skins.selectedSkin"))
-    prefB.clearUserPref("general.skins.selectedSkin");
-
-  // Disable plugins
-  var phs = Components.classes["@mozilla.org/plugin/host;1"]
-                      .getService(Components.interfaces.nsIPluginHost);
-  var plugins = phs.getPluginTags();
-  for (i = 0; i < plugins.length; ++i)
-    plugins[i].disabled = true;
+  AddonManager.getAllAddons(function(aAddons) {
+    aAddons.forEach(function(aAddon) {
+      if (aAddon.type == "theme") {
+        // Setting userDisabled to false on the default theme activates it,
+        // disables all other themes and deactivates the applied persona, if
+        // any.
+        const DEFAULT_THEME_ID = "{972ce4c6-7e08-4474-a285-3208198ce6fd}";
+        if (aAddon.id == DEFAULT_THEME_ID)
+          aAddon.userDisabled = false;
+      }
+      else {
+        aAddon.userDisabled = true;
+      }
+    });
+  });
 }
 
 function restoreDefaultSearchEngines() {
   var searchService = Components.classes["@mozilla.org/browser/search-service;1"]
                                 .getService(Components.interfaces.nsIBrowserSearchService);
 
   searchService.restoreDefaultEngines();
 }
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -124,16 +124,17 @@ endif
                  browser_bug484315.js \
                  browser_bug491431.js \
                  browser_bug495058.js \
                  browser_bug517902.js \
                  browser_bug520538.js \
                  browser_bug521216.js \
                  browser_bug537474.js \
                  browser_bug550565.js \
+                 browser_bug553455.js \
                  browser_bug555224.js \
                  browser_bug555767.js \
                  browser_bug556061.js \
                  browser_bug562649.js \
                  browser_bug563588.js \
                  browser_contextSearchTabPosition.js \
                  browser_ctrlTab.js \
                  browser_discovery.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug553455.js
@@ -0,0 +1,270 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const TESTROOT = "http://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
+const XPINSTALL_URL = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
+
+function wait_for_notification(aCallback) {
+  PopupNotifications.panel.addEventListener("popupshown", function() {
+    PopupNotifications.panel.removeEventListener("popupshown", arguments.callee, false);
+    aCallback(PopupNotifications.panel);
+  }, false);
+}
+
+function wait_for_install_dialog(aCallback) {
+  Services.wm.addListener({
+    onOpenWindow: function(aXULWindow) {
+      Services.wm.removeListener(this);
+
+      var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                                .getInterface(Ci.nsIDOMWindowInternal);
+      domwindow.addEventListener("load", function() {
+        domwindow.removeEventListener("load", arguments.callee, false);
+
+        is(domwindow.document.location.href, XPINSTALL_URL, "Should have seen the right window open");
+
+        // Allow other window load listeners to execute before passing to callback
+        executeSoon(function() {
+          // Override the countdown timer on the accept button
+          var button = domwindow.document.documentElement.getButton("accept");
+          button.disabled = false;
+
+          aCallback(domwindow);
+        });
+      }, false);
+    },
+
+    onCloseWindow: function(aXULWindow) {
+    },
+
+    onWindowTitleChange: function(aXULWindow, aNewTitle) {
+    }
+  });
+}
+
+var TESTS = [
+function test_blocked_install() {
+  var triggers = encodeURIComponent(JSON.stringify({
+    "XPI": "unsigned.xpi"
+  }));
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
+
+  // Wait for the blocked notification
+  wait_for_notification(function(aPanel) {
+    let notification = aPanel.childNodes[0];
+    is(notification.id, "addon-install-blocked", "Should have seen the install blocked");
+    is(notification.button.label, "Allow", "Should have seen the right button");
+
+    // Click on Allow
+    EventUtils.synthesizeMouse(notification.button, 20, 10, {});
+
+    // Wait for the install confirmation dialog
+    wait_for_install_dialog(function(aWindow) {
+      aWindow.document.documentElement.acceptDialog();
+
+      // Wait for the complete notification
+      wait_for_notification(function(aPanel) {
+        let notification = aPanel.childNodes[0];
+        is(notification.id, "addon-install-complete", "Should have seen the install complete");
+        is(notification.button.label, "Restart Now", "Should have seen the right button");
+
+        AddonManager.getAllInstalls(function(aInstalls) {
+        is(aInstalls.length, 1, "Should be one pending install");
+          aInstalls[0].cancel();
+
+          gBrowser.removeTab(gBrowser.selectedTab);
+          runNextTest();
+        });
+      });
+    });
+  });
+},
+
+function test_whitelisted_install() {
+  var pm = Services.perms;
+  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+
+  var triggers = encodeURIComponent(JSON.stringify({
+    "XPI": "unsigned.xpi"
+  }));
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
+
+  // Wait for the install confirmation dialog
+  wait_for_install_dialog(function(aWindow) {
+    aWindow.document.documentElement.acceptDialog();
+
+    // Wait for the complete notification
+    wait_for_notification(function(aPanel) {
+      let notification = aPanel.childNodes[0];
+      is(notification.id, "addon-install-complete", "Should have seen the install complete");
+      is(notification.button.label, "Restart Now", "Should have seen the right button");
+
+      AddonManager.getAllInstalls(function(aInstalls) {
+        is(aInstalls.length, 1, "Should be one pending install");
+        aInstalls[0].cancel();
+
+        gBrowser.removeTab(gBrowser.selectedTab);
+        Services.perms.remove("example.com", "install");
+        runNextTest();
+      });
+    });
+  });
+},
+
+function test_failed_download() {
+  var pm = Services.perms;
+  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+
+  var triggers = encodeURIComponent(JSON.stringify({
+    "XPI": "missing.xpi"
+  }));
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
+
+  // Wait for the failed notification
+  wait_for_notification(function(aPanel) {
+    let notification = aPanel.childNodes[0];
+    is(notification.id, "addon-install-failed", "Should have seen the install fail");
+
+    gBrowser.removeTab(gBrowser.selectedTab);
+    Services.perms.remove("example.com", "install");
+    runNextTest();
+  });
+},
+
+function test_corrupt_file() {
+  var pm = Services.perms;
+  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+
+  var triggers = encodeURIComponent(JSON.stringify({
+    "XPI": "corrupt.xpi"
+  }));
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
+
+  // Wait for the failed notification
+  wait_for_notification(function(aPanel) {
+    let notification = aPanel.childNodes[0];
+    is(notification.id, "addon-install-failed", "Should have seen the install fail");
+
+    gBrowser.removeTab(gBrowser.selectedTab);
+    Services.perms.remove("example.com", "install");
+    runNextTest();
+  });
+},
+
+function test_incompatible() {
+  var pm = Services.perms;
+  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+
+  var triggers = encodeURIComponent(JSON.stringify({
+    "XPI": "incompatible.xpi"
+  }));
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
+
+  // Wait for the failed notification
+  wait_for_notification(function(aPanel) {
+    let notification = aPanel.childNodes[0];
+    is(notification.id, "addon-install-failed", "Should have seen the install fail");
+
+    gBrowser.removeTab(gBrowser.selectedTab);
+    Services.perms.remove("example.com", "install");
+    runNextTest();
+  });
+},
+
+function test_restartless() {
+  var pm = Services.perms;
+  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+
+  var triggers = encodeURIComponent(JSON.stringify({
+    "XPI": "restartless.xpi"
+  }));
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
+
+  // Wait for the install confirmation dialog
+  wait_for_install_dialog(function(aWindow) {
+    aWindow.document.documentElement.acceptDialog();
+
+    // Wait for the complete notification
+    wait_for_notification(function(aPanel) {
+      let notification = aPanel.childNodes[0];
+      is(notification.id, "addon-install-complete", "Should have seen the install complete");
+      is(notification.button.label, "Open Add-ons Manager", "Should have seen the right button");
+
+      AddonManager.getAllInstalls(function(aInstalls) {
+        is(aInstalls.length, 0, "Should be no pending installs");
+
+        AddonManager.getAddonByID("restartless-xpi@tests.mozilla.org", function(aAddon) {
+          aAddon.uninstall();
+
+          gBrowser.removeTab(gBrowser.selectedTab);
+          Services.perms.remove("example.com", "install");
+          runNextTest();
+        });
+      });
+    });
+  });
+},
+
+function test_multiple() {
+  var pm = Services.perms;
+  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+
+  var triggers = encodeURIComponent(JSON.stringify({
+    "Unsigned XPI": "unsigned.xpi",
+    "Restartless XPI": "restartless.xpi"
+  }));
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
+
+  // Wait for the install confirmation dialog
+  wait_for_install_dialog(function(aWindow) {
+    aWindow.document.documentElement.acceptDialog();
+
+    // Wait for the complete notification
+    wait_for_notification(function(aPanel) {
+      let notification = aPanel.childNodes[0];
+      is(notification.id, "addon-install-complete", "Should have seen the install complete");
+      is(notification.button.label, "Restart Now", "Should have seen the right button");
+
+      AddonManager.getAllInstalls(function(aInstalls) {
+        is(aInstalls.length, 1, "Should be one pending install");
+        aInstalls[0].cancel();
+
+        AddonManager.getAddonByID("restartless-xpi@tests.mozilla.org", function(aAddon) {
+          aAddon.uninstall();
+
+          gBrowser.removeTab(gBrowser.selectedTab);
+          Services.perms.remove("example.com", "install");
+          runNextTest();
+        });
+      });
+    });
+  });
+}
+];
+
+function runNextTest() {
+  AddonManager.getAllInstalls(function(aInstalls) {
+    is(aInstalls.length, 0, "Should be no active installs");
+
+    if (TESTS.length == 0) {
+      finish();
+      return;
+    }
+
+    TESTS.shift()();
+  });
+}
+
+function test() {
+  waitForExplicitFinish();
+
+  runNextTest();
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/BrowserComponents.manifest
@@ -0,0 +1,33 @@
+# nsBrowserContentHandler.js
+component {5d0ce354-df01-421a-83fb-7ead0990c24e} nsBrowserContentHandler.js application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/browser/clh;1 {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+component {47cd0651-b1be-4a0f-b5c4-10e5a573ef71} nsBrowserContentHandler.js application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/browser/final-clh;1 {47cd0651-b1be-4a0f-b5c4-10e5a573ef71} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/uriloader/content-handler;1?type=text/html {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/uriloader/content-handler;1?type=application/vnd.mozilla.xul+xml {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+#ifdef MOZ_SVG
+contract @mozilla.org/uriloader/content-handler;1?type=image/svg+xml {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+#endif
+contract @mozilla.org/uriloader/content-handler;1?type=text/rdf {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/uriloader/content-handler;1?type=text/xml {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/uriloader/content-handler;1?type=application/xhtml+xml {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/uriloader/content-handler;1?type=text/css {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/uriloader/content-handler;1?type=text/plain {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/uriloader/content-handler;1?type=image/gif {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/uriloader/content-handler;1?type=image/jpeg {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/uriloader/content-handler;1?type=image/jpg {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/uriloader/content-handler;1?type=image/png {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/uriloader/content-handler;1?type=image/bmp {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/uriloader/content-handler;1?type=image/x-icon {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/uriloader/content-handler;1?type=image/vnd.microsoft.icon {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+contract @mozilla.org/uriloader/content-handler;1?type=application/http-index-format {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+category command-line-handler m-browser @mozilla.org/browser/clh;1 application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+category command-line-handler x-default @mozilla.org/browser/final-clh;1 application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+category command-line-validator b-browser @mozilla.org/browser/clh;1 application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+
+# nsBrowserGlue.js
+component {eab9012e-5f74-4cbc-b2b5-a590235513cc} nsBrowserGlue.js
+contract @mozilla.org/browser/browserglue;1 {eab9012e-5f74-4cbc-b2b5-a590235513cc}
+category app-startup nsBrowserGlue service,@mozilla.org/browser/browserglue;1
+component {C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5} nsBrowserGlue.js
+contract @mozilla.org/geolocation/prompt;1 {C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5}
--- a/browser/components/Makefile.in
+++ b/browser/components/Makefile.in
@@ -46,16 +46,17 @@ MODULE = browsercomps
 XPIDL_MODULE = browsercompsbase
 
 XPIDLSRCS = \
   nsIBrowserGlue.idl \
   nsIBrowserHandler.idl \
   $(NULL)
 
 EXTRA_PP_COMPONENTS = \
+  BrowserComponents.manifest \
   nsBrowserContentHandler.js \
   nsBrowserGlue.js \
   $(NULL)
 
 EXTRA_JS_MODULES = distribution.js
 
 PARALLEL_DIRS = \
   about \
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -172,17 +172,17 @@ AboutRedirector::GetURIFlags(nsIURI *aUR
       *result = kRedirMap[i].flags;
       return NS_OK;
     }
   }
 
   return NS_ERROR_ILLEGAL_VALUE;
 }
 
-NS_METHOD
+nsresult
 AboutRedirector::Create(nsISupports *aOuter, REFNSIID aIID, void **result)
 {
   AboutRedirector* about = new AboutRedirector();
   if (about == nsnull)
     return NS_ERROR_OUT_OF_MEMORY;
   NS_ADDREF(about);
   nsresult rv = about->QueryInterface(aIID, result);
   NS_RELEASE(about);
--- a/browser/components/about/AboutRedirector.h
+++ b/browser/components/about/AboutRedirector.h
@@ -49,17 +49,17 @@ class AboutRedirector : public nsIAboutM
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIABOUTMODULE
  
   AboutRedirector() {}
   virtual ~AboutRedirector() {}
 
-  static NS_METHOD
+  static nsresult
     Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
 
 protected:
 };
 
 } // namespace browser
 } // namespace mozilla
 
--- a/browser/components/build/nsModule.cpp
+++ b/browser/components/build/nsModule.cpp
@@ -31,17 +31,17 @@
  * 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 "nsIGenericFactory.h"
+#include "mozilla/ModuleUtils.h"
 
 #include "nsBrowserCompsCID.h"
 #include "DirectoryProvider.h"
 
 #if defined(XP_WIN)
 #include "nsWindowsShellService.h"
 #elif defined(XP_MACOSX)
 #include "nsMacShellService.h"
@@ -115,157 +115,130 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsICabPro
 #endif
 
 #endif
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFeedSniffer)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrivateBrowsingServiceWrapper, Init)
 
-/////////////////////////////////////////////////////////////////////////////
-
-static const nsModuleComponentInfo components[] =
-{
-  { "Browser Directory Provider",
-    NS_BROWSERDIRECTORYPROVIDER_CID,
-    NS_BROWSERDIRECTORYPROVIDER_CONTRACTID,
-    DirectoryProviderConstructor,
-    DirectoryProvider::Register,
-    DirectoryProvider::Unregister
-  },
-
+NS_DEFINE_NAMED_CID(NS_BROWSERDIRECTORYPROVIDER_CID);
 #if defined(XP_WIN)
-  { "Browser Shell Service",
-    NS_SHELLSERVICE_CID,
-    NS_SHELLSERVICE_CONTRACTID,
-    nsWindowsShellServiceConstructor},
-
+NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
 #elif defined(MOZ_WIDGET_GTK2)
-  { "Browser Shell Service",
-    NS_SHELLSERVICE_CID,
-    NS_SHELLSERVICE_CONTRACTID,
-    nsGNOMEShellServiceConstructor },
-
+NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
 #endif
-
-  { "Feed Sniffer",
-    NS_FEEDSNIFFER_CID,
-    NS_FEEDSNIFFER_CONTRACTID,
-    nsFeedSnifferConstructor,
-    nsFeedSniffer::Register },
-
-#ifdef MOZ_SAFE_BROWSING
-  { "about:blocked",
-    NS_BROWSER_ABOUT_REDIRECTOR_CID,
-    NS_ABOUT_MODULE_CONTRACTID_PREFIX "blocked",
-    AboutRedirector::Create },
+NS_DEFINE_NAMED_CID(NS_FEEDSNIFFER_CID);
+NS_DEFINE_NAMED_CID(NS_BROWSER_ABOUT_REDIRECTOR_CID);
+#ifndef WINCE
+NS_DEFINE_NAMED_CID(NS_FIREFOX_PROFILEMIGRATOR_CID);
+#if defined(XP_WIN) && !defined(__MINGW32__)
+NS_DEFINE_NAMED_CID(NS_WINIEPROFILEMIGRATOR_CID);
+#elif defined(XP_MACOSX)
+NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
+NS_DEFINE_NAMED_CID(NS_SAFARIPROFILEMIGRATOR_CID);
+NS_DEFINE_NAMED_CID(NS_MACIEPROFILEMIGRATOR_CID);
+NS_DEFINE_NAMED_CID(NS_OMNIWEBPROFILEMIGRATOR_CID);
+NS_DEFINE_NAMED_CID(NS_CAMINOPROFILEMIGRATOR_CID);
+NS_DEFINE_NAMED_CID(NS_ICABPROFILEMIGRATOR_CID);
 #endif
-
-  { "about:certerror",
-    NS_BROWSER_ABOUT_REDIRECTOR_CID,
-    NS_ABOUT_MODULE_CONTRACTID_PREFIX "certerror",
-    AboutRedirector::Create },
-
-  { "about:feeds",
-    NS_BROWSER_ABOUT_REDIRECTOR_CID,
-    NS_ABOUT_MODULE_CONTRACTID_PREFIX "feeds",
-    AboutRedirector::Create },
-
-  { "about:privatebrowsing",
-    NS_BROWSER_ABOUT_REDIRECTOR_CID,
-    NS_ABOUT_MODULE_CONTRACTID_PREFIX "privatebrowsing",
-    AboutRedirector::Create },
-
-  { "about:rights",
-    NS_BROWSER_ABOUT_REDIRECTOR_CID,
-    NS_ABOUT_MODULE_CONTRACTID_PREFIX "rights",
-    AboutRedirector::Create },
-
-  { "about:robots",
-    NS_BROWSER_ABOUT_REDIRECTOR_CID,
-    NS_ABOUT_MODULE_CONTRACTID_PREFIX "robots",
-    AboutRedirector::Create },
-
-  { "about:sessionrestore",
-    NS_BROWSER_ABOUT_REDIRECTOR_CID,
-    NS_ABOUT_MODULE_CONTRACTID_PREFIX "sessionrestore",
-    AboutRedirector::Create },
-
-#ifndef WINCE
+#if !defined(XP_OS2)
+NS_DEFINE_NAMED_CID(NS_OPERAPROFILEMIGRATOR_CID);
+#endif
+#if !defined(XP_BEOS)
+NS_DEFINE_NAMED_CID(NS_DOGBERTPROFILEMIGRATOR_CID);
+#endif
+NS_DEFINE_NAMED_CID(NS_PHOENIXPROFILEMIGRATOR_CID);
+NS_DEFINE_NAMED_CID(NS_SEAMONKEYPROFILEMIGRATOR_CID);
+#endif /* WINCE */
+NS_DEFINE_NAMED_CID(NS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID);
 
-  { "Profile Migrator",
-    NS_FIREFOX_PROFILEMIGRATOR_CID,
-    NS_PROFILEMIGRATOR_CONTRACTID,
-    nsProfileMigratorConstructor },
-
+static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
+    { &kNS_BROWSERDIRECTORYPROVIDER_CID, false, NULL, DirectoryProviderConstructor },
+#if defined(XP_WIN)
+    { &kNS_SHELLSERVICE_CID, false, NULL, nsWindowsShellServiceConstructor },
+#elif defined(MOZ_WIDGET_GTK2)
+    { &kNS_SHELLSERVICE_CID, false, NULL, nsGNOMEShellServiceConstructor },
+#endif
+    { &kNS_FEEDSNIFFER_CID, false, NULL, nsFeedSnifferConstructor },
+    { &kNS_BROWSER_ABOUT_REDIRECTOR_CID, false, NULL, AboutRedirector::Create },
+#ifndef WINCE
+    { &kNS_FIREFOX_PROFILEMIGRATOR_CID, false, NULL, nsProfileMigratorConstructor },
 #if defined(XP_WIN) && !defined(__MINGW32__)
-  { "Internet Explorer (Windows) Profile Migrator",
-    NS_WINIEPROFILEMIGRATOR_CID,
-    NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "ie",
-    nsIEProfileMigratorConstructor },
-
+    { &kNS_WINIEPROFILEMIGRATOR_CID, false, NULL, nsIEProfileMigratorConstructor },
 #elif defined(XP_MACOSX)
-  { "Browser Shell Service",
-    NS_SHELLSERVICE_CID,
-    NS_SHELLSERVICE_CONTRACTID,
-    nsMacShellServiceConstructor },
-
-  { "Safari Profile Migrator",
-    NS_SAFARIPROFILEMIGRATOR_CID,
-    NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "safari",
-    nsSafariProfileMigratorConstructor },
-
-  { "Internet Explorer (Macintosh) Profile Migrator",
-    NS_MACIEPROFILEMIGRATOR_CID,
-    NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "macie",
-    nsMacIEProfileMigratorConstructor },
-
-  { "OmniWeb Profile Migrator",
-    NS_OMNIWEBPROFILEMIGRATOR_CID,
-    NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "omniweb",
-    nsOmniWebProfileMigratorConstructor },
-
-  { "Camino Profile Migrator",
-    NS_CAMINOPROFILEMIGRATOR_CID,
-    NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "camino",
-    nsCaminoProfileMigratorConstructor },
-
-  { "iCab Profile Migrator",
-    NS_ICABPROFILEMIGRATOR_CID,
-    NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "icab",
-    nsICabProfileMigratorConstructor },
-
+    { &kNS_SHELLSERVICE_CID, false, NULL, nsMacShellServiceConstructor },
+    { &kNS_SAFARIPROFILEMIGRATOR_CID, false, NULL, nsSafariProfileMigratorConstructor },
+    { &kNS_MACIEPROFILEMIGRATOR_CID, false, NULL, nsMacIEProfileMigratorConstructor },
+    { &kNS_OMNIWEBPROFILEMIGRATOR_CID, false, NULL, nsOmniWebProfileMigratorConstructor },
+    { &kNS_CAMINOPROFILEMIGRATOR_CID, false, NULL, nsCaminoProfileMigratorConstructor },
+    { &kNS_ICABPROFILEMIGRATOR_CID, false, NULL, nsICabProfileMigratorConstructor },
 #endif
-
 #if !defined(XP_OS2)
-  { "Opera Profile Migrator",
-    NS_OPERAPROFILEMIGRATOR_CID,
-    NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "opera",
-    nsOperaProfileMigratorConstructor },
+    { &kNS_OPERAPROFILEMIGRATOR_CID, false, NULL, nsOperaProfileMigratorConstructor },
 #endif
-
 #if !defined(XP_BEOS)
-  { "Netscape 4.x Profile Migrator",
-    NS_DOGBERTPROFILEMIGRATOR_CID,
-    NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "dogbert",
-    nsDogbertProfileMigratorConstructor },
+    { &kNS_DOGBERTPROFILEMIGRATOR_CID, false, NULL, nsDogbertProfileMigratorConstructor },
 #endif
-
-  { "Phoenix Profile Migrator",
-    NS_PHOENIXPROFILEMIGRATOR_CID,
-    NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "phoenix",
-    nsPhoenixProfileMigratorConstructor },
-
-  { "Seamonkey Profile Migrator",
-    NS_SEAMONKEYPROFILEMIGRATOR_CID,
-    NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "seamonkey",
-    nsSeamonkeyProfileMigratorConstructor },
-
+    { &kNS_PHOENIXPROFILEMIGRATOR_CID, false, NULL, nsPhoenixProfileMigratorConstructor },
+    { &kNS_SEAMONKEYPROFILEMIGRATOR_CID, false, NULL, nsSeamonkeyProfileMigratorConstructor },
 #endif /* WINCE */
-
-  { "PrivateBrowsing Service C++ Wrapper",
-    NS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID,
-    NS_PRIVATE_BROWSING_SERVICE_CONTRACTID,
-    nsPrivateBrowsingServiceWrapperConstructor }
+    { &kNS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID, false, NULL, nsPrivateBrowsingServiceWrapperConstructor },
+    { NULL }
 };
 
-NS_IMPL_NSGETMODULE(nsBrowserCompsModule, components)
+static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
+    { NS_BROWSERDIRECTORYPROVIDER_CONTRACTID, &kNS_BROWSERDIRECTORYPROVIDER_CID },
+#if defined(XP_WIN)
+    { NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
+#elif defined(MOZ_WIDGET_GTK2)
+    { NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
+#endif
+    { NS_FEEDSNIFFER_CONTRACTID, &kNS_FEEDSNIFFER_CID },
+#ifdef MOZ_SAFE_BROWSING
+    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "blocked", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+#endif
+    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "certerror", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "feeds", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "privatebrowsing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "rights", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "robots", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "sessionrestore", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+#ifndef WINCE
+    { NS_PROFILEMIGRATOR_CONTRACTID, &kNS_FIREFOX_PROFILEMIGRATOR_CID },
+#if defined(XP_WIN) && !defined(__MINGW32__)
+    { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "ie", &kNS_WINIEPROFILEMIGRATOR_CID },
+#elif defined(XP_MACOSX)
+    { NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
+    { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "safari", &kNS_SAFARIPROFILEMIGRATOR_CID },
+    { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "macie", &kNS_MACIEPROFILEMIGRATOR_CID },
+    { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "omniweb", &kNS_OMNIWEBPROFILEMIGRATOR_CID },
+    { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "camino", &kNS_CAMINOPROFILEMIGRATOR_CID },
+    { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "icab", &kNS_ICABPROFILEMIGRATOR_CID },
+#endif
+#if !defined(XP_OS2)
+    { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "opera", &kNS_OPERAPROFILEMIGRATOR_CID },
+#endif
+#if !defined(XP_BEOS)
+    { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "dogbert", &kNS_DOGBERTPROFILEMIGRATOR_CID },
+#endif
+    { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "phoenix", &kNS_PHOENIXPROFILEMIGRATOR_CID },
+    { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "seamonkey", &kNS_SEAMONKEYPROFILEMIGRATOR_CID },
+#endif /* WINCE */
+    { NS_PRIVATE_BROWSING_SERVICE_CONTRACTID, &kNS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID },
+    { NULL }
+};
 
+static const mozilla::Module::CategoryEntry kBrowserCategories[] = {
+    { XPCOM_DIRECTORY_PROVIDER_CATEGORY, "browser-directory-provider", NS_BROWSERDIRECTORYPROVIDER_CONTRACTID },
+    { NS_CONTENT_SNIFFER_CATEGORY, "Feed Sniffer", NS_FEEDSNIFFER_CONTRACTID },
+    { NULL }
+};
+
+static const mozilla::Module kBrowserModule = {
+    mozilla::Module::kVersion,
+    kBrowserCIDs,
+    kBrowserContracts,
+    kBrowserCategories
+};
+
+NSMODULE_DEFN(nsBrowserCompsModule) = &kBrowserModule;
+
--- a/browser/components/dirprovider/DirectoryProvider.cpp
+++ b/browser/components/dirprovider/DirectoryProvider.cpp
@@ -47,17 +47,17 @@
 #include "nsEnumeratorUtils.h"
 #include "nsBrowserDirectoryServiceDefs.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsCategoryManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsCOMArray.h"
 #include "nsDirectoryServiceUtils.h"
-#include "nsIGenericFactory.h"
+#include "mozilla/ModuleUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStringAPI.h"
 #include "nsXULAppAPI.h"
 
 namespace mozilla {
 namespace browser {
 
 NS_IMPL_ISUPPORTS2(DirectoryProvider,
@@ -271,53 +271,16 @@ DirectoryProvider::GetFiles(const char *
       return NS_ERROR_OUT_OF_MEMORY;
 
     return NS_NewUnionEnumerator(aResult, extEnum, baseEnum);
   }
 
   return NS_ERROR_FAILURE;
 }
 
-NS_METHOD
-DirectoryProvider::Register(nsIComponentManager* aCompMgr, nsIFile* aPath,
-                            const char *aLoaderStr, const char *aType,
-                            const nsModuleComponentInfo *aInfo)
-{
-  nsresult rv;
-
-  nsCOMPtr<nsICategoryManager> catMan
-    (do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
-  if (!catMan)
-    return NS_ERROR_FAILURE;
-
-  rv = catMan->AddCategoryEntry(XPCOM_DIRECTORY_PROVIDER_CATEGORY,
-                                "browser-directory-provider",
-                                NS_BROWSERDIRECTORYPROVIDER_CONTRACTID,
-                                PR_TRUE, PR_TRUE, nsnull);
-  return rv;
-}
-
-
-NS_METHOD
-DirectoryProvider::Unregister(nsIComponentManager* aCompMgr, 
-                              nsIFile* aPath, const char *aLoaderStr,
-                              const nsModuleComponentInfo *aInfo)
-{
-  nsresult rv;
-
-  nsCOMPtr<nsICategoryManager> catMan
-    (do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
-  if (!catMan)
-    return NS_ERROR_FAILURE;
-
-  rv = catMan->DeleteCategoryEntry(XPCOM_DIRECTORY_PROVIDER_CATEGORY,
-                                   "browser-directory-provider", PR_TRUE);
-  return rv;
-}
-
 NS_IMPL_ISUPPORTS1(DirectoryProvider::AppendingEnumerator, nsISimpleEnumerator)
 
 NS_IMETHODIMP
 DirectoryProvider::AppendingEnumerator::HasMoreElements(PRBool *aResult)
 {
   *aResult = mNext ? PR_TRUE : PR_FALSE;
   return NS_OK;
 }
--- a/browser/components/dirprovider/DirectoryProvider.h
+++ b/browser/components/dirprovider/DirectoryProvider.h
@@ -37,40 +37,30 @@
 
 #ifndef DirectoryProvider_h__
 #define DirectoryProvider_h__
 
 #include "nsIDirectoryService.h"
 #include "nsComponentManagerUtils.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIFile.h"
-#include "nsIGenericFactory.h"
 
 #define NS_BROWSERDIRECTORYPROVIDER_CONTRACTID \
   "@mozilla.org/browser/directory-provider;1"
 
 namespace mozilla {
 namespace browser {
 
 class DirectoryProvider : public nsIDirectoryServiceProvider2
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDIRECTORYSERVICEPROVIDER
   NS_DECL_NSIDIRECTORYSERVICEPROVIDER2
 
-  static NS_METHOD Register(nsIComponentManager* aCompMgr,
-                            nsIFile* aPath, const char *aLoaderStr,
-                            const char *aType,
-                            const nsModuleComponentInfo *aInfo);
-
-  static NS_METHOD Unregister(nsIComponentManager* aCompMgr,
-                              nsIFile* aPath, const char *aLoaderStr,
-                              const nsModuleComponentInfo *aInfo);
-
 private:
   class AppendingEnumerator : public nsISimpleEnumerator
   {
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSISIMPLEENUMERATOR
 
     AppendingEnumerator(nsISimpleEnumerator* aBase,
new file mode 100644
--- /dev/null
+++ b/browser/components/feeds/src/BrowserFeeds.manifest
@@ -0,0 +1,16 @@
+component {229fa115-9412-4d32-baf3-2fc407f76fb1} FeedConverter.js
+contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1}
+contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.video.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1}
+contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.audio.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1}
+component {2376201c-bbc6-472f-9b62-7548040a61c6} FeedConverter.js
+contract @mozilla.org/browser/feeds/result-service;1 {2376201c-bbc6-472f-9b62-7548040a61c6}
+component {4f91ef2e-57ba-472e-ab7a-b4999e42d6c0} FeedConverter.js
+contract @mozilla.org/network/protocol;1?name=feed {4f91ef2e-57ba-472e-ab7a-b4999e42d6c0}
+component {1c31ed79-accd-4b94-b517-06e0c81999d5} FeedConverter.js
+contract @mozilla.org/network/protocol;1?name=pcast {1c31ed79-accd-4b94-b517-06e0c81999d5}
+component {49bb6593-3aff-4eb3-a068-2712c28bd58e} FeedWriter.js
+contract @mozilla.org/browser/feeds/result-writer;1 {49bb6593-3aff-4eb3-a068-2712c28bd58e}
+category JavaScript-global-constructor BrowserFeedWriter @mozilla.org/browser/feeds/result-writer;1
+component {792a7e82-06a0-437c-af63-b2d12e808acc} WebContentConverter.js
+contract @mozilla.org/embeddor.implemented/web-content-handler-registrar;1 {792a7e82-06a0-437c-af63-b2d12e808acc}
+category app-startup WebContentConverter service,@mozilla.org/embeddor.implemented/web-content-handler-registrar;1
\ No newline at end of file
--- a/browser/components/feeds/src/FeedConverter.js
+++ b/browser/components/feeds/src/FeedConverter.js
@@ -32,37 +32,30 @@
 # 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 ***** */
 
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/debug.js");
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 function LOG(str) {
   dump("*** " + str + "\n");
 }
 
-const FC_CLASSID = Components.ID("{229fa115-9412-4d32-baf3-2fc407f76fb1}");
-const FC_CLASSNAME = "Feed Stream Converter";
-const FS_CLASSID = Components.ID("{2376201c-bbc6-472f-9b62-7548040a61c6}");
-const FS_CLASSNAME = "Feed Result Service";
 const FS_CONTRACTID = "@mozilla.org/browser/feeds/result-service;1";
 const FPH_CONTRACTID = "@mozilla.org/network/protocol;1?name=feed";
-const FPH_CLASSID = Components.ID("{4f91ef2e-57ba-472e-ab7a-b4999e42d6c0}");
-const FPH_CLASSNAME = "Feed Protocol Handler";
 const PCPH_CONTRACTID = "@mozilla.org/network/protocol;1?name=pcast";
-const PCPH_CLASSID = Components.ID("{1c31ed79-accd-4b94-b517-06e0c81999d5}");
-const PCPH_CLASSNAME = "Podcast Protocol Handler";
 
 const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
 const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
 const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
 const TYPE_ANY = "*/*";
 
 const FEEDHANDLER_URI = "about:feeds";
 
@@ -143,16 +136,18 @@ function safeGetCharPref(pref, defaultVa
   catch (e) {
   }
   return defaultValue;
 }
 
 function FeedConverter() {
 }
 FeedConverter.prototype = {
+  classID: Components.ID("{229fa115-9412-4d32-baf3-2fc407f76fb1}"),
+
   /**
    * This is the downloaded text data for the feed.
    */
   _data: null,
   
   /**
    * This is the object listening to the conversion, which is ultimately the
    * docshell for the load.
@@ -363,36 +358,25 @@ FeedConverter.prototype = {
         iid.equals(Ci.nsIStreamListener) ||
         iid.equals(Ci.nsIRequestObserver)||
         iid.equals(Ci.nsISupports))
       return this;
     throw Cr.NS_ERROR_NO_INTERFACE;
   },
 };
 
-var FeedConverterFactory = {
-  createInstance: function FS_createInstance(outer, iid) {
-    if (outer != null)
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    return new FeedConverter().QueryInterface(iid);
-  },
-
-  QueryInterface: function FS_QueryInterface(iid) {
-    if (iid.equals(Ci.nsIFactory) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
-};
-
 /**
  * Keeps parsed FeedResults around for use elsewhere in the UI after the stream
  * converter completes. 
  */
-var FeedResultService = {
+function FeedResultService() {
+}
+
+FeedResultService.prototype = {
+  classID: Components.ID("{2376201c-bbc6-472f-9b62-7548040a61c6}"),
   
   /**
    * A URI spec -> [nsIFeedResult] hash. We have to keep a list as the
    * value in case the same URI is requested concurrently.
    */
   _results: { },
   
   /**
@@ -529,42 +513,44 @@ var FeedResultService = {
     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
 };
 
 /**
  * A protocol handler that attempts to deal with the variant forms of feed:
  * URIs that are actually either http or https.
  */
-function FeedProtocolHandler(scheme) {
-  this._scheme = scheme;
-  var ios = 
+function GenericProtocolHandler() {
+}
+GenericProtocolHandler.prototype = {
+  _init: function GPH_init(scheme) {
+    var ios = 
       Cc["@mozilla.org/network/io-service;1"].
       getService(Ci.nsIIOService);
-  this._http = ios.getProtocolHandler("http");
-}
-FeedProtocolHandler.prototype = {
-  _scheme: "",
+    this._http = ios.getProtocolHandler("http");
+    this._scheme = scheme;
+  },
+
   get scheme() {
     return this._scheme;
   },
   
   get protocolFlags() {
     return this._http.protocolFlags;
   },
   
   get defaultPort() {
     return this._http.defaultPort;
   },
   
-  allowPort: function FPH_allowPort(port, scheme) {
+  allowPort: function GPH_allowPort(port, scheme) {
     return this._http.allowPort(port, scheme);
   },
   
-  newURI: function FPH_newURI(spec, originalCharset, baseURI) {
+  newURI: function GPH_newURI(spec, originalCharset, baseURI) {
     // See bug 408599 - feed URIs can be either standard URLs of the form
     // feed://example.com, in which case the real protocol is http, or nested
     // URIs of the form feed:realscheme:. When realscheme is either http or
     // https, we deal with the way that creates a standard URL with the
     // realscheme as the host by unmangling in newChannel; for others, we fail
     // rather than let it wind up loading something like www.realscheme.com//foo
 
     const feedSlashes = "feed://";
@@ -580,17 +566,17 @@ FeedProtocolHandler.prototype = {
     var uri = 
         Cc["@mozilla.org/network/standard-url;1"].
         createInstance(Ci.nsIStandardURL);
     uri.init(Ci.nsIStandardURL.URLTYPE_STANDARD, 80, spec, originalCharset,
              baseURI);
     return uri;
   },
   
-  newChannel: function FPH_newChannel(aUri) {
+  newChannel: function GPH_newChannel(aUri) {
     var ios = 
         Cc["@mozilla.org/network/io-service;1"].
         getService(Ci.nsIIOService);
     // feed: URIs either start feed://, in which case the real scheme is http:
     // or feed:http(s)://, (which by now we've changed to feed://realscheme//)
     var feedSpec = aUri.spec;
     const httpsChunk = "feed://https//";
     const httpChunk = "feed://http//";
@@ -605,85 +591,35 @@ FeedProtocolHandler.prototype = {
     var channel =
       ios.newChannelFromURI(uri, null).QueryInterface(Ci.nsIHttpChannel);
     // Set this so we know this is supposed to be a feed
     channel.setRequestHeader("X-Moz-Is-Feed", "1", false);
     channel.originalURI = aUri;
     return channel;
   },
   
-  QueryInterface: function FPH_QueryInterface(iid) {
+  QueryInterface: function GPH_QueryInterface(iid) {
     if (iid.equals(Ci.nsIProtocolHandler) ||
         iid.equals(Ci.nsISupports))
       return this;
     throw Cr.NS_ERROR_NO_INTERFACE;
   }  
 };
 
-var Module = {
-  QueryInterface: function M_QueryInterface(iid) {
-    if (iid.equals(Ci.nsIModule) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
-  
-  getClassObject: function M_getClassObject(cm, cid, iid) {
-    if (!iid.equals(Ci.nsIFactory))
-      throw Cr.NS_ERROR_NOT_IMPLEMENTED;
-    
-    if (cid.equals(FS_CLASSID))
-      return FeedResultService;
-    if (cid.equals(FPH_CLASSID))
-      return new GenericComponentFactory(FeedProtocolHandler, "feed");
-    if (cid.equals(PCPH_CLASSID))
-      return new GenericComponentFactory(FeedProtocolHandler, "pcast");
-    if (cid.equals(FC_CLASSID))
-      return new GenericComponentFactory(FeedConverter);
-      
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
-  
-  registerSelf: function M_registerSelf(cm, file, location, type) {
-    var cr = cm.QueryInterface(Ci.nsIComponentRegistrar);
-    
-    cr.registerFactoryLocation(FS_CLASSID, FS_CLASSNAME, FS_CONTRACTID,
-                               file, location, type);
-    cr.registerFactoryLocation(FPH_CLASSID, FPH_CLASSNAME, FPH_CONTRACTID,
-                               file, location, type);
-    cr.registerFactoryLocation(PCPH_CLASSID, PCPH_CLASSNAME, PCPH_CONTRACTID,
-                               file, location, type);
+function FeedProtocolHandler() {
+  this._init('feed');
+}
+FeedProtocolHandler.prototype = new GenericProtocolHandler();
+FeedProtocolHandler.prototype.classID = Components.ID("{4f91ef2e-57ba-472e-ab7a-b4999e42d6c0}");
 
-    // The feed converter is always attached, since parsing must be done to 
-    // determine whether or not auto-handling can occur. 
-    const converterPrefix = "@mozilla.org/streamconv;1?from=";
-    var converterContractID = 
-        converterPrefix + TYPE_MAYBE_FEED + "&to=" + TYPE_ANY;
-    cr.registerFactoryLocation(FC_CLASSID, FC_CLASSNAME, converterContractID,
-                               file, location, type);
-
-    converterContractID = 
-        converterPrefix + TYPE_MAYBE_VIDEO_FEED + "&to=" + TYPE_ANY;
-    cr.registerFactoryLocation(FC_CLASSID, FC_CLASSNAME, converterContractID,
-                               file, location, type);
+function PodCastProtocolHandler() {
+  this._init('pcast');
+}
+PodCastProtocolHandler.prototype = new GenericProtocolHandler();
+PodCastProtocolHandler.prototype.classID = Components.ID("{1c31ed79-accd-4b94-b517-06e0c81999d5}");
 
-    converterContractID = 
-        converterPrefix + TYPE_MAYBE_AUDIO_FEED + "&to=" + TYPE_ANY;
-    cr.registerFactoryLocation(FC_CLASSID, FC_CLASSNAME, converterContractID,
-                               file, location, type);
-    },
-  
-  unregisterSelf: function M_unregisterSelf(cm, location, type) {
-    var cr = cm.QueryInterface(Ci.nsIComponentRegistrar);
-    cr.unregisterFactoryLocation(FPH_CLASSID, location);
-    cr.unregisterFactoryLocation(PCPH_CLASSID, location);
-  },
-  
-  canUnload: function M_canUnload(cm) {
-    return true;
-  }
-};
+var components = [FeedConverter,
+                  FeedResultService,
+                  FeedProtocolHandler,
+                  PodCastProtocolHandler];
 
-function NSGetModule(cm, file) {
-  return Module;
-}
 
-#include GenericFactory.js
+const NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
--- a/browser/components/feeds/src/FeedWriter.js
+++ b/browser/components/feeds/src/FeedWriter.js
@@ -1411,22 +1411,17 @@ FeedWriter.prototype = {
 
   // nsIClassInfo
   getInterfaces: function FW_getInterfaces(countRef) {
     var interfaces = [Ci.nsIFeedWriter, Ci.nsIClassInfo, Ci.nsISupports];
     countRef.value = interfaces.length;
     return interfaces;
   },
   getHelperForLanguage: function FW_getHelperForLanguage(language) null,
-  contractID: "@mozilla.org/browser/feeds/result-writer;1",
-  classDescription: "Feed Writer",
   classID: Components.ID("{49bb6593-3aff-4eb3-a068-2712c28bd58e}"),
   implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
   flags: Ci.nsIClassInfo.DOM_OBJECT,
-  _xpcom_categories: [{ category: "JavaScript global constructor",
-                        entry: "BrowserFeedWriter"}],
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIFeedWriter, Ci.nsIClassInfo,
                                          Ci.nsIDOMEventListener, Ci.nsIObserver,
                                          Ci.nsINavHistoryObserver])
 };
 
-function NSGetModule(cm, file)
-  XPCOMUtils.generateModule([FeedWriter]);
+var NSGetFactory = XPCOMUtils.generateNSGetFactory([FeedWriter]);
--- a/browser/components/feeds/src/Makefile.in
+++ b/browser/components/feeds/src/Makefile.in
@@ -49,16 +49,20 @@ ifndef MOZ_MEMORY
 USE_STATIC_LIBS = 1
 endif
 
 DEFINES += \
 	-DMOZ_APP_NAME=$(MOZ_APP_NAME) \
 	-DMOZ_APP_DISPLAYNAME=$(MOZ_APP_DISPLAYNAME) \
 	$(NULL)
 
+EXTRA_COMPONENTS = \
+  BrowserFeeds.manifest \
+  $(NULL)
+
 EXTRA_PP_COMPONENTS = \
 	FeedConverter.js \
 	FeedWriter.js \
 	WebContentConverter.js \
 	$(NULL)
 
 
 CPPSRCS = nsFeedSniffer.cpp
--- a/browser/components/feeds/src/WebContentConverter.js
+++ b/browser/components/feeds/src/WebContentConverter.js
@@ -44,17 +44,16 @@ const Ci = Components.interfaces;
 const Cr = Components.results;
 
 function LOG(str) {
   dump("*** " + str + "\n");
 }
 
 const WCCR_CONTRACTID = "@mozilla.org/embeddor.implemented/web-content-handler-registrar;1";
 const WCCR_CLASSID = Components.ID("{792a7e82-06a0-437c-af63-b2d12e808acc}");
-const WCCR_CLASSNAME = "Web Content Handler Registrar";
 
 const WCC_CLASSID = Components.ID("{db7ebf28-cc40-415f-8a51-1b111851df1e}");
 const WCC_CLASSNAME = "Web Service Handler";
 
 const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
 const TYPE_ANY = "*/*";
 
 const PREF_CONTENTHANDLERS_AUTO = "browser.contentHandlers.auto.";
@@ -920,18 +919,16 @@ WebContentConverterRegistrar.prototype =
         [Ci.nsIWebContentConverterService, Ci.nsIWebContentHandlerRegistrar,
          Ci.nsIObserver, Ci.nsIClassInfo, Ci.nsIFactory, Ci.nsISupports];
     countRef.value = interfaces.length;
     return interfaces;
   },
   getHelperForLanguage: function WCCR_getHelperForLanguage(language) {
     return null;
   },
-  contractID: WCCR_CONTRACTID,
-  classDescription: WCCR_CLASSNAME,
   classID: WCCR_CLASSID,
   implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
   flags: Ci.nsIClassInfo.DOM_OBJECT,
   
   /**
    * See nsISupports
    */
   QueryInterface: XPCOMUtils.generateQI(
@@ -943,12 +940,9 @@ WebContentConverterRegistrar.prototype =
       Ci.nsISupports]),
 
   _xpcom_categories: [{
     category: "app-startup",
     service: true
   }]
 };
 
-function NSGetModule(cm, file) {
-  return XPCOMUtils.generateModule([WebContentConverterRegistrar]);
-}
-
+var NSGetFactory = XPCOMUtils.generateNSGetFactory([WebContentConverterRegistrar]);
--- a/browser/components/feeds/src/nsFeedSniffer.cpp
+++ b/browser/components/feeds/src/nsFeedSniffer.cpp
@@ -418,24 +418,8 @@ nsFeedSniffer::OnDataAvailable(nsIReques
 }
 
 NS_IMETHODIMP
 nsFeedSniffer::OnStopRequest(nsIRequest* request, nsISupports* context, 
                              nsresult status)
 {
   return NS_OK; 
 }
-
-NS_METHOD
-nsFeedSniffer::Register(nsIComponentManager *compMgr, nsIFile *path, 
-                        const char *registryLocation,
-                        const char *componentType, 
-                        const nsModuleComponentInfo *info)
-{
-  nsresult rv;
-  nsCOMPtr<nsICategoryManager> catman = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
-  if (NS_FAILED(rv)) 
-    return rv;
-
-  return catman->AddCategoryEntry(NS_CONTENT_SNIFFER_CATEGORY, "Feed Sniffer", 
-                                  NS_FEEDSNIFFER_CONTRACTID, PR_TRUE, PR_TRUE, 
-                                  nsnull);
-}
--- a/browser/components/feeds/src/nsFeedSniffer.h
+++ b/browser/components/feeds/src/nsFeedSniffer.h
@@ -31,17 +31,16 @@
  * 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 "nsIGenericFactory.h"
 #include "nsIContentSniffer.h"
 #include "nsIStreamListener.h"
 #include "nsStringAPI.h"
 
 class nsFeedSniffer : public nsIContentSniffer, nsIStreamListener
 {
 public:
   NS_DECL_ISUPPORTS
@@ -51,21 +50,16 @@ public:
 
   static NS_METHOD AppendSegmentToString(nsIInputStream* inputStream,
                                          void* closure,
                                          const char* rawSegment,
                                          PRUint32 toOffset,
                                          PRUint32 count,
                                          PRUint32* writeCount);
 
-  static NS_METHOD Register(nsIComponentManager* compMgr, nsIFile* path, 
-                            const char* registryLocation,
-                            const char* componentType, 
-                            const nsModuleComponentInfo *info);
-
 protected:
   nsresult ConvertEncodedData(nsIRequest* request, const PRUint8* data,
                               PRUint32 length);
 
 private:
   nsCString mDecodedData;
 };
 
--- a/browser/components/nsBrowserContentHandler.js
+++ b/browser/components/nsBrowserContentHandler.js
@@ -31,29 +31,30 @@
 # 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 *****
 
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
 const nsISupports            = Components.interfaces.nsISupports;
 
 const nsIBrowserDOMWindow    = Components.interfaces.nsIBrowserDOMWindow;
 const nsIBrowserHandler      = Components.interfaces.nsIBrowserHandler;
 const nsIBrowserHistory      = Components.interfaces.nsIBrowserHistory;
 const nsIChannel             = Components.interfaces.nsIChannel;
 const nsICommandLine         = Components.interfaces.nsICommandLine;
 const nsICommandLineHandler  = Components.interfaces.nsICommandLineHandler;
 const nsIContentHandler      = Components.interfaces.nsIContentHandler;
 const nsIDocShellTreeItem    = Components.interfaces.nsIDocShellTreeItem;
 const nsIDOMChromeWindow     = Components.interfaces.nsIDOMChromeWindow;
 const nsIDOMWindow           = Components.interfaces.nsIDOMWindow;
-const nsIFactory             = Components.interfaces.nsIFactory;
 const nsIFileURL             = Components.interfaces.nsIFileURL;
 const nsIHttpProtocolHandler = Components.interfaces.nsIHttpProtocolHandler;
 const nsIInterfaceRequestor  = Components.interfaces.nsIInterfaceRequestor;
 const nsINetUtil             = Components.interfaces.nsINetUtil;
 const nsIPrefBranch          = Components.interfaces.nsIPrefBranch;
 const nsIPrefLocalizedString = Components.interfaces.nsIPrefLocalizedString;
 const nsISupportsString      = Components.interfaces.nsISupportsString;
 const nsIURIFixup            = Components.interfaces.nsIURIFixup;
@@ -319,24 +320,36 @@ function doSearch(searchTerm, cmdLine) {
   sa.AppendElement(submission.postData);
 
   // XXXbsmedberg: use handURIToExistingBrowser to obey tabbed-browsing
   // preferences, but need nsIBrowserDOMWindow extensions
 
   var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
                          .getService(nsIWindowWatcher);
 
-  return wwatch.openWindow(null, nsBrowserContentHandler.chromeURL,
+  return wwatch.openWindow(null, gBrowserContentHandler.chromeURL,
                            "_blank",
                            "chrome,dialog=no,all" +
-                             nsBrowserContentHandler.getFeatures(cmdLine),
+                           gBrowserContentHandler.getFeatures(cmdLine),
                            sa);
 }
 
-var nsBrowserContentHandler = {
+function nsBrowserContentHandler() {
+}
+nsBrowserContentHandler.prototype = {
+  classID: Components.ID("{5d0ce354-df01-421a-83fb-7ead0990c24e}"),
+
+  _xpcom_factory: {
+    createInstance: function bch_factory_ci(outer, iid) {
+      if (outer)
+        throw Components.results.NS_ERROR_NO_AGGREGATION;
+      return gBrowserContentHandler.QueryInterface(iid);
+    }
+  },
+
   /* helper functions */
 
   mChromeURL : null,
 
   get chromeURL() {
     if (this.mChromeURL) {
       return this.mChromeURL;
     }
@@ -344,27 +357,20 @@ var nsBrowserContentHandler = {
     var prefb = Components.classes["@mozilla.org/preferences-service;1"]
                           .getService(nsIPrefBranch);
     this.mChromeURL = prefb.getCharPref("browser.chromeURL");
 
     return this.mChromeURL;
   },
 
   /* nsISupports */
-  QueryInterface : function bch_QI(iid) {
-    if (!iid.equals(nsISupports) &&
-        !iid.equals(nsICommandLineHandler) &&
-        !iid.equals(nsIBrowserHandler) &&
-        !iid.equals(nsIContentHandler) &&
-        !iid.equals(nsICommandLineValidator) &&
-        !iid.equals(nsIFactory))
-      throw Components.results.NS_ERROR_NO_INTERFACE;
-
-    return this;
-  },
+  QueryInterface : XPCOMUtils.generateQI([nsICommandLineHandler,
+                                          nsIBrowserHandler,
+                                          nsIContentHandler,
+                                          nsICommandLineValidator]),
 
   /* nsICommandLineHandler */
   handle : function bch_handle(cmdLine) {
     if (cmdLine.handleFlag("browser", false)) {
       // Passing defaultArgs, so use NO_EXTERNAL_URIS
       openWindow(null, this.chromeURL, "_blank",
                  "chrome,dialog=no,all" + this.getFeatures(cmdLine),
                  this.defaultArgs, NO_EXTERNAL_URIS);
@@ -688,65 +694,55 @@ var nsBrowserContentHandler = {
     if (urlFlagIdx > -1 && (osintFlagIdx > -1 ||
         cmdLine.state == nsICommandLine.STATE_REMOTE_EXPLICIT)) {
       var urlParam = cmdLine.getArgument(urlFlagIdx + 1);
       if (cmdLine.length != urlFlagIdx + 2 || /firefoxurl:/.test(urlParam))
         throw NS_ERROR_ABORT;
       cmdLine.handleFlag("osint", false)
     }
   },
-
-  /* nsIFactory */
-  createInstance: function bch_CI(outer, iid) {
-    if (outer != null)
-      throw Components.results.NS_ERROR_NO_AGGREGATION;
+};
+var gBrowserContentHandler = new nsBrowserContentHandler();
 
-    return this.QueryInterface(iid);
-  },
-    
-  lockFactory : function bch_lock(lock) {
-    /* no-op */
-  }
-};
-
-const bch_contractID = "@mozilla.org/browser/clh;1";
-const bch_CID = Components.ID("{5d0ce354-df01-421a-83fb-7ead0990c24e}");
 const CONTRACTID_PREFIX = "@mozilla.org/uriloader/content-handler;1?type=";
 
 function handURIToExistingBrowser(uri, location, cmdLine)
 {
   if (!shouldLoadURI(uri))
     return;
 
   var navWin = getMostRecentBrowserWindow();
   if (!navWin) {
     // if we couldn't load it in an existing window, open a new one
-    openWindow(null, nsBrowserContentHandler.chromeURL, "_blank",
-               "chrome,dialog=no,all" + nsBrowserContentHandler.getFeatures(cmdLine),
+    openWindow(null, gBrowserContentHandler.chromeURL, "_blank",
+               "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine),
                uri.spec);
     return;
   }
 
   var navNav = navWin.QueryInterface(nsIInterfaceRequestor)
                      .getInterface(nsIWebNavigation);
   var rootItem = navNav.QueryInterface(nsIDocShellTreeItem).rootTreeItem;
   var rootWin = rootItem.QueryInterface(nsIInterfaceRequestor)
                         .getInterface(nsIDOMWindow);
   var bwin = rootWin.QueryInterface(nsIDOMChromeWindow).browserDOMWindow;
   bwin.openURI(uri, null, location,
                nsIBrowserDOMWindow.OPEN_EXTERNAL);
 }
 
+function nsDefaultCommandLineHandler() {
+}
 
-var nsDefaultCommandLineHandler = {
+nsDefaultCommandLineHandler.prototype = {
+  classID: Components.ID("{47cd0651-b1be-4a0f-b5c4-10e5a573ef71}"),
+
   /* nsISupports */
   QueryInterface : function dch_QI(iid) {
     if (!iid.equals(nsISupports) &&
-        !iid.equals(nsICommandLineHandler) &&
-        !iid.equals(nsIFactory))
+        !iid.equals(nsICommandLineHandler))
       throw Components.results.NS_ERROR_NO_INTERFACE;
 
     return this;
   },
 
   // List of uri's that were passed via the command line without the app
   // running and have already been handled. This is compared against uri's
   // opened using DDE on Win32 so we only open one of the requests.
@@ -838,155 +834,28 @@ var nsDefaultCommandLineHandler = {
           return;
         }
         catch (e) {
         }
       }
 
       var URLlist = urilist.filter(shouldLoadURI).map(function (u) u.spec);
       if (URLlist.length) {
-        openWindow(null, nsBrowserContentHandler.chromeURL, "_blank",
-                   "chrome,dialog=no,all" + nsBrowserContentHandler.getFeatures(cmdLine),
+        openWindow(null, gBrowserContentHandler.chromeURL, "_blank",
+                   "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine),
                    URLlist);
       }
 
     }
     else if (!cmdLine.preventDefault) {
       // Passing defaultArgs, so use NO_EXTERNAL_URIS
-      openWindow(null, nsBrowserContentHandler.chromeURL, "_blank",
-                 "chrome,dialog=no,all" + nsBrowserContentHandler.getFeatures(cmdLine),
-                 nsBrowserContentHandler.defaultArgs, NO_EXTERNAL_URIS);
+      openWindow(null, gBrowserContentHandler.chromeURL, "_blank",
+                 "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine),
+                 gBrowserContentHandler.defaultArgs, NO_EXTERNAL_URIS);
     }
   },
 
   // XXX localize me... how?
   helpInfo : "Usage: firefox [-flags] [<url>]\n",
-
-  /* nsIFactory */
-  createInstance: function dch_CI(outer, iid) {
-    if (outer != null)
-      throw Components.results.NS_ERROR_NO_AGGREGATION;
-
-    return this.QueryInterface(iid);
-  },
-    
-  lockFactory : function dch_lock(lock) {
-    /* no-op */
-  }
 };
 
-const dch_contractID = "@mozilla.org/browser/final-clh;1";
-const dch_CID = Components.ID("{47cd0651-b1be-4a0f-b5c4-10e5a573ef71}");
-
-var Module = {
-  /* nsISupports */
-  QueryInterface: function mod_QI(iid) {
-    if (iid.equals(Components.interfaces.nsIModule) ||
-        iid.equals(Components.interfaces.nsISupports))
-      return this;
-
-    throw Components.results.NS_ERROR_NO_INTERFACE;
-  },
-
-  /* nsIModule */
-  getClassObject: function mod_getco(compMgr, cid, iid) {
-    if (cid.equals(bch_CID))
-      return nsBrowserContentHandler.QueryInterface(iid);
-
-    if (cid.equals(dch_CID))
-      return nsDefaultCommandLineHandler.QueryInterface(iid);
-
-    throw Components.results.NS_ERROR_NO_INTERFACE;
-  },
-    
-  registerSelf: function mod_regself(compMgr, fileSpec, location, type) {
-    if (Components.classes["@mozilla.org/xre/app-info;1"]) {
-      // Don't register these if Firefox is launching a XULRunner application
-      const FIREFOX_UID = "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
-      var appInfo = Components.classes["@mozilla.org/xre/app-info;1"]
-                              .getService(Components.interfaces.nsIXULAppInfo);
-      if (appInfo.ID != FIREFOX_UID)
-        return;
-    }
-
-    var compReg =
-      compMgr.QueryInterface( Components.interfaces.nsIComponentRegistrar );
-
-    compReg.registerFactoryLocation( bch_CID,
-                                     "nsBrowserContentHandler",
-                                     bch_contractID,
-                                     fileSpec,
-                                     location,
-                                     type );
-    compReg.registerFactoryLocation( dch_CID,
-                                     "nsDefaultCommandLineHandler",
-                                     dch_contractID,
-                                     fileSpec,
-                                     location,
-                                     type );
-
-    function registerType(contentType) {
-      compReg.registerFactoryLocation( bch_CID,
-                                       "Browser Cmdline Handler",
-                                       CONTRACTID_PREFIX + contentType,
-                                       fileSpec,
-                                       location,
-                                       type );
-    }
-
-    registerType("text/html");
-    registerType("application/vnd.mozilla.xul+xml");
-#ifdef MOZ_SVG
-    registerType("image/svg+xml");
-#endif
-    registerType("text/rdf");
-    registerType("text/xml");
-    registerType("application/xhtml+xml");
-    registerType("text/css");
-    registerType("text/plain");
-    registerType("image/gif");
-    registerType("image/jpeg");
-    registerType("image/jpg");
-    registerType("image/png");
-    registerType("image/bmp");
-    registerType("image/x-icon");
-    registerType("image/vnd.microsoft.icon");
-    registerType("application/http-index-format");
-
-    var catMan = Components.classes["@mozilla.org/categorymanager;1"]
-                           .getService(nsICategoryManager);
-
-    catMan.addCategoryEntry("command-line-handler",
-                            "m-browser",
-                            bch_contractID, true, true);
-    catMan.addCategoryEntry("command-line-handler",
-                            "x-default",
-                            dch_contractID, true, true);
-    catMan.addCategoryEntry("command-line-validator",
-                            "b-browser",
-                            bch_contractID, true, true);
-  },
-    
-  unregisterSelf : function mod_unregself(compMgr, location, type) {
-    var compReg = compMgr.QueryInterface(nsIComponentRegistrar);
-    compReg.unregisterFactoryLocation(bch_CID, location);
-    compReg.unregisterFactoryLocation(dch_CID, location);
-
-    var catMan = Components.classes["@mozilla.org/categorymanager;1"]
-                           .getService(nsICategoryManager);
-
-    catMan.deleteCategoryEntry("command-line-handler",
-                               "m-browser", true);
-    catMan.deleteCategoryEntry("command-line-handler",
-                               "x-default", true);
-    catMan.deleteCategoryEntry("command-line-validator",
-                               "b-browser", true);
-  },
-
-  canUnload: function(compMgr) {
-    return true;
-  }
-};
-
-// NSGetModule: Return the nsIModule object.
-function NSGetModule(compMgr, fileSpec) {
-  return Module;
-}
+var components = [nsBrowserContentHandler, nsDefaultCommandLineHandler];
+var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1229,41 +1229,30 @@ BrowserGlue.prototype = {
         return win;
     }
     return null;
 #endif
   },
 
 
   // for XPCOM
-  classDescription: "Firefox Browser Glue Service",
   classID:          Components.ID("{eab9012e-5f74-4cbc-b2b5-a590235513cc}"),
-  contractID:       "@mozilla.org/browser/browserglue;1",
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference,
                                          Ci.nsIBrowserGlue]),
 
   // redefine the default factory for XPCOMUtils
   _xpcom_factory: BrowserGlueServiceFactory,
-
-  // get this contractID registered for certain categories via XPCOMUtils
-  _xpcom_categories: [
-    // make BrowserGlue a startup observer
-    { category: "app-startup", service: true,
-      apps: [ /* Firefox */ "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}" ] }
-  ]
 }
 
 function GeolocationPrompt() {}
 
 GeolocationPrompt.prototype = {
-  classDescription: "Geolocation Prompting Component",
   classID:          Components.ID("{C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5}"),
-  contractID:       "@mozilla.org/geolocation/prompt;1",
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIGeolocationPrompt]),
 
   prompt: function GP_prompt(request) {
     var requestingURI = request.requestingURI;
 
     // Ignore requests from non-nsIStandardURLs
     if (!(requestingURI instanceof Ci.nsIStandardURL))
@@ -1348,13 +1337,10 @@ GeolocationPrompt.prototype = {
     var chromeWin = getChromeWindow(requestingWindow).wrappedJSObject;
     var browser = chromeWin.gBrowser.getBrowserForDocument(requestingWindow.document);
 
     chromeWin.PopupNotifications.show(browser, "geolocation", message, "geo-notification-icon",
                                       mainAction, secondaryActions);
   },
 };
 
-
-//module initialization
-function NSGetModule(aCompMgr, aFileSpec) {
-  return XPCOMUtils.generateModule([BrowserGlue, GeolocationPrompt]);
-}
+var components = [BrowserGlue, GeolocationPrompt];
+var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
--- a/browser/components/places/Makefile.in
+++ b/browser/components/places/Makefile.in
@@ -38,17 +38,17 @@
 
 DEPTH		= ../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-DIRS = public src
+DIRS = src
 
 ifdef ENABLE_TESTS
 	DIRS += tests
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 XPIDL_FLAGS += -I$(topsrcdir)/browser/components/
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -490,17 +490,25 @@ PlacesViewBase.prototype = {
     // nothing to be done when the title changes.
     if (elt == this._rootElt)
       return;
 
     // Here we need the <menu>.
     if (elt.localName == "menupopup")
       elt = elt.parentNode;
 
-    elt.label = aNewTitle || PlacesUIUtils.getBestTitle(aPlacesNode);
+    if (!aNewTitle && elt.localName != "toolbarbutton") {
+      // Many users consider toolbars as shortcuts containers, so explicitly
+      // allow empty labels on toolbarbuttons.  For any other element try to be
+      // smarter, guessing a title from the uri.
+      elt.label = PlacesUIUtils.getBestTitle(aPlacesNode);
+    }
+    else {
+      elt.label = aNewTitle;
+    }
   },
 
   nodeRemoved:
   function PVB_nodeRemoved(aParentPlacesNode, aPlacesNode, aIndex) {
     let parentElt = aParentPlacesNode._DOMElement;
     let elt = aPlacesNode._DOMElement;
 
     if (!parentElt)
deleted file mode 100644
--- a/browser/components/places/public/Makefile.in
+++ /dev/null
@@ -1,52 +0,0 @@
-#
-# ***** 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 Places code.
-#
-# The Initial Developer of the Original Code is
-# Google Inc.
-# Portions created by the Initial Developer are Copyright (C) 2005
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#   Brett Wilson <brettw@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 *****
-
-DEPTH = ../../../..
-topsrcdir = @top_srcdir@
-srcdir = @srcdir@
-VPATH = @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-MODULE = browserplaces
-XPIDL_MODULE = browserplaces
-
-XPIDLSRCS  = nsIPlacesTransactionsService.idl \
-             $(NULL)
-
-include $(topsrcdir)/config/rules.mk
deleted file mode 100644
--- a/browser/components/places/public/nsIPlacesTransactionsService.idl
+++ /dev/null
@@ -1,381 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Places.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation
- *
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Sungjoon Steve Won <stevewon@gmail.com> (Original Author)
- *   Asaf Romano <mano@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 ***** */
-
-#include "nsISupports.idl"
-#include "nsITransactionManager.idl"
-
-interface nsIVariant;
-interface nsIURI;
-interface nsIMicrosummary;
-interface nsITransaction;
-
-/**
- * nsIPlacesTransactionService is a service designed to handle
- * nsITransactions that correspond to changes in Places. It is here as a
- * service so that we can keep the transactions around without holding onto
- * the global scope of a js window.
- *
- * NOTE: If you are interacting directly with the Places back-end, and you
- *       need to transactionalize a large amount of changes, look at
- *       nsINavBookmarksService.runInBatchMode.
- */
-
-[scriptable, uuid(32eee5da-2bc7-4d18-8a54-a8ff0dec4d2a)]
-interface nsIPlacesTransactionsService : nsITransactionManager
-{
-  /**
-   * Transaction for performing several Places Transactions in a single batch. 
-   * 
-   * @param aName
-   *        title of the aggregate transactions
-   * @param aTransactions
-   *        an array of transactions to perform
-   * @returns nsITransaction object
-   */
-  nsITransaction aggregateTransactions(in AString aName,
-                                       in nsIVariant aTransactions);
-
-  /**
-   * Transaction for creating a new folder item.
-   *
-   * @param aName
-   *        the name of the new folder
-   * @param aContainerId
-   *        the identifier of the folder in which the new folder should be
-   *        added.
-   * @param [optional] aIndex
-   *        the index of the item in aContainer, pass -1 or nothing to create
-   *        the item at the end of aContainer.
-   * @param [optional] aAnnotations
-   *        the annotations to set for the new folder.
-   * @param [optional] aChildItemsTransactions
-   *        array of transactions for items to be created under the new folder.
-   * @returns nsITransaction object
-   */
-  nsITransaction createFolder(in AString aName, in long long aContainerId,
-                              [optional] in long long aIndex,
-                              [optional] in nsIVariant aAnnotations,
-                              [optional] in nsIVariant aChildItemsTransactions);
-
-  /**
-   * Transaction for creating a new bookmark item
-   *
-   * @param aURI
-   *        the uri of the new bookmark (nsIURI)
-   * @param aContainerId
-   *        the identifier of the folder in which the bookmark should be added.
-   * @param [optional] aIndex
-   *        the index of the item in aContainer, pass -1 or nothing to create
-   *        the item at the end of aContainer.
-   * @param [optional] aTitle
-   *        the title of the new bookmark.
-   * @param [optional] aKeyword
-   *        the keyword of the new bookmark.
-   * @param [optional] aAnnotations
-   *        the annotations to set for the new bookmark.
-   * @param [optional] aChildTransactions
-   *        child transactions to commit after creating the bookmark. Prefer
-   *        using any of the arguments above if possible. In general, a child
-   *        transations should be used only if the change it does has to be
-   *        reverted manually when removing the bookmark item.
-   *        a child transaction must support setting its bookmark-item
-   *        identifier via an "id" js setter.
-   * @returns nsITransaction object
-   */
-  nsITransaction createItem(in nsIURI aURI, in long long aContainerId,
-                            [optional] in long long aIndex,
-                            [optional] in AString aTitle,
-                            [optional] in AString aKeyword,
-                            [optional] in nsIVariant aAnnotations,
-                            [optional] in nsIVariant aChildTransactions);
-
-  /**
-   * Transaction for creating a new separator item
-   *
-   * @param aContainerId
-   *        the identifier of the folder in which the separator should be
-   *        added.
-   * @param [optional] aIndex
-   *        the index of the item in aContainer, pass -1 or nothing to create
-   *        the separator at the end of aContainer.
-   * @returns nsITransaction object
-   */
-  nsITransaction createSeparator(in long long aContainerId,
-                                 [optional] in long long aIndex);
-
-  /**
-   * Transaction for creating a new live-bookmark item.
-   *
-   * @see nsILivemarksService::createLivemark for documentation regarding the
-   * first three arguments.
-   *
-   * @param aContainerId
-   *        the identifier of the folder in which the live-bookmark should be
-   *        added.
-   * @param [optional]  aIndex
-   *        the index of the item in aContainer, pass -1 or nothing to create
-   *        the item at the end of aContainer.
-   * @param [optional] aAnnotations
-   *        the annotations to set for the new live-bookmark.
-   * @returns nsITransaction object
-   */
-  nsITransaction createLivemark(in nsIURI aFeedURI,
-                                in nsIURI aSiteURI,
-                                in AString aName,
-                                in long long aContainerId,
-                                [optional] in long long aIndex,
-                                [optional] in nsIVariant aAnnotations);
-
-  /**
-   * Transaction for moving an Item.
-   *
-   * @param aItemId
-   *        the id of the item to move
-   * @param aNewContainerId
-   *        id of the new container to move to
-   * @param aNewIndex
-   *        index of the new position to move to
-   * @returns nsITransaction object
-   */
-  nsITransaction moveItem(in long long aItemId,
-                          in long long aNewContainerId,
-                          in long long aNewIndex);
-
-  /**
-   * Transaction for removing an Item
-   *
-   * @param aItemId
-   *        id of the item to remove
-   * @returns nsITransaction object
-   */
-  nsITransaction removeItem(in long long aItemId);
-
-  /**
-   * Transaction for editting a bookmark's title.
-   *
-   * @param aItemId
-   *        id of the item to edit
-   * @param aNewTitle
-   *        new title for the item to edit
-   * @returns nsITransaction object
-   */
-  nsITransaction editItemTitle(in long long aItemId, in AString aNewTitle);
-
-  /**
-   * Transaction for editing a bookmark's uri.
-   *
-   * @param aBookmarkId
-   *        id of the bookmark to edit
-   * @param aNewURI
-   *        new uri for the bookmark
-   * @returns nsITransaction object
-   */
-  nsITransaction editBookmarkURI(in long long aBookmarkId, in nsIURI aNewURI);
-
-  /**
-   * Transaction for setting/unsetting an item annotation
-   *
-   * @param aItemId
-   *        id of the item where to set annotation
-   * @param aAnnotationObject
-   *        Object representing an annotation, containing the following
-   *        properties: name, flags, expires, type, mimeType (only used for
-   *        binary annotations), value.
-   *        If value is null the annotation will be removed
-   * @returns nsITransaction object
-   */
-  nsITransaction setItemAnnotation(in nsIVariant aItemId,
-                                   in nsIVariant aAnnotationObject);
-
-  /**
-   * Transaction for setting/unsetting a page annotation
-   *
-   * @param aURI
-   *        URI of the page where to set annotation
-   * @param aAnnotationObject
-   *        Object representing an annotation, containing the following
-   *        properties: name, flags, expires, type, mimeType (only used for
-   *        binary annotations), value.
-   *        If value is null the annotation will be removed
-   * @returns nsITransaction object
-   */
-  nsITransaction setPageAnnotation(in nsIURI aURI,
-                                   in nsIVariant aAnnotationObject);
-
-  /**
-   * Transaction for setting/unsetting Load-in-sidebar annotation
-   *
-   * @param aBookmarkId
-   *        id of the bookmark where to set Load-in-sidebar annotation
-   * @param aLoadInSidebar
-   *        boolean value
-   * @returns nsITransaction object
-   */
-  nsITransaction setLoadInSidebar(in long long aBookmarkId,
-                                  in boolean aLoadInSidebar);
-
-  /**
-   * Transaction for editing a the description of a bookmark or a folder
-   * 
-   * @param aItemId
-   *        id of the item to edit
-   * @param aDescription
-   *        new description
-   * @returns nsITransaction object
-   */
-  nsITransaction editItemDescription(in long long aItemId,
-                                     in AString aDescription);
-
-  /**
-   * Transaction for editing a bookmark's keyword.
-   *
-   * @param aBookmarkId
-   *        id of the bookmark to edit
-   * @param aNewKeyword
-   *        new keyword for the bookmark
-   * @returns nsITransaction object
-   */
-  nsITransaction editBookmarkKeyword(in long long aBookmarkId,
-                                     in AString aNewKeyword);
-
-  /**
-   * Transaction for editing the post data associated with a bookmark.
-   *
-   * @param aBookmarkId
-   *        id of the bookmark to edit
-   * @param aPostData
-   *        post data
-   * @returns nsITransaction object
-   */
-  nsITransaction editBookmarkPostData(in long long aBookmarkId,
-                                      in AString aPostData);
-
-  /**
-   * Transaction for editing a live bookmark's site URI.
-   *
-   * @param aLivemarkId
-   *        id of the livemark
-   * @param aURI
-   *        new site uri
-   * @returns nsITransaction object
-   */
-  nsITransaction editLivemarkSiteURI(in long long aLivemarkId, in nsIURI aURI);
-
-  /**
-   * Transaction for editting a live bookmark's feed URI.
-   *
-   * @param aLivemarkId
-   *        id of the livemark
-   * @param aURI
-   *        new feed uri
-   * @returns nsITransaction object
-   */
-  nsITransaction editLivemarkFeedURI(in long long aLivemarkId, in nsIURI aURI);
-
-  /**
-   * Transaction for editing a bookmark's microsummary.
-   *
-   * @param aBookmarkId
-   *        id of the bookmark to edit
-   * @param aNewMicrosummary
-   *        new microsummary for the bookmark
-   * @returns nsITransaction object
-   */
-  nsITransaction editBookmarkMicrosummary(in long long aBookmarkId,
-                                          in nsIMicrosummary aNewMicrosummary);
-
-  /**
-   * Transaction for editing an item's date added property.
-   *
-   * @param aItemId
-   *        id of the item to edit
-   * @param aNewDateAdded
-   *        new date added for the item 
-   * @returns nsITransaction object
-   */
-  nsITransaction editItemDateAdded(in long long aItemId,
-                                   in PRTime aNewDateAdded);
-
-  /**
-   * Transaction for editing an item's last modified time.
-   *
-   * @param aItemId
-   *        id of the item to edit
-   * @param aNewLastModified
-   *        new last modified date for the item 
-   * @returns nsITransaction object
-   */
-  nsITransaction editItemLastModified(in long long aItemId,
-                                      in PRTime aNewLastModified);
-
-  /**
-   * Transaction for sorting a folder by name
-   *
-   * @param aFolderId
-   *        id of the folder to sort
-   * @returns nsITransaction object
-   */
-  nsITransaction sortFolderByName(in long long aFolderId);
-
-  /**
-   * Transaction for tagging a URL with the given set of tags. Current tags set
-   * for the URL persist. It's the caller's job to check whether or not aURI
-   * was already tagged by any of the tags in aTags, undoing this tags
-   * transaction removes them all from aURL!
-   *
-   * @param aURI
-   *        the URL to tag.
-   * @param aTags
-   *        Array of tags to set for the given URL.
-   */
-  nsITransaction tagURI(in nsIURI aURI, in nsIVariant aTags);
-
-  /**
-   * Transaction for removing tags from a URL. It's the caller's job to check
-   * whether or not aURI isn't tagged by any of the tags in aTags, undoing this
-   * tags transaction adds them all to aURL!
-   *
-   * @param aURI
-   *        the URL to un-tag.
-   * @param aTags
-   *        Array of tags to unset. pass null to remove all tags from the given
-   *        url.
-   */
-  nsITransaction untagURI(in nsIURI aURI, in nsIVariant aTags);
-};
new file mode 100644
--- /dev/null
+++ b/browser/components/places/src/BrowserPlaces.manifest
@@ -0,0 +1,2 @@
+component {6bcb9bde-9018-4443-a071-c32653469597} PlacesProtocolHandler.js
+contract @mozilla.org/network/protocol;1?name=place {6bcb9bde-9018-4443-a071-c32653469597}
--- a/browser/components/places/src/Makefile.in
+++ b/browser/components/places/src/Makefile.in
@@ -40,17 +40,17 @@
 DEPTH = ../../../..
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 EXTRA_COMPONENTS = \
-  nsPlacesTransactionsService.js \
+  BrowserPlaces.manifest \
   PlacesProtocolHandler.js \
   $(NULL)
 
 EXTRA_JS_MODULES = \
   PlacesUIUtils.jsm \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/components/places/src/PlacesProtocolHandler.js
+++ b/browser/components/places/src/PlacesProtocolHandler.js
@@ -71,18 +71,12 @@ PlacesProtocolHandler.prototype = {
   allowPort: function PPH_allowPort(aPort, aScheme) {
     return false;
   },
 
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsIProtocolHandler
   ]),
 
-  classDescription: "Places Protocol Handler",
-  contractID: "@mozilla.org/network/protocol;1?name=" + SCHEME,
   classID: Components.ID("{6bcb9bde-9018-4443-a071-c32653469597}")
 };
 
-function NSGetModule(aCompMgr, aFileSpec) {
-  return XPCOMUtils.generateModule([
-    PlacesProtocolHandler
-  ]);
-}
+var NSGetFactory = XPCOMUtils.generateNSGetFactory([PlacesProtocolHandler]);
--- a/browser/components/places/src/PlacesUIUtils.jsm
+++ b/browser/components/places/src/PlacesUIUtils.jsm
@@ -67,38 +67,38 @@ var PlacesUIUtils = {
 
   /**
    * Makes a URI from a spec, and do fixup
    * @param   aSpec
    *          The string spec of the URI
    * @returns A URI object for the spec.
    */
   createFixedURI: function PUIU_createFixedURI(aSpec) {
-    return this.URIFixup.createFixupURI(aSpec, 0);
+    return URIFixup.createFixupURI(aSpec, 0);
   },
 
   /**
    * Wraps a string in a nsISupportsString wrapper
    * @param   aString
    *          The string to wrap
    * @returns A nsISupportsString object containing a string.
    */
   _wrapString: function PUIU__wrapString(aString) {
     var s = Cc["@mozilla.org/supports-string;1"].
             createInstance(Ci.nsISupportsString);
     s.data = aString;
     return s;
   },
 
   getFormattedString: function PUIU_getFormattedString(key, params) {
-    return this._bundle.formatStringFromName(key, params, params.length);
+    return bundle.formatStringFromName(key, params, params.length);
   },
 
   getString: function PUIU_getString(key) {
-    return this._bundle.GetStringFromName(key);
+    return bundle.GetStringFromName(key);
   },
 
   /**
    * Get a transaction for copying a uri item from one container to another
    * as a bookmark.
    * @param   aData
    *          JSON object of dropped or pasted item properties
    * @param   aContainer
@@ -655,17 +655,17 @@ var PlacesUIUtils = {
     return ("performed" in aInfo && aInfo.performed);
   },
 
   _getTopBrowserWin: function PUIU__getTopBrowserWin() {
     return Services.wm.getMostRecentWindow("navigator:browser");
   },
 
   _getCurrentActiveWin: function PUIU__getCurrentActiveWin() {
-    return this.fm.activeWindow;
+    return focusManager.activeWindow;
   },
 
   /**
    * Returns the closet ancestor places view for the given DOM node
    * @param aNode
    *        a DOM node
    * @return the closet ancestor places view if exists, null otherwsie.
    */
@@ -1216,17 +1216,17 @@ var PlacesUIUtils = {
    *
    * @param aItemId id of a container
    * @returns the name of the query, or empty string if not a left-pane query
    */
   getLeftPaneQueryNameFromId: function PUIU_getLeftPaneQueryNameFromId(aItemId) {
     var queryName = "";
     // If the let pane hasn't been built, use the annotation service
     // directly, to avoid building the left pane too early.
-    if (this.__lookupGetter__("leftPaneFolderId")) {
+    if (Object.getOwnPropertyDescriptor(this, "leftPaneFolderId").value === undefined) {
       try {
         queryName = PlacesUtils.annotations.
                                 getItemAnnotation(aItemId, this.ORGANIZER_QUERY_ANNO);
       }
       catch (ex) {
         // doesn't have the annotation
         queryName = "";
       }
@@ -1235,48 +1235,214 @@ var PlacesUIUtils = {
       // If the left pane has already been built, use the name->id map
       // cached in PlacesUIUtils.
       for (let [name, id] in Iterator(this.leftPaneQueries)) {
         if (aItemId == id)
           queryName = name;
       }
     }
     return queryName; 
-  },
-
+  }
 };
 
 XPCOMUtils.defineLazyServiceGetter(PlacesUIUtils, "RDF",
                                    "@mozilla.org/rdf/rdf-service;1",
                                    "nsIRDFService");
 
 XPCOMUtils.defineLazyGetter(PlacesUIUtils, "localStore", function() {
   return PlacesUIUtils.RDF.GetDataSource("rdf:local-store");
 });
 
-XPCOMUtils.defineLazyServiceGetter(PlacesUIUtils, "ptm",
-                                   "@mozilla.org/browser/placesTransactionsService;1",
-                                   "nsIPlacesTransactionsService");
-
-XPCOMUtils.defineLazyServiceGetter(PlacesUIUtils, "URIFixup",
-                                   "@mozilla.org/docshell/urifixup;1",
-                                   "nsIURIFixup");
-
 XPCOMUtils.defineLazyGetter(PlacesUIUtils, "ellipsis", function() {
   return Services.prefs.getComplexValue("intl.ellipsis",
                                         Ci.nsIPrefLocalizedString).data;
 });
 
 XPCOMUtils.defineLazyServiceGetter(PlacesUIUtils, "privateBrowsing",
                                    "@mozilla.org/privatebrowsing;1",
                                    "nsIPrivateBrowsingService");
 
-XPCOMUtils.defineLazyGetter(PlacesUIUtils, "_bundle", function() {
+XPCOMUtils.defineLazyServiceGetter(this, "URIFixup",
+                                   "@mozilla.org/docshell/urifixup;1",
+                                   "nsIURIFixup");
+
+XPCOMUtils.defineLazyGetter(this, "bundle", function() {
   const PLACES_STRING_BUNDLE_URI =
     "chrome://browser/locale/places/places.properties";
   return Cc["@mozilla.org/intl/stringbundle;1"].
          getService(Ci.nsIStringBundleService).
          createBundle(PLACES_STRING_BUNDLE_URI);
 });
 
-XPCOMUtils.defineLazyServiceGetter(PlacesUIUtils, "fm",
+XPCOMUtils.defineLazyServiceGetter(this, "focusManager",
                                    "@mozilla.org/focus-manager;1",
                                    "nsIFocusManager");
+
+/**
+ * This is a compatibility shim for old PUIU.ptm users.
+ *
+ * If you're looking for transactions and writing new code using them, directly
+ * use the transactions objects exported by the PlacesUtils.jsm module.
+ *
+ * This object will be removed once enough users are converted to the new API.
+ */
+XPCOMUtils.defineLazyGetter(PlacesUIUtils, "ptm", function() {
+  // Ensure PlacesUtils is imported in scope.
+  PlacesUtils;
+
+  return {
+    aggregateTransactions: function(aName, aTransactions)
+      new PlacesAggregatedTransaction(aName, aTransactions),
+
+    createFolder: function(aName, aContainer, aIndex, aAnnotations,
+                           aChildItemsTransactions)
+      new PlacesCreateFolderTransaction(aName, aContainer, aIndex, aAnnotations,
+                                        aChildItemsTransactions),
+
+    createItem: function(aURI, aContainer, aIndex, aTitle, aKeyword,
+                         aAnnotations, aChildTransactions)
+      new PlacesCreateBookmarkTransaction(aURI, aContainer, aIndex, aTitle,
+                                          aKeyword, aAnnotations,
+                                          aChildTransactions),
+
+    createSeparator: function(aContainer, aIndex)
+      new PlacesCreateSeparatorTransaction(aContainer, aIndex),
+
+    createLivemark: function(aFeedURI, aSiteURI, aName, aContainer, aIndex,
+                             aAnnotations)
+      new PlacesCreateLivemarkTransaction(aFeedURI, aSiteURI, aName, aContainer,
+                                          aIndex, aAnnotations),
+
+    moveItem: function(aItemId, aNewContainer, aNewIndex)
+      new PlacesMoveItemTransaction(aItemId, aNewContainer, aNewIndex),
+
+    removeItem: function(aItemId)
+      new PlacesRemoveItemTransaction(aItemId),
+
+    editItemTitle: function(aItemId, aNewTitle)
+      new PlacesEditItemTitleTransaction(aItemId, aNewTitle),
+
+    editBookmarkURI: function(aItemId, aNewURI)
+      new PlacesEditBookmarkURITransaction(aItemId, aNewURI),
+
+    setItemAnnotation: function(aItemId, aAnnotationObject)
+      new PlacesSetItemAnnotationTransaction(aItemId, aAnnotationObject),
+
+    setPageAnnotation: function(aURI, aAnnotationObject)
+      new PlacesSetPageAnnotationTransaction(aURI, aAnnotationObject),
+
+    editBookmarkKeyword: function(aItemId, aNewKeyword)
+      new PlacesEditBookmarkKeywordTransaction(aItemId, aNewKeyword),
+
+    editBookmarkPostData: function(aItemId, aPostData)
+      new PlacesEditBookmarkPostDataTransaction(aItemId, aPostData),
+
+    editLivemarkSiteURI: function(aLivemarkId, aSiteURI)
+      new PlacesEditLivemarkSiteURITransaction(aLivemarkId, aSiteURI),
+
+    editLivemarkFeedURI: function(aLivemarkId, aFeedURI)
+      new PlacesEditLivemarkFeedURITransaction(aLivemarkId, aFeedURI),
+
+    editBookmarkMicrosummary: function(aItemId, aNewMicrosummary)
+      new PlacesEditBookmarkMicrosummaryTransaction(aItemId, aNewMicrosummary),
+
+    editItemDateAdded: function(aItemId, aNewDateAdded)
+      new PlacesEditItemDateAddedTransaction(aItemId, aNewDateAdded),
+
+    editItemLastModified: function(aItemId, aNewLastModified)
+      new PlacesEditItemLastModifiedTransaction(aItemId, aNewLastModified),
+
+    sortFolderByName: function(aFolderId)
+      new PlacesSortFolderByNameTransaction(aFolderId),
+
+    tagURI: function(aURI, aTags)
+      new PlacesTagURITransaction(aURI, aTags),
+
+    untagURI: function(aURI, aTags)
+      new PlacesUntagURITransaction(aURI, aTags),
+
+    /**
+     * Transaction for setting/unsetting Load-in-sidebar annotation.
+     *
+     * @param aBookmarkId
+     *        id of the bookmark where to set Load-in-sidebar annotation.
+     * @param aLoadInSidebar
+     *        boolean value.
+     * @returns nsITransaction object.
+     */
+    setLoadInSidebar: function(aItemId, aLoadInSidebar)
+    {
+      let annoObj = { name: PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO,
+                      type: Ci.nsIAnnotationService.TYPE_INT32,
+                      flags: 0,
+                      value: aLoadInSidebar,
+                      expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
+      return new PlacesSetItemAnnotationTransaction(aItemId, annoObj);
+    },
+
+   /**
+    * Transaction for editing a the description of a bookmark or a folder.
+    * 
+    * @param aItemId
+    *        id of the item to edit.
+    * @param aDescription
+    *        new description.
+    * @returns nsITransaction object.
+    */
+    editItemDescription: function(aItemId, aDescription)
+    {
+      let annoObj = { name: PlacesUIUtils.DESCRIPTION_ANNO,
+                      type: Ci.nsIAnnotationService.TYPE_STRING,
+                      flags: 0,
+                      value: aDescription,
+                      expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
+      return new PlacesSetItemAnnotationTransaction(aItemId, annoObj);
+    },
+
+    ////////////////////////////////////////////////////////////////////////////
+    //// nsITransactionManager forwarders.
+
+    beginBatch: function()
+      PlacesUtils.transactionManager.beginBatch(),
+
+    endBatch: function()
+      PlacesUtils.transactionManager.endBatch(),
+
+    doTransaction: function(txn)
+      PlacesUtils.transactionManager.doTransaction(txn),
+
+    undoTransaction: function()
+      PlacesUtils.transactionManager.undoTransaction(),
+
+    redoTransaction: function()
+      PlacesUtils.transactionManager.redoTransaction(),
+
+    get numberOfUndoItems()
+      PlacesUtils.transactionManager.numberOfUndoItems,
+    get numberOfRedoItems()
+      PlacesUtils.transactionManager.numberOfRedoItems,
+    get maxTransactionCount()
+      PlacesUtils.transactionManager.maxTransactionCount,
+    set maxTransactionCount(val)
+      PlacesUtils.transactionManager.maxTransactionCount = val,
+
+    clear: function()
+      PlacesUtils.transactionManager.clear(),
+
+    peekUndoStack: function()
+      PlacesUtils.transactionManager.peekUndoStack(),
+
+    peekRedoStack: function()
+      PlacesUtils.transactionManager.peekRedoStack(),
+
+    getUndoStack: function()
+      PlacesUtils.transactionManager.getUndoStack(),
+
+    getRedoStack: function()
+      PlacesUtils.transactionManager.getRedoStack(),
+
+    AddListener: function(aListener)
+      PlacesUtils.transactionManager.AddListener(aListener),
+
+    RemoveListener: function(aListener)
+      PlacesUtils.transactionManager.RemoveListener(aListener)
+  }
+});
deleted file mode 100644
--- a/browser/components/places/src/nsPlacesTransactionsService.js
+++ /dev/null
@@ -1,1193 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Places Command Controller.
- *
- * The Initial Developer of the Original Code is Google Inc.
- *
- * Portions created by the Initial Developer are Copyright (C) 2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Sungjoon Steve Won <stevewon@gmail.com> (Original Author)
- *   Asaf Romano <mano@mozilla.com>
- *   Marco Bonarco <mak77@bonardo.net>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-let Ci = Components.interfaces;
-let Cc = Components.classes;
-let Cr = Components.results;
-let Cu = Components.utils;
-
-const LOAD_IN_SIDEBAR_ANNO = "bookmarkProperties/loadInSidebar";
-const DESCRIPTION_ANNO = "bookmarkProperties/description";
-
-const CLASS_ID = Components.ID("c0844a84-5a12-4808-80a8-809cb002bb4f");
-const CONTRACT_ID = "@mozilla.org/browser/placesTransactionsService;1";
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyGetter(this, "Services", function() {
-  Cu.import("resource://gre/modules/Services.jsm");
-  return Services;
-});
-
-XPCOMUtils.defineLazyGetter(this, "PlacesUtils", function() {
-  Cu.import("resource://gre/modules/PlacesUtils.jsm");
-  return PlacesUtils;
-});
-
-// The minimum amount of transactions we should tell our observers to begin
-// batching (rather than letting them do incremental drawing).
-const MIN_TRANSACTIONS_FOR_BATCH = 5;
-
-function placesTransactionsService() {
-  Services.obs.addObserver(this, PlacesUtils.TOPIC_SHUTDOWN, false);
-  this.mTransactionManager = Cc["@mozilla.org/transactionmanager;1"].
-                             createInstance(Ci.nsITransactionManager);
-}
-
-placesTransactionsService.prototype = {
-  classDescription: "Places Transaction Manager",
-  classID: CLASS_ID,
-  contractID: CONTRACT_ID,
-
-  QueryInterface: XPCOMUtils.generateQI([
-    Ci.nsIPlacesTransactionsService,
-    Ci.nsITransactionManager,
-    Ci.nsIObserver,
-  ]),
-
-  // nsIObserver
-  observe: function PlacesTxn_observe(aSubject, aTopic, aData) {
-    if (aTopic == PlacesUtils.TOPIC_SHUTDOWN) {
-      Services.obs.removeObserver(this, PlacesUtils.TOPIC_SHUTDOWN);
-      delete this.mTransactionManager;
-    }
-  },
-
-  aggregateTransactions:
-  function placesTxn_aggregateTransactions(aName, aTransactions) {
-    return new placesAggregateTransactions(aName, aTransactions);
-  },
-
-  createFolder:
-  function placesTxn_createFolder(aName, aContainer, aIndex,
-                                  aAnnotations, aChildItemsTransactions) {
-     return new placesCreateFolderTransactions(aName, aContainer, aIndex,
-                                               aAnnotations, aChildItemsTransactions);
-  },
-
-  createItem:
-  function placesTxn_createItem(aURI, aContainer, aIndex, aTitle,
-                                aKeyword, aAnnotations, aChildTransactions) {
-    return new placesCreateItemTransactions(aURI, aContainer, aIndex, aTitle,
-                                            aKeyword, aAnnotations, aChildTransactions);
-  },
-
-  createSeparator:
-  function placesTxn_createSeparator(aContainer, aIndex) {
-    return new placesCreateSeparatorTransactions(aContainer, aIndex);
-  },
-
-  createLivemark:
-  function placesTxn_createLivemark(aFeedURI, aSiteURI, aName,
-                                    aContainer, aIndex, aAnnotations) {
-    return new placesCreateLivemarkTransactions(aFeedURI, aSiteURI, aName,
-                                                aContainer, aIndex, aAnnotations);
-  },
-
-  moveItem:
-  function placesTxn_moveItem(aItemId, aNewContainer, aNewIndex) {
-    return new placesMoveItemTransactions(aItemId, aNewContainer, aNewIndex);
-  },
-
-  removeItem:
-  function placesTxn_removeItem(aItemId) {
-    if (aItemId == PlacesUtils.tagsFolderId ||
-        aItemId == PlacesUtils.placesRootId ||
-        aItemId == PlacesUtils.bookmarksMenuFolderId ||
-        aItemId == PlacesUtils.toolbarFolderId)
-      throw Cr.NS_ERROR_INVALID_ARG;
-
-    // if the item lives within a tag container, use the tagging transactions
-    var parent = PlacesUtils.bookmarks.getFolderIdForItem(aItemId);
-    var grandparent = PlacesUtils.bookmarks.getFolderIdForItem(parent);
-    if (grandparent == PlacesUtils.tagsFolderId) {
-      var uri = PlacesUtils.bookmarks.getBookmarkURI(aItemId);
-      return this.untagURI(uri, [parent]);
-    }
-    
-    // if the item is a livemark container we will not save its children and
-    // will use createLivemark to undo.
-    if (PlacesUtils.itemIsLivemark(aItemId))
-      return new placesRemoveLivemarkTransaction(aItemId);
-
-    return new placesRemoveItemTransaction(aItemId);
-  },
-
-  editItemTitle:
-  function placesTxn_editItemTitle(aItemId, aNewTitle) {
-    return new placesEditItemTitleTransactions(aItemId, aNewTitle);
-  },
-
-  editBookmarkURI:
-  function placesTxn_editBookmarkURI(aItemId, aNewURI) {
-    return new placesEditBookmarkURITransactions(aItemId, aNewURI);
-  },
-
-  setItemAnnotation:
-  function placesTxn_setItemAnnotation(aItemId, aAnnotationObject) {
-    return new placesSetItemAnnotationTransactions(aItemId, aAnnotationObject);
-  },
-
-  setPageAnnotation:
-  function placesTxn_setPageAnnotation(aURI, aAnnotationObject) {
-    return new placesSetPageAnnotationTransactions(aURI, aAnnotationObject);
-  },
-
-  setLoadInSidebar:
-  function placesTxn_setLoadInSidebar(aItemId, aLoadInSidebar) {
-    var annoObj = { name: LOAD_IN_SIDEBAR_ANNO,
-                    type: Ci.nsIAnnotationService.TYPE_INT32,
-                    flags: 0,
-                    value: aLoadInSidebar,
-                    expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
-    return this.setItemAnnotation(aItemId, annoObj);
-  },
-
-  editItemDescription:
-  function placesTxn_editItemDescription(aItemId, aDescription) {
-    var annoObj = { name: DESCRIPTION_ANNO,
-                    type: Ci.nsIAnnotationService.TYPE_STRING,
-                    flags: 0,
-                    value: aDescription,
-                    expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
-    return this.setItemAnnotation(aItemId, annoObj);
-  },
-
-  editBookmarkKeyword:
-  function placesTxn_editBookmarkKeyword(aItemId, aNewKeyword) {
-    return new placesEditBookmarkKeywordTransactions(aItemId, aNewKeyword);
-  },
-
-  editBookmarkPostData:
-  function placesTxn_editBookmarkPostdata(aItemId, aPostData) {
-    return new placesEditBookmarkPostDataTransactions(aItemId, aPostData);
-  },
-
-  editLivemarkSiteURI:
-  function placesTxn_editLivemarkSiteURI(aLivemarkId, aSiteURI) {
-    return new placesEditLivemarkSiteURITransactions(aLivemarkId, aSiteURI);
-  },
-
-  editLivemarkFeedURI:
-  function placesTxn_editLivemarkFeedURI(aLivemarkId, aFeedURI) {
-    return new placesEditLivemarkFeedURITransactions(aLivemarkId, aFeedURI);
-  },
-
-  editBookmarkMicrosummary:
-  function placesTxn_editBookmarkMicrosummary(aItemId, aNewMicrosummary) {
-    return new placesEditBookmarkMicrosummaryTransactions(aItemId, aNewMicrosummary);
-  },
-
-  editItemDateAdded:
-  function placesTxn_editItemDateAdded(aItemId, aNewDateAdded) {
-    return new placesEditItemDateAddedTransaction(aItemId, aNewDateAdded);
-  },
-
-  editItemLastModified:
-  function placesTxn_editItemLastModified(aItemId, aNewLastModified) {
-    return new placesEditItemLastModifiedTransaction(aItemId, aNewLastModified);
-  },
-
-  sortFolderByName:
-  function placesTxn_sortFolderByName(aFolderId) {
-    return new placesSortFolderByNameTransactions(aFolderId);
-  },
-
-  tagURI:
-  function placesTxn_tagURI(aURI, aTags) {
-    return new placesTagURITransaction(aURI, aTags);
-  },
-
-  untagURI:
-  function placesTxn_untagURI(aURI, aTags) {
-    return new placesUntagURITransaction(aURI, aTags);
-  },
-
-  // Update commands in the undo group of the active window
-  // commands in inactive windows will are updated on-focus
-  _updateCommands: function placesTxn__updateCommands() {
-    var win = Services.wm.getMostRecentWindow(null);
-    if (win)
-      win.updateCommands("undo");
-  },
-
-  // nsITransactionManager
-  beginBatch: function() {
-    this.mTransactionManager.beginBatch();
-
-    // A no-op transaction is pushed to the stack, in order to make safe and
-    // easy to implement "Undo" an unknown number of transactions (including 0),
-    // "above" beginBatch and endBatch. Otherwise,implementing Undo that way
-    // head to dataloss: for example, if no changes were done in the
-    // edit-item panel, the last transaction on the undo stack would be the
-    // initial createItem transaction, or even worse, the batched editing of
-    // some other item.
-    // DO NOT MOVE this to the window scope, that would leak (bug 490068)! 
-    this.doTransaction({ doTransaction: function() { },
-                         undoTransaction: function() { },
-                         redoTransaction: function() { },
-                         isTransient: false,
-                         merge: function() { return false; } });
-  },
-
-  endBatch: function() this.mTransactionManager.endBatch(),
-
-  doTransaction: function placesTxn_doTransaction(txn) {
-    this.mTransactionManager.doTransaction(txn);
-    this._updateCommands();
-  },
-
-  undoTransaction: function placesTxn_undoTransaction() {
-    this.mTransactionManager.undoTransaction();
-    this._updateCommands();
-  },
-
-  redoTransaction: function placesTxn_redoTransaction() {
-    this.mTransactionManager.redoTransaction();
-    this._updateCommands();
-  },
-
-  clear: function() this.mTransactionManager.clear(),
-
-  get numberOfUndoItems() {
-    return this.mTransactionManager.numberOfUndoItems;
-  },
-
-  get numberOfRedoItems() {
-    return this.mTransactionManager.numberOfRedoItems;
-  },
-
-  get maxTransactionCount() {
-    return this.mTransactionManager.maxTransactionCount;
-  },
-  set maxTransactionCount(val) {
-    return this.mTransactionManager.maxTransactionCount = val;
-  },
-
-  peekUndoStack: function() this.mTransactionManager.peekUndoStack(),
-  peekRedoStack: function() this.mTransactionManager.peekRedoStack(),
-  getUndoStack: function() this.mTransactionManager.getUndoStack(),
-  getRedoStack: function() this.mTransactionManager.getRedoStack(),
-  AddListener: function(l) this.mTransactionManager.AddListener(l),
-  RemoveListener: function(l) this.mTransactionManager.RemoveListener(l)
-};
-
-/**
- * Method and utility stubs for Places Edit Transactions
- */
-function placesBaseTransaction() {
-}
-
-placesBaseTransaction.prototype = {
-  // for child-transactions
-  get wrappedJSObject() {
-    return this;
-  },
-
-  // nsITransaction
-  redoTransaction: function PBT_redoTransaction() {
-    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
-  },
-
-  get isTransient() {
-    return false;
-  },
-
-  merge: function mergeFunc(transaction) {
-    return false;
-  },
-
-  // nsISupports
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITransaction]),
-};
-
-function placesAggregateTransactions(name, transactions) {
-  this._transactions = transactions;
-  this._name = name;
-  this.container = -1;
-  this.redoTransaction = this.doTransaction;
-
-  // Check child transactions number.  We will batch if we have more than
-  // MIN_TRANSACTIONS_FOR_BATCH total number of transactions.
-  var countTransactions = function(aTransactions, aTxnCount) {
-    for (let i = 0;
-         i < aTransactions.length && aTxnCount < MIN_TRANSACTIONS_FOR_BATCH;
-         i++, aTxnCount++) {
-      let txn = aTransactions[i].wrappedJSObject;
-      if (txn && txn.childTransactions && txn.childTransactions.length)
-        aTxnCount = countTransactions(txn.childTransactions, aTxnCount);
-    }
-    return aTxnCount;
-  }
-
-  var txnCount = countTransactions(transactions, 0);
-  this._useBatch = txnCount >= MIN_TRANSACTIONS_FOR_BATCH;
-}
-
-placesAggregateTransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PAT_doTransaction() {
-    if (this._useBatch) {
-      var callback = {
-        _self: this,
-        runBatched: function() {
-          this._self.commit(false);
-        }
-      };
-      PlacesUtils.bookmarks.runInBatchMode(callback, null);
-    }
-    else
-      this.commit(false);
-  },
-
-  undoTransaction: function PAT_undoTransaction() {
-    if (this._useBatch) {
-      var callback = {
-        _self: this,
-        runBatched: function() {
-          this._self.commit(true);
-        }
-      };
-      PlacesUtils.bookmarks.runInBatchMode(callback, null);
-    }
-    else
-      this.commit(true);
-  },
-
-  commit: function PAT_commit(aUndo) {
-    // Use a copy of the transactions array, so we won't reverse the original
-    // one on undoing.
-    var transactions = this._transactions.slice(0);
-    if (aUndo)
-      transactions.reverse();
-    for (var i = 0; i < transactions.length; i++) {
-      var txn = transactions[i];
-      if (this.container > -1) 
-        txn.wrappedJSObject.container = this.container;
-      if (aUndo)
-        txn.undoTransaction();
-      else
-        txn.doTransaction();
-    }
-  }
-};
-
-function placesCreateFolderTransactions(aName, aContainer, aIndex,
-                                        aAnnotations,
-                                        aChildItemsTransactions) {
-  this._name = aName;
-  this._container = aContainer;
-  this._index = typeof(aIndex) == "number" ? aIndex : -1;
-  this._annotations = aAnnotations;
-  this._id = null;
-  this.childTransactions = aChildItemsTransactions || [];
-  this.redoTransaction = this.doTransaction;
-}
-
-placesCreateFolderTransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  // childItemsTransaction support
-  get container() { return this._container; },
-  set container(val) { return this._container = val; },
-
-  doTransaction: function PCFT_doTransaction() {
-    this._id = PlacesUtils.bookmarks.createFolder(this._container, 
-                                                  this._name, this._index);
-    if (this._annotations && this._annotations.length > 0)
-      PlacesUtils.setAnnotationsForItem(this._id, this._annotations);
-
-    if (this.childTransactions.length) {
-      // Set the new container id into child transactions.
-      for (var i = 0; i < this.childTransactions.length; ++i) {
-        this.childTransactions[i].wrappedJSObject.container = this._id;
-      }
-
-      let aggregateTxn = new placesAggregateTransactions("Create folder childTxn",
-                                                         this.childTransactions);
-      aggregateTxn.doTransaction();
-    }
-
-    if (this._GUID)
-      PlacesUtils.bookmarks.setItemGUID(this._id, this._GUID);
-  },
-
-  undoTransaction: function PCFT_undoTransaction() {
-    if (this.childTransactions.length) {
-      let aggregateTxn = new placesAggregateTransactions("Create folder childTxn",
-                                                         this.childTransactions);
-      aggregateTxn.undoTransaction();
-    }
-
-    // If a GUID exists for this item, preserve it before removing the item.
-    if (PlacesUtils.annotations.itemHasAnnotation(this._id, PlacesUtils.GUID_ANNO))
-      this._GUID = PlacesUtils.bookmarks.getItemGUID(this._id);
-
-    // Remove item only after all child transactions have been reverted.
-    PlacesUtils.bookmarks.removeItem(this._id);
-  }
-};
-
-function placesCreateItemTransactions(aURI, aContainer, aIndex, aTitle,
-                                      aKeyword, aAnnotations,
-                                      aChildTransactions) {
-  this._uri = aURI;
-  this._container = aContainer;
-  this._index = typeof(aIndex) == "number" ? aIndex : -1;
-  this._title = aTitle;
-  this._keyword = aKeyword;
-  this._annotations = aAnnotations;
-  this.childTransactions = aChildTransactions || [];
-  this.redoTransaction = this.doTransaction;
-}
-
-placesCreateItemTransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  // childItemsTransactions support for the create-folder transaction
-  get container() { return this._container; },
-  set container(val) { return this._container = val; },
-
-  doTransaction: function PCIT_doTransaction() {
-    this._id = PlacesUtils.bookmarks.insertBookmark(this.container, this._uri,
-                                                    this._index, this._title);
-    if (this._keyword)
-      PlacesUtils.bookmarks.setKeywordForBookmark(this._id, this._keyword);
-    if (this._annotations && this._annotations.length > 0)
-      PlacesUtils.setAnnotationsForItem(this._id, this._annotations);
- 
-    if (this.childTransactions.length) {
-      // Set the new item id into child transactions.
-      for (var i = 0; i < this.childTransactions.length; ++i) {
-        this.childTransactions[i].wrappedJSObject.id = this._id;
-      }
-      let aggregateTxn = new placesAggregateTransactions("Create item childTxn",
-                                                         this.childTransactions);
-      aggregateTxn.doTransaction();
-    }
-    if (this._GUID)
-      PlacesUtils.bookmarks.setItemGUID(this._id, this._GUID);
-  },
-
-  undoTransaction: function PCIT_undoTransaction() {
-    if (this.childTransactions.length) {
-      // Undo transactions should always be done in reverse order.
-      let aggregateTxn = new placesAggregateTransactions("Create item childTxn",
-                                                         this.childTransactions);
-      aggregateTxn.undoTransaction();
-    }
-
-    // If a GUID exists for this item, preserve it before removing the item.
-    if (PlacesUtils.annotations.itemHasAnnotation(this._id, PlacesUtils.GUID_ANNO))
-      this._GUID = PlacesUtils.bookmarks.getItemGUID(this._id);
-
-    // Remove item only after all child transactions have been reverted.
-    PlacesUtils.bookmarks.removeItem(this._id);
-  }
-};
-
-function placesCreateSeparatorTransactions(aContainer, aIndex) {
-  this._container = aContainer;
-  this._index = typeof(aIndex) == "number" ? aIndex : -1;
-  this._id = null;
-  this.redoTransaction = this.doTransaction;
-}
-
-placesCreateSeparatorTransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  // childItemsTransaction support
-  get container() { return this._container; },
-  set container(val) { return this._container = val; },
-
-  doTransaction: function PCST_doTransaction() {
-    this._id = PlacesUtils.bookmarks
-                          .insertSeparator(this.container, this._index);
-    if (this._GUID)
-      PlacesUtils.bookmarks.setItemGUID(this._id, this._GUID);
-  },
-
-  undoTransaction: function PCST_undoTransaction() {
-    // If a GUID exists for this item, preserve it before removing the item.
-    if (PlacesUtils.annotations.itemHasAnnotation(this._id, PlacesUtils.GUID_ANNO))
-      this._GUID = PlacesUtils.bookmarks.getItemGUID(this._id);
-
-    PlacesUtils.bookmarks.removeItem(this._id);
-  }
-};
-
-function placesCreateLivemarkTransactions(aFeedURI, aSiteURI, aName,
-                                          aContainer, aIndex,
-                                          aAnnotations) {
-  this.redoTransaction = this.doTransaction;
-  this._feedURI = aFeedURI;
-  this._siteURI = aSiteURI;
-  this._name = aName;
-  this._container = aContainer;
-  this._index = typeof(aIndex) == "number" ? aIndex : -1;
-  this._annotations = aAnnotations;
-}
-
-placesCreateLivemarkTransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  // childItemsTransaction support
-  get container() { return this._container; },
-  set container(val) { return this._container = val; },
-
-  doTransaction: function PCLT_doTransaction() {
-    this._id = PlacesUtils.livemarks.createLivemark(this._container, this._name,
-                                                    this._siteURI, this._feedURI,
-                                                    this._index);
-    if (this._annotations && this._annotations.length > 0)
-      PlacesUtils.setAnnotationsForItem(this._id, this._annotations);
-    if (this._GUID)
-      PlacesUtils.bookmarks.setItemGUID(this._id, this._GUID);
-  },
-
-  undoTransaction: function PCLT_undoTransaction() {
-    // If a GUID exists for this item, preserve it before removing the item.
-    if (PlacesUtils.annotations.itemHasAnnotation(this._id, PlacesUtils.GUID_ANNO))
-      this._GUID = PlacesUtils.bookmarks.getItemGUID(this._id);
-
-    PlacesUtils.bookmarks.removeItem(this._id);
-  }
-};
-
-function placesRemoveLivemarkTransaction(aFolderId) {
-  this.redoTransaction = this.doTransaction;
-  this._id = aFolderId;
-  this._title = PlacesUtils.bookmarks.getItemTitle(this._id);
-  this._container = PlacesUtils.bookmarks.getFolderIdForItem(this._id);
-  var annos = PlacesUtils.getAnnotationsForItem(this._id);
-  // Exclude livemark service annotations, those will be recreated automatically
-  var annosToExclude = ["livemark/feedURI",
-                        "livemark/siteURI",
-                        "livemark/expiration",
-                        "livemark/loadfailed",
-                        "livemark/loading"];
-  this._annotations = annos.filter(function(aValue, aIndex, aArray) {
-      return annosToExclude.indexOf(aValue.name) == -1;
-    });
-  this._feedURI = PlacesUtils.livemarks.getFeedURI(this._id);
-  this._siteURI = PlacesUtils.livemarks.getSiteURI(this._id);
-  this._dateAdded = PlacesUtils.bookmarks.getItemDateAdded(this._id);
-  this._lastModified = PlacesUtils.bookmarks.getItemLastModified(this._id);
-}
-
-placesRemoveLivemarkTransaction.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PRLT_doTransaction() {
-    this._index = PlacesUtils.bookmarks.getItemIndex(this._id);
-    PlacesUtils.bookmarks.removeItem(this._id);
-  },
-
-  undoTransaction: function PRLT_undoTransaction() {
-    this._id = PlacesUtils.livemarks.createLivemark(this._container,
-                                                    this._title,
-                                                    this._siteURI,
-                                                    this._feedURI,
-                                                    this._index);
-    PlacesUtils.bookmarks.setItemDateAdded(this._id, this._dateAdded);
-    PlacesUtils.bookmarks.setItemLastModified(this._id, this._lastModified);
-    // Restore annotations
-    PlacesUtils.setAnnotationsForItem(this._id, this._annotations);
-  }
-};
-
-function placesMoveItemTransactions(aItemId, aNewContainer, aNewIndex) {
-  this._id = aItemId;
-  this._oldContainer = PlacesUtils.bookmarks.getFolderIdForItem(this._id);
-  this._newContainer = aNewContainer;
-  this._newIndex = aNewIndex;
-  this.redoTransaction = this.doTransaction;
-}
-
-placesMoveItemTransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PMIT_doTransaction() {
-    this._oldIndex = PlacesUtils.bookmarks.getItemIndex(this._id);
-    PlacesUtils.bookmarks.moveItem(this._id, this._newContainer, this._newIndex);
-    this._undoIndex = PlacesUtils.bookmarks.getItemIndex(this._id);
-  },
-
-  undoTransaction: function PMIT_undoTransaction() {
-    // moving down in the same container takes in count removal of the item
-    // so to revert positions we must move to oldIndex + 1
-    if (this._newContainer == this._oldContainer &&
-        this._oldIndex > this._undoIndex)
-      PlacesUtils.bookmarks.moveItem(this._id, this._oldContainer, this._oldIndex + 1);
-    else
-      PlacesUtils.bookmarks.moveItem(this._id, this._oldContainer, this._oldIndex);
-  }
-};
-
-function placesRemoveItemTransaction(aItemId) {
-  this.redoTransaction = this.doTransaction;
-  this._id = aItemId;
-  this._itemType = PlacesUtils.bookmarks.getItemType(this._id);
-  if (this._itemType == Ci.nsINavBookmarksService.TYPE_FOLDER) {
-    this.childTransactions = this._getFolderContentsTransactions();
-    // Remove this folder itself.
-    let txn = PlacesUtils.bookmarks.getRemoveFolderTransaction(this._id);
-    this.childTransactions.push(txn);
-  }
-  else if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK) {
-    this._uri = PlacesUtils.bookmarks.getBookmarkURI(this._id);
-    this._keyword = PlacesUtils.bookmarks.getKeywordForBookmark(this._id);
-  }
-
-  if (this._itemType != Ci.nsINavBookmarksService.TYPE_SEPARATOR)
-    this._title = PlacesUtils.bookmarks.getItemTitle(this._id);
-
-  this._oldContainer = PlacesUtils.bookmarks.getFolderIdForItem(this._id);
-  this._annotations = PlacesUtils.getAnnotationsForItem(this._id);
-  this._dateAdded = PlacesUtils.bookmarks.getItemDateAdded(this._id);
-  this._lastModified = PlacesUtils.bookmarks.getItemLastModified(this._id);
-}
-
-placesRemoveItemTransaction.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PRIT_doTransaction() {
-    this._oldIndex = PlacesUtils.bookmarks.getItemIndex(this._id);
-
-    if (this._itemType == Ci.nsINavBookmarksService.TYPE_FOLDER) {
-      let aggregateTxn = new placesAggregateTransactions("Remove item childTxn",
-                                                         this.childTransactions);
-      aggregateTxn.doTransaction();
-    }
-    else {
-      PlacesUtils.bookmarks.removeItem(this._id);
-      if (this._uri) {
-        // if this was the last bookmark (excluding tag-items and livemark
-        // children, see getMostRecentBookmarkForURI) for the bookmark's url,
-        // remove the url from tag containers as well.
-        if (PlacesUtils.getMostRecentBookmarkForURI(this._uri) == -1) {
-          this._tags = PlacesUtils.tagging.getTagsForURI(this._uri);
-          PlacesUtils.tagging.untagURI(this._uri, this._tags);
-        }
-      }
-    }
-  },
-
-  undoTransaction: function PRIT_undoTransaction() {
-    if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK) {
-      this._id = PlacesUtils.bookmarks.insertBookmark(this._oldContainer,
-                                                      this._uri,
-                                                      this._oldIndex,
-                                                      this._title);
-      if (this._tags && this._tags.length > 0)
-        PlacesUtils.tagging.tagURI(this._uri, this._tags);
-      if (this._keyword)
-        PlacesUtils.bookmarks.setKeywordForBookmark(this._id, this._keyword);
-    }
-    else if (this._itemType == Ci.nsINavBookmarksService.TYPE_FOLDER) {
-      let aggregateTxn = new placesAggregateTransactions("Remove item childTxn",
-                                                         this.childTransactions);
-      aggregateTxn.undoTransaction();
-    }
-    else // TYPE_SEPARATOR
-      this._id = PlacesUtils.bookmarks.insertSeparator(this._oldContainer, this._oldIndex);
-
-    if (this._annotations.length > 0)
-      PlacesUtils.setAnnotationsForItem(this._id, this._annotations);
-
-    PlacesUtils.bookmarks.setItemDateAdded(this._id, this._dateAdded);
-    PlacesUtils.bookmarks.setItemLastModified(this._id, this._lastModified);
-  },
-
-  /**
-  * Returns a flat, ordered list of transactions for a depth-first recreation
-  * of items within this folder.
-  */
-  _getFolderContentsTransactions:
-  function PRIT__getFolderContentsTransactions() {
-    var transactions = [];
-    var contents =
-      PlacesUtils.getFolderContents(this._id, false, false).root;
-    for (var i = 0; i < contents.childCount; ++i) {
-      let txn = new placesRemoveItemTransaction(contents.getChild(i).itemId);
-      transactions.push(txn);
-    }
-    contents.containerOpen = false;
-    // Reverse transactions to preserve parent-child relationship.
-    return transactions.reverse();
-  }
-};
-
-function placesEditItemTitleTransactions(id, newTitle) {
-  this._id = id;
-  this._newTitle = newTitle;
-  this._oldTitle = "";
-  this.redoTransaction = this.doTransaction;
-}
-
-placesEditItemTitleTransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PEITT_doTransaction() {
-    this._oldTitle = PlacesUtils.bookmarks.getItemTitle(this._id);
-    PlacesUtils.bookmarks.setItemTitle(this._id, this._newTitle);
-  },
-
-  undoTransaction: function PEITT_undoTransaction() {
-    PlacesUtils.bookmarks.setItemTitle(this._id, this._oldTitle);
-  }
-};
-
-function placesEditBookmarkURITransactions(aBookmarkId, aNewURI) {
-  this._id = aBookmarkId;
-  this._newURI = aNewURI;
-  this.redoTransaction = this.doTransaction;
-}
-
-placesEditBookmarkURITransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PEBUT_doTransaction() {
-    this._oldURI = PlacesUtils.bookmarks.getBookmarkURI(this._id);
-    PlacesUtils.bookmarks.changeBookmarkURI(this._id, this._newURI);
-    // move tags from old URI to new URI
-    this._tags = PlacesUtils.tagging.getTagsForURI(this._oldURI);
-    if (this._tags.length != 0) {
-      // only untag the old URI if this is the only bookmark
-      if (PlacesUtils.getBookmarksForURI(this._oldURI, {}).length == 0)
-        PlacesUtils.tagging.untagURI(this._oldURI, this._tags);
-      PlacesUtils.tagging.tagURI(this._newURI, this._tags);
-    }
-  },
-
-  undoTransaction: function PEBUT_undoTransaction() {
-    PlacesUtils.bookmarks.changeBookmarkURI(this._id, this._oldURI);
-    // move tags from new URI to old URI 
-    if (this._tags.length != 0) {
-      // only untag the new URI if this is the only bookmark
-      if (PlacesUtils.getBookmarksForURI(this._newURI, {}).length == 0)
-        PlacesUtils.tagging.untagURI(this._newURI, this._tags);
-      PlacesUtils.tagging.tagURI(this._oldURI, this._tags);
-    }
-  }
-};
-
-function placesSetItemAnnotationTransactions(aItemId, aAnnotationObject) {
-  this.id = aItemId;
-  this._anno = aAnnotationObject;
-  // create an empty old anno
-  this._oldAnno = { name: this._anno.name,
-                    type: Ci.nsIAnnotationService.TYPE_STRING,
-                    flags: 0,
-                    value: null,
-                    expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
-  this.redoTransaction = this.doTransaction;
-}
-
-placesSetItemAnnotationTransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PSIAT_doTransaction() {
-    // Since this can be used as a child transaction this.id will be known
-    // only at this point, after the external caller has set it.
-    if (PlacesUtils.annotations.itemHasAnnotation(this.id, this._anno.name)) {
-      // Save the old annotation if it is set.
-      var flags = {}, expires = {}, mimeType = {}, type = {};
-      PlacesUtils.annotations.getItemAnnotationInfo(this.id, this._anno.name,
-                                                    flags, expires, mimeType,
-                                                    type);
-      this._oldAnno.flags = flags.value;
-      this._oldAnno.expires = expires.value;
-      this._oldAnno.mimeType = mimeType.value;
-      this._oldAnno.type = type.value;
-      this._oldAnno.value = PlacesUtils.annotations
-                                       .getItemAnnotation(this.id,
-                                                          this._anno.name);
-    }
-
-    PlacesUtils.setAnnotationsForItem(this.id, [this._anno]);
-  },
-
-  undoTransaction: function PSIAT_undoTransaction() {
-    PlacesUtils.setAnnotationsForItem(this.id, [this._oldAnno]);
-  }
-};
-
-function placesSetPageAnnotationTransactions(aURI, aAnnotationObject) {
-  this._uri = aURI;
-  this._anno = aAnnotationObject;
-  // create an empty old anno
-  this._oldAnno = { name: this._anno.name,
-                    type: Ci.nsIAnnotationService.TYPE_STRING,
-                    flags: 0,
-                    value: null,
-                    expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
-
-  if (PlacesUtils.annotations.pageHasAnnotation(this._uri, this._anno.name)) {
-    // fill the old anno if it is set
-    var flags = {}, expires = {}, mimeType = {}, type = {};
-    PlacesUtils.annotations.getPageAnnotationInfo(this._uri, this._anno.name,
-                                                  flags, expires, mimeType, type);
-    this._oldAnno.flags = flags.value;
-    this._oldAnno.expires = expires.value;
-    this._oldAnno.mimeType = mimeType.value;
-    this._oldAnno.type = type.value;
-    this._oldAnno.value = PlacesUtils.annotations
-                                     .getPageAnnotation(this._uri, this._anno.name);
-  }
-
-  this.redoTransaction = this.doTransaction;
-}
-
-placesSetPageAnnotationTransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PSPAT_doTransaction() {
-    PlacesUtils.setAnnotationsForURI(this._uri, [this._anno]);
-  },
-
-  undoTransaction: function PSPAT_undoTransaction() {
-    PlacesUtils.setAnnotationsForURI(this._uri, [this._oldAnno]);
-  }
-};
-
-function placesEditBookmarkKeywordTransactions(id, newKeyword) {
-  this.id = id;
-  this._newKeyword = newKeyword;
-  this._oldKeyword = "";
-  this.redoTransaction = this.doTransaction;
-}
-
-placesEditBookmarkKeywordTransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PEBKT_doTransaction() {
-    this._oldKeyword = PlacesUtils.bookmarks.getKeywordForBookmark(this.id);
-    PlacesUtils.bookmarks.setKeywordForBookmark(this.id, this._newKeyword);
-  },
-
-  undoTransaction: function PEBKT_undoTransaction() {
-    PlacesUtils.bookmarks.setKeywordForBookmark(this.id, this._oldKeyword);
-  }
-};
-
-function placesEditBookmarkPostDataTransactions(aItemId, aPostData) {
-  this.id = aItemId;
-  this._newPostData = aPostData;
-  this._oldPostData = null;
-  this.redoTransaction = this.doTransaction;
-}
-
-placesEditBookmarkPostDataTransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PEUPDT_doTransaction() {
-    this._oldPostData = PlacesUtils.getPostDataForBookmark(this.id);
-    PlacesUtils.setPostDataForBookmark(this.id, this._newPostData);
-  },
-
-  undoTransaction: function PEUPDT_undoTransaction() {
-    PlacesUtils.setPostDataForBookmark(this.id, this._oldPostData);
-  }
-};
-
-function placesEditLivemarkSiteURITransactions(folderId, uri) {
-  this._folderId = folderId;
-  this._newURI = uri;
-  this._oldURI = null;
-  this.redoTransaction = this.doTransaction;
-}
-
-placesEditLivemarkSiteURITransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PELSUT_doTransaction() {
-    this._oldURI = PlacesUtils.livemarks.getSiteURI(this._folderId);
-    PlacesUtils.livemarks.setSiteURI(this._folderId, this._newURI);
-  },
-
-  undoTransaction: function PELSUT_undoTransaction() {
-    PlacesUtils.livemarks.setSiteURI(this._folderId, this._oldURI);
-  }
-};
-
-function placesEditLivemarkFeedURITransactions(folderId, uri) {
-  this._folderId = folderId;
-  this._newURI = uri;
-  this._oldURI = null;
-  this.redoTransaction = this.doTransaction;
-}
-
-placesEditLivemarkFeedURITransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PELFUT_doTransaction() {
-    this._oldURI = PlacesUtils.livemarks.getFeedURI(this._folderId);
-    PlacesUtils.livemarks.setFeedURI(this._folderId, this._newURI);
-    PlacesUtils.livemarks.reloadLivemarkFolder(this._folderId);
-  },
-
-  undoTransaction: function PELFUT_undoTransaction() {
-    PlacesUtils.livemarks.setFeedURI(this._folderId, this._oldURI);
-    PlacesUtils.livemarks.reloadLivemarkFolder(this._folderId);
-  }
-};
-
-function placesEditBookmarkMicrosummaryTransactions(aItemId, newMicrosummary) {
-  this.id = aItemId;
-  this._mss = Cc["@mozilla.org/microsummary/service;1"].
-              getService(Ci.nsIMicrosummaryService);
-  this._newMicrosummary = newMicrosummary;
-  this._oldMicrosummary = null;
-  this.redoTransaction = this.doTransaction;
-}
-
-placesEditBookmarkMicrosummaryTransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PEBMT_doTransaction() {
-    this._oldMicrosummary = this._mss.getMicrosummary(this.id);
-    if (this._newMicrosummary)
-      this._mss.setMicrosummary(this.id, this._newMicrosummary);
-    else
-      this._mss.removeMicrosummary(this.id);
-  },
-
-  undoTransaction: function PEBMT_undoTransaction() {
-    if (this._oldMicrosummary)
-      this._mss.setMicrosummary(this.id, this._oldMicrosummary);
-    else
-      this._mss.removeMicrosummary(this.id);
-  }
-};
-
-function placesEditItemDateAddedTransaction(id, newDateAdded) {
-  this.id = id;
-  this._newDateAdded = newDateAdded;
-  this._oldDateAdded = null;
-  this.redoTransaction = this.doTransaction;
-}
-
-placesEditItemDateAddedTransaction.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  // to support folders as well
-  get container() { return this.id; },
-  set container(val) { return this.id = val; },
-
-  doTransaction: function PEIDA_doTransaction() {
-    this._oldDateAdded = PlacesUtils.bookmarks.getItemDateAdded(this.id);
-    PlacesUtils.bookmarks.setItemDateAdded(this.id, this._newDateAdded);
-  },
-
-  undoTransaction: function PEIDA_undoTransaction() {
-    PlacesUtils.bookmarks.setItemDateAdded(this.id, this._oldDateAdded);
-  }
-};
-
-function placesEditItemLastModifiedTransaction(id, newLastModified) {
-  this.id = id;
-  this._newLastModified = newLastModified;
-  this._oldLastModified = null;
-  this.redoTransaction = this.doTransaction;
-}
-
-placesEditItemLastModifiedTransaction.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  // to support folders as well
-  get container() { return this.id; },
-  set container(val) { return this.id = val; },
-
-  doTransaction: function PEILM_doTransaction() {
-    this._oldLastModified = PlacesUtils.bookmarks.getItemLastModified(this.id);
-    PlacesUtils.bookmarks.setItemLastModified(this.id, this._newLastModified);
-  },
-
-  undoTransaction: function PEILM_undoTransaction() {
-    PlacesUtils.bookmarks.setItemLastModified(this.id, this._oldLastModified);
-  }
-};
-
-function placesSortFolderByNameTransactions(aFolderId) {
-  this._folderId = aFolderId;
-  this._oldOrder = null,
-  this.redoTransaction = this.doTransaction;
-}
-
-placesSortFolderByNameTransactions.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PSSFBN_doTransaction() {
-    this._oldOrder = [];
-
-    var contents =
-      PlacesUtils.getFolderContents(this._folderId, false, false).root;
-    var count = contents.childCount;
-
-    // sort between separators
-    var newOrder = []; 
-    var preSep = []; // temporary array for sorting each group of items
-    var sortingMethod =
-      function (a, b) {
-        if (PlacesUtils.nodeIsContainer(a) && !PlacesUtils.nodeIsContainer(b))
-          return -1;
-        if (!PlacesUtils.nodeIsContainer(a) && PlacesUtils.nodeIsContainer(b))
-          return 1;
-        return a.title.localeCompare(b.title);
-      };
-
-    for (var i = 0; i < count; ++i) {
-      var item = contents.getChild(i);
-      this._oldOrder[item.itemId] = i;
-      if (PlacesUtils.nodeIsSeparator(item)) {
-        if (preSep.length > 0) {
-          preSep.sort(sortingMethod);
-          newOrder = newOrder.concat(preSep);
-          preSep.splice(0);
-        }
-        newOrder.push(item);
-      }
-      else
-        preSep.push(item);
-    }
-    contents.containerOpen = false;
-
-    if (preSep.length > 0) {
-      preSep.sort(sortingMethod);
-      newOrder = newOrder.concat(preSep);
-    }
-
-    // set the nex indexes
-    var callback = {
-      runBatched: function() {
-        for (var i = 0; i < newOrder.length; ++i) {
-          PlacesUtils.bookmarks.setItemIndex(newOrder[i].itemId, i);
-        }
-      }
-    };
-    PlacesUtils.bookmarks.runInBatchMode(callback, null);
-  },
-
-  undoTransaction: function PSSFBN_undoTransaction() {
-    var callback = {
-      _self: this,
-      runBatched: function() {
-        for (item in this._self._oldOrder)
-          PlacesUtils.bookmarks.setItemIndex(item, this._self._oldOrder[item]);
-      }
-    };
-    PlacesUtils.bookmarks.runInBatchMode(callback, null);
-  }
-};
-
-function placesTagURITransaction(aURI, aTags) {
-  this._uri = aURI;
-  this._tags = aTags;
-  this._unfiledItemId = -1;
-  this.redoTransaction = this.doTransaction;
-}
-
-placesTagURITransaction.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PTU_doTransaction() {
-    if (PlacesUtils.getMostRecentBookmarkForURI(this._uri) == -1) {
-      // Force an unfiled bookmark first
-      this._unfiledItemId =
-        PlacesUtils.bookmarks
-                   .insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
-                                   this._uri,
-                                   PlacesUtils.bookmarks.DEFAULT_INDEX,
-                                   PlacesUtils.history.getPageTitle(this._uri));
-      if (this._GUID)
-        PlacesUtils.bookmarks.setItemGUID(this._unfiledItemId, this._GUID);
-    }
-    PlacesUtils.tagging.tagURI(this._uri, this._tags);
-  },
-
-  undoTransaction: function PTU_undoTransaction() {
-    if (this._unfiledItemId != -1) {
-      // If a GUID exists for this item, preserve it before removing the item.
-      if (PlacesUtils.annotations.itemHasAnnotation(this._unfiledItemId, PlacesUtils.GUID_ANNO)) {
-        this._GUID = PlacesUtils.bookmarks.getItemGUID(this._unfiledItemId);
-      }
-      PlacesUtils.bookmarks.removeItem(this._unfiledItemId);
-      this._unfiledItemId = -1;
-    }
-    PlacesUtils.tagging.untagURI(this._uri, this._tags);
-  }
-};
-
-function placesUntagURITransaction(aURI, aTags) {
-  this._uri = aURI;
-  if (aTags) {    
-    // Within this transaction, we cannot rely on tags given by itemId
-    // since the tag containers may be gone after we call untagURI.
-    // Thus, we convert each tag given by its itemId to name.
-    this._tags = aTags;
-    for (var i=0; i < aTags.length; i++) {
-      if (typeof(this._tags[i]) == "number")
-        this._tags[i] = PlacesUtils.bookmarks.getItemTitle(this._tags[i]);
-    }
-  }
-  else
-    this._tags = PlacesUtils.tagging.getTagsForURI(this._uri);
-
-  this.redoTransaction = this.doTransaction;
-}
-
-placesUntagURITransaction.prototype = {
-  __proto__: placesBaseTransaction.prototype,
-
-  doTransaction: function PUTU_doTransaction() {
-    PlacesUtils.tagging.untagURI(this._uri, this._tags);
-  },
-
-  undoTransaction: function PUTU_undoTransaction() {
-    PlacesUtils.tagging.tagURI(this._uri, this._tags);
-  }
-};
-
-
-function NSGetModule(aCompMgr, aFileSpec) {
-  return XPCOMUtils.generateModule([placesTransactionsService]);
-}
--- a/browser/components/places/tests/browser/browser_views_liveupdate.js
+++ b/browser/components/places/tests/browser/browser_views_liveupdate.js
@@ -99,17 +99,17 @@ function startTest() {
                              bs.DEFAULT_INDEX,
                              "bm1");
   bs.setItemTitle(id, "bm1_edited");
   addedBookmarks.push(id);
   id = bs.insertBookmark(bs.bookmarksMenuFolder,
                          PlacesUtils._uri("place:"),
                          bs.DEFAULT_INDEX,
                          "bm2");
-  bs.setItemTitle(id, "bm2_edited");
+  bs.setItemTitle(id, "");
   addedBookmarks.push(id);
   id = bs.insertSeparator(bs.bookmarksMenuFolder, bs.DEFAULT_INDEX);
   addedBookmarks.push(id);
   id = bs.createFolder(bs.bookmarksMenuFolder,
                        "bmf",
                        bs.DEFAULT_INDEX);
   bs.setItemTitle(id, "bmf_edited");
   addedBookmarks.push(id);
@@ -130,17 +130,17 @@ function startTest() {
   bs.setItemTitle(id, "tb1_edited");
   addedBookmarks.push(id);
   // Test live update of title.
   bs.setItemTitle(id, "tb1_edited");
   id = bs.insertBookmark(bs.toolbarFolder,
                          PlacesUtils._uri("place:"),
                          bs.DEFAULT_INDEX,
                          "tb2");
-  bs.setItemTitle(id, "tb2_edited");
+  bs.setItemTitle(id, "");
   addedBookmarks.push(id);
   id = bs.insertSeparator(bs.toolbarFolder, bs.DEFAULT_INDEX);
   addedBookmarks.push(id);
   id = bs.createFolder(bs.toolbarFolder,
                        "tbf",
                        bs.DEFAULT_INDEX);
   bs.setItemTitle(id, "tbf_edited");
   addedBookmarks.push(id);
@@ -280,19 +280,23 @@ var bookmarksObserver = {
 
     // Check that item has been moved in the correct position.
     let validator = function(aElementOrTreeIndex) {
       if (typeof(aElementOrTreeIndex) == "number") {
         var sidebar = document.getElementById("sidebar");
         var tree = sidebar.contentDocument.getElementById("bookmarks-view");
         let cellText = tree.view.getCellText(aElementOrTreeIndex,
                                              tree.columns.getColumnAt(0));
+        if (!aNewValue)
+          return cellText == PlacesUIUtils.getBestTitle(tree.view.nodeForTreeIndex(aElementOrTreeIndex));
         return cellText == aNewValue;
       }
       else {
+        if (!aNewValue && aElementOrTreeIndex.localName != "toolbarbutton")
+          return aElementOrTreeIndex.label == PlacesUIUtils.getBestTitle(aElementOrTreeIndex._placesNode);
         return aElementOrTreeIndex.label == aNewValue;
       }
     };
 
     for (var i = 0; i < views.length; i++) {
       var [node, index, valid] = searchItemInView(aItemId, views[i], validator);
       isnot(node, null, "Found changed Places node in " + views[i]);
       is(node.title, aNewValue, "Node has correct title: " + aNewValue);
--- a/browser/components/places/tests/unit/test_placesTxn.js
+++ b/browser/components/places/tests/unit/test_placesTxn.js
@@ -33,60 +33,22 @@
  * 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 ***** */
 
-// Get bookmark service
-try {
-  var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].getService(Ci.nsINavBookmarksService);
-} catch(ex) {
-  do_throw("Could not get nav-bookmarks-service\n");
-}
-
-// Get livemark service
-try {
-  var lmsvc = Cc["@mozilla.org/browser/livemark-service;2"].getService(Ci.nsILivemarkService);
-} catch(ex) {
-  do_throw("Could not get livemark-service\n");
-} 
-
-// Get microsummary service
-try {
-  var mss = Cc["@mozilla.org/microsummary/service;1"].getService(Ci.nsIMicrosummaryService);
-} catch(ex) {
-  do_throw("Could not get microsummary-service\n");
-} 
-
-// Get Places Transaction Manager Service
-try {
-  var ptSvc = Cc["@mozilla.org/browser/placesTransactionsService;1"].
-              getService(Ci.nsIPlacesTransactionsService);
-} catch(ex) {
-  do_throw("Could not get Places Transactions Service\n");
-}
-
-// Get tagging service
-try {
-  var tagssvc = Cc["@mozilla.org/browser/tagging-service;1"].
-                getService(Ci.nsITaggingService);
-} catch(ex) {
-  do_throw("Could not get tagging service\n");
-}
-
-// Get annotations service
-try {
-  var annosvc = Cc["@mozilla.org/browser/annotation-service;1"].
-                getService(Ci.nsIAnnotationService);
-} catch(ex) {
-  do_throw("Could not get annotations service\n");
-}
+var bmsvc = PlacesUtils.bookmarks;
+var lmsvc = PlacesUtils.livemarks;
+var mss = PlacesUtils.microsummaries;
+var ptSvc = PlacesUIUtils.ptm;
+var tagssvc = PlacesUtils.tagging;
+var annosvc = PlacesUtils.annotations;
 
 // create and add bookmarks observer
 var observer = {
   onBeginUpdateBatch: function() {
     this._beginUpdateBatch = true;
   },
   onEndUpdateBatch: function() {
     this._endUpdateBatch = true;
@@ -138,19 +100,18 @@ bmsvc.addObserver(observer, false);
 var bmStartIndex = 0;
 
 // main
 function run_test() {
   // get bookmarks root index
   var root = bmsvc.bookmarksMenuFolder;
 
   //Test creating a folder with a description
-  const DESCRIPTION_ANNO = "bookmarkProperties/description";
   const TEST_DESCRIPTION = "this is my test description";
-  var annos = [{ name: DESCRIPTION_ANNO,
+  var annos = [{ name: PlacesUIUtils.DESCRIPTION_ANNO,
                  type: annosvc.TYPE_STRING,
                 flags: 0,
                 value: TEST_DESCRIPTION,
               expires: annosvc.EXPIRE_NEVER }];
   var txn1 = ptSvc.createFolder("Testing folder", root, bmStartIndex, annos);
   ptSvc.doTransaction(txn1);
 
   // This checks that calling undoTransaction on an "empty batch" doesn't
@@ -160,17 +121,17 @@ function run_test() {
   ptSvc.undoTransaction();
 
   var folderId = observer._itemAddedId;
   do_check_eq(bmsvc.getItemTitle(folderId), "Testing folder");
   do_check_eq(observer._itemAddedIndex, bmStartIndex);
   do_check_eq(observer._itemAddedParent, root);
   do_check_eq(observer._itemAddedId, folderId);
   do_check_eq(TEST_DESCRIPTION, 
-              annosvc.getItemAnnotation(folderId, DESCRIPTION_ANNO));
+              annosvc.getItemAnnotation(folderId, PlacesUIUtils.DESCRIPTION_ANNO));
 
   txn1.undoTransaction();
   do_check_eq(observer._itemRemovedId, folderId);
   do_check_eq(observer._itemRemovedFolder, root);
   do_check_eq(observer._itemRemovedIndex, bmStartIndex);
   txn1.redoTransaction();
   do_check_eq(observer._itemAddedIndex, bmStartIndex);
   do_check_eq(observer._itemAddedParent, root);
@@ -410,21 +371,21 @@ function run_test() {
   do_check_eq(observer._itemChangedId, bkmk1Id);
   do_check_eq(observer._itemChangedProperty, "uri");
   do_check_eq(observer._itemChangedValue, "http://newuri.com/");
   txn9.undoTransaction();
   do_check_eq(observer._itemChangedId, bkmk1Id);
   do_check_eq(observer._itemChangedProperty, "uri");
   do_check_eq(observer._itemChangedValue, "http://www.example3.com/");
   
-  // Test edit item description
+  // Test edit description transaction.
   var txn10 = ptSvc.editItemDescription(bkmk1Id, "Description1");
   txn10.doTransaction();
   do_check_eq(observer._itemChangedId, bkmk1Id);
-  do_check_eq(observer._itemChangedProperty, "bookmarkProperties/description");
+  do_check_eq(observer._itemChangedProperty, PlacesUIUtils.DESCRIPTION_ANNO);
 
   // Testing edit keyword
   var txn11 = ptSvc.editBookmarkKeyword(bkmk1Id, "kw1");
   txn11.doTransaction();
   do_check_eq(observer._itemChangedId, bkmk1Id);
   do_check_eq(observer._itemChangedProperty, "keyword");
   do_check_eq(observer._itemChangedValue, "kw1"); 
   txn11.undoTransaction();
@@ -505,26 +466,25 @@ function run_test() {
   do_check_true(lmsvc.isLivemark(lvmkId));
   do_check_eq(lmsvc.getSiteURI(lvmkId).spec, "http://siteuri.com/");
   do_check_eq(lmsvc.getFeedURI(lvmkId).spec, "http://feeduri.com/");
   do_check_eq(annosvc.getItemAnnotation(lvmkId, "livemark/testAnno"), "testAnno");
   txn15.redoTransaction();
   do_check_false(lmsvc.isLivemark(lvmkId));
   do_check_eq(observer._itemRemovedId, lvmkId);
 
-  // Test setLoadInSidebar
-  const LOAD_IN_SIDEBAR_ANNO = "bookmarkProperties/loadInSidebar";
+  // Test LoadInSidebar transaction.
   var txn16 = ptSvc.setLoadInSidebar(bkmk1Id, true);
   txn16.doTransaction();
   do_check_eq(observer._itemChangedId, bkmk1Id);
-  do_check_eq(observer._itemChangedProperty, LOAD_IN_SIDEBAR_ANNO);
+  do_check_eq(observer._itemChangedProperty, PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO);
   do_check_eq(observer._itemChanged_isAnnotationProperty, true);
   txn16.undoTransaction();
   do_check_eq(observer._itemChangedId, bkmk1Id);
-  do_check_eq(observer._itemChangedProperty, LOAD_IN_SIDEBAR_ANNO);
+  do_check_eq(observer._itemChangedProperty, PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO);
   do_check_eq(observer._itemChanged_isAnnotationProperty, true);
 
   // Test generic item annotation
   var itemAnnoObj = { name: "testAnno/testInt",
                       type: Ci.nsIAnnotationService.TYPE_INT32,
                       flags: 0,
                       value: 123,
                       expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
--- a/browser/components/places/tests/unit/test_txnGUIDs.js
+++ b/browser/components/places/tests/unit/test_txnGUIDs.js
@@ -1,89 +1,87 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *  vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Marco Bonardo <mak77@bonardo.net>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-/**
- * This test will ensure any transactions service that is going to create
- * a new item, won't replace the GUID when undoing and redoing the action.
- */
-var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
-            getService(Ci.nsINavBookmarksService);
-var txnsvc = Cc["@mozilla.org/browser/placesTransactionsService;1"].
-             getService(Ci.nsIPlacesTransactionsService);
-
-function test_GUID_persistance(aTxn) {
-  aTxn.doTransaction();
-  var itemId = bmsvc.getIdForItemAt(bmsvc.unfiledBookmarksFolder, 0);
-  var GUID = bmsvc.getItemGUID(itemId);
-  aTxn.undoTransaction();
-  aTxn.redoTransaction();
-  do_check_eq(GUID, bmsvc.getItemGUID(itemId));
-  aTxn.undoTransaction();
-}
-
-function run_test() {
-  // Create folder.
-  var createFolderTxn = txnsvc.createFolder("Test folder",
-                                            bmsvc.unfiledBookmarksFolder,
-                                            bmsvc.DEFAULT_INDEX);
-  test_GUID_persistance(createFolderTxn);
-
-  // Create bookmark.
-  var createBookmarkTxn = txnsvc.createItem(uri("http://www.example.com"),
-                                            bmsvc.unfiledBookmarksFolder,
-                                            bmsvc.DEFAULT_INDEX,
-                                            "Test bookmark");
-  test_GUID_persistance(createBookmarkTxn);
-
-  // Create separator.
-  var createSeparatorTxn = txnsvc.createSeparator(bmsvc.unfiledBookmarksFolder,
-                                                  bmsvc.DEFAULT_INDEX);
-  test_GUID_persistance(createFolderTxn);
-
-  // Create livemark.
-  var createLivemarkTxn = txnsvc.createLivemark(uri("http://feeduri.com"),
-                                               uri("http://siteuri.com"),
-                                               "Test livemark",
-                                               bmsvc.unfiledBookmarksFolder,
-                                               bmsvc.DEFAULT_INDEX);
-  test_GUID_persistance(createLivemarkTxn);
-
-  // Tag URI.
-  var tagURITxn = txnsvc.tagURI(uri("http://www.example.com"), ["foo"]);
-  test_GUID_persistance(tagURITxn);
-}
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *  vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Marco Bonardo <mak77@bonardo.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * This test will ensure any transactions service that is going to create
+ * a new item, won't replace the GUID when undoing and redoing the action.
+ */
+var bmsvc = PlacesUtils.bookmarks;
+var txnsvc = PlacesUIUtils.ptm;
+
+function test_GUID_persistance(aTxn) {
+  aTxn.doTransaction();
+  var itemId = bmsvc.getIdForItemAt(bmsvc.unfiledBookmarksFolder, 0);
+  var GUID = bmsvc.getItemGUID(itemId);
+  aTxn.undoTransaction();
+  aTxn.redoTransaction();
+  do_check_eq(GUID, bmsvc.getItemGUID(itemId));
+  aTxn.undoTransaction();
+}
+
+function run_test() {
+  // Create folder.
+  var createFolderTxn = txnsvc.createFolder("Test folder",
+                                            bmsvc.unfiledBookmarksFolder,
+                                            bmsvc.DEFAULT_INDEX);
+  test_GUID_persistance(createFolderTxn);
+
+  // Create bookmark.
+  var createBookmarkTxn = txnsvc.createItem(uri("http://www.example.com"),
+                                            bmsvc.unfiledBookmarksFolder,
+                                            bmsvc.DEFAULT_INDEX,
+                                            "Test bookmark");
+  test_GUID_persistance(createBookmarkTxn);
+
+  // Create separator.
+  var createSeparatorTxn = txnsvc.createSeparator(bmsvc.unfiledBookmarksFolder,
+                                                  bmsvc.DEFAULT_INDEX);
+  test_GUID_persistance(createFolderTxn);
+
+  // Create livemark.
+  var createLivemarkTxn = txnsvc.createLivemark(uri("http://feeduri.com"),
+                                               uri("http://siteuri.com"),
+                                               "Test livemark",
+                                               bmsvc.unfiledBookmarksFolder,
+                                               bmsvc.DEFAULT_INDEX);
+  test_GUID_persistance(createLivemarkTxn);
+
+  // Tag URI.
+  var tagURITxn = txnsvc.tagURI(uri("http://www.example.com"), ["foo"]);
+  test_GUID_persistance(tagURITxn);
+}
--- a/browser/components/privatebrowsing/src/Makefile.in
+++ b/browser/components/privatebrowsing/src/Makefile.in
@@ -52,13 +52,17 @@ endif
 
 
 CPPSRCS = \
 	nsPrivateBrowsingServiceWrapper.cpp \
 	$(NULL)
 
 LOCAL_INCLUDES = -I$(srcdir)/../../build
 
+EXTRA_COMPONENTS = \
+  nsPrivateBrowsingService.manifest \
+  $(NULL)
+
 EXTRA_PP_COMPONENTS = \
 	nsPrivateBrowsingService.js \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
+++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
@@ -125,23 +125,17 @@ PrivateBrowsingService.prototype = {
 
   // List of view source window URIs for restoring later
   _viewSrcURLs: [],
 
   // List of nsIXULWindows we are going to be closing during the transition
   _windowsToClose: [],
 
   // XPCOM registration
-  classDescription: "PrivateBrowsing Service",
-  contractID: "@mozilla.org/privatebrowsing;1",
   classID: Components.ID("{c31f4883-839b-45f6-82ad-a6a9bc5ad599}"),
-  _xpcom_categories: [
-    { category: "command-line-handler", entry: "m-privatebrowsing" },
-    { category: "app-startup", service: true }
-  ],
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrivateBrowsingService, 
                                          Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference,