Merge cvs-trunk-mirror -> mozilla-central. There's a C++ bug in js/src/jsinterp.cpp that I am going to file upstream.
authorBenjamin Smedberg <benjamin@smedbergs.us>
Thu, 20 Mar 2008 12:42:05 -0400
changeset 13381 895712d07d4c3e0642195ba453446181ddd7a65c
parent 13025 9df334adb143da61887e8ccbf56a090111e6efc4 (current diff)
parent 13380 ee9d5b26b31569898569c7961d2980a442982d8f (diff)
child 13382 61007906a1f8ad5c303b0815ac4e9821168d3937
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)
milestone2.0a1pre
Merge cvs-trunk-mirror -> mozilla-central. There's a C++ bug in js/src/jsinterp.cpp that I am going to file upstream.
browser/components/preferences/advanced-scripts.js
caps/tests/mozDriver.pl
caps/tests/securetest.list
client.mk
client.py
config/autoconf.mk.in
configure.in
extensions/cookie/test/test_same_base_domain_7.html
gfx/cairo/pixman-fbFetchTransformed-backout.patch
gfx/src/mac/Makefile.in
gfx/src/mac/fontEncoding.properties
gfx/src/mac/gfxmac.pkg
gfx/src/mac/nsATSUIUtils.cpp
gfx/src/mac/nsATSUIUtils.h
gfx/src/mac/nsCarbonHelpers.h
gfx/src/mac/nsCocoaImageUtils.mm
gfx/src/mac/nsDeviceContextMac.cpp
gfx/src/mac/nsDeviceContextMac.h
gfx/src/mac/nsDrawingSurfaceMac.cpp
gfx/src/mac/nsDrawingSurfaceMac.h
gfx/src/mac/nsFontMetricsMac.cpp
gfx/src/mac/nsFontMetricsMac.h
gfx/src/mac/nsFontUtils.cpp
gfx/src/mac/nsFontUtils.h
gfx/src/mac/nsGfxFactoryMac.cpp
gfx/src/mac/nsGfxUtils.h
gfx/src/mac/nsGraphicState.cpp
gfx/src/mac/nsGraphicState.h
gfx/src/mac/nsIDrawingSurfaceMac.h
gfx/src/mac/nsIImageMac.h
gfx/src/mac/nsImageMac.cpp
gfx/src/mac/nsImageMac.h
gfx/src/mac/nsMacGFX.rsrc
gfx/src/mac/nsMacResources.cpp
gfx/src/mac/nsMacResources.h
gfx/src/mac/nsMacUnicodeFontInfo.cpp
gfx/src/mac/nsMacUnicodeFontInfo.h
gfx/src/mac/nsRegionMac.cpp
gfx/src/mac/nsRegionMac.h
gfx/src/mac/nsRegionPool.cpp
gfx/src/mac/nsRegionPool.h
gfx/src/mac/nsRenderingContextMac.cpp
gfx/src/mac/nsRenderingContextMac.h
gfx/src/mac/nsUnicodeBlock.h
gfx/src/mac/nsUnicodeFallbackCache.h
gfx/src/mac/nsUnicodeFontMappingCache.h
gfx/src/mac/nsUnicodeFontMappingMac.cpp
gfx/src/mac/nsUnicodeFontMappingMac.h
gfx/src/mac/nsUnicodeMappingUtil.cpp
gfx/src/mac/nsUnicodeMappingUtil.h
gfx/src/mac/nsUnicodeRenderingToolkit.cpp
gfx/src/mac/nsUnicodeRenderingToolkit.h
gfx/src/mac/printerplugin/Resources/English.lproj/Localizable.strings
gfx/src/mac/printerplugin/Resources/English.lproj/PrintDialogPDE.r
js/src/Makefile.in
js/src/js.cpp
js/src/jsapi.cpp
js/src/jscntxt.cpp
js/src/jsdbgapi.cpp
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsgc.cpp
js/src/jsinterp.cpp
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsopcode.cpp
js/src/jsregexp.cpp
js/src/jsstr.cpp
js/src/jsxml.cpp
layout/tools/ColorNames.txt
layout/tools/HTMLTags.txt
layout/tools/Makefile.in
layout/tools/genhash.inc
layout/tools/genhash.pl
parser/htmlparser/robot/Makefile.in
parser/htmlparser/robot/nsDebugRobot.cpp
parser/htmlparser/robot/nsIRobotSink.h
parser/htmlparser/robot/nsIRobotSinkObserver.h
parser/htmlparser/robot/nsRobotSink.cpp
parser/htmlparser/robot/test/Makefile.in
parser/htmlparser/robot/test/RobotMain.cpp
toolkit/toolkit-makefiles.sh
uriloader/exthandler/tests/unit/test_handlerService.js
--- a/Makefile.in
+++ b/Makefile.in
@@ -70,17 +70,17 @@ include $(topsrcdir)/$(MOZ_BUILD_APP)/bu
 
 TIERS += testharness
 
 # test harnesses
 ifdef ENABLE_TESTS
 tier_testharness_dirs += tools/test-harness
 endif
 
-GARBAGE_DIRS += dist _javagen _tests staticlib
+GARBAGE_DIRS += dist _javagen _profile _tests staticlib
 DIST_GARBAGE = config.cache config.log config.status config-defs.h \
    dependencies.beos config/autoconf.mk config/myrules.mk config/myconfig.mk \
    unallmakefiles mozilla-config.h \
    netwerk/necko-config.h xpcom/xpcom-config.h xpcom/xpcom-private.h \
    $(topsrcdir)/.mozconfig.mk $(topsrcdir)/.mozconfig.out
 
 # Build pseudo-external modules first when export is explicitly called
 export::
@@ -157,17 +157,17 @@ ifdef UNIVERSAL_BINARY
 MAKE_SYM_STORE_ARGS := -a "ppc i386" --vcs-info
 MAKE_SYM_STORE_PATH := $(DIST)/universal
 else
 MAKE_SYM_STORE_ARGS := -a $(OS_TEST) --vcs-info
 MAKE_SYM_STORE_PATH := $(DIST)/bin
 endif
 DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
 endif
-ifeq ($(OS_ARCH),Linux)
+ifeq (,$(filter-out Linux SunOS,$(OS_ARCH)))
 MAKE_SYM_STORE_ARGS := --vcs-info
 DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
 MAKE_SYM_STORE_PATH := $(DIST)/bin
 endif
 
 ifdef MOZ_SYMBOLS_EXTRA_BUILDID
 EXTRA_BUILDID := -$(MOZ_SYMBOLS_EXTRA_BUILDID)
 endif
--- a/accessible/public/nsPIAccessible.idl
+++ b/accessible/public/nsPIAccessible.idl
@@ -112,10 +112,18 @@ interface nsPIAccessible : nsISupports
                     
   /**
    * Set the ARIA role map entry for a new accessible.
    * For a newly created accessible, specify which role map entry should be used.
    * @param aRoleMapEntry The ARIA nsRoleMapEntry* for the accessible, or 
    *                      nsnull if none.
    */
    void setRoleMapEntry(in nsRoleMapEntryPtr aRoleMapEntry);
+
+  /**
+   * Maps ARIA state attributes to state of accessible. Note the given state
+   * argument should hold states for accessible before you pass it into this
+   * method.
+   * @param  in/out where to fill the states into.
+   */
+   void getARIAState(out unsigned long aState);
 };
 
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -229,8 +229,13 @@ ACCESSIBILITY_ATOM(aria_valuetext, "aria
 // of an HTML button from the button frame
 ACCESSIBILITY_ATOM(defaultLabel, "defaultLabel")
 
 // Object attributes
 ACCESSIBILITY_ATOM(level, "level")
 ACCESSIBILITY_ATOM(posinset, "posinset") 
 ACCESSIBILITY_ATOM(setsize, "setsize")
 ACCESSIBILITY_ATOM(lineNumber, "line-number")
+ACCESSIBILITY_ATOM(containerRelevant, "container-relevant")
+ACCESSIBILITY_ATOM(containerLive, "container-live")
+ACCESSIBILITY_ATOM(containerChannel, "container-channel")
+ACCESSIBILITY_ATOM(containerAtomic, "container-atomic")
+ACCESSIBILITY_ATOM(containerBusy, "container-busy")
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -448,16 +448,20 @@ nsAccessibilityService::CreateRootAccess
   else {
     *aRootAcc = new nsRootAccessibleWrap(rootNode, weakShell);
   }
   if (!*aRootAcc)
     return NS_ERROR_OUT_OF_MEMORY;
 
   nsCOMPtr<nsPIAccessNode> privateAccessNode(do_QueryInterface(*aRootAcc));
   privateAccessNode->Init();
+  nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(rootNode);
+  nsCOMPtr<nsPIAccessible> privateAccessible =
+    do_QueryInterface(privateAccessNode);
+  privateAccessible->SetRoleMapEntry(roleMapEntry);
 
   NS_ADDREF(*aRootAcc);
 
   return NS_OK;
 }
 
  /**
    * HTML widget creation
--- a/accessible/src/base/nsAccessibilityUtils.cpp
+++ b/accessible/src/base/nsAccessibilityUtils.cpp
@@ -314,31 +314,45 @@ nsAccUtils::FireAccEvent(PRUint32 aEvent
 
   return pAccessible->FireAccessibleEvent(event);
 }
 
 PRBool
 nsAccUtils::IsAncestorOf(nsIDOMNode *aPossibleAncestorNode,
                          nsIDOMNode *aPossibleDescendantNode)
 {
-  NS_ENSURE_TRUE(aPossibleAncestorNode, PR_FALSE);
-  NS_ENSURE_TRUE(aPossibleDescendantNode, PR_FALSE);
+  NS_ENSURE_TRUE(aPossibleAncestorNode && aPossibleDescendantNode, PR_FALSE);
 
   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;
 }
 
+PRBool
+nsAccUtils::AreSiblings(nsIDOMNode *aDOMNode1,
+                       nsIDOMNode *aDOMNode2)
+{
+  NS_ENSURE_TRUE(aDOMNode1 && aDOMNode2, PR_FALSE);
+
+  nsCOMPtr<nsIDOMNode> parentNode1, parentNode2;
+  if (NS_SUCCEEDED(aDOMNode1->GetParentNode(getter_AddRefs(parentNode1))) &&
+      NS_SUCCEEDED(aDOMNode2->GetParentNode(getter_AddRefs(parentNode2))) &&
+      parentNode1 == parentNode2) {
+    return PR_TRUE;
+  }
+  return PR_FALSE;
+}
+
 already_AddRefed<nsIAccessible>
 nsAccUtils::GetAncestorWithRole(nsIAccessible *aDescendant, PRUint32 aRole)
 {
   nsCOMPtr<nsIAccessible> parentAccessible = aDescendant, testRoleAccessible;
   while (NS_SUCCEEDED(parentAccessible->GetParent(getter_AddRefs(testRoleAccessible))) &&
          testRoleAccessible) {
     PRUint32 testRole;
     testRoleAccessible->GetFinalRole(&testRole);
@@ -928,8 +942,38 @@ nsAccUtils::IsARIAPropForObjectAttr(nsIA
          aAtom != nsAccessibilityAtoms::aria_relevant &&
          aAtom != nsAccessibilityAtoms::aria_required &&
          aAtom != nsAccessibilityAtoms::aria_selected &&
          aAtom != nsAccessibilityAtoms::aria_valuemax &&
          aAtom != nsAccessibilityAtoms::aria_valuemin &&
          aAtom != nsAccessibilityAtoms::aria_valuenow &&
          aAtom != nsAccessibilityAtoms::aria_valuetext;
 }
+
+void nsAccUtils::GetLiveContainerAttributes(nsIPersistentProperties *aAttributes,
+                                                nsIContent *aStartContent, nsIContent *aTopContent)
+{
+  nsAutoString atomic, live, relevant, channel, busy;
+  nsIContent *ancestor = aStartContent;
+  while (ancestor) {
+    if (relevant.IsEmpty() &&
+        ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_relevant, relevant))
+      SetAccAttr(aAttributes, nsAccessibilityAtoms::containerRelevant, relevant);
+    if (live.IsEmpty() &&
+        ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_live, live))
+      SetAccAttr(aAttributes, nsAccessibilityAtoms::containerLive, live);
+    if (channel.IsEmpty() &&
+        ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_channel, channel))
+      SetAccAttr(aAttributes, nsAccessibilityAtoms::containerChannel, channel);
+    if (atomic.IsEmpty() &&
+        ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_atomic, atomic))
+      SetAccAttr(aAttributes, nsAccessibilityAtoms::containerAtomic, atomic);
+    if (busy.IsEmpty() &&
+        ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_busy, busy))
+      SetAccAttr(aAttributes, nsAccessibilityAtoms::containerBusy, busy);
+    if (ancestor == aTopContent)
+      break;
+    ancestor = ancestor->GetParent();
+    if (!ancestor) {
+      ancestor = aTopContent; // Use <body>/<frameset>
+    }
+  }
+}
--- a/accessible/src/base/nsAccessibilityUtils.h
+++ b/accessible/src/base/nsAccessibilityUtils.h
@@ -144,16 +144,23 @@ public:
    * @param aPossibleAncestorNode -- node to test for ancestor-ness of aPossibleDescendantNode
    * @param 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);
 
   /**
+   * Are the first node and the second siblings?
+   * @return PR_TRUE if aDOMNode1 and aDOMNode2 have same parent
+   */
+   static PRBool AreSiblings(nsIDOMNode *aDOMNode1,
+                             nsIDOMNode *aDOMNode2);
+
+  /**
     * If an ancestor in this document exists with the given role, return it
     * @param aDescendant Descendant to start search with
     * @param aRole Role to find matching ancestor for
     * @return The ancestor accessible with the given role, or nsnull if no match is found
     */
    static already_AddRefed<nsIAccessible>
      GetAncestorWithRole(nsIAccessible *aDescendant, PRUint32 aRole);
 
@@ -361,12 +368,22 @@ public:
                                                     nsIContent *aLookContent,
                                                     nsIAtom **aRelationAttrs,
                                                     PRUint32 aAttrNum = 1,
                                                     nsIContent *aExcludeContent = nsnull,
                                                     nsIAtom *aTagType = nsAccessibilityAtoms::label);
   
   // Return PR_TRUE if the ARIA property should always be exposed as an object attribute
   static PRBool IsARIAPropForObjectAttr(nsIAtom *aAtom);
+
+
+  /**
+   * Get container-foo live region attributes for the given node
+   * @param aAttributes     Where to store the attributes
+   * @param aStartContent   Node to start from
+   * @param aTopContent     Node to end at
+   */
+  static void GetLiveContainerAttributes(nsIPersistentProperties *aAttributes,
+                                         nsIContent *aStartContent, nsIContent *aTopContent);
 };
 
 #endif
 
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -484,32 +484,31 @@ NS_IMETHODIMP nsAccessible::SetNextSibli
 {
   mNextSibling = aNextSibling? aNextSibling: DEAD_END_ACCESSIBLE;
   return NS_OK;
 }
 
 nsIContent *nsAccessible::GetRoleContent(nsIDOMNode *aDOMNode)
 {
   // Given the DOM node for an acessible, return content node that
-  // we should look at role string from
+  // we should look for ARIA properties on.
   // For non-document accessibles, this is the associated content node.
-  // For doc accessibles, first try the <body> if it's HTML and there is
-  // a role attribute used there.
+  // For doc accessibles, use the <body>/<frameset> if it's HTML.
   // For any other doc accessible , this is the document element.
   nsCOMPtr<nsIContent> content(do_QueryInterface(aDOMNode));
   if (!content) {
     nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(aDOMNode));
     if (domDoc) {
       nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(aDOMNode));
       if (htmlDoc) {
         nsCOMPtr<nsIDOMHTMLElement> bodyElement;
         htmlDoc->GetBody(getter_AddRefs(bodyElement));
         content = do_QueryInterface(bodyElement);
       }
-      if (!content) {
+      else {
         nsCOMPtr<nsIDOMElement> docElement;
         domDoc->GetDocumentElement(getter_AddRefs(docElement));
         content = do_QueryInterface(docElement);
       }
     }
   }
   return content;
 }
@@ -1998,82 +1997,58 @@ NS_IMETHODIMP nsAccessible::GetFinalRole
     }
   }
   return mDOMNode ? GetRole(aRole) : NS_ERROR_FAILURE;  // Node already shut down
 }
 
 NS_IMETHODIMP
 nsAccessible::GetAttributes(nsIPersistentProperties **aAttributes)
 {
-  NS_ENSURE_ARG_POINTER(aAttributes);
-  *aAttributes = nsnull;
-
+  NS_ENSURE_ARG_POINTER(aAttributes);  // In/out param. Created if necessary.
+  
   nsCOMPtr<nsIContent> content = GetRoleContent(mDOMNode);
   if (!content) {
     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);
+  nsCOMPtr<nsIPersistentProperties> attributes = *aAttributes;
+  if (!attributes) {
+    // Create only if an array wasn't already passed in
+    attributes = do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
+    NS_ENSURE_TRUE(attributes, NS_ERROR_OUT_OF_MEMORY);
+    NS_ADDREF(*aAttributes = attributes);
+  }
  
   nsresult rv = GetAttributesInternal(attributes);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoString id;
   nsAutoString oldValueUnused;
   if (nsAccUtils::GetID(content, id)) {
+    // Expose ID. If an <iframe id> exists override the one on the <body> of the source doc,
+    // because the specific instance is what makes the ID useful for scripts
     attributes->SetStringProperty(NS_LITERAL_CSTRING("id"), id, oldValueUnused);
   }
   
-  nsAutoString _class;
-  if (content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::_class, _class))
-    nsAccUtils::SetAccAttr(attributes, nsAccessibilityAtoms::_class, _class);
-
   nsAutoString xmlRoles;
   if (content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::role, xmlRoles)) {
     attributes->SetStringProperty(NS_LITERAL_CSTRING("xml-roles"),  xmlRoles, oldValueUnused);          
   }
 
   nsCOMPtr<nsIAccessibleValue> supportsValue = do_QueryInterface(static_cast<nsIAccessible*>(this));
   if (supportsValue) {
     // We support values, so expose the string value as well, via the valuetext object attribute
     // We test for the value interface because we don't want to expose traditional get_accValue()
     // information such as URL's on links and documents, or text in an input
     nsAutoString valuetext;
     GetValue(valuetext);
     attributes->SetStringProperty(NS_LITERAL_CSTRING("valuetext"), valuetext, oldValueUnused);
   }
 
 
-  // Get container-foo computed live region properties based on the closest container with
-  // the live region attribute
-  nsAutoString atomic, live, relevant, channel, busy;
-  nsIContent *ancestor = content;
-  while (ancestor) {
-    if (relevant.IsEmpty() &&
-        ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_relevant, relevant))
-      attributes->SetStringProperty(NS_LITERAL_CSTRING("container-relevant"), relevant, oldValueUnused);
-    if (live.IsEmpty() &&
-        ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_live, live))
-      attributes->SetStringProperty(NS_LITERAL_CSTRING("container-live"), live, oldValueUnused);
-    if (channel.IsEmpty() &&
-        ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_channel, channel))
-      attributes->SetStringProperty(NS_LITERAL_CSTRING("container-channel"), channel, oldValueUnused);
-    if (atomic.IsEmpty() &&
-        ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_atomic, atomic))
-      attributes->SetStringProperty(NS_LITERAL_CSTRING("container-atomic"), atomic, oldValueUnused);
-    if (busy.IsEmpty() &&
-        ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_busy, busy))
-      attributes->SetStringProperty(NS_LITERAL_CSTRING("container-busy"), busy, oldValueUnused);
-    ancestor = ancestor->GetParent();
-  }
-
   PRUint32 role = Role(this);
   if (role == nsIAccessibleRole::ROLE_CHECKBUTTON ||
       role == nsIAccessibleRole::ROLE_PUSHBUTTON ||
       role == nsIAccessibleRole::ROLE_MENUITEM ||
       role == nsIAccessibleRole::ROLE_LISTITEM ||
       role == nsIAccessibleRole::ROLE_OUTLINEITEM ||
       content->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_checked)) {
     // Might be checkable -- checking role & ARIA attribute first is faster than getting state
@@ -2163,35 +2138,75 @@ nsAccessible::GetAttributes(nsIPersisten
         continue; // No need to expose obj attribute -- will be exposed some other way
       nsAutoString value;
       if (content->GetAttr(kNameSpaceID_None, attrAtom, value)) {
         attributes->SetStringProperty(nsDependentCString(attrStr + 5), value, oldValueUnused);
       }
     }
   }
 
-  attributes.swap(*aAttributes);
-
   return NS_OK;
 }
 
 nsresult
 nsAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
 {
-  nsCOMPtr<nsIDOMElement> element(do_QueryInterface(GetRoleContent(mDOMNode)));
+  // Attributes set by this method will not be used to override attributes on a sub-document accessible
+  // when there is a <frame>/<iframe> element that spawned the sub-document
+  nsIContent *content = GetRoleContent(mDOMNode);
+  nsCOMPtr<nsIDOMElement> element(do_QueryInterface(content));
   NS_ENSURE_TRUE(element, NS_ERROR_UNEXPECTED);
 
   nsAutoString tagName;
   element->GetTagName(tagName);
   if (!tagName.IsEmpty()) {
     nsAutoString oldValueUnused;
     aAttributes->SetStringProperty(NS_LITERAL_CSTRING("tag"), tagName,
                                    oldValueUnused);
   }
 
+  nsAccEvent::GetLastEventAttributes(mDOMNode, aAttributes);
+ 
+  // Expose class because it may have useful microformat information
+  // Let the class from an iframe's document be exposed, don't override from <iframe class>
+  nsAutoString _class;
+  if (content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::_class, _class))
+    nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::_class, _class);
+
+  // Get container-foo computed live region properties based on the closest container with
+  // the live region attribute. 
+  // Inner nodes override outer nodes within the same document --
+  //   The inner nodes can be used to override live region behavior on more general outer nodes
+  // However, nodes in outer documents override nodes in inner documents:
+  //   Outer doc author may want to override properties on a widget they used in an iframe
+  nsCOMPtr<nsIDOMNode> startNode = mDOMNode;
+  nsIContent *startContent = content;
+  while (PR_TRUE) {
+    NS_ENSURE_STATE(startContent);
+    nsIDocument *doc = startContent->GetDocument();
+    nsCOMPtr<nsIDOMNode> docNode = do_QueryInterface(doc);
+    NS_ENSURE_STATE(docNode);
+    nsIContent *topContent = GetRoleContent(docNode);
+    NS_ENSURE_STATE(topContent);
+    nsAccUtils::GetLiveContainerAttributes(aAttributes, startContent, topContent);
+    // Allow ARIA live region markup from outer documents to override
+    nsCOMPtr<nsISupports> container = doc->GetContainer();
+    nsIDocShellTreeItem *docShellTreeItem = nsnull;
+    if (container)
+      CallQueryInterface(container, &docShellTreeItem);
+    if (!docShellTreeItem)
+      break;
+    nsIDocShellTreeItem *sameTypeParent = nsnull;
+    docShellTreeItem->GetSameTypeParent(&sameTypeParent);
+    if (!sameTypeParent || sameTypeParent == docShellTreeItem)
+      break;
+    nsIDocument *parentDoc = doc->GetParentDocument();
+    startContent = parentDoc->FindContentForSubDocument(doc);      
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccessible::GroupPosition(PRInt32 *aGroupLevel,
                             PRInt32 *aSimilarItemsInGroup,
                             PRInt32 *aPositionInGroup)
 {
@@ -2261,17 +2276,17 @@ NS_IMETHODIMP
 nsAccessible::GetFinalState(PRUint32 *aState, PRUint32 *aExtraState)
 {
   NS_ENSURE_ARG_POINTER(aState);
 
   nsresult rv = GetState(aState, aExtraState);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Apply ARIA states to be sure accessible states will be overriden.
-  *aState |= GetARIAState();
+  GetARIAState(aState);
 
   if (mRoleMapEntry && mRoleMapEntry->role == nsIAccessibleRole::ROLE_PAGETAB) {
     if (*aState & nsIAccessibleStates::STATE_FOCUSED) {
       *aState |= nsIAccessibleStates::STATE_SELECTED;
     } else {
       // Expose 'selected' state on ARIA tab if the focus is on internal element
       // of related tabpanel.
       nsCOMPtr<nsIAccessible> tabPanel;
@@ -2386,49 +2401,49 @@ nsAccessible::GetFinalState(PRUint32 *aS
     else {
       *aExtraState |= nsIAccessibleStates::EXT_STATE_HORIZONTAL;
     }
   }
 
   return NS_OK;
 }
 
-PRUint32
-nsAccessible::GetARIAState()
+nsresult
+nsAccessible::GetARIAState(PRUint32 *aState)
 {
   // Test for universal states first
   nsIContent *content = GetRoleContent(mDOMNode);
   if (!content) {
-    return 0;
+    return NS_OK;
   }
 
   PRUint32 ariaState = 0;
   PRUint32 index = 0;
-  while (MappedAttrState(content, &ariaState, &nsARIAMap::gWAIUnivStateMap[index])) {
+  while (MappedAttrState(content, aState, &nsARIAMap::gWAIUnivStateMap[index])) {
     ++ index;
   }
 
   if (!mRoleMapEntry)
-    return ariaState;
+    return NS_OK;
 
   // Once DHTML role is used, we're only readonly if DHTML readonly used
   ariaState &= ~nsIAccessibleStates::STATE_READONLY;
 
   ariaState |= mRoleMapEntry->state;
-  if (MappedAttrState(content, &ariaState, &mRoleMapEntry->attributeMap1) &&
-      MappedAttrState(content, &ariaState, &mRoleMapEntry->attributeMap2) &&
-      MappedAttrState(content, &ariaState, &mRoleMapEntry->attributeMap3) &&
-      MappedAttrState(content, &ariaState, &mRoleMapEntry->attributeMap4) &&
-      MappedAttrState(content, &ariaState, &mRoleMapEntry->attributeMap5) &&
-      MappedAttrState(content, &ariaState, &mRoleMapEntry->attributeMap6) &&
-      MappedAttrState(content, &ariaState, &mRoleMapEntry->attributeMap7)) {
-    MappedAttrState(content, &ariaState, &mRoleMapEntry->attributeMap8);
+  if (MappedAttrState(content, aState, &mRoleMapEntry->attributeMap1) &&
+      MappedAttrState(content, aState, &mRoleMapEntry->attributeMap2) &&
+      MappedAttrState(content, aState, &mRoleMapEntry->attributeMap3) &&
+      MappedAttrState(content, aState, &mRoleMapEntry->attributeMap4) &&
+      MappedAttrState(content, aState, &mRoleMapEntry->attributeMap5) &&
+      MappedAttrState(content, aState, &mRoleMapEntry->attributeMap6) &&
+      MappedAttrState(content, aState, &mRoleMapEntry->attributeMap7)) {
+    MappedAttrState(content, aState, &mRoleMapEntry->attributeMap8);
   }
 
-  return ariaState;
+  return NS_OK;
 }
 
 // Not implemented by this class
 
 /* DOMString getValue (); */
 NS_IMETHODIMP nsAccessible::GetValue(nsAString& aValue)
 {
   if (!mDOMNode) {
@@ -2548,43 +2563,89 @@ nsAccessible::GetKeyBindings(PRUint8 aAc
 NS_IMETHODIMP nsAccessible::GetRole(PRUint32 *aRole)
 {
   NS_ENSURE_ARG_POINTER(aRole);
   *aRole = nsIAccessibleRole::ROLE_NOTHING;
   return NS_OK;
 }
 
 /* PRUint8 getAccNumActions (); */
-NS_IMETHODIMP nsAccessible::GetNumActions(PRUint8 *aNumActions)
+NS_IMETHODIMP
+nsAccessible::GetNumActions(PRUint8 *aNumActions)
 {
+  NS_ENSURE_ARG_POINTER(aNumActions);
   *aNumActions = 0;
+
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
+  PRBool isOnclick = nsAccUtils::HasListener(content,
+                                             NS_LITERAL_STRING("click"));
+
+  if (isOnclick)
+    *aNumActions = 1;
+  
   return NS_OK;
 }
 
 /* DOMString getAccActionName (in PRUint8 index); */
-NS_IMETHODIMP nsAccessible::GetActionName(PRUint8 index, nsAString& aName)
+NS_IMETHODIMP
+nsAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
 {
-  return NS_ERROR_FAILURE;
+  aName.Truncate();
+
+  if (aIndex != 0)
+    return NS_ERROR_INVALID_ARG;
+
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
+  PRBool isOnclick = nsAccUtils::HasListener(content,
+                                             NS_LITERAL_STRING("click"));
+  
+  if (isOnclick) {
+    aName.AssignLiteral("click");
+    return NS_OK;
+  }
+
+  return NS_ERROR_INVALID_ARG;
 }
 
 /* DOMString getActionDescription (in PRUint8 index); */
-NS_IMETHODIMP nsAccessible::GetActionDescription(PRUint8 aIndex, nsAString& aDescription)
+NS_IMETHODIMP
+nsAccessible::GetActionDescription(PRUint8 aIndex, nsAString& aDescription)
 {
   // default to localized action name.
   nsAutoString name;
   nsresult rv = GetActionName(aIndex, name);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return GetTranslatedString(name, aDescription);
 }
 
 /* void doAction (in PRUint8 index); */
-NS_IMETHODIMP nsAccessible::DoAction(PRUint8 index)
+NS_IMETHODIMP
+nsAccessible::DoAction(PRUint8 aIndex)
 {
-  return NS_ERROR_FAILURE;
+  if (aIndex != 0)
+    return NS_ERROR_INVALID_ARG;
+
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
+  PRBool isOnclick = nsAccUtils::HasListener(content,
+                                             NS_LITERAL_STRING("click"));
+  
+  if (isOnclick)
+    return DoCommand(content);
+
+  return NS_ERROR_INVALID_ARG;
 }
 
 /* DOMString getHelp (); */
 NS_IMETHODIMP nsAccessible::GetHelp(nsAString& _retval)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -125,23 +125,16 @@ public:
   NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
 
   /**
    * Returns attributes for accessible without explicitly setted ARIA
    * attributes.
    */
   virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
 
-  /**
-   * Maps ARIA state attributes to state of accessible. Note the given state
-   * argument should hold states for accessible before you pass it into this
-   * method.
-   */
-  PRUint32 GetARIAState();
-
 #ifdef DEBUG_A11Y
   static PRBool IsTextInterfaceSupportCorrect(nsIAccessible *aAccessible);
 #endif
 
   static PRBool IsCorrectFrameType(nsIFrame* aFrame, nsIAtom* aAtom);
   static PRUint32 State(nsIAccessible *aAcc) { PRUint32 state = 0; if (aAcc) aAcc->GetFinalState(&state, nsnull); return state; }
   static PRUint32 Role(nsIAccessible *aAcc) { PRUint32 role = nsIAccessibleRole::ROLE_NOTHING; if (aAcc) aAcc->GetFinalRole(&role); return role; }
   static PRBool IsText(nsIAccessible *aAcc) { PRUint32 role = Role(aAcc); return role == nsIAccessibleRole::ROLE_TEXT_LEAF || role == nsIAccessibleRole::ROLE_STATICTEXT; }
--- a/accessible/src/base/nsAccessibleEventData.cpp
+++ b/accessible/src/base/nsAccessibleEventData.cpp
@@ -52,28 +52,28 @@
 #include "nsIAccessibleText.h"
 #include "nsIContent.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 
 PRBool nsAccEvent::gLastEventFromUserInput = PR_FALSE;
 nsIDOMNode* nsAccEvent::gLastEventNodeWeak = 0;
 
-NS_IMPL_ISUPPORTS1(nsAccEvent, nsIAccessibleEvent)
+NS_IMPL_ISUPPORTS2(nsAccEvent, nsAccEvent, nsIAccessibleEvent)
 
 nsAccEvent::nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
-                       PRBool aIsAsynch):
-  mEventType(aEventType), mAccessible(aAccessible)
+                       PRBool aIsAsynch, EEventRule aEventRule):
+  mEventType(aEventType), mAccessible(aAccessible), mEventRule(aEventRule)
 {
   CaptureIsFromUserInput(aIsAsynch);
 }
 
 nsAccEvent::nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode,
-                       PRBool aIsAsynch):
-  mEventType(aEventType), mDOMNode(aDOMNode)
+                       PRBool aIsAsynch, EEventRule aEventRule):
+  mEventType(aEventType), mDOMNode(aDOMNode), mEventRule(aEventRule)
 {
   CaptureIsFromUserInput(aIsAsynch);
 }
 
 void nsAccEvent::GetLastEventAttributes(nsIDOMNode *aNode,
                                         nsIPersistentProperties *aAttributes)
 {
   if (aNode == gLastEventNodeWeak) {
@@ -277,16 +277,104 @@ nsAccEvent::GetAccessibleByNode()
       }
     }
   }
 #endif
 
   return accessible;
 }
 
+/* static */
+void
+nsAccEvent::ApplyEventRules(nsCOMArray<nsIAccessibleEvent> &aEventsToFire)
+{
+  PRUint32 numQueuedEvents = aEventsToFire.Count();
+  for (PRInt32 tail = numQueuedEvents - 1; tail >= 0; tail --) {
+    nsRefPtr<nsAccEvent> tailEvent = GetAccEventPtr(aEventsToFire[tail]);
+    switch(tailEvent->mEventRule) {
+      case nsAccEvent::eCoalesceFromSameSubtree:
+      {
+        for (PRInt32 index = 0; index < tail; index ++) {
+          nsRefPtr<nsAccEvent> thisEvent = GetAccEventPtr(aEventsToFire[index]);
+          if (thisEvent->mEventType != tailEvent->mEventType)
+            continue; // Different type
+
+          if (thisEvent->mEventRule == nsAccEvent::eAllowDupes ||
+              thisEvent->mEventRule == nsAccEvent::eDoNotEmit)
+            continue; //  Do not need to check
+
+          if (thisEvent->mDOMNode == tailEvent->mDOMNode) {
+            // Dupe
+            thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
+            continue;
+          }
+          if (nsAccUtils::IsAncestorOf(tailEvent->mDOMNode,
+                                       thisEvent->mDOMNode)) {
+            // thisDOMNode is a descendant of tailDOMNode
+            // Do not emit thisEvent, also apply this result to sibling
+            // nodes of thisDOMNode.
+            thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
+            ApplyToSiblings(aEventsToFire, 0, index, thisEvent->mEventType,
+                            thisEvent->mDOMNode, nsAccEvent::eDoNotEmit);
+            continue;
+          }
+          if (nsAccUtils::IsAncestorOf(thisEvent->mDOMNode,
+                                       tailEvent->mDOMNode)) {
+            // tailDOMNode is a descendant of thisDOMNode
+            // Do not emit tailEvent, also apply this result to sibling
+            // nodes of tailDOMNode.
+            tailEvent->mEventRule = nsAccEvent::eDoNotEmit;
+            ApplyToSiblings(aEventsToFire, 0, tail, tailEvent->mEventType,
+                            tailEvent->mDOMNode, nsAccEvent::eDoNotEmit);
+            break;
+          }
+        } // for (index)
+
+        if (tailEvent->mEventRule != nsAccEvent::eDoNotEmit) {
+          // Not in another event node's subtree, and no other event is in
+          // this event node's subtree.
+          // This event should be emitted
+          // Apply this result to sibling nodes of tailDOMNode
+          ApplyToSiblings(aEventsToFire, 0, tail, tailEvent->mEventType,
+                          tailEvent->mDOMNode, nsAccEvent::eAllowDupes);
+        }
+      } break; // case eCoalesceFromSameSubtree
+
+      case nsAccEvent::eRemoveDupes:
+      {
+        // Check for repeat events.
+        for (PRInt32 index = 0; index < tail; index ++) {
+          nsRefPtr<nsAccEvent> accEvent = GetAccEventPtr(aEventsToFire[index]);
+          if (accEvent->mEventType == tailEvent->mEventType &&
+              accEvent->mEventRule == tailEvent->mEventRule &&
+              accEvent->mDOMNode == tailEvent->mDOMNode) {
+            accEvent->mEventRule = nsAccEvent::eDoNotEmit;
+          }
+        }
+      } break; // case eRemoveDupes
+    } // switch
+  } // for (tail)
+}
+
+/* static */
+void
+nsAccEvent::ApplyToSiblings(nsCOMArray<nsIAccessibleEvent> &aEventsToFire,
+                            PRUint32 aStart, PRUint32 aEnd,
+                             PRUint32 aEventType, nsIDOMNode* aDOMNode,
+                             EEventRule aEventRule)
+{
+  for (PRUint32 index = aStart; index < aEnd; index ++) {
+    nsRefPtr<nsAccEvent> accEvent = GetAccEventPtr(aEventsToFire[index]);
+    if (accEvent->mEventType == aEventType &&
+        accEvent->mEventRule != nsAccEvent::eDoNotEmit &&
+        nsAccUtils::AreSiblings(accEvent->mDOMNode, aDOMNode)) {
+      accEvent->mEventRule = aEventRule;
+    }
+  }
+}
 
 // nsAccStateChangeEvent
 NS_IMPL_ISUPPORTS_INHERITED1(nsAccStateChangeEvent, nsAccEvent,
                              nsIAccessibleStateChangeEvent)
 
 nsAccStateChangeEvent::
   nsAccStateChangeEvent(nsIAccessible *aAccessible,
                         PRUint32 aState, PRBool aIsExtraState,
--- a/accessible/src/base/nsAccessibleEventData.h
+++ b/accessible/src/base/nsAccessibleEventData.h
@@ -36,56 +36,106 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsAccessibleEventData_H_
 #define _nsAccessibleEventData_H_
 
+#include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
+#include "nsCOMArray.h"
 #include "nsIAccessibleEvent.h"
 #include "nsIAccessible.h"
 #include "nsIAccessibleDocument.h"
 #include "nsIDOMNode.h"
 #include "nsString.h"
 
 class nsIPresShell;
 
+#define NS_ACCEVENT_IMPL_CID                            \
+{  /* 55b89892-a83d-4252-ba78-cbdf53a86936 */           \
+  0x55b89892,                                           \
+  0xa83d,                                               \
+  0x4252,                                               \
+  { 0xba, 0x78, 0xcb, 0xdf, 0x53, 0xa8, 0x69, 0x36 }    \
+}
+
 class nsAccEvent: public nsIAccessibleEvent
 {
 public:
+
+  // Rule for accessible events.
+  // The rule will be applied when flushing pending events.
+  enum EEventRule {
+     // eAllowDupes : More than one event of the same type is allowed.
+     //    This event will always be emitted.
+     eAllowDupes,
+     // eCoalesceFromSameSubtree : For events of the same type from the same
+     //    subtree or the same node, only the umbrelle event on the ancestor
+     //    will be emitted.
+     eCoalesceFromSameSubtree,
+     // eRemoveDupes : For repeat events, only the newest event in queue
+     //    will be emitted.
+     eRemoveDupes,
+     // eDoNotEmit : This event is confirmed as a duplicate, do not emit it.
+     eDoNotEmit
+   };
+
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_ACCEVENT_IMPL_CID)
+
   // Initialize with an nsIAccessible
-  nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible, PRBool aIsAsynch = PR_FALSE);
+  nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
+             PRBool aIsAsynch = PR_FALSE,
+             EEventRule aEventRule = eRemoveDupes);
   // Initialize with an nsIDOMNode
-  nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode, PRBool aIsAsynch = PR_FALSE);
+  nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode,
+             PRBool aIsAsynch = PR_FALSE,
+             EEventRule aEventRule = eRemoveDupes);
   virtual ~nsAccEvent() {}
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIACCESSIBLEEVENT
 
   static void GetLastEventAttributes(nsIDOMNode *aNode,
                                      nsIPersistentProperties *aAttributes);
 
 protected:
   already_AddRefed<nsIAccessible> GetAccessibleByNode();
 
   void CaptureIsFromUserInput(PRBool aIsAsynch);
   PRBool mIsFromUserInput;
 
 private:
   PRUint32 mEventType;
+  EEventRule mEventRule;
   nsCOMPtr<nsIAccessible> mAccessible;
   nsCOMPtr<nsIDOMNode> mDOMNode;
   nsCOMPtr<nsIAccessibleDocument> mDocAccessible;
 
   static PRBool gLastEventFromUserInput;
   static nsIDOMNode* gLastEventNodeWeak;
 
 public:
+  static PRUint32 EventType(nsIAccessibleEvent *aAccEvent) {
+    PRUint32 eventType;
+    aAccEvent->GetEventType(&eventType);
+    return eventType;
+  }
+  static EEventRule EventRule(nsIAccessibleEvent *aAccEvent) {
+    nsRefPtr<nsAccEvent> accEvent = GetAccEventPtr(aAccEvent);
+    return accEvent->mEventRule;
+  }
+  static PRBool IsFromUserInput(nsIAccessibleEvent *aAccEvent) {
+    PRBool isFromUserInput;
+    aAccEvent->GetIsFromUserInput(&isFromUserInput);
+    return isFromUserInput;
+  }
+
   static void ResetLastInputState()
    {gLastEventFromUserInput = PR_FALSE; gLastEventNodeWeak = nsnull; }
 
   /**
    * 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.
@@ -98,18 +148,51 @@ public:
 
   /**
    * 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,
                               PRBool aForceIsFromUserInput = PR_FALSE);
+
+  /**
+   * Apply event rules to pending events, this method is called in
+   * FlushingPendingEvents().
+   * Result of this method:
+   *   Event rule of filtered events will be set to eDoNotEmit.
+   *   Events with other event rule are good to emit.
+   */
+  static void ApplyEventRules(nsCOMArray<nsIAccessibleEvent> &aEventsToFire);
+
+private:
+  static already_AddRefed<nsAccEvent> GetAccEventPtr(nsIAccessibleEvent *aAccEvent) {
+    nsAccEvent* accEvent = nsnull;
+    aAccEvent->QueryInterface(NS_GET_IID(nsAccEvent), (void**)&accEvent);
+    return accEvent;
+  }
+
+  /**
+   * Apply aEventRule to same type event that from sibling nodes of aDOMNode.
+   * @param aEventsToFire    array of pending events
+   * @param aStart           start index of pending events to be scanned
+   * @param aEnd             end index to be scanned (not included)
+   * @param aEventType       target event type
+   * @param aDOMNode         target are siblings of this node
+   * @param aEventRule       the event rule to be applied
+   *                         (should be eDoNotEmit or eAllowDupes)
+   */
+  static void ApplyToSiblings(nsCOMArray<nsIAccessibleEvent> &aEventsToFire,
+                              PRUint32 aStart, PRUint32 aEnd,
+                              PRUint32 aEventType, nsIDOMNode* aDOMNode,
+                              EEventRule aEventRule);
 };
 
+NS_DEFINE_STATIC_IID_ACCESSOR(nsAccEvent, NS_ACCEVENT_IMPL_CID)
+
 class nsAccStateChangeEvent: public nsAccEvent,
                              public nsIAccessibleStateChangeEvent
 {
 public:
   nsAccStateChangeEvent(nsIAccessible *aAccessible,
                         PRUint32 aState, PRBool aIsExtraState,
                         PRBool aIsEnabled);
 
--- a/accessible/src/base/nsBaseWidgetAccessible.cpp
+++ b/accessible/src/base/nsBaseWidgetAccessible.cpp
@@ -16,16 +16,17 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   John Gaunt (jgaunt@netscape.com)
+ *   Alexander Surkov <surkov.alexander@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
@@ -88,211 +89,226 @@ NS_IMETHODIMP nsLeafAccessible::GetChild
 /* readonly attribute boolean allowsAnonChildAccessibles; */
 NS_IMETHODIMP
 nsLeafAccessible::GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren)
 {
   *aAllowsAnonChildren = PR_FALSE;
   return NS_OK;
 }
 
-//----------------
+////////////////////////////////////////////////////////////////////////////////
 // nsLinkableAccessible
-//----------------
 
-nsLinkableAccessible::nsLinkableAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell) :
+nsLinkableAccessible::
+  nsLinkableAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell) :
   nsHyperTextAccessibleWrap(aNode, aShell),
   mActionContent(nsnull),
   mIsLink(PR_FALSE),
   mIsOnclick(PR_FALSE)
 {
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(nsLinkableAccessible, nsHyperTextAccessibleWrap)
 
-NS_IMETHODIMP nsLinkableAccessible::TakeFocus()
-{ 
-  if (mActionContent && mActionContent->IsFocusable()) {
-    nsCOMPtr<nsIDOMNSHTMLElement> htmlElement(do_QueryInterface(mActionContent));
-    if (htmlElement) {
-      // HTML Elements also set the caret position
-      // in order to affect tabbing order
-      return htmlElement->Focus();
-    }
-    NS_WARNING("Has action content that is not an HTML element");
-  }
-  
+////////////////////////////////////////////////////////////////////////////////
+// nsLinkableAccessible. nsIAccessible
+
+NS_IMETHODIMP
+nsLinkableAccessible::TakeFocus()
+{
+  nsCOMPtr<nsIAccessible> actionAcc = GetActionAccessible();
+  if (actionAcc)
+    return actionAcc->TakeFocus();
+
   return NS_OK;
 }
 
-/* long GetState (); */
 NS_IMETHODIMP
 nsLinkableAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
 {
   nsresult rv = nsHyperTextAccessibleWrap::GetState(aState, aExtraState);
   NS_ENSURE_SUCCESS(rv, rv);
-  if (!mDOMNode)
-    return NS_OK;
 
   if (mIsLink) {
     *aState |= nsIAccessibleStates::STATE_LINKED;
-    nsCOMPtr<nsILink> link = do_QueryInterface(mActionContent);
-    if (link) {
-      nsLinkState linkState;
-      link->GetLinkState(linkState);
-      if (linkState == eLinkState_Visited) {
-        *aState |= nsIAccessibleStates::STATE_TRAVERSED;
-      }
-    }
+    nsCOMPtr<nsIAccessible> actionAcc = GetActionAccessible();
+    if (actionAcc && (State(actionAcc) & nsIAccessibleStates::STATE_TRAVERSED))
+      *aState |= nsIAccessibleStates::STATE_TRAVERSED;
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP nsLinkableAccessible::GetValue(nsAString& aValue)
+NS_IMETHODIMP
+nsLinkableAccessible::GetValue(nsAString& aValue)
 {
   aValue.Truncate();
+
   nsHyperTextAccessible::GetValue(aValue);
   if (!aValue.IsEmpty())
     return NS_OK;
 
   if (mIsLink) {
-    nsCOMPtr<nsIDOMNode> linkNode(do_QueryInterface(mActionContent));
-    nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
-    if (linkNode && presShell)
-      return presShell->GetLinkLocation(linkNode, aValue);
+    nsCOMPtr<nsIAccessible> actionAcc = GetActionAccessible();
+    if (actionAcc)
+      return actionAcc->GetValue(aValue);
   }
+
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 
-/* PRUint8 getAccNumActions (); */
-NS_IMETHODIMP nsLinkableAccessible::GetNumActions(PRUint8 *aNumActions)
+NS_IMETHODIMP
+nsLinkableAccessible::GetNumActions(PRUint8 *aNumActions)
 {
+  NS_ENSURE_ARG_POINTER(aNumActions);
+
   *aNumActions = mActionContent ? 1 : 0;
   return NS_OK;
 }
 
-/* nsAString GetActionName (in PRUint8 Aindex); */
-NS_IMETHODIMP nsLinkableAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
+NS_IMETHODIMP
+nsLinkableAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
 {
+  aName.Truncate();
+
   // Action 0 (default action): Jump to link
-  aName.Truncate();
   if (aIndex == eAction_Jump) {   
     if (mIsLink) {
       aName.AssignLiteral("jump");
       return NS_OK;
     }
     else if (mIsOnclick) {
       aName.AssignLiteral("click");
       return NS_OK;
     }
     return NS_ERROR_NOT_IMPLEMENTED;
   }
   return NS_ERROR_INVALID_ARG;
 }
 
-/* void accDoAction (in PRUint8 index); */
-NS_IMETHODIMP nsLinkableAccessible::DoAction(PRUint8 index)
+NS_IMETHODIMP
+nsLinkableAccessible::DoAction(PRUint8 aIndex)
 {
-  // Action 0 (default action): Jump to link
-  if (index == eAction_Jump) {
-    if (mActionContent) {
-      return DoCommand(mActionContent);
-    }
-  }
+  nsCOMPtr<nsIAccessible> actionAcc = GetActionAccessible();
+  if (actionAcc)
+    return actionAcc->DoAction(aIndex);
+
   return NS_ERROR_INVALID_ARG;
 }
 
-NS_IMETHODIMP nsLinkableAccessible::GetKeyboardShortcut(nsAString& aKeyboardShortcut)
+NS_IMETHODIMP
+nsLinkableAccessible::GetKeyboardShortcut(nsAString& aKeyboardShortcut)
 {
-  if (mActionContent) {
-    nsCOMPtr<nsIDOMNode> actionNode(do_QueryInterface(mActionContent));
-    if (actionNode && mDOMNode != actionNode) {
-      nsCOMPtr<nsIAccessible> accessible;
-      nsCOMPtr<nsIAccessibilityService> accService = 
-        do_GetService("@mozilla.org/accessibilityService;1");
-      accService->GetAccessibleInWeakShell(actionNode, mWeakShell,
-                                           getter_AddRefs(accessible));
-      if (accessible) {
-        accessible->GetKeyboardShortcut(aKeyboardShortcut);
-      }
-      return NS_OK;
-    }
-  }
+  aKeyboardShortcut.Truncate();
+
+  nsCOMPtr<nsIAccessible> actionAcc = GetActionAccessible();
+  if (actionAcc)
+    return actionAcc->GetKeyboardShortcut(aKeyboardShortcut);
+
   return nsAccessible::GetKeyboardShortcut(aKeyboardShortcut);
 }
 
-void nsLinkableAccessible::CacheActionContent()
+////////////////////////////////////////////////////////////////////////////////
+// nsLinkableAccessible. nsIAccessibleHyperLink
+
+NS_IMETHODIMP
+nsLinkableAccessible::GetURI(PRInt32 aIndex, nsIURI **aURI)
 {
-  for (nsCOMPtr<nsIContent> walkUpContent(do_QueryInterface(mDOMNode));
-       walkUpContent;
-       walkUpContent = walkUpContent->GetParent()) {
-    PRBool isOnclick = nsAccUtils::HasListener(walkUpContent, NS_LITERAL_STRING("click"));
-    nsIAtom *tag = walkUpContent->Tag();
-    if ((tag == nsAccessibilityAtoms::a || tag == nsAccessibilityAtoms::area) &&
-        walkUpContent->IsNodeOfType(nsINode::eHTML)) {
-      nsCOMPtr<nsILink> link = do_QueryInterface(walkUpContent);
-      if (link) {
-        // Currently we do not expose <link> tags, because they are not typically
-        // in <body> and rendered.
-        // We do not yet support xlinks
-        nsCOMPtr<nsIURI> uri;
-        link->GetHrefURI(getter_AddRefs(uri));
-        if (uri) {
-          mActionContent = walkUpContent;
-          mIsLink = PR_TRUE;
-          break;
-        }
-      }
-      if (SameCOMIdentity(mDOMNode, walkUpContent)) {
-        // This is the element that caused the creation of a linkable accessible
-        // Don't let it keep walking up, otherwise we may report the wrong container
-        // as the action node
-        mActionContent = walkUpContent;
-        mIsOnclick = isOnclick;
-        break;
-      }
-    }
-    if (isOnclick) {
-      mActionContent = walkUpContent;
-      mIsOnclick = PR_TRUE;
-      break;
+  if (mIsLink) {
+    nsCOMPtr<nsIAccessible> actionAcc = GetActionAccessible();
+    if (actionAcc) {
+      nsCOMPtr<nsIAccessibleHyperLink> hyperLinkAcc =
+        do_QueryInterface(actionAcc);
+      NS_ASSERTION(hyperLinkAcc,
+                   "nsIAccessibleHyperLink isn't implemented.");
+
+      if (hyperLinkAcc)
+        return hyperLinkAcc->GetURI(aIndex, aURI);
     }
   }
+  
+  return NS_ERROR_INVALID_ARG;
 }
 
-// nsIAccessibleHyperLink::GetURI()
-NS_IMETHODIMP nsLinkableAccessible::GetURI(PRInt32 aIndex, nsIURI **aURI)
-{
-  // XXX Also implement this for nsHTMLImageAccessible file names
-  *aURI = nsnull;
-  if (aIndex != 0 || !mIsLink || !SameCOMIdentity(mDOMNode, mActionContent)) {
-    return NS_ERROR_FAILURE;
-  }
+////////////////////////////////////////////////////////////////////////////////
+// nsLinkableAccessible. nsPIAccessNode
 
-  nsCOMPtr<nsILink> link(do_QueryInterface(mActionContent));
-  if (link) {
-    return link->GetHrefURI(aURI);
-  }
-
-  return NS_ERROR_FAILURE;
-}
-
-NS_IMETHODIMP nsLinkableAccessible::Init()
+NS_IMETHODIMP
+nsLinkableAccessible::Init()
 {
   CacheActionContent();
   return nsHyperTextAccessibleWrap::Init();
 }
 
-NS_IMETHODIMP nsLinkableAccessible::Shutdown()
+NS_IMETHODIMP
+nsLinkableAccessible::Shutdown()
 {
   mActionContent = nsnull;
   return nsHyperTextAccessibleWrap::Shutdown();
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// nsLinkableAccessible
+
+void
+nsLinkableAccessible::CacheActionContent()
+{
+  nsCOMPtr<nsIContent> walkUpContent(do_QueryInterface(mDOMNode));
+  PRBool isOnclick = nsAccUtils::HasListener(walkUpContent,
+                                             NS_LITERAL_STRING("click"));
+
+  if (isOnclick) {
+    mActionContent = walkUpContent;
+    mIsOnclick = PR_TRUE;
+    return;
+  }
+
+  while ((walkUpContent = walkUpContent->GetParent())) {
+    isOnclick = nsAccUtils::HasListener(walkUpContent,
+                                        NS_LITERAL_STRING("click"));
+  
+    nsCOMPtr<nsIDOMNode> walkUpNode(do_QueryInterface(walkUpContent));
+
+    nsCOMPtr<nsIAccessible> walkUpAcc;
+    GetAccService()->GetAccessibleInWeakShell(walkUpNode, mWeakShell,
+                                              getter_AddRefs(walkUpAcc));
+
+    if (walkUpAcc && Role(walkUpAcc) == nsIAccessibleRole::ROLE_LINK &&
+        (State(walkUpAcc) & nsIAccessibleStates::STATE_LINKED)) {
+      mIsLink = PR_TRUE;
+      mActionContent = walkUpContent;
+      return;
+    }
+
+    if (isOnclick) {
+      mActionContent = walkUpContent;
+      mIsOnclick = PR_TRUE;
+      return;
+    }
+  }
+}
+
+already_AddRefed<nsIAccessible>
+nsLinkableAccessible::GetActionAccessible()
+{
+  // Return accessible for the action content if it's different from node of
+  // this accessible. If the action accessible is not null then it is used to
+  // redirect methods calls otherwise we use method implementation from the
+  // base class.
+  nsCOMPtr<nsIDOMNode> actionNode(do_QueryInterface(mActionContent));
+  if (!actionNode || mDOMNode == actionNode)
+    return nsnull;
+
+  nsIAccessible *accessible = nsnull;
+  GetAccService()->GetAccessibleInWeakShell(actionNode, mWeakShell,
+                                            &accessible);
+  return accessible;
+}
+
 //---------------------
 // nsEnumRoleAccessible
 //---------------------
 
 nsEnumRoleAccessible::nsEnumRoleAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell, PRUint32 aRole) :
   nsAccessibleWrap(aNode, aShell),
   mRole(aRole)
 {
--- a/accessible/src/base/nsBaseWidgetAccessible.h
+++ b/accessible/src/base/nsBaseWidgetAccessible.h
@@ -73,30 +73,46 @@ public:
   *  and can activate ( click ) the link programmatically.
   */
 class nsLinkableAccessible : public nsHyperTextAccessibleWrap
 {
 public:
   enum { eAction_Jump = 0 };
 
   nsLinkableAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
+
   NS_DECL_ISUPPORTS_INHERITED
+
+  // nsIAccessible
   NS_IMETHOD GetNumActions(PRUint8 *_retval);
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD DoAction(PRUint8 index);
   NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
   NS_IMETHOD GetValue(nsAString& _retval);
   NS_IMETHOD TakeFocus();
   NS_IMETHOD GetKeyboardShortcut(nsAString& _retval);
+
+  // nsIHyperLinkAccessible
   NS_IMETHOD GetURI(PRInt32 i, nsIURI **aURI);
+
+  // nsPIAccessNode
   NS_IMETHOD Init();
   NS_IMETHOD Shutdown();
 
 protected:
+  /**
+   * Return an accessible for cached action node.
+   */
+  already_AddRefed<nsIAccessible> GetActionAccessible();
+
+  /**
+   * Cache action node.
+   */
   virtual void CacheActionContent();
+
   nsCOMPtr<nsIContent> mActionContent;
   PRPackedBool mIsLink;
   PRPackedBool mIsOnclick;
 };
 
 /**
  * A simple accessible that gets its enumerated role passed into constructor.
  */ 
--- a/accessible/src/base/nsCaretAccessible.cpp
+++ b/accessible/src/base/nsCaretAccessible.cpp
@@ -239,17 +239,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, nsDocAccessible::eRemoveDupes);
+  return mRootAccessible->FireDelayedAccessibleEvent(event);
 }
 
 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
@@ -147,24 +147,24 @@ NS_INTERFACE_MAP_END_INHERITING(nsHyperT
 
 NS_IMPL_ADDREF_INHERITED(nsDocAccessible, nsHyperTextAccessible)
 NS_IMPL_RELEASE_INHERITED(nsDocAccessible, nsHyperTextAccessible)
 
 NS_IMETHODIMP nsDocAccessible::GetName(nsAString& aName)
 {
   nsresult rv = NS_OK;
   aName.Truncate();
-  if (mRoleMapEntry) {
-    rv = nsAccessible::GetName(aName);
+  if (mParent) {
+    rv = mParent->GetName(aName); // Allow owning iframe to override the name
   }
   if (aName.IsEmpty()) {
-    rv = GetTitle(aName);
+    rv = nsAccessible::GetName(aName); // Allow name via aria-labelledby or title attribute
   }
-  if (aName.IsEmpty() && mParent) {
-    rv = mParent->GetName(aName);
+  if (aName.IsEmpty()) {
+    rv = GetTitle(aName);   // Finally try title element
   }
 
   return rv;
 }
 
 NS_IMETHODIMP nsDocAccessible::GetRole(PRUint32 *aRole)
 {
   *aRole = nsIAccessibleRole::ROLE_PANE; // Fall back
@@ -197,27 +197,48 @@ NS_IMETHODIMP nsDocAccessible::GetRole(P
     else if (itemType == nsIDocShellTreeItem::typeContent) {
       *aRole = nsIAccessibleRole::ROLE_DOCUMENT;
     }
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP nsDocAccessible::GetValue(nsAString& aValue)
+NS_IMETHODIMP nsDocAccessible::SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry)
 {
-  return GetURL(aValue);
+  NS_ENSURE_STATE(mDocument);
+
+  mRoleMapEntry = aRoleMapEntry;
+
+  // Allow use of ARIA role from outer to override
+  nsIDocument *parentDoc = mDocument->GetParentDocument();
+  NS_ENSURE_TRUE(parentDoc, NS_ERROR_FAILURE);
+  nsIContent *ownerContent = parentDoc->FindContentForSubDocument(mDocument);
+  nsCOMPtr<nsIDOMNode> ownerNode(do_QueryInterface(ownerContent));
+  if (ownerNode) {
+    nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(ownerNode);
+    if (roleMapEntry)
+      mRoleMapEntry = roleMapEntry; // Override
+  }
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP 
 nsDocAccessible::GetDescription(nsAString& aDescription)
 {
-  nsAutoString description;
-  GetTextFromRelationID(nsAccessibilityAtoms::aria_describedby, description);
-  aDescription = description;
+  if (mParent)
+    mParent->GetDescription(aDescription);
+
+  if (aDescription.IsEmpty()) {
+    nsAutoString description;
+    GetTextFromRelationID(nsAccessibilityAtoms::aria_describedby, description);
+    aDescription = description;
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
 {
   // nsAccessible::GetState() always fail for document accessible.
   nsAccessible::GetState(aState, aExtraState);
@@ -260,16 +281,41 @@ nsDocAccessible::GetState(PRUint32 *aSta
   }
   else if (aExtraState) {
     *aExtraState |= nsIAccessibleStates::EXT_STATE_EDITABLE;
   }
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDocAccessible::GetARIAState(PRUint32 *aState)
+{
+  // Combine with states from outer doc
+  NS_ENSURE_ARG_POINTER(aState);
+  nsresult rv = nsAccessible::GetARIAState(aState);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsPIAccessible> privateParentAccessible = do_QueryInterface(mParent);
+  if (privateParentAccessible)  // Allow iframe/frame etc. to have final state override via ARIA
+    return privateParentAccessible->GetARIAState(aState);
+
+  return rv;
+}
+
+NS_IMETHODIMP
+nsDocAccessible::GetAttributes(nsIPersistentProperties **aAttributes)
+{
+  nsAccessible::GetAttributes(aAttributes);
+  if (mParent) {
+    mParent->GetAttributes(aAttributes); // Add parent attributes (override inner)
+  }
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsDocAccessible::GetFocusedChild(nsIAccessible **aFocusedChild)
 {
   if (!gLastFocusedNode) {
     *aFocusedChild = nsnull;
     return NS_OK;
   }
 
   // Return an accessible for the current global focus, which does not have to
@@ -497,28 +543,20 @@ NS_IMETHODIMP nsDocAccessible::GetParent
 }
 
 NS_IMETHODIMP nsDocAccessible::Init()
 {
   PutCacheEntry(gGlobalDocAccessibleCache, mDocument, this);
 
   AddEventListeners();
 
-  nsresult rv = nsHyperTextAccessibleWrap::Init();
+  nsCOMPtr<nsIAccessible> parentAccessible;  // Ensure outer doc mParent accessible
+  GetParent(getter_AddRefs(parentAccessible));
 
-  if (mRoleMapEntry && mRoleMapEntry->role != nsIAccessibleRole::ROLE_DIALOG &&
-      mRoleMapEntry->role != nsIAccessibleRole::ROLE_APPLICATION &&
-      mRoleMapEntry->role != nsIAccessibleRole::ROLE_ALERT &&
-      mRoleMapEntry->role != nsIAccessibleRole::ROLE_DOCUMENT) {
-    // Document accessible can only have certain roles
-    // This was set in nsAccessible::Init() based on dynamic role attribute
-    mRoleMapEntry = nsnull; // role attribute is not valid for a document
-  }
-
-  return rv;
+  return nsHyperTextAccessibleWrap::Init();
 }
 
 NS_IMETHODIMP nsDocAccessible::Shutdown()
 {
   if (!mWeakShell) {
     return NS_OK;  // Already shutdown
   }
 
@@ -1021,17 +1059,17 @@ nsDocAccessible::AttributeChangedImpl(ns
     // in the wrong namespace or an element that doesn't support it
     InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
     return;
   }
   
   if (aAttribute == nsAccessibilityAtoms::alt ||
       aAttribute == nsAccessibilityAtoms::title) {
     FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE,
-                            targetNode, eRemoveDupes);
+                            targetNode);
     return;
   }
 
   if (aAttribute == nsAccessibilityAtoms::selected ||
       aAttribute == nsAccessibilityAtoms::aria_selected) {
     // ARIA or XUL selection
     nsCOMPtr<nsIAccessible> multiSelect = GetMultiSelectFor(targetNode);
     // Multi selects use selection_add and selection_remove
@@ -1043,17 +1081,18 @@ nsDocAccessible::AttributeChangedImpl(ns
       // 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, eAllowDupes);
+                              multiSelectDOMNode,
+                              nsAccEvent::eAllowDupes);
 
       static nsIContent::AttrValuesArray strings[] =
         {&nsAccessibilityAtoms::_empty, &nsAccessibilityAtoms::_false, nsnull};
       if (aContent->FindAttrValueIn(kNameSpaceID_None, aAttribute,
                                     strings, eCaseMatters) >= 0) {
         FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_SELECTION_REMOVE,
                                 targetNode);
         return;
@@ -1098,17 +1137,17 @@ nsDocAccessible::ARIAAttributeChanged(ns
     FireDelayedAccessibleEvent(event);
     return;
   }
 
   if (aAttribute == nsAccessibilityAtoms::aria_activedescendant) {
     // The activedescendant universal property redirects accessible focus events
     // to the element with the id that activedescendant points to
     nsCOMPtr<nsIDOMNode> currentFocus = GetCurrentFocus();
-    if (currentFocus == targetNode) {
+    if (SameCOMIdentity(GetRoleContent(currentFocus), targetNode)) {
       nsRefPtr<nsRootAccessible> rootAcc = GetRootAccessible();
       if (rootAcc)
         rootAcc->FireAccessibleFocusEvent(nsnull, currentFocus, nsnull, PR_TRUE);
     }
     return;
   }
 
   if (!aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::role)) {
@@ -1254,16 +1293,29 @@ nsDocAccessible::ContentRemoved(nsIDocum
 }
 
 void
 nsDocAccessible::ParentChainChanged(nsIContent *aContent)
 {
 }
 
 void
+nsDocAccessible::FireValueChangeForTextFields(nsIAccessible *aPossibleTextFieldAccessible)
+{
+  if (Role(aPossibleTextFieldAccessible) != nsIAccessibleRole::ROLE_ENTRY)
+    return;
+
+  // Dependent value change event for text changes in textfields
+  nsCOMPtr<nsIAccessibleEvent> valueChangeEvent =
+    new nsAccEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aPossibleTextFieldAccessible,
+                   PR_FALSE, nsAccEvent::eRemoveDupes);
+  FireDelayedAccessibleEvent(valueChangeEvent );
+}
+
+void
 nsDocAccessible::FireTextChangeEventForText(nsIContent *aContent,
                                             CharacterDataChangeInfo* aInfo,
                                             PRBool aIsInserted)
 {
   if (!mIsContentLoaded || !mDocument) {
     return;
   }
 
@@ -1313,16 +1365,18 @@ nsDocAccessible::FireTextChangeEventForT
     if (NS_FAILED(rv))
       return;
 
     nsCOMPtr<nsIAccessibleTextChangeEvent> event =
       new nsAccTextChangeEvent(accessible, offset,
                                renderedEndOffset - renderedStartOffset,
                                aIsInserted, PR_FALSE);
     textAccessible->FireAccessibleEvent(event);
+
+    FireValueChangeForTextFields(accessible);
   }
 }
 
 already_AddRefed<nsIAccessibleTextChangeEvent>
 nsDocAccessible::CreateTextChangeEventForNode(nsIAccessible *aContainerAccessible,
                                               nsIDOMNode *aChangeNode,
                                               nsIAccessible *aAccessibleForChangeNode,
                                               PRBool aIsInserting,
@@ -1394,103 +1448,39 @@ nsDocAccessible::CreateTextChangeEventFo
     new nsAccTextChangeEvent(aContainerAccessible, offset, length, aIsInserting, aIsAsynch);
   NS_IF_ADDREF(event);
 
   return event;
 }
   
 nsresult nsDocAccessible::FireDelayedToolkitEvent(PRUint32 aEvent,
                                                   nsIDOMNode *aDOMNode,
-                                                  EDupeEventRule aAllowDupes,
+                                                  nsAccEvent::EEventRule aAllowDupes,
                                                   PRBool aIsAsynch)
 {
   nsCOMPtr<nsIAccessibleEvent> event =
-    new nsAccEvent(aEvent, aDOMNode, aIsAsynch);
+    new nsAccEvent(aEvent, aDOMNode, aIsAsynch, aAllowDupes);
   NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
 
-  return FireDelayedAccessibleEvent(event, aAllowDupes);
+  return FireDelayedAccessibleEvent(event);
 }
 
 nsresult
-nsDocAccessible::FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent,
-                                            EDupeEventRule aAllowDupes)
+nsDocAccessible::FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent)
 {
   NS_ENSURE_TRUE(aEvent, NS_ERROR_FAILURE);
 
-  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 (numQueuedEvents == 0) {
-    isTimerStarted = PR_FALSE;
-  } 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;
-      }
-      PRUint32 eventType;
-      accessibleEvent->GetEventType(&eventType);
-      if (eventType == newEventType) {
-        nsCOMPtr<nsIDOMNode> domNode;
-        accessibleEvent->GetDOMNode(getter_AddRefs(domNode));
-        if (domNode == newEventDOMNode) {
-          mEventsToFire.RemoveObjectAt(index);
-          -- index;
-          -- numQueuedEvents;
-        }
-      }
-    }
-  }
-
   mEventsToFire.AppendObject(aEvent);
-  if (!isTimerStarted) {
+  if (mEventsToFire.Count() == 1) {
     // This is be the first delayed event in queue, start timer
     // so that event gets fired via FlushEventsCallback
     NS_ADDREF_THIS(); // Kung fu death grip to prevent crash in callback
     mFireEventTimer->InitWithFuncCallback(FlushEventsCallback,
                                           static_cast<nsPIAccessibleDocument*>(this),
                                           0, nsITimer::TYPE_ONE_SHOT);
   }
 
@@ -1499,30 +1489,32 @@ nsDocAccessible::FireDelayedAccessibleEv
 
 NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
 {
   PRUint32 length = mEventsToFire.Count();
   NS_ASSERTION(length, "How did we get here without events to fire?");
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   if (!presShell)
     length = 0; // The doc is now shut down, don't fire events in it anymore
-  PRUint32 index;
-  for (index = 0; index < length; index ++) {
+  else
+    nsAccEvent::ApplyEventRules(mEventsToFire);
+  
+  for (PRUint32 index = 0; index < length; index ++) {
     nsCOMPtr<nsIAccessibleEvent> accessibleEvent(
       do_QueryInterface(mEventsToFire[index]));
-    NS_ASSERTION(accessibleEvent, "Array item is not an accessible event");
+
+    if (nsAccEvent::EventRule(accessibleEvent) == nsAccEvent::eDoNotEmit)
+      continue;
 
     nsCOMPtr<nsIAccessible> accessible;
     accessibleEvent->GetAccessible(getter_AddRefs(accessible));
     nsCOMPtr<nsIDOMNode> domNode;
     accessibleEvent->GetDOMNode(getter_AddRefs(domNode));
-    PRUint32 eventType;
-    accessibleEvent->GetEventType(&eventType);
-    PRBool isFromUserInput;
-    accessibleEvent->GetIsFromUserInput(&isFromUserInput);
+    PRUint32 eventType = nsAccEvent::EventType(accessibleEvent);
+    PRBool isFromUserInput = nsAccEvent::IsFromUserInput(accessibleEvent);
 
     if (domNode == gLastFocusedNode &&
         eventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE || 
         eventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW) {
       // If frame type didn't change for this event, then we don't actually need to invalidate
       // However, we only keep track of the old frame type for the focus, where it's very
       // important not to destroy and recreate the accessible for minor style changes,
       // such as a:focus { overflow: scroll; }
@@ -1935,53 +1927,58 @@ NS_IMETHODIMP nsDocAccessible::Invalidat
     // 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.
     PRUint32 additionEvent = isAsynch ? nsIAccessibleEvent::EVENT_ASYNCH_SHOW :
                                         nsIAccessibleEvent::EVENT_DOM_CREATE;
     FireDelayedToolkitEvent(additionEvent, childNode,
-                            eCoalesceFromSameSubtree, isAsynch);
+                            nsAccEvent::eCoalesceFromSameSubtree,
+                            isAsynch);
 
     // Check to see change occured in an ARIA menu, and fire
     // an EVENT_MENUPOPUP_START if it did.
     nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(childNode);
     if (roleMapEntry && roleMapEntry->role == nsIAccessibleRole::ROLE_MENUPOPUP) {
       FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
-                              childNode, eRemoveDupes, isAsynch);
+                              childNode, nsAccEvent::eRemoveDupes,
+                              isAsynch);
     }
 
     // Check to see if change occured inside an alert, and fire an EVENT_ALERT if it did
     nsIContent *ancestor = aChild;
     while (PR_TRUE) {
       if (roleMapEntry && roleMapEntry->role == nsIAccessibleRole::ROLE_ALERT) {
         nsCOMPtr<nsIDOMNode> alertNode(do_QueryInterface(ancestor));
         FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_ALERT, alertNode,
-                                eRemoveDupes, isAsynch);
+                                nsAccEvent::eRemoveDupes, isAsynch);
         break;
       }
       ancestor = ancestor->GetParent();
       nsCOMPtr<nsIDOMNode> ancestorNode = do_QueryInterface(ancestor);
       if (!ancestorNode) {
         break;
       }
       roleMapEntry = nsAccUtils::GetRoleMapEntry(ancestorNode);
     }
   }
 
+  FireValueChangeForTextFields(containerAccessible);
+
   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, isAsynch);
+        new nsAccEvent(nsIAccessibleEvent::EVENT_REORDER, containerAccessible,
+                       isAsynch, nsAccEvent::eCoalesceFromSameSubtree);
       NS_ENSURE_TRUE(reorderEvent, NS_ERROR_OUT_OF_MEMORY);
-      FireDelayedAccessibleEvent(reorderEvent, eCoalesceFromSameSubtree);
+      FireDelayedAccessibleEvent(reorderEvent);
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocAccessible::GetAccessibleInParentChain(nsIDOMNode *aNode,
@@ -2047,23 +2044,24 @@ nsDocAccessible::FireShowHideEvents(nsID
 
   if (accessible) {
     // Found an accessible, so fire the show/hide on it and don't
     // look further into this subtree
     PRBool isAsynch = aEventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
                       aEventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW;
 
     nsCOMPtr<nsIAccessibleEvent> event =
-      new nsAccEvent(aEventType, accessible, isAsynch);
+      new nsAccEvent(aEventType, accessible, isAsynch,
+                     nsAccEvent::eCoalesceFromSameSubtree);
     NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
     if (aForceIsFromUserInput) {
       nsAccEvent::PrepareForEvent(event, aForceIsFromUserInput);
     }
     if (aDelay) {
-      return FireDelayedAccessibleEvent(event, eCoalesceFromSameSubtree);
+      return FireDelayedAccessibleEvent(event);
     }
     return FireAccessibleEvent(event);
   }
 
   // Could not find accessible to show hide yet, so fire on any
   // accessible descendants in this subtree
   nsCOMPtr<nsIContent> content(do_QueryInterface(aDOMNode));
   PRUint32 count = content->GetChildCount();
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -69,20 +69,22 @@ class nsDocAccessible : public nsHyperTe
   NS_DECL_NSPIACCESSIBLEDOCUMENT
   NS_DECL_NSIOBSERVER
 
   public:
     nsDocAccessible(nsIDOMNode *aNode, nsIWeakReference* aShell);
     virtual ~nsDocAccessible();
 
     NS_IMETHOD GetRole(PRUint32 *aRole);
+    NS_IMETHOD SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry);
     NS_IMETHOD GetName(nsAString& aName);
-    NS_IMETHOD GetValue(nsAString& aValue);
     NS_IMETHOD GetDescription(nsAString& aDescription);
+    NS_IMETHOD GetARIAState(PRUint32 *aState);
     NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
+    NS_IMETHOD GetAttributes(nsIPersistentProperties **aAttributes);
     NS_IMETHOD GetFocusedChild(nsIAccessible **aFocusedChild);
     NS_IMETHOD GetParent(nsIAccessible **aParent);
     NS_IMETHOD TakeFocus(void);
 
     // ----- nsIScrollPositionListener ---------------------------
     NS_IMETHOD ScrollPositionWillChange(nsIScrollableView *aView, nscoord aX, nscoord aY);
     NS_IMETHOD ScrollPositionDidChange(nsIScrollableView *aView, nscoord aX, nscoord aY);
 
@@ -96,46 +98,40 @@ class nsDocAccessible : public nsHyperTe
     NS_IMETHOD Init();
 
     // nsPIAccessNode
     NS_IMETHOD_(nsIFrame *) GetFrame(void);
 
     // 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 type
       * @param aDOMNode - DOM node the accesible event should be fired for
       * @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 aIsAsynch - set to PR_TRUE if this is not being called from code
       *                    synchronous with a DOM event
       */
     nsresult FireDelayedToolkitEvent(PRUint32 aEvent, nsIDOMNode *aDOMNode,
-                                     EDupeEventRule aAllowDupes = eRemoveDupes,
+                                     nsAccEvent::EEventRule aAllowDupes = nsAccEvent::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.
      */
-    nsresult FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent,
-                                        EDupeEventRule aAllowDupes = eRemoveDupes);
+    nsresult FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent);
 
     void ShutdownChildDocuments(nsIDocShellTreeItem *aStart);
 
   protected:
     virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
     virtual nsresult AddEventListeners();
     virtual nsresult RemoveEventListeners();
     void AddScrollListener();
@@ -202,16 +198,21 @@ class nsDocAccessible : public nsHyperTe
      * @param aEventType             event type to fire an event
      * @param aAvoidOnThisNode       Call with PR_TRUE the first time to prevent event firing on root node for change
      * @param aDelay                 whether to fire the event on a delay
      * @param aForceIsFromUserInput  the event is known to be from user input
      */
     nsresult FireShowHideEvents(nsIDOMNode *aDOMNode, PRBool aAvoidOnThisNode, PRUint32 aEventType,
                                 PRBool aDelay, PRBool aForceIsFromUserInput);
 
+    /**
+     * If the given accessible object is a ROLE_ENTRY, fire a value change event for it
+     */
+    void FireValueChangeForTextFields(nsIAccessible *aPossibleTextFieldAccessible);
+
     nsAccessNodeHashtable mAccessNodeCache;
     void *mWnd;
     nsCOMPtr<nsIDocument> mDocument;
     nsCOMPtr<nsITimer> mScrollWatchTimer;
     nsCOMPtr<nsITimer> mFireEventTimer;
     PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
     PRPackedBool mIsContentLoaded;
     PRPackedBool mIsLoadCompleteFired;
--- a/accessible/src/base/nsOuterDocAccessible.cpp
+++ b/accessible/src/base/nsOuterDocAccessible.cpp
@@ -150,8 +150,20 @@ void nsOuterDocAccessible::CacheChildren
 
   // Success getting inner document as first child -- now we cache it.
   mAccChildCount = 1;
   SetFirstChild(innerAccessible); // weak ref
   privateInnerAccessible->SetParent(this);
   privateInnerAccessible->SetNextSibling(nsnull);
 }
 
+nsresult
+nsOuterDocAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
+{
+  nsAutoString tag;
+  aAttributes->GetStringProperty(NS_LITERAL_CSTRING("tag"), tag);
+  if (!tag.IsEmpty()) {
+    // We're overriding the ARIA attributes on an sub document, but we don't want to
+    // override the other attributes
+    return NS_OK;
+  }
+  return nsAccessible::GetAttributesInternal(aAttributes);
+}
--- a/accessible/src/base/nsOuterDocAccessible.h
+++ b/accessible/src/base/nsOuterDocAccessible.h
@@ -53,11 +53,12 @@ class nsOuterDocAccessible : public nsAc
                          nsIWeakReference* aShell);
 
     NS_IMETHOD GetName(nsAString& aName);
     NS_IMETHOD GetRole(PRUint32 *aRole);
     NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
     NS_IMETHOD GetChildAtPoint(PRInt32 aX, PRInt32 aY,
                                nsIAccessible **aAccessible);
     void CacheChildren();
+    nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
 };
 
 #endif  
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -403,18 +403,17 @@ void nsRootAccessible::TryFireEarlyLoadE
       return;
     }
   }
   nsCOMPtr<nsIDocShellTreeItem> rootContentTreeItem;
   treeItem->GetSameTypeRootTreeItem(getter_AddRefs(rootContentTreeItem));
   NS_ASSERTION(rootContentTreeItem, "No root content tree item");
   if (rootContentTreeItem == treeItem) {
     // No frames or iframes, so we can fire the doc load finished event early
-    FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_INTERNAL_LOAD, aDocNode,
-                            eRemoveDupes);
+    FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_INTERNAL_LOAD, aDocNode);
   }
 }
 
 PRBool nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
                                                   nsIDOMNode *aNode,
                                                   nsIDOMEvent *aFocusEvent,
                                                   PRBool aForceEvent,
                                                   PRBool aIsAsynch)
@@ -443,30 +442,35 @@ PRBool nsRootAccessible::FireAccessibleF
         mCaretAccessible->SetControlSelectionListener(realFocusedNode);
       }
     }
   }
 
   // Check for aria-activedescendant, which changes which element has focus
   nsCOMPtr<nsIDOMNode> finalFocusNode = aNode;
   nsCOMPtr<nsIAccessible> finalFocusAccessible = aAccessible;
-  nsCOMPtr<nsIContent> finalFocusContent  = do_QueryInterface(aNode);
+  nsCOMPtr<nsIContent> finalFocusContent = GetRoleContent(finalFocusNode);
   if (finalFocusContent) {
     nsAutoString id;
     if (finalFocusContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_activedescendant, id)) {
       nsCOMPtr<nsIDOMDocument> domDoc;
       aNode->GetOwnerDocument(getter_AddRefs(domDoc));
+      if (!domDoc) {  // Maybe the passed-in node actually is a doc
+        domDoc = do_QueryInterface(aNode);
+      }
       if (!domDoc) {
         return PR_FALSE;
       }
       nsCOMPtr<nsIDOMElement> relatedEl;
       domDoc->GetElementById(id, getter_AddRefs(relatedEl));
       finalFocusNode = do_QueryInterface(relatedEl);
       if (!finalFocusNode) {
-        return PR_FALSE;
+        // If aria-activedescendant is set to nonextistant ID, then treat as focus
+        // on the activedescendant container (which has real DOM focus)
+        finalFocusNode = aNode;
       }
       finalFocusAccessible = nsnull;
     }
   }
 
   // Fire focus only if it changes, but always fire focus events when aForceEvent == PR_TRUE
   if (gLastFocusedNode == finalFocusNode && !aForceEvent) {
     return PR_FALSE;
@@ -498,19 +502,20 @@ PRBool nsRootAccessible::FireAccessibleF
             nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENU_START, menuBarAccessible);
           }
         }
       }
     }
   }
   else if (mCurrentARIAMenubar) {
     nsCOMPtr<nsIAccessibleEvent> menuEndEvent =
-      new nsAccEvent(nsIAccessibleEvent::EVENT_MENU_END, mCurrentARIAMenubar, PR_FALSE);
+      new nsAccEvent(nsIAccessibleEvent::EVENT_MENU_END, mCurrentARIAMenubar,
+                     PR_FALSE, nsAccEvent::eAllowDupes);
     if (menuEndEvent) {
-      FireDelayedAccessibleEvent(menuEndEvent, eAllowDupes);
+      FireDelayedAccessibleEvent(menuEndEvent);
     }
     mCurrentARIAMenubar = nsnull;
   }
 
   NS_IF_RELEASE(gLastFocusedNode);
   gLastFocusedNode = finalFocusNode;
   NS_IF_ADDREF(gLastFocusedNode);
 
@@ -531,17 +536,18 @@ PRBool nsRootAccessible::FireAccessibleF
       // 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, eRemoveDupes, aIsAsynch);
+                          finalFocusNode, nsAccEvent::eRemoveDupes,
+                          aIsAsynch);
 
   return PR_TRUE;
 }
 
 void nsRootAccessible::FireCurrentFocusEvent()
 {
   nsCOMPtr<nsIDOMNode> focusedNode = GetCurrentFocus();
   if (!focusedNode) {
@@ -913,17 +919,17 @@ nsresult nsRootAccessible::HandleEventWi
     nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENU_START, accessible, PR_TRUE);
   }
   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);
+    FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aTargetNode, nsAccEvent::eRemoveDupes);
   }
 #ifdef DEBUG
   else if (eventType.EqualsLiteral("mouseover")) {
     nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_DRAGDROP_START, accessible);
   }
 #endif
   return NS_OK;
 }
--- a/accessible/src/html/nsHTMLAreaAccessible.cpp
+++ b/accessible/src/html/nsHTMLAreaAccessible.cpp
@@ -32,102 +32,107 @@
  * 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 "nsHTMLAreaAccessible.h"
-#include "nsIAccessibilityService.h"
 #include "nsIServiceManager.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMHTMLAreaElement.h"
 #include "nsIFrame.h"
 #include "nsIImageFrame.h"
 #include "nsIImageMap.h"
 
 
-// --- area -----
+////////////////////////////////////////////////////////////////////////////////
+// nsHTMLAreaAccessible
 
-nsHTMLAreaAccessible::nsHTMLAreaAccessible(nsIDOMNode *aDomNode, nsIAccessible *aParent, nsIWeakReference* aShell):
-nsLinkableAccessible(aDomNode, aShell)
+nsHTMLAreaAccessible::
+  nsHTMLAreaAccessible(nsIDOMNode *aDomNode, nsIAccessible *aParent,
+                       nsIWeakReference* aShell):
+  nsHTMLLinkAccessible(aDomNode, aShell)
 { 
 }
 
-// Expose nsIAccessibleHyperLink unconditionally
-NS_IMPL_ISUPPORTS_INHERITED1(nsHTMLAreaAccessible, nsLinkableAccessible,
-                             nsIAccessibleHyperLink)
+////////////////////////////////////////////////////////////////////////////////
+// nsIAccessible
+
+NS_IMETHODIMP
+nsHTMLAreaAccessible::GetName(nsAString & aName)
+{
+  aName.Truncate();
 
-/* wstring getName (); */
-NS_IMETHODIMP nsHTMLAreaAccessible::GetName(nsAString & aName)
-{
-  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
-  if (!content) {
+  if (IsDefunct())
     return NS_ERROR_FAILURE;
+  
+  if (mRoleMapEntry) {
+    nsresult rv = nsAccessible::GetName(aName);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (!aName.IsEmpty()) 
+      return NS_OK;
   }
 
-  aName.Truncate();
-  if (mRoleMapEntry) {
-    nsresult rv = nsAccessible::GetName(aName);
-    if (!aName.IsEmpty()) {
-      return rv;
-    }
-  }
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   if (!content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::alt,
                         aName) &&  
       !content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::title,
                         aName)) {
     return GetValue(aName);
   }
 
   return NS_OK;
 }
 
-/* unsigned long getRole (); */
-NS_IMETHODIMP nsHTMLAreaAccessible::GetRole(PRUint32 *_retval)
+NS_IMETHODIMP
+nsHTMLAreaAccessible::GetDescription(nsAString& aDescription)
 {
-  *_retval = nsIAccessibleRole::ROLE_LINK;
+  aDescription.Truncate();
+
+  // Still to do - follow IE's standard here
+  nsCOMPtr<nsIDOMHTMLAreaElement> area(do_QueryInterface(mDOMNode));
+  if (area) 
+    area->GetShape(aDescription);
+
   return NS_OK;
 }
 
-/* wstring getDescription (); */
-NS_IMETHODIMP nsHTMLAreaAccessible::GetDescription(nsAString& _retval)
+NS_IMETHODIMP
+nsHTMLAreaAccessible::GetFirstChild(nsIAccessible **aChild)
 {
-  // Still to do - follow IE's standard here
-  nsCOMPtr<nsIDOMHTMLAreaElement> area(do_QueryInterface(mDOMNode));
-  if (area) 
-    area->GetShape(_retval);
+  NS_ENSURE_ARG_POINTER(aChild);
+
+  *aChild = nsnull;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsHTMLAreaAccessible::GetLastChild(nsIAccessible **aChild)
+{
+  NS_ENSURE_ARG_POINTER(aChild);
 
-/* nsIAccessible getFirstChild (); */
-NS_IMETHODIMP nsHTMLAreaAccessible::GetFirstChild(nsIAccessible **_retval)
-{
-  *_retval = nsnull;
+  *aChild = nsnull;
   return NS_OK;
 }
 
-/* nsIAccessible getLastChild (); */
-NS_IMETHODIMP nsHTMLAreaAccessible::GetLastChild(nsIAccessible **_retval)
+NS_IMETHODIMP
+nsHTMLAreaAccessible::GetChildCount(PRInt32 *aCount)
 {
-  *_retval = nsnull;
+  NS_ENSURE_ARG_POINTER(aCount);
+
+  *aCount = 0;
   return NS_OK;
 }
 
-/* long getAccChildCount (); */
-NS_IMETHODIMP nsHTMLAreaAccessible::GetChildCount(PRInt32 *_retval)
-{
-  *_retval = 0;
-  return NS_OK;
-}
-
-/* void accGetBounds (out long x, out long y, out long width, out long height); */
-NS_IMETHODIMP nsHTMLAreaAccessible::GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height)
+NS_IMETHODIMP
+nsHTMLAreaAccessible::GetBounds(PRInt32 *x, PRInt32 *y,
+                                PRInt32 *width, PRInt32 *height)
 {
   // Essentially this uses GetRect on mAreas of nsImageMap from nsImageFrame
 
   *x = *y = *width = *height = 0;
 
   nsPresContext *presContext = GetPresContext();
   NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
 
--- a/accessible/src/html/nsHTMLAreaAccessible.h
+++ b/accessible/src/html/nsHTMLAreaAccessible.h
@@ -34,35 +34,34 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsHTMLAreaAccessible_H_
 #define _nsHTMLAreaAccessible_H_
 
-#include "nsBaseWidgetAccessible.h"
+#include "nsHTMLLinkAccessible.h"
 
 /* Accessible for image map areas - must be child of image
  */
 
-class nsHTMLAreaAccessible : public nsLinkableAccessible
+class nsHTMLAreaAccessible : public nsHTMLLinkAccessible
 {
 
 public:
   nsHTMLAreaAccessible(nsIDOMNode *domNode, nsIAccessible *accParent,
                        nsIWeakReference* aShell);
 
-  NS_DECL_ISUPPORTS_INHERITED
+  // nsIAccessible
+  NS_IMETHOD GetName(nsAString & aName);
+  NS_IMETHOD GetDescription(nsAString& aDescription);
 
-  // nsIAccessible
-  NS_IMETHOD GetName(nsAString & _retval); 
-  NS_IMETHOD GetRole(PRUint32 *_retval); 
   NS_IMETHOD GetFirstChild(nsIAccessible **_retval);
   NS_IMETHOD GetLastChild(nsIAccessible **_retval);
   NS_IMETHOD GetChildCount(PRInt32 *_retval);
-  NS_IMETHOD GetDescription(nsAString& _retval);
+
   NS_IMETHOD GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height);
   NS_IMETHOD GetChildAtPoint(PRInt32 aX, PRInt32 aY, nsIAccessible **aAccessible)
     { NS_ENSURE_ARG_POINTER(aAccessible); NS_ADDREF(*aAccessible = this); return NS_OK; } // Don't walk into these
 };
 
 #endif  
--- a/accessible/src/html/nsHTMLLinkAccessible.cpp
+++ b/accessible/src/html/nsHTMLLinkAccessible.cpp
@@ -15,74 +15,173 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *   Author: Aaron Leventhal (aaronl@netscape.com)
+ *   Aaron Leventhal <aleventh@us.ibm.com> (original author)
+ *   Alexander Surkov <surkov.alexander@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 "nsHTMLLinkAccessible.h"
-#include "nsAccessibilityAtoms.h"
-#include "nsIAccessibleEvent.h"
-#include "nsINameSpaceManager.h"
+
+#include "nsILink.h"
 
-NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLLinkAccessible, nsLinkableAccessible)
+////////////////////////////////////////////////////////////////////////////////
+// nsHTMLLinkAccessible
 
-nsHTMLLinkAccessible::nsHTMLLinkAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell):
-nsLinkableAccessible(aDomNode, aShell)
+nsHTMLLinkAccessible::nsHTMLLinkAccessible(nsIDOMNode* aDomNode,
+                                           nsIWeakReference* aShell):
+  nsHyperTextAccessibleWrap(aDomNode, aShell)
 { 
 }
 
-/* wstring getName (); */
-NS_IMETHODIMP nsHTMLLinkAccessible::GetName(nsAString& aName)
+// Expose nsIAccessibleHyperLink unconditionally
+NS_IMPL_ISUPPORTS_INHERITED1(nsHTMLLinkAccessible, nsHyperTextAccessibleWrap,
+                             nsIAccessibleHyperLink)
+
+////////////////////////////////////////////////////////////////////////////////
+// nsIAccessible
+
+NS_IMETHODIMP
+nsHTMLLinkAccessible::GetName(nsAString& aName)
 { 
-  if (!mActionContent)
+  aName.Truncate();
+
+  if (IsDefunct())
     return NS_ERROR_FAILURE;
 
-  return AppendFlatStringFromSubtree(mActionContent, &aName);
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
+  return AppendFlatStringFromSubtree(content, &aName);
 }
 
-/* unsigned long getRole (); */
-NS_IMETHODIMP nsHTMLLinkAccessible::GetRole(PRUint32 *_retval)
+NS_IMETHODIMP
+nsHTMLLinkAccessible::GetRole(PRUint32 *aRole)
 {
-  *_retval = nsIAccessibleRole::ROLE_LINK;
+  NS_ENSURE_ARG_POINTER(aRole);
 
+  *aRole = nsIAccessibleRole::ROLE_LINK;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLLinkAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
 {
-  nsresult rv = nsLinkableAccessible::GetState(aState, aExtraState);
+  nsresult rv = nsHyperTextAccessibleWrap::GetState(aState, aExtraState);
   NS_ENSURE_SUCCESS(rv, rv);
   if (!mDOMNode)
     return NS_OK;
 
   *aState  &= ~nsIAccessibleStates::STATE_READONLY;
 
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   if (content && content->HasAttr(kNameSpaceID_None,
                                   nsAccessibilityAtoms::name)) {
     // This is how we indicate it is a named anchor
     // In other words, this anchor can be selected as a location :)
     // There is no other better state to use to indicate this.
     *aState |= nsIAccessibleStates::STATE_SELECTABLE;
   }
 
+  nsCOMPtr<nsILink> link = do_QueryInterface(mDOMNode);
+  NS_ENSURE_STATE(link);
+
+  nsLinkState linkState;
+  link->GetLinkState(linkState);
+  if (linkState == eLinkState_NotLink) {
+    // This is a named anchor, not a link with also a name attribute. bail out.
+    return NS_OK;
+  }
+
+  *aState |= nsIAccessibleStates::STATE_LINKED;
+
+  if (linkState == eLinkState_Visited)
+    *aState |= nsIAccessibleStates::STATE_TRAVERSED;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHTMLLinkAccessible::GetValue(nsAString& aValue)
+{
+  aValue.Truncate();
+
+  nsresult rv = nsHyperTextAccessible::GetValue(aValue);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!aValue.IsEmpty())
+    return NS_OK;
+  
+  nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
+  if (mDOMNode && presShell)
+    return presShell->GetLinkLocation(mDOMNode, aValue);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHTMLLinkAccessible::GetNumActions(PRUint8 *aNumActions)
+{
+  NS_ENSURE_ARG_POINTER(aNumActions);
+
+  *aNumActions = 1;
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsHTMLLinkAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
+{
+  // Action 0 (default action): Jump to link
+  aName.Truncate();
+  if (aIndex != eAction_Jump)
+    return NS_ERROR_INVALID_ARG;
+
+  aName.AssignLiteral("jump");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHTMLLinkAccessible::DoAction(PRUint8 aIndex)
+{
+  // Action 0 (default action): Jump to link
+  if (aIndex != eAction_Jump)
+    return NS_ERROR_INVALID_ARG;
+
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
+  return DoCommand(content);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsIAccessibleHyperLink
+
+NS_IMETHODIMP
+nsHTMLLinkAccessible::GetURI(PRInt32 aIndex, nsIURI **aURI)
+{
+  NS_ENSURE_ARG_POINTER(aURI);
+  *aURI = nsnull;
+
+  if (aIndex != 0)
+    return NS_ERROR_INVALID_ARG;
+
+  nsCOMPtr<nsILink> link(do_QueryInterface(mDOMNode));
+  NS_ENSURE_STATE(link);
+
+  return link->GetHrefURI(aURI);
+}
--- a/accessible/src/html/nsHTMLLinkAccessible.h
+++ b/accessible/src/html/nsHTMLLinkAccessible.h
@@ -15,17 +15,18 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *   Author: Aaron Leventhal (aaronl@netscape.com)
+ *   Aaron Leventhal <aleventh@us.ibm.com> (original author)
+ *   Alexander Surkov <surkov.alexander@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
@@ -34,24 +35,35 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsHTMLLinkAccessible_H_
 #define _nsHTMLLinkAccessible_H_
 
-#include "nsBaseWidgetAccessible.h"
+#include "nsHyperTextAccessibleWrap.h"
 
-class nsHTMLLinkAccessible : public nsLinkableAccessible
+class nsHTMLLinkAccessible : public nsHyperTextAccessibleWrap
 {
+public:
+  nsHTMLLinkAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell);
+ 
   NS_DECL_ISUPPORTS_INHERITED
 
-public:
-  nsHTMLLinkAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell);
-  
   // nsIAccessible
-  NS_IMETHOD GetName(nsAString& _retval); 
-  NS_IMETHOD GetRole(PRUint32 *_retval); 
+  NS_IMETHOD GetName(nsAString& aName);
+  NS_IMETHOD GetRole(PRUint32 *aRole); 
   NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
+  NS_IMETHOD GetValue(nsAString& aValue);
+
+  NS_IMETHOD GetNumActions(PRUint8 *aNumActions);
+  NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
+  NS_IMETHOD DoAction(PRUint8 aIndex);
+
+  // nsIAccessibleHyperLink
+  NS_IMETHOD GetURI(PRInt32 aIndex, nsIURI **aURI);
+
+protected:
+  enum { eAction_Jump = 0 };
 };
 
 #endif  
--- a/accessible/src/html/nsHTMLSelectAccessible.cpp
+++ b/accessible/src/html/nsHTMLSelectAccessible.cpp
@@ -453,16 +453,20 @@ void nsHTMLSelectListAccessible::CacheCh
 
   nsCOMPtr<nsIContent> selectContent(do_QueryInterface(mDOMNode));
   nsCOMPtr<nsIAccessibilityService> accService(do_GetService("@mozilla.org/accessibilityService;1"));
   if (!selectContent || !accService) {
     mAccChildCount = eChildCountUninitialized;
     return;
   }
 
+  if (mAccChildCount != eChildCountUninitialized) {
+    return;
+  }
+
   mAccChildCount = 0; // Avoid reentry
   PRInt32 childCount = 0;
   nsCOMPtr<nsIAccessible> lastGoodAccessible =
     CacheOptSiblings(accService, selectContent, nsnull, &childCount);
   mAccChildCount = childCount;
 }
 
 /** ----- nsHTMLSelectOptionAccessible ----- */
@@ -1061,17 +1065,16 @@ NS_IMETHODIMP nsHTMLComboboxAccessible::
     mListAccessible = nsnull;
   }
   return NS_OK;
 }
 
 /**
   * As a nsHTMLComboboxAccessible we can have the following states:
   *     STATE_FOCUSED
-  *     STATE_READONLY
   *     STATE_FOCUSABLE
   *     STATE_HASPOPUP
   *     STATE_EXPANDED
   *     STATE_COLLAPSED
   */
 NS_IMETHODIMP
 nsHTMLComboboxAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
 {
@@ -1091,17 +1094,16 @@ nsHTMLComboboxAccessible::GetState(PRUin
     *aState |= nsIAccessibleStates::STATE_EXPANDED;
   }
   else {
     *aState &= ~nsIAccessibleStates::STATE_FOCUSED; // Focus is on an option
     *aState |= nsIAccessibleStates::STATE_COLLAPSED;
   }
 
   *aState |= nsIAccessibleStates::STATE_HASPOPUP |
-             nsIAccessibleStates::STATE_READONLY |
              nsIAccessibleStates::STATE_FOCUSABLE;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsHTMLComboboxAccessible::GetDescription(nsAString& aDescription)
 {
   aDescription.Truncate();
--- a/accessible/src/msaa/CAccessibleAction.cpp
+++ b/accessible/src/msaa/CAccessibleAction.cpp
@@ -111,22 +111,24 @@ CAccessibleAction::get_description(long 
   if (!acc)
     return E_FAIL;
 
   nsAutoString description;
   PRUint8 index = static_cast<PRUint8>(aActionIndex);
   if (NS_FAILED(acc->GetActionDescription(index, description)))
     return E_FAIL;
 
-  if (!description.IsVoid()) {
-    INT result = ::SysReAllocStringLen(aDescription, description.get(),
-                                       description.Length());
-    if (!result)
-      return E_OUTOFMEMORY;
-  }
+  if (description.IsVoid())
+    return S_FALSE;
+
+  *aDescription = ::SysAllocStringLen(description.get(),
+                                      description.Length());
+  if (!*aDescription)
+    return E_OUTOFMEMORY;
+
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK;
 }
 
 STDMETHODIMP
 CAccessibleAction::get_keyBinding(long aActionIndex, long aNumMaxBinding,
                                  BSTR **aKeyBinding,
@@ -151,54 +153,76 @@ CAccessibleAction::get_keyBinding(long a
 
   PRBool aUseNumMaxBinding = length > static_cast<PRUint32>(aNumMaxBinding);
 
   PRUint32 maxBinding = static_cast<PRUint32>(aNumMaxBinding);
 
   PRUint32 numBinding = length > maxBinding ? maxBinding : length;
   *aNumBinding = numBinding;
 
-  *aKeyBinding = new BSTR[numBinding];
+  *aKeyBinding = static_cast<BSTR*>(nsMemory::Alloc((numBinding) * sizeof(BSTR*)));
   if (!*aKeyBinding)
     return E_OUTOFMEMORY;
 
-  for (PRUint32 i = 0; i < numBinding; i++) {
+  PRBool outOfMemory = PR_FALSE;
+  PRUint32 i = 0;
+  for (; i < numBinding; i++) {
     nsAutoString key;
     keys->Item(i, key);
-    INT result = ::SysReAllocStringLen(aKeyBinding[i], key.get(),
-                                       key.Length());
-    if (!result)
-      return E_OUTOFMEMORY;
+    *(aKeyBinding[i]) = ::SysAllocStringLen(key.get(), key.Length());
+
+    if (!*(aKeyBinding[i])) {
+      outOfMemory = PR_TRUE;
+      break;
+    }
+  }
+
+  if (outOfMemory) {
+    for (PRUint32 j = 0; j < i; j++)
+      ::SysFreeString(*(aKeyBinding[j]));
+
+    nsMemory::Free(*aKeyBinding);
+    *aKeyBinding = NULL;
+
+    return E_OUTOFMEMORY;
   }
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK;
 }
 
 STDMETHODIMP
 CAccessibleAction::get_name(long aActionIndex, BSTR *aName)
 {
 __try {
+  *aName = NULL;
+
   nsCOMPtr<nsIAccessible> acc(do_QueryInterface(this));
   if (!acc)
     return E_FAIL;
 
   nsAutoString name;
   PRUint8 index = static_cast<PRUint8>(aActionIndex);
   if (NS_FAILED(acc->GetActionName(index, name)))
     return E_FAIL;
 
-  INT result = ::SysReAllocStringLen(aName, name.get(), name.Length());
-  if (!result)
+  if (name.IsEmpty())
+    return S_FALSE;
+
+  *aName = ::SysAllocStringLen(name.get(), name.Length());
+  if (!*aName)
     return E_OUTOFMEMORY;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK;
 }
 
 STDMETHODIMP
 CAccessibleAction::get_localizedName(long aActionIndex, BSTR *aLocalizedName)
 {
-  ::SysFreeString(*aLocalizedName);
+__try {
+  *aLocalizedName = NULL;
+} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
+
   return E_NOTIMPL;
 }
 
--- a/accessible/src/msaa/CAccessibleHyperlink.cpp
+++ b/accessible/src/msaa/CAccessibleHyperlink.cpp
@@ -134,18 +134,21 @@ CAccessibleHyperlink::get_anchorTarget(l
   if (NS_FAILED(rv))
     return E_FAIL;
 
   nsAutoString stringURI;
   AppendUTF8toUTF16(prePath, stringURI);
   AppendUTF8toUTF16(path, stringURI);
 
   aAnchorTarget->vt = VT_BSTR;
-  if (!::SysReAllocStringLen(&aAnchorTarget->bstrVal, stringURI.get(), stringURI.Length()))
+  aAnchorTarget->bstrVal = ::SysAllocStringLen(stringURI.get(),
+                                               stringURI.Length());
+  if (!aAnchorTarget->bstrVal)
     return E_OUTOFMEMORY;
+
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK;
 }
 
 STDMETHODIMP
 CAccessibleHyperlink::get_startIndex(long *aIndex)
 {
--- a/accessible/src/msaa/CAccessibleImage.cpp
+++ b/accessible/src/msaa/CAccessibleImage.cpp
@@ -71,27 +71,34 @@ CAccessibleImage::QueryInterface(REFIID 
 }
 
 // IAccessibleImage
 
 STDMETHODIMP
 CAccessibleImage::get_description(BSTR *aDescription)
 {
 __try {
+  *aDescription = NULL;
+
   nsCOMPtr<nsIAccessible> acc(do_QueryInterface(this));
   if (!acc)
     return E_FAIL;
 
   nsAutoString description;
   nsresult rv = acc->GetName(description);
   if (NS_FAILED(rv))
     return E_FAIL;
 
-  if (!::SysReAllocStringLen(aDescription, description.get(), description.Length()))
+  if (description.IsEmpty())
+    return S_FALSE;
+
+  *aDescription = ::SysAllocStringLen(description.get(), description.Length());
+  if (!*aDescription)
     return E_OUTOFMEMORY;
+
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK;
 }
 
 STDMETHODIMP
 CAccessibleImage::get_imagePosition(enum IA2CoordinateType aCoordType,
                                     long *aX,
--- a/accessible/src/msaa/CAccessibleTable.cpp
+++ b/accessible/src/msaa/CAccessibleTable.cpp
@@ -155,27 +155,33 @@ CAccessibleTable::get_childIndex(long aR
 
   return E_FAIL;
 }
 
 STDMETHODIMP
 CAccessibleTable::get_columnDescription(long aColumn, BSTR *aDescription)
 {
 __try {
+  *aDescription = NULL;
+
   nsCOMPtr<nsIAccessibleTable> tableAcc(do_QueryInterface(this));
   NS_ASSERTION(tableAcc, CANT_QUERY_ASSERTION_MSG);
   if (!tableAcc)
     return E_FAIL;
 
   nsAutoString descr;
   nsresult rv = tableAcc->GetColumnDescription (aColumn, descr);
   if (NS_FAILED(rv))
     return E_FAIL;
 
-  if (!::SysReAllocStringLen(aDescription, descr.get(), descr.Length()))
+  if (descr.IsEmpty())
+    return S_FALSE;
+
+  *aDescription = ::SysAllocStringLen(descr.get(), descr.Length());
+  if (!*aDescription)
     return E_OUTOFMEMORY;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return S_OK;
 }
 
 STDMETHODIMP
 CAccessibleTable::get_columnExtentAt(long aRow, long aColumn,
@@ -365,27 +371,33 @@ CAccessibleTable::get_nSelectedRows(long
 
   return E_FAIL;
 }
 
 STDMETHODIMP
 CAccessibleTable::get_rowDescription(long aRow, BSTR *aDescription)
 {
 __try {
+  *aDescription = NULL;
+
   nsCOMPtr<nsIAccessibleTable> tableAcc(do_QueryInterface(this));
   NS_ASSERTION(tableAcc, CANT_QUERY_ASSERTION_MSG);
   if (!tableAcc)
     return E_FAIL;
 
   nsAutoString descr;
   nsresult rv = tableAcc->GetRowDescription (aRow, descr);
   if (NS_FAILED(rv))
     return E_FAIL;
 
-  if (!::SysReAllocStringLen(aDescription, descr.get(), descr.Length()))
+  if (descr.IsEmpty())
+    return S_FALSE;
+
+  *aDescription = ::SysAllocStringLen(descr.get(), descr.Length());
+  if (!*aDescription)
     return E_OUTOFMEMORY;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return S_OK;
 }
 
 STDMETHODIMP
 CAccessibleTable::get_rowExtentAt(long aRow, long aColumn, long *aNRowsSpanned)
--- a/accessible/src/msaa/CAccessibleText.cpp
+++ b/accessible/src/msaa/CAccessibleText.cpp
@@ -95,16 +95,18 @@ CAccessibleText::addSelection(long aStar
   return E_FAIL;
 }
 
 STDMETHODIMP
 CAccessibleText::get_attributes(long aOffset, long *aStartOffset,
                                 long *aEndOffset, BSTR *aTextAttributes)
 {
 __try {
+  *aTextAttributes = NULL;
+
   GET_NSIACCESSIBLETEXT
 
   nsCOMPtr<nsIAccessible> accessible;
   PRInt32 startOffset = 0, endOffset = 0;
   textAcc->GetAttributeRange(aOffset, &startOffset, &endOffset,
                              getter_AddRefs(accessible));
   if (!accessible)
     return E_FAIL;
@@ -232,37 +234,46 @@ CAccessibleText::get_selection(long aSel
 
   return E_FAIL;
 }
 
 STDMETHODIMP
 CAccessibleText::get_text(long aStartOffset, long aEndOffset, BSTR *aText)
 {
 __try {
+  *aText = NULL;
+
   GET_NSIACCESSIBLETEXT
 
   nsAutoString text;
   nsresult rv = textAcc->GetText(aStartOffset, aEndOffset, text);
   if (NS_FAILED(rv))
     return E_FAIL;
 
-  if (!::SysReAllocStringLen(aText, text.get(), text.Length()))
+  if (text.IsEmpty())
+    return S_FALSE;
+
+  *aText = ::SysAllocStringLen(text.get(), text.Length());
+  if (!*aText)
     return E_OUTOFMEMORY;
+
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK;
 }
 
 STDMETHODIMP
 CAccessibleText::get_textBeforeOffset(long aOffset,
                                       enum IA2TextBoundaryType aBoundaryType,
                                       long *aStartOffset, long *aEndOffset,
                                       BSTR *aText)
 {
 __try {
+  *aText = NULL;
+
   GET_NSIACCESSIBLETEXT
 
   nsresult rv = NS_OK;
   nsAutoString text;
   PRInt32 startOffset = 0, endOffset = 0;
 
   if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) {
     startOffset = 0;
@@ -277,30 +288,37 @@ CAccessibleText::get_textBeforeOffset(lo
   }
 
   if (NS_FAILED(rv))
     return E_FAIL;
 
   *aStartOffset = startOffset;
   *aEndOffset = endOffset;
 
-  if (!::SysReAllocStringLen(aText, text.get(), text.Length()))
+  if (text.IsEmpty())
+    return S_FALSE;
+
+  *aText = ::SysAllocStringLen(text.get(), text.Length());
+  if (!*aText)
     return E_OUTOFMEMORY;
+
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK;
 }
 
 STDMETHODIMP
 CAccessibleText::get_textAfterOffset(long aOffset,
                                      enum IA2TextBoundaryType aBoundaryType,
                                      long *aStartOffset, long *aEndOffset,
                                      BSTR *aText)
 {
 __try {
+  *aText = NULL;
+
   GET_NSIACCESSIBLETEXT
 
   nsresult rv = NS_OK;
   nsAutoString text;
   PRInt32 startOffset = 0, endOffset = 0;
 
   if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) {
     startOffset = 0;
@@ -315,18 +333,23 @@ CAccessibleText::get_textAfterOffset(lon
   }
 
   if (NS_FAILED(rv))
     return E_FAIL;
 
   *aStartOffset = startOffset;
   *aEndOffset = endOffset;
 
-  if (!::SysReAllocStringLen(aText, text.get(), text.Length()))
+  if (text.IsEmpty())
+    return S_FALSE;
+
+  *aText = ::SysAllocStringLen(text.get(), text.Length());
+  if (!*aText)
     return E_OUTOFMEMORY;
+
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK;
 }
 
 STDMETHODIMP
 CAccessibleText::get_textAtOffset(long aOffset,
                                   enum IA2TextBoundaryType aBoundaryType,
@@ -353,18 +376,23 @@ CAccessibleText::get_textAtOffset(long a
   }
 
   if (NS_FAILED(rv))
     return E_FAIL;
 
   *aStartOffset = startOffset;
   *aEndOffset = endOffset;
 
-  if (!::SysReAllocStringLen(aText, text.get(), text.Length()))
+  if (text.IsEmpty())
+    return S_FALSE;
+
+  *aText = ::SysAllocStringLen(text.get(), text.Length());
+  if (!*aText)
     return E_OUTOFMEMORY;
+
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK;
 }
 
 STDMETHODIMP
 CAccessibleText::removeSelection(long aSelectionIndex)
 {
@@ -492,18 +520,18 @@ CAccessibleText::GetModifiedText(PRBool 
   nsresult rv = GetModifiedText(aGetInsertedText, text,
                                 &startOffset, &endOffset);
   if (NS_FAILED(rv))
     return E_FAIL;
 
   aText->start = startOffset;
   aText->end = endOffset;
 
-  INT result = ::SysReAllocStringLen(&(aText->text), text.get(), text.Length());
-  return result ? NS_OK : E_OUTOFMEMORY;
+  aText->text = ::SysAllocStringLen(text.get(), text.Length());
+  return aText->text ? NS_OK : E_OUTOFMEMORY;
 }
 
 nsAccessibleTextBoundary
 CAccessibleText::GetGeckoTextBoundary(enum IA2TextBoundaryType aBoundaryType)
 {
   switch (aBoundaryType) {
     case IA2_TEXT_BOUNDARY_CHAR:
       return nsIAccessibleText::BOUNDARY_CHAR;
--- a/accessible/src/msaa/nsAccessNodeWrap.cpp
+++ b/accessible/src/msaa/nsAccessNodeWrap.cpp
@@ -526,33 +526,46 @@ nsAccessNodeWrap::get_innerHTML(BSTR __R
   *aInnerHTML = nsnull;
 
   nsCOMPtr<nsIDOMNSHTMLElement> domNSElement(do_QueryInterface(mDOMNode));
   if (!domNSElement)
     return E_FAIL; // Node already shut down
 
   nsAutoString innerHTML;
   domNSElement->GetInnerHTML(innerHTML);
-  *aInnerHTML = ::SysAllocString(innerHTML.get());
+  if (innerHTML.IsEmpty())
+    return S_FALSE;
+
+  *aInnerHTML = ::SysAllocStringLen(innerHTML.get(), innerHTML.Length());
+  if (!*aInnerHTML)
+    return E_OUTOFMEMORY;
+
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK;
 }
 
 STDMETHODIMP 
 nsAccessNodeWrap::get_language(BSTR __RPC_FAR *aLanguage)
 {
 __try {
-  *aLanguage = nsnull;
+  *aLanguage = NULL;
 
   nsAutoString language;
   if (NS_FAILED(GetLanguage(language))) {
     return E_FAIL;
   }
-  *aLanguage = ::SysAllocString(language.get());
+
+  if (language.IsEmpty())
+    return S_FALSE;
+
+  *aLanguage = ::SysAllocStringLen(language.get(), language.Length());
+  if (!*aLanguage)
+    return E_OUTOFMEMORY;
+
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK;
 }
 
 STDMETHODIMP 
 nsAccessNodeWrap::get_localInterface( 
     /* [out] */ void __RPC_FAR *__RPC_FAR *localInterface)
--- a/accessible/src/msaa/nsAccessibleRelationWrap.cpp
+++ b/accessible/src/msaa/nsAccessibleRelationWrap.cpp
@@ -81,67 +81,69 @@ nsAccessibleRelationWrap::QueryInterface
 }
 
 // IAccessibleRelation
 
 STDMETHODIMP
 nsAccessibleRelationWrap::get_relationType(BSTR *aRelationType)
 {
 __try {
+  *aRelationType = NULL;
+
   PRUint32 type = 0;
   nsresult rv = GetRelationType(&type);
   if (NS_FAILED(rv))
     return E_FAIL;
 
   INT res;
   switch (type) {
     case RELATION_CONTROLLED_BY:
-      res = ::SysReAllocString(aRelationType, IA2_RELATION_CONTROLLED_BY);
+      *aRelationType = ::SysAllocString(IA2_RELATION_CONTROLLED_BY);
       break;
     case RELATION_CONTROLLER_FOR:
-      res = ::SysReAllocString(aRelationType, IA2_RELATION_CONTROLLER_FOR);
+      *aRelationType = ::SysAllocString(IA2_RELATION_CONTROLLER_FOR);
       break;
     case RELATION_DESCRIBED_BY:
-      res = ::SysReAllocString(aRelationType, IA2_RELATION_DESCRIBED_BY);
+      *aRelationType = ::SysAllocString(IA2_RELATION_DESCRIBED_BY);
       break;
     case RELATION_DESCRIPTION_FOR:
-      res = ::SysReAllocString(aRelationType, IA2_RELATION_DESCRIPTION_FOR);
+      *aRelationType = ::SysAllocString(IA2_RELATION_DESCRIPTION_FOR);
       break;
     case RELATION_EMBEDDED_BY:
-      res = ::SysReAllocString(aRelationType, IA2_RELATION_EMBEDDED_BY);
+      *aRelationType = ::SysAllocString(IA2_RELATION_EMBEDDED_BY);
       break;
     case RELATION_EMBEDS:
-      res = ::SysReAllocString(aRelationType, IA2_RELATION_EMBEDS);
+      *aRelationType = ::SysAllocString(IA2_RELATION_EMBEDS);
       break;
     case RELATION_FLOWS_FROM:
-      res = ::SysReAllocString(aRelationType, IA2_RELATION_FLOWS_FROM);
+      *aRelationType = ::SysAllocString(IA2_RELATION_FLOWS_FROM);
       break;
     case RELATION_FLOWS_TO:
-      res = ::SysReAllocString(aRelationType, IA2_RELATION_FLOWS_TO);
+      *aRelationType = ::SysAllocString(IA2_RELATION_FLOWS_TO);
       break;
     case RELATION_LABEL_FOR:
-      res = ::SysReAllocString(aRelationType, IA2_RELATION_LABEL_FOR);
+      *aRelationType = ::SysAllocString(IA2_RELATION_LABEL_FOR);
       break;
     case RELATION_LABELLED_BY:
-      res = ::SysReAllocString(aRelationType, IA2_RELATION_LABELED_BY);
+      *aRelationType = ::SysAllocString(IA2_RELATION_LABELED_BY);
       break;
     case RELATION_MEMBER_OF:
-      res = ::SysReAllocString(aRelationType, IA2_RELATION_MEMBER_OF);
+      *aRelationType = ::SysAllocString(IA2_RELATION_MEMBER_OF);
       break;
     case RELATION_NODE_CHILD_OF:
-      res = ::SysReAllocString(aRelationType, IA2_RELATION_NODE_CHILD_OF);
+      *aRelationType = ::SysAllocString(IA2_RELATION_NODE_CHILD_OF);
       break;
     case RELATION_PARENT_WINDOW_OF:
-      res = ::SysReAllocString(aRelationType, IA2_RELATION_PARENT_WINDOW_OF);
+      *aRelationType = ::SysAllocString(IA2_RELATION_PARENT_WINDOW_OF);
       break;
     case RELATION_POPUP_FOR:
-      res = ::SysReAllocString(aRelationType, IA2_RELATION_POPUP_FOR);
+      *aRelationType = ::SysAllocString(IA2_RELATION_POPUP_FOR);
       break;
     case RELATION_SUBWINDOW_OF:
-      res = ::SysReAllocString(aRelationType, IA2_RELATION_SUBWINDOW_OF);
+      *aRelationType = ::SysAllocString(IA2_RELATION_SUBWINDOW_OF);
       break;
     default:
       return E_FAIL;
   }
 
   if (!res)
     return E_OUTOFMEMORY;
 
--- a/accessible/src/msaa/nsAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsAccessibleWrap.cpp
@@ -289,20 +289,25 @@ STDMETHODIMP nsAccessibleWrap::get_accNa
 {
 __try {
   *pszName = NULL;
   nsCOMPtr<nsIAccessible> xpAccessible;
   GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
   if (xpAccessible) {
     nsAutoString name;
     if (NS_FAILED(xpAccessible->GetName(name)))
+      return E_FAIL;
+
+    if (name.IsEmpty())
       return S_FALSE;
-    if (!name.IsVoid()) {
-      *pszName = ::SysAllocString(name.get());
-    }
+
+    *pszName = ::SysAllocStringLen(name.get(), name.Length());
+    if (!*pszName)
+      return E_OUTOFMEMORY;
+
 #ifdef DEBUG_A11Y
     NS_ASSERTION(mIsInitialized, "Access node was not initialized");
 #endif
   }
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK;
 }
@@ -314,19 +319,24 @@ STDMETHODIMP nsAccessibleWrap::get_accVa
 {
 __try {
   *pszValue = NULL;
   nsCOMPtr<nsIAccessible> xpAccessible;
   GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
   if (xpAccessible) {
     nsAutoString value;
     if (NS_FAILED(xpAccessible->GetValue(value)))
+      return E_FAIL;
+
+    if (value.IsEmpty())
       return S_FALSE;
 
-    *pszValue = ::SysAllocString(value.get());
+    *pszValue = ::SysAllocStringLen(value.get(), value.Length());
+    if (!*pszValue)
+      return E_OUTOFMEMORY;
   }
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return S_OK;
 }
 
 STDMETHODIMP
 nsAccessibleWrap::get_accDescription(VARIANT varChild,
                                      BSTR __RPC_FAR *pszDescription)
@@ -410,32 +420,39 @@ nsAccessibleWrap::get_accDescription(VAR
                                 positionInGroup, itemsInGroup);
     }
   } else if (groupLevel > 0) {
     nsTextFormatter::ssprintf(description, NS_LITERAL_STRING("L%d").get(),
                               groupLevel);
   }
 
   if (!description.IsEmpty()) {
-    *pszDescription = ::SysAllocString(description.get());
-    return S_OK;
+    *pszDescription = ::SysAllocStringLen(description.get(),
+                                          description.Length());
+    return *pszDescription ? S_OK : E_OUTOFMEMORY;
   }
 
   xpAccessible->GetDescription(description);
   if (!description.IsEmpty()) {
     // Signal to screen readers that this description is speakable
     // and is not a formatted positional information description
     // Don't localize the "Description: " part of this string, it will be
     // parsed out by assistive technologies.
     description = NS_LITERAL_STRING("Description: ") + description;
   }
 
-  *pszDescription = ::SysAllocString(description.get());
+  if (description.IsEmpty())
+    return S_FALSE;
+
+  *pszDescription = ::SysAllocStringLen(description.get(),
+                                        description.Length());
+  return *pszDescription ? S_OK : E_OUTOFMEMORY;
+
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
-  return S_OK;
+  return E_FAIL;
 }
 
 STDMETHODIMP nsAccessibleWrap::get_accRole(
       /* [optional][in] */ VARIANT varChild,
       /* [retval][out] */ VARIANT __RPC_FAR *pvarRole)
 {
 __try {
   VariantInit(pvarRole);
@@ -560,23 +577,27 @@ STDMETHODIMP nsAccessibleWrap::get_accKe
 __try {
   *pszKeyboardShortcut = NULL;
   nsCOMPtr<nsIAccessible> xpAccessible;
   GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
   if (xpAccessible) {
     nsAutoString shortcut;
     nsresult rv = xpAccessible->GetKeyboardShortcut(shortcut);
     if (NS_FAILED(rv))
+      return E_FAIL;
+
+    if (shortcut.IsEmpty())
       return S_FALSE;
 
-    *pszKeyboardShortcut = ::SysAllocString(shortcut.get());
-    return S_OK;
+    *pszKeyboardShortcut = ::SysAllocStringLen(shortcut.get(),
+                                               shortcut.Length());
+    return *pszKeyboardShortcut ? S_OK : E_OUTOFMEMORY;
   }
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
-  return S_FALSE;
+  return E_FAIL;
 }
 
 STDMETHODIMP nsAccessibleWrap::get_accFocus(
       /* [retval][out] */ VARIANT __RPC_FAR *pvarChild)
 {
   // VT_EMPTY:    None. This object does not have the keyboard focus itself
   //              and does not contain a child that has the keyboard focus.
   // VT_I4:       lVal is CHILDID_SELF. The object itself has the keyboard focus.
@@ -790,23 +811,28 @@ STDMETHODIMP nsAccessibleWrap::get_accDe
 {
 __try {
   *pszDefaultAction = NULL;
   nsCOMPtr<nsIAccessible> xpAccessible;
   GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
   if (xpAccessible) {
     nsAutoString defaultAction;
     if (NS_FAILED(xpAccessible->GetActionName(0, defaultAction)))
+      return E_FAIL;
+
+    if (defaultAction.IsEmpty())
       return S_FALSE;
 
-    *pszDefaultAction = ::SysAllocString(defaultAction.get());
+    *pszDefaultAction = ::SysAllocStringLen(defaultAction.get(),
+                                            defaultAction.Length());
+    return *pszDefaultAction ? S_OK : E_OUTOFMEMORY;
   }
 
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
-  return S_OK;
+  return E_FAIL;
 }
 
 STDMETHODIMP nsAccessibleWrap::accSelect(
       /* [in] */ long flagsSelect,
       /* [optional][in] */ VARIANT varChild)
 {
 __try {
   // currently only handle focus and selection
@@ -1336,49 +1362,68 @@ nsAccessibleWrap::get_states(AccessibleS
   if (extraStates & nsIAccessibleStates::EXT_STATE_VERTICAL)
     *aStates |= IA2_STATE_VERTICAL;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return S_OK;
 }
 
 STDMETHODIMP
-nsAccessibleWrap::get_extendedRole(BSTR *extendedRole)
+nsAccessibleWrap::get_extendedRole(BSTR *aExtendedRole)
 {
+__try {
+  *aExtendedRole = NULL;
+} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
+
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
-nsAccessibleWrap::get_localizedExtendedRole(BSTR *localizedExtendedRole)
+nsAccessibleWrap::get_localizedExtendedRole(BSTR *aLocalizedExtendedRole)
 {
+__try {
+  *aLocalizedExtendedRole = NULL;
+} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
+  
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
-nsAccessibleWrap::get_nExtendedStates(long *nExtendedStates)
+nsAccessibleWrap::get_nExtendedStates(long *aNExtendedStates)
 {
-  *nExtendedStates = 0;
+__try {
+  *aNExtendedStates = 0;
+} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
+
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
-nsAccessibleWrap::get_extendedStates(long maxExtendedStates,
-                                     BSTR **extendedStates,
-                                     long *nExtendedStates)
+nsAccessibleWrap::get_extendedStates(long aMaxExtendedStates,
+                                     BSTR **aExtendedStates,
+                                     long *aNExtendedStates)
 {
-  *nExtendedStates = 0;
+__try {
+  *aExtendedStates = NULL;
+  *aNExtendedStates = 0;
+} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
+
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
-nsAccessibleWrap::get_localizedExtendedStates(long maxLocalizedExtendedStates,
-                                              BSTR **localizedExtendedStates,
-                                              long *nLocalizedExtendedStates)
+nsAccessibleWrap::get_localizedExtendedStates(long aMaxLocalizedExtendedStates,
+                                              BSTR **aLocalizedExtendedStates,
+                                              long *aNLocalizedExtendedStates)
 {
-  *nLocalizedExtendedStates = 0;
+__try {
+  *aLocalizedExtendedStates = NULL;
+  *aNLocalizedExtendedStates = 0;
+} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
+
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
 nsAccessibleWrap::get_uniqueID(long *uniqueID)
 {
 __try {
   void *id = nsnull;
@@ -1518,17 +1563,17 @@ nsAccessibleWrap::get_attributes(BSTR *a
     }
 
     AppendUTF8toUTF16(name, strAttrs);
     strAttrs.Append(':');
     strAttrs.Append(value);
     strAttrs.Append(';');
   }
 
-  *aAttributes = ::SysAllocString(strAttrs.get()); 
+  *aAttributes = ::SysAllocStringLen(strAttrs.get(), strAttrs.Length()); 
   if (!*aAttributes)
     return E_OUTOFMEMORY;
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return S_OK;
 }
 
 STDMETHODIMP
@@ -1622,21 +1667,16 @@ nsAccessibleWrap::FireAccessibleEvent(ns
   // Means we're not active.
   NS_ENSURE_TRUE(mWeakShell, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIAccessible> accessible;
   aEvent->GetAccessible(getter_AddRefs(accessible));
   if (!accessible)
     return NS_OK;
 
-  PRUint32 role = ROLE_SYSTEM_TEXT; // Default value
-
-  nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(accessible));
-  NS_ENSURE_STATE(accessNode);
-
   if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED ||
       eventType == nsIAccessibleEvent::EVENT_FOCUS) {
     UpdateSystemCaret();
   }
  
   PRInt32 childID = GetChildIDFor(accessible); // get the id for the accessible
   if (!childID)
     return NS_OK; // Can't fire an event without a child ID
@@ -1647,17 +1687,17 @@ nsAccessibleWrap::FireAccessibleEvent(ns
       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);
+  HWND hWnd = GetHWNDFor(newAccessible);
   NS_ENSURE_TRUE(hWnd, NS_ERROR_FAILURE);
 
   // Gecko uses two windows for every scrollable area. One window contains
   // scrollbars and the child window contains only the client area.
   // Details of the 2 window system:
   // * Scrollbar window: caret drawing window & return value for WindowFromAccessibleObject()
   // * Client area window: text drawing window & MSAA event window
 
--- a/accessible/src/msaa/nsApplicationAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsApplicationAccessibleWrap.cpp
@@ -67,77 +67,99 @@ nsApplicationAccessibleWrap::QueryInterf
 }
 
 // IAccessibleApplication
 
 STDMETHODIMP
 nsApplicationAccessibleWrap::get_appName(BSTR *aName)
 {
 __try {
+  *aName = NULL;
+
   if (!sAppInfo)
     return E_FAIL;
 
   nsCAutoString cname;
   nsresult rv = sAppInfo->GetName(cname);
-
   if (NS_FAILED(rv))
     return E_FAIL;
 
+  if (cname.IsEmpty())
+    return S_FALSE;
+
   NS_ConvertUTF8toUTF16 name(cname);
-  if (!::SysReAllocStringLen(aName, name.get(), name.Length()))
+  *aName = ::SysAllocStringLen(name.get(), name.Length());
+  if (!*aName)
     return E_OUTOFMEMORY;
+
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK;
 }
 
 STDMETHODIMP
 nsApplicationAccessibleWrap::get_appVersion(BSTR *aVersion)
 {
 __try {
+  *aVersion = NULL;
+
   if (!sAppInfo)
     return E_FAIL;
 
   nsCAutoString cversion;
   nsresult rv = sAppInfo->GetVersion(cversion);
-
   if (NS_FAILED(rv))
     return E_FAIL;
 
+  if (cversion.IsEmpty())
+    return S_FALSE;
+
   NS_ConvertUTF8toUTF16 version(cversion);
-  if (!::SysReAllocStringLen(aVersion, version.get(), version.Length()))
+  *aVersion = ::SysAllocStringLen(version.get(), version.Length());
+  if (!*aVersion)
     return E_OUTOFMEMORY;
+
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return S_OK;
 }
 
 STDMETHODIMP
 nsApplicationAccessibleWrap::get_toolkitName(BSTR *aName)
 {
-  return ::SysReAllocString(aName, L"Gecko");
+__try {
+  *aName = ::SysAllocString(L"Gecko");
+  return *aName ? S_OK : E_OUTOFMEMORY;
+} __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
+
+  return E_FAIL;
 }
 
 STDMETHODIMP
 nsApplicationAccessibleWrap::get_toolkitVersion(BSTR *aVersion)
 {
 __try {
+  *aVersion = NULL;
+
   if (!sAppInfo)
     return E_FAIL;
 
   nsCAutoString cversion;
   nsresult rv = sAppInfo->GetPlatformVersion(cversion);
-
   if (NS_FAILED(rv))
     return E_FAIL;
 
+  if (cversion.IsEmpty())
+    return S_FALSE;
+
   NS_ConvertUTF8toUTF16 version(cversion);
-  if (!::SysReAllocStringLen(aVersion, version.get(), version.Length()))
-    return E_OUTOFMEMORY;
+  *aVersion = ::SysAllocStringLen(version.get(), version.Length());
+  return *aVersion ? S_OK : E_OUTOFMEMORY;
+
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
-  return S_OK;
+  return E_FAIL;
 }
 
 // nsApplicationAccessibleWrap
 
 void
 nsApplicationAccessibleWrap::PreCreate()
 {
   nsresult rv = CallGetService("@mozilla.org/xre/app-info;1", &sAppInfo);
--- a/accessible/src/msaa/nsDocAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsDocAccessibleWrap.cpp
@@ -197,78 +197,137 @@ NS_IMETHODIMP nsDocAccessibleWrap::FireA
 
   return NS_OK;
 }
 
 STDMETHODIMP nsDocAccessibleWrap::get_URL(/* [out] */ BSTR __RPC_FAR *aURL)
 {
 __try {
   *aURL = NULL;
+
   nsAutoString URL;
-  if (NS_SUCCEEDED(GetURL(URL))) {
-    *aURL= ::SysAllocString(URL.get());
-    return S_OK;
-  }
+  nsresult rv = GetURL(URL);
+  if (NS_FAILED(rv))
+    return E_FAIL;
+
+  if (URL.IsEmpty())
+    return S_FALSE;
+
+  *aURL = ::SysAllocStringLen(URL.get(), URL.Length());
+  return *aURL ? S_OK : E_OUTOFMEMORY;
+
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP nsDocAccessibleWrap::get_title( /* [out] */ BSTR __RPC_FAR *aTitle)
 {
 __try {
   *aTitle = NULL;
+
   nsAutoString title;
-  if (NS_SUCCEEDED(GetTitle(title))) { // getter_Copies(pszTitle)))) {
-    *aTitle= ::SysAllocString(title.get());
-    return S_OK;
-  }
+  nsresult rv = GetTitle(title);
+  if (NS_FAILED(rv))
+    return E_FAIL;
+
+  *aTitle = ::SysAllocStringLen(title.get(), title.Length());
+  return *aTitle ? S_OK : E_OUTOFMEMORY;
+
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP nsDocAccessibleWrap::get_mimeType(/* [out] */ BSTR __RPC_FAR *aMimeType)
 {
 __try {
   *aMimeType = NULL;
+
   nsAutoString mimeType;
-  if (NS_SUCCEEDED(GetMimeType(mimeType))) {
-    *aMimeType= ::SysAllocString(mimeType.get());
-    return S_OK;
-  }
+  nsresult rv = GetMimeType(mimeType);
+  if (NS_FAILED(rv))
+    return E_FAIL;
+
+  if (mimeType.IsEmpty())
+    return S_FALSE;
+
+  *aMimeType = ::SysAllocStringLen(mimeType.get(), mimeType.Length());
+  return *aMimeType ? S_OK : E_OUTOFMEMORY;
+
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP nsDocAccessibleWrap::get_docType(/* [out] */ BSTR __RPC_FAR *aDocType)
 {
 __try {
   *aDocType = NULL;
+
   nsAutoString docType;
-  if (NS_SUCCEEDED(GetDocType(docType))) {
-    *aDocType= ::SysAllocString(docType.get());
-    return S_OK;
-  }
+  nsresult rv = GetDocType(docType);
+  if (NS_FAILED(rv))
+    return E_FAIL;
+
+  if (docType.IsEmpty())
+    return S_FALSE;
+
+  *aDocType = ::SysAllocStringLen(docType.get(), docType.Length());
+  return *aDocType ? S_OK : E_OUTOFMEMORY;
+
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP nsDocAccessibleWrap::get_nameSpaceURIForID(/* [in] */  short aNameSpaceID,
   /* [out] */ BSTR __RPC_FAR *aNameSpaceURI)
 {
 __try {
-  if (aNameSpaceID < 0) {
-    return E_FAIL;  // -1 is kNameSpaceID_Unknown
-  }
   *aNameSpaceURI = NULL;
+
+  if (aNameSpaceID < 0)
+    return E_INVALIDARG;  // -1 is kNameSpaceID_Unknown
+
   nsAutoString nameSpaceURI;
-  if (NS_SUCCEEDED(GetNameSpaceURIForID(aNameSpaceID, nameSpaceURI))) {
-    *aNameSpaceURI = ::SysAllocString(nameSpaceURI.get());
-    return S_OK;
-  }
+  nsresult rv = GetNameSpaceURIForID(aNameSpaceID, nameSpaceURI);
+  if (NS_FAILED(rv))
+    return E_FAIL;
+
+  if (nameSpaceURI.IsEmpty())
+    return S_FALSE;
+
+  *aNameSpaceURI = ::SysAllocStringLen(nameSpaceURI.get(),
+                                       nameSpaceURI.Length());
+
+  return *aNameSpaceURI ? S_OK : E_OUTOFMEMORY;
+
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
-STDMETHODIMP nsDocAccessibleWrap::put_alternateViewMediaTypes( /* [in] */ BSTR __RPC_FAR *commaSeparatedMediaTypes)
+STDMETHODIMP
+nsDocAccessibleWrap::put_alternateViewMediaTypes( /* [in] */ BSTR __RPC_FAR *aCommaSeparatedMediaTypes)
 {
+__try {
+  *aCommaSeparatedMediaTypes = NULL;
+} __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
+
   return E_NOTIMPL;
 }
 
+STDMETHODIMP nsDocAccessibleWrap::get_accValue(
+      /* [optional][in] */ VARIANT varChild,
+      /* [retval][out] */ BSTR __RPC_FAR *pszValue)
+{
+  // For backwards-compat, we still support old MSAA hack to provide URL in accValue
+  *pszValue = NULL;
+  // Check for real value first
+  HRESULT hr = nsAccessibleWrap::get_accValue(varChild, pszValue);
+  if (FAILED(hr) || *pszValue || varChild.lVal != CHILDID_SELF)
+    return hr;
+  // If document is being used to create a widget, don't use the URL hack
+  PRUint32 role = Role(this);
+  if (role != nsIAccessibleRole::ROLE_DOCUMENT &&
+      role != nsIAccessibleRole::ROLE_APPLICATION &&
+      role != nsIAccessibleRole::ROLE_DIALOG &&
+      role != nsIAccessibleRole::ROLE_ALERT)
+    return hr;
+
+  return get_URL(pszValue);
+}
--- a/accessible/src/msaa/nsDocAccessibleWrap.h
+++ b/accessible/src/msaa/nsDocAccessibleWrap.h
@@ -82,12 +82,17 @@ public:
         /* [in] */ BSTR __RPC_FAR *commaSeparatedMediaTypes);
 
     // IAccessible
     // Override get_accChild so that it can get any child via the unique ID
     virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accChild( 
         /* [in] */ VARIANT varChild,
         /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispChild);
 
+    // Override get_accValue to provide URL when no other value is available
+    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accValue( 
+        /* [optional][in] */ VARIANT varChild,
+        /* [retval][out] */ BSTR __RPC_FAR *pszValue);
+
     NS_IMETHOD FireAnchorJumpEvent();
 };
 
 #endif
--- a/accessible/src/msaa/nsTextAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsTextAccessibleWrap.cpp
@@ -80,25 +80,31 @@ STDMETHODIMP nsTextAccessibleWrap::Query
   (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); 
   return S_OK;
 }
 
 STDMETHODIMP nsTextAccessibleWrap::get_domText( 
     /* [retval][out] */ BSTR __RPC_FAR *aDomText)
 {
 __try {
-  *aDomText = nsnull;
+  *aDomText = NULL;
 
   if (!mDOMNode) {
     return E_FAIL; // Node already shut down
   }
   nsAutoString nodeValue;
 
   mDOMNode->GetNodeValue(nodeValue);
-  *aDomText = ::SysAllocString(nodeValue.get());
+  if (nodeValue.IsEmpty())
+    return S_FALSE;
+
+  *aDomText = ::SysAllocStringLen(nodeValue.get(), nodeValue.Length());
+  if (!*aDomText)
+    return E_OUTOFMEMORY;
+
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK;
 }
 
 STDMETHODIMP nsTextAccessibleWrap::get_clippedSubstringBounds( 
     /* [in] */ unsigned int aStartIndex,
     /* [in] */ unsigned int aEndIndex,
@@ -235,17 +241,17 @@ nsresult nsTextAccessibleWrap::GetCharac
 
   return NS_OK;
 }
 
 STDMETHODIMP nsTextAccessibleWrap::get_fontFamily(
     /* [retval][out] */ BSTR __RPC_FAR *aFontFamily)
 {
 __try {
-  *aFontFamily = nsnull;
+  *aFontFamily = NULL;
 
   nsIFrame *frame = GetFrame();
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   if (!frame || !presShell) {
     return E_FAIL;
   }
 
   nsCOMPtr<nsIRenderingContext> rc;
@@ -271,14 +277,19 @@ STDMETHODIMP nsTextAccessibleWrap::get_f
   nsIFontMetrics *fm;
   rc->GetFontMetrics(fm);
   if (!fm) {
     return E_FAIL;
   }
 
   nsAutoString fontFamily;
   deviceContext->FirstExistingFont(fm->Font(), fontFamily);
-  
-  *aFontFamily = ::SysAllocString(fontFamily.get());
+  if (fontFamily.IsEmpty())
+    return S_FALSE;
+
+  *aFontFamily = ::SysAllocStringLen(fontFamily.get(), fontFamily.Length());
+  if (!*aFontFamily)
+    return E_OUTOFMEMORY;
+
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK;
 }
--- a/accessible/src/xul/nsXULSelectAccessible.cpp
+++ b/accessible/src/xul/nsXULSelectAccessible.cpp
@@ -1026,17 +1026,16 @@ NS_IMETHODIMP nsXULComboboxAccessible::G
     *aRole = nsIAccessibleRole::ROLE_COMBOBOX;
   }
   return NS_OK;
 }
 
 /**
   * As a nsComboboxAccessible we can have the following states:
   *     STATE_FOCUSED
-  *     STATE_READONLY
   *     STATE_FOCUSABLE
   *     STATE_HASPOPUP
   *     STATE_EXPANDED
   *     STATE_COLLAPSED
   */
 NS_IMETHODIMP
 nsXULComboboxAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
 {
@@ -1052,21 +1051,16 @@ nsXULComboboxAccessible::GetState(PRUint
     PRBool isOpen;
     menuList->GetOpen(&isOpen);
     if (isOpen) {
       *aState |= nsIAccessibleStates::STATE_EXPANDED;
     }
     else {
       *aState |= nsIAccessibleStates::STATE_COLLAPSED;
     }
-    PRBool isEditable;
-    menuList->GetEditable(&isEditable);
-    if (!isEditable) {
-      *aState |= nsIAccessibleStates::STATE_READONLY;
-    }
   }
 
   *aState |= nsIAccessibleStates::STATE_HASPOPUP |
              nsIAccessibleStates::STATE_FOCUSABLE;
 
   return NS_OK;
 }
 
--- a/accessible/src/xul/nsXULTextAccessible.cpp
+++ b/accessible/src/xul/nsXULTextAccessible.cpp
@@ -40,16 +40,17 @@
 // NOTE: alphabetically ordered
 #include "nsAccessibilityAtoms.h"
 #include "nsAccessibilityUtils.h"
 #include "nsBaseWidgetAccessible.h"
 #include "nsIDOMXULDescriptionElement.h"
 #include "nsINameSpaceManager.h"
 #include "nsString.h"
 #include "nsXULTextAccessible.h"
+#include "nsNetUtil.h"
 
 /**
   * For XUL descriptions and labels
   */
 nsXULTextAccessible::nsXULTextAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell):
 nsHyperTextAccessibleWrap(aDomNode, aShell)
 { 
 }
@@ -133,67 +134,123 @@ nsXULTooltipAccessible::GetState(PRUint3
 }
 
 NS_IMETHODIMP nsXULTooltipAccessible::GetRole(PRUint32 *_retval)
 {
   *_retval = nsIAccessibleRole::ROLE_TOOLTIP;
   return NS_OK;
 }
 
-/**
- * For XUL text links
- */
-nsXULLinkAccessible::nsXULLinkAccessible(nsIDOMNode *aDomNode, nsIWeakReference *aShell):
-nsLinkableAccessible(aDomNode, aShell)
+////////////////////////////////////////////////////////////////////////////////
+// nsXULLinkAccessible
+
+nsXULLinkAccessible::
+  nsXULLinkAccessible(nsIDOMNode *aDomNode, nsIWeakReference *aShell):
+  nsHyperTextAccessibleWrap(aDomNode, aShell)
 {
 }
 
-NS_IMETHODIMP nsXULLinkAccessible::GetValue(nsAString& aValue)
-{
-  if (mIsLink) {
-    mActionContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::href, aValue);
-    return NS_OK;
-  }
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
+////////////////////////////////////////////////////////////////////////////////
+// nsXULLinkAccessible. nsIAccessible
 
-NS_IMETHODIMP nsXULLinkAccessible::GetName(nsAString& aName)
-{ 
+NS_IMETHODIMP
+nsXULLinkAccessible::GetValue(nsAString& aValue)
+{
+  aValue.Truncate();
+
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
-  if (!content) {
-    return NS_ERROR_FAILURE;  // Node shut down
-  }
-  if (!content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::value,
-                        aName)) {
-    // if the value doesn't exist, flatten the inner content as the name (for descriptions)
-    return AppendFlatStringFromSubtree(content, &aName);
-  }
-  // otherwise, use the value attribute as the name (for labels)
+  content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::href, aValue);
   return NS_OK;
 }
 
-NS_IMETHODIMP nsXULLinkAccessible::GetRole(PRUint32 *aRole)
+NS_IMETHODIMP
+nsXULLinkAccessible::GetName(nsAString& aName)
 {
-  // We used to say ROLE_BUTTON if there was no href, but then screen readers
-  // would tell users to hit the space bar for activation, which is wrong for a link
+  aName.Truncate();
+
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
+  content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::value, aName);
+  if (!aName.IsEmpty())
+    return NS_OK;
+
+  return AppendFlatStringFromSubtree(content, &aName);
+}
+
+NS_IMETHODIMP
+nsXULLinkAccessible::GetRole(PRUint32 *aRole)
+{
+  NS_ENSURE_ARG_POINTER(aRole);
+
   *aRole = nsIAccessibleRole::ROLE_LINK;
   return NS_OK;
 }
 
-void nsXULLinkAccessible::CacheActionContent()
+
+NS_IMETHODIMP
+nsXULLinkAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
+{
+  nsresult rv = nsHyperTextAccessibleWrap::GetState(aState, aExtraState);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  *aState |= nsIAccessibleStates::STATE_LINKED;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXULLinkAccessible::GetNumActions(PRUint8 *aNumActions)
 {
-  // not a link if no content
-  nsCOMPtr<nsIContent> mTempContent = do_QueryInterface(mDOMNode);
-  if (!mTempContent) {
-    return;
-  }
+  NS_ENSURE_ARG_POINTER(aNumActions);
+  
+  *aNumActions = 1;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXULLinkAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
+{
+  aName.Truncate();
+
+  if (aIndex != eAction_Jump)
+    return NS_ERROR_INVALID_ARG;
+  
+  aName.AssignLiteral("jump");
+  return NS_OK;
+}
 
-  // not a link if there is no href attribute or not on a <link> tag
-  if (mTempContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::href) ||
-      mTempContent->Tag() == nsAccessibilityAtoms::link) {
-    mIsLink = PR_TRUE;
-    mActionContent = mTempContent;
-  }
-  else if (nsAccUtils::HasListener(mTempContent, NS_LITERAL_STRING("click"))) {
-    mIsOnclick = PR_TRUE;
-    mActionContent = mTempContent;
-  }
+NS_IMETHODIMP
+nsXULLinkAccessible::DoAction(PRUint8 aIndex)
+{
+  if (aIndex != eAction_Jump)
+    return NS_ERROR_INVALID_ARG;
+
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
+  return DoCommand(content);
 }
+
+////////////////////////////////////////////////////////////////////////////////
+// nsXULLinkAccessible. nsIAccessibleHyperLink
+
+NS_IMETHODIMP
+nsXULLinkAccessible::GetURI(PRInt32 aIndex, nsIURI **aURI)
+{
+  NS_ENSURE_ARG_POINTER(aURI);
+  *aURI = nsnull;
+
+  if (aIndex != 0)
+    return NS_ERROR_INVALID_ARG;
+
+  nsAutoString href;
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
+  content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::href, href);
+
+  nsCOMPtr<nsIDocument> document = content->GetOwnerDoc();
+  return NS_NewURI(aURI, href,
+                   document ? document->GetDocumentCharacterSet().get() : nsnull);
+}
--- a/accessible/src/xul/nsXULTextAccessible.h
+++ b/accessible/src/xul/nsXULTextAccessible.h
@@ -63,22 +63,33 @@ class nsXULTooltipAccessible : public ns
 
 public:
   nsXULTooltipAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell);
   NS_IMETHOD GetName(nsAString& _retval); 
   NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
   NS_IMETHOD GetRole(PRUint32 *_retval); 
 };
 
-class nsXULLinkAccessible : public nsLinkableAccessible
+class nsXULLinkAccessible : public nsHyperTextAccessibleWrap
 {
 
 public:
   nsXULLinkAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell);
-  NS_IMETHOD GetName(nsAString& _retval); 
+
+  // nsIAccessible
+  NS_IMETHOD GetName(nsAString& aName); 
   NS_IMETHOD GetRole(PRUint32 *aRole);
-  NS_IMETHOD GetValue(nsAString& _retval);
+  NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
+  NS_IMETHOD GetValue(nsAString& aValue);
+
+  NS_IMETHOD GetNumActions(PRUint8 *aNumActions);
+  NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
+  NS_IMETHOD DoAction(PRUint8 aIndex);
+
+  // nsIAccessibleHyperLink
+  NS_IMETHOD GetURI(PRInt32 aIndex, nsIURI **aURI);
 
 protected:
-  void CacheActionContent();
+  enum { eAction_Jump = 0 };
+
 };
 
 #endif  
--- a/accessible/src/xul/nsXULTreeAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeAccessible.cpp
@@ -1280,33 +1280,35 @@ nsXULTreeColumnsAccessible::
   nsXULTreeColumnsAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell):
   nsXULColumnsAccessible(aDOMNode, aShell)
 {
 }
 
 NS_IMETHODIMP
 nsXULTreeColumnsAccessible::GetNextSibling(nsIAccessible **aNextSibling)
 {
-  nsresult ret = nsXULColumnsAccessible::GetNextSibling(aNextSibling);
+  NS_ENSURE_ARG_POINTER(aNextSibling);
+  *aNextSibling = nsnull;
 
-  if (*aNextSibling == nsnull) { // if there is not other sibling, use the first row as its sibling
-    nsCOMPtr<nsITreeBoxObject> tree;
-    nsCOMPtr<nsITreeView> treeView;
+  nsCOMPtr<nsITreeBoxObject> tree;
+  nsCOMPtr<nsITreeView> treeView;
 
-    nsXULTreeAccessible::GetTreeBoxObject(mDOMNode, getter_AddRefs(tree));
-    if (tree) {
-      tree->GetView(getter_AddRefs(treeView));
-      if (treeView) {
-        PRInt32 rowCount;
-        treeView->GetRowCount(&rowCount);
-        if (rowCount > 0) {
-          nsCOMPtr<nsITreeColumn> column = nsXULTreeAccessible::GetFirstVisibleColumn(tree);
-          nsCOMPtr<nsIAccessibleTreeCache> treeCache(do_QueryInterface(mParent));
-          NS_ENSURE_TRUE(treeCache, NS_ERROR_FAILURE);
-          ret = treeCache->GetCachedTreeitemAccessible(0, column, aNextSibling);
-        }
+  nsXULTreeAccessible::GetTreeBoxObject(mDOMNode, getter_AddRefs(tree));
+  if (tree) {
+    tree->GetView(getter_AddRefs(treeView));
+    if (treeView) {
+      PRInt32 rowCount;
+      treeView->GetRowCount(&rowCount);
+      if (rowCount > 0) {
+        nsCOMPtr<nsITreeColumn> column =
+          nsXULTreeAccessible::GetFirstVisibleColumn(tree);
+
+        nsCOMPtr<nsIAccessibleTreeCache> treeCache(do_QueryInterface(mParent));
+        NS_ENSURE_TRUE(treeCache, NS_ERROR_FAILURE);
+
+        return treeCache->GetCachedTreeitemAccessible(0, column, aNextSibling);
       }
     }
   }
 
-  return ret;
+  return NS_OK;
 }
 
--- a/accessible/tests/mochitest/Makefile.in
+++ b/accessible/tests/mochitest/Makefile.in
@@ -42,16 +42,17 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = accessible
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES =\
 		test_bug368835.xul \
+		test_bug420863.html \
 		test_groupattrs.xul \
 		test_table_indexes.html \
 		test_nsIAccessibleTable_1.html \
 		test_nsIAccessibleTable_2.html \
 		test_nsIAccessibleTable_3.html \
 		test_nsIAccessibleTable_listboxes.xul \
 		$(NULL)
 
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_bug420863.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=420863
+-->
+<head>
+  <title>Table indexes chrome tests</title>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript">
+    var gAccService = null;
+
+    var gTdClickAttr = false;
+    var gTdClickEventHandler = false;
+    var gClickHandler = null;
+
+    var gID = "";
+    var gNode = null;
+    var gAcc = null;
+
+    function doTest()
+    {
+      const nsIAccessibleRetrieval =
+        Components.interfaces.nsIAccessibleRetrieval;
+
+      gAccService = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+                    getService(nsIAccessibleRetrieval);
+
+      // Actions should be exposed on any accessible having related DOM node
+      // with registered 'click' event handler.
+
+      //////////////////////////////////////////////////////////////////////////
+      // generic td
+      gID = "td1";
+      gNode = document.getElementById(gID);
+      gAcc = gAccService.getAccessibleFor(gNode);
+
+      is(gAcc.numActions, 0, gID + ": shouldn't have actions");
+
+      //////////////////////////////////////////////////////////////////////////
+      // td with 'onclick' attribute
+      gID = "td2";
+      gNode = document.getElementById(gID);
+      gAcc = gAccService.getAccessibleFor(gNode);
+
+      is(gAcc.numActions, 1, gID + ": should have one action");
+      is(gAcc.getActionName(0), "click", gID + ": should have 'click' action");
+      gAcc.doAction(0);
+
+      // actions are performed via timeout
+      window.setTimeout(doTest2, 0);
+    }
+
+    function doTest2()
+    {
+      //////////////////////////////////////////////////////////////////////////
+      // td with 'onclick' attribute (sequel, see doTest1())
+      ok(gTdClickAttr, gID + ": 'click' action hasn't been performed");
+
+      //////////////////////////////////////////////////////////////////////////
+      // td with registered 'click' event handler
+      gID = "td3";
+      gNode = document.getElementById(gID);
+      gAcc = gAccService.getAccessibleFor(gNode);
+
+      // register 'click' event handler
+      gClickHandler = {
+        handleEvent: function handleEvent(aEvent)
+        {
+          gTdClickEventHandler = true;
+        }
+      };
+      gNode.addEventListener("click", gClickHandler, false);
+
+      // check actions
+      is(gAcc.numActions, 1, gID + ": should have one action");
+      is(gAcc.getActionName(0), "click", gID + ": should have 'click' action");
+      gAcc.doAction(0);
+
+      // actions are performed via timeout
+      window.setTimeout(doTest3, 0);
+    }
+
+    function doTest3()
+    {
+      //////////////////////////////////////////////////////////////////////////
+      // td with registered 'click' event handler (sequel, see doTest2())
+      ok(gTdClickEventHandler, gID + ": 'click' action hasn't been performed");
+
+      // unregister click event handler
+      gNode.removeEventListener("click", gClickHandler, false);
+
+      // check actions
+      is(gAcc.numActions, 0, gID + ": shouldn't have actions");
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=420863"
+     title="If an HTML element has an onClick attribute, expose its click action on the element rather than its child text leaf node."
+     target="_blank">Mozilla Bug 420863</a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <table>
+    <tr>
+      <td id="td1">Can't click this cell</td>
+      <td onclick="gTdClickAttr = true;"
+          id="td2">Cell with 'onclick' attribute</td>
+      <td id="td3">Cell with registered 'click' event handler</td>
+    </tr>
+  </table>
+
+</body>
+</html>
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -68,17 +68,17 @@ DEFINES += -DAPP_UA_NAME="$(APP_UA_NAME)
 DIST_FILES = application.ini
 
 GRE_MILESTONE = $(shell $(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(LIBXUL_DIST)/bin/platform.ini Build Milestone)
 GRE_BUILDID = $(shell $(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(LIBXUL_DIST)/bin/platform.ini Build BuildID)
 
 DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DGRE_BUILDID=$(GRE_BUILDID)
 
 ifdef MOZ_MEMORY
-ifneq ($(OS_ARCH),WINNT)
+ifeq ($(OS_ARCH),Darwin)
 LIBS += -ljemalloc
 endif
 endif
 
 ifdef LIBXUL_SDK
 include $(topsrcdir)/config/rules.mk
 else
 # Build a binary bootstrapping with XRE_main
@@ -358,16 +358,19 @@ endif
 endif
 
 libs::
 	touch $(DIST)/bin/.autoreg
 
 libs:: $(srcdir)/profile/prefs.js
 	$(INSTALL) $^ $(DIST)/bin/defaults/profile
 
+libs:: $(srcdir)/blocklist.xml
+	$(INSTALL) $^ $(DIST)/bin
+
 ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
 
 APP_NAME = $(MOZ_APP_DISPLAYNAME)
 
 ifdef MOZ_DEBUG
 APP_NAME := $(APP_NAME)Debug
 endif
 
new file mode 100644
--- /dev/null
+++ b/browser/app/blocklist.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
+  <emItems>
+    <emItem id="fdm_ffext@freedownloadmanager.org">
+      <versionRange minVersion="1.0" maxVersion="1.3.1">
+        <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+           <versionRange minVersion="3.0a1" maxVersion="*"/>
+        </targetApplication>
+      </versionRange>
+    </emItem>
+    <emItem id="mozilla_cc@internetdownloadmanager.com">
+      <versionRange minVersion="2.1" maxVersion="3.3">
+        <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+           <versionRange minVersion="3.0a1" maxVersion="*"/>
+        </targetApplication>
+      </versionRange>
+    </emItem>
+  </emItems>
+</blocklist>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -208,16 +208,17 @@ pref("browser.urlbar.clickSelectsAll", t
 #endif
 #ifdef UNIX_BUT_NOT_MAC
 pref("browser.urlbar.doubleClickSelectsAll", true);
 #else
 pref("browser.urlbar.doubleClickSelectsAll", false);
 #endif
 pref("browser.urlbar.autoFill", false);
 pref("browser.urlbar.matchOnlyTyped", false);
+pref("browser.urlbar.matchOnWordBoundary", true);
 pref("browser.urlbar.filter.javascript", true);
 
 // the maximum number of results to show in autocomplete when doing richResults
 pref("browser.urlbar.maxRichResults", 25);
 // Size of "chunks" affects the number of places to process between each search
 // timeout (ms). Too big and the UI will be unresponsive; too small and we'll
 // be waiting on the timeout too often without many results.
 pref("browser.urlbar.search.chunkSize", 1000);
@@ -232,16 +233,17 @@ pref("browser.download.manager.showWhenS
 pref("browser.download.manager.useWindow", true);
 pref("browser.download.manager.closeWhenDone", false);
 pref("browser.download.manager.openDelay", 0);
 pref("browser.download.manager.focusWhenStarting", false);
 pref("browser.download.manager.flashCount", 2);
 pref("browser.download.manager.addToRecentDocs", true);
 pref("browser.download.manager.quitBehavior", 0);
 pref("browser.download.manager.scanWhenDone", true);
+pref("browser.download.manager.resumeOnWakeDelay", 10000);
 
 // search engines URL
 pref("browser.search.searchEnginesURL",      "https://%LOCALE%.add-ons.mozilla.com/%LOCALE%/firefox/%VERSION%/search-engines/");
 
 // pointer to the default engine name
 pref("browser.search.defaultenginename",      "chrome://browser-region/locale/region.properties");
 
 // disable logging for the search service by default
@@ -317,19 +319,20 @@ pref("browser.tabs.closeButtons", 1);
 // true   return to the tab that opened this tab (its owner)
 // false  return to the adjacent tab (old default)
 pref("browser.tabs.selectOwnerOnClose", true);
 
 // Default bookmark sorting
 pref("browser.bookmarks.sort.direction", "descending");
 pref("browser.bookmarks.sort.resource", "rdf:http://home.netscape.com/NC-rdf#Name");
 
-// By default, do not overwrite bookmarks.html in the profile directory
-// See bug #381216 for details
-pref("browser.bookmarks.overwrite",               false);
+// By default, do not export HTML at shutdown.
+// If true, at shutdown the bookmarks in your menu and toolbar will
+// be exported as HTML to the bookmarks.html file.
+pref("browser.bookmarks.autoExportHTML",          false);
 
 // Scripts & Windows prefs
 pref("dom.disable_open_during_load",              true);
 #ifdef DEBUG
 pref("javascript.options.showInConsole",          true);
 pref("general.warnOnAboutConfig",                 false);
 #else
 pref("javascript.options.showInConsole",          false);
@@ -339,16 +342,18 @@ pref("javascript.options.showInConsole",
 pref("dom.disable_window_open_feature.status",    true);
 // This is the pref to control the location bar, change this to true to 
 // force this instead of or in addition to the status bar - this makes 
 // the origin of popup windows more obvious to avoid spoofing. We would 
 // rather not do it by default because it affects UE for web applications, but
 // without it there isn't a really good way to prevent chrome spoofing, see bug 337344
 pref("dom.disable_window_open_feature.location",  true);
 pref("dom.disable_window_status_change",          true);
+// allow JS to move and resize existing windows
+pref("dom.disable_window_move_resize",            false);
 // prevent JS from monkeying with window focus, etc
 pref("dom.disable_window_flip",                   true);
 
 // popups.policy 1=allow,2=reject
 pref("privacy.popups.policy",               1);
 pref("privacy.popups.usecustom",            true);
 pref("privacy.popups.firstTime",            true);
 pref("privacy.popups.showBrowserMessage",   true);
@@ -626,18 +631,16 @@ pref("browser.sessionstore.interval", 10
 // maximum amount of POSTDATA to be saved in bytes per history entry (-1 = all of it)
 // (NB: POSTDATA will be saved either entirely or not at all)
 pref("browser.sessionstore.postdata", 0);
 // on which sites to save text data, POSTDATA and cookies
 // 0 = everywhere, 1 = unencrypted sites, 2 = nowhere
 pref("browser.sessionstore.privacy_level", 1);
 // how many tabs can be reopened (per window)
 pref("browser.sessionstore.max_tabs_undo", 10);
-// maximum number of pages of back-history per tab to save
-pref("browser.sessionstore.max_tab_back_history", 10);
 
 // allow META refresh by default
 pref("accessibility.blockautorefresh", false);
 
 // import bookmarks.html into Places bookmarks
 pref("browser.places.importBookmarksHTML", true);
 
 // if false, will add the "Smart Bookmarks" folder to the personal toolbar
new file mode 100644
index 0000000000000000000000000000000000000000..1c4899aaf72ac0ee9dea01bbe90485f34974ee8d
GIT binary patch
literal 9817
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
R2p$A@krI;^tr9T|_z!F)fe8Qr
new file mode 100644
index 0000000000000000000000000000000000000000..3a1e48d5fac2df3655642322baf5925d00eb87a7
GIT binary patch
literal 2224
zc$@*S2v7HkP)<h;3K|Lk000e1NJLTq000~S0012b1^@s6xls%;000PgNkl<ZNQtGE
zc~H}58pq$(Rg3{4fsl}22mvDyasZ+Pf?y!zCIO-$T)9X{Ab=cVM39oHa)?(27399l
z2E&bY+dp<^kGi{#x>v2k*qz<(^qOw#v9($ip8ccijNQ_$tDk@0=lOo-edoOpS_8d)
z1aGq~Y_nJvbFKCTT~YCTPJzjjpiqp5u(j?DYxTS^y28nAg$B=bp~3Ty+`{RHdHJ5l
zg@)<-#-h1TjOLl^Ci84}mS)@{mG%)|TDE)lK$tFn?7A{@2t?vOND=lzim(q-(+5GG
zF$OugZZH<jfxTp5#cG?sVk(-gGnp15U)1-CDzmp)syGjP!3l_tI}W_qlMo$y8e+C}
zuI`9Gdp9Yi=e9&X{LP*mHxyas!Crb1thU7)*3yMCt=8@Rf7#;VT$|F;J7(e&k3tm3
z1zRJVU@Pl&h+wr`jbyjgu(-#wxG|?Q`GRw{<kbEFrD|+Bzi=9?_C>IlUR<?1mVR1X
zJkNe^A(L6*wIjY|Jd)i2!HgQ923G?X;=Dm;x}v^ctzDNO>|%(eg9kEqPu?_|XTk1R
z0=r{r*;cxg|J>3rX59fSxB|%3G6=%TflAxA_+vfk>4RKl=IB{n-qaVxwnea&E<Gr=
zFSO|OBlsT`3PmRhc`;2O*x3##!jm9OJN>CTYxu+--K1Hkn`Fu59bRkoG36azQu(MM
zd-voACd(YyN*BRwT^Q18-M&94lgm3u*?W53%8YK1$hsgUtrJqyyFn@&0Hu2Lu_kBo
zR&M^(8J%uQA{4rQvQ~yzJS0+OP24h?=D=36v|_T(pZcL%Bod!0lgc|lkkkg;n8U!1
zZU$a#JH+iceLq>)|Djkm0_yBHL928BtH9vt&dq(3x>indYF|=@dhEkO;|$mxODnng
zQ}t^K6O&py<N3`H8Pxz=wl)Agv<|4WN}$rJ?nH5q+2i6n^OI6~C&h~4+Zyd86zFGe
z78H51*OUr-3ze$Tul2?mu$L^}%ic4Y@x7ubUSo53q!WTeY5)t~_c@7Dc8d^ThJZjT
zkf{~3WU?NQkn2@JN_R?X`p^Yc)&%4gTzFzM&mK{$`+c6xVzXTvl7+oPs;qG^n&&`o
zoV}({3{t)$+{$W5!RVD=k%P)02&=kErB|zbiABHnCs}|*wm~4JVhSH<B_o6ojaH3I
zPVTFgD@N|>@}@v<oONprZtU5-*d6C~CGYCHt;(7Jvt=HP=DC9ip;r(>2x+yh4HC&Y
zTcY6DXGuFx0za|+!7fqv!PvOgMgr0LcVB{Ol|(K9N>KSPh~(0Qr=h8-BN~}v^y8eo
zDJU>ZPi1Eh`#&9HGAq2|_#M9ziuz!8jvFk+3x6~i+;oJHcAZ$><;+m^d@Yuqe<GIl
zgIG2MQpMP+TI2pp@~*SX6wGmFGr<HTvK=Vc-oFK6Wu**;X(K`i#V4N0mdZ!I(&b$M
zy?&-cC>-4QRLY4y`u2{5PLL^w!BjNAYPHX45TE}BS&)3{>h}1fz>RHN<?`C@Fe6+m
zEKV~d2+n?~$e8$CrWk?n$b+!i&%6>qvH^u!@tA_`z2HwS<A1v|2b>w|@h1fa&!hap
zX~Tb(oyZJ#y~m3^4r$^(Fq&te#IfK+F)=PbUTn*|;jAXu8qxF-BkYiwNU|($CK!Pn
zRPse+)Zq@HXs}P6?Y<YEcpL&LrH}ndHXsL;1DU$_V_L|*eipaourRIf(>*zEDA0TU
zz~;7^F#5i!kS+BP#W@VAX<cBlc%ZC&u>&EbT^AnZ8VqF~1P1fa4I;5(Gm%op#`~B2
z8BeqTF~IT(ol#r0o!?QEshN6TA|HUTEzZw~{`Pwm>R!O;RX`1{dCZMH_Ki|C4uysp
z;0umDA(6|09$E`5b`zwDI-$tw0Y~|4140O)Q08kYM(F;BG=}pbGxUH8A%vueMx+sP
zdT{=Bz!QsC$P`Cs6sNUBrW}7Sd-vp>ZE@{Cqta^M!sxYMVj;D_;<SKJ)DOA&(;$(Z
zhahSNgoM=qFQy4(igQqGyRdApn0@*X*w$n8+7WMR9WZDWm-gd*B{g2_6xQ{)1Oc9F
z@*$XS;fTfH7f^JK8PRwtO)~gMm*;suIrU5?E#!clv8CZ^L{u~I1s#y783m=fALxu4
zV21C9gv1t5D7%*R`U%x{&Y=(08NtFVmvc!8Q0EtLw;G3gV8waeHf?ydUAmEyiV-wR
z-hKw~_AP*jDA$T2V+<tnzRMwDbz{K{=Q3kU{VFf^2*{LOpj4l~!{NHRIlQJWeqvi?
zditrbwQeLdz>e+gVuZp85(VmgiQvHdfPUj9Fnb}7c7u0Rkbhn)-p}+ADbW6CXG%9@
zsK+3J)d2n^JJ9Hrz==Kt64^<}%<iiG_K<7WttmnXp<fo{B)yZN{O5&)MCf5Kq1`_a
z>U?~`io-*`*9IuSZO%ssp`Z{a3k$9~6&L>oC{)7`&u@F;OEBK2F)Hpw$22S_?P@(4
z7iU}lgQBOrTUlNH+o~FPN27(w=xxwVp}}EaBJADd4d#vOLE_7PixP4`P76Dz2;17Y
z$ct?Ok)#XK#b>SrGph11tSloUqL%kRXZ0-C>KhGzI?@ckF1Ev5QVR6b!=TMC0QTd3
zpcsdT?Y_ydnOt^1fKm!ra3!!gjUW`A0(E9z&vOa>o8Q&ehF*W|^=rRzl*8PvROn|g
zp^Xp#b$D+m^}^p|_~%^02Ri;r3bfwG=w%Pt-1^%|JKNqCi8|K!^E@Y4oX+^48;qAd
zJNT<Tv=C_ZBf>!(?t>~XFD2bKpFjw#<OK#fG#FNyu_f|=fWxULzp(5n7d0B%1dHeB
y4xqNT`w;3IaX9`<hdvJ{5yH6;TKhlp68szI9&`lr-I_N50000<MNUMnLSTYTWkq%X
new file mode 100644
index 0000000000000000000000000000000000000000..44a59d6388af7143cd1cb989eb75c68b812659e0
GIT binary patch
literal 2228
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
CN+>7*
--- a/browser/base/content/aboutRobots.xhtml
+++ b/browser/base/content/aboutRobots.xhtml
@@ -80,17 +80,18 @@
         }
       }
     ]]></script>
   </head>
 
   <body dir="&locale.dir;">
 
     <!-- PAGE CONTAINER (for styling purposes only) -->
-    <div id="errorPageContainer">
+    <div id="errorPageContainer"
+         style="background: url('chrome://browser/content/aboutRobots-icon.png') left 0 no-repeat -moz-Field; -moz-background-origin: content;">
     
       <!-- Error Title -->
       <div id="errorTitle">
         <h1 id="errorTitleText">&robots.errorTitleText;</h1>
       </div>
       
       <!-- LONG CONTENT (the section most likely to require scrolling) -->
       <div id="errorLongContent">
@@ -119,12 +120,16 @@
 
       <!-- Button -->
       <xul:button xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
                   id="errorTryAgain"
                   label="&retry.label;"
                   label2="&robots.dontpress;"
                   oncommand="robotButton();" />
 
+      <img src="chrome://browser/content/aboutRobots-widget-left.png"
+           style="position: absolute; bottom: -12px; left: -10px;"/>
+      <img src="chrome://browser/content/aboutRobots-widget-right.png"
+           style="position: absolute; bottom: -12px; right: -10px;"/>
     </div>
 
   </body>
 </html>
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -31,17 +31,17 @@
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
-       <menubar id="main-menubar" statusbar="statusbar-display"
+       <menubar id="main-menubar"
                 style="border:0px;padding:0px;margin:0px;-moz-appearance:none">
             <menu id="file-menu" label="&fileMenu.label;"
                   accesskey="&fileMenu.accesskey;">
               <menupopup id="menu_FilePopup" onpopupshowing="getContentAreaFrameCount();">
                 <menuitem id="menu_newNavigator"
                           label="&newNavigatorCmd.label;"
                           accesskey="&newNavigatorCmd.accesskey;"
                           key="key_newNavigator"
@@ -338,17 +338,17 @@
                 <menuitem hidden="true" id="documentDirection-swap" 
                           label="&bidiSwitchPageDirectionItem.label;"
                           accesskey="&bidiSwitchPageDirectionItem.accesskey;"
                           oncommand="SwitchDocumentDirection(window.content)"/>
               </menupopup>
             </menu>
 
             <menu id="history-menu"
-                  oncommand="var url = event.target.getAttribute('statustext'); if (url) { PlacesUtils.markPageAsTyped(url); openUILink(url, event, false, true); }"
+                  oncommand="var node = event.target.node; if (node) { PlacesUIUtils.markPageAsTyped(node.uri); openUILink(node.uri, event, false, true); }"
                   onclick="checkForMiddleClick(this, event);"
                   label="&historyMenu.label;"
                   accesskey="&historyMenu.accesskey;">
               <menupopup id="goPopup"
                          type="places"
                          onpopupshowing="HistoryMenu.onPopupShowing(this);"
                          place="place:type=0&amp;sort=4&amp;maxResults=10">
                 <menuitem id="historyMenuBack"
@@ -395,17 +395,17 @@
 
   <menu id="bookmarksMenu" 
         label="&bookmarksMenu.label;" accesskey="&bookmarksMenu.accesskey;"
         ondragenter="PlacesMenuDNDController.onBookmarksMenuDragEnter(event);"
         ondragdrop="nsDragAndDrop.drop(event, BookmarksMenuDropHandler);"
         ondragover="nsDragAndDrop.dragOver(event, BookmarksMenuDropHandler);">
     <menupopup id="bookmarksMenuPopup"
                type="places"
-               place="place:folder=2&amp;expandQueries=1"
+               place="place:folder=BOOKMARKS_MENU&amp;expandQueries=1"
                context="placesContext"
                openInTabs="children"
                oncommand="BookmarksEventHandler.onCommand(event);"
                onclick="BookmarksEventHandler.onClick(event);"
                onpopupshowing="BookmarksEventHandler.onPopupShowing(event);">
       <menuitem label="&bookmarkThisPageCmd.label;" 
                 command="Browser:AddBookmarkAs" key="addBookmarkAsKb"/>
       <menuitem id="subscribeToPageMenuitem"
@@ -429,18 +429,16 @@
                 command="Browser:ShowAllBookmarks"
                 key="manBookmarkKb"/>
       <menu id="bookmarksToolbarFolderMenu"
             class="menu-iconic bookmark-item"
             container="true">
         <menupopup id="bookmarksToolbarFolderPopup"
                    type="places"
                    context="placesContext"
-                   oncommand="BookmarksEventHandler.onCommand(event);"
-                   onclick="BookmarksEventHandler.onClick(event);"
                    onpopupshowing="BookmarksEventHandler.onPopupShowing(event);"/>
       </menu>
       <menuseparator builder="start"/>
     </menupopup>
   </menu>
 
             <menu id="tools-menu" label="&toolsMenu.label;" accesskey="&toolsMenu.accesskey;">
               <menupopup id="menu_ToolsPopup">
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -95,36 +95,42 @@ var StarUI = {
   },
 
   // nsIDOMEventListener
   handleEvent: function SU_handleEvent(aEvent) {
     switch (aEvent.type) {
       case "popuphidden":
         if (aEvent.originalTarget == this.panel) {
           if (!this._element("editBookmarkPanelContent").hidden)
-            gEditItemOverlay.uninitPanel(true);
+            this.quitEditMode();
           this._restoreCommandsState();
           this._itemId = -1;
           this._uri = null;
           if (this._batching) {
-            PlacesUtils.ptm.endBatch();
+            PlacesUIUtils.ptm.endBatch();
             this._batching = false;
           }
         }
         break;
       case "keypress":
         if (aEvent.keyCode == KeyEvent.DOM_VK_ESCAPE) {
-          // In edit mode, the ESC key is mapped to the cancel button
-          if (!this._element("editBookmarkPanelContent").hidden)
-            this.cancelButtonOnCommand();
-          else // otherwise we just hide the panel
+          // In edit mode, if we're not editing a folder, the ESC key is mapped
+          // to the cancel button
+          if (!this._element("editBookmarkPanelContent").hidden) {
+            var elt = aEvent.target;
+            if (elt.localName != "tree" ||
+                (elt.localName == "tree" && !elt.hasAttribute("editing")))
+              this.cancelButtonOnCommand();
+          }
+        }
+        else if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN) {
+          // hide the panel unless the folder tree is focused
+          if (aEvent.target.localName != "tree")
             this.panel.hidePopup();
         }
-        else if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN)
-          this.panel.hidePopup(); // hide the panel
         break;
     }
   },
 
   _overlayLoaded: false,
   _overlayLoading: false,
   showEditBookmarkPopup:
   function SU_showEditBookmarkPopup(aItemId, aAnchorElement, aPosition) {
@@ -183,21 +189,21 @@ var StarUI = {
     this._itemId = aItemId !== undefined ? aItemId : this._itemId;
     this.beginBatch();
 
     // XXXmano hack: We push a no-op transaction on the stack so it's always
     // safe for the Cancel button to call undoTransaction after endBatch.
     // Otherwise, if no changes were done in the edit-item panel, the last
     // transaction on the undo stack may be the initial createItem transaction,
     // or worse, the batched editing of some other item.
-    PlacesUtils.ptm.doTransaction({ doTransaction: function() { },
-                                    undoTransaction: function() { },
-                                    redoTransaction: function() { },
-                                    isTransient: false,
-                                    merge: function() { return false; } });
+    PlacesUIUtils.ptm.doTransaction({ doTransaction: function() { },
+                                      undoTransaction: function() { },
+                                      redoTransaction: function() { },
+                                      isTransient: false,
+                                      merge: function() { return false; } });
 
     if (this.panel.state == "closed") {
       // Consume dismiss clicks, see bug 400924
       this.panel.popupBoxObject
           .setConsumeRollupEvent(Ci.nsIPopupBoxObject.ROLLUP_CONSUME);
       this.panel.openPopup(aAnchorElement, aPosition, -1, -1);
     }
     else {
@@ -236,20 +242,16 @@ var StarUI = {
     this._element("editBookmarkPanelTitle").value =
       bundle.getString("editBookmarkPanel.pageBookmarkedTitle");
 
     // description
     this._element("editBookmarkPanelDescription").textContent =
       bundle.getFormattedString("editBookmarkPanel.pageBookmarkedDescription",
                                 [brandShortName]);
 
-    // hide the edit panel and the buttons below to it (Cancel, Done)
-    this._element("editBookmarkPanelContent").hidden = true;
-    this._element("editBookmarkPanelBottomButtons").hidden = true;
-
     // show the "Edit.." button and the Remove Bookmark button, hide the
     // undo-remove-bookmark button.
     this._element("editBookmarkPanelEditButton").hidden = false;
     this._element("editBookmarkPanelRemoveButton").hidden = false;
     this._element("editBookmarkPanelUndoRemoveButton").hidden = true;
 
     // unset the unstarred state, if set
     this._element("editBookmarkPanelStarIcon").removeAttribute("unstarred");
@@ -260,90 +262,101 @@ var StarUI = {
       this.panel.popupBoxObject
           .setConsumeRollupEvent(Ci.nsIPopupBoxObject.ROLLUP_CONSUME);
       this.panel.openPopup(aAnchorElement, aPosition, -1, -1);
     }
     else
       this.panel.focus();
   },
 
+  quitEditMode: function SU_quitEditMode() {
+    this._element("editBookmarkPanelContent").hidden = true;
+    this._element("editBookmarkPanelBottomButtons").hidden = true;
+    gEditItemOverlay.uninitPanel(true);
+  },
+
   editButtonCommand: function SU_editButtonCommand() {
     this.showEditBookmarkPopup();
   },
 
   cancelButtonOnCommand: function SU_cancelButtonOnCommand() {
+    // The order here is important! We have to hide the panel first, otherwise
+    // changes done as part of Undo may change the panel contents and by
+    // that force it to commit more transactions
+    this.panel.hidePopup();
     this.endBatch();
-    PlacesUtils.ptm.undoTransaction();
-    this.panel.hidePopup();
+    PlacesUIUtils.ptm.undoTransaction();
   },
 
   removeBookmarkButtonCommand: function SU_removeBookmarkButtonCommand() {
 #ifdef ADVANCED_STARRING_UI
     // In minimal mode ("page bookmarked" notification), the bookmark
     // is removed and the panel is hidden immediately. In full edit mode,
     // a "Bookmark Removed" notification along with an Undo button is
     // shown
     if (this._batching) {
-      PlacesUtils.ptm.endBatch();
-      PlacesUtils.ptm.beginBatch(); // allow undo from within the notification
+      PlacesUIUtils.ptm.endBatch();
+      PlacesUIUtils.ptm.beginBatch(); // allow undo from within the notification
       var bundle = this._element("bundle_browser");
 
       // "Bookmark Removed" title (the description field is already empty in
       // this mode)
       this._element("editBookmarkPanelTitle").value =
         bundle.getString("editBookmarkPanel.bookmarkedRemovedTitle");
-      // hide the edit fields, the buttons below to and the remove bookmark
-      // button. Show the undo-remove-bookmark button.
-      this._element("editBookmarkPanelContent").hidden = true;
-      this._element("editBookmarkPanelBottomButtons").hidden = true;
+
+      // hide the edit panel
+      this.quitEditMode();
+
+      // Hide the remove bookmark button, show the undo-remove-bookmark
+      // button.
       this._element("editBookmarkPanelUndoRemoveButton").hidden = false;
       this._element("editBookmarkPanelRemoveButton").hidden = true;
       this._element("editBookmarkPanelStarIcon").setAttribute("unstarred", "true");
       this.panel.focus();
     }
 #endif
 
     // cache its uri so we can get the new itemId in the case of undo
     this._uri = PlacesUtils.bookmarks.getBookmarkURI(this._itemId);
 
     // remove all bookmarks for the bookmark's url, this also removes
     // the tags for the url
     var itemIds = PlacesUtils.getBookmarksForURI(this._uri);
     for (var i=0; i < itemIds.length; i++) {
-      var txn = PlacesUtils.ptm.removeItem(itemIds[i]);
-      PlacesUtils.ptm.doTransaction(txn);
+      var txn = PlacesUIUtils.ptm.removeItem(itemIds[i]);
+      PlacesUIUtils.ptm.doTransaction(txn);
     }
 
 #ifdef ADVANCED_STARRING_UI
     // hidePopup resets our itemId, thus we call it only after removing
     // the bookmark
     if (!this._batching)
 #endif
       this.panel.hidePopup();
   },
 
   undoRemoveBookmarkCommand: function SU_undoRemoveBookmarkCommand() {
     // restore the bookmark by undoing the last transaction and go back
     // to the edit state
     this.endBatch();
-    PlacesUtils.ptm.undoTransaction();
+    PlacesUIUtils.ptm.undoTransaction();
     this._itemId = PlacesUtils.getMostRecentBookmarkForURI(this._uri);
     this.showEditBookmarkPopup();
   },
 
   beginBatch: function SU_beginBatch() {
     if (!this._batching) {
-      PlacesUtils.ptm.beginBatch();
+      PlacesUIUtils.ptm.beginBatch();
       this._batching = true;
     }
   },
 
   endBatch: function SU_endBatch() {
     if (this._batching) {
-      PlacesUtils.ptm.endBatch();
+      PlacesUIUtils.ptm.endBatch();
       this._batching = false;
     }
   }
 }
 
 var PlacesCommandHook = {
   /**
    * Adds a bookmark to the page loaded in the given browser.
@@ -367,33 +380,33 @@ var PlacesCommandHook = {
       // no DOMWindow (?) but information about the loaded document
       // may still be obtained from the webNavigation.
       var webNav = aBrowser.webNavigation;
       var url = webNav.currentURI;
       var title;
       var description;
       try {
         title = webNav.document.title || url.spec;
-        description = PlacesUtils.getDescriptionFromDocument(webNav.document);
+        description = PlacesUIUtils.getDescriptionFromDocument(webNav.document);
       }
       catch (e) { }
 
       if (aShowEditUI) {
         // If we bookmark the page here (i.e. page was not "starred" already)
         // but open right into the "edit" state, start batching here, so
         // "Cancel" in that state removes the bookmark.
         StarUI.beginBatch();
       }
 
       var parent = aParent != undefined ?
                    aParent : PlacesUtils.unfiledBookmarksFolderId;
       var descAnno = { name: DESCRIPTION_ANNO, value: description };
-      var txn = PlacesUtils.ptm.createItem(uri, parent, -1,
-                                           title, null, [descAnno]);
-      PlacesUtils.ptm.doTransaction(txn);
+      var txn = PlacesUIUtils.ptm.createItem(uri, parent, -1,
+                                             title, null, [descAnno]);
+      PlacesUIUtils.ptm.doTransaction(txn);
       itemId = PlacesUtils.getMostRecentBookmarkForURI(uri);
     }
 
     // dock the panel to the star icon when possible, otherwise dock
     // it to the content area
     if (aBrowser.contentWindow == window.content) {
       var starIcon = aBrowser.ownerDocument.getElementById("star-button");
       if (starIcon && isElementVisible(starIcon)) {
@@ -427,18 +440,18 @@ var PlacesCommandHook = {
    * @param aTitle
    *        The link text
    */
   bookmarkLink: function PCH_bookmarkLink(aParent, aURL, aTitle) {
     var linkURI = makeURI(aURL);
     var itemId = PlacesUtils.getMostRecentBookmarkForURI(linkURI);
     if (itemId == -1) {
       StarUI.beginBatch();
-      var txn = PlacesUtils.ptm.createItem(linkURI, aParent, -1, aTitle);
-      PlacesUtils.ptm.doTransaction(txn);
+      var txn = PlacesUIUtils.ptm.createItem(linkURI, aParent, -1, aTitle);
+      PlacesUIUtils.ptm.doTransaction(txn);
       itemId = PlacesUtils.getMostRecentBookmarkForURI(linkURI);
     }
 
     StarUI.showEditBookmarkPopup(itemId, getBrowser(), "overlap");
   },
 
   /**
    * This function returns a list of nsIURI objects characterizing the
@@ -469,17 +482,17 @@ var PlacesCommandHook = {
   },
 
   /**
    * Adds a folder with bookmarks to all of the currently open tabs in this 
    * window.
    */
   bookmarkCurrentPages: function PCH_bookmarkCurrentPages() {
     var tabURIs = this._getUniqueTabInfo();
-    PlacesUtils.showMinimalAddMultiBookmarkUI(tabURIs);
+    PlacesUIUtils.showMinimalAddMultiBookmarkUI(tabURIs);
   },
 
   
   /**
    * Adds a Live Bookmark to a feed associated with the current page. 
    * @param     url
    *            The nsIURI of the page the feed was attached to
    * @title     title
@@ -495,22 +508,22 @@ var PlacesCommandHook = {
     
     var doc = gBrowser.contentDocument;
     var title = (arguments.length > 1) ? feedTitle : doc.title;
  
     var description;
     if (arguments.length > 2)
       description = feedSubtitle;
     else
-      description = PlacesUtils.getDescriptionFromDocument(doc);
+      description = PlacesUIUtils.getDescriptionFromDocument(doc);
 
     var toolbarIP =
       new InsertionPoint(PlacesUtils.bookmarks.toolbarFolder, -1);
-    PlacesUtils.showMinimalAddLivemarkUI(feedURI, gBrowser.currentURI,
-                                         title, description, toolbarIP, true);
+    PlacesUIUtils.showMinimalAddLivemarkUI(feedURI, gBrowser.currentURI,
+                                           title, description, toolbarIP, true);
   },
 
   /**
    * Opens the Places Organizer. 
    * @param   aLeftPaneRoot
    *          The query to select in the organizer window - options
    *          are: History, AllBookmarks, BookmarksMenu, BookmarksToolbar,
    *          UnfiledBookmarks and Tags.
@@ -564,73 +577,68 @@ var HistoryMenu = {
 
 /**
  * Functions for handling events in the Bookmarks Toolbar and menu.
  */
 var BookmarksEventHandler = {  
   /**
    * Handler for click event for an item in the bookmarks toolbar or menu.
    * Menus and submenus from the folder buttons bubble up to this handler.
-   * Only handle middle-click; left-click is handled in the onCommand function.
-   * When items are middle-clicked, open them in tabs.
+   * Left-click is handled in the onCommand function.
+   * When items are middle-clicked (or clicked with modifier), open in tabs.
    * If the click came through a menu, close the menu.
    * @param aEvent
    *        DOMEvent for the click
    */
   onClick: function BT_onClick(aEvent) {
-    // Only handle middle-clicks.
-    if (aEvent.button != 1)
+    // Only handle middle-click or left-click with modifiers.
+#ifdef XP_MACOSX
+    var modifKey = aEvent.metaKey || aEvent.shiftKey;
+#else
+    var modifKey = aEvent.ctrlKey || aEvent.shiftKey;
+#endif
+    if (aEvent.button == 2 || (aEvent.button == 0 && !modifKey))
       return;
 
     var target = aEvent.originalTarget;
-    var view = PlacesUtils.getViewForNode(target);
-    if (target.node && PlacesUtils.nodeIsFolder(target.node)) {
+    // If this event bubbled up from a menu or menuitem, close the menus.
+    // Do this before opening tabs, to avoid hiding the open tabs confirm-dialog.
+    if (target.localName == "menu" || target.localName == "menuitem") {
+      for (node = target.parentNode; node; node = node.parentNode) {
+        if (node.localName == "menupopup")
+          node.hidePopup();
+        else if (node.localName != "menu")
+          break;
+      }
+    }
+
+    if (target.node && PlacesUtils.nodeIsContainer(target.node)) {
       // Don't open the root folder in tabs when the empty area on the toolbar
       // is middle-clicked or when a non-bookmark item except for Open in Tabs)
       // in a bookmarks menupopup is middle-clicked.
       if (target.localName == "menu" || target.localName == "toolbarbutton")
-        PlacesUtils.openContainerNodeInTabs(target.node, aEvent);
+        PlacesUIUtils.openContainerNodeInTabs(target.node, aEvent);
     }
-    else
+    else if (aEvent.button == 1) {
+      // left-clicks with modifier are already served by onCommand
       this.onCommand(aEvent);
-
-    // If this event bubbled up from a menu or menuitem,
-    // close the menus.
-    if (target.localName == "menu" ||
-        target.localName == "menuitem") {
-      var node = target.parentNode;
-      while (node && 
-             (node.localName == "menu" || 
-              node.localName == "menupopup")) {
-        if (node.localName == "menupopup")
-          node.hidePopup();
-
-        node = node.parentNode;
-      }
     }
-    // The event target we get if someone middle clicks on a bookmark in the
-    // bookmarks toolbar overflow menu is different from if they click on a
-    // bookmark in a folder or in the bookmarks menu; handle this case
-    // separately.
-    var bookmarksBar = document.getElementById("bookmarksBarContent");
-    if (bookmarksBar._chevron.getAttribute("open") == "true")
-      bookmarksBar._chevron.firstChild.hidePopup();
   },
 
   /**
    * Handler for command event for an item in the bookmarks toolbar.
    * Menus and submenus from the folder buttons bubble up to this handler.
    * Opens the item.
    * @param aEvent 
    *        DOMEvent for the command
    */
   onCommand: function BM_onCommand(aEvent) {
     var target = aEvent.originalTarget;
     if (target.node)
-      PlacesUtils.openNodeWithEvent(target.node, aEvent);
+      PlacesUIUtils.openNodeWithEvent(target.node, aEvent);
   },
 
   /**
    * Handler for popupshowing event for an item in bookmarks toolbar or menu.
    * If the item isn't the main bookmarks menu, add an "Open All in Tabs"
    * menuitem to the bottom of the popup.
    * @param event 
    *        DOMEvent for popupshowing
@@ -698,27 +706,29 @@ var BookmarksEventHandler = {
           "openUILink(this.getAttribute('siteURI'), event);");
       // If a user middle-clicks this item we serve the oncommand event
       // We are using checkForMiddleClick because of Bug 246720
       // Note: stopPropagation is needed to avoid serving middle-click 
       // with BT_onClick that would open all items in tabs
       target._endOptOpenSiteURI.setAttribute("onclick",
           "checkForMiddleClick(this, event); event.stopPropagation();");
       target._endOptOpenSiteURI.setAttribute("label",
-          PlacesUtils.getFormattedString("menuOpenLivemarkOrigin.label",
+          PlacesUIUtils.getFormattedString("menuOpenLivemarkOrigin.label",
           [target.parentNode.getAttribute("label")]));
       target.appendChild(target._endOptOpenSiteURI);
     }
 
     if (hasMultipleURIs && !target._endOptOpenAllInTabs) {
         // Add the "Open All in Tabs" menuitem if there are
         // at least two menuitems with places result nodes.
         target._endOptOpenAllInTabs = document.createElement("menuitem");
         target._endOptOpenAllInTabs.setAttribute("oncommand",
-            "PlacesUtils.openContainerNodeInTabs(this.parentNode._resultNode, event);");
+            "PlacesUIUtils.openContainerNodeInTabs(this.parentNode._resultNode, event);");
+        target._endOptOpenAllInTabs.setAttribute("onclick",
+            "checkForMiddleClick(this, event); event.stopPropagation();");
         target._endOptOpenAllInTabs.setAttribute("label",
             gNavigatorBundle.getString("menuOpenAllInTabs.label"));
         target.appendChild(target._endOptOpenAllInTabs);
     }
   },
 
   fillInBTTooltip: function(aTipElement) {
     // Fx2XP: Don't show tooltips for bookmarks under sub-folders
@@ -779,17 +789,18 @@ var BookmarksMenuDropHandler = {
    * @param   event
    *          A dragover event
    * @param   session
    *          The active DragSession
    * @returns true if the user can drop onto the Bookmarks Menu item, false 
    *          otherwise.
    */
   canDrop: function BMDH_canDrop(event, session) {
-    return PlacesControllerDragHelper.canDrop();
+    var ip = new InsertionPoint(PlacesUtils.bookmarksMenuFolderId, -1);  
+    return ip && PlacesControllerDragHelper.canDrop(ip);
   },
 
   /**
    * Called when the user drops onto the top level Bookmarks Menu item.
    * @param   event
    *          A drop event
    * @param   data
    *          Data that was dropped
@@ -1009,33 +1020,32 @@ function placesMigrationTasks() {
         // Remove the old annotation.
         annosvc.removePageAnnotation(uri, oldPostDataAnno);
       } catch(ex) {}
     }
     gPrefService.setBoolPref("browser.places.migratePostDataAnnotations", false);
   }
 
   if (gPrefService.getBoolPref("browser.places.updateRecentTagsUri")) {
-    var bmsvc = PlacesUtils.bookmarks;
-    var tagsFolder = bmsvc.tagsFolder;
-    var oldUriSpec = "place:folder=" + tagsFolder + "&group=3&queryType=1"+
+    var oldUriSpec = "place:folder=TAGS&group=3&queryType=1" +
                      "&applyOptionsToContainers=1&sort=12&maxResults=10";
 
     var maxResults = 10;
     var newUriSpec = "place:type=" + 
                      Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_QUERY +
                      "&sort=" + 
                      Ci.nsINavHistoryQueryOptions.SORT_BY_LASTMODIFIED_DESCENDING +
                      "&maxResults=" + maxResults;
                      
     var ios = Cc["@mozilla.org/network/io-service;1"].
               getService(Ci.nsIIOService);
 
     var oldUri = ios.newURI(oldUriSpec, null, null);
     var newUri = ios.newURI(newUriSpec, null, null);
 
+    let bmsvc = PlacesUtils.bookmarks;
     let bookmarks = bmsvc.getBookmarkIdsForURI( oldUri, {});
     for (let i = 0; i < bookmarks.length; i++) {
       bmsvc.changeBookmarkURI( bookmarks[i], newUri);
     }
     gPrefService.setBoolPref("browser.places.updateRecentTagsUri", false);
   }
 }
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2635,17 +2635,17 @@ function openHomeDialog(aURL)
 }
 
 var bookmarksButtonObserver = {
   onDrop: function (aEvent, aXferData, aDragSession)
   {
     var split = aXferData.data.split("\n");
     var url = split[0];
     if (url != aXferData.data)  // do nothing if it's not a valid URL
-      PlacesUtils.showMinimalAddBookmarkUI(makeURI(url), split[1]);
+      PlacesUIUtils.showMinimalAddBookmarkUI(makeURI(url), split[1]);
   },
 
   onDragOver: function (aEvent, aFlavour, aDragSession)
   {
     var statusTextFld = document.getElementById("statusbar-display");
     statusTextFld.label = gNavigatorBundle.getString("droponbookmarksbutton");
     aDragSession.dragAction = Components.interfaces.nsIDragService.DRAGDROP_ACTION_LINK;
   },
@@ -3110,17 +3110,17 @@ function addToUrlbarHistory(aUrlToAdd)
 {
   if (!aUrlToAdd)
      return;
   if (aUrlToAdd.search(/[\x00-\x1F]/) != -1) // don't store bad URLs
      return;
 
    try {
      if (aUrlToAdd.indexOf(" ") == -1) {
-       PlacesUtils.markPageAsTyped(aUrlToAdd);
+       PlacesUIUtils.markPageAsTyped(aUrlToAdd);
      }
    }
    catch(ex) {
    }
 }
 
 function toJavaScriptConsole()
 {
@@ -3413,16 +3413,17 @@ var FullScreen =
 
       if (fullScrToggler) {
         fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
         fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
       }
 
       // The user may quit fullscreen during an animation
       clearInterval(this._animationInterval);
+      clearTimeout(this._animationTimeout);
       getNavToolbox().style.marginTop = "0px";
       if (this._isChromeCollapsed)
         this.mouseoverToggle(true);
       this._isAnimating = false;
       // This is needed if they use the context menu to quit fullscreen
       this._isPopupOpen = false;
 
       gBrowser.mPanelContainer.removeEventListener("mousemove",
@@ -3513,16 +3514,17 @@ var FullScreen =
   setAutohide: function()
   {
     gPrefService.setBoolPref("browser.fullscreen.autohide", !gPrefService.getBoolPref("browser.fullscreen.autohide"));
   },
 
   // Animate the toolbars disappearing
   _shouldAnimate: true,
   _isAnimating: false,
+  _animationTimeout: null,
   _animationInterval: null,
   _animateUp: function()
   {
     // check again, the user may have done something before the animation was due to start
     if (!window.fullScreen || !FullScreen._safeToCollapse(false)) {
       FullScreen._isAnimating = false;
       FullScreen._shouldAnimate = true;
       return;
@@ -3563,17 +3565,17 @@ var FullScreen =
     // 1 - animate only for first collapse after entering fullscreen (default for perf's sake)
     // 2 - animate every time it collapses
     if (gPrefService.getIntPref("browser.fullscreen.animateUp") == 0)
       this._shouldAnimate = false;
 
     if (!aShow && this._shouldAnimate) {
       this._isAnimating = true;
       this._shouldAnimate = false;
-      setTimeout(this._animateUp, 800);
+      this._animationTimeout = setTimeout(this._animateUp, 800);
       return;
     }
 
     // The chrome is collapsed so don't spam needless mousemove events
     if (aShow) {
       gBrowser.mPanelContainer.addEventListener("mousemove",
                                                 this._collapseCallback, false);
     }
@@ -4775,19 +4777,19 @@ function asyncOpenWebPanel(event)
          loadURI(url, null, postData.value, false);
          event.preventDefault();
          return false;
        }
        else if (linkNode.getAttribute("rel") == "sidebar") {
          // This is the Opera convention for a special link that - when clicked - allows
          // you to add a sidebar panel.  We support the Opera convention here.  The link's
          // title attribute contains the title that should be used for the sidebar panel.
-         PlacesUtils.showMinimalAddBookmarkUI(makeURI(wrapper.href),
-                                              wrapper.getAttribute("title"),
-                                              null, null, true, true);
+         PlacesUIUtils.showMinimalAddBookmarkUI(makeURI(wrapper.href),
+                                                wrapper.getAttribute("title"),
+                                                null, null, true, true);
          event.preventDefault();
          return false;
        }
        else if (target == "_search") {
          // Used in WinIE as a way of transiently loading pages in a sidebar.  We
          // mimic that WinIE functionality here and also load the page transiently.
 
          // DISALLOW_INHERIT_PRINCIPAL is used here in order to also
@@ -5741,19 +5743,19 @@ function AddKeywordForSearchField()
 
   var postData;
 
   if (isURLEncoded)
     postData = formData.join("&");
   else
     spec += "?" + formData.join("&");
 
-  var description = PlacesUtils.getDescriptionFromDocument(node.ownerDocument);
-  PlacesUtils.showMinimalAddBookmarkUI(makeURI(spec), "", description, null,
-                                       null, null, "", postData);
+  var description = PlacesUIUtils.getDescriptionFromDocument(node.ownerDocument);
+  PlacesUIUtils.showMinimalAddBookmarkUI(makeURI(spec), "", description, null,
+                                         null, null, "", postData);
 }
 
 function SwitchDocumentDirection(aWindow) {
   aWindow.document.dir = (aWindow.document.dir == "ltr" ? "rtl" : "ltr");
   for (var run = 0; run < aWindow.frames.length; run++)
     SwitchDocumentDirection(aWindow.frames[run]);
 }
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -286,17 +286,17 @@
                      command="Browser:Reload"
                      tooltiptext="&reloadButton.tooltip;"/>
 
       <toolbarbutton id="stop-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      label="&stopCmd.label;"
                      command="Browser:Stop"
                      tooltiptext="&stopButton.tooltip;"/>
 
-      <toolbarbutton id="home-button" class="bookmark-item chromeclass-toolbar-additional"
+      <toolbarbutton id="home-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      persist="class"
                      label="&homeButton.label;"
                      ondragover="nsDragAndDrop.dragOver(event, homeButtonObserver);"
                      ondragdrop="nsDragAndDrop.drop(event, homeButtonObserver);"
                      ondragexit="nsDragAndDrop.dragExit(event, homeButtonObserver);"
                      onclick="BrowserGoHome(event);"/>
 
       <toolbaritem id="urlbar-container" align="center" flex="400" persist="width"
@@ -446,19 +446,19 @@
 
     </toolbarpalette>
 
     <toolbar id="nav-bar" class="toolbar-primary chromeclass-toolbar"
              toolbarname="&navbarCmd.label;" accesskey="&navbarCmd.accesskey;"
              fullscreentoolbar="true" mode="icons" iconsize="large"
              customizable="true"
 #ifdef XP_MACOSX
-             defaultset="unified-back-forward-button,reload-button,stop-button,urlbar-container,search-container,throbber-box"
+             defaultset="unified-back-forward-button,reload-button,stop-button,home-button,urlbar-container,search-container,throbber-box"
 #else
-             defaultset="unified-back-forward-button,reload-button,stop-button,urlbar-container,search-container,fullscreenflex,window-controls"
+             defaultset="unified-back-forward-button,reload-button,stop-button,home-button,urlbar-container,search-container,fullscreenflex,window-controls"
 #endif
              context="toolbar-context-menu">
 #ifndef XP_MACOSX
       <hbox id="fullscreenflex" flex="1" hidden="true" fullscreencontrol="true"/>
       <hbox id="window-controls" hidden="true" fullscreencontrol="true">
         <toolbarbutton id="minimize-button" class="toolbarbutton-1"
                        tooltiptext="&fullScreenMinimize.tooltip;"
                        oncommand="window.minimize();"/>
@@ -475,17 +475,17 @@
     </toolbar>
 
     <toolbarset id="customToolbars" context="toolbar-context-menu"/>
 
     <toolbar id="PersonalToolbar"
              mode="icons" iconsize="small" defaulticonsize="small"
              class="chromeclass-directories"
              context="toolbar-context-menu"
-             defaultset="home-button,personal-bookmarks"
+             defaultset="personal-bookmarks"
              toolbarname="&personalbarCmd.label;" accesskey="&personalbarCmd.accesskey;"
              customizable="true"/>
   </toolbox>
 
   <hbox flex="1" id="browser">
     <vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome">
       <sidebarheader align="center">
         <label id="sidebar-title" persist="value" flex="1" crop="end" control="sidebar"/>
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -1186,23 +1186,23 @@ nsContextMenu.prototype = {
 
   addBookmarkForFrame: function CM_addBookmarkForFrame() {
     var doc = this.target.ownerDocument;
     var uri = doc.documentURIObject;
 
     var itemId = PlacesUtils.getMostRecentBookmarkForURI(uri);
     if (itemId == -1) {
       var title = doc.title;
-      var description = PlacesUtils.getDescriptionFromDocument(doc);
+      var description = PlacesUIUtils.getDescriptionFromDocument(doc);
 
       var descAnno = { name: DESCRIPTION_ANNO, value: description };
-      var txn = PlacesUtils.ptm.createItem(uri, 
+      var txn = PlacesUIUtils.ptm.createItem(uri, 
                                            PlacesUtils.bookmarksMenuFolderId,
                                            -1, title, null, [descAnno]);
-      PlacesUtils.ptm.doTransaction(txn);
+      PlacesUIUtils.ptm.doTransaction(txn);
       itemId = PlacesUtils.getMostRecentBookmarkForURI(uri);
       StarUI.beginBatch();
     }
 
     window.top.StarUI.showEditBookmarkPopup(itemId, this.browser, "overlap");
   },
 
   savePageAs: function CM_savePageAs() {
--- a/browser/base/content/test/browser_getshortcutoruri.js
+++ b/browser/base/content/test/browser_getshortcutoruri.js
@@ -67,17 +67,17 @@ var testData = [
    new keywordResult("http://searchpostget/?search1=foo6", "search2=foo6")],
 
   // Bookmark keywords that don't take parameters should not be activated if a
   // parameter is passed (bug 420328).
   [new bmKeywordData("bmget-noparam", "http://bmget-noparam/", null, "foo7"),
    new keywordResult(null, null)],
   [new bmKeywordData("bmpost-noparam", "http://bmpost-noparam/", "not_a=param", "foo8"),
    new keywordResult(null, null)],
-  
+
   // Test escaping (%s = escaped, %S = raw)
   // UTF-8 default
   [new bmKeywordData("bmget-escaping", "http://bmget/?esc=%s&raw=%S", null, "foé"),
    new keywordResult("http://bmget/?esc=fo%C3%A9&raw=foé", null)],
   // Explicitly-defined ISO-8859-1
   [new bmKeywordData("bmget-escaping2", "http://bmget/?esc=%s&raw=%S&mozcharset=ISO-8859-1", null, "foé"),
    new keywordResult("http://bmget/?esc=fo%E9&raw=foé", null)],
 ];
@@ -103,26 +103,26 @@ function test() {
   cleanupKeywords();
 }
 
 var gBMFolder = null;
 var gAddedEngines = [];
 function setupKeywords() {
   var searchService = Cc["@mozilla.org/browser/search-service;1"].
                       getService(Ci.nsIBrowserSearchService);
-  gBMFolder = Application.bookmarks.addFolder("keyword-test");
+  gBMFolder = Application.bookmarks.menu.addFolder("keyword-test");
   for each (var item in testData) {
     var data = item[0];
     if (data instanceof bmKeywordData) {
       var bm = gBMFolder.addBookmark(data.keyword, data.uri);
       bm.keyword = data.keyword;
       if (data.postData)
         bm.annotations.set("bookmarkProperties/POSTData", data.postData, Ci.nsIAnnotationService.EXPIRE_SESSION);
     }
-    
+
     if (data instanceof searchKeywordData) {
       searchService.addEngineWithDetails(data.keyword, "", data.keyword, "", data.method, data.uri.spec);
       var addedEngine = searchService.getEngineByName(data.keyword);
       if (data.postData) {
         var [paramName, paramValue] = data.postData.split("=");
         addedEngine.addParam(paramName, paramValue, null);
       }
 
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -9,16 +9,19 @@ browser.jar:
 %  overlay chrome://global/content/viewSource.xul chrome://browser/content/viewSourceOverlay.xul
 %  overlay chrome://global/content/viewPartialSource.xul chrome://browser/content/viewSourceOverlay.xul
 %  style chrome://global/content/customizeToolbar.xul chrome://browser/content/browser.css
 %  style chrome://global/content/customizeToolbar.xul chrome://browser/skin/
 *       content/browser/aboutDialog.xul               (content/aboutDialog.xul)
 *       content/browser/aboutDialog.js                (content/aboutDialog.js)
         content/browser/aboutDialog.css               (content/aboutDialog.css)
 *       content/browser/aboutRobots.xhtml             (content/aboutRobots.xhtml)
+        content/browser/aboutRobots-icon.png          (content/aboutRobots-icon.png)
+        content/browser/aboutRobots-widget-left.png   (content/aboutRobots-widget-left.png)
+        content/browser/aboutRobots-widget-right.png  (content/aboutRobots-widget-right.png)
 *       content/browser/browser.css                   (content/browser.css)
 *       content/browser/browser.js                    (content/browser.js)
 *       content/browser/browser.xul                   (content/browser.xul)
 *       content/browser/credits.xhtml                 (content/credits.xhtml)
 *       content/browser/EULA.js                       (content/EULA.js)
 *       content/browser/EULA.xhtml                    (content/EULA.xhtml)
 *       content/browser/EULA.xul                      (content/EULA.xul)
 *       content/browser/metaData.js                   (content/metaData.js)
--- a/browser/components/migration/content/migration.js
+++ b/browser/components/migration/content/migration.js
@@ -153,17 +153,17 @@ var MigrationWizard = {
   onImportSourcePageAdvanced: function ()
   {
     var newSource = document.getElementById("importSourceGroup").selectedItem.id;
     
     if (newSource == "nothing" || newSource == "fromfile") {
       if(newSource == "fromfile")
         window.opener.fromFile = true;
       document.documentElement.cancel();
-      return;
+      return false;
     }
     
     if (!this._migrator || (newSource != this._source)) {
       // Create the migrator for the selected source.
       var contractID = kProfileMigratorContractIDPrefix + newSource;
       this._migrator = Components.classes[contractID].createInstance(kIMig);
 
       this._itemsFlags = kIMig.ALL;
--- a/browser/components/migration/content/migration.xul
+++ b/browser/components/migration/content/migration.xul
@@ -51,17 +51,17 @@
 
   <script type="application/x-javascript" src="chrome://browser/content/migration/migration.js"/>
 
   <stringbundle id="bundle" src="chrome://browser/locale/migration/migration.properties"/>
   <stringbundle id="brandBundle" src="chrome://branding/locale/brand.properties"/>
 
   <wizardpage id="importSource" pageid="importSource" next="selectProfile"
               label="&importSource.title;"
-              onpageadvanced="MigrationWizard.onImportSourcePageAdvanced();">
+              onpageadvanced="return MigrationWizard.onImportSourcePageAdvanced();">
 #ifdef XP_WIN
     <description id="importAll" control="importSourceGroup">&importFrom.label;</description>
 #else
     <description id="importAll" control="importSourceGroup">&importFromUnix.label;</description>
 #endif
     <description id="importBookmarks" control="importSourceGroup" hidden="true">&importFromBookmarks.label;</description>
 
     <radiogroup id="importSourceGroup" align="start">
--- a/browser/components/migration/src/nsOperaProfileMigrator.cpp
+++ b/browser/components/migration/src/nsOperaProfileMigrator.cpp
@@ -312,16 +312,18 @@ nsOperaProfileMigrator::GetSourceHomePag
 
 #define _OPM(type) nsOperaProfileMigrator::type
 
 static
 nsOperaProfileMigrator::PrefTransform gTransforms[] = {
   { "User Prefs", "Download Directory", _OPM(STRING), "browser.download.dir", _OPM(SetFile), PR_FALSE, -1 },
   { nsnull, "Enable Cookies", _OPM(INT), "network.cookie.cookieBehavior", _OPM(SetCookieBehavior), PR_FALSE, -1 },
   { nsnull, "Accept Cookies Session Only", _OPM(BOOL), "network.cookie.lifetimePolicy", _OPM(SetCookieLifetime), PR_FALSE, -1 },
+  { nsnull, "Allow script to resize window", _OPM(BOOL), "dom.disable_window_move_resize", _OPM(SetBool), PR_FALSE, -1 },
+  { nsnull, "Allow script to move window", _OPM(BOOL), "dom.disable_window_move_resize", _OPM(SetBool), PR_FALSE, -1 },
   { nsnull, "Allow script to raise window", _OPM(BOOL), "dom.disable_window_flip", _OPM(SetBool), PR_FALSE, -1 },
   { nsnull, "Allow script to change status", _OPM(BOOL), "dom.disable_window_status_change", _OPM(SetBool), PR_FALSE, -1 },
   { nsnull, "Ignore Unrequested Popups", _OPM(BOOL), "dom.disable_open_during_load", _OPM(SetBool), PR_FALSE, -1 },
   { nsnull, "Load Figures", _OPM(BOOL), "permissions.default.image", _OPM(SetImageBehavior), PR_FALSE, -1 },
 
   { "Visited link", nsnull, _OPM(COLOR), "browser.visited_color", _OPM(SetString), PR_FALSE, -1 },
   { "Link", nsnull, _OPM(COLOR), "browser.anchor_color", _OPM(SetString), PR_FALSE, -1 },
   { nsnull, "Underline", _OPM(BOOL), "browser.underline_anchors", _OPM(SetBool), PR_FALSE, -1 },
--- a/browser/components/migration/src/nsSafariProfileMigrator.cpp
+++ b/browser/components/migration/src/nsSafariProfileMigrator.cpp
@@ -69,16 +69,17 @@
 #include <Carbon/Carbon.h>
 
 #define SAFARI_PREFERENCES_FILE_NAME      NS_LITERAL_STRING("com.apple.Safari.plist")
 #define SAFARI_BOOKMARKS_FILE_NAME        NS_LITERAL_STRING("Bookmarks.plist")
 #define SAFARI_HISTORY_FILE_NAME          NS_LITERAL_STRING("History.plist")
 #define SAFARI_COOKIES_FILE_NAME          NS_LITERAL_STRING("Cookies.plist")
 #define SAFARI_COOKIE_BEHAVIOR_FILE_NAME  NS_LITERAL_STRING("com.apple.WebFoundation.plist")
 #define SAFARI_DATE_OFFSET                978307200
+#define SAFARI_HOME_PAGE_PREF             "HomePage"
 #define MIGRATION_BUNDLE                  "chrome://browser/locale/migration/migration.properties"
 
 ///////////////////////////////////////////////////////////////////////////////
 // nsSafariProfileMigrator
 
 NS_IMPL_ISUPPORTS1(nsSafariProfileMigrator, nsIBrowserProfileMigrator)
 
 nsSafariProfileMigrator::nsSafariProfileMigrator()
@@ -202,43 +203,16 @@ nsSafariProfileMigrator::GetSourceHasMul
 
 NS_IMETHODIMP
 nsSafariProfileMigrator::GetSourceProfiles(nsISupportsArray** aResult)
 {
   *aResult = nsnull;
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsSafariProfileMigrator::GetSourceHomePageURL(nsACString& aResult)
-{
-  aResult.Truncate();
-
-  ICInstance internetConfig;
-  OSStatus error = ::ICStart(&internetConfig, 'FRFX');
-  if (error != noErr)
-    return NS_ERROR_FAILURE;
-
-  ICAttr dummy;
-  Str255 homePagePValue;
-  long prefSize = sizeof(homePagePValue);
-  error = ::ICGetPref(internetConfig, kICWWWHomePage, &dummy,
-                      homePagePValue, &prefSize);
-  if (error != noErr)
-    return NS_ERROR_FAILURE;
-
-  char homePageValue[256] = "";
-  CopyPascalStringToC((ConstStr255Param)homePagePValue, homePageValue);
-  aResult.Assign(homePageValue);
-
-  ::ICStop(internetConfig);
-
-  return NS_OK;
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // nsSafariProfileMigrator
 
 CFPropertyListRef CopyPListFromFile(nsILocalFile* aPListFile)
 {
   PRBool exists;
   aPListFile->Exists(&exists);
   nsCAutoString filePath;
@@ -1203,8 +1177,48 @@ nsSafariProfileMigrator::CopyOtherData(P
     nsCOMPtr<nsIFile> userChromeDir;
     NS_GetSpecialDirectory(NS_APP_USER_CHROME_DIR,
                            getter_AddRefs(userChromeDir));
 
     stylesheetFile->CopyTo(userChromeDir, NS_LITERAL_STRING("userContent.css"));
   }
   return NS_OK;
 }
+
+
+NS_IMETHODIMP
+nsSafariProfileMigrator::GetSourceHomePageURL(nsACString& aResult)
+{
+  aResult.Truncate();
+
+  // Let's first check if there's a home page key in the com.apple.safari file...
+  CFDictionaryRef safariPrefs = CopySafariPrefs();
+  if (GetDictionaryCStringValue(safariPrefs,
+                                CFSTR(SAFARI_HOME_PAGE_PREF),
+                                aResult, kCFStringEncodingUTF8)) {
+    ::CFRelease(safariPrefs);
+    return NS_OK;
+  }
+
+  ::CFRelease(safariPrefs);
+
+  // Couldn't find the home page in com.apple.safai, time to check
+  // com.apple.internetconfig for this key!
+  ICInstance internetConfig;
+  OSStatus error = ::ICStart(&internetConfig, 'FRFX');
+  if (error != noErr)
+    return NS_ERROR_FAILURE;
+
+  ICAttr dummy;
+  Str255 homePagePValue;
+  long prefSize = sizeof(homePagePValue);
+  error = ::ICGetPref(internetConfig, kICWWWHomePage, &dummy,
+                      homePagePValue, &prefSize);
+  if (error != noErr)
+    return NS_ERROR_FAILURE;
+
+  char homePageValue[256] = "";
+  CopyPascalStringToC((ConstStr255Param)homePagePValue, homePageValue);
+  aResult.Assign(homePageValue);
+  ::ICStop(internetConfig);
+
+  return NS_OK;
+}
--- a/browser/components/migration/src/nsSeamonkeyProfileMigrator.cpp
+++ b/browser/components/migration/src/nsSeamonkeyProfileMigrator.cpp
@@ -358,16 +358,17 @@ nsSeamonkeyProfileMigrator::PrefTransfor
   MAKESAMETYPEPREFTRANSFORM("security.warn_submit_insecure",            Bool),
   MAKESAMETYPEPREFTRANSFORM("security.warn_viewing_mixed",              Bool),
   MAKESAMETYPEPREFTRANSFORM("security.default_personal_cert",           String),
   MAKESAMETYPEPREFTRANSFORM("security.OSCP.enabled",                    Int),
   MAKESAMETYPEPREFTRANSFORM("security.OSCP.signingCA",                  String),
   MAKESAMETYPEPREFTRANSFORM("security.OSCP.URL",                        String),
   MAKESAMETYPEPREFTRANSFORM("security.enable_java",                     Bool),
   MAKESAMETYPEPREFTRANSFORM("javascript.enabled",                       Bool),
+  MAKESAMETYPEPREFTRANSFORM("dom.disable_window_move_resize",           Bool),
   MAKESAMETYPEPREFTRANSFORM("dom.disable_window_flip",                  Bool),
   MAKESAMETYPEPREFTRANSFORM("dom.disable_window_open_feature.status",   Bool),
   MAKESAMETYPEPREFTRANSFORM("dom.disable_window_status_change",         Bool),
   MAKESAMETYPEPREFTRANSFORM("dom.disable_image_src_set",                Bool),
   MAKESAMETYPEPREFTRANSFORM("accessibility.typeaheadfind.autostart",    Bool),
   MAKESAMETYPEPREFTRANSFORM("accessibility.typeaheadfind.linksonly",    Bool),
   MAKESAMETYPEPREFTRANSFORM("network.proxy.type",                       Int),
   MAKESAMETYPEPREFTRANSFORM("network.proxy.http",                       String),
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -42,16 +42,23 @@ const Cc = Components.classes;
 const Cr = Components.results;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/distribution.js");
 
 const PREF_EM_NEW_ADDONS_LIST = "extensions.newAddons";
 
+// Check to see if bookmarks need backing up once per
+// day on 1 hour idle.
+const BOOKMARKS_ARCHIVE_IDLE_TIME = 60 * 60;
+
+// Backup bookmarks once every 24 hours.
+const BOOKMARKS_ARCHIVE_INTERVAL = 86400 * 1000;
+
 // Factory object
 const BrowserGlueServiceFactory = {
   _instance: null,
   createInstance: function (outer, iid) 
   {
     if (outer != null)
       throw Components.results.NS_ERROR_NO_AGGREGATION;
     return this._instance == null ?
@@ -103,25 +110,33 @@ BrowserGlue.prototype = {
         break;
       case "quit-application-requested":
         this._onQuitRequest(subject, data);
         break;
       case "quit-application-granted":
         if (this._saveSession) {
           this._setPrefToSaveSession();
         }
+        this._shutdownPlaces();
+        this.idleService.removeIdleObserver(this, BOOKMARKS_ARCHIVE_IDLE_TIME);
         break;
       case "session-save":
         this._setPrefToSaveSession();
         subject.QueryInterface(Ci.nsISupportsPRBool);
         subject.data = true;
         break;
+      case "idle":
+        if (this.idleService.idleTime > BOOKMARKS_ARCHIVE_IDLE_TIME * 1000) {
+          // Back up bookmarks.
+          this._archiveBookmarks();
+        }
+        break;
     }
-  }
-, 
+  }, 
+
   // initialization (called on application startup) 
   _init: function() 
   {
     // observer registration
     const osvr = Cc['@mozilla.org/observer-service;1'].
                  getService(Ci.nsIObserverService);
     osvr.addObserver(this, "quit-application", false);
     osvr.addObserver(this, "xpcom-shutdown", false);
@@ -194,17 +209,17 @@ BrowserGlue.prototype = {
     this._initPlaces();
 
     // apply distribution customizations
     // prefs are applied in _onAppDefaults()
     var distro = new DistributionCustomizer();
     distro.applyCustomizations();
 
     // handle any UI migration
-    this._migrateUI();
+    // this._migrateUI();
   },
 
   // profile shutdown handler (contains profile cleanup routines)
   _onProfileShutdown: function() 
   {
     this._shutdownPlaces();
     this.Sanitizer.onShutdown();
   },
@@ -352,88 +367,128 @@ BrowserGlue.prototype = {
     if(typeof(Sanitizer) != "function") { // we should dynamically load the script
       Cc["@mozilla.org/moz/jssubscript-loader;1"].
       getService(Ci.mozIJSSubScriptLoader).
       loadSubScript("chrome://browser/content/sanitize.js", null);
     }
     return Sanitizer;
   },
 
+  _idleService: null,
+  get idleService() {
+    if (!this._idleService)
+      this._idleService = Cc["@mozilla.org/widget/idleservice;1"].
+                          getService(Ci.nsIIdleService);
+    return this._idleService;
+  },
+
   /**
    * Initialize Places
    * - imports the bookmarks html file if bookmarks datastore is empty
    */
   _initPlaces: function bg__initPlaces() {
     // we need to instantiate the history service before we check the 
     // the browser.places.importBookmarksHTML pref, as 
     // nsNavHistory::ForceMigrateBookmarksDB() will set that pref
     // if we need to force a migration (due to a schema change)
     var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
                   getService(Ci.nsINavHistoryService);
 
+    var prefBranch = Cc["@mozilla.org/preferences-service;1"].
+                     getService(Ci.nsIPrefBranch);
+
     var importBookmarks = false;
     try {
-      var prefBranch = Cc["@mozilla.org/preferences-service;1"].
-                       getService(Ci.nsIPrefBranch);
       importBookmarks = prefBranch.getBoolPref("browser.places.importBookmarksHTML");
     } catch(ex) {}
 
     if (!importBookmarks) {
       // Call it here for Fx3 profiles created before the Places folder
       // has been added, otherwise it's called during import.
       this.ensurePlacesDefaultQueriesInitialized();
-      return;
     }
-
-    var dirService = Cc["@mozilla.org/file/directory_service;1"].
-                     getService(Ci.nsIProperties);
-
-    var bookmarksFile = dirService.get("BMarks", Ci.nsILocalFile);
+    else {
+      // get latest backup
+      Cu.import("resource://gre/modules/utils.js");
+      var bookmarksFile = PlacesUtils.getMostRecentBackup();
 
-    if (bookmarksFile.exists()) {
-      // import the file
-      try {
-        var importer = 
-          Cc["@mozilla.org/browser/places/import-export-service;1"].
-          getService(Ci.nsIPlacesImportExportService);
-        importer.importHTMLFromFile(bookmarksFile, true);
-      } catch(ex) {
-      } finally {
-        prefBranch.setBoolPref("browser.places.importBookmarksHTML", false);
+      if (bookmarksFile && bookmarksFile.leafName.match("\.json$")) {
+        // restore a JSON backup
+        PlacesUtils.restoreBookmarksFromJSONFile(bookmarksFile);
       }
+      else {
+        // if there's no json backup use bookmarks.html
 
-      // only back up pre-places bookmarks.html if we plan on overwriting it
-      if (prefBranch.getBoolPref("browser.bookmarks.overwrite")) {
-        // backup pre-places bookmarks.html
-        // XXXtodo remove this before betas, after import/export is solid
-        var profDir = dirService.get("ProfD", Ci.nsILocalFile);
-        var bookmarksBackup = profDir.clone();
-        bookmarksBackup.append("bookmarks.preplaces.html");
-        if (!bookmarksBackup.exists()) {
-          // save old bookmarks.html file as bookmarks.preplaces.html
-          try {
-            bookmarksFile.copyTo(profDir, "bookmarks.preplaces.html");
-          } catch(ex) {
-            dump("nsBrowserGlue::_initPlaces(): copy of bookmarks.html to bookmarks.preplaces.html failed: " + ex + "\n");
-          }
+        var dirService = Cc["@mozilla.org/file/directory_service;1"].
+                         getService(Ci.nsIProperties);
+        var bookmarksFile = dirService.get("BMarks", Ci.nsILocalFile);
+
+        // import the file
+        try {
+          var importer = Cc["@mozilla.org/browser/places/import-export-service;1"].
+                         getService(Ci.nsIPlacesImportExportService);
+          importer.importHTMLFromFile(bookmarksFile, true /* overwrite existing */);
+        } finally {
+          prefBranch.setBoolPref("browser.places.importBookmarksHTML", false);
         }
       }
     }
+
+    // Initialize bookmark archiving on idle.
+    // Once a day, either on idle or shutdown, bookmarks are backed up.
+    this.idleService.addIdleObserver(this, BOOKMARKS_ARCHIVE_IDLE_TIME);
   },
 
   /**
    * Places shut-down tasks
    * - back up and archive bookmarks
+   * - export bookmarks as HTML, if so configured
+   *
+   * Note: quit-application-granted notification is received twice
+   *       so replace this method with a no-op when first called.
    */
   _shutdownPlaces: function bg__shutdownPlaces() {
-    // backup bookmarks to bookmarks.html
-    var importer =
+    // Backup and archive Places bookmarks.
+    this._archiveBookmarks();
+
+    // Backup bookmarks to bookmarks.html to support apps that depend
+    // on the legacy format.
+    var autoExportHTML = false;
+    try {
+      autoExportHTML = prefs.getIntPref("browser.bookmarks.autoExportHTML");
+    } catch(ex) {}
+
+    if (autoExportHTML) {
       Cc["@mozilla.org/browser/places/import-export-service;1"].
-      getService(Ci.nsIPlacesImportExportService);
-    importer.backupBookmarksFile();
+        getService(Ci.nsIPlacesImportExportService).
+        backupBookmarksFile();
+    }
+  },
+
+  /**
+   * Back up and archive bookmarks
+   */
+  _archiveBookmarks: function nsBrowserGlue__archiveBookmarks() {
+    Cu.import("resource://gre/modules/utils.js");
+
+    var lastBackup = PlacesUtils.getMostRecentBackup();
+
+    // Backup bookmarks if there aren't any backups or 
+    // they haven't been backed up in the last 24 hrs.
+    if (!lastBackup ||
+        Date.now() - lastBackup.lastModifiedTime > BOOKMARKS_ARCHIVE_INTERVAL) {
+      var maxBackups = 5;
+      var prefs = Cc["@mozilla.org/preferences-service;1"].
+                  getService(Ci.nsIPrefBranch);
+      try {
+        maxBackups = prefs.getIntPref("browser.bookmarks.max_backups");
+      } catch(ex) {}
+
+      PlacesUtils.archiveBookmarksFile(maxBackups, false /* don't force */);
+    }
   },
 
   _migrateUI: function bg__migrateUI() {
     var prefBranch = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
 
     var migration = 0;
     try {
       migration = prefBranch.getIntPref("browser.migration.version");
@@ -443,59 +498,22 @@ BrowserGlue.prototype = {
       // this code should always migrate pre-FF3 profiles to the current UI state
 
       // grab the localstore.rdf and make changes needed for new UI
       this._rdf = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
       this._dataSource = this._rdf.GetDataSource("rdf:local-store");
       this._dirty = false;
 
       var currentSet = this._rdf.GetResource("currentset");
-      var collapsed = this._rdf.GetResource("collapsed");
-      var target;
-      var moveHome;
-      var homePattern = /(?:^|,)home-button(?:$|,)/;
-
-      // get an nsIRDFResource for the PersonalToolbar item
-      var personalBar = this._rdf.GetResource("chrome://browser/content/browser.xul#PersonalToolbar");
-      var personalBarCollapsed = this._getPersist(personalBar, collapsed) == "true";
 
       // get an nsIRDFResource for the nav-bar item
       var navBar = this._rdf.GetResource("chrome://browser/content/browser.xul#nav-bar");
-      target = this._getPersist(navBar, currentSet);
-      if (target) {
-        let originalTarget = target;
-
-        // move Home if we find it in the nav-bar and the personal toolbar isn't collapsed
-        if (!personalBarCollapsed)
-          target = target.replace(homePattern, ",");
-        moveHome = (target != originalTarget);
-
-        // add the new combined back and forward button
-        if (!/(?:^|,)unified-back-forward-button(?:$|,)/.test(target))
-          target = "unified-back-forward-button," + target;
-
-        if (target != originalTarget)
-          this._setPersist(navBar, currentSet, target);
-      } else {
-        // nav-bar doesn't have a currentset, so the defaultset will be used,
-        // which means Home will be moved
-        moveHome = true;
-      }
-
-      if (moveHome) {
-        // If the personal toolbar has a currentset, add Home. The defaultset will be
-        // used otherwise.
-        target = this._getPersist(personalBar, currentSet);
-        if (target && !homePattern.test(target))
-          this._setPersist(personalBar, currentSet, "home-button," + target);
-
-        // uncollapse the personal toolbar
-        if (personalBarCollapsed)
-          this._setPersist(personalBar, collapsed, "false");
-      }
+      var target = this._getPersist(navBar, currentSet);
+      if (target && !/(?:^|,)unified-back-forward-button(?:$|,)/.test(target))
+        this._setPersist(navBar, currentSet, "unified-back-forward-button," + target);
 
       // force the RDF to be saved
       if (this._dirty)
         this._dataSource.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush();
 
       // free up the RDF service
       this._rdf = null;
       this._dataSource = null;
@@ -569,42 +587,39 @@ BrowserGlue.prototype = {
           this._placesBundle.GetStringFromName("smartBookmarksFolderTitle");
         var mostVisitedTitle =
           this._placesBundle.GetStringFromName("mostVisitedTitle");
         var recentlyBookmarkedTitle =
           this._placesBundle.GetStringFromName("recentlyBookmarkedTitle");
         var recentTagsTitle =
           this._placesBundle.GetStringFromName("recentTagsTitle");
 
-        var bookmarksMenuFolder = bmsvc.bookmarksMenuFolder;
-        var unfiledBookmarksFolder = bmsvc.unfiledBookmarksFolder;
-        var toolbarFolder = bmsvc.toolbarFolder;
         var defaultIndex = bmsvc.DEFAULT_INDEX;
 
         // index = 0, make it the first folder
-        var placesFolder = bmsvc.createFolder(toolbarFolder, smartBookmarksFolderTitle,
+        var placesFolder = bmsvc.createFolder(bmsvc.toolbarFolder, smartBookmarksFolderTitle,
                                               0);
 
         // XXX should this be a pref?  see bug #399268
         var maxResults = 10;
 
         var mostVisitedItem = bmsvc.insertBookmark(placesFolder,
           this._uri("place:queryType=" +
               Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY +
               "&sort=" +
               Ci.nsINavHistoryQueryOptions.SORT_BY_VISITCOUNT_DESCENDING +
               "&maxResults=" + maxResults),
               defaultIndex, mostVisitedTitle);
 
         // excludeQueries=1 so that user created "saved searches" 
         // and these queries (added automatically) are excluded
         var recentlyBookmarkedItem = bmsvc.insertBookmark(placesFolder,
-          this._uri("place:folder=" + bookmarksMenuFolder + 
-              "&folder=" + unfiledBookmarksFolder +
-              "&folder=" + toolbarFolder +
+          this._uri("place:folder=BOOKMARKS_MENU" + 
+              "&folder=UNFILED_BOOKMARKS" +
+              "&folder=TOOLBAR" +
               "&queryType=" + Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS +
               "&sort=" +
               Ci.nsINavHistoryQueryOptions.SORT_BY_DATEADDED_DESCENDING +
               "&excludeItemIfParentHasAnnotation=livemark%2FfeedURI" +
               "&maxResults=" + maxResults +
               "&excludeQueries=1"),
               defaultIndex, recentlyBookmarkedTitle);
 
--- a/browser/components/places/content/bookmarkProperties.js
+++ b/browser/components/places/content/bookmarkProperties.js
@@ -562,18 +562,18 @@ var BookmarkPropertiesPanel = {
     if (this._itemType != BOOKMARK_ITEM || !this._bookmarkURI) {
       namePicker.selectedItem = userEnteredNameField;
       return;
     }
 
     var itemToSelect = userEnteredNameField;
     try {
       this._microsummaries =
-        PlacesUtils.microsummaries.getMicrosummaries(this._bookmarkURI,
-                                                     this._bookmarkId);
+        PlacesUIUtils.microsummaries.getMicrosummaries(this._bookmarkURI,
+                                                       this._bookmarkId);
     }
     catch(ex) {
       // 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) {
@@ -585,18 +585,18 @@ var BookmarkPropertiesPanel = {
 
         var menupopup = namePicker.menupopup;
         while (enumerator.hasMoreElements()) {
           var microsummary = enumerator.getNext()
                                        .QueryInterface(Ci.nsIMicrosummary);
           var menuItem = this._createMicrosummaryMenuItem(microsummary);
 
           if (this._action == ACTION_EDIT &&
-              PlacesUtils.microsummaries
-                         .isMicrosummary(this._bookmarkId, microsummary))
+              PlacesUIUtils.microsummaries
+                           .isMicrosummary(this._bookmarkId, microsummary))
             itemToSelect = menuItem;
 
           menupopup.appendChild(menuItem);
         }
       }
 
       this._microsummaries.addObserver(this);
     }
@@ -708,29 +708,29 @@ var BookmarkPropertiesPanel = {
    *        the ID of the textbox element whose contents we'll test
    *
    * @returns true if the textbox contains a valid URI string, false otherwise
    */
   _containsValidURI: function BPP__containsValidURI(aTextboxID) {
     try {
       var value = this._element(aTextboxID).value;
       if (value) {
-        var uri = PlacesUtils.createFixedURI(value);
+        var uri = PlacesUIUtils.createFixedURI(value);
         return true;
       }
     } catch (e) { }
     return false;
   },
 
   /**
    * Get an edit title transaction for the item edit/added in the dialog
    */
   _getEditTitleTransaction:
   function BPP__getEditTitleTransaction(aItemId, aNewTitle) {
-    return PlacesUtils.ptm.editItemTitle(aItemId, aNewTitle);
+    return PlacesUIUtils.ptm.editItemTitle(aItemId, aNewTitle);
   },
 
   /**
    * XXXmano todo:
    *  1. Make setAnnotationsForURI unset a given annotation if the value field
    *     is not set.
    *  2. Replace PlacesEditItemDescriptionTransaction and
    *     PlacesSetLoadInSidebarTransaction transaction with a generic
@@ -808,87 +808,87 @@ var BookmarkPropertiesPanel = {
     // title
     var newTitle = this._element("userEnteredName").label;
     if (newTitle != this._itemTitle)
       transactions.push(this._getEditTitleTransaction(itemId, newTitle));
 
     // description
     var description = this._element("descriptionTextfield").value;
     if (description != this._itemDescription) {
-      transactions.push(PlacesUtils.ptm.
+      transactions.push(PlacesUIUtils.ptm.
                         editItemDescription(itemId, description,
                         this._itemType != BOOKMARK_ITEM));
     }
 
     if (this._itemType == BOOKMARK_ITEM) {
       // location
-      var url = PlacesUtils.createFixedURI(this._element("editURLBar").value);
+      var url = PlacesUIUtils.createFixedURI(this._element("editURLBar").value);
       if (!this._bookmarkURI.equals(url))
-        transactions.push(PlacesUtils.ptm.editBookmarkURI(itemId, url));
+        transactions.push(PlacesUIUtils.ptm.editBookmarkURI(itemId, url));
 
       // keyword transactions
       var newKeyword = this._element("keywordTextfield").value;
       if (newKeyword != this._bookmarkKeyword) {
-        transactions.push(PlacesUtils.ptm.
+        transactions.push(PlacesUIUtils.ptm.
                           editBookmarkKeyword(itemId, newKeyword));
       }
 
       // microsummaries
       var namePicker = this._element("namePicker");
       var newMicrosummary = namePicker.selectedItem.microsummary;
 
       // Only add a microsummary update to the transaction if the
       // microsummary has actually changed, i.e. the user selected no
       // microsummary, but the bookmark previously had one, or the user
       // selected a microsummary which is not the one the bookmark previously
       // had.
       if ((newMicrosummary == null &&
-           PlacesUtils.microsummaries.hasMicrosummary(itemId)) ||
+           PlacesUIUtils.microsummaries.hasMicrosummary(itemId)) ||
           (newMicrosummary != null &&
-           !PlacesUtils.microsummaries
-                       .isMicrosummary(itemId, newMicrosummary))) {
+           !PlacesUIUtils.microsummaries
+                         .isMicrosummary(itemId, newMicrosummary))) {
         transactions.push(
-          PlacesUtils.ptm.editBookmarkMicrosummary(itemId, newMicrosummary));
+          PlacesUIUtils.ptm.editBookmarkMicrosummary(itemId, newMicrosummary));
       }
 
       // load in sidebar
       var loadInSidebarChecked = this._element("loadInSidebarCheckbox").checked;
       if (loadInSidebarChecked != this._loadBookmarkInSidebar) {
         transactions.push(
-          PlacesUtils.ptm.setLoadInSidebar(itemId, loadInSidebarChecked));
+          PlacesUIUtils.ptm.setLoadInSidebar(itemId, loadInSidebarChecked));
       }
     }
     else if (this._itemType == LIVEMARK_CONTAINER) {
       var feedURIString = this._element("feedLocationTextfield").value;
-      var feedURI = PlacesUtils.createFixedURI(feedURIString);
+      var feedURI = PlacesUIUtils.createFixedURI(feedURIString);
       if (!this._feedURI.equals(feedURI)) {
         transactions.push(
-          PlacesUtils.ptm.editLivemarkFeedURI(this._folderId, feedURI));
+          PlacesUIUtils.ptm.editLivemarkFeedURI(this._folderId, feedURI));
       }
 
       // Site Location is empty, we can set its URI to null
       var newSiteURIString = this._element("feedSiteLocationTextfield").value;
       var newSiteURI = null;
       if (newSiteURIString)
-        newSiteURI = PlacesUtils.createFixedURI(newSiteURIString);
+        newSiteURI = PlacesUIUtils.createFixedURI(newSiteURIString);
 
       if ((!newSiteURI && this._siteURI)  ||
           (newSiteURI && (!this._siteURI || !this._siteURI.equals(newSiteURI)))) {
         transactions.push(
-          PlacesUtils.ptm.editLivemarkSiteURI(this._folderId, newSiteURI));
+          PlacesUIUtils.ptm.editLivemarkSiteURI(this._folderId, newSiteURI));
       }
     }
 
     // If we have any changes to perform, do them via the
     // transaction manager passed by the opener so they can be undone.
     if (transactions.length > 0) {
       window.arguments[0].performed = true;
       var aggregate =
-        PlacesUtils.ptm.aggregateTransactions(this._getDialogTitle(), transactions);
-      PlacesUtils.ptm.doTransaction(aggregate);
+        PlacesUIUtils.ptm.aggregateTransactions(this._getDialogTitle(), transactions);
+      PlacesUIUtils.ptm.doTransaction(aggregate);
     }
   },
 
   /**
    * [New Item Mode] Get the insertion point details for the new item, given
    * dialog state and opening arguments.
    *
    * The container-identifier and insertion-index are returned separately in
@@ -907,58 +907,58 @@ var BookmarkPropertiesPanel = {
   },
 
   /**
    * Returns a transaction for creating a new bookmark item representing the
    * various fields and opening arguments of the dialog.
    */
   _getCreateNewBookmarkTransaction:
   function BPP__getCreateNewBookmarkTransaction(aContainer, aIndex) {
-    var uri = PlacesUtils.createFixedURI(this._element("editURLBar").value);
+    var uri = PlacesUIUtils.createFixedURI(this._element("editURLBar").value);
     var title = this._element("userEnteredName").label;
     var keyword = this._element("keywordTextfield").value;
     var annotations = [];
     var description = this._element("descriptionTextfield").value;
     if (description)
       annotations.push(this._getDescriptionAnnotation(description));
 
     var loadInSidebar = this._element("loadInSidebarCheckbox").checked;
     if (loadInSidebar)
       annotations.push(this._getLoadInSidebarAnnotation(true));
 
     var childTransactions = [];
     var microsummary = this._element("namePicker").selectedItem.microsummary;
     if (microsummary) {
       childTransactions.push(
-        PlacesUtils.ptm.editBookmarkMicrosummary(-1, microsummary));
+        PlacesUIUtils.ptm.editBookmarkMicrosummary(-1, microsummary));
     }
 
     if (this._postData) {
       childTransactions.push(
-        PlacesUtils.ptm.editBookmarkPostData(-1, this._postData));
+        PlacesUIUtils.ptm.editBookmarkPostData(-1, this._postData));
     }
 
-    var transactions = [PlacesUtils.ptm.createItem(uri, aContainer, aIndex,
-                                                   title, keyword,
-                                                   annotations,
-                                                   childTransactions)];
+    var transactions = [PlacesUIUtils.ptm.createItem(uri, aContainer, aIndex,
+                                                     title, keyword,
+                                                     annotations,
+                                                     childTransactions)];
 
-    return PlacesUtils.ptm.aggregateTransactions(this._getDialogTitle(), transactions);
+    return PlacesUIUtils.ptm.aggregateTransactions(this._getDialogTitle(), transactions);
   },
 
   /**
    * Returns a childItems-transactions array representing the URIList with
    * which the dialog has been opened.
    */
   _getTransactionsForURIList: function BPP__getTransactionsForURIList() {
     var transactions = [];
     for (var i = 0; i < this._URIList.length; ++i) {
       var uri = this._URIList[i];
       var title = this._getURITitleFromHistory(uri);
-      transactions.push(PlacesUtils.ptm.createItem(uri, -1, -1, title));
+      transactions.push(PlacesUIUtils.ptm.createItem(uri, -1, -1, title));
     }
     return transactions; 
   },
 
   /**
    * Returns a transaction for creating a new folder item representing the
    * various fields and opening arguments of the dialog.
    */
@@ -968,37 +968,37 @@ var BookmarkPropertiesPanel = {
     var annotations = [];
     var childItemsTransactions;
     if (this._URIList)
       childItemsTransactions = this._getTransactionsForURIList();
     var description = this._element("descriptionTextfield").value;
     if (description)
       annotations.push(this._getDescriptionAnnotation(description));
 
-    return PlacesUtils.ptm.createFolder(folderName, aContainer, aIndex,
-                                        annotations, childItemsTransactions);
+    return PlacesUIUtils.ptm.createFolder(folderName, aContainer, aIndex,
+                                          annotations, childItemsTransactions);
   },
 
   /**
    * Returns a transaction for creating a new live-bookmark item representing
    * the various fields and opening arguments of the dialog.
    */
   _getCreateNewLivemarkTransaction:
   function BPP__getCreateNewLivemarkTransaction(aContainer, aIndex) {
     var feedURIString = this._element("feedLocationTextfield").value;
-    var feedURI = PlacesUtils.createFixedURI(feedURIString);
+    var feedURI = PlacesUIUtils.createFixedURI(feedURIString);
 
     var siteURIString = this._element("feedSiteLocationTextfield").value;
     var siteURI = null;
     if (siteURIString)
-      siteURI = PlacesUtils.createFixedURI(siteURIString);
+      siteURI = PlacesUIUtils.createFixedURI(siteURIString);
 
     var name = this._element("namePicker").value;
-    return PlacesUtils.ptm.createLivemark(feedURI, siteURI, name,
-                                          aContainer, aIndex);
+    return PlacesUIUtils.ptm.createLivemark(feedURI, siteURI, name,
+                                            aContainer, aIndex);
   },
 
   /**
    * Dialog-accept code-path for creating a new item (any type)
    */
   _createNewItem: function BPP__getCreateItemTransaction() {
     var [container, index] = this._getInsertionPointDetails();
     var createTxn;
@@ -1013,17 +1013,17 @@ var BookmarkPropertiesPanel = {
     // list
     if (container != PlacesUtils.toolbarFolderId &&
         container != PlacesUtils.bookmarksMenuFolderId)
       this._markFolderAsRecentlyUsed(container);
 
     // perfrom our transaction do via the transaction manager passed by the
     // opener so it can be undone.
     window.arguments[0].performed = true;
-    PlacesUtils.ptm.doTransaction(createTxn);
+    PlacesUIUtils.ptm.doTransaction(createTxn);
   },
 
   onNamePickerInput: function BPP_onNamePickerInput() {
     this._element("userEnteredName").label = this._element("namePicker").value;
   },
 
   toggleTreeVisibility: function BPP_toggleTreeVisibility() {
     var expander = this._element("expander");
@@ -1044,17 +1044,17 @@ var BookmarkPropertiesPanel = {
                             expander.getAttribute("tooltiptextup"));
       document.documentElement.buttons = "accept,cancel,extra2";
 
       this._folderTree.collapsed = false;
 
       if (!this._folderTree.place) {
         const FOLDER_TREE_PLACE_URI =
           "place:excludeItems=1&excludeQueries=1&excludeReadOnlyFolders=1&folder=" +
-          PlacesUtils.allBookmarksFolderId;
+          PlacesUIUtils.allBookmarksFolderId;
         this._folderTree.place = FOLDER_TREE_PLACE_URI;
       }
 
       var currentFolder = this._getFolderIdFromMenuList();
       this._folderTree.selectItems([currentFolder]);
       this._folderTree.focus();
 
       resizeTo(window.outerWidth, window.outerHeight + this._folderTreeHeight);
--- a/browser/components/places/content/bookmarksPanel.js
+++ b/browser/components/places/content/bookmarksPanel.js
@@ -32,17 +32,17 @@
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
 function init() {
   document.getElementById("bookmarks-view").place =
-    "place:queryType=1&folder=" + window.top.PlacesUtils.allBookmarksFolderId;
+    "place:queryType=1&folder=" + window.top.PlacesUIUtils.allBookmarksFolderId;
 }
 
 function searchBookmarks(aSearchString) {
   var tree = document.getElementById('bookmarks-view');
   if (!aSearchString)
     tree.place = tree.place;
   else
     tree.applyFilter(aSearchString,
--- a/browser/components/places/content/bookmarksPanel.xul
+++ b/browser/components/places/content/bookmarksPanel.xul
@@ -68,17 +68,17 @@
              oncommand="searchBookmarks(this.value);"/>
   </hbox>
 
   <tree id="bookmarks-view" class="sidebar-placesTree" type="places"
         flex="1"
         hidecolumnpicker="true"
         context="placesContext"
         onkeypress="SidebarUtils.handleTreeKeyPress(event);"
-        onclick="SidebarUtils.handleTreeClick(this, event);"
+        onclick="SidebarUtils.handleTreeClick(this, event, true);"
         onmousemove="SidebarUtils.handleTreeMouseMove(event);"
         onmouseout="SidebarUtils.clearURLFromStatusBar();">
     <treecols>
       <treecol id="title" flex="1" primary="true" hideheader="true"/>
     </treecols>
     <treechildren id="bookmarks-view-children" view="bookmarks-view" class="sidebar-placesTreechildren" flex="1"/>
   </tree>
 </page>
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -34,17 +34,17 @@
  * 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 ***** */
 
 // XXXmano: we should move most/all of these constants to PlacesUtils
-const ORGANIZER_ROOT_BOOKMARKS = "place:folder=2&excludeItems=1&queryType=1";
+const ORGANIZER_ROOT_BOOKMARKS = "place:folder=BOOKMARKS_MENU&excludeItems=1&queryType=1";
 const ORGANIZER_SUBSCRIPTIONS_QUERY = "place:annotation=livemark%2FfeedURI";
 
 // No change to the view, preserve current selection
 const RELOAD_ACTION_NOTHING = 0;
 // Inserting items new to the view, select the inserted rows
 const RELOAD_ACTION_INSERT = 1;
 // Removing items from the view, select the first item after the last selected
 const RELOAD_ACTION_REMOVE = 2;
@@ -98,19 +98,19 @@ PlacesController.prototype = {
   /**
    * The places view.
    */
   _view: null,
 
   isCommandEnabled: function PC_isCommandEnabled(aCommand) {
     switch (aCommand) {
     case "cmd_undo":
-      return PlacesUtils.ptm.numberOfUndoItems > 0;
+      return PlacesUIUtils.ptm.numberOfUndoItems > 0;
     case "cmd_redo":
-      return PlacesUtils.ptm.numberOfRedoItems > 0;
+      return PlacesUIUtils.ptm.numberOfRedoItems > 0;
     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":
@@ -147,17 +147,17 @@ PlacesController.prototype = {
             (PlacesUtils.nodeIsBookmark(selectedNode) &&
             !PlacesUtils.nodeIsLivemarkItem(selectedNode)))
           return true;
       }
       return false;
     case "placesCmd_reloadMicrosummary":
       var selectedNode = this._view.selectedNode;
       return selectedNode && PlacesUtils.nodeIsBookmark(selectedNode) &&
-             PlacesUtils.microsummaries.hasMicrosummary(selectedNode.itemId);
+             PlacesUIUtils.microsummaries.hasMicrosummary(selectedNode.itemId);
     case "placesCmd_reload":
       // Livemark containers
       var selectedNode = this._view.selectedNode;
       return selectedNode && PlacesUtils.nodeIsLivemarkContainer(selectedNode);
     case "placesCmd_sortBy:name":
       var selectedNode = this._view.selectedNode;
       return selectedNode &&
              PlacesUtils.nodeIsFolder(selectedNode) &&
@@ -187,20 +187,20 @@ PlacesController.prototype = {
     // filters out other commands that we do _not_ support (see 329587).
     const CMD_PREFIX = "placesCmd_";
     return (aCommand.substr(0, CMD_PREFIX.length) == CMD_PREFIX);
   },
 
   doCommand: function PC_doCommand(aCommand) {
     switch (aCommand) {
     case "cmd_undo":
-      PlacesUtils.ptm.undoTransaction();
+      PlacesUIUtils.ptm.undoTransaction();
       break;
     case "cmd_redo":
-      PlacesUtils.ptm.redoTransaction();
+      PlacesUIUtils.ptm.redoTransaction();
       break;
     case "cmd_cut":
       this.cut();
       break;
     case "cmd_copy":
       this.copy();
       break;
     case "cmd_paste":
@@ -208,23 +208,23 @@ PlacesController.prototype = {
       break;
     case "cmd_delete":
       this.remove("Remove Selection");
       break;
     case "cmd_selectAll":
       this.selectAll();
       break;
     case "placesCmd_open":
-      PlacesUtils.openNodeIn(this._view.selectedNode, "current");
+      PlacesUIUtils.openNodeIn(this._view.selectedNode, "current");
       break;
     case "placesCmd_open:window":
-      PlacesUtils.openNodeIn(this._view.selectedNode, "window");
+      PlacesUIUtils.openNodeIn(this._view.selectedNode, "window");
       break;
     case "placesCmd_open:tab":
-      PlacesUtils.openNodeIn(this._view.selectedNode, "tab");
+      PlacesUIUtils.openNodeIn(this._view.selectedNode, "tab");
       break;
     case "placesCmd_new:folder":
       this.newItem("folder");
       break;
     case "placesCmd_new:bookmark":
       this.newItem("bookmark");
       break;
     case "placesCmd_new:livemark":
@@ -332,18 +332,18 @@ PlacesController.prototype = {
    * @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.
    */
   _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 flavors = PlacesUtils.placesFlavors;
-    var clipboard = PlacesUtils.clipboard;
+    var flavors = PlacesUIUtils.placesFlavors;
+    var clipboard = PlacesUIUtils.clipboard;
     var hasPlacesData =
       clipboard.hasDataMatchingFlavors(flavors, flavors.length,
                                        Ci.nsIClipboard.kGlobalClipboard);
     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
@@ -437,17 +437,17 @@ PlacesController.prototype = {
           break;
         case Ci.nsINavHistoryResultNode.RESULT_TYPE_URI:
         case Ci.nsINavHistoryResultNode.RESULT_TYPE_VISIT:
         case Ci.nsINavHistoryResultNode.RESULT_TYPE_FULL_VISIT:
           nodeData["link"] = true;
           uri = PlacesUtils._uri(node.uri);
           if (PlacesUtils.nodeIsBookmark(node)) {
             nodeData["bookmark"] = true;
-            var mss = PlacesUtils.microsummaries;
+            var mss = PlacesUIUtils.microsummaries;
             if (mss.hasMicrosummary(node.itemId))
               nodeData["microsummary"] = true;
             else if (node.parent &&
                      PlacesUtils.nodeIsLivemarkContainer(node.parent))
               nodeData["livemarkChild"] = true;
           }
           break;
       }
@@ -593,18 +593,17 @@ PlacesController.prototype = {
     }
 
     // Set Open Folder/Links In Tabs items enabled state if they're visible
     if (anyVisible) {
       var openContainerInTabsItem = document.getElementById("placesContext_openContainer:tabs");
       if (!openContainerInTabsItem.hidden && this._view.selectedNode &&
           PlacesUtils.nodeIsContainer(this._view.selectedNode)) {
         openContainerInTabsItem.disabled =
-          PlacesUtils.getURLsForContainerNode(this._view.selectedNode)
-                     .length == 0;
+          !PlacesUtils.hasChildURIs(this._view.selectedNode);
       }
       else {
         // see selectiontype rule in the overlay
         var openLinksInTabsItem = document.getElementById("placesContext_openLinks:tabs");
         openLinksInTabsItem.disabled = openLinksInTabsItem.hidden;
       }
     }
 
@@ -623,19 +622,19 @@ PlacesController.prototype = {
    */
   showBookmarkPropertiesForSelection: 
   function PC_showBookmarkPropertiesForSelection() {
     var node = this._view.selectedNode;
     if (!node)
       return;
 
     if (PlacesUtils.nodeIsFolder(node))
-      PlacesUtils.showFolderProperties(node.itemId);
+      PlacesUIUtils.showFolderProperties(node.itemId);
     else if (PlacesUtils.nodeIsBookmark(node))
-      PlacesUtils.showBookmarkProperties(node.itemId);
+      PlacesUIUtils.showBookmarkProperties(node.itemId);
   },
 
   /**
    * This method can be run on a URI parameter to ensure that it didn't
    * receive a string instead of an nsIURI object.
    */
   _assertURINotString: function PC__assertURINotString(value) {
     NS_ASSERT((typeof(value) == "object") && !(value instanceof String), 
@@ -651,17 +650,17 @@ PlacesController.prototype = {
       PlacesUtils.livemarks.reloadLivemarkFolder(selectedNode.itemId);
   },
 
   /**
    * Reload the microsummary associated with the selection
    */
   reloadSelectedMicrosummary: function PC_reloadSelectedMicrosummary() {
     var selectedNode = this._view.selectedNode;
-    var mss = PlacesUtils.microsummaries;
+    var mss = PlacesUIUtils.microsummaries;
     if (mss.hasMicrosummary(selectedNode.itemId))
       mss.refreshMicrosummary(selectedNode.itemId);
   },
 
   /**
    * Gives the user a chance to cancel loading lots of tabs at once
    */
   _confirmOpenTabs: function(numTabsToOpen) {
@@ -683,24 +682,24 @@ PlacesController.prototype = {
         var strings = document.getElementById("placeBundle");
         const BRANDING_BUNDLE_URI = "chrome://branding/locale/brand.properties";
         var brandShortName = Cc["@mozilla.org/intl/stringbundle;1"].
                              getService(Ci.nsIStringBundleService).
                              createBundle(BRANDING_BUNDLE_URI).
                              GetStringFromName("brandShortName");
        
         var buttonPressed = promptService.confirmEx(window,
-          PlacesUtils.getString("tabs.openWarningTitle"),
-          PlacesUtils.getFormattedString(messageKey, 
+          PlacesUIUtils.getString("tabs.openWarningTitle"),
+          PlacesUIUtils.getFormattedString(messageKey, 
             [numTabsToOpen, brandShortName]),
           (promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0)
           + (promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_1),
-          PlacesUtils.getString(openKey),
+          PlacesUIUtils.getString(openKey),
           null, null,
-          PlacesUtils.getFormattedString("tabs.openWarningPromptMeBranded",
+          PlacesUIUtils.getFormattedString("tabs.openWarningPromptMeBranded",
             [brandShortName]),
           warnOnOpen);
 
          reallyOpen = (buttonPressed == 0);
          // don't set the pref unless they press OK and it's false
          if (reallyOpen && !warnOnOpen.value)
            pref.setBoolPref(kWarnOnOpenPref, false);
       }
@@ -709,39 +708,39 @@ PlacesController.prototype = {
   },
 
   /**
    * Opens the links in the selected folder, or the selected links in new tabs. 
    */
   openSelectionInTabs: function PC_openLinksInTabs(aEvent) {
     var node = this._view.selectedNode;
     if (node && PlacesUtils.nodeIsContainer(node))
-      PlacesUtils.openContainerNodeInTabs(this._view.selectedNode, aEvent);
+      PlacesUIUtils.openContainerNodeInTabs(this._view.selectedNode, aEvent);
     else
-      PlacesUtils.openURINodesInTabs(this._view.getSelectionNodes(), aEvent);
+      PlacesUIUtils.openURINodesInTabs(this._view.getSelectionNodes(), aEvent);
   },
 
   /**
    * Shows the Add Bookmark UI for the current insertion point.
    *
    * @param aType
    *        the type of the new item (bookmark/livemark/folder)
    */
   newItem: function PC_newItem(aType) {
     var ip = this._view.insertionPoint;
     if (!ip)
       throw Cr.NS_ERROR_NOT_AVAILABLE;
 
     var performed = false;
     if (aType == "bookmark")
-      performed = PlacesUtils.showAddBookmarkUI(null, null, null, ip);
+      performed = PlacesUIUtils.showAddBookmarkUI(null, null, null, ip);
     else if (aType == "livemark")
-      performed = PlacesUtils.showAddLivemarkUI(null, null, null, null, ip);
+      performed = PlacesUIUtils.showAddLivemarkUI(null, null, null, null, ip);
     else // folder
-      performed = PlacesUtils.showAddFolderUI(null, ip);
+      performed = PlacesUIUtils.showAddFolderUI(null, ip);
 
     if (performed) {
       // select the new item
       var insertedNodeId = PlacesUtils.bookmarks
                                       .getIdForItemAt(ip.itemId, ip.index);
       this._view.selectItems([insertedNodeId], ip.itemId);
     }
   },
@@ -752,34 +751,34 @@ PlacesController.prototype = {
    * of the folder. 
    */
   newFolder: function PC_newFolder() {
     var ip = this._view.insertionPoint;
     if (!ip)
       throw Cr.NS_ERROR_NOT_AVAILABLE;
 
     var performed = false;
-    performed = PlacesUtils.showAddFolderUI(null, ip);
+    performed = PlacesUIUtils.showAddFolderUI(null, ip);
     if (performed) {
       // select the new item
       var insertedNodeId = PlacesUtils.bookmarks
                                       .getIdForItemAt(ip.itemId, ip.index);
       this._view.selectItems([insertedNodeId]);
     }
   },
 
   /**
    * Create a new Bookmark separator somewhere.
    */
   newSeparator: function PC_newSeparator() {
     var ip = this._view.insertionPoint;
     if (!ip)
       throw Cr.NS_ERROR_NOT_AVAILABLE;
-    var txn = PlacesUtils.ptm.createSeparator(ip.itemId, ip.index);
-    PlacesUtils.ptm.doTransaction(txn);
+    var txn = PlacesUIUtils.ptm.createSeparator(ip.itemId, ip.index);
+    PlacesUIUtils.ptm.doTransaction(txn);
     // select the new item
     var insertedNodeId = PlacesUtils.bookmarks
                                     .getIdForItemAt(ip.itemId, ip.index);
     this._view.selectItems([insertedNodeId]);
   },
 
   /**
    * Opens a dialog for moving the selected nodes.
@@ -790,18 +789,18 @@ PlacesController.prototype = {
                       this._view.getSelectionNodes());
   },
 
   /**
    * Sort the selected folder by name
    */
   sortFolderByName: function PC_sortFolderByName() {
     var itemId = PlacesUtils.getConcreteItemId(this._view.selectedNode);
-    var txn = PlacesUtils.ptm.sortFolderByName(itemId);
-    PlacesUtils.ptm.doTransaction(txn);
+    var txn = PlacesUIUtils.ptm.sortFolderByName(itemId);
+    PlacesUIUtils.ptm.doTransaction(txn);
   },
 
   /**
    * Walk the list of folders we're removing in this delete operation, and
    * see if the selected node specified is already implicitly being removed 
    * because it is a child of that folder. 
    * @param   node
    *          Node to check for containment. 
@@ -851,35 +850,35 @@ PlacesController.prototype = {
     for (var i = 0; i < range.length; ++i) {
       var node = range[i];
       if (this._shouldSkipNode(node, removedFolders))
         continue;
 
       if (PlacesUtils.nodeIsFolder(node))
         removedFolders.push(node);
 
-      transactions.push(PlacesUtils.ptm.removeItem(node.itemId));
+      transactions.push(PlacesUIUtils.ptm.removeItem(node.itemId));
     }
   },
 
   /**
    * Removes the set of selected ranges from bookmarks.
    * @param   txnName
    *          See |remove|.
    */
   _removeRowsFromBookmarks: function PC__removeRowsFromBookmarks(txnName) {
     var ranges = this._view.getRemovableSelectionRanges();
     var transactions = [];
     // Delete the selected rows. Do this by walking the selection backward, so
     // that when undo is performed they are re-inserted in the correct order.
     for (var i = ranges.length - 1; i >= 0 ; --i)
       this._removeRange(ranges[i], transactions);
     if (transactions.length > 0) {
-      var txn = PlacesUtils.ptm.aggregateTransactions(txnName, transactions);
-      PlacesUtils.ptm.doTransaction(txn);
+      var txn = PlacesUIUtils.ptm.aggregateTransactions(txnName, transactions);
+      PlacesUIUtils.ptm.doTransaction(txn);
     }
   },
 
   /**
    * Removes the set of selected ranges from history.
    */
   _removeRowsFromHistory: function PC__removeRowsFromHistory() {
     // Other containers are history queries, just delete from history
@@ -992,17 +991,17 @@ PlacesController.prototype = {
       }
 
       var dataSet = new TransferDataSet();
       for (var i = 0; i < nodes.length; ++i) {
         var node = nodes[i];
 
         var data = new TransferData();
         function addData(type, overrideURI) {
-          data.addDataForFlavour(type, PlacesUtils._wrapString(
+          data.addDataForFlavour(type, PlacesUIUtils._wrapString(
                                  PlacesUtils.wrapNode(node, type, overrideURI)));
         }
 
         function addURIData(overrideURI) {
           addData(PlacesUtils.TYPE_X_MOZ_URL, overrideURI);
           addData(PlacesUtils.TYPE_UNICODE, overrideURI);
           addData(PlacesUtils.TYPE_HTML, overrideURI);
         }
@@ -1070,31 +1069,31 @@ PlacesController.prototype = {
         }
 
         // all items wrapped as TYPE_X_MOZ_PLACE
         placeString += generateChunk(PlacesUtils.TYPE_X_MOZ_PLACE);
       }
 
       function addData(type, data) {
         xferable.addDataFlavor(type);
-        xferable.setTransferData(type, PlacesUtils._wrapString(data), data.length * 2);
+        xferable.setTransferData(type, PlacesUIUtils._wrapString(data), data.length * 2);
       }
       // This order is _important_! It controls how this and other applications 
       // select data to be inserted based on type.
       if (placeString)
         addData(PlacesUtils.TYPE_X_MOZ_PLACE, placeString);
       if (mozURLString)
         addData(PlacesUtils.TYPE_X_MOZ_URL, mozURLString);
       if (unicodeString)
         addData(PlacesUtils.TYPE_UNICODE, unicodeString);
       if (htmlString)
         addData(PlacesUtils.TYPE_HTML, htmlString);
 
       if (placeString || unicodeString || htmlString || mozURLString) {
-        PlacesUtils.clipboard.setData(xferable, null, Ci.nsIClipboard.kGlobalClipboard);
+        PlacesUIUtils.clipboard.setData(xferable, null, Ci.nsIClipboard.kGlobalClipboard);
       }
     }
     finally {
       if (oldViewer)
         result.viewer = oldViewer;
     }
   },
 
@@ -1128,17 +1127,17 @@ PlacesController.prototype = {
       var xferable = 
           Cc["@mozilla.org/widget/transferable;1"].
           createInstance(Ci.nsITransferable);
       for (var i = 0; i < types.length; ++i) 
         xferable.addDataFlavor(types[i]);
       return xferable;
     }
 
-    var clipboard = PlacesUtils.clipboard;
+    var clipboard = PlacesUIUtils.clipboard;
 
     var ip = this._view.insertionPoint;
     if (!ip)
       throw Cr.NS_ERROR_NOT_AVAILABLE;
 
     /**
      * Gets a list of transactions to perform the paste of specific types.
      * @param   types
@@ -1156,19 +1155,19 @@ PlacesController.prototype = {
         var items = PlacesUtils.unwrapNodes(data, type.value);
         var transactions = [];
         var index = ip.index;
         for (var i = 0; i < items.length; ++i) {
           // adjusted to make sure that items are given the correct index -
           // transactions insert differently if index == -1
           if (ip.index > -1)
             index = ip.index + i;
-          transactions.push(PlacesUtils.makeTransaction(items[i], type.value, 
-                                                        ip.itemId, index,
-                                                        true));
+          transactions.push(PlacesUIUtils.makeTransaction(items[i], type.value,
+                                                          ip.itemId, index,
+                                                          true));
         }
         return transactions;
       }
       catch (e) {
         // getAnyTransferData will throw if there is no data of the specified
         // type on the clipboard. 
         // unwrapNodes will throw if the data that is present is malformed in
         // some way. 
@@ -1177,18 +1176,18 @@ PlacesController.prototype = {
       return [];
     }
 
     // Get transactions to paste any folders, separators or links that might
     // be on the clipboard, aggregate them and execute them. 
     var transactions = getTransactions([PlacesUtils.TYPE_X_MOZ_PLACE,
                                         PlacesUtils.TYPE_X_MOZ_URL, 
                                         PlacesUtils.TYPE_UNICODE]);
-    var txn = PlacesUtils.ptm.aggregateTransactions("Paste", transactions);
-    PlacesUtils.ptm.doTransaction(txn);
+    var txn = PlacesUIUtils.ptm.aggregateTransactions("Paste", transactions);
+    PlacesUIUtils.ptm.doTransaction(txn);
 
     // select the pasted items, they should be consecutive
     var insertedNodeIds = [];
     for (var i = 0; i < transactions.length; ++i)
       insertedNodeIds.push(PlacesUtils.bookmarks
                                       .getIdForItemAt(ip.itemId, ip.index + i));
     if (insertedNodeIds.length > 0)
       this._view.selectItems(insertedNodeIds);
@@ -1234,41 +1233,73 @@ var PlacesControllerDragHelper = {
     var dragService = Cc["@mozilla.org/widget/dragservice;1"].
                       getService(Ci.nsIDragService);
     return dragService.getCurrentSession();
   },
 
   /**
    * Determines whether or not the data currently being dragged can be dropped
    * on a places view.
+   * @param ip
+   *        The insertion point where the items should be dropped
    */
-  canDrop: function PCDH_canDrop() {
+  canDrop: function PCDH_canDrop(ip) {
     var session = this.getSession();
-    if (session) {
-      var types = PlacesUtils.GENERIC_VIEW_DROP_TYPES;
-      for (var i = 0; i < types.length; ++i) {
-        if (session.isDataFlavorSupported(types[i]))
-          return true;
+    if (!session)
+      return false;
+
+    var types = PlacesUIUtils.GENERIC_VIEW_DROP_TYPES;
+    var foundType = false;
+    for (var i = 0; i < types.length && !foundType; ++i) {
+      if (session.isDataFlavorSupported(types[i]))
+        foundType = true;
+    }
+
+    if (!foundType)
+      return false;
+
+    // Check every dragged item
+    var xferable = this._initTransferable(session);
+    var dropCount = session.numDropItems;
+    for (i = 0; i < dropCount; i++) {
+      // Get the information of the dragged item
+      session.getData(xferable, i);
+      var data = { }, flavor = { };
+      xferable.getAnyTransferData(flavor, data, { });
+      data.value.QueryInterface(Ci.nsISupportsString);
+      var dragged = PlacesUtils.unwrapNodes(data.value.data, flavor.value)[0];
+    
+      // The following loop disallows the dropping of a folder on itself or
+      // on any of its descendants.
+      if (dragged.type == PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER ||
+          /^place:/.test(dragged.uri)) {
+        var parentId = ip.itemId;
+        while (parentId != PlacesUtils.placesRootId) {
+          if (dragged.concreteId == parentId || dragged.id == parentId)
+            return false;
+          parentId = PlacesUtils.bookmarks.getFolderIdForItem(parentId);
+        }
       }
     }
-    return false;
+
+    return true;
   },
 
   /** 
    * Creates a Transferable object that can be filled with data of types
    * supported by a view. 
    * @param   session
    *          The active drag session
    * @returns An object implementing nsITransferable that can receive data
    *          dropped onto a view. 
    */
   _initTransferable: function PCDH__initTransferable(session) {
     var xferable = Cc["@mozilla.org/widget/transferable;1"].
                    createInstance(Ci.nsITransferable);
-    var types = PlacesUtils.GENERIC_VIEW_DROP_TYPES;
+    var types = PlacesUIUtils.GENERIC_VIEW_DROP_TYPES;
     for (var i = 0; i < types.length; ++i) {
       if (session.isDataFlavorSupported(types[i]))
         xferable.addDataFlavor(types[i]);
     }
     return xferable;
   },
 
   /**
@@ -1301,23 +1332,23 @@ var PlacesControllerDragHelper = {
       // drag multiple elts upward: need to increment index or each successive
       // elt will be inserted at the same index, each above the previous.
       if ((index != -1) && ((index < unwrapped.index) ||
                            (unwrapped.folder && (index < unwrapped.folder.index)))) {
         index = index + movedCount;
         movedCount++;
       }
 
-      transactions.push(PlacesUtils.makeTransaction(unwrapped,
+      transactions.push(PlacesUIUtils.makeTransaction(unwrapped,
                         flavor.value, insertionPoint.itemId,
                         index, copy));
     }
 
-    var txn = PlacesUtils.ptm.aggregateTransactions("DropItems", transactions);
-    PlacesUtils.ptm.doTransaction(txn);
+    var txn = PlacesUIUtils.ptm.aggregateTransactions("DropItems", transactions);
+    PlacesUIUtils.ptm.doTransaction(txn);
   }
 };
 
 function goUpdatePlacesCommands() {
   var placesController;
   try {
     // Or any other command...
     placesController = top.document.commandDispatcher
--- a/browser/components/places/content/editBookmarkOverlay.js
+++ b/browser/components/places/content/editBookmarkOverlay.js
@@ -152,17 +152,17 @@ var gEditItemOverlay = {
     // folder picker
     this._initFolderMenuList(container);
 
     // name picker
     this._initNamePicker();
 
     // description field
     this._initTextField("descriptionField", 
-                        PlacesUtils.getItemDescription(this._itemId));
+                        PlacesUIUtils.getItemDescription(this._itemId));
     
     this._showHideRows();
 
     // observe changes
     if (!this._observersAdded) {
       PlacesUtils.bookmarks.addObserver(this, false);
       window.addEventListener("unload", this, false);
       this._observersAdded = true;
@@ -307,17 +307,20 @@ var gEditItemOverlay = {
 
     return menuItem;
   },
 
   _getItemStaticTitle: function EIO__getItemStaticTitle() {
     const annos = PlacesUtils.annotations;
     if (annos.itemHasAnnotation(this._itemId, STATIC_TITLE_ANNO))
       return annos.getItemAnnotation(this._itemId, STATIC_TITLE_ANNO);
-    return PlacesUtils.bookmarks.getItemTitle(this._itemId);
+    var title = PlacesUtils.bookmarks.getItemTitle(this._itemId);
+    if (title === null)
+      return PlacesUtils.history.getPageTitle(this._uri);
+    return title;
   },
 
   _initNamePicker: function EIO_initNamePicker() {
     var userEnteredNameField = this._element("userEnteredName");
     var namePicker = this._element("namePicker");
     var droppable = false;
 
     userEnteredNameField.label = this._getItemStaticTitle();
@@ -331,18 +334,18 @@ var gEditItemOverlay = {
       this._microsummaries.removeObserver(this);
       this._microsummaries = null;
     }
 
     var itemToSelect = userEnteredNameField;
     try {
       if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK &&
           !this._readOnly)
-        this._microsummaries = PlacesUtils.microsummaries
-                                          .getMicrosummaries(this._uri, -1);
+        this._microsummaries = PlacesUIUtils.microsummaries
+                                            .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).
@@ -353,18 +356,18 @@ var gEditItemOverlay = {
 
       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);
-          if (PlacesUtils.microsummaries
-                         .isMicrosummary(this._itemId, microsummary))
+          if (PlacesUIUtils.microsummaries
+                           .isMicrosummary(this._itemId, microsummary))
             itemToSelect = menuItem;
 
           menupopup.appendChild(menuItem);
         }
       }
 
       this._microsummaries.addObserver(this);
     }
@@ -456,43 +459,43 @@ var gEditItemOverlay = {
           tagsToRemove.push(currentTags[i]);
       }
       for (i = 0; i < tags.length; i++) {
         if (currentTags.indexOf(tags[i]) == -1)
           tagsToAdd.push(tags[i]);
       }
 
       if (tagsToAdd.length > 0) {
-        var tagTxn = PlacesUtils.ptm.tagURI(this._uri, tagsToAdd);
-        PlacesUtils.ptm.doTransaction(tagTxn);
+        var tagTxn = PlacesUIUtils.ptm.tagURI(this._uri, tagsToAdd);
+        PlacesUIUtils.ptm.doTransaction(tagTxn);
       }
       if (tagsToRemove.length > 0) {
-        var untagTxn = PlacesUtils.ptm.untagURI(this._uri, tagsToRemove);
-        PlacesUtils.ptm.doTransaction(untagTxn);
+        var untagTxn = PlacesUIUtils.ptm.untagURI(this._uri, tagsToRemove);
+        PlacesUIUtils.ptm.doTransaction(untagTxn);
       }
     }
   },
 
   onNamePickerInput: function EIO_onNamePickerInput() {
     var title = this._element("namePicker").value;
     this._element("userEnteredName").label = title;
   },
 
   onNamePickerChange: function EIO_onNamePickerChange() {
     if (this._itemId == -1)
       return;
 
     var namePicker = this._element("namePicker")
     var txns = [];
-    const ptm = PlacesUtils.ptm;
+    const ptm = PlacesUIUtils.ptm;
 
     // Here we update either the item title or its cached static title
     var newTitle = this._element("userEnteredName").label;
     if (this._getItemStaticTitle() != newTitle) {
-      if (PlacesUtils.microsummaries.hasMicrosummary(this._itemId)) {
+      if (PlacesUIUtils.microsummaries.hasMicrosummary(this._itemId)) {
         // Note: this implicitly also takes care of the microsummary->static
         // title case, the removeMicorosummary method in the service will set
         // the item-title to the value of this annotation.
         //
         // XXXmano: use a transaction
         PlacesUtils.setAnnotationsForItem(this._itemId,
                                           [{name: STATIC_TITLE_ANNO,
                                             value: newTitle}]);
@@ -503,114 +506,118 @@ var gEditItemOverlay = {
 
     var newMicrosummary = namePicker.selectedItem.microsummary;
 
     // Only add a microsummary update to the transaction if the microsummary
     // has actually changed, i.e. the user selected no microsummary, but the
     // bookmark previously had one, or the user selected a microsummary which
     // is not the one the bookmark previously had
     if ((newMicrosummary == null &&
-         PlacesUtils.microsummaries.hasMicrosummary(this._itemId)) ||
+         PlacesUIUtils.microsummaries.hasMicrosummary(this._itemId)) ||
         (newMicrosummary != null &&
-         !PlacesUtils.microsummaries
-                     .isMicrosummary(this._itemId, newMicrosummary))) {
+         !PlacesUIUtils.microsummaries
+                       .isMicrosummary(this._itemId, newMicrosummary))) {
       txns.push(ptm.editBookmarkMicrosummary(this._itemId, newMicrosummary));
     }
 
     var aggregate = ptm.aggregateTransactions("Edit Item Title", txns);
     ptm.doTransaction(aggregate);
   },
 
   onDescriptionFieldBlur: function EIO_onDescriptionFieldInput() {
     var description = this._element("descriptionField").value;
     if (description != PlacesUtils.getItemDescription(this._itemId)) {
-      var txn = PlacesUtils.ptm
-                           .editItemDescription(this._itemId, description);
-      PlacesUtils.ptm.doTransaction(txn);
+      var txn = PlacesUIUtils.ptm
+                             .editItemDescription(this._itemId, description);
+      PlacesUIUtils.ptm.doTransaction(txn);
     }
   },
 
   onLocationFieldBlur: function EIO_onLocationFieldBlur() {
     var uri;
     try {
-      uri = PlacesUtils.createFixedURI(this._element("locationField").value);
+      uri = PlacesUIUtils.createFixedURI(this._element("locationField").value);
     }
     catch(ex) { return; }
 
     if (!this._uri.equals(uri)) {
-      var txn = PlacesUtils.ptm.editBookmarkURI(this._itemId, uri);
-      PlacesUtils.ptm.doTransaction(txn);
+      var txn = PlacesUIUtils.ptm.editBookmarkURI(this._itemId, uri);
+      PlacesUIUtils.ptm.doTransaction(txn);
     }
   },
 
   onKeywordFieldBlur: function EIO_onKeywordFieldBlur() {
     var keyword = this._element("keywordField").value;
     if (keyword != PlacesUtils.bookmarks.getKeywordForBookmark(this._itemId)) {
-      var txn = PlacesUtils.ptm.editBookmarkKeyword(this._itemId, keyword);
-      PlacesUtils.ptm.doTransaction(txn);
+      var txn = PlacesUIUtils.ptm.editBookmarkKeyword(this._itemId, keyword);
+      PlacesUIUtils.ptm.doTransaction(txn);
     }
   },
 
   onFeedLocationFieldBlur: function EIO_onFeedLocationFieldBlur() {
     var uri;
     try {
-      uri = PlacesUtils.createFixedURI(this._element("feedLocationField").value);
+      uri = PlacesUIUtils.createFixedURI(this._element("feedLocationField").value);
     }
     catch(ex) { return; }
 
     var currentFeedURI = PlacesUtils.livemarks.getFeedURI(this._itemId);
     if (!currentFeedURI.equals(uri)) {
-      var txn = PlacesUtils.ptm.editLivemarkFeedURI(this._itemId, uri);
-      PlacesUtils.ptm.doTransaction(txn);
+      var txn = PlacesUIUtils.ptm.editLivemarkFeedURI(this._itemId, uri);
+      PlacesUIUtils.ptm.doTransaction(txn);
     }
   },
 
   onSiteLocationFieldBlur: function EIO_onSiteLocationFieldBlur() {
     var uri = null;
     try {
-      uri = PlacesUtils.createFixedURI(this._element("siteLocationField").value);
+      uri = PlacesUIUtils.createFixedURI(this._element("siteLocationField").value);
     }
     catch(ex) {  }
 
     var currentSiteURI = PlacesUtils.livemarks.getSiteURI(this._itemId);
     if (!uri || !currentSiteURI.equals(uri)) {
-      var txn = PlacesUtils.ptm.editLivemarkSiteURI(this._itemId, uri);
-      PlacesUtils.ptm.doTransaction(txn);
+      var txn = PlacesUIUtils.ptm.editLivemarkSiteURI(this._itemId, uri);
+      PlacesUIUtils.ptm.doTransaction(txn);
     }
   },
 
   onLoadInSidebarCheckboxCommand:
   function EIO_onLoadInSidebarCheckboxCommand() {
     var loadInSidebarChecked = this._element("loadInSidebarCheckbox").checked;
-    var txn = PlacesUtils.ptm.setLoadInSidebar(this._itemId,
-                                               loadInSidebarChecked);
-    PlacesUtils.ptm.doTransaction(txn);
+    var txn = PlacesUIUtils.ptm.setLoadInSidebar(this._itemId,
+                                                 loadInSidebarChecked);
+    PlacesUIUtils.ptm.doTransaction(txn);
   },
 
   toggleFolderTreeVisibility: function EIO_toggleFolderTreeVisibility() {
     var expander = this._element("foldersExpander");
     if (!this._folderTree.collapsed) {
       expander.className = "expander-down";
       expander.setAttribute("tooltiptext",
                             expander.getAttribute("tooltiptextdown"));
-      this._folderTree.collapsed = true;
+      this._folderTree.collapsed =
+        this._element("newFolderBox").collapsed = true;
       this._element("chooseFolderSeparator").hidden =
         this._element("chooseFolderMenuItem").hidden = false;
     }
     else {
       expander.className = "expander-up"
       expander.setAttribute("tooltiptext",
                             expander.getAttribute("tooltiptextup"));
-      this._folderTree.collapsed = false;
-      if (!this._folderTree.place) {
-        const FOLDER_TREE_PLACE_URI =
-          "place:excludeItems=1&excludeQueries=1&excludeReadOnlyFolders=1&folder=" +
-          window.top.PlacesUtils.allBookmarksFolderId;
-        this._folderTree.place = FOLDER_TREE_PLACE_URI;
-      }
+      this._folderTree.collapsed =
+        this._element("newFolderBox").collapsed = false;
+
+      // XXXmano: Ideally we would only do this once, but for some odd reason,
+      // the editable mode set on this tree, together with its collapsed state
+      // breaks the view.
+      const FOLDER_TREE_PLACE_URI =
+        "place:excludeItems=1&excludeQueries=1&excludeReadOnlyFolders=1&folder=" +
+        window.top.PlacesUIUtils.allBookmarksFolderId;
+      this._folderTree.place = FOLDER_TREE_PLACE_URI;
 
       this._element("chooseFolderSeparator").hidden =
         this._element("chooseFolderMenuItem").hidden = true;
       var currentFolder = this._getFolderIdFromMenuList();
       this._folderTree.selectItems([currentFolder]);
       this._folderTree.focus();
     }
   },
@@ -658,18 +665,18 @@ var gEditItemOverlay = {
       // menulist right away
       setTimeout(function(self) self.toggleFolderTreeVisibility(), 100, this);
       return;
     }
 
     // Move the item
     var container = this._getFolderIdFromMenuList();
     if (PlacesUtils.bookmarks.getFolderIdForItem(this._itemId) != container) {
-      var txn = PlacesUtils.ptm.moveItem(this._itemId, container, -1);
-      PlacesUtils.ptm.doTransaction(txn);
+      var txn = PlacesUIUtils.ptm.moveItem(this._itemId, container, -1);
+      PlacesUIUtils.ptm.doTransaction(txn);
 
       // Mark the containing folder as recently-used if it isn't in the
       // static list
       if (container != PlacesUtils.unfiledBookmarksFolderId &&
           container != PlacesUtils.toolbarFolderId &&
           container != PlacesUtils.bookmarksMenuFolderId)
         this._markFolderAsRecentlyUsed(container);
     }
@@ -761,16 +768,36 @@ var gEditItemOverlay = {
       if (tags[i] == "") {
         tags.splice(i, 1);
         i--;
       }
     }
     return tags;
   },
 
+  newFolder: function EIO_newFolder() {
+    var ip = this._folderTree.insertionPoint;
+
+    // default to the bookmarks menu folder
+    if (ip.itemId == PlacesUIUtils.allBookmarksFolderId ||
+        ip.itemId == PlacesUIUtils.unfiledBookmarksFolderId) {
+      ip.itemId = PlacesUtils.bookmarksMenuFolderId;
+      ip.index = -1;
+    }
+
+    // XXXmano: add a separate "New Folder" string at some point...
+    var defaultLabel = this._element("newFolderButton").label;
+    var txn = PlacesUIUtils.ptm.createFolder(defaultLabel, ip.itemId, ip.index);
+    PlacesUIUtils.ptm.doTransaction(txn);
+    this._folderTree.focus();
+    this._folderTree.selectItems([this._lastNewItem]);
+    this._folderTree.startEditing(this._folderTree.view.selection.currentIndex,
+                                  this._folderTree.columns.getFirstColumn());
+  },
+
   // nsIDOMEventListener
   handleEvent: function EIO_nsIDOMEventListener(aEvent) {
     switch (aEvent.type) {
     case "CheckboxStateChange":
       // Update the tags field when items are checked/unchecked in the listbox
       var tags = this._getTagsArrayFromTagField();
 
       if (aEvent.target.checked)
@@ -864,14 +891,17 @@ var gEditItemOverlay = {
 
     var folderItem = this._getFolderMenuItem(aNewParent);
 
     // just setting selectItem _does not_ trigger oncommand, so we don't
     // recurse
     this._folderMenuList.selectedItem = folderItem;
   },
 
+  onItemAdded: function EIO_onItemAdded(aItemId, aFolder, aIndex) {
+    this._lastNewItem = aItemId;
+  },
+
   onBeginUpdateBatch: function() { },
   onEndUpdateBatch: function() { },
-  onItemAdded: function() { },
   onItemRemoved: function() { },
   onItemVisited: function() { },
 };
--- a/browser/components/places/content/editBookmarkOverlay.xul
+++ b/browser/components/places/content/editBookmarkOverlay.xul
@@ -30,19 +30,22 @@
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
+<!-- XXXmano: temporary also use moveBookmarks for the "New Folder" button -->
 <!DOCTYPE overlay [
-<!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/editBookmarkOverlay.dtd">
-%placesDTD;
+<!ENTITY % editBookmarkOverlayDTD SYSTEM "chrome://browser/locale/places/editBookmarkOverlay.dtd">
+%editBookmarkOverlayDTD;
+<!ENTITY % moveBookmarksDTD SYSTEM "chrome://browser/locale/places/moveBookmarks.dtd">
+%moveBookmarksDTD;
 ]>
 
 <?xml-stylesheet href="chrome://browser/skin/places/editBookmarkOverlay.css"?>
 <?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
 
 <overlay id="editBookmarkOverlay"
          xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
@@ -119,46 +122,55 @@
             <menupopup>
               <!-- Static item for special folders -->
               <menuitem id="editBMPanel_unfiledRootItem"
                         class="menuitem-iconic folder-icon"/>
               <menuitem id="editBMPanel_bmRootItem"
                         class="menuitem-iconic folder-icon"/>
               <menuitem id="editBMPanel_toolbarFolderItem"
                         class="menuitem-iconic folder-icon"/>
-              <menuseparator id="editBMPanel_foldersSeparator" hidden="true"/>
               <menuseparator id="editBMPanel_chooseFolderSeparator"/>
               <menuitem id="editBMPanel_chooseFolderMenuItem"
 	        label="&editBookmarkOverlay.choose.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="gEditItemOverlay.toggleFolderTreeVisibility();"
                   observes="paneElementsBroadcaster"/>
         </row>
 
         <tree id="editBMPanel_folderTree"
               class="placesTree"
               type="places"
               height="150"
               collapsed="true"
+              editable="true"
               onselect="gEditItemOverlay.onFolderTreeSelect();"
               hidecolumnpicker="true"
               observes="paneElementsBroadcaster">
           <treecols>
             <treecol anonid="title" flex="1" primary="true" hideheader="true"/>
           </treecols>
           <treechildren flex="1"/>
         </tree>
 
+        <hbox id="editBMPanel_newFolderBox" collapsed="true">
+          <button label="&newFolderButton.label;"
+                  id="editBMPanel_newFolderButton"
+                  accesskey="&newFolderButton.accesskey;"
+                  oncommand="gEditItemOverlay.newFolder();"/>
+          <spacer flex="1"/>
+        </hbox>
+
         <row align="center" id="editBMPanel_tagsRow">
           <label value="&editBookmarkOverlay.tags.label;"
                  accesskey="&editBookmarkOverlay.tags.accesskey;"
                  control="editBMPanel_tagsField"
                  observes="paneElementsBroadcaster"/>
           <textbox id="editBMPanel_tagsField"
                    onblur="gEditItemOverlay.onTagsFieldBlur();"
                    observes="paneElementsBroadcaster"
--- a/browser/components/places/content/history-panel.js
+++ b/browser/components/places/content/history-panel.js
@@ -97,17 +97,17 @@ function GroupBy(groupingType)
 
 function historyAddBookmarks()
 { 
   // no need to check gHistoryTree.view.selection.count
   // node will be null if there is a multiple selection 
   // or if the selected item is not a URI node
   var node = gHistoryTree.selectedNode;
   if (node && PlacesUtils.nodeIsURI(node))
-    PlacesUtils.showMinimalAddBookmarkUI(PlacesUtils._uri(node.uri), node.title);
+    PlacesUIUtils.showMinimalAddBookmarkUI(PlacesUtils._uri(node.uri), node.title);
 }
 
 function searchHistory(aInput)
 {
   var query = PlacesUtils.history.getNewQuery();
   var options = PlacesUtils.history.getNewQueryOptions();
 
   const NHQO = Ci.nsINavHistoryQueryOptions;
--- a/browser/components/places/content/history-panel.xul
+++ b/browser/components/places/content/history-panel.xul
@@ -116,17 +116,17 @@
 
   <tree id="historyTree"
         class="sidebar-placesTree"
         flex="1"
         type="places"
         context="placesContext"
         hidecolumnpicker="true"
         onkeypress="SidebarUtils.handleTreeKeyPress(event);"
-        onclick="SidebarUtils.handleTreeClick(this, event);"
+        onclick="SidebarUtils.handleTreeClick(this, event, true);"
         onmousemove="SidebarUtils.handleTreeMouseMove(event);"
         onmouseout="SidebarUtils.clearURLFromStatusBar();">
     <treecols>
       <treecol id="title" flex="1" primary="true" hideheader="true"/>
     </treecols>
     <treechildren class="sidebar-placesTreechildren" flex="1"/>
   </tree>
 </page>
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -71,17 +71,17 @@
                                                 "popup-internal-box");
       </field>
 
       <!-- markers for start and end of valid places items -->
       <field name="_startMarker">-1</field>
       <field name="_endMarker">-1</field>
 
       <!-- This is the view that manage the popup -->
-      <field name="_rootView">PlacesUtils.getViewForNode(this);</field>
+      <field name="_rootView">PlacesUIUtils.getViewForNode(this);</field>
 
       <field name="_built">false</field>
 
       <method name="onDragOver">
         <parameter name="aEvent"/>
         <parameter name="aFlavour"/>
         <parameter name="aDragSession"/>
         <body><![CDATA[
@@ -212,17 +212,17 @@
           PlacesControllerDragHelper.onDrop(dropPoint.ip);
         ]]></body>
       </method>
 
       <!-- This returns the FavourSet accepted by this popup -->
       <method name="getSupportedFlavours">
         <body><![CDATA[
           var flavourSet = new FlavourSet();
-          var acceptedDropFlavours = PlacesUtils.GENERIC_VIEW_DROP_TYPES;
+          var acceptedDropFlavours = PlacesUIUtils.GENERIC_VIEW_DROP_TYPES;
           acceptedDropFlavours.forEach(flavourSet.appendFlavour, flavourSet);
           return flavourSet;
         ]]></body>
       </method>
 
       <!-- Check if we should hide the drop indicator for the target -->
       <method name="_hideDropIndicator">
         <parameter name="aEvent"/>
@@ -310,22 +310,18 @@
             dropPoint.ip = new InsertionPoint(resultNode.itemId, -1, 1);
             dropPoint.beforeIndex = -1;
             return dropPoint;
         ]]></body>
       </method>
 
       <method name="canDrop">
         <body><![CDATA[
-          // Can't drop if the menu isn't a folder
-          var resultNode = this._rootView.getResultNode();
-          if (!PlacesUtils.nodeIsFolder(resultNode))
-            return false;
-
-          return PlacesControllerDragHelper.canDrop();
+          var ip = this._rootView.insertionPoint;
+          return ip && PlacesControllerDragHelper.canDrop(ip);
         ]]></body>
       </method>
 
       <!-- Sub-menus should be opened when the mouse drags over them, and closed
            when the mouse drags off.  The overFolder object manages opening and
            closing of folders when the mouse hovers. -->
       <field name="_overFolder"><![CDATA[({
         _self: this,
@@ -575,17 +571,17 @@
       </method>
 
       <method name="insertNewItem">
         <parameter name="aChild"/>
         <parameter name="aParentPopup"/>
         <parameter name="aBefore"/>
         <body><![CDATA[
           var element =
-            PlacesUtils.createMenuItemForNode(aChild, this._containerNodesMap);
+            PlacesUIUtils.createMenuItemForNode(aChild, this._containerNodesMap);
 
           if (aBefore)
             aParentPopup.insertBefore(element, aBefore);
           else {
             // Add the new element to the menu.  If there is static content at
             // the end of the menu, add the element before that.  Otherwise,
             // just add to the end.
             if (aParentPopup._endMarker != -1)
@@ -600,28 +596,28 @@
       <method name="_showEmptyMenuItem">
         <parameter name="aPopup"/>
         <body><![CDATA[
           if (aPopup._emptyMenuItem) {
             aPopup._emptyMenuItem.hidden = false;
             return;
           }
 
-          var label = PlacesUtils.getString("bookmarksMenuEmptyFolder");
+          var label = PlacesUIUtils.getString("bookmarksMenuEmptyFolder");
           aPopup._emptyMenuItem = document.createElement("menuitem");
           aPopup._emptyMenuItem.setAttribute("label", label);
           aPopup._emptyMenuItem.setAttribute("disabled", true);
           aPopup.appendChild(aPopup._emptyMenuItem);
         ]]></body>
       </method>
 
       <method name="_rebuild">
         <parameter name="aPopup"/>
         <body><![CDATA[
-          PlacesUtils.cleanPlacesPopup(aPopup);
+          PlacesUIUtils.cleanPlacesPopup(aPopup);
 
           var cc = aPopup._resultNode.childCount;
           if (cc > 0) {
             if (aPopup._emptyMenuItem)
               aPopup._emptyMenuItem.hidden = true;
 
             for (var i = 0; i < cc; ++i) {
               var child = aPopup._resultNode.getChild(i);
@@ -751,17 +747,17 @@
           if (iconURI) {
             var spec = iconURI.spec;
             if (menuitem.getAttribute("image") != spec)
               menuitem.setAttribute("image", spec);
           }
           else
             menuitem.removeAttribute("image");
 
-          var title = PlacesUtils.getBestTitle(aNode);
+          var title = PlacesUIUtils.getBestTitle(aNode);
           if (menuitem.getAttribute("label") != title)
             menuitem.setAttribute("label", title);
 
           if (!menuitem.hasAttribute("livemark") &&
               PlacesUtils.nodeIsLivemarkContainer(aNode))
             menuitem.setAttribute("livemark", "true");
         },
 
@@ -948,23 +944,28 @@
               window.content.focus();
           ]]>
         </body>
       </method>
     </implementation>
     <handlers>
       <handler event="popupshowing" phase="capturing"><![CDATA[
         this._ensureInitialized();
-        if (event.target._resultNode)
-          this.onPopupShowing(event);
+        var popup = event.target;
+        // Avoid handling popupshowing of inner views
+        if (!popup._resultNode || PlacesUIUtils.getViewForNode(popup) != this)
+          return;
+
+        this.onPopupShowing(event);
       ]]></handler>
 
       <handler event="popuphidden"><![CDATA[
         var popup = event.target;
-        if (!popup._resultNode)
+        // We should avoid to handle events of inner views
+        if (!popup._resultNode || PlacesUIUtils.getViewForNode(popup) != this)
           return;
 
         // UI performance: folder queries are cheap, keep the resultnode open
         // so we don't rebuild its contents whenever the popup is reopened.
         if (!PlacesUtils.nodeIsFolder(popup._resultNode))
           popup._resultNode.containerOpen = false;
 
         // The autoopened attribute is set for folders which have been
--- a/browser/components/places/content/moveBookmarks.js
+++ b/browser/components/places/content/moveBookmarks.js
@@ -47,38 +47,38 @@ var gMoveBookmarksDialog = {
     return this._foldersTree;
   },
 
   init: function() {
     this._nodes = window.arguments[0];
 
     this.foldersTree.place =
       "place:excludeItems=1&excludeQueries=1&excludeReadOnlyFolders=1&folder=" +
-      PlacesUtils.allBookmarksFolderId;
+      PlacesUIUtils.allBookmarksFolderId;
   },
 
   onOK: function MBD_onOK(aEvent) {
     var selectedNode = this.foldersTree.selectedNode;
     NS_ASSERT(selectedNode,
               "selectedNode must be set in a single-selection tree with initial selection set");
     var selectedFolderID = PlacesUtils.getConcreteItemId(selectedNode);
 
     var transactions = [];
     for (var i=0; i < this._nodes.length; i++) {
       // Nothing to do if the node is already under the selected folder
       if (this._nodes[i].parent.itemId == selectedFolderID)
         continue;
 
       transactions.push(new
-        PlacesUtils.ptm.moveItem(this._nodes[i].itemId, selectedFolderID, -1));
+        PlacesUIUtils.ptm.moveItem(this._nodes[i].itemId, selectedFolderID, -1));
     }
 
     if (transactions.length != 0) {
-      var txn = PlacesUtils.ptm.aggregateTransactions("Move Items", transactions);
-      PlacesUtils.ptm.doTransaction(txn);
+      var txn = PlacesUIUtils.ptm.aggregateTransactions("Move Items", transactions);
+      PlacesUIUtils.ptm.doTransaction(txn);
     }
   },
 
   newFolder: function MBD_newFolder() {
     // The command is disabled when the tree is not focused
     this.foldersTree.focus();
     goDoCommand("placesCmd_new:folder");
   }
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -38,22 +38,22 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 var PlacesOrganizer = {
   _places: null,
   _content: null,
 
   _initFolderTree: function() {
-    var leftPaneRoot = PlacesUtils.leftPaneFolderId;
+    var leftPaneRoot = PlacesUIUtils.leftPaneFolderId;
     this._places.place = "place:excludeItems=1&expandQueries=0&folder=" + leftPaneRoot;
   },
 
   selectLeftPaneQuery: function PO_selectLeftPaneQuery(aQueryName) {
-    var itemId = PlacesUtils.leftPaneQueries[aQueryName];
+    var itemId = PlacesUIUtils.leftPaneQueries[aQueryName];
     this._places.selectItems([itemId]);
     // Forcefully expand all-bookmarks
     if (aQueryName == "AllBookmarks")
       asContainer(this._places.selectedNode).containerOpen = true;
   },
 
   init: function PO_init() {
     this._places = document.getElementById("placesList");
@@ -220,17 +220,17 @@ var PlacesOrganizer = {
       var searchFilter = document.getElementById("searchFilter");
       searchFilter.reset();
     }
 
     // Update the "Find in <current collection>" command and the gray text in
     // the search box in the toolbar if the active collection is the current
     // collection.
     var findCommand = document.getElementById("OrganizerCommand_find:current");
-    var findLabel = PlacesUtils.getFormattedString("findInPrefix", [node.title]);
+    var findLabel = PlacesUIUtils.getFormattedString("findInPrefix", [node.title]);
     findCommand.setAttribute("label", findLabel);
     if (PlacesSearchBox.filterCollection == "collection")
       PlacesSearchBox.updateCollectionTitle(node.title);
   },
 
   /**
    * Handle clicks on the tree. If the user middle clicks on a URL, load that
    * URL according to rules. Single clicks or modified clicks do not result in
@@ -241,35 +241,35 @@ var PlacesOrganizer = {
   onTreeClick: function PO_onTreeClick(aEvent) {
     if (aEvent.target.localName != "treechildren")
       return;
 
     var currentView = aEvent.currentTarget;
     var selectedNode = currentView.selectedNode;
     if (selectedNode && aEvent.button == 1) {
       if (PlacesUtils.nodeIsURI(selectedNode))
-        PlacesUtils.openNodeWithEvent(selectedNode, aEvent);
+        PlacesUIUtils.openNodeWithEvent(selectedNode, aEvent);
       else if (PlacesUtils.nodeIsContainer(selectedNode)) {
         // The command execution function will take care of seeing the
         // selection is a folder/container and loading its contents in
         // tabs for us.
-        PlacesUtils.openContainerNodeInTabs(selectedNode);
+        PlacesUIUtils.openContainerNodeInTabs(selectedNode);
       }
     }
   },
 
   openFlatContainer: function PO_openFlatContainerFlatContainer(aContainer) {
     if (aContainer.itemId != -1)
       this._places.selectItems([aContainer.itemId]);
     else if (PlacesUtils.nodeIsQuery(aContainer))
       this._places.selectPlaceURI(aContainer.uri);
   },
 
   openSelectedNode: function PU_openSelectedNode(aEvent) {
-    PlacesUtils.openNodeWithEvent(this._content.selectedNode, aEvent);
+    PlacesUIUtils.openNodeWithEvent(this._content.selectedNode, aEvent);
   },
 
   /**
    * Returns the options associated with the query currently loaded in the
    * main places pane.
    */
   getCurrentOptions: function PO_getCurrentOptions() {
     return asQuery(this._content.getResult().root).queryOptions;
@@ -300,17 +300,17 @@ var PlacesOrganizer = {
   },
 
   /**
    * Open a file-picker and import the selected file into the bookmarks store
    */
   importFromFile: function PO_importFromFile() {
     var fp = Cc["@mozilla.org/filepicker;1"].
              createInstance(Ci.nsIFilePicker);
-    fp.init(window, PlacesUtils.getString("SelectImport"),
+    fp.init(window, PlacesUIUtils.getString("SelectImport"),
             Ci.nsIFilePicker.modeOpen);
     fp.appendFilters(Ci.nsIFilePicker.filterHTML | Ci.nsIFilePicker.filterAll);
     if (fp.show() != Ci.nsIFilePicker.returnCancel) {
       if (fp.file) {
         var importer = Cc["@mozilla.org/browser/places/import-export-service;1"].
                        getService(Ci.nsIPlacesImportExportService);
         var file = fp.file.QueryInterface(Ci.nsILocalFile);
         importer.importHTMLFromFile(file, false);
@@ -319,17 +319,17 @@ var PlacesOrganizer = {
   },
 
   /**
    * Allows simple exporting of bookmarks.
    */
   exportBookmarks: function PO_exportBookmarks() {
     var fp = Cc["@mozilla.org/filepicker;1"].
              createInstance(Ci.nsIFilePicker);
-    fp.init(window, PlacesUtils.getString("EnterExport"),
+    fp.init(window, PlacesUIUtils.getString("EnterExport"),
             Ci.nsIFilePicker.modeSave);
     fp.appendFilters(Ci.nsIFilePicker.filterHTML);
     fp.defaultString = "bookmarks.html";
     if (fp.show() != Ci.nsIFilePicker.returnCancel) {
       var exporter = Cc["@mozilla.org/browser/places/import-export-service;1"].
                      getService(Ci.nsIPlacesImportExportService);
       exporter.exportHTMLToFile(fp.file);
     }
@@ -354,34 +354,34 @@ var PlacesOrganizer = {
     if (!bookmarksBackupDir.exists())
       return; // no backup files
 
     // get list of files
     var fileList = [];
     var files = bookmarksBackupDir.directoryEntries;
     while (files.hasMoreElements()) {
       var f = files.getNext().QueryInterface(Ci.nsIFile);
-      if (!f.isHidden() && f.leafName.match(/\.html?$/))
+      if (!f.isHidden() && f.leafName.match(/^bookmarks-.+(html|json)?$/))
         fileList.push(f);
     }
 
     fileList.sort(function PO_fileList_compare(a, b) {
-        return b.lastModifiedTime - a.lastModifiedTime;
-      });
+      return b.lastModifiedTime - a.lastModifiedTime;
+    });
 
     if (fileList.length == 0)
       return;
 
     // populate menu
     for (var i = 0; i < fileList.length; i++) {
       var m = restorePopup.insertBefore
         (document.createElement("menuitem"),
          document.getElementById("restoreFromFile"));
       var dateStr = fileList[i].leafName.replace("bookmarks-", "").
-        replace(".html", "");
+        replace(/\.(html|json)$/, "");
       if (!dateStr.length)
         dateStr = fileList[i].leafName;
       m.setAttribute("label", dateStr);
       m.setAttribute("value", fileList[i].leafName);
       m.setAttribute("oncommand",
                      "PlacesOrganizer.onRestoreMenuItemClick(this);");
     }
     restorePopup.insertBefore(document.createElement("menuseparator"),
@@ -394,82 +394,82 @@ var PlacesOrganizer = {
   onRestoreMenuItemClick: function PO_onRestoreMenuItemClick(aMenuItem) {
     var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
                  getService(Ci.nsIProperties);
     var bookmarksFile = dirSvc.get("ProfD", Ci.nsIFile);
     bookmarksFile.append("bookmarkbackups");
     bookmarksFile.append(aMenuItem.getAttribute("value"));
     if (!bookmarksFile.exists())
       return;
+    this.restoreBookmarksFromFile(bookmarksFile);
+  },
 
+  /**
+   * Called when 'Choose File...' is selected from the restore menu.
+   * Prompts for a file and restores bookmarks to those in the file.
+   */
+  onRestoreBookmarksFromFile: function PO_onRestoreBookmarksFromFile() {
+    var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
+    fp.init(window, PlacesUIUtils.getString("bookmarksRestoreTitle"),
+            Ci.nsIFilePicker.modeOpen);
+
+    var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
+                 getService(Ci.nsIProperties);
+    var backupsDir = dirSvc.get("Desk", Ci.nsILocalFile);
+    fp.displayDirectory = backupsDir;
+
+    if (fp.show() != Ci.nsIFilePicker.returnCancel)
+      PlacesUtils.restoreBookmarksFromFile(fp.file);
+  },
+
+  /**
+   * Restores bookmarks from an HTML or JSON file.
+   */
+  restoreBookmarksFromFile: function PO_restoreBookmarksFromFile(aFile) {
     var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].
                   getService(Ci.nsIPromptService);
     if (!prompts.confirm(null,
-                         PlacesUtils.getString("bookmarksRestoreAlertTitle"),
-                         PlacesUtils.getString("bookmarksRestoreAlert")))
+                         PlacesUIUtils.getString("bookmarksRestoreAlertTitle"),
+                         PlacesUIUtils.getString("bookmarksRestoreAlert")))
       return;
 
-    var ieSvc = Cc["@mozilla.org/browser/places/import-export-service;1"].
-                getService(Ci.nsIPlacesImportExportService);
-    ieSvc.importHTMLFromFile(bookmarksFile, true);
+    if (aFile.leafName.match("\.json$")) {
+      // restore a JSON backup
+      PlacesUtils.restoreBookmarksFromJSONFile(aFile);
+    }
+    else {
+      var importer = Cc["@mozilla.org/browser/places/import-export-service;1"].
+                     getService(Ci.nsIPlacesImportExportService);
+      importer.importHTMLFromFile(aFile, true /* overwrite existing */);
+    }
   },
 
   /**
-   * Backup bookmarks to desktop, auto-generate a filename with a date
+   * Backup bookmarks to desktop, auto-generate a filename with a date.
+   * The file is a JSON serialization of bookmarks, tags and any annotations
+   * of those items.
    */
   backupBookmarks: function PO_backupBookmarks() {
     var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
-    fp.init(window, PlacesUtils.getString("bookmarksBackupTitle"),
+    fp.init(window, PlacesUIUtils.getString("bookmarksBackupTitle"),
             Ci.nsIFilePicker.modeSave);
-    fp.appendFilters(Ci.nsIFilePicker.filterHTML);
 
     var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
                  getService(Ci.nsIProperties);
     var backupsDir = dirSvc.get("Desk", Ci.nsILocalFile);
     fp.displayDirectory = backupsDir;
 
     // Use YYYY-MM-DD (ISO 8601) as it doesn't contain illegal characters
     // and makes the alphabetical order of multiple backup files more useful.
     var date = (new Date).toLocaleFormat("%Y-%m-%d");
     fp.defaultString = PlacesUtils.getFormattedString("bookmarksBackupFilename",
-                                                      [date]);
-
-    if (fp.show() != Ci.nsIFilePicker.returnCancel) {
-      var ieSvc = Cc["@mozilla.org/browser/places/import-export-service;1"].
-                  getService(Ci.nsIPlacesImportExportService);
-      ieSvc.exportHTMLToFile(fp.file);
-    }
-  },
+                                                        [date]);
 
-  /**
-   * Called when 'Choose File...' is selected from the Revert menupopup
-   * Prompts for a file and reverts bookmarks to those in the file
-   */
-  restoreFromFile: function PO_restoreFromFile() {
-    var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].
-                  getService(Ci.nsIPromptService);
-    if (!prompts.confirm(null, PlacesUtils.getString("bookmarksRestoreAlertTitle"),
-                         PlacesUtils.getString("bookmarksRestoreAlert")))
-      return;
-
-    var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
-    fp.init(window, PlacesUtils.getString("bookmarksRestoreTitle"),
-            Ci.nsIFilePicker.modeOpen);
-    fp.appendFilters(Ci.nsIFilePicker.filterHTML);
-
-    var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
-                 getService(Ci.nsIProperties);
-    var backupsDir = dirSvc.get("Desk", Ci.nsILocalFile);
-    fp.displayDirectory = backupsDir;
-
-    if (fp.show() != Ci.nsIFilePicker.returnCancel) {
-      var ieSvc = Cc["@mozilla.org/browser/places/import-export-service;1"].
-                  getService(Ci.nsIPlacesImportExportService);
-      ieSvc.importHTMLFromFile(fp.file, true);
-    }
+    if (fp.show() != Ci.nsIFilePicker.returnCancel)
+      PlacesUtils.backupBookmarksToFile(fp.file);
   },
 
   _paneDisabled: false,
   _setDetailsFieldsDisabledState:
   function PO__setDetailsFieldsDisabledState(aDisabled) {
     if (aDisabled) {
       document.getElementById("paneElementsBroadcaster")
               .setAttribute("disabled", "true");
@@ -562,26 +562,26 @@ var PlacesOrganizer = {
     }
     else {
       detailsDeck.selectedIndex = 0;
       var selectItemDesc = document.getElementById("selectItemDescription");
       var itemsCountLabel = document.getElementById("itemsCountText");
       var rowCount = this._content.treeBoxObject.view.rowCount;
       if (rowCount == 0) {
         selectItemDesc.hidden = true;
-        itemsCountLabel.value = PlacesUtils.getString("detailsPane.noItems");
+        itemsCountLabel.value = PlacesUIUtils.getString("detailsPane.noItems");
       }
       else {
         selectItemDesc.hidden = false;
         if (rowCount == 1)
-          itemsCountLabel.value = PlacesUtils.getString("detailsPane.oneItem");
+          itemsCountLabel.value = PlacesUIUtils.getString("detailsPane.oneItem");
         else {
           itemsCountLabel.value =
-            PlacesUtils.getFormattedString("detailsPane.multipleItems",
-                                           [rowCount]);
+            PlacesUIUtils.getFormattedString("detailsPane.multipleItems",
+                                             [rowCount]);
         }
       }
     }
 
     // Nothing to do if the pane was already disabled
     if (!this._paneDisabled) {
       gEditItemOverlay.uninitPanel();
       this._setDetailsFieldsDisabledState(true);
@@ -656,36 +656,36 @@ var PlacesOrganizer = {
                                                              options);
     var placeURI = Cc["@mozilla.org/network/io-service;1"].
                    getService(Ci.nsIIOService).
                    newURI(placeSpec, null, null);
 
     // Prompt the user for a name for the query.
     // XXX - using prompt service for now; will need to make
     // a real dialog and localize when we're sure this is the UI we want.
-    var title = PlacesUtils.getString("saveSearch.title");
-    var inputLabel = PlacesUtils.getString("saveSearch.inputLabel");
-    var defaultText = PlacesUtils.getString("saveSearch.defaultText");
+    var title = PlacesUIUtils.getString("saveSearch.title");
+    var inputLabel = PlacesUIUtils.getString("saveSearch.inputLabel");
+    var defaultText = PlacesUIUtils.getString("saveSearch.defaultText");
 
     var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].
                   getService(Ci.nsIPromptService);
     var check = {value: false};
     var input = {value: defaultText};
     var save = prompts.prompt(null, title, inputLabel, input, null, check);
 
     // Don't add the query if the user cancels or clears the seach name.
     if (!save || input.value == "")
      return;
 
     // Add the place: uri as a bookmark under the bookmarks root.
-    var txn = PlacesUtils.ptm.createItem(placeURI,
-                                         PlacesUtils.bookmarksMenuFolderId,
-                                         PlacesUtils.bookmarks.DEFAULT_INDEX,
-                                         input.value);
-    PlacesUtils.ptm.doTransaction(txn);
+    var txn = PlacesUIUtils.ptm.createItem(placeURI,
+                                           PlacesUtils.bookmarksMenuFolderId,
+                                           PlacesUtils.bookmarks.DEFAULT_INDEX,
+                                           input.value);
+    PlacesUIUtils.ptm.doTransaction(txn);
 
     // select and load the new query
     this._places.selectPlaceURI(placeSpec);
   }
 };
 
 /**
  * A set of utilities relating to search within Bookmarks and History.
@@ -788,18 +788,18 @@ var PlacesSearchBox = {
   /**
    * Updates the display with the title of the current collection.
    * @param   title
    *          The title of the current collection.
    */
   updateCollectionTitle: function PSB_updateCollectionTitle(title) {
     this.searchFilter.emptyText =
       title ?
-      PlacesUtils.getFormattedString("searchCurrentDefault", [title]) :
-      PlacesUtils.getString("searchBookmarks");
+      PlacesUIUtils.getFormattedString("searchCurrentDefault", [title]) :
+      PlacesUIUtils.getString("searchBookmarks");
   },
 
   /**
    * Gets/sets the active collection from the dropdown menu.
    */
   get filterCollection() {
     return this.searchFilter.getAttribute("collection");
   },
@@ -1347,17 +1347,17 @@ var PlacesQueryBuilder = {
       case "scopeBarHistory":
         PlacesSearchBox.filterCollection = "history";
         folders = [];
         break;
       case "scopeBarFolder":
         var selectedFolder = PlacesOrganizer._places.selectedNode.itemId;
         // note "all bookmarks" isn't the concrete parent of the top-level
         // bookmark folders
-        if (selectedFolder != PlacesUtils.allBookmarksFolderId) {
+        if (selectedFolder != PlacesUIUtils.allBookmarksFolderId) {
           PlacesSearchBox.filterCollection = "collection";
           folders.push(PlacesOrganizer._places.selectedNode.itemId);
           break;
         }
       default: // all bookmarks
         PlacesSearchBox.filterCollection = "bookmarks";
         folders.push(PlacesUtils.bookmarksMenuFolderId,
                      PlacesUtils.toolbarFolderId,
@@ -1459,18 +1459,18 @@ var ViewMenu = {
       menuitem.column = column;
       var label = column.getAttribute("label");
       if (propertyPrefix) {
         var menuitemPrefix = propertyPrefix;
         // for string properties, use "name" as the id, instead of "title"
         // see bug #386287 for details
         var columnId = column.getAttribute("anonid");
         menuitemPrefix += columnId == "title" ? "name" : columnId;
-        label = PlacesUtils.getString(menuitemPrefix + ".label");
-        var accesskey = PlacesUtils.getString(menuitemPrefix + ".accesskey");
+        label = PlacesUIUtils.getString(menuitemPrefix + ".label");
+        var accesskey = PlacesUIUtils.getString(menuitemPrefix + ".accesskey");
         menuitem.setAttribute("accesskey", accesskey);
       }
       menuitem.setAttribute("label", label);
       if (type == "radio") {
         menuitem.setAttribute("type", "radio");
         menuitem.setAttribute("name", "columns");
         // This column is the sort key. Its item is checked.
         if (column.getAttribute("sortDirection") != "") {
--- a/browser/components/places/content/places.xul
+++ b/browser/components/places/content/places.xul
@@ -104,17 +104,17 @@
              oncommand="PlacesSearchBox.findCurrent();"/>
     <command id="OrganizerCommand_export"
              oncommand="PlacesOrganizer.exportBookmarks();"/>
     <command id="OrganizerCommand_import"
              oncommand="PlacesOrganizer.importBookmarks();"/>
     <command id="OrganizerCommand_backup"
              oncommand="PlacesOrganizer.backupBookmarks();"/>
     <command id="OrganizerCommand_restoreFromFile"
-             oncommand="PlacesOrganizer.restoreFromFile();"/>
+             oncommand="PlacesOrganizer.onRestoreBookmarksFromFile();"/>
     <command id="OrganizerCommand_search:save"
              oncommand="PlacesOrganizer.saveSearch();"/>
     <command id="OrganizerCommand_search:moreCriteria"
              oncommand="PlacesQueryBuilder.addRow();"/>
     <command id="OrganizerCommand:Back"
              oncommand="PlacesOrganizer.back();"/>
     <command id="OrganizerCommand:Forward"
              oncommand="PlacesOrganizer.forward();"/>
@@ -427,30 +427,27 @@
               <toolbarbutton id="scopeBarDownloads" type="radio" group="scopeBar"
                              oncommand="PlacesQueryBuilder.onScopeSelected(this);"
                              label="&search.scopeDownloads.label;"/>
               -->
               <toolbarbutton id="scopeBarHistory" type="radio" group="scopeBar"
                              oncommand="PlacesQueryBuilder.onScopeSelected(this);"
                              label="&search.scopeHistory.label;"/>
               <spacer flex="1"/>
+              <button id="saveSearch" class="small" 
+                       label="&saveSearch.label;" accesskey="&saveSearch.accesskey;"
+                       command="OrganizerCommand_search:save"/>
               <button id="organizerScopeBarExpander"
                       class="expander-down"
                       tooltiptext="&search.scopeBarExpanderDown.tooltip;"
                       tooltiptextdown="&search.scopeBarExpanderDown.tooltip;"
                       tooltiptextup="&search.scopeBarExpanderUp.tooltip;"
                       oncommand="PlacesQueryBuilder.toggleVisibility();"/>
             </toolbar>
-#include advancedSearch.inc          
-            <hbox id="searchActions" align="center">
-              <spacer flex="1"/>
-               <button id="saveSearch" class="small" 
-                       label="&saveSearch.label;" accesskey="&saveSearch.accesskey;"
-                       command="OrganizerCommand_search:save"/>
-            </hbox>
+#include advancedSearch.inc
           </vbox>
           <vbox flex="1">
             <tree id="placeContent" class="placesTree" context="placesContext" 
                   flex="1" type="places"
                   flatList="true"
                   enableColumnDrag="true"
                   onkeypress="if (event.keyCode == KeyEvent.DOM_VK_RETURN) PlacesOrganizer.openSelectedNode(event);"
                   ondblclick="PlacesOrganizer.openSelectedNode(event);"
--- a/browser/components/places/content/placesOverlay.xul
+++ b/browser/components/places/content/placesOverlay.xul
@@ -89,17 +89,17 @@
              oncommand="goDoCommand('placesCmd_reloadMicrosummary');"/>
     <command id="placesCmd_sortBy:name"
              oncommand="goDoCommand('placesCmd_sortBy:name');"/>
     <command id="placesCmd_moveBookmarks"
              oncommand="goDoCommand('placesCmd_moveBookmarks');"/>
   </commandset>
 
   <popup id="placesContext"
-         onpopupshowing="this._view = PlacesUtils.getViewForNode(document.popupNode);
+         onpopupshowing="this._view = PlacesUIUtils.getViewForNode(document.popupNode);
                          return this._view.buildContextMenu(this);"
          onpopuphiding="this._view.destroyContextMenu();">
     <menuitem id="placesContext_open"
               command="placesCmd_open"
               label="&cmd.open.label;"
               accesskey="&cmd.open.accesskey;"
               default="true"
               selectiontype="single"
@@ -112,25 +112,25 @@
               selection="link"/>
     <menuitem id="placesContext_open:newtab"
               command="placesCmd_open:tab"
               label="&cmd.open_tab.label;"
               accesskey="&cmd.open_tab.accesskey;"
               selectiontype="single"
               selection="link"/>
     <menuitem id="placesContext_openContainer:tabs"
-              oncommand="var view = PlacesUtils.getViewForNode(document.popupNode);
+              oncommand="var view = PlacesUIUtils.getViewForNode(document.popupNode);
                          view.controller.openSelectionInTabs(event);"
               onclick="checkForMiddleClick(this, event);"
               label="&cmd.open_all_in_tabs.label;"
               accesskey="&cmd.open_all_in_tabs.accesskey;"
               selectiontype="single"
               selection="folder|host|query"/>
     <menuitem id="placesContext_openLinks:tabs"
-              oncommand="var view = PlacesUtils.getViewForNode(document.popupNode);
+              oncommand="var view = PlacesUIUtils.getViewForNode(document.popupNode);
                          view.controller.openSelectionInTabs(event);"
               onclick="checkForMiddleClick(this, event);"
               label="&cmd.open_all_in_tabs.label;"
               accesskey="&cmd.open_all_in_tabs.accesskey;"
               selectiontype="multiple"
               selection="link"/>
     <menuseparator id="placesContext_openSeparator"/>
     <menuitem id="placesContext_new:bookmark"
--- a/browser/components/places/content/sidebarUtils.js
+++ b/browser/components/places/content/sidebarUtils.js
@@ -16,16 +16,17 @@
 #
 # The Initial Developer of the Original Code is
 # Netscape Communications Corporation.
 # Portions created by the Initial Developer are Copyright (C) 1998
 # the Initial Developer. All Rights Reserved.
 #
 # Contributor(s):
 #   Dan Mills <thunder@mozilla.com> (Ported from history-panel.js)
+#   Marco Bonardo <mak77@supereva.it>
 #
 # 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
@@ -33,52 +34,69 @@
 # 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 *****
 
 var SidebarUtils = {
   handleTreeClick: function SU_handleTreeClick(aTree, aEvent, aGutterSelect) {
+    // right-clicks are not handled here
+    if (aEvent.button == 2)
+      return;
+
     var tbo = aTree.treeBoxObject;
-
     var row = { }, col = { }, obj = { };
     tbo.getCellAt(aEvent.clientX, aEvent.clientY, row, col, obj);
 
     if (row.value == -1 || obj.value == "twisty")
       return;
 
     var mouseInGutter = false;
     if (aGutterSelect) {
       var x = { }, y = { }, w = { }, h = { };
       tbo.getCoordsForCellItem(row.value, col.value, "image",
                                x, y, w, h);
       mouseInGutter = aEvent.clientX < x.value;
     }
-    
-    var modifKey = aEvent.shiftKey || aEvent.ctrlKey || aEvent.altKey || 
-                   aEvent.metaKey  || (aEvent.button != 0);
-    if (!modifKey && tbo.view.isContainer(row.value)) {
+
+#ifdef XP_MACOSX
+    var modifKey = aEvent.metaKey || aEvent.shiftKey;
+#else
+    var modifKey = aEvent.ctrlKey || aEvent.shiftKey;
+#endif
+
+    var isContainer = tbo.view.isContainer(row.value);
+    var openInTabs = isContainer &&
+                     (aEvent.button == 1 ||
+                      (aEvent.button == 0 && modifKey)) &&
+                     PlacesUtils.hasChildURIs(tbo.view.nodeForTreeIndex(row.value));
+
+    if (aEvent.button == 0 && isContainer && !openInTabs) {
       tbo.view.toggleOpenState(row.value);
       return;
     }
-    if (!mouseInGutter && 
-        aEvent.originalTarget.localName == "treechildren" && 
-        (aEvent.button == 0 || aEvent.button == 1)) {
+    else if (!mouseInGutter && openInTabs &&
+            aEvent.originalTarget.localName == "treechildren") {
+      tbo.view.selection.select(row.value);
+      PlacesUIUtils.openContainerNodeInTabs(aTree.selectedNode, aEvent);
+    }
+    else if (!mouseInGutter && !isContainer &&
+             aEvent.originalTarget.localName == "treechildren") {
       // Clear all other selection since we're loading a link now. We must
       // do this *before* attempting to load the link since openURL uses
-      // selection as an indication of which link to load. 
+      // selection as an indication of which link to load.
       tbo.view.selection.select(row.value);
-      PlacesUtils.openNodeWithEvent(aTree.selectedNode, aEvent);
+      PlacesUIUtils.openNodeWithEvent(aTree.selectedNode, aEvent);
     }
   },
 
   handleTreeKeyPress: function SU_handleTreeKeyPress(aEvent) {
     if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN)
-      PlacesUtils.openNodeWithEvent(aEvent.target.selectedNode, aEvent);
+      PlacesUIUtils.openNodeWithEvent(aEvent.target.selectedNode, aEvent);
   },
 
   /**
    * The following function displays the URL of a node that is being
    * hovered over.
    */
   handleTreeMouseMove: function SU_handleTreeMouseMove(aEvent) {
     if (aEvent.target.localName != "treechildren")
--- a/browser/components/places/content/toolbar.xml
+++ b/browser/components/places/content/toolbar.xml
@@ -553,17 +553,17 @@
 
             var children = popup.childNodes;
             for (var i = 0; i < children.length; i++) {
               if (children[i].node == aNode) {
                 element = children[i];
                 break;
               }
             }
-            var title = PlacesUtils.getBestTitle(aNode);
+            var title = PlacesUIUtils.getBestTitle(aNode);
           }
 
           if (PlacesUtils.nodeIsSeparator(aNode)) {
             // nothing to do when a separator changes
             return;
           }
 
           var iconURI = aNode.icon;
@@ -746,17 +746,16 @@
 
           var dropPoint = { ip: null, beforeIndex: null, folderNode: null };
           // Loop through all the nodes to see which one this should
           // get dropped in/next to
           for (var i = 0; i < this._self.childNodes.length; i++) {
             var xulNode = this._self.childNodes[i];
             if (PlacesUtils.nodeIsFolder(xulNode.node) &&
                 !PlacesUtils.nodeIsReadOnly(xulNode.node)) {
-              NS_ASSERT(xulNode.getAttribute("type") == "menu");
               // This is a folder. If the mouse is in the left 25% of the
               // node, drop to the left of the folder.  If it's in the middle
               // 50%, drop into the folder.  If it's past that, drop to the right.
               if (event.clientX < xulNode.boxObject.x + (xulNode.boxObject.width * 0.25)) {
                 // Drop to the left of this folder.
                 dropPoint.ip =
                   new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
                                      i, -1);
@@ -774,27 +773,27 @@
               }
             }
             else {
               // This is a non-folder node. If the mouse is left of the middle,
               // drop to the left of the folder.  If it's right, drop to the right.
               if (event.clientX < xulNode.boxObject.x + (xulNode.boxObject.width / 2)) {
                 // Drop to the left of this bookmark.
                 dropPoint.ip =
-	        new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
-	                           i, -1);
+	                new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
+	                                   i, -1);
                 dropPoint.beforeIndex = i;
                 return dropPoint;
               }
             }
           }
           // Should drop to the right of the last node.
           dropPoint.ip =
-	  new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
-	                     -1, 1);
+        	  new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
+	                             -1, 1);
           dropPoint.beforeIndex = -1;
           return dropPoint;
         },
         
         onDragStart: function TBV_DO_onDragStart(event, xferData, dragAction) {
           // sub menus have their own d&d handlers
           if (event.target.parentNode != this._self)
             return false;
@@ -821,17 +820,18 @@
           this._self.focus();
           xferData.data = this._self._controller.getTransferData(dragAction.action);
 #ifdef XP_WIN
           return true;
 #endif
         },
 
         canDrop: function TBV_DO_canDrop(event, session) {
-          return PlacesControllerDragHelper.canDrop();
+          var ip = this._self.insertionPoint;
+          return ip && PlacesControllerDragHelper.canDrop(ip);
         },
 
         onDragOver: function TBV_DO_onDragOver(event, flavor, session) {
           PlacesControllerDragHelper.currentDropTarget = event.target;
           var dropPoint = this._getDropPoint(event);
 
           var ib = this._self._dropIndicatorBar;
           if (this._ibTimer) {
@@ -904,17 +904,17 @@
           // Close any folder being hovered over
           if (this._overFolder.node)
             this._overFolder.closeTimer = this._setTimer(this._overFolder.hoverTime);
           PlacesControllerDragHelper.currentDropTarget = null;
         },
 
         getSupportedFlavours: function TBV_DO_getSupportedFlavours() {
           var flavorSet = new FlavourSet();
-          var types = PlacesUtils.GENERIC_VIEW_DROP_TYPES;
+          var types = PlacesUIUtils.GENERIC_VIEW_DROP_TYPES;
           for (var i = 0; i < types.length; ++i)
             flavorSet.appendFlavour(types[i]);
           return flavorSet;
         }
       })]]></field>
 
       <method name="checkForMenuEvent">
         <parameter name="event"/>
@@ -963,31 +963,31 @@
       <method name="_showEmptyMenuItem">
         <parameter name="aPopup"/>
         <body><![CDATA[
           if (aPopup._emptyMenuItem) {
             aPopup._emptyMenuItem.hidden = false;
             return;
           }
 
-          var label = PlacesUtils.getString("bookmarksMenuEmptyFolder");
+          var label = PlacesUIUtils.getString("bookmarksMenuEmptyFolder");
           aPopup._emptyMenuItem = document.createElement("menuitem");
           aPopup._emptyMenuItem.setAttribute("label", label);
           aPopup._emptyMenuItem.setAttribute("disabled", true);
           aPopup.appendChild(aPopup._emptyMenuItem);
         ]]></body>
       </method>
 
       <method name="insertNewItemToPopup">
         <parameter name="aChild"/>
         <parameter name="aParentPopup"/>
         <parameter name="aBefore"/>
         <body><![CDATA[
           var element =
-            PlacesUtils.createMenuItemForNode(aChild, this._containerNodesMap);
+            PlacesUIUtils.createMenuItemForNode(aChild, this._containerNodesMap);
 
           if (aBefore)
             aParentPopup.insertBefore(element, aBefore);
           else {
             // Add the new element to the menu.  If there is static content at
             // the end of the menu, add the element before that.  Otherwise,
             // just add to the end.
             if (aParentPopup._endMarker != -1) {
@@ -1001,17 +1001,17 @@
       </method>
 
       <method name="_containerPopupShowing">
         <parameter name="aPopup"/>
         <body><![CDATA[
           if (aPopup._built)
             return;
 
-          PlacesUtils.cleanPlacesPopup(aPopup);
+          PlacesUIUtils.cleanPlacesPopup(aPopup);
 
           var resultNode = aPopup._resultNode;
           if (!resultNode.containerOpen)
             resultNode.containerOpen = true;
 
           var cc = resultNode.childCount;
           if (cc > 0) {
             if (aPopup._emptyMenuItem)
@@ -1026,33 +1026,16 @@
             // This menu is empty.  If there is no static content, add
             // an element to show it is empty.
             if (aPopup._startMarker == -1 && aPopup._endMarker == -1)
               this._showEmptyMenuItem(aPopup);
           }
           aPopup._built = true;
         ]]></body>
       </method>
-
-      <method name="_isChevronChild">
-        <parameter name="aChild"/>
-        <body><![CDATA[
-          if (!this._chevron.firstChild.hasAttribute("type"))
-            return false;
-
-          var parent = aChild.parentNode;
-          while (parent != this) {
-            if (parent == this._chevron)
-              return true;
-
-            parent = parent.parentNode;
-          }
-          return false;
-        ]]></body>
-      </method>
     </implementation>
 
     <handlers>
       <handler event="mouseover"><![CDATA[
         var button = event.target;
         if (button.parentNode == this && button.node &&
             PlacesUtils.nodeIsURI(button.node))
           window.XULBrowserWindow.setOverLink(event.target.node.uri, null);
@@ -1073,46 +1056,40 @@
         if (!this.checkForMenuEvent(event, "drop"))
           nsDragAndDrop.drop(event, this._DNDObserver);
       ]]></handler>
       <handler event="dragexit"><![CDATA[
         if (!this.checkForMenuEvent(event, "dragExit"))
           nsDragAndDrop.dragExit(event, this._DNDObserver);
       ]]></handler>
       <handler event="popupshowing" phase="capturing"><![CDATA[
-        var target = event.originalTarget;
-
-        // the chevron has its own view
-        if (this._isChevronChild(target))
-          return;
+        var popup = event.originalTarget;
 
-        if (target._resultNode)
-          this._containerPopupShowing(target);
+        // Avoid handling popupshowing of inner views
+        if (popup._resultNode && PlacesUIUtils.getViewForNode(popup) == this)
+          this._containerPopupShowing(popup);
 
-        var targetParent = target.parentNode;
-        if (targetParent.localName == "toolbarbutton" &&
+        var parent = popup.parentNode;
+        if (parent.localName == "toolbarbutton" &&
             !PlacesControllerDragHelper.getSession())
-          this._openedMenuButton = targetParent;
+          this._openedMenuButton = parent;
       ]]></handler>
       <handler event="popuphidden"><![CDATA[
-        var target = event.originalTarget;
-        if (!target._resultNode)
-          return;
-
-        // the chevron has its own view
-        if (this._isChevronChild(target))
-          return;
+        var popup = event.originalTarget;
 
-        // UI performance: folder queries are cheap, keep the resultnode open
-        // so we don't rebuild its contents whenever the popup is reopened.
-        if (!PlacesUtils.nodeIsFolder(target._resultNode))
-          target._resultNode.containerOpen = false;
+        // Avoid handling popupshowing of inner views
+        if (popup._resultNode && PlacesUIUtils.getViewForNode(popup) == this) {
+          // UI performance: folder queries are cheap, keep the resultnode open
+          // so we don't rebuild its contents whenever the popup is reopened.
+          if (!PlacesUtils.nodeIsFolder(popup._resultNode))
+            popup._resultNode.containerOpen = false;
+        }
 
-        var targetParent = target.parentNode;
-        if (targetParent.localName == "toolbarbutton" &&
+        var parent = popup.parentNode;
+        if (parent.localName == "toolbarbutton" &&
             !PlacesControllerDragHelper.getSession())
           this._openedMenuButton = null;
       ]]></handler>
 
       <handler event="mousemove"><![CDATA[
         if (this._openedMenuButton == null || PlacesControllerDragHelper.getSession())
           return;
 
--- a/browser/components/places/content/tree.xml
+++ b/browser/components/places/content/tree.xml
@@ -510,20 +510,16 @@
           if (index != -1) {
             var lastSelected = resultview.nodeForTreeIndex(index);
             if (resultview.isContainer(index) && orientation == Ci.nsITreeView.DROP_ON) {
               // If the last selected item is an open container, append _into_
               // it, rather than insert adjacent to it. 
               container = lastSelected;
               index = -1;
             }
-            else if (resultview.isSorted()) {
-              // If we are into a sorted view we should append at the end
-              index = -1;
-            }
             else if (!this._disallowInsertion(lastSelected) &&
                      lastSelected.containerOpen &&
                      orientation == Ci.nsITreeView.DROP_AFTER) {
              // If the last selected item is an open container and the user is
              // trying to drag into it as a first item, really insert into it.
              container = lastSelected;
              orientation = Ci.nsITreeView.DROP_BEFORE;
              index = 0;
@@ -534,18 +530,28 @@
               // insertion point.
               container = lastSelected.parent || container;
 
               // avoid the potentially expensive call to getIndexOfNode() 
               // if we know this container doesn't allow insertion
               if (this._disallowInsertion(container))
                 return null;
 
-              var lsi = PlacesUtils.getIndexOfNode(lastSelected);
-              index = orientation == Ci.nsITreeView.DROP_BEFORE ? lsi : lsi + 1;
+              var queryOptions = asQuery(result.root).queryOptions;
+              if (queryOptions.excludeItems || queryOptions.excludeQueries ||
+                  queryOptions.excludeReadOnlyFolders ||
+                  queryOptions.sortingMode != Ci.nsINavHistoryQueryOptions.SORT_BY_NONE) {
+                // If we are within either a sorted view or a view in which
+                // some items may be invisible, insert at the end
+                index = -1;   
+              }
+              else {
+                var lsi = PlacesUtils.getIndexOfNode(lastSelected);
+                index = orientation == Ci.nsITreeView.DROP_BEFORE ? lsi : lsi + 1;
+              }
             }
           }
 
           if (this._disallowInsertion(container))
             return null;
 
           return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
                                     index, orientation);
@@ -706,17 +712,17 @@
           }
         ]]></body>
       </method>
 
       <!-- nsDragAndDrop -->
       <method name="getSupportedFlavours">
         <body><![CDATA[
           var flavorSet = new FlavourSet();
-          var types = PlacesUtils.GENERIC_VIEW_DROP_TYPES;
+          var types = PlacesUIUtils.GENERIC_VIEW_DROP_TYPES;
           for (var i = 0; i < types.length; ++i)
             flavorSet.appendFlavour(types[i]);
           return flavorSet;
         ]]></body>
       </method>
 
       <method name="buildContextMenu">
         <parameter name="aPopup"/>
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -187,18 +187,18 @@ PlacesTreeView.prototype = {
    * It is used to compute each node's viewIndex.
    */
   _buildVisibleSection:
   function PTV__buildVisibleSection(aContainer, aVisible, aToOpen, aVisibleStartIndex)
   {
     if (!aContainer.containerOpen)
       return;  // nothing to do
 
-    const openLiteral = PlacesUtils.RDF.GetResource("http://home.netscape.com/NC-rdf#open");
-    const trueLiteral = PlacesUtils.RDF.GetLiteral("true");
+    const openLiteral = PlacesUIUtils.RDF.GetResource("http://home.netscape.com/NC-rdf#open");
+    const trueLiteral = PlacesUIUtils.RDF.GetLiteral("true");
 
     var cc = aContainer.childCount;
     for (var i=0; i < cc; i++) {
       var curChild = aContainer.getChild(i);
       var curChildType = curChild.type;
 
       // don't display separators when sorted
       if (curChildType == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR) {
@@ -214,18 +214,18 @@ PlacesTreeView.prototype = {
       aVisible.push({ node: curChild, properties: null });
 
       // recursively do containers
       if (!this._flatList && PlacesUtils.containerTypes.indexOf(curChildType) != -1) {
         asContainer(curChild);
 
         var resource = this._getResourceForNode(curChild);
         var isopen = resource != null &&
-                     PlacesUtils.localStore.HasAssertion(resource, openLiteral,
-                                                         trueLiteral, true);
+                     PlacesUIUtils.localStore.HasAssertion(resource, openLiteral,
+                                                           trueLiteral, true);
         if (isopen != curChild.containerOpen)
           aToOpen.push(curChild);
         else if (curChild.containerOpen && curChild.childCount > 0)
           this._buildVisibleSection(curChild, aVisible, aToOpen, aVisibleStartIndex);
       }
     }
   },
 
@@ -829,17 +829,17 @@ PlacesTreeView.prototype = {
               "Node's visible index and array out of sync");
     return viewIndex;
   },
 
   _getResourceForNode: function PTV_getResourceForNode(aNode)
   {
     var uri = aNode.uri;
     NS_ASSERT(uri, "if there is no uri, we can't persist the open state");
-    return uri ? PlacesUtils.RDF.GetResource(uri) : null;
+    return uri ? PlacesUIUtils.RDF.GetResource(uri) : null;
   },
 
   // nsITreeView
   get rowCount() {
     return this._visibleElements.length;
   },
 
   get selection() {
@@ -981,17 +981,19 @@ PlacesTreeView.prototype = {
       var dragSession = dragService.getCurrentSession();
       var elt = dragSession.sourceNode.parentNode;
       if (elt.localName == "tree" && elt.view == this &&
           this.selection.isSelected(aRow))
         return false;
       if (node.parent && PlacesUtils.nodeIsReadOnly(node.parent))
         return false;
     }
-    return PlacesControllerDragHelper.canDrop();
+  
+    var ip = this._getInsertionPoint(aRow, aOrientation);
+    return ip && PlacesControllerDragHelper.canDrop(ip);
   },
 
   // XXXmano: these two are copied over from tree.xml, to fix this we need to
   // either add a helper to PlacesUtils or keep it here and add insertionPoint
   // to the view interface.
   _disallowInsertion: function PTV__disallowInsertion(aContainer) {
     // Disallow insertion of items under readonly folders
     return (!PlacesUtils.nodeIsFolder(aContainer) ||
@@ -1126,17 +1128,17 @@ PlacesTreeView.prototype = {
     switch (columnType) {
       case this.COLUMN_TYPE_TITLE:
         // normally, this is just the title, but we don't want empty items in
         // the tree view so return a special string if the title is empty.
         // Do it here so that callers can still get at the 0 length title
         // if they go through the "result" API.
         if (PlacesUtils.nodeIsSeparator(node))
           return "";
-        return PlacesUtils.getBestTitle(node);
+        return PlacesUIUtils.getBestTitle(node);
       case this.COLUMN_TYPE_TAGS:
         return node.tags;
       case this.COLUMN_TYPE_URI:
         if (PlacesUtils.nodeIsURI(node))
           return node.uri;
         return "";
       case this.COLUMN_TYPE_DATE:
         if (node.time == 0 || !PlacesUtils.nodeIsURI(node)) {
@@ -1200,23 +1202,23 @@ PlacesTreeView.prototype = {
 
     if (this._flatList && this._openContainerCallback) {
       this._openContainerCallback(node);
       return;
     }
 
     var resource = this._getResourceForNode(node);
     if (resource) {
-      const openLiteral = PlacesUtils.RDF.GetResource("http://home.netscape.com/NC-rdf#open");
-      const trueLiteral = PlacesUtils.RDF.GetLiteral("true");
+      const openLiteral = PlacesUIUtils.RDF.GetResource("http://home.netscape.com/NC-rdf#open");
+      const trueLiteral = PlacesUIUtils.RDF.GetLiteral("true");
 
       if (node.containerOpen)
-        PlacesUtils.localStore.Unassert(resource, openLiteral, trueLiteral);
+        PlacesUIUtils.localStore.Unassert(resource, openLiteral, trueLiteral);
       else
-        PlacesUtils.localStore.Assert(resource, openLiteral, trueLiteral, true);
+        PlacesUIUtils.localStore.Assert(resource, openLiteral, trueLiteral, true);
     }
 
     node.containerOpen = !node.containerOpen;
   },
 
   cycleHeader: function PTV_cycleHeader(aColumn) {
     if (!this._result)
       throw Cr.NS_ERROR_UNEXPECTED;
@@ -1337,21 +1339,43 @@ PlacesTreeView.prototype = {
         break;
       default:
         throw Cr.NS_ERROR_INVALID_ARG;
     }
     this._result.sortingAnnotation = newSortingAnnotation;
     this._result.sortingMode = newSort;
   },
 
+  isEditable: function PTV_isEditable(aRow, aColumn) {
+    // At this point we only support editing the title field.
+    if (aColumn.index != 0)
+      return false;
+
+    var node = this.nodeForTreeIndex(aRow);
+    if (!PlacesUtils.nodeIsReadOnly(node) &&
+        (PlacesUtils.nodeIsFolder(node) ||
+         (PlacesUtils.nodeIsBookmark(node) &&
+          !PlacesUtils.nodeIsLivemarkItem(node))))
+      return true;
+
+    return false;
+  },
+
+  setCellText: function PTV_setCellText(aRow, aColumn, aText) {
+    // we may only get here if the cell is editable
+    var node = this.nodeForTreeIndex(aRow);
+    if (node.title != aText) {
+      var txn = PlacesUIUtils.ptm.editItemTitle(node.itemId, aText);
+      PlacesUIUtils.ptm.doTransaction(txn);
+    }
+  },
+
   selectionChanged: function() { },
   cycleCell: function PTV_cycleCell(aRow, aColumn) { },
-  isEditable: function(aRow, aColumn) { return false; },
   isSelectable: function(aRow, aColumn) { return false; },
-  setCellText: function(aRow, aColumn) { },
   performAction: function(aAction) { },
   performActionOnRow: function(aAction, aRow) { },
   performActionOnCell: function(aAction, aRow, aColumn) { }
 };
 
 function PlacesTreeView(aShowRoot, aFlatList, aOnOpenFlatContainer) {
   if (aShowRoot && aFlatList)
     throw("Flat-list mode is not supported when show-root is set");
--- a/browser/components/places/content/utils.js
+++ b/browser/components/places/content/utils.js
@@ -18,16 +18,17 @@
  * Portions created by the Initial Developer are Copyright (C) 2005
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Ben Goodger <beng@google.com>
  *   Myk Melez <myk@mozilla.org>
  *   Asaf Romano <mano@mozilla.com>
  *   Sungjoon Steve Won <stevewon@gmail.com>
+ *   Dietrich Ayala <dietrich@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
@@ -41,133 +42,57 @@
 function LOG(str) {
   dump("*** " + str + "\n");
 }
 
 var Ci = Components.interfaces;
 var Cc = Components.classes;
 var Cr = Components.results;
 
-Components.utils.import("resource://gre/modules/JSON.jsm");
+__defineGetter__("PlacesUtils", function() {
+  delete this.PlacesUtils
+  var tmpScope = {};
+  Components.utils.import("resource://gre/modules/utils.js", tmpScope);
+  return this.PlacesUtils = tmpScope.PlacesUtils;
+});
 
 const LOAD_IN_SIDEBAR_ANNO = "bookmarkProperties/loadInSidebar";
 const DESCRIPTION_ANNO = "bookmarkProperties/description";
-const POST_DATA_ANNO = "bookmarkProperties/POSTData";
 const LMANNO_FEEDURI = "livemark/feedURI";
 const LMANNO_SITEURI = "livemark/siteURI";
 const ORGANIZER_FOLDER_ANNO = "PlacesOrganizer/OrganizerFolder";
 const ORGANIZER_QUERY_ANNO = "PlacesOrganizer/OrganizerQuery";
 
 #ifdef XP_MACOSX
 // On Mac OSX, the transferable system converts "\r\n" to "\n\n", where we
 // really just want "\n".
 const NEWLINE= "\n";
 #else
 // On other platforms, the transferable system converts "\r\n" to "\n".
 const NEWLINE = "\r\n";
 #endif
 
 function QI_node(aNode, aIID) {
-  var result = null;
-  try {
-    result = aNode.QueryInterface(aIID);
-  }
-  catch (e) {
-  }
-  NS_ASSERT(result, "Node QI Failed");
-  return result;
+  return aNode.QueryInterface(aIID);
 }
 function asVisit(aNode)    { return QI_node(aNode, Ci.nsINavHistoryVisitResultNode);    }
 function asFullVisit(aNode){ return QI_node(aNode, Ci.nsINavHistoryFullVisitResultNode);}
 function asContainer(aNode){ return QI_node(aNode, Ci.nsINavHistoryContainerResultNode);}
 function asQuery(aNode)    { return QI_node(aNode, Ci.nsINavHistoryQueryResultNode);    }
 
-var PlacesUtils = {
-  // Place entries that are containers, e.g. bookmark folders or queries.
-  TYPE_X_MOZ_PLACE_CONTAINER: "text/x-moz-place-container",
-  // Place entries that are bookmark separators.
-  TYPE_X_MOZ_PLACE_SEPARATOR: "text/x-moz-place-separator",
-  // Place entries that are not containers or separators
-  TYPE_X_MOZ_PLACE: "text/x-moz-place",
-  // Place entries in shortcut url format (url\ntitle)
-  TYPE_X_MOZ_URL: "text/x-moz-url",
-  // Place entries formatted as HTML anchors
-  TYPE_HTML: "text/html",
-  // Place entries as raw URL text
-  TYPE_UNICODE: "text/unicode",
-
-  /**
-   * The Bookmarks Service.
-   */
-  get bookmarks() {
-    delete this.bookmarks;
-    return this.bookmarks = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
-                            getService(Ci.nsINavBookmarksService);
-  },
-
-  /**
-   * The Nav History Service.
-   */
-  get history() {
-    delete this.history;
-    return this.history = Cc["@mozilla.org/browser/nav-history-service;1"].
-                          getService(Ci.nsINavHistoryService);
-  },
-
-  get globalHistory() {
-    delete this.globalHistory;
-    return this.globalHistory = Cc["@mozilla.org/browser/global-history;2"].
-                                getService(Ci.nsIBrowserHistory);
-  },
-
-  /**
-   * The Live Bookmark Service.
-   */
-  get livemarks() {
-    delete this.livemarks;
-    return this.livemarks = Cc["@mozilla.org/browser/livemark-service;2"].
-                            getService(Ci.nsILivemarkService);
-  },
-
-  /**
-   * The Annotations Service.
-   */
-  get annotations() {
-    delete this.annotations;
-    return this.annotations = Cc["@mozilla.org/browser/annotation-service;1"].
-                              getService(Ci.nsIAnnotationService);
-  },
-
-  /**
-   * The Favicons Service
-   */
-  get favicons() {
-    delete this.favicons;
-    return this.favicons = Cc["@mozilla.org/browser/favicon-service;1"].
-                           getService(Ci.nsIFaviconService);
-  },
-
+var PlacesUIUtils = {
   /**
    * The Microsummary Service
    */
   get microsummaries() {
     delete this.microsummaries;
     return this.microsummaries = Cc["@mozilla.org/microsummary/service;1"].
                                  getService(Ci.nsIMicrosummaryService);
   },
 
-  /**
-   * The Places Tagging Service
-   */
-  get tagging() {
-    delete this.tagging;
-    return this.tagging = Cc["@mozilla.org/browser/tagging-service;1"].
-                          getService(Ci.nsITaggingService);
-  },
-
   get RDF() {
     delete this.RDF;
     return this.RDF = Cc["@mozilla.org/rdf/rdf-service;1"].
                       getService(Ci.nsIRDFService);
   },
 
   get localStore() {
     delete this.localStore;
@@ -196,29 +121,16 @@ var PlacesUtils = {
     delete this.ellipsis;
     var pref = Cc["@mozilla.org/preferences-service;1"].
                getService(Ci.nsIPrefBranch);
     return this.ellipsis = pref.getComplexValue("intl.ellipsis",
                                                 Ci.nsIPrefLocalizedString).data;
   },
 
   /**
-   * Makes a URI from a spec.
-   * @param   aSpec
-   *          The string spec of the URI
-   * @returns A URI object for the spec.
-   */
-  _uri: function PU__uri(aSpec) {
-    NS_ASSERT(aSpec, "empty URL spec");
-    return Cc["@mozilla.org/network/io-service;1"].
-           getService(Ci.nsIIOService).
-           newURI(aSpec, null, null);
-  },
-
-  /**
    * Makes a URI from a spec, and do fixup
    * @param   aSpec
    *          The string spec of the URI
    * @returns A URI object for the spec.
    */
   createFixedURI: function PU_createFixedURI(aSpec) {
     return this.URIFixup.createFixupURI(aSpec, 0);
   },
@@ -252,438 +164,28 @@ var PlacesUtils = {
     return this._bundle.formatStringFromName(key, params, params.length);
   },
 
   getString: function PU_getString(key) {
     return this._bundle.GetStringFromName(key);
   },
 
   /**
-   * Determines whether or not a ResultNode is a Bookmark folder.
-   * @param   aNode
-   *          A result node
-   * @returns true if the node is a Bookmark folder, false otherwise
-   */
-  nodeIsFolder: function PU_nodeIsFolder(aNode) {
-    NS_ASSERT(aNode, "null node");
-    return (aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER ||
-            aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT);
-  },
-
-  /**
-   * Determines whether or not a ResultNode represents a bookmarked URI.
-   * @param   aNode
-   *          A result node
-   * @returns true if the node represents a bookmarked URI, false otherwise
-   */
-  nodeIsBookmark: function PU_nodeIsBookmark(aNode) {
-    NS_ASSERT(aNode, "null node");
-    return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_URI &&
-           aNode.itemId != -1;
-  },
-
-  /**
-   * Determines whether or not a ResultNode is a Bookmark separator.
-   * @param   aNode
-   *          A result node
-   * @returns true if the node is a Bookmark separator, false otherwise
-   */
-  nodeIsSeparator: function PU_nodeIsSeparator(aNode) {
-    NS_ASSERT(aNode, "null node");
-
-    return (aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR);
-  },
-
-  /**
-   * Determines whether or not a ResultNode is a visit item.
-   * @param   aNode
-   *          A result node
-   * @returns true if the node is a visit item, false otherwise
-   */
-  nodeIsVisit: function PU_nodeIsVisit(aNode) {
-    NS_ASSERT(aNode, "null node");
-
-    const NHRN = Ci.nsINavHistoryResultNode;
-    var type = aNode.type;
-    return type == NHRN.RESULT_TYPE_VISIT ||
-           type == NHRN.RESULT_TYPE_FULL_VISIT;
-  },
-
-  /**
-   * Determines whether or not a ResultNode is a URL item.
-   * @param   aNode
-   *          A result node
-   * @returns true if the node is a URL item, false otherwise
-   */
-  uriTypes: [Ci.nsINavHistoryResultNode.RESULT_TYPE_URI,
-             Ci.nsINavHistoryResultNode.RESULT_TYPE_VISIT,
-             Ci.nsINavHistoryResultNode.RESULT_TYPE_FULL_VISIT],
-  nodeIsURI: function PU_nodeIsURI(aNode) {
-    NS_ASSERT(aNode, "null node");
-    return this.uriTypes.indexOf(aNode.type) != -1;
-  },
-
-  /**
-   * Determines whether or not a ResultNode is a Query item.
-   * @param   aNode
-   *          A result node
-   * @returns true if the node is a Query item, false otherwise
-   */
-  nodeIsQuery: function PU_nodeIsQuery(aNode) {
-    NS_ASSERT(aNode, "null node");
-    return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY;
-  },
-
-  /**
-   * Determines if a node is read only (children cannot be inserted, sometimes
-   * they cannot be removed depending on the circumstance)
-   * @param   aNode
-   *          A result node
-   * @returns true if the node is readonly, false otherwise
-   */
-  nodeIsReadOnly: function PU_nodeIsReadOnly(aNode) {
-    NS_ASSERT(aNode, "null node");
-
-    if (this.nodeIsFolder(aNode))
-      return this.bookmarks.getFolderReadonly(asQuery(aNode).folderItemId);
-    if (this.nodeIsQuery(aNode))
-      return asQuery(aNode).childrenReadOnly;
-    return false;
-  },
-
-  /**
-   * Determines whether or not a ResultNode is a host container.
-   * @param   aNode
-   *          A result node
-   * @returns true if the node is a host container, false otherwise
-   */
-  nodeIsHost: function PU_nodeIsHost(aNode) {
-    NS_ASSERT(aNode, "null node");
-    return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY &&
-           aNode.parent &&
-           asQuery(aNode.parent).queryOptions.resultType ==
-             Ci.nsINavHistoryQueryOptions.RESULTS_AS_SITE_QUERY;
-  },
-
-  /**
-   * Determines whether or not a ResultNode is a day container.
-   * @param   node
-   *          A NavHistoryResultNode
-   * @returns true if the node is a day container, false otherwise
-   */
-  nodeIsDay: function PU_nodeIsDay(aNode) {
-    NS_ASSERT(aNode, "null node");
-    var resultType;
-    return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY &&
-           aNode.parent &&
-           ((resultType = asQuery(aNode.parent).queryOptions.resultType) ==
-               Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_QUERY ||
-             resultType == Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_SITE_QUERY);
-  },
-
-  /**
-   * Determines whether or not a ResultNode is a container.
-   * @param   aNode
-   *          A result node
-   * @returns true if the node is a container item, false otherwise
-   */
-  containerTypes: [Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
-                   Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT,
-                   Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY,
-                   Ci.nsINavHistoryResultNode.RESULT_TYPE_DYNAMIC_CONTAINER],
-  nodeIsContainer: function PU_nodeIsContainer(aNode) {
-    NS_ASSERT(aNode, "null node");
-    return this.containerTypes.indexOf(aNode.type) != -1;
-  },
-
-  /**
-   * Determines whether or not a result-node is a dynamic-container item.
-   * The dynamic container result node type is for dynamically created
-   * containers (e.g. for the file browser service where you get your folders
-   * in bookmark menus).
-   * @param   aNode
-   *          A result node
-   * @returns true if the node is a dynamic container item, false otherwise
-   */
-  nodeIsDynamicContainer: function PU_nodeIsDynamicContainer(aNode) {
-    NS_ASSERT(aNode, "null node");
-    if (aNode.type == NHRN.RESULT_TYPE_DYNAMIC_CONTAINER)
-      return true;
-    return false;
-  },
-
- /**
-  * Determines whether a result node is a remote container registered by the
-  * livemark service.
-  * @param aNode
-  *        A result Node
-  * @returns true if the node is a livemark container item
-  */
-  nodeIsLivemarkContainer: function PU_nodeIsLivemarkContainer(aNode) {
-    // Use the annotations service directly to avoid instantiating
-    // the Livemark service on startup. (bug 398300)
-    return this.nodeIsFolder(aNode) &&
-           this.annotations.itemHasAnnotation(aNode.itemId, LMANNO_FEEDURI);
-  },
-
- /**
-  * Determines whether a result node is a live-bookmark item
-  * @param aNode
-  *        A result node
-  * @returns true if the node is a livemark container item
-  */
-  nodeIsLivemarkItem: function PU_nodeIsLivemarkItem(aNode) {
-    return aNode.parent && this.nodeIsLivemarkContainer(aNode.parent);
-  },
-
-  /**
-   * Determines whether or not a node is a readonly folder.
-   * @param   aNode
-   *          The node to test.
-   * @returns true if the node is a readonly folder.
-  */
-  isReadonlyFolder: function(aNode) {
-    NS_ASSERT(aNode, "null node");
-
-    return this.nodeIsFolder(aNode) &&
-           this.bookmarks.getFolderReadonly(asQuery(aNode).folderItemId);
-  },
-
-  /**
-   * Gets the concrete item-id for the given node. Generally, this is just
-   * node.itemId, but for folder-shortcuts that's node.folderItemId.
-   */
-  getConcreteItemId: function PU_getConcreteItemId(aNode) {
-    if (aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT)
-      return asQuery(aNode).folderItemId;
-    return aNode.itemId;
-  },
-
-  /**
-   * Gets the index of a node within its parent container
-   * @param   aNode
-   *          The node to look up
-   * @returns The index of the node within its parent container, or -1 if the
-   *          node was not found or the node specified has no parent.
-   */
-  getIndexOfNode: function PU_getIndexOfNode(aNode) {
-    NS_ASSERT(aNode, "null node");
-
-    var parent = aNode.parent;
-    if (!parent)
-      return -1;
-    var wasOpen = parent.containerOpen;
-    var result, oldViewer;
-    if (!wasOpen) {
-      result = parent.parentResult;
-      oldViewer = result.viewer;
-      result.viewer = null;
-      parent.containerOpen = true;
-    }
-    var cc = parent.childCount;
-    for (var i = 0; i < cc && parent.getChild(i) != aNode; ++i);
-    if (!wasOpen) {
-      parent.containerOpen = false;
-      result.viewer = oldViewer;
-    }
-    return i < cc ? i : -1;
-  },
-
-  /**
-   * String-wraps a result node according to the rules of the specified
-   * content type.
-   * @param   aNode
-   *          The Result node to wrap (serialize)
-   * @param   aType
-   *          The content type to serialize as
-   * @param   [optional] aOverrideURI
-   *          Used instead of the node's URI if provided.
-   *          This is useful for wrapping a container as TYPE_X_MOZ_URL,
-   *          TYPE_HTML or TYPE_UNICODE.
-   * @returns A string serialization of the node
-   */
-  wrapNode: function PU_wrapNode(aNode, aType, aOverrideURI) {
-    var self = this;
-
-    // when wrapping a node, we want all the items, even if the original
-    // query options are excluding them.
-    // this can happen when copying from the left hand pane of the bookmarks
-    // organizer
-    function convertNode(cNode) {
-      try {
-        if (self.nodeIsFolder(cNode) && cNode.queryOptions.excludeItems)
-          return self.getFolderContents(cNode.itemId, false, true).root;
-      }
-      catch (e) {
-      }
-      return cNode;
-    }
-
-    switch (aType) {
-      case this.TYPE_X_MOZ_PLACE:
-      case this.TYPE_X_MOZ_PLACE_SEPARATOR:
-      case this.TYPE_X_MOZ_PLACE_CONTAINER:
-        function gatherDataPlace(bNode) {
-          var nodeId = 0;
-          if (bNode.itemId != -1)
-            nodeId = bNode.itemId;
-          var nodeUri = bNode.uri
-          var nodeTitle = bNode.title;
-          var nodeParentId = 0;
-          if (bNode.parent && self.nodeIsFolder(bNode.parent))
-            nodeParentId = bNode.parent.itemId;
-          var nodeIndex = self.getIndexOfNode(bNode);
-          var nodeKeyword = self.bookmarks.getKeywordForBookmark(bNode.itemId);
-          var nodeAnnos = self.getAnnotationsForItem(bNode.itemId);
-          var nodeType = "";
-          if (self.nodeIsContainer(bNode))
-            nodeType = self.TYPE_X_MOZ_PLACE_CONTAINER;
-          else if (self.nodeIsURI(bNode)) // a bookmark or a history visit
-            nodeType = self.TYPE_X_MOZ_PLACE;
-          else if (self.nodeIsSeparator(bNode))
-            nodeType = self.TYPE_X_MOZ_PLACE_SEPARATOR;
-
-          var node = { id: nodeId,
-                       uri: nodeUri,
-                       title: nodeTitle,
-                       parent: nodeParentId,
-                       index: nodeIndex,
-                       keyword: nodeKeyword,
-                       annos: nodeAnnos,
-                       type: nodeType };
-
-          // Recurse down children if the node is a folder
-          if (self.nodeIsContainer(bNode)) {
-            asContainer(bNode);
-            if (self.nodeIsLivemarkContainer(bNode)) {
-              // just save the livemark info, reinstantiate on other end
-              var feedURI = self.livemarks.getFeedURI(bNode.itemId).spec;
-              var siteURI = self.livemarks.getSiteURI(bNode.itemId).spec;
-              node.uri = { feed: feedURI,
-                           site: siteURI };
-            }
-            else { // bookmark folders + history containers
-              var wasOpen = bNode.containerOpen;
-              if (!wasOpen)
-                bNode.containerOpen = true;
-              var childNodes = [];
-              var cc = bNode.childCount;
-              for (var i = 0; i < cc; ++i) {
-                var childObj = gatherDataPlace(bNode.getChild(i));
-                if (childObj != null)
-                  childNodes.push(childObj);
-              }
-              var parent = node;
-              node = { folder: parent,
-                       children: childNodes,
-                       type: self.TYPE_X_MOZ_PLACE_CONTAINER };
-              bNode.containerOpen = wasOpen;
-            }
-          }
-          return node;
-        }
-        return JSON.toString(gatherDataPlace(convertNode(aNode)));
-
-      case this.TYPE_X_MOZ_URL:
-        function gatherDataUrl(bNode) {
-          if (self.nodeIsLivemarkContainer(bNode)) {
-            var siteURI = self.livemarks.getSiteURI(bNode.itemId).spec;
-            return siteURI + NEWLINE + bNode.title;
-          }
-          if (self.nodeIsURI(bNode))
-            return (aOverrideURI || bNode.uri) + NEWLINE + bNode.title;
-          // ignore containers and separators - items without valid URIs
-          return "";
-        }
-        return gatherDataUrl(convertNode(aNode));
-
-      case this.TYPE_HTML:
-        function gatherDataHtml(bNode) {
-          function htmlEscape(s) {
-            s = s.replace(/&/g, "&amp;");
-            s = s.replace(/>/g, "&gt;");
-            s = s.replace(/</g, "&lt;");
-            s = s.replace(/"/g, "&quot;");
-            s = s.replace(/'/g, "&apos;");
-            return s;
-          }
-          // escape out potential HTML in the title
-          var escapedTitle = htmlEscape(bNode.title);
-          if (self.nodeIsLivemarkContainer(bNode)) {
-            var siteURI = self.livemarks.getSiteURI(bNode.itemId).spec;
-            return "<A HREF=\"" + siteURI + "\">" + escapedTitle + "</A>" + NEWLINE;
-          }
-          if (self.nodeIsContainer(bNode)) {
-            asContainer(bNode);
-            var wasOpen = bNode.containerOpen;
-            if (!wasOpen)
-              bNode.containerOpen = true;
-
-            var childString = "<DL><DT>" + escapedTitle + "</DT>" + NEWLINE;
-            var cc = bNode.childCount;
-            for (var i = 0; i < cc; ++i)
-              childString += "<DD>"
-                             + NEWLINE
-                             + gatherDataHtml(bNode.getChild(i))
-                             + "</DD>"
-                             + NEWLINE;
-            bNode.containerOpen = wasOpen;
-            return childString + "</DL>" + NEWLINE;
-          }
-          if (self.nodeIsURI(bNode))
-            return "<A HREF=\"" + bNode.uri + "\">" + escapedTitle + "</A>" + NEWLINE;
-          if (self.nodeIsSeparator(bNode))
-            return "<HR>" + NEWLINE;
-          return "";
-        }
-        return gatherDataHtml(convertNode(aNode));
-    }
-    // case this.TYPE_UNICODE:
-    function gatherDataText(bNode) {
-      if (self.nodeIsLivemarkContainer(bNode))
-        return self.livemarks.getSiteURI(bNode.itemId).spec;
-      if (self.nodeIsContainer(bNode)) {
-        asContainer(bNode);
-        var wasOpen = bNode.containerOpen;
-        if (!wasOpen)
-          bNode.containerOpen = true;
-
-        var childString = bNode.title + NEWLINE;
-        var cc = bNode.childCount;
-        for (var i = 0; i < cc; ++i) {
-          var child = bNode.getChild(i);
-          var suffix = i < (cc - 1) ? NEWLINE : "";
-          childString += gatherDataText(child) + suffix;
-        }
-        bNode.containerOpen = wasOpen;
-        return childString;
-      }
-      if (self.nodeIsURI(bNode))
-        return (aOverrideURI || bNode.uri);
-      if (self.nodeIsSeparator(bNode))
-        return "--------------------";
-      return "";
-    }
-
-    return gatherDataText(convertNode(aNode));
-  },
-
-  /**
    * Get a transaction for copying a uri item from one container to another
    * as a bookmark.
    * @param   aURI
    *          The URI of the item being copied
    * @param   aContainer
    *          The container being copied into
    * @param   aIndex
    *          The index within the container the item is copied to
    * @returns A nsITransaction object that performs the copy.
    */
   _getURIItemCopyTransaction: function (aData, aContainer, aIndex) {
-    return this.ptm.createItem(this._uri(aData.uri), aContainer, aIndex,
+    return this.ptm.createItem(PlacesUtils._uri(aData.uri), aContainer, aIndex,
                                aData.title, "");
   },
 
   /**
    * Get a transaction for copying a bookmark item from one container to
    * another.
    * @param   aID
    *          The identifier of the bookmark item being copied
@@ -694,25 +196,24 @@ var PlacesUtils = {
    * @param   [optional] aExcludeAnnotations
    *          Optional, array of annotations (listed by their names) to exclude
    *          when copying the item.
    * @returns A nsITransaction object that performs the copy.
    */
   _getBookmarkItemCopyTransaction:
   function PU__getBookmarkItemCopyTransaction(aData, aContainer, aIndex,
                                               aExcludeAnnotations) {
-    var itemURL = this._uri(aData.uri);
+    var itemURL = PlacesUtils._uri(aData.uri);
     var itemTitle = aData.title;
-    var keyword = aData.keyword;
-    var annos = aData.annos;
+    var keyword = aData.keyword || null;
+    var annos = aData.annos || [];
     if (aExcludeAnnotations) {
-      annos =
-        annos.filter(function(aValue, aIndex, aArray) {
-                       return aExcludeAnnotations.indexOf(aValue.name) == -1;
-                    });
+      annos = annos.filter(function(aValue, aIndex, aArray) {
+        return aExcludeAnnotations.indexOf(aValue.name) == -1;
+      });
     }
     var childTxns = [];
     if (aData.dateAdded)
       childTxns.push(this.ptm.editItemDateAdded(null, aData.dateAdded));
     if (aData.lastModified)
       childTxns.push(this.ptm.editItemLastModified(null, aData.lastModified));
 
     return this.ptm.createItem(itemURL, aContainer, aIndex, itemTitle, keyword,
@@ -742,113 +243,87 @@ var PlacesUtils = {
         var txn = null;
         var node = aChildren[i];
 
         // adjusted to make sure that items are given the correct index -
         // transactions insert differently if index == -1
         if (aIndex > -1)
           index = aIndex + i;
 
-        if (node.type == self.TYPE_X_MOZ_PLACE_CONTAINER) {
-          if (node.folder) {
-            var title = node.folder.title;
-            var annos = node.folder.annos;
-            var folderItemsTransactions =
-              getChildItemsTransactions(node.children);
-            txn = self.ptm.createFolder(title, -1, index, annos,
+        if (node.type == PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER) {
+          if (node.livemark && node.annos) // node is a livemark
+            txn = self._getLivemarkCopyTransaction(node, aContainer, index);
+          else {
+            var folderItemsTransactions = [];
+            if (node.dateAdded)
+              folderItemsTransactions.push(self.ptm.editItemDateAdded(null, node.dateAdded));
+            if (node.lastModified)
+              folderItemsTransactions.push(self.ptm.editItemLastModified(null, node.lastModified));
+            var annos = node.annos || [];
+            txn = self.ptm.createFolder(node.title, -1, index, annos,
                                         folderItemsTransactions);
           }
-          else { // node is a livemark
-            var feedURI = self._uri(node.uri.feed);
-            var siteURI = self._uri(node.uri.site);
-            txn = self.ptm.createLivemark(feedURI, siteURI, node.title,
-                                          aContainer, index, node.annos);
-          }
         }
-        else if (node.type == self.TYPE_X_MOZ_PLACE_SEPARATOR)
+        else if (node.type == PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR)
           txn = self.ptm.createSeparator(-1, index);
-        else if (node.type == self.TYPE_X_MOZ_PLACE)
+        else if (node.type == PlacesUtils.TYPE_X_MOZ_PLACE)
           txn = self._getBookmarkItemCopyTransaction(node, -1, index);
 
         NS_ASSERT(txn, "Unexpected item under a bookmarks folder");
         if (txn)
           childItemsTransactions.push(txn);
       }
       return childItemsTransactions;
     }
 
-    var title = aData.folder.title;
-    var annos = aData.folder.annos;
-    var childItems = getChildItemsTransactions(aData.children);
-    if (aData.folder.dateAdded)
-      childItems.push(this.ptm.editItemDateAdded(null, aData.folder.dateAdded));
-    if (aData.folder.lastModified)
-      childItems.push(this.ptm.editItemLastModified(null, aData.folder.lastModified));
-    return this.ptm.createFolder(title, aContainer, aIndex, annos, childItems);
+    // tag folders use tag transactions
+    if (aContainer == PlacesUtils.bookmarks.tagsFolder) {
+      var txns = [];
+      if (aData.children) {
+        aData.children.forEach(function(aChild) {
+          txns.push(this.ptm.tagURI(PlacesUtils._uri(aChild.uri), [aData.title]));
+        }, this);
+      }
+      return this.ptm.aggregateTransactions("addTags", txns);
+    }
+    else if (aData.livemark && aData.annos) {
+      // Place is a Livemark Container
+      return this._getLivemarkCopyTransaction(aData, aContainer, aIndex);
+    }
+    else {
+      var childItems = getChildItemsTransactions(aData.children);
+      if (aData.dateAdded)
+        childItems.push(this.ptm.editItemDateAdded(null, aData.dateAdded));
+      if (aData.lastModified)
+        childItems.push(this.ptm.editItemLastModified(null, aData.lastModified));
+
+      var annos = aData.annos || [];
+      return this.ptm.createFolder(aData.title, aContainer, aIndex, annos, childItems);
+    }
   },
 
-  /**
-   * Unwraps data from the Clipboard or the current Drag Session.
-   * @param   blob
-   *          A blob (string) of data, in some format we potentially know how
-   *          to parse.
-   * @param   type
-   *          The content type of the blob.
-   * @returns An array of objects representing each item contained by the source.
-   */
-  unwrapNodes: function PU_unwrapNodes(blob, type) {
-    // We split on "\n"  because the transferable system converts "\r\n" to "\n"
-    var nodes = [];
-    switch(type) {
-      case this.TYPE_X_MOZ_PLACE:
-      case this.TYPE_X_MOZ_PLACE_SEPARATOR:
-      case this.TYPE_X_MOZ_PLACE_CONTAINER:
-        nodes = JSON.fromString("[" + blob + "]");
-        break;
-      case this.TYPE_X_MOZ_URL:
-        var parts = blob.split("\n");
-        // data in this type has 2 parts per entry, so if there are fewer
-        // than 2 parts left, the blob is malformed and we should stop
-        // but drag and drop of files from the shell has parts.length = 1
-        if (parts.length != 1 && parts.length % 2)
-          break;
-        for (var i = 0; i < parts.length; i=i+2) {
-          var uriString = parts[i];
-          var titleString = "";
-          if (parts.length > i+1)
-            titleString = parts[i+1];
-          else {
-            // for drag and drop of files, try to use the leafName as title
-            try {
-              titleString = this._uri(uriString).QueryInterface(Ci.nsIURL)
-                              .fileName;
-            }
-            catch (e) {}
-          }
-          // note:  this._uri() will throw if uriString is not a valid URI
-          if (this._uri(uriString)) {
-            nodes.push({ uri: uriString,
-                         title: titleString ? titleString : uriString });
-          }
-        }
-        break;
-      case this.TYPE_UNICODE:
-        var parts = blob.split("\n");
-        for (var i = 0; i < parts.length; i++) {
-          var uriString = parts[i];
-          // note: this._uri() will throw if uriString is not a valid URI
-          if (uriString != "" && this._uri(uriString))
-            nodes.push({ uri: uriString, title: uriString });
-        }
-        break;
-      default:
-        LOG("Cannot unwrap data of type " + type);
-        throw Cr.NS_ERROR_INVALID_ARG;
-    }
-    return nodes;
+  _getLivemarkCopyTransaction:
+  function PU__getLivemarkCopyTransaction(aData, aContainer, aIndex) {
+    NS_ASSERT(aData.livemark && aData.annos, "node is not a livemark");
+    // Place is a Livemark Container
+    var feedURI = null;
+    var siteURI = null;
+    aData.annos = aData.annos.filter(function(aAnno) {
+      if (aAnno.name == LMANNO_FEEDURI) {
+        feedURI = PlacesUtils._uri(aAnno.value);
+        return false;
+      }
+      else if (aAnno.name == LMANNO_SITEURI) {
+        siteURI = PlacesUtils._uri(aAnno.value);
+        return false;
+      }
+      return true;
+    }, this);
+    return this.ptm.createLivemark(feedURI, siteURI, aData.title, aContainer,
+                                   aIndex, aData.annos);
   },
 
   /**
    * Constructs a Transaction for the drop or paste of a blob of data into
    * a container.
    * @param   data
    *          The unwrapped data blob of dropped or pasted data.
    * @param   type
@@ -860,91 +335,52 @@ var PlacesUtils = {
    * @param   copy
    *          The drag action was copy, so don't move folders or links.
    * @returns An object implementing nsITransaction that can perform
    *          the move/insert.
    */
   makeTransaction: function PU_makeTransaction(data, type, container,
                                                index, copy) {
     switch (data.type) {
-    case this.TYPE_X_MOZ_PLACE_CONTAINER:
-      if (data.folder) {
-        // Place is a folder.
+      case PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER:
         if (copy)
           return this._getFolderCopyTransaction(data, container, index);
-      }
-      else if (copy) {
-        // Place is a Livemark Container, should be reinstantiated
-        var feedURI = this._uri(data.uri.feed);
-        var siteURI = this._uri(data.uri.site);
-        return this.ptm.createLivemark(feedURI, siteURI, data.title, container,
-                                       index, data.annos);
-      }
-      break;
-    case this.TYPE_X_MOZ_PLACE:
-      if (data.id <= 0)
-        return this._getURIItemCopyTransaction(data, container, index);
-
-      if (copy) {
-        // Copying a child of a live-bookmark by itself should result
-        // as a new normal bookmark item (bug 376731)
-        var copyBookmarkAnno =
-          this._getBookmarkItemCopyTransaction(data, container, index,
-                                               ["livemark/bookmarkFeedURI"]);
-        return copyBookmarkAnno;
-      }
-      break;
-    case this.TYPE_X_MOZ_PLACE_SEPARATOR:
-      if (copy) {
+        else { // Move the item
+          var id = data.folder ? data.folder.id : data.id;
+          return this.ptm.moveItem(id, container, index);
+        }
+        break;
+      case PlacesUtils.TYPE_X_MOZ_PLACE:
+        if (data.id <= 0) // non-bookmark item
+          return this._getURIItemCopyTransaction(data, container, index);
+  
+        if (copy) {
+          // Copying a child of a live-bookmark by itself should result
+          // as a new normal bookmark item (bug 376731)
+          var copyBookmarkAnno =
+            this._getBookmarkItemCopyTransaction(data, container, index,
+                                                 ["livemark/bookmarkFeedURI"]);
+          return copyBookmarkAnno;
+        }
+        else
+          return this.ptm.moveItem(data.id, container, index);
+        break;
+      case PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR:
         // There is no data in a separator, so copying it just amounts to
         // inserting a new separator.
         return this.ptm.createSeparator(container, index);
-      }
-      break;
-    default:
-      if (type == this.TYPE_X_MOZ_URL || type == this.TYPE_UNICODE) {
-        var title = (type == this.TYPE_X_MOZ_URL) ? data.title : data.uri;
-        return this.ptm.createItem(this._uri(data.uri), container, index,
-                                   title);
-      }
-      return null;
+        break;
+      default:
+        if (type == PlacesUtils.TYPE_X_MOZ_URL || type == PlacesUtils.TYPE_UNICODE) {
+          var title = (type == PlacesUtils.TYPE_X_MOZ_URL) ? data.title : data.uri;
+          return this.ptm.createItem(PlacesUtils._uri(data.uri), container, index,
+                                     title);
+        }
     }
-    if (data.id <= 0)
-      return null;
-
-    // Move the item otherwise
-    var id = data.folder ? data.folder.id : data.id;
-    return this.ptm.moveItem(id, container, index);
-  },
-
-  /**
-   * Generates a nsINavHistoryResult for the contents of a folder.
-   * @param   folderId
-   *          The folder to open
-   * @param   [optional] excludeItems
-   *          True to hide all items (individual bookmarks). This is used on
-   *          the left places pane so you just get a folder hierarchy.
-   * @param   [optional] expandQueries
-   *          True to make query items expand as new containers. For managing,
-   *          you want this to be false, for menus and such, you want this to
-   *          be true.
-   * @returns A nsINavHistoryResult containing the contents of the
-   *          folder. The result.root is guaranteed to be open.
-   */
-  getFolderContents:
-  function PU_getFolderContents(aFolderId, aExcludeItems, aExpandQueries) {
-    var query = this.history.getNewQuery();
-    query.setFolders([aFolderId], 1);
-    var options = this.history.getNewQueryOptions();
-    options.excludeItems = aExcludeItems;
-    options.expandQueries = aExpandQueries;
-
-    var result = this.history.executeQuery(query, options);
-    result.root.containerOpen = true;
-    return result;
+    return null;
   },
 
   /**
    * Methods to show the bookmarkProperties dialog in its various modes.
    *
    * The showMinimalAdd* methods open the dialog by its alternative URI. Thus
    * they persist the dialog dimensions separately from the showAdd* methods.
    * Note these variants also do not return the dialog "performed" state since
@@ -1310,41 +746,42 @@ var PlacesUtils = {
    * By calling this before we visit a URL, we will use TRANSITION_TYPED
    * as the transition for the visit to that URL (if we don't have a referrer).
    * This is used when visiting pages from the history menu, history sidebar,
    * url bar, url autocomplete results, and history searches from the places
    * organizer.  If we don't call this, we'll treat those visits as
    * TRANSITION_LINK.
    */
   markPageAsTyped: function PU_markPageAsTyped(aURL) {
-    this.globalHistory.markPageAsTyped(this.createFixedURI(aURL));
+    PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory)
+               .markPageAsTyped(this.createFixedURI(aURL));
   },
 
   /**
    * By calling this before we visit a URL, we will use TRANSITION_BOOKMARK
    * as the transition for the visit to that URL (if we don't have a referrer).
    * This is used when visiting pages from the bookmarks menu, 
    * personal toolbar, and bookmarks from within the places organizer.
    * If we don't call this, we'll treat those visits as TRANSITION_LINK.
    */
   markPageAsFollowedBookmark: function PU_markPageAsFollowedBookmark(aURL) {
-    this.history.markPageAsFollowedBookmark(this.createFixedURI(aURL));
+    PlacesUtils.history.markPageAsFollowedBookmark(this.createFixedURI(aURL));
   },
 
   /**
    * Allows opening of javascript/data URI only if the given node is
    * bookmarked (see bug 224521).
    * @param aURINode
    *        a URI node
    * @return true if it's safe to open the node in the browser, false otherwise.
    *
    */
   checkURLSecurity: function PU_checkURLSecurity(aURINode) {
-    if (!this.nodeIsBookmark(aURINode)) {
-      var uri = this._uri(aURINode.uri);
+    if (!PlacesUtils.nodeIsBookmark(aURINode)) {
+      var uri = PlacesUtils._uri(aURINode.uri);
       if (uri.schemeIs("javascript") || uri.schemeIs("data")) {
         const BRANDING_BUNDLE_URI = "chrome://branding/locale/brand.properties";
         var brandShortName = Cc["@mozilla.org/intl/stringbundle;1"].
                              getService(Ci.nsIStringBundleService).
                              createBundle(BRANDING_BUNDLE_URI).
                              GetStringFromName("brandShortName");
         var promptService = Cc["@mozilla.org/embedcomp/prompt-service;1"].
                             getService(Ci.nsIPromptService);
@@ -1353,147 +790,16 @@ var PlacesUtils = {
         promptService.alert(window, brandShortName, errorStr);
         return false;
       }
     }
     return true;
   },
 
   /**
-   * Fetch all annotations for a URI, including all properties of each
-   * annotation which would be required to recreate it.
-   * @param aURI
-   *        The URI for which annotations are to be retrieved.
-   * @return Array of objects, each containing the following properties:
-   *         name, flags, expires, mimeType, type, value
-   */
-  getAnnotationsForURI: function PU_getAnnotationsForURI(aURI) {
-    var annosvc = this.annotations;
-    var annos = [], val = null;
-    var annoNames = annosvc.getPageAnnotationNames(aURI, {});
-    for (var i = 0; i < annoNames.length; i++) {
-      var flags = {}, exp = {}, mimeType = {}, storageType = {};
-      annosvc.getPageAnnotationInfo(aURI, annoNames[i], flags, exp, mimeType, storageType);
-      if (storageType.value == annosvc.TYPE_BINARY) {
-        var data = {}, length = {}, mimeType = {};
-        annosvc.getPageAnnotationBinary(aURI, annoNames[i], data, length, mimeType);
-        val = data.value;
-      }
-      else
-        val = annosvc.getPageAnnotation(aURI, annoNames[i]);