merging from cvs-trunk-mirror
authoredward.lee@engineering.uiuc.edu
Thu, 16 Aug 2007 12:06:15 -0700
changeset 4723 af18e0cab10fb49606160081b0e59ba5fc7aee6f
parent 4509 a9f2926e60d3ae7680e140636ba61fe1c9cf354a (current diff)
parent 4722 7e42e1974f443e1aa824e15681e836ad91dda968 (diff)
child 4865 1622e8aa318f633d1d5ac2de3c2a89f91d3f2ab7
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9a8pre
merging from cvs-trunk-mirror
config/autoconf.mk.in
configure.in
intl/lwbrk/src/nsCarbonBreaker.cpp
intl/lwbrk/src/nsUniscribeBreaker.cpp
js/src/js.cpp
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsatom.cpp
js/src/jsdate.cpp
js/src/jsdbgapi.cpp
js/src/jsemit.cpp
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsgc.cpp
js/src/jsiter.cpp
js/src/jslock.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsopcode.cpp
js/src/jsparse.cpp
js/src/jsregexp.cpp
js/src/jsscan.cpp
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsstr.cpp
js/src/jsxdrapi.cpp
js/src/jsxml.cpp
js/tests/ecma_3/Date/15.9.4.3.js
js/tests/js1_7/geniter/regress-392310.js
toolkit/components/places/src/nsMorkHistoryImporter.h
toolkit/components/url-classifier/src/nsUrlClassifierTable.js
toolkit/locales/en-US/chrome/mozapps/downloads/downloadProperties.dtd
toolkit/mozapps/downloads/content/Makefile.in
toolkit/mozapps/downloads/content/downloadProperties.js
toolkit/mozapps/downloads/content/downloadProperties.xul
toolkit/themes/pinstripe/mozapps/downloads/background-gradient.gif
toolkit/themes/pinstripe/mozapps/downloads/background-stripe.gif
toolkit/themes/pinstripe/mozapps/downloads/download-inprogress.png
toolkit/themes/pinstripe/mozapps/downloads/downloads.xml
toolkit/themes/pinstripe/mozapps/downloads/progress-bar-paused.gif
toolkit/themes/pinstripe/mozapps/downloads/progress-bar.gif
toolkit/themes/pinstripe/mozapps/downloads/progress-remainder.gif
toolkit/themes/winstripe/mozapps/downloads/downloadCleanup.png
toolkit/themes/winstripe/mozapps/downloads/downloadCleanupDisabled.png
toolkit/themes/winstripe/mozapps/downloads/downloadOptions.png
toolkit/themes/winstripe/mozapps/downloads/downloadSelected.png
toolkit/themes/winstripe/mozapps/downloads/downloads.xml
toolkit/themes/winstripe/mozapps/downloads/downloadsBG.png
toolkit/themes/winstripe/mozapps/downloads/viewFader.png
toolkit/xre/nsNativeAppSupportMac.cpp
tools/rb/fix-macosx-stack.pl
uriloader/exthandler/nsHandlerAppImpl.cpp
uriloader/exthandler/nsHandlerAppImpl.h
uriloader/exthandler/nsHandlerService.js
uriloader/exthandler/nsIHandlerService.idl
uriloader/exthandler/tests/Makefile.in
uriloader/exthandler/tests/unit/head_handlerService.js
uriloader/exthandler/tests/unit/tail_handlerService.js
uriloader/exthandler/tests/unit/test_handlerService.js
xpcom/base/nsStackFrameUnix.cpp
xpcom/base/nsStackFrameWin.cpp
xpcom/base/nsStackFrameWin.h
--- a/accessible/public/nsIAccessibleEvent.idl
+++ b/accessible/public/nsIAccessibleEvent.idl
@@ -56,48 +56,51 @@ interface nsIDOMNode;
  * 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(18612bcb-79bd-45c1-92e9-07aded5fd0f5)]
+[scriptable, uuid(98f9e2d4-ec22-4601-b927-b9faf7a63248)]
 interface nsIAccessibleEvent : nsISupports
 {
   /**
    * An object has been created.
    */
-  const unsigned long EVENT_CREATE = 0x0001;
+  const unsigned long EVENT_DOM_CREATE = 0x0001;
 
   /**
    * An object has been destroyed.
    */
-  const unsigned long EVENT_DESTROY = 0x0002;
+  const unsigned long EVENT_DOM_DESTROY = 0x0002;
 
   /**
-   * A hidden object is shown.
+   * An object's properties or content have changed significantly so that the
+   * type of object has really changed, and therefore the accessible should be 
+   * destroyed or recreated.
    */
-  const unsigned long EVENT_SHOW = 0x0003;
+  const unsigned long EVENT_DOM_SIGNIFICANT_CHANGE = 0x0003;
 
   /**
-   * An object is hidden.
+   * A hidden object is shown -- this is a layout occurance and is thus asynchronous
    */
-  const unsigned long EVENT_HIDE = 0x0004;
+  const unsigned long EVENT_ASYNCH_SHOW = 0x0004;
 
   /**
-   * A container object has added, removed, or reordered its children.
+   * An object is hidden -- this is a layout occurance and is thus asynchronous
    */
-  const unsigned long EVENT_REORDER = 0x0005;
+  const unsigned long EVENT_ASYNCH_HIDE = 0x0005;
 
   /**
-   * An object has a new parent object.
+   * An object had a significant layout change which could affect
+   * the type of accessible object -- this is a layout occurance and is thus asynchronous
    */
-  const unsigned long EVENT_PARENT_CHANGE = 0x0006;
+  const unsigned long EVENT_ASYNCH_SIGNIFICANT_CHANGE = 0x0006;
 
   /**
    * The active descendant of a component has changed. The active descendant
    * is used in objects with transient children.
    */
   const unsigned long EVENT_ACTIVE_DECENDENT_CHANGED = 0x0007;
 
   /**
@@ -465,19 +468,24 @@ interface nsIAccessibleEvent : nsISuppor
   const unsigned long EVENT_PAGE_CHANGED = 0x005A;
 
   /**
    * Used internally in Gecko.
    */
   const unsigned long EVENT_INTERNAL_LOAD = 0x005B;
 
   /**
+   * An object's children have changed
+   */
+  const unsigned long EVENT_REORDER = 0x005C;
+
+  /**
    * Help make sure event map does not get out-of-line.
    */
-  const unsigned long EVENT_LAST_ENTRY = 0x005C;
+  const unsigned long EVENT_LAST_ENTRY = 0x005D;
 
   /**
    * The type of event, based on the enumerated event values
    * defined in this interface.
    */
   readonly attribute unsigned long eventType;
   
   /**
@@ -493,16 +501,22 @@ interface nsIAccessibleEvent : nsISuppor
    */
   readonly attribute nsIAccessibleDocument accessibleDocument;
 
   /**
    * The nsIDOMNode associated with the event
    * May return null if accessible for event has been shut down
    */
   readonly attribute nsIDOMNode DOMNode;
+
+  /**
+   * Returns true if the event was caused by explicit user input,
+   * as opposed to purely originating from a timer or mouse movement
+   */
+  readonly attribute boolean isFromUserInput;
 };
 
 
 [scriptable, uuid(444db51a-05fd-4576-8a64-32dbb2a83884)]
 interface nsIAccessibleStateChangeEvent : nsIAccessibleEvent
 {
   /**
    * Returns the state of accessible (see constants declared
--- a/accessible/src/atk/nsAccessibleWrap.cpp
+++ b/accessible/src/atk/nsAccessibleWrap.cpp
@@ -1115,34 +1115,37 @@ nsAccessibleWrap::FireAccessibleEvent(ns
     nsAccEvent *event = reinterpret_cast<nsAccEvent*>(aEvent);
     void *eventData = event->mEventData;
 
     AtkObject *atkObj = nsAccessibleWrap::GetAtkObject(accessible);
 
     // We don't create ATK objects for nsIAccessible plain text leaves,
     // just return NS_OK in such case
     if (!atkObj) {
-        NS_ASSERTION(type == nsIAccessibleEvent::EVENT_SHOW ||
-                     type == nsIAccessibleEvent::EVENT_HIDE,
+        NS_ASSERTION(type == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
+                     type == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
+                     type == nsIAccessibleEvent::EVENT_DOM_CREATE ||
+                     type == nsIAccessibleEvent::EVENT_DOM_DESTROY,
                      "Event other than SHOW and HIDE fired for plain text leaves");
         return NS_OK;
     }
 
     nsAccessibleWrap *accWrap = GetAccessibleWrap(atkObj);
     if (!accWrap) {
         return NS_OK; // Node is shut down
     }
 
     AtkTableChange * pAtkTableChange = nsnull;
 
     switch (type) {
     case nsIAccessibleEvent::EVENT_STATE_CHANGE:
         return FireAtkStateChangeEvent(aEvent, atkObj);
 
-    case nsIAccessibleEvent::EVENT_TEXT_CHANGED:
+    case nsIAccessibleEvent::EVENT_TEXT_REMOVED:
+    case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
         return FireAtkTextChangedEvent(aEvent, atkObj);
 
     case nsIAccessibleEvent::EVENT_PROPERTY_CHANGED:
         return FireAtkPropChangedEvent(aEvent, atkObj);
 
     case nsIAccessibleEvent::EVENT_FOCUS:
       {
         MAI_LOG_DEBUG(("\n\nReceived: EVENT_FOCUS\n"));
@@ -1286,20 +1289,22 @@ nsAccessibleWrap::FireAccessibleEvent(ns
         MAI_LOG_DEBUG(("\n\nReceived: EVENT_HYPERTEXT_LINK_SELECTED\n"));
         atk_focus_tracker_notify(atkObj);
         g_signal_emit_by_name(atkObj,
                               "link_selected",
                               // Selected link index 
                               *(gint *)eventData);
         break;
 
-    case nsIAccessibleEvent::EVENT_SHOW:
+    case nsIAccessibleEvent::EVENT_DOM_CREATE:
+    case nsIAccessibleEvent::EVENT_ASYNCH_SHOW:
         return FireAtkShowHideEvent(aEvent, atkObj, PR_TRUE);
 
-    case nsIAccessibleEvent::EVENT_HIDE:
+    case nsIAccessibleEvent::EVENT_DOM_DESTROY:
+    case nsIAccessibleEvent::EVENT_ASYNCH_HIDE:
         return FireAtkShowHideEvent(aEvent, atkObj, PR_FALSE);
 
         /*
          * Because dealing with menu is very different between nsIAccessible
          * and ATK, and the menu activity is important, specially transfer the
          * following two event.
          * Need more verification by AT test.
          */
@@ -1412,17 +1417,17 @@ nsAccessibleWrap::FireAtkStateChangeEven
 
     return NS_OK;
 }
 
 nsresult
 nsAccessibleWrap::FireAtkTextChangedEvent(nsIAccessibleEvent *aEvent,
                                           AtkObject *aObject)
 {
-    MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_CHANGED\n"));
+    MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_REMOVED/INSERTED\n"));
 
     nsCOMPtr<nsIAccessibleTextChangeEvent> event =
         do_QueryInterface(aEvent);
     NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
 
     PRInt32 start = 0;
     event->GetStart(&start);
 
@@ -1511,19 +1516,19 @@ nsAccessibleWrap::FireAtkPropChangedEven
     return NS_OK;
 }
 
 nsresult
 nsAccessibleWrap::FireAtkShowHideEvent(nsIAccessibleEvent *aEvent,
                                        AtkObject *aObject, PRBool aIsAdded)
 {
     if (aIsAdded)
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_SHOW\n"));
+        MAI_LOG_DEBUG(("\n\nReceived: Show event\n"));
     else
-        MAI_LOG_DEBUG(("\n\nReceived: EVENT_HIDE\n"));
+        MAI_LOG_DEBUG(("\n\nReceived: Hide event\n"));
 
     nsCOMPtr<nsIAccessible> accessible;
     aEvent->GetAccessible(getter_AddRefs(accessible));
     NS_ENSURE_STATE(accessible);
 
     nsCOMPtr<nsIAccessible> parentAccessible;
     accessible->GetParent(getter_AddRefs(parentAccessible));
     NS_ENSURE_STATE(parentAccessible);
@@ -1540,13 +1545,8 @@ nsAccessibleWrap::FireAtkShowHideEvent(n
                           "children_changed::remove",
                           indexInParent,
                           aObject,
                           NULL);
 
     return NS_OK;
 }
 
-PRBool nsAccessibleWrap::MustPrune(nsIAccessible *aAccessible)
-{
-  PRUint32 role = Role(aAccessible);
-  return role == nsIAccessibleRole::ROLE_GRAPHIC;
-}
--- a/accessible/src/atk/nsAccessibleWrap.h
+++ b/accessible/src/atk/nsAccessibleWrap.h
@@ -110,19 +110,16 @@ public:
     void SetMaiHyperlink(MaiHyperlink* aMaiHyperlink);
 
     static const char * ReturnString(nsAString &aString) {
       static nsCString returnedString;
       returnedString = NS_ConvertUTF16toUTF8(aString);
       return returnedString.get();
     }
 
-    // Should this accessible be allowed to have any ATK children
-    static PRBool MustPrune(nsIAccessible *aAccessible);
-
 protected:
     nsresult FireAtkStateChangeEvent(nsIAccessibleEvent *aEvent,
                                      AtkObject *aObject);
     nsresult FireAtkTextChangedEvent(nsIAccessibleEvent *aEvent,
                                      AtkObject *aObject);
     nsresult FireAtkPropChangedEvent(nsIAccessibleEvent *aEvent,
                                      AtkObject *aObject);
     nsresult FireAtkShowHideEvent(nsIAccessibleEvent *aEvent,
--- a/accessible/src/atk/nsAppRootAccessible.cpp
+++ b/accessible/src/atk/nsAppRootAccessible.cpp
@@ -38,28 +38,36 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsCOMPtr.h"
 #include "nsMai.h"
 #include "nsAppRootAccessible.h"
 #include "prlink.h"
+#include "prenv.h"
+#include "nsIPrefBranch.h"
 #include "nsIServiceManager.h"
 #include "nsAutoPtr.h"
 
 #include <gtk/gtk.h>
 #include <atk/atk.h>
 
 typedef GType (* AtkGetTypeType) (void);
 GType g_atk_hyperlink_impl_type = G_TYPE_INVALID;
 static PRBool sATKChecked = PR_FALSE;
 static PRLibrary *sATKLib = nsnull;
 static const char sATKLibName[] = "libatk-1.0.so.0";
-static const char sATKHyperlinkImplGetTypeSymbol[] = "atk_hyperlink_impl_get_type";
+static const char sATKHyperlinkImplGetTypeSymbol[] =
+    "atk_hyperlink_impl_get_type";
+static const char sAccEnv [] = "GNOME_ACCESSIBILITY";
+static const char sSysPrefService [] =
+    "@mozilla.org/system-preference-service;1";
+static const char sAccessibilityKey [] =
+    "config.use_system_prefs.accessibility";
 
 /* gail function pointer */
 static guint (* gail_add_global_event_listener) (GSignalEmissionHook listener,
                                                  const gchar *event_type);
 static void (* gail_remove_global_event_listener) (guint remove_listener);
 static AtkObject * (*gail_get_root) (void);
 
 /* maiutil */
@@ -501,38 +509,59 @@ nsApplicationAccessibleWrap::nsApplicati
 nsApplicationAccessibleWrap::~nsApplicationAccessibleWrap()
 {
     MAI_LOG_DEBUG(("======Destory AppRootAcc=%p\n", (void*)this));
 }
 
 NS_IMETHODIMP
 nsApplicationAccessibleWrap::Init()
 {
-    // load and initialize gail library
-    nsresult rv = LoadGtkModule(sGail);
-    if (NS_SUCCEEDED(rv)) {
-        (*sGail.init)();
-    }
-    else {
-        MAI_LOG_DEBUG(("Fail to load lib: %s\n", sGail.libName));
+    // XXX following code is copied from widget/src/gtk2/nsWindow.cpp
+    // we should put it to somewhere that can be used from both modules
+    // see bug 390761
+
+    // check if accessibility enabled/disabled by environment variable
+    PRBool isGnomeATEnabled = PR_FALSE;
+    const char *envValue = PR_GetEnv(sAccEnv);
+    if (envValue) {
+        isGnomeATEnabled = atoi(envValue);
+    } else {
+        //check gconf-2 setting
+        nsresult rv;
+        nsCOMPtr<nsIPrefBranch> sysPrefService =
+            do_GetService(sSysPrefService, &rv);
+        if (NS_SUCCEEDED(rv) && sysPrefService) {
+            sysPrefService->GetBoolPref(sAccessibilityKey, &isGnomeATEnabled);
+        }
     }
 
-    MAI_LOG_DEBUG(("Mozilla Atk Implementation initializing\n"));
-    // Initialize the MAI Utility class
-    // it will overwrite gail_util
-    g_type_class_unref(g_type_class_ref(MAI_TYPE_UTIL));
+    if (isGnomeATEnabled) {
+        // load and initialize gail library
+        nsresult rv = LoadGtkModule(sGail);
+        if (NS_SUCCEEDED(rv)) {
+            (*sGail.init)();
+        }
+        else {
+            MAI_LOG_DEBUG(("Fail to load lib: %s\n", sGail.libName));
+        }
 
-    // load and initialize atk-bridge library
-    rv = LoadGtkModule(sAtkBridge);
-    if (NS_SUCCEEDED(rv)) {
-        // init atk-bridge
-        (*sAtkBridge.init)();
+        MAI_LOG_DEBUG(("Mozilla Atk Implementation initializing\n"));
+        // Initialize the MAI Utility class
+        // it will overwrite gail_util
+        g_type_class_unref(g_type_class_ref(MAI_TYPE_UTIL));
+
+        // load and initialize atk-bridge library
+        rv = LoadGtkModule(sAtkBridge);
+        if (NS_SUCCEEDED(rv)) {
+            // init atk-bridge
+            (*sAtkBridge.init)();
+        }
+        else
+            MAI_LOG_DEBUG(("Fail to load lib: %s\n", sAtkBridge.libName));
     }
-    else
-        MAI_LOG_DEBUG(("Fail to load lib: %s\n", sAtkBridge.libName));
 
     return nsApplicationAccessible::Init();
 }
 
 void
 nsApplicationAccessibleWrap::Unload()
 {
     if (sAtkBridge.lib) {
--- a/accessible/src/atk/nsXULTreeAccessibleWrap.cpp
+++ b/accessible/src/atk/nsXULTreeAccessibleWrap.cpp
@@ -91,16 +91,33 @@ NS_IMETHODIMP nsXULTreeAccessibleWrap::G
 {
   nsresult rv = NS_OK;
 
   nsCOMPtr<nsIAccessible> acc;
   rv = nsAccessible::GetFirstChild(getter_AddRefs(acc));
   NS_ENSURE_TRUE(acc, NS_ERROR_FAILURE);
 
   rv = acc->GetChildCount(aColumns);
+
+  // The last child could be column picker. In that case, we need to minus the
+  // number of columns by 1
+  nsCOMPtr<nsIAccessible> lastChildAccessible;
+  acc->GetLastChild(getter_AddRefs(lastChildAccessible));
+  nsCOMPtr<nsIAccessNode> accessNode = do_QueryInterface(lastChildAccessible);
+  NS_ENSURE_TRUE(accessNode, NS_ERROR_FAILURE);
+  nsCOMPtr<nsIDOMNode> domNode;
+  accessNode->GetDOMNode(getter_AddRefs(domNode));
+  nsCOMPtr<nsIContent> content = do_QueryInterface(domNode);
+  NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
+  // it's menupopup inside column picker
+  if (content->NodeInfo()->Equals(nsAccessibilityAtoms::menupopup,
+                                  kNameSpaceID_XUL)) {
+    (*aColumns)--;
+  }
+
   return *aColumns > 0 ? rv : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP nsXULTreeAccessibleWrap::GetColumnHeader(nsIAccessibleTable **aColumnHeader)
 {
   nsresult rv = NS_OK;
 
   nsCOMPtr<nsIAccessible> acc;
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -152,34 +152,32 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] 
             {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE},
             {"expanded", kBoolState, nsIAccessibleStates::STATE_EXPANDED},
             {"expanded", "false", nsIAccessibleStates::STATE_COLLAPSED}, kEndEntry},
   {"rowheader", nsIAccessibleRole::ROLE_ROWHEADER, eNameOkFromChildren, eNoValue, kNoReqStates,
             {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
             {"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
             {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE},
             {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
-  {"secret", nsIAccessibleRole::ROLE_PASSWORD_TEXT, eNameLabelOrTitle, eNoValue, nsIAccessibleStates::STATE_PROTECTED,
-            // Manually map EXT_STATE_SINGLE_LINE and EXT_STATE_MULTI_LINE FROM aaa:multiline
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
   {"section", nsIAccessibleRole::ROLE_SECTION, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"separator", nsIAccessibleRole::ROLE_SEPARATOR, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"slider", nsIAccessibleRole::ROLE_SLIDER, eNameLabelOrTitle, eHasValueMinMax, kNoReqStates,
             {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
             {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
   {"spinbutton", nsIAccessibleRole::ROLE_SPINBUTTON, eNameLabelOrTitle, eHasValueMinMax, kNoReqStates,
             {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
             {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
   {"status", nsIAccessibleRole::ROLE_STATUSBAR, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"tab", nsIAccessibleRole::ROLE_PAGETAB, eNameOkFromChildren, eNoValue, kNoReqStates,
             {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
   {"tablist", nsIAccessibleRole::ROLE_PAGETABLIST, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"tabpanel", nsIAccessibleRole::ROLE_PROPERTYPAGE, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"textbox", nsIAccessibleRole::ROLE_ENTRY, eNameLabelOrTitle, eNoValue, kNoReqStates,
             // Manually map EXT_STATE_SINGLE_LINE and EXT_STATE_MULTI_LINE FROM aaa:multiline
+            {"secret", kBoolState, nsIAccessibleStates::STATE_PROTECTED},
             {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
             {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
   {"toolbar", nsIAccessibleRole::ROLE_TOOLBAR, eNameLabelOrTitle, eNoValue, kNoReqStates,
             {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
   {"tooltip", nsIAccessibleRole::ROLE_TOOLTIP, eNameOkFromChildren, eNoValue, kNoReqStates, kEndEntry},
   {"tree", nsIAccessibleRole::ROLE_OUTLINE, eNameLabelOrTitle, eNoValue, kNoReqStates,
             {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
             {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY},
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -148,16 +148,17 @@ ACCESSIBILITY_ATOM(labelledby, "labelled
 ACCESSIBILITY_ATOM(owns, "owns")
 
   // Alphabetical list of attributes
 ACCESSIBILITY_ATOM(acceltext, "acceltext")
 ACCESSIBILITY_ATOM(accesskey, "accesskey")
 ACCESSIBILITY_ATOM(alt, "alt")
 ACCESSIBILITY_ATOM(anonid, "anonid") // Used for ID's in XBL
 ACCESSIBILITY_ATOM(autocomplete, "autocomplete") // Used as attribute value too
+ACCESSIBILITY_ATOM(contenteditable, "contenteditable")
 ACCESSIBILITY_ATOM(control, "control")
 ACCESSIBILITY_ATOM(cycles, "cycles") // used for XUL cycler attribute
 ACCESSIBILITY_ATOM(curpos, "curpos") // XUL
 ACCESSIBILITY_ATOM(data, "data")
 ACCESSIBILITY_ATOM(disabled, "disabled")
 ACCESSIBILITY_ATOM(droppable, "droppable")   // XUL combo box
 ACCESSIBILITY_ATOM(editable, "editable")
 ACCESSIBILITY_ATOM(_for, "for")
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -1783,19 +1783,19 @@ NS_IMETHODIMP nsAccessibilityService::Re
 #endif
 }
 
 // Called from layout when the frame tree owned by a node changes significantly
 NS_IMETHODIMP nsAccessibilityService::InvalidateSubtreeFor(nsIPresShell *aShell,
                                                            nsIContent *aChangeContent,
                                                            PRUint32 aEvent)
 {
-  NS_ASSERTION(aEvent == nsIAccessibleEvent::EVENT_REORDER ||
-               aEvent == nsIAccessibleEvent::EVENT_SHOW ||
-               aEvent == nsIAccessibleEvent::EVENT_HIDE,
+  NS_ASSERTION(aEvent == nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE ||
+               aEvent == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
+               aEvent == nsIAccessibleEvent::EVENT_ASYNCH_HIDE,
                "Incorrect aEvent passed in");
 
   nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(aShell));
   NS_ASSERTION(aShell, "No pres shell in call to InvalidateSubtreeFor");
   nsCOMPtr<nsIAccessibleDocument> accessibleDoc =
     nsAccessNode::GetDocAccessibleFor(weakShell);
   nsCOMPtr<nsPIAccessibleDocument> privateAccessibleDoc =
     do_QueryInterface(accessibleDoc);
--- a/accessible/src/base/nsAccessibilityUtils.cpp
+++ b/accessible/src/base/nsAccessibilityUtils.cpp
@@ -163,22 +163,42 @@ nsAccUtils::HasListener(nsIContent *aCon
   NS_ENSURE_ARG_POINTER(aContent);
   nsCOMPtr<nsIEventListenerManager> listenerManager;
   aContent->GetListenerManager(PR_FALSE, getter_AddRefs(listenerManager));
 
   return listenerManager && listenerManager->HasListenersFor(aEventType);  
 }
 
 nsresult
-nsAccUtils::FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible)
+nsAccUtils::FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
+                         PRBool aIsAsynch)
 {
   NS_ENSURE_ARG(aAccessible);
 
   nsCOMPtr<nsPIAccessible> pAccessible(do_QueryInterface(aAccessible));
   NS_ASSERTION(pAccessible, "Accessible doesn't implement nsPIAccessible");
 
   nsCOMPtr<nsIAccessibleEvent> event =
-    new nsAccEvent(aEventType, aAccessible, nsnull);
+    new nsAccEvent(aEventType, aAccessible, nsnull, aIsAsynch);
   NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
 
   return pAccessible->FireAccessibleEvent(event);
 }
 
+PRBool
+nsAccUtils::IsAncestorOf(nsIDOMNode *aPossibleAncestorNode,
+                         nsIDOMNode *aPossibleDescendantNode)
+{
+  NS_ENSURE_ARG_POINTER(aPossibleAncestorNode);
+  NS_ENSURE_ARG_POINTER(aPossibleDescendantNode);
+
+  nsCOMPtr<nsIDOMNode> loopNode = aPossibleDescendantNode;
+  nsCOMPtr<nsIDOMNode> parentNode;
+  while (NS_SUCCEEDED(loopNode->GetParentNode(getter_AddRefs(parentNode))) &&
+         parentNode) {
+    if (parentNode == aPossibleAncestorNode) {
+      return PR_TRUE;
+    }
+    loopNode.swap(parentNode);
+  }
+  return PR_FALSE;
+}
+
--- a/accessible/src/base/nsAccessibilityUtils.h
+++ b/accessible/src/base/nsAccessibilityUtils.h
@@ -106,12 +106,23 @@ public:
    * Return true if the given node has registered event listener of the given
    * type.
    */
   static PRBool HasListener(nsIContent *aContent, const nsAString& aEventType);
 
   /**
    * Fire accessible event of the given type for the given accessible.
    */
-  static nsresult FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible);
+  static nsresult FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
+                               PRBool aIsAsynch = PR_FALSE);
+
+  /**
+   * Is the first passed in node an ancestor of the second?
+   * Note: A node is not considered to be the ancestor of itself.
+   * @aPossibleAncestorNode -- node to test for ancestor-ness of aPossibleDescendantNode
+   * @aPossibleDescendantNode -- node to test for descendant-ness of aPossibleAncestorNode
+   * @return PR_TRUE if aPossibleAncestorNode is an ancestor of aPossibleDescendantNode
+   */
+  static PRBool IsAncestorOf(nsIDOMNode *aPossibleAncestorNode,
+                             nsIDOMNode *aPossibleDescendantNode);
 };
 
 #endif
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -206,24 +206,26 @@ nsresult nsAccessible::QueryInterface(RE
       static nsIContent::AttrValuesArray strings[] =
         {&nsAccessibilityAtoms::_empty, &nsAccessibilityAtoms::_false, nsnull};
       if (content->FindAttrValueIn(kNameSpaceID_WAIProperties ,
                                    nsAccessibilityAtoms::multiselectable,
                                    strings, eCaseMatters) ==
           nsIContent::ATTR_VALUE_NO_MATCH) {
         *aInstancePtr = static_cast<nsIAccessibleSelectable*>(this);
         NS_ADDREF_THIS();
+        return NS_OK;
       }
     }
   }
 
   if (aIID.Equals(NS_GET_IID(nsIAccessibleValue))) {
     if (mRoleMapEntry && mRoleMapEntry->valueRule != eNoValue) {
       *aInstancePtr = static_cast<nsIAccessibleValue*>(this);
       NS_ADDREF_THIS();
+      return NS_OK;
     }
   }                       
 
   if (aIID.Equals(NS_GET_IID(nsIAccessibleHyperLink))) {
     nsCOMPtr<nsIAccessible> parent(GetParent());
     nsCOMPtr<nsIAccessibleHyperText> hyperTextParent(do_QueryInterface(parent));
     if (hyperTextParent) {
       *aInstancePtr = static_cast<nsIAccessibleHyperLink*>(this);
@@ -2078,16 +2080,18 @@ nsAccessible::GetAttributes(nsIPersisten
 
   if (!mDOMNode)
     return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIPersistentProperties> attributes =
      do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
   NS_ENSURE_TRUE(attributes, NS_ERROR_OUT_OF_MEMORY);
 
+  nsAccEvent::GetLastEventAttributes(mDOMNode, attributes);
+ 
   nsresult rv = GetAttributesInternal(attributes);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIContent> content = GetRoleContent(mDOMNode);
   if (content) {
     nsAutoString id;
     nsAutoString oldValueUnused;
     if (content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::id, id)) {
@@ -2116,27 +2120,23 @@ nsAccessible::GetAttributes(nsIPersisten
 
   if (!nsAccUtils::HasAccGroupAttrs(attributes)) {
     // The role of an accessible can be pointed by ARIA attribute but ARIA
     // posinset, level, setsize may be skipped. Therefore we calculate here
     // these properties to map them into description.
 
     // If accessible is invisible we don't want to calculate group ARIA
     // attributes for it.
-    PRUint32 state = State(this);
-    if (state & nsIAccessibleStates::STATE_INVISIBLE)
-      return NS_OK;
-
     PRUint32 role = Role(this);
-    if (role == nsIAccessibleRole::ROLE_LISTITEM ||
+    if ((role == nsIAccessibleRole::ROLE_LISTITEM ||
         role == nsIAccessibleRole::ROLE_MENUITEM ||
         role == nsIAccessibleRole::ROLE_RADIOBUTTON ||
         role == nsIAccessibleRole::ROLE_PAGETAB ||
-        role == nsIAccessibleRole::ROLE_OUTLINEITEM) {
-
+        role == nsIAccessibleRole::ROLE_OUTLINEITEM) &&
+        0 == (State(this) & nsIAccessibleStates::STATE_INVISIBLE)) {
       nsCOMPtr<nsIAccessible> parent = GetParent();
       NS_ENSURE_TRUE(parent, NS_ERROR_FAILURE);
 
       PRInt32 positionInGroup = 0;
       PRInt32 setSize = 0;
 
       nsCOMPtr<nsIAccessible> sibling, nextSibling;
       parent->GetFirstChild(getter_AddRefs(sibling));
@@ -2716,16 +2716,21 @@ NS_IMETHODIMP nsAccessible::GetAccessibl
               }
             }
           }
           relatedNode = do_QueryInterface(buttonEl);
         }
       }
       break;
     }
+  case nsIAccessibleRelation::RELATION_MEMBER_OF:
+    {
+      relatedNode = nsAccEvent::GetLastEventAtomicRegion(mDOMNode);
+      break;
+    }
   default:
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   if (!relatedID.IsEmpty()) {
     // In some cases we need to get the relatedNode from an ID-style attribute
     nsCOMPtr<nsIDOMDocument> domDoc;
     mDOMNode->GetOwnerDocument(getter_AddRefs(domDoc));
@@ -3263,8 +3268,21 @@ nsAccessible::GetAttrValue(PRUint32 aNam
   PRInt32 result = NS_OK;
   nsAutoString value;
   if (content->GetAttr(aNameSpaceID, aName, value) && !value.IsEmpty())
     *aValue = value.ToFloat(&result);
 
   return result;
 }
 
+PRBool nsAccessible::MustPrune(nsIAccessible *aAccessible)
+{ 
+  PRUint32 role = Role(aAccessible);
+  return role == nsIAccessibleRole::ROLE_MENUITEM || 
+         role == nsIAccessibleRole::ROLE_ENTRY ||
+         role == nsIAccessibleRole::ROLE_PASSWORD_TEXT ||
+         role == nsIAccessibleRole::ROLE_PUSHBUTTON ||
+         role == nsIAccessibleRole::ROLE_TOGGLE_BUTTON ||
+         role == nsIAccessibleRole::ROLE_GRAPHIC ||
+         role == nsIAccessibleRole::ROLE_SLIDER ||
+         role == nsIAccessibleRole::ROLE_PROGRESSBAR ||
+         role == nsIAccessibleRole::ROLE_SEPARATOR;
+}
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -150,23 +150,27 @@ public:
   static PRBool IsCorrectFrameType(nsIFrame* aFrame, nsIAtom* aAtom);
   static PRUint32 State(nsIAccessible *aAcc) { PRUint32 state; aAcc->GetFinalState(&state, nsnull); return state; }
   static PRUint32 Role(nsIAccessible *aAcc) { PRUint32 role; aAcc->GetFinalRole(&role); return role; }
   static PRBool IsText(nsIAccessible *aAcc) { PRUint32 role = Role(aAcc); return role == nsIAccessibleRole::ROLE_TEXT_LEAF || role == nsIAccessibleRole::ROLE_STATICTEXT; }
   static PRBool IsEmbeddedObject(nsIAccessible *aAcc) { PRUint32 role = Role(aAcc); return role != nsIAccessibleRole::ROLE_TEXT_LEAF && role != nsIAccessibleRole::ROLE_WHITESPACE && role != nsIAccessibleRole::ROLE_STATICTEXT; }
   static PRInt32 TextLength(nsIAccessible *aAccessible); // Returns -1 on failure
   static PRBool IsLeaf(nsIAccessible *aAcc) { PRInt32 numChildren; aAcc->GetChildCount(&numChildren); return numChildren > 0; }
   static PRBool IsNodeRelevant(nsIDOMNode *aNode); // Is node something that could have an attached accessible
+  /**
+   * When exposing to platform accessibility APIs, should the children be pruned off?
+   */
+  static PRBool MustPrune(nsIAccessible *aAccessible);
   
   already_AddRefed<nsIAccessible> GetParent() {
     nsIAccessible *parent = nsnull;
     GetParent(&parent);
     return parent;
   }
-
+  
 protected:
   PRBool MappedAttrState(nsIContent *aContent, PRUint32 *aStateInOut, nsStateMapEntry *aStateMapEntry);
   virtual nsIFrame* GetBoundsFrame();
   virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
   PRBool IsVisible(PRBool *aIsOffscreen); 
 
   // Relation helpers
   nsresult GetTextFromRelationID(nsIAtom *aIDAttrib, nsString &aName);
--- a/accessible/src/base/nsAccessibleEventData.cpp
+++ b/accessible/src/base/nsAccessibleEventData.cpp
@@ -32,36 +32,197 @@
  * 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 "nsAccessibleEventData.h"
+#include "nsAccessibilityAtoms.h"
 #include "nsIAccessibilityService.h"
 #include "nsIAccessNode.h"
+#include "nsIDocument.h"
+#include "nsIDOMDocument.h"
+#include "nsIEventStateManager.h"
+#include "nsIPersistentProperties2.h"
 #include "nsIServiceManager.h"
 #ifdef MOZ_XUL
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsXULTreeAccessible.h"
 #endif
+#include "nsIContent.h"
+#include "nsIPresShell.h"
+#include "nsPresContext.h"
+
+PRBool nsAccEvent::gLastEventFromUserInput = PR_FALSE;
+nsIDOMNode* nsAccEvent::gLastEventNodeWeak = 0;
 
 NS_IMPL_ISUPPORTS1(nsAccEvent, nsIAccessibleEvent)
 
 nsAccEvent::nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
-                       void *aEventData):
+                       void *aEventData, PRBool aIsAsynch):
   mEventType(aEventType), mAccessible(aAccessible), mEventData(aEventData)
 {
+  CaptureIsFromUserInput(aIsAsynch);
 }
 
 nsAccEvent::nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode,
-                       void *aEventData):
+                       void *aEventData, PRBool aIsAsynch):
   mEventType(aEventType), mDOMNode(aDOMNode), mEventData(aEventData)
 {
+  CaptureIsFromUserInput(aIsAsynch);
+}
+
+void nsAccEvent::GetLastEventAttributes(nsIDOMNode *aNode,
+                                        nsIPersistentProperties *aAttributes)
+{
+  if (aNode != gLastEventNodeWeak) {
+    return; // Passed-in node doesn't Change the last event's node
+  }
+  nsAutoString oldValueUnused;
+  aAttributes->SetStringProperty(NS_LITERAL_CSTRING("event-from-input"),
+                                 gLastEventFromUserInput ? NS_LITERAL_STRING("true") :
+                                                           NS_LITERAL_STRING("false"),
+                                 oldValueUnused);
+
+  nsCOMPtr<nsIContent> lastEventContent = do_QueryInterface(aNode);
+  nsIContent *loopContent = lastEventContent;
+
+  nsAutoString atomic, live, relevant, channel, busy;
+
+  while (loopContent) {
+    if (relevant.IsEmpty()) {
+      loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::relevant, relevant);
+    }
+    if (live.IsEmpty()) {
+      loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::live, live);
+    }
+    if (channel.IsEmpty()) {
+      loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::channel, channel);
+    }
+    if (atomic.IsEmpty()) {
+      loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::atomic, atomic);
+    }
+    if (busy.IsEmpty()) {
+      loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::busy, busy);
+    }
+    loopContent = loopContent->GetParent();
+  }
+
+  if (!relevant.IsEmpty()) {
+    aAttributes->SetStringProperty(NS_LITERAL_CSTRING("container-relevant"), relevant, oldValueUnused);
+  }
+  if (!live.IsEmpty()) {
+    aAttributes->SetStringProperty(NS_LITERAL_CSTRING("container-live"), live, oldValueUnused);
+  }
+  if (!channel.IsEmpty()) {
+    aAttributes->SetStringProperty(NS_LITERAL_CSTRING("container-channel"), channel, oldValueUnused);
+  }
+  if (!atomic.IsEmpty()) {
+    aAttributes->SetStringProperty(NS_LITERAL_CSTRING("container-atomic"), atomic, oldValueUnused);
+  }
+  if (!busy.IsEmpty()) {
+    aAttributes->SetStringProperty(NS_LITERAL_CSTRING("container-busy"), busy, oldValueUnused);
+  }
+}
+
+nsIDOMNode* nsAccEvent::GetLastEventAtomicRegion(nsIDOMNode *aNode)
+{
+  if (aNode != gLastEventNodeWeak) {
+    return nsnull; // Passed-in node doesn't Change the last changed node
+  }
+  nsCOMPtr<nsIContent> lastEventContent = do_QueryInterface(aNode);
+  nsIContent *loopContent = lastEventContent;
+  nsAutoString atomic;
+
+  while (loopContent) {
+    loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::atomic, atomic);
+    if (!atomic.IsEmpty()) {
+      break;
+    }
+    loopContent = loopContent->GetParent();
+  }
+
+  nsCOMPtr<nsIDOMNode> atomicRegion;
+  if (atomic.EqualsLiteral("true")) {
+    atomicRegion = do_QueryInterface(loopContent);
+  }
+  return atomicRegion;
+}
+
+void nsAccEvent::CaptureIsFromUserInput(PRBool aIsAsynch)
+{
+  nsCOMPtr<nsIDOMNode> eventNode;
+  GetDOMNode(getter_AddRefs(eventNode));
+  if (!eventNode) {
+    NS_NOTREACHED("There should always be a DOM node for an event");
+    return;
+  }
+
+  if (aIsAsynch) {
+    // Cannot calculate, so use previous value
+    gLastEventNodeWeak = eventNode;
+  }
+  else {
+    PrepareForEvent(eventNode);
+  }
+  
+  mIsFromUserInput = gLastEventFromUserInput;
+}
+
+NS_IMETHODIMP
+nsAccEvent::GetIsFromUserInput(PRBool *aIsFromUserInput)
+{
+  *aIsFromUserInput = mIsFromUserInput;
+  return NS_OK;
+}
+
+void nsAccEvent::PrepareForEvent(nsIAccessibleEvent *aEvent)
+{
+  nsCOMPtr<nsIDOMNode> eventNode;
+  aEvent->GetDOMNode(getter_AddRefs(eventNode));
+  PRBool isFromUserInput;
+  aEvent->GetIsFromUserInput(&isFromUserInput);
+  PrepareForEvent(eventNode, isFromUserInput);
+}
+
+void nsAccEvent::PrepareForEvent(nsIDOMNode *aEventNode,
+                                 PRBool aForceIsFromUserInput)
+{
+  gLastEventNodeWeak = aEventNode;
+  if (aForceIsFromUserInput) {
+    gLastEventFromUserInput = PR_TRUE;
+    return;
+  }
+
+  nsCOMPtr<nsIDOMDocument> domDoc;
+  aEventNode->GetOwnerDocument(getter_AddRefs(domDoc));
+  if (!domDoc) {  // IF the node is a document itself
+    domDoc = do_QueryInterface(aEventNode);
+  }
+  nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
+  if (!doc) {
+    NS_NOTREACHED("There should always be a document for an event");
+    return;
+  }
+
+  nsCOMPtr<nsIPresShell> presShell = doc->GetPrimaryShell();
+  if (!presShell) {
+    NS_NOTREACHED("Threre should always be an pres shell for an event");
+    return;
+  }
+
+  nsIEventStateManager *esm = presShell->GetPresContext()->EventStateManager();
+  if (!esm) {
+    NS_NOTREACHED("Threre should always be an ESM for an event");
+    return;
+  }
+
+  gLastEventFromUserInput = esm->IsHandlingUserInputExternal();
 }
 
 NS_IMETHODIMP
 nsAccEvent::GetEventType(PRUint32 *aEventType)
 {
   *aEventType = mEventType;
   return NS_OK;
 }
@@ -229,17 +390,18 @@ nsAccStateChangeEvent::IsEnabled(PRBool 
 
 // nsAccTextChangeEvent
 NS_IMPL_ISUPPORTS_INHERITED1(nsAccTextChangeEvent, nsAccEvent,
                              nsIAccessibleTextChangeEvent)
 
 nsAccTextChangeEvent::
   nsAccTextChangeEvent(nsIAccessible *aAccessible,
                        PRInt32 aStart, PRUint32 aLength, PRBool aIsInserted):
-  nsAccEvent(::nsIAccessibleEvent::EVENT_TEXT_CHANGED, aAccessible, nsnull),
+  nsAccEvent(aIsInserted ? nsIAccessibleEvent::EVENT_TEXT_INSERTED : nsIAccessibleEvent::EVENT_TEXT_REMOVED,
+             aAccessible, nsnull),
   mStart(aStart), mLength(aLength), mIsInserted(aIsInserted)
 {
 }
 
 NS_IMETHODIMP
 nsAccTextChangeEvent::GetStart(PRInt32 *aStart)
 {
   *aStart = mStart;
@@ -261,24 +423,24 @@ nsAccTextChangeEvent::IsInserted(PRBool 
 }
 
 // nsAccCaretMoveEvent
 NS_IMPL_ISUPPORTS_INHERITED1(nsAccCaretMoveEvent, nsAccEvent,
                              nsIAccessibleCaretMoveEvent)
 
 nsAccCaretMoveEvent::
   nsAccCaretMoveEvent(nsIAccessible *aAccessible, PRInt32 aCaretOffset) :
-  nsAccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible, nsnull),
+  nsAccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible, nsnull, PR_TRUE), // Currently always asynch
   mCaretOffset(aCaretOffset)
 {
 }
 
 nsAccCaretMoveEvent::
   nsAccCaretMoveEvent(nsIDOMNode *aNode) :
-  nsAccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aNode, nsnull),
+  nsAccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aNode, nsnull, PR_TRUE), // Currently always asynch
   mCaretOffset(-1)
 {
 }
 
 NS_IMETHODIMP
 nsAccCaretMoveEvent::GetCaretOffset(PRInt32* aCaretOffset)
 {
   NS_ENSURE_ARG_POINTER(aCaretOffset);
--- a/accessible/src/base/nsAccessibleEventData.h
+++ b/accessible/src/base/nsAccessibleEventData.h
@@ -41,39 +41,66 @@
 #ifndef _nsAccessibleEventData_H_
 #define _nsAccessibleEventData_H_
 
 #include "nsCOMPtr.h"
 #include "nsIAccessibleEvent.h"
 #include "nsIAccessible.h"
 #include "nsIAccessibleDocument.h"
 #include "nsIDOMNode.h"
+class nsIPresShell;
 
 class nsAccEvent: public nsIAccessibleEvent
 {
 public:
   // Initialize with an nsIAccessible
-  nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible, void *aEventData);
+  nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible, void *aEventData, PRBool aIsAsynch = PR_FALSE);
   // Initialize with an nsIDOMNode
-  nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode, void *aEventData);
+  nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode, void *aEventData, PRBool aIsAsynch = PR_FALSE);
   virtual ~nsAccEvent() {}
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIACCESSIBLEEVENT
 
+  static void GetLastEventAttributes(nsIDOMNode *aNode,
+                                      nsIPersistentProperties *aAttributes);
+  static nsIDOMNode* GetLastEventAtomicRegion(nsIDOMNode *aNode);
+
 protected:
   already_AddRefed<nsIAccessible> GetAccessibleByNode();
 
+  void CaptureIsFromUserInput(PRBool aIsAsynch);
+  PRBool mIsFromUserInput;
+
 private:
   PRUint32 mEventType;
   nsCOMPtr<nsIAccessible> mAccessible;
   nsCOMPtr<nsIDOMNode> mDOMNode;
   nsCOMPtr<nsIAccessibleDocument> mDocAccessible;
 
+  static PRBool gLastEventFromUserInput;
+  static nsIDOMNode* gLastEventNodeWeak;
+
 public:
+  /**
+   * Find and cache the last input state. This will be called automatically
+   * for synchronous events. For asynchronous events it should be
+   * called from the synchronous code which is the true source of the event,
+   * before the event is fired.
+   */
+  static void PrepareForEvent(nsIDOMNode *aChangeNode,
+                              PRBool aForceIsFromUserInput = PR_FALSE);
+
+  /**
+   * The input state was previously stored with the nsIAccessibleEvent,
+   * so use that state now -- call this when about to flush an event that 
+   * was waiting in an event queue
+   */
+  static void PrepareForEvent(nsIAccessibleEvent *aEvent);
+
   void *mEventData;
 };
 
 class nsAccStateChangeEvent: public nsAccEvent,
                              public nsIAccessibleStateChangeEvent
 {
 public:
   nsAccStateChangeEvent(nsIAccessible *aAccessible,
--- a/accessible/src/base/nsCaretAccessible.cpp
+++ b/accessible/src/base/nsCaretAccessible.cpp
@@ -216,17 +216,17 @@ NS_IMETHODIMP nsCaretAccessible::NotifyS
   }
   mLastCaretOffset = caretOffset;
   mLastTextAccessible = textAcc;
 
   nsCOMPtr<nsIAccessibleCaretMoveEvent> event =
     new nsAccCaretMoveEvent(focusNode);
   NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
 
-  return mRootAccessible->FireDelayedAccessibleEvent(event, PR_FALSE);
+  return mRootAccessible->FireDelayedAccessibleEvent(event, nsDocAccessible::eRemoveDupes);
 }
 
 nsRect
 nsCaretAccessible::GetCaretRect(nsIWidget **aOutWidget)
 {
   nsRect caretRect;
   NS_ENSURE_TRUE(aOutWidget, caretRect);
   *aOutWidget = nsnull;
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -238,17 +238,18 @@ nsDocAccessible::GetState(PRUint32 *aSta
   }
  
   if (frame != nsnull) {
     if (!CheckVisibilityInParentChain(mDocument, frame->GetViewExternal())) {
       *aState |= nsIAccessibleStates::STATE_INVISIBLE;
     }
   }
 
-  nsCOMPtr<nsIEditor> editor = GetEditor();
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
   if (!editor) {
     *aState |= nsIAccessibleStates::STATE_READONLY;
   }
   else if (aExtraState) {
     *aExtraState |= nsIAccessibleStates::EXT_STATE_EDITABLE;
   }
 
   return NS_OK;
@@ -392,47 +393,43 @@ NS_IMETHODIMP nsDocAccessible::GetDocume
   if (domDoc) {
     NS_ADDREF(*aDOMDoc);
     return NS_OK;
   }
 
   return NS_ERROR_FAILURE;
 }
 
-void nsDocAccessible::SetEditor(nsIEditor* aEditor)
+NS_IMETHODIMP nsDocAccessible::GetAssociatedEditor(nsIEditor **aEditor)
 {
-  mEditor = aEditor;
-}
+  NS_ENSURE_ARG_POINTER(aEditor);
 
-void nsDocAccessible::CheckForEditor()
-{
-  if (mEditor) {
-    return;  // Already have editor, don't need to check
-  }
-  if (!mDocument) {
-    return;  // No document -- we've been shut down
+  *aEditor = nsnull;
+  NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
+
+  if (!mDocument->HasFlag(NODE_IS_EDITABLE)) {
+    return NS_OK; // Document not editable
   }
 
   nsCOMPtr<nsISupports> container = mDocument->GetContainer();
   nsCOMPtr<nsIEditingSession> editingSession(do_GetInterface(container));
   if (!editingSession)
-    return; // No editing session interface
+    return NS_OK; // No editing session interface
 
   nsCOMPtr<nsIEditor> editor;
-  editingSession->GetEditorForWindow(mDocument->GetWindow(),
-                                     getter_AddRefs(editor));
-  SetEditor(editor);
-  if (!editor)
-    return;
-
-  // State editable is now set, readonly is now clear
-  nsCOMPtr<nsIAccessibleStateChangeEvent> event =
-    new nsAccStateChangeEvent(this, nsIAccessibleStates::EXT_STATE_EDITABLE,
-                              PR_TRUE, PR_TRUE);
-  FireAccessibleEvent(event);
+  editingSession->GetEditorForWindow(mDocument->GetWindow(), getter_AddRefs(editor));
+  if (!editor) {
+    return NS_OK;
+  }
+  PRBool isEditable;
+  editor->GetIsDocumentEditable(&isEditable);
+  if (isEditable) {
+    NS_ADDREF(*aEditor = editor);
+  }
+  return NS_OK;
 }
 
 NS_IMETHODIMP nsDocAccessible::GetCachedAccessNode(void *aUniqueID, nsIAccessNode **aAccessNode)
 {
   GetCacheEntry(mAccessNodeCache, aUniqueID, aAccessNode); // Addrefs for us
 #ifdef DEBUG_A11Y
   // All cached accessible nodes should be in the parent
   // It will assert if not all the children were created
@@ -526,18 +523,16 @@ NS_IMETHODIMP nsDocAccessible::Shutdown(
 {
   if (!mWeakShell) {
     return NS_OK;  // Already shutdown
   }
 
   nsCOMPtr<nsIDocShellTreeItem> treeItem = GetDocShellTreeItemFor(mDOMNode);
   ShutdownChildDocuments(treeItem);
 
-  mEditor = nsnull;
-
   if (mDocLoadTimer) {
     mDocLoadTimer->Cancel();
     mDocLoadTimer = nsnull;
   }
 
   RemoveEventListeners();
 
   mWeakShell = nsnull;  // Avoid reentrancy
@@ -648,24 +643,20 @@ nsresult nsDocAccessible::AddEventListen
   // Make sure we're a content docshell
   // We don't want to listen to chrome progress
   PRInt32 itemType;
   docShellTreeItem->GetItemType(&itemType);
 
   PRBool isContent = (itemType == nsIDocShellTreeItem::typeContent);
 
   if (isContent) {
-    CheckForEditor();
-
-    if (!mEditor) {
-      // We're not an editor yet, but we might become one
-      nsCOMPtr<nsICommandManager> commandManager = do_GetInterface(docShellTreeItem);
-      if (commandManager) {
-        commandManager->AddCommandObserver(this, "obs_documentCreated");
-      }
+    // We're not an editor yet, but we might become one
+    nsCOMPtr<nsICommandManager> commandManager = do_GetInterface(docShellTreeItem);
+    if (commandManager) {
+      commandManager->AddCommandObserver(this, "obs_documentCreated");
     }
   }
 
   nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
   docShellTreeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
   if (rootTreeItem) {
     GetDocAccessibleFor(rootTreeItem, PR_TRUE); // Ensure root accessible is created;
     nsRefPtr<nsRootAccessible> rootAccessible = GetRootAccessible();
@@ -893,19 +884,22 @@ NS_IMETHODIMP nsDocAccessible::ScrollPos
   }
   mScrollPositionChangedTicks = 1;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsDocAccessible::Observe(nsISupports *aSubject, const char *aTopic,
                                        const PRUnichar *aData)
 {
-  if (!nsCRT::strcmp(aTopic,"obs_documentCreated")) {
-    CheckForEditor();
-    NS_ASSERTION(mEditor, "Should have editor if we see obs_documentCreated");
+  if (!nsCRT::strcmp(aTopic,"obs_documentCreated")) {    
+    // State editable will now be set, readonly is now clear
+    nsCOMPtr<nsIAccessibleStateChangeEvent> event =
+      new nsAccStateChangeEvent(this, nsIAccessibleStates::EXT_STATE_EDITABLE,
+                                PR_TRUE, PR_TRUE);
+    FireAccessibleEvent(event);
   }
 
   return NS_OK;
 }
 
 ///////////////////////////////////////////////////////////////////////
 // nsIDocumentObserver
 
@@ -945,16 +939,21 @@ nsDocAccessible::AttributeChanged(nsIDoc
   }
 
   nsCOMPtr<nsIDOMNode> targetNode(do_QueryInterface(aContent));
   NS_ASSERTION(targetNode, "No node for attr modified");
   if (!targetNode || !IsNodeRelevant(targetNode)) {
     return;
   }
 
+  // Since we're in synchronous code, we can store whether the current attribute
+  // change is from user input or not. If the attribute change causes an asynchronous
+  // layout change, that event can use the last known user input state
+  nsAccEvent::PrepareForEvent(targetNode);
+
   // Universal boolean properties that don't require a role.
   if (aAttribute == nsAccessibilityAtoms::disabled) {
     // Fire the state change whether disabled attribute is
     // set for XUL, HTML or ARIA namespace.
     // Checking the namespace would not seem to gain us anything, because
     // disabled really is going to mean the same thing in any namespace.
     // We use the attribute instead of the disabled state bit because
     // ARIA's aaa:disabled does not affect the disabled state bit
@@ -974,24 +973,24 @@ nsDocAccessible::AttributeChanged(nsIDoc
   if (aNameSpaceID == kNameSpaceID_WAIProperties) {
     ARIAAttributeChanged(aContent, aAttribute);
     return;
   }
 
   if (aNameSpaceID == kNameSpaceID_XHTML2_Unofficial ||
       aNameSpaceID == kNameSpaceID_XHTML) {
     if (aAttribute == nsAccessibilityAtoms::role)
-      InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_REORDER);
+      InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
     return;
   }
 
   if (aAttribute == nsAccessibilityAtoms::href ||
       aAttribute == nsAccessibilityAtoms::onclick ||
       aAttribute == nsAccessibilityAtoms::droppable) {
-    InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_REORDER);
+    InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
     return;
   }
 
   if (aAttribute == nsAccessibilityAtoms::selected) {
     // DHTML or XUL selection
     nsCOMPtr<nsIAccessible> multiSelect = GetMultiSelectFor(targetNode);
     // Multi selects use selection_add and selection_remove
     // Single select widgets just mirror event_selection for
@@ -1002,17 +1001,17 @@ nsDocAccessible::AttributeChanged(nsIDoc
       // Need to find the right event to use here, SELECTION_WITHIN would
       // seem right but we had started using it for something else
       nsCOMPtr<nsIAccessNode> multiSelectAccessNode =
         do_QueryInterface(multiSelect);
       nsCOMPtr<nsIDOMNode> multiSelectDOMNode;
       multiSelectAccessNode->GetDOMNode(getter_AddRefs(multiSelectDOMNode));
       NS_ASSERTION(multiSelectDOMNode, "A new accessible without a DOM node!");
       FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN,
-                              multiSelectDOMNode, nsnull, PR_TRUE);
+                              multiSelectDOMNode, nsnull, eAllowDupes);
 
       static nsIContent::AttrValuesArray strings[] =
         {&nsAccessibilityAtoms::_empty, &nsAccessibilityAtoms::_false, nsnull};
       if (aContent->FindAttrValueIn(kNameSpaceID_None,
                                     nsAccessibilityAtoms::selected,
                                     strings, eCaseMatters) !=
           nsIContent::ATTR_VALUE_NO_MATCH) {
 
@@ -1020,16 +1019,25 @@ nsDocAccessible::AttributeChanged(nsIDoc
                                 targetNode, nsnull);
         return;
       }
 
       FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_SELECTION_ADD,
                                                   targetNode, nsnull);
     }
   }
+
+  if (aAttribute == nsAccessibilityAtoms::contenteditable) {
+    nsCOMPtr<nsIAccessibleStateChangeEvent> editableChangeEvent =
+      new nsAccStateChangeEvent(targetNode,
+                                nsIAccessibleStates::EXT_STATE_EDITABLE,
+                                PR_TRUE);
+    FireDelayedAccessibleEvent(editableChangeEvent);
+    return;
+  }
 }
 
 void
 nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
 {
   nsCOMPtr<nsIDOMNode> targetNode(do_QueryInterface(aContent));
   if (!targetNode)
     return;
@@ -1076,16 +1084,25 @@ nsDocAccessible::ARIAAttributeChanged(ns
     nsCOMPtr<nsIAccessibleStateChangeEvent> event =
       new nsAccStateChangeEvent(targetNode,
                                 nsIAccessibleStates::STATE_CHECKED,
                                 PR_FALSE);
     FireDelayedAccessibleEvent(event);
     return;
   }
 
+  if (aAttribute == nsAccessibilityAtoms::pressed) {
+    nsCOMPtr<nsIAccessibleStateChangeEvent> event =
+      new nsAccStateChangeEvent(targetNode,
+                                nsIAccessibleStates::STATE_PRESSED,
+                                PR_FALSE);
+    FireDelayedAccessibleEvent(event);
+    return;
+  }
+
   if (aAttribute == nsAccessibilityAtoms::expanded) {
     nsCOMPtr<nsIAccessibleStateChangeEvent> event =
       new nsAccStateChangeEvent(targetNode,
                                 nsIAccessibleStates::STATE_EXPANDED,
                                 PR_FALSE);
     FireDelayedAccessibleEvent(event);
     return;
   }
@@ -1107,17 +1124,17 @@ nsDocAccessible::ARIAAttributeChanged(ns
 
   if (aAttribute == nsAccessibilityAtoms::multiselectable) {
     // This affects whether the accessible supports nsIAccessibleSelectable.
     // COM says we cannot change what interfaces are supported on-the-fly,
     // so invalidate this object. A new one will be created on demand.
     if (HasRoleAttribute(aContent)) {
       // The multiselectable and other waistate attributes only take affect
       // when dynamic content role is present
-      InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_REORDER);
+      InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
     }
   }
 }
 
 void nsDocAccessible::ContentAppended(nsIDocument *aDocument,
                                       nsIContent* aContainer,
                                       PRInt32 aNewIndexInContainer)
 {
@@ -1134,17 +1151,17 @@ void nsDocAccessible::ContentAppended(ns
     nsCOMPtr<nsIContent> child(aContainer->GetChildAt(index));
 
     FireTextChangedEventOnDOMNodeInserted(child, aContainer, index);
 
     // InvalidateCacheSubtree will not fire the EVENT_SHOW for the new node
     // unless an accessible can be created for the passed in node, which it
     // can't do unless the node is visible. The right thing happens there so
     // no need for an extra visibility check here.
-    InvalidateCacheSubtree(child, nsIAccessibleEvent::EVENT_SHOW);
+    InvalidateCacheSubtree(child, nsIAccessibleEvent::EVENT_DOM_CREATE);
   }
 }
 
 void nsDocAccessible::ContentStatesChanged(nsIDocument* aDocument,
                                            nsIContent* aContent1,
                                            nsIContent* aContent2,
                                            PRInt32 aStateMask)
 {
@@ -1168,27 +1185,27 @@ nsDocAccessible::ContentInserted(nsIDocu
                                  nsIContent* aChild, PRInt32 aIndexInContainer)
 {
   FireTextChangedEventOnDOMNodeInserted(aChild, aContainer, aIndexInContainer);
 
   // InvalidateCacheSubtree will not fire the EVENT_SHOW for the new node
   // unless an accessible can be created for the passed in node, which it
   // can't do unless the node is visible. The right thing happens there so
   // no need for an extra visibility check here.
-  InvalidateCacheSubtree(aChild, nsIAccessibleEvent::EVENT_SHOW);
+  InvalidateCacheSubtree(aChild, nsIAccessibleEvent::EVENT_DOM_CREATE);
 }
 
 void
 nsDocAccessible::ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer,
                                 nsIContent* aChild, PRInt32 aIndexInContainer)
 {
   FireTextChangedEventOnDOMNodeRemoved(aChild, aContainer, aIndexInContainer);
 
   // Invalidate the subtree of the removed element.
-  InvalidateCacheSubtree(aChild, nsIAccessibleEvent::EVENT_HIDE);
+  InvalidateCacheSubtree(aChild, nsIAccessibleEvent::EVENT_DOM_DESTROY);
 }
 
 void
 nsDocAccessible::ParentChainChanged(nsIContent *aContent)
 {
 }
 
 void
@@ -1359,45 +1376,84 @@ nsDocAccessible::FireTextChangedEventOnD
     return;
 
   textAccessible->FireAccessibleEvent(event);
 }
 
 nsresult nsDocAccessible::FireDelayedToolkitEvent(PRUint32 aEvent,
                                                   nsIDOMNode *aDOMNode,
                                                   void *aData,
-                                                  PRBool aAllowDupes)
+                                                  EDupeEventRule aAllowDupes,
+                                                  PRBool aIsAsynch)
 {
-  nsCOMPtr<nsIAccessibleEvent> event = new nsAccEvent(aEvent, aDOMNode, aData);
+  nsCOMPtr<nsIAccessibleEvent> event =
+    new nsAccEvent(aEvent, aDOMNode, aData, PR_TRUE);
   NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
 
-  return FireDelayedAccessibleEvent(event);
+  return FireDelayedAccessibleEvent(event, aAllowDupes, aIsAsynch);
 }
 
 nsresult
 nsDocAccessible::FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent,
-                                           PRBool aAllowDupes)
+                                            EDupeEventRule aAllowDupes,
+                                            PRBool aIsAsynch)
 {
   PRBool isTimerStarted = PR_TRUE;
   PRInt32 numQueuedEvents = mEventsToFire.Count();
   if (!mFireEventTimer) {
     // Do not yet have a timer going for firing another event.
     mFireEventTimer = do_CreateInstance("@mozilla.org/timer;1");
     NS_ENSURE_TRUE(mFireEventTimer, NS_ERROR_OUT_OF_MEMORY);
   }
 
   PRUint32 newEventType;
   aEvent->GetEventType(&newEventType);
 
   nsCOMPtr<nsIDOMNode> newEventDOMNode;
   aEvent->GetDOMNode(getter_AddRefs(newEventDOMNode));
 
+  if (!aIsAsynch) {
+    // If already asynchronous don't call PrepareFromEvent() -- it
+    // should only be called while ESM still knows if the event occurred
+    // originally because of user input
+    nsAccEvent::PrepareForEvent(newEventDOMNode);
+  }
+
   if (numQueuedEvents == 0) {
     isTimerStarted = PR_FALSE;
-  } else if (!aAllowDupes) {
+  } else if (aAllowDupes == eCoalesceFromSameSubtree) {
+    // Especially for mutation events, we will define a duplicate event
+    // as one on the same node or on a descendant node.
+    // This prevents a flood of events when a subtree is changed.
+    for (PRInt32 index = 0; index < numQueuedEvents; index ++) {
+      nsIAccessibleEvent *accessibleEvent = mEventsToFire[index];
+      NS_ASSERTION(accessibleEvent, "Array item is not an accessible event");
+      if (!accessibleEvent) {
+        continue;
+      }
+      PRUint32 eventType;
+      accessibleEvent->GetEventType(&eventType);
+      if (eventType == newEventType) {
+        nsCOMPtr<nsIDOMNode> domNode;
+        accessibleEvent->GetDOMNode(getter_AddRefs(domNode));
+        if (newEventDOMNode == domNode || nsAccUtils::IsAncestorOf(newEventDOMNode, domNode)) {
+          mEventsToFire.RemoveObjectAt(index);
+          // The other event is the same type, but in a descendant of this
+          // event, so remove that one. The umbrella event in the ancestor
+          // is already enough
+          -- index;
+          -- numQueuedEvents;
+        }
+        else if (nsAccUtils::IsAncestorOf(domNode, newEventDOMNode)) {
+          // There is a better SHOW/HIDE event (it's in an ancestor)
+          return NS_OK;
+        }
+      }    
+    }
+  } else if (aAllowDupes == eRemoveDupes) {
     // Check for repeat events. If a redundant event exists remove
     // original and put the new event at the end of the queue
     // so it is fired after the others
     for (PRInt32 index = 0; index < numQueuedEvents; index ++) {
       nsIAccessibleEvent *accessibleEvent = mEventsToFire[index];
       NS_ASSERTION(accessibleEvent, "Array item is not an accessible event");
       if (!accessibleEvent) {
         continue;
@@ -1465,41 +1521,51 @@ NS_IMETHODIMP nsDocAccessible::FlushPend
           NS_ENSURE_TRUE(caretMoveEvent, NS_ERROR_OUT_OF_MEMORY);
 
           FireAccessibleEvent(caretMoveEvent);
 
           PRInt32 selectionCount;
           accessibleText->GetSelectionCount(&selectionCount);
           if (selectionCount) {  // There's a selection so fire selection change as well
             nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
-                                     accessible);
+                                     accessible, PR_TRUE);
           }
         } 
       }
       else {
+        // The input state was previously stored with the nsIAccessibleEvent,
+        // so use that state now when firing the event
+        nsAccEvent::PrepareForEvent(accessibleEvent);
         FireAccessibleEvent(accessibleEvent);
+        // Post event processing
+        if (eventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
+            eventType == nsIAccessibleEvent::EVENT_DOM_DESTROY) {
+          // Shutdown nsIAccessNode's or nsIAccessibles for any DOM nodes in this subtree
+          nsCOMPtr<nsIDOMNode> hidingNode;
+          accessibleEvent->GetDOMNode(getter_AddRefs(hidingNode));
+          if (hidingNode) {
+            RefreshNodes(hidingNode); // Will this bite us with asynch events
+          }
+        }
       }
     }
   }
   mEventsToFire.Clear(); // Clear out array
   return NS_OK;
 }
 
 void nsDocAccessible::FlushEventsCallback(nsITimer *aTimer, void *aClosure)
 {
   nsPIAccessibleDocument *accessibleDoc = static_cast<nsPIAccessibleDocument*>(aClosure);
   NS_ASSERTION(accessibleDoc, "How did we get here without an accessible document?");
   accessibleDoc->FlushPendingEvents();
 }
 
-void nsDocAccessible::RefreshNodes(nsIDOMNode *aStartNode, PRUint32 aChangeEvent)
+void nsDocAccessible::RefreshNodes(nsIDOMNode *aStartNode)
 {
-  NS_ASSERTION(aChangeEvent != nsIAccessibleEvent::EVENT_SHOW,
-               "nsDocAccessible::RefreshNodes isn't supposed to work with show event.");
-
   nsCOMPtr<nsIDOMNode> iterNode(aStartNode), nextNode;
   nsCOMPtr<nsIAccessNode> accessNode;
 
   do {
     GetCachedAccessNode(iterNode, getter_AddRefs(accessNode));
     if (accessNode) {
       // Accessibles that implement their own subtrees,
       // like html combo boxes and xul trees must shutdown all of their own
@@ -1560,21 +1626,36 @@ void nsDocAccessible::RefreshNodes(nsIDO
     } while (PR_TRUE);
   }
   while (iterNode && iterNode != aStartNode);
 }
 
 NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
                                                       PRUint32 aChangeEventType)
 {
-  NS_ASSERTION(aChangeEventType == nsIAccessibleEvent::EVENT_REORDER ||
-               aChangeEventType == nsIAccessibleEvent::EVENT_SHOW ||
-               aChangeEventType == nsIAccessibleEvent::EVENT_HIDE,
+  PRBool isHiding = 
+    aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
+    aChangeEventType == nsIAccessibleEvent::EVENT_DOM_DESTROY;
+
+  PRBool isShowing = 
+    aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
+    aChangeEventType == nsIAccessibleEvent::EVENT_DOM_CREATE;
+
+  PRBool isChanging = 
+    aChangeEventType == nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE ||
+    aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE;
+
+  NS_ASSERTION(isChanging || isHiding || isShowing,
                "Incorrect aChangeEventType passed in");
 
+  PRBool isAsynch = 
+    aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
+    aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
+    aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE;
+
   // Invalidate cache subtree
   // We have to check for accessibles for each dom node by traversing DOM tree
   // instead of just the accessible tree, although that would be faster
   // Otherwise we might miss the nsAccessNode's that are not nsAccessible's.
 
   NS_ENSURE_TRUE(mDOMNode, NS_ERROR_FAILURE);
   nsCOMPtr<nsIDOMNode> childNode = aChild ? do_QueryInterface(aChild) : mDOMNode;
   if (!IsNodeRelevant(childNode)) {
@@ -1586,51 +1667,61 @@ NS_IMETHODIMP nsDocAccessible::Invalidat
     // by not firing SHOW/HIDE/REORDER events for every document mutation
     // caused by page load, since AT is not going to want to grab the
     // document and listen to these changes until after the page is first loaded
     // Leave early, and ensure mAccChildCount stays uninitialized instead of 0,
     // which it is if anyone asks for its children right now.
     return InvalidateChildren();
   }
 
+  // Update last change state information
   nsCOMPtr<nsIAccessNode> childAccessNode;
   GetCachedAccessNode(childNode, getter_AddRefs(childAccessNode));
   nsCOMPtr<nsIAccessible> childAccessible = do_QueryInterface(childAccessNode);
-  if (!childAccessible && aChangeEventType != nsIAccessibleEvent::EVENT_HIDE) {
+  if (!childAccessible && !isHiding) {
     // If not about to hide it, make sure there's an accessible so we can fire an
     // event for it
     GetAccService()->GetAccessibleFor(childNode, getter_AddRefs(childAccessible));
   }
 
 #ifdef DEBUG_A11Y
   nsAutoString localName;
   childNode->GetLocalName(localName);
   const char *hasAccessible = childAccessible ? " (acc)" : "";
-  if (aChangeEventType == nsIAccessibleEvent::EVENT_HIDE) {
+  if (aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE) {
     printf("[Hide %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
   }
-  else if (aChangeEventType == nsIAccessibleEvent::EVENT_SHOW) {
+  else if (aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW) {
     printf("[Show %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
   }
-  else if (aChangeEventType == nsIAccessibleEvent::EVENT_REORDER) {
-    printf("[Reorder %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
+  else if (aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE) {
+    printf("[Layout change %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
+  }
+  else if (aChangeEventType == nsIAccessibleEvent::EVENT_DOM_CREATE) {
+    printf("[Create %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
+  }
+  else if (aChangeEventType == nsIAccessibleEvent::EVENT_DOM_DESTROY) {
+    printf("[Destroy  %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
+  }
+  else if (aChangeEventType == nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE) {
+    printf("[Type change %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
   }
 #endif
 
-  if (aChangeEventType == nsIAccessibleEvent::EVENT_HIDE ||
-      aChangeEventType == nsIAccessibleEvent::EVENT_REORDER) {
-    // Fire EVENT_HIDE if previous accessible existed for node being hidden.
+  if (!isShowing) {
+    // Fire EVENT_ASYNCH_HIDE or EVENT_DOM_DESTROY if previous accessible existed for node being hidden.
     // Fire this before the accessible goes away.
-    if (childAccessible)
-      nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_HIDE, childAccessible);
-  }
-
-  // Shutdown nsIAccessNode's or nsIAccessibles for any DOM nodes in this subtree
-  if (aChangeEventType != nsIAccessibleEvent::EVENT_SHOW) {
-    RefreshNodes(childNode, aChangeEventType);
+    if (childAccessible) {
+      PRUint32 removalEventType = isAsynch ? nsIAccessibleEvent::EVENT_ASYNCH_HIDE :
+                                  nsIAccessibleEvent::EVENT_DOM_DESTROY;
+      nsCOMPtr<nsIAccessibleEvent> removalEvent =
+        new nsAccEvent(removalEventType, childAccessible, nsnull, PR_TRUE);
+      NS_ENSURE_TRUE(removalEvent, NS_ERROR_OUT_OF_MEMORY);
+      FireDelayedAccessibleEvent(removalEvent, eCoalesceFromSameSubtree, isAsynch);
+    }
   }
 
   // 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.
@@ -1641,62 +1732,61 @@ NS_IMETHODIMP nsDocAccessible::Invalidat
     containerAccessible = this;
   }
   nsCOMPtr<nsPIAccessible> privateContainerAccessible =
     do_QueryInterface(containerAccessible);
   if (privateContainerAccessible) {
     privateContainerAccessible->InvalidateChildren();
   }
 
-  // Fire an event so the assistive technology knows the objects it is holding onto
-  // in this part of the subtree are no longer useful and should be released.
-  // However, they still won't crash if the AT tries to use them, because a stub of the
-  // object still exists as long as it is refcounted, even from outside of Gecko.
-  nsCOMPtr<nsIAccessNode> containerAccessNode =
-    do_QueryInterface(containerAccessible);
-  if (containerAccessNode) {
-    nsCOMPtr<nsIDOMNode> containerNode;
-    containerAccessNode->GetDOMNode(getter_AddRefs(containerNode));
-    if (containerNode) {
-      FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_REORDER,
-                              containerNode, nsnull);
-    }
-  }
-
-  if (aChild && (aChangeEventType == nsIAccessibleEvent::EVENT_SHOW ||
-      aChangeEventType == nsIAccessibleEvent::EVENT_REORDER)) {
+  if (aChild && !isHiding) {
     // Fire EVENT_SHOW, EVENT_MENUPOPUP_START for newly visible content.
     // Fire after a short timer, because we want to make sure the view has been
     // updated to make this accessible content visible. If we don't wait,
     // the assistive technology may receive the event and then retrieve
     // nsIAccessibleStates::STATE_INVISIBLE for the event's accessible object.
-    FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_SHOW, childNode, nsnull);
+    PRUint32 additionEvent = isAsynch ? nsIAccessibleEvent::EVENT_ASYNCH_SHOW :
+                                        nsIAccessibleEvent::EVENT_DOM_CREATE;
+    FireDelayedToolkitEvent(additionEvent, childNode, nsnull,
+                            eCoalesceFromSameSubtree, isAsynch);
+
+    // Check to see change occured in an ARIA menu, and fire an EVENT_MENUPOPUP_START if it did
     nsAutoString role;
     if (GetRoleAttribute(aChild, role) &&
         StringEndsWith(role, NS_LITERAL_STRING(":menu"), nsCaseInsensitiveStringComparator())) {
       FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
-                              childNode, nsnull);
+                              childNode, nsnull, eAllowDupes, isAsynch);
     }
-  }
 
-  // Check to see if change occured inside an alert, and fire an EVENT_ALERT if it did
-  if (aChangeEventType != nsIAccessibleEvent::EVENT_HIDE) {
+    // Check to see if change occured inside an alert, and fire an EVENT_ALERT if it did
     nsIContent *ancestor = aChild;
-    nsAutoString role;
     while (ancestor) {
       if (GetRoleAttribute(ancestor, role) &&
           StringEndsWith(role, NS_LITERAL_STRING(":alert"), nsCaseInsensitiveStringComparator())) {
         nsCOMPtr<nsIDOMNode> alertNode(do_QueryInterface(ancestor));
-        FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_ALERT, alertNode, nsnull);
+        FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_ALERT, alertNode, nsnull,
+                                eRemoveDupes, isAsynch);
         break;
       }
       ancestor = ancestor->GetParent();
     }
   }
 
+  if (!isShowing) {
+    // Fire an event so the assistive technology knows the children have changed
+    // This is only used by older MSAA clients. Newer ones should derive this
+    // from SHOW and HIDE so that they don't fetch extra objects
+    if (childAccessible) {
+      nsCOMPtr<nsIAccessibleEvent> reorderEvent =
+        new nsAccEvent(nsIAccessibleEvent::EVENT_REORDER, containerAccessible, nsnull, PR_TRUE);
+      NS_ENSURE_TRUE(reorderEvent, NS_ERROR_OUT_OF_MEMORY);
+      FireDelayedAccessibleEvent(reorderEvent, eCoalesceFromSameSubtree, isAsynch);
+    }
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocAccessible::GetAccessibleInParentChain(nsIDOMNode *aNode,
                                             nsIAccessible **aAccessible)
 {
   // Find accessible in parent chain of DOM nodes, or return null
@@ -1750,17 +1840,17 @@ void nsDocAccessible::DocLoadCallback(ns
     nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = do_QueryInterface(container);
     if (!docShellTreeItem) {
       return;
     }
     nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
     docShellTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
     if (sameTypeRoot != docShellTreeItem) {
       // A frame or iframe has finished loading new content
-      docAcc->InvalidateCacheSubtree(nsnull, nsIAccessibleEvent::EVENT_REORDER);
+      docAcc->InvalidateCacheSubtree(nsnull, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
       return;
     }
 
     // Fire STATE_CHANGE event for doc load finish if focus is in same doc tree
     if (gLastFocusedNode) {
       nsCOMPtr<nsIDocShellTreeItem> focusedTreeItem =
         GetDocShellTreeItemFor(gLastFocusedNode);
       if (focusedTreeItem) {
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -94,43 +94,64 @@ class nsDocAccessible : public nsHyperTe
 
     // nsIAccessNode
     NS_IMETHOD Shutdown();
     NS_IMETHOD Init();
 
     // nsPIAccessNode
     NS_IMETHOD_(nsIFrame *) GetFrame(void);
 
-    // Non-virtual
+    // nsIAccessibleText
+    NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
+
+    enum EDupeEventRule { eAllowDupes, eCoalesceFromSameSubtree, eRemoveDupes };
+
+    /**
+      * Non-virtual method to fire a delayed event after a 0 length timeout
+      *
+      * @param aEvent - the nsIAccessibleEvent event ype
+      * @param aDOMNode - DOM node the accesible event should be fired for
+      * @param aData - any additional data for the event
+      * @param aAllowDupes - eAllowDupes: more than one event of the same type is allowed. 
+      *                      eCoalesceFromSameSubtree: if two events are in the same subtree,
+      *                                                only the event on ancestor is used
+      *                      eRemoveDupes (default): events of the same type are discarded
+      *                                              (the last one is used)
+      *
+      * @param aIsAsyn - set to PR_TRUE if this is not being called from code
+      *                  synchronous with a DOM event
+      */
     nsresult FireDelayedToolkitEvent(PRUint32 aEvent, nsIDOMNode *aDOMNode,
-                                     void *aData, PRBool aAllowDupes = PR_FALSE);
+                                     void *aData, EDupeEventRule aAllowDupes = eRemoveDupes,
+                                     PRBool aIsAsynch = PR_FALSE);
 
     /**
      * Fire accessible event in timeout.
      *
+     * @param aEvent - the event to fire
      * @param aAllowDupes - if false then delayed events of the same type and
      *                      for the same DOM node in the event queue won't
      *                      be fired.
+     * @param aIsAsych - set to PR_TRUE if this is being called from
+     *                   an event asynchronous with the DOM
      */
     nsresult FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent,
-                                        PRBool aAllowDupes = PR_FALSE);
+                                        EDupeEventRule aAllowDupes = eRemoveDupes,
+                                        PRBool aIsAsynch = PR_FALSE);
 
     void ShutdownChildDocuments(nsIDocShellTreeItem *aStart);
 
   protected:
     virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
     virtual nsresult AddEventListeners();
     virtual nsresult RemoveEventListeners();
     void AddScrollListener();
     void RemoveScrollListener();
-    void RefreshNodes(nsIDOMNode *aStartNode, PRUint32 aChangeEvent);
+    void RefreshNodes(nsIDOMNode *aStartNode);
     static void ScrollTimerCallback(nsITimer *aTimer, void *aClosure);
-    void CheckForEditor();
-    virtual void SetEditor(nsIEditor *aEditor);
-    virtual already_AddRefed<nsIEditor> GetEditor() { nsIEditor *editor = mEditor; NS_IF_ADDREF(editor); return editor; }
 
     /**
      * Fires accessible events when ARIA attribute is chaned.
      *
      * @param aContent - node that attribute is changed for
      * @param aAttribute - changed attribute
      */
     void ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute);
@@ -159,17 +180,16 @@ class nsDocAccessible : public nsHyperTe
     nsAccessNodeHashtable mAccessNodeCache;
     void *mWnd;
     nsCOMPtr<nsIDocument> mDocument;
     nsCOMPtr<nsITimer> mScrollWatchTimer;
     nsCOMPtr<nsITimer> mFireEventTimer;
     PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
     PRPackedBool mIsContentLoaded;
     nsCOMArray<nsIAccessibleEvent> mEventsToFire;
-    nsCOMPtr<nsIEditor> mEditor;
 
 protected:
     PRBool mIsAnchor;
     PRBool mIsAnchorJumped;
 
 private:
     static void DocLoadCallback(nsITimer *aTimer, void *aClosure);
     nsCOMPtr<nsITimer> mDocLoadTimer;
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -414,23 +414,24 @@ void nsRootAccessible::TryFireEarlyLoadE
     if (state & nsIAccessibleStates::STATE_BUSY) {
       // Don't fire page load events on subdocuments for initial page load of entire page
       return;
     }
   }
 
   // No frames or iframes, so we can fire the doc load finished event early
   FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_INTERNAL_LOAD, aDocNode,
-                          nsnull, PR_FALSE);
+                          nsnull, eRemoveDupes);
 }
 
 PRBool nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
                                                   nsIDOMNode *aNode,
                                                   nsIDOMEvent *aFocusEvent,
-                                                  PRBool aForceEvent)
+                                                  PRBool aForceEvent,
+                                                  PRBool aIsAsynch)
 {
   if (mCaretAccessible) {
     nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aFocusEvent));
     if (nsevent) {
       // Use the originally focused node where the selection lives.
       // For example, use the anonymous HTML:input instead of the containing
       // XUL:textbox. In this case, sometimes it is a later focus event
       // which points to the actual anonymous child with focus, so to be safe 
@@ -505,17 +506,17 @@ PRBool nsRootAccessible::FireAccessibleF
       // Suppress document focus, because real DOM focus will be fired next,
       // and that's what we care about
       // Make sure we never fire focus for the nsRootAccessible (mDOMNode)
       return PR_FALSE;
     }
   }
 
   FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_FOCUS,
-                          finalFocusNode, nsnull);
+                          finalFocusNode, nsnull, eRemoveDupes, aIsAsynch);
 
   return PR_TRUE;
 }
 
 void nsRootAccessible::FireCurrentFocusEvent()
 {
   nsCOMPtr<nsIDOMNode> focusedNode = GetCurrentFocus();
   if (!focusedNode) {
@@ -602,22 +603,22 @@ nsresult nsRootAccessible::HandleEventWi
   if (eventType.EqualsLiteral("DOMContentLoaded")) {
     // Don't create the doc accessible until load scripts have a chance to set
     // role attribute for <body> or <html> element, because the value of 
     // role attribute will be cached when the doc accessible is Init()'d
     TryFireEarlyLoadEvent(aTargetNode);
     return NS_OK;
   }
 
-  if (eventType.EqualsLiteral("TreeViewChanged")) {
+  if (eventType.EqualsLiteral("TreeViewChanged")) { // Always asynch, always from user input
     NS_ENSURE_TRUE(localName.EqualsLiteral("tree"), NS_OK);
     nsCOMPtr<nsIContent> treeContent = do_QueryInterface(aTargetNode);
-
+    nsAccEvent::PrepareForEvent(aTargetNode, PR_TRUE);
     return accService->InvalidateSubtreeFor(eventShell, treeContent,
-                                            nsIAccessibleEvent::EVENT_REORDER);
+                                            nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE);
   }
 
   nsCOMPtr<nsIAccessible> accessible;
   accService->GetAccessibleInShell(aTargetNode, eventShell,
                                    getter_AddRefs(accessible));
   nsCOMPtr<nsPIAccessible> privAcc(do_QueryInterface(accessible));
   if (!privAcc)
     return NS_OK;
@@ -759,17 +760,17 @@ nsresult nsRootAccessible::HandleEventWi
     if (role == nsIAccessibleRole::ROLE_MENUPOPUP) {
       event = nsIAccessibleEvent::EVENT_MENUPOPUP_START;
     }
     else if (role == nsIAccessibleRole::ROLE_TOOLTIP) {
       // There is a single <xul:tooltip> node which Mozilla moves around.
       // The accessible for it stays the same no matter where it moves. 
       // AT's expect to get an EVENT_SHOW for the tooltip. 
       // In event callback the tooltip's accessible will be ready.
-      event = nsIAccessibleEvent::EVENT_SHOW;
+      event = nsIAccessibleEvent::EVENT_ASYNCH_SHOW;
     }
     if (event) {
       nsAccUtils::FireAccEvent(event, accessible);
     }
   }
 
   else if (eventType.EqualsLiteral("popuphiding")) {
     // If accessible focus was on or inside popup that closes,
@@ -817,23 +818,26 @@ nsresult nsRootAccessible::HandleEventWi
         accessible->GetParent(getter_AddRefs(containerAccessible));
         NS_ENSURE_TRUE(containerAccessible, NS_ERROR_FAILURE);
         // It is not top level menuitem
         // Only fire focus event if it is not inside collapsed popup
         if (State(containerAccessible) & nsIAccessibleStates::STATE_COLLAPSED)
           return NS_OK;
       }
     }
-    FireAccessibleFocusEvent(accessible, aTargetNode, aEvent, PR_TRUE);
+    nsAccEvent::PrepareForEvent(aTargetNode, PR_TRUE);  // Always asynch, always from user input
+    FireAccessibleFocusEvent(accessible, aTargetNode, aEvent, PR_TRUE, PR_TRUE);
   }
-  else if (eventType.EqualsLiteral("DOMMenuBarActive")) {
-    nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENU_START, accessible);
+  else if (eventType.EqualsLiteral("DOMMenuBarActive")) {  // Always asynch, always from user input
+    nsAccEvent::PrepareForEvent(aTargetNode, PR_TRUE);
+    nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENU_START, accessible, PR_TRUE);
   }
-  else if (eventType.EqualsLiteral("DOMMenuBarInactive")) {
-    nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENU_END, accessible);
+  else if (eventType.EqualsLiteral("DOMMenuBarInactive")) {  // Always asynch, always from user input
+    nsAccEvent::PrepareForEvent(aTargetNode, PR_TRUE);
+    nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENU_END, accessible, PR_TRUE);
     FireCurrentFocusEvent();
   }
   else if (eventType.EqualsLiteral("ValueChange")) {
     nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, accessible);
   }
   return NS_OK;
 }
 
--- a/accessible/src/base/nsRootAccessible.h
+++ b/accessible/src/base/nsRootAccessible.h
@@ -96,17 +96,18 @@ class nsRootAccessible : public nsDocAcc
       * @param aFocusNode        The DOM Node which has received focus.
       * @param aFocusEvent       DOM focus event that caused the node/accessible to receive focus
       * @param aForceEvent       Fire a focus event even if the last focused item was the same
       * @return                  Boolean -- was a focus event actually fired
       */
     PRBool FireAccessibleFocusEvent(nsIAccessible *aFocusAccessible,
                                     nsIDOMNode *aFocusNode,
                                     nsIDOMEvent *aFocusEvent,
-                                    PRBool aForceEvent = PR_FALSE);
+                                    PRBool aForceEvent = PR_FALSE,
+                                    PRBool aIsAsynch = PR_FALSE);
 
     nsCaretAccessible *GetCaretAccessible();
 
   private:
     nsCOMPtr<nsITimer> mFireFocusTimer;
     static void FireFocusCallback(nsITimer *aTimer, void *aClosure);
     
   protected:
--- a/accessible/src/html/Makefile.in
+++ b/accessible/src/html/Makefile.in
@@ -42,17 +42,18 @@ srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE = accessibility
 LIBRARY_NAME = accessibility_html_s
 LIBXUL_LIBRARY = 1
 
-REQUIRES	= content \
+REQUIRES	= composer \
+		  content \
 		  docshell \
 		  dom \
 		  editor \
 		  gfx \
 		  imglib2 \
 		  intl \
 		  js \
 		  layout \
--- a/accessible/src/html/nsHTMLFormControlAccessible.cpp
+++ b/accessible/src/html/nsHTMLFormControlAccessible.cpp
@@ -43,16 +43,17 @@
 #include "nsIDOMDocument.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMNSHTMLElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIDOMNSHTMLButtonElement.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIDOMHTMLLegendElement.h"
 #include "nsIDOMHTMLTextAreaElement.h"
+#include "nsIEditor.h"
 #include "nsIFrame.h"
 #include "nsINameSpaceManager.h"
 #include "nsISelectionController.h"
 #include "jsapi.h"
 #include "nsIJSContextStack.h"
 #include "nsIServiceManager.h"
 #include "nsITextControlFrame.h"
 
@@ -367,31 +368,16 @@ nsHTML4ButtonAccessible::GetState(PRUint
 
 // --- textfield -----
 
 nsHTMLTextFieldAccessible::nsHTMLTextFieldAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
 nsHyperTextAccessibleWrap(aNode, aShell)
 {
 }
 
-NS_IMPL_ISUPPORTS_INHERITED1(nsHTMLTextFieldAccessible, nsHyperTextAccessibleWrap,
-                             nsIAccessibleText)
-
-NS_IMETHODIMP nsHTMLTextFieldAccessible::Init()
-{
-  CheckForEditor();
-  return nsHyperTextAccessibleWrap::Init();
-}
-
-NS_IMETHODIMP nsHTMLTextFieldAccessible::Shutdown()
-{
-  mEditor = nsnull;
-  return nsHyperTextAccessibleWrap::Shutdown();
-}
-
 NS_IMETHODIMP nsHTMLTextFieldAccessible::GetRole(PRUint32 *aRole)
 {
   *aRole = nsIAccessibleRole::ROLE_ENTRY;
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   if (content &&
       content->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::type,
                            nsAccessibilityAtoms::password, eIgnoreCase)) {
     *aRole = nsIAccessibleRole::ROLE_PASSWORD_TEXT;
@@ -537,46 +523,39 @@ NS_IMETHODIMP nsHTMLTextFieldAccessible:
     if ( element ) {
       return element->Focus();
     }
     return NS_ERROR_FAILURE;
   }
   return NS_ERROR_INVALID_ARG;
 }
 
-void nsHTMLTextFieldAccessible::SetEditor(nsIEditor* aEditor)
+NS_IMETHODIMP nsHTMLTextFieldAccessible::GetAssociatedEditor(nsIEditor **aEditor)
 {
-  mEditor = aEditor;
-}
-
-void nsHTMLTextFieldAccessible::CheckForEditor()
-{
+  *aEditor = nsnull;
   nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(mDOMNode));
-  if (!editableElt) {
-    return;
-  }
+  NS_ENSURE_TRUE(editableElt, NS_ERROR_FAILURE);
 
   // nsGenericHTMLElement::GetEditor has a security check.
   // Make sure we're not restricted by the permissions of
   // whatever script is currently running.
   nsCOMPtr<nsIJSContextStack> stack =
     do_GetService("@mozilla.org/js/xpc/ContextStack;1");
   PRBool pushed = stack && NS_SUCCEEDED(stack->Push(nsnull));
 
   nsCOMPtr<nsIEditor> editor;
-  nsresult rv = editableElt->GetEditor(getter_AddRefs(editor));
-  if (NS_SUCCEEDED(rv)) {
-    SetEditor(editor);
-  }
+  nsresult rv = editableElt->GetEditor(aEditor);
 
   if (pushed) {
     JSContext* cx;
     stack->Pop(&cx);
     NS_ASSERTION(!cx, "context should be null");
   }
+
+  return rv;
 }
 
 // --- groupbox  -----
 
 /*
  * The HTML for this is <fieldset> <legend>box-title</legend> form elements </fieldset> 
  */
 
--- a/accessible/src/html/nsHTMLFormControlAccessible.h
+++ b/accessible/src/html/nsHTMLFormControlAccessible.h
@@ -97,36 +97,28 @@ public:
 };
 
 class nsHTMLTextFieldAccessible : public nsHyperTextAccessibleWrap
 {
 
 public:
   enum { eAction_Click = 0 };
 
-  NS_DECL_ISUPPORTS_INHERITED
-
   nsHTMLTextFieldAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
 
-  NS_IMETHOD Init(); 
-  NS_IMETHOD Shutdown(); 
   NS_IMETHOD GetRole(PRUint32 *_retval); 
   NS_IMETHOD GetName(nsAString& aName); 
   NS_IMETHOD GetValue(nsAString& _retval); 
   NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
   NS_IMETHOD GetNumActions(PRUint8 *_retval);
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD DoAction(PRUint8 index);
 
-protected:
-  // Editor helpers, subclasses of nsHyperTextAccessible may have editor
-  virtual void SetEditor(nsIEditor *aEditor);
-  virtual already_AddRefed<nsIEditor> GetEditor() { nsIEditor *editor = mEditor; NS_IF_ADDREF(editor); return editor; }
-  void CheckForEditor();
-  nsCOMPtr<nsIEditor> mEditor;
+  // nsIAccessibleEditableText
+  NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
 };
 
 class nsHTMLGroupboxAccessible : public nsHyperTextAccessibleWrap
 {
 public:
   nsHTMLGroupboxAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
   NS_IMETHOD GetRole(PRUint32 *aRole); 
   NS_IMETHOD GetName(nsAString& aName);
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -42,35 +42,39 @@
 #include "nsAccessibilityService.h"
 #include "nsAccessibleTreeWalker.h"
 #include "nsPIAccessNode.h"
 #include "nsIClipboard.h"
 #include "nsContentCID.h"
 #include "nsIDOMAbstractView.h"
 #include "nsIDOMCharacterData.h"
 #include "nsIDOMDocument.h"
+#include "nsPIDOMWindow.h"        
 #include "nsIDOMDocumentView.h"
 #include "nsIDOMRange.h"
 #include "nsIDOMWindowInternal.h"
 #include "nsIDOMXULDocument.h"
+#include "nsIEditingSession.h"
+#include "nsIEditor.h"
 #include "nsIFontMetrics.h"
 #include "nsIFrame.h"
+#include "nsIInterfaceRequestorUtils.h"
 #include "nsIPlaintextEditor.h"
 #include "nsIServiceManager.h"
 #include "nsTextFragment.h"
 #include "gfxSkipChars.h"
 
 static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
 
 // ------------
 // nsHyperTextAccessible
 // ------------
 
-NS_IMPL_ADDREF_INHERITED(nsHyperTextAccessible, nsAccessible)
-NS_IMPL_RELEASE_INHERITED(nsHyperTextAccessible, nsAccessible)
+NS_IMPL_ADDREF_INHERITED(nsHyperTextAccessible, nsAccessibleWrap)
+NS_IMPL_RELEASE_INHERITED(nsHyperTextAccessible, nsAccessibleWrap)
 
 nsresult nsHyperTextAccessible::QueryInterface(REFNSIID aIID, void** aInstancePtr)
 {
   *aInstancePtr = nsnull;
 
   if (aIID.Equals(NS_GET_IID(nsHyperTextAccessible))) {
     *aInstancePtr = static_cast<nsHyperTextAccessible*>(this);
     NS_ADDREF_THIS();
@@ -164,17 +168,18 @@ NS_IMETHODIMP
 nsHyperTextAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
 {
   nsresult rv = nsAccessibleWrap::GetState(aState, aExtraState);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!aExtraState)
     return NS_OK;
 
-  nsCOMPtr<nsIEditor> editor = GetEditor();
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
   if (editor) {
     PRUint32 flags;
     editor->GetFlags(&flags);
     if (0 == (flags & nsIPlaintextEditor::eEditorReadonlyMask)) {
       *aExtraState |= nsIAccessibleStates::EXT_STATE_EDITABLE;
     }
   }
 
@@ -190,18 +195,26 @@ nsHyperTextAccessible::GetState(PRUint32
 void nsHyperTextAccessible::CacheChildren()
 {
   if (!mWeakShell) {
     // This node has been shut down
     mAccChildCount = eChildCountUninitialized;
     return;
   }
 
+  // Special case for text entry fields, go directly to editor's root for children
   if (mAccChildCount == eChildCountUninitialized) {
-    nsCOMPtr<nsIEditor> editor = GetEditor();
+    PRUint32 role;
+    GetRole(&role);
+    if (role != nsIAccessibleRole::ROLE_ENTRY && role != nsIAccessibleRole::ROLE_PASSWORD_TEXT) {
+      nsAccessible::CacheChildren();
+      return;
+    }
+    nsCOMPtr<nsIEditor> editor;
+    GetAssociatedEditor(getter_AddRefs(editor));
     if (!editor) {
       nsAccessible::CacheChildren();
       return;
     }
     nsCOMPtr<nsIDOMElement> editorRoot;
     editor->GetRootElement(getter_AddRefs(editorRoot));
     nsCOMPtr<nsIDOMNode> editorRootDOMNode = do_QueryInterface(editorRoot);
     if (!editorRootDOMNode) {
@@ -295,18 +308,20 @@ nsIntRect nsHyperTextAccessible::GetBoun
   }
 
   return screenRect;
 }
 
 /*
  * Gets the specified text.
  */
-nsIFrame* nsHyperTextAccessible::GetPosAndText(PRInt32& aStartOffset, PRInt32& aEndOffset, nsAString *aText,
-                                               nsIFrame **aEndFrame, nsIntRect *aBoundsRect)
+nsIFrame*
+nsHyperTextAccessible::GetPosAndText(PRInt32& aStartOffset, PRInt32& aEndOffset,
+                                     nsAString *aText, nsIFrame **aEndFrame,
+                                     nsIntRect *aBoundsRect)
 {
   PRInt32 startOffset = aStartOffset;
   PRInt32 endOffset = aEndOffset;
 
   // Clear out parameters and set up loop
   if (aText) {
     aText->Truncate();
   }
@@ -335,54 +350,63 @@ nsIFrame* nsHyperTextAccessible::GetPosA
   // Loop through children and collect valid offsets, text and bounds
   // depending on what we need for out parameters
   while (NextChild(accessible)) {
     nsCOMPtr<nsPIAccessNode> accessNode(do_QueryInterface(accessible));
     nsIFrame *frame = accessNode->GetFrame();
     if (!frame) {
       continue;
     }
+    nsIFrame *primaryFrame = frame;
     if (IsText(accessible)) {
-      // We only need info up to rendered offset -- that is what we're converting to content offset
+      // We only need info up to rendered offset -- that is what we're
+      // converting to content offset
       PRInt32 substringEndOffset;
       nsresult rv = frame->GetRenderedText(nsnull, &skipChars, &iter);
       PRUint32 ourRenderedStart = iter.GetSkippedOffset();
       PRInt32 ourContentStart = iter.GetOriginalOffset();
       if (NS_SUCCEEDED(rv)) {
-        substringEndOffset = iter.ConvertOriginalToSkipped(skipChars.GetOriginalCharCount() + ourContentStart) -
-                    ourRenderedStart;
+        substringEndOffset =
+          iter.ConvertOriginalToSkipped(skipChars.GetOriginalCharCount() +
+                                        ourContentStart) -
+          ourRenderedStart;
       }
       else {
-        // XXX for non-textframe text like list bullets, should go away after list bullet rewrite
+        // XXX for non-textframe text like list bullets,
+        // should go away after list bullet rewrite
         substringEndOffset = TextLength(accessible);
       }
       if (startOffset < substringEndOffset) {
         // Our start is within this substring
         if (startOffset > 0 || endOffset < substringEndOffset) {
           // We don't want the whole string for this accessible
           // Get out the continuing text frame with this offset
           PRInt32 outStartLineUnused;
-          PRInt32 contentOffset = iter.ConvertSkippedToOriginal(startOffset) + ourRenderedStart - ourContentStart;
-          frame->GetChildFrameContainingOffset(contentOffset, PR_TRUE, &outStartLineUnused, &frame);
+          PRInt32 contentOffset = iter.ConvertSkippedToOriginal(startOffset) +
+                                  ourRenderedStart - ourContentStart;
+          frame->GetChildFrameContainingOffset(contentOffset, PR_TRUE,
+                                               &outStartLineUnused, &frame);
           if (aEndFrame) {
             *aEndFrame = frame; // We ended in the current frame
           }
           if (substringEndOffset > endOffset) {
             // Need to stop before the end of the available text
             substringEndOffset = endOffset;
           }
           aEndOffset = endOffset;
         }
         if (aText) {
           nsCOMPtr<nsPIAccessible> pAcc(do_QueryInterface(accessible));
-          pAcc->AppendTextTo(*aText, startOffset, substringEndOffset - startOffset);
+          pAcc->AppendTextTo(*aText, startOffset,
+                             substringEndOffset - startOffset);
         }
         if (aBoundsRect) {    // Caller wants the bounds of the text
-          aBoundsRect->UnionRect(*aBoundsRect, GetBoundsForString(frame, startOffset,
-                                 substringEndOffset));
+          aBoundsRect->UnionRect(*aBoundsRect,
+                                 GetBoundsForString(primaryFrame, startOffset,
+                                                    substringEndOffset));
         }
         if (!startFrame) {
           startFrame = frame;
           aStartOffset = startOffset;
         }
         // We already started copying in this accessible's string,
         // for the next accessible we'll start at offset 0
         startOffset = 0;
@@ -403,17 +427,18 @@ nsIFrame* nsHyperTextAccessible::GetPosA
       }
       else {
         if (endOffset > 0) {
           if (aText) {
             *aText += (frame->GetType() == nsAccessibilityAtoms::brFrame) ?
                       kForcedNewLineChar : kEmbeddedObjectChar;
           }
           if (aBoundsRect) {
-            aBoundsRect->UnionRect(*aBoundsRect, frame->GetScreenRectExternal());
+            aBoundsRect->UnionRect(*aBoundsRect,
+                                   frame->GetScreenRectExternal());
           }
         }
         if (!startFrame) {
           startFrame = frame;
           aStartOffset = 0;
         }
       }
       -- endOffset;
@@ -515,22 +540,27 @@ nsresult nsHyperTextAccessible::DOMPoint
   }
   else {
     // For non-text nodes, aNodeOffset comes in as a child node index
     nsCOMPtr<nsIContent> parentContent(do_QueryInterface(aNode));
     // Should not happen, but better to protect against crash if doc node is somehow passed in
     NS_ENSURE_TRUE(parentContent, NS_ERROR_FAILURE);
     // findNode could be null if aNodeOffset == # of child nodes, which means one of two things:
     // 1) we're at the end of the children, keep findNode = null, so that we get the last possible offset
-    // 2) there are no children, use parentContent for the node to find. In this case parentContent can't be
-    //    the nsIAccessibleText, because an accesible text must have children
+    // 2) there are no children and the passed-in node is mDOMNode, which means we're an aempty nsIAccessibleText
+    // 3) there are no children, and the passed-in node is not mDOMNode -- use parentContent for the node to find
      
     findNode = do_QueryInterface(parentContent->GetChildAt(aNodeOffset));
     if (!findNode && !aNodeOffset) {
-      NS_ASSERTION(!SameCOMIdentity(parentContent, mDOMNode), "Cannot find child for DOMPointToHypertextOffset search");
+      if (SameCOMIdentity(parentContent, mDOMNode)) {
+        // There are no children, which means this is an empty nsIAccessibleText, in which
+        // case we can only be at hypertext offset 0
+        *aHyperTextOffset = 0;
+        return NS_OK;
+      }
       findNode = do_QueryInterface(parentContent); // Case #2: there are no children
     }
   }
 
   // Get accessible for this findNode, or if that node isn't accessible, use the
   // accessible for the next DOM node which has one (based on forward depth first search)
   nsCOMPtr<nsIAccessible> descendantAccessible;
   if (findNode) {
@@ -1130,69 +1160,91 @@ NS_IMETHODIMP nsHyperTextAccessible::Set
     return InsertText(aText, 0);
   }
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP nsHyperTextAccessible::InsertText(const nsAString &aText, PRInt32 aPosition)
 {
   if (NS_SUCCEEDED(SetCaretOffset(aPosition))) {
-    nsCOMPtr<nsIEditor> editor = GetEditor();
+    nsCOMPtr<nsIEditor> editor;
+    GetAssociatedEditor(getter_AddRefs(editor));
     nsCOMPtr<nsIPlaintextEditor> peditor(do_QueryInterface(editor));
     return peditor ? peditor->InsertText(aText) : NS_ERROR_FAILURE;
   }
 
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP nsHyperTextAccessible::CopyText(PRInt32 aStartPos, PRInt32 aEndPos)
 {
-  nsCOMPtr<nsIEditor> editor = GetEditor();
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
   if (editor && NS_SUCCEEDED(SetSelectionRange(aStartPos, aEndPos)))
     return editor->Copy();
 
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP nsHyperTextAccessible::CutText(PRInt32 aStartPos, PRInt32 aEndPos)
 {
-  nsCOMPtr<nsIEditor> editor = GetEditor();
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
   if (editor && NS_SUCCEEDED(SetSelectionRange(aStartPos, aEndPos)))
     return editor->Cut();
 
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP nsHyperTextAccessible::DeleteText(PRInt32 aStartPos, PRInt32 aEndPos)
 {
-  nsCOMPtr<nsIEditor> editor = GetEditor();
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
   if (editor && NS_SUCCEEDED(SetSelectionRange(aStartPos, aEndPos)))
     return editor->DeleteSelection(nsIEditor::eNone);
 
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP nsHyperTextAccessible::PasteText(PRInt32 aPosition)
 {
-  nsCOMPtr<nsIEditor> editor = GetEditor();
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
   if (editor && NS_SUCCEEDED(SetCaretOffset(aPosition)))
     return editor->Paste(nsIClipboard::kGlobalClipboard);
 
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsHyperTextAccessible::GetAssociatedEditor(nsIEditor **aEditor)
 {
   NS_ENSURE_ARG_POINTER(aEditor);
 
-  nsCOMPtr<nsIEditor> editor(GetEditor());
-  NS_IF_ADDREF(*aEditor = editor);
+  *aEditor = nsnull;
+  nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
+  NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
+
+  if (!content->HasFlag(NODE_IS_EDITABLE)) {
+    return NS_OK;
+  }
 
-  return NS_OK;
+  nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = GetDocShellTreeItemFor(mDOMNode);
+  nsCOMPtr<nsIEditingSession> editingSession(do_GetInterface(docShellTreeItem));
+  if (!editingSession)
+    return NS_OK; // No editing session interface
+
+  nsCOMPtr<nsIPresShell> shell = GetPresShell();
+  NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
+
+  nsCOMPtr<nsIDocument> doc = shell->GetDocument();
+  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
+
+  nsCOMPtr<nsIEditor> editor;
+  return editingSession->GetEditorForWindow(doc->GetWindow(), aEditor);
 }
 
 /**
   * =================== Caret & Selection ======================
   */
 
 nsresult nsHyperTextAccessible::SetSelectionRange(PRInt32 aStartPos, PRInt32 aEndPos)
 {
@@ -1254,17 +1306,18 @@ nsresult nsHyperTextAccessible::GetSelec
 {
   if (aSelCon) {
     *aSelCon = nsnull;
   }
   if (aDomSel) {
     *aDomSel = nsnull;
   }
   
-  nsCOMPtr<nsIEditor> editor = GetEditor();
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
   if (editor) {
     if (aSelCon) {
       editor->GetSelectionController(aSelCon);
       NS_ENSURE_TRUE(*aSelCon, NS_ERROR_FAILURE);
     }
 
     if (aDomSel) {
       editor->GetSelection(aDomSel);
--- a/accessible/src/html/nsHyperTextAccessible.h
+++ b/accessible/src/html/nsHyperTextAccessible.h
@@ -40,17 +40,16 @@
 #ifndef _nsHyperTextAccessible_H_
 #define _nsHyperTextAccessible_H_
 
 #include "nsAccessibleWrap.h"
 #include "nsIAccessibleText.h"
 #include "nsIAccessibleHyperText.h"
 #include "nsIAccessibleEditableText.h"
 #include "nsAccessibleEventData.h"
-#include "nsIEditor.h"
 #include "nsFrameSelection.h"
 #include "nsISelectionController.h"
 
 enum EGetTextType { eGetBefore=-1, eGetAt=0, eGetAfter=1 };
 
 // This character marks where in the text returned via nsIAccessibleText(),
 // that embedded object characters exist
 const PRUnichar kEmbeddedObjectChar = 0xfffc;
@@ -152,20 +151,16 @@ protected:
     * @param aBoundsRect (optional), return the bounds rectangle for this substring
     * @return the start frame for this substring
     */
   nsIFrame* GetPosAndText(PRInt32& aStartOffset, PRInt32& aEndOffset, nsAString *aText = nsnull,
                           nsIFrame **aEndFrame = nsnull, nsIntRect *aBoundsRect = nsnull);
 
   nsIntRect GetBoundsForString(nsIFrame *aFrame, PRUint32 aStartRenderedOffset, PRUint32 aEndRenderedOffset);
 
-  // Editor helpers, subclasses of nsHyperTextAccessible may have editor
-  virtual void SetEditor(nsIEditor *aEditor) { return; }
-  virtual already_AddRefed<nsIEditor> GetEditor() { return nsnull; }
-
   // Selection helpers
   nsresult GetSelections(nsISelectionController **aSelCon, nsISelection **aDomSel);
   nsresult SetSelectionRange(PRInt32 aStartPos, PRInt32 aEndPos);
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsHyperTextAccessible,
                               NS_HYPERTEXTACCESSIBLE_IMPL_CID)
 
--- a/accessible/src/mac/nsAccessibleWrap.h
+++ b/accessible/src/mac/nsAccessibleWrap.h
@@ -73,29 +73,16 @@ class nsAccessibleWrap : public nsAccess
     
     // returns a pointer to the native window for this accessible tree.
     void GetNativeWindow (void **aOutNativeWindow);
     
     virtual nsresult Shutdown ();
     virtual nsresult InvalidateChildren ();
 
     NS_IMETHOD FireAccessibleEvent(nsIAccessibleEvent *aEvent);
-
-    // we'll flatten buttons and checkboxes. usually they have a text node
-    // child, that is their title. Works in conjunction with IsPruned() below.
-    // XXX There is no IsPruned() method, so what does that comment mean?
-    PRBool IsFlat() {
-      PRUint32 role = Role(this);
-      return (role == nsIAccessibleRole::ROLE_CHECKBUTTON ||
-              role == nsIAccessibleRole::ROLE_PUSHBUTTON ||
-              role == nsIAccessibleRole::ROLE_TOGGLE_BUTTON ||
-              role == nsIAccessibleRole::ROLE_SPLITBUTTON ||
-              role == nsIAccessibleRole::ROLE_ENTRY ||
-              role == nsIAccessibleRole::ROLE_GRAPHIC);
-    }
     
     // ignored means that the accessible might still have children, but is not displayed
     // to the user. it also has no native accessible object represented for it.
     PRBool IsIgnored();
     
     PRInt32 GetUnignoredChildCount(PRBool aDeepCount);
     
     PRBool HasPopup () {
@@ -114,20 +101,21 @@ class nsAccessibleWrap : public nsAccess
       // we don't create a native object if we're child of a "flat" accessible; for example, on OS X buttons 
       // shouldn't have any children, because that makes the OS confused. 
       //
       // to maintain a scripting environment where the XPCOM accessible hierarchy look the same 
       // on all platforms, we still let the C++ objects be created though.
       
       nsCOMPtr<nsIAccessible> curParent = GetParent();
       while (curParent) {
-        nsAccessibleWrap *ancestorWrap = static_cast<nsAccessibleWrap*>((nsIAccessible*)curParent.get());
-        if (ancestorWrap->IsFlat())
+        if (MustPrune(curParent))
           return PR_TRUE;
-        curParent = static_cast<nsAccessibleWrap*>((nsIAccessible*)curParent.get())->GetParent();
+        nsCOMPtr<nsIAccessible> newParent;
+        curParent->GetParent(getter_AddRefs(newParent));
+        curParent.swap(newParent);
       }
       // no parent was flat
       return PR_FALSE;
     }
 
     // Wrapper around our native object.
     AccessibleWrapper *mNativeWrapper;
 };
--- a/accessible/src/mac/nsAccessibleWrap.mm
+++ b/accessible/src/mac/nsAccessibleWrap.mm
@@ -201,33 +201,33 @@ nsAccessibleWrap::InvalidateChildren ()
   }
   return nsAccessible::InvalidateChildren();
 }
 
 PRInt32
 nsAccessibleWrap::GetUnignoredChildCount(PRBool aDeepCount)
 {
   // if we're flat, we have no children.
-  if (IsFlat())
+  if (MustPrune(this))
     return 0;
   
   PRInt32 childCount = 0;
   GetChildCount(&childCount);
   
   nsCOMPtr<nsIAccessible> curAcc;
   
   while (NextChild(curAcc)) {
     nsAccessibleWrap *childWrap = static_cast<nsAccessibleWrap*>((nsIAccessible*)curAcc.get());
     
     // if the current child is not ignored, count it.
     if (!childWrap->IsIgnored())
       ++childCount;
       
     // if it's flat, we don't care to inspect its children.
-    if (childWrap->IsFlat())
+    if (MustPrune(childWrap))
       continue;
     
     if (aDeepCount) {
       // recursively count the unignored children of our children since it's a deep count.
       childCount += childWrap->GetUnignoredChildCount(PR_TRUE);
     } else {
       // no deep counting, but if the child is ignored, we want to substitute it for its
       // children.
@@ -248,24 +248,24 @@ nsAccessibleWrap::IsIgnored()
 }
 
 void
 nsAccessibleWrap::GetUnignoredChildren(nsTArray<nsRefPtr<nsAccessibleWrap> > &aChildrenArray)
 {
   nsCOMPtr<nsIAccessible> curAcc;
   
   // we're flat; there are no children.
-  if (IsFlat())
+  if (MustPrune(this))
     return;
   
   while (NextChild(curAcc)) {
     nsAccessibleWrap *childWrap = static_cast<nsAccessibleWrap*>((nsIAccessible*)curAcc.get());
     if (childWrap->IsIgnored()) {
       // element is ignored, so try adding its children as substitutes, if it has any.
-      if (!childWrap->IsFlat()) {
+      if (!MustPrune(childWrap)) {
         nsTArray<nsRefPtr<nsAccessibleWrap> > children;
         childWrap->GetUnignoredChildren(children);
         if (!children.IsEmpty()) {
           // add the found unignored descendants to the array.
           aChildrenArray.AppendElements(children);
         }
       }
     } else
--- a/accessible/src/msaa/nsAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsAccessibleWrap.cpp
@@ -1524,17 +1524,18 @@ nsAccessibleWrap::FireAccessibleEvent(ns
   }
  
   PRInt32 childID = GetChildIDFor(accessible); // get the id for the accessible
   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
   nsCOMPtr<nsIAccessible> newAccessible;
-  if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
+  if (eventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
+      eventType == nsIAccessibleEvent::EVENT_DOM_DESTROY) {
     // Don't use frame from current accessible when we're hiding that
     // accessible.
     accessible->GetParent(getter_AddRefs(newAccessible));
   } else {
     newAccessible = accessible;
   }
 
   HWND hWnd = GetHWNDFor(accessible);
@@ -1709,19 +1710,8 @@ void nsAccessibleWrap::UpdateSystemCaret
   if (::CreateCaret(caretWnd, caretBitMap, 1, caretRect.height)) {  // Also destroys the last caret
     ::ShowCaret(caretWnd);
     RECT windowRect;
     ::GetWindowRect(caretWnd, &windowRect);
     ::SetCaretPos(caretRect.x - windowRect.left, caretRect.y - windowRect.top);
     ::DeleteObject(caretBitMap);
   }
 }
-
-PRBool nsAccessibleWrap::MustPrune(nsIAccessible *aAccessible)
-{ 
-  PRUint32 role = Role(aAccessible);
-  return role == nsIAccessibleRole::ROLE_MENUITEM || 
-         role == nsIAccessibleRole::ROLE_ENTRY ||
-         role == nsIAccessibleRole::ROLE_PASSWORD_TEXT ||
-         role == nsIAccessibleRole::ROLE_PUSHBUTTON ||
-         role == nsIAccessibleRole::ROLE_TOGGLE_BUTTON ||
-         role == nsIAccessibleRole::ROLE_GRAPHIC;
-}
--- a/accessible/src/msaa/nsAccessibleWrap.h
+++ b/accessible/src/msaa/nsAccessibleWrap.h
@@ -317,19 +317,16 @@ class nsAccessibleWrap : public nsAccess
   static IDispatch *NativeAccessible(nsIAccessible *aXPAccessible);
 
 protected:
   // mEnumVARIANTPosition not the current accessible's position, but a "cursor" of 
   // where we are in the current list of children, with respect to
   // nsIEnumVariant::Reset(), Skip() and Next().
   PRUint16 mEnumVARIANTPosition;
 
-  // Should this accessible be allowed to have any MSAA children
-  static PRBool MustPrune(nsIAccessible *aAccessible);
-
   enum navRelations {
     NAVRELATION_CONTROLLED_BY = 0x1000,
     NAVRELATION_CONTROLLER_FOR = 0x1001,
     NAVRELATION_LABEL_FOR = 0x1002,
     NAVRELATION_LABELLED_BY = 0x1003,
     NAVRELATION_MEMBER_OF = 0x1004,
     NAVRELATION_NODE_CHILD_OF = 0x1005,
     NAVRELATION_FLOWS_TO = 0x1006,
--- a/accessible/src/msaa/nsEventMap.h
+++ b/accessible/src/msaa/nsEventMap.h
@@ -41,22 +41,22 @@
 #include "winable.h"
 #include "AccessibleEventId.h"
 
 const PRUint32 kEVENT_WIN_UNKNOWN = 0x00000000;
 const PRUint32 kEVENT_LAST_ENTRY  = 0xffffffff;
 
 static const PRUint32 gWinEventMap[] = {
   kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent doesn't have 0 constant
-  kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_CREATE
-  kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_DESTROY
-  EVENT_OBJECT_SHOW,                                 // nsIAccessibleEvent::EVENT_SHOW
-  EVENT_OBJECT_HIDE,                                 // nsIAccessibleEvent::EVENT_HIDE
-  EVENT_OBJECT_REORDER,                              // nsIAccessibleEvent::EVENT_REORDER
-  kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_PARENT_CHANGE
+  EVENT_OBJECT_SHOW,                                 // nsIAccessibleEvent::EVENT_DOM_CREATE
+  EVENT_OBJECT_HIDE,                                 // nsIAccessibleEvent::EVENT_DOM_DESTROY
+  kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE
+  EVENT_OBJECT_SHOW,                                 // nsIAccessibleEvent::EVENT_ASYNCH_SHOW
+  EVENT_OBJECT_HIDE,                                 // nsIAccessibleEvent::EVENT_ASYNCH_HIDE
+  kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_ASYNCH_LAYOUT_CHANGE
   IA2_EVENT_ACTIVE_DECENDENT_CHANGED,                // nsIAccessibleEvent::EVENT_ACTIVE_DECENDENT_CHANGED
   EVENT_OBJECT_FOCUS,                                // nsIAccessibleEvent::EVENT_FOCUS
   EVENT_OBJECT_STATECHANGE,                          // nsIAccessibleEvent::EVENT_STATE_CHANGE
   EVENT_OBJECT_LOCATIONCHANGE,                       // nsIAccessibleEvent::EVENT_LOCATION_CHANGE
   EVENT_OBJECT_NAMECHANGE,                           // nsIAccessibleEvent::EVENT_NAME_CHANGE
   EVENT_OBJECT_DESCRIPTIONCHANGE,                    // nsIAccessibleEvent::EVENT_DESCRIPTION_CHANGE
   EVENT_OBJECT_VALUECHANGE,                          // nsIAccessibleEvent::EVENT_VALUE_CHANGE
   kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_HELP_CHANGE
@@ -132,11 +132,12 @@ static const PRUint32 gWinEventMap[] = {
   IA2_EVENT_HYPERTEXT_LINK_ACTIVATED,                // nsIAccessibleEvent::EVENT_HYPERTEXT_LINK_ACTIVATED
   IA2_EVENT_HYPERTEXT_LINK_SELECTED,                 // nsIAccessibleEvent::EVENT_HYPERTEXT_LINK_SELECTED
   IA2_EVENT_HYPERLINK_START_INDEX_CHANGED,           // nsIAccessibleEvent::EVENT_HYPERLINK_START_INDEX_CHANGED
   IA2_EVENT_HYPERTEXT_CHANGED,                       // nsIAccessibleEvent::EVENT_HYPERTEXT_CHANGED
   IA2_EVENT_HYPERTEXT_NLINKS_CHANGED,                // nsIAccessibleEvent::EVENT_HYPERTEXT_NLINKS_CHANGED
   IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED,                // nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED
   IA2_EVENT_PAGE_CHANGED,                            // nsIAccessibleEvent::EVENT_PAGE_CHANGED
   kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_INTERNAL_LOAD
+  EVENT_OBJECT_REORDER,                              // nsIAccessibleEvent::EVENT_REORDER
   kEVENT_LAST_ENTRY                                  // nsIAccessibleEvent::EVENT_LAST_ENTRY
 };
 
--- a/accessible/src/msaa/nsHyperTextAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsHyperTextAccessibleWrap.cpp
@@ -49,17 +49,18 @@ IMPL_IUNKNOWN_INHERITED2(nsHyperTextAcce
                          CAccessibleEditableText);
 
 NS_IMETHODIMP
 nsHyperTextAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
 {
   PRUint32 eventType;
   aEvent->GetEventType(&eventType);
 
-  if (eventType == nsIAccessibleEvent::EVENT_TEXT_CHANGED) {
+  if (eventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED ||
+      eventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED) {
     nsCOMPtr<nsIAccessible> accessible;
     aEvent->GetAccessible(getter_AddRefs(accessible));
     if (accessible) {
       nsCOMPtr<nsIWinAccessNode> winAccessNode(do_QueryInterface(accessible));
       if (winAccessNode) {
         void *instancePtr = NULL;
         nsresult rv = winAccessNode->QueryNativeInterface(IID_IAccessibleText,
                                                           &instancePtr);
--- a/accessible/src/xforms/nsXFormsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsAccessible.cpp
@@ -37,16 +37,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsXFormsAccessible.h"
 
 #include "nscore.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMNodeList.h"
+#include "nsIEditor.h"
 #include "nsIMutableArray.h"
 #include "nsIXFormsUtilityService.h"
 #include "nsIPlaintextEditor.h"
 
 // nsXFormsAccessibleBase
 
 nsIXFormsUtilityService *nsXFormsAccessibleBase::sXFormsService = nsnull;
 
@@ -304,72 +305,50 @@ nsXFormsEditableAccessible::
 NS_IMETHODIMP
 nsXFormsEditableAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
 {
   NS_ENSURE_ARG_POINTER(aState);
 
   nsresult rv = nsXFormsAccessible::GetState(aState, aExtraState);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (!aExtraState || !mEditor)
+  if (!aExtraState)
     return NS_OK;
 
   PRBool isReadonly = PR_FALSE;
   rv = sXFormsService->IsReadonly(mDOMNode, &isReadonly);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!isReadonly) {
     PRBool isRelevant = PR_FALSE;
     rv = sXFormsService->IsRelevant(mDOMNode, &isRelevant);
     NS_ENSURE_SUCCESS(rv, rv);
     if (isRelevant) {
       *aExtraState |= nsIAccessibleStates::EXT_STATE_EDITABLE |
                       nsIAccessibleStates::EXT_STATE_SELECTABLE_TEXT;
     }
   }
 
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
+  NS_ENSURE_TRUE(editor, NS_ERROR_FAILURE);
   PRUint32 flags;
-  mEditor->GetFlags(&flags);
+  editor->GetFlags(&flags);
   if (flags & nsIPlaintextEditor::eEditorSingleLineMask)
     *aExtraState |= nsIAccessibleStates::EXT_STATE_SINGLE_LINE;
   else
     *aExtraState |= nsIAccessibleStates::EXT_STATE_MULTI_LINE;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsXFormsEditableAccessible::Init()
-{
-  nsCOMPtr<nsIEditor> editor;
-  sXFormsService->GetEditor(mDOMNode, getter_AddRefs(editor));
-  SetEditor(editor);
-
-  return nsXFormsAccessible::Init();
-}
-
-NS_IMETHODIMP
-nsXFormsEditableAccessible::Shutdown()
+nsXFormsEditableAccessible::GetAssociatedEditor(nsIEditor **aEditor)
 {
-  SetEditor(nsnull);
-  return nsXFormsAccessible::Shutdown();
-}
-
-already_AddRefed<nsIEditor>
-nsXFormsEditableAccessible::GetEditor()
-{
-  nsIEditor *editor = mEditor;
-  NS_IF_ADDREF(editor);
-  return editor;
-}
-
-void
-nsXFormsEditableAccessible::SetEditor(nsIEditor *aEditor)
-{
-  mEditor = aEditor;
+  return sXFormsService->GetEditor(mDOMNode, aEditor);
 }
 
 // nsXFormsSelectableAccessible
 
 
 NS_IMPL_ISUPPORTS_INHERITED1(nsXFormsSelectableAccessible,
                              nsXFormsEditableAccessible,
                              nsIAccessibleSelectable)
--- a/accessible/src/xforms/nsXFormsAccessible.h
+++ b/accessible/src/xforms/nsXFormsAccessible.h
@@ -142,25 +142,18 @@ public:
  */
 class nsXFormsEditableAccessible : public nsXFormsAccessible
 {
 public:
   nsXFormsEditableAccessible(nsIDOMNode *aNode, nsIWeakReference *aShell);
 
   NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
 
-  NS_IMETHOD Init();
-  NS_IMETHOD Shutdown();
-
-protected:
-  virtual void SetEditor(nsIEditor *aEditor);
-  virtual already_AddRefed<nsIEditor> GetEditor();
-
-private:
-  nsCOMPtr<nsIEditor> mEditor;
+  // nsIAccessibleEditableText
+  NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
 };
 
 
 /**
  * The class is base for accessible objects for XForms select and XForms
  * select1 elements.
  */
 class nsXFormsSelectableAccessible : public nsXFormsEditableAccessible
--- a/accessible/src/xul/nsXULFormControlAccessible.cpp
+++ b/accessible/src/xul/nsXULFormControlAccessible.cpp
@@ -45,16 +45,17 @@
 #include "nsXULMenuAccessible.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIDOMXULButtonElement.h"
 #include "nsIDOMXULCheckboxElement.h"
 #include "nsIDOMXULMenuListElement.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIDOMXULTextboxElement.h"
+#include "nsIEditor.h"
 #include "nsIFrame.h"
 #include "nsINameSpaceManager.h"
 #include "nsITextControlFrame.h"
 #include "nsIPresShell.h"
 
 /**
   * XUL Button: can contain arbitrary HTML content
   */
@@ -758,31 +759,16 @@ nsXULToolbarSeparatorAccessible::GetStat
   * XUL Textfield
   */
 
 nsXULTextFieldAccessible::nsXULTextFieldAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell) :
  nsHyperTextAccessibleWrap(aNode, aShell)
 {
 }
 
-NS_IMPL_ISUPPORTS_INHERITED1(nsXULTextFieldAccessible, nsHyperTextAccessible,
-                             nsIAccessibleText)
-
-NS_IMETHODIMP nsXULTextFieldAccessible::Init()
-{
-  CheckForEditor();
-  return nsHyperTextAccessibleWrap::Init();
-}
-
-NS_IMETHODIMP nsXULTextFieldAccessible::Shutdown()
-{
-  mEditor = nsnull;
-  return nsHyperTextAccessibleWrap::Shutdown();
-}
-
 NS_IMETHODIMP nsXULTextFieldAccessible::GetValue(nsAString& aValue)
 {
   PRUint32 state;
   GetState(&state, nsnull);
   if (state & nsIAccessibleStates::STATE_PROTECTED)    // Don't return password text!
     return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIDOMXULTextBoxElement> textBox(do_QueryInterface(mDOMNode));
@@ -930,27 +916,16 @@ NS_IMETHODIMP nsXULTextFieldAccessible::
 
 NS_IMETHODIMP
 nsXULTextFieldAccessible::GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren)
 {
   *aAllowsAnonChildren = PR_FALSE;
   return NS_OK;
 }
 
-void nsXULTextFieldAccessible::SetEditor(nsIEditor* aEditor)
+NS_IMETHODIMP nsXULTextFieldAccessible::GetAssociatedEditor(nsIEditor **aEditor)
 {
-  mEditor = aEditor;
-}
-
-void nsXULTextFieldAccessible::CheckForEditor()
-{
+  *aEditor = nsnull;
   nsCOMPtr<nsIDOMNode> inputField = GetInputField();
   nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(inputField));
-  if (!editableElt) {
-    return;
-  }
-
-  nsCOMPtr<nsIEditor> editor;
-  nsresult rv = editableElt->GetEditor(getter_AddRefs(editor));
-  if (NS_SUCCEEDED(rv)) {
-    SetEditor(editor);
-  }
+  NS_ENSURE_TRUE(editableElt, NS_ERROR_FAILURE);
+  return editableElt->GetEditor(aEditor);
 }
--- a/accessible/src/xul/nsXULFormControlAccessible.h
+++ b/accessible/src/xul/nsXULFormControlAccessible.h
@@ -156,35 +156,28 @@ public:
   NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
 };
 
 class nsXULTextFieldAccessible : public nsHyperTextAccessibleWrap
 {
 public:
   enum { eAction_Click = 0 };
 
-  NS_DECL_ISUPPORTS_INHERITED
-
   nsXULTextFieldAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
 
-  NS_IMETHOD Init();
-  NS_IMETHOD Shutdown();
   NS_IMETHOD GetValue(nsAString& aValue);
   NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
   NS_IMETHOD GetRole(PRUint32 *aRole);
   NS_IMETHOD GetNumActions(PRUint8 *_retval);
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD DoAction(PRUint8 index);
   NS_IMETHOD GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren);
 
+  // nsIAccessibleEditableText
+  NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
+
 protected:
   already_AddRefed<nsIDOMNode> GetInputField();
-
-  // Editor helpers, subclasses of nsHyperTextAccessible may have editor
-  virtual void SetEditor(nsIEditor *aEditor);
-  virtual already_AddRefed<nsIEditor> GetEditor() { nsIEditor *editor = mEditor; NS_IF_ADDREF(editor); return editor; }
-  void CheckForEditor();
-  nsCOMPtr<nsIEditor> mEditor;
 };
 
 
 #endif  
 
--- a/allmakefiles.sh
+++ b/allmakefiles.sh
@@ -139,21 +139,16 @@ MAKEFILES_expat="
 parser/expat/Makefile
 parser/expat/lib/Makefile
 "
 
 MAKEFILES_extensions="
 extensions/Makefile
 "
 
-MAKEFILES_gc="
-gc/boehm/Makefile
-gc/boehm/leaksoup/Makefile
-"
-
 MAKEFILES_gfx="
 gfx/Makefile
 gfx/idl/Makefile
 gfx/public/Makefile
 gfx/src/Makefile
 gfx/src/beos/Makefile
 gfx/src/psshared/Makefile
 gfx/src/photon/Makefile
@@ -315,17 +310,16 @@ content/html/document/src/Makefile
 content/xml/Makefile
 content/xml/content/Makefile
 content/xml/content/src/Makefile
 content/xml/document/Makefile
 content/xml/document/public/Makefile
 content/xml/document/src/Makefile
 content/xul/Makefile
 content/xul/content/Makefile
-content/xul/content/public/Makefile
 content/xul/content/src/Makefile
 content/xul/document/Makefile
 content/xul/document/public/Makefile
 content/xul/document/src/Makefile
 content/xul/templates/public/Makefile
 content/xul/templates/src/Makefile
 content/xbl/Makefile
 content/xbl/public/Makefile
@@ -560,17 +554,16 @@ webshell/public/Makefile
 MAKEFILES_widget="
 widget/Makefile
 widget/public/Makefile
 widget/src/Makefile
 widget/src/beos/Makefile
 widget/src/build/Makefile
 widget/src/gtkxtbin/Makefile
 widget/src/photon/Makefile
-widget/src/mac/Makefile
 widget/src/cocoa/Makefile
 widget/src/os2/Makefile
 widget/src/windows/Makefile
 widget/src/xpwidgets/Makefile
 widget/src/support/Makefile
 "
 
 MAKEFILES_xpcom="
@@ -1259,17 +1252,16 @@ add_makefiles "
 $MAKEFILES_docshell
 $MAKEFILES_dom
 $MAKEFILES_editor
 $MAKEFILES_codesighs
 $MAKEFILES_composer
 $MAKEFILES_embedding
 $MAKEFILES_expat
 $MAKEFILES_extensions
-$MAKEFILES_gc
 $MAKEFILES_gfx
 $MAKEFILES_accessible
 $MAKEFILES_htmlparser
 $MAKEFILES_intl
 $MAKEFILES_javaxpcom
 $MAKEFILES_ldap
 $MAKEFILES_leaky
 $MAKEFILES_jpeg
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -234,16 +234,20 @@ pref("browser.search.openintab", false);
 pref("browser.search.update", true);
 
 // disable logging for the search service update system by default
 pref("browser.search.update.log", false);
 
 // Check whether we need to perform engine updates every 6 hours
 pref("browser.search.updateinterval", 6);
 
+// Whether or not microsummary and generator updates are enabled
+pref("browser.microsummary.enabled", true);
+pref("browser.microsummary.updateGenerators", true);
+
 // enable search suggestions by default
 pref("browser.search.suggest.enabled", true);
 
 pref("browser.history.grouping", "day");
 pref("browser.history.showSessions", false);
 pref("browser.sessionhistory.max_entries", 50);
 pref("browser.history_expire_days", 180);
 
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -587,8 +587,146 @@ var PlacesMenuDNDController = {
   // Whether or not drag and drop to menus is supported on this platform
   // Dragging in menus is disabled on OS X due to various repainting issues.
 #ifdef XP_MACOSX
   _dragSupported: false
 #else
   _dragSupported: true
 #endif
 };
+
+var PlacesStarButton = {
+  init: function PSB_init() {
+    PlacesUtils.bookmarks.addObserver(this, false);
+  },
+
+  uninit: function PSB_uninit() {
+    PlacesUtils.bookmarks.removeObserver(this);
+  },
+
+  QueryInterface: function PSB_QueryInterface(aIID) {
+    if (aIID.equals(Ci.nsIDOMEventListener) ||
+        aIID.equals(Ci.nsINavBookmarkObserver) ||
+        aIID.equals(Ci.nsISupports))
+      return this;
+
+    throw Cr.NS_NOINTERFACE;
+  },
+
+  get panel() {
+    return document.getElementById("editBookmarkPanel");
+  },
+
+  _starred: false,
+  _batching: false,
+
+  updateState: function PSB_updateState() {
+    var uri = getBrowser().currentURI;
+    this._starred = uri && PlacesUtils.bookmarks.isBookmarked(uri);
+    if (this._starred)
+      document.getElementById("star-icon").setAttribute("starred", "true");
+    else
+      document.getElementById("star-icon").removeAttribute("starred");
+  },
+
+  _star: function PSB_star(aBrowser) {
+    var uri = aBrowser.currentURI;
+    if (!uri)
+      throw "No URL";
+
+    var title = PlacesUtils.history.getPageTitle(uri);
+
+    var descAnno = {
+      name: DESCRIPTION_ANNO,
+      value: PlacesUtils.getDescriptionFromDocument(aBrowser.contentDocument)
+    };
+    var txn = PlacesUtils.ptm.createItem(uri, PlacesUtils.placesRootId, -1,
+                                         title, null, [descAnno]);
+    PlacesUtils.ptm.commitTransaction(txn);
+  },
+
+  // nsIDOMEventListener
+  handleEvent: function PSB_handleEvent(aEvent) {
+    if (aEvent.originalTarget != this.panel)
+      return;
+
+    // This only happens for auto-hide. When the panel is closed from within
+    // itself, doneCallback removes the listener and only then hides the popup
+    gAddBookmarksPanel.saveItem();
+    gAddBookmarksPanel.uninitPanel();
+  },
+
+  showBookmarkPagePopup: function PSB_showBookmarkPagePopup(aBrowser) {
+    const bms = PlacesUtils.bookmarks;
+
+    var dockTo = document.getElementById("star-icon");
+    if (!dockTo)
+      dockTo = getBrowser();
+
+    var panel = this.panel;
+    panel.showPopup(dockTo, -1, -1, "popup", "bottomright", "topright");
+
+    var uri = aBrowser.currentURI;
+
+    var itemId = -1;
+    var bmkIds = bms.getBookmarkIdsForURI(uri, {});
+    for each (var bk in bmkIds) {
+      // Find the first folder which isn't a tag container
+      var folder = bms.getFolderIdForItem(bk);
+      if (folder == PlacesUtils.placesRootId ||
+          bms.getFolderIdForItem(folder) != PlacesUtils.tagRootId) {
+        itemId = bk;
+        break;
+      }
+    }
+    if (itemId == -1) {
+      // if we're called before the URI is bookmarked, or if the remaining
+      // items for this url are under tag containers, star the page first
+      itemId = this._star(aBrowser);
+    }
+    gAddBookmarksPanel.initPanel(itemId, PlacesUtils.tm, this.doneCallback,
+                                 { hiddenRows: "description" });
+    panel.addEventListener("popuphiding", this, false);
+  },
+
+  onClick: function PSB_onClick(aEvent) {
+    if (this._starred)
+      this.showBookmarkPagePopup(getBrowser());
+    else
+      this._star(getBrowser());
+  },
+
+  doneCallback: function PSB_doneCallback(aSavedChanges) {
+    var panel = PlacesStarButton.panel;
+    panel.removeEventListener("popuphiding", PlacesStarButton, false);
+    gAddBookmarksPanel.uninitPanel();
+    panel.hidePopup();
+  },
+
+  // nsINavBookmarkObserver  
+  onBeginUpdateBatch: function PSB_onBeginUpdateBatch() {
+    this._batching = true;
+  },
+
+  onEndUpdateBatch: function PSB_onEndUpdateBatch() {
+    this.updateState();
+    this._batching = false;
+  },
+  
+  onItemAdded: function PSB_onItemAdded(aItemId, aFolder, aIndex) {
+    if (!this._batching && !this._starred)
+      this.updateState();
+  },
+
+  onItemRemoved: function PSB_onItemRemoved(aItemId, aFolder, aIndex) {
+    if (!this._batching)
+      this.updateState();
+  },
+
+  onItemChanged: function PSB_onItemChanged(aItemId, aProperty,
+                                            aIsAnnotationProperty, aValue) {
+    if (!this._batching && aProperty == "uri")
+      this.updateState();
+  },
+
+  onItemVisited: function() { },
+  onItemMoved: function() { }
+};
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -12,26 +12,19 @@ searchbar {
 }
 
 /* ::::: print preview toolbar ::::: */
 toolbar[printpreview="true"] {
   -moz-binding: url("chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar");
 }
 
 menuitem.spell-suggestion {
-  font-weight:bold;
+  font-weight: bold;
 }
 
 #sidebar-box toolbarbutton.tabs-closebutton {
   -moz-user-focus: normal;
 }
 
 /* apply Fitts' law to the notification bar's close button */
 window[sizemode="maximized"] #content .notification-inner {
-	border-right: 0px !important;
+  border-right: 0px !important;
 }
-
-/* ::::: Tooltips (multi-line) from content ::::: */
-.htmltooltip-label {
-  max-width: 40em;
-  margin: 0;
-  white-space: -moz-pre-wrap;
-}
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1012,16 +1012,17 @@ function delayedStartup()
 
   // add bookmark options to context menu for tabs
   addBookmarkMenuitems();
 
   PlacesMenuDNDController.init();
 
   initBookmarksToolbar();
   PlacesUtils.bookmarks.addObserver(gBookmarksObserver, false);
+  PlacesStarButton.init();
 
   // called when we go into full screen, even if it is
   // initiated by a web page script
   window.addEventListener("fullscreen", onFullScreen, true);
 
   if (gIsLoadingBlank && gURLBar && isElementVisible(gURLBar))
     focusElement(gURLBar);
   else
@@ -1152,16 +1153,17 @@ function BrowserShutdown()
   os.removeObserver(gXPInstallObserver, "xpinstall-install-blocked");
 
   try {
     gBrowser.removeProgressListener(window.XULBrowserWindow);
   } catch (ex) {
   }
 
   PlacesUtils.bookmarks.removeObserver(gBookmarksObserver);
+  PlacesStarButton.uninit();
 
   try {
     gPrefService.removeObserver(gAutoHideTabbarPrefListener.domain,
                                 gAutoHideTabbarPrefListener);
     gPrefService.removeObserver(gHomeButton.prefDomain, gHomeButton);
   } catch (ex) {
     Components.utils.reportError(ex);
   }
@@ -1653,31 +1655,25 @@ function BrowserCloseTabOrWindow()
 #ifdef XP_MACOSX
   // If we're not a browser window, just close the window
   if (window.location.href != getBrowserURL()) {
     closeWindow(true);
     return;
   }
 #endif
 
-  if (gBrowser.tabContainer.childNodes.length > 1) {
-    // Just close up a tab.
+  if (gBrowser.tabContainer.childNodes.length > 1 ||
+      window.toolbar.visible && !gPrefService.getBoolPref("browser.tabs.autoHide")) {
+    // Just close the tab (and focus the address bar if it was the last one).
+    var isLastTab = gBrowser.tabContainer.childNodes.length == 1;
     gBrowser.removeCurrentTab();
-    return;
-  }
-#ifndef XP_MACOSX
-  if (window.toolbar.visible &&
-      !gPrefService.getBoolPref("browser.tabs.autoHide")) {
-    // Replace the remaining tab with a blank one and focus the address bar
-    gBrowser.removeCurrentTab();
-    if (gURLBar)
+    if (isLastTab && gURLBar)
       setTimeout(function() { gURLBar.focus(); }, 0);
     return;
   }
-#endif
 
   closeWindow(true);
 }
 
 function BrowserTryToCloseWindow()
 {
   if (WindowIsClosing())
     window.close();     // WindowIsClosing does all the necessary checks
@@ -3520,16 +3516,19 @@ nsBrowserStatusHandler.prototype =
 
           // Setting the urlBar value in some cases causes userTypedValue to
           // become set because of oninput, so reset it to its old value.
           browser.userTypedValue = userTypedValue;
         } else {
           gURLBar.value = userTypedValue;
           SetPageProxyState("invalid");
         }
+
+        // Update starring UI
+        PlacesStarButton.updateState(aLocationURI);
       }
     }
     UpdateBackForwardCommands(gBrowser.webNavigation);
 
     if (gFindBar.findMode != gFindBar.FIND_NORMAL) {
       // Close the Find toolbar if we're in old-style TAF mode
       gFindBar.close();
     }
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -48,16 +48,17 @@
 
 <?xml-stylesheet href="chrome://browser/skin/" type="text/css"?> 
 
 <?xml-stylesheet href="chrome://global/skin/toolbar.css" type="text/css"?>
 
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
 <?xul-overlay href="chrome://browser/content/baseMenuOverlay.xul"?>
 <?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
+<?xul-overlay href="chrome://browser/content/places/editBookmarkOverlay.xul"?>
 
 # All DTD information is stored in a separate file so that it can be shared by
 # hiddenWindow.xul.
 #include browser-doctype.inc
  
 <window id="main-window"
         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
@@ -93,17 +94,22 @@
            onclick="checkForMiddleClick(this, event);"/>
     <popup id="forwardMenu"
            position="after_start"
            onpopupshowing="return BrowserForwardMenu(event);"
            oncommand="gotoHistoryIndex(event);"
            onclick="checkForMiddleClick(this, event);"/>
     <tooltip id="aHTMLTooltip" onpopupshowing="return FillInHTMLTooltip(document.tooltipNode);"/>
 
-    <panel type="autocomplete" chromedir="&locale.dir;" id="PopupAutoComplete"/>
+    <panel type="autocomplete" chromedir="&locale.dir;" id="PopupAutoComplete" noautofocus="true"/>
+
+    <panel id="editBookmarkPanel"
+           position="after_end">
+      <vbox id="editBookmarkPanelContent" flex="1"/>
+    </panel>
 
     <popup id="toolbar-context-menu"
            onpopupshowing="onViewToolbarsPopupShowing(event);">
       <menuseparator/>
       <menuitem command="cmd_CustomizeToolbars"
                 label="&viewCustomizeToolbar.label;"
                 accesskey="&viewCustomizeToolbar.accesskey;"/>
     </popup>
@@ -244,16 +250,17 @@
                              onclick="checkForMiddleClick(this, event);"/>
                 </button>
                 <image id="lock-icon" onclick="if (event.button == 0) displaySecurityInfo(); event.stopPropagation();"/>
 #ifdef MOZ_SAFE_BROWSING
                 <image id="safebrowsing-urlbar-icon" tooltiptext="&safeb.urlbaricon.tooltip;"
                        level="safe"
                        onclick="goDoCommand('safebrowsing-show-warning')" />
 #endif
+                <image id="star-icon" onclick="if (event.button == 0) PlacesStarButton.onClick(event);"/>
               </hbox>
             </textbox>
             <stack id="go-button-stack">
               <vbox>
                 <!-- These image segments allow the button to stretch nicely
                      in larger urlbars. -->
                 <image id="go-button-top"
                        class="go-button-background"
--- a/browser/base/content/credits.xhtml
+++ b/browser/base/content/credits.xhtml
@@ -460,32 +460,35 @@
             <li>Radiant Core</li>
             <li>silverorange</li>
             <li>Revver</li>
             <li></li>
             <li>MozillaZine Community</li>
           </ul>
         </div>
 
-        <p id="gecko" class="center">&credit.poweredByGecko;</p>
+        <p id="gecko" class="center">&credit.poweredByGecko;&reg;</p>
 
         <p class="footnote">
           &brandFullName;&trade; &license.part0; &copy;1998-2007 &license.part1;
           <a href="" link="about:credits" onclick="visitLink(event);">&license.contrib;</a>,
           &license.part2;
           <a href="" link="about:license" onclick="visitLink(event);">about:license</a>
           &license.part3;</p>
 
         <p class="footnote">
-          Mozilla Firefox&trade; and the Firefox logo are trademarks of the Mozilla
-          Foundation. You are not granted rights or licenses to the trademarks
+          Mozilla Firefox&reg; and the Firefox logo are registered trademarks of the
+          Mozilla Foundation. You are not granted rights or licenses to the trademarks
           of the Mozilla Foundation or any party, including without limitation the
           Firefox name or logo.</p>
 
         <p class="footnote">
+          Gecko&reg; is a registered trademark of Netscape Communications Corporation.</p>
+
+        <p class="footnote">
           U.S. GOVERNMENT END USERS. The Software is a &ldquo;commercial item,&rdquo;
           as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of
           &ldquo;commercial computer software&rdquo; and &ldquo;commercial computer software
           documentation,&rdquo; as such terms are used in 48 C.F.R. 12.212 (Sept. 1995).
           Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through
           227.7202-4 (June 1995), all U.S. Government End Users acquire the
           Software with only those rights set forth herein.</p>
 
--- a/browser/components/feeds/src/FeedWriter.js
+++ b/browser/components/feeds/src/FeedWriter.js
@@ -561,23 +561,23 @@ FeedWriter.prototype = {
           /* Bug 351263: Make sure to not steal focus if the "Choose
            * Application" item is being selected with the keyboard. We do this
            * by ignoring command events while the dropdown is closed (user
            * arrowing through the combobox), but handling them while the
            * combobox dropdown is open (user pressed enter when an item was
            * selected). If we don't show the filepicker here, it will be shown
            * when clicking "Subscribe Now".
            */
-          if (this._document.getElementById("handlersMenuList")
-                  .getAttribute("open") == "true") {
-            if (!this._chooseClientApp()) {
-              // Select the (per-prefs) selected handler if no application was
-              // selected
-              this._setSelectedHandler();
-            }
+          var popupbox = this._document.getElementById("handlersMenuList")
+                             .firstChild.boxObject;
+          popupbox.QueryInterface(Components.interfaces.nsIPopupBoxObject);
+          if (popupbox.popupState == "hiding" && !this._chooseClientApp()) {
+            // Select the (per-prefs) selected handler if no application was
+            // selected
+            this._setSelectedHandler();
           }
           break;
         default:
           this._setAlwaysUseLabel();
       }
     }
   },
 
--- a/browser/components/feeds/src/WebContentConverter.js
+++ b/browser/components/feeds/src/WebContentConverter.js
@@ -171,17 +171,16 @@ var WebContentConverterRegistrar = {
     return this.stringBundle.formatStringFromName(key, params, params.length);
   },
   
   _getString: function WCCR_getString(key) {
     return this.stringBundle.GetStringFromName(key);
   },
 
   _contentTypes: { },
-  _protocols: { },
 
   /**
    * Track auto handlers for various content types using a content-type to 
    * handler map.
    */
   _autoHandleContentTypes: { },
 
   /**
@@ -260,23 +259,33 @@ var WebContentConverterRegistrar = {
                             null, null, null);
     }      
   },
   
   /**
    * See nsIWebContentConverterService
    */
   removeProtocolHandler: 
-  function WCCR_removeProtocolHandler(protocol, uri) {
-    function notURI(currentURI) {
-      return currentURI != uri;
+  function WCCR_removeProtocolHandler(aProtocol, aURITemplate) {
+    var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
+              getService(Ci.nsIExternalProtocolService);
+    var handlerInfo = eps.getProtocolHandlerInfo(aProtocol);
+    var handlers =  handlerInfo.possibleApplicationHandlers;
+    for (let i = 0; i < handlers.length; i++) {
+      try { // We only want to test web handlers
+        let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
+        if (handler.uriTemplate == aURITemplate) {
+          handlers.removeElementAt(i);
+          var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
+                   getService(Ci.nsIHandlerService);
+          hs.store(handlerInfo);
+          return;
+        }
+      } catch (e) { /* it wasn't a web handler */ }
     }
-  
-    if (protocol in this._protocols) 
-      this._protocols[protocol] = this._protocols[protocol].filter(notURI);
   },
   
   /**
    * See nsIWebContentConverterService
    */
   removeContentHandler: 
   function WCCR_removeContentHandler(contentType, uri) {
     function notURI(serviceInfo) {
@@ -319,23 +328,128 @@ var WebContentConverterRegistrar = {
   },
 
   _makeURI: function(aURL, aOriginCharset, aBaseURI) {
     var ioService = Components.classes["@mozilla.org/network/io-service;1"]
                               .getService(Components.interfaces.nsIIOService);
     return ioService.newURI(aURL, aOriginCharset, aBaseURI);
   },
 
+  _checkAndGetURI:
+  function WCCR_checkAndGetURI(aURIString)
+  {
+    try {
+      var uri = this._makeURI(aURIString);
+    } catch (ex) {
+      // not supposed to throw according to spec
+      return; 
+    }
+ 
+    // If the uri doesn't contain '%s', it won't be a good handler
+    if (uri.spec.indexOf("%s") < 0)
+      throw NS_ERROR_DOM_SYNTAX_ERR; 
+
+    return uri;
+  },
+
+  /**
+   * Determines if a web handler is already registered.
+   *
+   * @param aProtocol
+   *        The scheme of the web handler we are checking for.
+   * @param aURITemplate
+   *        The URI template that the handler uses to handle the protocol.
+   * @return true if it is already registered, false otherwise.
+   */
+  _protocolHandlerRegistered:
+  function WCCR_protocolHandlerRegistered(aProtocol, aURITemplate) {
+    var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
+              getService(Ci.nsIExternalProtocolService);
+    var handlerInfo = eps.getProtocolHandlerInfo(aProtocol);
+    var handlers =  handlerInfo.possibleApplicationHandlers;
+    for (let i = 0; i < handlers.length; i++) {
+      try { // We only want to test web handlers
+        let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
+        if (handler.uriTemplate == aURITemplate)
+          return true;
+      } catch (e) { /* it wasn't a web handler */ }
+    }
+    return false;
+  },
+
   /**
    * See nsIWebContentHandlerRegistrar
    */
   registerProtocolHandler: 
-  function WCCR_registerProtocolHandler(aProtocol, aURI, aTitle, aContentWindow) {
-    // not yet implemented
-    return;
+  function WCCR_registerProtocolHandler(aProtocol, aURIString, aTitle, aContentWindow) {
+    LOG("registerProtocolHandler(" + aProtocol + "," + aURIString + "," + aTitle + ")");
+    
+    // First, check to make sure this isn't already handled internally (we don't
+    // want to let them take over, say "chrome").
+    var ios = Cc["@mozilla.org/network/io-service;1"].
+              getService(Ci.nsIIOService);
+    var handler = ios.getProtocolHandler(aProtocol);
+    if (!(handler instanceof Ci.nsIExternalProtocolHandler)) {
+      // This is handled internally, so we don't want them to register
+      // XXX this should be a "security exception" according to spec, but that
+      // isn't defined yet.
+      throw("Permission denied to add " + aURIString + "as a protocol handler");
+    }
+ 
+    var uri = this._checkAndGetURI(aURIString);
+
+    var buttons, message;
+    if (this._protocolHandlerRegistered(aProtocol, uri.spec))
+      message = this._getFormattedString("protocolHandlerRegistered",
+                                         [aTitle, aProtocol]);
+    else {
+      // Now Ask the user and provide the proper callback
+      message = this._getFormattedString("addProtocolHandler",
+                                         [aTitle, uri.host, aProtocol]);
+      var fis = Cc["@mozilla.org/browser/favicon-service;1"].
+                getService(Ci.nsIFaviconService);
+      var notificationIcon = fis.getFaviconLinkForIcon(uri);
+      var notificationValue = "Protocol Registration: " + aProtocol;
+      var addButton = {
+        label: this._getString("addProtocolHandlerAddButton"),
+        accessKey: this._getString("addHandlerAddButtonAccesskey"),
+        protocolInfo: { protocol: aProtocol, uri: uri.spec, name: aTitle },
+
+        callback:
+        function WCCR_addProtocolHandlerButtonCallback(aNotification, aButtonInfo) {
+          var protocol = aButtonInfo.protocolInfo.protocol;
+          var uri      = aButtonInfo.protocolInfo.uri;
+          var name     = aButtonInfo.protocolInfo.name;
+
+          var handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
+                        createInstance(Ci.nsIWebHandlerApp);
+          handler.name = name;
+          handler.uriTemplate = uri;
+
+          var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
+                    getService(Ci.nsIExternalProtocolService);
+          var handlerInfo = eps.getProtocolHandlerInfo(protocol);
+          handlerInfo.possibleApplicationHandlers.appendElement(handler, false);
+
+          var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
+                   getService(Ci.nsIHandlerService);
+          hs.store(handlerInfo);
+        }
+      };
+      buttons = [addButton];
+    }
+
+    var browserWindow = this._getBrowserWindowForContentWindow(aContentWindow);
+    var browserElement = this._getBrowserForContentWindow(browserWindow, aContentWindow);
+    var notificationBox = browserWindow.getBrowser().getNotificationBox(browserElement);
+    notificationBox.appendNotification(message,
+                                       notificationValue,
+                                       notificationIcon,
+                                       notificationBox.PRIORITY_INFO_LOW,
+                                       buttons);
   },
 
   /**
    * See nsIWebContentHandlerRegistrar
    * This is the web front end into the registration system, so a prompt to 
    * confirm the registration is provided, and the result is saved to 
    * preferences.
    */
@@ -345,26 +459,17 @@ var WebContentConverterRegistrar = {
 
     // We only support feed types at present.
     // XXX this should be a "security exception" according to spec, but that
     // isn't defined yet.
     var contentType = this._resolveContentType(aContentType);
     if (contentType != TYPE_MAYBE_FEED)
       return;
 
-    try {
-      var uri = this._makeURI(aURIString);
-    } catch (ex) {
-      // not supposed to throw according to spec
-      return; 
-    }
-    
-    // If the uri doesn't contain '%s', it won't be a good content handler
-    if (uri.spec.indexOf("%s") < 0)
-      throw NS_ERROR_DOM_SYNTAX_ERR; 
+    var uri = this._checkAndGetURI(aURIString);
             
     // For security reasons we reject non-http(s) urls (see bug Bug 354316),
     // we may need to revise this once we support more content types
     // XXX this should be a "security exception" according to spec, but that
     // isn't defined yet.
     if (uri.scheme != "http" &&  uri.scheme != "https")
       throw("Permission denied to add " + uri.spec + "as a content handler");
 
--- a/browser/components/microsummaries/src/nsMicrosummaryService.js
+++ b/browser/components/microsummaries/src/nsMicrosummaryService.js
@@ -1555,26 +1555,19 @@ MicrosummarySet.prototype = {
 
 
       // Unlike the "href" attribute, the "href" property contains
       // an absolute URI spec, so we use it here to create the URI.
       var generatorURI = this._ios.newURI(link.href,
                                           resource.content.characterSet,
                                           null);
 
-      try {
-        const securityManager = Cc["@mozilla.org/scriptsecuritymanager;1"].
-                                getService(Ci.nsIScriptSecurityManager);
-        securityManager.checkLoadURI(resource.uri,
-                                     generatorURI,
-                                     Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
-      }
-      catch(e) {
+      if (!/^https?$/i.test(generatorURI.scheme)) {
         LOG("can't load generator " + generatorURI.spec + " from page " +
-            resource.uri.spec + ": " + e);
+            resource.uri.spec);
         continue;
       }
 
       var generator = new MicrosummaryGenerator(generatorURI, null, linkTitle);
       var microsummary = new Microsummary(resource.uri, generator);
       if (!this.hasItemForMicrosummary(microsummary))
         this.AppendElement(microsummary);
     }
--- a/browser/components/migration/content/migration.js
+++ b/browser/components/migration/content/migration.js
@@ -390,22 +390,22 @@ var MigrationWizard = {
 
     // When importing bookmarks, show only bookmarks
     if (this._bookmarks)
       this._itemsFlags = 32;
 
     this._listItems("migratingItems");
     setTimeout(this.onMigratingMigrate, 0, this);
   },
-  
+
   onMigratingMigrate: function (aOuter)
   {
     aOuter._migrator.migrate(aOuter._itemsFlags, aOuter._autoMigrate, aOuter._selectedProfile);
   },
-
+  
   _listItems: function (aID)
   {
     var items = document.getElementById(aID);
     while (items.hasChildNodes())
       items.removeChild(items.firstChild);
     
     var bundle = document.getElementById("bundle");
     var brandBundle = document.getElementById("brandBundle");
--- a/browser/components/migration/public/nsIBrowserProfileMigrator.idl
+++ b/browser/components/migration/public/nsIBrowserProfileMigrator.idl
@@ -52,27 +52,27 @@ interface nsIBrowserProfileMigrator : ns
   const unsigned short FORMDATA    = 0x0008;
   const unsigned short PASSWORDS   = 0x0010;
   const unsigned short BOOKMARKS   = 0x0020;
   const unsigned short OTHERDATA   = 0x0040;
 
   /**
    * Copy user profile information to the current active profile.
    * @param aItems   list of data items to migrate. see above for values.
-   * @param aReplace replace or append current data where applicable. 
+   * @param aStartup helper interface which is non-null if called during startup. 
    * @param aProfile profile to migrate from, if there is more than one.
    */
   void migrate(in unsigned short aItems, in nsIProfileStartup aStartup, in wstring aProfile);
 
   /**
    * A bit field containing profile items that this migrator
    * offers for import. 
    * @param   aProfile the profile that we are looking for available data
    *          to import
-   * @param   aStarting "true" if the profile is not currently being used.
+   * @param   aDoingStartup "true" if the profile is not currently being used.
    * @returns bit field containing profile items (see above)
    */
   unsigned short getMigrateData(in wstring aProfile, in boolean aDoingStartup);
 
   /** 
    * Whether or not there is any data that can be imported from this 
    * browser (i.e. whether or not it is installed, and there exists
    * a user profile)
--- a/browser/components/migration/src/nsIEProfileMigrator.cpp
+++ b/browser/components/migration/src/nsIEProfileMigrator.cpp
@@ -497,30 +497,40 @@ nsIEProfileMigrator::GetSourceHomePageUR
             aResult.Assign(homePageURL);
   }
   return NS_OK;
 }
 
 
 ///////////////////////////////////////////////////////////////////////////////
 // nsIEProfileMigrator
-NS_IMPL_ISUPPORTS1(nsIEProfileMigrator, nsIBrowserProfileMigrator);
+NS_IMPL_ISUPPORTS2(nsIEProfileMigrator, nsIBrowserProfileMigrator, nsINavHistoryBatchCallback);
 
 nsIEProfileMigrator::nsIEProfileMigrator() 
 {
   mObserverService = do_GetService("@mozilla.org/observer-service;1");
 }
 
 nsIEProfileMigrator::~nsIEProfileMigrator() 
 {
 }
 
 nsresult
 nsIEProfileMigrator::CopyHistory(PRBool aReplace) 
 {
+  nsresult rv;
+  nsCOMPtr<nsINavHistoryService> history = do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return history->RunInBatchMode(this, nsnull);
+}
+
+NS_IMETHODIMP
+nsIEProfileMigrator::RunBatched(nsISupports* aUserData)
+{
   nsCOMPtr<nsIBrowserHistory> hist(do_GetService(NS_GLOBALHISTORY2_CONTRACTID));
   nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
 
   // First, Migrate standard IE History entries...
   ::CoInitialize(NULL);
 
   IUrlHistoryStg2* ieHistory;
   HRESULT hr = ::CoCreateInstance(CLSID_CUrlHistory, 
--- a/browser/components/migration/src/nsIEProfileMigrator.h
+++ b/browser/components/migration/src/nsIEProfileMigrator.h
@@ -41,29 +41,32 @@
 #ifndef ieprofilemigrator___h___
 #define ieprofilemigrator___h___
 
 #include <time.h>
 #include <windows.h>
 #include "nsIBrowserProfileMigrator.h"
 #include "nsIObserverService.h"
 #include "nsVoidArray.h"
+#include "nsINavHistoryService.h"
 
 class nsIFile;
 class nsICookieManager2;
 class nsIRDFResource;
 class nsINavBookmarksService;
 class nsIPrefBranch;
 
 #import PSTOREC_DLL raw_interfaces_only
 using namespace PSTORECLib;
 
-class nsIEProfileMigrator : public nsIBrowserProfileMigrator {
+class nsIEProfileMigrator : public nsIBrowserProfileMigrator,
+                            public nsINavHistoryBatchCallback {
 public:
   NS_DECL_NSIBROWSERPROFILEMIGRATOR
+  NS_DECL_NSINAVHISTORYBATCHCALLBACK
   NS_DECL_ISUPPORTS
 
   nsIEProfileMigrator();
   virtual ~nsIEProfileMigrator();
 
 protected:
   nsresult CopyPreferences(PRBool aReplace);
   nsresult CopyStyleSheet(PRBool aReplace);
--- a/browser/components/migration/src/nsSafariProfileMigrator.cpp
+++ b/browser/components/migration/src/nsSafariProfileMigrator.cpp
@@ -828,16 +828,26 @@ nsSafariProfileMigrator::CopyCookies(PRB
   ::CFRelease(safariCookies);
 
   return NS_OK;
 }
 
 nsresult
 nsSafariProfileMigrator::CopyHistory(PRBool aReplace)
 {
+  nsresult rv;
+  nsCOMPtr<nsINavHistoryService> history = do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+ 
+  return history->RunInBatchMode(this, nsnull);
+}
+ 
+NS_IMETHODIMP
+nsSafariProfileMigrator::RunBatched(nsISupports* aUserData)
+{
   nsCOMPtr<nsIProperties> fileLocator(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
   nsCOMPtr<nsILocalFile> safariHistoryFile;
   fileLocator->Get(NS_MAC_USER_LIB_DIR, NS_GET_IID(nsILocalFile),
                    getter_AddRefs(safariHistoryFile));
   safariHistoryFile->Append(NS_LITERAL_STRING("Safari"));
   safariHistoryFile->Append(SAFARI_HISTORY_FILE_NAME);
 
   CFDictionaryRef safariHistory = (CFDictionaryRef)CopyPListFromFile(safariHistoryFile);
--- a/browser/components/migration/src/nsSafariProfileMigrator.h
+++ b/browser/components/migration/src/nsSafariProfileMigrator.h
@@ -38,25 +38,28 @@
 
 #ifndef safariprofilemigrator___h___
 #define safariprofilemigrator___h___
 
 #include "nsIBrowserProfileMigrator.h"
 #include "nsIObserverService.h"
 #include "nsISupportsArray.h"
 #include "nsStringAPI.h"
+#include "nsINavHistoryService.h"
 
 #include <CoreFoundation/CoreFoundation.h>
 
 class nsIRDFDataSource;
 
-class nsSafariProfileMigrator : public nsIBrowserProfileMigrator
+class nsSafariProfileMigrator : public nsIBrowserProfileMigrator,
+                                public nsINavHistoryBatchCallback
 {
 public:
   NS_DECL_NSIBROWSERPROFILEMIGRATOR
+  NS_DECL_NSINAVHISTORYBATCHCALLBACK
   NS_DECL_ISUPPORTS
 
   nsSafariProfileMigrator();
   virtual ~nsSafariProfileMigrator();
 
   typedef enum { STRING, INT, BOOL } PrefType;
 
   typedef nsresult(*prefConverter)(void*, nsIPrefBranch*);
--- a/browser/components/places/content/bookmarkProperties.js
+++ b/browser/components/places/content/bookmarkProperties.js
@@ -569,22 +569,19 @@ var BookmarkPropertiesPanel = {
     }
 
     var itemToSelect = userEnteredNameField;
     try {
       this._microsummaries = this._mss.getMicrosummaries(this._bookmarkURI,
                                                          this._bookmarkId);
     }
     catch(ex) {
-      // getMicrosummaries will throw an exception in at least two cases:
-      // 1. the bookmarked URI contains a scheme that the service won't
-      //    download for security reasons (currently it only handles http,
-      //    https, and file);
-      // 2. the page to which the URI refers isn't HTML or XML (the only two
-      //    content types the service knows how to summarize).
+      // getMicrosummaries will throw an exception if the page to which the URI
+      // refers isn't HTML or XML (the only two content types the service knows
+      // how to summarize).
       this._microsummaries = null;
     }
     if (this._microsummaries) {
       var enumerator = this._microsummaries.Enumerate();
 
       if (enumerator.hasMoreElements()) {
         // Show the drop marker if there are microsummaries
         namePicker.setAttribute("droppable", "true");
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -99,17 +99,17 @@ PlacesController.prototype = {
     case "cmd_cut":
     case "cmd_delete":
       return this._hasRemovableSelection(false);
     case "placesCmd_moveBookmarks":
       return this._hasRemovableSelection(true);
     case "cmd_copy":
       return this._view.hasSelection;
     case "cmd_paste":
-      return this._canInsert() && this._canPaste();
+      return this._canInsert() && this._isClipboardDataPasteable();
     case "cmd_selectAll":
       if (this._view.selType != "single") {
         var result = this._view.getResult();
         if (result) {
           var container = asContainer(result.root);
           if (container.childCount > 0);
             return true;
         }
@@ -376,77 +376,73 @@ PlacesController.prototype = {
       var root = this._view.getResultNode();
       for (var i = 0; i < nodes.length; ++i) {
         if (nodes[i] == root)
           return true;      
       }
     }
     return false;
   },
-
+  
   /**
    * Looks at the data on the clipboard to see if it is paste-able. 
    * Paste-able data is:
    *   - in a format that the view can receive
-   * @returns true if the data is paste-able, false if the clipboard data
-   *          cannot be pasted
+   * @returns true if: - clipboard data is of a TYPE_X_MOZ_PLACE_* flavor,
+                       - clipboard data is of type TEXT_UNICODE and
+                         is a valid URI.
    */
-  _canPaste: function PC__canPaste() {
-    var types = this._view.peerDropTypes;
-    var flavors = 
-        Cc["@mozilla.org/supports-array;1"].
-        createInstance(Ci.nsISupportsArray);
-    for (var i = 0; i < types.length; ++i) {
-      var cstring = 
-          Cc["@mozilla.org/supports-cstring;1"].
-          createInstance(Ci.nsISupportsCString);
-      cstring.data = types[i];
+  _isClipboardDataPasteable: function PC__isClipboardDataPasteable() {
+    // if the clipboard contains TYPE_X_MOZ_PLACE_* data, it is definitely
+    // pasteable, with no need to unwrap all the nodes.
+    
+    var placeTypes = [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
+                      PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR,
+                      PlacesUtils.TYPE_X_MOZ_PLACE];
+    var flavors = Cc["@mozilla.org/supports-array;1"].
+                    createInstance(Ci.nsISupportsArray);
+    for (var i = 0; i < placeTypes.length; ++i) {
+      var cstring = Cc["@mozilla.org/supports-cstring;1"].
+                      createInstance(Ci.nsISupportsCString);
+      cstring.data = placeTypes[i];
       flavors.AppendElement(cstring);
     }
-
-    var clipboard = 
-        Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
-    var hasClipboardData = clipboard.hasDataMatchingFlavors(flavors, 
+    var clipboard = Cc["@mozilla.org/widget/clipboard;1"].
+                      getService(Ci.nsIClipboard);
+    var hasPlacesData = clipboard.hasDataMatchingFlavors(flavors,
                                             Ci.nsIClipboard.kGlobalClipboard);
-    if (!hasClipboardData)
-      return false;
+    if (hasPlacesData)
+      return this._view.insertionPoint != null;
+      
+    // if the clipboard doesn't have TYPE_X_MOZ_PLACE_* data, we also allow
+    // pasting of valid "text/unicode" and "text/x-moz-url" data
+    var xferable = Cc["@mozilla.org/widget/transferable;1"].
+                     createInstance(Ci.nsITransferable);
 
-    // XXX todo
-    // see bug #387007 for an idea on how to make this more efficient
-    // right now, we are pulling data off the clipboard and using
-    // unwrapNodes() to verify it.
-
-    var xferable = 
-        Cc["@mozilla.org/widget/transferable;1"].
-        createInstance(Ci.nsITransferable);
-
-    for (var j = 0; j < types.length; ++j) {
-      xferable.addDataFlavor(types[j]);
-    }
+    xferable.addDataFlavor(PlacesUtils.TYPE_X_MOZ_URL);
+    xferable.addDataFlavor(PlacesUtils.TYPE_UNICODE);
     clipboard.getData(xferable, Ci.nsIClipboard.kGlobalClipboard);
-
+    
     try {
-      // getAnyTransferData can throw if no data is available. 
+      // getAnyTransferData will throw if no data is available.
       var data = { }, type = { };
       xferable.getAnyTransferData(type, data, { });
       data = data.value.QueryInterface(Ci.nsISupportsString).data;
-      if (this._view.peerDropTypes.indexOf(type.value) == -1)
+      if (type.value != PlacesUtils.TYPE_X_MOZ_URL &&
+          type.value != PlacesUtils.TYPE_UNICODE)
         return false;
 
-      // unwrapNodes() will throw if the data blob is malformed. 
+      // unwrapNodes() will throw if the data blob is malformed.
       var unwrappedNodes = PlacesUtils.unwrapNodes(data, type.value);
       return this._view.insertionPoint != null;
     }
     catch (e) {
-      // unwrapeNodes() failed, possibly because a field that should have 
-      // contained a URI did not actually contain something that is 
-      // parse-able as a URI. 
+      // getAnyTransferData or unwrapNodes failed
       return false;
     }
-    return false;
   },
 
   /** 
    * Gathers information about the selected nodes according to the following
    * rules:
    *    "link"              node is a URI
    *    "bookmark"          node is a bookamrk
    *    "folder"            node is a folder
new file mode 100644
--- /dev/null
+++ b/browser/components/places/content/editBookmarkOverlay.js
@@ -0,0 +1,581 @@
+/* -*- Mode: C++; tab-width: 8; 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 Bookmark Properties dialog.
+ *
+ * The Initial Developer of the Original Code is Google Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   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 ***** */
+
+const LAST_USED_ANNO = "bookmarkPropertiesDialog/lastUsed";
+const MAX_FOLDER_ITEM_IN_MENU_LIST = 5;
+
+var gAddBookmarksPanel = {
+  /**
+   * The Microsummary Service for displaying microsummaries.
+   */
+  __mss: null,
+  get _mss() {
+    if (!this.__mss)
+      this.__mss = Cc["@mozilla.org/microsummary/service;1"].
+                  getService(Ci.nsIMicrosummaryService);
+    return this.__mss;
+  },
+
+  _uri: null,
+  _itemId: -1,
+  _itemType: -1,
+  _microsummaries: null,
+  _doneCallback: null,
+  _currentTags: [],
+  _hiddenRows: [],
+
+  /**
+   * Determines the initial data for the item edited or added by this dialog
+   */
+  _determineInfo: function ABP__determineInfo(aInfo) {
+    const bms = PlacesUtils.bookmarks;
+    this._itemType = bms.getItemType(this._itemId);
+    if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK)
+      this._currentTags = PlacesUtils.tagging.getTagsForURI(this._uri);
+    else
+      this._currentTags.splice(0);
+
+    // hidden rows
+    if (aInfo && aInfo.hiddenRows)
+      this._hiddenRows = aInfo.hiddenRows;
+    else
+      this._hiddenRows.splice(0);
+  },
+
+  _showHideRows: function EBP__showHideRows() {
+    this._element("nameRow").hidden = this._hiddenRows.indexOf("name") != -1;
+    this._element("folderRow").hidden =
+      this._hiddenRows.indexOf("folderPicker") != -1;
+    this._element("tagsRow").hidden = this._hiddenRows.indexOf("tags") != -1 ||
+      this._itemType != Ci.nsINavBookmarksService.TYPE_BOOKMARK;
+    this._element("descriptionRow").hidden =
+      this._hiddenRows.indexOf("description") != -1;
+  },
+
+  /**
+   * Initialize the panel
+   */
+  initPanel: function ABP_initPanel(aItemId, aTm, aDoneCallback, aInfo) {
+    this._folderMenuList = this._element("folderMenuList");
+    this._folderTree = this._element("folderTree");
+    this._tm = aTm;
+    this._itemId = aItemId;
+    this._uri = PlacesUtils.bookmarks.getBookmarkURI(this._itemId);
+    this._doneCallback = aDoneCallback;
+    this._determineInfo(aInfo);
+
+    // folder picker
+    this._initFolderMenuList();
+    
+    // name picker
+    this._initNamePicker();
+
+    // tags field
+    this._element("tagsField").value = this._currentTags.join(", ");
+
+    // description field
+    this._element("descriptionField").value =
+      PlacesUtils.getItemDescription(this._itemId);
+
+    this._showHideRows();
+  },
+
+  /**
+   * Appends a menu-item representing a bookmarks folder to a menu-popup.
+   * @param aMenupopup
+   *        The popup to which the menu-item should be added.
+   * @param aFolderId
+   *        The identifier of the bookmarks folder.
+   * @return the new menu item.
+   */
+  _appendFolderItemToMenupopup:
+  function BPP__appendFolderItemToMenuList(aMenupopup, aFolderId) {
+    // First make sure the folders-separator is visible
+    this._element("foldersSeparator").hidden = false;
+
+    var folderMenuItem = document.createElement("menuitem");
+    var folderTitle = PlacesUtils.bookmarks.getItemTitle(aFolderId)
+    folderMenuItem.folderId = aFolderId;
+    folderMenuItem.setAttribute("label", folderTitle);
+    folderMenuItem.className = "menuitem-iconic folder-icon";
+    aMenupopup.appendChild(folderMenuItem);
+    return folderMenuItem;
+  },
+
+  _initFolderMenuList: function BPP__initFolderMenuList() {
+    // clean up first
+    var menupopup = this._folderMenuList.menupopup;
+    while (menupopup.childNodes.length > 4)
+      menupopup.removeChild(menupopup.lastChild);
+
+    var container = PlacesUtils.bookmarks.getFolderIdForItem(this._itemId);
+
+    // only show "All Bookmarks" if the url isn't bookmarked somewhere else
+    this._element("placesRootItem").hidden = container != PlacesUtils.placesRootId;
+
+    // List of recently used folders:
+    var annos = PlacesUtils.annotations;
+    var folderIds = annos.getItemsWithAnnotation(LAST_USED_ANNO, { });
+
+    /**
+     * The value of the LAST_USED_ANNO annotation is the time (in the form of
+     * Date.getTime) at which the folder has been last used.
+     *
+     * First we build the annotated folders array, each item has both the
+     * folder identifier and the time at which it was last-used by this dialog
+     * set. Then we sort it descendingly based on the time field.
+     */
+    var folders = [];
+    for (var i=0; i < folderIds.length; i++) {
+      var lastUsed = annos.getItemAnnotation(folderIds[i], LAST_USED_ANNO);
+      folders.push({ folderId: folderIds[i], lastUsed: lastUsed });
+    }
+    folders.sort(function(a, b) {
+      if (b.lastUsed < a.lastUsed)
+        return -1;
+      if (b.lastUsed > a.lastUsed)
+        return 1;
+      return 0;
+    });
+
+    var numberOfItems = Math.min(MAX_FOLDER_ITEM_IN_MENU_LIST, folders.length);
+    for (i=0; i < numberOfItems; i++) {
+      this._appendFolderItemToMenupopup(menupopup, folders[i].folderId);
+    }
+
+    var defaultItem = this._getFolderMenuItem(container, true);
+    this._folderMenuList.selectedItem = defaultItem;
+
+    // Hide the folders-separator if no folder is annotated as recently-used
+    this._element("foldersSeparator").hidden = (menupopup.childNodes.length <= 4);
+  },
+
+  QueryInterface: function BPP_QueryInterface(aIID) {
+    if (aIID.equals(Ci.nsIMicrosummaryObserver) ||
+        aIID.equals(Ci.nsIDOMEventListener) ||
+        aIID.eqauls(Ci.nsISupports))
+      return this;
+
+    throw Cr.NS_ERROR_NO_INTERFACE;
+  },
+
+  _element: function BPP__element(aID) {
+    return document.getElementById("editBMPanel_" + aID);
+  },
+
+  _createMicrosummaryMenuItem:
+  function BPP__createMicrosummaryMenuItem(aMicrosummary) {
+    var menuItem = document.createElement("menuitem");
+
+    // Store a reference to the microsummary in the menu item, so we know
+    // which microsummary this menu item represents when it's time to
+    // save changes or load its content.
+    menuItem.microsummary = aMicrosummary;
+
+    // Content may have to be generated asynchronously; we don't necessarily
+    // have it now.  If we do, great; otherwise, fall back to the generator
+    // name, then the URI, and we trigger a microsummary content update. Once
+    // the update completes, the microsummary will notify our observer to
+    // update the corresponding menu-item.
+    // XXX Instead of just showing the generator name or (heaven forbid)
+    // its URI when we don't have content, we should tell the user that
+    // we're loading the microsummary, perhaps with some throbbing to let
+    // her know it is in progress.
+    if (aMicrosummary.content)
+      menuItem.setAttribute("label", aMicrosummary.content);
+    else {
+      menuItem.setAttribute("label", aMicrosummary.generator.name ||
+                                     aMicrosummary.generator.uri.spec);
+      aMicrosummary.update();
+    }
+
+    return menuItem;
+  },
+
+  _initNamePicker: function ABP_initNamePicker() {
+    var userEnteredNameField = this._element("userEnteredName");
+    var namePicker = this._element("namePicker");
+    var droppable = false;
+
+    userEnteredNameField.label =
+      PlacesUtils.bookmarks.getItemTitle(this._itemId);
+
+    // clean up old entries
+    var menupopup = namePicker.menupopup;
+    while (menupopup.childNodes.length > 2)
+      menupopup.removeChild(menupopup.lastChild);
+
+    var itemToSelect = userEnteredNameField;
+    try {
+      this._microsummaries = this._mss.getMicrosummaries(this._uri, -1);
+    }
+    catch(ex) {
+      // getMicrosummaries will throw an exception in at least two cases:
+      // 1. the bookmarked URI contains a scheme that the service won't
+      //    download for security reasons (currently it only handles http,
+      //    https, and file);
+      // 2. the page to which the URI refers isn't HTML or XML (the only two
+      //    content types the service knows how to summarize).
+      this._microsummaries = null;
+    }
+    if (this._microsummaries) {
+      var enumerator = this._microsummaries.Enumerate();
+
+      if (enumerator.hasMoreElements()) {
+        // Show the drop marker if there are microsummaries
+        droppable = true;
+        while (enumerator.hasMoreElements()) {
+          var microsummary = enumerator.getNext()
+                                       .QueryInterface(Ci.nsIMicrosummary);
+          var menuItem = this._createMicrosummaryMenuItem(microsummary);
+          menupopup.appendChild(menuItem);
+        }
+      }
+
+      this._microsummaries.addObserver(this);
+    }
+
+    if (namePicker.selectedItem == itemToSelect)
+      namePicker.value = itemToSelect.label;
+    else
+      namePicker.selectedItem = itemToSelect;
+
+    namePicker.setAttribute("droppable", droppable);
+  },
+
+  // nsIMicrosummaryObserver
+  onContentLoaded: function ABP_onContentLoaded(aMicrosummary) {
+    var namePicker = this._element("namePicker");
+    var childNodes = namePicker.menupopup.childNodes;
+
+    // 0: user-entered item; 1: separator
+    for (var i = 2; i < childNodes.length; i++) {
+      if (childNodes[i].microsummary == aMicrosummary) {
+        var newLabel = aMicrosummary.content;
+        // XXXmano: non-editable menulist would do this for us, see bug 360220
+        // We should fix editable-menulists to set the DOMAttrModified handler
+        // as well.
+        //
+        // Also note the order importance: if the label of the menu-item is
+        // set to something different than the menulist's current value,
+        // the menulist no longer has selectedItem set
+        if (namePicker.selectedItem == childNodes[i])
+          namePicker.value = newLabel;
+
+        childNodes[i].label = newLabel;
+        return;
+      }
+    }
+  },
+
+  onElementAppended: function BPP_onElementAppended(aMicrosummary) {
+    var namePicker = this._element("namePicker");
+    namePicker.menupopup
+              .appendChild(this._createMicrosummaryMenuItem(aMicrosummary));
+
+    // Make sure the drop-marker is shown
+    namePicker.setAttribute("droppable", "true");
+  },
+
+  uninitPanel: function ABP_uninitPanel() {
+    if (this._microsummaries)
+      this._microsummaries.removeObserver(this);
+
+    // hide the folder tree if it was previously visible
+    if (!this._folderTree.collapsed)
+      this.toggleFolderTreeVisibility();
+
+    // hide the tag selector if it was previously visible
+    var tagsSelector = this._element("tagsSelector");
+    if (!tagsSelector.collapsed)
+      tagsSelector.collapsed = true;
+  },
+
+  saveItem: function ABP_saveItem() {
+    var container = this._getFolderIdFromMenuList();
+    const bms = PlacesUtils.bookmarks;
+    const ptm = PlacesUtils.ptm;
+    var txns = [];
+
+    // container
+    if (bms.getFolderIdForItem(this._itemId) != container)
+      txns.push(ptm.moveItem(this._itemId, container, -1));
+
+    // title
+    var newTitle = this._element("userEnteredName").label;
+    if (bms.getItemTitle(this._itemId) != newTitle)
+      txns.push(ptm.editItemTitle(this._itemId, newTitle));
+
+    // description
+    var newDescription = this._element("descriptionField").value;
+    if (newDescription != PlacesUtils.getItemDescription(this._itemId))
+      txns.push(ptm.editItemDescription(this._itemId, newDescription));
+
+    // Tags, NOT YET UNDOABLE
+    var tags = this._getTagsArrayFromTagField();
+    if (tags.length > 0 || this._currentTags.length > 0) {
+      var tagsToRemove = [];
+      var tagsToAdd = [];
+      var t;
+      for each (t in this._currentTags) {
+        if (tags.indexOf(t) == -1)
+          tagsToRemove.push(t);
+      }
+      for each (t in tags) {
+        if (this._currentTags.indexOf(t) == -1)
+          tagsToAdd.push(t);
+      }
+
+      if (tagsToAdd.length > 0)
+        PlacesUtils.tagging.tagURI(this._uri, tagsToAdd);
+      if (tagsToRemove.length > 0)
+        PlacesUtils.tagging.untagURI(this._uri, tagsToRemove);
+    }
+
+    if (txns.length > 0) {
+      // Mark the containing folder as recently-used if it isn't the
+      // "All Bookmarks" root
+      if (container != PlacesUtils.placesRootId)
+        this._markFolderAsRecentlyUsed(container);
+    }
+
+    if (txns.length > 0)
+      ptm.commitTransaction(ptm.aggregateTransactions("Edit Item", txns));
+  },
+
+  onNamePickerInput: function ABP_onNamePickerInput() {
+    this._element("userEnteredName").label = this._element("namePicker").value;
+  },
+
+  toggleFolderTreeVisibility: function ABP_toggleFolderTreeVisibility() {
+    var expander = this._element("foldersExpander");
+    if (!this._folderTree.collapsed) {
+      expander.className = "expander-down";
+      expander.setAttribute("tooltiptext",
+                            expander.getAttribute("tooltiptextdown"));
+      this._folderTree.collapsed = true;
+    }
+    else {
+      expander.className = "expander-up"
+      expander.setAttribute("tooltiptext",
+                            expander.getAttribute("tooltiptextup"));
+      if (!this._folderTree.treeBoxObject.view.isContainerOpen(0))
+        this._folderTree.treeBoxObject.view.toggleOpenState(0);
+      this._folderTree.selectFolders([this._getFolderIdFromMenuList()]);
+      this._folderTree.collapsed = false;
+      this._folderTree.focus();
+    }
+  },
+
+  _getFolderIdFromMenuList:
+  function BPP__getFolderIdFromMenuList() {
+    var selectedItem = this._folderMenuList.selectedItem
+    switch (selectedItem.id) {
+      case "editBMPanel_placesRootItem":
+        return PlacesUtils.placesRootId;
+      case "editBMPanel_bmRootItem":
+        return PlacesUtils.bookmarksRootId;
+      case "editBMPanel_toolbarFolderItem":
+        return PlacesUtils.toolbarFolderId;
+    }
+
+    NS_ASSERT("folderId" in selectedItem,
+              "Invalid menuitem in the folders-menulist");
+    return selectedItem.folderId;
+  },
+
+  /**
+   * Get the corresponding menu-item in the folder-menu-list for a bookmarks
+   * folder if such an item exists. Otherwise, this creates a menu-item for the
+   * folder. If the items-count limit (see MAX_FOLDERS_IN_MENU_LIST) is reached,
+   * the new item replaces the last menu-item.
+   * @param aFolderId
+   *        The identifier of the bookmarks folder
+   * @param aCheckStaticFolderItems
+   *        whether or not to also treat the static items at the top of
+   *        menu-list. Note dynamic items get precedence even if this is set to
+   *        true.
+   */
+  _getFolderMenuItem:
+  function BPP__getFolderMenuItem(aFolderId, aCheckStaticFolderItems) {
+    var menupopup = this._folderMenuList.menupopup;
+
+    // 0: All Bookmarks, 1: Bookmarks root, 2: toolbar folder, 3: separator
+    for (var i=4;  i < menupopup.childNodes.length; i++) {
+      if (menupopup.childNodes[i].folderId == aFolderId)
+        return menupopup.childNodes[i];
+    }
+
+    if (aCheckStaticFolderItems) {
+      if (aFolderId == PlacesUtils.placesRootId)
+        return this._element("placesRootItem");
+      if (aFolderId == PlacesUtils.bookmarksRootId)
+        return this._element("bmRootItem")
+      if (aFolderId == PlacesUtils.toolbarFolderId)
+        return this._element("toolbarFolderItem")
+    }
+
+    // 3 special folders + separator + folder-items-count limit
+    if (menupopup.childNodes.length == 4 + MAX_FOLDER_ITEM_IN_MENU_LIST)
+      menupopup.removeChild(menupopup.lastChild);
+
+    return this._appendFolderItemToMenupopup(menupopup, aFolderId);
+  },
+
+  onMenuListFolderSelect: function BPP_onMenuListFolderSelect(aEvent) {
+    if (this._folderTree.hidden)
+      return;
+
+    this._folderTree.selectFolders([this._getFolderIdFromMenuList()]);
+  },
+
+  onFolderTreeSelect: function BPP_onFolderTreeSelect() {
+    var selectedNode = this._folderTree.selectedNode;
+    if (!selectedNode)
+      return;
+
+    var folderId = selectedNode.itemId;
+    // Don't set the selected item if the static item for the folder is
+    // already selected
+    var oldSelectedItem = this._folderMenuList.selectedItem;
+    if ((oldSelectedItem.id == "editBMPanel_toolbarFolderItem" &&
+         folderId == PlacesUtils.bookmarks.toolbarFolder) ||
+        (oldSelectedItem.id == "editBMPanel_bmRootItem" &&
+         folderId == PlacesUtils.bookmarks.bookmarksRoot))
+      return;
+
+    var folderItem = this._getFolderMenuItem(folderId, false);
+    this._folderMenuList.selectedItem = folderItem;
+  },
+
+  _markFolderAsRecentlyUsed:
+  function ABP__markFolderAsRecentlyUsed(aFolderId) {
+    // We'll figure out when/if to expire the annotation if it turns out
+    // we keep this recently-used-folders implementation
+    PlacesUtils.annotations
+               .setItemAnnotation(aFolderId, LAST_USED_ANNO,
+                                  new Date().getTime(), 0,
+                                  Ci.nsIAnnotationService.EXPIRE_NEVER);
+  },
+
+  accept: function ABP_accept() {
+    this.saveItem();
+    if (typeof(this._doneCallback) == "function")
+      this._doneCallback();
+  },
+
+  deleteAndClose: function ABP_deleteAndClose() {
+    // remove the item
+    if (this._itemId != -1)
+      PlacesUtils.bookmarks.removeItem(this._itemId);
+
+    // remove all tags for the associated url
+    PlacesUtils.tagging.untagURI(this._uri, null);
+
+    if (typeof(this._doneCallback) == "function")
+      this._doneCallback();
+  },
+
+  toggleTagsSelector: function ABP_toggleTagsSelector() {
+    var tagsSelector = this._element("tagsSelector");
+    var expander = this._element("tagsSelectorExpander");
+    if (tagsSelector.collapsed) {
+      expander.className = "expander-down";
+      expander.setAttribute("tooltiptext",
+                            expander.getAttribute("tooltiptextdown"));
+
+      // rebuild the tag list
+      while (tagsSelector.hasChildNodes())
+        tagsSelector.removeChild(tagsSelector.lastChild);
+
+      var tagsInField = this._getTagsArrayFromTagField();
+      var allTags = PlacesUtils.tagging.allTags;
+      for each (var tag in allTags) {
+        var elt = document.createElement("listitem");
+        elt.setAttribute("type", "checkbox");
+        elt.setAttribute("label", tag);
+        if (tagsInField.indexOf(tag) != -1)
+          elt.setAttribute("checked", "true");
+
+        tagsSelector.appendChild(elt);
+      }
+
+      // This is a no-op if we've added the listener.
+      tagsSelector.addEventListener("CheckboxStateChange", this, false);
+    }
+    else {
+      expander.className = "expander-down";
+      expander.setAttribute("tooltiptext",
+                            expander.getAttribute("tooltiptextdown"));
+    }
+
+    tagsSelector.collapsed = !tagsSelector.collapsed;
+  },
+
+  _getTagsArrayFromTagField: function() {
+    // we don't require the leading space (after each comma)
+    var tags = this._element("tagsField").value.split(",");
+    for (var i=0; i < tags.length; i++) {
+      // remove trailing and leading spaces
+      tags[i] = tags[i].replace(/^\s+/, "").replace(/\s+$/, "");
+
+      // remove empty entries from the array.
+      if (tags[i] == "") {
+        tags.splice(i, 1);
+        i--;
+      }
+    }
+    return tags;
+  },
+
+  // nsIDOMEventListener
+  handleEvent: function ABP_nsIDOMEventListener(aEvent) {
+    if (aEvent.type == "CheckboxStateChange") {
+      // Update the tags field when items are checked/unchecked in the listbox
+      var tags = this._getTagsArrayFromTagField();
+
+      if (aEvent.target.checked)
+        tags.push(aEvent.target.label);
+      else {
+        var indexOfItem = tags.indexOf(aEvent.target.label);
+        if (indexOfItem != -1)
+          tags.splice(indexOfItem, 1);
+      }
+      this._element("tagsField").value = tags.join(", ");
+    }
+  }
+};
new file mode 100644
--- /dev/null
+++ b/browser/components/places/content/editBookmarkOverlay.xul
@@ -0,0 +1,150 @@
+# ***** 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 Edit Bookmarks Panel code.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Asaf Romano <mano@mozilla.com> (Original Author)
+#
+# 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 *****
+
+<!DOCTYPE overlay [
+<!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/editBookmarkOverlay.dtd">
+%placesDTD;
+]>
+
+<?xml-stylesheet href="chrome://browser/skin/places/editBookmarkOverlay.css"?>
+
+<overlay id="editBookmarkOverlay"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/javascript"
+          src="chrome://browser/content/places/editBookmarkOverlay.js"/>
+
+  <vbox id="editBookmarkPanelContent">
+    <grid id="editBookmarkPanelGrid" flex="1">
+      <columns>
+        <column/>
+        <column flex="1"/>
+      </columns>
+      <rows>
+        <row align="center" id="editBMPanel_nameRow">
+          <label value="&editBookmarkOverlay.name.label;"
+                 contorl="editBMPanel_namePicker"/>
+          <menulist id="editBMPanel_namePicker"
+                    flex="1"
+                    editable="true"
+                    droppable="false"
+                    oninput="gAddBookmarksPanel.onNamePickerInput();">
+            <menupopup>
+              <menuitem id="editBMPanel_userEnteredName"/>
+              <menuitem disabled="true">
+                <menuseparator flex="1"/>
+                <label value="&editBookmarkOverlay.liveTitlesSeparator.label;"/>
+              </menuitem>
+            </menupopup>
+          </menulist>
+        </row>
+        <row align="center" id="editBMPanel_folderRow">
+          <label value="&editBookmarkOverlay.folder.label;"
+                 control="editBMPanel_folderMenuList"/>
+          <menulist id="editBMPanel_folderMenuList"
+                    class="folder-icon"
+                    oncommand="gAddBookmarksPanel.onMenuListFolderSelect();">
+            <menupopup>
+              <!-- Static item for special folders -->
+              <menuitem id="editBMPanel_placesRootItem"
+                        label="&editBookmarkOverlay.allBookmarksFolderItem.label;"
+                        class="menuitem-iconic folder-icon"/>
+              <menuitem id="editBMPanel_bmRootItem"
+                        label="&editBookmarkOverlay.bookmarksMenuFolderItem.label;"
+                        class="menuitem-iconic folder-icon"/>
+              <menuitem id="editBMPanel_toolbarFolderItem"
+                        label="&editBookmarkOverlay.toolbarFolderItem.label;"
+                        class="menuitem-iconic folder-icon"/>
+              <menuseparator id="editBMPanel_foldersSeparator" hidden="true"/>
+            </menupopup>
+          </menulist>
+          <button id="editBMPanel_foldersExpander"
+                  class="expander-down"
+                  tooltiptext="&editBookmarkOverlay.foldersExpanderDown.tooltip;"
+                  tooltiptextdown="&editBookmarkOverlay.foldersExpanderDown.tooltip;"
+                  tooltiptextup="&editBookmarkOverlay.expanderUp.tooltip;"
+                  oncommand="gAddBookmarksPanel.toggleFolderTreeVisibility();"/>
+        </row>
+        <tree id="editBMPanel_folderTree"
+              class="placesTree"
+              type="places"
+              height="150"
+              collapsed="true"
+              onselect="gAddBookmarksPanel.onFolderTreeSelect();"
+              showRoot="true"
+              place="place:folder=2&amp;group=3&amp;excludeItems=1&amp;excludeQueries=1&amp;excludeReadOnlyFolders=1"
+              hidecolumnpicker="true">
+          <treecols>
+            <treecol anonid="title" flex="1" primary="true" hideheader="true"/>
+          </treecols>
+          <treechildren flex="1"/>
+        </tree>
+        <row align="center" id="editBMPanel_tagsRow">
+          <label value="&editBookmarkOverlay.tags.label;"
+                 control="tagsField"/>
+          <textbox id="editBMPanel_tagsField"/>
+          <button id="editBMPanel_tagsSelectorExpander"
+                  class="expander-down"
+                  tooltiptext="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
+                  tooltiptextdown="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
+                  tooltiptextup="&editBookmarkOverlay.expanderUp.tooltip;"
+                  oncommand="gAddBookmarksPanel.toggleTagsSelector();"/>
+        </row>
+
+        <!-- XXX: Temporary workaround -->
+        </rows></grid>
+        <listbox id="editBMPanel_tagsSelector" height="150" collapsed="true"/>
+        <grid flex="1"><columns><column/><column flex="1"/></columns><rows>
+
+        <row id="editBMPanel_descriptionRow" align="center">
+          <label value="&editBookmarkOverlay.description.label;"
+                 control="editBMPanel_descriptionField"/>
+          <textbox id="editBMPanel_descriptionField"/>
+        </row>
+      </rows>
+    </grid>
+
+    <hbox>
+      <spacer flex="1"/>
+      <button label="&editBookmarkOverlay.delete.label;"
+              oncommand="gAddBookmarksPanel.deleteAndClose();"/>
+      <button label="&editBookmarkOverlay.ok.label;"
+              default="true"
+              oncommand="gAddBookmarksPanel.accept();"/>
+    </hbox>
+  </vbox>
+</overlay>
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -422,17 +422,18 @@ PlacesTreeView.prototype = {
   COLUMN_TYPE_DATE: 3,
   COLUMN_TYPE_VISITCOUNT: 4,
   COLUMN_TYPE_KEYWORD: 5,
   COLUMN_TYPE_DESCRIPTION: 6,
   COLUMN_TYPE_DATEADDED: 7,
   COLUMN_TYPE_LASTMODIFIED: 8,
 
   _getColumnType: function PTV__getColumnType(aColumn) {
-    switch (aColumn.id) {
+    var columnType = aColumn.id || aColumn.element.getAttribute("anonid");
+    switch (columnType) {
       case "title":
         return this.COLUMN_TYPE_TITLE;
       case "url":
         return this.COLUMN_TYPE_URI;
       case "date":
         return this.COLUMN_TYPE_DATE;
       case "visitCount":
         return this.COLUMN_TYPE_VISITCOUNT;
@@ -871,17 +872,18 @@ PlacesTreeView.prototype = {
         break;
       case this.SESSION_STATUS_CONTINUE:
         aProperties.AppendElement(this._sessionContinueAtom);
         break
     }
   },
 
   getCellProperties: function PTV_getCellProperties(aRow, aColumn, aProperties) {
-    if (aColumn.id != "title")
+    var columnType = aColumn.id || aColumn.element.getAttribute("anonid") ;
+    if (columnType != "title")
       return;
 
     this._ensureValidRow(aRow);
     var node = this._visibleElements[aRow];
 
     if (PlacesUtils.nodeIsSeparator(node))
       aProperties.AppendElement(this._separatorAtom);
   },
--- a/browser/components/places/content/utils.js
+++ b/browser/components/places/content/utils.js
@@ -154,16 +154,26 @@ var PlacesUtils = {
   _microsummaries: null,
   get microsummaries() {
     if (!this._microsummaries)
       this._microsummaries = Cc["@mozilla.org/microsummary/service;1"].
                              getService(Ci.nsIMicrosummaryService);
     return this._microsummaries;
   },
 
+  /**
+   * The Places Tagging Service
+   */
+  get tagging() {
+    if (!this._tagging)
+      this._tagging = Cc["@mozilla.org/browser/tagging-service;1"].
+                      getService(Ci.nsITaggingService);
+    return this._tagging;
+  },
+
   _RDF: null,
   get RDF() {
     if (!this._RDF)
       this._RDF = Cc["@mozilla.org/rdf/rdf-service;1"].
                   getService(Ci.nsIRDFService);
     return this._RDF;
   },
 
@@ -1344,48 +1354,52 @@ var PlacesUtils = {
    * @param aAnnotations
    *        Array of objects, each containing the following properties:
    *        name, flags, expires, type, mimeType (only used for binary
    *        annotations) value.
    */
   setAnnotationsForURI: function PU_setAnnotationsForURI(aURI, aAnnos) {
     var annosvc = this.annotations;
     aAnnos.forEach(function(anno) {
+      var flags = ("flags" in anno) ? anno.flags : 0;
+      var expires = ("expires" in anno) ?
+        anno.expires : Ci.nsIAnnotationService.EXPIRE_NEVER;
       if (anno.type == annosvc.TYPE_BINARY) {
         annosvc.setPageAnnotationBinary(aURI, anno.name, anno.value,
                                         anno.value.length, anno.mimeType,
-                                        anno.flags, anno.expires);
+                                        flags, expires);
       }
-      else {
-        annosvc.setPageAnnotation(aURI, anno.name, anno.value,
-                                  anno.flags, anno.expires);
-      }
+      else
+        annosvc.setPageAnnotation(aURI, anno.name, anno.value, flags, expires);
     });
   },
 
   /**
    * Annotate an item with a batch of annotations.
    * @param aItemId
    *        The identifier of the item for which annotations are to be set
    * @param aAnnotations
    *        Array of objects, each containing the following properties:
    *        name, flags, expires, type, mimeType (only used for binary
    *        annotations) value.
    */
   setAnnotationsForItem: function PU_setAnnotationsForItem(aItemId, aAnnos) {
     var annosvc = this.annotations;
     aAnnos.forEach(function(anno) {
+      var flags = ("flags" in anno) ? anno.flags : 0;
+      var expires = ("expires" in anno) ?
+        anno.expires : Ci.nsIAnnotationService.EXPIRE_NEVER;
       if (anno.type == annosvc.TYPE_BINARY) {
         annosvc.setItemAnnotationBinary(aItemId, anno.name, anno.value,
                                         anno.value.length, anno.mimeType,
-                                        anno.flags, anno.expires);
+                                        flags, expires);
       }
       else {
-        annosvc.setItemAnnotation(aItemId, anno.name, anno.value,
-                                  anno.flags, anno.expires);
+        annosvc.setItemAnnotation(aItemId, anno.name, anno.value, flags,
+                                  expires);
       }
     });
   },
 
   /**
    * Helper for getting a serialized Places query for a particular folder.
    * @param aFolderId The folder id to get a query for.
    * @return string serialized place URI
@@ -1434,16 +1448,23 @@ var PlacesUtils = {
 
   get toolbarFolderId() {
     if (!("_toolbarFolderId" in this))
       this._toolbarFolderId = this.bookmarks.toolbarFolder;
 
     return this._toolbarFolderId;
   },
 
+  get tagRootId() {
+    if (!("_tagRootId" in this))
+      this._tagRootId = this.bookmarks.tagRoot;
+
+    return this._tagRootId;
+  },
+
   /**
    * Set the POST data associated with a URI, if any.
    * Used by POST keywords.
    *   @param aURI
    *   @returns string of POST data
    */
   setPostDataForURI: function PU_setPostDataForURI(aURI, aPostData) {
     const annos = this.annotations;
@@ -1462,16 +1483,29 @@ var PlacesUtils = {
     const annos = this.annotations;
     if (annos.pageHasAnnotation(aURI, POST_DATA_ANNO))
       return annos.getPageAnnotation(aURI, POST_DATA_ANNO);
 
     return null;
   },
 
   /**
+   * Retrieve the description of an item
+   * @param aItemId
+   *        item identifier
+   * @returns the description of the given item, or an empty string if it is
+   * not set.
+   */
+  getItemDescription: function PU_getItemDescription(aItemId) {
+    if (this.annotations.itemHasAnnotation(aItemId, DESCRIPTION_ANNO))
+      return this.annotations.getItemAnnotation(aItemId, DESCRIPTION_ANNO);
+    return "";
+  },
+
+  /**
    * Converts a JavaScript object into a JSON string
    * (see http://www.json.org/ for the full grammar).
    *
    * The inverse operation consists of eval("(" + JSON_string + ")");
    * and should be provably safe.
    *
    * @param aJSObject is the object to be converted
    * @return the object's JSON representation
--- a/browser/components/places/jar.mn
+++ b/browser/components/places/jar.mn
@@ -26,8 +26,10 @@ browser.jar:
 *   content/browser/history/history-panel.xul            (content/history-panel.xul) 
 *   content/browser/places/history-panel.js              (content/history-panel.js)
 # ditto for the bookmarks sidebar
 *   content/browser/bookmarks/bookmarksPanel.xul         (content/bookmarksPanel.xul)
 *   content/browser/bookmarks/bookmarksPanel.js          (content/bookmarksPanel.js)
 *   content/browser/bookmarks/sidebarUtils.js            (content/sidebarUtils.js)
 *   content/browser/places/moveBookmarks.xul             (content/moveBookmarks.xul)
 *   content/browser/places/moveBookmarks.js              (content/moveBookmarks.js)
+*   content/browser/places/editBookmarkOverlay.xul       (content/editBookmarkOverlay.xul)
+*   content/browser/places/editBookmarkOverlay.js        (content/editBookmarkOverlay.js)
--- a/browser/components/places/public/nsIPlacesImportExportService.idl
+++ b/browser/components/places/public/nsIPlacesImportExportService.idl
@@ -44,28 +44,27 @@ interface nsILocalFile;
  * The PlacesImportExport interface provides methods for importing
  * and exporting Places data.
  */
 
 [scriptable, uuid(21c00314-fa63-11db-8314-0800200c9a66)]
 interface nsIPlacesImportExportService: nsISupports
 {
   /**
-   * Loads the given bookmarks.html file and merges it with the current
-   * bookmarks hierarchy.
+   * Loads the given bookmarks.html file and replaces it with the current
+   * bookmarks hierarchy (if aIsInitialImport is true) or appends it
+   * (if aIsInitialImport is false)
    */
   void importHTMLFromFile(in nsILocalFile aFile, in boolean aIsInitialImport);
 
-
   /**
    * Loads the given bookmarks.html file and puts it in the given folder
    */
   void importHTMLFromFileToFolder(in nsILocalFile aFile, in PRInt64 aFolder, in boolean aIsInitialImport);
 
-
   /**
    * Saves the current bookmarks hierarchy to a bookmarks.html file.
    */
   void exportHTMLToFile(in nsILocalFile aFile);
 
   /**
    * Backup and archive the bookmarks.html file.
    */
--- a/browser/components/sessionstore/src/nsSessionStartup.js
+++ b/browser/components/sessionstore/src/nsSessionStartup.js
@@ -271,29 +271,29 @@ SessionStartup.prototype = {
         // get app name from branding properties
         var brandStringBundle = this._getStringBundle("chrome://branding/locale/brand.properties");
         var brandShortName = brandStringBundle.GetStringFromName("brandShortName");
 
         // create prompt strings
         var ssStringBundle = this._getStringBundle("chrome://browser/locale/sessionstore.properties");
         var restoreTitle = ssStringBundle.formatStringFromName("restoredTitle", [brandShortName], 1);
         var restoreText = ssStringBundle.formatStringFromName("restoredMsg", [brandShortName], 1);
-        var buttonTitle = ssStringBundle.GetStringFromName("buttonTitle");
+        var okTitle = ssStringBundle.GetStringFromName("okTitle");
         var cancelTitle = ssStringBundle.GetStringFromName("cancelTitle");
 
         var promptService = Cc["@mozilla.org/embedcomp/prompt-service;1"].
                             getService(Ci.nsIPromptService);
 
         // set the buttons that will appear on the dialog
         var flags = promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0 +
                     promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_1 +
                     promptService.BUTTON_POS_0_DEFAULT;
         
         var buttonChoice = promptService.confirmEx(null, restoreTitle, restoreText, 
-                                          flags, buttonTitle, cancelTitle, null, 
+                                          flags, okTitle, cancelTitle, null, 
                                           null, {});
         recover = (buttonChoice == 0);
       }
     }
     catch (ex) { dump(ex + "\n"); } // if the prompt fails, recover anyway
     return recover;
   },
 
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -386,18 +386,16 @@ SessionStoreService.prototype = {
    * @param aWindow
    *        Window reference
    */
   onLoad: function sss_onLoad(aWindow) {
     // return if window has already been initialized
     if (aWindow && aWindow.__SSi && this._windows[aWindow.__SSi])
       return;
 
-    var _this = this;
-
     // ignore non-browser windows and windows opened while shutting down
     if (aWindow.document.documentElement.getAttribute("windowtype") != "navigator:browser" ||
       this._loadState == STATE_QUITTING)
       return;
 
     // assign it a unique identifier (timestamp)
     aWindow.__SSi = "window" + Date.now();
 
@@ -418,17 +416,17 @@ SessionStoreService.prototype = {
         // make sure that the restored tabs are first in the window
         this._initialState._firstTabs = true;
         this.restoreWindow(aWindow, this._initialState, this._isCmdLineEmpty(aWindow));
         delete this._initialState;
       }
       
       if (this._lastSessionCrashed) {
         // restart any interrupted downloads
-        aWindow.setTimeout(function(){ _this.retryDownloads(aWindow); }, 0);
+        aWindow.setTimeout(this.retryDownloads, 0);
       }
     }
     
     var tabbrowser = aWindow.getBrowser();
     var tabpanels = tabbrowser.mPanelContainer;
     
     // add tab change listeners to all already existing tabs
     for (var i = 0; i < tabpanels.childNodes.length; i++) {
@@ -1621,60 +1619,52 @@ SessionStoreService.prototype = {
         cookieManager.add(cookie.host, cookie.path || "", cookie.name || "", cookie.value, !!cookie.secure, !!cookie.httponly, true, "expiry" in cookie ? cookie.expiry : MAX_EXPIRY);
       }
       catch (ex) { Components.utils.reportError(ex); } // don't let a single cookie stop recovering
     }
   },
 
   /**
    * Restart incomplete downloads
-   * @param aWindow
-   *        Window reference
    */
-  retryDownloads: function sss_retryDownloads(aWindow) {
-    var downloadManager = Cc["@mozilla.org/download-manager;1"].
-                          getService(Ci.nsIDownloadManager);
+  retryDownloads: function sss_retryDownloads() {
     var ioService = Cc["@mozilla.org/network/io-service;1"].
                     getService(Ci.nsIIOService);
-    
-    var database = downloadManager.DBConnection;
+    var dlManager = Cc["@mozilla.org/download-manager;1"].
+                    getService(Ci.nsIDownloadManager);
     
-    var stmt = database.createStatement("SELECT source, target, id " +
-                                        "FROM moz_downloads " +
-                                        "WHERE state = ?1");
+    function AsyncDownloadRetrier(aDlId) {
+      this._dlId = aDlId;
+      this._dlManager = dlManager;
+    }
+    AsyncDownloadRetrier.prototype = {
+      onStartRequest: function(aRequest, aContext) { },
+      onStopRequest: function(aRequest, aContext, aStatus) {
+        if (Components.isSuccessCode(aStatus))
+          this._dlManager.retryDownload(this._dlId);
+      }
+    };
+    
+    var stmt = dlManager.DBConnection.
+                         createStatement("SELECT id, source " +
+                                         "FROM moz_downloads " +
+                                         "WHERE state = ?1");
     stmt.bindInt32Parameter(0, Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING);
 
-    var dls = [];
     // restart all downloads that were in progress before the crash
+    // and which are currently available through the network
     while (stmt.executeStep()) {
-      // URL being downloaded
-      var url = stmt.getUTF8String(0);
+      var dlId = stmt.getInt64(0);
+      var url = stmt.getUTF8String(1);
       
-      var savedTo = stmt.getUTF8String(1);
-      var savedToURI = ioService.newURI(savedTo, null, null);
-      savedTo = savedToURI.path;
-   
-      var dl = { id: stmt.getInt64(2), url: url, savedTo: savedTo };
-      dls.push(dl);
-    }
-    stmt.reset();
-
-    // We need to remove it from the database otherwise it just sits there
-    stmt = database.createStatement("DELETE FROM moz_downloads " +
-                                    "WHERE state = ?1");
-    stmt.bindInt32Parameter(0, Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING);
-    stmt.execute();
-
-    for (var i = dls.length - 1; i >= 0; --i) {
       var linkChecker = Cc["@mozilla.org/network/urichecker;1"].
                         createInstance(Ci.nsIURIChecker);
-      linkChecker.init(ioService.newURI(dls[i].url, null, null));
+      linkChecker.init(ioService.newURI(url, null, null));
       linkChecker.loadFlags = Ci.nsIRequest.LOAD_BACKGROUND;
-      linkChecker.asyncCheck(new AutoDownloader(dls[i].url, dls[i].savedTo, aWindow),
-                             null);
+      linkChecker.asyncCheck(new AsyncDownloadRetrier(dlId), null);
     }
   },
 
 /* ........ Disk Access .............. */
 
   /**
    * save state delayed by N ms
    * marks window as dirty (i.e. data update can't be skipped)
@@ -2044,40 +2034,16 @@ SessionStoreService.prototype = {
       Components.returnCode = Cr.NS_ERROR_NO_INTERFACE;
       return null;
     }
     
     return this;
   }
 };
 
-/* :::::::::: Asynchronous File Downloader :::::::::::::: */
-
-function AutoDownloader(aURL, aFilename, aWindow) {
-   this._URL = aURL;
-   this._filename = aFilename;
-   this._window = aWindow;
-}
-
-AutoDownloader.prototype = {
-  onStartRequest: function(aRequest, aContext) { },
-  onStopRequest: function(aRequest, aContext, aStatus) {
-    if (Components.isSuccessCode(aStatus)) {
-      var file =
-        Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
-      file.initWithPath(this._filename);
-      if (file.exists()) {
-        file.remove(false);
-      }
-      
-      this._window.saveURL(this._URL, this._filename, null, true, true, null);
-    }
-  }
-};
-
 /* :::::::: Service Registration & Initialization ::::::::::::::: */
 
 /* ........ nsIModule .............. */
 
 const SessionStoreModule = {
 
   getClassObject: function(aCompMgr, aCID, aIID) {
     if (aCID.equals(CID)) {
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -522,8 +522,9 @@ extensions/talkback@mozilla.org/componen
 #else
 extensions/talkback@mozilla.org/components/talkback/talkback
 extensions/talkback@mozilla.org/components/talkback/XTalkback.ad
 extensions/talkback@mozilla.org/components/master.ini
 extensions/talkback@mozilla.org/components/talkback.so
 #endif
 #endif
 components/airbag.xpt
+components/nsUrlClassifierTable.js
--- a/browser/installer/unix/packages-static
+++ b/browser/installer/unix/packages-static
@@ -213,16 +213,17 @@ bin/components/nsHelperAppDlg.js
 bin/components/nsInterfaceInfoToIDL.js
 ; bin/components/nsProgressDialog.js   not needed for firefox
 bin/components/nsProxyAutoConfig.js
 ; bin/components/nsResetPref.js    not needed for firefox
 bin/components/nsSidebar.js
 ; bin/components/nsUpdateNotifier.js not needed for firefox
 bin/components/nsXmlRpcClient.js
 bin/components/nsExtensionManager.js
+bin/components/nsBlocklistService.js
 bin/components/nsUpdateService.js
 bin/components/pluginGlue.js
 bin/components/extensions.xpt
 bin/components/update.xpt
 bin/components/nsSessionStartup.js
 bin/components/nsSessionStore.js
 bin/components/sessionstore.xpt
 bin/components/nsURLFormatter.js
@@ -231,26 +232,27 @@ bin/components/libbrowserdirprovider.so
 bin/components/libbrowsercomps.so
 bin/components/txEXSLTRegExFunctions.js
 bin/components/nsLivemarkService.js
 bin/components/nsTaggingService.js
 bin/components/nsDefaultCLH.js
 bin/components/nsContentPrefService.js
 bin/components/nsContentDispatchChooser.js
 bin/components/nsHandlerService.js
+bin/components/nsScriptableIO.js
+bin/components/nsWebHandlerApp.js
 
 ; Modules
 bin/modules/*
 
 ; Safe Browsing
 bin/components/nsSafebrowsingApplication.js
 bin/components/safebrowsing.xpt
 bin/components/nsUrlClassifierListManager.js
 bin/components/nsUrlClassifierLib.js
-bin/components/nsUrlClassifierTable.js
 bin/components/url-classifier.xpt
 
 ; Kerberos NegotiateAuth
 bin/components/libauth.so
 
 ; GNOME hooks
 bin/components/libmozgnome.so
 bin/components/mozgnome.xpt
--- a/browser/installer/windows/packages-static
+++ b/browser/installer/windows/packages-static
@@ -206,16 +206,17 @@ bin\components\nsTryToClose.js
 bin\components\nsDictionary.js
 bin\components\nsHelperAppDlg.js
 bin\components\nsProxyAutoConfig.js
 bin\components\nsSearchService.js
 bin\components\nsSearchSuggestions.js
 bin\components\nsSidebar.js
 bin\components\nsXmlRpcClient.js
 bin\components\nsExtensionManager.js
+bin\components\nsBlocklistService.js
 bin\components\nsUpdateService.js
 bin\components\nsMicrosummaryService.js
 bin\components\nsPlacesTransactionsService.js
 bin\components\nsPostUpdateWin.js
 bin\components\nsLoginInfo.js
 bin\components\nsLoginManager.js
 bin\components\nsLoginManagerPrompter.js
 bin\components\storage-Legacy.js
@@ -231,26 +232,27 @@ bin\components\browserdirprovider.dll
 bin\components\brwsrcmp.dll
 bin\components\txEXSLTRegExFunctions.js
 bin\components\nsLivemarkService.js
 bin\components\nsTaggingService.js
 bin\components\nsDefaultCLH.js
 bin\components\nsContentPrefService.js
 bin\components\nsContentDispatchChooser.js
 bin\components\nsHandlerService.js
+bin\components\nsScriptableIO.js
+bin\components\nsWebHandlerApp.js
 
 ; Modules
 bin\modules\*
 
 ; Safe Browsing
 bin\components\nsSafebrowsingApplication.js
 bin\components\safebrowsing.xpt
 bin\components\nsUrlClassifierListManager.js
 bin\components\nsUrlClassifierLib.js
-bin\components\nsUrlClassifierTable.js
 bin\components\url-classifier.xpt
 
 ; [Browser Chrome Files]
 bin\chrome\browser.jar
 bin\chrome\browser.manifest
 bin\chrome\classic.jar
 bin\chrome\classic.manifest
 bin\extensions\{972ce4c6-7e08-4474-a285-3208198ce6fd}\install.rdf
--- a/browser/locales/en-US/chrome/browser/feeds/subscribe.properties
+++ b/browser/locales/en-US/chrome/browser/feeds/subscribe.properties
@@ -3,8 +3,15 @@ addHandler=Add "%S" (%S) as a Feed Reade
 addHandlerAddButton=Add Feed Reader
 addHandlerAddButtonAccesskey=A
 handlerRegistered="%S" is already registered as a Feed Reader
 liveBookmarks=Live Bookmarks
 subscribeNow=Subscribe Now
 chooseApplicationMenuItem=Choose Application...
 chooseApplicationDialogTitle=Choose Application
 alwaysUse=Always use %S to subscribe to feeds
+
+# Protocol Handling
+# "Add %appName (%appDomain) as an application for %protocolType links?"
+addProtocolHandler=Add %S (%S) as an application for %S links?
+addProtocolHandlerAddButton=Add Application
+# "%appName has already been added as an application for %protocolType links."
+protocolHandlerRegistered=%S has already been added as an application for %S links.
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/chrome/browser/places/editBookmarkOverlay.dtd
@@ -0,0 +1,13 @@
+<!ENTITY editBookmarkOverlay.name.label                      "Name:">
+<!ENTITY editBookmarkOverlay.liveTitlesSeparator.label       "Live Titles">
+<!ENTITY editBookmarkOverlay.folder.label                    "Folder:">
+<!ENTITY editBookmarkOverlay.allBookmarksFolderItem.label    "All Bookmarks">
+<!ENTITY editBookmarkOverlay.bookmarksMenuFolderItem.label   "Bookmarks Menu">
+<!ENTITY editBookmarkOverlay.toolbarFolderItem.label         "Bookmarks Toolbar">
+<!ENTITY editBookmarkOverlay.foldersExpanderDown.tooltip     "Show all the bookmarks folders">
+<!ENTITY editBookmarkOverlay.expanderUp.tooltip              "Hide">
+<!ENTITY editBookmarkOverlay.tags.label                      "Tags">
+<!ENTITY editBookmarkOverlay.description.label               "Description:">
+<!ENTITY editBookmarkOverlay.tagsExpanderDown.tooltip        "Show all tags">
+<!ENTITY editBookmarkOverlay.ok.label                        "OK">
+<!ENTITY editBookmarkOverlay.delete.label                    "Delete">
--- a/browser/locales/en-US/chrome/browser/sessionstore.properties
+++ b/browser/locales/en-US/chrome/browser/sessionstore.properties
@@ -1,4 +1,7 @@
 restoredTitle= %S - Restore Previous Session 
 restoredMsg=Your last %S session closed unexpectedly. You can restore the tabs and windows from your previous session, or start a new session if you think the problem was related to a page you were viewing.
-buttonTitle=Restore Session
+
+# Localization note: It is recommended that okTitle be longer than cancelTitle
+# so that hitting the more prominent button doesn't lead to dataloss (see bug 346264).
+okTitle=Restore Previous Session
 cancelTitle=Start New Session
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -22,16 +22,17 @@
     locale/browser/searchbar.dtd                   (%chrome/browser/searchbar.dtd)
     locale/browser/engineManager.dtd               (%chrome/browser/engineManager.dtd)
     locale/browser/engineManager.properties        (%chrome/browser/engineManager.properties)
     locale/browser/setDesktopBackground.dtd        (%chrome/browser/setDesktopBackground.dtd)
     locale/browser/shellservice.properties         (%chrome/browser/shellservice.properties)
     locale/browser/sessionstore.properties         (%chrome/browser/sessionstore.properties)
     locale/browser/places/places.dtd               (%chrome/browser/places/places.dtd)
     locale/browser/places/places.properties        (%chrome/browser/places/places.properties)
+    locale/browser/places/editBookmarkOverlay.dtd  (%chrome/browser/places/editBookmarkOverlay.dtd)
     locale/browser/places/bookmarkProperties.dtd   (%chrome/browser/places/bookmarkProperties.dtd)
     locale/browser/places/bookmarkProperties.properties (%chrome/browser/places/bookmarkProperties.properties)
     locale/browser/preferences/selectBookmark.dtd  (%chrome/browser/preferences/selectBookmark.dtd)
     locale/browser/places/moveBookmarks.dtd        (%chrome/browser/places/moveBookmarks.dtd)
 #ifdef MOZ_SAFE_BROWSING
     locale/browser/safebrowsing/phishing-afterload-warning-message.dtd (%chrome/browser/safebrowsing/phishing-afterload-warning-message.dtd)
     locale/browser/safebrowsing/report-phishing.dtd                    (%chrome/browser/safebrowsing/report-phishing.dtd)
 #endif
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -1264,8 +1264,17 @@ toolbarbutton.bookmark-item[dragover="tr
   border-top: none !important;
   border-left: 2px solid;
   border-right: 2px solid;
   border-bottom: 3px solid;
   -moz-border-right-colors: -moz-mac-menushadow ThreeDLightShadow  !important;
   -moz-border-bottom-colors: -moz-mac-menushadow -moz-mac-menushadow ThreeDShadow  !important;
   -moz-border-left-colors: ThreeDLightShadow ThreeDHighlight !important;
 }
+
+/* star icon */
+#star-icon {
+  list-style-image: url("chrome://browser/skin/places/starPage.png");
+}
+
+#star-icon[starred="true"] {
+  list-style-image: url("chrome://browser/skin/places/pageStarred.png");
+}
--- a/browser/themes/pinstripe/browser/jar.mn
+++ b/browser/themes/pinstripe/browser/jar.mn
@@ -39,16 +39,19 @@ classic.jar:
   skin/classic/browser/places/bookmarksToolbar.png          (places/bookmarksToolbar.png)
   skin/classic/browser/places/toolbarDropMarker.png         (places/toolbarDropMarker.png)
   skin/classic/browser/places/folderDragOver.png            (places/folderDragOver.png)
   skin/classic/browser/places/folderDropArrow.png           (places/folderDropArrow.png)
   skin/classic/browser/places/folderDropHoverArrow.png      (places/folderDropHoverArrow.png)
   skin/classic/browser/places/livemarkFolder.png            (places/livemarkFolder.png)
   skin/classic/browser/places/livemarkFolderHover.png       (places/livemarkFolderHover.png)
   skin/classic/browser/places/bookmarkProperties.css        (places/bookmarkProperties.css)
+  skin/classic/browser/places/editBookmarkOverlay.css       (places/editBookmarkOverlay.css)
+  skin/classic/browser/places/starPage.png                  (places/starPage.png)
+  skin/classic/browser/places/pageStarred.png               (places/pageStarred.png)
   skin/classic/browser/places/organizer-toolbar.png         (bookmarks/Bookmarks-toolbar.png)
   skin/classic/browser/places/expander-closed-active.png    (bookmarks/expander-closed-active.png)
   skin/classic/browser/places/expander-closed.png           (bookmarks/expander-closed.png)
   skin/classic/browser/places/expander-open-active.png      (bookmarks/expander-open-active.png)
   skin/classic/browser/places/expander-open.png             (bookmarks/expander-open.png)
 #ifdef MOZ_SAFE_BROWSING
   skin/classic/browser/safebrowsing/browser-protection.css  (safebrowsing/browser-protection.css)
   skin/classic/browser/safebrowsing/close16x16.png          (safebrowsing/close16x16.png)
new file mode 100644
--- /dev/null
+++ b/browser/themes/pinstripe/browser/places/editBookmarkOverlay.css
@@ -0,0 +1,143 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Firefox.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Myk Melez <myk@mozilla.org>
+ *   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 ***** */
+
+@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+@namespace html url("http://www.w3.org/1999/xhtml");
+
+/**** folder menulist ****/
+.folder-icon > .menulist-label-box > .menulist-icon,
+.folder-icon > .menu-iconic-left > .menu-iconic-icon {
+  width: 16px;
+  height: 16px;
+}
+
+.folder-icon > .menu-iconic-left {
+  display: -moz-box;
+}
+
+.folder-icon {
+  list-style-image: url("chrome://global/skin/tree/folder.png") !important;
+}
+
+.menulist-icon {
+	margin: 0 !important;
+}
+
+/**** folder tree ****/
+
+#editBMPanel_folderTree {
+   margin: 6px 0;
+}
+
+/**** expanders ****/
+
+.expander-up,
+.expander-down {
+  -moz-appearance: none;
+  margin-left: 8px;
+  padding: 0;
+  min-width: 0;
+}
+
+.expander-up {
+	list-style-image: url("chrome://browser/skin/places/expander-open.png") !important;
+}
+
+.expander-down {
+	list-style-image: url("chrome://browser/skin/places/expander-closed.png") !important;
+}
+
+.expander-down:hover:active {
+	list-style-image: url("chrome://browser/skin/places/expander-closed-active.png") !important;
+}
+
+.expander-up:hover:active {
+	list-style-image: url("chrome://browser/skin/places/expander-open-active.png") !important;
+}
+
+/**** name picker ****/
+
+/* Make the microsummary picker look like a regular textbox instead of 
+ * an editable menulist when no microsummaries are available.
+ */
+#editBMPanel_namePicker[droppable="false"] {
+  -moz-appearance: none;
+  margin: 0px;
+  border: none;
+  padding: 0px;
+  height: auto !important;
+}
+
+#editBMPanel_namePicker[droppable="false"] > .menulist-dropmarker {
+  display: none;
+}
+
+#editBMPanel_namePicker[droppable="false"] > .menulist-editable-box {
+  /* These rules are duplicates of the rules for the textbox element
+   * in textbox.css and should track changes in that file.
+   */
+  -moz-appearance: textfield;
+  cursor: text;
+  margin: 2px 4px;
+  border: 2px solid;
+  -moz-border-top-colors: ThreeDShadow ThreeDDarkShadow;
+  -moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
+  -moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
+  -moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
+  padding: 2px 2px 3px 4px;
+  background-color: -moz-Field;
+  color: -moz-FieldText;
+}
+
+#editBMPanel_namePicker[droppable="false"] > .menulist-editable-box > html|*.textbox-input {
+  margin: 0px !important;
+  border: none !important;
+  padding: 0px !important;
+  background-color: inherit;
+  color: inherit;
+  font: inherit;
+}
+
+/* Hide the drop marker and the popup. */
+
+#editBMPanel_namePicker[droppable="false"] > .menulist-dropmarker {
+  display: none;
+}
+
+#editBMPanel_namePicker[droppable="false"] > menupopup {
+  display: none;
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b63f06afbcdc46f379d1ce0fb0783ef4a0ffc90b
GIT binary patch
literal 3270
zc$@*o3_0_OP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00009a7bBm000XU
z000XU0RWnu7ytkYPiaF#P*7-ZbZ>KLZ*U+<Lqi~Na&Km7Y-Iodc-oy)XH-+^7Crag
z^g>IBfRsybQWXdwQbLP>6p<z>Aqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uh<iVD~V
z<RPMtgQJLw%KPDaqifc@_vX$1wbwr9tn;0-&j-K=43<bUQ8j=JsX`tR;Dg7+#^K~H
zK!FM*Z~zbpvt%K2{UZSY_<lS*D<Z%Lz5oGu(+dayz)hRLFdT>f59&ghTmgWD0l;*T
zI7<kC6aYYajzXpYKt=(8otP$50H6c_V9R4-;{Z@C0AMG7=F<Rxo%or10RUT+Ar%3j
zkpLhQWr#!oXgdI`&sK^>09Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p
z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-<?i
z0%4j!F2Z@488U%158(66005wo6%pWr^Zj_v4zAA5HjcIqUoGmt2LB>rV&neh&#Q1i
z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_<lS*MWK+n+1cgf
z<k(8YLR(?VSAG6x!e78w{cQPuJpA|d;J)G{fihizM+Erb!p!tcr5w+a34~(Y=8s4G
zw+sLL9n&JjNn*KJDiq^U5^;`1nvC-@r6P$!k}1U{(*I=Q-z@tBKHoI}uxdU5dyy@u
zU1J0GOD7Ombim^G008p4Z^6_k2m^p<gW=D2|L;HjN1!DDfM!XOaR2~bL?kX$%CkSm
z2mk;?pn)o|K^yeJ7%adB9Ki+L!3+FgHiSYX#KJ-lLJDMn9CBbOtb#%)hRv`YDqt_v
zKpix|QD}yfa1JiQRk#j4a1Z)n2%f<xynzV>LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW
zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_Ifq<Ex{*7`05XF7hP+2Hl!3BQJ=6@fL%FCo
z8iYoo3(#bAF`ADSpqtQgv>H8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X
zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ<AYmRsNLWl*PS{AOARHt#5!wki2?K;t
z!Y3k=s7tgax)J%r7-BLphge7~Bi0g+6E6^Zh(p9TBoc{3GAFr^0!gu?RMHaCM$&Fl
zBk3%un>0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4
z<uv66WtcKSRim0x-Ke2d5jBrmLam{;Qm;{ms1r1GnmNsb7D-E`t)i9F8fX`2_i3-_
zbh;7Ul^#x)&{xvS=|||7=mYe33=M`AgU5(xC>fg=2N-7=cNnjjOr{yriy6mMFgG#l
znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U
zt5vF<Q0r40Q)j6=sE4X&sBct1q<&fbi3VB2Ov6t@q*0);U*o*SAPZv|vv@2aYYnT0
zb%8a+Cb7-ge0D0knEf5Qi#@8Tp*ce{N;6lpQuCB%KL_KOarm5cP6_8Ir<e17iry6O
zDdH&`rZh~sF=bq9s+O0QSgS~@QL9Jmy*94xr=6y~MY~!1fet~(N+(<=M`w@D1)b+p
z*;C!83a1uLJv#NSE~;y#8=<>IcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya?
z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y
zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB
zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt
z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a<fJbF^|4I#xQ~n$Dc=
zKYhjYmgz5NSkDm8*fZm{6U!;YX`NG>(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C
z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB
zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe
zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0
z?2xS?_ve_-k<Mujg;0Lz*3buG=3$G&ehepthlN*$KaOySSQ^nWmo<0M+(UEUMEXRQ
zMBbZcF;6+KElM>iKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$
z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4
z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu
zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu
z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E
ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw
zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX
z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i&
z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01
z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R
z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw
zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD
zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3|
zawq-H%e&ckC+@AhPrP6BK<z=<L*0kfKU@CX*zeqbYQT4(^U>T#_XdT7&;F71j}Joy
zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z
zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot<a{81DF0~rvGr5Xr~8u`lav1h
z1DNytV>2z=00004XF*Lt006O$eEU(80000WV@Og>004R=004l4008;_004mL004C`
z008P>0026e000+nl3&F}0005uNkl<Zc-o|r&x;aa7{@>EjI(IMyzHjXHnp>M(L=ON
z5EMuqr0Xioz4hRE=`UFN5BBcCx(ivSAY`ROu@FN)h%Czzwi1Qa*mca2(GE?uYvU61
z!h3k$@Av)i{0dAa6aMD}W(iioTm`nhFlXdTWk28CG4PGhf+p0n7X+|5%XAzd6HBI8
zJa-9T)hd|!KLf0SnE`~VB~Y~lk`e;Q_<3cIygv25rfNwfS%R^HswLTLSesVC6jQ#k
z3~VbWgsw#XXi{*VQ|D7KaRAVaG_KPZ?r8YC7q0W2LASLb10oVTgJz_Wl=-844<H5S
zh^Mkgq+P4RpxY8MklXwCs(8?Dig;>`kcb{T_d%~ibLSz0Zl?#_3V2Nuz&+sl^5rxO
zD+%Av-##~J?o@C`!{<QO$d^6^rn+AYiIeMz8>TOyUVXqp`%Br#m$I|QD3oycXYD>W
zqzVAtcMrTWGGgg8jEA_xeLC-6(t7<2ceoGZA&blUUrQw)-aG(xDaN4Jrt$O%j@|D8
zy>`8($FE!^5{;sS!#K8`0k)<~(3NnQPW>&l$|D@RUj<fxi|)v|Q-54#_l1QN3<6y9
z%b@Jo_RX(vY67@z<V#zJw47Bi?|0sRD0=bTU&4<80N7x%)P>4tOaK4?07*qoM6N<$
Eg3c`;d;kCd
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5223196e8ea68fbd7d714e8820a0bcc25f184d2a
GIT binary patch
literal 3075
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
R_H+OM002ovPDHLkV1iqKt?2*&
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -1434,8 +1434,17 @@ toolbarbutton.bookmark-item[dragover="tr
 
 .bookmark-item[dragover-top="true"] {
   -moz-border-top-colors: #000000;
 }
 
 .bookmark-item[dragover-bottom="true"] {
   -moz-border-bottom-colors: #000000;
 }
+
+/* star icon */
+#star-icon {
+  list-style-image: url("chrome://browser/skin/places/starPage.png");
+}
+
+#star-icon[starred="true"] {
+  list-style-image: url("chrome://browser/skin/places/pageStarred.png");
+}
--- a/browser/themes/winstripe/browser/jar.mn
+++ b/browser/themes/winstripe/browser/jar.mn
@@ -45,16 +45,19 @@ classic.jar:
         skin/classic/browser/feeds/subscribe.css                (feeds/subscribe.css)
         skin/classic/browser/places/places.css                  (places/places.css)
         skin/classic/browser/places/query.png                   (places/query.png)
         skin/classic/browser/places/livemarkItem.png            (places/livemarkItem.png)
         skin/classic/browser/places/bookmarksMenu.png           (places/bookmarksMenu.png)
         skin/classic/browser/places/bookmarksToolbar.png        (places/bookmarksToolbar.png)
         skin/classic/browser/places/toolbarDropMarker.png       (places/toolbarDropMarker.png)
         skin/classic/browser/places/folderDragOver.png          (places/folderDragOver.png)
+        skin/classic/browser/places/editBookmarkOverlay.css     (places/editBookmarkOverlay.css)
+        skin/classic/browser/places/starPage.png                (places/starPage.png)
+        skin/classic/browser/places/pageStarred.png             (places/pageStarred.png)
         skin/classic/browser/places/bookmarkProperties.css      (places/bookmarkProperties.css)
         skin/classic/browser/places/organizer-toolbar.png       (bookmarks/Bookmarks-toolbar.png)
 #ifdef MOZ_SAFE_BROWSING
         skin/classic/browser/safebrowsing/browser-protection.css      (safebrowsing/browser-protection.css)
         skin/classic/browser/safebrowsing/close16x16.png              (safebrowsing/close16x16.png)
         skin/classic/browser/safebrowsing/dim.png                     (safebrowsing/dim.png)
         skin/classic/browser/safebrowsing/tail.png                    (safebrowsing/tail.png)
         skin/classic/browser/safebrowsing/warning16x16.png            (safebrowsing/warning16x16.png)
new file mode 100644
--- /dev/null
+++ b/browser/themes/winstripe/browser/places/editBookmarkOverlay.css
@@ -0,0 +1,110 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Firefox.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Myk Melez <myk@mozilla.org>
+ *   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 ***** */
+
+/**** folder menulist ****/
+.folder-icon > .menulist-label-box > .menulist-icon {
+  width: 16px;
+  height: 16px;
+}
+
+.folder-icon > .menu-iconic-left {
+  display: -moz-box;
+}
+
+.folder-icon {
+  list-style-image: url("chrome://global/skin/icons/folder-item.png") !important;
+  -moz-image-region: rect(0px, 32px, 16px, 16px) !important;
+}
+
+
+/**** expanders ****/
+
+.expander-up,
+.expander-down {
+  min-width: 0;
+}
+
+.expander-up {
+	list-style-image: url("chrome://global/skin/arrow/arrow-up.gif");
+}
+
+.expander-down {
+  list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif");
+}
+
+.expander-down:hover:active {
+	list-style-image: url("chrome://global/skin/arrow/arrow-dn-hov.gif");
+}
+
+.expander-up:hover:active {
+	list-style-image: url("chrome://global/skin/arrow/arrow-up-hov.gif");
+}
+
+/**** name picker ****/
+
+/* Make the microsummary picker look like a regular textbox instead of 
+ * an editable menulist when no microsummaries are available.
+ */
+#editBMPanel_namePicker[droppable="false"] {
+  /* These rules come from the textbox element in textbox.css. */
+
+  /* Normal editable menulists set this to "none". */
+  -moz-appearance: textfield;
+  cursor: text;
+
+  border: 2px solid;
+  -moz-border-top-colors: ThreeDShadow ThreeDDarkShadow;
+  -moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
+  -moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
+  -moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
+  background-color: -moz-Field;
+  color: -moz-FieldText;
+}
+
+#editBMPanel_namePicker[droppable="false"] > .menulist-dropmarker {
+  /* Normal editable menulists set this to "menulist-textfield". */
+  -moz-appearance: none;
+  padding: 2px 2px 3px 4px;
+}
+
+
+/* Hide the drop marker and the popup. */
+
+#editBMPanel_namePicker[droppable="false"] > .menulist-dropmarker,
+#editBMPanel_namePicker[droppable="false"] > menupopup {
+  display: none;
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b63f06afbcdc46f379d1ce0fb0783ef4a0ffc90b
GIT binary patch
literal 3270
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
Eg3c`;d;kCd
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5223196e8ea68fbd7d714e8820a0bcc25f184d2a
GIT binary patch
literal 3075
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
R_H+OM002ovPDHLkV1iqKt?2*&
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -174,16 +174,17 @@ MOZ_COMPONENT_NSPR_LIBS=@MOZ_COMPONENT_N
 
 MOZ_FIX_LINK_PATHS=@MOZ_FIX_LINK_PATHS@
 
 XPCOM_FROZEN_LDOPTS=@XPCOM_FROZEN_LDOPTS@
 XPCOM_LIBS=@XPCOM_LIBS@
 MOZ_TIMELINE=@MOZ_TIMELINE@
 
 ENABLE_STRIP	= @ENABLE_STRIP@
+PKG_SKIP_STRIP	= @PKG_SKIP_STRIP@
 
 ClientWallet=1
 CookieManagement=1
 SingleSignon=1
 
 MOZ_OJI		= @MOZ_OJI@
 MOZ_PLUGINS	= @MOZ_PLUGINS@
 
--- a/configure.in
+++ b/configure.in
@@ -6091,16 +6091,24 @@ dnl ====================================
 dnl = Enable stripping of libs & executables
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(strip,
 [  --enable-strip          Enable stripping of libs & executables ],
     ENABLE_STRIP=1,
     ENABLE_STRIP= )
 
 dnl ========================================================
+dnl = Enable stripping of libs & executables when packaging
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(install-strip,
+[  --enable-install-strip  Enable stripping of libs & executables when packaging ],
+    PKG_SKIP_STRIP= ,
+    PKG_SKIP_STRIP=1)
+
+dnl ========================================================
 dnl = --enable-elf-dynstr-gc
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(elf-dynstr-gc,
 [  --enable-elf-dynstr-gc  Enable elf dynstr garbage collector (opt builds only)],
     USE_ELF_DYNSTR_GC=1,
     USE_ELF_DYNSTR_GC= )
 
 dnl ========================================================
@@ -7436,16 +7444,17 @@ AC_SUBST(MOZ_XPINSTALL)
 AC_SUBST(MOZ_VIEW_SOURCE)
 AC_SUBST(MOZ_SPELLCHECK)
 AC_SUBST(MOZ_XPFE_COMPONENTS)
 AC_SUBST(MOZ_USER_DIR)
 AC_SUBST(MOZ_CRASHREPORTER)
 AC_SUBST(MOZ_MOCHITEST)
 
 AC_SUBST(ENABLE_STRIP)
+AC_SUBST(PKG_SKIP_STRIP)
 AC_SUBST(USE_ELF_DYNSTR_GC)
 AC_SUBST(USE_PREBINDING)
 AC_SUBST(INCREMENTAL_LINKER)
 AC_SUBST(MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS)
 AC_SUBST(MOZ_COMPONENT_NSPR_LIBS)
 AC_SUBST(MOZ_XPCOM_OBSOLETE_LIBS)
 
 AC_SUBST(MOZ_FIX_LINK_PATHS)
--- a/content/base/public/nsIContentSerializer.h
+++ b/content/base/public/nsIContentSerializer.h
@@ -47,26 +47,27 @@ class nsIDOMComment; /* forward declarat
 class nsIDOMDocumentType; /* forward declaration */
 class nsIDOMElement; /* forward declaration */
 class nsIDOMDocument; /* forward declaration */
 class nsAString;
 
 /* starting interface:    nsIContentSerializer */
 
 #define NS_ICONTENTSERIALIZER_IID \
-{ 0x0921afbc, 0x4c6f, 0x4249, \
-  { 0xa7, 0xf5, 0x32, 0xe4, 0x91, 0xbf, 0x6e, 0x32 } }
+{ 0x34769de0, 0x30d0, 0x4cef, \
+  { 0x89, 0x4a, 0xfc, 0xd8, 0xbb, 0x27, 0xc4, 0xb4 } }
 
 class nsIContentSerializer : public nsISupports {
  public: 
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTSERIALIZER_IID)
 
   NS_IMETHOD Init(PRUint32 flags, PRUint32 aWrapColumn,
-                  const char* aCharSet, PRBool aIsCopying) = 0;
+                  const char* aCharSet, PRBool aIsCopying,
+                  PRBool aIsWholeDocument) = 0;
 
   NS_IMETHOD AppendText(nsIDOMText* aText, PRInt32 aStartOffset,
                         PRInt32 aEndOffset, nsAString& aStr) = 0;
 
   NS_IMETHOD AppendCDATASection(nsIDOMCDATASection* aCDATASection,
                                 PRInt32 aStartOffset, PRInt32 aEndOffset,
                                 nsAString& aStr) = 0;
 
--- a/content/base/src/mozSanitizingSerializer.cpp
+++ b/content/base/src/mozSanitizingSerializer.cpp
@@ -121,29 +121,30 @@ NS_IMPL_ISUPPORTS4(mozSanitizingHTMLSeri
                    nsIContentSerializer,
                    nsIContentSink,
                    nsIHTMLContentSink,
                    mozISanitizingHTMLSerializer)
 
 
 NS_IMETHODIMP 
 mozSanitizingHTMLSerializer::Init(PRUint32 aFlags, PRUint32 dummy,
-                                  const char* aCharSet, PRBool aIsCopying)
+                                  const char* aCharSet, PRBool aIsCopying,
+                                  PRBool aIsWholeDocument)
 {
   NS_ENSURE_TRUE(nsContentUtils::GetParserService(), NS_ERROR_UNEXPECTED);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 mozSanitizingHTMLSerializer::Initialize(nsAString* aOutString,
                                         PRUint32 aFlags,
                                         const nsAString& allowedTags)
 {
-  nsresult rv = Init(aFlags, 0, nsnull, PR_FALSE);
+  nsresult rv = Init(aFlags, 0, nsnull, PR_FALSE, PR_FALSE);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // XXX This is wrong. It violates XPCOM string ownership rules.
   // We're only getting away with this because instances of this
   // class are restricted to single function scope.
   // (Comment copied from nsPlaintextSerializer)
   mOutputString = aOutString;
 
--- a/content/base/src/mozSanitizingSerializer.h
+++ b/content/base/src/mozSanitizingSerializer.h
@@ -67,17 +67,17 @@ public:
   virtual ~mozSanitizingHTMLSerializer();
   static PRBool PR_CALLBACK ReleaseProperties(nsHashKey* key, void* data,
                                               void* closure);
 
   NS_DECL_ISUPPORTS
 
   // nsIContentSerializer
   NS_IMETHOD Init(PRUint32 flags, PRUint32 dummy, const char* aCharSet, 
-                  PRBool aIsCopying);
+                  PRBool aIsCopying, PRBool aIsWholeDocument);
 
   NS_IMETHOD AppendText(nsIDOMText* aText, PRInt32 aStartOffset,
                         PRInt32 aEndOffset, nsAString& aStr);
   NS_IMETHOD AppendCDATASection(nsIDOMCDATASection* aCDATASection,
                                 PRInt32 aStartOffset, PRInt32 aEndOffset,
                                 nsAString& aStr)
                       { return NS_OK; }
   NS_IMETHOD AppendProcessingInstruction(nsIDOMProcessingInstruction* aPI,
--- a/content/base/src/nsDocumentEncoder.cpp
+++ b/content/base/src/nsDocumentEncoder.cpp
@@ -888,17 +888,19 @@ nsDocumentEncoder::EncodeToString(nsAStr
 
   nsCOMPtr<nsIAtom> charsetAtom;
   if (!mCharset.IsEmpty()) {
     if (!mCharsetConverterManager) {
       mCharsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
-  mSerializer->Init(mFlags, mWrapColumn, mCharset.get(), mIsCopying);
+  
+  PRBool isWholeDocument = !(mSelection || mRange || mNode);
+  mSerializer->Init(mFlags, mWrapColumn, mCharset.get(), mIsCopying, isWholeDocument);
 
   if (mSelection) {
     nsCOMPtr<nsIDOMRange> range;
     PRInt32 i, count = 0;
 
     rv = mSelection->GetRangeCount(&count);
     NS_ENSURE_SUCCESS(rv, rv);
 
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -421,16 +421,17 @@ GK_ATOM(insertafter, "insertafter")
 GK_ATOM(insertbefore, "insertbefore")
 GK_ATOM(instanceOf, "instanceOf")
 GK_ATOM(intersection, "intersection")
 GK_ATOM(iscontainer, "iscontainer")
 GK_ATOM(isempty, "isempty")
 GK_ATOM(isindex, "isindex")
 GK_ATOM(ismap, "ismap")
 GK_ATOM(kbd, "kbd")
+GK_ATOM(noautofocus, "noautofocus")
 GK_ATOM(key, "key")
 GK_ATOM(keycode, "keycode")
 GK_ATOM(keydown, "keydown")
 GK_ATOM(keypress, "keypress")
 GK_ATOM(keyset, "keyset")
 GK_ATOM(keytext, "keytext")
 GK_ATOM(keyup, "keyup")
 GK_ATOM(label, "label")
--- a/content/base/src/nsHTMLContentSerializer.cpp
+++ b/content/base/src/nsHTMLContentSerializer.cpp
@@ -88,16 +88,17 @@ nsresult NS_NewHTMLContentSerializer(nsI
 }
 
 nsHTMLContentSerializer::nsHTMLContentSerializer()
 : mIndent(0),
   mColPos(0),
   mInBody(PR_FALSE),
   mAddSpace(PR_FALSE),
   mMayIgnoreLineBreakSequence(PR_FALSE),
+  mIsWholeDocument(PR_FALSE),
   mInCDATA(PR_FALSE),
   mNeedLineBreaker(PR_TRUE)
 {
 }
 
 nsHTMLContentSerializer::~nsHTMLContentSerializer()
 {
   NS_ASSERTION(mOLStateStack.Count() == 0, "Expected OL State stack to be empty");
@@ -107,26 +108,28 @@ nsHTMLContentSerializer::~nsHTMLContentS
       delete state;
       mOLStateStack.RemoveElementAt(i);
     }
   }
 }
 
 NS_IMETHODIMP 
 nsHTMLContentSerializer::Init(PRUint32 aFlags, PRUint32 aWrapColumn,
-                              const char* aCharSet, PRBool aIsCopying)
+                              const char* aCharSet, PRBool aIsCopying,
+                              PRBool aIsWholeDocument)
 {
   mFlags = aFlags;
   if (!aWrapColumn) {
     mMaxColumn = 72;
   }
   else {
     mMaxColumn = aWrapColumn;
   }
 
+  mIsWholeDocument = aIsWholeDocument;
   mIsCopying = aIsCopying;
   mIsFirstChildOfOL = PR_FALSE;
   mDoFormat = (mFlags & nsIDocumentEncoder::OutputFormatted) ? PR_TRUE
                                                              : PR_FALSE;
   mBodyOnly = (mFlags & nsIDocumentEncoder::OutputBodyOnly) ? PR_TRUE
                                                             : PR_FALSE;
   // Set the line break character:
   if ((mFlags & nsIDocumentEncoder::OutputCRLineBreak)
@@ -631,17 +634,17 @@ nsHTMLContentSerializer::AppendElementSt
   // even if we're not in pretty printing mode
   PRBool hasDirtyAttr = content->HasAttr(kNameSpaceID_None,
                                          nsGkAtoms::mozdirty);
 
   nsIAtom *name = content->Tag();
 
   // We need too skip any meta tags that set the content type
   // becase we set our own later.
-  if (name == nsGkAtoms::meta) {
+  if (mIsWholeDocument && name == nsGkAtoms::meta) {
     nsAutoString header;
     content->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
     if (header.LowerCaseEqualsLiteral("content-type")) {
       return NS_OK;
     }
   }
 
   if (name == nsGkAtoms::br && mPreLevel > 0
@@ -733,17 +736,17 @@ nsHTMLContentSerializer::AppendElementSt
 
   if (name == nsGkAtoms::script ||
       name == nsGkAtoms::style ||
       name == nsGkAtoms::noscript ||
       name == nsGkAtoms::noframes) {
     mInCDATA = PR_TRUE;
   }
 
-  if (name == nsGkAtoms::head) {
+  if (mIsWholeDocument && name == nsGkAtoms::head) {
     AppendToString(mLineBreak, aStr);
     AppendToString(NS_LITERAL_STRING("<meta http-equiv=\"content-type\""),
                    aStr);
     AppendToString(NS_LITERAL_STRING(" content=\"text/html; charset="), aStr);
     AppendToString(NS_ConvertASCIItoUTF16(mCharset), aStr);
     AppendToString(NS_LITERAL_STRING("\">"), aStr);
   }
 
@@ -760,17 +763,17 @@ nsHTMLContentSerializer::AppendElementEn
   if (!content) return NS_ERROR_FAILURE;
 
   PRBool hasDirtyAttr = content->HasAttr(kNameSpaceID_None,
                                          nsGkAtoms::mozdirty);
 
   nsIAtom *name = content->Tag();
 
   // So that we don't mess up the line breaks.
-  if (name == nsGkAtoms::meta) {
+  if (mIsWholeDocument && name == nsGkAtoms::meta) {
     nsAutoString header;
     content->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
     if (header.LowerCaseEqualsLiteral("content-type")) {
       return NS_OK;
     }
   }
 
   if (name == nsGkAtoms::script) {
--- a/content/base/src/nsHTMLContentSerializer.h
+++ b/content/base/src/nsHTMLContentSerializer.h
@@ -53,17 +53,18 @@ class nsIContent;
 class nsIAtom;
 
 class nsHTMLContentSerializer : public nsXMLContentSerializer {
  public:
   nsHTMLContentSerializer();
   virtual ~nsHTMLContentSerializer();
 
   NS_IMETHOD Init(PRUint32 flags, PRUint32 aWrapColumn,
-                  const char* aCharSet, PRBool aIsCopying);
+                  const char* aCharSet, PRBool aIsCopying,
+                  PRBool aIsWholeDocument);
 
   NS_IMETHOD AppendText(nsIDOMText* aText, 
                         PRInt32 aStartOffset,
                         PRInt32 aEndOffset,
                         nsAString& aStr);
   NS_IMETHOD AppendElementStart(nsIDOMElement *aElement,
                                 nsIDOMElement *aOriginalElement,
                                 nsAString& aStr);
@@ -134,16 +135,20 @@ class nsHTMLContentSerializer : public n
   PRPackedBool  mIsCopying; // Set to PR_TRUE only while copying
 
   // Indicates that a space will be added if and only if content is
   // continued on the same line while serializing source.  Otherwise,
   // the newline character acts as the whitespace and no space is needed.
   PRPackedBool  mAddSpace;
   PRPackedBool  mMayIgnoreLineBreakSequence;
 
+  // This is to ensure that we only do meta tag fixups when dealing with
+  // whole documents.
+  PRPackedBool  mIsWholeDocument;
+
   // To keep track of First LI child of OL in selected range 
   PRPackedBool  mIsFirstChildOfOL;
   PRInt32       mPreLevel;
 
   /*
    * mInCDATA is set to PR_TRUE while the serializer is serializing
    * the content of a element whose content is considerd CDATA by the
    * serializer (such elements are 'script', 'style', 'noscript' and
--- a/content/base/src/nsPlainTextSerializer.cpp
+++ b/content/base/src/nsPlainTextSerializer.cpp
@@ -144,17 +144,18 @@ NS_IMPL_ISUPPORTS4(nsPlainTextSerializer
                    nsIContentSerializer,
                    nsIContentSink,
                    nsIHTMLContentSink,
                    nsIHTMLToTextSink)
 
 
 NS_IMETHODIMP 
 nsPlainTextSerializer::Init(PRUint32 aFlags, PRUint32 aWrapColumn,
-                            const char* aCharSet, PRBool aIsCopying)
+                            const char* aCharSet, PRBool aIsCopying,
+                            PRBool aIsWholeDocument)
 {
 #ifdef DEBUG
   // Check if the major control flags are set correctly.
   if(aFlags & nsIDocumentEncoder::OutputFormatFlowed) {
     NS_ASSERTION(aFlags & nsIDocumentEncoder::OutputFormatted,
                  "If you want format=flowed, you must combine it with "
                  "nsIDocumentEncoder::OutputFormatted");
   }
@@ -269,17 +270,17 @@ nsPlainTextSerializer::PopBool(nsVoidArr
   }
   return returnValue;
 }
 
 NS_IMETHODIMP
 nsPlainTextSerializer::Initialize(nsAString* aOutString,
                                   PRUint32 aFlags, PRUint32 aWrapCol)
 {
-  nsresult rv = Init(aFlags, aWrapCol, nsnull, PR_FALSE);
+  nsresult rv = Init(aFlags, aWrapCol, nsnull, PR_FALSE, PR_FALSE);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // XXX This is wrong. It violates XPCOM string ownership rules.
   // We're only getting away with this because instances of this
   // class are restricted to single function scope.
   mOutputString = aOutString;
 
   return NS_OK;
--- a/content/base/src/nsPlainTextSerializer.h
+++ b/content/base/src/nsPlainTextSerializer.h
@@ -64,17 +64,18 @@ class nsPlainTextSerializer : public nsI
 public:
   nsPlainTextSerializer();
   virtual ~nsPlainTextSerializer();
 
   NS_DECL_ISUPPORTS
 
   // nsIContentSerializer
   NS_IMETHOD Init(PRUint32 flags, PRUint32 aWrapColumn,
-                  const char* aCharSet, PRBool aIsCopying);
+                  const char* aCharSet, PRBool aIsCopying,
+                  PRBool aIsWholeDocument);
 
   NS_IMETHOD AppendText(nsIDOMText* aText, PRInt32 aStartOffset,
                         PRInt32 aEndOffset, nsAString& aStr);
   NS_IMETHOD AppendCDATASection(nsIDOMCDATASection* aCDATASection,
                                 PRInt32 aStartOffset, PRInt32 aEndOffset,
                                 nsAString& aStr);
   NS_IMETHOD AppendProcessingInstruction(nsIDOMProcessingInstruction* aPI,
                                          PRInt32 aStartOffset,
--- a/content/base/src/nsXMLContentSerializer.cpp
+++ b/content/base/src/nsXMLContentSerializer.cpp
@@ -88,17 +88,18 @@ nsXMLContentSerializer::nsXMLContentSeri
 nsXMLContentSerializer::~nsXMLContentSerializer()
 {
 }
 
 NS_IMPL_ISUPPORTS1(nsXMLContentSerializer, nsIContentSerializer)
 
 NS_IMETHODIMP 
 nsXMLContentSerializer::Init(PRUint32 flags, PRUint32 aWrapColumn,
-                             const char* aCharSet, PRBool aIsCopying)
+                             const char* aCharSet, PRBool aIsCopying,
+                             PRBool aIsWholeDocument)
 {
   mCharset = aCharSet;
   return NS_OK;
 }
 
 nsresult
 nsXMLContentSerializer::AppendTextData(nsIDOMNode* aNode, 
                                        PRInt32 aStartOffset,
--- a/content/base/src/nsXMLContentSerializer.h
+++ b/content/base/src/nsXMLContentSerializer.h
@@ -55,17 +55,18 @@ class nsIAtom;
 class nsXMLContentSerializer : public nsIContentSerializer {
  public:
   nsXMLContentSerializer();
   virtual ~nsXMLContentSerializer();
 
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD Init(PRUint32 flags, PRUint32 aWrapColumn,
-                  const char* aCharSet, PRBool aIsCopying);
+                  const char* aCharSet, PRBool aIsCopying,
+                  PRBool aIsWholeDocument);
 
   NS_IMETHOD AppendText(nsIDOMText* aText, PRInt32 aStartOffset,
                         PRInt32 aEndOffset, nsAString& aStr);
 
   NS_IMETHOD AppendCDATASection(nsIDOMCDATASection* aCDATASection,
                                 PRInt32 aStartOffset, PRInt32 aEndOffset,
                                 nsAString& aStr);
 
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -81,16 +81,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug371576-2.html \
 		test_bug371576-3.html \
 		test_bug371576-4.html \
 		test_bug371576-5.html \
 		test_bug372086.html \
 		test_bug373181.xhtml \
 		test_bug375314.html \
 		test_bug382113.html \
+		test_bug390735.html \
 		bug382113_object.html \
 		test_CrossSiteXHR.html \
 		file_CrossSiteXHR_fail1.xml \
 		file_CrossSiteXHR_fail2.xml \
 		file_CrossSiteXHR_fail2.xml^headers^ \
 		file_CrossSiteXHR_fail3.xml \
 		file_CrossSiteXHR_fail4.xml \
 		file_CrossSiteXHR_pass1.xml \
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug390735.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=390735
+-->
+<head>
+  <meta http-equiv="content-type" content="text/html; charset=utf-8">
+  <title>Test for Bug 390735</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+/** Test for Bug 390735 **/
+
+var contents = document.getElementsByTagName("head")[0].innerHTML;
+var expectedFind = "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">";
+
+ok(contents.indexOf(expectedFind) > -1, "The meta tag element was not found");
+</script>
+</pre>
+</body>
+</html>
--- a/content/events/public/nsIEventStateManager.h
+++ b/content/events/public/nsIEventStateManager.h
@@ -47,22 +47,20 @@ class nsIDOMEvent;
 class nsIFrame;
 class nsIView;
 class nsIWidget;
 class imgIContainer;
 
 /*
  * Event state manager interface.
  */
-// {9d25327a-7a17-4d19-928c-f7f3ac19b763}
+// {fb7516ff-2f01-4893-84e8-e4b282813023}
 #define NS_IEVENTSTATEMANAGER_IID \
-{ 0x9d25327a, 0x7a17, 0x4d19, \
-  { 0x92, 0x8c, 0xf7, 0xf3, 0xac, 0x19, 0xb7, 0x63 } }
-
-
+{ 0xfb7516ff, 0x2f01, 0x4893, \
+  { 0x84, 0xe8, 0xe4, 0xb2, 0x82, 0x81, 0x30, 0x23 } }
 
 #define NS_EVENT_NEEDS_FRAME(event) (!NS_IS_FOCUS_EVENT(event))
 
 class nsIEventStateManager : public nsISupports {
 
 public:
   enum EFocusedWithType {
     eEventFocusedByUnknown,     // focus gained via unknown method
@@ -140,16 +138,25 @@ public:
   NS_IMETHOD SetCursor(PRInt32 aCursor, imgIContainer* aContainer,
                        PRBool aHaveHotspot, float aHotspotX, float aHotspotY,
                        nsIWidget* aWidget, PRBool aLockCursor) = 0;
 
   // Method for moving the focus forward/back.
   NS_IMETHOD ShiftFocus(PRBool aDirection, nsIContent* aStart)=0;
 
   NS_IMETHOD NotifyDestroyPresContext(nsPresContext* aPresContext) = 0;
+  
+  /**
+   * Returns true if the current code is being executed as a result of user input.
+   * This includes timers or anything else that is initiated from user input.
+   * However, mouse hover events are not counted as user input, nor are
+   * page load events. If this method is called from asynchronously executed code,
+   * such as during layout reflows, it will return false.
+   */
+  NS_IMETHOD_(PRBool) IsHandlingUserInputExternal() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIEventStateManager, NS_IEVENTSTATEMANAGER_IID)
 
 #define NS_EVENT_STATE_ACTIVE        0x00000001 // mouse is down on content
 #define NS_EVENT_STATE_FOCUS         0x00000002 // content has focus
 #define NS_EVENT_STATE_HOVER         0x00000004 // mouse is hovering over content
 #define NS_EVENT_STATE_DRAGOVER      0x00000008 // drag  is hovering over content
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -88,16 +88,17 @@
 #include "nsIDOMEventTarget.h"
 #include "nsIEnumerator.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeNode.h"
 #include "nsIWebNavigation.h"
 #include "nsIContentViewer.h"
 #include "nsIPrefBranch2.h"
 #include "nsIObjectFrame.h"
+#include "nsXULPopupManager.h"
 
 #include "nsIServiceManager.h"
 #include "nsIScriptSecurityManager.h"
 
 #include "nsIFocusController.h"
 
 #include "nsIDOMXULElement.h"
 #include "nsIDOMDocument.h"
@@ -3373,23 +3374,64 @@ nsEventStateManager::ShiftFocusInternal(
       mCurrentTabIndex = docHasFocus && selectionFrame ? 0 : 1;
     } else if (!docHasFocus) {
       mCurrentTabIndex = 0;
     } else if (selectionFrame) {
       mCurrentTabIndex = 1;   // will keep it from wrapping around to end
     }
   }
 
+  // when a popup is open, we want to ensure that tab navigation occurs only
+  // within the most recently opened panel. If a popup is open, its frame will
+  // be stored in popupFrame.
+  nsIFrame* popupFrame = nsnull;
+  if (curFocusFrame) {
+    // check if the focus is currently inside a popup. Elements such as the
+    // autocomplete widget use the noautofocus attribute to allow the focus to
+    // remain outside the popup when it is opened.
+    popupFrame = nsLayoutUtils::GetClosestFrameOfType(curFocusFrame,
+                                                      nsGkAtoms::menuPopupFrame);
+  }
+  else {
+    // if there is no focus, yet a panel is open, focus the
+    // first item in the popup
+    nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+    if (pm) {
+      popupFrame = pm->GetTopPopup(ePopupTypePanel);
+    }
+  }
+
+  if (popupFrame) {
+    // Don't navigate outside of a popup, so pretend that the
+    // root content is the popup itself
+    rootContent = popupFrame->GetContent();
+    NS_ASSERTION(rootContent, "Popup frame doesn't have a content node");
+  }
+
   nsCOMPtr<nsIContent> nextFocus;
   nsIFrame* nextFocusFrame;
   if (aForward || !docHasFocus || selectionFrame)
     GetNextTabbableContent(rootContent, startContent, curFocusFrame,
                            aForward, ignoreTabIndex || mCurrentTabIndex < 0,
                            getter_AddRefs(nextFocus), &nextFocusFrame);
 
+  if (popupFrame && !nextFocus) {
+    // if no content was found to focus, yet we are inside a popup, try again
+    // from the beginning or end of the popup. Set the current tab index to
+    // the beginning or end.
+    mCurrentTabIndex = aForward ? 1 : 0;
+    GetNextTabbableContent(rootContent, rootContent, nsnull,
+                           aForward, ignoreTabIndex,
+                           getter_AddRefs(nextFocus), &nextFocusFrame);
+    // if the same node was found, don't change the focus
+    if (startContent == nextFocus) {
+      nextFocus = nsnull;
+    }
+  }
+
   // Clear out mCurrentTabIndex. It has a garbage value because of GetNextTabbableContent()'s side effects
   // It will be set correctly when focus is changed via ChangeFocusWith()
   mCurrentTabIndex = 0;
 
   if (nextFocus) {
     // Check to see if the next focused element has a subshell.
     // This is the case for an IFRAME or FRAME element.  If it
     // does, we send focus into the subshell.
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -151,16 +151,18 @@ public:
     --sUserInputEventDepth;
   }
 
   static PRBool IsHandlingUserInput()
   {
     return sUserInputEventDepth > 0;
   }
 
+  NS_IMETHOD_(PRBool) IsHandlingUserInputExternal() { return IsHandlingUserInput(); }
+  
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsEventStateManager,
                                            nsIEventStateManager)
 
 protected:
   /**
    * In certain situations the focus controller's concept of focus gets out of
    * whack with mCurrentFocus. This is used in known cases to reset the focus
    * controller's focus. At some point we should probably move to a single
--- a/content/html/content/src/nsFormSubmission.cpp
+++ b/content/html/content/src/nsFormSubmission.cpp
@@ -752,23 +752,26 @@ nsFSMultipartFormData::AddNameValuePair(
   NS_ENSURE_SUCCESS(rv, rv);
 
   //
   // Make MIME block for name/value pair
   //
   // XXX: name parameter should be encoded per RFC 2231
   // RFC 2388 specifies that RFC 2047 be used, but I think it's not 
   // consistent with MIME standard.
+  // NOTE: The ordering of these headers, and in particular which comes first
+  // and which comes last, is important.  See comments in
+  // nsFSMultipartFormData::AddNameFilePair
   mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
                  + NS_LITERAL_CSTRING(CRLF)
+                 + NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
+                 + nameStr + NS_LITERAL_CSTRING("\"" CRLF)
                  + NS_LITERAL_CSTRING("Content-Type: text/plain; charset=")
                  + mCharset
-                 + NS_LITERAL_CSTRING(CRLF)
-                 + NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
-                 + nameStr + NS_LITERAL_CSTRING("\"" CRLF CRLF)
+                 + NS_LITERAL_CSTRING(CRLF CRLF)
                  + valueStr + NS_LITERAL_CSTRING(CRLF);
 
   return NS_OK;
 }
 
 nsresult
 nsFSMultipartFormData::AddNameFilePair(nsIDOMHTMLElement* aSource,
                                        const nsAString& aName,
@@ -785,22 +788,33 @@ nsFSMultipartFormData::AddNameFilePair(n
   //
   // Make MIME block for name/value pair
   //
   // more appropriate than always using binary?
   mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
                  + NS_LITERAL_CSTRING(CRLF);
   if (!mBackwardsCompatibleSubmit) {
     // XXX Is there any way to tell when "8bit" or "7bit" etc may be
+    // XXXbz See bug 58189 for why we try to send it and bug 83065 for why we
+    // don't just always do it.  It seems like a better solution would be to
+    // just make sure we send this header before the Content-Type header (to
+    // deal with the PHP brain-deadness described in bug 83065), but to send it
+    // anyway.  However, we need to make sure it comes after the
+    // Content-Disposition header, because other server-side packages make the
+    // equally brain-dead assumption that Content-Disposition is the first
+    // header in every part.  See bug 116346 for that fun.
     mPostDataChunk +=
           NS_LITERAL_CSTRING("Content-Transfer-Encoding: binary" CRLF);
   }
   // XXX: name/filename parameter should be encoded per RFC 2231
   // RFC 2388 specifies that RFC 2047 be used, but I think it's not 
   // consistent with the MIME standard.
+  // NOTE: The Content-Disposition MUST come first and the Content-Type last to
+  // satisfy non-MIME-compliant server-side parsers.  See comment above on
+  // Content-Transfer-Encoding.
   mPostDataChunk +=
          NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
        + nameStr + NS_LITERAL_CSTRING("\"; filename=\"")
        + filenameStr + NS_LITERAL_CSTRING("\"" CRLF)
        + NS_LITERAL_CSTRING("Content-Type: ") + aContentType
        + NS_LITERAL_CSTRING(CRLF CRLF);
 
   //
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -3658,16 +3658,17 @@ nsHTMLDocument::CreateAndAddWyciwygChann
   NS_ENSURE_SUCCESS(rv, rv);
 
   mWyciwygChannel = do_QueryInterface(channel);
 
   mWyciwygChannel->SetSecurityInfo(mSecurityInfo);
 
   // Note: we want to treat this like a "previous document" hint so that,
   // e.g. a <meta> tag in the document.write content can override it.
+  SetDocumentCharacterSetSource(kCharsetFromHintPrevDoc);
   mWyciwygChannel->SetCharsetAndSource(kCharsetFromHintPrevDoc,
                                        GetDocumentCharacterSet());
 
   // Use our new principal
   channel->SetOwner(NodePrincipal());
 
   // Inherit load flags from the original document's channel
   channel->SetLoadFlags(mLoadFlags);
--- a/docshell/build/nsDocShellModule.cpp
+++ b/docshell/build/nsDocShellModule.cpp
@@ -50,17 +50,17 @@
 
 // uriloader
 #include "nsURILoader.h"
 #include "nsDocLoader.h"
 #include "nsOSHelperAppService.h"
 #include "nsExternalProtocolHandler.h"
 #include "nsPrefetchService.h"
 #include "nsOfflineCacheUpdate.h"
-#include "nsHandlerAppImpl.h"
+#include "nsLocalHandlerApp.h"
 
 // session history
 #include "nsSHEntry.h"
 #include "nsSHistory.h"
 #include "nsSHTransaction.h"
 
 // global history
 #include "nsGlobalHistoryAdapter.h"
--- a/dom/public/idl/base/nsIDOMWindowUtils.idl
+++ b/dom/public/idl/base/nsIDOMWindowUtils.idl
@@ -42,17 +42,17 @@
  * to the current nsIDOMWindow.  Some of the methods may require
  * elevated privileges; the method implementations should contain the
  * necessary security checks.  Access this interface by calling
  * getInterface on a DOMWindow.
  */
 
 interface nsIDOMElement;
 
-[scriptable, uuid(1F313394-73AB-41BF-8307-9FC5DA8A481E)]
+[scriptable, uuid(25f55fb2-a6f8-4f7f-93c3-3adafd5166bc)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -65,16 +65,22 @@ interface nsIDOMWindowUtils : nsISupport
    *       have subsequently been individually animated.
    * @note Only images immediately in this window are affected;
    *       this is not recursive to subwindows.
    * @see imgIContainer
    */
   attribute unsigned short imageAnimationMode;
 
   /**
+   * Whether the charset of the window's current document has been forced by
+   * the user
+   */
+  readonly attribute boolean docCharsetIsForced;
+
+  /**
    * Function to get metadata associated with the window's current document
    * @param aName the name of the metadata.  This should be all lowercase.
    * @return the value of the metadata, or the empty string if it's not set
    *
    * Will throw a DOM security error if called without UniversalXPConnect
    * privileges.
    */
   AString getDocumentMetadata(in AString aName);
--- a/dom/src/base/Makefile.in
+++ b/dom/src/base/Makefile.in
@@ -78,16 +78,17 @@ REQUIRES	= xpcom \
 		  find \
 		  appshell \
 		  intl \
 		  unicharutil \
 		  rdf \
 		  xultmpl \
 		  jar \
 		  storage \
+		  htmlparser \
 		  $(NULL)
 
 ifdef NS_TRACE_MALLOC
 REQUIRES	+= tracemalloc
 endif
 
 ifdef MOZ_JSDEBUGGER
 REQUIRES	+= jsdebug
--- a/dom/src/base/nsDOMWindowUtils.cpp
+++ b/dom/src/base/nsDOMWindowUtils.cpp
@@ -47,16 +47,17 @@
 #include "nsIFocusController.h"
 #include "nsIEventStateManager.h"
 
 #include "nsContentUtils.h"
 
 #include "nsIFrame.h"
 #include "nsIWidget.h"
 #include "nsGUIEvent.h"
+#include "nsIParser.h"
 
 #ifdef MOZ_ENABLE_GTK2
 #include <gdk/gdkx.h>
 #endif
 
 NS_INTERFACE_MAP_BEGIN(nsDOMWindowUtils)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMWindowUtils)
   NS_INTERFACE_MAP_ENTRY(nsIDOMWindowUtils)
@@ -108,16 +109,33 @@ nsDOMWindowUtils::SetImageAnimationMode(
         return NS_OK;
       }
     }
   }
   return NS_ERROR_NOT_AVAILABLE;
 }
 
 NS_IMETHODIMP
+nsDOMWindowUtils::GetDocCharsetIsForced(PRBool *aIsForced)
+{
+  *aIsForced = PR_FALSE;
+
+  PRBool hasCap = PR_FALSE;
+  if (NS_FAILED(nsContentUtils::GetSecurityManager()->IsCapabilityEnabled("UniversalXPConnect", &hasCap)) || !hasCap)
+    return NS_ERROR_DOM_SECURITY_ERR;
+
+  if (mWindow) {
+    nsCOMPtr<nsIDocument> doc(do_QueryInterface(mWindow->GetExtantDocument()));
+    *aIsForced = doc &&
+      doc->GetDocumentCharacterSetSource() >= kCharsetFromParentForced;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDOMWindowUtils::GetDocumentMetadata(const nsAString& aName,
                                       nsAString& aValue)
 {
   PRBool hasCap = PR_FALSE;
   if (NS_FAILED(nsContentUtils::GetSecurityManager()->IsCapabilityEnabled("UniversalXPConnect", &hasCap))
       || !hasCap)
     return NS_ERROR_DOM_SECURITY_ERR;
 
--- a/dom/src/base/nsJSEnvironment.cpp
+++ b/dom/src/base/nsJSEnvironment.cpp
@@ -1043,25 +1043,16 @@ nsJSContext::~nsJSContext()
 struct ContextCallbackItem : public JSTracer
 {
   nsCycleCollectionTraversalCallback *cb;
 };
 
 void
 NoteContextChild(JSTracer *trc, void *thing, uint32 kind)
 {
-  if (kind == JSTRACE_ATOM) {
-    JSAtom *atom = (JSAtom *)thing;
-    jsval v = ATOM_KEY(atom);
-    if (!JSVAL_IS_PRIMITIVE(v)) {
-      thing = JSVAL_TO_GCTHING(v);
-      kind = JSTRACE_OBJECT;
-    }
-  }
-
   if (kind == JSTRACE_OBJECT || kind == JSTRACE_NAMESPACE ||
       kind == JSTRACE_QNAME || kind == JSTRACE_XML) {
     ContextCallbackItem *item = static_cast<ContextCallbackItem*>(trc);
     item->cb->NoteScriptChild(JAVASCRIPT, thing);
   }
 }
 
 // QueryInterface implementation for nsJSContext
--- a/editor/libeditor/text/nsEditorEventListeners.cpp
+++ b/editor/libeditor/text/nsEditorEventListeners.cpp
@@ -518,33 +518,37 @@ nsTextEditorDragListener::DragGesture(ns
 
   return rv;
 }
 
 
 nsresult
 nsTextEditorDragListener::DragEnter(nsIDOMEvent* aDragEvent)
 {
+  nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
   if (!mCaret)
   {
-    nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
     if (presShell)
     {
       mCaret = do_CreateInstance("@mozilla.org/layout/caret;1");
       if (mCaret)
       {
         mCaret->Init(presShell);
         mCaret->SetCaretReadOnly(PR_TRUE);
 
         mOtherCaret = presShell->SetCaret(mCaret);
       }
       mCaretDrawn = PR_FALSE;
     }
   }
-  
+  else if (presShell)
+  {
+    presShell->SetCaret(mCaret);
+  }
+
   return DragOver(aDragEvent);
 }
 
 
 nsresult
 nsTextEditorDragListener::DragOver(nsIDOMEvent* aDragEvent)
 {
   // XXX cache this between drag events?
--- a/extensions/inspector/jar.mn
+++ b/extensions/inspector/jar.mn
@@ -63,16 +63,18 @@ inspector.jar:
   content/inspector/prefs/pref-inspector.xul                          (resources/content/prefs/pref-inspector.xul)
   content/inspector/prefs/prefsOverlay.xul                            (resources/content/prefs/prefsOverlay.xul)
   content/inspector/prefs/pref-sidebar.js                             (resources/content/prefs/pref-sidebar.js)
   content/inspector/tests/allskin.xul                                 (resources/content/tests/allskin.xul)
   content/inspector/viewers/accessibleObject/accessibleObject.js      (resources/content/viewers/accessibleObject/accessibleObject.js)
   content/inspector/viewers/accessibleObject/accessibleObject.xul     (resources/content/viewers/accessibleObject/accessibleObject.xul)
   content/inspector/viewers/accessibleProps/accessibleProps.js        (resources/content/viewers/accessibleProps/accessibleProps.js)
   content/inspector/viewers/accessibleProps/accessibleProps.xul       (resources/content/viewers/accessibleProps/accessibleProps.xul)
+  content/inspector/viewers/accessibleTree/accessibleTree.js          (resources/content/viewers/accessibleTree/accessibleTree.js)
+  content/inspector/viewers/accessibleTree/accessibleTree.xul         (resources/content/viewers/accessibleTree/accessibleTree.xul)
   content/inspector/viewers/computedStyle/computedStyle.js            (resources/content/viewers/computedStyle/computedStyle.js)
   content/inspector/viewers/computedStyle/computedStyle.xul           (resources/content/viewers/computedStyle/computedStyle.xul)
   content/inspector/viewers/dom/FindDialog.js                         (resources/content/viewers/dom/FindDialog.js)
   content/inspector/viewers/dom/columnsDialog.js                      (resources/content/viewers/dom/columnsDialog.js)
   content/inspector/viewers/dom/columnsDialog.xul                     (resources/content/viewers/dom/columnsDialog.xul)
   content/inspector/viewers/dom/commandOverlay.xul                    (resources/content/viewers/dom/commandOverlay.xul)
   content/inspector/viewers/dom/insertDialog.js                       (resources/content/viewers/dom/insertDialog.js)
   content/inspector/viewers/dom/insertDialog.xul                      (resources/content/viewers/dom/insertDialog.xul)
--- a/extensions/inspector/resources/content/res/viewer-registry.rdf
+++ b/extensions/inspector/resources/content/res/viewer-registry.rdf
@@ -91,21 +91,24 @@
       ins:filter="return true;"/>
     </rdf:li>
 
     <rdf:li>
       <rdf:Description ins:uid="accessibleObject"
                        ins:panels="bxObjectPanel bxObjPanel"
                        ins:description="Accessible Object">
         <ins:filter><![CDATA[
-          if (!linkedViewer || linkedViewer.uid != "dom" ||
-              !linkedViewer.getAccessibleNodes() ||
+          if (!linkedViewer ||
               !(object instanceof Components.interfaces.nsIDOMNode))
             return false;
 
+          if (linkedViewer.uid != "accessibleTree" &&
+              (linkedViewer.uid != "dom" || !linkedViewer.getAccessibleNodes()))
+            return false;
+
           try {
             var accService =
               Components.classes["@mozilla.org/accessibleRetrieval;1"]
                         .getService(Components.interfaces.nsIAccessibleRetrieval);
 
             return accService.getAttachedAccessibleFor(object);
           } catch(e) {
             return false;
@@ -114,21 +117,45 @@
       </rdf:Description>
     </rdf:li>
 
     <rdf:li>
       <rdf:Description ins:uid="accessibleProps"
                        ins:panels="bxObjectPanel bxObjPanel"
                        ins:description="Accessible Properties">
         <ins:filter><![CDATA[
-          if (!linkedViewer || linkedViewer.uid != "dom" ||
-              !linkedViewer.getAccessibleNodes() ||
+          if (!linkedViewer ||
               !(object instanceof Components.interfaces.nsIDOMNode))
             return false;
 
+          if (linkedViewer.uid != "accessibleTree" &&
+              (linkedViewer.uid != "dom" || !linkedViewer.getAccessibleNodes()))
+            return false;
+
+          try {
+            var accService =
+              Components.classes["@mozilla.org/accessibleRetrieval;1"]
+                        .getService(Components.interfaces.nsIAccessibleRetrieval);
+
+            return accService.getAttachedAccessibleFor(object);
+          } catch(e) {
+            return false;
+          }
+        ]]></ins:filter>
+      </rdf:Description>
+    </rdf:li>
+
+    <rdf:li>
+      <rdf:Description ins:uid="accessibleTree"
+                       ins:panels="bxDocPanel"
+                       ins:description="Accessible Tree">
+        <ins:filter><![CDATA[
+          if (!(object instanceof Components.interfaces.nsIDOMDocument))
+            return false;
+
           try {
             var accService =
               Components.classes["@mozilla.org/accessibleRetrieval;1"]
                         .getService(Components.interfaces.nsIAccessibleRetrieval);
 
             return accService.getAttachedAccessibleFor(object);
           } catch(e) {
             return false;
new file mode 100644
--- /dev/null
+++ b/extensions/inspector/resources/content/viewers/accessibleTree/accessibleTree.js
@@ -0,0 +1,426 @@
+/* ***** 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) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Alexander Surkov <surkov.alexander@gmail.com> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either 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 ***** */
+
+/***************************************************************
+* AccessibleEventsViewer --------------------------------------------
+*  The viewer for the accessible tree of a document.
+* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+* REQUIRED IMPORTS:
+*   chrome://inspector/content/jsutil/xpcom/XPCU.js
+****************************************************************/
+
+///////////////////////////////////////////////////////////////////////////////
+//// Global Variables
+
+var viewer;
+
+///////////////////////////////////////////////////////////////////////////////
+//// Global Constants
+
+const kAccessibleRetrievalCID = "@mozilla.org/accessibleRetrieval;1";
+
+const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+const nsIAccessibleEvent = Components.interfaces.nsIAccessibleEvent;
+const nsIAccessible = Components.interfaces.nsIAccessible;
+const nsIAccessNode = Components.interfaces.nsIAccessNode;
+
+///////////////////////////////////////////////////////////////////////////////
+//// Initialization
+
+window.addEventListener("load", AccessibleTreeViewer_initialize, false);
+
+function AccessibleTreeViewer_initialize()
+{
+  viewer = new AccessibleTreeViewer();
+  viewer.initialize(parent.FrameExchange.receiveData(window));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//// AccessibleEventsViewer
+
+function AccessibleTreeViewer()
+{
+  this.mURL = window.location;
+  this.mObsMan = new ObserverManager(this);
+
+  this.mTree = document.getElementById("olAccessibleTree");
+  this.mOlBox = this.mTree.treeBoxObject;
+}
+
+AccessibleTreeViewer.prototype =
+{
+  //Initialization
+
+  mSubject: null,
+  mPane: null,
+  mView: null,
+
+  // interface inIViewer
+
+  get uid() { return "accessibleTree"; },
+  get pane() { return this.mPane; },
+  get selection() { return this.mSelection; },
+
+  get subject() { return this.mSubject; },
+  set subject(aObject)
+  {
+    this.mView = new inAccTreeView(aObject);
+    this.mOlBox.view = this.mView;
+    this.mObsMan.dispatchEvent("subjectChange", { subject: aObject });
+    this.mView.selection.select(0);
+  },
+
+  initialize: function initialize(aPane)
+  {
+    this.mPane = aPane;
+    aPane.notifyViewerReady(this);
+  },
+
+  destroy: function destroy()
+  {
+    this.mOlBox.view = null;
+  },
+
+  isCommandEnabled: function isCommandEnabled(aCommand)
+  {
+    return false;
+  },
+
+  getCommand: function getCommand(aCommand)
+  {
+    return null;
+  },
+
+  // event dispatching
+
+  addObserver: function addObserver(aEvent, aObserver)
+  {
+    this.mObsMan.addObserver(aEvent, aObserver);
+  },
+  removeObserver: function removeObserver(aEvent, aObserver)
+  {
+    this.mObsMan.removeObserver(aEvent, aObserver);
+  },
+
+  // stuff
+
+  onItemSelected: function onItemSelected()
+  {
+    var idx = this.mTree.currentIndex;
+    this.mSelection = this.mView.getDOMNode(idx);
+    this.mObsMan.dispatchEvent("selectionChange",
+                               { selection: this.mSelection } );
+  }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//// inAccTreeView
+
+function inAccTreeView(aDocument)
+{
+  this.mNodes = [];
+
+  this.mAccService = XPCU.getService(kAccessibleRetrievalCID,
+                                     nsIAccessibleRetrieval);
+
+  this.mDocument = aDocument;
+  this.mAccDocument = this.mAccService.getAccessibleFor(aDocument);
+
+  var node = this.createNode(this.mAccDocument);
+  this.mNodes.push(node);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//// inAccTreeView. nsITreeView interface
+
+inAccTreeView.prototype = new inBaseTreeView();
+
+inAccTreeView.prototype.__defineGetter__("rowCount",
+function rowCount()
+{
+  return this.mNodes.length;
+});
+
+inAccTreeView.prototype.getCellText =
+function getCellText(aRow, aCol)
+{
+  var node = this.rowToNode(aRow);
+  if (!node)
+    return "";
+
+  var accessible = node.accessible;
+
+  if (aCol.id == "olcRole")
+    return this.mAccService.getStringRole(accessible.finalRole);
+
+  if (aCol.id == "olcName")
+    return accessible.name;
+
+  if (aCol.id == "olcNodeName") {
+    var node = this.getDOMNodeFor(accessible);
+    return node ? node.nodeName : "";
+  }
+
+  return "";
+}
+
+inAccTreeView.prototype.isContainer =
+function isContainer(aRow)
+{
+  var node = this.rowToNode(aRow);
+  return node ? node.isContainer : false;
+}
+
+inAccTreeView.prototype.isContainerOpen =
+function isContainerOpen(aRow)
+{
+  var node = this.rowToNode(aRow);
+  return node ? node.isOpen : false;
+}
+
+inAccTreeView.prototype.isContainerEmpty =
+function isContainerEmpty(aRow)
+{
+  return !this.isContainer(aRow);
+}
+
+inAccTreeView.prototype.getLevel =
+function getLevel(aRow)
+{
+  var node = this.rowToNode(aRow);
+  return node ? node.level : 0;
+}
+
+inAccTreeView.prototype.getParentIndex =
+function getParentIndex(aRow)
+{
+  var node = this.rowToNode(aRow);
+  if (!node)
+    return -1;
+
+  var checkNode = null;
+  var i = aRow - 1;
+  do {
+    checkNode = this.rowToNode(i);
+    if (!checkNode)
+      return -1;
+
+    if (checkNode == node.parent)
+      return i;
+    --i;
+  } while (checkNode);
+
+  return -1;
+}
+
+inAccTreeView.prototype.hasNextSibling =
+function hasNextSibling(aRow, aAfterRow)
+{
+  var node = this.rowToNode(aRow);
+  return node && (node.next != null);
+}
+
+inAccTreeView.prototype.toggleOpenState =
+function toggleOpenState(aRow)
+{
+  var node = this.rowToNode(aRow);
+  if (!node)
+    return;
+
+  var oldCount = this.rowCount;
+  if (node.isOpen)
+    this.collapseNode(aRow);
+  else
+    this.expandNode(aRow);
+
+  this.mTree.invalidateRow(aRow);
+  this.mTree.rowCountChanged(aRow + 1, this.rowCount - oldCount);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//// inAccTreeView. Tree utils.
+
+/**
+ * Expands a tree node on the given row.
+ *
+ * @param aRow - row index.
+ */
+inAccTreeView.prototype.expandNode =
+function expandNode(aRow)
+{
+  var node = this.rowToNode(aRow);
+  if (!node)
+    return;
+
+  var kids = node.accessible.children;
+  var kidCount = kids.length;
+
+  var newNode = null;
+  var prevNode = null;
+
+  for (var i = 0; i < kidCount; ++i) {
+    var accessible = kids.queryElementAt(i, nsIAccessible);
+    newNode = this.createNode(accessible, node);
+    this.mNodes.splice(aRow + i + 1, 0, newNode);
+
+    if (prevNode)
+      prevNode.next = newNode;
+    newNode.previous = prevNode;
+    prevNode = newNode;
+  }
+
+  node.isOpen = true;
+}
+
+/**
+ * Collapse a tree node on the given row.
+ *
+ * @param aRow - row index.
+ */
+inAccTreeView.prototype.collapseNode =
+function collapseNode(aRow)
+{
+  var node = this.rowToNode(aRow);
+  if (!node)
+    return;
+
+  var row = this.getLastDescendantOf(node, aRow);
+  this.mNodes.splice(aRow + 1, row - aRow);
+
+  node.isOpen = false;
+}
+
+/**
+ * Create a tree node.
+ *
+ * @param aAccessible - an accessible object associated with created tree node.
+ * @param aParent - parent tree node for the created tree node.
+ * @retrurn - tree node object for the given accesible.
+ */
+inAccTreeView.prototype.createNode =
+function createNode(aAccessible, aParent)
+{
+  var node = new inAccTreeViewNode(aAccessible);
+  node.level = aParent ? aParent.level + 1 : 0;
+  node.parent = aParent;
+  node.isContainer = aAccessible.children.length > 0;
+
+  return node;
+}
+
+/**
+ * Return row index of the last node that is a descendant of the given node.
+ * If there is no required node then return the given row.
+ *
+ * @param aNode - tree node for that last descedant is searched.
+ * @param aRow - row index of the given tree node.
+ */
+inAccTreeView.prototype.getLastDescendantOf =
+function getLastDescendantOf(aNode, aRow)
+{
+  var rowCount = this.rowCount;
+
+  var row = aRow + 1;
+  for (; row < rowCount; ++row) {
+    if (this.mNodes[row].level <= aNode.level)
+      return row - 1;
+  }
+
+  return rowCount - 1;
+}
+
+/**
+ * Return a tree node by the given row.
+ *
+ * @param aRow - row index.
+ */
+inAccTreeView.prototype.rowToNode =
+function rowToNode(aRow)
+{
+  if (aRow < 0 || aRow >= this.rowCount)
+    return null;
+
+  return this.mNodes[aRow];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//// inAccTreeView. Accessibility utils.
+
+/**
+ * Return DOM node for the given accessible.
+ *
+ * @param aAccessible - an accessible object.
+ */
+inAccTreeView.prototype.getDOMNodeFor =
+function getDOMNodeFor(aAccessible)
+{
+  var accessNode = XPCU.QI(aAccessible, nsIAccessNode);
+  return accessNode.DOMNode;
+}
+
+/**
+ * Return DOM node for an accessible of the tree node pointed by the given
+ * row index.
+ *
+ * @param aRow - row index.
+ */
+inAccTreeView.prototype.getDOMNode =
+function getDOMNode(aRow)
+{
+  var node = this.mNodes[aRow];
+  if (!node)
+    return null;
+
+  return this.getDOMNodeFor(node.accessible);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//// inAccTreeViewNode
+
+function inAccTreeViewNode(aAccessible)
+{
+  this.accessible = aAccessible;
+
+  this.parent = null;
+  this.next = null;
+  this.previous = null;
+
+  this.level = 0;
+  this.isOpen = false;
+  this.isContainer = false;
+}
+
new file mode 100644
--- /dev/null
+++ b/extensions/inspector/resources/content/viewers/accessibleTree/accessibleTree.xul
@@ -0,0 +1,84 @@
+<?xml version="1.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 DOM Inspector.
+   -
+   - 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):
+   -  Alexander Surkov <surkov.alexander@gmail.com> (original author)
+   -
+   - 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 ***** -->
+
+<!DOCTYPE page [
+  <!ENTITY % dtd1 SYSTEM "chrome://inspector/locale/inspector.dtd"> %dtd1;
+  <!ENTITY % dtd2 SYSTEM "chrome://inspector/content/util.dtd"> %dtd2;
+  <!ENTITY % dtd3 SYSTEM "chrome://inspector/locale/viewers/accessibleTree.dtd"> %dtd3;
+]>
+
+<?xml-stylesheet href="chrome://inspector/skin/"?>
+
+<page id="winAccessibleTree"
+      xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/javascript"
+          src="chrome://inspector/content/jsutil/xul/inBaseTreeView.js"/>
+  <script type="application/javascript"
+          src="chrome://inspector/content/jsutil/xpcom/XPCU.js"/>
+  <script type="application/javascript"
+          src="chrome://inspector/content/jsutil/events/ObserverManager.js"/>
+  <script type="application/javascript"
+          src="chrome://inspector/content/viewers/accessibleTree/accessibleTree.js"/>
+
+  <tree id="olAccessibleTree" class="plain" flex="1"
+        onselect="viewer.onItemSelected()">
+    <treecols>
+      <treecol id="olcRole"
+               label="&role.label;"
+               persist="width,hidden,ordinal"
+               primary="true"
+               flex="1"/>
+      <splitter class="tree-splitter"/>
+      <treecol id="olcName"
+               label="&name.label;"
+               persist="width,hidden,ordinal"
+               flex="1"/>
+      <splitter class="tree-splitter"/>
+      <treecol id="olcNodeName"
+               label="&nodeName.label;"
+               persist="width,hidden,ordinal"
+               flex="1"/>
+    </treecols>
+    <treechildren id="olbAccessibleTree"
+                  alternatingbackground="true"/>
+  </tree>
+
+</page>
+
new file mode 100644
--- /dev/null
+++ b/extensions/inspector/resources/locale/en-US/viewers/accessibleTree.dtd
@@ -0,0 +1,43 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+#if 0
+   - 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 DOM Inspector.
+   -
+   - 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):
+   -   Alexander Surkov <surkov.alexander@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 LGPL or the GPL. 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.
+   -
+#endif
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY role.label "Role">
+<!ENTITY name.label "Name">
+<!ENTITY nodeName.label "Node Name">
+
new file mode 100644
--- /dev/null
+++ b/extensions/inspector/resources/locale/fr/viewers/accessibleTree.dtd
@@ -0,0 +1,43 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+#if 0
+   - 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 DOM Inspector.
+   -
+   - 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):
+   -   Alexander Surkov <surkov.alexander@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 LGPL or the GPL. 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.
+   -
+#endif
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY role.label "Role">
+<!ENTITY name.label "Name">
+<!ENTITY nodeName.label "Node Name">
+
--- a/extensions/inspector/resources/locale/jar.mn
+++ b/extensions/inspector/resources/locale/jar.mn
@@ -3,16 +3,17 @@
 inspector.jar:
 % locale inspector @AB_CD@ %locale/@AB_CD@/inspector/
 * locale/@AB_CD@/inspector/contents.rdf                 (contents.rdf)
   locale/@AB_CD@/inspector/inspector.dtd                (@AB_CD@/inspector.dtd)
   locale/@AB_CD@/inspector/prefs.dtd                    (@AB_CD@/prefs.dtd)
   locale/@AB_CD@/inspector/editing.dtd                  (@AB_CD@/editing.dtd)
   locale/@AB_CD@/inspector/tasksOverlay.dtd             (@AB_CD@/tasksOverlay.dtd)
 * locale/@AB_CD@/inspector/viewers/accessibleProps.dtd  (@AB_CD@/viewers/accessibleProps.dtd)
+* locale/@AB_CD@/inspector/viewers/accessibleTree.dtd   (@AB_CD@/viewers/accessibleTree.dtd)
 * locale/@AB_CD@/inspector/viewers/dom.dtd              (@AB_CD@/viewers/dom.dtd)
 * locale/@AB_CD@/inspector/viewers/domNode.dtd          (@AB_CD@/viewers/domNode.dtd)
 * locale/@AB_CD@/inspector/viewers/styleRules.dtd       (@AB_CD@/viewers/styleRules.dtd)
 * locale/@AB_CD@/inspector/viewers/stylesheets.dtd      (@AB_CD@/viewers/stylesheets.dtd)
 * locale/@AB_CD@/inspector/viewers/xblBindings.dtd      (@AB_CD@/viewers/xblBindings.dtd)
 * locale/@AB_CD@/inspector/viewers/boxModel.dtd         (@AB_CD@/viewers/boxModel.dtd)
 * locale/@AB_CD@/inspector/viewers/computedStyle.dtd    (@AB_CD@/viewers/computedStyle.dtd)
 * locale/@AB_CD@/inspector/viewers/jsObject.dtd         (@AB_CD@/viewers/jsObject.dtd)
new file mode 100644
--- /dev/null
+++ b/extensions/inspector/resources/locale/nb-NO/viewers/accessibleTree.dtd
@@ -0,0 +1,43 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+#if 0
+   - 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 DOM Inspector.
+   -
+   - 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):
+   -   Alexander Surkov <surkov.alexander@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 LGPL or the GPL. 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.
+   -
+#endif
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY role.label "Role">
+<!ENTITY name.label "Name">
+<!ENTITY nodeName.label "Node Name">
+
new file mode 100644
--- /dev/null
+++ b/extensions/inspector/resources/locale/pl/viewers/accessibleTree.dtd
@@ -0,0 +1,44 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+#if 0
+   - 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 DOM Inspector.
+   -
+   - 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):
+   -   Alexander Surkov <surkov.alexander@gmail.com>
+   -   Marek Stępień <mstepien@aviary.pl>
+   -
+   - 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 LGPL or the GPL. 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.
+   -
+#endif
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY role.label "Rola">
+<!ENTITY name.label "Nazwa">
+<!ENTITY nodeName.label "Nazwa węzła">
+
new file mode 100644
--- /dev/null
+++ b/extensions/inspector/resources/locale/ru/viewers/accessibleTree.dtd
@@ -0,0 +1,43 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+#if 0
+   - 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 DOM Inspector.
+   -
+   - 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):
+   -   Alexander Surkov <surkov.alexander@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 LGPL or the GPL. 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.
+   -
+#endif
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY role.label "Роль">
+<!ENTITY name.label "Имя">
+<!ENTITY nodeName.label "Имя узла">
+
--- a/gfx/cairo/cairo/src/cairo-malloc-private.h
+++ b/gfx/cairo/cairo/src/cairo-malloc-private.h
@@ -35,70 +35,85 @@
  */
 
 #ifndef CAIRO_MALLOC_PRIVATE_H
 #define CAIRO_MALLOC_PRIVATE_H
 
 #include "cairo-wideint-private.h"
 
 /**
+ * _cairo_malloc:
+ * @size: size in bytes
+ *
+ * Allocate @size memory using malloc().
+ * The memory should be freed using free().
+ * malloc is skipped, if 0 bytes are requested, and %NULL will be returned.
+ *
+ * Return value: A pointer to the newly allocated memory, or %NULL in
+ * case of malloc() failure or size is 0.
+ */
+
+#define _cairo_malloc(size) \
+   ((size) ? malloc((unsigned) (size)) : NULL)
+
+/**
  * _cairo_malloc_ab:
  * @n: number of elements to allocate
  * @size: size of each element
  *
- * Allocates @a*@size memory using malloc(), taking care to not
+ * Allocates @a*@size memory using _cairo_malloc(), taking care to not
  * overflow when doing the multiplication.  Behaves much like
  * calloc(), except that the returned memory is not set to zero.
  * The memory should be freed using free().
  *
  * @size should be a constant so that the compiler can optimize
  * out a constant division.
  *
  * Return value: A pointer to the newly allocated memory, or %NULL in
  * case of malloc() failure or overflow.
  */
 
 #define _cairo_malloc_ab(a, size) \
-  ((unsigned) (a) >= INT32_MAX / (unsigned) (size) ? NULL : \
-   malloc((unsigned) (a) * (unsigned) (size)))
+  ((size) && (unsigned) (a) >= INT32_MAX / (unsigned) (size) ? NULL : \
+   _cairo_malloc((unsigned) (a) * (unsigned) (size)))
 
 /**
  * _cairo_malloc_abc:
  * @a: first factor of number of elements to allocate
  * @b: second factor of number of elements to allocate
  * @size: size of each element
  *
- * Allocates @a*@b*@size memory using malloc(), taking care to not
+ * Allocates @a*@b*@size memory using _cairo_malloc(), taking care to not
  * overflow when doing the multiplication.  Behaves like
  * _cairo_malloc_ab().  The memory should be freed using free().
  *
  * @size should be a constant so that the compiler can optimize
  * out a constant division.
  *
  * Return value: A pointer to the newly allocated memory, or %NULL in
  * case of malloc() failure or overflow.
  */
 
 #define _cairo_malloc_abc(a, b, size) \
-  ((unsigned) (a) >= INT32_MAX / (unsigned) (b) ? NULL : \
-   (unsigned) ((a)*(b)) >= INT32_MAX / (unsigned) (size) ? NULL : \
-   malloc((unsigned) (a) * (unsigned) (b) * (unsigned) size))
+  ((b) && (unsigned) (a) >= INT32_MAX / (unsigned) (b) ? NULL : \
+   (size) && (unsigned) ((a)*(b)) >= INT32_MAX / (unsigned) (size) ? NULL : \
+   _cairo_malloc((unsigned) (a) * (unsigned) (b) * (unsigned) (size)))
 
 /**
  * _cairo_malloc_ab_plus_c:
  * @n: number of elements to allocate
  * @size: size of each element
  * @k: additional size to allocate
  *
- * Allocates @a*@ksize+@k memory using malloc(), taking care to not
+ * Allocates @a*@ksize+@k memory using _cairo_malloc(), taking care to not
  * overflow when doing the arithmetic.  Behaves like
  * _cairo_malloc_ab().  The memory should be freed using free().
  *
  * Return value: A pointer to the newly allocated memory, or %NULL in
  * case of malloc() failure or overflow.
  */
 
 #define _cairo_malloc_ab_plus_c(n, size, k) \
-  ((unsigned) (n) >= INT32_MAX / (unsigned) (size) ? NULL : \
+  ((size) && (unsigned) (n) >= INT32_MAX / (unsigned) (size) ? NULL : \
    (unsigned) (k) >= INT32_MAX - (unsigned) (n) * (unsigned) (size) ? NULL : \
-   malloc((unsigned) (n) * (unsigned) (size) + (unsigned) (k)))
+   _cairo_malloc((unsigned) (n) * (unsigned) (size) + (unsigned) (k)))
 
 #endif /* CAIRO_MALLOC_PRIVATE_H */
--- a/gfx/src/thebes/nsSystemFontsMac.cpp
+++ b/gfx/src/thebes/nsSystemFontsMac.cpp
@@ -138,17 +138,17 @@ nsSystemFontsMac::GetSystemFont(nsSystem
         //case eSystemFont_Document:    = 'sans-serif'
         case eSystemFont_Workspace:     fontID = kThemeViewsFont;          break;
         case eSystemFont_Desktop:       fontID = kThemeViewsFont;          break;
         case eSystemFont_Info:          fontID = kThemeViewsFont;          break;
         case eSystemFont_Dialog:        fontID = kThemeSystemFont;         break;
         case eSystemFont_Button:        fontID = kThemeSmallSystemFont;    break;
         case eSystemFont_PullDownMenu:  fontID = kThemeMenuItemFont;       break;
         case eSystemFont_List:          fontID = kThemeSmallSystemFont;    break;
-        case eSystemFont_Field:         fontID = kThemeApplicationFont;    break;
+        case eSystemFont_Field:         fontID = kThemeSmallSystemFont;    break;
         // moz
         case eSystemFont_Tooltips:      fontID = kThemeSmallSystemFont;    break;
         case eSystemFont_Widget:        fontID = kThemeSmallSystemFont;    break;
         default:
             // should never hit this
             return NS_ERROR_FAILURE;
     }
 
--- a/gfx/thebes/src/gfxFont.cpp
+++ b/gfx/thebes/src/gfxFont.cpp
@@ -342,17 +342,19 @@ gfxFont::Measure(gfxTextRun *aTextRun,
             floatAdvance += aSpacing[i].mBefore + aSpacing[i].mAfter;
         }
     }
     RunMetrics metrics;
     const gfxFont::Metrics& fontMetrics = GetMetrics();
     metrics.mAdvanceWidth = floatAdvance;
     const PRUint32 appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
     metrics.mAscent = fontMetrics.maxAscent*appUnitsPerDevUnit;
-    metrics.mDescent = fontMetrics.maxDescent*appUnitsPerDevUnit;
+    gfxFloat descentForUnderline =
+        NS_round(fontMetrics.underlineSize) + NS_round(metrics.mAscent - fontMetrics.underlineOffset) - metrics.mAscent;
+    metrics.mDescent = PR_MAX(fontMetrics.maxDescent, descentForUnderline)*appUnitsPerDevUnit;
     metrics.mBoundingBox =
         gfxRect(0, -metrics.mAscent, floatAdvance, metrics.mAscent + metrics.mDescent);
     return metrics;
 }
 
 gfxFontGroup::gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle)
     : mFamilies(aFamilies), mStyle(*aStyle)
 {
--- a/gfx/thebes/src/gfxWindowsFonts.cpp
+++ b/gfx/thebes/src/gfxWindowsFonts.cpp
@@ -75,21 +75,24 @@
 #include "prlog.h"
 static PRLogModuleInfo *gFontLog = PR_NewLogModule("winfonts");
 
 #define ROUND(x) floor((x) + 0.5)
 
 
 struct DCFromContext {
     DCFromContext(gfxContext *aContext) {
+        dc = NULL;
         nsRefPtr<gfxASurface> aSurface = aContext->CurrentSurface();
-        if (aSurface->GetType() == gfxASurface::SurfaceTypeWin32) {
+        NS_ASSERTION(aSurface, "DCFromContext: null surface");
+        if (aSurface && aSurface->GetType() == gfxASurface::SurfaceTypeWin32) {
             dc = static_cast<gfxWindowsSurface*>(aSurface.get())->GetDC();
             needsRelease = PR_FALSE;
-        } else {
+        }
+        if (!dc) {
             dc = GetDC(NULL);
             needsRelease = PR_TRUE;
         }
     }
 
     ~DCFromContext() {
         if (needsRelease)
             ReleaseDC(NULL, dc);
--- a/intl/build/Makefile.in
+++ b/intl/build/Makefile.in
@@ -111,8 +111,11 @@ CXXFLAGS	+= \
 		$(MOZ_PANGO_CFLAGS) \
 		$(NULL)
 
 EXTRA_DSO_LDOPTS += \
 		$(MOZ_PANGO_LIBS) \
 		$(NULL)
 endif
 
+ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
+OS_LIBS += $(call EXPAND_LIBNAME,usp10)
+endif
--- a/intl/locale/src/nsLocaleService.cpp
+++ b/intl/locale/src/nsLocaleService.cpp
@@ -294,31 +294,36 @@ nsLocaleService::~nsLocaleService(void)
 {
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsLocaleService, nsILocaleService)
 
 NS_IMETHODIMP
 nsLocaleService::NewLocale(const nsAString &aLocale, nsILocale **_retval)
 {
-	int		i;
-	nsresult result;
+    nsresult result;
 
-	*_retval = (nsILocale*)nsnull;
-	
-	nsLocale* resultLocale = new nsLocale();
-	if (!resultLocale) return NS_ERROR_OUT_OF_MEMORY;
+    *_retval = nsnull;
+
+    nsLocale* resultLocale = new nsLocale();
+    if (!resultLocale) return NS_ERROR_OUT_OF_MEMORY;
 
-	for(i=0;i<LocaleListLength;i++) {
-		nsString category; category.AssignWithConversion(LocaleList[i]);
-		result = resultLocale->AddCategory(category, aLocale);
-		if (NS_FAILED(result)) { delete resultLocale; return result;}
-	}
+    for (PRInt32 i = 0; i < LocaleListLength; i++) {
+      nsString category; category.AssignWithConversion(LocaleList[i]);
+      result = resultLocale->AddCategory(category, aLocale);
+      if (NS_FAILED(result)) { delete resultLocale; return result;}
+#if (defined(XP_UNIX) && !defined(XP_MACOSX)) || defined(XP_BEOS)
+      category.AppendLiteral("##PLATFORM");
+      result = resultLocale->AddCategory(category, aLocale);
+      if (NS_FAILED(result)) { delete resultLocale; return result;}
+#endif
+    }
 
-	return resultLocale->QueryInterface(NS_GET_IID(nsILocale),(void**)_retval);
+    NS_ADDREF(*_retval = resultLocale);
+    return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsLocaleService::GetSystemLocale(nsILocale **_retval)
 {
 	if (mSystemLocale) {
 		NS_ADDREF(*_retval = mSystemLocale);
--- a/intl/lwbrk/src/Makefile.in
+++ b/intl/lwbrk/src/Makefile.in
@@ -58,27 +58,38 @@ CPPSRCS		= \
 		nsSemanticUnitScanner.cpp \
 		$(NULL)
 
 ifdef MOZ_ENABLE_PANGO
 CPPSRCS		+= \
 		nsPangoBreaker.cpp \
 		$(NULL)
 else
+ifeq  ($(MOZ_WIDGET_TOOLKIT),windows)
 CPPSRCS		+= \
-		nsRuleBreaker.cpp \
+		nsUniscribeBreaker.cpp \
+		$(NULL)
+else
+ifeq ($(MOZ_WIDGET_TOOLKIT), cocoa)
+CPPSRCS		+= \
+		nsCarbonBreaker.cpp \
+		$(NULL)
+else
+CPPSRCS		+= \
+	nsRuleBreaker.cpp \
 		$(NULL)
 
 CSRCS		= rulebrk.c
 endif
+endif
+endif
 
 include $(topsrcdir)/config/rules.mk
 
 ifdef MOZ_ENABLE_PANGO
 CXXFLAGS	+= \
 		$(MOZ_PANGO_CFLAGS) \
 		$(NULL)
 
 EXTRA_DSO_LDOPTS += \
 		$(MOZ_PANGO_LIBS) \
 		$(NULL)
 endif
-
new file mode 100755
--- /dev/null
+++ b/intl/lwbrk/src/nsCarbonBreaker.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; 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 mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Vee Satayamas <vsatayamas@gmail.com>
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * - Vee Satayamas <vsatayamas@gmail.com>
+ * - Patipat Susumpow <kengggg@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsComplexBreaker.h"
+#include <Carbon/Carbon.h>
+
+void
+NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
+                        PRPackedBool* aBreakBefore)
+{
+  NS_ASSERTION(aText, "aText shouldn't be null");
+  TextBreakLocatorRef breakLocator;
+
+  memset(aBreakBefore, PR_FALSE, aLength * sizeof(PRPackedBool));
+
+  OSStatus status = UCCreateTextBreakLocator(NULL, 0, kUCTextBreakLineMask, &breakLocator);
+
+  if (status != noErr)
+    return;
+     
+  for (UniCharArrayOffset position = 0; position < aLength;) {
+    UniCharArrayOffset offset;
+    status = UCFindTextBreak(breakLocator, 
+                  kUCTextBreakLineMask, 
+                  position == 0 ? kUCTextBreakLeadingEdgeMask : 
+                                  (kUCTextBreakLeadingEdgeMask | 
+                                   kUCTextBreakIterateMask),
+                  aText, 
+                  aLength, 
+                  position, 
+                  &offset);
+    if (status != noErr)
+      break;        
+    aBreakBefore[offset] = PR_TRUE;
+    position = offset;
+  }
+  UCDisposeTextBreakLocator(&breakLocator);
+}
new file mode 100755
--- /dev/null
+++ b/intl/lwbrk/src/nsUniscribeBreaker.cpp
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; 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 mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Pattara Kiatisevi <ott@linux.thai.net>.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * - Nattachai Ungsriwong <nattachai@gmail.com>
+ * - Theppitak Karoonboonyanan <thep@linux.thai.net>
+ * - Vee Satayamas <vsatayamas@gmail.com> 
+ * - Pattara Kiatisevi <ott@linux.thai.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsComplexBreaker.h"
+
+#include <Usp10.h>
+#include "nsUTF8Utils.h"
+#include "nsString.h"
+#include "nsTArray.h"
+
+void
+NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
+                        PRPackedBool* aBreakBefore)
+{
+  NS_ASSERTION(aText, "aText shouldn't be null"); 
+  int outItems = 0;
+  HRESULT result;
+  nsAutoTArray<SCRIPT_ITEM, 64> items;
+
+  memset(aBreakBefore, PR_FALSE, aLength);
+
+  if (!items.AppendElements(64))
+    return;
+
+  do {
+    result = ScriptItemize(aText, aLength, items.Length(), NULL, NULL, items.Elements(), &outItems);
+
+    if (result == E_OUTOFMEMORY) {
+      if (!items.AppendElements(items.Length()))
+        return;
+    }
+  } while (result == E_OUTOFMEMORY);
+
+  for (int iItem = 0; iItem < outItems; ++iItem)  {
+    PRUint32 endOffset = (iItem + 1 == outItems ? aLength : items[iItem + 1].iCharPos);
+    PRUint32 startOffset = items[iItem].iCharPos;
+    nsAutoTArray<SCRIPT_LOGATTR, 64> sla;
+    
+    if (!sla.AppendElements(endOffset - startOffset))
+      return;
+
+    if (ScriptBreak(aText, aLength, &items[iItem].a, sla.Elements()) < 0) 
+      return;
+
+    for (PRUint32 j=0; j+startOffset < endOffset; ++j) {
+       aBreakBefore[j+startOffset] = sla[j].fSoftBreak;
+    }
+  }
+  
+}
--- a/js/src/js.cpp
+++ b/js/src/js.cpp
@@ -961,19 +961,19 @@ UpdateSwitchTableBounds(JSScript *script
 
 static void
 SrcNotes(JSContext *cx, JSScript *script)
 {
     uintN offset, delta, caseOff, switchTableStart, switchTableEnd;
     jssrcnote *notes, *sn;
     JSSrcNoteType type;
     const char *name;
-    jsatomid atomIndex;
     uint32 index;
     JSAtom *atom;
+    JSString *str;
 
     fprintf(gOutFile, "\nSource notes:\n");
     offset = 0;
     notes = SCRIPT_NOTES(script);
     switchTableEnd = switchTableStart = 0;
     for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
         delta = SN_DELTA(sn);
         offset += delta;
@@ -1010,30 +1010,29 @@ SrcNotes(JSContext *cx, JSScript *script
           case SRC_PCDELTA:
           case SRC_DECL:
           case SRC_BRACE:
             fprintf(gOutFile, " offset %u", (uintN) js_GetSrcNoteOffset(sn, 0));
             break;
           case SRC_LABEL:
           case SRC_LABELBRACE:
           case SRC_BREAK2LABEL:
-          case SRC_CONT2LABEL: {
-            const char *bytes;
-
-            atomIndex = (jsatomid) js_GetSrcNoteOffset(sn, 0);
-            JS_GET_SCRIPT_ATOM(script, atomIndex, atom);
-            bytes = js_AtomToPrintableString(cx, atom);
-            fprintf(gOutFile, " atom %u (%s)", (uintN)atomIndex, bytes);
+          case SRC_CONT2LABEL:
+            index = js_GetSrcNoteOffset(sn, 0);
+            JS_GET_SCRIPT_ATOM(script, index, atom);
+            JS_ASSERT(ATOM_IS_STRING(atom));
+            str = ATOM_TO_STRING(atom);
+            fprintf(gOutFile, " atom %u (", index);
+            js_FileEscapedString(gOutFile, str, 0);
+            putc(')', gOutFile);
             break;
-          }
           case SRC_FUNCDEF: {
             const char *bytes;
             JSObject *obj;
             JSFunction *fun;
-            JSString *str;
 
             index = js_GetSrcNoteOffset(sn, 0);
             JS_GET_SCRIPT_OBJECT(script, index, obj);
             fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
             str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
             bytes = str ? JS_GetStringBytes(str) : "N/A";
             fprintf(gOutFile, " function %u (%s)", index, bytes);
             break;
@@ -1268,33 +1267,45 @@ Tracing(JSContext *cx, JSObject *obj, ui
 }
 
 static void
 DumpScope(JSContext *cx, JSObject *obj, FILE *fp)
 {
     uintN i;
     JSScope *scope;
     JSScopeProperty *sprop;
+    jsval v;
+    JSString *str;
 
     i = 0;
     scope = OBJ_SCOPE(obj);
     for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
         if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
             continue;
-        fprintf(fp, "%3u %p", i, (void *)sprop);
+        fprintf(fp, "%3u %p ", i, (void *)sprop);
+
+        v = ID_TO_VALUE(sprop->id);
         if (JSID_IS_INT(sprop->id)) {
-            fprintf(fp, " [%ld]", (long)JSVAL_TO_INT(sprop->id));
-        } else if (JSID_IS_ATOM(sprop->id)) {
-            JSAtom *atom = JSID_TO_ATOM(sprop->id);
-            fprintf(fp, " \"%s\"", js_AtomToPrintableString(cx, atom));
+            fprintf(fp, "[%ld]", (long)JSVAL_TO_INT(v));
         } else {
-            jsval v = OBJECT_TO_JSVAL(JSID_TO_OBJECT(sprop->id));
-            fprintf(fp, " \"%s\"", js_ValueToPrintableString(cx, v));
+            if (JSID_IS_ATOM(sprop->id)) {
+                str = JSVAL_TO_STRING(v);
+            } else if (JSID_IS_HIDDEN(sprop->id)) {
+                str = JSVAL_TO_STRING(v);
+                fputs("hidden ", fp);
+            } else {
+                JS_ASSERT(JSID_IS_OBJECT(sprop->id));
+                str = js_ValueToString(cx, v);
+                fputs("object ", fp);
+            }
+            if (!str)
+                fputs("<error>", fp);
+            else
+                js_FileEscapedString(fp, str, '"');
         }
-
 #define DUMP_ATTR(name) if (sprop->attrs & JSPROP_##name) fputs(" " #name, fp)
         DUMP_ATTR(ENUMERATE);
         DUMP_ATTR(READONLY);
         DUMP_ATTR(PERMANENT);
         DUMP_ATTR(EXPORTED);
         DUMP_ATTR(GETTER);
         DUMP_ATTR(SETTER);
 #undef  DUMP_ATTR
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1435,20 +1435,22 @@ JS_ResolveStandardClass(JSContext *cx, J
     JSRuntime *rt;
     JSAtom *atom;
     JSStdName *stdnm;
     uintN i;
 
     CHECK_REQUEST(cx);
     *resolved = JS_FALSE;
 
-    if (!JSVAL_IS_STRING(id))
+    rt = cx->runtime;
+    JS_ASSERT(rt->state != JSRTS_DOWN);
+    if (rt->state == JSRTS_LANDING || !JSVAL_IS_STRING(id))
         return JS_TRUE;
+
     idstr = JSVAL_TO_STRING(id);
-    rt = cx->runtime;
 
     /* Check whether we're resolving 'undefined', and define it if so. */
     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
     if (idstr == ATOM_TO_STRING(atom)) {
         *resolved = JS_TRUE;
         return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
                                    NULL, NULL, JSPROP_PERMANENT, NULL);
     }
@@ -1959,20 +1961,16 @@ JS_PrintTraceThingInfo(char *buf, size_t
       case JSTRACE_DOUBLE:
         name = "double";
         break;
 
       case JSTRACE_FUNCTION:
         name = "function";
         break;
 
-      case JSTRACE_ATOM:
-        name = "atom";
-        break;
-
 #if JS_HAS_XML_SUPPORT
       case JSTRACE_NAMESPACE:
         name = "namespace";
         break;
 
       case JSTRACE_QNAME:
         name = "qname";
         break;
@@ -2023,48 +2021,35 @@ JS_PrintTraceThingInfo(char *buf, size_t
           {
             JSFunction *fun = (JSFunction *)thing;
 
             if (fun->atom && ATOM_IS_STRING(fun->atom))
                 js_PutEscapedString(buf, bufsize, ATOM_TO_STRING(fun->atom), 0);
             break;
           }
 
-          case JSTRACE_ATOM:
-          {
-            JSAtom *atom = (JSAtom *)thing;
-
-            if (ATOM_IS_INT(atom))
-                JS_snprintf(buf, bufsize, "%d", ATOM_TO_INT(atom));
-            else if (ATOM_IS_STRING(atom))
-                js_PutEscapedString(buf, bufsize, ATOM_TO_STRING(atom), 0);
-            else
-                JS_snprintf(buf, bufsize, "object");
-            break;
-          }
-
 #if JS_HAS_XML_SUPPORT
-          case GCX_NAMESPACE:
+          case JSTRACE_NAMESPACE:
           {
             JSXMLNamespace *ns = (JSXMLNamespace *)thing;
 
             if (ns->prefix) {
                 n = js_PutEscapedString(buf, bufsize, ns->prefix, 0);
                 buf += n;
                 bufsize -= n;
             }
             if (bufsize > 2) {
                 *buf++ = ':';
                 bufsize--;
                 js_PutEscapedString(buf, bufsize, ns->uri, 0);
             }
             break;
           }
 
-          case GCX_QNAME:
+          case JSTRACE_QNAME:
           {
             JSXMLQName *qn = (JSXMLQName *)thing;
 
             if (qn->prefix) {
                 n = js_PutEscapedString(buf, bufsize, qn->prefix, 0);
                 buf += n;
                 bufsize -= n;
             }
@@ -2079,17 +2064,17 @@ JS_PrintTraceThingInfo(char *buf, size_t
                     *buf++ = ':';
                     bufsize -= 2;
                     js_PutEscapedString(buf, bufsize, qn->localName, 0);
                 }
             }
             break;
           }
 
-          case GCX_XML:
+          case JSTRACE_XML:
           {
             extern const char *js_xml_class_str[];
             JSXML *xml = (JSXML *)thing;
 
             JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]);
             break;
           }
 #endif
@@ -2525,29 +2510,28 @@ JS_NewExternalString(JSContext *cx, jsch
     JSString *str;
 
     CHECK_REQUEST(cx);
     JS_ASSERT(GCX_EXTERNAL_STRING <= type && type < (intN) GCX_NTYPES);
 
     str = (JSString *) js_NewGCThing(cx, (uintN) type, sizeof(JSString));
     if (!str)
         return NULL;
-    str->length = length;
-    str->chars = chars;
+    JSSTRING_INIT(str, chars, length);
     return str;
 }
 
 JS_PUBLIC_API(intN)
 JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
 {
     uint8 type = (uint8) (*js_GetGCThingFlags(str) & GCF_TYPEMASK);
 
     if (type >= GCX_EXTERNAL_STRING)
         return (intN)type;
-    JS_ASSERT(type == GCX_STRING || type == GCX_MUTABLE_STRING);
+    JS_ASSERT(type == GCX_STRING);
     return -1;
 }
 
 JS_PUBLIC_API(void)
 JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
 {
 #if JS_STACK_GROWTH_DIRECTION > 0
     if (limitAddr == 0)
@@ -2892,17 +2876,17 @@ JS_GetConstructor(JSContext *cx, JSObjec
         return NULL;
     }
     return JSVAL_TO_OBJECT(cval);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
 {
-    JS_ASSERT(((jsid)obj & JSID_TAGMASK) == 0);
+    JS_ASSERT(JSID_IS_OBJECT(obj));
     *idp = OBJECT_TO_JSID(obj);
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
 {
     CHECK_REQUEST(cx);
@@ -5038,17 +5022,17 @@ JS_NewString(JSContext *cx, char *bytes,
     CHECK_REQUEST(cx);
 
     /* Make a UTF-16 vector from the 8-bit char codes in bytes. */
     chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
 
     /* Free chars (but not bytes, which caller frees on error) if we fail. */
-    str = js_NewString(cx, chars, length, 0);
+    str = js_NewString(cx, chars, length);
     if (!str) {
         JS_free(cx, chars);
         return NULL;
     }
 
     /* Hand off bytes to the deflated string cache, if possible. */
     if (!js_SetStringBytes(cx, str, bytes, nbytes))
         JS_free(cx, bytes);
@@ -5060,17 +5044,17 @@ JS_NewStringCopyN(JSContext *cx, const c
 {
     jschar *js;
     JSString *str;
 
     CHECK_REQUEST(cx);
     js = js_InflateString(cx, s, &n);
     if (!js)
         return NULL;
-    str = js_NewString(cx, js, n, 0);
+    str = js_NewString(cx, js, n);
     if (!str)
         JS_free(cx, js);
     return str;
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewStringCopyZ(JSContext *cx, const char *s)
 {
@@ -5080,17 +5064,17 @@ JS_NewStringCopyZ(JSContext *cx, const c
 
     CHECK_REQUEST(cx);
     if (!s)
         return cx->runtime->emptyString;
     n = strlen(s);
     js = js_InflateString(cx, s, &n);
     if (!js)
         return NULL;
-    str = js_NewString(cx, js, n, 0);
+    str = js_NewString(cx, js, n);
     if (!str)
         JS_free(cx, js);
     return str;
 }
 
 JS_PUBLIC_API(JSString *)
 JS_InternString(JSContext *cx, const char *s)
 {
@@ -5102,17 +5086,17 @@ JS_InternString(JSContext *cx, const cha
         return NULL;
     return ATOM_TO_STRING(atom);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
 {
     CHECK_REQUEST(cx);
-    return js_NewString(cx, chars, length, 0);
+    return js_NewString(cx, chars, length);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
 {
     CHECK_REQUEST(cx);
     return js_NewStringCopyN(cx, s, n);
 }
@@ -5172,25 +5156,27 @@ JS_GetStringChars(JSString *str)
      * rate bugs in string concatenation, is worth this slight loss in API
      * compatibility.
      */
     if (JSSTRING_IS_DEPENDENT(str)) {
         n = JSSTRDEP_LENGTH(str);
         size = (n + 1) * sizeof(jschar);
         s = (jschar *) malloc(size);
         if (s) {
-            js_strncpy(s, JSSTRDEP_CHARS(str), n);
+            memcpy(s, JSSTRDEP_CHARS(str), n * sizeof *s);
             s[n] = 0;
-            str->length = n;
-            str->chars = s;
+            JSSTRING_INIT(str, s, n);
+        } else {
+            s = JSSTRDEP_CHARS(str);
         }
+    } else {
+        JSSTRING_CLEAR_MUTABLE(str);
+        s = str->u.chars;
     }
-
-    *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
-    return JSSTRING_CHARS(str);
+    return s;
 }
 
 JS_PUBLIC_API(size_t)
 JS_GetStringLength(JSString *str)
 {
     return JSSTRING_LENGTH(str);
 }
 
@@ -5198,18 +5184,24 @@ JS_PUBLIC_API(intN)
 JS_CompareStrings(JSString *str1, JSString *str2)
 {
     return js_CompareStrings(str1, str2);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
 {
+    JSString *str;
+
     CHECK_REQUEST(cx);
-    return js_NewString(cx, chars, length, GCF_MUTABLE);
+    str = js_NewString(cx, chars, length);
+    if (!str)
+        return str;
+    JSSTRING_SET_MUTABLE(str);
+    return str;
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewDependentString(JSContext *cx, JSString *str, size_t start,
                       size_t length)
 {
     CHECK_REQUEST(cx);
     return js_NewDependentString(cx, str, start, length);
@@ -5228,21 +5220,17 @@ JS_UndependString(JSContext *cx, JSStrin
     CHECK_REQUEST(cx);
     return js_UndependString(cx, str);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_MakeStringImmutable(JSContext *cx, JSString *str)
 {
     CHECK_REQUEST(cx);
-    if (!js_UndependString(cx, str))
-        return JS_FALSE;
-
-    *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
-    return JS_TRUE;
+    return js_MakeStringImmutable(cx, str);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst,
                     size_t *dstlenp)
 {
     size_t n;
 
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -597,18 +597,17 @@ array_join_sub(JSContext *cx, JSObject *
             *rval = JS_GetEmptyStringValue(cx);
             return ok;
         }
 
         /* Flag he as BUSY so we can distinguish a cycle from a join-point. */
         MAKE_BUSY(he);
 
         if (sep) {
-            sepstr = JSSTRING_CHARS(sep);
-            seplen = JSSTRING_LENGTH(sep);
+            JSSTRING_CHARS_AND_LENGTH(sep, sepstr, seplen);
         } else {
             sepstr = NULL;      /* indicates to use "," as separator */
             seplen = 1;
         }
     }
 
     /* Use rval to locally root each element value as we loop and convert. */
     for (index = 0; index < length; index++) {
@@ -710,17 +709,17 @@ array_join_sub(JSContext *cx, JSObject *
 
   make_string:
     if (!chars) {
         JS_ReportOutOfMemory(cx);
         return JS_FALSE;
     }
     chars[nchars] = 0;
     JS_ASSERT(growth == (size_t)-1 || (nchars + 1) * sizeof(jschar) == growth);
-    str = js_NewString(cx, chars, nchars, 0);
+    str = js_NewString(cx, chars, nchars);
     if (!str) {
         free(chars);
         return JS_FALSE;
     }
     *rval = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
 
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -207,446 +207,488 @@ const char js_send_str[]            = "s
 #ifdef NARCISSUS
 const char js_call_str[]             = "__call__";
 const char js_construct_str[]        = "__construct__";
 const char js_hasInstance_str[]      = "__hasInstance__";
 const char js_ExecutionContext_str[] = "ExecutionContext";
 const char js_current_str[]          = "current";
 #endif
 
-#define HASH_DOUBLE(dp) ((JSDOUBLE_HI32(*dp) ^ JSDOUBLE_LO32(*dp)))
+/*
+ * JSAtomState.doubleAtoms and JSAtomState.stringAtoms hashtable entry. To
+ * support pinned and interned string atoms, we use the lowest bits of the
+ * keyAndFlags field to store ATOM_PINNED and ATOM_INTERNED flags.
+ */
+typedef struct JSAtomHashEntry {
+    JSDHashEntryHdr hdr;
+    jsuword         keyAndFlags;
+} JSAtomHashEntry;
 
-JS_STATIC_DLL_CALLBACK(JSHashNumber)
-js_hash_atom_key(const void *key)
-{
-    jsval v;
-    jsdouble *dp;
+#define ATOM_ENTRY_FLAG_MASK            (ATOM_PINNED | ATOM_INTERNED)
+
+JS_STATIC_ASSERT(ATOM_ENTRY_FLAG_MASK < JSVAL_ALIGN);
 
-    v = (jsval)key;
-    if (JSVAL_IS_STRING(v))
-        return js_HashString(JSVAL_TO_STRING(v));
-    if (JSVAL_IS_DOUBLE(v)) {
-        dp = JSVAL_TO_DOUBLE(v);
-        return HASH_DOUBLE(dp);
-    }
-    JS_ASSERT(JSVAL_IS_INT(v) || v == JSVAL_TRUE || v == JSVAL_FALSE ||
-              v == JSVAL_NULL || v == JSVAL_VOID);
-    return (JSHashNumber)v;
+/*
+ * Helper macros to access and modify JSAtomHashEntry.
+ */
+#define TO_ATOM_ENTRY(hdr)              ((JSAtomHashEntry *) hdr)
+#define ATOM_ENTRY_KEY(entry)                                                 \
+    ((void *)((entry)->keyAndFlags & ~ATOM_ENTRY_FLAG_MASK))
+#define ATOM_ENTRY_FLAGS(entry)                                               \
+    ((uintN)((entry)->keyAndFlags & ATOM_ENTRY_FLAG_MASK))
+#define INIT_ATOM_ENTRY(entry, key)                                           \
+    ((void)((entry)->keyAndFlags = (jsuword)(key)))
+#define ADD_ATOM_ENTRY_FLAGS(entry, flags)                                    \
+    ((void)((entry)->keyAndFlags |= (jsuword)(flags)))
+#define CLEAR_ATOM_ENTRY_FLAGS(entry, flags)                                  \
+    ((void)((entry)->keyAndFlags &= ~(jsuword)(flags)))
+
+static const JSDHashTableOps DoubleHashOps;
+static const JSDHashTableOps StringHashOps;
+
+#define IS_DOUBLE_TABLE(table)      ((table)->ops == &DoubleHashOps)
+#define IS_STRING_TABLE(table)      ((table)->ops == &StringHashOps)
+
+#define IS_INITIALIZED_STATE(state) IS_DOUBLE_TABLE(&(state)->doubleAtoms)
+
+JS_STATIC_DLL_CALLBACK(JSDHashNumber)
+HashDouble(JSDHashTable *table, const void *key)
+{
+    jsdouble d;
+
+    JS_ASSERT(IS_DOUBLE_TABLE(table));
+    d = *(jsdouble *)key;
+    return JSDOUBLE_HI32(d) ^ JSDOUBLE_LO32(d);
 }
 
-JS_STATIC_DLL_CALLBACK(intN)
-js_compare_atom_keys(const void *k1, const void *k2)
+JS_STATIC_DLL_CALLBACK(JSDHashNumber)
+HashString(JSDHashTable *table, const void *key)
 {
-    jsval v1, v2;
-
-    v1 = (jsval)k1, v2 = (jsval)k2;
-    if (JSVAL_IS_STRING(v1) && JSVAL_IS_STRING(v2))
-        return js_EqualStrings(JSVAL_TO_STRING(v1), JSVAL_TO_STRING(v2));
-    if (JSVAL_IS_DOUBLE(v1) && JSVAL_IS_DOUBLE(v2)) {
-        double d1 = *JSVAL_TO_DOUBLE(v1);
-        double d2 = *JSVAL_TO_DOUBLE(v2);
-        if (JSDOUBLE_IS_NaN(d1))
-            return JSDOUBLE_IS_NaN(d2);
-#if defined(XP_WIN)
-        /* XXX MSVC miscompiles such that (NaN == 0) */
-        if (JSDOUBLE_IS_NaN(d2))
-            return JS_FALSE;
-#endif
-        return d1 == d2;
-    }
-    return v1 == v2;
+    JS_ASSERT(IS_STRING_TABLE(table));
+    return js_HashString((JSString *)key);
 }
 
-JS_STATIC_DLL_CALLBACK(int)
-js_compare_stub(const void *v1, const void *v2)
+JS_STATIC_DLL_CALLBACK(JSBool)
+MatchDouble(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key)
 {
-    return 1;
-}
+    JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
+    jsdouble d1, d2;
 
-/* These next two are exported to jsscript.c and used similarly there. */
-void * JS_DLL_CALLBACK
-js_alloc_table_space(void *priv, size_t size)
-{
-    return malloc(size);
-}
+    JS_ASSERT(IS_DOUBLE_TABLE(table));
+    if (entry->keyAndFlags == 0) {
+        /* See comments in MatchString. */
+        return JS_FALSE;
+    }
 
-void JS_DLL_CALLBACK
-js_free_table_space(void *priv, void *item)
-{
-    free(item);
+    d1 = *(jsdouble *)ATOM_ENTRY_KEY(entry);
+    d2 = *(jsdouble *)key;
+    if (JSDOUBLE_IS_NaN(d1))
+        return JSDOUBLE_IS_NaN(d2);
+#if defined(XP_WIN)
+    /* XXX MSVC miscompiles such that (NaN == 0) */
+    if (JSDOUBLE_IS_NaN(d2))
+        return JS_FALSE;
+#endif
+    return d1 == d2;
 }
 
-JS_STATIC_DLL_CALLBACK(JSHashEntry *)
-js_alloc_atom(void *priv, const void *key)
+JS_STATIC_DLL_CALLBACK(JSBool)
+MatchString(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key)
 {
-    JSAtom *atom;
+    JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
 
-    atom = (JSAtom *) malloc(sizeof(JSAtom));
-    if (!atom)
-        return NULL;
-    ((JSAtomState *)priv)->tablegen++;
-    atom->entry.key = key;
-    atom->entry.value = NULL;
-    atom->flags = 0;
-    return &atom->entry;
+    JS_ASSERT(IS_STRING_TABLE(table));
+    if (entry->keyAndFlags == 0) {
+        /*
+         * This happens when js_AtomizeString adds a new hash entry and
+         * releases the lock but before it takes the lock the second time to
+         * initialize keyAndFlags for the entry.
+         *
+         * We always return false for such entries so JS_DHashTableOperate
+         * never finds them. We clean them during GC's sweep phase.
+         *
+         * It means that with a contested lock or when GC is triggered outside
+         * the lock we may end up adding two entries, but this is a price for
+         * simpler code.
+         */
+        return JS_FALSE;
+    }
+    return js_EqualStrings((JSString *)ATOM_ENTRY_KEY(entry), (JSString *)key);
 }
 
-JS_STATIC_DLL_CALLBACK(void)
-js_free_atom(void *priv, JSHashEntry *he, uintN flag)
-{
-    if (flag != HT_FREE_ENTRY)
-        return;
-    ((JSAtomState *)priv)->tablegen++;
-    free(he);
-}
-
-static JSHashAllocOps atom_alloc_ops = {
-    js_alloc_table_space,   js_free_table_space,
-    js_alloc_atom,          js_free_atom
+static const JSDHashTableOps DoubleHashOps = {
+    JS_DHashAllocTable,
+    JS_DHashFreeTable,
+    HashDouble,
+    MatchDouble,
+    JS_DHashMoveEntryStub,
+    JS_DHashClearEntryStub,
+    JS_DHashFinalizeStub,
+    NULL
 };
 
-#define JS_ATOM_HASH_SIZE   1024
+static const JSDHashTableOps StringHashOps = {
+    JS_DHashAllocTable,
+    JS_DHashFreeTable,
+    HashString,
+    MatchString,
+    JS_DHashMoveEntryStub,
+    JS_DHashClearEntryStub,
+    JS_DHashFinalizeStub,
+    NULL
+};
+
+/*
+ * For a browser build from 2007-08-09 after the browser starts up there are
+ * just 55 double atoms, but over 15000 string atoms. Not to penalize more
+ * economical embeddings allocating too much memory initially we initialize
+ * atomized strings with just 1K entries.
+ */
+#define JS_STRING_HASH_COUNT   1024
+#define JS_DOUBLE_HASH_COUNT   64
 
 JSBool
 js_InitAtomState(JSRuntime *rt)
 {
     JSAtomState *state = &rt->atomState;
 
    /*
     * The caller must zero the state before calling this function.
     */
-    JS_ASSERT(!state->table);
+    JS_ASSERT(!state->stringAtoms.ops);
+    JS_ASSERT(!state->doubleAtoms.ops);
     JS_ASSERT(state->tablegen == 0);
 
-    state->table = JS_NewHashTable(JS_ATOM_HASH_SIZE, js_hash_atom_key,
-                                   js_compare_atom_keys, js_compare_stub,
-                                   &atom_alloc_ops, state);
-    if (!state->table)
+    if (!JS_DHashTableInit(&state->stringAtoms, &StringHashOps,
+                           NULL, sizeof(JSAtomHashEntry),
+                           JS_DHASH_DEFAULT_CAPACITY(JS_STRING_HASH_COUNT))) {
+        state->stringAtoms.ops = NULL;
         return JS_FALSE;
+    }
+    JS_ASSERT(IS_STRING_TABLE(&state->stringAtoms));
+
+    if (!JS_DHashTableInit(&state->doubleAtoms, &DoubleHashOps,
+                           NULL, sizeof(JSAtomHashEntry),
+                           JS_DHASH_DEFAULT_CAPACITY(JS_DOUBLE_HASH_COUNT))) {
+        state->doubleAtoms.ops = NULL;
+        JS_DHashTableFinish(&state->stringAtoms);
+        state->stringAtoms.ops = NULL;
+        return JS_FALSE;
+    }
+    JS_ASSERT(IS_DOUBLE_TABLE(&state->doubleAtoms));
 
 #ifdef JS_THREADSAFE
     js_InitLock(&state->lock);
 #endif
+    JS_ASSERT(IS_INITIALIZED_STATE(state));
     return JS_TRUE;
 }
 
-JS_STATIC_DLL_CALLBACK(intN)
-js_atom_uninterner(JSHashEntry *he, intN i, void *arg)
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+js_string_uninterner(JSDHashTable *table, JSDHashEntryHdr *hdr,
+                     uint32 number, void *arg)
 {
-    JSAtom *atom;
-    JSRuntime *rt;
+    JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
+    JSRuntime *rt = (JSRuntime *)arg;
 
-    atom = (JSAtom *)he;
-    rt = (JSRuntime *)arg;
-    if (ATOM_IS_STRING(atom))
-        js_FinalizeStringRT(rt, ATOM_TO_STRING(atom));
-    return HT_ENUMERATE_NEXT;
+    /*
+     * Any string entry that remains at this point must be initialized, as the
+     * last GC should clean any uninitialized ones.
+     */
+    JS_ASSERT(IS_STRING_TABLE(table));
+    JS_ASSERT(entry->keyAndFlags != 0);
+    js_FinalizeStringRT(rt, (JSString *)ATOM_ENTRY_KEY(entry));
+    return JS_DHASH_NEXT;
 }
 
 void
 js_FinishAtomState(JSRuntime *rt)
 {
     JSAtomState *state = &rt->atomState;
 
-    if (!state->table) {
+    if (!IS_INITIALIZED_STATE(state)) {
         /*
-         * state->table is null when JS_NewRuntime fails and calls
-         * JS_DestroyRuntime on a partially initialized runtime.
+         * We are called with uninitialized state when JS_NewRuntime fails and
+         * calls JS_DestroyRuntime on a partially initialized runtime.
          */
         return;
     }
 
-    JS_HashTableEnumerateEntries(state->table, js_atom_uninterner, rt);
-    JS_HashTableDestroy(state->table);
+    JS_DHashTableEnumerate(&state->stringAtoms, js_string_uninterner, rt);
+    JS_DHashTableFinish(&state->stringAtoms);
+    JS_DHashTableFinish(&state->doubleAtoms);
+
 #ifdef JS_THREADSAFE
     js_FinishLock(&state->lock);
 #endif
 #ifdef DEBUG
     memset(state, JS_FREE_PATTERN, sizeof *state);
 #endif
 }
 
 JSBool
 js_InitCommonAtoms(JSContext *cx)
 {
     JSAtomState *state = &cx->runtime->atomState;
     uintN i;
     JSAtom **atoms;
 
-    atoms = (JSAtom **)((uint8 *)state + ATOM_OFFSET_START);
+    atoms = COMMON_ATOMS_START(state);
     for (i = 0; i < JS_ARRAY_LENGTH(js_common_atom_names); i++, atoms++) {
         *atoms = js_Atomize(cx, js_common_atom_names[i],
                             strlen(js_common_atom_names[i]), ATOM_PINNED);
         if (!*atoms)
             return JS_FALSE;
     }
     JS_ASSERT((uint8 *)atoms - (uint8 *)state == LAZY_ATOM_OFFSET_START);
     memset(atoms, 0, ATOM_OFFSET_LIMIT - LAZY_ATOM_OFFSET_START);
 
     return JS_TRUE;
 }
 
-JS_STATIC_DLL_CALLBACK(intN)
-js_atom_unpinner(JSHashEntry *he, intN i, void *arg)
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+js_atom_unpinner(JSDHashTable *table, JSDHashEntryHdr *hdr,
+                 uint32 number, void *arg)
 {
-    JSAtom *atom;
-
-    atom = (JSAtom *)he;
-    atom->flags &= ~ATOM_PINNED;
-    return HT_ENUMERATE_NEXT;
+    JS_ASSERT(IS_STRING_TABLE(table));
+    CLEAR_ATOM_ENTRY_FLAGS(TO_ATOM_ENTRY(hdr), ATOM_PINNED);
+    return JS_DHASH_NEXT;
 }
 
 void
 js_FinishCommonAtoms(JSContext *cx)
 {
     JSAtomState *state = &cx->runtime->atomState;
 
-    JS_HashTableEnumerateEntries(state->table, js_atom_unpinner, NULL);
+    JS_DHashTableEnumerate(&state->stringAtoms, js_atom_unpinner, NULL);
 #ifdef DEBUG
-    memset((uint8 *)state + ATOM_OFFSET_START, JS_FREE_PATTERN,
+    memset(COMMON_ATOMS_START(state), JS_FREE_PATTERN,
            ATOM_OFFSET_LIMIT - ATOM_OFFSET_START);
 #endif
 }
 
-void
-js_TraceAtom(JSTracer *trc, JSAtom *atom)
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+js_locked_atom_tracer(JSDHashTable *table, JSDHashEntryHdr *hdr,
+                      uint32 number, void *arg)
 {
-    jsval key;
+    JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
+    JSTracer *trc = (JSTracer *)arg;
 
-    key = ATOM_KEY(atom);
-    JS_CALL_VALUE_TRACER(trc, key, "key");
-    if (atom->flags & ATOM_HIDDEN)
-        JS_CALL_TRACER(trc, atom->entry.value, JSTRACE_ATOM, "hidden");
+    if (entry->keyAndFlags == 0) {
+        /* Ignore uninitialized entries during tracing. */
+        return JS_DHASH_NEXT;
+    }
+    JS_SET_TRACING_INDEX(trc, "locked_atom", (size_t)number);
+    JS_CallTracer(trc, ATOM_ENTRY_KEY(entry),
+                  IS_STRING_TABLE(table) ? JSTRACE_STRING : JSTRACE_DOUBLE);
+    return JS_DHASH_NEXT;
 }
 
-typedef struct TraceArgs {
-    JSBool      allAtoms;
-    JSTracer    *trc;
-} TraceArgs;
-
-JS_STATIC_DLL_CALLBACK(intN)
-js_locked_atom_tracer(JSHashEntry *he, intN i, void *arg)
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+js_pinned_atom_tracer(JSDHashTable *table, JSDHashEntryHdr *hdr,
+                        uint32 number, void *arg)
 {
-    JSAtom *atom;
-    TraceArgs *args;
+    JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
+    JSTracer *trc = (JSTracer *)arg;
+    uintN flags = ATOM_ENTRY_FLAGS(entry);
 
-    atom = (JSAtom *)he;
-    args = (TraceArgs *)arg;
-    if ((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) || args->allAtoms) {
-        JS_SET_TRACING_INDEX(args->trc,
-                             (atom->flags & ATOM_PINNED)
+    JS_ASSERT(IS_STRING_TABLE(table));
+    if (flags & (ATOM_PINNED | ATOM_INTERNED)) {
+        JS_SET_TRACING_INDEX(trc,
+                             flags & ATOM_PINNED
                              ? "pinned_atom"
-                             : (atom->flags & ATOM_INTERNED)
-                             ? "interned_atom"
-                             : "locked_atom",
-                             (size_t)i);
-        JS_CallTracer(args->trc, atom, JSTRACE_ATOM);
+                             : "interned_atom",
+                             (size_t)number);
+        JS_CallTracer(trc, ATOM_ENTRY_KEY(entry), JSTRACE_STRING);
     }
-    return HT_ENUMERATE_NEXT;
+    return JS_DHASH_NEXT;
 }
 
 void
-js_TraceLockedAtoms(JSTracer *trc, JSBool allAtoms)
+js_TraceAtomState(JSTracer *trc, JSBool allAtoms)
 {
     JSAtomState *state;
-    TraceArgs args;
 
     state = &trc->context->runtime->atomState;
-    if (!state->table)
-        return;
-    args.allAtoms = allAtoms;
-    args.trc = trc;
-    JS_HashTableEnumerateEntries(state->table, js_locked_atom_tracer, &args);
+    if (allAtoms) {
+        JS_DHashTableEnumerate(&state->doubleAtoms, js_locked_atom_tracer, trc);
+        JS_DHashTableEnumerate(&state->stringAtoms, js_locked_atom_tracer, trc);
+    } else {
+        JS_DHashTableEnumerate(&state->stringAtoms, js_pinned_atom_tracer, trc);
+    }
 }
 
-JS_STATIC_DLL_CALLBACK(intN)
-js_atom_sweeper(JSHashEntry *he, intN i, void *arg)
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+js_atom_sweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
+                uint32 number, void *arg)
 {
-    JSAtom *atom;
+    JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
+    JSContext *cx = (JSContext *)arg;
 
-    atom = (JSAtom *)he;
-    if (atom->flags & ATOM_MARK) {
-        atom->flags &= ~ATOM_MARK;
-        return HT_ENUMERATE_NEXT;
+    /* Remove uninitialized entries.  */
+    if (entry->keyAndFlags == 0)
+        return JS_DHASH_REMOVE;
+
+    if (ATOM_ENTRY_FLAGS(entry) & (ATOM_PINNED | ATOM_INTERNED)) {
+        /* Pinned or interned key cannot be finalized. */
+        JS_ASSERT(!js_IsAboutToBeFinalized(cx, ATOM_ENTRY_KEY(entry)));
+    } else if (js_IsAboutToBeFinalized(cx, ATOM_ENTRY_KEY(entry))) {
+        /* Remove entries with things about to be GC'ed. */
+        return JS_DHASH_REMOVE;
     }
-    JS_ASSERT((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) == 0);
-    atom->entry.key = atom->entry.value = NULL;
-    atom->flags = 0;
-    return HT_ENUMERATE_REMOVE;
+    return JS_DHASH_NEXT;
 }
 
 void
 js_SweepAtomState(JSContext *cx)
 {
     JSAtomState *state = &cx->runtime->atomState;
 
-    JS_HashTableEnumerateEntries(state->table, js_atom_sweeper, NULL);
-}
-
-static JSAtom *
-AtomizeHashedKey(JSContext *cx, jsval key, JSHashNumber keyHash)
-{
-    JSAtomState *state;
-    JSHashTable *table;
-    JSHashEntry *he, **hep;
-    JSAtom *atom;
+    JS_DHashTableEnumerate(&state->doubleAtoms, js_atom_sweeper, cx);
+    JS_DHashTableEnumerate(&state->stringAtoms, js_atom_sweeper, cx);
 
-    state = &cx->runtime->atomState;
-    JS_LOCK(&state->lock, cx);
-    table = state->table;
-    hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
-    if ((he = *hep) == NULL) {
-        he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
-        if (!he) {
-            JS_UNLOCK(&state->lock,cx);
-            JS_ReportOutOfMemory(cx);
-            return NULL;
-        }
-    }
-
-    atom = (JSAtom *)he;
-    cx->weakRoots.lastAtom = atom;
-    JS_UNLOCK(&state->lock,cx);
-    return atom;
+    /*
+     * Optimize for simplicity and mutate tablegen even if the sweeper has not
+     * removed any entries.
+     */
+    state->tablegen++;
 }
 
-/* Worst-case alignment grain and aligning macro for 2x-sized buffer. */
-#define ALIGNMENT(t)    JS_MAX(JSVAL_ALIGN, sizeof(t))
-#define ALIGN(b,t)      ((t*) &(b)[ALIGNMENT(t) - (jsuword)(b) % ALIGNMENT(t)])
-
 JSAtom *
 js_AtomizeDouble(JSContext *cx, jsdouble d)
 {
-    char buf[2 * ALIGNMENT(double)];
-    jsdouble *dp;
-    JSHashNumber keyHash;
-    jsval key;
     JSAtomState *state;
-    JSHashTable *table;
-    JSHashEntry *he, **hep;
+    JSDHashTable *table;
+    JSAtomHashEntry *entry;
     uint32 gen;
-    JSAtom *atom;
+    jsdouble *key;
+    jsval v;
 
-    dp = ALIGN(buf, double);
-    *dp = d;
-    keyHash = HASH_DOUBLE(dp);
-    key = DOUBLE_TO_JSVAL(dp);
     state = &cx->runtime->atomState;
-    table = state->table;
+    table = &state->doubleAtoms;
 
     JS_LOCK(&state->lock, cx);
-    hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
-    if ((he = *hep) == NULL) {
-        gen = state->tablegen;
+    entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, &d, JS_DHASH_ADD));
+    if (!entry)
+        goto failed_hash_add;
+    if (entry->keyAndFlags == 0) {
+        gen = ++state->tablegen;
         JS_UNLOCK(&state->lock, cx);
 
-        if (!js_NewDoubleValue(cx, d, &key))
+        key = js_NewDouble(cx, d, 0);
+        if (!key)
             return NULL;
 
         JS_LOCK(&state->lock, cx);
-        if (state->tablegen != gen) {
-            hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
-            if ((he = *hep) != NULL)
+        if (state->tablegen == gen) {
+            JS_ASSERT(entry->keyAndFlags == 0);
+        } else {
+            entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, key,
+                                                       JS_DHASH_ADD));
+            if (!entry)
+                goto failed_hash_add;
+            if (entry->keyAndFlags != 0)
                 goto finish;
+            ++state->tablegen;
         }
-        he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
-        if (!he) {
-            JS_UNLOCK(&state->lock, cx);
-            JS_ReportOutOfMemory(cx);
-            return NULL;
-        }
+        INIT_ATOM_ENTRY(entry, key);
     }
 
   finish:
-    atom = (JSAtom *)he;
-    cx->weakRoots.lastAtom = atom;
+    v = DOUBLE_TO_JSVAL((jsdouble *)ATOM_ENTRY_KEY(entry));
+    cx->weakRoots.lastAtom = v;
     JS_UNLOCK(&state->lock,cx);
-    return atom;
-}
+
+    return (JSAtom *)v;
 
-/*
- * To put an atom into the hidden subspace. XOR its keyHash with this value,
- * which is (sqrt(2)-1) in 32-bit fixed point.
- */
-#define HIDDEN_ATOM_SUBSPACE_KEYHASH    0x6A09E667
+  failed_hash_add:
+    JS_UNLOCK(&state->lock,cx);
+    JS_ReportOutOfMemory(cx);
+    return NULL;
+}
 
 JSAtom *
 js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
 {
-    JSHashNumber keyHash;
-    void *key;
     JSAtomState *state;
-    JSHashTable *table;
-    JSHashEntry *he, **hep;
+    JSDHashTable *table;
+    JSAtomHashEntry *entry;
+    JSString *key;
     uint32 gen;
-    JSString *hashed;
-    JSAtom *atom;
+    jsval v;
 
-    keyHash = js_HashString(str);
-    if (flags & ATOM_HIDDEN)
-        keyHash ^= HIDDEN_ATOM_SUBSPACE_KEYHASH;
-    key = (void *)STRING_TO_JSVAL(str);
+    JS_ASSERT((flags &
+               ~(ATOM_PINNED | ATOM_INTERNED | ATOM_TMPSTR | ATOM_NOCOPY))
+              == 0);
     state = &cx->runtime->atomState;
-    table = state->table;
+    table = &state->stringAtoms;
 
     JS_LOCK(&state->lock, cx);
-    hep = JS_HashTableRawLookup(table, keyHash, key);
-    if ((he = *hep) == NULL) {
+    entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, str, JS_DHASH_ADD));
+    if (!entry)
+        goto failed_hash_add;
+    if (entry->keyAndFlags == 0) {
+        ++state->tablegen;
         gen = state->tablegen;
         JS_UNLOCK(&state->lock, cx);
 
         if (flags & ATOM_TMPSTR) {
             if (flags & ATOM_NOCOPY) {
-                hashed = js_NewString(cx, str->chars, str->length, 0);
-                if (!hashed)
+                key = js_NewString(cx, str->u.chars, str->length);
+                if (!key)
                     return NULL;
 
                 /* Transfer ownership of str->chars to GC-controlled string. */
-                str->chars = NULL;
+                str->u.chars = NULL;
             } else {
-                hashed = js_NewStringCopyN(cx, str->chars, str->length);
-                if (!hashed)
+                key = js_NewStringCopyN(cx, str->u.chars, str->length);
+                if (!key)
                     return NULL;
             }
-            key = (void *)STRING_TO_JSVAL(hashed);
         } else {
             JS_ASSERT((flags & ATOM_NOCOPY) == 0);
             if (!JS_MakeStringImmutable(cx, str))
                 return NULL;
+            key = str;
         }
 
         JS_LOCK(&state->lock, cx);
-        if (state->tablegen != gen) {
-            hep = JS_HashTableRawLookup(table, keyHash, key);
-            if ((he = *hep) != NULL)
+        if (state->tablegen == gen) {
+            JS_ASSERT(entry->keyAndFlags == 0);
+        } else {
+            entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, key,
+                                                       JS_DHASH_ADD));
+            if (!entry)
+                goto failed_hash_add;
+            if (entry->keyAndFlags != 0)
                 goto finish;
+            ++state->tablegen;
         }
-        he = JS_HashTableRawAdd(table, hep, keyHash, key, NULL);
-        if (!he) {
-            JS_UNLOCK(&state->lock, cx);
-            JS_ReportOutOfMemory(cx);
-            return NULL;
-        }
+        INIT_ATOM_ENTRY(entry, key);
     }
 
   finish:
-    atom = (JSAtom *)he;
-    atom->flags |= flags & (ATOM_PINNED | ATOM_INTERNED | ATOM_HIDDEN);
-    cx->weakRoots.lastAtom = atom;
+    ADD_ATOM_ENTRY_FLAGS(entry, flags & (ATOM_PINNED | ATOM_INTERNED));
+    v = STRING_TO_JSVAL((JSString *)ATOM_ENTRY_KEY(entry));
+    cx->weakRoots.lastAtom = v;
     JS_UNLOCK(&state->lock, cx);
-    return atom;
+    return (JSAtom *)v;
+
+  failed_hash_add:
+    JS_UNLOCK(&state->lock,cx);
+    JS_ReportOutOfMemory(cx);
+    return NULL;
 }
 
 JS_FRIEND_API(JSAtom *)
 js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags)
 {
     jschar *chars;
-    JSString *str;
+    JSString str;
     JSAtom *atom;
-    char buf[2 * ALIGNMENT(JSString)];
 
     /*
      * Avoiding the malloc in js_InflateString on shorter strings saves us
      * over 20,000 malloc calls on mozilla browser startup. This compares to
      * only 131 calls where the string is longer than a 31 char (net) buffer.
      * The vast majority of atomized strings are already in the hashtable. So
      * js_AtomizeString rarely has to copy the temp string we make.
      */
@@ -661,114 +703,137 @@ js_Atomize(JSContext *cx, const char *by
     } else {
         inflatedLength = length;
         chars = js_InflateString(cx, bytes, &inflatedLength);
         if (!chars)
             return NULL;
         flags |= ATOM_NOCOPY;
     }
 
-    str = ALIGN(buf, JSString);
-
-    str->chars = chars;
-    str->length = inflatedLength;
-    atom = js_AtomizeString(cx, str, ATOM_TMPSTR | flags);
-    if (chars != inflated && str->chars)
+    JSSTRING_INIT(&str, (jschar *)chars, inflatedLength);
+    atom = js_AtomizeString(cx, &str, ATOM_TMPSTR | flags);
+    if (chars != inflated && str.u.chars)
         JS_free(cx, chars);
     return atom;
 }
 
 JS_FRIEND_API(JSAtom *)
 js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags)
 {
-    JSString *str;
-    char buf[2 * ALIGNMENT(JSString)];
+    JSString str;
 
-    str = ALIGN(buf, JSString);
-    str->chars = (jschar *)chars;
-    str->length = length;
-    return js_AtomizeString(cx, str, ATOM_TMPSTR | flags);
+    JSSTRING_INIT(&str, (jschar *)chars, length);
+    return js_AtomizeString(cx, &str, ATOM_TMPSTR | flags);
 }
 
 JSAtom *
 js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
 {
-    JSString *str;
-    char buf[2 * ALIGNMENT(JSString)];
-    JSHashNumber keyHash;
-    jsval key;
+    JSString str, *str2;
     JSAtomState *state;
-    JSHashTable *table;
-    JSHashEntry **hep;
+    JSDHashEntryHdr *hdr;
+
+    JSSTRING_INIT(&str, (jschar *)chars, length);
+    state = &cx->runtime->atomState;
 
-    str = ALIGN(buf, JSString);
-    str->chars = (jschar *)chars;
-    str->length = length;
-    keyHash = js_HashString(str);
-    key = STRING_TO_JSVAL(str);
-    state = &cx->runtime->atomState;
     JS_LOCK(&state->lock, cx);
-    table = state->table;
-    hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
+    hdr = JS_DHashTableOperate(&state->stringAtoms, &str, JS_DHASH_LOOKUP);
+    str2 = JS_DHASH_ENTRY_IS_BUSY(hdr)
+           ? (JSString *)ATOM_ENTRY_KEY(TO_ATOM_ENTRY(hdr))
+           : NULL;
     JS_UNLOCK(&state->lock, cx);
-    return (hep) ? (JSAtom *)*hep : NULL;
+
+    return str2 ? (JSAtom *)STRING_TO_JSVAL(str2) : NULL;
 }
 
-JSAtom *
-js_AtomizePrimitiveValue(JSContext *cx, jsval v)
+JSBool
+js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp)
 {
-    if (JSVAL_IS_STRING(v))
-        return js_AtomizeString(cx, JSVAL_TO_STRING(v), 0);
-    if (JSVAL_IS_DOUBLE(v))
-        return js_AtomizeDouble(cx, *JSVAL_TO_DOUBLE(v));
-    JS_ASSERT(JSVAL_IS_INT(v) || v == JSVAL_TRUE || v == JSVAL_FALSE ||
-              v == JSVAL_NULL || v == JSVAL_VOID);
-    return AtomizeHashedKey(cx, v, (JSHashNumber)v);
+    JSAtom *atom;
+
+    if (JSVAL_IS_STRING(v)) {
+        atom = js_AtomizeString(cx, JSVAL_TO_STRING(v), 0);
+        if (!atom)
+            return JS_FALSE;
+    } else if (JSVAL_IS_DOUBLE(v)) {
+        atom = js_AtomizeDouble(cx, *JSVAL_TO_DOUBLE(v));
+        if (!atom)
+            return JS_FALSE;
+    } else {
+        JS_ASSERT(JSVAL_IS_INT(v) || v == JSVAL_TRUE || v == JSVAL_FALSE ||
+                  v == JSVAL_NULL || v == JSVAL_VOID);
+        atom = (JSAtom *)v;
+    }
+    *atomp = atom;
+    return JS_TRUE;
 }
 
 JSAtom *
 js_ValueToStringAtom(JSContext *cx, jsval v)
 {
     JSString *str;
 
     str = js_ValueToString(cx, v);
     if (!str)
         return NULL;
     return js_AtomizeString(cx, str, 0);
 }
 
 #ifdef DEBUG
 
-JS_STATIC_DLL_CALLBACK(int)
-atom_dumper(JSHashEntry *he, int i, void *arg)
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+atom_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr,
+            uint32 number, void *arg)
 {
+    JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
     FILE *fp = (FILE *)arg;
-    JSAtom *atom = (JSAtom *)he;
+    void *key;
+    uintN flags;
 
-    fprintf(fp, "%3u %08x ", (uintN)i, (uintN)he->keyHash);
-    if (ATOM_IS_STRING(atom))
-        js_FileEscapedString(fp, ATOM_TO_STRING(atom), '"');
-    else if (ATOM_IS_INT(atom))
-        fprintf(fp, "%ld", (long)ATOM_TO_INT(atom));
-    else
-        fprintf(fp, "%.16g", *ATOM_TO_DOUBLE(atom));
+    fprintf(fp, "%3u %08x ", number, (uintN)entry->hdr.keyHash);
+    if (entry->keyAndFlags == 0) {
+        fputs("<uninitialized>", fp);
+    } else {
+        key = ATOM_ENTRY_KEY(entry);
+        if (IS_DOUBLE_TABLE(table)) {
+            fprintf(fp, "%.16g", *(jsdouble *)key);
+        } else {
+            JS_ASSERT(IS_STRING_TABLE(table));
+            js_FileEscapedString(fp, (JSString *)key, '"');
+        }
+        flags = ATOM_ENTRY_FLAGS(entry);
+        if (flags != 0) {
+            fputs((flags & (ATOM_PINNED | ATOM_INTERNED))
+                  ? " pinned | interned"
+                  : (flags & ATOM_PINNED) ? " pinned" : " interned",
+                  fp);
+        }
+    }
     putc('\n', fp);
-    return HT_ENUMERATE_NEXT;
+    return JS_DHASH_NEXT;
 }
 
 JS_FRIEND_API(void)
 js_DumpAtoms(JSContext *cx, FILE *fp)
 {
     JSAtomState *state = &cx->runtime->atomState;
 
-    fprintf(fp, "\natom table contents:\n");
-    JS_HashTableEnumerateEntries(state->table, atom_dumper, fp);
-#ifdef HASHMETER
-    JS_HashTableDumpMeter(state->table, atom_dumper, fp);
+    fprintf(fp, "stringAtoms table contents:\n");
+    JS_DHashTableEnumerate(&state->stringAtoms, atom_dumper, fp);
+#ifdef JS_DHASHMETER
+    JS_DHashTableDumpMeter(&state->stringAtoms, atom_dumper, fp);
 #endif
+    putc('\n', fp);
+
+    fprintf(fp, "doubleAtoms table contents:\n");
+    JS_DHashTableEnumerate(&state->doubleAtoms, atom_dumper, fp);
+#ifdef JS_DHASHMETER
+    JS_DHashTableDumpMeter(&state->doubleAtoms, atom_dumper, fp);
+#endif
+    putc('\n', fp);
 }
 
 #endif
 
 JS_STATIC_DLL_CALLBACK(JSHashNumber)
 js_hash_atom_ptr(const void *key)
 {
     const JSAtom *atom = (const JSAtom *) key;
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -41,48 +41,37 @@
 #define jsatom_h___
 /*
  * JS atom table.
  */
 #include <stddef.h>
 #include "jsconfig.h"
 #include "jstypes.h"
 #include "jshash.h" /* Added by JSIFY */
+#include "jsdhash.h"
 #include "jsapi.h"
 #include "jsprvtd.h"
 #include "jspubtd.h"
 
 #ifdef JS_THREADSAFE
 #include "jslock.h"
 #endif
 
 JS_BEGIN_EXTERN_C
 
-#define ATOM_PINNED     0x01            /* atom is pinned against GC */
-#define ATOM_INTERNED   0x02            /* pinned variant for JS_Intern* API */
-#define ATOM_MARK       0x04            /* atom is reachable via GC */
-#define ATOM_HIDDEN     0x08            /* atom is in special hidden subspace */
-#define ATOM_NOCOPY     0x40            /* don't copy atom string bytes */
-#define ATOM_TMPSTR     0x80            /* internal, to avoid extra string */
+#define ATOM_PINNED     0x1       /* atom is pinned against GC */
+#define ATOM_INTERNED   0x2       /* pinned variant for JS_Intern* API */
+#define ATOM_NOCOPY     0x4       /* don't copy atom string bytes */
+#define ATOM_TMPSTR     0x8       /* internal, to avoid extra string */
 
-struct JSAtom {
-    JSHashEntry         entry;          /* key is jsval or unhidden atom
-                                           if ATOM_HIDDEN */
-    uint32              flags;          /* pinned, interned, and mark flags */
-};
-
-#define ATOM_KEY(atom)            ((jsval)(atom)->entry.key)
-#define ATOM_IS_INT(atom)         JSVAL_IS_INT(ATOM_KEY(atom))
-#define ATOM_TO_INT(atom)         JSVAL_TO_INT(ATOM_KEY(atom))
+#define ATOM_KEY(atom)            ((jsval)(atom))
 #define ATOM_IS_DOUBLE(atom)      JSVAL_IS_DOUBLE(ATOM_KEY(atom))
 #define ATOM_TO_DOUBLE(atom)      JSVAL_TO_DOUBLE(ATOM_KEY(atom))
 #define ATOM_IS_STRING(atom)      JSVAL_IS_STRING(ATOM_KEY(atom))
 #define ATOM_TO_STRING(atom)      JSVAL_TO_STRING(ATOM_KEY(atom))
-#define ATOM_IS_BOOLEAN(atom)     JSVAL_IS_BOOLEAN(ATOM_KEY(atom))
-#define ATOM_TO_BOOLEAN(atom)     JSVAL_TO_BOOLEAN(ATOM_KEY(atom))
 
 JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4);
 JS_STATIC_ASSERT(sizeof(JSAtom *) == JS_BYTES_PER_WORD);
 
 #if JS_BYTES_PER_WORD == 4
 # define ATOM_HASH(atom)          ((JSHashNumber)(atom) >> 2)
 #elif JS_BYTES_PER_WORD == 8
 # define ATOM_HASH(atom)          (((JSHashNumber)(atom) >> 3) ^              \
@@ -151,18 +140,18 @@ struct JSAtomList {
     JS_END_MACRO
 
 struct JSAtomMap {
     JSAtom              **vector;       /* array of ptrs to indexed atoms */
     jsatomid            length;         /* count of (to-be-)indexed atoms */
 };
 
 struct JSAtomState {
-    JSHashTable         *table;         /* hash table containing all atoms */
-
+    JSDHashTable        stringAtoms;    /* hash table with shared strings */
+    JSDHashTable        doubleAtoms;    /* hash table with shared doubles */
     uint32              tablegen;       /* number of atoms mutations to
                                            optimize hashing */
 #ifdef JS_THREADSAFE
     JSThinLock          lock;
 #endif
 
     /*
      * From this point until the end of struct definition the struct must
@@ -269,16 +258,19 @@ struct JSAtomState {
         JSAtom          *watchAtom;
     } lazy;
 };
 
 #define ATOM_OFFSET_START       offsetof(JSAtomState, emptyAtom)
 #define LAZY_ATOM_OFFSET_START  offsetof(JSAtomState, lazy)
 #define ATOM_OFFSET_LIMIT       (sizeof(JSAtomState))
 
+#define COMMON_ATOMS_START(state)                                             \
+    (JSAtom **)((uint8 *)(state) + ATOM_OFFSET_START)
+
 /* Start and limit offsets should correspond to atoms. */
 JS_STATIC_ASSERT(ATOM_OFFSET_START % sizeof(JSAtom *) == 0);
 JS_STATIC_ASSERT(ATOM_OFFSET_LIMIT % sizeof(JSAtom *) == 0);
 
 #define ATOM_OFFSET(name)       offsetof(JSAtomState, name##Atom)
 #define OFFSET_TO_ATOM(rt,off)  (*(JSAtom **)((char*)&(rt)->atomState + (off)))
 #define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState,classAtoms[JSProto_##name])
 
@@ -374,20 +366,17 @@ js_InitAtomState(JSRuntime *rt);
 extern void
 js_FinishAtomState(JSRuntime *rt);
 
 /*
  * Atom tracing and garbage collection hooks.
  */
 
 extern void
-js_TraceAtom(JSTracer *trc, JSAtom *atom);
-
-extern void
-js_TraceLockedAtoms(JSTracer *trc, JSBool allAtoms);
+js_TraceAtomState(JSTracer *trc, JSBool allAtoms);
 
 extern void
 js_SweepAtomState(JSContext *cx);
 
 extern JSBool
 js_InitCommonAtoms(JSContext *cx);
 
 extern void
@@ -418,18 +407,18 @@ js_AtomizeChars(JSContext *cx, const jsc
  * sequence is currently not atomized.
  */
 extern JSAtom *
 js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length);
 
 /*
  * This variant handles all primitive values.
  */
-extern JSAtom *
-js_AtomizePrimitiveValue(JSContext *cx, jsval v);
+JSBool
+js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp);
 
 /*
  * Convert v to an atomized string.
  */
 extern JSAtom *
 js_ValueToStringAtom(JSContext *cx, jsval v);
 
 #ifdef DEBUG
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -554,83 +554,97 @@ date_msecFromDate(jsdouble year, jsdoubl
     jsdouble msec_time;
     jsdouble result;
 
     day = MakeDay(year, mon, mday);
     msec_time = MakeTime(hour, min, sec, msec);
     result = MakeDate(day, msec_time);
     return result;
 }
-
-/*
- * See ECMA 15.9.4.[3-10];
- */
+
+/* compute the time in msec (unclipped) from the given args */
 #define MAXARGS        7
 
 static JSBool
-date_UTC(JSContext *cx, uintN argc, jsval *vp)
+date_msecFromArgs(JSContext *cx, uintN argc, jsval *argv, jsdouble *rval)
 {
-    jsval *argv;
     uintN loop;
     jsdouble array[MAXARGS];
     jsdouble d;
+    jsdouble msec_time;
 
-    argv = vp + 2;
     for (loop = 0; loop < MAXARGS; loop++) {
         if (loop < argc) {
             if (!js_ValueToNumber(cx, argv[loop], &d))
                 return JS_FALSE;
-            /* return NaN if any arg is NaN */
+            /* return NaN if any arg is not finite */
             if (!JSDOUBLE_IS_FINITE(d)) {
-                return js_NewNumberValue(cx, d, vp);
+                *rval = *cx->runtime->jsNaN;
+                return JS_TRUE;
             }
-            array[loop] = floor(d);
+            array[loop] = js_DoubleToInteger(d);
         } else {
-            array[loop] = 0;
+            if (loop == 2) {
+                array[loop] = 1; /* Default the date argument to 1. */
+            } else {
+                array[loop] = 0;
+            }
         }
     }
 
     /* adjust 2-digit years into the 20th century */
     if (array[0] >= 0 && array[0] <= 99)
         array[0] += 1900;
 
-    /* if we got a 0 for 'date' (which is out of range)
-     * pretend it's a 1.  (So Date.UTC(1972, 5) works) */
-    if (array[2] < 1)
-        array[2] = 1;
+    msec_time = date_msecFromDate(array[0], array[1], array[2],
+                                  array[3], array[4], array[5], array[6]);
+    *rval = msec_time;
+    return JS_TRUE;
+}
 
-    d = date_msecFromDate(array[0], array[1], array[2],
-                              array[3], array[4], array[5], array[6]);
-    d = TIMECLIP(d);
+
+/*
+ * See ECMA 15.9.4.[3-10];
+ */
+static JSBool
+date_UTC(JSContext *cx, uintN argc, jsval *vp)
+{
+    jsdouble msec_time;
 
-    return js_NewNumberValue(cx, d, vp);
+    if (!date_msecFromArgs(cx, argc, vp + 2, &msec_time))
+        return JS_FALSE;
+
+    msec_time = TIMECLIP(msec_time);
+
+    return js_NewNumberValue(cx, msec_time, vp);
 }
 
 static JSBool
 date_parseString(JSString *str, jsdouble *result)
 {
     jsdouble msec;
 
-    const jschar *s = JSSTRING_CHARS(str);
-    size_t limit = JSSTRING_LENGTH(str);
+    const jschar *s;
+    size_t limit;
     size_t i = 0;
     int year = -1;
     int mon = -1;
     int mday = -1;
     int hour = -1;
     int min = -1;
     int sec = -1;
     int c = -1;
     int n = -1;
     int tzoffset = -1;
     int prevc = 0;
     JSBool seenplusminus = JS_FALSE;
     int temp;
     JSBool seenmonthname = JS_FALSE;
 
+    JSSTRING_CHARS_AND_LENGTH(str, s, limit);
     if (limit == 0)
         goto syntax;
     while (i < limit) {
         c = s[i];
         i++;
         if (c <= ' ' || c == ',' || c == '-') {
             if (c == '-' && '0' <= s[i] && s[i] <= '9') {
               prevc = c;
@@ -2096,58 +2110,32 @@ Date(JSContext *cx, JSObject *obj, uintN
             if (!str)
                 return JS_FALSE;