Merge from cvs-trunk-mirror to mozilla-central.
authorjorendorff@mozilla.com
Tue, 09 Oct 2007 13:00:59 -0500
changeset 6748 ebd6bf4a0991885cf9b52e8943ef7b71f725e26b
parent 6192 45182e442e212f37637fda61e1a1b20ceb45a7a7 (current diff)
parent 6747 26905090f75dc5415f9b821323ccffb108d32897 (diff)
child 6925 93c6f56cecb805b71fd1ba9dcd91dd8c06463143
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9a9pre
Merge from cvs-trunk-mirror to mozilla-central.
browser/base/branding/uninstall.properties
browser/base/content/test/moz.png
browser/branding/unofficial/content/uninstall.properties
client.mk
config/autoconf.mk.in
config/rules.mk
configure.in
content/svg/content/src/nsSVGAnimatedBoolean.cpp
content/svg/content/src/nsSVGAnimatedBoolean.h
embedding/qa/jstests/nsIFontListTest.txt
gfx/idl/nsIFontCatalogService.idl
gfx/idl/nsIFontList.idl
gfx/idl/nsIFreeType2.idl
gfx/src/freetype/Makefile.in
gfx/src/freetype/nsFreeType.cpp
gfx/src/freetype/nsFreeType.h
gfx/src/nsFontList.cpp
gfx/src/nsFontList.h
js/src/js.cpp
js/src/jsapi.cpp
js/src/jsdbgapi.cpp
js/src/jsemit.cpp
js/src/jsfun.cpp
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsparse.cpp
js/src/jsregexp.cpp
js/src/jsscan.cpp
js/src/jsscript.cpp
js/src/jsxml.cpp
js/src/prmjtime.cpp
js/tests/Maketests
js/tests/create-patterns.pl
js/tests/ecma_3/Expressions/11.10-01.js
js/tests/ecma_3/Expressions/11.10-02.js
js/tests/ecma_3/Expressions/11.7.1-01.js
js/tests/ecma_3/Expressions/11.7.2-01.js
js/tests/ecma_3/Expressions/11.7.3-01.js
js/tests/js1_5/Expressions/regress-394673.js
js/tests/js1_5/GetSet/regress-375976.js
js/tests/js1_5/Object/regress-382503.js
js/tests/js1_5/Regress/regress-379245.js
js/tests/js1_5/Regress/regress-396684.js
js/tests/js1_5/extensions/regress-358594-01.js
js/tests/js1_5/extensions/regress-358594-02.js
js/tests/js1_5/extensions/regress-358594-03.js
js/tests/js1_5/extensions/regress-358594-04.js
js/tests/js1_5/extensions/regress-358594-05.js
js/tests/js1_5/extensions/regress-358594-06.js
js/tests/js1_5/extensions/regress-372309.js
js/tests/js1_5/extensions/regress-394967.js
js/tests/js1_7/GC/regress-381374.js
js/tests/js1_7/block/regress-396900.js
js/tests/js1_7/extensions/regress-380933.js
js/tests/known-failures.pl
js/tests/post-process-logs.pl
js/tests/runtests.sh
js/tests/userhook-e4x.js
js/tests/userhook-js.js
js/tests/userhookeach-e4x.js
js/tests/userhookeach-js.js
js/tests/userhookeach.js
layout/generic/gopher-audio.gif
layout/generic/gopher-binary.gif
layout/generic/gopher-find.gif
layout/generic/gopher-image.gif
layout/generic/gopher-menu.gif
layout/generic/gopher-movie.gif
layout/generic/gopher-sound.gif
layout/generic/gopher-telnet.gif
layout/generic/gopher-text.gif
layout/generic/gopher-unknown.gif
layout/reftests/svg/text-style-01-ref.svg
layout/reftests/svg/text-style-01a.svg
layout/reftests/svg/text-style-01b.svg
layout/reftests/svg/text-style-01c.svg
layout/reftests/svg/text-style-01d.svg
layout/reftests/svg/text-style-01e.svg
other-licenses/branding/firefox/content/uninstall.properties
testing/sisyphus/data/firefox,1.8.1,too-much-gc,debug.data
testing/sisyphus/data/firefox,1.9.0,too-much-gc,debug.data
testing/sisyphus/data/firefox,1.9.0-jprof,debug.data
testing/sisyphus/data/firefox,1.9.0-jprof,opt.data
testing/sisyphus/data/js,1.8.1,too-much-gc,debug.data
testing/sisyphus/data/js,1.9.0,too-much-gc,debug.data
toolkit/mozapps/installer/windows/nsis/SetVistaDefaultApp.dll
toolkit/mozapps/installer/windows/nsis/UAC.dll
tools/release/t/tinder-config.pl
uriloader/exthandler/tests/Makefile.in
--- a/Makefile.in
+++ b/Makefile.in
@@ -158,17 +158,17 @@ 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
 
-SYMBOL_ARCHIVE_BASENAME := \
+SYMBOL_ARCHIVE_BASENAME = \
   $(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_ARCH)-$(BUILDID)$(EXTRA_BUILDID)
 
 buildsymbols:
 ifdef MOZ_CRASHREPORTER
 	echo building symbol store
 	mkdir -p $(DIST)/crashreporter-symbols/$(BUILDID)
 	$(PYTHON) $(topsrcdir)/toolkit/crashreporter/tools/symbolstore.py    \
 	  $(MAKE_SYM_STORE_ARGS) -s $(topsrcdir) $(DUMP_SYMS_BIN)     \
--- a/accessible/public/ia2/Makefile.in
+++ b/accessible/public/ia2/Makefile.in
@@ -94,16 +94,18 @@ CSRCS	= \
 MIDL_GENERATED_FILES = \
   dlldata.c \
   $(MIDL_INTERFACES:%.idl=%_p.c) \
   $(MIDL_INTERFACES:%.idl=%_i.c) \
   $(MIDL_INTERFACES:%.idl=%.h) \
   $(MIDL_ENUMS:%.idl=%.h) \
   $(NULL)
 
+EMBED_MANIFEST_AT = 2
+
 include $(topsrcdir)/config/rules.mk
 
 OS_LIBS = \
   kernel32.lib \
   rpcndr.lib \
   rpcns4.lib \
   rpcrt4.lib \
   ole32.lib \
--- a/accessible/public/msaa/Makefile.in
+++ b/accessible/public/msaa/Makefile.in
@@ -114,10 +114,12 @@ EXPORTS = \
 	$(NULL)
 
 export:: done_gen
 
 # This marshall dll is also registered in the installer
 register::
 	regsvr32 -s $(DIST)/bin/$(SHARED_LIBRARY)
 
+EMBED_MANIFEST_AT = 2
+
 include $(topsrcdir)/config/rules.mk
 
--- a/accessible/public/nsIAccessibleDocument.idl
+++ b/accessible/public/nsIAccessibleDocument.idl
@@ -53,17 +53,17 @@ interface nsIDOMWindow;
  * You can QueryInterface to nsIAccessibleDocument from
  * the nsIAccessible or nsIAccessNode for the root node
  * of a document. You can also get one from 
  * nsIAccessNode::GetAccessibleDocument() or 
  * nsIAccessibleEvent::GetAccessibleDocument()
  *
  * @status UNDER_REVIEW
  */
-[scriptable, uuid(6cc11286-e02d-4a8d-960a-e7a61161b230)]
+[scriptable, uuid(81ddd75f-adbd-4a1c-b87c-6522bcea0596)]
 interface nsIAccessibleDocument : nsISupports
 {
   /**
    * The URL of the document
    */
   readonly attribute AString URL;
 
   /**
@@ -115,10 +115,34 @@ interface nsIAccessibleDocument : nsISup
    * Returns the first accessible parent of a DOM node.
    * Guaranteed not to return nsnull if the DOM node is in a document.
    * @param aDOMNode The DOM node we need an accessible for.
    * @param aCanCreate Can accessibles be created or must it be the first 
    *                   cached accessible in the parent chain?
    * @return An first nsIAccessible found by crawling up the DOM node
    *         to the document root.
    */
-  nsIAccessible getAccessibleInParentChain(in nsIDOMNode aDOMNode);
+  nsIAccessible getAccessibleInParentChain(in nsIDOMNode aDOMNode,
+                                           in boolean aCanCreate);
+
+  /**
+   * A bit flag representing the type of ARIA properties which should be
+   * checked in this document:
+   * either eUnknownPropType, eCheckNamespaced, eCheckHyphenated or eCheckAny
+   */
+  readonly attribute unsigned long ariaPropTypes;
+  
+  /**
+   * Check attributes in the form of:
+   * [someprefix]:[propname]  (e.g. aria:live) where ancestor defines: 
+   * xmlns:[someprefix]="http://www.w3.org/2005/07/aaa"
+   */
+  const unsigned long eCheckNamespaced = 1;
+  
+  /**
+   * Check hyphenated attributes in the form of aria-[propname].
+   * This is the default in text/html documents.
+   * Can be combined with eCheckNamespaced flag. This may
+   * change during the life of the document, if setAttributeNS()
+   * is used to set an ARIA property.
+   */
+  const unsigned long eCheckHyphenated = 2;
 };
--- a/accessible/public/nsIAccessibleText.idl
+++ b/accessible/public/nsIAccessibleText.idl
@@ -40,17 +40,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 typedef long nsAccessibleTextBoundary;
 
 interface nsIAccessible;
 
-[scriptable, uuid(948419b2-53f6-4a74-bb69-1345faf3e8e8)]
+[scriptable, uuid(caa4f543-070e-4705-8428-2e53575c41bb)]
 interface nsIAccessibleText : nsISupports
 {
   const nsAccessibleTextBoundary BOUNDARY_CHAR = 0;
   const nsAccessibleTextBoundary BOUNDARY_WORD_START = 1;
   const nsAccessibleTextBoundary BOUNDARY_WORD_END = 2;
   const nsAccessibleTextBoundary BOUNDARY_SENTENCE_START = 3; // don't use, deprecated
   const nsAccessibleTextBoundary BOUNDARY_SENTENCE_END = 4;  // don't use, deprecated
   const nsAccessibleTextBoundary BOUNDARY_LINE_START = 5;
@@ -175,25 +175,41 @@ interface nsIAccessibleText : nsISupport
   void addSelection (in long startOffset, in long endOffset);
 
   void removeSelection (in long selectionNum);
 
 
   /**
    * Makes a specific part of string visible on screen.
    *
-   * @param aStartIndex - 0-based character offset.
-   * @param aEndIndex - 0-based character offset - the offset of the
-   *                        character just past the last character of the
-   *                        string.
-   * @param aScrollType - defines how to scroll (see nsIAccessibleScrollType for
-   *                      available constants).
+   * @param startIndex  0-based character offset
+   * @param endIndex    0-based character offset - the offset of the
+   *                    character just past the last character of the
+   *                    string
+   * @param scrollType  defines how to scroll (see nsIAccessibleScrollType for
+   *                    available constants)
    */
-  void scrollSubstringTo(in long aStartIndex, in long aEndIndex,
-                         in unsigned long aScrollType);
+  void scrollSubstringTo(in long startIndex, in long endIndex,
+                         in unsigned long scrollType);
+
+  /**
+   * Moves the top left of a substring to a specified location.
+   *
+   * @param startIndex      0-based character offset
+   * @param endIndex        0-based character offset - the offset of the
+   *                        character just past the last character of
+   *                        the string
+   * @param coordinateType  specifies the coordinates origin (for available
+   *                        constants refer to nsIAccessibleCoordinateType)
+   * @param x               defines the x coordinate
+   * @param y               defines the y coordinate
+   */
+  void scrollSubstringToPoint(in long startIndex, in long endIndex,
+                              in unsigned long coordinateType,
+                              in long x, in long y);
 };
 
 /*
  Assumptions:
 
  Using wstring (UCS2) instead of string encoded in UTF-8.
  Multibyte encodings (or at least potentially multi-byte
  encodings) would be preferred for the reasons cited above.
--- a/accessible/public/nsIAccessibleTypes.idl
+++ b/accessible/public/nsIAccessibleTypes.idl
@@ -85,18 +85,17 @@ interface nsIAccessibleScrollType : nsIS
    * Scroll an object the minimum amount necessary in order for the entire
    * frame to be visible (if possible).
    */
   const unsigned long SCROLL_TYPE_ANYWHERE = 0x06;
 };
 
 
 /**
- * These constants define which coordinate system a point is located in. Note,
- * keep them synchronized with IA2CoordinateType.
+ * These constants define which coordinate system a point is located in.
  */
 [scriptable, uuid(c9fbdf10-619e-436f-bf4b-8566686f1577)]
 interface nsIAccessibleCoordinateType : nsISupports
 {
   /**
    * The coordinates are relative to the screen.
    */
   const unsigned long COORDTYPE_SCREEN_RELATIVE = 0x00;
--- a/accessible/public/nsPIAccessible.idl
+++ b/accessible/public/nsPIAccessible.idl
@@ -36,17 +36,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 interface nsIAccessible;
 interface nsIAccessibleEvent;
 
-[uuid(03932812-53d1-4dc7-965d-6b6ad8a872b1)]
+[uuid(af05f83c-6fd2-48c1-b1c3-811857472421)]
 interface nsPIAccessible : nsISupports
 {
   /**
    * Set accessible parent.
    */
   void setParent(in nsIAccessible aAccParent);
 
   /**
@@ -60,16 +60,21 @@ interface nsPIAccessible : nsISupports
   void setNextSibling(in nsIAccessible aAccNextSibling);
 
   /**
    * Return parent accessible only if cached.
    */
   void getCachedParent(out nsIAccessible aAccParent);
 
   /**
+   * Return first child accessible only if cached.
+   */
+  void getCachedFirstChild(out nsIAccessible aAccFirstChild);
+
+  /**
    * Set the child count to -1 (unknown) and null out cached child pointers
    */
   void invalidateChildren();
 
   /**
    * Fire accessible event.
    *
    * @param aEvent - DOM event
--- a/accessible/src/atk/nsAppRootAccessible.cpp
+++ b/accessible/src/atk/nsAppRootAccessible.cpp
@@ -504,30 +504,31 @@ nsApplicationAccessibleWrap::nsApplicati
     nsApplicationAccessible()
 {
     MAI_LOG_DEBUG(("======Create AppRootAcc=%p\n", (void*)this));
 }
 
 nsApplicationAccessibleWrap::~nsApplicationAccessibleWrap()
 {
     MAI_LOG_DEBUG(("======Destory AppRootAcc=%p\n", (void*)this));
+    nsAccessibleWrap::ShutdownAtkObject();
 }
 
 NS_IMETHODIMP
 nsApplicationAccessibleWrap::Init()
 {
     // XXX following code is copied from widget/src/gtk2/nsWindow.cpp
     // we should put it to somewhere that can be used from both modules
     // see bug 390761
 
     // check if accessibility enabled/disabled by environment variable
     PRBool isGnomeATEnabled = PR_FALSE;
     const char *envValue = PR_GetEnv(sAccEnv);
     if (envValue) {
-        isGnomeATEnabled = atoi(envValue);
+        isGnomeATEnabled = !!atoi(envValue);
     } else {
         //check gconf-2 setting
         nsresult rv;
         nsCOMPtr<nsIPrefBranch> sysPrefService =
             do_GetService(sSysPrefService, &rv);
         if (NS_SUCCEEDED(rv) && sysPrefService) {
             sysPrefService->GetBoolPref(sAccessibilityKey, &isGnomeATEnabled);
         }
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -36,184 +36,195 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsARIAMap.h"
 #include "nsIAccessibleRole.h"
 #include "nsIAccessibleStates.h"
 
+#define ARIA_PROPERTY(atom) &nsAccessibilityAtoms::atom,
+nsIAtom** nsARIAMap::gAriaAtomPtrsNS[eAria_none] = {
+#include "nsARIAPropertyList.h"
+};
+#undef ARIA_PROPERTY
+
+#define ARIA_PROPERTY(atom) &nsAccessibilityAtoms::aria_##atom,
+nsIAtom** nsARIAMap::gAriaAtomPtrsHyphenated[eAria_none] = {
+#include "nsARIAPropertyList.h"
+};
+#undef ARIA_PROPERTY
+
 /**
  *  This list of WAI-defined roles are currently hardcoded.
  *  Eventually we will most likely be loading an RDF resource that contains this information
  *  Using RDF will also allow for role extensibility. See bug 280138.
  *
- *  XXX Should we store attribute names in this table as atoms instead of strings?
  *  Definition of nsRoleMapEntry and nsStateMapEntry contains comments explaining this table.
  *
- *  When no nsIAccessibleRole neum mapping exists for an ARIA role, the
+ *  When no nsIAccessibleRole enum mapping exists for an ARIA role, the
  *  role will be exposed via the object attribute "xml-roles".
  *  In addition, in MSAA, the unmapped role will also be exposed as a BSTR string role.
  *
  *  There are no nsIAccessibleRole enums for the following landmark roles:
  *    banner, contentinfo, main, navigation, note, search, secondary, seealso, breadcrumbs
  */ 
 
-static const nsStateMapEntry kEndEntry = {0, 0, 0};  // To fill in array of state mappings
+static const nsStateMapEntry kEndEntry = {eAria_none, 0, 0};  // To fill in array of state mappings
 
 nsRoleMapEntry nsARIAMap::gWAIRoleMap[] = 
 {
   {"alert", nsIAccessibleRole::ROLE_ALERT, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"alertdialog", nsIAccessibleRole::ROLE_ALERT, eNameOkFromChildren, eNoValue, kNoReqStates, kEndEntry},
   {"application", nsIAccessibleRole::ROLE_APPLICATION, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"button", nsIAccessibleRole::ROLE_PUSHBUTTON, eNameOkFromChildren, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"pressed", kBoolState, nsIAccessibleStates::STATE_PRESSED},
-            {"pressed", "mixed", nsIAccessibleStates::STATE_MIXED}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_pressed, kBoolState, nsIAccessibleStates::STATE_PRESSED},
+            {eAria_pressed, "mixed", nsIAccessibleStates::STATE_MIXED}, kEndEntry},
   {"checkbox", nsIAccessibleRole::ROLE_CHECKBUTTON, eNameOkFromChildren, eNoValue, nsIAccessibleStates::STATE_CHECKABLE,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED},
-            {"checked", "mixed", nsIAccessibleStates::STATE_MIXED},
-            {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED},
+            {eAria_checked, "mixed", nsIAccessibleStates::STATE_MIXED},
+            {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
   {"columnheader", nsIAccessibleRole::ROLE_COLUMNHEADER, eNameOkFromChildren, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
-            {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE},
-            {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
+            {eAria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
+            {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
   {"combobox", nsIAccessibleRole::ROLE_COMBOBOX, eNameLabelOrTitle, eHasValueMinMax,
                nsIAccessibleStates::STATE_COLLAPSED | nsIAccessibleStates::STATE_HASPOPUP,
             // Manually map EXT_STATE_SUPPORTS_AUTOCOMPLETION aaa:autocomplete
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY},
-            {"expanded", kBoolState, nsIAccessibleStates::STATE_EXPANDED}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
+            {eAria_expanded, kBoolState, nsIAccessibleStates::STATE_EXPANDED}, kEndEntry},
   {"description", nsIAccessibleRole::ROLE_TEXT_CONTAINER, eNameOkFromChildren, eNoValue, kNoReqStates, kEndEntry},
   {"dialog", nsIAccessibleRole::ROLE_DIALOG, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"document", nsIAccessibleRole::ROLE_DOCUMENT, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"grid", nsIAccessibleRole::ROLE_TABLE, eNameLabelOrTitle, eNoValue, nsIAccessibleStates::STATE_FOCUSABLE,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"multiselectable", kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE},
-            {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE},
+            {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
   {"gridcell", nsIAccessibleRole::ROLE_CELL, eNameOkFromChildren, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"expanded", kBoolState, nsIAccessibleStates::STATE_EXPANDED},
-            {"expanded", "false", nsIAccessibleStates::STATE_COLLAPSED},
-            {"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
-            {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE},
-            {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_expanded, kBoolState, nsIAccessibleStates::STATE_EXPANDED},
+            {eAria_expanded, "false", nsIAccessibleStates::STATE_COLLAPSED},
+            {eAria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
+            {eAria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
+            {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
   {"group", nsIAccessibleRole::ROLE_GROUPING, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"heading", nsIAccessibleRole::ROLE_HEADING, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"img", nsIAccessibleRole::ROLE_GRAPHIC, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"label", nsIAccessibleRole::ROLE_LABEL, eNameOkFromChildren, eNoValue, kNoReqStates, kEndEntry},
   {"link", nsIAccessibleRole::ROLE_LINK, eNameOkFromChildren, eNoValue, nsIAccessibleStates::STATE_LINKED,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
   {"list", nsIAccessibleRole::ROLE_LIST, eNameLabelOrTitle, eNoValue, kNoReqStates,
-            {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY},
-            {"multiselectable", kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry},
+            {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
+            {eAria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry},
   {"listbox", nsIAccessibleRole::ROLE_LIST, eNameLabelOrTitle, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY},
-            {"multiselectable", kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
+            {eAria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry},
   {"listitem", nsIAccessibleRole::ROLE_LISTITEM, eNameOkFromChildren, eNoValue, kNoReqStates,
-            {"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
-            {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE},
-            {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
-            {"checked", "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
-            {"checked", "false", nsIAccessibleStates::STATE_CHECKABLE}, kEndEntry},
+            {eAria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
+            {eAria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
+            {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
+            {eAria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
+            {eAria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE}, kEndEntry},
   {"menu", nsIAccessibleRole::ROLE_MENUPOPUP, eNameLabelOrTitle, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
   {"menubar", nsIAccessibleRole::ROLE_MENUBAR, eNameLabelOrTitle, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
   {"menuitem", nsIAccessibleRole::ROLE_MENUITEM, eNameOkFromChildren, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
-            {"checked", "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
-            {"checked", "false", nsIAccessibleStates::STATE_CHECKABLE}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
+            {eAria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
+            {eAria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE}, kEndEntry},
   {"menuitemcheckbox", nsIAccessibleRole::ROLE_CHECK_MENU_ITEM, eNameOkFromChildren, eNoValue, nsIAccessibleStates::STATE_CHECKABLE,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED },
-            {"checked", "mixed", nsIAccessibleStates::STATE_MIXED}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED },
+            {eAria_checked, "mixed", nsIAccessibleStates::STATE_MIXED}, kEndEntry},
   {"menuitemradio", nsIAccessibleRole::ROLE_RADIO_MENU_ITEM, eNameOkFromChildren, eNoValue, nsIAccessibleStates::STATE_CHECKABLE,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED }, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED }, kEndEntry},
   {"option", nsIAccessibleRole::ROLE_LISTITEM, eNameOkFromChildren, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
-            {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE},
-            {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
-            {"checked", "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
-            {"checked", "false", nsIAccessibleStates::STATE_CHECKABLE}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
+            {eAria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
+            {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
+            {eAria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
+            {eAria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE}, kEndEntry},
   {"progressbar", nsIAccessibleRole::ROLE_PROGRESSBAR, eNameLabelOrTitle, eHasValueMinMax, nsIAccessibleStates::STATE_READONLY,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
   {"radio", nsIAccessibleRole::ROLE_RADIOBUTTON, eNameOkFromChildren, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED}, kEndEntry},
   {"radiogroup", nsIAccessibleRole::ROLE_GROUPING, eNameLabelOrTitle, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
   {"region", nsIAccessibleRole::ROLE_PANE, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"row", nsIAccessibleRole::ROLE_ROW, eNameOkFromChildren, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
-            {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE},
-            {"expanded", kBoolState, nsIAccessibleStates::STATE_EXPANDED},
-            {"expanded", "false", nsIAccessibleStates::STATE_COLLAPSED}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
+            {eAria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
+            {eAria_expanded, kBoolState, nsIAccessibleStates::STATE_EXPANDED},
+            {eAria_expanded, "false", nsIAccessibleStates::STATE_COLLAPSED}, kEndEntry},
   {"rowheader", nsIAccessibleRole::ROLE_ROWHEADER, eNameOkFromChildren, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
-            {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE},
-            {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
+            {eAria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
+            {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
   {"section", nsIAccessibleRole::ROLE_SECTION, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"separator", nsIAccessibleRole::ROLE_SEPARATOR, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"slider", nsIAccessibleRole::ROLE_SLIDER, eNameLabelOrTitle, eHasValueMinMax, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
   {"spinbutton", nsIAccessibleRole::ROLE_SPINBUTTON, eNameLabelOrTitle, eHasValueMinMax, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
   {"status", nsIAccessibleRole::ROLE_STATUSBAR, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"tab", nsIAccessibleRole::ROLE_PAGETAB, eNameOkFromChildren, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
   {"tablist", nsIAccessibleRole::ROLE_PAGETABLIST, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"tabpanel", nsIAccessibleRole::ROLE_PROPERTYPAGE, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"textbox", nsIAccessibleRole::ROLE_ENTRY, eNameLabelOrTitle, eNoValue, kNoReqStates,
             // Manually map EXT_STATE_SINGLE_LINE and EXT_STATE_MULTI_LINE FROM aaa:multiline
             // Manually map EXT_STATE_SUPPORTS_AUTOCOMPLETION aaa:autocomplete
-            {"autocomplete", "list", nsIAccessibleStates::STATE_HASPOPUP},
-            {"autocomplete", "both", nsIAccessibleStates::STATE_HASPOPUP},
-            {"secret", kBoolState, nsIAccessibleStates::STATE_PROTECTED},
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
+            {eAria_autocomplete, "list", nsIAccessibleStates::STATE_HASPOPUP},
+            {eAria_autocomplete, "both", nsIAccessibleStates::STATE_HASPOPUP},
+            {eAria_secret, kBoolState, nsIAccessibleStates::STATE_PROTECTED},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
   {"toolbar", nsIAccessibleRole::ROLE_TOOLBAR, eNameLabelOrTitle, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
   {"tooltip", nsIAccessibleRole::ROLE_TOOLTIP, eNameOkFromChildren, eNoValue, kNoReqStates, kEndEntry},
   {"tree", nsIAccessibleRole::ROLE_OUTLINE, eNameLabelOrTitle, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY},
-            {"multiselectable", kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
+            {eAria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry},
   {"treegrid", nsIAccessibleRole::ROLE_TREE_TABLE, eNameLabelOrTitle, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY},
-            {"multiselectable", kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
+            {eAria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry},
   {"treeitem", nsIAccessibleRole::ROLE_OUTLINEITEM, eNameOkFromChildren, eNoValue, kNoReqStates,
-            {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
-            {"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
-            {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE},
-            {"expanded", kBoolState, nsIAccessibleStates::STATE_EXPANDED},
-            {"expanded", "false", nsIAccessibleStates::STATE_COLLAPSED},
-            {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
-            {"checked", "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
-            {"checked", "false", nsIAccessibleStates::STATE_CHECKABLE},},
+            {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
+            {eAria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
+            {eAria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
+            {eAria_expanded, kBoolState, nsIAccessibleStates::STATE_EXPANDED},
+            {eAria_expanded, "false", nsIAccessibleStates::STATE_COLLAPSED},
+            {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
+            {eAria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
+            {eAria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE},},
   {nsnull, nsIAccessibleRole::ROLE_NOTHING, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry} // Last item
 };
 
 /**
  * Universal states:
  * The following state rules are applied to any accessible element,
  * whether there is an ARIA role or not:
  */
 nsStateMapEntry nsARIAMap::gWAIUnivStateMap[] = {
-  {"required", kBoolState, nsIAccessibleStates::STATE_REQUIRED},
-  {"invalid",  kBoolState, nsIAccessibleStates::STATE_INVALID},
-  {"haspopup", kBoolState, nsIAccessibleStates::STATE_HASPOPUP},
-  {"busy",     "true",     nsIAccessibleStates::STATE_BUSY},
-  {"busy",     "error",    nsIAccessibleStates::STATE_INVALID},
+  {eAria_required, kBoolState, nsIAccessibleStates::STATE_REQUIRED},
+  {eAria_invalid,  kBoolState, nsIAccessibleStates::STATE_INVALID},
+  {eAria_haspopup, kBoolState, nsIAccessibleStates::STATE_HASPOPUP},
+  {eAria_busy,     "true",     nsIAccessibleStates::STATE_BUSY},
+  {eAria_busy,     "error",    nsIAccessibleStates::STATE_INVALID},
   kEndEntry
 };
 
--- a/accessible/src/base/nsARIAMap.h
+++ b/accessible/src/base/nsARIAMap.h
@@ -36,16 +36,23 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsARIAMap_H_
 #define _nsARIAMap_H_
 
 #include "prtypes.h"
+#include "nsAccessibilityAtoms.h"
+
+#define ARIA_PROPERTY(atom) eAria_##atom,
+enum EAriaProperty {
+#include "nsARIAPropertyList.h"
+  eAria_none };
+#undef ARIA_PROPERTY
 
 // Name mapping rule: can the name be computed from descendants?
 enum ENameRule
 {
   // eNameLabelOrTitle:
   // Collect name from:
   //   1) The content subtrees pointed to by labelledby
   //      which contains the IDs for the label content, or if unspecified
@@ -74,17 +81,17 @@ enum EValueRule
 
 // Used in nsRoleMapEntry.state if no nsIAccessibleStates are automatic for a given role
 #define kNoReqStates 0
 
 // For this name and value pair, what is the nsIAccessibleStates mapping.
 // nsStateMapEntry.state
 struct nsStateMapEntry
 {
-  const char* attributeName;  // magic value of nsnull means last entry in map
+  EAriaProperty attributeName;  // eARIA_none indicates last entry in map
   const char* attributeValue; // magic value of kBoolState (0) means supports "true" and "false"
   PRUint32 state;             // If match, this is the nsIAccessibleStates to map to
 };
 
 // For each ARIA role, this maps the nsIAccessible information
 struct nsRoleMapEntry
 {
   // ARIA role: string representation such as "button"
@@ -119,13 +126,15 @@ struct nsRoleMapEntry
 
 /**
  *  These are currently initialized (hardcoded) in nsARIAMap.cpp, 
  *  and provide the mappings for WAI-ARIA roles and properties using the 
  *  structs defined in this file.
  */
 struct nsARIAMap
 {
+  static nsIAtom** gAriaAtomPtrsNS[eAria_none];
+  static nsIAtom** gAriaAtomPtrsHyphenated[eAria_none];
   static nsRoleMapEntry gWAIRoleMap[];
   static nsStateMapEntry gWAIUnivStateMap[];
 };
 
 #endif
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/nsARIAPropertyList.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation
+ * Portions created by the Initial Developer are Copyright (C)2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Aaron Leventhal <aleventh@us.ibm.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+  // ARIA properties
+ARIA_PROPERTY(activedescendant)
+ARIA_PROPERTY(atomic)
+ARIA_PROPERTY(autocomplete)
+ARIA_PROPERTY(busy)
+ARIA_PROPERTY(channel)
+ARIA_PROPERTY(checked)
+ARIA_PROPERTY(controls)
+ARIA_PROPERTY(datatype)
+ARIA_PROPERTY(describedby)
+ARIA_PROPERTY(disabled)
+ARIA_PROPERTY(dropeffect)
+ARIA_PROPERTY(expanded)
+ARIA_PROPERTY(flowto)
+ARIA_PROPERTY(grab)
+ARIA_PROPERTY(haspopup)
+ARIA_PROPERTY(invalid)
+ARIA_PROPERTY(labelledby)
+ARIA_PROPERTY(level)
+ARIA_PROPERTY(live)
+ARIA_PROPERTY(multiline)
+ARIA_PROPERTY(multiselectable)
+ARIA_PROPERTY(owns)
+ARIA_PROPERTY(posinset)
+ARIA_PROPERTY(pressed)
+ARIA_PROPERTY(readonly)
+ARIA_PROPERTY(relevant)
+ARIA_PROPERTY(required)
+ARIA_PROPERTY(secret)
+ARIA_PROPERTY(selected)
+ARIA_PROPERTY(setsize)
+ARIA_PROPERTY(sort)
+ARIA_PROPERTY(valuenow)
+ARIA_PROPERTY(valuemin)
+ARIA_PROPERTY(valuemax)
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -56,17 +56,16 @@
 #include "nsIDOMHTMLElement.h"
 #include "nsIDOMNSDocument.h"
 #include "nsIDOMNSHTMLElement.h"
 #include "nsIDOMViewCSS.h"
 #include "nsIDOMWindow.h"
 #include "nsPIDOMWindow.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIFrame.h"
-#include "nsIScrollableFrame.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsIServiceManager.h"
 #include "nsIStringBundle.h"
 #include "nsITimer.h"
 #include "nsRootAccessible.h"
@@ -436,81 +435,24 @@ nsAccessNode::ScrollTo(PRUint32 aScrollT
 
 NS_IMETHODIMP
 nsAccessNode::ScrollToPoint(PRUint32 aCoordinateType, PRInt32 aX, PRInt32 aY)
 {
   nsIFrame *frame = GetFrame();
   if (!frame)
     return NS_ERROR_FAILURE;
 
-  nsPresContext *presContext = frame->PresContext();
-
-  switch (aCoordinateType) {
-    case nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE:
-      break;
-
-    case nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE:
-    {
-      nsIntPoint wndCoords = nsAccUtils::GetScreenCoordsForWindow(mDOMNode);
-      aX += wndCoords.x;
-      aY += wndCoords.y;
-      break;
-    }
-
-    case nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE:
-    {
-      nsCOMPtr<nsPIAccessNode> parent;
-
-      nsCOMPtr<nsIAccessible> accessible;
-      nsresult rv = QueryInterface(NS_GET_IID(nsIAccessible),
-                                   getter_AddRefs(accessible));
-      if (NS_SUCCEEDED(rv) && accessible) {
-        nsCOMPtr<nsIAccessible> parentAccessible;
-        accessible->GetParent(getter_AddRefs(parentAccessible));
-        parent = do_QueryInterface(parentAccessible);
-      } else {
-        nsCOMPtr<nsIAccessNode> parentAccessNode;
-        GetParentNode(getter_AddRefs(parentAccessNode));
-        parent = do_QueryInterface(parentAccessNode);
-      }
-
-      NS_ENSURE_STATE(parent);
-      nsIFrame *parentFrame = parent->GetFrame();
-      NS_ENSURE_STATE(parentFrame);
-
-      nsIntRect parentRect = parentFrame->GetScreenRectExternal();
-      aX += parentRect.x;
-      aY += parentRect.y;
-      break;
-    }
-
-    default:
-      return NS_ERROR_INVALID_ARG;
-  }
+  nsIntPoint coords;
+  nsresult rv = nsAccUtils::ConvertToScreenCoords(aX, aY, aCoordinateType,
+                                                  this, &coords);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   nsIFrame *parentFrame = frame;
-  while (parentFrame = parentFrame->GetParent()) {
-    nsIScrollableFrame *scrollableFrame = nsnull;
-    CallQueryInterface(parentFrame, &scrollableFrame);
-    if (scrollableFrame) {
-      nsIntRect frameRect = frame->GetScreenRectExternal();
-      PRInt32 devDeltaX = aX - frameRect.x;
-      PRInt32 devDeltaY = aY - frameRect.y;
-
-      nsPoint deltaPoint;
-      deltaPoint.x = presContext->DevPixelsToAppUnits(devDeltaX);
-      deltaPoint.y = presContext->DevPixelsToAppUnits(devDeltaY);
-
-      nsPoint scrollPoint = scrollableFrame->GetScrollPosition();
-
-      scrollPoint -= deltaPoint;
-
-      scrollableFrame->ScrollTo(scrollPoint);
-    }
-  }
+  while (parentFrame = parentFrame->GetParent())
+    nsAccUtils::ScrollFrameToPoint(parentFrame, frame, coords);
 
   return NS_OK;
 }
 
 nsresult
 nsAccessNode::MakeAccessNode(nsIDOMNode *aNode, nsIAccessNode **aAccessNode)
 {
   *aAccessNode = nsnull;
@@ -890,73 +832,73 @@ nsAccessNode::GetLanguage(nsAString& aLa
   }
  
   return NS_OK;
 }
 
 PRBool
 nsAccessNode::GetARIARole(nsIContent *aContent, nsString& aRole)
 {
-  nsAutoString prefix;
-  PRBool strictPrefixChecking = PR_TRUE;
   aRole.Truncate();
 
-  if (aContent->IsNodeOfType(nsINode::eHTML)) { // HTML node
+  PRBool allowPrefixLookup = PR_TRUE;
+
+  if (aContent->IsNodeOfType(nsINode::eHTML)) {
     // Allow non-namespaced role attribute in HTML
-    aContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::role, aRole);
-    // Find non-namespaced role attribute on HTML node
+    if (!aContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::role, aRole)) {
+      return PR_FALSE;
+    }
     nsCOMPtr<nsIDOMNSDocument> doc(do_QueryInterface(aContent->GetDocument()));
     if (doc) {
-      // In text/html we are hardcoded to allow the exact prefix "wairole:" to 
-      // always indicate that we are using the WAI roles.
-      // This allows ARIA to be used within text/html where namespaces cannot be defined.
-      // We also now relax the prefix checking, which means no prefix is required to use WAI Roles
       nsAutoString mimeType;
       doc->GetContentType(mimeType);
       if (mimeType.EqualsLiteral("text/html")) {
-        prefix = NS_LITERAL_STRING("wairole:");
-        strictPrefixChecking = PR_FALSE;
+        allowPrefixLookup = PR_FALSE;
       }
     }
   }
-
-  // Try namespaced-role attribute (xhtml or xhtml2 namespace) -- allowed in any kind of content
-  if (aRole.IsEmpty() && !aContent->GetAttr(kNameSpaceID_XHTML, nsAccessibilityAtoms::role, aRole) &&
-      !aContent->GetAttr(kNameSpaceID_XHTML2_Unofficial, nsAccessibilityAtoms::role, aRole)) {
+  // In non-HTML content, use XHTML namespaced-role attribute
+  else if (!aContent->GetAttr(kNameSpaceID_XHTML, nsAccessibilityAtoms::role, aRole)) {
     return PR_FALSE;
   }
 
   PRBool hasPrefix = (aRole.Find(":") >= 0);
 
   if (!hasPrefix) {
     // * No prefix* -- not a QName
     // Just return entire string as long as prefix is not currently required
-    if (strictPrefixChecking) {
-      // Prefix was required and we didn't have one
-      aRole.Truncate();
-      return PR_FALSE;
-    }
     return PR_TRUE;
   }
 
-  // * Has prefix * -- is a QName (role="prefix:rolename")
-  if (strictPrefixChecking) {  // Not text/html, we need to actually find the WAIRole prefix
+  // Has prefix -- is a QName (role="prefix:rolename")
+
+  // Check hardcoded 'wairole:' prefix
+  NS_NAMED_LITERAL_STRING(hardcodedWairolePrefix, "wairole:");
+  if (StringBeginsWith(aRole, hardcodedWairolePrefix)) {
+    // The exact prefix "wairole:" is reserved to 
+    // always indicate that we are using WAI roles.
+    aRole.Cut(0, hardcodedWairolePrefix.Length());
+    return PR_TRUE;
+  }
+
+  // Check for prefix mapped with xmlns:prefixname=""
+  nsAutoString prefix;
+  if (allowPrefixLookup) {  // Not text/html, so we will try to find the WAIRole prefix
     // QI to nsIDOM3Node causes some overhead. Unfortunately we need to do this each
     // time there is a prefixed role attribute, because the prefix to namespace mappings
     // can change within any subtree via the xmlns attribute
     nsCOMPtr<nsIDOM3Node> dom3Node(do_QueryInterface(aContent));
     if (dom3Node) {
       // Look up exact prefix name for WAI Roles
       NS_NAMED_LITERAL_STRING(kWAIRoles_Namespace, "http://www.w3.org/2005/01/wai-rdf/GUIRoleTaxonomy#");
       dom3Node->LookupPrefix(kWAIRoles_Namespace, prefix);
       prefix += ':';
+      PRUint32 length = prefix.Length();
+      if (length > 1 && StringBeginsWith(aRole, prefix)) {
+        // Is a QName (role="prefix:rolename"), and prefix matches WAI Role prefix
+        // Trim the WAI Role prefix off
+        aRole.Cut(0, length);
+      }
     }
   }
 
-  PRUint32 length = prefix.Length();
-  if (length > 1 && StringBeginsWith(aRole, prefix)) {
-    // Is a QName (role="prefix:rolename"), and prefix matches WAI Role prefix
-    // Trim the WAI Role prefix off
-    aRole.Cut(0, length);
-  }
-
   return PR_TRUE;
 }
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -86,16 +86,17 @@ ACCESSIBILITY_ATOM(tableOuterFrame, "Tab
   // Alphabetical list of tag names
 ACCESSIBILITY_ATOM(a, "a")
 ACCESSIBILITY_ATOM(abbr, "abbr")
 ACCESSIBILITY_ATOM(acronym, "acronym")
 ACCESSIBILITY_ATOM(area, "area")
 ACCESSIBILITY_ATOM(blockquote, "blockquote")
 ACCESSIBILITY_ATOM(br, "br")
 ACCESSIBILITY_ATOM(body, "body")
+ACCESSIBILITY_ATOM(caption, "caption") // XUL
 ACCESSIBILITY_ATOM(choices, "choices") // XForms
 ACCESSIBILITY_ATOM(description, "description")    // XUL
 ACCESSIBILITY_ATOM(dd, "dd")
 ACCESSIBILITY_ATOM(div, "div")
 ACCESSIBILITY_ATOM(dl, "dl")
 ACCESSIBILITY_ATOM(dt, "dt")
 ACCESSIBILITY_ATOM(form, "form")
 ACCESSIBILITY_ATOM(h1, "h1")
@@ -135,79 +136,55 @@ ACCESSIBILITY_ATOM(textbox, "textbox")  
 ACCESSIBILITY_ATOM(toolbaritem, "toolbaritem")   // XUL
 ACCESSIBILITY_ATOM(toolbarseparator, "toolbarseparator")   // XUL
 ACCESSIBILITY_ATOM(toolbarspring, "toolbarspring")   // XUL
 ACCESSIBILITY_ATOM(toolbarspacer, "toolbarspacer")   // XUL
 ACCESSIBILITY_ATOM(tooltip, "tooltip")   // XUL
 ACCESSIBILITY_ATOM(tr, "tr")
 ACCESSIBILITY_ATOM(ul, "ul")
 
-  // DHTML accessibility relationship attributes
-ACCESSIBILITY_ATOM(controls, "controls")
-ACCESSIBILITY_ATOM(describedby, "describedby")
-ACCESSIBILITY_ATOM(flowto, "flowto")
-ACCESSIBILITY_ATOM(labelledby, "labelledby")
-ACCESSIBILITY_ATOM(owns, "owns")
-
   // Alphabetical list of attributes
 ACCESSIBILITY_ATOM(acceltext, "acceltext")
 ACCESSIBILITY_ATOM(accesskey, "accesskey")
 ACCESSIBILITY_ATOM(alt, "alt")
 ACCESSIBILITY_ATOM(anonid, "anonid") // Used for ID's in XBL
-ACCESSIBILITY_ATOM(autocomplete, "autocomplete") // Used as attribute value too
 ACCESSIBILITY_ATOM(contenteditable, "contenteditable")
 ACCESSIBILITY_ATOM(control, "control")
 ACCESSIBILITY_ATOM(cycles, "cycles") // used for XUL cycler attribute
 ACCESSIBILITY_ATOM(curpos, "curpos") // XUL
 ACCESSIBILITY_ATOM(data, "data")
-ACCESSIBILITY_ATOM(disabled, "disabled")
 ACCESSIBILITY_ATOM(droppable, "droppable")   // XUL combo box
 ACCESSIBILITY_ATOM(editable, "editable")
 ACCESSIBILITY_ATOM(_for, "for")
 ACCESSIBILITY_ATOM(hidden, "hidden")   // XUL tree columns
 ACCESSIBILITY_ATOM(href, "href")
 ACCESSIBILITY_ATOM(increment, "increment") // XUL
 ACCESSIBILITY_ATOM(lang, "lang")
 ACCESSIBILITY_ATOM(maxpos, "maxpos") // XUL
 ACCESSIBILITY_ATOM(minpos, "minpos") // XUL
-ACCESSIBILITY_ATOM(multiline, "multiline")
 ACCESSIBILITY_ATOM(name, "name")
 ACCESSIBILITY_ATOM(onclick, "onclick")
-ACCESSIBILITY_ATOM(readonly, "readonly")
 ACCESSIBILITY_ATOM(src, "src")
 ACCESSIBILITY_ATOM(summary, "summary")
 ACCESSIBILITY_ATOM(tabindex, "tabindex")
 ACCESSIBILITY_ATOM(title, "title")
 ACCESSIBILITY_ATOM(tooltiptext, "tooltiptext")
 ACCESSIBILITY_ATOM(type, "type")
 ACCESSIBILITY_ATOM(value, "value")
 
   // ARIA (DHTML accessibility) attributes
-ACCESSIBILITY_ATOM(atomic, "atomic")
-ACCESSIBILITY_ATOM(busy, "busy")
-ACCESSIBILITY_ATOM(channel, "channel")
-ACCESSIBILITY_ATOM(activedescendant, "activedescendant")
-ACCESSIBILITY_ATOM(checked, "checked")
-ACCESSIBILITY_ATOM(datatype, "datatype")
-ACCESSIBILITY_ATOM(dropeffect, "dropeffect")
-ACCESSIBILITY_ATOM(expanded, "expanded")
-ACCESSIBILITY_ATOM(grab, "grab")
-ACCESSIBILITY_ATOM(haspopup, "haspopup")
-ACCESSIBILITY_ATOM(invalid, "invalid")
-ACCESSIBILITY_ATOM(level, "level")
-ACCESSIBILITY_ATOM(live, "live")
-ACCESSIBILITY_ATOM(multiselectable, "multiselectable")
-ACCESSIBILITY_ATOM(posinset, "posinset")
-ACCESSIBILITY_ATOM(pressed, "pressed")
-ACCESSIBILITY_ATOM(relevant, "relevant")
-ACCESSIBILITY_ATOM(required, "required")
+  // Also add to nsARIAMap.cpp and nsARIAMap.h
+  // ARIA role attribute
 ACCESSIBILITY_ATOM(role, "role")
-ACCESSIBILITY_ATOM(secret, "secret")
-ACCESSIBILITY_ATOM(selected, "selected")
-ACCESSIBILITY_ATOM(setsize, "setsize")
-ACCESSIBILITY_ATOM(valuenow, "valuenow")    // For DHTML widget values
-ACCESSIBILITY_ATOM(valuemin, "valuemin")
-ACCESSIBILITY_ATOM(valuemax, "valuemax")
+
+  // ARIA properties
+#define ARIA_PROPERTY(atom) ACCESSIBILITY_ATOM(atom, #atom)
+#include "nsARIAPropertyList.h"
+#undef ARIA_PROPERTY
+
+#define ARIA_PROPERTY(atom) ACCESSIBILITY_ATOM(aria_##atom, "aria-"#atom)
+#include "nsARIAPropertyList.h"
+#undef ARIA_PROPERTY
 
   // misc atoms
 // a form property used to obtain the default label
 // of an HTML button from the button frame
 ACCESSIBILITY_ATOM(defaultLabel, "defaultLabel")
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -1039,17 +1039,20 @@ nsAccessibilityService::GetStringStates(
   return NS_OK;
 }
 
 // nsIAccessibleRetrieval::getStringEventType()
 NS_IMETHODIMP
 nsAccessibilityService::GetStringEventType(PRUint32 aEventType,
                                            nsAString& aString)
 {
-  if ( aEventType >= NS_ARRAY_LENGTH(kEventTypeNames)) {
+  NS_ASSERTION(nsIAccessibleEvent::EVENT_LAST_ENTRY == NS_ARRAY_LENGTH(kEventTypeNames),
+               "nsIAccessibleEvent constants are out of sync to kEventTypeNames");
+
+  if (aEventType >= NS_ARRAY_LENGTH(kEventTypeNames)) {
     aString.AssignLiteral("unknown");
     return NS_OK;
   }
 
   CopyUTF8toUTF16(kEventTypeNames[aEventType], aString);
   return NS_OK;
 }
 
@@ -1424,50 +1427,68 @@ NS_IMETHODIMP nsAccessibilityService::Ge
     GetAccessibleForDeckChildren(aNode, getter_AddRefs(newAcc));
   }
 
   // If no accessible, see if we need to create a generic accessible because
   // of some property that makes this object interesting
   // We don't do this for <body>, <html>, <window>, <dialog> etc. which 
   // correspond to the doc accessible and will be created in any case
   if (!newAcc && content->Tag() != nsAccessibilityAtoms::body && content->GetParent() && 
-      (content->IsFocusable() || content->GetID() ||
+      (content->IsFocusable() ||
       (isHTML && nsAccUtils::HasListener(content, NS_LITERAL_STRING("click"))) ||
-       content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::describedby) ||
-       content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::labelledby) ||
-       content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::flowto) ||
-       content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::controls) ||
-       content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::atomic) ||
-       content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::busy) ||
-       content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::channel) ||
-       content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::datatype) ||
-       content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::dropeffect) ||
-       content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::grab) ||
-       content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::haspopup) ||
-       content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::live) ||
-       content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::relevant) ||
-       content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::required) ||
-       content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::invalid) ||
-       !role.IsEmpty())) {
+       HasUniversalAriaProperty(content, aWeakShell) || !role.IsEmpty())) {
     // This content is focusable or has an interesting dynamic content accessibility property.
     // If it's interesting we need it in the accessibility hierarchy so that events or
     // other accessibles can point to it, or so that it can hold a state, etc.
     if (isHTML) {
       // Interesting HTML container which may have selectable text and/or embedded objects
       CreateHyperTextAccessible(frame, getter_AddRefs(newAcc));
     }
     else {  // XUL, SVG, MathML etc.
       // Interesting generic non-HTML container
       newAcc = new nsAccessibleWrap(aNode, aWeakShell);
     }
   }
 
   return InitAccessible(newAcc, aAccessible);
 }
 
+PRBool
+nsAccessibilityService::HasUniversalAriaProperty(nsIContent *aContent,
+                                                 nsIWeakReference *aWeakShell)
+{
+  nsCOMPtr<nsIAccessibleDocument> docAccessible =
+    nsAccessNode::GetDocAccessibleFor(aWeakShell);
+  if (!docAccessible) {
+    return PR_FALSE;
+  }
+
+  // Precalculate |ariaPropTypes| so that HasAriaProperty() doesn't have to do that each time
+  PRUint32 ariaPropTypes;
+  docAccessible->GetAriaPropTypes(&ariaPropTypes);
+
+  return nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_atomic, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_busy, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_channel, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_controls, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_datatype, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_describedby, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_dropeffect, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_flowto, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_grab, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_haspopup, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_invalid, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_labelledby, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_live, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_owns, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_relevant, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_required, ariaPropTypes) ||
+         nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_sort, ariaPropTypes);
+}
+
 NS_IMETHODIMP
 nsAccessibilityService::GetRelevantContentNodeFor(nsIDOMNode *aNode,
                                                   nsIDOMNode **aRelevantNode)
 {
   // The method returns node that is relevant for attached accessible check.
   // Sometimes element that is XBL widget hasn't accessible children in
   // anonymous content. This method check whether given node can be accessible
   // by looking through all nested bindings that given node is anonymous for. If
--- a/accessible/src/base/nsAccessibilityService.h
+++ b/accessible/src/base/nsAccessibilityService.h
@@ -114,16 +114,26 @@ private:
    * Return accessible object if parent is a deck frame.
    *
    * @param aNode - DOMNode that accessible is returned for.
    */
   nsresult GetAccessibleForDeckChildren(nsIDOMNode *aNode,
                                         nsIAccessible **aAccessible);
 
   static nsAccessibilityService *gAccessibilityService;
+
+  /**
+   * Does this content node have a universal ARIA property set on it?
+   * A universal ARIA property is one that can be defined on any element even if there is no role.
+   *
+   * @param aContent The content node to test
+   * @param aWeakShell  A weak reference to the pres shell
+   * @return PR_TRUE if there is a universal ARIA property set on the node
+   */
+  PRBool HasUniversalAriaProperty(nsIContent *aContent, nsIWeakReference *aWeakShell);
 };
 
 /**
  * Map nsIAccessibleRole constants to strings. Used by
  * nsIAccessibleRetrieval::getStringRole() method.
  */
 static const char kRoleNames[][20] = {
   "nothing",             //ROLE_NOTHING
@@ -335,13 +345,14 @@ static const char kEventTypeNames[][40] 
   "hyperlink number of anchors changed",     // EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED
   "hyperlink selected link changed",         // EVENT_HYPERLINK_SELECTED_LINK_CHANGED
   "hypertext link activated",                // EVENT_HYPERTEXT_LINK_ACTIVATED
   "hypertext link selected",                 // EVENT_HYPERTEXT_LINK_SELECTED
   "hyperlink start index changed",           // EVENT_HYPERLINK_START_INDEX_CHANGED
   "hypertext changed",                       // EVENT_HYPERTEXT_CHANGED
   "hypertext links count changed",           // EVENT_HYPERTEXT_NLINKS_CHANGED
   "object attribute changed",                // EVENT_OBJECT_ATTRIBUTE_CHANGED
+  "page changed",                            // EVENT_PAGE_CHANGED
   "internal load",                           // EVENT_INTERNAL_LOAD
   "reorder"                                  // EVENT_REORDER
 };
 
 #endif /* __nsIAccessibilityService_h__ */
--- a/accessible/src/base/nsAccessibilityUtils.cpp
+++ b/accessible/src/base/nsAccessibilityUtils.cpp
@@ -33,31 +33,38 @@
  * 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 "nsAccessibilityUtils.h"
 
+#include "nsIAccessibleStates.h"
 #include "nsIAccessibleTypes.h"
 #include "nsPIAccessible.h"
+#include "nsPIAccessNode.h"
 #include "nsAccessibleEventData.h"
 
+#include "nsAccessible.h"
+#include "nsARIAMap.h"
 #include "nsIDocument.h"
 #include "nsIDOMAbstractView.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentView.h"
+#include "nsIDOMDocumentXBL.h"
+#include "nsIDOMNodeList.h"
 #include "nsIDOMRange.h"
 #include "nsIDOMXULSelectCntrlEl.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIDOMWindowInternal.h"
 #include "nsIEventListenerManager.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
+#include "nsIScrollableFrame.h"
 #include "nsIEventStateManager.h"
 #include "nsISelection2.h"
 #include "nsISelectionController.h"
 
 #include "nsContentCID.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 
@@ -164,22 +171,40 @@ nsAccUtils::SetAccAttrsForXULSelectContr
   if (!item)
     return;
 
   nsCOMPtr<nsIDOMXULSelectControlElement> control;
   item->GetControl(getter_AddRefs(control));
   if (!control)
     return;
 
-  PRUint32 itemsCount;
+  PRUint32 itemsCount = 0;
   control->GetItemCount(&itemsCount);
-  PRInt32 indexOf;
+
+  PRInt32 indexOf = 0;
   control->GetIndexOfItem(item, &indexOf);
 
-  SetAccGroupAttrs(aAttributes, 0, indexOf + 1, itemsCount);
+  PRUint32 setSize = itemsCount, posInSet = indexOf;
+  for (PRUint32 index = 0; index < itemsCount; index++) {
+    nsCOMPtr<nsIDOMXULSelectControlItemElement> currItem;
+    control->GetItemAtIndex(index, getter_AddRefs(currItem));
+    nsCOMPtr<nsIDOMNode> currNode(do_QueryInterface(currItem));
+
+    nsCOMPtr<nsIAccessible> itemAcc;
+    nsAccessNode::GetAccService()->GetAccessibleFor(currNode,
+                                                    getter_AddRefs(itemAcc));
+    if (!itemAcc ||
+        nsAccessible::State(itemAcc) & nsIAccessibleStates::STATE_INVISIBLE) {
+      setSize--;
+      if (index < indexOf)
+        posInSet--;
+    }
+  }
+
+  SetAccGroupAttrs(aAttributes, 0, posInSet + 1, setSize);
 }
 
 PRBool
 nsAccUtils::HasListener(nsIContent *aContent, const nsAString& aEventType)
 {
   NS_ENSURE_ARG_POINTER(aContent);
   nsCOMPtr<nsIEventListenerManager> listenerManager;
   aContent->GetListenerManager(PR_FALSE, getter_AddRefs(listenerManager));
@@ -278,16 +303,29 @@ nsAccUtils::GetAncestorWithRole(nsIAcces
 }
 
 nsresult
 nsAccUtils::ScrollSubstringTo(nsIFrame *aFrame,
                               nsIDOMNode *aStartNode, PRInt32 aStartIndex,
                               nsIDOMNode *aEndNode, PRInt32 aEndIndex,
                               PRUint32 aScrollType)
 {
+  PRInt16 vPercent, hPercent;
+  ConvertScrollTypeToPercents(aScrollType, &vPercent, &hPercent);
+
+  return ScrollSubstringTo(aFrame, aStartNode, aStartIndex, aEndNode, aEndIndex,
+                           vPercent, hPercent);
+}
+
+nsresult
+nsAccUtils::ScrollSubstringTo(nsIFrame *aFrame,
+                              nsIDOMNode *aStartNode, PRInt32 aStartIndex,
+                              nsIDOMNode *aEndNode, PRInt32 aEndIndex,
+                              PRInt16 aVPercent, PRInt16 aHPercent)
+{
   if (!aFrame || !aStartNode || !aEndNode)
     return NS_ERROR_FAILURE;
 
   nsPresContext *presContext = aFrame->PresContext();
 
   nsCOMPtr<nsIDOMRange> scrollToRange = do_CreateInstance(kRangeCID);
   NS_ENSURE_TRUE(scrollToRange, NS_ERROR_FAILURE);
 
@@ -302,28 +340,52 @@ nsAccUtils::ScrollSubstringTo(nsIFrame *
   selCon->GetSelection(nsISelectionController::SELECTION_ACCESSIBILITY,
                        getter_AddRefs(selection1));
 
   nsCOMPtr<nsISelection2> selection(do_QueryInterface(selection1));
   if (selection) {
     selection->RemoveAllRanges();
     selection->AddRange(scrollToRange);
 
-    PRInt16 vPercent, hPercent;
-    ConvertScrollTypeToPercents(aScrollType, &vPercent, &hPercent);
     selection->ScrollIntoView(nsISelectionController::SELECTION_ANCHOR_REGION,
-                              PR_TRUE, vPercent, hPercent);
+                              PR_TRUE, aVPercent, aHPercent);
 
     selection->CollapseToStart();
   }
 
   return NS_OK;
 }
 
 void
+nsAccUtils::ScrollFrameToPoint(nsIFrame *aScrollableFrame,
+                               nsIFrame *aFrame,
+                               const nsIntPoint& aPoint)
+{
+  nsIScrollableFrame *scrollableFrame = nsnull;
+  CallQueryInterface(aScrollableFrame, &scrollableFrame);
+  if (!scrollableFrame)
+    return;
+
+  nsPresContext *presContext = aFrame->PresContext();
+
+  nsIntRect frameRect = aFrame->GetScreenRectExternal();
+  PRInt32 devDeltaX = aPoint.x - frameRect.x;
+  PRInt32 devDeltaY = aPoint.y - frameRect.y;
+
+  nsPoint deltaPoint;
+  deltaPoint.x = presContext->DevPixelsToAppUnits(devDeltaX);
+  deltaPoint.y = presContext->DevPixelsToAppUnits(devDeltaY);
+
+  nsPoint scrollPoint = scrollableFrame->GetScrollPosition();
+  scrollPoint -= deltaPoint;
+
+  scrollableFrame->ScrollTo(scrollPoint);
+}
+
+void
 nsAccUtils::ConvertScrollTypeToPercents(PRUint32 aScrollType,
                                         PRInt16 *aVPercent,
                                         PRInt16 *aHPercent)
 {
   switch (aScrollType)
   {
     case nsIAccessibleScrollType::SCROLL_TYPE_TOP_LEFT:
       *aVPercent = NS_PRESSHELL_SCROLL_TOP;
@@ -350,16 +412,77 @@ nsAccUtils::ConvertScrollTypeToPercents(
       *aHPercent = NS_PRESSHELL_SCROLL_RIGHT;
       break;
     default:
       *aVPercent = NS_PRESSHELL_SCROLL_ANYWHERE;
       *aHPercent = NS_PRESSHELL_SCROLL_ANYWHERE;
   }
 }
 
+nsresult
+nsAccUtils::ConvertToScreenCoords(PRInt32 aX, PRInt32 aY,
+                                  PRUint32 aCoordinateType,
+                                  nsIAccessNode *aAccessNode,
+                                  nsIntPoint *aCoords)
+{
+  NS_ENSURE_ARG_POINTER(aCoords);
+
+  aCoords->MoveTo(aX, aY);
+
+  switch (aCoordinateType) {
+    case nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE:
+      break;
+
+    case nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE:
+    {
+      NS_ENSURE_ARG(aAccessNode);
+
+      nsCOMPtr<nsIDOMNode> DOMNode;
+      aAccessNode->GetDOMNode(getter_AddRefs(DOMNode));
+      NS_ENSURE_STATE(DOMNode);
+
+      nsIntPoint wndCoords = nsAccUtils::GetScreenCoordsForWindow(DOMNode);
+      *aCoords += wndCoords;
+      break;
+    }
+
+    case nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE:
+    {
+      NS_ENSURE_ARG(aAccessNode);
+
+      nsCOMPtr<nsPIAccessNode> parent;
+      nsCOMPtr<nsIAccessible> accessible(do_QueryInterface(aAccessNode));
+      if (accessible) {
+        nsCOMPtr<nsIAccessible> parentAccessible;
+        accessible->GetParent(getter_AddRefs(parentAccessible));
+        parent = do_QueryInterface(parentAccessible);
+      } else {
+        nsCOMPtr<nsIAccessNode> parentAccessNode;
+        aAccessNode->GetParentNode(getter_AddRefs(parentAccessNode));
+        parent = do_QueryInterface(parentAccessNode);
+      }
+
+      NS_ENSURE_STATE(parent);
+
+      nsIFrame *parentFrame = parent->GetFrame();
+      NS_ENSURE_STATE(parentFrame);
+
+      nsIntRect parentRect = parentFrame->GetScreenRectExternal();
+      aCoords->x += parentRect.x;
+      aCoords->y += parentRect.y;
+      break;
+    }
+
+    default:
+      return NS_ERROR_INVALID_ARG;
+  }
+
+  return NS_OK;
+}
+
 nsIntPoint
 nsAccUtils::GetScreenCoordsForWindow(nsIDOMNode *aNode)
 {
   nsIntPoint coords(0, 0);
   nsCOMPtr<nsIDocShellTreeItem> treeItem(GetDocShellTreeItemFor(aNode));
   if (!treeItem)
     return coords;
 
@@ -405,8 +528,230 @@ nsAccUtils::GetDocShellTreeItemFor(nsIDO
 }
 
 PRBool
 nsAccUtils::GetID(nsIContent *aContent, nsAString& aID)
 {
   nsIAtom *idAttribute = aContent->GetIDAttributeName();
   return idAttribute ? aContent->GetAttr(kNameSpaceID_None, idAttribute, aID) : PR_FALSE;
 }
+
+PRUint32
+nsAccUtils::GetAriaPropTypes(nsIContent *aContent, nsIWeakReference *aWeakShell)
+{
+  NS_ENSURE_ARG_POINTER(aContent);
+
+  PRUint32 ariaPropTypes = 0;
+
+  // Get the doc accessible using the optimsal methodology
+  nsCOMPtr<nsIAccessibleDocument> docAccessible;
+  if (aWeakShell) {
+    docAccessible = nsAccessNode::GetDocAccessibleFor(aWeakShell);
+  }
+  else {
+      nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aContent);
+    if (node) {
+      docAccessible = nsAccessNode::GetDocAccessibleFor(node);
+    }
+  }
+  if (docAccessible) {
+    docAccessible->GetAriaPropTypes(&ariaPropTypes);
+  }
+  return ariaPropTypes;
+}
+
+PRBool
+nsAccUtils::HasAriaProperty(nsIContent *aContent, nsIWeakReference *aWeakShell,
+                            EAriaProperty aProperty, PRUint32 aAriaPropTypes)
+{
+  if (!aAriaPropTypes) {
+    // The property types to check for is unknown, get it from the doc accessible
+    aAriaPropTypes = GetAriaPropTypes(aContent, aWeakShell);
+  }
+
+  return ((aAriaPropTypes & nsIAccessibleDocument::eCheckNamespaced) &&
+          aContent->HasAttr(kNameSpaceID_WAIProperties,
+                            *nsARIAMap::gAriaAtomPtrsNS[aProperty])) ||
+         ((aAriaPropTypes & nsIAccessibleDocument::eCheckHyphenated) &&
+          aContent->HasAttr(kNameSpaceID_None,
+                            *nsARIAMap::gAriaAtomPtrsHyphenated[aProperty]));
+}
+
+PRBool
+nsAccUtils::GetAriaProperty(nsIContent *aContent, nsIWeakReference *aWeakShell,
+                            EAriaProperty aProperty, nsAString& aValue,
+                            PRUint32 aAriaPropTypes)
+{
+  aValue.Truncate();
+  if (!aAriaPropTypes) {
+    // The property types to check for is unknown, get it from the doc accessible
+    aAriaPropTypes = GetAriaPropTypes(aContent, aWeakShell);
+  }
+  return ((aAriaPropTypes & nsIAccessibleDocument::eCheckNamespaced) &&
+          aContent->GetAttr(kNameSpaceID_WAIProperties,
+                            *nsARIAMap::gAriaAtomPtrsNS[aProperty],
+                            aValue)) ||
+         ((aAriaPropTypes & nsIAccessibleDocument::eCheckHyphenated) &&
+          aContent->GetAttr(kNameSpaceID_None,
+                            *nsARIAMap::gAriaAtomPtrsHyphenated[aProperty],
+                            aValue));
+}
+
+nsIContent*
+nsAccUtils::FindNeighbourPointingToNode(nsIContent *aForNode, 
+                                        EAriaProperty aAriaProperty, 
+                                        nsIAtom *aTagName,
+                                        nsIAtom *aRelationAttr,
+                                        PRUint32 aAncestorLevelsToSearch)
+{
+  NS_ASSERTION(aAriaProperty == eAria_none || !aRelationAttr,
+               "Cannot pass in both an ARIA relation property and an atom relation. Choose one");
+  NS_ASSERTION(aAriaProperty == eAria_none || !aTagName,
+               "Cannot use aTagName with ARIA relation property, because ARIA relations apply to any tag");
+  nsCOMPtr<nsIContent> binding;
+  nsAutoString controlID;
+  if (!nsAccUtils::GetID(aForNode, controlID)) {
+    binding = aForNode->GetBindingParent();
+    if (binding == aForNode)
+      return nsnull;
+
+    aForNode->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::anonid, controlID);
+    if (controlID.IsEmpty())
+      return nsnull;
+  }
+
+  // Look for label in subtrees of nearby ancestors
+  PRUint32 count = 0;
+  nsIContent *labelContent = nsnull;
+  nsIContent *prevSearched = nsnull;
+
+  while (!labelContent && ++count <= aAncestorLevelsToSearch &&
+         (aForNode = aForNode->GetParent()) != nsnull) {
+
+    if (aForNode == binding) {
+      // When we reach the binding parent, make sure to check
+      // all of its anonymous child subtrees
+      nsCOMPtr<nsIDocument> doc = aForNode->GetCurrentDoc();
+      nsCOMPtr<nsIDOMDocumentXBL> xblDoc(do_QueryInterface(doc));
+      if (!xblDoc)
+        return nsnull;
+
+      nsCOMPtr<nsIDOMNodeList> nodes;
+      nsCOMPtr<nsIDOMElement> forElm(do_QueryInterface(aForNode));
+      xblDoc->GetAnonymousNodes(forElm, getter_AddRefs(nodes));
+      if (!nodes)
+        return nsnull;
+
+      PRUint32 length;
+      nsresult rv = nodes->GetLength(&length);
+      if (NS_FAILED(rv))
+        return nsnull;
+
+      for (PRUint32 index = 0; index < length && !labelContent; index++) {
+        nsCOMPtr<nsIDOMNode> node;
+        rv = nodes->Item(index, getter_AddRefs(node));
+        if (NS_FAILED(rv))
+          return nsnull;
+
+        nsCOMPtr<nsIContent> content = do_QueryInterface(node);
+        if (!content)
+          return nsnull;
+
+        if (content != prevSearched) {
+          labelContent = FindDescendantPointingToID(&controlID, content, aAriaProperty,
+                                                    aRelationAttr, nsnull, aTagName);
+        }
+      }
+      break;
+    }
+
+    labelContent = FindDescendantPointingToID(&controlID, aForNode, aAriaProperty,
+                                              aRelationAttr, prevSearched, aTagName);
+    prevSearched = aForNode;
+  }
+
+  return labelContent;
+}
+
+// Pass in aAriaProperty = null and aRelationAttr == nsnull if any <label> will do
+nsIContent*
+nsAccUtils::FindDescendantPointingToID(const nsString *aId,
+                                       nsIContent *aLookContent,
+                                       EAriaProperty aAriaProperty,
+                                       nsIAtom *aRelationAttr,
+                                       nsIContent *aExcludeContent,
+                                       nsIAtom *aTagType)
+{
+  // Surround id with spaces for search
+  nsCAutoString idWithSpaces(' ');
+  LossyAppendUTF16toASCII(*aId, idWithSpaces);
+  idWithSpaces += ' ';
+  PRUint32 ariaPropTypes = (aAriaProperty == eAria_none) ? 0 :
+                            nsAccUtils::GetAriaPropTypes(aLookContent);
+  return FindDescendantPointingToIDImpl(idWithSpaces, aLookContent,
+                                        aAriaProperty, ariaPropTypes,
+                                        aRelationAttr, aExcludeContent, aTagType);
+}
+
+nsIContent*
+nsAccUtils::FindDescendantPointingToIDImpl(nsCString& aIdWithSpaces,
+                                           nsIContent *aLookContent,
+                                           EAriaProperty aAriaProperty,
+                                           PRUint32 aAriaPropTypes,
+                                           nsIAtom *aRelationAttr,
+                                           nsIContent *aExcludeContent,
+                                           nsIAtom *aTagType)
+{
+  if (aAriaProperty != eAria_none) {  // Tag ignored for ARIA properties, which can apply to anything
+    nsAutoString idList;
+    if (nsAccUtils::GetAriaProperty(aLookContent, nsnull, aAriaProperty,
+                                    idList, aAriaPropTypes)) {
+      idList.Insert(' ', 0);  // Surround idlist with spaces for search
+      idList.Append(' ');
+      // idList is now a set of id's with spaces around each,
+      // and id also has spaces around it.
+      // If id is a substring of idList then we have a match
+      if (idList.Find(aIdWithSpaces) != -1) {
+        return aLookContent;
+      }
+    }
+  }
+  else if (!aTagType || aLookContent->Tag() == aTagType) {
+    // Tag matches
+    if (aRelationAttr) {
+      // Check for ID in the attribute aRelationAttr, which can be a list
+      nsAutoString idList;
+      if (aLookContent->GetAttr(kNameSpaceID_None, aRelationAttr, idList)) {
+        idList.Insert(' ', 0);  // Surround idlist with spaces for search
+        idList.Append(' ');
+        // idList is now a set of id's with spaces around each,
+        // and id also has spaces around it.
+        // If id is a substring of idList then we have a match
+        if (idList.Find(aIdWithSpaces) != -1) {
+          return aLookContent;
+        }
+      }
+    }
+    if (aTagType) {
+      // Don't bother to search descendants of an element with matching tag.
+      // That would be like looking for a nested <label> or <description>
+      return nsnull;
+    }
+  }
+
+  // Recursively search descendants for match
+  PRUint32 count  = 0;
+  nsIContent *child;
+  nsIContent *labelContent = nsnull;
+
+  while ((child = aLookContent->GetChildAt(count++)) != nsnull) {
+    if (child != aExcludeContent) {
+      labelContent = FindDescendantPointingToIDImpl(aIdWithSpaces, child,
+                                                    aAriaProperty, aAriaPropTypes,
+                                                    aRelationAttr, aExcludeContent, aTagType);
+      if (labelContent) {
+        return labelContent;
+      }
+    }
+  }
+  return nsnull;
+}
+
--- a/accessible/src/base/nsAccessibilityUtils.h
+++ b/accessible/src/base/nsAccessibilityUtils.h
@@ -36,23 +36,26 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsAccessibilityUtils_h_
 #define nsAccessibilityUtils_h_
 
 #include "nsAccessibilityAtoms.h"
 #include "nsIAccessible.h"
+#include "nsIAccessNode.h"
+#include "nsARIAMap.h"
 
 #include "nsIDOMNode.h"
 #include "nsIPersistentProperties2.h"
 #include "nsIContent.h"
 #include "nsIFrame.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsPoint.h"
+#include "nsIAccessibleDocument.h"
 
 class nsAccUtils
 {
 public:
   /**
    * Returns value of attribute from the given attributes container.
    *
    * @param aAttributes - attributes container
@@ -155,25 +158,68 @@ public:
    * @param aEndOffset    an offset inside the end node
    * @param aScrollType   the place a range should be scrolled to
    */
   static nsresult ScrollSubstringTo(nsIFrame *aFrame,
                                     nsIDOMNode *aStartNode, PRInt32 aStartIndex,
                                     nsIDOMNode *aEndNode, PRInt32 aEndIndex,
                                     PRUint32 aScrollType);
 
+  /** Helper method to scroll range into view, used for implementation of
+   * nsIAccessibleText::scrollSubstringTo[Point]().
+   *
+   * @param aFrame        the frame for accessible the range belongs to.
+   * @param aStartNode    start node of a range
+   * @param aStartOffset  an offset inside the start node
+   * @param aEndNode      end node of a range
+   * @param aEndOffset    an offset inside the end node
+   * @param aVPercent     how to align vertically, specified in percents
+   * @param aHPercent     how to align horizontally, specified in percents
+   */
+  static nsresult ScrollSubstringTo(nsIFrame *aFrame,
+                                    nsIDOMNode *aStartNode, PRInt32 aStartIndex,
+                                    nsIDOMNode *aEndNode, PRInt32 aEndIndex,
+                                    PRInt16 aVPercent, PRInt16 aHPercent);
+
+  /**
+   * Scrolls the given frame to the point, used for implememntation of
+   * nsIAccessNode::scrollToPoint and nsIAccessibleText::scrollSubstringToPoint.
+   *
+   * @param aScrollableFrame  the scrollable frame
+   * @param aFrame            the frame to scroll
+   * @param aPoint            the point scroll to
+   */
+  static void ScrollFrameToPoint(nsIFrame *aScrollableFrame,
+                                 nsIFrame *aFrame, const nsIntPoint& aPoint);
+
   /**
    * Converts scroll type constant defined in nsIAccessibleScrollType to
    * vertical and horizontal percents.
    */
   static void ConvertScrollTypeToPercents(PRUint32 aScrollType,
                                           PRInt16 *aVPercent,
                                           PRInt16 *aHPercent);
 
   /**
+   * Converts the given coordinates to coordinates relative screen.
+   *
+   * @param aX               [in] the given x coord
+   * @param aY               [in] the given y coord
+   * @param aCoordinateType  [in] specifies coordinates origin (refer to
+   *                         nsIAccessibleCoordinateType)
+   * @param aAccessNode      [in] the accessible if coordinates are given
+   *                         relative it.
+   * @param aCoords          [out] converted coordinates
+   */
+  static nsresult ConvertToScreenCoords(PRInt32 aX, PRInt32 aY,
+                                        PRUint32 aCoordinateType,
+                                        nsIAccessNode *aAccessNode,
+                                        nsIntPoint *aCoords);
+
+  /**
    * Returns coordinates relative screen for the top level window.
    *
    * @param - aNode - the DOM node hosted in the window.
    */
   static nsIntPoint GetScreenCoordsForWindow(nsIDOMNode *aNode);
 
   /**
    * Return document shell tree item for the given DOM node.
@@ -183,12 +229,98 @@ public:
 
   /**
    * Get the ID for an element, in some types of XML this may not be the ID attribute
    * @param aContent  Node to get the ID for
    * @param aID       Where to put ID string
    * @return          PR_TRUE if there is an ID set for this node
    */
   static PRBool GetID(nsIContent *aContent, nsAString& aID);
+
+  /**
+   * Find out what kinds of properties are checked for this content node's document
+   * @param aContent     The content node we're going to look for ARIA properties on
+   * @param aWeakShell   The presshell for the document we're looking for ARIA properties on (optional optimization)
+   * @return             The types of properties checked
+   */
+  static PRUint32 GetAriaPropTypes(nsIContent *aContent, nsIWeakReference *aWeakShell = nsnull);
+
+  /**
+   *  Check for the relevant ARIA property. Can check either for a properly namespaced property,
+   *  or a fake hyphenated namespace using "aria-" as a prefix in HTML. Is optimized to only
+   *  check for each type when it is possible to exist on a given node.
+   *  @param aContent     Node to check for property on
+   *  @param aWeakShell   The current pres shell if known (as an optimization), or nsnull if not known by caller
+   *  @param aProperty    An enumeration indicating which ARIA property we are checking
+   *  @param aAriaPropTypes  A bitflag for the property types to check for (namespaced, hyphenated or both), if known by caller
+   *  @return             PR_TRUE if the property is defined
+   */
+  static PRBool HasAriaProperty(nsIContent *aContent, nsIWeakReference *aWeakShell,
+                                EAriaProperty aProperty,
+                                PRUint32 aCheckFlags = 0);
+
+  /**
+   *  Get the relevant ARIA property. Can check either for a properly namespaced property,
+   *  or a fake hyphenated namespace using "aria-" as a prefix in HTML. Is optimized to only
+   *  check for each type when it is possible to exist on a given node.
+   *  @param aContent     Node to check for property on
+   *  @param aWeakShell   The current pres shell if known (as an optimization), or nsnull if not known by caller
+   *  @param aProperty    An enumeration indicating which ARIA property we are checking
+   *  @param aValue       Where to store the property value
+   *  @param aAriaPropTypes  A bitflag for the property types to check for (namespaced, hyphenated or both), if known by caller
+   *  @return             PR_TRUE if the property is defined
+   */
+  static PRBool GetAriaProperty(nsIContent *aContent, nsIWeakReference *aWeakShell,
+                                EAriaProperty aProperty, nsAString& aValue, 
+                                PRUint32 aCheckFlags = 0);
+
+  /**
+   * Search element in neighborhood of the given element by tag name and
+   * attribute value that equals to ID attribute of the given element.
+   * ID attribute can be either 'id' attribute or 'anonid' if the element is
+   * anonymous.
+   *
+   * @param aAriaProperty - the ARIA property to search for or eAria_none, if aRelationAttr is passed in
+   * @param aForNode - the given element the search is performed for
+   * @param aTagName - tag name of searched element, or nsnull for any -- ignored if aAriaProperty passed in
+   * @param aRelationAttr - attribute name of searched element, ignored if aAriaProperty passed in
+   * @param aAncestorLevelsToSearch - points how is the neighborhood of the
+   *                                  given element big.
+   */
+  static nsIContent *FindNeighbourPointingToNode(nsIContent *aForNode,
+                                                 EAriaProperty aAriaProperty,
+                                                 nsIAtom *aTagName = nsnull,
+                                                 nsIAtom *aRelationAttr = nsnull,
+                                                 PRUint32 aAncestorLevelsToSearch = 5);
+
+  /**
+   * Search for element that satisfies the requirements in subtree of the given
+   * element. The requirements are tag name, attribute name and value of
+   * attribute.
+   *
+   * @param aId - value of searched attribute
+   * @param aLookContent - element that search is performed inside
+   * @param aAriaProperty - the ARIA property to search for or eAria_none, if aRelationAttr is passed in
+   * @param aRelationAttr - searched attribute-- ignored if aAriaProperty passed in
+   * @param                 if both aAriaProperty and aRelationAttr are null, then any element with aTagType will do
+   * @param aExcludeContent - element that is skiped for search
+   * @param aTagType - tag name of searched element, by default it is 'label' --
+   *                   ignored if aAriaProperty passed in
+   */
+  static nsIContent *FindDescendantPointingToID(const nsString *aId,
+                                                nsIContent *aLookContent,
+                                                EAriaProperty aAriaProperty,
+                                                nsIAtom *aRelationAttr = nsnull,
+                                                nsIContent *aExcludeContent = nsnull,
+                                                nsIAtom *aTagType = nsAccessibilityAtoms::label);
+
+  // Helper for FindDescendantPointingToID(), same args
+  static nsIContent *FindDescendantPointingToIDImpl(nsCString& aIdWithSpaces,
+                                                    nsIContent *aLookContent,
+                                                    EAriaProperty aAriaProperty,
+                                                    PRUint32 aAriaPropTypes,
+                                                    nsIAtom *aRelationAttr = nsnull,
+                                                    nsIContent *aExcludeContent = nsnull,
+                                                    nsIAtom *aTagType = nsAccessibilityAtoms::label);
 };
 
 #endif
 
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -70,16 +70,17 @@
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIFrame.h"
 #include "nsIViewManager.h"
 #include "nsIDocShellTreeItem.h"
 
 #include "nsXPIDLString.h"
 #include "nsUnicharUtils.h"
+#include "nsReadableUtils.h"
 #include "prdtoa.h"
 #include "nsIAtom.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsIURI.h"
 #include "nsITimer.h"
 #include "nsIMutableArray.h"
 #include "nsIObserverService.h"
@@ -146,16 +147,22 @@ NS_IMPL_RELEASE_INHERITED(nsAccessible, 
  * static
  * help method. to detect whether this accessible object implements
  * nsIAccessibleText, when it is text or has text child node.
  */
 PRBool nsAccessible::IsTextInterfaceSupportCorrect(nsIAccessible *aAccessible)
 {
   PRBool foundText = PR_FALSE;
 
+  nsCOMPtr<nsIAccessibleDocument> accDoc = do_QueryInterface(aAccessible);
+  if (accDoc) {
+    // Don't test for accessible docs, it makes us create accessibles too
+    // early and fire mutation events before we need to
+    return PR_TRUE;
+  }
   nsCOMPtr<nsIAccessible> child, nextSibling;
   aAccessible->GetFirstChild(getter_AddRefs(child));
   while (child) {
     if (IsText(child)) {
       foundText = PR_TRUE;
       break;
     }
     child->GetNextSibling(getter_AddRefs(nextSibling));
@@ -192,26 +199,23 @@ nsresult nsAccessible::QueryInterface(RE
 
   if (aIID.Equals(NS_GET_IID(nsIAccessibleSelectable))) {
     nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
     if (!content) {
       return NS_ERROR_FAILURE; // This accessible has been shut down
     }
     if (HasRoleAttribute(content)) {
       // If we have an XHTML role attribute present and the
-      // waistate multiselectable attribute not empty or false, then we need
+      // waistate multiselectable attribute is true, then we need
       // to support nsIAccessibleSelectable
       // If either attribute (role or multiselectable) change, then we'll
       // destroy this accessible so that we can follow COM identity rules.
-      static nsIContent::AttrValuesArray strings[] =
-        {&nsAccessibilityAtoms::_empty, &nsAccessibilityAtoms::_false, nsnull};
-      if (content->FindAttrValueIn(kNameSpaceID_WAIProperties ,
-                                   nsAccessibilityAtoms::multiselectable,
-                                   strings, eCaseMatters) ==
-          nsIContent::ATTR_VALUE_NO_MATCH) {
+      nsAutoString multiselectable;
+      if (nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_multiselectable, multiselectable) &&
+          multiselectable.EqualsLiteral("true")) {
         *aInstancePtr = static_cast<nsIAccessibleSelectable*>(this);
         NS_ADDREF_THIS();
         return NS_OK;
       }
     }
   }
 
   if (aIID.Equals(NS_GET_IID(nsIAccessibleValue))) {
@@ -298,24 +302,25 @@ NS_IMETHODIMP nsAccessible::GetDescripti
   // 3. it doesn't have an accName; or
   // 4. its title attribute already equals to its accName nsAutoString name; 
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   if (!content) {
     return NS_ERROR_FAILURE;  // Node shut down
   }
   if (!content->IsNodeOfType(nsINode::eTEXT)) {
     nsAutoString description;
-    nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::describedby, description);
+    nsresult rv = GetTextFromRelationID(eAria_describedby, description);
     if (NS_FAILED(rv)) {
       PRBool isXUL = content->IsNodeOfType(nsINode::eXUL);
       if (isXUL) {
         // Try XUL <description control="[id]">description text</description>
         nsIContent *descriptionContent =
-          FindNeighbourPointingToNode(content, nsAccessibilityAtoms::description,
-                                      nsAccessibilityAtoms::control);
+          nsAccUtils::FindNeighbourPointingToNode(content, eAria_none,
+                                                  nsAccessibilityAtoms::description,
+                                                  nsAccessibilityAtoms::control);
 
         if (descriptionContent) {
           // We have a description content node
           AppendFlatStringFromSubtree(descriptionContent, &description);
         }
       }
       if (description.IsEmpty()) {
         nsIAtom *descAtom = isXUL ? nsAccessibilityAtoms::tooltiptext :
@@ -440,16 +445,26 @@ nsAccessible::GetKeyboardShortcut(nsAStr
   }
 
   aAccessKey = accesskey;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsAccessible::SetParent(nsIAccessible *aParent)
 {
+#ifdef DEBUG
+  if (aParent && aParent != mParent) {
+    nsCOMPtr<nsPIAccessible> privParent = do_QueryInterface(mParent);
+    if (privParent) {
+      nsCOMPtr<nsIAccessible> firstChild;
+      privParent->GetCachedFirstChild(getter_AddRefs(firstChild));
+      NS_ASSERTION(firstChild != this, "Reparenting other node's first child!");
+    }
+  }
+#endif
   mParent = aParent;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsAccessible::SetFirstChild(nsIAccessible *aFirstChild)
 {
 #ifdef DEBUG
   // If there's parent of this child already, make sure it's us!
@@ -570,30 +585,41 @@ NS_IMETHODIMP nsAccessible::GetParent(ns
   nsresult rv = GetCachedParent(aParent);
   if (NS_FAILED(rv) || *aParent) {
     return rv;
   }
 
   nsCOMPtr<nsIAccessibleDocument> docAccessible(GetDocAccessible());
   NS_ENSURE_TRUE(docAccessible, NS_ERROR_FAILURE);
 
-  return docAccessible->GetAccessibleInParentChain(mDOMNode, aParent);
+  return docAccessible->GetAccessibleInParentChain(mDOMNode, PR_TRUE, aParent);
 }
 
 NS_IMETHODIMP nsAccessible::GetCachedParent(nsIAccessible **  aParent)
 {
   *aParent = nsnull;
   if (!mWeakShell) {
     // This node has been shut down
     return NS_ERROR_FAILURE;
   }
   NS_IF_ADDREF(*aParent = mParent);
   return NS_OK;
 }
 
+NS_IMETHODIMP nsAccessible::GetCachedFirstChild(nsIAccessible **  aFirstChild)
+{
+  *aFirstChild = nsnull;
+  if (!mWeakShell) {
+    // This node has been shut down
+    return NS_ERROR_FAILURE;
+  }
+  NS_IF_ADDREF(*aFirstChild = mFirstChild);
+  return NS_OK;
+}
+
   /* readonly attribute nsIAccessible nextSibling; */
 NS_IMETHODIMP nsAccessible::GetNextSibling(nsIAccessible * *aNextSibling) 
 { 
   *aNextSibling = nsnull; 
   if (!mWeakShell) {
     // This node has been shut down
     return NS_ERROR_FAILURE;
   }
@@ -651,16 +677,26 @@ NS_IMETHODIMP nsAccessible::GetPreviousS
 NS_IMETHODIMP nsAccessible::GetFirstChild(nsIAccessible * *aFirstChild) 
 {  
   if (gIsCacheDisabled) {
     InvalidateChildren();
   }
   PRInt32 numChildren;
   GetChildCount(&numChildren);  // Make sure we cache all of the children
 
+#ifdef DEBUG
+  nsCOMPtr<nsPIAccessible> firstChild(do_QueryInterface(mFirstChild));
+  if (firstChild) {
+    nsCOMPtr<nsIAccessible> realParent;
+    firstChild->GetCachedParent(getter_AddRefs(realParent));
+    NS_ASSERTION(!realParent || realParent == this,
+                 "Two accessibles have the same first child accessible.");
+  }
+#endif
+
   NS_IF_ADDREF(*aFirstChild = mFirstChild);
 
   return NS_OK;  
 }
 
   /* readonly attribute nsIAccessible lastChild; */
 NS_IMETHODIMP nsAccessible::GetLastChild(nsIAccessible * *aLastChild)
 {  
@@ -1127,17 +1163,17 @@ nsAccessible::GetChildAtPoint(PRInt32 aX
     return NS_OK;
   }
 
   nsCOMPtr<nsIAccessible> accessible;
   accService->GetAccessibleFor(relevantNode, getter_AddRefs(accessible));
   if (!accessible) {
     // No accessible for the node with the point, so find the first
     // accessible in the DOM parent chain
-    accDocument->GetAccessibleInParentChain(relevantNode,
+    accDocument->GetAccessibleInParentChain(relevantNode, PR_TRUE,
                                             getter_AddRefs(accessible));
     if (!accessible) {
       NS_IF_ADDREF(*aAccessible = fallbackAnswer);
       return NS_OK;
     }
   }
 
   if (accessible == this) {
@@ -1372,20 +1408,34 @@ NS_IMETHODIMP nsAccessible::SetSelected(
   if (state & nsIAccessibleStates::STATE_SELECTABLE) {
     nsCOMPtr<nsIAccessible> multiSelect = GetMultiSelectFor(mDOMNode);
     if (!multiSelect) {
       return aSelect ? TakeFocus() : NS_ERROR_FAILURE;
     }
     nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
     NS_ASSERTION(content, "Called for dead accessible");
 
-    // For DHTML widgets use WAI namespace
-    PRUint32 nameSpaceID = mRoleMapEntry ? kNameSpaceID_WAIProperties : kNameSpaceID_None;
+    // For ARIA widgets use WAI namespace or hyphenated property, depending on what doc accepts
+    PRUint32 nameSpaceID = kNameSpaceID_None;  // Default
+    if (mRoleMapEntry) {
+      if (0 == (nsAccUtils::GetAriaPropTypes(content, mWeakShell) &
+                nsIAccessibleDocument::eCheckNamespaced)) {
+        // No WAI namespaced properties used in this doc, use hyphenated property
+        if (aSelect) {
+          return content->SetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_selected,
+                                  NS_LITERAL_STRING("true"), PR_TRUE);
+        }
+        return content->UnsetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_selected, PR_TRUE);
+      }
+      nameSpaceID = kNameSpaceID_WAIProperties;
+    }
+    // Use normal property
     if (aSelect) {
-      return content->SetAttr(nameSpaceID, nsAccessibilityAtoms::selected, NS_LITERAL_STRING("true"), PR_TRUE);
+      return content->SetAttr(nameSpaceID, nsAccessibilityAtoms::selected,
+                              NS_LITERAL_STRING("true"), PR_TRUE);
     }
     return content->UnsetAttr(nameSpaceID, nsAccessibilityAtoms::selected, PR_TRUE);
   }
 
   return NS_ERROR_FAILURE;
 }
 
 /* void takeSelection (); */
@@ -1628,18 +1678,19 @@ nsresult nsAccessible::AppendFlatStringF
     AppendFlatStringFromSubtreeRecurse(aContent->GetChildAt(index), aFlatString);
   }
   return NS_OK;
 }
 
 nsIContent *nsAccessible::GetLabelContent(nsIContent *aForNode)
 {
   if (aForNode->IsNodeOfType(nsINode::eXUL))
-    return FindNeighbourPointingToNode(aForNode, nsAccessibilityAtoms::label,
-                                       nsAccessibilityAtoms::control);
+    return nsAccUtils::FindNeighbourPointingToNode(aForNode, eAria_none,
+                                                   nsAccessibilityAtoms::label,
+                                                   nsAccessibilityAtoms::control);
 
   return GetHTMLLabelContent(aForNode);
 }
 
 nsIContent* nsAccessible::GetHTMLLabelContent(nsIContent *aForNode)
 {
   // Get either <label for="[id]"> element which explictly points to aForNode, or 
   // <label> ancestor which implicitly point to it
@@ -1657,33 +1708,33 @@ nsIContent* nsAccessible::GetHTMLLabelCo
       // There can be a label targeted at this control using the 
       // for="control_id" attribute. To save computing time, only 
       // look for those inside of a form element
       nsAutoString forId;
       if (!nsAccUtils::GetID(aForNode, forId)) {
         break;
       }
       // Actually we'll be walking down the content this time, with a depth first search
-      return FindDescendantPointingToID(&forId, walkUpContent,
-                                        nsAccessibilityAtoms::_for);
+      return nsAccUtils::FindDescendantPointingToID(&forId, walkUpContent, eAria_none,
+                                                    nsAccessibilityAtoms::_for);
     }
   }
 
   return nsnull;
 }
 
-nsresult nsAccessible::GetTextFromRelationID(nsIAtom *aIDAttrib, nsString &aName)
+nsresult nsAccessible::GetTextFromRelationID(EAriaProperty aIDProperty, nsString &aName)
 {
   // Get DHTML name from content subtree pointed to by ID attribute
   aName.Truncate();
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   NS_ASSERTION(content, "Called from shutdown accessible");
 
   nsAutoString ids;
-  if (!content->GetAttr(kNameSpaceID_WAIProperties, aIDAttrib, ids)) {
+  if (!nsAccUtils::GetAriaProperty(content, mWeakShell, aIDProperty, ids)) {
     return NS_ERROR_FAILURE;
   }
   ids.CompressWhitespace(PR_TRUE, PR_TRUE);
 
   nsCOMPtr<nsIDOMDocument> domDoc;
   mDOMNode->GetOwnerDocument(getter_AddRefs(domDoc));
   NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
   
@@ -1716,154 +1767,31 @@ nsresult nsAccessible::GetTextFromRelati
     if (NS_SUCCEEDED(rv)) {
       aName.CompressWhitespace();
     }
   }
   
   return rv;
 }
 
-nsIContent*
-nsAccessible::FindNeighbourPointingToNode(nsIContent *aForNode,
-                                          nsIAtom *aTagName, nsIAtom *aRelationAttr,
-                                          PRUint32 aRelationNameSpaceID,
-                                          PRUint32 aAncestorLevelsToSearch)
-{
-  nsCOMPtr<nsIContent> binding;
-  nsAutoString controlID;
-  if (!nsAccUtils::GetID(aForNode, controlID)) {
-    binding = aForNode->GetBindingParent();
-    if (binding == aForNode)
-      return nsnull;
-
-    aForNode->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::anonid, controlID);
-    if (controlID.IsEmpty())
-      return nsnull;
-  }
-
-  // Look for label in subtrees of nearby ancestors
-  PRUint32 count = 0;
-  nsIContent *labelContent = nsnull;
-  nsIContent *prevSearched = nsnull;
-
-  while (!labelContent && ++count <= aAncestorLevelsToSearch &&
-         (aForNode = aForNode->GetParent()) != nsnull) {
-
-    if (aForNode == binding) {
-      // When we reach the binding parent, make sure to check
-      // all of its anonymous child subtrees
-      nsCOMPtr<nsIDocument> doc = aForNode->GetCurrentDoc();
-      nsCOMPtr<nsIDOMDocumentXBL> xblDoc(do_QueryInterface(doc));
-      if (!xblDoc)
-        return nsnull;
-
-      nsCOMPtr<nsIDOMNodeList> nodes;
-      nsCOMPtr<nsIDOMElement> forElm(do_QueryInterface(aForNode));
-      xblDoc->GetAnonymousNodes(forElm, getter_AddRefs(nodes));
-      if (!nodes)
-        return nsnull;
-
-      PRUint32 length;
-      nsresult rv = nodes->GetLength(&length);
-      if (NS_FAILED(rv))
-        return nsnull;
-
-      for (PRUint32 index = 0; index < length && !labelContent; index++) {
-        nsCOMPtr<nsIDOMNode> node;
-        rv = nodes->Item(index, getter_AddRefs(node));
-        if (NS_FAILED(rv))
-          return nsnull;
-
-        nsCOMPtr<nsIContent> content = do_QueryInterface(node);
-        if (!content)
-          return nsnull;
-
-        if (content != prevSearched) {
-          labelContent = FindDescendantPointingToID(&controlID, content,  aRelationAttr,
-                                                    aRelationNameSpaceID, nsnull,
-                                                    aTagName);
-        }
-      }
-      break;
-    }
-
-    labelContent = FindDescendantPointingToID(&controlID, aForNode,
-                                              aRelationAttr, aRelationNameSpaceID,
-                                              prevSearched, aTagName);
-    prevSearched = aForNode;
-  }
-
-  return labelContent;
-}
-
-// Pass in aRelationAttr == nsnull if any <label> will do
-nsIContent*
-nsAccessible::FindDescendantPointingToID(const nsAString *aId,
-                                         nsIContent *aLookContent,
-                                         nsIAtom *aRelationAttr,
-                                         PRUint32 aRelationNameSpaceID,
-                                         nsIContent *aExcludeContent,
-                                         nsIAtom *aTagType)
-{
-  if (!aTagType || aLookContent->Tag() == aTagType) {
-    if (aRelationAttr) {
-      // Check for ID in the attribute aRelationAttr, which can be a list
-      nsAutoString idList;
-      if (aLookContent->GetAttr(aRelationNameSpaceID, aRelationAttr, idList)) {
-        idList.Insert(' ', 0);  // Surround idlist with spaces for search
-        idList.Append(' ');
-        nsAutoString id(*aId);
-        id.Insert(' ', 0); // Surround id with spaces for search
-        id.Append(' ');
-        // idList is now a set of id's with spaces around each,
-        // and id also has spaces around it.
-        // If id is a substring of idList then we have a match
-        if (idList.Find(id) != -1) {
-          return aLookContent;
-        }
-      }
-    }
-    if (aTagType) {
-      return nsnull;
-    }
-  }
-
-  // Recursively search descendants for labels
-  PRUint32 count  = 0;
-  nsIContent *child;
-  nsIContent *labelContent = nsnull;
-
-  while ((child = aLookContent->GetChildAt(count++)) != nsnull) {
-    if (child != aExcludeContent) {
-      labelContent = FindDescendantPointingToID(aId, child, aRelationAttr,
-                                                aRelationNameSpaceID, aExcludeContent,
-                                                aTagType);
-      if (labelContent) {
-        return labelContent;
-      }
-    }
-  }
-  return nsnull;
-}
-
 /**
   * Only called if the element is not a nsIDOMXULControlElement. Initially walks up
   *   the DOM tree to the form, concatonating label elements as it goes. Then checks for
   *   labels with the for="controlID" property.
   */
 nsresult nsAccessible::GetHTMLName(nsAString& aLabel, PRBool aCanAggregateSubtree)
 {
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   if (!content) {
     return NS_ERROR_FAILURE;   // Node shut down
   }
 
   // Check for DHTML accessibility labelledby relationship property
   nsAutoString label;
-  nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::labelledby, label);
+  nsresult rv = GetTextFromRelationID(eAria_labelledby, label);
   if (NS_SUCCEEDED(rv)) {
     aLabel = label;
     return rv;
   }
 
   nsIContent *labelContent = GetHTMLLabelContent(content);
   if (labelContent) {
     AppendFlatStringFromSubtree(labelContent, &label);
@@ -1904,17 +1832,17 @@ nsresult nsAccessible::GetHTMLName(nsASt
   */
 nsresult nsAccessible::GetXULName(nsAString& aLabel, PRBool aCanAggregateSubtree)
 {
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   NS_ASSERTION(content, "No nsIContent for DOM node");
 
   // First check for label override via accessibility labelledby relationship
   nsAutoString label;
-  nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::labelledby, label);
+  nsresult rv = GetTextFromRelationID(eAria_labelledby, label);
   if (NS_SUCCEEDED(rv)) {
     aLabel = label;
     return rv;
   }
 
   // CASE #1 (via label attribute) -- great majority of the cases
   nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl(do_QueryInterface(mDOMNode));
   if (labeledEl) {
@@ -1937,18 +1865,19 @@ nsresult nsAccessible::GetXULName(nsAStr
       }
     }
   }
 
   // CASES #2 and #3 ------ label as a child or <label control="id" ... > </label>
   if (NS_FAILED(rv) || label.IsEmpty()) {
     label.Truncate();
     nsIContent *labelContent =
-      FindNeighbourPointingToNode(content, nsAccessibilityAtoms::label,
-                                  nsAccessibilityAtoms::control);
+      nsAccUtils::FindNeighbourPointingToNode(content, eAria_none,
+                                              nsAccessibilityAtoms::label,
+                                              nsAccessibilityAtoms::control);
 
     nsCOMPtr<nsIDOMXULLabelElement> xulLabel(do_QueryInterface(labelContent));
     // Check if label's value attribute is used
     if (xulLabel && NS_SUCCEEDED(xulLabel->GetValue(label)) && label.IsEmpty()) {
       // If no value attribute, a non-empty label must contain
       // children that define it's text -- possibly using HTML
       AppendFlatStringFromSubtree(labelContent, &label);
     }
@@ -2035,35 +1964,38 @@ NS_IMETHODIMP nsAccessible::GetFinalRole
 
   if (mRoleMapEntry) {
     *aRole = mRoleMapEntry->role;
 
     // These unfortunate exceptions don't fit into the ARIA table
     // This is where the nsIAccessible role depends on both the role and ARIA state
     if (*aRole == nsIAccessibleRole::ROLE_ENTRY) {
       nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
-      if (content && 
-          content->AttrValueIs(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::secret,
-                               nsAccessibilityAtoms::_true, eCaseMatters)) {
+      nsAutoString secret;
+      if (content && nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_secret, secret) &&
+          secret.EqualsLiteral("true")) {
         // For entry field with aaa:secret="true"
         *aRole = nsIAccessibleRole::ROLE_PASSWORD_TEXT;
       }
     }
     else if (*aRole == nsIAccessibleRole::ROLE_PUSHBUTTON) {
       nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
       if (content) {
-        if (content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::pressed)) {
+        if (nsAccUtils::HasAriaProperty(content, mWeakShell, eAria_pressed)) {
           // For aaa:pressed="false" or aaa:pressed="true"
           // For simplicity, any pressed attribute indicates it's a toggle button
           *aRole = nsIAccessibleRole::ROLE_TOGGLE_BUTTON;
         }
-        else if (content->AttrValueIs(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::haspopup,
-                                      nsAccessibilityAtoms::_true, eCaseMatters)) {
-          // For button with aaa:haspopup="true"
-          *aRole = nsIAccessibleRole::ROLE_BUTTONMENU;
+        else {
+          nsAutoString haspopup;
+          if (nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_haspopup, haspopup) &&
+              haspopup.EqualsLiteral("true")) {
+            // For button with aaa:haspopup="true"
+            *aRole = nsIAccessibleRole::ROLE_BUTTONMENU;
+          }
         }
       }
     }
   
     if (*aRole != nsIAccessibleRole::ROLE_NOTHING) {
       return NS_OK;
     }
   }
@@ -2094,47 +2026,51 @@ nsAccessible::GetAttributes(nsIPersisten
     attributes->SetStringProperty(NS_LITERAL_CSTRING("id"), id, oldValueUnused);
     // XXX In the future we may need to expose the dynamic content role inheritance chain
     // through this attribute
     nsAutoString xmlRole;
     if (GetARIARole(content, xmlRole)) {
       attributes->SetStringProperty(NS_LITERAL_CSTRING("xml-roles"), xmlRole, oldValueUnused);          
     }
 
-    char *ariaProperties[] = { "live", "channel", "atomic", "relevant", "datatype", "level",
+    // Make sure to keep these two arrays in sync
+    PRUint32 ariaPropTypes = nsAccUtils::GetAriaPropTypes(content, mWeakShell);
+    char *ariaPropertyString[] = { "live", "channel", "atomic", "relevant", "datatype", "level",
                                "posinset", "setsize", "sort", "grab", "dropeffect"};
-
-    for (PRUint32 index = 0; index < NS_ARRAY_LENGTH(ariaProperties); index ++) {
+    EAriaProperty ariaPropertyEnum[] = { eAria_live, eAria_channel, eAria_atomic, eAria_relevant,
+                                       eAria_datatype, eAria_level, eAria_posinset, eAria_setsize,
+                                       eAria_sort, eAria_grab, eAria_dropeffect};
+    NS_ASSERTION(NS_ARRAY_LENGTH(ariaPropertyString) == NS_ARRAY_LENGTH(ariaPropertyEnum),
+                 "ARIA attributes and object property name arrays out of sync");
+    for (PRUint32 index = 0; index < NS_ARRAY_LENGTH(ariaPropertyString); index ++) {
       nsAutoString value;
-      nsCOMPtr<nsIAtom> attr = do_GetAtom(ariaProperties[index]);
-      NS_ENSURE_TRUE(attr, NS_ERROR_OUT_OF_MEMORY);
-      if (content->GetAttr(kNameSpaceID_WAIProperties, attr, value)) {
+      if (nsAccUtils::GetAriaProperty(content, mWeakShell, ariaPropertyEnum[index], value, ariaPropTypes)) {
         ToLowerCase(value);
-        attributes->SetStringProperty(nsDependentCString(ariaProperties[index]), value, oldValueUnused);    
+        attributes->SetStringProperty(nsDependentCString(ariaPropertyString[index]), value, oldValueUnused);    
       }
     }
 
     // Get container-foo computed live region properties based on the closest container with
     // the live region attribute
     nsAutoString atomic, live, relevant, channel, busy;
     while (content) {
-      if (relevant.IsEmpty() && 
-          content->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::relevant, relevant))
+      if (relevant.IsEmpty() &&
+          nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_relevant, relevant, ariaPropTypes))
         attributes->SetStringProperty(NS_LITERAL_CSTRING("container-relevant"), relevant, oldValueUnused);
       if (live.IsEmpty() &&
-          content->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::live, live))
+          nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_live, live, ariaPropTypes))
         attributes->SetStringProperty(NS_LITERAL_CSTRING("container-live"), live, oldValueUnused);
       if (channel.IsEmpty() &&
-          content->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::channel, channel))
+          nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_channel, channel, ariaPropTypes))
         attributes->SetStringProperty(NS_LITERAL_CSTRING("container-channel"), channel, oldValueUnused);
       if (atomic.IsEmpty() &&
-          content->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::atomic, atomic))
+          nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_atomic, atomic, ariaPropTypes))
         attributes->SetStringProperty(NS_LITERAL_CSTRING("container-atomic"), atomic, oldValueUnused);
       if (busy.IsEmpty() &&
-          content->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::busy, busy))
+          nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_busy, busy, ariaPropTypes))
         attributes->SetStringProperty(NS_LITERAL_CSTRING("container-busy"), busy, oldValueUnused);
       content = content->GetParent();
     }
   }
 
   if (!nsAccUtils::HasAccGroupAttrs(attributes)) {
     // The role of an accessible can be pointed by ARIA attribute but ARIA
     // posinset, level, setsize may be skipped. Therefore we calculate here
@@ -2259,24 +2195,22 @@ nsAccessible::GroupPosition(PRInt32 *aGr
 
   return NS_OK;
 }
 
 PRBool nsAccessible::MappedAttrState(nsIContent *aContent, PRUint32 *aStateInOut,
                                      nsStateMapEntry *aStateMapEntry)
 {
   // Return true if we should continue
-  if (!aStateMapEntry->attributeName) {
+  if (aStateMapEntry->attributeName == eAria_none) {
     return PR_FALSE;  // Stop looking -- no more states
   }
 
   nsAutoString attribValue;
-  nsCOMPtr<nsIAtom> attribAtom = do_GetAtom(aStateMapEntry->attributeName); // XXX put atoms directly in entry
-  NS_ENSURE_TRUE(attribAtom, NS_ERROR_OUT_OF_MEMORY);
-  if (aContent->GetAttr(kNameSpaceID_WAIProperties, attribAtom, attribValue)) {
+  if (nsAccUtils::GetAriaProperty(aContent, mWeakShell, aStateMapEntry->attributeName, attribValue)) {
     if (aStateMapEntry->attributeValue == kBoolState) {
       // No attribute value map specified in state map entry indicates state cleared
       if (attribValue.EqualsLiteral("false")) {
         *aStateInOut &= ~aStateMapEntry->state;
       }
       else {
         *aStateInOut |= aStateMapEntry->state;
       }
@@ -2295,16 +2229,39 @@ nsAccessible::GetFinalState(PRUint32 *aS
   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();
 
+  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;
+      rv = GetAccessibleRelated(nsIAccessibleRelation::RELATION_LABEL_FOR,
+                                getter_AddRefs(tabPanel));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      if (tabPanel && Role(tabPanel) == nsIAccessibleRole::ROLE_PROPERTYPAGE) {
+        nsCOMPtr<nsIAccessNode> tabPanelAccessNode(do_QueryInterface(tabPanel));
+        nsCOMPtr<nsIDOMNode> tabPanelNode;
+        tabPanelAccessNode->GetDOMNode(getter_AddRefs(tabPanelNode));
+        NS_ENSURE_STATE(tabPanelNode);
+
+        if (nsAccUtils::IsAncestorOf(tabPanelNode, gLastFocusedNode))
+          *aState |= nsIAccessibleStates::STATE_SELECTED;
+      }
+    }
+  }
+
   // Set additional states which presence depends on another states.
   if (!aExtraState)
     return NS_OK;
 
   if (!(*aState & nsIAccessibleStates::STATE_UNAVAILABLE)) {
     *aExtraState |= nsIAccessibleStates::EXT_STATE_ENABLED |
                     nsIAccessibleStates::EXT_STATE_SENSITIVE;
   }
@@ -2330,29 +2287,28 @@ nsAccessible::GetFinalState(PRUint32 *aS
   if (role == nsIAccessibleRole::ROLE_ENTRY ||
       role == nsIAccessibleRole::ROLE_PASSWORD_TEXT ||
       role == nsIAccessibleRole::ROLE_COMBOBOX) {
 
     nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
     NS_ENSURE_STATE(content);
 
     nsAutoString autocomplete;
-    if (content->GetAttr(kNameSpaceID_WAIProperties,
-                         nsAccessibilityAtoms::autocomplete, autocomplete) &&
+    if (nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_autocomplete, autocomplete) &&
         (autocomplete.EqualsIgnoreCase("inline") ||
          autocomplete.EqualsIgnoreCase("list") ||
          autocomplete.EqualsIgnoreCase("both"))) {
       *aExtraState |= nsIAccessibleStates::EXT_STATE_SUPPORTS_AUTOCOMPLETION;
     }
 
     // XXX We can remove this hack once we support RDF-based role & state maps
     if (mRoleMapEntry && mRoleMapEntry->role == nsIAccessibleRole::ROLE_ENTRY) {
-      if (content->AttrValueIs(kNameSpaceID_WAIProperties,
-                               nsAccessibilityAtoms::multiline,
-                               nsAccessibilityAtoms::_true, eCaseMatters)) {
+      nsAutoString multiline;
+      if (nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_multiline, multiline) &&
+          multiline.EqualsLiteral("true")) {
         *aExtraState |= nsIAccessibleStates::EXT_STATE_MULTI_LINE;
       }
       else {
         *aExtraState |= nsIAccessibleStates::EXT_STATE_SINGLE_LINE;
       }
     }
   }
 
@@ -2388,18 +2344,17 @@ nsAccessible::GetARIAState()
   // Test for universal states first
   nsIContent *content = GetRoleContent(mDOMNode);
   if (!content) {
     return 0;
   }
 
   PRUint32 ariaState = 0;
   PRUint32 index = 0;
-  while (nsARIAMap::gWAIUnivStateMap[index].attributeName != nsnull) {
-    MappedAttrState(content, &ariaState, &nsARIAMap::gWAIUnivStateMap[index]);
+  while (MappedAttrState(content, &ariaState, &nsARIAMap::gWAIUnivStateMap[index])) {
     ++ index;
   }
 
   if (!mRoleMapEntry)
     return ariaState;
 
   // Once DHTML role is used, we're only readonly if DHTML readonly used
   ariaState &= ~nsIAccessibleStates::STATE_READONLY;
@@ -2433,54 +2388,50 @@ NS_IMETHODIMP nsAccessible::GetValue(nsA
   if (!mDOMNode) {
     return NS_ERROR_FAILURE;  // Node already shut down
   }
   if (mRoleMapEntry) {
     if (mRoleMapEntry->valueRule == eNoValue) {
       return NS_OK;
     }
     nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
-    if (content && content->GetAttr(kNameSpaceID_WAIProperties,
-                                    nsAccessibilityAtoms::valuenow, aValue)) {
+    if (content && nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_valuenow, aValue)) {
       return NS_OK;
     }
   }
   return NS_OK;
 }
 
 // nsIAccessibleValue
 NS_IMETHODIMP
 nsAccessible::GetMaximumValue(double *aMaximumValue)
 {
-  return GetAttrValue(kNameSpaceID_WAIProperties,
-                      nsAccessibilityAtoms::valuemax, aMaximumValue);
+  return GetAttrValue(eAria_valuemax, aMaximumValue);
 }
 
 NS_IMETHODIMP
 nsAccessible::GetMinimumValue(double *aMinimumValue)
 {
-  return GetAttrValue(kNameSpaceID_WAIProperties,
-                      nsAccessibilityAtoms::valuemin, aMinimumValue);
+  return GetAttrValue(eAria_valuemin, aMinimumValue);
 }
 
 NS_IMETHODIMP
 nsAccessible::GetMinimumIncrement(double *aMinIncrement)
 {
   NS_ENSURE_ARG_POINTER(aMinIncrement);
   *aMinIncrement = 0;
 
   // No mimimum increment in dynamic content spec right now
   return NS_OK_NO_ARIA_VALUE;
 }
 
 NS_IMETHODIMP
 nsAccessible::GetCurrentValue(double *aValue)
 {
-  return GetAttrValue(kNameSpaceID_WAIProperties,
-                      nsAccessibilityAtoms::valuenow, aValue);
+  return GetAttrValue(eAria_valuenow, aValue);
 }
 
 NS_IMETHODIMP
 nsAccessible::SetCurrentValue(double aValue)
 {
   if (!mDOMNode)
     return NS_ERROR_FAILURE;  // Node already shut down
 
@@ -2501,16 +2452,22 @@ nsAccessible::SetCurrentValue(double aVa
   if (NS_SUCCEEDED(GetMaximumValue(&maxValue)) && aValue > maxValue)
     return NS_ERROR_INVALID_ARG;
 
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   NS_ENSURE_STATE(content);
 
   nsAutoString newValue;
   newValue.AppendFloat(aValue);
+  if (0 == (nsAccUtils::GetAriaPropTypes(content, mWeakShell) &
+            nsIAccessibleDocument::eCheckNamespaced)) {
+    // No WAI namespaced properties used in this doc
+    return content->SetAttr(kNameSpaceID_None,
+                            nsAccessibilityAtoms::aria_valuenow, newValue, PR_TRUE);
+  }
   return content->SetAttr(kNameSpaceID_WAIProperties,
                           nsAccessibilityAtoms::valuenow, newValue, PR_TRUE);
 }
 
 /* void setName (in DOMString name); */
 NS_IMETHODIMP nsAccessible::SetName(const nsAString& name)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
@@ -2607,49 +2564,26 @@ NS_IMETHODIMP nsAccessible::GetAccessibl
 }
 
 /* nsIAccessible getAccessibleBelow(); */
 NS_IMETHODIMP nsAccessible::GetAccessibleBelow(nsIAccessible **_retval)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-already_AddRefed<nsIDOMNode>
-nsAccessible::FindNeighbourPointingToThis(nsIAtom *aRelationAttr,
-                                          PRUint32 aRelationNameSpaceID,
-                                          PRUint32 aAncestorLevelsToSearch)
-{
-  nsIContent *content = GetRoleContent(mDOMNode);
-  if (!content)
-    return nsnull; // Node shut down
-
-  nsIContent* description = FindNeighbourPointingToNode(content, nsnull,
-                                                        aRelationAttr,
-                                                        aRelationNameSpaceID,
-                                                        aAncestorLevelsToSearch);
-
-  if (!description)
-    return nsnull;
-
-  nsIDOMNode *relatedNode;
-  CallQueryInterface(description, &relatedNode);
-  return relatedNode;
-}
-
 nsIDOMNode* nsAccessible::GetAtomicRegion()
 {
   nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
   nsIContent *loopContent = content;
   nsAutoString atomic;
-
-  while (loopContent) {
-    loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::atomic, atomic);
-    if (!atomic.IsEmpty()) {
-      break;
-    }
+  PRUint32 ariaPropTypes = nsAccUtils::GetAriaPropTypes(content, mWeakShell);
+
+  while (loopContent && !nsAccUtils::GetAriaProperty(loopContent, mWeakShell,
+                                                     eAria_atomic, atomic,
+                                                     ariaPropTypes)) {
     loopContent = loopContent->GetParent();
   }
 
   nsCOMPtr<nsIDOMNode> atomicRegion;
   if (atomic.EqualsLiteral("true")) {
     atomicRegion = do_QueryInterface(loopContent);
   }
   return atomicRegion;
@@ -2678,95 +2612,82 @@ NS_IMETHODIMP nsAccessible::GetAccessibl
   case nsIAccessibleRelation::RELATION_LABEL_FOR:
     {
       if (content->Tag() == nsAccessibilityAtoms::label) {
         nsIAtom *relatedIDAttr = content->IsNodeOfType(nsINode::eHTML) ?
           nsAccessibilityAtoms::_for : nsAccessibilityAtoms::control;
         content->GetAttr(kNameSpaceID_None, relatedIDAttr, relatedID);
       }
       if (relatedID.IsEmpty()) {
-        const PRUint32 kAncestorLevelsToSearch = 3;
-        relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::labelledby,
-                                                  kNameSpaceID_WAIProperties,
-                                                  kAncestorLevelsToSearch);
+        relatedNode =
+          do_QueryInterface(nsAccUtils::FindNeighbourPointingToNode(content, eAria_labelledby));
       }
       break;
     }
   case nsIAccessibleRelation::RELATION_LABELLED_BY:
     {
-      content->GetAttr(kNameSpaceID_WAIProperties,
-                       nsAccessibilityAtoms::labelledby, relatedID);
-      if (relatedID.IsEmpty()) {
+      if (!nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_labelledby, relatedID)) {
         relatedNode = do_QueryInterface(GetLabelContent(content));
       }
       break;
     }
   case nsIAccessibleRelation::RELATION_DESCRIBED_BY:
     {
-      content->GetAttr(kNameSpaceID_WAIProperties,
-                       nsAccessibilityAtoms::describedby, relatedID);
-      if (relatedID.IsEmpty()) {
-        nsIContent *description =
-          FindNeighbourPointingToNode(content,
-                                      nsAccessibilityAtoms::description,
-                                      nsAccessibilityAtoms::control);
-
-        relatedNode = do_QueryInterface(description);
+      if (!nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_describedby, relatedID)) {
+        relatedNode = do_QueryInterface(
+          nsAccUtils::FindNeighbourPointingToNode(content, eAria_none,
+                                                  nsAccessibilityAtoms::description,
+                                                  nsAccessibilityAtoms::control));
+
       }
       break;
     }
   case nsIAccessibleRelation::RELATION_DESCRIPTION_FOR:
     {
-      const PRUint32 kAncestorLevelsToSearch = 3;
       relatedNode =
-        FindNeighbourPointingToThis(nsAccessibilityAtoms::describedby,
-                                    kNameSpaceID_WAIProperties,
-                                    kAncestorLevelsToSearch);
+        do_QueryInterface(nsAccUtils::FindNeighbourPointingToNode(content, eAria_describedby));
 
       if (!relatedNode && content->Tag() == nsAccessibilityAtoms::description &&
           content->IsNodeOfType(nsINode::eXUL)) {
         // This affectively adds an optional control attribute to xul:description,
         // which only affects accessibility, by allowing the description to be
         // tied to a control.
         content->GetAttr(kNameSpaceID_None,
                          nsAccessibilityAtoms::control, relatedID);
       }
       break;
     }
   case nsIAccessibleRelation::RELATION_NODE_CHILD_OF:
     {
-      relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::owns,
-                                                kNameSpaceID_WAIProperties);
+      relatedNode =
+        do_QueryInterface(nsAccUtils::FindNeighbourPointingToNode(content, eAria_owns));
       break;
     }
   case nsIAccessibleRelation::RELATION_CONTROLLED_BY:
     {
-      relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::controls,
-                                                kNameSpaceID_WAIProperties);
+      relatedNode =
+        do_QueryInterface(nsAccUtils::FindNeighbourPointingToNode(content, eAria_controls));
       break;
     }
   case nsIAccessibleRelation::RELATION_CONTROLLER_FOR:
     {
-      content->GetAttr(kNameSpaceID_WAIProperties,
-                       nsAccessibilityAtoms::controls, relatedID);
+      nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_controls, relatedID);
       break;
     }
   case nsIAccessibleRelation::RELATION_FLOWS_TO:
     {
-      content->GetAttr(kNameSpaceID_WAIProperties,
-                       nsAccessibilityAtoms::flowto, relatedID);
+      nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_flowto, relatedID);
       break;
     }
   case nsIAccessibleRelation::RELATION_FLOWS_FROM:
     {
-      relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::flowto,
-                                                kNameSpaceID_WAIProperties);
+      relatedNode =
+        do_QueryInterface(nsAccUtils::FindNeighbourPointingToNode(content, eAria_flowto));
       break;
     }
-
   case nsIAccessibleRelation::RELATION_DEFAULT_BUTTON:
     {
       if (content->IsNodeOfType(nsINode::eHTML)) {
         // HTML form controls implements nsIFormControl interface.
         nsCOMPtr<nsIFormControl> control(do_QueryInterface(content));
         if (control) {
           nsCOMPtr<nsIDOMHTMLFormElement> htmlform;
           control->GetForm(getter_AddRefs(htmlform));
@@ -3188,17 +3109,17 @@ NS_IMETHODIMP nsAccessible::GetObject(PR
   NS_ADDREF_THIS();
   return NS_OK;
 }
 
 // nsIAccessibleHyperLink::IsValid()
 NS_IMETHODIMP nsAccessible::IsValid(PRBool *aIsValid)
 {
   PRUint32 state = State(this);
-  *aIsValid = (state & nsIAccessibleStates::STATE_INVALID) != 0;
+  *aIsValid = (0 == (state & nsIAccessibleStates::STATE_INVALID));
   // XXX In order to implement this we would need to follow every link
   // Perhaps we can get information about invalid links from the cache
   // In the mean time authors can use role="wairole:link" aaa:invalid="true"
   // to force it for links they internally know to be invalid
   return NS_OK;
 }
 
 NS_IMETHODIMP nsAccessible::IsSelected(PRBool *aIsSelected)
@@ -3341,34 +3262,33 @@ PRBool nsAccessible::CheckVisibilityInPa
 
     document = parentDoc;
   }
 
   return PR_TRUE;
 }
 
 nsresult
-nsAccessible::GetAttrValue(PRUint32 aNameSpaceID, nsIAtom *aName,
-                           double *aValue)
+nsAccessible::GetAttrValue(EAriaProperty aProperty, double *aValue)
 {
   NS_ENSURE_ARG_POINTER(aValue);
   *aValue = 0;
 
   if (!mDOMNode)
     return NS_ERROR_FAILURE;  // Node already shut down
 
  if (!mRoleMapEntry || mRoleMapEntry->valueRule == eNoValue)
     return NS_OK_NO_ARIA_VALUE;
 
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   NS_ENSURE_STATE(content);
 
   PRInt32 result = NS_OK;
   nsAutoString value;
-  if (content->GetAttr(aNameSpaceID, aName, value) && !value.IsEmpty())
+  if (nsAccUtils::GetAriaProperty(content, mWeakShell, aProperty, value))
     *aValue = value.ToFloat(&result);
 
   return result;
 }
 
 PRBool nsAccessible::MustPrune(nsIAccessible *aAccessible)
 { 
   PRUint32 role = Role(aAccessible);
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -163,73 +163,26 @@ public:
   
 protected:
   PRBool MappedAttrState(nsIContent *aContent, PRUint32 *aStateInOut, nsStateMapEntry *aStateMapEntry);
   virtual nsIFrame* GetBoundsFrame();
   virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
   PRBool IsVisible(PRBool *aIsOffscreen); 
 
   // Relation helpers
-  nsresult GetTextFromRelationID(nsIAtom *aIDAttrib, nsString &aName);
-
-  /**
-   * Search element in neighborhood of the given element by tag name and
-   * attribute value that equals to ID attribute of the current element.
-   * ID attribute can be either 'id' attribute or 'anonid' if the element is
-   * anonymous.
-   *
-   * @param aRelationAttr - attribute name of searched element
-   * @param aRelationNamespaceID - namespace id of searched attribute, by default
-   *                               empty namespace
-   * @param aAncestorLevelsToSearch - points how is the neighborhood of the
-   *                                  given element big.
-   */
-  already_AddRefed<nsIDOMNode> FindNeighbourPointingToThis(nsIAtom *aRelationAttr,
-                                                           PRUint32 aRelationNameSpaceID = kNameSpaceID_None,
-                                                           PRUint32 aAncestorLevelsToSearch = 0);
 
   /**
-   * Search element in neighborhood of the given element by tag name and
-   * attribute value that equals to ID attribute of the given element.
-   * ID attribute can be either 'id' attribute or 'anonid' if the element is
-   * anonymous.
+   * For a given ARIA relation, such as labelledby or describedby, get the collated text
+   * for the subtree that's pointed to.
    *
-   * @param aForNode - the given element the search is performed for
-   * @param aTagName - tag name of searched element
-   * @param aRelationAttr - attribute name of searched element
-   * @param aRelationNamespaceID - namespace id of searched attribute, by default
-   *                               empty namespace
-   * @param aAncestorLevelsToSearch - points how is the neighborhood of the
-   *                                  given element big.
+   * @param aIDProperty  The ARIA relationship property to get the text for
+   * @param aName        Where to put the text
+   * @return error or success code
    */
-  static nsIContent *FindNeighbourPointingToNode(nsIContent *aForNode,
-                                                 nsIAtom *aTagName,
-                                                 nsIAtom *aRelationAttr,
-                                                 PRUint32 aRelationNameSpaceID = kNameSpaceID_None,
-                                                 PRUint32 aAncestorLevelsToSearch = 5);
-
-  /**
-   * Search for element that satisfies the requirements in subtree of the given
-   * element. The requirements are tag name, attribute name and value of
-   * attribute.
-   *
-   * @param aId - value of searched attribute
-   * @param aLookContent - element that search is performed inside
-   * @param aRelationAttr - searched attribute
-   * @param aRelationNamespaceID - namespace id of searched attribute, by default
-   *                               empty namespace
-   * @param aExcludeContent - element that is skiped for search
-   * @param aTagType - tag name of searched element, by default it is 'label'
-   */
-  static nsIContent *FindDescendantPointingToID(const nsAString *aId,
-                                                nsIContent *aLookContent,
-                                                nsIAtom *aRelationAttr,
-                                                PRUint32 aRelationNamespaceID = kNameSpaceID_None,
-                                                nsIContent *aExcludeContent = nsnull,
-                                                nsIAtom *aTagType = nsAccessibilityAtoms::label);
+  nsresult GetTextFromRelationID(EAriaProperty aIDProperty, nsString &aName);
 
   static nsIContent *GetHTMLLabelContent(nsIContent *aForNode);
   static nsIContent *GetLabelContent(nsIContent *aForNode);
   static nsIContent *GetRoleContent(nsIDOMNode *aDOMNode);
 
   // Name helpers
   nsresult GetHTMLName(nsAString& _retval, PRBool aCanAggregateSubtree = PR_TRUE);
   nsresult GetXULName(nsAString& aName, PRBool aCanAggregateSubtree = PR_TRUE);
@@ -279,25 +232,24 @@ protected:
 
   /**
    *  Get the container node for an atomic region, defined by aria:atomic="true"
    *  @return the container node
    */
   nsIDOMNode* GetAtomicRegion();
 
   /**
-   * Get numeric value of the given attribute.
+   * Get numeric value of the given ARIA attribute.
    *
-   * @param aNameSpaceID - namespace ID of the attribute
-   * @param aName - name of the attribute
+   * @param aAriaProperty - the ARIA property we're using
    * @param aValue - value of the attribute
    *
    * @return - NS_OK_NO_ARIA_VALUE if there is no setted ARIA attribute
    */
-  nsresult GetAttrValue(PRUint32 aNameSpaceID, nsIAtom *aName, double *aValue);
+  nsresult GetAttrValue(EAriaProperty aAriaProperty, double *aValue);
 
   // Data Members
   nsCOMPtr<nsIAccessible> mParent;
   nsIAccessible *mFirstChild, *mNextSibling;
   nsRoleMapEntry *mRoleMapEntry; // Non-null indicates author-supplied role; possibly state & value as well
   PRInt32 mAccChildCount;
 };
 
--- a/accessible/src/base/nsAccessibleTreeWalker.cpp
+++ b/accessible/src/base/nsAccessibleTreeWalker.cpp
@@ -225,16 +225,17 @@ NS_IMETHODIMP nsAccessibleTreeWalker::Ge
 }
 
 void nsAccessibleTreeWalker::UpdateFrame(PRBool aTryFirstChild)
 {
   if (!mState.frame) {
     return;
   }
   if (aTryFirstChild) {
+    nsIContent *containerContent = mState.frame->GetContent();
     mState.frame = mState.frame->GetFirstChild(nsnull);
 // temporary workaround for Bug 359210. We never want to walk frames.
 // Aaron Leventhal will refix :before and :after content later without walking frames.
 #if 0
     if (mState.frame && mState.siblingIndex < 0) {
       // Container frames can contain generated content frames from
       // :before and :after style rules, so we walk their frame trees
       // instead of content trees
@@ -248,16 +249,27 @@ void nsAccessibleTreeWalker::UpdateFrame
       // nsStyleContext *styleContext = primaryFrame->GetStyleContext();
       // if (aContent) {
       //   pseudoContext = presContext->StyleSet()->
       //     ProbePseudoStyleFor(content, nsAccessibilityAtoms::after, aStyleContext);
       mState.domNode = do_QueryInterface(mState.frame->GetContent());
       mState.siblingIndex = eSiblingsWalkFrames;
     }
 #endif
+    // Special case: <input type="file">
+    // We should still need to walk frames inside the file control frame
+    // This special case may turn into a more general rule after Firefox 3,
+    // if HTML 5 controls use nsIAnonymousContentCreator
+    if (containerContent->Tag() == nsAccessibilityAtoms::input &&
+        containerContent->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::type,
+                                      NS_LITERAL_STRING("file"), eIgnoreCase) &&
+        mState.frame && mState.siblingIndex < 0)  {
+      mState.domNode = do_QueryInterface(mState.frame->GetContent());
+      mState.siblingIndex = eSiblingsWalkFrames;
+    }
   }
   else {
     mState.frame = mState.frame->GetNextSibling();
   }
 }
 
 /**
  * If the DOM node's frame has an accessible or the DOMNode
--- a/accessible/src/base/nsBaseWidgetAccessible.cpp
+++ b/accessible/src/base/nsBaseWidgetAccessible.cpp
@@ -221,34 +221,43 @@ NS_IMETHODIMP nsLinkableAccessible::GetK
   return nsAccessible::GetKeyboardShortcut(aKeyboardShortcut);
 }
 
 void nsLinkableAccessible::CacheActionContent()
 {
   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 (nsAccUtils::HasListener(walkUpContent, NS_LITERAL_STRING("click"))) {
+    if (isOnclick) {
       mActionContent = walkUpContent;
       mIsOnclick = PR_TRUE;
       break;
     }
   }
 }
 
 // nsIAccessibleHyperLink::GetURI()
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -79,30 +79,48 @@
 
 PRUint32 nsDocAccessible::gLastFocusedAccessiblesState = 0;
 
 //-----------------------------------------------------
 // construction
 //-----------------------------------------------------
 nsDocAccessible::nsDocAccessible(nsIDOMNode *aDOMNode, nsIWeakReference* aShell):
   nsHyperTextAccessibleWrap(aDOMNode, aShell), mWnd(nsnull),
-  mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE)
+  mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE),
+  mAriaPropTypes(eCheckNamespaced)
 {
   // For GTK+ native window, we do nothing here.
   if (!mDOMNode)
     return;
 
   // Because of the way document loading happens, the new nsIWidget is created before
   // the old one is removed. Since it creates the nsDocAccessible, for a brief moment
   // there can be 2 nsDocAccessible's for the content area, although for 2 different
   // pres shells.
 
   nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mWeakShell));
   if (shell) {
+    // Find mDocument
     mDocument = shell->GetDocument();
+    // Find mAriaPropTypes: the initial type of ARIA properties that should be checked for
+    if (!mDocument) {
+      NS_WARNING("No document!");
+      return;
+    }
+    
+    nsCOMPtr<nsIDOMNSHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
+    if (htmlDoc) {
+      nsAutoString mimeType;
+      GetMimeType(mimeType);
+      mAriaPropTypes = eCheckHyphenated;
+      if (! mimeType.EqualsLiteral("text/html")) {
+        mAriaPropTypes |= eCheckNamespaced;
+      }
+    }
+    // Find mWnd
     nsIViewManager* vm = shell->GetViewManager();
     if (vm) {
       nsCOMPtr<nsIWidget> widget;
       vm->GetWidget(getter_AddRefs(widget));
       if (widget) {
         mWnd = widget->GetNativeData(NS_NATIVE_WINDOW);
       }
     }
@@ -899,17 +917,24 @@ NS_IMETHODIMP nsDocAccessible::Observe(n
       new nsAccStateChangeEvent(this, nsIAccessibleStates::EXT_STATE_EDITABLE,
                                 PR_TRUE, PR_TRUE);
     FireAccessibleEvent(event);
   }
 
   return NS_OK;
 }
 
-///////////////////////////////////////////////////////////////////////
+NS_IMETHODIMP
+nsDocAccessible::GetAriaPropTypes(PRUint32 *aAriaPropTypes) 
+{
+  *aAriaPropTypes = mAriaPropTypes;
+  return NS_OK;
+}
+
+  ///////////////////////////////////////////////////////////////////////
 // nsIDocumentObserver
 
 NS_IMPL_NSIDOCUMENTOBSERVER_CORE_STUB(nsDocAccessible)
 NS_IMPL_NSIDOCUMENTOBSERVER_LOAD_STUB(nsDocAccessible)
 NS_IMPL_NSIDOCUMENTOBSERVER_STYLE_STUB(nsDocAccessible)
 
 void
 nsDocAccessible::AttributeChanged(nsIDocument *aDocument, nsIContent* aContent,
@@ -943,16 +968,24 @@ nsDocAccessible::AttributeChangedImpl(ns
   // Otherwise it may just be a state change, for example an object changing
   // its visibility
 
   nsCOMPtr<nsISupports> container = mDocument->GetContainer();
   nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
   if (!docShell) {
     return;
   }
+  if (aNameSpaceID == kNameSpaceID_WAIProperties) {
+    // Using setAttributeNS() in HTML to set namespaced ARIA properties.
+    // From this point forward, check namespaced properties, which
+    // take precedence over hyphenated properties, since in text/html
+    // that can only be set dynamically.
+    mAriaPropTypes |= eCheckNamespaced;
+  }
+
   PRUint32 busyFlags;
   docShell->GetBusyFlags(&busyFlags);
   if (busyFlags) {
     return; // Still loading, ignore setting of initial attributes
   }
 
   nsCOMPtr<nsIPresShell> shell = GetPresShell();
   if (!shell) {
@@ -966,17 +999,18 @@ nsDocAccessible::AttributeChangedImpl(ns
   }
 
   // Since we're in synchronous code, we can store whether the current attribute
   // change is from user input or not. If the attribute change causes an asynchronous
   // layout change, that event can use the last known user input state
   nsAccEvent::PrepareForEvent(targetNode);
 
   // Universal boolean properties that don't require a role.
-  if (aAttribute == nsAccessibilityAtoms::disabled) {
+  if (aAttribute == nsAccessibilityAtoms::disabled ||
+      (aAttribute == nsAccessibilityAtoms::aria_disabled && (mAriaPropTypes & eCheckHyphenated))) {
     // Fire the state change whether disabled attribute is
     // set for XUL, HTML or ARIA namespace.
     // Checking the namespace would not seem to gain us anything, because
     // disabled really is going to mean the same thing in any namespace.
     // We use the attribute instead of the disabled state bit because
     // ARIA's aaa:disabled does not affect the disabled state bit
     nsCOMPtr<nsIAccessibleStateChangeEvent> enabledChangeEvent =
       new nsAccStateChangeEvent(targetNode,
@@ -986,31 +1020,42 @@ nsDocAccessible::AttributeChangedImpl(ns
     nsCOMPtr<nsIAccessibleStateChangeEvent> sensitiveChangeEvent =
       new nsAccStateChangeEvent(targetNode,
                                 nsIAccessibleStates::EXT_STATE_SENSITIVE,
                                 PR_TRUE);
     FireDelayedAccessibleEvent(sensitiveChangeEvent);
     return;
   }
 
+  // Check for namespaced ARIA attribute
+  nsCOMPtr<nsIAtom> ariaAttribute;
   if (aNameSpaceID == kNameSpaceID_WAIProperties) {
-    ARIAAttributeChanged(aContent, aAttribute);
+    ariaAttribute = aAttribute;
+  }
+  else if (mAriaPropTypes & eCheckHyphenated && aNameSpaceID == kNameSpaceID_None) {
+    // Check for hyphenated aria-foo property?
+    const char* attributeName;
+    aAttribute->GetUTF8String(&attributeName);
+    if (!PL_strncmp("aria-", attributeName, 5)) {
+      // Convert to WAI property atom attribute
+      ariaAttribute = do_GetAtom(attributeName + 5);
+    }
+  }
+  if (ariaAttribute) {  // We have an ARIA attribute
+    ARIAAttributeChanged(aContent, ariaAttribute);
     return;
   }
 
-  if (aNameSpaceID == kNameSpaceID_XHTML2_Unofficial ||
-      aNameSpaceID == kNameSpaceID_XHTML) {
-    if (aAttribute == nsAccessibilityAtoms::role)
-      InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
-    return;
-  }
-
-  if (aAttribute == nsAccessibilityAtoms::href ||
+  if (aAttribute == nsAccessibilityAtoms::role ||
+      aAttribute == nsAccessibilityAtoms::href ||
       aAttribute == nsAccessibilityAtoms::onclick ||
       aAttribute == nsAccessibilityAtoms::droppable) {
+    // Not worth the expense to ensure which namespace these are in
+    // It doesn't kill use to recreate the accessible even if the attribute was used
+    // in the wrong namespace or an element that doesn't support it
     InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
     return;
   }
 
   if (aAttribute == nsAccessibilityAtoms::selected) {
     // DHTML or XUL selection
     nsCOMPtr<nsIAccessible> multiSelect = GetMultiSelectFor(targetNode);
     // Multi selects use selection_add and selection_remove
@@ -1251,17 +1296,17 @@ nsDocAccessible::FireTextChangeEventForT
     return;
   }
 
   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aContent));
   if (!node)
     return;
 
   nsCOMPtr<nsIAccessible> accessible;
-  nsresult rv = GetAccessibleInParentChain(node, getter_AddRefs(accessible));
+  nsresult rv = GetAccessibleInParentChain(node, PR_TRUE, getter_AddRefs(accessible));
   if (NS_FAILED(rv) || !accessible)
     return;
 
   nsRefPtr<nsHyperTextAccessible> textAccessible;
   rv = accessible->QueryInterface(NS_GET_IID(nsHyperTextAccessible),
                                   getter_AddRefs(textAccessible));
   if (NS_FAILED(rv) || !textAccessible)
     return;
@@ -1346,17 +1391,17 @@ nsDocAccessible::CreateTextChangeEventFo
       child->GetNextSibling(getter_AddRefs(changeAccessible));
       if (!changeAccessible) {
         break;
       }
       child.swap(changeAccessible);
     }
   }
   else {
-    NS_ASSERTION(changeAccessible == aAccessibleForChangeNode,
+    NS_ASSERTION(!changeAccessible || changeAccessible == aAccessibleForChangeNode,
                  "Hypertext is reporting a different accessible for this node");
     length = TextLength(aAccessibleForChangeNode);
     if (Role(aAccessibleForChangeNode) == nsIAccessibleRole::ROLE_WHITESPACE) {  // newline
       // Don't fire event for the first html:br in an editor.
       nsCOMPtr<nsIEditor> editor;
       textAccessible->GetAssociatedEditor(getter_AddRefs(editor));
       if (editor) {
         PRBool isEmpty = PR_FALSE;
@@ -1499,40 +1544,55 @@ NS_IMETHODIMP nsDocAccessible::FlushPend
 
     nsCOMPtr<nsIAccessible> accessible;
     accessibleEvent->GetAccessible(getter_AddRefs(accessible));
 
     PRUint32 eventType;
     accessibleEvent->GetEventType(&eventType);
     if (eventType == nsIAccessibleEvent::EVENT_DOM_CREATE || 
         eventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW) {
+      nsCOMPtr<nsIAccessible> containerAccessible;
+      if (accessible) {
+        accessible->GetParent(getter_AddRefs(containerAccessible));
+        nsCOMPtr<nsPIAccessible> privateContainerAccessible =
+          do_QueryInterface(containerAccessible);
+        if (privateContainerAccessible)
+          privateContainerAccessible->InvalidateChildren();
+      }
+
       // Also fire text changes if the node being created could affect the text in an nsIAccessibleText parent.
       // When a node is being made visible or is inserted, the text in an ancestor hyper text will gain characters
       // At this point we now have the frame and accessible for this node if there is one. That is why we
       // wait to fire this here, instead of in InvalidateCacheSubtree(), where we wouldn't be able to calculate
       // the offset, length and text for the text change.
       nsCOMPtr<nsIDOMNode> domNode;
       accessibleEvent->GetDOMNode(getter_AddRefs(domNode));
+      PRBool isFromUserInput;
+      accessibleEvent->GetIsFromUserInput(&isFromUserInput);
       if (domNode && domNode != mDOMNode) {
-        nsCOMPtr<nsIAccessible> containerAccessible;
-        GetAccessibleInParentChain(domNode, getter_AddRefs(containerAccessible));
+        if (!containerAccessible)
+          GetAccessibleInParentChain(domNode, PR_TRUE,
+                                     getter_AddRefs(containerAccessible));
+
         nsCOMPtr<nsIAccessibleTextChangeEvent> textChangeEvent =
           CreateTextChangeEventForNode(containerAccessible, domNode, accessible, PR_TRUE, PR_TRUE);
         if (textChangeEvent) {
-          PRBool isFromUserInput;
-          accessibleEvent->GetIsFromUserInput(&isFromUserInput);
           nsCOMPtr<nsIDOMNode> hyperTextNode;
           textChangeEvent->GetDOMNode(getter_AddRefs(hyperTextNode));
           nsAccEvent::PrepareForEvent(hyperTextNode, isFromUserInput);
           // XXX Queue them up and merge the text change events
           // XXX We need a way to ignore SplitNode and JoinNode() when they
           // do not affect the text within the hypertext
           FireAccessibleEvent(textChangeEvent);
         }
       }
+
+      // Fire show/create events for this node or first accessible descendants of it
+      FireShowHideEvents(domNode, eventType, PR_FALSE, isFromUserInput); 
+      continue;
     }
 
     if (accessible) {
       if (eventType == nsIAccessibleEvent::EVENT_INTERNAL_LOAD) {
         nsCOMPtr<nsPIAccessibleDocument> docAccessible =
           do_QueryInterface(accessible);
         NS_ASSERTION(docAccessible, "No doc accessible for doc load event");
         if (docAccessible) {
@@ -1693,38 +1753,61 @@ NS_IMETHODIMP nsDocAccessible::Invalidat
 
   // Invalidate cache subtree
   // We have to check for accessibles for each dom node by traversing DOM tree
   // instead of just the accessible tree, although that would be faster
   // Otherwise we might miss the nsAccessNode's that are not nsAccessible's.
 
   NS_ENSURE_TRUE(mDOMNode, NS_ERROR_FAILURE);
   nsCOMPtr<nsIDOMNode> childNode = aChild ? do_QueryInterface(aChild) : mDOMNode;
-  if (!IsNodeRelevant(childNode)) {
-    return NS_OK;  // Don't fire event unless it can be for an attached accessible
-  }
-  if (!mIsContentLoaded && mAccessNodeCache.Count() <= 1) {
-    // Still loading and no accessibles has yet been created other than this
-    // doc accessible. In this case we optimize
-    // by not firing SHOW/HIDE/REORDER events for every document mutation
-    // caused by page load, since AT is not going to want to grab the
-    // document and listen to these changes until after the page is first loaded
-    // Leave early, and ensure mAccChildCount stays uninitialized instead of 0,
-    // which it is if anyone asks for its children right now.
-    return InvalidateChildren();
+
+  if (!mIsContentLoaded) {
+    // Still loading document
+    if (mAccessNodeCache.Count() <= 1) {
+      // Still loading and no accessibles has yet been created other than this
+      // doc accessible. In this case we optimize
+      // by not firing SHOW/HIDE/REORDER events for every document mutation
+      // caused by page load, since AT is not going to want to grab the
+      // document and listen to these changes until after the page is first loaded
+      // Leave early, and ensure mAccChildCount stays uninitialized instead of 0,
+      // which it is if anyone asks for its children right now.
+      return InvalidateChildren();
+    }
+    if (aChangeEventType == nsIAccessibleEvent::EVENT_DOM_CREATE) {
+      nsCOMPtr<nsIPresShell> presShell = GetPresShell();
+      NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
+      nsIEventStateManager *esm = presShell->GetPresContext()->EventStateManager();
+      NS_ENSURE_TRUE(esm, NS_ERROR_FAILURE);
+      if (!esm->IsHandlingUserInputExternal()) {
+        // Adding content during page load, but not caused by user input
+        // Just invalidate accessible hierarchy and return,
+        // otherwise the page load time slows down way too much
+        nsCOMPtr<nsIAccessible> containerAccessible;
+        GetAccessibleInParentChain(childNode, PR_FALSE, getter_AddRefs(containerAccessible));
+        if (!containerAccessible) {
+          containerAccessible = this;
+        }
+        nsCOMPtr<nsPIAccessible> privateContainer = do_QueryInterface(containerAccessible);
+        return privateContainer->InvalidateChildren();
+      }     
+      // else: user input, so we must fall through and for full handling,
+      // e.g. fire the mutation events. Note: user input could cause DOM_CREATE
+      // during page load if user typed into an input field or contentEditable area
+    }
   }
 
   // Update last change state information
   nsCOMPtr<nsIAccessNode> childAccessNode;
   GetCachedAccessNode(childNode, getter_AddRefs(childAccessNode));
   nsCOMPtr<nsIAccessible> childAccessible = do_QueryInterface(childAccessNode);
   if (!childAccessible && !isHiding) {
     // If not about to hide it, make sure there's an accessible so we can fire an
     // event for it
-    GetAccService()->GetAccessibleFor(childNode, getter_AddRefs(childAccessible));
+    GetAccService()->GetAttachedAccessibleFor(childNode,
+                                              getter_AddRefs(childAccessible));
   }
 
 #ifdef DEBUG_A11Y
   nsAutoString localName;
   childNode->GetLocalName(localName);
   const char *hasAccessible = childAccessible ? " (acc)" : "";
   if (aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE) {
     printf("[Hide %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
@@ -1742,32 +1825,49 @@ NS_IMETHODIMP nsDocAccessible::Invalidat
     printf("[Destroy  %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
   }
   else if (aChangeEventType == nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE) {
     printf("[Type change %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
   }
 #endif
 
   nsCOMPtr<nsIAccessible> containerAccessible;
-  GetAccessibleInParentChain(childNode, getter_AddRefs(containerAccessible));
+  GetAccessibleInParentChain(childNode, PR_TRUE, getter_AddRefs(containerAccessible));
   if (!containerAccessible) {
     containerAccessible = this;
   }
 
   if (!isShowing) {
-    // Fire EVENT_ASYNCH_HIDE or EVENT_DOM_DESTROY if previous accessible existed for node being hidden.
-    // Fire this before the accessible goes away.
-    if (childAccessible) {
-      PRUint32 removalEventType = isAsynch ? nsIAccessibleEvent::EVENT_ASYNCH_HIDE :
-                                  nsIAccessibleEvent::EVENT_DOM_DESTROY;
-      nsCOMPtr<nsIAccessibleEvent> removalEvent =
-        new nsAccEvent(removalEventType, childAccessible, nsnull, PR_TRUE);
-      NS_ENSURE_TRUE(removalEvent, NS_ERROR_OUT_OF_MEMORY);
-      FireDelayedAccessibleEvent(removalEvent, eCoalesceFromSameSubtree, isAsynch);
+    // Fire EVENT_ASYNCH_HIDE or EVENT_DOM_DESTROY
+    nsCOMPtr<nsIContent> content(do_QueryInterface(childNode));
+    if (isHiding) {
+      nsCOMPtr<nsIPresShell> presShell = GetPresShell();
+      if (content) {
+        nsIFrame *frame = presShell->GetPrimaryFrameFor(content);
+        if (frame) {
+          nsIFrame *frameParent = frame->GetParent();
+          if (!frameParent || !frameParent->GetStyleVisibility()->IsVisible()) {
+            // Ancestor already hidden or being hidden at the same time:
+            // don't process redundant hide event
+            // This often happens when visibility is cleared for node,
+            // which hides an entire subtree -- we get notified for each
+            // node in the subtree and need to collate the hide events ourselves.
+            return NS_OK;
+          }
+        }
+      }
     }
+
+    PRUint32 removalEventType = isAsynch ? nsIAccessibleEvent::EVENT_ASYNCH_HIDE :
+                                           nsIAccessibleEvent::EVENT_DOM_DESTROY;
+
+    // Fire an event if the accessible existed for node being hidden, otherwise
+    // for the first line accessible descendants. Fire before the accessible(s) away.
+    nsresult rv = FireShowHideEvents(childNode, removalEventType, PR_TRUE, PR_FALSE);
+    NS_ENSURE_SUCCESS(rv, rv);
     if (childNode != mDOMNode) { // Fire text change unless the node being removed is for this doc
       // When a node is hidden or removed, the text in an ancestor hyper text will lose characters
       // At this point we still have the frame and accessible for this node if there was one
       // XXX Collate events when a range is deleted
       // XXX We need a way to ignore SplitNode and JoinNode() when they
       // do not affect the text within the hypertext
       nsCOMPtr<nsIAccessibleTextChangeEvent> textChangeEvent =
         CreateTextChangeEventForNode(containerAccessible, childNode, childAccessible,
@@ -1781,21 +1881,16 @@ NS_IMETHODIMP nsDocAccessible::Invalidat
   // We need to get an accessible for the mutation event's container node
   // If there is no accessible for that node, we need to keep moving up the parent
   // chain so there is some accessible.
   // We will use this accessible to fire the accessible mutation event.
   // We're guaranteed success, because we will eventually end up at the doc accessible,
   // and there is always one of those.
 
   if (aChild && !isHiding) {
-    nsCOMPtr<nsPIAccessible> privateContainerAccessible =
-      do_QueryInterface(containerAccessible);
-    if (privateContainerAccessible) {
-      privateContainerAccessible->InvalidateChildren();
-    }
     // 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, nsnull,
@@ -1832,16 +1927,17 @@ NS_IMETHODIMP nsDocAccessible::Invalidat
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocAccessible::GetAccessibleInParentChain(nsIDOMNode *aNode,
+                                            PRBool aCanCreate,
                                             nsIAccessible **aAccessible)
 {
   // Find accessible in parent chain of DOM nodes, or return null
   *aAccessible = nsnull;
   nsCOMPtr<nsIDOMNode> currentNode(aNode), parentNode;
   nsCOMPtr<nsIAccessNode> accessNode;
 
   nsIAccessibilityService *accService = GetAccService();
@@ -1855,19 +1951,78 @@ nsDocAccessible::GetAccessibleInParentCh
       *aAccessible = this;
       break;
     }
 
     nsCOMPtr<nsIDOMNode> relevantNode;
     if (NS_SUCCEEDED(accService->GetRelevantContentNodeFor(currentNode, getter_AddRefs(relevantNode))) && relevantNode) {
       currentNode = relevantNode;
     }
+    if (aCanCreate) {
+      accService->GetAccessibleInWeakShell(currentNode, mWeakShell, aAccessible);
+    }
+    else { // Only return cached accessibles, don't create anything
+      nsCOMPtr<nsIAccessNode> accessNode;
+      GetCachedAccessNode(currentNode, getter_AddRefs(accessNode)); // AddRefs
+      if (accessNode) {
+        CallQueryInterface(accessNode, aAccessible); // AddRefs
+      }
+    }
+  } while (!*aAccessible);
 
-    accService->GetAccessibleInWeakShell(currentNode, mWeakShell, aAccessible);
-  } while (!*aAccessible);
+  return NS_OK;
+}
+
+nsresult
+nsDocAccessible::FireShowHideEvents(nsIDOMNode *aDOMNode, PRUint32 aEventType,
+                                    PRBool aDelay, PRBool aForceIsFromUserInput)
+{
+  NS_ENSURE_ARG(aDOMNode);
+
+  nsCOMPtr<nsIAccessible> accessible;
+  if (aEventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
+      aEventType == nsIAccessibleEvent::EVENT_DOM_DESTROY) {
+    // Don't allow creation for accessibles when nodes going away
+    nsCOMPtr<nsIAccessNode> accessNode;
+    GetCachedAccessNode(aDOMNode, getter_AddRefs(accessNode));
+    accessible = do_QueryInterface(accessNode);
+  } else {
+    // Allow creation of new accessibles for show events
+    GetAccService()->GetAttachedAccessibleFor(aDOMNode,
+                                              getter_AddRefs(accessible));
+  }
+
+  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, nsnull, isAsynch);
+    NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
+    if (aForceIsFromUserInput) {
+      nsAccEvent::PrepareForEvent(aDOMNode, aForceIsFromUserInput);
+    }
+    if (aDelay) {
+      return FireDelayedAccessibleEvent(event, eCoalesceFromSameSubtree, isAsynch);
+    }
+    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();
+  for (PRUint32 index = 0; index < count; index++) {
+    nsCOMPtr<nsIDOMNode> childNode = do_QueryInterface(content->GetChildAt(index));
+    nsresult rv = FireShowHideEvents(childNode, aEventType,
+                                     aDelay, aForceIsFromUserInput);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
 
   return NS_OK;
 }
 
 void nsDocAccessible::DocLoadCallback(nsITimer *aTimer, void *aClosure)
 {
   // Doc has finished loading, fire "load finished" event
   // By using short timer we can wait make the window visible, 
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -187,28 +187,41 @@ class nsDocAccessible : public nsHyperTe
      */
     already_AddRefed<nsIAccessibleTextChangeEvent>
     CreateTextChangeEventForNode(nsIAccessible *aContainerAccessible,
                                  nsIDOMNode *aChangeNode,
                                  nsIAccessible *aAccessibleForNode,
                                  PRBool aIsInserting,
                                  PRBool aIsAsynch);
 
+    /**
+     * Fire show/hide events for either the current node if it has an accessible,
+     * or the first-line accessible descendants of the given node.
+     *
+     * @param aDOMNode               the given node
+     * @param aEventType             event type to fire an event
+     * @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, PRUint32 aEventType,
+                                PRBool aDelay, PRBool aForceIsFromUserInput);
+
     nsAccessNodeHashtable mAccessNodeCache;
     void *mWnd;
     nsCOMPtr<nsIDocument> mDocument;
     nsCOMPtr<nsITimer> mScrollWatchTimer;
     nsCOMPtr<nsITimer> mFireEventTimer;
     PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
     PRPackedBool mIsContentLoaded;
     nsCOMArray<nsIAccessibleEvent> mEventsToFire;
 
 protected:
     PRBool mIsAnchor;
     PRBool mIsAnchorJumped;
+    PRUint32 mAriaPropTypes;
     static PRUint32 gLastFocusedAccessiblesState;
 
 private:
     static void DocLoadCallback(nsITimer *aTimer, void *aClosure);
     nsCOMPtr<nsITimer> mDocLoadTimer;
 };
 
 #endif  
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -318,24 +318,16 @@ nsresult nsRootAccessible::AddEventListe
   if (target) {
     target->AddEventListener(NS_LITERAL_STRING("pagehide"), this, PR_TRUE);
   }
 
   if (!mCaretAccessible) {
     mCaretAccessible = new nsCaretAccessible(this);
   }
 
-  // Fire accessible focus event for pre-existing focus, but wait until all internal
-  // focus events are finished for window initialization.
-  mFireFocusTimer = do_CreateInstance("@mozilla.org/timer;1");
-  if (mFireFocusTimer) {
-    mFireFocusTimer->InitWithFuncCallback(FireFocusCallback, this,
-                                          0, nsITimer::TYPE_ONE_SHOT);
-  }
-
   return nsDocAccessible::AddEventListeners();
 }
 
 nsresult nsRootAccessible::RemoveEventListeners()
 {
   nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(mDocument));
   if (target) { 
     for (const char* const* e = docEvents,
@@ -383,16 +375,22 @@ void nsRootAccessible::TryFireEarlyLoadE
   if (!treeItem) {
     return;
   }
   PRInt32 itemType;
   treeItem->GetItemType(&itemType);
   if (itemType != nsIDocShellTreeItem::typeContent) {
     return;
   }
+
+  // At minimum, create doc accessible so that events are listened to,
+  // allowing us to see any mutations from a page load handler
+  nsCOMPtr<nsIAccessible> docAccessible;
+  GetAccService()->GetAccessibleFor(aDocNode, getter_AddRefs(docAccessible));
+
   nsCOMPtr<nsIDocShellTreeNode> treeNode(do_QueryInterface(treeItem));
   if (treeNode) {
     PRInt32 subDocuments;
     treeNode->GetChildCount(&subDocuments);
     if (subDocuments) {
       return;
     }
   }
@@ -455,17 +453,17 @@ PRBool nsRootAccessible::FireAccessibleF
   }
 
   // Check for aaa:activedescendant, which changes which element has focus
   nsCOMPtr<nsIDOMNode> finalFocusNode = aNode;
   nsCOMPtr<nsIAccessible> finalFocusAccessible = aAccessible;
   nsCOMPtr<nsIContent> finalFocusContent  = do_QueryInterface(aNode);
   if (finalFocusContent) {
     nsAutoString id;
-    if (finalFocusContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::activedescendant, id)) {
+    if (nsAccUtils::GetAriaProperty(finalFocusContent, nsnull, eAria_activedescendant, id)) {
       nsCOMPtr<nsIDOMDocument> domDoc;
       aNode->GetOwnerDocument(getter_AddRefs(domDoc));
       if (!domDoc) {
         return PR_FALSE;
       }
       nsCOMPtr<nsIDOMElement> relatedEl;
       domDoc->GetElementById(id, getter_AddRefs(relatedEl));
       finalFocusNode = do_QueryInterface(relatedEl);
@@ -659,17 +657,17 @@ nsresult nsRootAccessible::HandleEventWi
       FireAccessibleFocusEvent(accessible, aTargetNode, aEvent);
 
     return NS_OK;
   }
 
   if (eventType.EqualsLiteral("CheckboxStateChange")) {
     PRUint32 state = State(accessible);
 
-    PRBool isEnabled = state & nsIAccessibleStates::STATE_CHECKED;
+    PRBool isEnabled = !!(state & nsIAccessibleStates::STATE_CHECKED);
 
     nsCOMPtr<nsIAccessibleStateChangeEvent> accEvent =
       new nsAccStateChangeEvent(accessible,
                                 nsIAccessibleStates::STATE_CHECKED,
                                 PR_FALSE, isEnabled);
 
     return privAcc->FireAccessibleEvent(accEvent);
   }
@@ -728,16 +726,29 @@ nsresult nsRootAccessible::HandleEventWi
 
       return nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_SELECTION,
                                       treeItemAccessible);
     }
   }
   else
 #endif
   if (eventType.EqualsLiteral("focus")) {
+    if (aTargetNode == mDOMNode) {
+      // Got focus event for the window, we will make sure that an accessible
+      // focus event for initial focus is fired. We do this on a short timer
+      // because the initial focus may not have been set yet.
+      if (!mFireFocusTimer) {
+        mFireFocusTimer = do_CreateInstance("@mozilla.org/timer;1");
+      }
+      if (mFireFocusTimer) {
+        mFireFocusTimer->InitWithFuncCallback(FireFocusCallback, this,
+                                              0, nsITimer::TYPE_ONE_SHOT);
+      }
+    }
+
     // Keep a reference to the target node. We might want to change
     // it to the individual radio button or selected item, and send
     // the focus event to that.
     nsCOMPtr<nsIDOMNode> focusedItem(aTargetNode);
 
     if (!treeItemAccessible) {
       nsCOMPtr<nsIDOMXULSelectControlElement> selectControl =
         do_QueryInterface(aTargetNode);
--- a/accessible/src/html/Makefile.in
+++ b/accessible/src/html/Makefile.in
@@ -56,16 +56,17 @@ REQUIRES	= composer \
 		  imglib2 \
 		  intl \
 		  js \
 		  layout \
 		  locale \
 		  necko \
 		  string \
 		  thebes \
+		  view \
 		  webshell \
 		  widget \
 		  xpcom \
 		  xpconnect \
 		  $(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 REQUIRES += editor
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -51,16 +51,17 @@
 #include "nsIDOMDocumentView.h"
 #include "nsIDOMRange.h"
 #include "nsIDOMWindowInternal.h"
 #include "nsIDOMXULDocument.h"
 #include "nsIEditingSession.h"
 #include "nsIEditor.h"
 #include "nsIFontMetrics.h"
 #include "nsIFrame.h"
+#include "nsIScrollableFrame.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIPlaintextEditor.h"
 #include "nsISelection2.h"
 #include "nsIServiceManager.h"
 #include "nsTextFragment.h"
 #include "gfxSkipChars.h"
 
 static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
@@ -660,16 +661,69 @@ nsresult nsHyperTextAccessible::DOMPoint
       // If not at end of last text node, we will return the accessible we were in
       NS_ADDREF(*aFinalAccessible = childAccessible);
     }
   }
 
   return NS_OK;
 }
 
+nsresult
+nsHyperTextAccessible::HypertextOffsetsToDOMRange(PRInt32 aStartHTOffset,
+                                                  PRInt32 aEndHTOffset,
+                                                  nsIDOMNode **aStartNode,
+                                                  PRInt32 *aStartOffset,
+                                                  nsIDOMNode **aEndNode,
+                                                  PRInt32 *aEndOffset)
+{
+  NS_ENSURE_ARG_POINTER(aStartNode);
+  *aStartNode = nsnull;
+
+  NS_ENSURE_ARG_POINTER(aStartOffset);
+  *aStartOffset = -1;
+
+  NS_ENSURE_ARG_POINTER(aEndNode);
+  *aEndNode = nsnull;
+
+  NS_ENSURE_ARG_POINTER(aEndOffset);
+  *aEndOffset = -1;
+
+  nsCOMPtr<nsIAccessible> startAcc, endAcc;
+  PRInt32 startOffset = aStartHTOffset, endOffset = aEndHTOffset;
+  nsIFrame *startFrame = nsnull, *endFrame = nsnull;
+
+  startFrame = GetPosAndText(startOffset, endOffset, nsnull, &endFrame, nsnull,
+                             getter_AddRefs(startAcc), getter_AddRefs(endAcc));
+  if (!startAcc || !endAcc)
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIDOMNode> startNode, endNode;
+  nsresult rv = GetDOMPointByFrameOffset(startFrame, startOffset, startAcc,
+                                         getter_AddRefs(startNode),
+                                         &startOffset);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aStartHTOffset != aEndHTOffset) {
+    rv = GetDOMPointByFrameOffset(endFrame, endOffset, endAcc,
+                                  getter_AddRefs(endNode), &endOffset);
+    NS_ENSURE_SUCCESS(rv, rv);
+  } else {
+    endNode = startNode;
+    endOffset = startOffset;
+  }
+
+  NS_ADDREF(*aStartNode = startNode);
+  *aStartOffset = startOffset;
+
+  NS_ADDREF(*aEndNode = endNode);
+  *aEndOffset = endOffset;
+
+  return NS_OK;
+}
+
 PRInt32
 nsHyperTextAccessible::GetRelativeOffset(nsIPresShell *aPresShell,
                                          nsIFrame *aFromFrame,
                                          PRInt32 aFromOffset,
                                          nsIAccessible *aFromAccessible,
                                          nsSelectionAmount aAmount,
                                          nsDirection aDirection,
                                          PRBool aNeedsStart)
@@ -1567,111 +1621,57 @@ NS_IMETHODIMP nsHyperTextAccessible::Get
   }
 
   return DOMPointToHypertextOffset(endNode, endOffset, aEndOffset, nsnull, PR_TRUE);
 }
 
 /*
  * Changes the start and end offset of the specified selection.
  */
-NS_IMETHODIMP nsHyperTextAccessible::SetSelectionBounds(PRInt32 aSelectionNum, PRInt32 aStartOffset, PRInt32 aEndOffset)
+NS_IMETHODIMP
+nsHyperTextAccessible::SetSelectionBounds(PRInt32 aSelectionNum,
+                                          PRInt32 aStartOffset,
+                                          PRInt32 aEndOffset)
 {
   nsCOMPtr<nsISelection> domSel;
   nsresult rv = GetSelections(nsnull, getter_AddRefs(domSel));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  PRInt32 isOnlyCaret = (aStartOffset == aEndOffset); // Caret is a collapsed selection
+  // Caret is a collapsed selection
+  PRBool isOnlyCaret = (aStartOffset == aEndOffset);
 
   PRInt32 rangeCount;
   domSel->GetRangeCount(&rangeCount);
   nsCOMPtr<nsIDOMRange> range;
   if (aSelectionNum == rangeCount) { // Add a range
     range = do_CreateInstance(kRangeCID);
     NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY);
   }
   else if (aSelectionNum < 0 || aSelectionNum > rangeCount) {
     return NS_ERROR_INVALID_ARG;
   }
   else {
     domSel->GetRangeAt(aSelectionNum, getter_AddRefs(range));
     NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
   }
 
-  nsIFrame *endFrame;
-  nsCOMPtr<nsIAccessible> startAcc, endAcc;
-  nsIFrame *startFrame = GetPosAndText(aStartOffset, aEndOffset, nsnull, &endFrame, nsnull,
-                                       getter_AddRefs(startAcc), getter_AddRefs(endAcc));
-
-  nsCOMPtr<nsIPresShell> shell = GetPresShell();
+  PRInt32 startOffset, endOffset;
+  nsCOMPtr<nsIDOMNode> startNode, endNode;
 
-  if (!startFrame) { // past the end of the hyper text
-    nsCOMPtr<nsIAccessNode> startAccessNode = do_QueryInterface(startAcc);
-    NS_ENSURE_TRUE(startAccessNode, NS_ERROR_FAILURE);
-    nsCOMPtr<nsIDOMNode> node;
-    startAccessNode->GetDOMNode(getter_AddRefs(node));
-    NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
-    rv = range->SetStartAfter(node);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  else {
-    nsIContent *startParentContent = startFrame->GetContent();
-    PRInt32 startOffset;
-    if (startFrame->GetType() != nsAccessibilityAtoms::textFrame) {
-      nsIContent *newParent = startParentContent->GetParent();
-      startOffset = newParent->IndexOf(startParentContent);
-      startParentContent = newParent;
-    }
-    else {
-      // We have a rendered offset into the text frame, and it needs to be
-      // a content offset for us to set the caret
-      nsIFrame *startPrimaryFrame =
-        shell->GetPrimaryFrameFor(startFrame->GetContent());
-      rv = RenderedToContentOffset(startPrimaryFrame, aStartOffset, &startOffset);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-    nsCOMPtr<nsIDOMNode> startParentNode(do_QueryInterface(startParentContent));
-    NS_ENSURE_TRUE(startParentNode, NS_ERROR_FAILURE);
-    rv = range->SetStart(startParentNode, startOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
+  rv = HypertextOffsetsToDOMRange(aStartOffset, aEndOffset,
+                                  getter_AddRefs(startNode), &startOffset,
+                                  getter_AddRefs(endNode), &endOffset);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  if (isOnlyCaret) { 
-    rv = range->Collapse(PR_TRUE);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  else if (!endFrame) {  // past the end of the hyper text
-    nsCOMPtr<nsIAccessNode> endAccessNode = do_QueryInterface(endAcc);
-    NS_ENSURE_TRUE(endAccessNode, NS_ERROR_FAILURE);
-    nsCOMPtr<nsIDOMNode> node;
-    endAccessNode->GetDOMNode(getter_AddRefs(node));
-    NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
-    rv = range->SetEndAfter(node);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  else {
-    nsIContent *endParentContent = endFrame->GetContent();
-    PRInt32 endOffset;
-    if (endFrame->GetType() != nsAccessibilityAtoms::textFrame) {
-      nsIContent *newParent = endParentContent->GetParent();
-      endOffset = newParent->IndexOf(endParentContent);
-      endParentContent = newParent;
-    }
-    else {
-      // We have a rendered offset into the text frame, and it needs to be
-      // a content offset for us to set the caret
-      nsIFrame *endPrimaryFrame =
-        shell->GetPrimaryFrameFor(endFrame->GetContent());
-      rv = RenderedToContentOffset(endPrimaryFrame, aEndOffset, &endOffset);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-    nsCOMPtr<nsIDOMNode> endParentNode(do_QueryInterface(endParentContent));
-    NS_ENSURE_TRUE(endParentNode, NS_ERROR_FAILURE);
-    rv = range->SetEnd(endParentNode, endOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
+  rv = range->SetStart(startNode, startOffset);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = isOnlyCaret ? range->Collapse(PR_TRUE) :
+                     range->SetEnd(endNode, endOffset);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   if (aSelectionNum == rangeCount) { // Add successfully created new range
     return domSel->AddRange(range);
   }
   return NS_OK;
 }
 
 /*
@@ -1703,66 +1703,106 @@ NS_IMETHODIMP nsHyperTextAccessible::Rem
   if (aSelectionNum < 0 || aSelectionNum >= rangeCount)
     return NS_ERROR_INVALID_ARG;
 
   nsCOMPtr<nsIDOMRange> range;
   domSel->GetRangeAt(aSelectionNum, getter_AddRefs(range));
   return domSel->RemoveRange(range);
 }
 
+// void nsIAccessibleText::
+//   scrollSubstringTo(in long startIndex, in long endIndex,
+//                     in unsigned long scrollType);
 NS_IMETHODIMP
 nsHyperTextAccessible::ScrollSubstringTo(PRInt32 aStartIndex, PRInt32 aEndIndex,
                                          PRUint32 aScrollType)
 {
-  PRInt32 startOffset = aStartIndex, endOffset = aEndIndex;
-  nsIFrame *startFrame = nsnull, *endFrame = nsnull;
-  nsCOMPtr<nsIAccessible> startAcc, endAcc;
-
-  startFrame = GetPosAndText(startOffset, endOffset,
-                             nsnull, &endFrame, nsnull,
-                             getter_AddRefs(startAcc), getter_AddRefs(endAcc));
-  if (!startFrame || !endFrame)
-    return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIDOMNode> startNode;
-  nsCOMPtr<nsIContent> startContent(startFrame->GetContent());
+  PRInt32 startOffset, endOffset;
+  nsCOMPtr<nsIDOMNode> startNode, endNode;
 
-  if (startFrame->GetType() == nsAccessibilityAtoms::textFrame) {
-    nsresult rv = RenderedToContentOffset(startFrame, startOffset,
-                                          &startOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
-    startNode = do_QueryInterface(startContent);
-  } else {
-    nsCOMPtr<nsIContent> startParent(startContent->GetParent());
-    NS_ENSURE_STATE(startParent);
-    startOffset = startParent->IndexOf(startContent);
-    startNode = do_QueryInterface(startParent);
-  }
-  NS_ENSURE_STATE(startNode);
-
-  nsCOMPtr<nsIDOMNode> endNode;
-  nsCOMPtr<nsIContent> endContent(endFrame->GetContent());
-
-  if (endFrame->GetType() == nsAccessibilityAtoms::textFrame) {
-    nsresult rv = RenderedToContentOffset(endFrame, endOffset,
-                                          &endOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
-    endNode = do_QueryInterface(endContent);
-  } else {
-    nsCOMPtr<nsIContent> endParent(endContent->GetParent());
-    NS_ENSURE_STATE(endParent);
-    endOffset = endParent->IndexOf(endContent);
-    endNode = do_QueryInterface(endParent);
-  }
-  NS_ENSURE_STATE(endNode);
+  nsresult rv = HypertextOffsetsToDOMRange(aStartIndex, aEndIndex,
+                                           getter_AddRefs(startNode),
+                                           &startOffset,
+                                           getter_AddRefs(endNode),
+                                           &endOffset);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   return nsAccUtils::ScrollSubstringTo(GetFrame(), startNode, startOffset,
                                        endNode, endOffset, aScrollType);
 }
 
+// void nsIAccessibleText::
+//   scrollSubstringToPoint(in long startIndex, in long endIndex,
+//                          in unsigned long coordinateType,
+//                          in long x, in long y);
+NS_IMETHODIMP
+nsHyperTextAccessible::ScrollSubstringToPoint(PRInt32 aStartIndex,
+                                              PRInt32 aEndIndex,
+                                              PRUint32 aCoordinateType,
+                                              PRInt32 aX, PRInt32 aY)
+{
+  nsIFrame *frame = GetFrame();
+  if (!frame)
+    return NS_ERROR_FAILURE;
+
+  nsIntPoint coords;
+  nsresult rv = nsAccUtils::ConvertToScreenCoords(aX, aY, aCoordinateType,
+                                                  this, &coords);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PRInt32 startOffset, endOffset;
+  nsCOMPtr<nsIDOMNode> startNode, endNode;
+
+  rv = HypertextOffsetsToDOMRange(aStartIndex, aEndIndex,
+                                  getter_AddRefs(startNode), &startOffset,
+                                  getter_AddRefs(endNode), &endOffset);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsPresContext *presContext = frame->PresContext();
+
+  PRBool initialScrolled = PR_FALSE;
+  nsIFrame *parentFrame = frame;
+  while (parentFrame = parentFrame->GetParent()) {
+    nsIScrollableFrame *scrollableFrame = nsnull;
+    CallQueryInterface(parentFrame, &scrollableFrame);
+    if (scrollableFrame) {
+      if (!initialScrolled) {
+        // Scroll substring to the given point. Turn the point into percents
+        // relative scrollable area to use nsAccUtils::ScrollSubstringTo.
+        nsIntRect frameRect = parentFrame->GetScreenRectExternal();
+        PRInt32 devOffsetX = coords.x - frameRect.x;
+        PRInt32 devOffsetY = coords.y - frameRect.y;
+
+        nsPoint offsetPoint(presContext->DevPixelsToAppUnits(devOffsetX),
+                            presContext->DevPixelsToAppUnits(devOffsetY));
+
+        nsSize size(parentFrame->GetSize());
+        PRInt16 hPercent = offsetPoint.x * 100 / size.width;
+        PRInt16 vPercent = offsetPoint.y * 100 / size.height;
+
+        rv = nsAccUtils::ScrollSubstringTo(GetFrame(), startNode, startOffset,
+                                           endNode, endOffset,
+                                           vPercent, hPercent);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        initialScrolled = PR_TRUE;
+      } else {
+        // Substring was scrolled to the given point already inside its closest
+        // scrollable area. If there are nested scrollable areas then make
+        // sure we scroll lower areas to the given point inside currently
+        // traversed scrollable area.
+        nsAccUtils::ScrollFrameToPoint(parentFrame, frame, coords);
+      }
+    }
+    frame = parentFrame;
+  }
+
+  return NS_OK;
+}
+
 nsresult nsHyperTextAccessible::ContentToRenderedOffset(nsIFrame *aFrame, PRInt32 aContentOffset,
                                                         PRUint32 *aRenderedOffset)
 {
   NS_ASSERTION(aFrame->GetType() == nsAccessibilityAtoms::textFrame,
                "Need text frame for offset conversion");
   NS_ASSERTION(aFrame->GetPrevContinuation() == nsnull,
                "Call on primary frame only");
 
@@ -1798,9 +1838,63 @@ nsresult nsHyperTextAccessible::Rendered
   PRUint32 ourRenderedStart = iter.GetSkippedOffset();
   PRInt32 ourContentStart = iter.GetOriginalOffset();
 
   *aContentOffset = iter.ConvertSkippedToOriginal(aRenderedOffset + ourRenderedStart) - ourContentStart;
 
   return NS_OK;
 }
 
+nsresult
+nsHyperTextAccessible::GetDOMPointByFrameOffset(nsIFrame *aFrame,
+                                                PRInt32 aOffset,
+                                                nsIAccessible *aAccessible,
+                                                nsIDOMNode **aNode,
+                                                PRInt32 *aNodeOffset)
+{
+  NS_ENSURE_ARG(aAccessible);
 
+  nsCOMPtr<nsIDOMNode> node;
+
+  if (!aFrame) {
+    // If the given frame is null then set offset after the DOM node of the
+    // given accessible.
+    nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(aAccessible));
+
+    nsCOMPtr<nsIDOMNode> DOMNode;
+    accessNode->GetDOMNode(getter_AddRefs(DOMNode));
+    nsCOMPtr<nsIContent> content(do_QueryInterface(DOMNode));
+    NS_ENSURE_STATE(content);
+
+    nsCOMPtr<nsIContent> parent(content->GetParent());
+    NS_ENSURE_STATE(parent);
+
+    *aNodeOffset = parent->IndexOf(content) + 1;
+    node = do_QueryInterface(parent);
+
+  } else if (aFrame->GetType() == nsAccessibilityAtoms::textFrame) {
+    nsCOMPtr<nsIContent> content(aFrame->GetContent());
+    NS_ENSURE_STATE(content);
+
+    nsCOMPtr<nsIPresShell> shell(GetPresShell());
+    NS_ENSURE_STATE(shell);
+
+    nsIFrame *primaryFrame = shell->GetPrimaryFrameFor(content);
+    nsresult rv = RenderedToContentOffset(primaryFrame, aOffset, aNodeOffset);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    node = do_QueryInterface(content);
+
+  } else {
+    nsCOMPtr<nsIContent> content(aFrame->GetContent());
+    NS_ENSURE_STATE(content);
+
+    nsCOMPtr<nsIContent> parent(content->GetParent());
+    NS_ENSURE_STATE(parent);
+
+    *aNodeOffset = parent->IndexOf(content);
+    node = do_QueryInterface(parent);
+  }
+
+  NS_IF_ADDREF(*aNode = node);
+  return NS_OK;
+}
+
--- a/accessible/src/html/nsHyperTextAccessible.h
+++ b/accessible/src/html/nsHyperTextAccessible.h
@@ -118,16 +118,33 @@ public:
     *                       by the offset returned is at [offset]. If the passed-in offset in inside a
     *                       descendant, then the returned offset will be on the relevant embedded object char.
     */
   nsresult DOMPointToHypertextOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset,
                                      PRInt32 *aHypertextOffset,
                                      nsIAccessible **aFinalAccessible = nsnull,
                                      PRBool aIsEndOffset = PR_FALSE);
 
+  /**
+   * Turn a start and end hypertext offsets into DOM range.
+   *
+   * @param  aStartHTOffset  [in] the given start hypertext offset
+   * @param  aEndHTOffset    [in] the given end hypertext offset
+   * @param  aStartNode      [out] start node of the range
+   * @param  aStartOffset    [out] start offset of the range
+   * @param  aEndNode        [out] end node of the range
+   * @param  aEndOffset      [out] end offset of the range
+   */
+  nsresult HypertextOffsetsToDOMRange(PRInt32 aStartHTOffset,
+                                      PRInt32 aEndHTOffset,
+                                      nsIDOMNode **aStartNode,
+                                      PRInt32 *aStartOffset,
+                                      nsIDOMNode **aEndNode,
+                                      PRInt32 *aEndOffset);
+
 protected:
   /*
    * This does the work for nsIAccessibleText::GetText[At|Before|After]Offset
    * @param aType, eGetBefore, eGetAt, eGetAfter
    * @param aBoundaryType, char/word-start/word-end/line-start/line-end/paragraph/attribute
    * @param aOffset, offset into the hypertext to start from
    * @param *aStartOffset, the resulting start offset for the returned substring
    * @param *aEndOffset, the resulting end offset for the returned substring
@@ -198,15 +215,20 @@ protected:
    * @param aSelCon      The selection controller for the current hyper text, or nsnull if not needed
    * @param aDomSel      The selection interface for the current hyper text, or nsnull if not needed
    * @param aRanges      The selected ranges within the current subtree, or nsnull if not needed
    */
   nsresult GetSelections(nsISelectionController **aSelCon,
                          nsISelection **aDomSel = nsnull,
                          nsCOMArray<nsIDOMRange>* aRanges = nsnull);
   nsresult SetSelectionRange(PRInt32 aStartPos, PRInt32 aEndPos);
+
+  // Helpers
+  nsresult GetDOMPointByFrameOffset(nsIFrame *aFrame, PRInt32 aOffset,
+                                    nsIAccessible *aAccessible,
+                                    nsIDOMNode **aNode, PRInt32 *aNodeOffset);
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsHyperTextAccessible,
                               NS_HYPERTEXTACCESSIBLE_IMPL_CID)
 
 #endif  // _nsHyperTextAccessible_H_
 
--- a/accessible/src/msaa/CAccessibleText.cpp
+++ b/accessible/src/msaa/CAccessibleText.cpp
@@ -365,44 +365,28 @@ CAccessibleText::scrollSubstringTo(long 
   GET_NSIACCESSIBLETEXT
 
   nsresult rv = textAcc->ScrollSubstringTo(aStartIndex, aEndIndex, aScrollType);
   return NS_FAILED(rv) ? E_FAIL : S_OK;
 }
 
 STDMETHODIMP
 CAccessibleText::scrollSubstringToPoint(long aStartIndex, long aEndIndex,
-                                        enum IA2CoordinateType aCoordinateType,
+                                        enum IA2CoordinateType aCoordType,
                                         long aX, long aY)
 {
   GET_NSIACCESSIBLETEXT
 
-  nsCOMPtr<nsIAccessible> accessible;
-  PRInt32 startOffset = 0, endOffset = 0;
-
-  // XXX: aEndIndex isn't used.
-  textAcc->GetAttributeRange(aStartIndex, &startOffset, &endOffset,
-                             getter_AddRefs(accessible));
-  if (!accessible)
-    return E_FAIL;
+  PRUint32 geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
+    nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
+    nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
 
-  nsCOMPtr<nsIWinAccessNode> winAccessNode(do_QueryInterface(accessible));
-  if (!winAccessNode)
-    return E_FAIL;
-
-  void **instancePtr = 0;
-  winAccessNode->QueryNativeInterface(IID_IAccessible2, instancePtr);
-  if (!instancePtr)
-    return E_FAIL;
-
-  IAccessible2 *pAccessible2 = static_cast<IAccessible2*>(*instancePtr);
-  HRESULT hr = pAccessible2->scrollToPoint(aCoordinateType, aX, aY);
-  pAccessible2->Release();
-
-  return hr;
+  nsresult rv = textAcc->ScrollSubstringToPoint(aStartIndex, aEndIndex,
+                                                geckoCoordType, aX, aY);
+  return NS_FAILED(rv) ? E_FAIL : S_OK;
 }
 
 STDMETHODIMP
 CAccessibleText::get_newText(IA2TextSegment *aNewText)
 {
   return GetModifiedText(PR_TRUE, aNewText);
 }
 
--- a/accessible/src/msaa/nsAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsAccessibleWrap.cpp
@@ -1184,20 +1184,25 @@ STDMETHODIMP
 nsAccessibleWrap::scrollTo(enum IA2ScrollType aScrollType)
 {
   if (NS_SUCCEEDED(ScrollTo(aScrollType)))
     return S_OK;
   return E_FAIL;
 }
 
 STDMETHODIMP
-nsAccessibleWrap::scrollToPoint(enum IA2CoordinateType coordinateType,
-                                long x, long y)
+nsAccessibleWrap::scrollToPoint(enum IA2CoordinateType aCoordType,
+                                long aX, long aY)
 {
-  return E_NOTIMPL;
+  PRUint32 geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
+    nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
+    nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
+
+  return NS_SUCCEEDED(ScrollToPoint(geckoCoordType, aX, aY)) ?
+    S_OK : E_FAIL;
 }
 
 STDMETHODIMP
 nsAccessibleWrap::get_groupPosition(long *aGroupLevel,
                                     long *aSimilarItemsInGroup,
                                     long *aPositionInGroup)
 {
   PRInt32 groupLevel = 0;
--- a/accessible/src/xforms/nsXFormsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsAccessible.cpp
@@ -211,32 +211,31 @@ nsXFormsAccessible::GetState(PRUint32 *a
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXFormsAccessible::GetName(nsAString& aName)
 {
   nsAutoString name;
-  nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::labelledby, name);
+  nsresult rv = GetTextFromRelationID(eAria_labelledby, name);
   if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
     aName = name;
     return NS_OK;
   }
 
   // search the xforms:label element
   return GetBoundChildElementValue(NS_LITERAL_STRING("label"), aName);
 }
 
 NS_IMETHODIMP
 nsXFormsAccessible::GetDescription(nsAString& aDescription)
 {
   nsAutoString description;
-  nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::describedby,
-                                      description);
+  nsresult rv = GetTextFromRelationID(eAria_describedby, description);
 
   if (NS_SUCCEEDED(rv) && !description.IsEmpty()) {
     aDescription = description;
     return NS_OK;
   }
 
   // search the xforms:hint element
   return GetBoundChildElementValue(NS_LITERAL_STRING("hint"), aDescription);
--- a/accessible/src/xforms/nsXFormsFormControlsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsFormControlsAccessible.cpp
@@ -54,27 +54,26 @@ nsXFormsLabelAccessible::GetRole(PRUint3
   *aRole = nsIAccessibleRole::ROLE_STATICTEXT;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXFormsLabelAccessible::GetName(nsAString& aName)
 {
   nsAutoString name;
-  nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::labelledby, name);
+  nsresult rv = GetTextFromRelationID(eAria_labelledby, name);
   aName = name;
   return rv;
 }
 
 NS_IMETHODIMP
 nsXFormsLabelAccessible::GetDescription(nsAString& aDescription)
 {
   nsAutoString description;
-  nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::describedby,
-                                      description);
+  nsresult rv = GetTextFromRelationID(eAria_describedby, description);
   aDescription = description;
   return rv;
 }
 
 // nsXFormsOutputAccessible
 
 nsXFormsOutputAccessible::
   nsXFormsOutputAccessible(nsIDOMNode *aNode, nsIWeakReference *aShell):
--- a/accessible/src/xul/nsXULMenuAccessible.cpp
+++ b/accessible/src/xul/nsXULMenuAccessible.cpp
@@ -594,35 +594,38 @@ nsXULMenupopupAccessible::nsXULMenupopup
 }
 
 NS_IMETHODIMP
 nsXULMenupopupAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
 {
   nsresult rv = nsAccessible::GetState(aState, aExtraState);
   NS_ENSURE_SUCCESS(rv, rv);
 
+#ifdef DEBUG_A11Y
   // We are onscreen if our parent is active
   PRBool isActive = PR_FALSE;
 
   nsCOMPtr<nsIDOMElement> element(do_QueryInterface(mDOMNode));
   element->HasAttribute(NS_LITERAL_STRING("menuactive"), &isActive);
   if (!isActive) {
     nsCOMPtr<nsIAccessible> parent(GetParent());
     nsCOMPtr<nsIDOMNode> parentNode;
     nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(parent));
     if (accessNode) 
       accessNode->GetDOMNode(getter_AddRefs(parentNode));
     element = do_QueryInterface(parentNode);
     if (element)
       element->HasAttribute(NS_LITERAL_STRING("open"), &isActive);
   }
+  NS_ASSERTION(isActive || *aState & nsIAccessibleStates::STATE_INVISIBLE,
+               "XULMenupopup doesn't have STATE_INVISIBLE when it's inactive");
+#endif
 
-  if (!isActive)
+  if (*aState & nsIAccessibleStates::STATE_INVISIBLE)
     *aState |= (nsIAccessibleStates::STATE_OFFSCREEN |
-                nsIAccessibleStates::STATE_INVISIBLE |
                 nsIAccessibleStates::STATE_COLLAPSED);
 
   return NS_OK;
 }
 
 already_AddRefed<nsIDOMNode>
 nsXULMenupopupAccessible::FindInNodeList(nsIDOMNodeList *aNodeList, 
                                          nsIAtom *aAtom, PRUint32 aNameSpaceID)
--- a/accessible/src/xul/nsXULTextAccessible.cpp
+++ b/accessible/src/xul/nsXULTextAccessible.cpp
@@ -77,16 +77,46 @@ nsXULTextAccessible::GetState(PRUint32 *
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Labels and description have read only state
   // They are not focusable or selectable
   *aState |= nsIAccessibleStates::STATE_READONLY;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsXULTextAccessible::GetAccessibleRelated(PRUint32 aRelationType,
+                                          nsIAccessible **aRelated)
+{
+  nsresult rv =
+    nsHyperTextAccessibleWrap::GetAccessibleRelated(aRelationType, aRelated);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (*aRelated) {
+    return NS_OK;
+  }
+
+  nsIContent *content = GetRoleContent(mDOMNode);
+  if (!content)
+    return NS_ERROR_FAILURE;
+
+  if (aRelationType == nsIAccessibleRelation::RELATION_LABEL_FOR) {
+    // Caption is the label for groupbox
+    nsIContent *parent = content->GetParent();
+    if (parent && parent->Tag() == nsAccessibilityAtoms::caption) {
+      nsCOMPtr<nsIAccessible> parentAccessible;
+      GetParent(getter_AddRefs(parentAccessible));
+      if (Role(parentAccessible) == nsIAccessibleRole::ROLE_GROUPING) {
+        parentAccessible.swap(*aRelated);
+      }
+    }
+  }
+
+  return NS_OK;
+}
+
 /**
   * For XUL tooltip
   */
 nsXULTooltipAccessible::nsXULTooltipAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell):
 nsLeafAccessible(aDomNode, aShell)
 { 
 }
 
--- a/accessible/src/xul/nsXULTextAccessible.h
+++ b/accessible/src/xul/nsXULTextAccessible.h
@@ -49,16 +49,18 @@ class nsIWeakReference;
 class nsXULTextAccessible : public nsHyperTextAccessibleWrap
 {
 
 public:
   nsXULTextAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell);
   NS_IMETHOD GetName(nsAString& _retval); 
   NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
   NS_IMETHOD GetRole(PRUint32 *aRole) { *aRole = nsIAccessibleRole::ROLE_LABEL; return NS_OK; }
+  NS_IMETHOD GetAccessibleRelated(PRUint32 aRelationType,
+                                  nsIAccessible **aRelated);
 };
 
 class nsXULTooltipAccessible : public nsLeafAccessible
 {
 
 public:
   nsXULTooltipAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell);
   NS_IMETHOD GetName(nsAString& _retval); 
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -171,17 +171,17 @@ CPPSRCS		+= $(STATIC_CPPSRCS)
 EXTRA_DSO_LIBS	+= $(STATIC_EXTRA_DSO_LIBS)
 REQUIRES	+= $(STATIC_REQUIRES)
 EXTRA_LIBS	+= $(STATIC_EXTRA_LIBS)
 endif
 
 ifeq ($(OS_ARCH),WINNT)
 OS_LIBS += $(call EXPAND_LIBNAME,comctl32 comdlg32 uuid shell32 ole32 oleaut32 version winspool)
 ifdef MOZ_ENABLE_CAIRO_GFX
-OS_LIBS += $(call EXPAND_LIBNAME,usp10)
+OS_LIBS += $(call EXPAND_LIBNAME,usp10 msimg32)
 ifdef MOZ_ENABLE_GLITZ
 OS_LIBS += $(call EXPAND_LIBNAME,opengl32)
 endif
 endif
 
 RCINCLUDE = splash.rc
 ifndef GNU_CC
 RCFLAGS += -DMOZ_PHOENIX -I$(srcdir)
@@ -401,17 +401,21 @@ endif
 else
 ifdef LIBXUL_SDK
 libs::
 	cp $(LIBXUL_DIST)/bin/xulrunner-stub$(BIN_SUFFIX) $(DIST)/bin/firefox$(BIN_SUFFIX)
 endif
 endif
 
 libs::
+ifeq ($(OS_ARCH),WINNT)
+	$(PERL) -pe 's/(?<!\r)\n/\r\n/g;' < $(topsrcdir)/LICENSE > $(DIST)/bin/LICENSE
+else
 	$(INSTALL) $(topsrcdir)/LICENSE	$(DIST)/bin
+endif
 
 libs:: $(srcdir)/profile/prefs.js
 	$(INSTALL) $^ $(DIST)/bin/defaults/profile
 
 install:: $(srcdir)/profile/prefs.js
 	$(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/defaults/profile
 
 ifdef LIBXUL_SDK
--- a/browser/app/module.ver
+++ b/browser/app/module.ver
@@ -1,8 +1,8 @@
 WIN32_MODULE_COMPANYNAME=Mozilla Corporation
 WIN32_MODULE_COPYRIGHT=©Firefox and Mozilla Developers, according to the MPL 1.1/GPL 2.0/LGPL 2.1 licenses, as applicable.
 WIN32_MODULE_PRODUCTVERSION=3,0,0,0
-WIN32_MODULE_PRODUCTVERSION_STRING=3.0a8pre
+WIN32_MODULE_PRODUCTVERSION_STRING=3.0a9pre
 WIN32_MODULE_TRADEMARKS=Firefox is a Trademark of The Mozilla Foundation.
 WIN32_MODULE_DESCRIPTION=Firefox
 WIN32_MODULE_PRODUCTNAME=Firefox
 WIN32_MODULE_NAME=Firefox
--- a/browser/app/mozilla.in
+++ b/browser/app/mozilla.in
@@ -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 *****
 
-## $Id: mozilla.in,v 1.15 2007/08/03 14:46:19 benjamin%smedbergs.us Exp $
+## $Id: mozilla.in,v 1.16 2007/10/05 07:29:26 reed%reedloden.com Exp $
 ## 
 ## Usage:
 ##
 ## $ mozilla [args]
 ##
 ## This script is meant to run the mozilla-bin binary from either 
 ## mozilla/xpfe/bootstrap or mozilla/dist/bin.
 ##
@@ -65,16 +65,17 @@ if test -x "$run_moz"; then
   dist_bin="$curdir"
   found=1
 else
   here=`/bin/pwd`
   while [ -h "$progname" ]; do
     bn=`basename "$progname"`
     cd `dirname "$progname"`
     progname=`/bin/ls -l "$bn" | sed -e 's/^.* -> //' `
+    progbase=`basename "$progname"`
     if [ ! -x "$progname" ]; then
       break
     fi
     curdir=`dirname "$progname"`
     run_moz="$curdir/run-mozilla.sh"
     if [ -x "$run_moz" ]; then
       cd "$curdir"
       dist_bin=`pwd`
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -97,17 +97,17 @@ pref("app.update.auto", true);
 // See chart in nsUpdateService.js.in for more details
 //
 pref("app.update.mode", 1);
 
 // If set to true, the Update Service will present no UI for any event.
 pref("app.update.silent", false);
 
 // Update service URL:
-pref("app.update.url", "https://aus2.mozilla.org/update/2/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/update.xml");
+pref("app.update.url", "https://aus2.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
 // app.update.url.manual is in branding section
 // app.update.url.details is in branding section
 
 // User-settable override to app.update.url for testing purposes.
 //pref("app.update.url.override", "");
 
 // Interval: Time between checks for a new version (in seconds)
 //           default=1 day
@@ -210,16 +210,17 @@ pref("browser.download.manager.showAlert
 pref("browser.download.manager.retention", 2);
 pref("browser.download.manager.showWhenStarting", true);
 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.displayedHistoryDays", 7);
+pref("browser.download.manager.addToRecentDocs", true);
 
 // 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
@@ -429,16 +430,19 @@ pref("accessibility.typeaheadfind.linkso
 pref("accessibility.typeaheadfind.flashBar", 1);
 
 // Disable the default plugin for firefox
 pref("plugin.default_plugin_disabled", true);
 
 // plugin finder service url
 pref("pfs.datasource.url", "https://pfs.mozilla.org/plugins/PluginFinderService.php?mimetype=%PLUGIN_MIMETYPE%&appID=%APP_ID%&appVersion=%APP_VERSION%&clientOS=%CLIENT_OS%&chromeLocale=%CHROME_LOCALE%");
 
+// by default we show an infobar message when pages require plugins the user has not installed
+pref("plugins.hide_infobar_for_missing_plugin", false);
+
 #ifdef XP_WIN
 pref("browser.preferences.instantApply", false);
 #else
 pref("browser.preferences.instantApply", true);
 #endif
 #ifdef XP_MACOSX
 pref("browser.preferences.animateFadeIn", true);
 #else
deleted file mode 100644
--- a/browser/base/branding/uninstall.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-# These values are used to construct the registry keys for the Add/Remove
-# Programs dialog under Windows.  They must be kept in sync with the values
-# used by the installer.
-# XXX fileUninstall is no longer brand-specific, and can therefore be removed.
-fileUninstall=uninstall.exe
-URLInfoAbout=http://www.mozilla.org/
-URLUpdateInfo=http://www.mozilla.org/projects/minefield/
--- a/browser/base/content/browser-context.inc
+++ b/browser/base/content/browser-context.inc
@@ -237,29 +237,33 @@
                 accesskey="&metadataCmd.accesskey;"
                 oncommand="gContextMenu.showMetadata();"/>
       <menuseparator id="spell-separator"/>
       <menuitem id="spell-check-enabled"
                 label="&spellEnable.label;"
                 type="checkbox"
                 accesskey="&spellEnable.accesskey;"
                 oncommand="InlineSpellCheckerUI.toggleEnabled();"/>
+#ifndef MOZ_WIDGET_COCOA
       <menuitem id="spell-add-dictionaries-main"
                 label="&spellAddDictionaries.label;"
                 accesskey="&spellAddDictionaries.accesskey;"
                 oncommand="gContextMenu.addDictionaries();"/>
+#endif
       <menu id="spell-dictionaries"
             label="&spellDictionaries.label;"
             accesskey="&spellDictionaries.accesskey;">
           <menupopup id="spell-dictionaries-menu">
+#ifndef MOZ_WIDGET_COCOA
               <menuseparator id="spell-language-separator"/>
               <menuitem id="spell-add-dictionaries"
                         label="&spellAddDictionaries.label;"
                         accesskey="&spellAddDictionaries.accesskey;"
                         oncommand="gContextMenu.addDictionaries();"/>
+#endif
           </menupopup>
       </menu>
       <menuseparator hidden="true" id="context-sep-bidi"/>
       <menuitem hidden="true" id="context-bidi-text-direction-toggle"
                 label="&bidiSwitchTextDirectionItem.label;"
                 accesskey="&bidiSwitchTextDirectionItem.accesskey;"
                 command="cmd_switchTextDirection"/>
       <menuitem hidden="true" id="context-bidi-page-direction-toggle"
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -134,17 +134,18 @@ var PlacesCommandHook = {
 
   _doShowEditBookmarkPanel:
   function PCH__doShowEditBookmarkPanel(aItemId, aAnchorElement, aPosition) {
     this.panel.addEventListener("keypress", this, true);
     this._blockCommands(); // un-done in the popuphiding handler
     this.panel.openPopup(aAnchorElement, aPosition, -1, -1);
 
     gEditItemOverlay.initPanel(aItemId,
-                               { hiddenRows: ["description", "location"] });
+                               { hiddenRows: ["description", "location",
+                                              "loadInSidebar", "keyword"] });
     setTimeout(function() {
                  var namePicker = document.getElementById("editBMPanel_namePicker");
                  namePicker.focus();
                  namePicker.editor.selectAll();
               }, 0);
   },
 
   /**
@@ -764,23 +765,28 @@ var PlacesStarButton = {
   _starred: false,
   _batching: false,
 
   updateState: function PSB_updateState() {
     var starIcon = document.getElementById("star-button");
     if (!starIcon)
       return;
 
+    var browserBundle = document.getElementById("bundle_browser");
     var uri = getBrowser().currentURI;
     this._starred = uri && (PlacesUtils.getMostRecentBookmarkForURI(uri) != -1 ||
                             PlacesUtils.getMostRecentFolderForFeedURI(uri) != -1);
-    if (this._starred)
+    if (this._starred) {
       starIcon.setAttribute("starred", "true");
-    else
+      starIcon.setAttribute("tooltiptext", browserBundle.getString("starButtonOn.tooltip"));
+    }
+    else {
       starIcon.removeAttribute("starred");
+      starIcon.setAttribute("tooltiptext", browserBundle.getString("starButtonOff.tooltip"));
+    }
   },
 
   onClick: function PSB_onClick(aEvent) {
     PlacesCommandHook.bookmarkCurrentPage(this._starred);
   },
 
   // nsINavBookmarkObserver  
   onBeginUpdateBatch: function PSB_onBeginUpdateBatch() {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1,9 +1,9 @@
-# -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+# -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 # ***** BEGIN LICENSE BLOCK *****
 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
 #
 # The contents of this file are subject to the Mozilla Public License Version
 # 1.1 (the "License"); you may not use this file except in compliance with
 # the License. You may obtain a copy of the License at
 # http://www.mozilla.org/MPL/
 #
@@ -251,35 +251,16 @@ function SetClickAndHoldHandlers()
   if (backButton)
     _addClickAndHoldListenersOnElement(backButton);
   var forwardButton = document.getElementById("forward-button");
   if (forwardButton)
     _addClickAndHoldListenersOnElement(forwardButton);
 }
 #endif
 
-function addBookmarkMenuitems()
-{
-  var tabbrowser = getBrowser();
-  var tabMenu = document.getAnonymousElementByAttribute(tabbrowser,"anonid","tabContextMenu");
-  var bookmarkAllTabsItem = document.createElement("menuitem");
-  bookmarkAllTabsItem.setAttribute("label", gNavigatorBundle.getString("bookmarkAllTabs_label"));
-  bookmarkAllTabsItem.setAttribute("accesskey", gNavigatorBundle.getString("bookmarkAllTabs_accesskey"));
-  bookmarkAllTabsItem.setAttribute("command", "Browser:BookmarkAllTabs");
-  var bookmarkCurTabItem = document.createElement("menuitem");
-  bookmarkCurTabItem.setAttribute("label", gNavigatorBundle.getString("bookmarkCurTab_label"));
-  bookmarkCurTabItem.setAttribute("accesskey", gNavigatorBundle.getString("bookmarkCurTab_accesskey"));
-  bookmarkCurTabItem.setAttribute("oncommand", "BookmarkThisTab();");
-  var menuseparator = document.createElement("menuseparator");
-  var insertPos = tabMenu.lastChild.previousSibling;
-  tabMenu.insertBefore(bookmarkAllTabsItem, insertPos);
-  tabMenu.insertBefore(bookmarkCurTabItem, bookmarkAllTabsItem);
-  tabMenu.insertBefore(menuseparator, bookmarkCurTabItem);
-}
-
 function BookmarkThisTab()
 {
   var tab = getBrowser().mContextTab;
   if (tab.localName != "tab")
     tab = getBrowser().mCurrentTab;
 
   PlacesCommandHook.bookmarkPage(tab.linkedBrowser,
                                  PlacesUtils.bookmarksRootId,
@@ -930,21 +911,20 @@ function prepareForStartup()
   gBrowser.browsers[0].removeAttribute("disablehistory");
 
   // enable global history
   gBrowser.docShell.QueryInterface(Components.interfaces.nsIDocShellHistory).useGlobalHistory = true;
 
   // hook up UI through progress listener
   gBrowser.addProgressListener(window.XULBrowserWindow, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
 
-  // Initialize the feedhandler
-  FeedHandler.init();
-
-  // Initialize the searchbar
-  BrowserSearch.init();
+  // setup our common DOMLinkAdded listener
+  gBrowser.addEventListener("DOMLinkAdded", DOMLinkHandler, false);
+
+  gBrowser.addEventListener("pagehide", FeedHandler.onPageHide, false);
 }
 
 function delayedStartup()
 {
   var os = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
   os.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);
   os.addObserver(gXPInstallObserver, "xpinstall-install-blocked", false);
 
@@ -974,19 +954,16 @@ function delayedStartup()
   Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
 
   if (gMustLoadSidebar) {
     var sidebar = document.getElementById("sidebar");
     var sidebarBox = document.getElementById("sidebar-box");
     sidebar.setAttribute("src", sidebarBox.getAttribute("src"));
   }
 
-  // add bookmark options to context menu for tabs
-  addBookmarkMenuitems();
-
   initBookmarksToolbar();
   PlacesUtils.bookmarks.addObserver(gBookmarksObserver, false);
   PlacesStarButton.init();
 
   // called when we go into full screen, even if it is
   // initiated by a web page script
   window.addEventListener("fullscreen", onFullScreen, true);
 
@@ -1106,19 +1083,16 @@ function delayedStartup()
       var ss = Cc["@mozilla.org/browser/sessionstore;1"].
                getService(Ci.nsISessionStore);
       ss.init(window);
     } catch(ex) {
       dump("nsSessionStore could not be initialized: " + ex + "\n");
     }
   }
 
-  // browser-specific tab augmentation
-  AugmentTabs.init();
-
   // bookmark-all-tabs command
   gBookmarkAllTabsHandler = new BookmarkAllTabsHandler();
   
   // Prevent chrome-spoofing popups from forging our chrome, by adding a
   // notification box entry in cases of chromeless popups.
   checkForChromelessWindow();
 }
 
@@ -1546,32 +1520,32 @@ function BrowserHomeClick(aEvent)
 }
 
 function loadOneOrMoreURIs(aURIString)
 {
 #ifdef XP_MACOSX
   // we're not a browser window, pass the URI string to a new browser window
   if (window.location.href != getBrowserURL())
   {
-    newWindow = openDialog(getBrowserURL(), "_blank", "all,dialog=no", aURIString);
+    window.openDialog(getBrowserURL(), "_blank", "all,dialog=no", aURIString);
     return;
   }
 #endif
   // This function throws for certain malformed URIs, so use exception handling
   // so that we don't disrupt startup
   try {
     gBrowser.loadTabs(aURIString.split("|"), false, true);
   } 
   catch (e) {
   }
 }
 
 function openLocation()
 {
-  if (gURLBar && isElementVisible(gURLBar)) {
+  if (gURLBar && isElementVisible(gURLBar) && !gURLBar.readOnly) {
     gURLBar.focus();
     gURLBar.select();
     return;
   }
 #ifdef XP_MACOSX
   if (window.location.href != getBrowserURL()) {
     var win = getTopWin();
     if (win) {
@@ -1750,17 +1724,17 @@ function getShortcutOrURI(aURL, aPostDat
     if (matches)
       [, shortcutURL, charset] = matches;
     else {
       //XXX Bug 317472 will add lastCharset support to places.
     }
 
     var encodedParam = "";
     if (charset)
-      encodedParam = escape(converFromUnicode(charset, param));
+      encodedParam = escape(convertFromUnicode(charset, param));
     else // Default charset is UTF-8
       encodedParam = encodeURIComponent(param);
 
     shortcutURL = shortcutURL.replace(/%s/g, encodedParam).replace(/%S/g, param);
 
     if (/%s/i.test(postData)) // POST keyword
       aPostDataRef.value = getPostDataStream(postData, param, encodedParam,
                                              "application/x-www-form-urlencoded");
@@ -2642,116 +2616,170 @@ var DownloadsButtonDNDObserver = {
   {
     var flavourSet = new FlavourSet();
     flavourSet.appendFlavour("text/x-moz-url");
     flavourSet.appendFlavour("text/unicode");
     return flavourSet;
   }
 }
 
-const BrowserSearch = {
-
-  /**
-   * Initialize the BrowserSearch
-   */
-  init: function() {
-    gBrowser.addEventListener("DOMLinkAdded", 
-                              function (event) { BrowserSearch.onLinkAdded(event); }, 
-                              false);
+const DOMLinkHandler = {
+  handleEvent: function (event) {
+    switch (event.type) {
+      case "DOMLinkAdded":
+        this.onLinkAdded(event);
+        break;
+    }
   },
-
-  /**
-   * A new <link> tag has been discovered - check to see if it advertises
-   * a OpenSearch engine.
-   */
-  onLinkAdded: function(event) {
-    // XXX this event listener can/should probably be combined with the onLinkAdded
-    // listener in tabbrowser.xml.  See comments in FeedHandler.onLinkAdded().
-    const target = event.target;
-    var etype = target.type;
-    const searchRelRegex = /(^|\s)search($|\s)/i;
-    const searchHrefRegex = /^(https?|ftp):\/\//i;
-
-    if (!etype)
-      return;
-      
-    // Bug 349431: If the engine has no suggested title, ignore it rather
-    // than trying to find an alternative.
-    if (!target.title)
+  onLinkAdded: function (event) {
+    var link = event.originalTarget;
+    var rel = link.rel && link.rel.toLowerCase();
+    if (!link || !link.ownerDocument || !rel || !link.href)
       return;
 
-    if (etype == "application/opensearchdescription+xml" &&
-        searchRelRegex.test(target.rel) && searchHrefRegex.test(target.href))
-    {
-      const targetDoc = target.ownerDocument;
-      // Set the attribute of the (first) search-engine button.
-      var searchButton = document.getAnonymousElementByAttribute(this.getSearchBar(),
-                                  "anonid", "searchbar-engine-button");
-      if (searchButton) {
-        var browser = gBrowser.getBrowserForDocument(targetDoc);
-         // Append the URI and an appropriate title to the browser data.
-        var iconURL = null;
-        if (gBrowser.shouldLoadFavIcon(browser.currentURI))
-          iconURL = browser.currentURI.prePath + "/favicon.ico";
-
-        var hidden = false;
-        // If this engine (identified by title) is already in the list, add it
-        // to the list of hidden engines rather than to the main list.
-        // XXX This will need to be changed when engines are identified by URL;
-        // see bug 335102.
-         var searchService =
-            Components.classes["@mozilla.org/browser/search-service;1"]
-                      .getService(Components.interfaces.nsIBrowserSearchService);
-        if (searchService.getEngineByName(target.title))
-          hidden = true;
-
-        var engines = [];
-        if (hidden) {
-          if (browser.hiddenEngines)
-            engines = browser.hiddenEngines;
-        }
-        else {
-          if (browser.engines)
-            engines = browser.engines;
-        }
-
-        engines.push({ uri: target.href,
-                       title: target.title,
-                       icon: iconURL });
-
-         if (hidden) {
-           browser.hiddenEngines = engines;
-         }
-         else {
-           browser.engines = engines;
-           if (browser == gBrowser || browser == gBrowser.mCurrentBrowser)
-             this.updateSearchButton();
-         }
+    var feedAdded = false;
+    var iconAdded = false;
+    var searchAdded = false;
+    var relStrings = rel.split(/\s+/);
+    var rels = {};
+    for (let i = 0; i < relStrings.length; i++)
+      rels[relStrings[i]] = true;
+
+    for (let relVal in rels) {
+      switch (relVal) {
+        case "feed":
+        case "alternate":
+          if (!feedAdded) {
+            if (!rels.feed && rels.alternate && rels.stylesheet)
+              break;
+
+            var feed = { title: link.title, href: link.href, type: link.type };
+            if (isValidFeed(feed, link.ownerDocument.nodePrincipal, rels.feed)) {
+              FeedHandler.addFeed(feed, link.ownerDocument);
+              feedAdded = true;
+            }
+          }
+          break;
+        case "icon":
+          if (!iconAdded) {
+            if (!gPrefService.getBoolPref("browser.chrome.site_icons"))
+              break;
+
+            try {
+              var contentPolicy = Cc["@mozilla.org/layout/content-policy;1"].
+                                  getService(Ci.nsIContentPolicy);
+            } catch(e) {
+              break; // Refuse to load if we can't do a security check.
+            }
+
+            var targetDoc = link.ownerDocument;
+            var ios = Cc["@mozilla.org/network/io-service;1"].
+                      getService(Ci.nsIIOService);
+            var uri = ios.newURI(link.href, targetDoc.characterSet, null);
+
+            // Verify that the load of this icon is legal.
+            // error pages can load their favicon, to be on the safe side,
+            // only allow chrome:// favicons
+            const aboutNeterr = "about:neterror?";
+            if (targetDoc.documentURI.substr(0, aboutNeterr.length) != aboutNeterr ||
+                !uri.schemeIs("chrome")) {
+              var ssm = Cc["@mozilla.org/scriptsecuritymanager;1"].
+                        getService(Ci.nsIScriptSecurityManager);
+              try {
+                ssm.checkLoadURIWithPrincipal(targetDoc.nodePrincipal, uri,
+                                              Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
+              } catch(e) {
+                break;
+              }
+            }
+
+            // Security says okay, now ask content policy
+            if (contentPolicy.shouldLoad(Ci.nsIContentPolicy.TYPE_IMAGE,
+                                         uri, targetDoc.documentURIObject,
+                                         link, link.type, null)
+                                         != Ci.nsIContentPolicy.ACCEPT)
+              break;
+
+            var browserIndex = gBrowser.getBrowserIndexForDocument(targetDoc);
+            // no browser? no favicon.
+            if (browserIndex == -1)
+              break;
+
+            var tab = gBrowser.mTabContainer.childNodes[browserIndex];
+            gBrowser.setIcon(tab, link.href);
+            iconAdded = true;
+          }
+          break;
+        case "search":
+          if (!searchAdded) {
+            var type = link.type && link.type.toLowerCase();
+            type = type.replace(/^\s+|\s*(?:;.*)?$/g, "");
+
+            if (type == "application/opensearchdescription+xml" && link.title &&
+                /^(?:https?|ftp):/i.test(link.href)) {
+              var engine = { title: link.title, href: link.href };
+              BrowserSearch.addEngine(engine, link.ownerDocument);
+              searchAdded = true;
+            }
+          }
+          break;
       }
     }
+  }
+}
+
+const BrowserSearch = {
+  addEngine: function(engine, targetDoc) {
+    if (!this.searchBar)
+      return;
+    var browser = gBrowser.getBrowserForDocument(targetDoc);
+    // Append the URI and an appropriate title to the browser data.
+    var iconURL = null;
+    if (gBrowser.shouldLoadFavIcon(browser.currentURI))
+      iconURL = browser.currentURI.prePath + "/favicon.ico";
+
+    var hidden = false;
+    // If this engine (identified by title) is already in the list, add it
+    // to the list of hidden engines rather than to the main list.
+    // XXX This will need to be changed when engines are identified by URL;
+    // see bug 335102.
+    var searchService = Cc["@mozilla.org/browser/search-service;1"].
+                        getService(Ci.nsIBrowserSearchService);
+    if (searchService.getEngineByName(engine.title))
+      hidden = true;
+
+    var engines = (hidden ? browser.hiddenEngines : browser.engines) || [];
+
+    engines.push({ uri: engine.href,
+                   title: engine.title,
+                   icon: iconURL });
+
+    if (hidden)
+      browser.hiddenEngines = engines;
+    else {
+      browser.engines = engines;
+      if (browser == gBrowser || browser == gBrowser.mCurrentBrowser)
+        this.updateSearchButton();
+    }
   },
 
   /**
    * Update the browser UI to show whether or not additional engines are 
    * available when a page is loaded or the user switches tabs to a page that 
-   * has search engines. 
+   * has search engines.
    */
   updateSearchButton: function() {
-    var searchButton = document.getAnonymousElementByAttribute(this.getSearchBar(),
-                                "anonid", "searchbar-engine-button");
-    if (!searchButton)
+    var searchBar = this.searchBar;
+    if (!searchBar)
       return;
     var engines = gBrowser.mCurrentBrowser.engines;
-    if (!engines || engines.length == 0) {
-      if (searchButton.hasAttribute("addengines"))
-        searchButton.removeAttribute("addengines");
-    }
-    else {
-      searchButton.setAttribute("addengines", "true");
-    }
+    if (engines && engines.length > 0)
+      searchBar.searchButton.setAttribute("addengines", "true");
+    else
+      searchBar.searchButton.removeAttribute("addengines");
   },
 
   /**
    * Gives focus to the search bar, if it is present on the toolbar, or loads
    * the default engine's search form otherwise. For Mac, opens a new window
    * or focuses an existing window, if necessary.
    */
   webSearch: function BrowserSearch_webSearch() {
@@ -2773,18 +2801,18 @@ const BrowserSearch = {
 
         win = window.openDialog("chrome://browser/content/", "_blank",
                                 "chrome,all,dialog=no", "about:blank");
         win.addEventListener("load", webSearchCallback, false);
       }
       return;
     }
 #endif
-    var searchBar = this.getSearchBar();
-    if (searchBar) {
+    var searchBar = this.searchBar;
+    if (isElementVisible(searchBar)) {
       searchBar.select();
       searchBar.focus();
     } else {
       var ss = Cc["@mozilla.org/browser/search-service;1"].
                getService(Ci.nsIBrowserSearchService);
       var searchForm = ss.defaultEngine.searchForm;
       loadURI(searchForm, null, null, false);
     }
@@ -2803,17 +2831,17 @@ const BrowserSearch = {
    */
   loadSearch: function BrowserSearch_search(searchText, useNewTab) {
     var ss = Cc["@mozilla.org/browser/search-service;1"].
              getService(Ci.nsIBrowserSearchService);
     var engine;
   
     // If the search bar is visible, use the current engine, otherwise, fall
     // back to the default engine.
-    if (this.getSearchBar())
+    if (isElementVisible(this.searchBar))
       engine = ss.currentEngine;
     else
       engine = ss.defaultEngine;
   
     var submission = engine.getSubmission(searchText, null); // HTML response
 
     // getSubmission can return null if the engine doesn't have a URL
     // with a text/html response type.  This is unlikely (since
@@ -2825,25 +2853,20 @@ const BrowserSearch = {
     if (useNewTab) {
       getBrowser().loadOneTab(submission.uri.spec, null, null,
                               submission.postData, null, false);
     } else
       loadURI(submission.uri.spec, null, submission.postData, false);
   },
 
   /**
-   * Returns the search bar element if it is present in the toolbar and not
-   * hidden, null otherwise.
+   * Returns the search bar element if it is present in the toolbar, null otherwise.
    */
-  getSearchBar: function BrowserSearch_getSearchBar() {
-    var searchBar = document.getElementById("searchbar");
-    if (searchBar && isElementVisible(searchBar))
-      return searchBar;
-
-    return null;
+  get searchBar() {
+    return document.getElementById("searchbar");
   },
 
   loadAddEngines: function BrowserSearch_loadAddEngines() {
     var newWindowPref = gPrefService.getIntPref("browser.link.open_newwindow");
     var where = newWindowPref == 3 ? "tab" : "window";
     var regionBundle = document.getElementById("bundle_browser_region");
     var searchEnginesURL = formatURL("browser.search.searchEnginesURL", true);
     openUILinkIn(searchEnginesURL, where);
@@ -3413,17 +3436,18 @@ nsBrowserStatusHandler.prototype =
 
         this.stopCommand.setAttribute("disabled", "true");
     }
   },
 
   onLocationChange : function(aWebProgress, aRequest, aLocationURI)
   {
     var location = aLocationURI ? aLocationURI.spec : "";
- 
+    this._hostChanged = true;
+
     if (document.tooltipNode) {
       // Optimise for the common case
       if (aWebProgress.DOMWindow == content) {
         document.getElementById("aHTMLTooltip").hidePopup();
         document.tooltipNode = null;
       }
       else {
         for (var tooltipWindow =
@@ -3624,69 +3648,95 @@ nsBrowserStatusHandler.prototype =
         notification.delay = aDelay;
         notification.docShell = docShell;
       }
       return false;
     }
     return true;
   },
 
-  onSecurityChange : function(aWebProgress, aRequest, aState)
+  // Properties used to cache security state used to update the UI
+  _state: null,
+  _host: undefined,
+  _tooltipText: null,
+  _hostChanged: false, // onLocationChange will flip this bit
+
+  onSecurityChange : function browser_onSecChange(aWebProgress,
+                                                  aRequest, aState)
   {
+    // Don't need to do anything if the data we use to update the UI hasn't
+    // changed
+    if (this._state == aState &&
+        this._tooltipText == gBrowser.securityUI.tooltipText &&
+        !this._hostChanged) {
+#ifdef DEBUG
+      var contentHost = gBrowser.contentWindow.location.host;
+      if (this._host !== undefined && this._host != contentHost) {
+          Components.utils.reportError(
+            "ASSERTION: browser.js host is inconsistent. Content window has " + 
+            "<" + contentHost + "> but cached host is <" + this._host + ">.\n"
+          );
+      }
+#endif
+      return;
+    }
+    this._state = aState;
+
+    try {
+      this._host = gBrowser.contentWindow.location.host;
+    } catch(ex) {
+      this._host = null;
+    }
+
+    this._hostChanged = false;
+    this._tooltipText = gBrowser.securityUI.tooltipText
+
+    // aState is defined as a bitmask that may be extended in the future.
+    // We filter out any unknown bits before testing for known values.
     const wpl = Components.interfaces.nsIWebProgressListener;
-    this.securityButton.removeAttribute("label");
-
     const wpl_security_bits = wpl.STATE_IS_SECURE |
                               wpl.STATE_IS_BROKEN |
                               wpl.STATE_IS_INSECURE |
                               wpl.STATE_SECURE_HIGH |
                               wpl.STATE_SECURE_MED |
                               wpl.STATE_SECURE_LOW;
-
-    /* aState is defined as a bitmask that may be extended in the future.
-     * We filter out any unknown bits before testing for known values.
-     */
-    switch (aState & wpl_security_bits) {
+    var level = null;
+    var setHost = false;
+
+    switch (this._state & wpl_security_bits) {
       case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_HIGH:
-        this.securityButton.setAttribute("level", "high");
-        if (this.urlBar)
-          this.urlBar.setAttribute("level", "high");
-        try {
-          this.securityButton.setAttribute("label",
-            gBrowser.contentWindow.location.host);
-        } catch(exception) {}
+        level = "high";
+        setHost = true;
         break;
       case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_MED:
       case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_LOW:
-        this.securityButton.setAttribute("level", "low");
-        if (this.urlBar)
-          this.urlBar.setAttribute("level", "low");
-        try {
-          this.securityButton.setAttribute("label",
-            gBrowser.contentWindow.location.host);
-        } catch(exception) {}
+        level = "low";
+        setHost = true;
         break;
       case wpl.STATE_IS_BROKEN:
-        this.securityButton.setAttribute("level", "broken");
-        if (this.urlBar)
-          this.urlBar.setAttribute("level", "broken");
-        break;
-      case wpl.STATE_IS_INSECURE:
-      default:
-        this.securityButton.removeAttribute("level");
-        if (this.urlBar)
-          this.urlBar.removeAttribute("level");
+        level = "broken";
         break;
     }
 
-    var securityUI = gBrowser.securityUI;
-    this.securityButton.setAttribute("tooltiptext", securityUI.tooltipText);
-    var lockIcon = document.getElementById("lock-icon");
-    if (lockIcon)
-      lockIcon.setAttribute("tooltiptext", securityUI.tooltipText);
+    if (level) {
+      this.securityButton.setAttribute("level", level);
+      if (this.urlBar)
+        this.urlBar.setAttribute("level", level);    
+    } else {
+      this.securityButton.removeAttribute("level");
+      if (this.urlBar)
+        this.urlBar.removeAttribute("level");
+    }
+
+    if (setHost && this._host)
+      this.securityButton.setAttribute("label", this._host);
+    else
+      this.securityButton.removeAttribute("label");
+
+    this.securityButton.setAttribute("tooltiptext", this._tooltipText);
   },
 
   // simulate all change notifications after switching tabs
   onUpdateCurrentBrowser : function(aStateFlags, aStatus, aMessage, aTotalProgress)
   {
     var nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
     var loadingDone = aStateFlags & nsIWebProgressListener.STATE_STOP;
     // use a pseudo-object instead of a (potentially non-existing) channel for getting
@@ -4973,33 +5023,35 @@ missingPluginInstaller.prototype.newMiss
   // so don't stomp on the page developers toes.
 
   if (!(aEvent.target instanceof HTMLObjectElement)) {
     aEvent.target.addEventListener("click",
                                    gMissingPluginInstaller.installSinglePlugin,
                                    false);
   }
 
+  try {
+    if (gPrefService.getBoolPref("plugins.hide_infobar_for_missing_plugin"))
+      return;
+  } catch (ex) {} // if the pref is missing, treat it as false, which shows the infobar
+
   var tabbrowser = getBrowser();
   const browsers = tabbrowser.mPanelContainer.childNodes;
 
-  var window = aEvent.target.ownerDocument.defaultView;
-  // walk up till the toplevel window
-  while (window.parent != window)
-    window = window.parent;
+  var contentWindow = aEvent.target.ownerDocument.defaultView.top;
 
   var i = 0;
   for (; i < browsers.length; i++) {
-    if (tabbrowser.getBrowserAtIndex(i).contentWindow == window)
+    if (tabbrowser.getBrowserAtIndex(i).contentWindow == contentWindow)
       break;
   }
 
   var tab = tabbrowser.mTabContainer.childNodes[i];
   if (!tab.missingPlugins)
-    tab.missingPlugins = new Object();
+    tab.missingPlugins = {};
 
   var pluginInfo = getPluginInfo(aEvent.target);
 
   tab.missingPlugins[pluginInfo.mimetype] = pluginInfo;
 
   var browser = tabbrowser.getBrowserAtIndex(i);
   var notificationBox = gBrowser.getNotificationBox(browser);
   if (!notificationBox.getNotificationWithValue("missing-plugins")) {
@@ -5008,17 +5060,17 @@ missingPluginInstaller.prototype.newMiss
     var buttons = [{
       label: bundle_browser.getString("missingpluginsMessage.button.label"),
       accessKey: bundle_browser.getString("missingpluginsMessage.button.accesskey"),
       popup: null,
       callback: pluginsMissing
     }];
 
     const priority = notificationBox.PRIORITY_WARNING_MEDIUM;
-    const iconURL = "chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png";
+    const iconURL = "chrome://mozapps/skin/plugins/pluginGeneric.png";
     notificationBox.appendNotification(messageString, "missing-plugins",
                                        iconURL, priority, buttons);
   }
 }
 
 missingPluginInstaller.prototype.closeNotification = function() {
   var notificationBox = gBrowser.getNotificationBox();
   var notification = notificationBox.getNotificationWithValue("missing-plugins");
@@ -5055,26 +5107,16 @@ function convertFromUnicode(charset, str
   }
 }
 
 /**
  * The Feed Handler object manages discovery of RSS/ATOM feeds in web pages
  * and shows UI when they are discovered. 
  */
 var FeedHandler = {
-  /**
-   * Initialize the Feed Handler
-   */
-  init: function() {
-    gBrowser.addEventListener("DOMLinkAdded", 
-                              function (event) { FeedHandler.onLinkAdded(event); }, 
-                              true);
-    gBrowser.addEventListener("pagehide", FeedHandler.onPageHide, true);
-  },
-  
   onPageHide: function(event) {
     var theBrowser = gBrowser.getBrowserForDocument(event.target);
     if (theBrowser)
       theBrowser.feeds = null;
   },
   
   /**
    * The click handler for the Feed icon in the location bar. Opens the
@@ -5219,35 +5261,19 @@ var FeedHandler = {
 
         this._feedMenuitem.setAttribute("feed", feeds[0].href);
         this._feedMenuitem.removeAttribute("disabled");
         this._feedMenuitem.removeAttribute("hidden");
         this._feedMenupopup.setAttribute("hidden", "true");
       }
     }
   }, 
-  
-  /**
-   * A new <link> tag has been discovered - check to see if it advertises
-   * an RSS feed. 
-   */
-  onLinkAdded: function(event) {
-    // XXX this event listener can/should probably be combined with the onLinkAdded
-    // listener in tabbrowser.xml, which only listens for favicons and then passes
-    // them to onLinkIconAvailable in the ProgressListener.  We could extend the
-    // progress listener to have a generic onLinkAvailable and have tabbrowser pass
-    // along all events.  It should give us the browser for the tab, as well as
-    // the actual event.
-
-    var feed = recognizeFeedFromLink(event.target,
-      event.target.ownerDocument.nodePrincipal);
-
+
+  addFeed: function(feed, targetDoc) {
     if (feed) {
-      const targetDoc = event.target.ownerDocument;
-
       // find which tab this is for, and set the attribute on the browser
       var browserForLink = gBrowser.getBrowserForDocument(targetDoc);
       if (!browserForLink) {
         // ??? this really shouldn't happen..
         return;
       }
 
       var feeds = [];
@@ -5268,69 +5294,16 @@ var FeedHandler = {
   }
 };
 
 #include browser-places.js
 
 #include browser-contentPrefSink.js
 #include browser-textZoom.js
 
-/**
- * This object is for augmenting tabs
- */
-var AugmentTabs = {
-
-  tabContextMenu: null,
-  undoCloseTabMenu: null,
-
-  /**
-   * Called in delayedStartup
-   */
-  init: function at_init() {
-    // get tab context menu
-    var tabbrowser = getBrowser();
-    this.tabContextMenu = document.getAnonymousElementByAttribute(tabbrowser, "anonid", "tabContextMenu");
-
-    // listen for tab-context menu showing
-    this.tabContextMenu.addEventListener("popupshowing", this.onTabContextMenuLoad, false);
-
-    if (gPrefService.getBoolPref("browser.sessionstore.enabled"))
-      this._addUndoCloseTabContextMenu();
-  },
-
-  /**
-   * Add undo-close-tab to tab context menu
-   */
-  _addUndoCloseTabContextMenu: function at_addUndoCloseTabContextMenu() {
-    // get strings 
-    var menuLabel = gNavigatorBundle.getString("tabContext.undoCloseTab");
-    var menuAccessKey = gNavigatorBundle.getString("tabContext.undoCloseTabAccessKey");
-
-    // create new menu item
-    var undoCloseTabItem = document.createElement("menuitem");
-    undoCloseTabItem.setAttribute("id", "tabContextUndoCloseTab");
-    undoCloseTabItem.setAttribute("label", menuLabel);
-    undoCloseTabItem.setAttribute("accesskey", menuAccessKey);
-    undoCloseTabItem.setAttribute("command", "History:UndoCloseTab");
-
-    // add to tab context menu
-    var insertPos = this.tabContextMenu.lastChild.previousSibling;
-    this.undoCloseTabMenu = this.tabContextMenu.insertBefore(undoCloseTabItem, insertPos);
-  },
-
-  onTabContextMenuLoad: function at_onTabContextMenuLoad() {
-    if (AugmentTabs.undoCloseTabMenu) {
-      // only add the menu of there are tabs to restore
-      var ss = Cc["@mozilla.org/browser/sessionstore;1"].
-               getService(Ci.nsISessionStore);
-      AugmentTabs.undoCloseTabMenu.hidden = !(ss.getClosedTabCount(window) > 0);
-    }
-  }
-};
-
 HistoryMenu.toggleRecentlyClosedTabs = function PHM_toggleRecentlyClosedTabs() {
   // enable/disable the Recently Closed Tabs sub menu
   var undoPopup = document.getElementById("historyUndoPopup");
 
   // get closed-tabs from nsSessionStore
   var ss = Cc["@mozilla.org/browser/sessionstore;1"].
            getService(Ci.nsISessionStore);
   // no restorable tabs, so disable menu
@@ -5562,8 +5535,268 @@ function showToolbars() {
   }
   
   var goButtonStack = document.getElementById("go-button-stack");
   if (goButtonStack)
     goButtonStack.removeAttribute("hidden");
   
   return false; // Dismiss the notification message
 }
+
+/**
+ * Utility class to handle manipulations of the identity indicators in the UI
+ */
+function IdentityHandler() {
+  this._identityPopup = document.getElementById("identity-popup");
+  this._identityBox = document.getElementById("identity-box");
+  this._identityPopupContentBox = document.getElementById("identity-popup-content-box");
+  this._identityPopupTitle = document.getElementById("identity-popup-title");
+  this._identityPopupContent = document.getElementById("identity-popup-content");
+  this._identityPopupContentSupp = document.getElementById("identity-popup-content-supplemental");
+  this._identityPopupContentVerif = document.getElementById("identity-popup-content-verifier");
+  this._identityPopupEncLabel = document.getElementById("identity-popup-encryption-label");
+  this._identityIconLabel = document.getElementById("identity-icon-label");
+
+  this._stringBundle = document.getElementById("bundle_browser");
+  this._staticStrings = {};
+  this._staticStrings[this.IDENTITY_MODE_DOMAIN_VERIFIED] = {
+    title: this._stringBundle.getString("identity.domainverified.title"),
+    encryption_label: this._stringBundle.getString("identity.encrypted")  
+  };
+  this._staticStrings[this.IDENTITY_MODE_IDENTIFIED] = {
+    title: this._stringBundle.getString("identity.identified.title"),
+    encryption_label: this._stringBundle.getString("identity.encrypted")
+  };
+  this._staticStrings[this.IDENTITY_MODE_UNKNOWN] = {
+    title: this._stringBundle.getString("identity.unknown.title"),
+    encryption_label: this._stringBundle.getString("identity.unencrypted")  
+  };
+}
+
+IdentityHandler.prototype = {
+
+  // Mode strings used to control CSS display
+  IDENTITY_MODE_IDENTIFIED       : "verifiedIdentity", // High-quality identity information
+  IDENTITY_MODE_DOMAIN_VERIFIED  : "verifiedDomain",   // Minimal SSL CA-signed domain verification
+  IDENTITY_MODE_UNKNOWN          : "unknownIdentity",  // No trusted identity information
+
+  // Cache the most recently seen SSLStatus and URI to prevent unnecessary updates
+  _lastStatus : null,
+  _lastURI : null,
+
+  /**
+   * Handler for mouseclicks on the "Tell me more about this website" link text
+   * in the "identity-popup" panel.
+   */
+  handleMoreInfoClick : function(event) {
+    if (event.button == 0) {
+      displaySecurityInfo();
+      event.stopPropagation();
+    }   
+  },
+  
+  /**
+   * Helper to parse out the important parts of _lastStatus (of the SSL cert in
+   * particular) for use in constructing identity UI strings
+  */
+  getIdentityData : function() {
+    var result = {};
+    var status = this._lastStatus.QueryInterface(Components.interfaces.nsISSLStatus);
+    var cert = status.serverCert;
+    
+    // Human readable name of Subject
+    result.subjectOrg = cert.organization;
+    
+    // SubjectName fields, broken up for individual access
+    if (cert.subjectName) {
+      result.subjectNameFields = {};
+      cert.subjectName.split(",").forEach(function(v) {
+        var field = v.split("=");
+        this[field[0]] = field[1];
+      }, result.subjectNameFields);
+      
+      // Call out city, state, and country specifically
+      result.city = result.subjectNameFields.L;
+      result.state = result.subjectNameFields.ST;
+      result.country = result.subjectNameFields.C;
+    }
+    
+    // Human readable name of Certificate Authority
+    result.caOrg =  cert.issuerOrganization || cert.issuerCommonName;
+    
+    return result;
+  },
+  
+  /**
+   * Determine the identity of the page being displayed by examining its SSL cert
+   * (if available) and, if necessary, update the UI to reflect this.  Intended to
+   * be called by an nsIWebProgressListener.
+   *
+   * @param nsIWebProgress webProgress
+   * @param nsIRequest request
+   * @param PRUint32 state
+   */
+  checkIdentity : function(state) {
+    var currentURI = gBrowser.currentURI;
+    if (currentURI.schemeIs("http") && this._lastURI.schemeIs("http"))
+      return;
+
+    var currentStatus = gBrowser.securityUI
+                                .QueryInterface(Components.interfaces.nsISSLStatusProvider)
+                                .SSLStatus;
+    if (currentStatus == this._lastStatus && currentURI == this._lastURI) {
+      // No need to update, this is a no-op check
+      return;
+    }
+
+    this._lastStatus = currentStatus;
+    this._lastURI = currentURI;
+    
+    if (state & Components.interfaces.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL)
+      this.setMode(this.IDENTITY_MODE_IDENTIFIED);
+    else if (state & Components.interfaces.nsIWebProgressListener.STATE_SECURE_HIGH)
+      this.setMode(this.IDENTITY_MODE_DOMAIN_VERIFIED);
+    else
+      this.setMode(this.IDENTITY_MODE_UNKNOWN);
+  },
+  
+  /**
+   * Update the UI to reflect the specified mode, which should be one of the
+   * IDENTITY_MODE_* constants.
+   */
+  setMode : function(newMode) {
+    document.getElementById("identity-box").className = newMode;
+    this.setIdentityMessages(newMode);
+    
+    // Update the popup too, if it's open
+    if (this._identityPopup.state == "open")
+      this.setPopupMessages(newMode);
+  },
+  
+  /**
+   * Set up the messages for the primary identity UI based on the specified mode,
+   * and the details of the SSL cert, where applicable
+   *
+   * @param newMode The newly set identity mode.  Should be one of the IDENTITY_MODE_* constants.
+   */
+  setIdentityMessages : function(newMode) {
+    if (newMode == this.IDENTITY_MODE_DOMAIN_VERIFIED) {
+      var iData = this.getIdentityData();     
+      
+      // It would be sort of nice to use the CN= field in the cert, since that's
+      // typically what we want here, but thanks to x509 certs being extensible,
+      // it's not the only place you have to check, there can be more than one domain,
+      // et cetera, ad nauseum.  We know the cert is valid for location.host, so
+      // let's just use that, it's what the status bar does too.
+      var icon_label = this._lastURI.host; 
+      var tooltip = this._stringBundle.getFormattedString("identity.identified.verifier",
+                                                          [iData.caOrg]);
+    }
+    else if (newMode == this.IDENTITY_MODE_IDENTIFIED) {
+      // If it's identified, then we can populate the dialog with credentials
+      iData = this.getIdentityData();  
+      tooltip = this._stringBundle.getFormattedString("identity.identified.verifier",
+                                                      [iData.caOrg]);
+      if (iData.country)
+        icon_label = this._stringBundle.getFormattedString("identity.identified.title_with_country",
+                                                           [iData.subjectOrg, iData.country]);
+      else
+        icon_label = iData.subjectOrg;
+    }
+    else {
+      tooltip = this._stringBundle.getString("identity.unknown.body");
+      icon_label = "";
+    }
+    
+    // Push the appropriate strings out to the UI
+    this._identityBox.tooltipText = tooltip;
+    this._identityIconLabel.value = icon_label;
+  },
+  
+  /**
+   * Set up the title and content messages for the identity message popup,
+   * based on the specified mode, and the details of the SSL cert, where
+   * applicable
+   *
+   * @param newMode The newly set identity mode.  Should be one of the IDENTITY_MODE_* constants.
+   */
+  setPopupMessages : function(newMode) {
+      
+    this._identityPopup.className = newMode;
+    this._identityPopupContentBox.className = newMode;
+    
+    // Set the static strings up front
+    this._identityPopupTitle.value = this._staticStrings[newMode].title;
+    this._identityPopupEncLabel.textContent = this._staticStrings[newMode].encryption_label;
+    
+    // Initialize the optional strings to empty values
+    var supplemental = "";
+    var verifier = "";
+      
+    if (newMode == this.IDENTITY_MODE_DOMAIN_VERIFIED) {
+      var iData = this.getIdentityData();
+
+      var body = this._lastURI.host;     
+      verifier = this._stringBundle.getFormattedString("identity.identified.verifier",
+                                                       [iData.caOrg]);
+      supplemental = this._stringBundle.getString("identity.domainverified.supplemental");
+    }
+    else if (newMode == this.IDENTITY_MODE_IDENTIFIED) {
+      // If it's identified, then we can populate the dialog with credentials
+      iData = this.getIdentityData();
+
+      // Pull the basics out with fallback options in case common
+      // (optional) fields are left blank
+      body = iData.subjectOrg; 
+      verifier = this._stringBundle.getFormattedString("identity.identified.verifier",
+                                                       [iData.caOrg]);
+
+      // Build an appropriate supplemental block out of whatever location data we have
+      if (iData.city)
+        supplemental += iData.city + "\n";        
+      if (iData.state && iData.country)
+        supplemental += this._stringBundle.getFormattedString("identity.identified.state_and_country",
+                                                              [iData.state, iData.country]);
+      else if (iData.state) // State only
+        supplemental += iData.state;
+      else if (iData.country) // Country only
+        supplemental += iData.country;
+    }
+    else {
+      body = this._stringBundle.getString("identity.unknown.body");
+    }
+    
+    // Push the appropriate strings out to the UI
+    this._identityPopupContent.textContent = body;
+    this._identityPopupContentSupp.textContent = supplemental;
+    this._identityPopupContentVerif.textContent = verifier;
+  },
+  
+  /**
+   * Click handler for the identity-box element in primary chrome.  
+   */
+  handleIdentityClick : function(event) {
+    if (event.button != 0)
+      return; // We only want left-clicks
+        
+    // Make sure that the display:none style we set in xul is removed now that
+    // the popup is actually needed
+    this._identityPopup.hidden = false;
+    
+    // Update the popup strings
+    this.setPopupMessages(this._identityBox.className);
+    
+    // Now open the popup, anchored off the primary chrome element
+    this._identityPopup.openPopup(this._identityBox, 'after_start');
+  }
+};
+
+var gIdentityHandler; 
+
+/**
+ * Returns the singleton instance of the identity handler class.  Should always be
+ * used instead of referencing the global variable directly or creating new instances
+ */
+function getIdentityHandler() {
+  if (!gIdentityHandler)
+    gIdentityHandler = new IdentityHandler();
+  return gIdentityHandler;    
+}
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -99,19 +99,21 @@
     <tooltip id="aHTMLTooltip" onpopupshowing="return FillInHTMLTooltip(document.tooltipNode);"/>
 
     <panel type="autocomplete" chromedir="&locale.dir;" id="PopupAutoComplete" noautofocus="true"/>
 
     <panel id="editBookmarkPanel" orient="vertical">
       <vbox id="editBookmarkPanelContent" flex="1"/>
       <hbox flex="1">
         <spacer flex="1"/>
-        <button label="&editBookmark.delete.label;"
+        <button id="editBookmarkPanelDeleteButton"
+                label="&editBookmark.delete.label;"
                 oncommand="PlacesCommandHook.deleteButtonOnCommand();"/>
-        <button label="&editBookmark.done.label;"
+        <button id="editBookmarkPanelDoneButton"
+                label="&editBookmark.done.label;"
                 default="true"
                 oncommand="PlacesCommandHook.doneButtonOnCommand();"/>
       </hbox>
     </panel>
 
     <popup id="toolbar-context-menu"
            onpopupshowing="onViewToolbarsPopupShowing(event);">
       <menuseparator/>
@@ -262,17 +264,18 @@
                      level="safe"
                      onclick="goDoCommand('safebrowsing-show-warning')"/>
 #endif
             </hbox>
           </textbox>
           <stack id="go-button-stack" class="endcap">
             <box class="endcap-box" chromedir="&locale.dir;"/>
             <hbox>
-              <toolbarbutton id="star-button" onclick="if (event.button == 0) PlacesStarButton.onClick(event);"/>
+              <toolbarbutton id="star-button"
+                             onclick="if (event.button == 0) PlacesStarButton.onClick(event);"/>
               <toolbarbutton id="go-button" chromedir="&locale.dir;"
                              label="&goEndCap.label;"
                              onclick="handleURLBarCommand(event);"
                              ondragover="nsDragAndDrop.dragOver(event, goButtonObserver);"
                              ondragdrop="nsDragAndDrop.drop(event, goButtonObserver);"
                              ondragexit="nsDragAndDrop.dragExit(event, goButtonObserver);"
                              tooltiptext="&goEndCap.tooltip;"/>
             </hbox>
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -1037,17 +1037,17 @@ nsContextMenu.prototype = {
     if (selectedText.length > 15)
       selectedText = selectedText.substr(0,15) + "...";
 
     // Use the current engine if the search bar is visible, the default
     // engine otherwise.
     var engineName = "";
     var ss = Cc["@mozilla.org/browser/search-service;1"].
              getService(Ci.nsIBrowserSearchService);
-    if (BrowserSearch.getSearchBar())
+    if (isElementVisible(BrowserSearch.searchBar))
       engineName = ss.currentEngine.name;
     else
       engineName = ss.defaultEngine.name;
 
     // format "Search <engine> for <selection>" string to show in menu
     var menuLabel = gNavigatorBundle.getFormattedString("contextMenuSearchText",
                                                         [engineName,
                                                          selectedText]);
--- a/browser/base/content/pageinfo/feeds.js
+++ b/browser/base/content/pageinfo/feeds.js
@@ -45,24 +45,33 @@ function initFeedTab()
     "application/xml": gBundle.getString("feedXML"),
     "application/rdf+xml": gBundle.getString("feedXML")
   };
 
   // get the feeds
   var linkNodes = gDocument.getElementsByTagName("link");
   var length = linkNodes.length;
   for (var i = 0; i < length; i++) {
-    var feed = recognizeFeedFromLink(linkNodes[i], gDocument.nodePrincipal);
-    if (feed) {
-      var type = feed.type;
-      if (type in feedTypes)
-        type = feedTypes[type];
-      else
-        type = feedTypes["application/rss+xml"];
-      addRow(feed.title, type, feed.href);
+    var link = linkNodes[i];
+    if (!link.href)
+      continue;
+
+    var rel = link.rel && link.rel.toLowerCase();
+    var rels = {};
+    if (rel) {
+      for each (let relVal in rel.split(/\s+/))
+        rels[relVal] = true;
+    }
+
+    if (rels.feed || (link.type && rels.alternate && !rels.stylesheet)) {
+      var feed = { title: link.title, href: link.href, type: link.type || "" };
+      if (isValidFeed(feed, gDocument.nodePrincipal, rels.feed)) {
+        var type = feedTypes[feed.type] || feedTypes["application/rss+xml"];
+        addRow(feed.title, type, feed.href);
+      }
     }
   }
 
   var feedListbox = document.getElementById("feedListbox");
   document.getElementById("feedTab").hidden = feedListbox.getRowCount() == 0;
 }
 
 function onSubscribeFeed()
--- a/browser/base/content/pageinfo/pageInfo.xul
+++ b/browser/base/content/pageinfo/pageInfo.xul
@@ -54,16 +54,17 @@
 <?xul-overlay href="chrome://browser/content/macBrowserOverlay.xul"?>
 #endif
 
 <window id="main-window"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
   windowtype="Browser:page-info"
   onload="onLoadPageInfo()"
   onunload="onUnloadPageInfo()"
+  xmlns:xhtml="http://www.w3.org/1999/xhtml">
   align="stretch"
   screenX="10" screenY="10"
   width="&pageInfoWindow.width;" height="&pageInfoWindow.height;"
   persist="screenX screenY width height sizemode">
 
   <script type="application/x-javascript" src="chrome://global/content/globalOverlay.js"/>
   <script type="application/x-javascript" src="chrome://global/content/contentAreaUtils.js"/>
   <script type="application/x-javascript" src="chrome://browser/content/pageinfo/pageInfo.js"/>
@@ -311,59 +312,59 @@
     <!-- Feeds -->
     <vbox id="feedPanel">
       <richlistbox id="feedListbox" flex="1"/>
     </vbox>
 
     <!-- Permissions -->
     <vbox id="permPanel">
       <hbox>
-        <label value="&permissionsFor;" control="hosttext" />
+        <label value="&permissionsFor;" control="hostText" />
         <textbox id="hostText" class="header" readonly="true"
                  crop="end" flex="1"/>
       </hbox>
 
       <vbox id="permList" flex="1">
         <vbox>
-          <label value="&permImage;"/>
-          <hbox>
+          <label value="&permImage;" control="permImageGroup imageRadioGroup"/>
+          <hbox id="permImageGroup" xhtml:role="group">
             <checkbox id="imageDef" command="cmd_imageDef" label="&permUseDefault;"/>
             <spacer flex="1"/>
             <radiogroup id="imageRadioGroup" orient="horizontal">
               <radio id="image#1" command="cmd_imageToggle" label="&permAllow;"/>
               <radio id="image#2" command="cmd_imageToggle" label="&permBlock;"/>
             </radiogroup>
           </hbox>
         </vbox>
         <vbox>
-          <label value="&permPopup;"/>
-          <hbox>
+          <label value="&permPopup;" control="permPopupGroup popupRadioGroup"/>
+          <hbox id="permPopupGroup" xhtml:role="group">
             <checkbox id="popupDef" command="cmd_popupDef" label="&permUseDefault;"/>
             <spacer flex="1"/>
             <radiogroup id="popupRadioGroup" orient="horizontal">
               <radio id="popup#1" command="cmd_popupToggle" label="&permAllow;"/>
               <radio id="popup#2" command="cmd_popupToggle" label="&permBlock;"/>
             </radiogroup>
           </hbox>
         </vbox>
         <vbox>
-          <label value="&permCookie;"/>
-          <hbox>
+          <label value="&permCookie;" control="permCookieGroup cookieRadioGroup"/>
+          <hbox id="permCookieGroup" xhtml:role="group">
             <checkbox id="cookieDef" command="cmd_cookieDef" label="&permUseDefault;"/>
             <spacer flex="1"/>
             <radiogroup id="cookieRadioGroup" orient="horizontal">
               <radio id="cookie#1" command="cmd_cookieToggle" label="&permAllow;"/>
               <radio id="cookie#8" command="cmd_cookieToggle" label="&permAllowSession;"/>
               <radio id="cookie#2" command="cmd_cookieToggle" label="&permBlock;"/>
             </radiogroup>
           </hbox>
         </vbox>
         <vbox>
-          <label value="&permInstall;"/>
-          <hbox>
+          <label value="&permInstall;" control="permInstallGroup installRadioGroup"/>
+          <hbox id="permInstallGroup" xhtml:role="group">
             <checkbox id="installDef" command="cmd_installDef" label="&permUseDefault;"/>
             <spacer flex="1"/>
             <radiogroup id="installRadioGroup" orient="horizontal">
               <radio id="install#1" command="cmd_installToggle" label="&permAllow;"/>
               <radio id="install#2" command="cmd_installToggle" label="&permBlock;"/>
             </radiogroup>
           </hbox>
         </vbox>
@@ -422,44 +423,44 @@
         <caption id="security-privacy" label="&securityView.privacy.header;" />
         <grid>
           <columns>
             <column flex="1"/>
             <column flex="1"/>
           </columns>
           <rows>
             <row><!-- History -->
-              <description id="security-privacy-history-label"
+              <label id="security-privacy-history-label"
                            control="security-privacy-history-value"
-                           class="fieldLabel">&securityView.privacy.history;</description>
+                           class="fieldLabel">&securityView.privacy.history;</label>
               <textbox id="security-privacy-history-value"
                        class="fieldValue"
                        value="&securityView.unknown;"
                        readonly="true"/>
             </row>
             <row><!-- Cookies -->
-              <description id="security-privacy-cookies-label"
+              <label id="security-privacy-cookies-label"
                            control="security-privacy-cookies-value"
-                           class="fieldLabel">&securityView.privacy.cookies;</description>
+                           class="fieldLabel">&securityView.privacy.cookies;</label>
               <hbox>
                 <textbox id="security-privacy-cookies-value"
                          class="fieldValue"
                          value="&securityView.unknown;"
                          flex="1"
                          readonly="true"/>
                 <button id="security-view-cookies"
                         label="&securityView.privacy.viewCookies;"
                         accesskey="&securityView.privacy.viewCookies.accessKey;"
                         oncommand="security.viewCookies();"/>
               </hbox>
             </row>
             <row><!-- Passwords -->
-              <description  id="security-privacy-passwords-label"
+              <label id="security-privacy-passwords-label"
                             control="security-privacy-passwords-value"
-                            class="fieldLabel">&securityView.privacy.passwords;</description>
+                            class="fieldLabel">&securityView.privacy.passwords;</label>
               <hbox>
                 <textbox id="security-privacy-passwords-value"
                          class="fieldValue"
                          value="&securityView.unknown;"
                          flex="1"
                          readonly="true"/>
                 <button id="security-view-password"
                         label="&securityView.privacy.viewPasswords;"
--- a/browser/base/content/sanitize.js
+++ b/browser/base/content/sanitize.js
@@ -131,16 +131,21 @@ Sanitizer.prototype = {
         globalHistory.removeAllPages();
         
         try {
           var os = Components.classes["@mozilla.org/observer-service;1"]
                              .getService(Components.interfaces.nsIObserverService);
           os.notifyObservers(null, "browser:purge-session-history", "");
         }
         catch (e) { }
+        
+        // Clear last URL of the Open Web Location dialog
+        var prefs = Components.classes["@mozilla.org/preferences-service;1"]
+                              .getService(Components.interfaces.nsIPrefBranch2);
+        prefs.clearUserPref("general.open_location.last_url");
       },
       
       get canClear()
       {
         // bug 347231: Always allow clearing history due to dependencies on
         // the browser:purge-session-history notification. (like error console)
         return true;
       }
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -87,16 +87,27 @@
                           tbattr="tabbrowser-multiple"
                           oncommand="var tabbrowser = this.parentNode.parentNode.parentNode.parentNode;
                                      tabbrowser.reloadAllTabs(tabbrowser.mContextTab);"/>
             <xul:menuitem label="&closeOtherTabs.label;" accesskey="&closeOtherTabs.accesskey;"
                           tbattr="tabbrowser-multiple"
                           oncommand="var tabbrowser = this.parentNode.parentNode.parentNode.parentNode;
                                      tabbrowser.removeAllTabsBut(tabbrowser.mContextTab);"/>
             <xul:menuseparator/>
+            <xul:menuitem label="&bookmarkCurTab.label;"
+                          accesskey="&bookmarkCurTab.accesskey;"
+                          oncommand="BookmarkThisTab();"/>
+            <xul:menuitem label="&bookmarkAllTabs.label;"
+                          accesskey="&bookmarkAllTabs.accesskey;"
+                          command="Browser:BookmarkAllTabs"/>
+            <xul:menuitem label="&undoCloseTab.label;"
+                          accesskey="&undoCloseTab.accesskey;"
+                          command="History:UndoCloseTab"
+                          anonid="undoCloseTabMenuItem"/>
+            <xul:menuseparator/>
             <xul:menuitem label="&closeTab.label;" accesskey="&closeTab.accesskey;"
                           oncommand="var tabbrowser = this.parentNode.parentNode.parentNode.parentNode;
                                      tabbrowser.removeTab(tabbrowser.mContextTab);"/>
           </xul:menupopup>
 
           <xul:tabs class="tabbrowser-tabs" flex="1"
                     anonid="tabcontainer"
                     setfocus="false"
@@ -149,16 +160,19 @@
         document.getAnonymousElementByAttribute(this, "anonid", "panelcontainer");
       </field>
       <field name="mTabs" readonly="true">
         this.mTabContainer.childNodes
       </field>
       <field name="mStringBundle">
         document.getAnonymousElementByAttribute(this, "anonid", "tbstringbundle");
       </field>
+      <field name="mUndoCloseTabMenuItem">
+        document.getAnonymousElementByAttribute(this, "anonid", "undoCloseTabMenuItem");
+      </field>
       <field name="mCurrentTab">
         null
       </field>
       <field name="mCurrentBrowser">
         null
       </field>
       <field name="mProgressListeners">
         []
@@ -643,16 +657,26 @@
         <parameter name="aPopupMenu"/>
         <body>
           <![CDATA[
             this.mContextTab = document.popupNode;
             var disabled = this.mPanelContainer.childNodes.length == 1;
             var menuItems = aPopupMenu.getElementsByAttribute("tbattr", "tabbrowser-multiple");
             for (var i = 0; i < menuItems.length; i++)
               menuItems[i].disabled = disabled;
+
+            // Session store
+            if (gPrefService.getBoolPref("browser.sessionstore.enabled")) {
+              this.mUndoCloseTabMenuItem.hidden =
+                Cc["@mozilla.org/browser/sessionstore;1"].
+                getService(Ci.nsISessionStore).
+                getClosedTabCount(window) == 0;
+            }
+            else
+              this.mUndoCloseTabMenuItem.hidden = true;
           ]]>
         </body>
       </method>
 
       <method name="updateCurrentBrowser">
         <body>
           <![CDATA[
             var newBrowser = this.getBrowserAtIndex(this.mTabContainer.selectedIndex);
@@ -848,83 +872,16 @@
               return;
 
             this.removeTab(event.target);
             event.stopPropagation();
           ]]>
         </body>
       </method>
 
-      <method name="onLinkAdded">
-        <parameter name="event"/>
-        <body>
-          <![CDATA[
-            if (!this.mPrefs.getBoolPref("browser.chrome.site_icons"))
-              return;
-
-            if (!event.originalTarget.rel.match((/(?:^|\s)icon(?:\s|$)/i)))
-              return;
-
-            // We have an icon.
-            var href = event.originalTarget.href;
-            if (!href)
-              return;
-
-            const nsIContentPolicy = Components.interfaces.nsIContentPolicy;
-            try {
-              var contentPolicy =
-                Components.classes['@mozilla.org/layout/content-policy;1']
-                          .getService(nsIContentPolicy);
-            } catch(e) {
-              return; // Refuse to load if we can't do a security check.
-            }
-
-            // Get the IOService so we can make URIs
-            const ioService =
-              Components.classes["@mozilla.org/network/io-service;1"]
-                        .getService(Components.interfaces.nsIIOService);
-
-            const targetDoc = event.target.ownerDocument;
-            // Make a URI out of our href.
-            var uri = ioService.newURI(href, targetDoc.characterSet, null);
-            try {
-              // Verify that the load of this icon is legal.
-              // error pages can load their favicon, to be on the safe side,
-              // only allow chrome:// favicons
-              const nsIScriptSecMan =
-                Components.interfaces.nsIScriptSecurityManager;
-              var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
-                                     .getService(nsIScriptSecMan);
-              const aboutNeterr = "about:neterror?";
-              if (targetDoc.documentURI.substr(0, aboutNeterr.length) != aboutNeterr ||
-                  !uri.schemeIs("chrome"))
-                secMan.checkLoadURIWithPrincipal(targetDoc.nodePrincipal, uri,
-                                                 nsIScriptSecMan.DISALLOW_SCRIPT);
-            } catch(e) {
-              return;
-            }
-
-            // Security says okay, now ask content policy
-            if (contentPolicy.shouldLoad(nsIContentPolicy.TYPE_IMAGE,
-                                         uri, targetDoc.documentURIObject,
-                                         event.target, event.target.type,
-                                         null) != nsIContentPolicy.ACCEPT)
-              return;
-
-            var browserIndex = this.getBrowserIndexForDocument(targetDoc);
-            // no browser? no favicon.
-            if (browserIndex == -1)
-              return;
-
-            var tab = this.mTabContainer.childNodes[browserIndex];
-            this.setIcon(tab, href);
-          ]]>
-        </body>
-      </method>
-
       <method name="onTitleChanged">
         <parameter name="evt"/>
         <body>
           <![CDATA[
             if (evt.target != this.contentDocument)
               return;
 
             var i = 0;
@@ -2395,18 +2352,16 @@
             this.getBrowserAtIndex(i).removeEventListener("DOMTitleChanged", this.onTitleChanged, true);
           }
           document.removeEventListener("keypress", this._keyEventHandler, false);
         ]]>
       </destructor>
     </implementation>
 
     <handlers>
-      <handler event="DOMLinkAdded" phase="capturing" action="this.onLinkAdded(event);"/>
-
       <handler event="DOMWindowClose" phase="capturing">
         <![CDATA[
           if (!event.isTrusted)
             return;
 
           const browsers = this.mPanelContainer.childNodes;
           if (browsers.length == 1) {
             // There's only one browser left. If a window is being
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -45,15 +45,18 @@ include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES =	test_feed_discovery.html \
 		feed_discovery.html \
 		test_bug395533.html \
 		bug395533-data.txt \
 		$(NULL)
 
 _BROWSER_FILES = browser_bug321000.js \
+                 browser_autodiscovery.js \
+                 autodiscovery.html \
+                 moz.png \
     $(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/autodiscovery.html
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML>
+<html>
+  <head id="linkparent">
+    <title>Autodiscovery Test</title>
+  </head>
+  <body>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_autodiscovery.js
@@ -0,0 +1,105 @@
+function url(spec) {
+  var ios = Components.classes["@mozilla.org/network/io-service;1"]
+                      .getService(Components.interfaces.nsIIOService);
+  return ios.newURI(spec, null, null);
+}
+
+var gTestPage = null;
+function test() {
+  waitForExplicitFinish();
+  var activeWin = Application.activeWindow;
+  gTestPage = activeWin.open(url("chrome://mochikit/content/browser/browser/base/content/test/autodiscovery.html"));
+  gTestPage.focus();
+  setTimeout(iconDiscovery, 1000);
+}
+
+function iconDiscovery() {
+  var tests = [
+    { text: "rel icon discovered" },
+    { rel: "abcdefg icon qwerty", text: "rel may contain additional rels separated by spaces" },
+    { rel: "ICON", text: "rel is case insensitive" },
+    { rel: "shortcut-icon", pass: false, text: "rel shortcut-icon not discovered" },
+    { href: "moz.png", text: "relative href works" },
+    { href: "notthere.png", text: "404'd icon is removed properly" },
+    { href: "data:image/x-icon,%00", type: "image/x-icon", text: "data: URIs work" },
+    { type: "image/png; charset=utf-8", text: "type may have optional parameters (RFC2046)" }
+  ];
+
+  for (let i = 0; i < tests.length; i++) {
+    gProxyFavIcon.removeAttribute("src");
+
+    var test = tests[i];
+    var head = gTestPage.document.getElementById("linkparent");
+    var link = gTestPage.document.createElement("link");
+
+    var rel = test.rel || "icon";
+    var href = test.href || "chrome://mochikit/content/browser/browser/base/content/test/moz.png";
+    var type = test.type || "image/png";
+    if (test.pass == undefined)
+      test.pass = true;
+
+    link.rel = rel;
+    link.href = href;
+    link.type = type;
+    head.appendChild(link);
+
+    var hasSrc = gProxyFavIcon.hasAttribute("src");
+    if (test.pass)
+      ok(hasSrc, test.text);
+    else
+      ok(!hasSrc, test.text);
+
+    head.removeChild(link);
+  }
+  searchDiscovery();
+}
+
+function searchDiscovery() {
+  var tests = [
+    { text: "rel search discovered" },
+    { rel: "SEARCH", text: "rel is case insensitive" },
+    { rel: "-search-", pass: false, text: "rel -search- not discovered" },
+    { rel: "foo bar baz search quux", text: "rel may contain additional rels separated by spaces" },
+    { href: "https://not.mozilla.com", text: "HTTPS ok" },
+    { href: "ftp://not.mozilla.com", text: "FTP ok" },
+    { href: "data:text/foo,foo", pass: false, text: "data URI not permitted" },
+    { href: "javascript:alert(0)", pass: false, text: "JS URI not permitted" },
+    { type: "APPLICATION/OPENSEARCHDESCRIPTION+XML", text: "type is case insensitve" },
+    { type: " application/opensearchdescription+xml ", text: "type may contain extra whitespace" },
+    { type: "application/opensearchdescription+xml; charset=utf-8", text: "type may have optional parameters (RFC2046)" },
+    { type: "aapplication/opensearchdescription+xml", pass: false, text: "type should not be loosely matched" },
+    { rel: "search search search", count: 1, text: "only one engine should be added" }
+  ];
+
+  for (let i = 0; i < tests.length; i++) {
+    var test = tests[i];
+    var head = gTestPage.document.getElementById("linkparent");
+    var link = gTestPage.document.createElement("link");
+
+    var rel = test.rel || "search";
+    var href = test.href || "http://so.not.here.mozilla.com/search.xml";
+    var type = test.type || "application/opensearchdescription+xml";
+    var title = test.title || i;
+    if (test.pass == undefined)
+      test.pass = true;
+
+    link.rel = rel;
+    link.href = href;
+    link.type = type;
+    link.title = title;
+    head.appendChild(link);
+
+    var browser = gBrowser.getBrowserForDocument(gTestPage.document);
+    if (browser.engines) {
+      var hasEngine = (test.count) ? (browser.engines[0].title == title &&
+                                      browser.engines.length == test.count) :
+                                     (browser.engines[0].title == title);
+      ok(hasEngine, test.text);
+      browser.engines = null;
+    }
+    else
+      ok(!test.pass, test.text);
+  }
+  gTestPage.close();
+  finish();  
+}
new file mode 100755
index 0000000000000000000000000000000000000000..769c636340e11f9d2a0b7eb6a84d574dd9563f0c
GIT binary patch
literal 580
zc$@)50=xZ*P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt006JZ
zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz)=5M`RCwBA
z{Qv(y10?_;fS8au@87>?@9gaSt*os4-<6T^zln*-e<1(Y>eZ{a-@A8D7MlS80mJ}u
z0SKQtbH>fs*!aH-1H=C_K)ecw?*efe5W7I}s#U9Y!PLVrKmdV>nKNfT1{(H16si$K
zmjm&CV+al6D=8`c7X*o+82}JK4A3z64>JJB_`e(E3S)?2<zN>X{|^lf1sei(+1<Me
zFarPr2&}oIqvIC?)OL^o?-&p^!wh-{#k-;2f_VoZfS{%bLi}zFF<>UtAY{W<LBj?n
zz6$CsfB=HI;P*^44eyZn#$YcBg1rF~2L~`P&;bI75#$0;v@zVf$It;Z4d`qJS0Dzu
zh@l)BQx!mb7Roj*FK2kaXAgtR*|Q9LfP8=e0=od{pY0$UI-sVXf!f>w#jt?wfcn3@
zy!=0d5|Evi_8%aC7~Z{m#}1AKK|~<_M{=g1px}QcP=ErR57Iaj7$e5OumVLr$n^jL
z1djz!sJcLHd57c@W2lWFi_p^m2m=HVoB>kgf@C|$pqa*ykjAAMgaHBwo)>`0c=vmt
z+g3yQpuk*x7A(#H^u|wInF%0(FiZq_r2`t3pnwGh6fWCA7$ATcDb3CR0R{jJCzQv)
SYsoAC0000<MNUMnLSTYrIq9PS
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -481,23 +481,23 @@ function buildHelpMenu()
   if (um.activeUpdate && updates.isDownloading)
     checkForUpdates.setAttribute("loading", "true");
   else
     checkForUpdates.removeAttribute("loading");
 }
 
 function isElementVisible(aElement)
 {
-  // * When an element is hidden, the width and height of its boxObject
-  //   are set to 0
-  // * css-visibility (unlike css-display) is inherited.
+  if (!aElement)
+    return false;
+
+  // If aElement or a direct or indirect parent is hidden or collapsed,
+  // height, width or both will be 0.
   var bo = aElement.boxObject;
-  return (bo.height != 0 && bo.width != 0 &&
-          document.defaultView
-                  .getComputedStyle(aElement, null).visibility == "visible");
+  return (bo.height > 0 && bo.width > 0);
 }
 
 function getBrowserFromContentWindow(aContentWindow)
 {
   var browsers = gBrowser.browsers;
   for (var i = 0; i < browsers.length; i++) {
     if (browsers[i].contentWindow == aContentWindow)
       return browsers[i];
@@ -581,73 +581,53 @@ function openNewWindowWith(aURL, aDocume
 
   var referrerURI = aDocument ? aDocument.documentURIObject : aReferrer;
   window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no",
                     aURL, charsetArg, referrerURI, aPostData,
                     aAllowThirdPartyFixup);
 }
 
 /**
- * recognizeFeedFromLink: recognizes RSS/ATOM feeds from DOM link elements.
+ * isValidFeed: checks whether the given data represents a valid feed.
  *
- * @param  aLink
- *         The DOM link element to check for representing a feed.
+ * @param  aData
+ *         An object representing a feed with title, href and type.
  * @param  aPrincipal
  *         The principal of the document, used for security check.
- * @return object
- *         The feed object containing href, type, and title properties,
- *          if successful, otherwise null.
+ * @param  aIsFeed
+ *         Whether this is already a known feed or not, if true only a security
+ *         check will be performed.
  */ 
-function recognizeFeedFromLink(aLink, aPrincipal)
+function isValidFeed(aData, aPrincipal, aIsFeed)
 {
-  if (!aLink || !aPrincipal)
-    return null;
-
-  var erel = aLink.rel && aLink.rel.toLowerCase();
-  var etype = aLink.type && aLink.type.toLowerCase();
-  var etitle = aLink.title;
-  const rssTitleRegex = /(^|\s)rss($|\s)/i;
-  var rels = {};
+  if (!aData || !aPrincipal)
+    return false;
 
-  if (erel) {
-    for each (var relValue in erel.split(/\s+/))
-      rels[relValue] = true;
-  }
-  var isFeed = rels.feed;
-
-  if (!isFeed && (!rels.alternate || rels.stylesheet || !etype))
-    return null;
+  if (!aIsFeed) {
+    var type = aData.type && aData.type.toLowerCase();
+    type = type.replace(/^\s+|\s*(?:;.*)?$/g, "");
 
-  if (!isFeed) {
-    // Use type value
-    etype = etype.replace(/^\s+/, "");
-    etype = etype.replace(/\s+$/, "");
-    etype = etype.replace(/\s*;.*/, "");
-    isFeed = (etype == "application/rss+xml" ||
-              etype == "application/atom+xml");
-    if (!isFeed) {
+    aIsFeed = (type == "application/rss+xml" ||
+               type == "application/atom+xml");
+
+    if (!aIsFeed) {
       // really slimy: general XML types with magic letters in the title
-      isFeed = ((etype == "text/xml" || etype == "application/xml" ||
-                 etype == "application/rdf+xml") && rssTitleRegex.test(etitle));
+      const titleRegex = /(^|\s)rss($|\s)/i;
+      aIsFeed = ((type == "text/xml" || type == "application/rdf+xml" ||
+                  type == "application/xml") && titleRegex.test(aData.title));
     }
   }
 
-  if (isFeed) {
-    try { 
-      urlSecurityCheck(aLink.href,
-                       aPrincipal,
+  if (aIsFeed) {
+    try {
+      urlSecurityCheck(aData.href, aPrincipal,
                        Components.interfaces.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
     }
-    catch (ex) {
-      dump(ex.message);
-      return null; // doesn't pass security check
+    catch(ex) {
+      aIsFeed = false;
     }
-
-    // successful!  return the feed
-    return {
-        href: aLink.href,
-        type: etype,
-        title: aLink.title
-      };
   }
 
-  return null;
+  if (type)
+    aData.type = type;
+
+  return aIsFeed;
 }
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -60,17 +60,14 @@ browser.jar:
 *       content/browser/viewSourceOverlay.xul         (content/viewSourceOverlay.xul)
 #ifdef MOZ_USE_GENERIC_BRANDING
 % content branding %content/branding/ xpcnativewrappers=yes
   content/branding/about.png                     (branding/about.png)
   content/branding/aboutCredits.png              (branding/aboutCredits.png)
   content/branding/aboutFooter.png               (branding/aboutFooter.png)
   content/branding/icon48.png                    (branding/icon48.png)
   content/branding/icon64.png                    (branding/icon64.png)
-#ifdef XP_WIN
-  content/branding/uninstall.properties          (branding/uninstall.properties)
-#endif
 #endif
 
 #ifdef TOOLBAR_CUSTOMIZATION_SHEET
 toolkit.jar:
 *+      content/global/customizeToolbar.xul           (content/customizeToolbarSheet.xul)
 #endif
--- a/browser/branding/unofficial/content/jar.mn
+++ b/browser/branding/unofficial/content/jar.mn
@@ -1,10 +1,7 @@
 browser.jar:
 % content branding %content/branding/ xpcnativewrappers=yes
   content/branding/about.png                     (about.png)
   content/branding/aboutCredits.png              (aboutCredits.png)
   content/branding/aboutFooter.png               (aboutFooter.png)
   content/branding/icon48.png                    (icon48.png)
   content/branding/icon64.png                    (icon64.png)
-#ifdef XP_WIN
-  content/branding/uninstall.properties          (uninstall.properties)
-#endif
deleted file mode 100644
--- a/browser/branding/unofficial/content/uninstall.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-# These values are used to construct the registry keys for the Add/Remove
-# Programs dialog under Windows.  They must be kept in sync with the values
-# used by the installer.
-# XXX fileUninstall is no longer brand-specific, and can therefore be removed.
-fileUninstall=uninstall.exe
-URLInfoAbout=http://www.mozilla.org/
-URLUpdateInfo=http://www.mozilla.org/projects/bonecho/
--- a/browser/components/feeds/src/FeedWriter.js
+++ b/browser/components/feeds/src/FeedWriter.js
@@ -630,17 +630,17 @@ FeedWriter.prototype = {
 
   _initSubscriptionUI: function FW__initSubscriptionUI() {
     var handlersMenuPopup = this._document.getElementById("handlersMenuPopup");
     if (!handlersMenuPopup)
       return;
 
     // Last-selected application
     var selectedApp;
-    menuItem = this._document.createElementNS(XUL_NS, "menuitem");
+    var menuItem = this._document.createElementNS(XUL_NS, "menuitem");
     menuItem.id = "selectedAppMenuItem";
     menuItem.className = "menuitem-iconic";
     menuItem.setAttribute("handlerType", "client");
     handlersMenuPopup.appendChild(menuItem);
 
     var selectedApplicationItem = this.selectedApplicationItemWrapped;
     try {
       var prefs = Cc["@mozilla.org/preferences-service;1"].
--- a/browser/components/microsummaries/src/nsMicrosummaryService.js
+++ b/browser/components/microsummaries/src/nsMicrosummaryService.js
@@ -51,18 +51,18 @@ const MODE_TRUNCATE = 0x20;
 const NS_ERROR_MODULE_DOM = 2152923136;
 const NS_ERROR_DOM_BAD_URI = NS_ERROR_MODULE_DOM + 1012;
 
 // How often to check for microsummaries that need updating, in milliseconds.
 const CHECK_INTERVAL = 15 * 1000; // 15 seconds
 // How often to check for generator updates, in seconds
 const GENERATOR_INTERVAL = 7 * 86400; // 1 week
 
-const MICSUM_NS = new Namespace("http://www.mozilla.org/microsummaries/0.1");
-const XSLT_NS = new Namespace("http://www.w3.org/1999/XSL/Transform");
+const MICSUM_NS = "http://www.mozilla.org/microsummaries/0.1";
+const XSLT_NS = "http://www.w3.org/1999/XSL/Transform";
 
 const ANNO_MICSUM_GEN_URI    = "microsummary/generatorURI";
 const ANNO_MICSUM_EXPIRATION = "microsummary/expiration";
 const ANNO_STATIC_TITLE      = "bookmarks/staticTitle";
 const ANNO_CONTENT_TYPE      = "bookmarks/contentType";
 
 const MAX_SUMMARY_LENGTH = 4096;
 
@@ -1762,18 +1762,17 @@ MicrosummaryResource.prototype = {
 
   get lastMod()     { return this._lastMod },
   set lastMod(aMod) { this._lastMod = aMod },
 
   // Implement notification callback interfaces so we can suppress UI
   // and abort loads for bad SSL certs and HTTP authorization requests.
   
   // Interfaces this component implements.
-  interfaces: [Ci.nsIBadCertListener,
-               Ci.nsIAuthPromptProvider,
+  interfaces: [Ci.nsIAuthPromptProvider,
                Ci.nsIAuthPrompt,
                Ci.nsIPrompt,
                Ci.nsIProgressEventSink,
                Ci.nsIInterfaceRequestor,
                Ci.nsISupports],
 
   // nsISupports
 
@@ -1795,35 +1794,16 @@ MicrosummaryResource.prototype = {
   },
 
   // nsIInterfaceRequestor
   
   getInterface: function MSR_getInterface(iid) {
     return this.QueryInterface(iid);
   },
 
-  // nsIBadCertListener
-
-  // Suppress UI and abort secure loads from servers with bad SSL certificates.
-  
-  confirmUnknownIssuer: function MSR_confirmUnknownIssuer(socketInfo, cert, certAddType) {
-    return false;
-  },
-
-  confirmMismatchDomain: function MSR_confirmMismatchDomain(socketInfo, targetURL, cert) {
-    return false;
-  },
-
-  confirmCertExpired: function MSR_confirmCertExpired(socketInfo, cert) {
-    return false;
-  },
-
-  notifyCrlNextupdate: function MSR_notifyCrlNextupdate(socketInfo, targetURL, cert) {
-  },
-
   // Suppress UI and abort loads for files secured by authentication.
 
   // Auth requests appear to succeed when we cancel them (since the server
   // redirects us to a "you're not authorized" page), so we have to set a flag
   // to let the load handler know to treat the load as a failure.
   get _authFailed()         { return this.__authFailed; },
   set _authFailed(newValue) { return this.__authFailed = newValue },
 
@@ -2060,18 +2040,20 @@ MicrosummaryResource.prototype = {
   },
 
   _handleLoad: function MSR__handleLoad(event) {
     var request = event.target;
 
     if (request.responseXML) {
       this._isXML = true;
       // XXX Figure out the parsererror format and log a specific error.
-      if (request.responseXML.documentElement.nodeName == "parsererror")
-        throw(request.channel.originalURI.spec + " contains invalid XML");
+      if (request.responseXML.documentElement.nodeName == "parsererror") {
+        this._handleError(event);
+        return;
+      }
       this._content = request.responseXML;
       this._contentType = request.channel.contentType;
       this._loadCallback(this);
     }
 
     else if (request.channel.contentType == "text/html") {
       this._parse(request.responseText);
     }
@@ -2105,18 +2087,20 @@ MicrosummaryResource.prototype = {
     var windowMediator = Cc['@mozilla.org/appshell/window-mediator;1'].
                          getService(Ci.nsIWindowMediator);
     var window = windowMediator.getMostRecentWindow("navigator:browser");
     // XXX We can use other windows, too, so perhaps we should try to get
     // some other window if there's no browser window open.  Perhaps we should
     // even prefer other windows, since there's less chance of any browser
     // window machinery like throbbers treating our load like one initiated
     // by the user.
-    if (!window)
-      throw(this._uri.spec + " can't parse; no browser window");
+    if (!window) {
+      this._handleError(event);
+      return;
+    }
     var document = window.document;
     var rootElement = document.documentElement;
   
     // Create an iframe, make it hidden, and secure it against untrusted content.
     this._iframe = document.createElement('iframe');
     this._iframe.setAttribute("collapsed", true);
     this._iframe.setAttribute("type", "content");
   
--- a/browser/components/migration/content/migration.xul
+++ b/browser/components/migration/content/migration.xul
@@ -43,18 +43,17 @@
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         windowtype="Browser:MigrationWizard"
         title="&migrationWizard.title;"
         onload="MigrationWizard.init()"
         onunload="MigrationWizard.uninit()"
         style="width: 40em;"
         buttons="accept,cancel"
         branded="true"
-        xmlns:xhtml2="http://www.w3.org/TR/xhtml2"
-        xmlns:wairole="http://www.w3.org/2005/01/wai-rdf/GUIRoleTaxonomy#">
+        xmlns:xhtml="http://www.w3.org/1999/xhtml">
 
   <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;"
@@ -128,17 +127,17 @@
               next="homePageImport"
               onpageshow="return MigrationWizard.onImportItemsPageShow();"
               onpagerewound="return MigrationWizard.onImportItemsPageRewound();"
               onpageadvanced="return MigrationWizard.onImportItemsPageAdvanced();"
               oncommand="MigrationWizard.onImportItemCommand();">
     <description control="dataSources">&importItems.label;</description>
 
     <vbox id="dataSources" style="overflow: auto; -moz-appearance: listbox" align="left" flex="1"
-          xhtml2:role="wairole:groupbox"/>
+          xhtml:role="group"/>
   </wizardpage>
 
   <wizardpage id="homePageImport" pageid="homePageImport"
               next="migrating"
               onpageshow="return MigrationWizard.onHomePageMigrationPageShow();"
               onpageadvanced="return MigrationWizard.onHomePageMigrationPageAdvanced();">
 
     <description id="homePageImportDesc" control="homePageRadioGroup"/>
@@ -148,22 +147,20 @@
     </radiogroup>
   </wizardpage>
 
   <wizardpage id="migrating" pageid="migrating" label="&migrating.title;"
               next="done"
               onpageshow="MigrationWizard.onMigratingPageShow();">
     <description control="migratingItems">&migrating.label;</description>
 
-    <vbox id="migratingItems" style="overflow: auto;" align="left"
-          xhtml2:role="wairole:groupbox"/>
+    <vbox id="migratingItems" style="overflow: auto;" align="left" xhtml:role="group"/>
   </wizardpage>
 
   <wizardpage id="done" pageid="done" label="&done.title;"
               onpageshow="MigrationWizard.onDonePageShow();">
     <description control="doneItems">&done.label;</description>
 
-    <vbox id="doneItems" style="overflow: auto;" align="left"
-          xhtml2:role="wairole:groupbox"/>
+    <vbox id="doneItems" style="overflow: auto;" align="left" xhtml:role="group"/>
   </wizardpage>
 
 </wizard>
 
--- a/browser/components/migration/src/nsOperaProfileMigrator.cpp
+++ b/browser/components/migration/src/nsOperaProfileMigrator.cpp
@@ -1273,18 +1273,16 @@ nsOperaProfileMigrator::ParseBookmarksFo
   nsAutoString name, keyword, description;
   nsCAutoString url;
   PRBool onToolbar = PR_FALSE;
   do {
     nsCAutoString cBuffer;
     rv = aStream->ReadLine(cBuffer, &moreData);
     if (NS_FAILED(rv)) return rv;
     
-    if (!moreData) break;
-
     CopyUTF8toUTF16(cBuffer, buffer);
     nsString data;
     LineType type = GetLineType(buffer, getter_Copies(data));
     switch(type) {
     case LineType_FOLDER:
       entryType = EntryType_FOLDER;
       break;
     case LineType_BOOKMARK:
@@ -1312,16 +1310,17 @@ nsOperaProfileMigrator::ParseBookmarksFo
       if (NS_LITERAL_STRING("YES").Equals(data))
         onToolbar = PR_TRUE;
       break;
     case LineType_NL: {
       // XXX We don't know for sure how Opera deals with IDN hostnames in URL.
       // Assuming it's in UTF-8 is rather safe because it covers two cases 
       // (UTF-8 and ASCII) out of three cases (the last is a non-UTF-8
       // multibyte encoding).
+      // XXX Todo: |description| is not saved.
       if (entryType == EntryType_BOOKMARK) {
         if (!name.IsEmpty() && !url.IsEmpty()) {
           nsCOMPtr<nsIURI> uri;
           rv = NS_NewURI(getter_AddRefs(uri), url);
           if (NS_FAILED(rv))
             continue;
           PRInt64 id;
           rv = aBMS->InsertBookmark(onToolbar ? aToolbar : aParent,
@@ -1348,17 +1347,17 @@ nsOperaProfileMigrator::ParseBookmarksFo
         }
       }
       break;
     }
     case LineType_OTHER:
       break;
     }
   }
-  while (1);
+  while (moreData);
 
 done:
   return rv;
 }
 
 void
 nsOperaProfileMigrator::GetOperaProfile(const PRUnichar* aProfile, nsILocalFile** aFile)
 {
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -396,19 +396,19 @@ BrowserGlue.prototype = {
     this.Sanitizer.sanitize(aParentWindow);
   },
 
   // for XPCOM
   classDescription: "Firefox Browser Glue Service",
   classID:          Components.ID("{eab9012e-5f74-4cbc-b2b5-a590235513cc}"),
   contractID:       "@mozilla.org/browser/browserglue;1",
 
-  QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupports,
-                                          Ci.nsISupportsWeakReference,
-                                          Ci.nsIBrowserGlue]),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
+                                         Ci.nsISupportsWeakReference,
+                                         Ci.nsIBrowserGlue]),
 
   // redefine the default factory for XPCOMUtils
   _xpcom_factory: BrowserGlueServiceFactory,
 
   // get this contractID registered for certain categories via XPCOMUtils
   _xpcom_categories: [
     // make BrowserGlue a startup observer
     { category: "app-startup", service: true }
--- a/browser/components/places/content/advancedSearch.inc
+++ b/browser/components/places/content/advancedSearch.inc
@@ -29,17 +29,28 @@
 # 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 ***** 
 
-<vbox id="advancedSearch" collapsed="true">
+<vbox id="advancedSearch">
+  <hbox>
+    <label value="&advancedSearch.match.label;" control="advancedSearchType"/> 
+    <menulist id="advancedSearchType"
+              oncommand="PlacesQueryBuilder.doSearch();">
+      <menupopup>
+        <menuitem value="and" label="&advancedSearch.all.label;"/>
+        <menuitem value="or" label="&advancedSearch.any.label;"/>
+      </menupopup>
+    </menulist>
+    <label value="&advancedSearch.rules.label;"/>
+  </hbox>
   <grid flex="1">
     <columns>
       <column flex="1"/>
       <column flex="1"/>
       <column flex="0"/>
       <column flex="0"/>
     </columns>
     <rows id="advancedSearchRows">
@@ -142,13 +153,13 @@
         </hbox>              
         <button id="advancedSearch0Minus"
                 label="&advancedSearch.minus.label;"
                 class="small"
                 oncommand="PlacesQueryBuilder.removeRow(event.target.parentNode);"/>
         <button id="advancedSearch0Plus"
                 label="&advancedSearch.plus.label;"
                 class="small"
-                command="placesCmd_search:moreCriteria"/>
+                command="OrganizerCommand_search:moreCriteria"/>
       </row>
     </rows>
   </grid>
 </vbox>
--- a/browser/components/places/content/bookmarkProperties.js
+++ b/browser/components/places/content/bookmarkProperties.js
@@ -349,17 +349,17 @@ var BookmarkPropertiesPanel = {
 
     this._determineItemInfo();
     this._populateProperties();
     this._forceHideRows();
     this.validateChanges();
 
     this._folderMenuList = this._element("folderMenuList");
     this._folderTree = this._element("folderTree");
-    if (isElementVisible(this._folderMenuList))
+    if (!this._element("folderRow").hidden)
       this._initFolderMenuList();
 
     window.sizeToContent();
 
     // read the persisted attribute.
     this._folderTreeHeight = parseInt(this._folderTree.getAttribute("height"));
   },
 
@@ -891,17 +891,17 @@ var BookmarkPropertiesPanel = {
    * [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
    * the form of [containerIdentifier, insertionIndex]
    */
   _getInsertionPointDetails: function BPP__getInsertionPointDetails() {
     var containerId, indexInContainer = -1;
-    if (isElementVisible(this._folderMenuList))
+    if (!this._element("folderRow").hidden)
       containerId = this._getFolderIdFromMenuList();
     else {
       containerId = this._defaultInsertionPoint.itemId;
       indexInContainer = this._defaultInsertionPoint.index;
     }
 
     return [containerId, indexInContainer];
   },
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -627,17 +627,18 @@ PlacesController.prototype = {
         // New separator, count again:
         visibleItemsBeforeSep = false;
       }
     }
 
     // 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) {
+      if (!openContainerInTabsItem.hidden && this._view.selectedNode &&
+          PlacesUtils.nodeIsContainer(this._view.selectedNode)) {
         openContainerInTabsItem.disabled =
           PlacesUtils.getURLsForContainerNode(this._view.selectedNode)
                      .length == 0;
       }
       else {
         // see selectiontype rule in the overlay
         var openLinksInTabsItem = document.getElementById("placesContext_openLinks:tabs");
         openLinksInTabsItem.disabled = openLinksInTabsItem.hidden;
--- a/browser/components/places/content/editBookmarkOverlay.js
+++ b/browser/components/places/content/editBookmarkOverlay.js
@@ -49,18 +49,18 @@ var gEditItemOverlay = {
       this.__mss = Cc["@mozilla.org/microsummary/service;1"].
                   getService(Ci.nsIMicrosummaryService);
     return this.__mss;
   },
 
   _uri: null,
   _itemId: -1,
   _itemType: -1,
+  _readOnly: false,
   _microsummaries: null,
-  _doneCallback: null,
   _hiddenRows: [],
   _observersAdded: false,
 
   get itemId() {
     return this._itemId;
   },
 
   /**
@@ -71,66 +71,117 @@ var gEditItemOverlay = {
     if (aInfo && aInfo.hiddenRows)
       this._hiddenRows = aInfo.hiddenRows;
     else
       this._hiddenRows.splice(0);
   },
 
   _showHideRows: function EIO__showHideRows() {
     var isBookmark = this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK;
-    this._element("nameRow").hidden = this._hiddenRows.indexOf("name") != -1;
-    this._element("folderRow").hidden =
+
+    this._element("nameRow").collapsed = this._hiddenRows.indexOf("name") != -1;
+    this._element("folderRow").collapsed =
       this._hiddenRows.indexOf("folderPicker") != -1;
-    this._element("tagsRow").hidden =
-      this._hiddenRows.indexOf("tags") != -1 || !isBookmark;
-    this._element("descriptionRow").hidden =
-      this._hiddenRows.indexOf("description") != -1;
-    this._element("locationRow").hidden =
-      this._hiddenRows.indexOf("location") != -1 || !isBookmark;
+    this._element("tagsRow").collapsed = !isBookmark ||
+      this._hiddenRows.indexOf("tags") != -1;
+    this._element("descriptionRow").collapsed =
+      this._hiddenRows.indexOf("description") != -1 ||
+      this._readOnly;
+    this._element("keywordRow").collapsed = !isBookmark || this._readOnly ||
+      this._hiddenRows.indexOf("keyword") != -1;
+    this._element("locationRow").collapsed = !isBookmark ||
+      this._hiddenRows.indexOf("location") != -1;
+    this._element("loadInSidebarCheckbox").collapsed = !isBookmark ||
+      this._readOnly || this._hiddenRows.indexOf("loadInSidebar") != -1;
+    this._element("feedLocationRow").collapsed = !this._isLivemark ||
+      this._hiddenRows.indexOf("feedLocation") != -1;
+    this._element("siteLocationRow").collapsed = !this._isLivemark ||
+      this._hiddenRows.indexOf("siteLocation") != -1;
   },
 
   /**
    * Initialize the panel
    */
   initPanel: function EIO_initPanel(aItemId, aInfo) {
+    const bms = PlacesUtils.bookmarks;
+
     this._folderMenuList = this._element("folderMenuList");
     this._folderTree = this._element("folderTree");
     this._itemId = aItemId;
-    this._itemType = PlacesUtils.bookmarks.getItemType(this._itemId);
+    this._itemType = bms.getItemType(this._itemId);
     this._determineInfo(aInfo);
 
+    var container = bms.getFolderIdForItem(this._itemId);
     if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK) {
-      this._uri = PlacesUtils.bookmarks.getBookmarkURI(this._itemId);
-      // tags field
-      this._element("tagsField").value =
-        PlacesUtils.tagging.getTagsForURI(this._uri).join(", ");
+      this._uri = bms.getBookmarkURI(this._itemId);
+      this._isLivemark = false;
+      if (PlacesUtils.livemarks.isLivemark(container))
+        this._readOnly = true;
+      else
+        this._readOnly = false;
+
+      this._initTextField("locationField", this._uri.spec);
+      this._initTextField("tagsField",
+                           PlacesUtils.tagging
+                                      .getTagsForURI(this._uri).join(", "),
+                          false);
+      this._initTextField("keywordField",
+                          bms.getKeywordForBookmark(this._itemId));
 
-      this._element("locationField").value = this._uri.spec;
+      // Load In Sidebar checkbox
+      this._element("loadInSidebarCheckbox").checked =
+        PlacesUtils.annotations.itemHasAnnotation(this._itemId,
+                                                  LOAD_IN_SIDEBAR_ANNO);
+    }
+    else {
+      this._readOnly = false;
+      this._isLivemark = PlacesUtils.livemarks.isLivemark(this._itemId);
+      if (this._isLivemark) {
+        var feedURI = PlacesUtils.livemarks.getFeedURI(this._itemId);
+        var siteURI = PlacesUtils.livemarks.getSiteURI(this._itemId);
+        this._initTextField("feedLocationField", feedURI.spec);
+        this._initTextField("siteLocationField", siteURI ? siteURI.spec : "");
+      }
+      this._uri = null;
     }
 
     // folder picker
-    this._initFolderMenuList();
+    this._initFolderMenuList(container);
 
     // name picker
     this._initNamePicker();
 
     // description field
-    this._element("descriptionField").value =
-      PlacesUtils.getItemDescription(this._itemId);
-
+    this._initTextField("descriptionField", 
+                        PlacesUtils.getItemDescription(this._itemId));
+    
     this._showHideRows();
 
     // observe changes
     if (!this._observersAdded) {
       PlacesUtils.bookmarks.addObserver(this, false);
       window.addEventListener("unload", this, false);
       this._observersAdded = true;
     }
   },
 
+  _initTextField: function(aTextFieldId, aValue, aReadOnly) {
+    var field = this._element(aTextFieldId);
+    field.readOnly = aReadOnly !== undefined ? aReadOnly : this._readOnly;
+
+    if (field.value != aValue) {
+      field.value = aValue;
+
+      // clear the undo stack
+      var editor = field.editor;
+      if (editor)
+        editor.transactionManager.clear();
+    }
+  },
+
   /**
    * Appends a menu-item representing a bookmarks folder to a menu-popup.
    * @param aMenupopup
    *        The popup to which the menu-item should be added.
    * @param aFolderId
    *        The identifier of the bookmarks folder.
    * @return the new menu item.
    */
@@ -143,26 +194,25 @@ var gEditItemOverlay = {
     var folderTitle = PlacesUtils.bookmarks.getItemTitle(aFolderId)
     folderMenuItem.folderId = aFolderId;
     folderMenuItem.setAttribute("label", folderTitle);
     folderMenuItem.className = "menuitem-iconic folder-icon";
     aMenupopup.appendChild(folderMenuItem);
     return folderMenuItem;
   },
 
-  _initFolderMenuList: function EIO__initFolderMenuList() {
+  _initFolderMenuList: function EIO__initFolderMenuList(aSelectedFolder) {
     // clean up first
     var menupopup = this._folderMenuList.menupopup;
     while (menupopup.childNodes.length > 4)
       menupopup.removeChild(menupopup.lastChild);
 
-    var container = PlacesUtils.bookmarks.getFolderIdForItem(this._itemId);
-
     // only show "All Bookmarks" if the url isn't bookmarked somewhere else
-    this._element("unfiledRootItem").hidden = container != PlacesUtils.unfiledRootId;
+    this._element("unfiledRootItem").hidden =
+      aSelectedFolder != PlacesUtils.unfiledRootId;
 
     // List of recently used folders:
     var annos = PlacesUtils.annotations;
     var folderIds = annos.getItemsWithAnnotation(LAST_USED_ANNO, { });
 
     /**
      * The value of the LAST_USED_ANNO annotation is the time (in the form of
      * Date.getTime) at which the folder has been last used.
@@ -184,21 +234,22 @@ var gEditItemOverlay = {
       return 0;
     });
 
     var numberOfItems = Math.min(MAX_FOLDER_ITEM_IN_MENU_LIST, folders.length);
     for (i=0; i < numberOfItems; i++) {
       this._appendFolderItemToMenupopup(menupopup, folders[i].folderId);
     }
 
-    var defaultItem = this._getFolderMenuItem(container, true);
+    var defaultItem = this._getFolderMenuItem(aSelectedFolder, true);
     this._folderMenuList.selectedItem = defaultItem;
 
     // Hide the folders-separator if no folder is annotated as recently-used
     this._element("foldersSeparator").hidden = (menupopup.childNodes.length <= 4);
+    this._folderMenuList.disabled = this._readOnly;
   },
 
   QueryInterface: function EIO_QueryInterface(aIID) {
     if (aIID.equals(Ci.nsIMicrosummaryObserver) ||
         aIID.equals(Ci.nsIDOMEventListener) ||
         aIID.equals(Ci.nsINavBookmarkObserver) ||
         aIID.eqauls(Ci.nsISupports))
       return this;
@@ -260,17 +311,18 @@ var gEditItemOverlay = {
 
     if (this._microsummaries) {
       this._microsummaries.removeObserver(this);
       this._microsummaries = null;
     }
 
     var itemToSelect = userEnteredNameField;
     try {
-      if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK)
+      if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK &&
+          !this._readOnly)
         this._microsummaries = this._mss.getMicrosummaries(this._uri, -1);
     }
     catch(ex) {
       // getMicrosummaries will throw an exception in at least two cases:
       // 1. the bookmarked URI contains a scheme that the service won't
       //    download for security reasons (currently it only handles http,
       //    https, and file);
       // 2. the page to which the URI refers isn't HTML or XML (the only two
@@ -298,16 +350,22 @@ var gEditItemOverlay = {
     }
 
     if (namePicker.selectedItem == itemToSelect)
       namePicker.value = itemToSelect.label;
     else
       namePicker.selectedItem = itemToSelect;
 
     namePicker.setAttribute("droppable", droppable);
+    namePicker.readOnly = this._readOnly;
+
+    // clear the undo stack
+    var editor = namePicker.editor;
+    if (editor)
+      editor.transactionManager.clear();
   },
 
   // nsIMicrosummaryObserver
   onContentLoaded: function EIO_onContentLoaded(aMicrosummary) {
     var namePicker = this._element("namePicker");
     var childNodes = namePicker.menupopup.childNodes;
 
     // 0: user-entered item; 1: separator
@@ -450,16 +508,62 @@ var gEditItemOverlay = {
     catch(ex) { return; }
 
     if (!this._uri.equals(uri)) {
       var txn = PlacesUtils.ptm.editBookmarkURI(this._itemId, uri);
       PlacesUtils.ptm.commitTransaction(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.commitTransaction(txn);
+    }
+  },
+
+  onFeedLocationFieldBlur: function EIO_onFeedLocationFieldBlur() {
+    // XXXmano: uri fixup
+    var uri;
+    try {
+      uri = IO.newURI(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.commitTransaction(txn);
+    }
+  },
+
+  onSiteLocationFieldBlur: function EIO_onSiteLocationFieldBlur() {
+    // XXXmano: uri fixup
+    var uri = null;
+    try {
+      uri = IO.newURI(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.commitTransaction(txn);
+    }
+  },
+
+  onLoadInSidebarCheckboxCommand:
+  function EIO_onLoadInSidebarCheckboxCommand() {
+    var loadInSidebarChecked = this._element("loadInSidebarCheckbox").checked;
+    var txn = PlacesUtils.ptm.setLoadInSidebar(this._itemId,
+                                               loadInSidebarChecked);
+    PlacesUtils.ptm.commitTransaction(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;
     }
@@ -540,17 +644,17 @@ var gEditItemOverlay = {
 
       // Mark the containing folder as recently-used if it isn't the
       // "All Bookmarks" root
       if (container != PlacesUtils.unfiledRootId)
         this._markFolderAsRecentlyUsed(container);
     }
 
     // Update folder-tree selection
-    if (isElementVisible(this._folderTree)) {
+    if (!this._folderTree.collapsed) {
       var selectedNode = this._folderTree.selectedNode;
       if (!selectedNode || selectedNode.itemId != container)
         this._folderTree.selectFolders([container]);
     }
   },
 
   onFolderTreeSelect: function EIO_onFolderTreeSelect() {
     var selectedNode = this._folderTree.selectedNode;
@@ -593,33 +697,33 @@ var gEditItemOverlay = {
 
       tagsSelector.appendChild(elt);
     }
   },
 
   toggleTagsSelector: function EIO_toggleTagsSelector() {
     var tagsSelector = this._element("tagsSelector");
     var expander = this._element("tagsSelectorExpander");
-    if (!isElementVisible(tagsSelector)) {
+    if (tagsSelector.collapsed) {
       expander.className = "expander-up";
       expander.setAttribute("tooltiptext",
                             expander.getAttribute("tooltiptextup"));
 
       this._rebuildTagsSelectorList();
 
       // This is a no-op if we've added the listener.
       tagsSelector.addEventListener("CheckboxStateChange", this, false);
+      tagsSelector.collapsed = false;
     }
     else {
       expander.className = "expander-down";
       expander.setAttribute("tooltiptext",
                             expander.getAttribute("tooltiptextdown"));
+      tagsSelector.collapsed = true;
     }
-
-    tagsSelector.collapsed = !tagsSelector.collapsed;
   },
 
   _getTagsArrayFromTagField: function EIO__getTagsArrayFromTagField() {
     // we don't require the leading space (after each comma)
     var tags = this._element("tagsField").value.split(",");
     for (var i=0; i < tags.length; i++) {
       // remove trailing and leading spaces
       tags[i] = tags[i].replace(/^\s+/, "").replace(/\s+$/, "");
@@ -665,36 +769,63 @@ var gEditItemOverlay = {
     switch (aProperty) {
     case "title":
       if (PlacesUtils.annotations.itemHasAnnotation(this._itemId,
                                                     STATIC_TITLE_ANNO))
         return;  // onContentLoaded updates microsummary-items
 
       var userEnteredNameField = this._element("userEnteredName");
       if (userEnteredNameField.value != aValue) {
-          userEnteredNameField.value = aValue;
+        userEnteredNameField.value = aValue;
         var namePicker = this._element("namePicker");
-        if (namePicker.selectedItem == userEnteredNameField)
+        if (namePicker.selectedItem == userEnteredNameField) {
           namePicker.label = aValue;
+
+          // clear undo stack
+          namePicker.editor.transactionManager.clear();
+        }
       }
       break;
     case "uri":
       var locationField = this._element("locationField");
       if (locationField.value != aValue) {
-        locationField.value = aValue;
         this._uri = IO.newURI(aValue);
+        this._initTextField("locationField", this._uri.spec);
         this._initNamePicker(); // for microsummaries
-        this._element("tagsField").value =
-          PlacesUtils.tagging.getTagsForURI(this._uri).join(", ");
+        this._initTextField("tagsField",
+                             PlacesUtils.tagging
+                                        .getTagsForURI(this._uri).join(", "),
+                            false);
         this._rebuildTagsSelectorList();
       }
       break;
+    case "keyword":
+      this._initTextField("keywordField",
+                          PlacesUtils.bookmarks
+                                     .getKeywordForBookmark(this._itemId));
+      break;
     case DESCRIPTION_ANNO:
-      this._element("descriptionField").value =
-        PlacesUtils.annotations.getItemDescription(this._itemId);
+      this._initTextField("descriptionField",
+                          PlacesUtils.getItemDescription(this._itemId));
+      break;
+    case LOAD_IN_SIDEBAR_ANNO:
+      this._element("loadInSidebarCheckbox").checked =
+        PlacesUtils.annotations.itemHasAnnotation(this._itemId,
+                                                  LOAD_IN_SIDEBAR_ANNO);
+      break;
+    case LMANNO_FEEDURI:
+      var feedURISpec = PlacesUtils.livemarks.getFeedURI(this._itemId).spec;
+      this._initTextField("feedLocationField", feedURISpec);
+      break;
+    case LMANNO_SITEURI:
+      var siteURISpec = "";
+      var siteURI = PlacesUtils.livemarks.getSiteURI(this._itemId);
+      if (siteURI)
+        siteURISpec = siteURI.spec;
+      this._initTextField("siteLocationField", siteURISpec);
       break;
     }
   },
 
   onItemMoved: function EIO_onItemMoved(aItemId, aOldParent, aOldIndex,
                                         aNewParent, aNewIndex) {
     if (aItemId != this._itemId ||
         aNewParent == this._getFolderIdFromMenuList())
--- a/browser/components/places/content/editBookmarkOverlay.xul
+++ b/browser/components/places/content/editBookmarkOverlay.xul
@@ -44,55 +44,81 @@
 
 <overlay id="editBookmarkOverlay"
          xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <script type="application/javascript"
           src="chrome://browser/content/places/editBookmarkOverlay.js"/>
 
   <vbox id="editBookmarkPanelContent">
+    <broadcaster id="paneElementsBroadcaster"/>
+
     <grid id="editBookmarkPanelGrid" flex="1">
       <columns>
         <column/>
         <column flex="1"/>
       </columns>
       <rows>
         <row align="center" id="editBMPanel_nameRow">
           <label value="&editBookmarkOverlay.name.label;"
-                 contorl="editBMPanel_namePicker"/>
+                 control="editBMPanel_namePicker"
+                 observes="paneElementsBroadcaster"/>
           <menulist id="editBMPanel_namePicker"
                     flex="1"
                     editable="true"
                     droppable="false"
                     oninput="gEditItemOverlay.onNamePickerInput();"
                     onblur="gEditItemOverlay.onNamePickerChange();"
-                    oncommand="gEditItemOverlay.onNamePickerChange();">
+                    oncommand="gEditItemOverlay.onNamePickerChange();"
+                    observes="paneElementsBroadcaster">
             <menupopup>
               <menuitem id="editBMPanel_userEnteredName"/>
               <menuitem disabled="true">
                 <menuseparator flex="1"/>
                 <label value="&editBookmarkOverlay.liveTitlesSeparator.label;"/>
               </menuitem>
             </menupopup>
           </menulist>
         </row>
 
         <row align="center" id="editBMPanel_locationRow">
           <label value="&editBookmarkOverlay.location.label;"
-                 contorl="editBMPanel_locationField"/>
+                 control="editBMPanel_locationField"
+                 observes="paneElementsBroadcaster"/>
           <textbox id="editBMPanel_locationField"
-                   onblur="gEditItemOverlay.onLocationFieldBlur();"/>
+                   onblur="gEditItemOverlay.onLocationFieldBlur();"
+                   observes="paneElementsBroadcaster"/>
+        </row>
+
+        <row align="center" id="editBMPanel_feedLocationRow">
+          <label value="&editBookmarkOverlay.feedLocation.label;"
+                 control="editBMPanel_feedLocationField"
+                 observes="paneElementsBroadcaster"/>
+          <textbox id="editBMPanel_feedLocationField"
+                   onblur="gEditItemOverlay.onFeedLocationFieldBlur();"
+                   observes="paneElementsBroadcaster"/>
+        </row>
+
+        <row align="center" id="editBMPanel_siteLocationRow">
+          <label value="&editBookmarkOverlay.siteLocation.label;"
+                 control="editBMPanel_siteLocationField"
+                 observes="paneElementsBroadcaster"/>
+          <textbox id="editBMPanel_siteLocationField"
+                   onblur="gEditItemOverlay.onSiteLocationFieldBlur();"
+                   observes="paneElementsBroadcaster"/>
         </row>
 
         <row align="center" id="editBMPanel_folderRow">
           <label value="&editBookmarkOverlay.folder.label;"
-                 control="editBMPanel_folderMenuList"/>
+                 control="editBMPanel_folderMenuList"
+                 observes="paneElementsBroadcaster"/>
           <menulist id="editBMPanel_folderMenuList"
                     class="folder-icon"
-                    oncommand="gEditItemOverlay.onFolderMenuListCommand();">
+                    oncommand="gEditItemOverlay.onFolderMenuListCommand();"
+                    observes="paneElementsBroadcaster">
             <menupopup>
               <!-- Static item for special folders -->
               <menuitem id="editBMPanel_unfiledRootItem"
                         label="&editBookmarkOverlay.allBookmarksFolderItem.label;"
                         class="menuitem-iconic folder-icon"/>
               <menuitem id="editBMPanel_bmRootItem"
                         label="&editBookmarkOverlay.bookmarksMenuFolderItem.label;"
                         class="menuitem-iconic folder-icon"/>
@@ -102,51 +128,74 @@
               <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();"/>
+                  oncommand="gEditItemOverlay.toggleFolderTreeVisibility();"
+                  observes="paneElementsBroadcaster"/>
         </row>
 
         <tree id="editBMPanel_folderTree"
               class="placesTree"
               type="places"
               height="150"
               collapsed="true"
               onselect="gEditItemOverlay.onFolderTreeSelect();"
               showRoot="true"
               place="place:folder=2&amp;group=3&amp;excludeItems=1&amp;excludeQueries=1&amp;excludeReadOnlyFolders=1"
-              hidecolumnpicker="true">
+              hidecolumnpicker="true"
+              observes="paneElementsBroadcaster">
           <treecols>
             <treecol anonid="title" flex="1" primary="true" hideheader="true"/>
           </treecols>
           <treechildren flex="1"/>
         </tree>
 
         <row align="center" id="editBMPanel_tagsRow">
           <label value="&editBookmarkOverlay.tags.label;"
-                 control="tagsField"/>
+                 control="editBMPanel_tagsField"
+                 observes="paneElementsBroadcaster"/>
           <textbox id="editBMPanel_tagsField"
-                   onblur="gEditItemOverlay.onTagsFieldBlur();"/>
+                   onblur="gEditItemOverlay.onTagsFieldBlur();"
+                   observes="paneElementsBroadcaster"/>
           <button id="editBMPanel_tagsSelectorExpander"
                   class="expander-down"
                   tooltiptext="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
                   tooltiptextdown="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
                   tooltiptextup="&editBookmarkOverlay.expanderUp.tooltip;"
-                  oncommand="gEditItemOverlay.toggleTagsSelector();"/>
+                  oncommand="gEditItemOverlay.toggleTagsSelector();"
+                  observes="paneElementsBroadcaster"/>
         </row>
 
-        <listbox id="editBMPanel_tagsSelector" height="150" collapsed="true"/>
+        <listbox id="editBMPanel_tagsSelector"
+                 height="150" collapsed="true"
+                 observes="paneElementsBroadcaster"/>
 
-        <row id="editBMPanel_descriptionRow" align="center">
+        <row id="editBMPanel_keywordRow">
+          <label value="&editBookmarkOverlay.keyword.label;"
+                 control="editBMPanel_keywordField"
+                 observes="paneElementsBroadcaster"/>
+          <textbox id="editBMPanel_keywordField"
+                   onblur="gEditItemOverlay.onKeywordFieldBlur();"
+                   observes="paneElementsBroadcaster"/>
+        </row>
+
+        <row id="editBMPanel_descriptionRow">
           <label value="&editBookmarkOverlay.description.label;"
-                 control="editBMPanel_descriptionField"/>
+                 control="editBMPanel_descriptionField"
+                 observes="paneElementsBroadcaster"/>
           <textbox id="editBMPanel_descriptionField"
-                   onblur="gEditItemOverlay.onDescriptionFieldBlur();"/>
+                   multiline="true"
+                   onblur="gEditItemOverlay.onDescriptionFieldBlur();"
+                   observes="paneElementsBroadcaster"/>
         </row>
+        <checkbox id="editBMPanel_loadInSidebarCheckbox"
+                  label="&editBookmarkOverlay.loadInSidebar.label;"
+                  oncommand="gEditItemOverlay.onLoadInSidebarCheckboxCommand();"
+                  observes="paneElementsBroadcaster"/>
       </rows>
     </grid>
   </vbox>
 </overlay>
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -252,16 +252,17 @@
             }
 #endif
             popup._containerNodesMap = this._containerNodesMap;
             this._containerNodesMap.push({ resultNode: child, domNode: popup });
           }
 
           if (element) {
             element.node = child;
+            element.node.viewIndex = 0;
             if (child.icon)
               element.setAttribute("image", child.icon.spec);
 
             if (before)
               this.insertBefore(element, before);
             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,
--- a/browser/components/places/content/moveBookmarks.xul
+++ b/browser/components/places/content/moveBookmarks.xul
@@ -56,31 +56,32 @@
         screenX="24"
         screenY="24"
         persist="screenX screenY width height">
 
   <script type="application/x-javascript"
           src="chrome://browser/content/places/moveBookmarks.js"/>
 
   <hbox flex="1">
-    <label id="movetolabel" value="&moveTo.label;"/>
+    <label id="movetolabel" value="&moveTo.label;" control="foldersTree"/>
     <hbox flex="1">
       <tree id="foldersTree"
             class="placesTree"
             flex="1"
             type="places"
             showRoot="true"
             seltype="single"
             place="place:folder=2&amp;group=3&amp;excludeItems=1&amp;excludeReadOnlyFolders=1" 
             hidecolumnpicker="true">
         <treecols>
           <treecol id="title" flex="1" primary="true" hideheader="true"/>
         </treecols>
         <treechildren id="placesListChildren" view="placesList" flex="1"/>
       </tree>
       <vbox>
-        <button label="&newFolderButton.label;"
+        <button id="newFolderButton"
+                label="&newFolderButton.label;"
                 accesskey="&newFolderButton.accesskey;"
                 oncommand="gMoveBookmarksDialog.newFolder();"/>
       </vbox>
     </hbox>
   </hbox>
 </dialog>
--- a/browser/components/places/content/organizer.css
+++ b/browser/components/places/content/organizer.css
@@ -22,8 +22,15 @@ button.commandButton {
 .textbox-input-closebutton {
   display: none;
 }
 
 #searchFilter[filtered="true"] .textbox-input-closebutton {
   display: -moz-box;
 }
 
+/* Edit Item Panel */
+
+#infoScrollbox[minimal="true"] #editBMPanel_descriptionRow,
+#infoScrollbox[minimal="true"] #editBMPanel_loadInSidebarCheckbox,
+#infoScrollbox[minimal="true"] #editBMPanel_keywordRow {
+  visibility: collapse;
+}
--- a/browser/components/places/content/places.css
+++ b/browser/components/places/content/places.css
@@ -5,9 +5,8 @@ tree[type="places"] {
 hbox[type="places"] {
   -moz-binding: url("chrome://browser/content/places/toolbar.xml#places-bar");
   overflow: hidden;
 }
 
 menupopup[type="places"] {
   -moz-binding: url("chrome://browser/content/places/menu.xml#places-menupopup");
 }
-
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -35,18 +35,18 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 /**
- * Selects a place URI in the places list. 
- * This function is global so it can be easily accessed by openers. 
+ * Selects a place URI in the places list.
+ * This function is global so it can be easily accessed by openers.
  * @param   placeURI
  *          A place: URI string to select
  */
 function selectPlaceURI(placeURI) {
   PlacesOrganizer._places.selectPlaceURI(placeURI);
 }
 
 var PlacesOrganizer = {
@@ -54,17 +54,17 @@ var PlacesOrganizer = {
   _content: null,
 
   init: function PO_init() {
     var self = this;
     // on timeout because of the corresponding setTimeout()
     // in the places tree binding's constructor
     setTimeout(function() { self._init(); }, 0);
   },
-  
+
   _init: function PO__init() {
     this._places = document.getElementById("placesList");
     this._content = document.getElementById("placeContent");
 
     OptionsFilter.init(Groupers);
     Groupers.init();
 
     // Select the specified place in the places list.
@@ -80,16 +80,29 @@ var PlacesOrganizer = {
 
     this._content.focus();
 
     // Set up the search UI.
     PlacesSearchBox.init();
 
     // Set up the advanced query builder UI
     PlacesQueryBuilder.init();
+
+#ifdef XP_MACOSX
+    // 1. Make Edit->Find focus the organizer search field
+    var findCommand = document.getElementById("cmd_find");
+    findCommand.setAttribute("oncommand", "PlacesSearchBox.findCurrent();");
+    findCommand.removeAttribute("disabled");
+
+    // 2. Disable some keybindings from browser.xul
+    var elements = ["cmd_handleBackspace", "cmd_handleShiftBackspace"];
+    for (var i=0; i < elements.length; i++) {
+      document.getElementById(elements[i]).setAttribute("disabled", "true");
+    }
+#endif
   },
 
   destroy: function PO_destroy() {
     OptionsFilter.destroy();
   },
 
   _location: null,
   get location() {
@@ -101,16 +114,17 @@ var PlacesOrganizer = {
 
     if (!aLocation)
       return aLocation;
 
     if (this.location)
       this._backHistory.unshift(this.location);
 
     this._content.place = this._location = aLocation;
+    this.onContentTreeSelect();
 
     // update navigation commands
     if (this._backHistory.length == 0)
       document.getElementById("OrganizerCommand:Back").setAttribute("disabled", true);
     else
       document.getElementById("OrganizerCommand:Back").removeAttribute("disabled");
     if (this._forwardHistory.length == 0)
       document.getElementById("OrganizerCommand:Forward").setAttribute("disabled", true);
@@ -133,37 +147,33 @@ var PlacesOrganizer = {
     this.location = historyEntry;
   },
 
   HEADER_TYPE_SHOWING: 1,
   HEADER_TYPE_SEARCH: 2,
   HEADER_TYPE_ADVANCED_SEARCH: 3,
 
   /**
-   * Updates the text shown in the heading banner above the content view. 
+   * Updates the text shown in the heading banner above the content view.
    * @param   type
    *          The type of information being shown - normal (built-in history or
    *          other query, bookmark folder), search results from the toolbar
    *          search box, or advanced search.
    * @param   text
    *          The text (if any) to display
    */
   setHeaderText: function PO_setHeaderText(type, text) {
     NS_ASSERT(type == 1 || type == 2 || type == 3, "Invalid Header Type");
 
     var prefix = document.getElementById("showingPrefix");
     prefix.setAttribute("value",
                         PlacesUtils.getString("headerTextPrefix" + type));
 
     var contentTitle = document.getElementById("contentTitle");
     contentTitle.setAttribute("value", text);
-    
-    // Hide the advanced search controls when the user hasn't searched
-    var searchModifiers = document.getElementById("searchModifiers");
-    searchModifiers.hidden = type == this.HEADER_TYPE_SHOWING;
   },
 
   onPlaceURIKeypress: function PO_onPlaceURIKeypress(aEvent) {
     var keyCode = aEvent.keyCode;
     if (keyCode == KeyEvent.DOM_VK_RETURN)
       this.loadPlaceURI();
     else if (keyCode == KeyEvent.DOM_VK_ESCAPE) {
       event.target.value = "";
@@ -177,43 +187,42 @@ var PlacesOrganizer = {
   toggleDebugPanel: function PO_toggleDebugPanel() {
     var dp = document.getElementById("debugPanel");
     dp.hidden = !dp.hidden;
     if (!dp.hidden)
       document.getElementById("placeURI").focus();
   },
 
   /**
-   * Loads the place URI entered in the debug 
+   * Loads the place URI entered in the debug
    */
   loadPlaceURI: function PO_loadPlaceURI() {
-
     // clear forward history
     this._forwardHistory.splice(0);
 
     var placeURI = document.getElementById("placeURI");
 
     var queriesRef = { }, optionsRef = { };
-    PlacesUtils.history.queryStringToQueries(placeURI.value, 
+    PlacesUtils.history.queryStringToQueries(placeURI.value,
                                              queriesRef, { }, optionsRef);
-    
+
     // for debug panel
     var autoFilterResults = document.getElementById("autoFilterResults");
     if (autoFilterResults.checked) {
-      var options = 
+      var options =
         OptionsFilter.filter(queriesRef.value, optionsRef.value, null);
     }
     else
       options = optionsRef.value;
 
     this.location =
       PlacesUtils.history.queriesToQueryString(queriesRef.value,
                                                queriesRef.value.length,
                                                options);
-    
+
     placeURI.value = this.location;
 
     this.setHeaderText(this.HEADER_TYPE_SHOWING, "Debug results for: " + placeURI.value);
 
     this.updateLoadedURI();
 
     placeURI.focus();
   },
@@ -222,17 +231,17 @@ var PlacesOrganizer = {
    * Updates the URI displayed in the debug panel.
    */
   updateLoadedURI: function PO_updateLoadedURI() {
     var queryNode = asQuery(this._content.getResult().root);
     var queries = queryNode.getQueries({});
     var options = queryNode.queryOptions;
     var loadedURI = document.getElementById("loadedURI");
     loadedURI.value =
-      PlacesUtils.history.queriesToQueryString(queries, queries.length, 
+      PlacesUtils.history.queriesToQueryString(queries, queries.length,
                                                options);
   },
 
   /**
    * Called when a place folder is selected in the left pane.
    * @param   resetSearchBox
    *          true if the search box should also be reset, false if it should
    *          be left alone.
@@ -249,19 +258,19 @@ var PlacesOrganizer = {
     var options = node.queryOptions.clone();
     options.excludeItems = false;
 
     // clear forward history
     this._forwardHistory.splice(0);
 
     // update location
     this.location = PlacesUtils.history.queriesToQueryString(queries, queries.length, options);
-   
-    // Make sure the query builder is hidden.
-    PlacesQueryBuilder.hide();
+
+    // Make sure the search UI is hidden.
+    PlacesSearchBox.hideSearchUI();
     if (resetSearchBox) {
       var searchFilter = document.getElementById("searchFilter");
       searchFilter.reset();
     }
 
     this.setHeaderText(this.HEADER_TYPE_SHOWING, node.title);
 
     this.updateLoadedURI();
@@ -272,53 +281,67 @@ var PlacesOrganizer = {
     var findCommand = document.getElementById("OrganizerCommand_find:current");
     var findLabel = PlacesUtils.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 
-   * any special action, since they're related to selection. 
+   * 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
+   * any special action, since they're related to selection.
    * @param   aEvent
    *          The mouse event.
    */
-  onTreeClick: function PO_onTreeClicked(aEvent) {
+  onTreeClick: function PO_onTreeClick(aEvent) {
     var currentView = aEvent.currentTarget;
     var controller = currentView.controller;
 
-    // If the user clicked on a tree column header, update the sorting 
+    // If the user clicked on a tree column header, update the sorting
     // preferences to reflect their choices.
     // XXXmano: should be done in tree.xml
     if (aEvent.target.localName == "treecol") {
       OptionsFilter.update(this._content.getResult());
       return;
     }
     if (currentView.hasSingleSelection && aEvent.button == 1) {
       if (PlacesUtils.nodeIsURI(currentView.selectedNode))
         controller.openSelectedNodeWithEvent(aEvent);
       else if (PlacesUtils.nodeIsContainer(currentView.selectedNode)) {
-        // The command execution function will take care of seeing the 
-        // selection is a folder/container and loading its contents in 
-        // tabs for us. 
+        // The command execution function will take care of seeing the
+        // selection is a folder/container and loading its contents in
+        // tabs for us.
         controller.openLinksInTabs();
       }
     }
   },
 
+  onTreeDblClick: function PO_onTreeDblClick(aEvent) {
+    if (aEvent.button != 0 || !this._content.hasSingleSelection ||
+        aEvent.originalTarget.localName != "treechildren")
+      return;
+
+    var row = { }, col = { }, obj = { };
+    this._content.treeBoxObject.getCellAt(aEvent.clientX, aEvent.clientY, row,
+                                         col, obj);
+    if (row.value == -1  || obj.value == "twisty")
+      return;
+
+    this._content.controller.openSelectedNodeWithEvent(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;
   },
-  
+
   /**
    * Show the migration wizard for importing from a file.
    */
   importBookmarks: function PO_import() {
     // XXX: ifdef it to be non-modal (non-"sheet") on mac (see bug 259039)
     var features = "modal,centerscreen,chrome,resizable=no";
 
     // The migrator window will set this to true when it closes, if the user
@@ -374,19 +397,19 @@ var PlacesOrganizer = {
 
     // remove existing menu items
     // last item is the restoreFromFile item
     while (restorePopup.childNodes.length > 1)
       restorePopup.removeChild(restorePopup.firstChild);
 
     // get bookmarks backup dir
     var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
-                     getService(Ci.nsIProperties);
+                 getService(Ci.nsIProperties);
     var bookmarksBackupDir = dirSvc.get("ProfD", Ci.nsIFile);
-    bookmarksBackupDir.append("bookmarkbackups"); 
+    bookmarksBackupDir.append("bookmarkbackups");
     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);
@@ -419,211 +442,371 @@ var PlacesOrganizer = {
                               document.getElementById("restoreFromFile"));
   },
 
   /**
    * Called when a menuitem is selected from the restore menu.
    */
   onRestoreMenuItemClick: function PO_onRestoreMenuItemClick(aMenuItem) {
     var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
-                     getService(Ci.nsIProperties);
+                 getService(Ci.nsIProperties);
     var bookmarksFile = dirSvc.get("ProfD", Ci.nsIFile);
-    bookmarksFile.append("bookmarkbackups"); 
+    bookmarksFile.append("bookmarkbackups");
     bookmarksFile.append(aMenuItem.getAttribute("value"));
     if (!bookmarksFile.exists())
       return;
 
     var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].
-      getService(Ci.nsIPromptService);
+                  getService(Ci.nsIPromptService);
     if (!prompts.confirm(null,
                          PlacesUtils.getString("bookmarksRestoreAlertTitle"),
                          PlacesUtils.getString("bookmarksRestoreAlert")))
       return;
 
     var ieSvc = Cc["@mozilla.org/browser/places/import-export-service;1"].
-      getService(Ci.nsIPlacesImportExportService);
+                getService(Ci.nsIPlacesImportExportService);
     ieSvc.importHTMLFromFile(bookmarksFile, true);
   },
 
   /**
    * Backup bookmarks to desktop, auto-generate a filename with a date
    */
   backupBookmarks: function PO_backupBookmarks() {
     var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
     fp.init(window, PlacesUtils.getString("bookmarksBackupTitle"),
             Ci.nsIFilePicker.modeSave);
     fp.appendFilters(Ci.nsIFilePicker.filterHTML);
-  
+
     var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
-      getService(Ci.nsIProperties);
+                 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);
+                  getService(Ci.nsIPlacesImportExportService);
       ieSvc.exportHTMLToFile(fp.file);
     }
   },
 
   /**
    * 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);
+                  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);
+                 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);
+                  getService(Ci.nsIPlacesImportExportService);
       ieSvc.importHTMLFromFile(fp.file, true);
     }
   },
 
+  _paneDisabled: false,
+  _setDetailsFieldsDisabledState:
+  function PO__setDetailsFieldsDisabledState(aDisabled) {
+    if (aDisabled) {
+      document.getElementById("paneElementsBroadcaster")
+              .setAttribute("disabled", "true");
+    }
+    else {
+      document.getElementById("paneElementsBroadcaster")
+              .removeAttribute("disabled");
+    }
+  },
+
+  _detectAndSetDetailsPaneMinimalState:
+  function PO__detectAndSetDetailsPaneMinimalState(aNode) {
+    /**
+     * The details of simple folder-items (as opposed to livemarks) or the
+     * of livemark-children are not likely to fill the scrollbox anyway,
+     * thus we remove the "More/Less" button and show all details.
+     *
+     * the wasminimal attribute here is used to persist the "more/less"
+     * state in a bookmark->folder->bookmark scenario.
+     */
+    var infoScrollbox = document.getElementById("infoScrollbox");
+    var scrollboxExpander = document.getElementById("infoScrollboxExpander");
+    if ((PlacesUtils.nodeIsFolder(aNode) &&
+         !PlacesUtils.nodeIsLivemarkContainer(aNode)) ||
+        PlacesUtils.nodeIsLivemarkItem(aNode)) {
+      if (infoScrollbox.getAttribute("minimal") == "true")
+        infoScrollbox.setAttribute("wasminimal", "true");
+      infoScrollbox.removeAttribute("minimal");
+      scrollboxExpander.hidden = true;
+    }
+    else {
+      if (infoScrollbox.getAttribute("wasminimal") == "true")
+        infoScrollbox.setAttribute("minimal", "true");
+      infoScrollbox.removeAttribute("wasminimal");
+      scrollboxExpander.hidden = false;
+    }
+  },
+
+  updateThumbnailProportions: function PO_updateThumbnailProportions() {
+    var previewBox = document.getElementById("previewBox");
+    var canvas = document.getElementById("itemThumbnail");
+    var height = previewBox.boxObject.height;
+    var width = height * (screen.width / screen.height);
+    canvas.width = width;
+    canvas.height = height;
+  },
+
   onContentTreeSelect: function PO_onContentTreeSelect() {
+    // If a textbox within a panel is focused, force-blur it so its contents
+    // are saved
+    if (gEditItemOverlay.itemId != -1) {
+      var focusedElement = document.commandDispatcher.focusedElement;
+      if (focusedElement instanceof HTMLInputElement &&
+          /^editBMPanel.*/.test(focusedElement.parentNode.parentNode.id))
+        focusedElement.blur();
+    }
+
     var contentTree = document.getElementById("placeContent");
-    var deck = document.getElementById("infoDeck");
-    this.updateStatusBarForView(contentTree);
-    if (contentTree.hasSingleSelection) {
-      var selectedNode = contentTree.selectedNode;
-      if (selectedNode.itemId != -1 &&
-          !PlacesUtils.nodeIsSeparator(selectedNode)) {
-        gEditItemOverlay.initPanel(selectedNode.itemId,
-                                   { hiddenRows: ["folderPicker"] });
-        deck.selectedIndex = 1;
-        return;
+    var detailsDeck = document.getElementById("detailsDeck");
+    if (contentTree.hasSelection) {
+      detailsDeck.selectedIndex = 1;
+      if (contentTree.hasSingleSelection) {
+        var selectedNode = contentTree.selectedNode;
+        if (selectedNode.itemId != -1 &&
+            !PlacesUtils.nodeIsSeparator(selectedNode)) {
+          if (this._paneDisabled) {
+            this._setDetailsFieldsDisabledState(false);
+            this._paneDisabled = false;
+          }
+
+          gEditItemOverlay.initPanel(selectedNode.itemId,
+                                     { hiddenRows: ["folderPicker"] });
+
+          this._detectAndSetDetailsPaneMinimalState(selectedNode);
+          this.updateThumbnailProportions();
+          this._updateThumbnail();
+          return;
+        }
       }
     }
-    gEditItemOverlay.uninitPanel();
-    deck.selectedIndex = 0;
+    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");
+      }
+      else {
+        selectItemDesc.hidden = false;
+        if (rowCount == 1)
+          itemsCountLabel.value = PlacesUtils.getString("detailsPane.oneItem");
+        else {
+          itemsCountLabel.value =
+            PlacesUtils.getFormattedString("detailsPane.multipleItems",
+                                           [rowCount]);
+        }
+      }
+
+      this.updateThumbnailProportions();
+      this._updateThumbnail();
+    }
+
+    // Nothing to do if the pane was already disabled
+    if (!this._paneDisabled) {
+      gEditItemOverlay.uninitPanel();
+      this._setDetailsFieldsDisabledState(true);
+      this._paneDisabled = true;
+    }
+  },
+
+  _updateThumbnail: function PO__updateThumbnail() {
+    var bo = document.getElementById("previewBox").boxObject;
+    var width  = bo.width;
+    var height = bo.height;
+
+    var canvas = document.getElementById("itemThumbnail");
+    var ctx = canvas.getContext('2d');
+    var notAvailableText = canvas.getAttribute("notavailabletext");
+    ctx.save();
+    ctx.fillStyle = "-moz-Dialog";
+    ctx.fillRect(0, 0, width, height);
+    ctx.translate(width/2, height/2);
+
+    ctx.fillStyle = "GrayText";
+    ctx.mozTextStyle = "12pt sans serif";
+    var len = ctx.mozMeasureText(notAvailableText);
+    ctx.translate(-len/2,0);
+    ctx.mozDrawText(notAvailableText);
+    ctx.restore();
+  },
+
+  toggleAdditionalInfoFields: function PO_toggleAdditionalInfoFields() {
+    var infoScrollbox = document.getElementById("infoScrollbox");
+    var scrollboxExpander = document.getElementById("infoScrollboxExpander");
+    if (infoScrollbox.getAttribute("minimal") == "true") {
+      infoScrollbox.removeAttribute("minimal");
+      scrollboxExpander.label = scrollboxExpander.getAttribute("lesslabel");
+    }
+    else {
+      infoScrollbox.setAttribute("minimal", "true");
+      scrollboxExpander.label = scrollboxExpander.getAttribute("morelabel");
+    }
   },
 
   /**
    * Save the current search (or advanced query) to the bookmarks root.
    */
-  saveSearch: function PP_saveSearch() {
+  saveSearch: function PO_saveSearch() {
     // Get the place: uri for the query.
     // If the advanced query builder is showing, use that.
     var queries = [];
     var options = this.getCurrentOptions();
     options.excludeQueries = true;
-    var advancedSearch = document.getElementById("advancedSearch");
-    if (!advancedSearch.collapsed) {
+    var searchUI = document.getElementById("searchModifiers");
+    if (!searchUI.hidden)
       queries = PlacesQueryBuilder.queries;
-    }
-    // If not, use the value of the search box.
     else if (PlacesSearchBox.value && PlacesSearchBox.value.length > 0) {
+      // If not, use the value of the search box.
       var query = PlacesUtils.history.getNewQuery();
       query.searchTerms = PlacesSearchBox.value;
       queries.push(query);
     }
-    // if there is no query, do nothing.
     else {
+      // if there is no query, do nothing.
       // XXX should probably have a dialog here to explain that the user needs to search first.
      return;
     }
     var placeSpec = PlacesUtils.history.queriesToQueryString(queries,
                                                              queries.length,
                                                              options);
     var placeURI = IO.newURI(placeSpec);
 
     // 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 prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].
-                    getService(Ci.nsIPromptService);
+                  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 places root.
-    var txn = PlacesUtils.ptm.createItem(placeURI, PlacesUtils.bookmarks.bookmarksRoot, PlacesUtils.bookmarks.DEFAULT_INDEX, input.value);
+    // Add the place: uri as a bookmark under the bookmarks root.
+    var txn = PlacesUtils.ptm.createItem(placeURI,
+                                         PlacesUtils.bookmarksRootId,
+                                         PlacesUtils.bookmarks.DEFAULT_INDEX,
+                                         input.value);
     PlacesUtils.ptm.commitTransaction(txn);
   }
 };
 
 /**
- * A set of utilities relating to search within Bookmarks and History. 
+ * A set of utilities relating to search within Bookmarks and History.
  */
 var PlacesSearchBox = {
 
   /**
    * The Search text field
    */
   get searchFilter() {
     return document.getElementById("searchFilter");
   },
 
   /**
+   * Folders to include when searching.
+   */
+  _folders: [],
+  get folders() {
+    if (this._folders.length == 0)
+      this._folders.push(PlacesUtils.bookmarksRootId, PlacesUtils.unfiledRootId);
+    return this._folders;
+  },
+  set folders(aFolders) {
+    this._folders = aFolders;
+    return aFolders;
+  },
+
+  /**
    * Run a search for the specified text, over the collection specified by
    * the dropdown arrow. The default is all bookmarks, but can be
-   * localized to the active collection. 
+   * localized to the active collection.
    * @param   filterString
-   *          The text to search for. 
+   *          The text to search for.
    */
   search: function PSB_search(filterString) {
-    // for non-"bookmarks" collections, 
-    // do not search for "" since it will match all history. Assume if the user
-    // deleted everything that they want to type something else and don't 
-    // update the view.
-    if (PlacesSearchBox.filterCollection != "bookmarks" &&
-        (filterString == "" || this.searchFilter.hasAttribute("empty")))
+    var PO = PlacesOrganizer;
+    // If the user empties the search box manually, reset it and load all
+    // contents of the current scope.
+    // XXX this might be to jumpy, maybe should search for "", so results
+    // are ungrouped, and search box not reset
+    if ((filterString == "" || this.searchFilter.hasAttribute("empty"))) {
+      PO.onPlaceSelected(false);
       return;
+    }
 
-    var content = PlacesOrganizer._content;
-    var PO = PlacesOrganizer;
+    var currentOptions = PO.getCurrentOptions();
+    var content = PO._content;
 
     switch (PlacesSearchBox.filterCollection) {
     case "collection":
-      var folderId = PlacesOrganizer._places.selectedNode.itemId;
-      content.applyFilter(filterString, true, [folderId], OptionsFilter);
-      PO.setHeaderText(PO.HEADER_TYPE_SEARCH, filterString);
+      content.applyFilter(filterString, true, this.folders, OptionsFilter);
+      // XXX changing the button text is badness
+      //var scopeBtn = document.getElementById("scopeBarFolder");
+      //scopeBtn.label = PlacesOrganizer._places.selectedNode.title;
       break;
     case "bookmarks":
-      if (filterString) {
-        content.applyFilter(filterString, true);
-        PO.setHeaderText(PO.HEADER_TYPE_SEARCH, filterString);
+      content.applyFilter(filterString, true,
+                          [PlacesUtils.bookmarksRootId,
+                           PlacesUtils.unfiledRootId]);
+      break;
+    case "history":
+      if (currentOptions.queryType != Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY) {
+        var query = PlacesUtils.history.getNewQuery();
+        query.searchTerms = filterString;
+        var options = currentOptions.clone();
+        options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY;
+        content.load([query],
+                     OptionsFilter.filter([query], options, null));
       }
       else
-        PlacesOrganizer.onPlaceSelected();
+        content.applyFilter(filterString, false, null, OptionsFilter);
       break;
     case "all":
       content.applyFilter(filterString, false, null, OptionsFilter);
-      PO.setHeaderText(PO.HEADER_TYPE_SEARCH, filterString);
       break;
     }
-    
+
+    PO.setHeaderText(PO.HEADER_TYPE_SEARCH, filterString);
+    PlacesSearchBox.showSearchUI();
     this.searchFilter.setAttribute("filtered", "true");
   },
 
   /**
    * Finds across all bookmarks
    */
   findAll: function PSB_findAll() {
     this.filterCollection = "all";
@@ -640,30 +823,31 @@ 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) {
     if (title) {
-      this.searchFilter.grayText = 
+      this.searchFilter.grayText =
         PlacesUtils.getFormattedString("searchCurrentDefault", [title]);
     }
     else
       this.searchFilter.grayText = PlacesUtils.getString("searchByDefault");
 
     this.syncGrayText();
   },
 
   /**
    * Updates the display with the current gray text.
    */
   syncGrayText: function PSB_syncGrayText() {
     this.searchFilter.value = this.searchFilter.grayText;
+    this.searchFilter.setAttribute("label", this.searchFilter.grayText);
   },
 
   /**
    * Gets/sets the active collection from the dropdown menu.
    */
   get filterCollection() {
     return this.searchFilter.getAttribute("collection");
   },
@@ -680,53 +864,66 @@ var PlacesSearchBox = {
 
   /**
    * Focus the search box
    */
   focus: function PSB_focus() {
     this.searchFilter.focus();
   },
 
-  /** 
-   * Set up the gray text in the search bar as the Places View loads. 
+  /**
+   * Set up the gray text in the search bar as the Places View loads.
    */
   init: function PSB_init() {
     var searchFilter = this.searchFilter;
     searchFilter.grayText = PlacesUtils.getString("searchByDefault");
+    searchFilter.setAttribute("label", searchFilter.grayText);
     searchFilter.reset();
   },
-  
+
   /**
-   * Gets or sets the text shown in the Places Search Box 
+   * Gets or sets the text shown in the Places Search Box
    */
   get value() {
     return this.searchFilter.value;
   },
   set value(value) {
     return this.searchFilter.value = value;
+  },
+
+  showSearchUI: function PSB_showSearchUI() {
+    // Hide the advanced search controls when the user hasn't searched
+    var searchModifiers = document.getElementById("searchModifiers");
+    searchModifiers.hidden = false;
+
+    // if new search, open builder with pre-populated text row
+    if (PlacesQueryBuilder.numRows == 0)
+      document.getElementById("OrganizerCommand_search:moreCriteria").doCommand();
+  },
+
+  hideSearchUI: function PSB_hideSearchUI() {
+    var searchModifiers = document.getElementById("searchModifiers");
+    searchModifiers.hidden = true;
   }
 };
 
 /**
  * Functions and data for advanced query builder
  */
 var PlacesQueryBuilder = {
 
   queries: [],
   queryOptions: null,
 
-  _numRows: 0,
+  numRows: 0,
 
   /**
-   * The maximum number of terms that can be added. 
-   * XXXben - this should be generated dynamically based on the contents of a 
-   *          list of terms searchable through this widget, rather than being
-   *          a hard coded number.
+   * The maximum number of terms that can be added.
    */
-  _maxRows: 3,
+  _maxRows: null,
 
   _keywordSearch: {
     advancedSearch_N_Subject: "advancedSearch_N_SubjectKeyword",
     advancedSearch_N_LocationMenulist: false,
     advancedSearch_N_TimeMenulist: false,
     advancedSearch_N_Textbox: "",
     advancedSearch_N_TimePicker: false,
     advancedSearch_N_TimeMenulist2: false
@@ -760,49 +957,68 @@ var PlacesQueryBuilder = {
 
   init: function PQB_init() {
     // Initialize advanced search
     this._nextSearch = {
       "keyword": this._timeSearch,
       "visited": this._locationSearch,
       "location": null
     };
-    
+
     this._queryBuilders = {
       "keyword": this.setKeywordQuery,
       "visited": this.setVisitedQuery,
       "location": this.setLocationQuery
     };
 
+    this._maxRows = this._queryBuilders.length;
+
     this._dateService = Cc["@mozilla.org/intl/scriptabledateformat;1"].
                         getService(Ci.nsIScriptableDateFormat);
   },
 
   /**
    * Hides the query builder, and the match rule UI if visible.
    */
   hide: function PQB_hide() {
     var advancedSearch = document.getElementById("advancedSearch");
     // Need to collapse the advanced search box.
     advancedSearch.collapsed = true;
 
     var titleDeck = document.getElementById("titleDeck");
     titleDeck.setAttribute("selectedIndex", 0);
   },
-  
+
   /**
    * Shows the query builder
    */
   show: function PQB_show() {
     var advancedSearch = document.getElementById("advancedSearch");
     advancedSearch.collapsed = false;
   },
 
+  toggleVisibility: function ABP_toggleVisibility() {
+    var expander = document.getElementById("organizerScopeBarExpander");
+    var advancedSearch = document.getElementById("advancedSearch");
+    if (advancedSearch.collapsed) {
+      advancedSearch.collapsed = false;
+      expander.className = "expander-down";
+      expander.setAttribute("tooltiptext",
+                            expander.getAttribute("tooltiptextdown"));
+    }
+    else {
+      advancedSearch.collapsed = true;
+      expander.className = "expander-up"
+      expander.setAttribute("tooltiptext",
+                            expander.getAttribute("tooltiptextup"));
+    }
+  },
+
   /**
-   * Includes the rowId in the id attribute of an element in a row newly 
+   * Includes the rowId in the id attribute of an element in a row newly
    * created from the template row.
    * @param   element
    *          The element whose id attribute needs to be updated.
    * @param   rowId
    *          The index of the new row.
    */
   _setRowId: function PQB__setRowId(element, rowId) {
     if (element.id)
@@ -812,106 +1028,99 @@ var PlacesQueryBuilder = {
     for (var i = 0; i < element.childNodes.length; ++i) {
       this._setRowId(element.childNodes[i], rowId);
     }
   },
 
   _updateUIForRowChange: function PQB__updateUIForRowChange() {
     // Titlebar should show "match any/all" iff there are > 1 queries visible.
     var titleDeck = document.getElementById("titleDeck");
-    titleDeck.setAttribute("selectedIndex", (this._numRows <= 1) ? 0 : 1);
+    titleDeck.setAttribute("selectedIndex", (this.numRows <= 1) ? 0 : 1);
 
     const asType = PlacesOrganizer.HEADER_TYPE_ADVANCED_SEARCH;
     PlacesOrganizer.setHeaderText(asType, "");
 
     // Update the "can add more criteria" command to make sure various +
     // buttons are disabled.
-    var command = document.getElementById("OrganizerCommand_find:moreCriteria");
-    if (this._numRows >= this._maxRows)
+    var command = document.getElementById("OrganizerCommand_search:moreCriteria");
+    if (this.numRows >= this._maxRows)
       command.setAttribute("disabled", "true");
     else
       command.removeAttribute("disabled");
   },
 
   /**
-   * Adds a row to the view, prefilled with the next query subject. If the 
+   * Adds a row to the view, prefilled with the next query subject. If the
    * query builder is not visible, it will be shown.
    */
   addRow: function PQB_addRow() {
     // Limits the number of rows that can be added based on the maximum number
     // of search query subjects.
-    if (this._numRows >= this._maxRows)
+    if (this.numRows >= this._maxRows)
       return;
 
     // Clone the template row and unset the hidden attribute.
     var gridRows = document.getElementById("advancedSearchRows");
     var newRow = gridRows.firstChild.cloneNode(true);
     newRow.hidden = false;
 
     // Determine what the search type is based on the last visible row. If this
     // is the first row, the type is "keyword search". Otherwise, it's the next
-    // in the sequence after the one defined by the previous visible row's 
+    // in the sequence after the one defined by the previous visible row's
     // Subject selector, as defined in _nextSearch.
     var searchType = this._keywordSearch;
     var lastMenu = document.getElementById("advancedSearch" +
-                                           this._numRows +
+                                           this.numRows +
                                            "Subject");
-    if (this._numRows > 0 && lastMenu && lastMenu.selectedItem) {
+    if (this.numRows > 0 && lastMenu && lastMenu.selectedItem)
       searchType = this._nextSearch[lastMenu.selectedItem.value];
-    }
-    // There is no "next" search type. We are here in error. 
+
+    // There is no "next" search type. We are here in error.
     if (!searchType)
       return;
-    // We don't insert into the document until _after_ the searchType is 
+    // We don't insert into the document until _after_ the searchType is
     // determined, since this will interfere with the computation.
     gridRows.appendChild(newRow);
-    this._setRowId(newRow, ++this._numRows);
+    this._setRowId(newRow, ++this.numRows);
 
-    // Ensure the Advanced Search container is visible, if this is the first 
+    // Ensure the Advanced Search container is visible, if this is the first
     // row being added.
-    var advancedSearch = document.getElementById("advancedSearch");
-    if (advancedSearch.collapsed) {
+    if (this.numRows == 1) {
       this.show();
 
-      // Update the header.
-      const asType = PlacesOrganizer.HEADER_TYPE_ADVANCED_SEARCH;
-      PlacesOrganizer.setHeaderText(asType, "");
-      
-      // Pre-fill the search terms field with the value from the one on the 
+      // Pre-fill the search terms field with the value from the one on the
       // toolbar.
-      // For some reason, setting.value here synchronously does not appear to 
+      // For some reason, setting.value here synchronously does not appear to
       // work.
       var searchTermsField = document.getElementById("advancedSearch1Textbox");
       if (searchTermsField)
         setTimeout(function() { searchTermsField.value = PlacesSearchBox.value; }, 10);
+      var query = PlacesUtils.history.getNewQuery();
+      query.searchTerms = PlacesSearchBox.value;
+      this.queries = [query];
+      return;
+    }
 
-      // Call ourselves again to add a second row so that the user is presented
-      // with more than just "Keyword Search" which they already performed from
-      // the toolbar.
-      this.addRow();
-      return;
-    }      
-
-    this.showSearch(this._numRows, searchType);
+    this.showSearch(this.numRows, searchType);
     this._updateUIForRowChange();
   },
 
   /**
    * Remove a row from the set of terms
    * @param   row
    *          The row to remove. If this is null, the last row will be removed.
    * If there are no more rows, the query builder will be hidden.
    */
   removeRow: function PQB_removeRow(row) {
     if (!row)
-      row = document.getElementById("advancedSearch" + this._numRows + "Row");
+      row = document.getElementById("advancedSearch" + this.numRows + "Row");
     row.parentNode.removeChild(row);
-    --this._numRows;
+    --this.numRows;
 
-    if (this._numRows < 1) {
+    if (this.numRows < 1) {
       this.hide();
 
       // Re-do the original toolbar-search-box search that the user used to
       // spawn the advanced UI... this effectively "reverts" the UI to the
       // point it was in before they began monkeying with advanced search.
       PlacesSearchBox.search(PlacesSearchBox.value);
       return;
     }
@@ -925,17 +1134,17 @@ var PlacesQueryBuilder = {
     var dateString = textbox.value;
     var dateArr = dateString.split("-");
     // The date can be split into a range by the '-' character, i.e.
     // 9/5/05 - 10/2/05.  Unfortunately, dates can also be written like
     // 9-5-05 - 10-2-05.  Try to parse the date based on how many hyphens
     // there are.
     var d0 = null;
     var d1 = null;
-    // If there are an even number of elements in the date array, try to 
+    // If there are an even number of elements in the date array, try to
     // parse it as a range of two dates.
     if ((dateArr.length & 1) == 0) {
       var mid = dateArr.length / 2;
       var dateStr0 = dateArr[0];
       var dateStr1 = dateArr[mid];
       for (var i = 1; i < mid; ++i) {
         dateStr0 += "-" + dateArr[i];
         dateStr1 += "-" + dateArr[i + mid];
@@ -966,21 +1175,21 @@ var PlacesQueryBuilder = {
       this.doSearch();
     }
   },
 
   onCalendarChanged: function PQB_onCalendarChanged(event, row) {
     var calendar = document.getElementById("advancedSearch" + row + "Calendar");
     var begin = calendar.beginrange;
     var end = calendar.endrange;
-    
+
     // If the calendar doesn't have a begin/end, don't change the textbox.
     if (begin == null || end == null)
       return true;
-      
+
     // If the begin and end are the same day, only fill that into the textbox.
     var textbox = document.getElementById("advancedSearch" + row + "TimePicker");
     var beginDate = begin.getDate();
     var beginMonth = begin.getMonth() + 1;
     var beginYear = begin.getFullYear();
     var endDate = end.getDate();
     var endMonth = end.getMonth() + 1;
     var endYear = end.getFullYear();
@@ -1002,20 +1211,20 @@ var PlacesQueryBuilder = {
                                                    beginDate);
       var endStr = this._dateService.FormatDate("",
                                                 this._dateService.dateFormatShort,
                                                 endYear,
                                                 endMonth,
                                                 endDate);
       textbox.value = beginStr + " - " + endStr;
     }
-    
+
     // Update the search.
     this.doSearch();
-    
+
     return true;
   },
 
   handleTimePickerClick: function PQB_handleTimePickerClick(event, row) {
     var popup = document.getElementById("advancedSearch" + row + "DatePopup");
     if (popup.showing)
       popup.hidePopup();
     else {
@@ -1053,42 +1262,40 @@ var PlacesQueryBuilder = {
           }
         }
         element.hidden = false;
       }
       else {
         element.hidden = true;
       }
     }
-    
+
     this.doSearch();
   },
 
   setKeywordQuery: function PQB_setKeywordQuery(query, prefix) {
     query.searchTerms += document.getElementById(prefix + "Textbox").value + " ";
   },
 
   setLocationQuery: function PQB_setLocationQuery(query, prefix) {
     var type = document.getElementById(prefix + "LocationMenulist").selectedItem.value;
     if (type == "onsite") {
       query.domain = document.getElementById(prefix + "Textbox").value;
     }
     else {
       query.uriIsPrefix = (type == "startswith");
-      var ios = Cc["@mozilla.org/network/io-service;1"].
-                  getService(Ci.nsIIOService);
       var spec = document.getElementById(prefix + "Textbox").value;
       try {
-        query.uri = ios.newURI(spec, null, null);
+        query.uri = IO.newURI(spec);
       }
       catch (e) {
-        // Invalid input can cause newURI to barf, that's OK, tack "http://" 
+        // Invalid input can cause newURI to barf, that's OK, tack "http://"
         // onto the front and try again to see if the user omitted it
         try {
-          query.uri = ios.newURI("http://" + spec, null, null);
+          query.uri = IO.newURI("http://" + spec);
         }
         catch (e) {
           // OK, they have entered something which can never match. This should
           // not happen.
         }
       }
     }
   },
@@ -1133,134 +1340,177 @@ var PlacesQueryBuilder = {
     }
   },
 
   doSearch: function PQB_doSearch() {
     // Create the individual queries.
     var queryType = document.getElementById("advancedSearchType").selectedItem.value;
     this.queries = [];
     if (queryType == "and")
-      queries.push(PlacesUtils.history.getNewQuery());
+      this.queries.push(PlacesUtils.history.getNewQuery());
     var updated = 0;
-    for (var i = 1; updated < this._numRows; ++i) {
+    for (var i = 1; updated < this.numRows; ++i) {
       var prefix = "advancedSearch" + i;
 
-      // The user can remove rows from the middle and start of the list, not 
+      // The user can remove rows from the middle and start of the list, not
       // just from the end, so we need to make sure that this row actually
       // exists before attempting to construct a query for it.
       var querySubjectElement = document.getElementById(prefix + "Subject");
       if (querySubjectElement) {
         // If the queries are being AND-ed, put all the rows in one query.
         // If they're being OR-ed, add a separate query for each row.
         var query;
         if (queryType == "and")
           query = this.queries[0];
         else
           query = PlacesUtils.history.getNewQuery();
-        
+
         var querySubject = querySubjectElement.value;
         this._queryBuilders[querySubject](query, prefix);
-        
+
         if (queryType == "or")
           this.queries.push(query);
-          
+
         ++updated;
       }
     }
-    
+
     // Make sure we're getting uri results, not visits
     this.options = PlacesOrganizer.getCurrentOptions();
-    this.options.resultType = options.RESULT_TYPE_URI;
+    this.options.resultType = this.options.RESULT_TYPE_URI;
 
     // XXXben - find some public way of doing this!
-    PlacesOrganizer._content.load(queries, 
-                                  OptionsFilter.filter(queries, options, null));
+    PlacesOrganizer._content.load(this.queries,
+                                  OptionsFilter.filter(this.queries, this.options, null));
     PlacesOrganizer.updateLoadedURI();
+  },
+
+  onScopeSelected: function PQB_onScopeSelected(aButton) {
+    var id = aButton.getAttribute("id");
+    // get scope bar
+    var bar = document.getElementById("organizerScopeBar");
+    var child = bar.firstChild;
+    while (child) {
+      if (child.getAttribute("id") != id)
+        child.removeAttribute("checked");
+      else
+        child.setAttribute("checked", "true");
+      child = child.nextSibling;
+    }
+
+    // update collection type and get folders
+    var folders = [];
+    switch (id) {
+      case "scopeBarFolder":
+        PlacesSearchBox.filterCollection = "collection";
+        folders.push(PlacesOrganizer._places.selectedNode.itemId);
+        break;
+      case "scopeBarToolbar":
+        PlacesSearchBox.filterCollection = "collection";
+        folders.push(PlacesUtils.toolbarFolderId);
+        break;
+      case "scopeBarMenu":
+        PlacesSearchBox.filterCollection = "collection";
+        folders.push(PlacesUtils.bookmarksRootId);
+        break;
+      case "scopeBarHistory":
+        PlacesSearchBox.filterCollection = "history";
+        folders = [];
+        break;
+      default: // all bookmarks
+        PlacesSearchBox.filterCollection = "bookmarks";
+        folders.push(PlacesUtils.bookmarksRootId,
+                     PlacesUtils.unfiledRootId);
+    }
+
+    // set scope, and re-search
+    PlacesSearchBox.folders = folders;
+    PlacesSearchBox.search(PlacesSearchBox.searchFilter.value);
   }
 };
 
 /**
- * Population and commands for the View Menu. 
+ * Population and commands for the View Menu.
  */
 var ViewMenu = {
   /**
    * Removes content generated previously from a menupopup.
    * @param   popup
    *          The popup that contains the previously generated content.
    * @param   startID
-   *          The id attribute of an element that is the start of the 
+   *          The id attribute of an element that is the start of the
    *          dynamically generated region - remove elements after this
-   *          item only. 
+   *          item only.
    *          Must be contained by popup. Can be null (in which case the
-   *          contents of popup are removed). 
+   *          contents of popup are removed).
    * @param   endID
    *          The id attribute of an element that is the end of the
    *          dynamically generated region - remove elements up to this
    *          item only.
    *          Must be contained by popup. Can be null (in which case all
    *          items until the end of the popup will be removed). Ignored
-   *          if startID is null. 
-   * @returns The element for the caller to insert new items before, 
+   *          if startID is null.
+   * @returns The element for the caller to insert new items before,
    *          null if the caller should just append to the popup.
    */
   _clean: function VM__clean(popup, startID, endID) {
-    if (endID) 
+    if (endID)
       NS_ASSERT(startID, "meaningless to have valid endID and null startID");
     if (startID) {
       var startElement = document.getElementById(startID);
-      NS_ASSERT(startElement.parentNode == 
+      NS_ASSERT(startElement.parentNode ==
                 popup, "startElement is not in popup");
-      NS_ASSERT(startElement, 
+      NS_ASSERT(startElement,
                 "startID does not correspond to an existing element");
       var endElement = null;
       if (endID) {
         endElement = document.getElementById(endID);
-        NS_ASSERT(endElement.parentNode == popup, 
+        NS_ASSERT(endElement.parentNode == popup,
                   "endElement is not in popup");
-        NS_ASSERT(endElement, 
+        NS_ASSERT(endElement,
                   "endID does not correspond to an existing element");
       }
       while (startElement.nextSibling != endElement)
         popup.removeChild(startElement.nextSibling);
       return endElement;
     }
     else {
       while(popup.hasChildNodes())
-        popup.removeChild(popup.firstChild);  
+        popup.removeChild(popup.firstChild);
     }
     return null;
   },
 
   /**
    * Fills a menupopup with a list of columns
    * @param   event
    *          The popupshowing event that invoked this function.
    * @param   startID
    *          see _clean
    * @param   endID
    *          see _clean
    * @param   type
-   *          the type of the menuitem, e.g. "radio" or "checkbox". 
-   *          Can be null (no-type). 
+   *          the type of the menuitem, e.g. "radio" or "checkbox".
+   *          Can be null (no-type).
    *          Checkboxes are checked if the column is visible.
    * @param   propertyPrefix
    *          If propertyPrefix is non-null:
    *          propertyPrefix + column ID + ".label" will be used to get the
    *          localized label string.
    *          propertyPrefix + column ID + ".accesskey" will be used to get the
    *          localized accesskey.
    *          If propertyPrefix is null, the column label is used as label and
    *          no accesskey is assigned.
    */
   fillWithColumns: function VM_fillWithColumns(event, startID, endID, type, propertyPrefix) {
-    var popup = event.target;  
+    var popup = event.target;
     var pivot = this._clean(popup, startID, endID);
 
-    // If no column is "sort-active", the "Unsorted" item needs to be checked, 
-    // so track whether or not we find a column that is sort-active. 
+    // If no column is "sort-active", the "Unsorted" item needs to be checked,
+    // so track whether or not we find a column that is sort-active.
     var isSorted = false;
     var content = document.getElementById("placeContent");
     var columns = content.columns;
     for (var i = 0; i < columns.count; ++i) {
       var column = columns.getColumnAt(i).element;
       var menuitem = document.createElementNS(XUL_NS, "menuitem");
       menuitem.id = "menucol_" + column.id;
       menuitem.setAttribute("column", column.id);
@@ -1273,49 +1523,49 @@ var ViewMenu = {
         label = PlacesUtils.getString(menuitemPrefix + ".label");
         var accesskey = PlacesUtils.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. 
+        // This column is the sort key. Its item is checked.
         if (column.getAttribute("sortDirection") != "") {
           menuitem.setAttribute("checked", "true");
           isSorted = true;
         }
       }
       else if (type == "checkbox") {
         menuitem.setAttribute("type", "checkbox");
         // Cannot uncheck the primary column.
         if (column.getAttribute("primary") == "true")
           menuitem.setAttribute("disabled", "true");
-        // Items for visible columns are checked. 
+        // Items for visible columns are checked.
         if (!column.hidden)
           menuitem.setAttribute("checked", "true");
       }
       if (pivot)
         popup.insertBefore(menuitem, pivot);
       else
-        popup.appendChild(menuitem);      
+        popup.appendChild(menuitem);
     }
     event.stopPropagation();
   },
-  
+
   /**
    * Set up the content of the view menu.
    */
   populateSortMenu: function VM_populateSortMenu(event) {
     this.fillWithColumns(event, "viewUnsorted", "directionSeparator", "radio", "view.sortBy.");
 
     var sortColumn = this._getSortColumn();
     var viewSortAscending = document.getElementById("viewSortAscending");
     var viewSortDescending = document.getElementById("viewSortDescending");
-    // We need to remove an existing checked attribute because the unsorted 
+    // We need to remove an existing checked attribute because the unsorted
     // menu item is not rebuilt every time we open the menu like the others.
     var viewUnsorted = document.getElementById("viewUnsorted");
     if (!sortColumn) {
       viewSortAscending.removeAttribute("checked");
       viewSortDescending.removeAttribute("checked");
       viewUnsorted.setAttribute("checked", "true");
     }
     else if (sortColumn.getAttribute("sortDirection") == "ascending") {
@@ -1324,48 +1574,48 @@ var ViewMenu = {
       viewUnsorted.removeAttribute("checked");
     }
     else if (sortColumn.getAttribute("sortDirection") == "descending") {
       viewSortDescending.setAttribute("checked", "true");
       viewSortAscending.removeAttribute("checked");
       viewUnsorted.removeAttribute("checked");
     }
   },
-  
+
   /**
    * Shows/Hides a tree column.
    * @param   element
    *          The menuitem element for the column
    */
   showHideColumn: function VM_showHideColumn(element) {
     const PREFIX = "menucol_";
     var columnID = element.id.substr(PREFIX.length, element.id.length);
     var column = document.getElementById(columnID);
-    NS_ASSERT(column, 
+    NS_ASSERT(column,
               "menu item for column that doesn't exist?! id = " + element.id);
 
     var splitter = column.nextSibling;
     if (splitter && splitter.localName != "splitter")
       splitter = null;
-    
+
     if (element.getAttribute("checked") == "true") {
       column.removeAttribute("hidden");
       if (splitter)
         splitter.removeAttribute("hidden");
     }
     else {
       column.setAttribute("hidden", "true");
       if (splitter)
         splitter.setAttribute("hidden", "true");
-    }    
+    }
   },
 
   /**
-   * Gets the last column that was sorted. 
-   * @returns  the currently sorted column, null if there is no sorted column. 
+   * Gets the last column that was sorted.
+   * @returns  the currently sorted column, null if there is no sorted column.
    */
   _getSortColumn: function VM__getSortColumn() {
     var content = document.getElementById("placeContent");
     var cols = content.columns;
     for (var i = 0; i < cols.count; ++i) {
       var column = cols.getColumnAt(i).element;
       var sortDirection = column.getAttribute("sortDirection");
       if (sortDirection == "ascending" || sortDirection == "descending")
@@ -1375,17 +1625,17 @@ var ViewMenu = {
   },
 
   /**
    * Sorts the view by the specified key.
    * @param   aColumnID
    *          The ID of the colum that is the sort key. Can be null - the
    *          current sort column id or "title" will be used.
    * @param   aDirection
-   *          The direction to sort - "ascending" or "descending". 
+   *          The direction to sort - "ascending" or "descending".
    *          Can be null - the last direction or descending will be used.
    *
    * If both aColumnID and aDirection are null, the view will be unsorted.
    */
   setSortColumn: function VM_setSortColumn(aColumnID, aDirection) {
     var result = document.getElementById("placeContent").getResult();
     if (!aColumnID && !aDirection) {
       result.sortingMode = Ci.nsINavHistoryQueryOptions.SORT_BY_NONE;
@@ -1411,17 +1661,17 @@ var ViewMenu = {
         break;
       case "url":
         sortingMode = aDirection == "descending" ?
           NHQO.SORT_BY_URI_DESCENDING : NHQO.SORT_BY_URI_ASCENDING;
         break;
       case "date":
         sortingMode = aDirection == "descending" ?
           NHQO.SORT_BY_DATE_DESCENDING : NHQO.SORT_BY_DATE_ASCENDING;
-        break;      
+        break;
       case "visitCount":
         sortingMode = aDirection == "descending" ?
           NHQO.SORT_BY_VISITCOUNT_DESCENDING : NHQO.SORT_BY_VISITCOUNT_ASCENDING;
         break;
       case "keyword":
         sortingMode = aDirection == "descending" ?
           NHQO.SORT_BY_KEYWORD_DESCENDING : NHQO.SORT_BY_KEYWORD_ASCENDING;
         break;
@@ -1443,93 +1693,93 @@ var ViewMenu = {
     }
     result.sortingAnnotation = sortingAnnotation;
     result.sortingMode = sortingMode;
     OptionsFilter.update(result);
   }
 };
 
 /**
- * A "Configuration" set for a class of history query results. Some results 
+ * A "Configuration" set for a class of history query results. Some results
  * will require that the grouping UI be labeled differently from the standard
  * so this object is provided to allow those results to configure the UI when
  * they are displayed.
  * @param   substr
- *          A prefix substring of an annotation that the result's query 
+ *          A prefix substring of an annotation that the result's query
  *          matches.
  * @param   onLabel
  *          The label for the "Grouping On" command
  * @param   onAccesskey
  *          The accesskey for the "Grouping On" command
  * @param   offLabel
  *          The label for the "Grouping Off" command
  * @param   offAccesskey
  *          The accesskey for the "Grouping Off" command
  * @param   onOncommand
  *          The "oncommand" attribute of the "Grouping On" command
  * @param   offOncommand
  *          The "oncommand" attribute of the "Grouping Off" command
  * @param   disabled
- *          Whether or not grouping is disabled for results that match this 
+ *          Whether or not grouping is disabled for results that match this
  *          config.
  */
-function GroupingConfig(substr, onLabel, onAccesskey, offLabel, offAccesskey, 
+function GroupingConfig(substr, onLabel, onAccesskey, offLabel, offAccesskey,
                         onOncommand, offOncommand, disabled) {
   this.substr = substr;
   this.onLabel = onLabel;
   this.onAccesskey = onAccesskey;
   this.offLabel = offLabel;
   this.offAccesskey = offAccesskey;
   this.onOncommand = onOncommand;
   this.offOncommand = offOncommand;
   this.disabled = disabled;
 }
 
 /**
- * Handles Grouping within the Content View, and the commands that support it. 
+ * Handles Grouping within the Content View, and the commands that support it.
  */
 var Groupers = {
   defaultGrouper: null,
   annotationGroupers: [],
 
   /**
-   * Initializes groupings for various view types. 
+   * Initializes groupings for various view types.
    */
   init: function G_init() {
-    this.defaultGrouper = 
+    this.de