Merge m-c to tracemonkey.
authorRobert Sayre <sayrer@gmail.com>
Mon, 23 Feb 2009 12:44:23 -0500
changeset 25480 92fe7ae071340cce10f6ae9e7e3910bb1ec37065
parent 25479 b088ab0bf3b04c025498cf30211ab48929aa0603 (current diff)
parent 25396 b84ee6f45b08ddaa910d35b865bf6fd294a33728 (diff)
child 25482 efc15d672f0941185c2b98ac35a4114d5f83a780
push id5575
push userrsayre@mozilla.com
push dateWed, 25 Feb 2009 09:05:38 +0000
treeherdermozilla-central@8eba35e62d92 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.2a1pre
Merge m-c to tracemonkey.
accessible/src/base/nsNameUtils.cpp
accessible/src/base/nsNameUtils.h
accessible/src/base/nsTextUtils.cpp
accessible/src/base/nsTextUtils.h
accessible/tests/mochitest/test_nsIAccessible_editablebody.html
accessible/tests/mochitest/test_nsIAccessible_editabledoc.html
browser/themes/gnomestripe/browser/tabbrowser/newtab.png
build/pgo/automation.py.in
dom/tests/mochitest/ajax/offline/changingManifest.cacheManifest
dom/tests/mochitest/ajax/offline/changingManifest.cacheManifest^headers^
dom/tests/mochitest/ajax/offline/updating.cacheManifest
dom/tests/mochitest/ajax/offline/updating.cacheManifest^headers^
dom/tests/mochitest/ajax/offline/updatingIFrame.html
dom/tests/mochitest/ajax/offline/updatingIFrame.html^headers^
dom/tests/mochitest/geolocation/test_lastPosition.html
intl/uconv/ucvibm/cp1046.uf
intl/uconv/ucvibm/cp1046.ut
intl/uconv/ucvlatin/8859-11.ut
intl/uconv/ucvlatin/macukrai.uf
intl/uconv/ucvlatin/macukrai.ut
intl/uconv/ucvlatin/nsMacUkrainianToUnicode.cpp
intl/uconv/ucvlatin/nsMacUkrainianToUnicode.h
intl/uconv/ucvlatin/nsUnicodeToMacUkrainian.cpp
intl/uconv/ucvlatin/nsUnicodeToMacUkrainian.h
intl/uconv/ucvlatin/tis620.ut
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsinterp.cpp
js/src/jsobj.cpp
js/src/jsparse.cpp
js/src/jsstddef.h
js/src/jsstr.cpp
js/src/jstracer.cpp
js/src/jstracer.h
js/src/shell/js.cpp
layout/base/tests/test_bug441782.html
netwerk/test/httpserver/test/test_remotesetpath.js
security/manager/ssl/tests/mochitest/test_bug413909.html
toolkit/components/downloads/test/unit/bug_381535_downloads.rdf
toolkit/components/downloads/test/unit/downloads.rdf
toolkit/components/downloads/test/unit/test_bug_329741.js
toolkit/components/downloads/test/unit/test_bug_381535.js
toolkit/components/downloads/test/unit/test_download_manager_migration.js
toolkit/mozapps/installer/build_static.pl
xpcom/MoreFiles/FSCopyObject.c
xpcom/MoreFiles/FSCopyObject.h
xpcom/MoreFiles/Makefile.in
xpcom/MoreFiles/MoreFilesX.c
xpcom/MoreFiles/MoreFilesX.h
xpcom/MoreFiles/ReadMe.txt
--- a/Makefile.in
+++ b/Makefile.in
@@ -171,43 +171,47 @@ endif
 DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
 endif
 ifeq (,$(filter-out Linux SunOS,$(OS_ARCH)))
 MAKE_SYM_STORE_ARGS := --vcs-info
 DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
 MAKE_SYM_STORE_PATH := $(DIST)/bin
 endif
 
+SYM_STORE_SOURCE_DIRS := $(topsrcdir)
+
+include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
+
 ifdef MOZ_SYMBOLS_EXTRA_BUILDID
 EXTRA_BUILDID := -$(MOZ_SYMBOLS_EXTRA_BUILDID)
 endif
 
-SYMBOL_ARCHIVE_BASENAME = \
-  $(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_ARCH)-$(BUILDID)$(EXTRA_BUILDID)
+SYMBOL_INDEX_NAME = \
+  $(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_ARCH)-$(BUILDID)$(EXTRA_BUILDID)-symbols.txt
 
 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)     \
-	  $(DIST)/crashreporter-symbols/$(BUILDID)                    \
-	  $(MAKE_SYM_STORE_PATH) >                                    \
-	  $(DIST)/crashreporter-symbols/$(BUILDID)/$(SYMBOL_ARCHIVE_BASENAME)-symbols.txt
+	$(PYTHON) $(topsrcdir)/toolkit/crashreporter/tools/symbolstore.py \
+	  $(MAKE_SYM_STORE_ARGS)                                          \
+	  $(foreach dir,$(SYM_STORE_SOURCE_DIRS),-s $(dir))               \
+	  $(DUMP_SYMS_BIN)                                                \
+	  $(DIST)/crashreporter-symbols/$(BUILDID)                        \
+	  $(MAKE_SYM_STORE_PATH) >                                        \
+	  $(DIST)/crashreporter-symbols/$(BUILDID)/$(SYMBOL_INDEX_NAME)
 	echo packing symbols
 	mkdir -p $(topsrcdir)/../$(BUILDID)
 	cd $(DIST)/crashreporter-symbols/$(BUILDID) && \
-          zip -r9D ../crashreporter-symbols-$(SYMBOL_ARCHIVE_BASENAME).zip .
-	mv $(DIST)/crashreporter-symbols/crashreporter-symbols-$(SYMBOL_ARCHIVE_BASENAME).zip \
-          $(topsrcdir)/../$(BUILDID)
+          zip -r9D ../../$(SYMBOL_ARCHIVE_BASENAME).zip .
 endif # MOZ_CRASHREPORTER
 
 uploadsymbols:
 ifdef MOZ_CRASHREPORTER
-	$(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.sh $(topsrcdir)/../$(BUILDID)/crashreporter-symbols-$(SYMBOL_ARCHIVE_BASENAME).zip
+	$(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.sh $(DIST)/$(SYMBOL_ARCHIVE_BASENAME).zip
 endif
 
 ifeq ($(OS_ARCH),WINNT)
 signnss:
 ifdef MOZILLA_OFFICIAL
 	echo signing NSS libs
 	cd $(DIST)/bin; ./shlibsign.exe -v -i softokn3.dll
 	cd $(DIST)/bin; ./shlibsign.exe -v -i freebl3.dll
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -76,29 +76,29 @@ CPPSRCS = \
   nsAccessNode.cpp \
   nsAccessibleEventData.cpp \
   nsARIAMap.cpp \
   nsDocAccessible.cpp \
   nsOuterDocAccessible.cpp \
   nsAccessibilityAtoms.cpp \
   nsCoreUtils.cpp \
   nsAccUtils.cpp \
-  nsNameUtils.cpp \
   nsRelUtils.cpp \
   nsAccessibilityService.cpp \
   nsAccessible.cpp \
   nsAccessibleRelation.cpp \
   nsAccessibleTreeWalker.cpp \
   nsBaseWidgetAccessible.cpp \
   nsFormControlAccessible.cpp \
   nsRootAccessible.cpp \
   nsApplicationAccessible.cpp \
   nsCaretAccessible.cpp \
   nsTextAccessible.cpp \
-  nsTextUtils.cpp \
+  nsTextEquivUtils.cpp \
+  nsTextAttrs.cpp \
   $(NULL)
 
 EXPORTS = \
   nsRootAccessible.h \
   nsAccessibleEventData.h \
   nsAccessNode.h \
   $(NULL)
 
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -60,470 +60,548 @@ static const nsStateMapEntry kEndEntry =
 
 nsRoleMapEntry nsARIAMap::gWAIRoleMap[] = 
 {
   {
     "alert",
     nsIAccessibleRole::ROLE_ALERT,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "alertdialog",
     nsIAccessibleRole::ROLE_DIALOG,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "application",
     nsIAccessibleRole::ROLE_APPLICATION,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "article",
     nsIAccessibleRole::ROLE_DOCUMENT,
     eNoValue,
     eNoAction,
-    kNoReqStates,
+    eNoLiveAttr,
+    nsIAccessibleStates::STATE_READONLY,
     kEndEntry
   },
   {
     "button",
     nsIAccessibleRole::ROLE_PUSHBUTTON,
     eNoValue,
     eClickAction,
+    eNoLiveAttr,
     kNoReqStates,
-    {&nsAccessibilityAtoms::aria_pressed, kBoolState, nsIAccessibleStates::STATE_PRESSED},
-    {&nsAccessibilityAtoms::aria_pressed, "mixed", nsIAccessibleStates::STATE_MIXED},
+    {&nsAccessibilityAtoms::aria_pressed, kBoolState, nsIAccessibleStates::STATE_PRESSED | nsIAccessibleStates::STATE_CHECKABLE},
+    {&nsAccessibilityAtoms::aria_pressed, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
     kEndEntry
   },
   {
     "checkbox",
     nsIAccessibleRole::ROLE_CHECKBUTTON,
     eNoValue,
     eCheckUncheckAction,
+    eNoLiveAttr,
     nsIAccessibleStates::STATE_CHECKABLE,
     {&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED},
     {&nsAccessibilityAtoms::aria_checked, "mixed", nsIAccessibleStates::STATE_MIXED},
     {&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
     kEndEntry
   },
   {
     "columnheader",
     nsIAccessibleRole::ROLE_COLUMNHEADER,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     {&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
     {&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
     {&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
     kEndEntry
   },
   {
     "combobox",
     nsIAccessibleRole::ROLE_COMBOBOX,
     eHasValueMinMax,
     eOpenCloseAction,
+    eNoLiveAttr,
     nsIAccessibleStates::STATE_COLLAPSED | nsIAccessibleStates::STATE_HASPOPUP,
     // Manually map EXT_STATE_SUPPORTS_AUTOCOMPLETION aria-autocomplete
     {&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
     kEndEntry
   },
   {
     "dialog",
     nsIAccessibleRole::ROLE_DIALOG,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "document",
     nsIAccessibleRole::ROLE_DOCUMENT,
     eNoValue,
     eNoAction,
-    kNoReqStates,
+    eNoLiveAttr,
+    nsIAccessibleStates::STATE_READONLY,
     kEndEntry
   },
   {
     "grid",
     nsIAccessibleRole::ROLE_TABLE,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     nsIAccessibleStates::STATE_FOCUSABLE,
     {&nsAccessibilityAtoms::aria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE},
     {&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
     kEndEntry
   },
   {
     "gridcell",
     nsIAccessibleRole::ROLE_GRID_CELL,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     {&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
     {&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
     {&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
     kEndEntry
   },
   {
     "group",
     nsIAccessibleRole::ROLE_GROUPING,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "heading",
     nsIAccessibleRole::ROLE_HEADING,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "img",
     nsIAccessibleRole::ROLE_GRAPHIC,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "label",
     nsIAccessibleRole::ROLE_LABEL,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "link",
     nsIAccessibleRole::ROLE_LINK,
     eNoValue,
     eJumpAction,
+    eNoLiveAttr,
     nsIAccessibleStates::STATE_LINKED,
     kEndEntry
   },
   {
     "list",
     nsIAccessibleRole::ROLE_LIST,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     nsIAccessibleStates::STATE_READONLY,
     {&nsAccessibilityAtoms::aria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE},
     kEndEntry
   },
   {
     "listbox",
     nsIAccessibleRole::ROLE_LISTBOX,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     {&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
     {&nsAccessibilityAtoms::aria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE},
     kEndEntry
   },
   {
     "listitem",
     nsIAccessibleRole::ROLE_LISTITEM,
     eNoValue,
     eNoAction, // XXX: should depend on state, parent accessible
+    eNoLiveAttr,
     nsIAccessibleStates::STATE_READONLY,
     {&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
     {&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
     {&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
     {&nsAccessibilityAtoms::aria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
     {&nsAccessibilityAtoms::aria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE},
     kEndEntry
   },
   {
+    "log",
+    nsIAccessibleRole::ROLE_NOTHING,
+    eNoValue,
+    eNoAction,
+    ePoliteLiveAttr,
+    kNoReqStates,
+    kEndEntry
+  },
+  {
+    "marquee",
+    nsIAccessibleRole::ROLE_NOTHING,
+    eNoValue,
+    eNoAction,
+    eOffLiveAttr,
+    kNoReqStates,
+    kEndEntry
+  },
+  {
     "math",
     nsIAccessibleRole::ROLE_FLAT_EQUATION,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "menu",
     nsIAccessibleRole::ROLE_MENUPOPUP,
     eNoValue,
     eNoAction, // XXX: technically accessibles of menupopup role haven't
                // any action, but menu can be open or close.
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "menubar",
     nsIAccessibleRole::ROLE_MENUBAR,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "menuitem",
     nsIAccessibleRole::ROLE_MENUITEM,
     eNoValue,
     eClickAction,
+    eNoLiveAttr,
     kNoReqStates,
     {&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
     {&nsAccessibilityAtoms::aria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
     {&nsAccessibilityAtoms::aria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE},
     kEndEntry
   },
   {
     "menuitemcheckbox",
     nsIAccessibleRole::ROLE_CHECK_MENU_ITEM,
     eNoValue,
     eClickAction,
+    eNoLiveAttr,
     nsIAccessibleStates::STATE_CHECKABLE,
     {&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED },
     {&nsAccessibilityAtoms::aria_checked, "mixed", nsIAccessibleStates::STATE_MIXED},
     kEndEntry
   },
   {
     "menuitemradio",
     nsIAccessibleRole::ROLE_RADIO_MENU_ITEM,
     eNoValue,
     eClickAction,
+    eNoLiveAttr,
     nsIAccessibleStates::STATE_CHECKABLE,
     {&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED },
     kEndEntry
   },
   {
     "option",
     nsIAccessibleRole::ROLE_OPTION,
     eNoValue,
     eSelectAction,
+    eNoLiveAttr,
     kNoReqStates,
     {&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
     {&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
     {&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
     {&nsAccessibilityAtoms::aria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
     {&nsAccessibilityAtoms::aria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE},
     kEndEntry
   },
   {
     "presentation",
     nsIAccessibleRole::ROLE_NOTHING,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "progressbar",
     nsIAccessibleRole::ROLE_PROGRESSBAR,
     eHasValueMinMax,
     eNoAction,
+    eNoLiveAttr,
     nsIAccessibleStates::STATE_READONLY,
     kEndEntry
   },
   {
     "radio",
     nsIAccessibleRole::ROLE_RADIOBUTTON,
     eNoValue,
     eSelectAction,
-    kNoReqStates,
+    eNoLiveAttr,
+    nsIAccessibleStates::STATE_CHECKABLE,
     {&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED},
     kEndEntry
   },
   {
     "radiogroup",
     nsIAccessibleRole::ROLE_GROUPING,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "region",
     nsIAccessibleRole::ROLE_PANE,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "row",
     nsIAccessibleRole::ROLE_ROW,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     {&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
     {&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
     kEndEntry
   },
   {
     "rowheader",
     nsIAccessibleRole::ROLE_ROWHEADER,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     {&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
     {&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
     {&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
     kEndEntry
   },
   {
     "section",
     nsIAccessibleRole::ROLE_SECTION,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "separator",
     nsIAccessibleRole::ROLE_SEPARATOR,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "slider",
     nsIAccessibleRole::ROLE_SLIDER,
     eHasValueMinMax,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     {&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
     kEndEntry
   },
   {
     "spinbutton",
     nsIAccessibleRole::ROLE_SPINBUTTON,
     eHasValueMinMax,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     {&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
     kEndEntry
   },
   {
     "status",
     nsIAccessibleRole::ROLE_STATUSBAR,
     eNoValue,
     eNoAction,
+    ePoliteLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "tab",
     nsIAccessibleRole::ROLE_PAGETAB,
     eNoValue,
     eSwitchAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "tablist",
     nsIAccessibleRole::ROLE_PAGETABLIST,
     eNoValue,
     eNoAction,
+    ePoliteLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "tabpanel",
     nsIAccessibleRole::ROLE_PROPERTYPAGE,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "textbox",
     nsIAccessibleRole::ROLE_ENTRY,
     eNoValue,
     eActivateAction,
+    eNoLiveAttr,
     kNoReqStates,
     // Manually map EXT_STATE_SINGLE_LINE and EXT_STATE_MULTI_LINE FROM aria-multiline
     // Manually map EXT_STATE_SUPPORTS_AUTOCOMPLETION aria-autocomplete
     {&nsAccessibilityAtoms::aria_autocomplete, "list", nsIAccessibleStates::STATE_HASPOPUP},
     {&nsAccessibilityAtoms::aria_autocomplete, "both", nsIAccessibleStates::STATE_HASPOPUP},
     {&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
     kEndEntry
   },
   {
+    "timer",
+    nsIAccessibleRole::ROLE_NOTHING,
+    eNoValue,
+    eNoAction,
+    eOffLiveAttr,
+    kNoReqStates,
+    kEndEntry
+  },
+  {
     "toolbar",
     nsIAccessibleRole::ROLE_TOOLBAR,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "tooltip",
     nsIAccessibleRole::ROLE_TOOLTIP,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     kEndEntry
   },
   {
     "tree",
     nsIAccessibleRole::ROLE_OUTLINE,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     {&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
     {&nsAccessibilityAtoms::aria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE},
     kEndEntry
   },
   {
     "treegrid",
     nsIAccessibleRole::ROLE_TREE_TABLE,
     eNoValue,
     eNoAction,
+    eNoLiveAttr,
     kNoReqStates,
     {&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
     {&nsAccessibilityAtoms::aria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE},
     kEndEntry
   },
   {
     "treeitem",
     nsIAccessibleRole::ROLE_OUTLINEITEM,
     eNoValue,
     eActivateAction, // XXX: should expose second 'expand/collapse' action based
                      // on states
+    eNoLiveAttr,
     kNoReqStates,
     {&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
     {&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
     {&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
     {&nsAccessibilityAtoms::aria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
     {&nsAccessibilityAtoms::aria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE},
-  },
+    kEndEntry
+  }
 };
 
 PRUint32 nsARIAMap::gWAIRoleMapLength = NS_ARRAY_LENGTH(nsARIAMap::gWAIRoleMap);
 
 nsRoleMapEntry nsARIAMap::gLandmarkRoleMap = {
   "",
   nsIAccessibleRole::ROLE_NOTHING,
   eNoValue,
   eNoAction,
+  eNoLiveAttr,
   kNoReqStates,
   kEndEntry
 };
 
 nsRoleMapEntry nsARIAMap::gEmptyRoleMap = {
   "",
   nsIAccessibleRole::ROLE_NOTHING,
   eNoValue,
   eNoAction,
+  eNoLiveAttr,
   kNoReqStates,
   kEndEntry
 };
 
 /**
  * Universal states:
  * The following state rules are applied to any accessible element,
  * whether there is an ARIA role or not:
@@ -535,8 +613,46 @@ nsStateMapEntry nsARIAMap::gWAIUnivState
   {&nsAccessibilityAtoms::aria_busy,     "true",     nsIAccessibleStates::STATE_BUSY},
   {&nsAccessibilityAtoms::aria_busy,     "error",    nsIAccessibleStates::STATE_INVALID},
   {&nsAccessibilityAtoms::aria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
   {&nsAccessibilityAtoms::aria_expanded, kBoolState, nsIAccessibleStates::STATE_EXPANDED},
   {&nsAccessibilityAtoms::aria_expanded, "false", nsIAccessibleStates::STATE_COLLAPSED},
   kEndEntry
 };
 
+
+/**
+ * ARIA attribute map for attribute characteristics
+ * 
+ * @note ARIA attributes that don't have any flags are not included here
+ */
+nsAttributeCharacteristics nsARIAMap::gWAIUnivAttrMap[] = {
+  {&nsAccessibilityAtoms::aria_activedescendant,  ATTR_EXPOSEOBJ                 },
+  {&nsAccessibilityAtoms::aria_atomic,                             ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_busy,                               ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_checked,           ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_controls,          ATTR_EXPOSEOBJ                 },
+  {&nsAccessibilityAtoms::aria_describedby,       ATTR_EXPOSEOBJ                 },
+  {&nsAccessibilityAtoms::aria_disabled,          ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_dropeffect,                         ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_expanded,          ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_flowto,            ATTR_EXPOSEOBJ                 },  
+  {&nsAccessibilityAtoms::aria_grabbed,                            ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_haspopup,          ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_invalid,           ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_labelledby,        ATTR_EXPOSEOBJ                 },
+  {&nsAccessibilityAtoms::aria_live,                               ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_multiline,         ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_multiselectable,   ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_owns,              ATTR_EXPOSEOBJ                 },
+  {&nsAccessibilityAtoms::aria_pressed,           ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_readonly,          ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_relevant,          ATTR_EXPOSEOBJ                 },
+  {&nsAccessibilityAtoms::aria_required,          ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_selected,          ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_sort,                               ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_valuenow,          ATTR_EXPOSEOBJ                 },
+  {&nsAccessibilityAtoms::aria_valuemin,          ATTR_EXPOSEOBJ                 },
+  {&nsAccessibilityAtoms::aria_valuemax,          ATTR_EXPOSEOBJ                 },
+  {&nsAccessibilityAtoms::aria_valuetext,         ATTR_EXPOSEOBJ                 }
+};
+
+PRUint32 nsARIAMap::gWAIUnivAttrMapLength = NS_ARRAY_LENGTH(nsARIAMap::gWAIUnivAttrMap);
--- a/accessible/src/base/nsARIAMap.h
+++ b/accessible/src/base/nsARIAMap.h
@@ -58,46 +58,79 @@ enum EActionRule
   eClickAction,
   eCheckUncheckAction,
   eJumpAction,
   eOpenCloseAction,
   eSelectAction,
   eSwitchAction
 };
 
+enum ELiveAttrRule
+{
+  eNoLiveAttr,
+  eOffLiveAttr,
+  ePoliteLiveAttr
+};
+
+// ARIA attribute characteristic masks, grow as needed
+
+/**
+ * This mask indicates the attribute should be exposed as an object attribute,
+ * used to expose semantics not traditionally found in a11y APIs.
+ * (See for example usage in nsAccessible::GetAttributes)
+ */
+const PRUint8 ATTR_EXPOSEOBJ  = 0x0001;
+
+/**
+ * This mask indicates the attribute is expected to have an NMTOKEN or bool value.
+ * (See for example usage in nsAccessible::GetAttributes)
+ */
+const PRUint8 ATTR_VALTOKEN   = 0x0010;
+
 // Used for an nsStateMapEntry if a given state attribute supports "true" and "false"
 #define kBoolState 0
 
 // 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
 {
   nsIAtom** attributeName;  // nsnull 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
 };
 
+// Small footprint storage of persistent aria attribute characteristics
+struct nsAttributeCharacteristics
+{
+  nsIAtom** attributeName;
+  const PRUint8 characteristics;
+};
+
 // For each ARIA role, this maps the nsIAccessible information
 struct nsRoleMapEntry
 {
   // ARIA role: string representation such as "button"
   const char *roleString;
   
   // Role mapping rule: maps to this nsIAccessibleRole
   PRUint32 role;
   
   // Value mapping rule: how to compute nsIAccessible value
   EValueRule valueRule;
 
   // Action mapping rule, how to expose nsIAccessible action
   EActionRule actionRule;
 
+  // 'live' and 'container-live' object attributes mapping rule: how to expose
+  // these object attributes if ARIA 'live' attribute is missed.
+  ELiveAttrRule liveAttRule;
+
   // Automatic state mapping rule: always include in nsIAccessibleStates
   PRUint32 state;   // or kNoReqStates if no nsIAccessibleStates are automatic for this role.
   
   // ARIA properties supported for this role
   // (in other words, the aria-foo attribute to nsIAccessibleStates mapping rules)
   // Currently you cannot have unlimited mappings, because
   // a variable sized array would not allow the use of
   // C++'s struct initialization feature.
@@ -137,11 +170,17 @@ struct nsARIAMap
    */
   static nsRoleMapEntry gEmptyRoleMap;
 
   /**
    * State map of ARIA states applied to any accessible not depending on
    * the role.
    */
   static nsStateMapEntry gWAIUnivStateMap[];
+  
+  /**
+   * Map of attribute to attribute characteristics.
+   */
+  static nsAttributeCharacteristics gWAIUnivAttrMap[];
+  static PRUint32 gWAIUnivAttrMapLength;
 };
 
 #endif
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -267,73 +267,63 @@ nsAccUtils::SetAccAttrsForXULContainerIt
 void
 nsAccUtils::SetLiveContainerAttributes(nsIPersistentProperties *aAttributes,
                                        nsIContent *aStartContent,
                                        nsIContent *aTopContent)
 {
   nsAutoString atomic, live, relevant, busy;
   nsIContent *ancestor = aStartContent;
   while (ancestor) {
+
+    // container-relevant attribute
     if (relevant.IsEmpty() &&
         nsAccUtils::HasDefinedARIAToken(ancestor, nsAccessibilityAtoms::aria_relevant) &&
         ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_relevant, relevant))
       SetAccAttr(aAttributes, nsAccessibilityAtoms::containerRelevant, relevant);
 
-    if (live.IsEmpty() &&
-        nsAccUtils::HasDefinedARIAToken(ancestor, nsAccessibilityAtoms::aria_live) &&
-        ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_live, live))
-      SetAccAttr(aAttributes, nsAccessibilityAtoms::containerLive, live);
+    // container-live attribute
+    if (live.IsEmpty()) {
+      if (nsAccUtils::HasDefinedARIAToken(ancestor,
+                                          nsAccessibilityAtoms::aria_live)) {
+        ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_live,
+                          live);
+        SetAccAttr(aAttributes, nsAccessibilityAtoms::containerLive, live);
+      } else {
+        nsCOMPtr<nsIDOMNode> node(do_QueryInterface(ancestor));
+        nsRoleMapEntry *role = GetRoleMapEntry(node);
+        if (role) {
+          nsAutoString live;
+          GetLiveAttrValue(role->liveAttRule, live);
+          SetAccAttr(aAttributes, nsAccessibilityAtoms::containerLive, live);
+        }
+      }
+    }
 
+    // container-atomic attribute
     if (atomic.IsEmpty() &&
         nsAccUtils::HasDefinedARIAToken(ancestor, nsAccessibilityAtoms::aria_atomic) &&
         ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_atomic, atomic))
       SetAccAttr(aAttributes, nsAccessibilityAtoms::containerAtomic, atomic);
 
+    // container-busy attribute
     if (busy.IsEmpty() &&
         nsAccUtils::HasDefinedARIAToken(ancestor, nsAccessibilityAtoms::aria_busy) &&
         ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_busy, busy))
       SetAccAttr(aAttributes, nsAccessibilityAtoms::containerBusy, busy);
 
     if (ancestor == aTopContent)
       break;
 
     ancestor = ancestor->GetParent();
     if (!ancestor)
       ancestor = aTopContent; // Use <body>/<frameset>
   }
 }
 
 PRBool
-nsAccUtils::IsARIAPropForObjectAttr(nsIAtom *aAtom)
-{
-  return aAtom != nsAccessibilityAtoms::aria_activedescendant &&
-    aAtom != nsAccessibilityAtoms::aria_checked &&
-    aAtom != nsAccessibilityAtoms::aria_controls &&
-    aAtom != nsAccessibilityAtoms::aria_describedby &&
-    aAtom != nsAccessibilityAtoms::aria_disabled &&
-    aAtom != nsAccessibilityAtoms::aria_expanded &&
-    aAtom != nsAccessibilityAtoms::aria_flowto &&
-    aAtom != nsAccessibilityAtoms::aria_invalid &&
-    aAtom != nsAccessibilityAtoms::aria_haspopup &&
-    aAtom != nsAccessibilityAtoms::aria_labelledby &&
-    aAtom != nsAccessibilityAtoms::aria_multiline &&
-    aAtom != nsAccessibilityAtoms::aria_multiselectable &&
-    aAtom != nsAccessibilityAtoms::aria_owns &&
-    aAtom != nsAccessibilityAtoms::aria_pressed &&
-    aAtom != nsAccessibilityAtoms::aria_readonly &&
-    aAtom != nsAccessibilityAtoms::aria_relevant &&
-    aAtom != nsAccessibilityAtoms::aria_required &&
-    aAtom != nsAccessibilityAtoms::aria_selected &&
-    aAtom != nsAccessibilityAtoms::aria_valuemax &&
-    aAtom != nsAccessibilityAtoms::aria_valuemin &&
-    aAtom != nsAccessibilityAtoms::aria_valuenow &&
-    aAtom != nsAccessibilityAtoms::aria_valuetext;
-}
-
-PRBool
 nsAccUtils::HasDefinedARIAToken(nsIContent *aContent, nsIAtom *aAtom)
 {
   if (!aContent->HasAttr(kNameSpaceID_None, aAtom) ||
       aContent->AttrValueIs(kNameSpaceID_None, aAtom,
                             nsAccessibilityAtoms::_empty, eCaseMatters) ||
       aContent->AttrValueIs(kNameSpaceID_None, aAtom,
                             nsAccessibilityAtoms::_undefined, eCaseMatters)) {
         return PR_FALSE;
@@ -681,16 +671,38 @@ nsAccUtils::GetRoleMapEntry(nsIDOMNode *
     }
   }
 
   // Always use some entry if there is a role string
   // To ensure an accessible object is created
   return &nsARIAMap::gLandmarkRoleMap;
 }
 
+PRUint8
+nsAccUtils::GetAttributeCharacteristics(nsIAtom* aAtom)
+{
+    for (PRUint32 i = 0; i < nsARIAMap::gWAIUnivAttrMapLength; i++)
+      if (*nsARIAMap::gWAIUnivAttrMap[i].attributeName == aAtom)
+        return nsARIAMap::gWAIUnivAttrMap[i].characteristics;
+
+    return 0;
+}
+
+void
+nsAccUtils::GetLiveAttrValue(PRUint32 aRule, nsAString& aValue)
+{
+  switch (aRule) {
+    case eOffLiveAttr:
+      aValue = NS_LITERAL_STRING("off");
+      break;
+    case ePoliteLiveAttr:
+      aValue = NS_LITERAL_STRING("polite");
+      break;
+  }
+}
 
 #ifdef DEBUG_A11Y
 
 PRBool
 nsAccUtils::IsTextInterfaceSupportCorrect(nsIAccessible *aAccessible)
 {
   PRBool foundText = PR_FALSE;
   
--- a/accessible/src/base/nsAccUtils.h
+++ b/accessible/src/base/nsAccUtils.h
@@ -126,22 +126,16 @@ public:
    * @param aStartContent  node to start from
    * @param aTopContent    node to end at
    */
   static void SetLiveContainerAttributes(nsIPersistentProperties *aAttributes,
                                          nsIContent *aStartContent,
                                          nsIContent *aTopContent);
 
   /**
-   * Return PR_TRUE if the ARIA property should always be exposed as an object
-   * attribute.
-   */
-  static PRBool IsARIAPropForObjectAttr(nsIAtom *aAtom);
-
-  /**
    * Any ARIA property of type boolean or NMTOKEN is undefined if the ARIA
    * property is not present, or is "" or "undefined". Do not call 
    * this method for properties of type string, decimal, IDREF or IDREFS.
    * 
    * Return PR_TRUE if the ARIA property is defined, otherwise PR_FALSE
    */
   static PRBool HasDefinedARIAToken(nsIContent *aContent, nsIAtom *aAtom);
 
@@ -263,16 +257,31 @@ public:
     PRUint32 state = 0;
     if (aAcc)
       aAcc->GetState(&state, nsnull);
 
     return state;
   }
 
   /**
+   * Get the ARIA attribute characteristics for a given ARIA attribute.
+   * 
+   * @param aAtom  ARIA attribute
+   * @return       A bitflag representing the attribute characteristics
+   *               (see nsARIAMap.h for possible bit masks, prefixed "ARIA_")
+   */
+  static PRUint8 GetAttributeCharacteristics(nsIAtom* aAtom);
+
+  /**
+   * Return the 'live' or 'container-live' object attribute value from the given
+   * ELiveAttrRule constant.
+   */
+  static void GetLiveAttrValue(PRUint32 aRule, nsAString& aValue);
+
+  /**
    * Query nsAccessNode from the given nsIAccessible.
    */
   static already_AddRefed<nsAccessNode>
     QueryAccessNode(nsIAccessible *aAccessible)
   {
     nsAccessNode* accessNode = nsnull;
     if (aAccessible)
       CallQueryInterface(aAccessible, &accessNode);
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -183,25 +183,33 @@ ACCESSIBILITY_ATOM(selected, "selected")
 ACCESSIBILITY_ATOM(summary, "summary")
 ACCESSIBILITY_ATOM(tabindex, "tabindex")
 ACCESSIBILITY_ATOM(title, "title")
 ACCESSIBILITY_ATOM(tooltiptext, "tooltiptext")
 ACCESSIBILITY_ATOM(type, "type")
 ACCESSIBILITY_ATOM(value, "value")
 
   // Alphabetical list of object attributes
+ACCESSIBILITY_ATOM(checkable, "checkable")
 ACCESSIBILITY_ATOM(display, "display")
 ACCESSIBILITY_ATOM(textAlign, "text-align")
 ACCESSIBILITY_ATOM(textIndent, "text-indent")
 
   // Alphabetical list of text attributes (AT API)
+ACCESSIBILITY_ATOM(color, "color")
 ACCESSIBILITY_ATOM(backgroundColor, "background-color")
+ACCESSIBILITY_ATOM(fontFamily, "font-family")
+ACCESSIBILITY_ATOM(fontStyle, "font-style")
+ACCESSIBILITY_ATOM(fontWeight, "font-weight")
 ACCESSIBILITY_ATOM(fontSize, "font-size")
 ACCESSIBILITY_ATOM(invalid, "invalid")
 ACCESSIBILITY_ATOM(language, "language")
+ACCESSIBILITY_ATOM(textLineThroughStyle, "text-line-through-style")
+ACCESSIBILITY_ATOM(textUnderlineStyle, "text-underline-style")
+ACCESSIBILITY_ATOM(textPosition, "text-position")
 
   // ARIA (DHTML accessibility) attributes
   // Also add to nsARIAMap.cpp and nsARIAMap.h
   // ARIA role attribute
 ACCESSIBILITY_ATOM(role, "role")
 ACCESSIBILITY_ATOM(aria_activedescendant, "aria-activedescendant")
 ACCESSIBILITY_ATOM(aria_atomic, "aria-atomic")
 ACCESSIBILITY_ATOM(aria_autocomplete, "aria-autocomplete")
@@ -244,11 +252,12 @@ ACCESSIBILITY_ATOM(defaultLabel, "defaul
 
 // Object attributes
 ACCESSIBILITY_ATOM(tableCellIndex, "table-cell-index")
 ACCESSIBILITY_ATOM(containerAtomic, "container-atomic")
 ACCESSIBILITY_ATOM(containerBusy, "container-busy")
 ACCESSIBILITY_ATOM(containerLive, "container-live")
 ACCESSIBILITY_ATOM(containerRelevant, "container-relevant")
 ACCESSIBILITY_ATOM(level, "level")
+ACCESSIBILITY_ATOM(live, "live")
 ACCESSIBILITY_ATOM(lineNumber, "line-number")
 ACCESSIBILITY_ATOM(posinset, "posinset") 
 ACCESSIBILITY_ATOM(setsize, "setsize")
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -35,17 +35,16 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsAccessible.h"
 #include "nsAccessibleRelation.h"
 #include "nsHyperTextAccessibleWrap.h"
-#include "nsNameUtils.h"
 
 #include "nsIAccessibleDocument.h"
 #include "nsIAccessibleHyperText.h"
 #include "nsAccessibleTreeWalker.h"
 
 #include "nsIDOMElement.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentXBL.h"
@@ -324,29 +323,32 @@ 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::aria_describedby, description);
+    nsresult rv = nsTextEquivUtils::
+      GetTextEquivFromIDRefs(this, nsAccessibilityAtoms::aria_describedby,
+                             description);
     if (NS_FAILED(rv)) {
       PRBool isXUL = content->IsNodeOfType(nsINode::eXUL);
       if (isXUL) {
         // Try XUL <description control="[id]">description text</description>
         nsIContent *descriptionContent =
           nsCoreUtils::FindNeighbourPointingToNode(content,
                                                    nsAccessibilityAtoms::control,
                                                    nsAccessibilityAtoms::description);
 
         if (descriptionContent) {
           // We have a description content node
-          AppendFlatStringFromSubtree(descriptionContent, &description);
+          nsTextEquivUtils::
+            AppendTextEquivFromContent(this, descriptionContent, &description);
         }
       }
       if (description.IsEmpty()) {
         nsIAtom *descAtom = isXUL ? nsAccessibilityAtoms::tooltiptext :
                                     nsAccessibilityAtoms::title;
         if (content->GetAttr(kNameSpaceID_None, descAtom, description)) {
           nsAutoString name;
           GetName(name);
@@ -1451,330 +1453,40 @@ nsAccessible::TakeFocus()
     // in order to affect tabbing order
     return htmlElement->Focus();
   }
 
   content->SetFocus(GetPresContext());
   return NS_OK;
 }
 
-nsresult nsAccessible::AppendStringWithSpaces(nsAString *aFlatString, const nsAString& textEquivalent)
-{
-  // Insert spaces to insure that words from controls aren't jammed together
-  if (!textEquivalent.IsEmpty()) {
-    if (!aFlatString->IsEmpty())
-      aFlatString->Append(PRUnichar(' '));
-    aFlatString->Append(textEquivalent);
-    aFlatString->Append(PRUnichar(' '));
-  }
-  return NS_OK;
-}
-
-nsresult nsAccessible::AppendNameFromAccessibleFor(nsIContent *aContent,
-                                                   nsAString *aFlatString,
-                                                   PRBool aFromValue)
-{
-  nsAutoString textEquivalent, value;
-
-  nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(aContent));
-  nsCOMPtr<nsIAccessible> accessible;
-  if (domNode == mDOMNode) {
-    accessible = this;
-    if (!aFromValue) {
-      // prevent recursive call GetName()
-      return NS_OK;
-    }
-  }
-  else {
-    nsCOMPtr<nsIAccessibilityService> accService =
-      do_GetService("@mozilla.org/accessibilityService;1");
-    NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
-    accService->GetAccessibleInWeakShell(domNode, mWeakShell, getter_AddRefs(accessible));
-  }
-  if (accessible) {
-    if (aFromValue) {
-      accessible->GetValue(textEquivalent);
-    }
-    else {
-      accessible->GetName(textEquivalent);
-    }
-  }
-
-  textEquivalent.CompressWhitespace();
-  return AppendStringWithSpaces(aFlatString, textEquivalent);
-}
-
-/*
- * AppendFlatStringFromContentNode and AppendFlatStringFromSubtree
- *
- * This method will glean useful text, in whatever form it exists, from any content node given to it.
- * It is used by any decendant of nsAccessible that needs to get text from a single node, as
- * well as by nsAccessible::AppendFlatStringFromSubtree, which gleans and concatenates text from any node and
- * that node's decendants.
- */
-
-nsresult nsAccessible::AppendFlatStringFromContentNode(nsIContent *aContent, nsAString *aFlatString)
-{
-  if (aContent->IsNodeOfType(nsINode::eTEXT)) {
-    // If it's a text node, append the text
-    PRBool isHTMLBlock = PR_FALSE;
-    nsCOMPtr<nsIPresShell> shell = GetPresShell();
-    if (!shell) {
-      return NS_ERROR_FAILURE;  
-    }
-
-    nsIContent *parentContent = aContent->GetParent();
-    nsCOMPtr<nsIContent> appendedSubtreeStart(do_QueryInterface(mDOMNode));
-    if (parentContent && parentContent != appendedSubtreeStart) {
-      nsIFrame *frame = shell->GetPrimaryFrameFor(parentContent);
-      if (frame) {
-        // If this text is inside a block level frame (as opposed to span level), we need to add spaces around that 
-        // block's text, so we don't get words jammed together in final name
-        // Extra spaces will be trimmed out later
-        const nsStyleDisplay* display = frame->GetStyleDisplay();
-        if (display->IsBlockOutside() ||
-          display->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL) {
-          isHTMLBlock = PR_TRUE;
-          if (!aFlatString->IsEmpty()) {
-            aFlatString->Append(PRUnichar(' '));
-          }
-        }
-      }
-    }
-    if (aContent->TextLength() > 0) {
-      nsIFrame *frame = shell->GetPrimaryFrameFor(aContent);
-      if (frame) {
-        nsresult rv = frame->GetRenderedText(aFlatString);
-        NS_ENSURE_SUCCESS(rv, rv);
-      } else {
-        //if aContent is an object that is display: none, we have no a frame
-        aContent->AppendTextTo(*aFlatString);
-      }
-      if (isHTMLBlock && !aFlatString->IsEmpty()) {
-        aFlatString->Append(PRUnichar(' '));
-      }
-    }
-    return NS_OK;
-  }
-
-  nsAutoString textEquivalent;
-  if (!aContent->IsNodeOfType(nsINode::eHTML)) {
-    if (aContent->IsNodeOfType(nsINode::eXUL)) {
-      nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl(do_QueryInterface(aContent));
-      if (labeledEl) {
-        labeledEl->GetLabel(textEquivalent);
-      }
-      else {
-        if (aContent->NodeInfo()->Equals(nsAccessibilityAtoms::label, kNameSpaceID_XUL)) {
-          aContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::value, textEquivalent);
-        }
-        if (textEquivalent.IsEmpty()) {
-          aContent->GetAttr(kNameSpaceID_None,
-                            nsAccessibilityAtoms::tooltiptext, textEquivalent);
-        }
-      }
-      AppendNameFromAccessibleFor(aContent, &textEquivalent, PR_TRUE /* use value */);
-
-      return AppendStringWithSpaces(aFlatString, textEquivalent);
-    }
-    return NS_OK; // Not HTML and not XUL -- we don't handle it yet
-  }
-
-  nsCOMPtr<nsIAtom> tag = aContent->Tag();
-  if (tag == nsAccessibilityAtoms::img) {
-    return AppendNameFromAccessibleFor(aContent, aFlatString);
-  }
-
-  if (tag == nsAccessibilityAtoms::input) {
-    static nsIContent::AttrValuesArray strings[] =
-      {&nsAccessibilityAtoms::button, &nsAccessibilityAtoms::submit,
-       &nsAccessibilityAtoms::reset, &nsAccessibilityAtoms::image, nsnull};
-    if (aContent->FindAttrValueIn(kNameSpaceID_None, nsAccessibilityAtoms::type,
-                                  strings, eIgnoreCase) >= 0) {
-      return AppendNameFromAccessibleFor(aContent, aFlatString);
-    }
-  }
-
-  if (tag == nsAccessibilityAtoms::object && !aContent->GetChildCount()) {
-    // If object has no alternative content children, try title
-    aContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::title, textEquivalent);
-  }
-  else if (tag == nsAccessibilityAtoms::br) {
-    // If it's a line break, insert a space so that words aren't jammed together
-    aFlatString->AppendLiteral("\r\n");
-    return NS_OK;
-  }
-  else if (tag != nsAccessibilityAtoms::a && tag != nsAccessibilityAtoms::area) { 
-    AppendNameFromAccessibleFor(aContent, aFlatString, PR_TRUE /* use value */);
-  }
-
-  textEquivalent.CompressWhitespace();
-  return AppendStringWithSpaces(aFlatString, textEquivalent);
-}
-
-
-nsresult nsAccessible::AppendFlatStringFromSubtree(nsIContent *aContent, nsAString *aFlatString)
-{
-  static PRBool isAlreadyHere; // Prevent recursion which can cause infinite loops
-  if (isAlreadyHere) {
-    return NS_OK;
-  }
-
-  isAlreadyHere = PR_TRUE;
-
-  nsCOMPtr<nsIPresShell> shell = GetPresShell();
-  NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
-
-  nsIFrame *frame = shell->GetPrimaryFrameFor(aContent);
-  PRBool isHidden = (!frame || !frame->GetStyleVisibility()->IsVisible());
-  nsresult rv = AppendFlatStringFromSubtreeRecurse(aContent, aFlatString,
-                                                   isHidden);
-
-  isAlreadyHere = PR_FALSE;
-
-  if (NS_SUCCEEDED(rv) && !aFlatString->IsEmpty()) {
-    nsAString::const_iterator start, end;
-    aFlatString->BeginReading(start);
-    aFlatString->EndReading(end);
-
-    PRInt32 spacesToTruncate = 0;
-    while (-- end != start && *end == ' ')
-      ++ spacesToTruncate;
-
-    if (spacesToTruncate > 0)
-      aFlatString->Truncate(aFlatString->Length() - spacesToTruncate);
-  }
-
-  return rv;
-}
-
-nsresult
-nsAccessible::AppendFlatStringFromSubtreeRecurse(nsIContent *aContent,
-                                                 nsAString *aFlatString,
-                                                 PRBool aIsRootHidden)
-{
-  // Depth first search for all text nodes that are decendants of content node.
-  // Append all the text into one flat string
-  PRUint32 numChildren = 0;
-  nsCOMPtr<nsIDOMXULSelectControlElement> selectControlEl(do_QueryInterface(aContent));
-  nsCOMPtr<nsIAtom> tag = aContent->Tag();
-
-  if (!selectControlEl && 
-      tag != nsAccessibilityAtoms::textarea && 
-      tag != nsAccessibilityAtoms::select) {
-    // Don't walk children of elements with options, just get label directly.
-    // Don't traverse the children of a textarea, we want the value, not the
-    // static text node.
-    // Don't traverse the children of a select element, we only want the
-    // current value.
-    numChildren = aContent->GetChildCount();
-  }
-
-  if (numChildren == 0) {
-    // There are no children or they are irrelvant: get the text from the current node
-    AppendFlatStringFromContentNode(aContent, aFlatString);
-    return NS_OK;
-  }
-
-  // There are relevant children: use them to get the text.
-  nsCOMPtr<nsIPresShell> shell = GetPresShell();
-  NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
-
-  PRUint32 index;
-  for (index = 0; index < numChildren; index++) {
-    nsCOMPtr<nsIContent> childContent = aContent->GetChildAt(index);
-
-    // Walk into hidden subtree if the the root parent is also hidden. This
-    // happens when the author explictly uses a hidden label or description.
-    if (!aIsRootHidden) {
-      nsIFrame *childFrame = shell->GetPrimaryFrameFor(childContent);
-      if (!childFrame || !childFrame->GetStyleVisibility()->IsVisible())
-        continue;
-    }
-
-    AppendFlatStringFromSubtreeRecurse(childContent, aFlatString,
-                                       aIsRootHidden);
-  }
-
-  return NS_OK;
-}
-
-nsresult nsAccessible::GetTextFromRelationID(nsIAtom *aIDProperty, nsString &aName)
-{
-  // Get DHTML name from content subtree pointed to by ID attribute
-  aName.Truncate();
-  NS_ASSERTION(mDOMNode, "Called from shutdown accessible");
-
-  nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(mDOMNode);
-  if (!content)
-    return NS_OK;
-
-  nsCOMPtr<nsIArray> refElms;
-  nsCoreUtils::GetElementsByIDRefsAttr(content, aIDProperty,
-                                       getter_AddRefs(refElms));
-
-  if (!refElms)
-    return NS_OK;
-
-  PRUint32 count = 0;
-  nsresult rv = refElms->GetLength(&count);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIContent> refContent;
-  for (PRUint32 idx = 0; idx < count; idx++) {
-    refContent = do_QueryElementAt(refElms, idx, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (!aName.IsEmpty())
-      aName += ' '; // Need whitespace between multiple labels or descriptions
-
-    rv = AppendFlatStringFromSubtree(refContent, &aName);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  aName.CompressWhitespace();
-  return NS_OK;
-}
-
 nsresult
 nsAccessible::GetHTMLName(nsAString& aLabel)
 {
   nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(mDOMNode);
   if (!content) {
     aLabel.SetIsVoid(PR_TRUE);
     return NS_OK;
   }
 
   nsIContent *labelContent = nsCoreUtils::GetHTMLLabelContent(content);
   if (labelContent) {
     nsAutoString label;
-    nsresult rv = AppendFlatStringFromSubtree(labelContent, &label);
+    nsresult rv =
+      nsTextEquivUtils::AppendTextEquivFromContent(this, labelContent, &label);
     NS_ENSURE_SUCCESS(rv, rv);
 
     label.CompressWhitespace();
     if (!label.IsEmpty()) {
       aLabel = label;
       return NS_OK;
     }
   }
 
-  PRUint32 role = nsAccUtils::Role(this);
-  PRUint32 canAggregateName =
-    nsNameUtils::gRoleToNameRulesMap[role] & eFromSubtree;
-
-  if (canAggregateName) {
-    // Don't use AppendFlatStringFromSubtree for container widgets like menulist
-    nsresult rv = AppendFlatStringFromSubtree(content, &aLabel);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (!aLabel.IsEmpty())
-      return NS_OK;
-  }
-
-  return NS_OK;
+  return nsTextEquivUtils::GetNameFromSubtree(this, aLabel);
 }
 
 /**
   * 3 main cases for XUL Controls to be labeled
   *   1 - control contains label="foo"
   *   2 - control has, as a child, a label element
   *        - label has either value="foo" or children
   *   3 - non-child label contains control="controlID"
@@ -1824,17 +1536,17 @@ nsAccessible::GetXULName(nsAString& aLab
       nsCoreUtils::FindNeighbourPointingToNode(content, nsAccessibilityAtoms::control,
                                                nsAccessibilityAtoms::label);
 
     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 its text -- possibly using HTML
-      AppendFlatStringFromSubtree(labelContent, &label);
+      nsTextEquivUtils::AppendTextEquivFromContent(this, labelContent, &label);
     }
   }
 
   // XXX If CompressWhiteSpace worked on nsAString we could avoid a copy
   label.CompressWhitespace();
   if (!label.IsEmpty()) {
     aLabel = label;
     return NS_OK;
@@ -1849,22 +1561,17 @@ nsAccessible::GetXULName(nsAString& aLab
         parent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::title, label)) {
       label.CompressWhitespace();
       aLabel = label;
       return NS_OK;
     }
     parent = parent->GetParent();
   }
 
-  PRUint32 role = nsAccUtils::Role(this);
-  PRUint32 canAggregateName =
-    nsNameUtils::gRoleToNameRulesMap[role] & eFromSubtree;
-
-  return canAggregateName ?
-         AppendFlatStringFromSubtree(content, &aLabel) : NS_OK;
+  return nsTextEquivUtils::GetNameFromSubtree(this, aLabel);
 }
 
 NS_IMETHODIMP
 nsAccessible::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
 {
   NS_ENSURE_ARG_POINTER(aEvent);
   nsCOMPtr<nsIDOMNode> eventNode;
   aEvent->GetDOMNode(getter_AddRefs(eventNode));
@@ -1921,17 +1628,18 @@ NS_IMETHODIMP nsAccessible::GetFinalRole
       GetParent(getter_AddRefs(parent));
       if (nsAccUtils::Role(parent) == nsIAccessibleRole::ROLE_COMBOBOX_LIST)
         *aRole = nsIAccessibleRole::ROLE_COMBOBOX_OPTION;
     }
 
     // gLandmarkRoleMap: can use role of accessible class impl
     // gEmptyRoleMap and all others: cannot use role of accessible class impl
     if (mRoleMapEntry != &nsARIAMap::gLandmarkRoleMap) {
-      // We can now expose ROLE_NOTHING when there is a role map entry, which
+      // We can now expose ROLE_NOTHING when there is a role map entry or used
+      // role is nothing, which
       // will cause ATK to use ROLE_UNKNOWN and MSAA to use a BSTR role with
       // the ARIA role or element's tag. In either case the AT can also use
       // the object attributes tag and xml-roles to find out more.
       return NS_OK;
     }
   }
   return mDOMNode ? GetRole(aRole) : NS_ERROR_FAILURE;  // Node already shut down
 }
@@ -1978,64 +1686,63 @@ nsAccessible::GetAttributes(nsIPersisten
     // We support values, so expose the string value as well, via the valuetext object attribute
     // We test for the value interface because we don't want to expose traditional get_accValue()
     // information such as URL's on links and documents, or text in an input
     nsAutoString valuetext;
     GetValue(valuetext);
     attributes->SetStringProperty(NS_LITERAL_CSTRING("valuetext"), valuetext, oldValueUnused);
   }
 
-
-  PRUint32 role = nsAccUtils::Role(this);
-  if (role == nsIAccessibleRole::ROLE_CHECKBUTTON ||
-      role == nsIAccessibleRole::ROLE_PUSHBUTTON ||
-      role == nsIAccessibleRole::ROLE_MENUITEM ||
-      role == nsIAccessibleRole::ROLE_LISTITEM ||
-      role == nsIAccessibleRole::ROLE_OPTION ||
-      role == nsIAccessibleRole::ROLE_RADIOBUTTON ||
-      role == nsIAccessibleRole::ROLE_RICH_OPTION ||
-      role == nsIAccessibleRole::ROLE_OUTLINEITEM ||
-      content->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_checked)) {
-    // Might be checkable -- checking role & ARIA attribute first is faster than getting state
-    PRUint32 state = 0;
-    GetState(&state, nsnull);
-    if (state & nsIAccessibleStates::STATE_CHECKABLE) {
-      // No official state for checkable, so use object attribute to expose that
-      attributes->SetStringProperty(NS_LITERAL_CSTRING("checkable"), NS_LITERAL_STRING("true"),
-                                    oldValueUnused);
-    }
-  }
+  // Expose checkable object attribute if the accessible has checkable state
+  if (nsAccUtils::State(this) & nsIAccessibleStates::STATE_CHECKABLE)
+    nsAccUtils::SetAccAttr(attributes, nsAccessibilityAtoms::checkable, NS_LITERAL_STRING("true"));
 
   // Group attributes (level/setsize/posinset)
   if (!nsAccUtils::HasAccGroupAttrs(attributes)) {
     // Calculate group attributes based on accessible hierarhy if they weren't
     // provided by ARIA or by accessible class implementation.
+    PRUint32 role = nsAccUtils::Role(this);
     rv = ComputeGroupAttributes(role, attributes);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  // Expose all ARIA attributes
+  // Expose object attributes from ARIA attributes.
   PRUint32 numAttrs = content->GetAttrCount();
   for (PRUint32 count = 0; count < numAttrs; count ++) {
     const nsAttrName *attr = content->GetAttrNameAt(count);
     if (attr && attr->NamespaceEquals(kNameSpaceID_None)) {
       nsIAtom *attrAtom = attr->Atom();
       const char *attrStr;
       attrAtom->GetUTF8String(&attrStr);
       if (PL_strncmp(attrStr, "aria-", 5)) 
         continue; // Not ARIA
-      if (!nsAccUtils::IsARIAPropForObjectAttr(attrAtom))
+      PRUint8 attrFlags = nsAccUtils::GetAttributeCharacteristics(attrAtom);
+      if (attrFlags & ATTR_EXPOSEOBJ)
         continue; // No need to expose obj attribute -- will be exposed some other way
+      if ((attrFlags & ATTR_VALTOKEN) &&
+          !nsAccUtils::HasDefinedARIAToken(content, attrAtom))
+        continue; // only expose token based attributes if they are defined
       nsAutoString value;
       if (content->GetAttr(kNameSpaceID_None, attrAtom, value)) {
         attributes->SetStringProperty(nsDependentCString(attrStr + 5), value, oldValueUnused);
       }
     }
   }
 
+  // If there is no aria-live attribute then expose default value of 'live'
+  // object attribute used for ARIA role of this accessible.
+  if (mRoleMapEntry) {
+    nsAutoString live;
+    nsAccUtils::GetAccAttr(attributes, nsAccessibilityAtoms::live, live);
+    if (live.IsEmpty()) {
+      nsAccUtils::GetLiveAttrValue(mRoleMapEntry->liveAttRule, live);
+      nsAccUtils::SetAccAttr(attributes, nsAccessibilityAtoms::live, live);
+    }
+  }
+
   return NS_OK;
 }
 
 nsresult
 nsAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
 {
   // Attributes set by this method will not be used to override attributes on a sub-document accessible
   // when there is a <frame>/<iframe> element that spawned the sub-document
@@ -2325,17 +2032,21 @@ nsAccessible::GetState(PRUint32 *aState,
     // In XUL all boxes are either vertical or horizontal
     if (xulStyle->mBoxOrient == NS_STYLE_BOX_ORIENT_VERTICAL) {
       *aExtraState |= nsIAccessibleStates::EXT_STATE_VERTICAL;
     }
     else {
       *aExtraState |= nsIAccessibleStates::EXT_STATE_HORIZONTAL;
     }
   }
-
+  
+  // If we are editable, force readonly bit off
+  if (*aExtraState & nsIAccessibleStates::EXT_STATE_EDITABLE)
+    *aState &= ~nsIAccessibleStates::STATE_READONLY;
+ 
   return NS_OK;
 }
 
 nsresult
 nsAccessible::GetARIAState(PRUint32 *aState)
 {
   // Test for universal states first
   nsIContent *content = nsCoreUtils::GetRoleContent(mDOMNode);
@@ -2344,17 +2055,18 @@ nsAccessible::GetARIAState(PRUint32 *aSt
   }
 
   PRUint32 index = 0;
   while (MappedAttrState(content, aState, &nsARIAMap::gWAIUnivStateMap[index])) {
     ++ index;
   }
 
   if (mRoleMapEntry) {
-    // Once DHTML role is used, we're only readonly if DHTML readonly used
+    // Once an ARIA role is used, default to not-readonly. This can be overridden
+    // by aria-readonly, or if the ARIA role is mapped to readonly by default
     *aState &= ~nsIAccessibleStates::STATE_READONLY;
 
     if (content->HasAttr(kNameSpaceID_None, content->GetIDAttributeName())) {
       // If has a role & ID and aria-activedescendant on the container, assume focusable
       nsIContent *ancestorContent = content;
       while ((ancestorContent = ancestorContent->GetParent()) != nsnull) {
         if (ancestorContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_activedescendant)) {
             // ancestor has activedescendant property, this content could be active
@@ -2376,16 +2088,17 @@ nsAccessible::GetARIAState(PRUint32 *aSt
         break;
       }
     }    
   }
 
   if (!mRoleMapEntry)
     return NS_OK;
 
+  // Note: the readonly bitflag will be overridden later if content is editable
   *aState |= mRoleMapEntry->state;
   if (MappedAttrState(content, aState, &mRoleMapEntry->attributeMap1) &&
       MappedAttrState(content, aState, &mRoleMapEntry->attributeMap2) &&
       MappedAttrState(content, aState, &mRoleMapEntry->attributeMap3) &&
       MappedAttrState(content, aState, &mRoleMapEntry->attributeMap4) &&
       MappedAttrState(content, aState, &mRoleMapEntry->attributeMap5) &&
       MappedAttrState(content, aState, &mRoleMapEntry->attributeMap6) &&
       MappedAttrState(content, aState, &mRoleMapEntry->attributeMap7)) {
@@ -3363,24 +3076,28 @@ nsAccessible::GetARIAName(nsAString& aNa
 {
   nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(mDOMNode);
   if (!content)
     return NS_OK;
 
   // First check for label override via aria-label property
   nsAutoString label;
   if (content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_label, label)) {
+    label.CompressWhitespace();
     aName = label;
     return NS_OK;
   }
   
   // Second check for label override via aria-labelledby relationship
-  nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::aria_labelledby, label);
-  if (NS_SUCCEEDED(rv))
+  nsresult rv = nsTextEquivUtils::
+    GetTextEquivFromIDRefs(this, nsAccessibilityAtoms::aria_labelledby, label);
+  if (NS_SUCCEEDED(rv)) {
+    label.CompressWhitespace();
     aName = label;
+  }
 
   return rv;
 }
 
 nsresult
 nsAccessible::GetNameInternal(nsAString& aName)
 {
   nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(mDOMNode);
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -36,34 +36,35 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsAccessible_H_
 #define _nsAccessible_H_
 
 #include "nsAccessNodeWrap.h"
 
+#include "nsARIAMap.h"
+#include "nsRelUtils.h"
+#include "nsTextEquivUtils.h"
+
 #include "nsIAccessible.h"
 #include "nsPIAccessible.h"
 #include "nsIAccessibleHyperLink.h"
 #include "nsIAccessibleSelectable.h"
 #include "nsIAccessibleValue.h"
 #include "nsIAccessibleRole.h"
 #include "nsIAccessibleStates.h"
 #include "nsIAccessibleEvent.h"
 
-#include "nsRelUtils.h"
-
 #include "nsIDOMNodeList.h"
 #include "nsINameSpaceManager.h"
 #include "nsWeakReference.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsIDOMDOMStringList.h"
-#include "nsARIAMap.h"
 
 struct nsRect;
 class nsIContent;
 class nsIFrame;
 class nsIPresShell;
 class nsIDOMNode;
 class nsIAtom;
 class nsIView;
@@ -176,49 +177,29 @@ 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
-
-  /**
-   * For a given ARIA relation, such as labelledby or describedby, get the collated text
-   * for the subtree that's pointed to.
-   *
-   * @param aIDProperty  The ARIA relationship property to get the text for
-   * @param aName        Where to put the text
-   * @return error or success code
-   */
-  nsresult GetTextFromRelationID(nsIAtom *aIDProperty, nsString &aName);
-
   //////////////////////////////////////////////////////////////////////////////
   // Name helpers.
 
   /**
    * Compute the name of HTML node.
    */
   nsresult GetHTMLName(nsAString& aName);
 
   /**
    * Compute the name for XUL node.
    */
   nsresult GetXULName(nsAString& aName);
 
-  // For accessibles that are not lists of choices, the name of the subtree should be the 
-  // sum of names in the subtree
-  nsresult AppendFlatStringFromSubtree(nsIContent *aContent, nsAString *aFlatString);
-  nsresult AppendNameFromAccessibleFor(nsIContent *aContent, nsAString *aFlatString,
-                                       PRBool aFromValue = PR_FALSE);
-  nsresult AppendFlatStringFromContentNode(nsIContent *aContent, nsAString *aFlatString);
-  nsresult AppendStringWithSpaces(nsAString *aFlatString, const nsAString& textEquivalent);
-
   // helper method to verify frames
   static nsresult GetFullKeyName(const nsAString& aModifierName, const nsAString& aKeyName, nsAString& aStringOut);
   static nsresult GetTranslatedString(const nsAString& aKey, nsAString& aStringOut);
 
   /**
    * Walk into subtree and calculate the string which is used as the accessible
    * name or description.
    *
--- a/accessible/src/base/nsCaretAccessible.cpp
+++ b/accessible/src/base/nsCaretAccessible.cpp
@@ -339,17 +339,17 @@ nsCaretAccessible::GetCaretRect(nsIWidge
   NS_ENSURE_TRUE(*aOutWidget, nsIntRect());
 
   nsPresContext *presContext = presShell->GetPresContext();
   NS_ENSURE_TRUE(presContext, nsIntRect());
 
   rect += offsetFromWidget;
   caretRect = nsRect::ToOutsidePixels(rect, presContext->AppUnitsPerDevPixel());
 
-  (*aOutWidget)->WidgetToScreen(caretRect, caretRect);
+  caretRect.MoveBy((*aOutWidget)->WidgetToScreenOffset());
 
   // Correct for character size, so that caret always matches the size of the character
   // This is important for font size transitions, and is necessary because the Gecko caret uses the
   // previous character's size as the user moves forward in the text by character.
   PRInt32 charX, charY, charWidth, charHeight;
   if (NS_SUCCEEDED(mLastTextAccessible->GetCharacterExtents(mLastCaretOffset, &charX, &charY,
                                                             &charWidth, &charHeight,
                                                             nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE))) {
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -258,17 +258,19 @@ NS_IMETHODIMP nsDocAccessible::SetRoleMa
 NS_IMETHODIMP 
 nsDocAccessible::GetDescription(nsAString& aDescription)
 {
   if (mParent)
     mParent->GetDescription(aDescription);
 
   if (aDescription.IsEmpty()) {
     nsAutoString description;
-    GetTextFromRelationID(nsAccessibilityAtoms::aria_describedby, description);
+    nsTextEquivUtils::
+      GetTextEquivFromIDRefs(this, nsAccessibilityAtoms::aria_describedby,
+                             description);
     aDescription = description;
   }
 
   return NS_OK;
 }
 
 nsresult
 nsDocAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState)
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/nsTextAttrs.cpp
@@ -0,0 +1,605 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Alexander Surkov <surkov.alexander@gmail.com> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsTextAttrs.h"
+
+#include "nsAccessNode.h"
+#include "nsHyperTextAccessibleWrap.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Constants and structures
+
+/**
+ * Item of the gCSSTextAttrsMap map.
+ */
+struct nsCSSTextAttrMapItem
+{
+  const char* mCSSName;
+  const char* mCSSValue;
+  nsIAtom** mAttrName;
+  const char* mAttrValue;
+};
+
+/**
+ * The map of CSS properties to text attributes.
+ */
+const char* const kAnyValue = nsnull;
+const char* const kCopyValue = nsnull;
+
+static nsCSSTextAttrMapItem gCSSTextAttrsMap[] =
+{
+  // CSS name            CSS value        Attribute name                                Attribute value
+  { "color",             kAnyValue,       &nsAccessibilityAtoms::color,                 kCopyValue },
+  { "font-family",       kAnyValue,       &nsAccessibilityAtoms::fontFamily,            kCopyValue },
+  { "font-style",        kAnyValue,       &nsAccessibilityAtoms::fontStyle,             kCopyValue },
+  { "font-weight",       kAnyValue,       &nsAccessibilityAtoms::fontWeight,            kCopyValue },
+  { "text-decoration",   "line-through",  &nsAccessibilityAtoms::textLineThroughStyle,  "solid" },
+  { "text-decoration",   "underline",     &nsAccessibilityAtoms::textUnderlineStyle,    "solid" },
+  { "vertical-align",    kAnyValue,       &nsAccessibilityAtoms::textPosition,          kCopyValue }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// nsTextAttrs
+
+nsTextAttrsMgr::nsTextAttrsMgr(nsHyperTextAccessible *aHyperTextAcc,
+                               nsIDOMNode *aHyperTextNode,
+                               PRBool aIncludeDefAttrs,
+                               nsIDOMNode *aOffsetNode) :
+  mHyperTextAcc(aHyperTextAcc), mHyperTextNode(aHyperTextNode),
+  mIncludeDefAttrs(aIncludeDefAttrs), mOffsetNode(aOffsetNode)
+{
+}
+
+nsresult
+nsTextAttrsMgr::GetAttributes(nsIPersistentProperties *aAttributes,
+                              PRInt32 *aStartHTOffset,
+                              PRInt32 *aEndHTOffset)
+{
+  // 1. Hyper text accessible and its DOM node must be specified always.
+  // 2. Offset DOM node and result hyper text offsets must be specifed in
+  // the case of text attributes.
+  // 3. Offset DOM node and result hyper text offsets must not be specifed but
+  // include default text attributes flag and attributes list must be specified
+  // in the case of default text attributes.
+  NS_PRECONDITION(mHyperTextAcc && mHyperTextNode &&
+                  ((mOffsetNode && aStartHTOffset && aEndHTOffset) ||
+                  (!mOffsetNode && !aStartHTOffset && !aEndHTOffset &&
+                   mIncludeDefAttrs && aAttributes)),
+                  "Wrong usage of nsTextAttrsMgr!");
+
+  nsCOMPtr<nsIDOMElement> hyperTextElm =
+    nsCoreUtils::GetDOMElementFor(mHyperTextNode);
+  nsCOMPtr<nsIDOMElement> offsetElm;
+  if (mOffsetNode)
+    offsetElm = nsCoreUtils::GetDOMElementFor(mOffsetNode);
+
+  nsIFrame *rootFrame = nsCoreUtils::GetFrameFor(hyperTextElm);
+  nsIFrame *frame = nsnull;
+  if (offsetElm)
+    frame = nsCoreUtils::GetFrameFor(offsetElm);
+
+  nsTPtrArray<nsITextAttr> textAttrArray(10);
+
+  // "language" text attribute
+  nsLangTextAttr langTextAttr(mHyperTextAcc, mHyperTextNode, mOffsetNode);
+  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&langTextAttr));
+
+  // "color" text attribute
+  nsCSSTextAttr colorTextAttr(0, hyperTextElm, offsetElm);
+  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&colorTextAttr));
+
+  // "font-family" text attribute
+  nsCSSTextAttr fontFamilyTextAttr(1, hyperTextElm, offsetElm);
+  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontFamilyTextAttr));
+
+  // "font-style" text attribute
+  nsCSSTextAttr fontStyleTextAttr(2, hyperTextElm, offsetElm);
+  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontStyleTextAttr));
+
+  // "font-weight" text attribute
+  nsCSSTextAttr fontWeightTextAttr(3, hyperTextElm, offsetElm);
+  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontWeightTextAttr));
+
+  // "text-line-through-style" text attribute
+  nsCSSTextAttr lineThroughTextAttr(4, hyperTextElm, offsetElm);
+  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&lineThroughTextAttr));
+
+  // "text-underline-style" text attribute
+  nsCSSTextAttr underlineTextAttr(5, hyperTextElm, offsetElm);
+  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&underlineTextAttr));
+
+  // "text-position" text attribute
+  nsCSSTextAttr posTextAttr(6, hyperTextElm, offsetElm);
+  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&posTextAttr));
+
+  // "background-color" text attribute
+  nsBGColorTextAttr bgColorTextAttr(rootFrame, frame);
+  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&bgColorTextAttr));
+
+  // "font-size" text attribute
+  nsFontSizeTextAttr fontSizeTextAttr(rootFrame, frame);
+  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontSizeTextAttr));
+
+  // Expose text attributes if applicable.
+  if (aAttributes) {
+    PRUint32 len = textAttrArray.Length();
+    for (PRUint32 idx = 0; idx < len; idx++) {
+      nsITextAttr *textAttr = textAttrArray[idx];
+
+      nsAutoString value;
+      if (textAttr->GetValue(value, mIncludeDefAttrs))
+        nsAccUtils::SetAccAttr(aAttributes, textAttr->GetName(), value);
+    }
+  }
+
+  nsresult rv = NS_OK;
+
+  // Expose text attributes range where they are applied if applicable.
+  if (mOffsetNode)
+    rv = GetRange(textAttrArray, aStartHTOffset, aEndHTOffset);
+
+  textAttrArray.Clear();
+  return rv;
+}
+
+nsresult
+nsTextAttrsMgr::GetRange(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
+                         PRInt32 *aStartHTOffset, PRInt32 *aEndHTOffset)
+{
+  nsCOMPtr<nsIDOMElement> rootElm =
+    nsCoreUtils::GetDOMElementFor(mHyperTextNode);
+  NS_ENSURE_STATE(rootElm);
+
+  nsCOMPtr<nsIDOMNode> tmpNode(mOffsetNode);
+  nsCOMPtr<nsIDOMNode> currNode(mOffsetNode);
+
+  PRUint32 len = aTextAttrArray.Length();
+
+  // Navigate backwards and forwards from current node to the root node to
+  // calculate range bounds for the text attribute. Navigation sequence is the
+  // following:
+  // 1. Navigate through the siblings.
+  // 2. If the traversed sibling has children then navigate from its leaf child
+  //    to it through whole tree of the traversed sibling.
+  // 3. Get the parent and cycle algorithm until the root node.
+
+  // Navigate backwards (find the start offset).
+  while (currNode && currNode != rootElm) {
+    nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(currNode));
+    NS_ENSURE_STATE(currElm);
+
+    if (currNode != mOffsetNode) {
+      PRBool stop = PR_FALSE;
+      for (PRUint32 idx = 0; idx < len; idx++) {
+        nsITextAttr *textAttr = aTextAttrArray[idx];
+        if (!textAttr->Equal(currElm)) {
+
+          PRInt32 startHTOffset = 0;
+          nsCOMPtr<nsIAccessible> startAcc;
+          nsresult rv = mHyperTextAcc->
+            DOMPointToHypertextOffset(tmpNode, -1, &startHTOffset,
+                                      getter_AddRefs(startAcc));
+          NS_ENSURE_SUCCESS(rv, rv);
+
+          if (!startAcc)
+            startHTOffset = 0;
+
+          if (startHTOffset > *aStartHTOffset)
+            *aStartHTOffset = startHTOffset;
+
+          stop = PR_TRUE;
+          break;
+        }
+      }
+      if (stop)
+        break;
+    }
+
+    currNode->GetPreviousSibling(getter_AddRefs(tmpNode));
+    if (tmpNode) {
+      // Navigate through the subtree of traversed children to calculate
+      // left bound of the range.
+      FindStartOffsetInSubtree(aTextAttrArray, tmpNode, currNode,
+                               aStartHTOffset);
+    }
+
+    currNode->GetParentNode(getter_AddRefs(tmpNode));
+    currNode.swap(tmpNode);
+  }
+
+  // Navigate forwards (find the end offset).
+  PRBool moveIntoSubtree = PR_TRUE;
+  currNode = mOffsetNode;
+
+  while (currNode && currNode != rootElm) {
+    nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(currNode));
+    NS_ENSURE_STATE(currElm);
+
+    // Stop new end offset searching if the given text attribute changes its
+    // value.
+    PRBool stop = PR_FALSE;
+    for (PRUint32 idx = 0; idx < len; idx++) {
+      nsITextAttr *textAttr = aTextAttrArray[idx];
+      if (!textAttr->Equal(currElm)) {
+
+        PRInt32 endHTOffset = 0;
+        nsresult rv = mHyperTextAcc->
+          DOMPointToHypertextOffset(currNode, -1, &endHTOffset);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        if (endHTOffset < *aEndHTOffset)
+          *aEndHTOffset = endHTOffset;
+
+        stop = PR_TRUE;
+        break;
+      }
+    }
+
+    if (stop)
+      break;
+
+    if (moveIntoSubtree) {
+      // Navigate through subtree of traversed node. We use 'moveIntoSubtree'
+      // flag to avoid traversing the same subtree twice.
+      currNode->GetFirstChild(getter_AddRefs(tmpNode));
+      if (tmpNode)
+        FindEndOffsetInSubtree(aTextAttrArray, tmpNode, aEndHTOffset);
+    }
+
+    currNode->GetNextSibling(getter_AddRefs(tmpNode));
+    moveIntoSubtree = PR_TRUE;
+    if (!tmpNode) {
+      currNode->GetParentNode(getter_AddRefs(tmpNode));
+      moveIntoSubtree = PR_FALSE;
+    }
+
+    currNode.swap(tmpNode);
+  }
+
+  return NS_OK;
+}
+
+PRBool
+nsTextAttrsMgr::FindEndOffsetInSubtree(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
+                                       nsIDOMNode *aCurrNode,
+                                       PRInt32 *aHTOffset)
+{
+  if (!aCurrNode)
+    return PR_FALSE;
+
+  nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(aCurrNode));
+  NS_ENSURE_STATE(currElm);
+
+  // If the given text attribute (pointed by nsTextAttr object) changes its
+  // value on the traversed element then fit the end of range.
+  PRUint32 len = aTextAttrArray.Length();
+  for (PRUint32 idx = 0; idx < len; idx++) {
+    nsITextAttr *textAttr = aTextAttrArray[idx];
+    if (!textAttr->Equal(currElm)) {
+      PRInt32 endHTOffset = 0;
+      nsresult rv = mHyperTextAcc->
+        DOMPointToHypertextOffset(aCurrNode, -1, &endHTOffset);
+      NS_ENSURE_SUCCESS(rv, PR_FALSE);
+
+      if (endHTOffset < *aHTOffset)
+        *aHTOffset = endHTOffset;
+
+      return PR_TRUE;
+    }
+  }
+
+  // Deeply traverse into the tree to fit the end of range.
+  nsCOMPtr<nsIDOMNode> nextNode;
+  aCurrNode->GetFirstChild(getter_AddRefs(nextNode));
+  if (nextNode) {
+    PRBool res = FindEndOffsetInSubtree(aTextAttrArray, nextNode, aHTOffset);
+    if (res)
+      return res;
+  }
+
+  aCurrNode->GetNextSibling(getter_AddRefs(nextNode));
+  if (nextNode) {
+    if (FindEndOffsetInSubtree(aTextAttrArray, nextNode, aHTOffset))
+      return PR_TRUE;
+  }
+
+  return PR_FALSE;
+}
+
+PRBool
+nsTextAttrsMgr::FindStartOffsetInSubtree(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
+                                         nsIDOMNode *aCurrNode,
+                                         nsIDOMNode *aPrevNode,
+                                         PRInt32 *aHTOffset)
+{
+  if (!aCurrNode)
+    return PR_FALSE;
+
+  // Find the closest element back to the traversed element.
+  nsCOMPtr<nsIDOMNode> nextNode;
+  aCurrNode->GetLastChild(getter_AddRefs(nextNode));
+  if (nextNode) {
+    if (FindStartOffsetInSubtree(aTextAttrArray, nextNode, aPrevNode, aHTOffset))
+      return PR_TRUE;
+  }
+
+  nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(aCurrNode));
+  NS_ENSURE_STATE(currElm);
+
+  // If the given text attribute (pointed by nsTextAttr object) changes its
+  // value on the traversed element then fit the start of range.
+  PRUint32 len = aTextAttrArray.Length();
+  for (PRUint32 idx = 0; idx < len; idx++) {
+    nsITextAttr *textAttr = aTextAttrArray[idx];
+    if (!textAttr->Equal(currElm)) {
+
+      PRInt32 startHTOffset = 0;
+      nsCOMPtr<nsIAccessible> startAcc;
+      nsresult rv = mHyperTextAcc->
+        DOMPointToHypertextOffset(aPrevNode, -1, &startHTOffset,
+                                  getter_AddRefs(startAcc));
+      NS_ENSURE_SUCCESS(rv, PR_FALSE);
+
+      if (!startAcc)
+        startHTOffset = 0;
+
+      if (startHTOffset > *aHTOffset)
+        *aHTOffset = startHTOffset;
+
+      return PR_TRUE;
+    }
+  }
+
+  // Moving backwards to find the start of range.
+  aCurrNode->GetPreviousSibling(getter_AddRefs(nextNode));
+  if (nextNode) {
+    if (FindStartOffsetInSubtree(aTextAttrArray, nextNode, aCurrNode, aHTOffset))
+      return PR_TRUE;
+  }
+
+  return PR_FALSE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsLangTextAttr
+
+nsLangTextAttr::nsLangTextAttr(nsHyperTextAccessible *aRootAcc, 
+                               nsIDOMNode *aRootNode, nsIDOMNode *aNode) :
+  nsTextAttr<nsAutoString>(aNode == nsnull)
+{
+  mRootContent = do_QueryInterface(aRootNode);
+
+  nsresult rv = aRootAcc->GetLanguage(mRootNativeValue);
+  mIsRootDefined = NS_SUCCEEDED(rv) && !mRootNativeValue.IsEmpty();
+
+  if (aNode) {
+    nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
+    mIsDefined = GetLang(content, mNativeValue);
+  }
+}
+
+PRBool
+nsLangTextAttr::GetValueFor(nsIDOMElement *aElm, nsAutoString *aValue)
+{
+  nsCOMPtr<nsIContent> content = do_QueryInterface(aElm);
+  return GetLang(content, *aValue);
+}
+
+void
+nsLangTextAttr::Format(const nsAutoString& aValue, nsAString& aFormattedValue)
+{
+  aFormattedValue = aValue;
+}
+
+PRBool
+nsLangTextAttr::GetLang(nsIContent *aContent, nsAString& aLang)
+{
+  nsCoreUtils::GetLanguageFor(aContent, mRootContent, aLang);
+  return !aLang.IsEmpty();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsCSSTextAttr
+
+nsCSSTextAttr::nsCSSTextAttr(PRUint32 aIndex, nsIDOMElement *aRootElm,
+                             nsIDOMElement *aElm) :
+  nsTextAttr<nsAutoString>(aElm == nsnull), mIndex(aIndex)
+{
+  mIsRootDefined = GetValueFor(aRootElm, &mRootNativeValue);
+
+  if (aElm)
+    mIsDefined = GetValueFor(aElm, &mNativeValue);
+}
+
+nsIAtom*
+nsCSSTextAttr::GetName()
+{
+  return *gCSSTextAttrsMap[mIndex].mAttrName;
+}
+
+PRBool
+nsCSSTextAttr::GetValueFor(nsIDOMElement *aElm, nsAutoString *aValue)
+{
+  nsCOMPtr<nsIDOMCSSStyleDeclaration> currStyleDecl;
+  nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), aElm,
+                                           getter_AddRefs(currStyleDecl));
+  if (!currStyleDecl)
+    return PR_FALSE;
+
+  NS_ConvertASCIItoUTF16 cssName(gCSSTextAttrsMap[mIndex].mCSSName);
+
+  nsresult rv = currStyleDecl->GetPropertyValue(cssName, *aValue);
+  if (NS_FAILED(rv))
+    return PR_TRUE;
+
+  const char *cssValue = gCSSTextAttrsMap[mIndex].mCSSValue;
+  if (cssValue != kAnyValue && !aValue->EqualsASCII(cssValue))
+    return PR_FALSE;
+
+  return PR_TRUE;
+}
+
+void
+nsCSSTextAttr::Format(const nsAutoString& aValue, nsAString& aFormattedValue)
+{
+  const char *attrValue = gCSSTextAttrsMap[mIndex].mAttrValue;
+  if (attrValue != kCopyValue)
+    AppendASCIItoUTF16(attrValue, aFormattedValue);
+  else
+    aFormattedValue = aValue;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsBackgroundTextAttr
+
+nsBGColorTextAttr::nsBGColorTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame) :
+  nsTextAttr<nscolor>(aFrame == nsnull), mRootFrame(aRootFrame)
+{
+  mIsRootDefined = GetColor(mRootFrame, &mRootNativeValue);
+  if (aFrame)
+    mIsDefined = GetColor(aFrame, &mNativeValue);
+}
+
+PRBool
+nsBGColorTextAttr::GetValueFor(nsIDOMElement *aElm, nscolor *aValue)
+{
+  nsIFrame *frame = nsCoreUtils::GetFrameFor(aElm);
+  if (!frame)
+    return PR_FALSE;
+
+  return GetColor(frame, aValue);
+}
+
+void
+nsBGColorTextAttr::Format(const nscolor& aValue, nsAString& aFormattedValue)
+{
+  // Combine the string like rgb(R, G, B) from nscolor.
+  nsAutoString value;
+  value.AppendLiteral("rgb(");
+  value.AppendInt(NS_GET_R(aValue));
+  value.AppendLiteral(", ");
+  value.AppendInt(NS_GET_G(aValue));
+  value.AppendLiteral(", ");
+  value.AppendInt(NS_GET_B(aValue));
+  value.Append(')');
+
+  aFormattedValue = value;
+}
+
+PRBool
+nsBGColorTextAttr::GetColor(nsIFrame *aFrame, nscolor *aColor)
+{
+  const nsStyleBackground *styleBackground = aFrame->GetStyleBackground();
+
+  if (NS_GET_A(styleBackground->mFallbackBackgroundColor) > 0) {
+    *aColor = styleBackground->mFallbackBackgroundColor;
+    return PR_TRUE;
+  }
+
+  nsIFrame *parentFrame = aFrame->GetParent();
+  if (!parentFrame) {
+    *aColor = aFrame->PresContext()->DefaultBackgroundColor();
+    return PR_TRUE;
+  }
+
+  // Each frame of parents chain for the initially passed 'aFrame' has
+  // transparent background color. So background color isn't changed from
+  // 'mRootFrame' to initially passed 'aFrame'.
+  if (parentFrame == mRootFrame)
+    return PR_FALSE;
+
+  return GetColor(parentFrame, aColor);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsFontSizeTextAttr
+
+nsFontSizeTextAttr::nsFontSizeTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame) :
+  nsTextAttr<nscoord>(aFrame == nsnull)
+{
+  mDC = aRootFrame->PresContext()->DeviceContext();
+
+  mRootNativeValue = GetFontSize(aRootFrame);
+  mIsRootDefined = PR_TRUE;
+
+  if (aFrame) {
+    mNativeValue = GetFontSize(aFrame);
+    mIsDefined = PR_TRUE;
+  }
+}
+
+PRBool
+nsFontSizeTextAttr::GetValueFor(nsIDOMElement *aElm, nscoord *aValue)
+{
+  nsIFrame *frame = nsCoreUtils::GetFrameFor(aElm);
+  if (!frame)
+    return PR_FALSE;
+  
+  *aValue = GetFontSize(frame);
+  return PR_TRUE;
+}
+
+void
+nsFontSizeTextAttr::Format(const nscoord& aValue, nsAString& aFormattedValue)
+{
+  // Convert from nscoord to pt.
+  //
+  // Note: according to IA2, "The conversion doesn't have to be exact.
+  // The intent is to give the user a feel for the size of the text."
+  // 
+  // ATK does not specify a unit and will likely follow IA2 here.
+  //
+  // XXX todo: consider sharing this code with layout module? (bug 474621)
+  float inches = static_cast<float>(aValue) /
+    static_cast<float>(mDC->AppUnitsPerInch());
+  int pts = static_cast<int>(inches * 72 + .5); // 72 pts per inch
+
+  nsAutoString value;
+  value.AppendInt(pts);
+  value.Append(NS_LITERAL_STRING("pt"));
+  aFormattedValue = value;
+}
+
+nscoord
+nsFontSizeTextAttr::GetFontSize(nsIFrame *aFrame)
+{
+  nsStyleFont* styleFont =
+    (nsStyleFont*)(aFrame->GetStyleDataExternal(eStyleStruct_Font));
+
+  return styleFont->mSize;
+}
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/nsTextAttrs.h
@@ -0,0 +1,371 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Alexander Surkov <surkov.alexander@gmail.com> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsTextAttrs_h_
+#define nsTextAttrs_h_
+
+class nsHyperTextAccessible;
+
+#include "nsAccessibilityAtoms.h"
+
+#include "nsIDOMNode.h"
+#include "nsIDOMElement.h"
+#include "nsIDOMCSSStyleDeclaration.h"
+
+#include "nsIContent.h"
+#include "nsIFrame.h"
+#include "nsIPersistentProperties2.h"
+
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#include "nsTPtrArray.h"
+
+class nsITextAttr;
+
+/**
+ * Used to expose text attributes for the hyper text accessible (see
+ * nsHyperTextAccessible class). It is indended for the work with 'language' and
+ * CSS based text attributes.
+ *
+ * @note "invalid: spelling" text attrbiute is implemented entirerly in
+ *       nsHyperTextAccessible class.
+ */
+class nsTextAttrsMgr
+{
+public:
+  /**
+   * Constructor. If instance of the class is intended to expose default text
+   * attributes then 'aIncludeDefAttrs' and 'oOffsetNode' argument must be
+   * skiped.
+   *
+   * @param aHyperTextAcc    hyper text accessible text attributes are
+   *                         calculated for
+   * @param aHyperTextNode   DOM node of the given hyper text accessbile
+   * @param aIncludeDefAttrs [optional] indicates whether default text
+   *                         attributes should be included into list of exposed
+   *                         text attributes.
+   * @param oOffsetNode      [optional] DOM node represents hyper text offset
+   *                         inside hyper text accessible
+   */
+  nsTextAttrsMgr(nsHyperTextAccessible *aHyperTextAcc,
+                 nsIDOMNode *aHyperTextNode,
+                 PRBool aIncludeDefAttrs = PR_TRUE,
+                 nsIDOMNode *oOffsetNode = nsnull);
+
+  /*
+   * Return text attributes and hyper text offsets where these attributes are
+   * applied. Offsets are calculated in the case of non default attributes.
+   *
+   * @note In the case of default attributes pointers on hyper text offsets
+   *       must be skiped.
+   *
+   * @param aAttributes    [in, out] text attributes list
+   * @param aStartHTOffset [out, optional] start hyper text offset
+   * @param aEndHTOffset   [out, optional] end hyper text offset
+   */
+  nsresult GetAttributes(nsIPersistentProperties *aAttributes,
+                         PRInt32 *aStartHTOffset = nsnull,
+                         PRInt32 *aEndHTOffset = nsnull);
+
+protected:
+
+  /**
+   * Calculates range (start and end offsets) of text where the text attributes
+   * are stretched. New offsets may be smaller if one of text attributes changes
+   * its value before or after the given offsets.
+   *
+   * @param aTextAttrArray  [in] text attributes array
+   * @param aStartHTOffset  [in, out] the start offset
+   * @param aEndHTOffset    [in, out] the end offset
+   */
+   nsresult GetRange(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
+                     PRInt32 *aStartHTOffset, PRInt32 *aEndHTOffset);
+
+  /*
+   * Find new end offset for text attributes navigating through the tree. New
+   * end offset may be smaller if one of text attributes changes its value
+   * before the given end offset.
+   *
+   * @param  aTextAttrArray  [in] text attributes array
+   * @param  aCurrNode       [in] the first node of the tree
+   * @param  aHTOffset       [in, out] the end offset
+   * @return                 true if the end offset has been changed
+   */
+   PRBool FindEndOffsetInSubtree(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
+                                 nsIDOMNode *aCurrNode, PRInt32 *aHTOffset);
+
+  /*
+   * Find the start offset for text attributes navigating through the tree. New
+   * start offset may be bigger if one of text attributes changes its value
+   * after the given start offset.
+   *
+   * @param  aTextAttrArray  [in] text attributes array
+   * @param  aCurrNode       [in] the node navigating through thee thee is
+   *                         started from
+   * @param  aPrevNode       [in] the previous node placed before the start node
+   * @param  aHTOffset       [in, out] the start offset
+   * @return                 true if the start offset has been changed
+   */
+   PRBool FindStartOffsetInSubtree(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
+                                   nsIDOMNode *aCurrNode, nsIDOMNode *aPrevNode,
+                                   PRInt32 *aHTOffset);
+
+private:
+  nsRefPtr<nsHyperTextAccessible> mHyperTextAcc;
+  nsCOMPtr<nsIDOMNode> mHyperTextNode;
+
+  PRBool mIncludeDefAttrs;
+  nsCOMPtr<nsIDOMNode> mOffsetNode;
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Private implementation details
+
+/**
+ * Interface class of text attribute class implementations.
+ */
+class nsITextAttr
+{
+public:
+  /**
+   * Return the name of text attribute.
+   */
+  virtual nsIAtom* GetName() = 0;
+
+  /**
+   * Retrieve the value of text attribute in out param, return true if differs
+   * from the default value of text attribute or if include default attribute
+   * value flag is setted.
+   * 
+   * @param aValue                [in, out] the value of text attribute
+   * @param aIncludeDefAttrValue  [in] include default attribute value flag
+   * @return                      true if text attribute value differs from
+   *                              default or include default attribute value
+   *                              flag is applied
+   */
+  virtual PRBool GetValue(nsAString& aValue, PRBool aIncludeDefAttrValue) = 0;
+
+  /**
+   * Return true if the text attribute value on the given element equals with
+   * predefined attribute value.
+   */
+  virtual PRBool Equal(nsIDOMElement *aElm) = 0;
+};
+
+
+/**
+ * Base class to work with text attributes. See derived classes below.
+ */
+template<class T>
+class nsTextAttr : public nsITextAttr
+{
+public:
+  nsTextAttr(PRBool aGetRootValue) : mGetRootValue(aGetRootValue) {}
+
+  // nsITextAttr
+  virtual PRBool GetValue(nsAString& aValue, PRBool aIncludeDefAttrValue)
+  {
+    if (mGetRootValue) {
+      Format(mRootNativeValue, aValue);
+      return mIsRootDefined;
+    }
+
+    PRBool isDefined = mIsDefined;
+    T* nativeValue = &mNativeValue;
+
+    if (!isDefined) {
+      if (aIncludeDefAttrValue) {
+        isDefined = mIsRootDefined;
+        nativeValue = &mRootNativeValue;
+      }
+    } else if (!aIncludeDefAttrValue) {
+      isDefined = mRootNativeValue != mNativeValue;
+    }
+
+    if (!isDefined)
+      return PR_FALSE;
+
+    Format(*nativeValue, aValue);
+    return PR_TRUE;
+  }
+
+  virtual PRBool Equal(nsIDOMElement *aElm)
+  {
+    T nativeValue;
+    PRBool isDefined = GetValueFor(aElm, &nativeValue);
+
+    if (!mIsDefined && !isDefined)
+      return PR_TRUE;
+
+    if (mIsDefined && isDefined)
+      return nativeValue == mNativeValue;
+
+    if (mIsDefined)
+      return mNativeValue == mRootNativeValue;
+
+    return nativeValue == mRootNativeValue;
+  }
+
+protected:
+
+  // Return native value for the given DOM element.
+  virtual PRBool GetValueFor(nsIDOMElement *aElm, T *aValue) = 0;
+
+  // Format native value to text attribute value.
+  virtual void Format(const T& aValue, nsAString& aFormattedValue) = 0;
+
+  // Indicates if root value should be exposed.
+  PRBool mGetRootValue;
+
+  // Native value and flag indicating if the value is defined (initialized in
+  // derived classes). Note, undefined native value means it is inherited
+  // from root.
+  T mNativeValue;
+  PRBool mIsDefined;
+
+  // Native root value and flag indicating if the value is defined  (initialized
+  // in derived classes).
+  T mRootNativeValue;
+  PRBool mIsRootDefined;
+};
+
+
+/**
+ * Class is used for the work with 'language' text attribute in nsTextAttrsMgr
+ * class.
+ */
+class nsLangTextAttr : public nsTextAttr<nsAutoString>
+{
+public:
+  nsLangTextAttr(nsHyperTextAccessible *aRootAcc, nsIDOMNode *aRootNode,
+                 nsIDOMNode *aNode);
+
+  // nsITextAttr
+  virtual nsIAtom *GetName() { return nsAccessibilityAtoms::language; }
+
+protected:
+
+  // nsTextAttr
+  virtual PRBool GetValueFor(nsIDOMElement *aElm, nsAutoString *aValue);
+  virtual void Format(const nsAutoString& aValue, nsAString& aFormattedValue);
+
+private:
+  PRBool GetLang(nsIContent *aContent, nsAString& aLang);
+  nsCOMPtr<nsIContent> mRootContent;
+};
+
+
+/**
+ * Class is used for the work with CSS based text attributes in nsTextAttrsMgr
+ * class.
+ */
+class nsCSSTextAttr : public nsTextAttr<nsAutoString>
+{
+public:
+  nsCSSTextAttr(PRUint32 aIndex, nsIDOMElement *aRootElm, nsIDOMElement *aElm);
+
+  // nsITextAttr
+  virtual nsIAtom *GetName();
+
+protected:
+
+  // nsTextAttr
+  virtual PRBool GetValueFor(nsIDOMElement *aElm, nsAutoString *aValue);
+  virtual void Format(const nsAutoString& aValue, nsAString& aFormattedValue);
+
+private:
+  PRInt32 mIndex;
+};
+
+
+/**
+ * Class is used for the work with 'background-color' text attribute in
+ * nsTextAttrsMgr class.
+ */
+class nsBGColorTextAttr : public nsTextAttr<nscolor>
+{
+public:
+  nsBGColorTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame);
+
+  // nsITextAttr
+  virtual nsIAtom *GetName() { return nsAccessibilityAtoms::backgroundColor; }
+
+protected:
+  // nsTextAttr
+  virtual PRBool GetValueFor(nsIDOMElement *aElm, nscolor *aValue);
+  virtual void Format(const nscolor& aValue, nsAString& aFormattedValue);
+
+private:
+  PRBool GetColor(nsIFrame *aFrame, nscolor *aColor);
+  nsIFrame *mRootFrame;
+};
+
+
+/**
+ * Class is used for the work with "font-size" text attribute in nsTextAttrsMgr
+ * class.
+ */
+class nsFontSizeTextAttr : public nsTextAttr<nscoord>
+{
+public:
+  nsFontSizeTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame);
+
+  // nsITextAttr
+  virtual nsIAtom *GetName() { return nsAccessibilityAtoms::fontSize; }
+
+protected:
+
+  // nsTextAttr
+  virtual PRBool GetValueFor(nsIDOMElement *aElm, nscoord *aValue);
+  virtual void Format(const nscoord& aValue, nsAString& aFormattedValue);
+
+private:
+
+  /**
+   * Return font size for the given frame.
+   *
+   * @param aFrame      [in] the given frame to query font-size
+   * @return            font size
+   */
+   nscoord GetFontSize(nsIFrame *aFrame);
+
+  nsIDeviceContext *mDC;
+};
+
+#endif
rename from accessible/src/base/nsNameUtils.cpp
rename to accessible/src/base/nsTextEquivUtils.cpp
--- a/accessible/src/base/nsNameUtils.cpp
+++ b/accessible/src/base/nsTextEquivUtils.cpp
@@ -32,22 +32,361 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "nsNameUtils.h"
+#include "nsTextEquivUtils.h"
+
+#include "nsAccessible.h"
+
+#include "nsIDOMXULLabeledControlEl.h"
+
+#include "nsArrayUtils.h"
+
+#define NS_OK_NO_NAME_CLAUSE_HANDLED \
+NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_GENERAL, 0x24)
+
+////////////////////////////////////////////////////////////////////////////////
+// nsTextEquivUtils. Public.
+
+nsresult
+nsTextEquivUtils::GetNameFromSubtree(nsIAccessible *aAccessible,
+                                     nsAString& aName)
+{
+  aName.Truncate();
+
+  if (gInitiatorAcc)
+    return NS_OK;
+
+  gInitiatorAcc = aAccessible;
+
+  PRUint32 role = nsAccUtils::Role(aAccessible);
+  PRUint32 nameRule = gRoleToNameRulesMap[role];
+
+  if (nameRule == eFromSubtree) {
+    nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(aAccessible));
+
+    nsCOMPtr<nsIDOMNode> DOMNode;
+    accessNode->GetDOMNode(getter_AddRefs(DOMNode));
+    nsCOMPtr<nsIContent> content(do_QueryInterface(DOMNode));
+    if (content) {
+      nsAutoString name;
+      AppendFromAccessibleChildren(aAccessible, &name);
+      name.CompressWhitespace();
+      aName = name;
+    }
+  }
+
+  gInitiatorAcc = nsnull;
+
+  return NS_OK;
+}
+
+nsresult
+nsTextEquivUtils::GetTextEquivFromIDRefs(nsIAccessible *aAccessible,
+                                         nsIAtom *aIDRefsAttr,
+                                         nsAString& aTextEquiv)
+{
+  aTextEquiv.Truncate();
+
+  nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(aAccessible));
+
+  nsCOMPtr<nsIDOMNode> DOMNode;
+  accessNode->GetDOMNode(getter_AddRefs(DOMNode));
+
+  nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(DOMNode);
+  if (!content)
+    return NS_OK;
+
+  nsCOMPtr<nsIArray> refElms;
+  nsCoreUtils::GetElementsByIDRefsAttr(content, aIDRefsAttr,
+                                       getter_AddRefs(refElms));
+
+  if (!refElms)
+    return NS_OK;
+
+  PRUint32 count = 0;
+  nsresult rv = refElms->GetLength(&count);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIContent> refContent;
+  for (PRUint32 idx = 0; idx < count; idx++) {
+    refContent = do_QueryElementAt(refElms, idx, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (!aTextEquiv.IsEmpty())
+      aTextEquiv += ' ';
+
+    rv = AppendTextEquivFromContent(aAccessible, refContent, &aTextEquiv);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return NS_OK;
+}
+
+nsresult
+nsTextEquivUtils::AppendTextEquivFromContent(nsIAccessible *aInitiatorAcc,
+                                             nsIContent *aContent,
+                                             nsAString *aString)
+{
+  // Prevent recursion which can cause infinite loops.
+  if (gInitiatorAcc)
+    return NS_OK;
+
+  gInitiatorAcc = aInitiatorAcc;
+
+  nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(aContent));
+  nsCOMPtr<nsIPresShell> shell = nsCoreUtils::GetPresShellFor(DOMNode);
+  if (!shell) {
+    NS_ASSERTION(PR_TRUE, "There is no presshell!");
+    gInitiatorAcc = nsnull;
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  // If the given content is not visible or isn't accessible then go down
+  // through the DOM subtree otherwise go down through accessible subtree and
+  // calculate the flat string.
+  nsIFrame *frame = shell->GetPrimaryFrameFor(aContent);
+  PRBool isVisible = frame && frame->GetStyleVisibility()->IsVisible();
+
+  nsresult rv;
+  PRBool goThroughDOMSubtree = PR_TRUE;
+
+  if (isVisible) {
+    nsCOMPtr<nsIAccessible> accessible;
+    rv = nsAccessNode::GetAccService()->
+      GetAccessibleInShell(DOMNode, shell, getter_AddRefs(accessible));
+    if (NS_SUCCEEDED(rv) && accessible) {
+      rv = AppendFromAccessible(accessible, aString);
+      goThroughDOMSubtree = PR_FALSE;
+    }
+  }
+
+  if (goThroughDOMSubtree)
+    rv = AppendFromDOMNode(aContent, aString);
+
+  gInitiatorAcc = nsnull;
+  return rv;
+}
+
+nsresult
+nsTextEquivUtils::AppendTextEquivFromTextContent(nsIContent *aContent,
+                                                 nsAString *aString)
+{
+  if (aContent->IsNodeOfType(nsINode::eTEXT)) {
+    
+    nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(aContent));
+    
+    PRBool isHTMLBlock = PR_FALSE;
+    nsCOMPtr<nsIPresShell> shell = nsCoreUtils::GetPresShellFor(DOMNode);
+    NS_ENSURE_STATE(shell);
+    
+    nsIContent *parentContent = aContent->GetParent();
+    if (parentContent) {
+      nsIFrame *frame = shell->GetPrimaryFrameFor(parentContent);
+      if (frame) {
+        // If this text is inside a block level frame (as opposed to span
+        // level), we need to add spaces around that block's text, so we don't
+        // get words jammed together in final name.
+        const nsStyleDisplay* display = frame->GetStyleDisplay();
+        if (display->IsBlockOutside() ||
+            display->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL) {
+          isHTMLBlock = PR_TRUE;
+          if (!aString->IsEmpty()) {
+            aString->Append(PRUnichar(' '));
+          }
+        }
+      }
+    }
+    
+    if (aContent->TextLength() > 0) {
+      nsIFrame *frame = shell->GetPrimaryFrameFor(aContent);
+      if (frame) {
+        nsresult rv = frame->GetRenderedText(aString);
+        NS_ENSURE_SUCCESS(rv, rv);
+      } else {
+        // If aContent is an object that is display: none, we have no a frame.
+        aContent->AppendTextTo(*aString);
+      }
+      if (isHTMLBlock && !aString->IsEmpty()) {
+        aString->Append(PRUnichar(' '));
+      }
+    }
+    
+    return NS_OK;
+  }
+  
+  if (aContent->IsNodeOfType(nsINode::eHTML) &&
+      aContent->NodeInfo()->Equals(nsAccessibilityAtoms::br)) {
+    aString->AppendLiteral("\r\n");
+    return NS_OK;
+  }
+  
+  return NS_OK_NO_NAME_CLAUSE_HANDLED;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsTextEquivUtils. Private.
+
+nsCOMPtr<nsIAccessible> nsTextEquivUtils::gInitiatorAcc;
+
+nsresult
+nsTextEquivUtils::AppendFromAccessibleChildren(nsIAccessible *aAccessible,
+                                               nsAString *aString)
+{
+  nsCOMPtr<nsIAccessible> accChild, accNextChild;
+  aAccessible->GetFirstChild(getter_AddRefs(accChild));
+
+  while (accChild) {
+    nsresult rv = AppendFromAccessible(accChild, aString);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    accChild->GetNextSibling(getter_AddRefs(accNextChild));
+    accChild.swap(accNextChild);
+  }
+
+  return NS_OK;
+}
+
+nsresult
+nsTextEquivUtils::AppendFromAccessible(nsIAccessible *aAccessible,
+                                       nsAString *aString)
+{
+  nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(aAccessible));
+
+  nsCOMPtr<nsIDOMNode> DOMNode;
+  accessNode->GetDOMNode(getter_AddRefs(DOMNode));
+  nsCOMPtr<nsIContent> content(do_QueryInterface(DOMNode));
+  NS_ASSERTION(content, "There is no content!");
+
+  if (content) {
+    nsresult rv = AppendTextEquivFromTextContent(content, aString);
+    if (rv != NS_OK_NO_NAME_CLAUSE_HANDLED)
+      return rv;
+  }
+
+  nsAutoString text;
+  nsresult rv = aAccessible->GetName(text);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  AppendString(aString, text);
+
+  PRUint32 role = nsAccUtils::Role(aAccessible);
+  PRUint32 nameRule = gRoleToNameRulesMap[role];
+
+  if (nameRule == eFromValue) {
+    // Implementation of step f) of text equivalent computation. If the given
+    // accessible is not root accessible (the accessible the text equivalent is
+    // computed for in the end) then append accessible value. Otherwise append
+    // value if and only if the given accessible is in the middle of its parent.
+
+    if (aAccessible != gInitiatorAcc) {
+      rv = aAccessible->GetValue(text);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      AppendString(aString, text);
+    } else {
+      nsCOMPtr<nsIAccessible> nextSibling;
+      aAccessible->GetNextSibling(getter_AddRefs(nextSibling));
+      if (nextSibling) {
+        nsCOMPtr<nsIAccessible> parent;
+        aAccessible->GetParent(getter_AddRefs(parent));
+        if (parent) {
+          nsCOMPtr<nsIAccessible> firstChild;
+          parent->GetFirstChild(getter_AddRefs(firstChild));
+          if (firstChild && firstChild != aAccessible) {
+            rv = aAccessible->GetValue(text);
+            NS_ENSURE_SUCCESS(rv, rv);
+
+            AppendString(aString, text);
+          }
+        }
+      }
+    }
+  }
+
+  // Implementation of g) step of text equivalent computation guide. Go down
+  // into subtree if accessible allows "text equivalent from subtree rule" or
+  // it's not root and not control.
+  if (text.IsEmpty() && (nameRule & eFromSubtreeIfRec))
+    return AppendFromAccessibleChildren(aAccessible, aString);
+
+  return NS_OK;
+}
+
+nsresult
+nsTextEquivUtils::AppendFromDOMChildren(nsIContent *aContent,
+                                        nsAString *aString)
+{
+  PRUint32 childCount = aContent->GetChildCount();
+  for (PRUint32 childIdx = 0; childIdx < childCount; childIdx++) {
+    nsCOMPtr<nsIContent> childContent = aContent->GetChildAt(childIdx);
+
+    nsresult rv = AppendFromDOMNode(childContent, aString);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return NS_OK;
+}
+
+nsresult
+nsTextEquivUtils::AppendFromDOMNode(nsIContent *aContent, nsAString *aString)
+{
+  nsresult rv = AppendTextEquivFromTextContent(aContent, aString);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (rv != NS_OK_NO_NAME_CLAUSE_HANDLED)
+    return NS_OK;
+
+  if (aContent->IsNodeOfType(nsINode::eXUL)) {
+    nsAutoString textEquivalent;
+    nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl =
+      do_QueryInterface(aContent);
+
+    if (labeledEl) {
+      labeledEl->GetLabel(textEquivalent);
+    } else {
+      if (aContent->NodeInfo()->Equals(nsAccessibilityAtoms::label,
+                                       kNameSpaceID_XUL))
+        aContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::value,
+                          textEquivalent);
+
+      if (textEquivalent.IsEmpty())
+        aContent->GetAttr(kNameSpaceID_None,
+                          nsAccessibilityAtoms::tooltiptext, textEquivalent);
+    }
+
+    AppendString(aString, textEquivalent);
+  }
+
+  return AppendFromDOMChildren(aContent, aString);
+}
+
+void
+nsTextEquivUtils::AppendString(nsAString *aString,
+                               const nsAString& aTextEquivalent)
+{
+  // Insert spaces to insure that words from controls aren't jammed together.
+  if (aTextEquivalent.IsEmpty())
+    return;
+
+  if (!aString->IsEmpty())
+    aString->Append(PRUnichar(' '));
+
+  aString->Append(aTextEquivalent);
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 // Name rules to role map.
 
-PRUint32 nsNameUtils::gRoleToNameRulesMap[] =
+PRUint32 nsTextEquivUtils::gRoleToNameRulesMap[] =
 {
   eNoRule,           // ROLE_NOTHING
   eNoRule,           // ROLE_TITLEBAR
   eNoRule,           // ROLE_MENUBAR
   eNoRule,           // ROLE_SCROLLBAR
   eNoRule,           // ROLE_GRIP
   eNoRule,           // ROLE_SOUND
   eNoRule,           // ROLE_CURSOR
@@ -68,36 +407,36 @@ PRUint32 nsNameUtils::gRoleToNameRulesMa
   eNoRule,           // ROLE_SEPARATOR
   eNoRule,           // ROLE_TOOLBAR
   eNoRule,           // ROLE_STATUSBAR
   eNoRule,           // ROLE_TABLE
   eFromSubtree,      // ROLE_COLUMNHEADER
   eFromSubtree,      // ROLE_ROWHEADER
   eFromSubtree,      // ROLE_COLUMN
   eFromSubtree,      // ROLE_ROW
-  eNoRule,           // ROLE_CELL
+  eFromSubtreeIfRec, // ROLE_CELL
   eFromSubtree,      // ROLE_LINK
   eFromSubtree,      // ROLE_HELPBALLOON
   eNoRule,           // ROLE_CHARACTER
-  eNoRule,           // ROLE_LIST
+  eFromSubtreeIfRec, // ROLE_LIST
   eFromSubtree,      // ROLE_LISTITEM
   eNoRule,           // ROLE_OUTLINE
   eFromSubtree,      // ROLE_OUTLINEITEM
   eFromSubtree,      // ROLE_PAGETAB
   eNoRule,           // ROLE_PROPERTYPAGE
   eNoRule,           // ROLE_INDICATOR
   eNoRule,           // ROLE_GRAPHIC
   eNoRule,           // ROLE_STATICTEXT
   eNoRule,           // ROLE_TEXT_LEAF
   eFromSubtree,      // ROLE_PUSHBUTTON
   eFromSubtree,      // ROLE_CHECKBUTTON
   eFromSubtree,      // ROLE_RADIOBUTTON
-  eNoRule,           // ROLE_COMBOBOX
+  eFromValue,        // ROLE_COMBOBOX
   eNoRule,           // ROLE_DROPLIST
-  eNoRule,           // ROLE_PROGRESSBAR
+  eFromValue,        // ROLE_PROGRESSBAR
   eNoRule,           // ROLE_DIAL
   eNoRule,           // ROLE_HOTKEYFIELD
   eNoRule,           // ROLE_SLIDER
   eNoRule,           // ROLE_SPINBUTTON
   eNoRule,           // ROLE_DIAGRAM
   eNoRule,           // ROLE_ANIMATION
   eNoRule,           // ROLE_EQUATION
   eFromSubtree,      // ROLE_BUTTONDROPDOWN
@@ -116,47 +455,47 @@ PRUint32 nsNameUtils::gRoleToNameRulesMa
   eNoRule,           // ROLE_DATE_EDITOR
   eNoRule,           // ROLE_DESKTOP_ICON
   eNoRule,           // ROLE_DESKTOP_FRAME
   eNoRule,           // ROLE_DIRECTORY_PANE
   eNoRule,           // ROLE_FILE_CHOOSER
   eNoRule,           // ROLE_FONT_CHOOSER
   eNoRule,           // ROLE_CHROME_WINDOW
   eNoRule,           // ROLE_GLASS_PANE
-  eNoRule,           // ROLE_HTML_CONTAINER
+  eFromSubtreeIfRec, // ROLE_HTML_CONTAINER
   eNoRule,           // ROLE_ICON
-  eNoRule,           // ROLE_LABEL
+  eFromSubtree,      // ROLE_LABEL
   eNoRule,           // ROLE_LAYERED_PANE
   eNoRule,           // ROLE_OPTION_PANE
   eNoRule,           // ROLE_PASSWORD_TEXT
   eNoRule,           // ROLE_POPUP_MENU
   eFromSubtree,      // ROLE_RADIO_MENU_ITEM
   eNoRule,           // ROLE_ROOT_PANE
   eNoRule,           // ROLE_SCROLL_PANE
   eNoRule,           // ROLE_SPLIT_PANE
   eFromSubtree,      // ROLE_TABLE_COLUMN_HEADER
   eFromSubtree,      // ROLE_TABLE_ROW_HEADER
   eFromSubtree,      // ROLE_TEAR_OFF_MENU_ITEM
   eNoRule,           // ROLE_TERMINAL
-  eNoRule,           // ROLE_TEXT_CONTAINER
+  eFromSubtreeIfRec, // ROLE_TEXT_CONTAINER
   eFromSubtree,      // ROLE_TOGGLE_BUTTON
   eNoRule,           // ROLE_TREE_TABLE
   eNoRule,           // ROLE_VIEWPORT
   eNoRule,           // ROLE_HEADER
   eNoRule,           // ROLE_FOOTER
-  eNoRule,           // ROLE_PARAGRAPH
+  eFromSubtreeIfRec, // ROLE_PARAGRAPH
   eNoRule,           // ROLE_RULER
   eNoRule,           // ROLE_AUTOCOMPLETE
   eNoRule,           // ROLE_EDITBAR
-  eNoRule,           // ROLE_ENTRY
+  eFromValue,        // ROLE_ENTRY
   eNoRule,           // ROLE_CAPTION
   eNoRule,           // ROLE_DOCUMENT_FRAME
   eNoRule,           // ROLE_HEADING
   eNoRule,           // ROLE_PAGE
-  eNoRule,           // ROLE_SECTION
+  eFromSubtreeIfRec, // ROLE_SECTION
   eNoRule,           // ROLE_REDUNDANT_OBJECT
   eNoRule,           // ROLE_FORM
   eNoRule,           // ROLE_IME
   eNoRule,           // ROLE_APP_ROOT
   eFromSubtree,      // ROLE_PARENT_MENUITEM
   eNoRule,           // ROLE_CALENDAR
   eNoRule,           // ROLE_COMBOBOX_LIST
   eFromSubtree,      // ROLE_COMBOBOX_OPTION
rename from accessible/src/base/nsNameUtils.h
rename to accessible/src/base/nsTextEquivUtils.h
--- a/accessible/src/base/nsNameUtils.h
+++ b/accessible/src/base/nsTextEquivUtils.h
@@ -32,40 +32,137 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#ifndef _nsNameUtils_H_
-#define _nsNameUtils_H_
+#ifndef _nsTextEquivUtils_H_
+#define _nsTextEquivUtils_H_
 
-#include "prtypes.h"
+#include "nsIAccessible.h"
+
+#include "nsIContent.h"
+#include "nsIStringBundle.h"
 
 /**
- * Name from subtree calculation rules.
+ * Text equivalent computation rules (see nsTextEquivUtils::gRoleToNameRulesMap)
  */
-enum ENameFromSubtreeRule
+enum ETextEquivRule
 {
-  // do not walk into subtree to compute the name
+  // No rule.
   eNoRule = 0x00,
-  
-  // compute the name from the subtree
-  eFromSubtree = 0x01
+
+  // Walk into subtree only if the currently navigated accessible is not root
+  // accessible (i.e. if the accessible is part of text equivalent computation).
+  eFromSubtreeIfRec = 0x01,
+
+  // Text equivalent computation from subtree is allowed.
+  eFromSubtree = 0x03,
+
+  // The accessible allows to append its value to text equivalent.
+  // XXX: This is temporary solution. Once we move accessible value of links
+  // and linkable accessibles to MSAA part we can remove this.
+  eFromValue = 0x04
 };
 
 /**
  * The class provides utils methods to compute the accessible name and
  * description.
  */
-class nsNameUtils
+class nsTextEquivUtils
 {
 public:
 
   /**
-   * Map array from roles to name rules (bit state of ENameFromSubtreeRule).
+   * Calculates the name from accessible subtree if allowed.
+   *
+   * @param aAccessible [in] the given accessible
+   * @param aName       [out] accessible name
+   */
+  static nsresult GetNameFromSubtree(nsIAccessible *aAccessible,
+                                     nsAString& aName);
+
+  /**
+   * Calculates text equivalent for the given accessible from its IDRefs
+   * attribute (like aria-labelledby or aria-describedby).
+   *
+   * @param aAccessible  [in] the accessible text equivalent is computed for
+   * @param aIDRefsAttr  [in] IDRefs attribute on DOM node of the accessible
+   * @param aTextEquiv   [out] result text equivalent
+   */
+  static nsresult GetTextEquivFromIDRefs(nsIAccessible *aAccessible,
+                                         nsIAtom *aIDRefsAttr,
+                                         nsAString& aTextEquiv);
+
+  /**
+   * Calculates the text equivalent from the given content and its subtree if
+   * allowed and appends it to the given string.
+   *
+   * @param aInitiatorAcc  [in] the accessible text equivalent is computed for
+   *                       in the end (root accessible of text equivalent
+   *                       calculation recursion)
+   * @param aContent       [in] the given content the text equivalent is
+   *                       computed from
+   * @param aString        [in, out] the string
+   */
+  static nsresult AppendTextEquivFromContent(nsIAccessible *aInitiatorAcc,
+                                             nsIContent *aContent,
+                                             nsAString *aString);
+
+  /**
+   * Calculates the text equivalent from the given text content (may be text
+   * node or html:br) and appends it to the given string.
+   *
+   * @param aContent       [in] the text content
+   * @param aString        [in, out] the string
+   */
+  static nsresult AppendTextEquivFromTextContent(nsIContent *aContent,
+                                                 nsAString *aString);
+
+private:
+  /**
+   * Iterates accessible children and calculates text equivalent from each
+   * child.
+   */
+  static nsresult AppendFromAccessibleChildren(nsIAccessible *aAccessible,
+                                               nsAString *aString);
+  
+  /**
+   * Calculates text equivalent from the given accessible and its subtree if
+   * allowed.
+   */
+  static nsresult AppendFromAccessible(nsIAccessible *aAccessible,
+                                       nsAString *aString);
+
+  /**
+   * Iterates DOM children and calculates text equivalent from each child node.
+   */
+  static nsresult AppendFromDOMChildren(nsIContent *aContent,
+                                        nsAString *aString);
+
+  /**
+   * Calculates text equivalent from the given DOM node and its subtree if
+   * allowed.
+   */
+  static nsresult AppendFromDOMNode(nsIContent *aContent, nsAString *aString);
+
+  /**
+   * Concatenates strings and appends space between them.
+   */
+  static void AppendString(nsAString *aString, const nsAString& aTextEquivalent);
+
+  /**
+   * Map array from roles to name rules (constants of ETextEquivRule).
    */
   static PRUint32 gRoleToNameRulesMap[];
+
+  /**
+   * The accessible for which we are computing a text equivalent. It is useful
+   * for bailing out during recursive text computation, or for special cases
+   * like step f. of the ARIA implementation guide.
+   */
+  static nsCOMPtr<nsIAccessible> gInitiatorAcc;
 };
 
 #endif
deleted file mode 100644
--- a/accessible/src/base/nsTextUtils.cpp
+++ /dev/null
@@ -1,298 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Alexander Surkov <surkov.alexander@gmail.com> (original author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsTextUtils.h"
-
-#include "nsAccessNode.h"
-
-////////////////////////////////////////////////////////////////////////////////
-// nsLangTextAttr
-
-PRBool
-nsLangTextAttr::Equal(nsIDOMElement *aElm)
-{
-  nsCOMPtr<nsIContent> content(do_QueryInterface(aElm));
-  if (!content)
-    return PR_FALSE;
-
-  nsAutoString lang;
-  nsCoreUtils::GetLanguageFor(content, mRootContent, lang);
-
-  return lang == mLang;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// nsCSSTextAttr
-
-/**
- * Item of the gCSSTextAttrsMap map.
- */
-struct nsCSSTextAttrMapItem
-{
-  const char* mCSSName;
-  const char* mCSSValue;
-  const char* mAttrName;
-  const char* mAttrValue;
-};
-
-/**
- * The map of CSS properties to text attributes.
- */
-
-const char* const kAnyValue = nsnull;
-const char* const kCopyName = nsnull;
-const char* const kCopyValue = nsnull;
-
-static nsCSSTextAttrMapItem gCSSTextAttrsMap[] = {
-  // CSS name            CSS value        Attribute name              Attribute value
-  { "color",             kAnyValue,       kCopyName,                  kCopyValue },
-  { "font-family",       kAnyValue,       kCopyName,                  kCopyValue },
-  { "font-style",        kAnyValue,       kCopyName,                  kCopyValue },
-  { "font-weight",       kAnyValue,       kCopyName,                  kCopyValue },
-  { "text-decoration",   "line-through",  "text-line-through-style",  "solid" },
-  { "text-decoration",   "underline",     "text-underline-style",     "solid" },
-  { "vertical-align",    kAnyValue,       "text-position",            kCopyValue }
-};
-
-nsCSSTextAttr::nsCSSTextAttr(PRBool aIncludeDefAttrValue, nsIDOMElement *aElm,
-                             nsIDOMElement *aRootElm) :
-  mIndex(-1), mIncludeDefAttrValue(aIncludeDefAttrValue)
-{
-  nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), aElm,
-                                           getter_AddRefs(mStyleDecl));
-
-  if (!mIncludeDefAttrValue)
-    nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), aRootElm,
-                                             getter_AddRefs(mDefStyleDecl));
-}
-
-PRBool
-nsCSSTextAttr::Equal(nsIDOMElement *aElm)
-{
-  if (!aElm || !mStyleDecl)
-    return PR_FALSE;
-
-  nsCOMPtr<nsIDOMCSSStyleDeclaration> currStyleDecl;
-  nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), aElm,
-                                           getter_AddRefs(currStyleDecl));
-  if (!currStyleDecl)
-    return PR_FALSE;
-
-  NS_ConvertASCIItoUTF16 cssName(gCSSTextAttrsMap[mIndex].mCSSName);
-
-  nsAutoString currValue;
-  nsresult rv = currStyleDecl->GetPropertyValue(cssName, currValue);
-  if (NS_FAILED(rv))
-    return PR_FALSE;
-
-  nsAutoString value;
-  rv = mStyleDecl->GetPropertyValue(cssName, value);
-  return NS_SUCCEEDED(rv) && value == currValue;
-}
-
-PRBool
-nsCSSTextAttr::Iterate()
-{
-  return ++mIndex < static_cast<PRInt32>(NS_ARRAY_LENGTH(gCSSTextAttrsMap));
-}
-
-PRBool
-nsCSSTextAttr::Get(nsACString& aName, nsAString& aValue)
-{
-  if (!mStyleDecl)
-    return PR_FALSE;
-
-  NS_ConvertASCIItoUTF16 cssName(gCSSTextAttrsMap[mIndex].mCSSName);
-  nsresult rv = mStyleDecl->GetPropertyValue(cssName, aValue);
-  if (NS_FAILED(rv))
-    return PR_FALSE;
-
-  // Don't expose text attribute if corresponding CSS value on the element
-  // equals to CSS value on the root element and we don't want to include
-  // default values.
-  if (!mIncludeDefAttrValue) {
-    if (!mDefStyleDecl)
-      return PR_FALSE;
-
-    nsAutoString defValue;
-    mDefStyleDecl->GetPropertyValue(cssName, defValue);
-    if (defValue == aValue)
-      return PR_FALSE;
-  }
-
-  // Don't expose text attribute if its required specific CSS value isn't
-  // matched with the CSS value we got.
-  const char *cssValue = gCSSTextAttrsMap[mIndex].mCSSValue;
-  if (cssValue != kAnyValue && !aValue.EqualsASCII(cssValue))
-    return PR_FALSE;
-
-  // Get the name of text attribute.
-  if (gCSSTextAttrsMap[mIndex].mAttrName != kCopyName)
-    aName = gCSSTextAttrsMap[mIndex].mAttrName;
-  else
-    aName = gCSSTextAttrsMap[mIndex].mCSSName;
-
-  // Get the value of text attribute.
-  const char *attrValue = gCSSTextAttrsMap[mIndex].mAttrValue;
-  if (attrValue != kCopyValue)
-    AppendASCIItoUTF16(attrValue, aValue);
-
-  return PR_TRUE;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// nsBackgroundTextAttr
-
-nsBackgroundTextAttr::nsBackgroundTextAttr(nsIFrame *aFrame,
-                                           nsIFrame *aRootFrame) :
-  mFrame(aFrame), mRootFrame(aRootFrame)
-{
-}
-
-PRBool
-nsBackgroundTextAttr::Equal(nsIDOMElement *aElm)
-{
-  nsIFrame *frame = nsCoreUtils::GetFrameFor(aElm);
-  if (!frame)
-    return PR_FALSE;
-
-  return GetColor(mFrame) == GetColor(frame);    
-}
-
-PRBool
-nsBackgroundTextAttr::Get(nsAString& aValue)
-{
-  // Do not expose "background-color" text attribute if its value is matched
-  // with the default value.
-  nscolor color = GetColor(mFrame);
-  if (mRootFrame && color == GetColor(mRootFrame))
-    return PR_FALSE;
-
-  // Combine the string like rgb(R, G, B) from nscolor.
-  nsAutoString value;
-  value.AppendLiteral("rgb(");
-  value.AppendInt(NS_GET_R(color));
-  value.AppendLiteral(", ");
-  value.AppendInt(NS_GET_G(color));
-  value.AppendLiteral(", ");
-  value.AppendInt(NS_GET_B(color));
-  value.Append(')');
-
-  aValue = value;
-  return PR_TRUE;
-}
-
-nscolor
-nsBackgroundTextAttr::GetColor(nsIFrame *aFrame)
-{
-  const nsStyleBackground *styleBackground = aFrame->GetStyleBackground();
-
-  if (!styleBackground->IsTransparent())
-    return styleBackground->mBackgroundColor;
-
-  nsIFrame *parentFrame = aFrame->GetParent();
-  if (!parentFrame)
-    return aFrame->PresContext()->DefaultBackgroundColor();
-
-  // Each frame of parents chain for the initially passed 'aFrame' has
-  // transparent background color. So background color isn't changed from
-  // 'mRootFrame' to initially passed 'aFrame'.
-  if (parentFrame == mRootFrame)
-    return GetColor(mRootFrame);
-
-  return GetColor(parentFrame);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// nsFontSizeTextAttr
-
-nsFontSizeTextAttr::nsFontSizeTextAttr(nsIFrame *aFrame,
-                                           nsIFrame *aRootFrame) :
-  mFrame(aFrame), mRootFrame(aRootFrame)
-{
-}
-
-PRBool
-nsFontSizeTextAttr::Equal(nsIDOMElement *aElm)
-{
-  nsIFrame *frame = nsCoreUtils::GetFrameFor(aElm);
-  if (!frame)
-    return PR_FALSE;
-
-  return GetFontSize(mFrame) == GetFontSize(frame);    
-}
-
-
-PRBool
-nsFontSizeTextAttr::Get(nsAString& aValue)
-{
-  // Do not expose "font-size" text attribute if its value is the same
-  // as the default value.
-  nscoord fontsize = GetFontSize(mFrame);
-  if (mRootFrame && fontsize == GetFontSize(mRootFrame))
-    return PR_FALSE;
-
-  // Convert from nscoord to pt.
-  //
-  // Note: according to IA2, "The conversion doesn't have to be exact.
-  // The intent is to give the user a feel for the size of the text."
-  // 
-  // ATK does not specify a unit and will likely follow IA2 here.
-  //
-  // XXX todo: consider sharing this code with layout module? (bug 474621)
-  nsIDeviceContext *dc = mFrame->PresContext()->DeviceContext();
-  float inches = static_cast<float>(GetFontSize(mFrame)) /
-                        static_cast<float>(dc->AppUnitsPerInch());
-  int pts = inches * 72 + .5; // 72 pts per inch
-  
-  nsAutoString value;
-  value.AppendInt(pts);
-  value.Append(NS_LITERAL_STRING("pt"));
-  aValue = value;
-
-  return PR_TRUE;
-}
-
-nscoord
-nsFontSizeTextAttr::GetFontSize(nsIFrame *aFrame)
-{
-  nsStyleFont* styleFont =
-    (nsStyleFont*)(aFrame->GetStyleDataExternal(eStyleStruct_Font));
-
-  return styleFont->mSize;
-}
deleted file mode 100644
--- a/accessible/src/base/nsTextUtils.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Alexander Surkov <surkov.alexander@gmail.com> (original author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef nsTextUtils_h_
-#define nsTextUtils_h_
-
-#include "nsIDOMElement.h"
-#include "nsIDOMCSSStyleDeclaration.h"
-
-#include "nsIContent.h"
-#include "nsIFrame.h"
-
-#include "nsCOMPtr.h"
-#include "nsString.h"
-
-/**
- * Base class to work with text attributes. See derived classes below.
- */
-class nsTextAttr
-{
-public:
-  /**
-   * Return true if the text attribute for the given element equals with
-   * predefined attribute.
-   */
-  virtual PRBool Equal(nsIDOMElement *aElm) = 0;
-};
-
-/**
- * Class is used for the work with 'lang' text attributes. Used in
- * nsHyperTextAccessible.
- */
-class nsLangTextAttr : public nsTextAttr
-{
-public:
-  nsLangTextAttr(nsAString& aLang, nsIContent *aRootContent) :
-    mLang(aLang), mRootContent(aRootContent) { }
-
-  virtual PRBool Equal(nsIDOMElement *aElm);
-
-private:
-  nsString mLang;
-  nsCOMPtr<nsIContent> mRootContent;
-};
-
-/**
- * Class is used for the work with CSS based text attributes. Used in
- * nsHyperTextAccessible.
- */
-class nsCSSTextAttr : public nsTextAttr
-{
-public:
-  nsCSSTextAttr(PRBool aIncludeDefAttrValue, nsIDOMElement *aElm,
-                nsIDOMElement *aRootElm);
-
-  // nsTextAttr
-  virtual PRBool Equal(nsIDOMElement *aElm);
-
-  // nsCSSTextAttr
-  /**
-   * Interates through attributes.
-   */
-  PRBool Iterate();
-
-  /**
-   * Get name and value of attribute.
-   */
-  PRBool Get(nsACString& aName, nsAString& aValue);
-
-private:
-  PRInt32 mIndex;
-  PRBool mIncludeDefAttrValue;
-
-  nsCOMPtr<nsIDOMCSSStyleDeclaration> mStyleDecl;
-  nsCOMPtr<nsIDOMCSSStyleDeclaration> mDefStyleDecl;
-};
-
-/**
- * Class is used for the work with "background-color" text attribute. It is
- * used in nsHyperTextAccessible.
- */
-class nsBackgroundTextAttr : public nsTextAttr
-{
-public:
-  nsBackgroundTextAttr(nsIFrame *aFrame, nsIFrame *aRootFrame);
-  
-  // nsTextAttr
-  virtual PRBool Equal(nsIDOMElement *aElm);
-
-  // nsBackgroundTextAttr
-
-  /**
-   * Retrieve the "background-color" in out param, return true if differs from
-   * the default background-color.
-   * 
-   * @param aValue      [out] the background color in pts
-   * @return            true if background color differs from default
-   */
-  virtual PRBool Get(nsAString& aValue);
-
-private:
-  /**
-   * Return background color for the given frame.
-   *
-   * @note  If background color for the given frame is transparent then walk
-   *        trhough the frame parents chain until we'll got either a frame with
-   *        not transparent background color or the given root frame. In the
-   *        last case return background color for the root frame.
-   *
-   * @param aFrame      [in] the given frame to calculate background-color
-   * @return            background color
-   */
-  nscolor GetColor(nsIFrame *aFrame);
-
-  nsIFrame *mFrame;
-  nsIFrame *mRootFrame;
-};
-
-/**
- * Class is used for the work with "font-size" text attribute. It is
- * used in nsHyperTextAccessible.
- */
-class nsFontSizeTextAttr : public nsTextAttr
-{
-public:
-  nsFontSizeTextAttr(nsIFrame *aFrame, nsIFrame *aRootFrame);
-  
-  // nsTextAttr
-  virtual PRBool Equal(nsIDOMElement *aElm);
-
-  // nsFontSizeTextAttr
-
-  /**
-   * Retrieve the "font-size" in out param, return true if differs from
-   * the default font-size.
-   * 
-   * @param aValue      [out] the font size in pts
-   * @return            true if font size differs from default
-   */
-  virtual PRBool Get(nsAString& aValue);
-
-private:
-  /**
-   * Return font size for the given frame.
-   *
-   * @param aFrame      [in] the given frame to query font-size
-   * @return            font size
-   */
-   nscoord GetFontSize(nsIFrame *aFrame);
-
-  nsIFrame *mFrame;
-  nsIFrame *mRootFrame;
-};
-
-#endif
--- a/accessible/src/html/nsHTMLFormControlAccessible.cpp
+++ b/accessible/src/html/nsHTMLFormControlAccessible.cpp
@@ -622,17 +622,18 @@ nsHTMLGroupboxAccessible::GetNameInterna
   nsresult rv = nsAccessible::GetNameInternal(aName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!aName.IsEmpty())
     return NS_OK;
 
   nsIContent *legendContent = GetLegend();
   if (legendContent) {
-    return AppendFlatStringFromSubtree(legendContent, &aName);
+    return nsTextEquivUtils::
+      AppendTextEquivFromContent(this, legendContent, &aName);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLGroupboxAccessible::GetRelationByType(PRUint32 aRelationType,
                                             nsIAccessibleRelation **aRelation)
--- a/accessible/src/html/nsHTMLSelectAccessible.cpp
+++ b/accessible/src/html/nsHTMLSelectAccessible.cpp
@@ -521,17 +521,18 @@ nsHTMLSelectOptionAccessible::GetNameInt
   // CASE #2 -- no label parameter, get the first child, 
   // use it if it is a text node
   nsCOMPtr<nsIContent> text = content->GetChildAt(0);
   if (!text)
     return NS_OK;
 
   if (text->IsNodeOfType(nsINode::eTEXT)) {
     nsAutoString txtValue;
-    nsresult rv = AppendFlatStringFromContentNode(text, &txtValue);
+    nsresult rv = nsTextEquivUtils::
+      AppendTextEquivFromTextContent(text, &txtValue);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Temp var (txtValue) needed until CompressWhitespace built for nsAString
     txtValue.CompressWhitespace();
     aName.Assign(txtValue);
     return NS_OK;
   }
 
--- a/accessible/src/html/nsHTMLTableAccessible.cpp
+++ b/accessible/src/html/nsHTMLTableAccessible.cpp
@@ -962,17 +962,18 @@ NS_IMETHODIMP nsHTMLTableAccessible::Get
   nsCOMPtr<nsIAccessible> captionAccessible;
   GetCaption(getter_AddRefs(captionAccessible));
   nsCOMPtr<nsIAccessNode> captionAccessNode = do_QueryInterface(captionAccessible);
   if (captionAccessNode) {
     nsCOMPtr<nsIDOMNode> captionNode;
     captionAccessNode->GetDOMNode(getter_AddRefs(captionNode));
     nsCOMPtr<nsIContent> captionContent = do_QueryInterface(captionNode);
     if (captionContent) {
-      AppendFlatStringFromSubtree(captionContent, &aDescription);
+      nsTextEquivUtils::
+        AppendTextEquivFromContent(this, captionContent, &aDescription);
     }
   }
 #ifdef SHOW_LAYOUT_HEURISTIC
   if (aDescription.IsEmpty()) {
     PRBool isProbablyForLayout;
     IsProbablyForLayout(&isProbablyForLayout);
     aDescription = mLayoutHeuristic;
   }
--- a/accessible/src/html/nsHTMLTextAccessible.cpp
+++ b/accessible/src/html/nsHTMLTextAccessible.cpp
@@ -164,32 +164,19 @@ nsHTMLBRAccessible::GetNameInternal(nsAS
 NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLLabelAccessible, nsLinkableAccessible)
 
 nsHTMLLabelAccessible::nsHTMLLabelAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell):
 nsTextAccessible(aDomNode, aShell)
 { 
 }
 
 nsresult
-nsHTMLLabelAccessible::GetNameInternal(nsAString& aReturn)
-{ 
-  nsresult rv = NS_ERROR_FAILURE;
-  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
-
-  nsAutoString name;
-  if (content)
-    rv = AppendFlatStringFromSubtree(content, &name);
-
-  if (NS_SUCCEEDED(rv)) {
-    // Temp var needed until CompressWhitespace built for nsAString
-    name.CompressWhitespace();
-    aReturn = name;
-  }
-
-  return rv;
+nsHTMLLabelAccessible::GetNameInternal(nsAString& aName)
+{
+  return nsTextEquivUtils::GetNameFromSubtree(this, aName);
 }
 
 NS_IMETHODIMP nsHTMLLabelAccessible::GetRole(PRUint32 *aRole)
 {
   *aRole = nsIAccessibleRole::ROLE_LABEL;
   return NS_OK;
 }
 
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -36,17 +36,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHyperTextAccessible.h"
 #include "nsAccessibilityAtoms.h"
 #include "nsAccessibilityService.h"
 #include "nsAccessibleTreeWalker.h"
-#include "nsTextUtils.h"
+#include "nsTextAttrs.h"
 
 #include "nsIClipboard.h"
 #include "nsContentCID.h"
 #include "nsIDOMAbstractView.h"
 #include "nsIDOMCharacterData.h"
 #include "nsIDOMDocument.h"
 #include "nsPIDOMWindow.h"        
 #include "nsIDOMDocumentView.h"
@@ -1169,27 +1169,18 @@ nsHyperTextAccessible::GetTextAttributes
 
   nsCOMPtr<nsIContent> content(do_QueryInterface(node));
   if (content && content->IsNodeOfType(nsINode::eELEMENT))
     node = do_QueryInterface(content->GetChildAt(nodeOffset));
 
   if (!node)
     return NS_OK;
 
-  // Set 'lang' text attribute.
-  rv =  GetLangTextAttributes(aIncludeDefAttrs, node,
-                              aStartOffset, aEndOffset,
-                              aAttributes ? *aAttributes : nsnull);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Set CSS based text attributes.
-  rv = GetCSSTextAttributes(aIncludeDefAttrs, node,
-                            aStartOffset, aEndOffset,
-                            aAttributes ? *aAttributes : nsnull);
-  return rv;
+  nsTextAttrsMgr textAttrsMgr(this, mDOMNode, aIncludeDefAttrs, node);
+  return textAttrsMgr.GetAttributes(*aAttributes, aStartOffset, aEndOffset);
 }
 
 // nsIPersistentProperties
 // nsIAccessibleText::defaultTextAttributes
 NS_IMETHODIMP
 nsHyperTextAccessible::GetDefaultTextAttributes(nsIPersistentProperties **aAttributes)
 {
   NS_ENSURE_ARG_POINTER(aAttributes);
@@ -1199,45 +1190,18 @@ nsHyperTextAccessible::GetDefaultTextAtt
     do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
   NS_ENSURE_TRUE(attributes, NS_ERROR_OUT_OF_MEMORY);
 
   NS_ADDREF(*aAttributes = attributes);
 
   if (!mDOMNode)
     return NS_ERROR_FAILURE;
 
-  nsCOMPtr<nsIDOMElement> element = nsCoreUtils::GetDOMElementFor(mDOMNode);
-
-  nsCSSTextAttr textAttr(PR_TRUE, element, nsnull);
-  while (textAttr.Iterate()) {
-    nsCAutoString name;
-    nsAutoString value, oldValue;
-    if (textAttr.Get(name, value))
-      attributes->SetStringProperty(name, value, oldValue);
-  }
-  
-  nsIFrame *sourceFrame = nsCoreUtils::GetFrameFor(element);
-  NS_ENSURE_STATE(sourceFrame);
-
-  // set font size
-  nsAutoString value;
-  nsFontSizeTextAttr fontSizeTextAttr(sourceFrame, nsnull);
-  fontSizeTextAttr.Get(value);
-  nsAccUtils::SetAccAttr(attributes,
-                         nsAccessibilityAtoms::fontSize, value);
-  
-  value.Truncate();
-  
-  // set font background color
-  nsBackgroundTextAttr backgroundTextAttr(sourceFrame, nsnull);
-  backgroundTextAttr.Get(value);
-  nsAccUtils::SetAccAttr(attributes,
-                         nsAccessibilityAtoms::backgroundColor, value);
-
-  return NS_OK;
+  nsTextAttrsMgr textAttrsMgr(this, mDOMNode, PR_TRUE, nsnull);
+  return textAttrsMgr.GetAttributes(*aAttributes);
 }
 
 nsresult
 nsHyperTextAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
 {
   if (!mDOMNode) {
     return NS_ERROR_FAILURE;  // Node already shut down
   }
@@ -2315,280 +2279,8 @@ nsHyperTextAccessible::GetSpellTextAttri
       }
 
       return NS_OK;
     }
   }
 
   return NS_OK;
 }
-
-// nsHyperTextAccessible
-nsresult
-nsHyperTextAccessible::GetLangTextAttributes(PRBool aIncludeDefAttrs,
-                                             nsIDOMNode *aSourceNode,
-                                             PRInt32 *aStartHTOffset,
-                                             PRInt32 *aEndHTOffset,
-                                             nsIPersistentProperties *aAttributes)
-{
-  nsCOMPtr<nsIDOMElement> sourceElm(nsCoreUtils::GetDOMElementFor(aSourceNode));
-
-  nsCOMPtr<nsIContent> content(do_QueryInterface(sourceElm));
-  nsCOMPtr<nsIContent> rootContent(do_QueryInterface(mDOMNode));
-
-  nsAutoString lang;
-  nsCoreUtils::GetLanguageFor(content, rootContent, lang);
-
-  nsAutoString rootLang;
-  nsresult rv = GetLanguage(rootLang);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (aAttributes) {
-    // Expose 'language' text attribute if the DOM 'lang' attribute is
-    // presented and it's different from the 'lang' attribute on the root
-    // element or we should include default values of text attribute.
-    const nsAString& resultLang = lang.IsEmpty() ? rootLang : lang;
-    if (!resultLang.IsEmpty() && (aIncludeDefAttrs || lang != rootLang))
-      nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::language,
-                             resultLang);
-  }
-
-  nsLangTextAttr textAttr(lang, rootContent);
-  return GetRangeForTextAttr(aSourceNode, &textAttr,
-                             aStartHTOffset, aEndHTOffset);
-}
-
-// nsHyperTextAccessible
-nsresult
-nsHyperTextAccessible::GetCSSTextAttributes(PRBool aIncludeDefAttrs,
-                                            nsIDOMNode *aSourceNode,
-                                            PRInt32 *aStartHTOffset,
-                                            PRInt32 *aEndHTOffset,
-                                            nsIPersistentProperties *aAttributes)
-{
-  nsCOMPtr<nsIDOMElement> sourceElm(nsCoreUtils::GetDOMElementFor(aSourceNode));
-  nsCOMPtr<nsIDOMElement> rootElm(nsCoreUtils::GetDOMElementFor(mDOMNode));
-
-  nsCSSTextAttr textAttr(aIncludeDefAttrs, sourceElm, rootElm);
-  while (textAttr.Iterate()) {
-    nsCAutoString name;
-    nsAutoString value, oldValue;
-    if (aAttributes && textAttr.Get(name, value))
-      aAttributes->SetStringProperty(name, value, oldValue);
-
-    nsresult rv = GetRangeForTextAttr(aSourceNode, &textAttr,
-                                      aStartHTOffset, aEndHTOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  nsIFrame *sourceFrame = nsCoreUtils::GetFrameFor(sourceElm);
-  if (sourceFrame) {
-    nsIFrame *rootFrame = nsnull;
-
-    if (!aIncludeDefAttrs)
-      rootFrame = nsCoreUtils::GetFrameFor(rootElm);
-
-    nsFontSizeTextAttr fontSizeTextAttr(sourceFrame, rootFrame);
-    nsAutoString value;
-    if (fontSizeTextAttr.Get(value)) {
-      nsAccUtils::SetAccAttr(aAttributes,
-                             nsAccessibilityAtoms::fontSize, value);
-    }
-
-    nsBackgroundTextAttr backgroundTextAttr(sourceFrame, rootFrame);
-    value.Truncate();
-    if (backgroundTextAttr.Get(value)) {
-      nsAccUtils::SetAccAttr(aAttributes,
-                             nsAccessibilityAtoms::backgroundColor, value);
-    }
-
-    nsresult rv = GetRangeForTextAttr(aSourceNode, &backgroundTextAttr,
-                                      aStartHTOffset, aEndHTOffset);
-    return rv;
-  }
-
-  return NS_OK;
-}
-
-// nsHyperTextAccessible
-nsresult
-nsHyperTextAccessible::GetRangeForTextAttr(nsIDOMNode *aNode,
-                                           nsTextAttr *aComparer,
-                                           PRInt32 *aStartHTOffset,
-                                           PRInt32 *aEndHTOffset)
-{
-  nsCOMPtr<nsIDOMElement> rootElm(nsCoreUtils::GetDOMElementFor(mDOMNode));
-  NS_ENSURE_STATE(rootElm);
-
-  nsCOMPtr<nsIDOMNode> tmpNode(aNode);
-  nsCOMPtr<nsIDOMNode> currNode(aNode);
-
-  // Navigate backwards and forwards from current node to the root node to
-  // calculate range bounds for the text attribute. Navigation sequence is the
-  // following:
-  // 1. Navigate through the siblings.
-  // 2. If the traversed sibling has children then navigate from its leaf child
-  //    to it through whole tree of the traversed sibling.
-  // 3. Get the parent and cycle algorithm until the root node.
-
-  // Navigate backwards (find the start offset).
-  while (currNode && currNode != rootElm) {
-    nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(currNode));
-    NS_ENSURE_STATE(currElm);
-
-    if (currNode != aNode && !aComparer->Equal(currElm)) {
-      PRInt32 startHTOffset = 0;
-      nsCOMPtr<nsIAccessible> startAcc;
-      nsresult rv = DOMPointToHypertextOffset(tmpNode, -1, &startHTOffset,
-                                              getter_AddRefs(startAcc));
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      if (!startAcc)
-        startHTOffset = 0;
-
-      if (startHTOffset > *aStartHTOffset)
-        *aStartHTOffset = startHTOffset;
-
-      break;
-    }
-
-    currNode->GetPreviousSibling(getter_AddRefs(tmpNode));
-    if (tmpNode) {
-      // Navigate through the subtree of traversed children to calculate
-      // left bound of the range.
-      FindStartOffsetInSubtree(tmpNode, currNode, aComparer, aStartHTOffset);
-    }
-
-    currNode->GetParentNode(getter_AddRefs(tmpNode));
-    currNode.swap(tmpNode);
-  }
-
-  // Navigate forwards (find the end offset).
-  PRBool moveIntoSubtree = PR_TRUE;
-  currNode = aNode;
-  while (currNode && currNode != rootElm) {
-    nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(currNode));
-    NS_ENSURE_STATE(currElm);
-
-    // Stop new end offset searching if the given text attribute changes its
-    // value.
-    if (!aComparer->Equal(currElm)) {
-      PRInt32 endHTOffset = 0;
-      nsresult rv = DOMPointToHypertextOffset(currNode, -1, &endHTOffset);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      if (endHTOffset < *aEndHTOffset)
-        *aEndHTOffset = endHTOffset;
-
-      break;
-    }
-
-    if (moveIntoSubtree) {
-      // Navigate through subtree of traversed node. We use 'moveIntoSubtree'
-      // flag to avoid traversing the same subtree twice.
-      currNode->GetFirstChild(getter_AddRefs(tmpNode));
-      if (tmpNode)
-        FindEndOffsetInSubtree(tmpNode, aComparer, aEndHTOffset);
-    }
-
-    currNode->GetNextSibling(getter_AddRefs(tmpNode));
-    moveIntoSubtree = PR_TRUE;
-    if (!tmpNode) {
-      currNode->GetParentNode(getter_AddRefs(tmpNode));
-      moveIntoSubtree = PR_FALSE;
-    }
-
-    currNode.swap(tmpNode);
-  }
-
-  return NS_OK;
-}
-
-
-PRBool
-nsHyperTextAccessible::FindEndOffsetInSubtree(nsIDOMNode *aCurrNode,
-                                              nsTextAttr *aComparer,
-                                              PRInt32 *aHTOffset)
-{
-  if (!aCurrNode)
-    return PR_FALSE;
-
-  nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(aCurrNode));
-  NS_ENSURE_STATE(currElm);
-
-  // If the given text attribute (pointed by nsTextAttr object) changes its
-  // value on the traversed element then fit the end of range.
-  if (!aComparer->Equal(currElm)) {
-    PRInt32 endHTOffset = 0;
-    nsresult rv = DOMPointToHypertextOffset(aCurrNode, -1, &endHTOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (endHTOffset < *aHTOffset)
-      *aHTOffset = endHTOffset;
-
-    return PR_TRUE;
-  }
-
-  // Deeply traverse into the tree to fit the end of range.
-  nsCOMPtr<nsIDOMNode> nextNode;
-  aCurrNode->GetFirstChild(getter_AddRefs(nextNode));
-  if (nextNode) {
-    PRBool res = FindEndOffsetInSubtree(nextNode, aComparer, aHTOffset);
-    if (res)
-      return res;
-  }
-
-  aCurrNode->GetNextSibling(getter_AddRefs(nextNode));
-  if (nextNode) {
-    if (FindEndOffsetInSubtree(nextNode, aComparer, aHTOffset))
-      return PR_TRUE;
-  }
-
-  return PR_FALSE;
-}
-
-PRBool
-nsHyperTextAccessible::FindStartOffsetInSubtree(nsIDOMNode *aCurrNode,
-                                                nsIDOMNode *aPrevNode,
-                                                nsTextAttr *aComparer,
-                                                PRInt32 *aHTOffset)
-{
-  if (!aCurrNode)
-    return PR_FALSE;
-
-  // Find the closest element back to the traversed element.
-  nsCOMPtr<nsIDOMNode> nextNode;
-  aCurrNode->GetLastChild(getter_AddRefs(nextNode));
-  if (nextNode) {
-    if (FindStartOffsetInSubtree(nextNode, aPrevNode, aComparer, aHTOffset))
-      return PR_TRUE;
-  }
-
-  nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(aCurrNode));
-  NS_ENSURE_STATE(currElm);
-
-  // If the given text attribute (pointed by nsTextAttr object) changes its
-  // value on the traversed element then fit the start of range.
-  if (!aComparer->Equal(currElm)) {
-    PRInt32 startHTOffset = 0;
-    nsCOMPtr<nsIAccessible> startAcc;
-    nsresult rv = DOMPointToHypertextOffset(aPrevNode, -1, &startHTOffset,
-                                            getter_AddRefs(startAcc));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (!startAcc)
-      startHTOffset = 0;
-
-    if (startHTOffset > *aHTOffset)
-      *aHTOffset = startHTOffset;
-
-    return PR_TRUE;
-  }
-
-  // Moving backwards to find the start of range.
-  aCurrNode->GetPreviousSibling(getter_AddRefs(nextNode));
-  if (nextNode) {
-    if (FindStartOffsetInSubtree(nextNode, aCurrNode, aComparer, aHTOffset))
-      return PR_TRUE;
-  }
-
-  return PR_FALSE;
-}
--- a/accessible/src/html/nsHyperTextAccessible.h
+++ b/accessible/src/html/nsHyperTextAccessible.h
@@ -40,17 +40,17 @@
 #ifndef _nsHyperTextAccessible_H_
 #define _nsHyperTextAccessible_H_
 
 #include "nsAccessibleWrap.h"
 #include "nsIAccessibleText.h"
 #include "nsIAccessibleHyperText.h"
 #include "nsIAccessibleEditableText.h"
 #include "nsAccessibleEventData.h"
-#include "nsTextUtils.h"
+#include "nsTextAttrs.h"
 
 #include "nsFrameSelection.h"
 #include "nsISelectionController.h"
 
 enum EGetTextType { eGetBefore=-1, eGetAt=0, eGetAfter=1 };
 
 // This character marks where in the text returned via nsIAccessibleText(),
 // that embedded object characters exist
@@ -288,97 +288,15 @@ protected:
    * @param aStartOffset      [in, out] the start offset
    * @param aEndOffset        [in, out] the end offset
    * @param aAttributes       [out, optional] result attributes
    */
   nsresult GetSpellTextAttribute(nsIDOMNode *aNode, PRInt32 aNodeOffset,
                                  PRInt32 *aStartOffset,
                                  PRInt32 *aEndOffset,
                                  nsIPersistentProperties *aAttributes);
-
-  /**
-   * Set 'lang' text attribute and return range offsets where attibute is
-   * stretched. The method is used by GetTextAttributes() method.
-   *
-   * @param aIncludeDefAttrs  [in] points whether text attributes having default
-   *                          values of attributes should be included
-   * @param aSourceNode       [in] the node we start to traverse from
-   * @param aStartOffset      [in, out] the start offset
-   * @param aEndOffset        [in, out] the end offset
-   * @param aAttributes       [out, optional] result attributes
-   */
-  nsresult GetLangTextAttributes(PRBool aIncludeDefAttrs,
-                                 nsIDOMNode *aSourceNode,
-                                 PRInt32 *aStartOffset,
-                                 PRInt32 *aEndOffset,
-                                 nsIPersistentProperties *aAttributes);
-
-  /**
-   * Set CSS based text attribute and return range offsets where attibutes are
-   * stretched. The method is used by GetTextAttributes() method.
-   *
-   * @param aIncludeDefAttrs  [in] points whether text attributes having default
-   *                          values of attributes should be included
-   * @param aSourceNode       [in] the node we start to traverse from
-   * @param aStartOffset      [in, out] the start offset
-   * @param aEndOffset        [in, out] the end offset
-   * @param aAttributes       [out, optional] result attributes
-   */
-  nsresult GetCSSTextAttributes(PRBool aIncludeDefAttrs,
-                                nsIDOMNode *aSourceNode,
-                                PRInt32 *aStartOffset,
-                                PRInt32 *aEndOffset,
-                                nsIPersistentProperties *aAttributes);
-
-  /**
-   * Calculates range (start and end offsets) of text where the text attribute
-   * (pointed by nsTextAttr object) is stretched. New offsets may be smaller if
-   * the given text attribute changes its value before or after the given
-   * offsets.
-   *
-   * @param aNode          [in] the node we start to traverse from
-   * @param aComparer      [in] object used to describe the text attribute
-   * @param aStartHTOffset [in, out] the start offset
-   * @param aEndHTOffset   [in, out] the end offset
-   */
-  nsresult GetRangeForTextAttr(nsIDOMNode *aNode,
-                               nsTextAttr *aComparer,
-                               PRInt32 *aStartHTOffset,
-                               PRInt32 *aEndHTOffset);
-
-  /**
-   * Find new end offset for text attributes navigating through the tree. New
-   * end offset may be smaller if the given text attribute (pointed by
-   * nsTextAttr object) changes its value before the given end offset.
-   *
-   * @param  aCurrNode  [in] the first node of the tree
-   * @param  aComparer  [in] object used to describe the text attribute
-   * @param  aHTOffset  [in, out] the end offset
-   * @return            true if the end offset has been changed
-   */
-  PRBool FindEndOffsetInSubtree(nsIDOMNode *aCurrNode,
-                                nsTextAttr *aComparer,
-                                PRInt32 *aHTOffset);
-
-  /**
-   * Find the start offset for text attributes navigating through the tree. New
-   * start offset may be bigger if the given text attribute (pointed by
-   * nsTextAttr object) changes its value after the given start offset.
-   *
-   * @param  aCurrNode  [in] the node navigating through thee thee is started
-   *                    from
-   * @param  aPrevNode  [in] the previous node placed before the start node
-   * @param  aComparer  [in] object used to describe the text attribute
-   * @param  aHTOffset  [in, out] the start offset
-   * @return            true if the start offset has been changed
-   */
-  PRBool FindStartOffsetInSubtree(nsIDOMNode *aCurrNode,
-                                  nsIDOMNode *aPrevNode,
-                                  nsTextAttr *aComparer,
-                                  PRInt32 *aHTOffset);
-
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsHyperTextAccessible,
                               NS_HYPERTEXTACCESSIBLE_IMPL_CID)
 
 #endif  // _nsHyperTextAccessible_H_
 
--- a/accessible/src/xforms/nsXFormsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsAccessible.cpp
@@ -229,17 +229,19 @@ nsXFormsAccessible::GetNameInternal(nsAS
   // search the xforms:label element
   return GetBoundChildElementValue(NS_LITERAL_STRING("label"), aName);
 }
 
 NS_IMETHODIMP
 nsXFormsAccessible::GetDescription(nsAString& aDescription)
 {
   nsAutoString description;
-  nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::aria_describedby, description);
+  nsresult rv = nsTextEquivUtils::
+    GetTextEquivFromIDRefs(this, nsAccessibilityAtoms::aria_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
@@ -61,17 +61,19 @@ nsXFormsLabelAccessible::GetNameInternal
   // XXX Correct name calculation for this, see bug 453594.
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXFormsLabelAccessible::GetDescription(nsAString& aDescription)
 {
   nsAutoString description;
-  nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::aria_describedby, description);
+  nsresult rv = nsTextEquivUtils::
+    GetTextEquivFromIDRefs(this, nsAccessibilityAtoms::aria_describedby,
+                           description);
   aDescription = description;
   return rv;
 }
 
 // nsXFormsOutputAccessible
 
 nsXFormsOutputAccessible::
   nsXFormsOutputAccessible(nsIDOMNode *aNode, nsIWeakReference *aShell):
--- a/accessible/src/xul/nsXULMenuAccessible.h
+++ b/accessible/src/xul/nsXULMenuAccessible.h
@@ -56,18 +56,16 @@ public:
   nsXULSelectableAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell);
   virtual ~nsXULSelectableAccessible() {}
 
   // nsAccessNode
   virtual nsresult Shutdown();
 
 protected:
   nsresult ChangeSelection(PRInt32 aIndex, PRUint8 aMethod, PRBool *aSelState);
-  nsresult AppendFlatStringFromSubtree(nsIContent *aContent, nsAString *aFlatString)
-    { return NS_OK; }  // Overrides base impl in nsAccessible
 
   // nsIDOMXULMultiSelectControlElement inherits from this, so we'll always have
   // one of these if the widget is valid and not defunct
   nsCOMPtr<nsIDOMXULSelectControlElement> mSelectControl;
 };
 
 /* Accessible for supporting XUL menus
  */
--- a/accessible/src/xul/nsXULTextAccessible.cpp
+++ b/accessible/src/xul/nsXULTextAccessible.cpp
@@ -160,22 +160,25 @@ nsXULLinkAccessible::GetValue(nsAString&
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::href, aValue);
   return NS_OK;
 }
 
 nsresult
 nsXULLinkAccessible::GetNameInternal(nsAString& aName)
 {
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::value, aName);
   if (!aName.IsEmpty())
     return NS_OK;
 
-  return AppendFlatStringFromSubtree(content, &aName);
+  return nsTextEquivUtils::GetNameFromSubtree(this, aName);
 }
 
 NS_IMETHODIMP
 nsXULLinkAccessible::GetRole(PRUint32 *aRole)
 {
   NS_ENSURE_ARG_POINTER(aRole);
 
   *aRole = nsIAccessibleRole::ROLE_LINK;
--- a/accessible/tests/mochitest/Makefile.in
+++ b/accessible/tests/mochitest/Makefile.in
@@ -73,44 +73,51 @@ include $(topsrcdir)/config/rules.mk
 		test_groupattrs.xul \
 		test_groupattrs.html \
 		test_name_markup.html \
 	$(warning test_table_indexes.html temporarily disabled) \
 		test_nsIAccessible_actions.html \
 		$(warning test_nsIAccessible_actions.xul temporarily disabled) \
 		test_nsIAccessible_applicationAccessible.html \
 		test_nsIAccessible_comboboxes.xul \
-		test_nsIAccessible_editablebody.html \
-		test_nsIAccessible_editabledoc.html \
 		test_nsIAccessible_name.html \
 		test_nsIAccessible_name_button.html \
 		test_nsIAccessible_name_link.html \
-		$(warning test_nsIAccessible_name.xul temporarily disabled) \
+		test_nsIAccessible_name.xul \
  		test_nsIAccessible_selects.html \
 		test_nsIAccessible_focus.html \
 		test_nsIAccessibleDocument.html \
 		test_nsIAccessibleEditableText.html \
 		test_nsIAccessibleHyperLink.html \
 		$(warning test_nsIAccessibleHyperLink.xul temporarily disabled) \
 		test_nsIAccessibleHyperText.html \
 		test_nsIAccessibleImage.html \
 		test_nsIAccessibleTable_1.html \
 		test_nsIAccessibleTable_2.html \
 		test_nsIAccessibleTable_3.html \
 		test_nsIAccessibleTable_4.html \
 		$(warning test_nsIAccessibleTable_listboxes.xul temporarily disabled) \
 		test_nsIAccessNode_utils.html \
 		test_nsOuterDocAccessible.html \
+ 		test_objectattrs.html \
 		test_relations.html \
 		test_relations.xul \
 		test_role_nsHyperTextAcc.html \
 		test_role_table_cells.html \
 		test_states.html \
+		test_states_editablebody.html \
+		test_states_doc.html \
+		test_states_docarticle.html \
+		test_states_frames.html \
 		test_textattrs.html \
 		test_textboxes.html \
 		test_textboxes.xul \
 		testTextboxes.js \
 		test_bug429285.html \
 		test_bug434464.html \
+		z_states_frame.html \
+		z_states_framearticle.html \
+		z_states_framecheckbox.html \
+		z_states_frametextbox.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)
--- a/accessible/tests/mochitest/attributes.js
+++ b/accessible/tests/mochitest/attributes.js
@@ -1,162 +1,198 @@
-////////////////////////////////////////////////////////////////////////////////
-// Object attributes.
-
-/**
- * Test object attributes.
- *
- * @param aAccOrElmOrID         [in] the ID, DOM node or accessible
- * @param aAttrs                [in] the map of expected object attributes
- *                              (name/value pairs)
- * @param aSkipUnexpectedAttrs  [in] points this function doesn't fail if
- *                              unexpected attribute is encountered
- */
-function testAttrs(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs)
-{
-  var accessible = getAccessible(aAccOrElmOrID);
-  if (!accessible)
-    return;
-
-  var attrs = null;
-  try {
-    attrs = accessible.attributes;
-  } catch (e) { }
-  
-  if (!attrs) {
-    ok(false, "Can't get object attributes for " + aAccOrElmOrID);
-    return;
-  }
-  
-  var errorMsg = " for " + aAccOrElmOrID;
-  compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs);
-}
-
-/**
- * Test group object attributes (posinset, setsize and level)
- *
- * @param aAccOrElmOrID  [in] the ID, DOM node or accessible
- * @param aPosInSet      [in] the value of 'posinset' attribute
- * @param aSetSize       [in] the value of 'setsize' attribute
- * @param aLevel         [in, optional] the value of 'level' attribute
- */
-function testGroupAttrs(aAccOrElmOrID, aPosInSet, aSetSize, aLevel)
-{
-  var attrs = {
-    "posinset": String(aPosInSet),
-    "setsize": String(aSetSize)
-  };
-
-  if (aLevel)
-    attrs["level"] = String(aLevel);
-
-  testAttrs(aAccOrElmOrID, attrs, true);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Text attributes.
-
-/**
- * Test text attributes.
- *
- * @param aID                   [in] the ID of DOM element having text
- *                              accessible
- * @param aOffset               [in] the offset inside text accessible to fetch
- *                              text attributes
- * @param aAttrs                [in] the map of expected text attributes
- *                              (name/value pairs)
- * @param aStartOffset          [in] expected start offset where text attributes
- *                              are applied
- * @param aEndOffset            [in] expected end offset where text attribute
- *                              are applied
- * @param aSkipUnexpectedAttrs  [in] points the function doesn't fail if
- *                              unexpected attribute is encountered
- */
-function testTextAttrs(aID, aOffset, aAttrs, aStartOffset, aEndOffset,
-                       aSkipUnexpectedAttrs)
-{
-  var accessible = getAccessible(aID, [nsIAccessibleText]);
-  if (!accessible)
-    return;
-
-  var startOffset = { value: -1 };
-  var endOffset = { value: -1 };
-  var attrs = null;
-  try {
-    attrs = accessible.getTextAttributes(false, aOffset,
-                                         startOffset, endOffset);
-  } catch (e) {
-  }
-
-  if (!attrs) {
-    ok(false, "Can't get text attributes for " + aID);
-    return;
-  }
-
-  var errorMsg = " for " + aID + " at offset " + aOffset;
-
-  is(startOffset.value, aStartOffset, "Wrong start offset" + errorMsg);
-  is(endOffset.value, aEndOffset, "Wrong end offset" + errorMsg);
-
-  compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs);
-}
-
-/**
- * Test default text attributes.
- *
- * @param aID                   [in] the ID of DOM element having text
- *                              accessible
- * @param aDefAttrs             [in] the map of expected text attributes
- *                              (name/value pairs)
- * @param aSkipUnexpectedAttrs  [in] points the function doesn't fail if
- *                              unexpected attribute is encountered
- */
-function testDefaultTextAttrs(aID, aDefAttrs, aSkipUnexpectedAttrs)
-{
-  var accessible = getAccessible(aID, [nsIAccessibleText]);
-  if (!accessible)
-    return;
-  
-  var defAttrs = null;
-  try{
-    defAttrs = accessible.defaultTextAttributes;
-  } catch (e) {
-  }
-  
-  if (!defAttrs) {
-    ok(false, "Can't get default text attributes for " + aID);
-    return;
-  }
-  
-  var errorMsg = ". Getting default text attributes for " + aID;
-  compareAttrs(errorMsg, defAttrs, aDefAttrs, aSkipUnexpectedAttrs);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Private.
-
-function compareAttrs(aErrorMsg, aAttrs, aExpectedAttrs, aSkipUnexpectedAttrs)
-{
-  var enumerate = aAttrs.enumerate();
-  while (enumerate.hasMoreElements()) {
-    var prop = enumerate.getNext().QueryInterface(nsIPropertyElement);
-
-    if (!(prop.key in aExpectedAttrs)) {
-      if (!aSkipUnexpectedAttrs)
-        ok(false, "Unexpected attribute '" + prop.key + "' having '" +
-           prop.value + "'" + aErrorMsg);
-    } else {
-      is(prop.value, aExpectedAttrs[prop.key],
-         "Attribute '" + prop.key + " 'has wrong value" + aErrorMsg);
-    }
-  }
-
-  for (var name in aExpectedAttrs) {
-    var value = "";
-    try {
-      value = aAttrs.getStringProperty(name);
-    } catch(e) { }
-
-    if (!value)
-      ok(false,
-         "There is no expected attribute '" + name + "' " + aErrorMsg);
-  }
-}
+////////////////////////////////////////////////////////////////////////////////
+// Object attributes.
+
+/**
+ * Test object attributes.
+ *
+ * @param aAccOrElmOrID         [in] the ID, DOM node or accessible
+ * @param aAttrs                [in] the map of expected object attributes
+ *                              (name/value pairs)
+ * @param aSkipUnexpectedAttrs  [in] points this function doesn't fail if
+ *                              unexpected attribute is encountered
+ */
+function testAttrs(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs)
+{
+  var accessible = getAccessible(aAccOrElmOrID);
+  if (!accessible)
+    return;
+
+  var attrs = null;
+  try {
+    attrs = accessible.attributes;
+  } catch (e) { }
+  
+  if (!attrs) {
+    ok(false, "Can't get object attributes for " + aAccOrElmOrID);
+    return;
+  }
+  
+  var errorMsg = " for " + aAccOrElmOrID;
+  compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs);
+}
+
+/**
+ * Test group object attributes (posinset, setsize and level)
+ *
+ * @param aAccOrElmOrID  [in] the ID, DOM node or accessible
+ * @param aPosInSet      [in] the value of 'posinset' attribute
+ * @param aSetSize       [in] the value of 'setsize' attribute
+ * @param aLevel         [in, optional] the value of 'level' attribute
+ */
+function testGroupAttrs(aAccOrElmOrID, aPosInSet, aSetSize, aLevel)
+{
+  var attrs = {
+    "posinset": String(aPosInSet),
+    "setsize": String(aSetSize)
+  };
+
+  if (aLevel)
+    attrs["level"] = String(aLevel);
+
+  testAttrs(aAccOrElmOrID, attrs, true);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Text attributes.
+
+/**
+ * Test text attributes.
+ *
+ * @param aID                   [in] the ID of DOM element having text
+ *                              accessible
+ * @param aOffset               [in] the offset inside text accessible to fetch
+ *                              text attributes
+ * @param aAttrs                [in] the map of expected text attributes
+ *                              (name/value pairs) exposed at the offset
+ * @param aDefAttrs             [in] the map of expected text attributes
+ *                              (name/value pairs) exposed on hyper text
+ *                              accessible
+ * @param aStartOffset          [in] expected start offset where text attributes
+ *                              are applied
+ * @param aEndOffset            [in] expected end offset where text attribute
+ *                              are applied
+ * @param aSkipUnexpectedAttrs  [in] points the function doesn't fail if
+ *                              unexpected attribute is encountered
+ */
+function testTextAttrs(aID, aOffset, aAttrs, aDefAttrs,
+                       aStartOffset, aEndOffset, aSkipUnexpectedAttrs)
+{
+  var accessible = getAccessible(aID, [nsIAccessibleText]);
+  if (!accessible)
+    return;
+
+  var startOffset = { value: -1 };
+  var endOffset = { value: -1 };
+
+  // do not include attributes exposed on hyper text accessbile
+  var attrs = getTextAttributes(aID, accessible, false, aOffset,
+                                startOffset, endOffset);
+
+  if (!attrs)
+    return;
+
+  var errorMsg = " for " + aID + " at offset " + aOffset;
+
+  is(startOffset.value, aStartOffset, "Wrong start offset" + errorMsg);
+  is(endOffset.value, aEndOffset, "Wrong end offset" + errorMsg);
+
+  compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs);
+
+  // include attributes exposed on hyper text accessbile
+  var expectedAttrs = {};
+  for (var name in aAttrs)
+    expectedAttrs[name] = aAttrs[name];
+
+  for (var name in aDefAttrs) {
+    if (!(name in expectedAttrs))
+      expectedAttrs[name] = aDefAttrs[name];
+  }
+
+  attrs = getTextAttributes(aID, accessible, true, aOffset,
+                            startOffset, endOffset);
+  
+  if (!attrs)
+    return;
+
+  compareAttrs(errorMsg, attrs, expectedAttrs, aSkipUnexpectedAttrs);
+}
+
+/**
+ * Test default text attributes.
+ *
+ * @param aID                   [in] the ID of DOM element having text
+ *                              accessible
+ * @param aDefAttrs             [in] the map of expected text attributes
+ *                              (name/value pairs)
+ * @param aSkipUnexpectedAttrs  [in] points the function doesn't fail if
+ *                              unexpected attribute is encountered
+ */
+function testDefaultTextAttrs(aID, aDefAttrs, aSkipUnexpectedAttrs)
+{
+  var accessible = getAccessible(aID, [nsIAccessibleText]);
+  if (!accessible)
+    return;
+  
+  var defAttrs = null;
+  try{
+    defAttrs = accessible.defaultTextAttributes;
+  } catch (e) {
+  }
+  
+  if (!defAttrs) {
+    ok(false, "Can't get default text attributes for " + aID);
+    return;
+  }
+  
+  var errorMsg = ". Getting default text attributes for " + aID;
+  compareAttrs(errorMsg, defAttrs, aDefAttrs, aSkipUnexpectedAttrs);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Private.
+
+function getTextAttributes(aID, aAccessible, aIncludeDefAttrs, aOffset,
+                           aStartOffset, aEndOffset)
+{
+  // This function expects the passed in accessible to already be queried for
+  // nsIAccessibleText.
+  var attrs = null;
+  try {
+    attrs = aAccessible.getTextAttributes(aIncludeDefAttrs, aOffset,
+                                          aStartOffset, aEndOffset);
+  } catch (e) {
+  }
+
+  if (attrs)
+    return attrs;
+
+  ok(false, "Can't get text attributes for " + aID);
+  return null;
+}
+
+function compareAttrs(aErrorMsg, aAttrs, aExpectedAttrs, aSkipUnexpectedAttrs)
+{
+  var enumerate = aAttrs.enumerate();
+  while (enumerate.hasMoreElements()) {
+    var prop = enumerate.getNext().QueryInterface(nsIPropertyElement);
+
+    if (!(prop.key in aExpectedAttrs)) {
+      if (!aSkipUnexpectedAttrs)
+        ok(false, "Unexpected attribute '" + prop.key + "' having '" +
+           prop.value + "'" + aErrorMsg);
+    } else {
+      is(prop.value, aExpectedAttrs[prop.key],
+         "Attribute '" + prop.key + " 'has wrong value" + aErrorMsg);
+    }
+  }
+
+  for (var name in aExpectedAttrs) {
+    var value = "";
+    try {
+      value = aAttrs.getStringProperty(name);
+    } catch(e) { }
+
+    if (!value)
+      ok(false,
+         "There is no expected attribute '" + name + "' " + aErrorMsg);
+  }
+}
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -173,16 +173,19 @@ function getNode(aNodeOrID)
  *                           to query it/them from obtained accessible
  * @param aElmObj            [out, optional] object to store DOM element which
  *                           accessible is obtained for
  * @param aDoNotFailIfNoAcc  [in, optional] no error if the given identifier is
  *                           not accessible
  */
 function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIfNoAcc)
 {
+  if (!aAccOrElmOrID)
+    return;
+
   var elm = null;
 
   if (aAccOrElmOrID instanceof nsIAccessible) {
     aAccOrElmOrID.QueryInterface(nsIAccessNode);
     elm = aAccOrElmOrID.DOMNode;
 
   } else if (aAccOrElmOrID instanceof nsIDOMNode) {
     elm = aAccOrElmOrID;
@@ -242,16 +245,37 @@ function getAccessible(aAccOrElmOrID, aI
  * Return true if the given identifier has an accessible.
  */
 function isAccessible(aAccOrElmOrID)
 {
   return getAccessible(aAccOrElmOrID, null, null, true) ? true : false;
 }
 
 /**
+ * Run through accessible tree of the given identifier so that we ensure
+ * accessible tree is created.
+ */
+function ensureAccessibleTree(aAccOrElmOrID)
+{
+  var acc = getAccessible(aAccOrElmOrID);
+  if (!acc)
+    return;
+
+  var child = acc.firstChild;
+  while (child) {
+    ensureAccessibleTree(child);
+    try {
+      child = child.nextSibling;
+    } catch (e) {
+      child = null;
+    }
+  }
+}
+
+/**
  * Convert role to human readable string.
  */
 function roleToString(aRole)
 {
   return gAccRetrieval.getStringRole(aRole);
 }
 
 /**
--- a/accessible/tests/mochitest/events.js
+++ b/accessible/tests/mochitest/events.js
@@ -1,17 +1,55 @@
+////////////////////////////////////////////////////////////////////////////////
+// Constants
+
+const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER;
+const EVENT_DOM_DESTROY = nsIAccessibleEvent.EVENT_DOM_DESTROY;
+
 ////////////////////////////////////////////////////////////////////////////////
 // General
 
 /**
  * Set up this variable to dump events into DOM.
  */
 var gA11yEventDumpID = "";
 
 /**
+ * Executes the function when requested event is handled.
+ *
+ * @param aEventType  [in] event type
+ * @param aTarget     [in] event target
+ * @param aFunc       [in] function to call when event is handled
+ * @param aContext    [in, optional] object in which context the function is
+ *                    called
+ * @param aArg1       [in, optional] argument passed into the function
+ * @param aArg2       [in, optional] argument passed into the function
+ */
+function waitForEvent(aEventType, aTarget, aFunc, aContext, aArg1, aArg2)
+{
+  var handler = {
+    handleEvent: function handleEvent(aEvent) {
+      if (!aTarget || aTarget == aEvent.DOMNode) {
+        unregisterA11yEventListener(aEventType, this);
+
+        window.setTimeout(
+          function ()
+          {
+            aFunc.call(aContext, aArg1, aArg2);
+          },
+          0
+        );
+      }
+    }
+  };
+
+  registerA11yEventListener(aEventType, handler);
+}
+
+/**
  * Register accessibility event listener.
  *
  * @param aEventType     the accessible event type (see nsIAccessibleEvent for
  *                       available constants).
  * @param aEventHandler  event listener object, when accessible event of the
  *                       given type is handled then 'handleEvent' method of
  *                       this object is invoked with nsIAccessibleEvent object
  *                       as the first argument.
@@ -381,13 +419,16 @@ function removeA11yEventListener(aEventT
     delete gA11yEventListeners[aEventType];
   }
 
   return true;
 }
 
 function dumpInfoToDOM(aInfo)
 {
+  if (!gA11yEventDumpID)
+    return;
+
   var dumpElm = document.getElementById(gA11yEventDumpID);
   var div = document.createElement("div");      
   div.textContent = aInfo;
   dumpElm.appendChild(div);
 }
--- a/accessible/tests/mochitest/namerules.xml
+++ b/accessible/tests/mochitest/namerules.xml
@@ -114,16 +114,17 @@
     </ruleset>
 
     <ruleset id="htmloption">
       <ruleset ref="aria"/>
       <rule attr="label" type="string"/>
       <rule fromsubtree="true"/>
       <rule attr="title" type="string"/>
     </ruleset>
+
   </ruledfn>
 
   <rulesample>
 
     <markup ref="html:button" ruleset="htmlctrl">
       <html:span id="l1" a11yname="test2">test2</html:span>
       <html:span id="l2" a11yname="test3">test3</html:span>
       <html:label for="btn" a11yname="test4">test4</html:label>
@@ -188,22 +189,23 @@
       <html:span id="l2" a11yname="test3">test3</html:span>
       <html:label for="gc" a11yname="test4">test4</html:label>
       <html:table>
         <html:tr>
           <html:td id="gc"
                    role="gridcell"
                    aria-label="test1"
                    aria-labelledby="l1 l2"
-                   a11yname="  This is a paragraph  This is a link     This is a list"
+                   a11yname="This is a paragraph This is a link • Listitem1 • Listitem2"
                    title="This is a paragraph This is a link This is a list">
             <html:p>This is a paragraph</html:p>
             <html:a href="#">This is a link</html:a>
             <html:ul>
-              <html:li>This is a list</html:li>
+              <html:li>Listitem1</html:li>
+              <html:li>Listitem2</html:li>
             </html:ul>
           </html:td>
         </html:tr>
       </html:table>
     </markup>
 
   </rulesample>
 
--- a/accessible/tests/mochitest/nsIAccessible_name.js
+++ b/accessible/tests/mochitest/nsIAccessible_name.js
@@ -1,207 +1,284 @@
-function testName(aAccOrElmOrID, aName, aMsg)
-{
-  var msg = aMsg ? aMsg : "";
-
-  var acc = getAccessible(aAccOrElmOrID);
-  if (!acc) {
-    ok(false, msg + "No accessible for " + aAccOrElmOrID + "!");
-  }
-
-  try {
-    is(acc.name, aName, msg + "Wrong name of the accessible for " + aAccOrElmOrID);
-  } catch (e) {
-    ok(false, msg + "Can't get name of the accessible for " + aAccOrElmOrID);
-  }
-  return acc;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Name tests described by "namerules.xml" file.
-
-var gNameRulesFileURL =
-  "chrome://mochikit/content/a11y/accessible/namerules.xml";
-
-var gRuleDoc = null;
-
-/**
- * Start name tests. Run through markup elements and test names for test
- * element (see namerules.xml for details).
- */
-function testNames()
-{
-  var request = new XMLHttpRequest();
-  request.open("get", gNameRulesFileURL, false);
-  request.send();
-
-  gRuleDoc = request.responseXML;
-
-  var markupElms = evaluateXPath(gRuleDoc, "//rules/rulesample/markup");
-  for (var idx = 0; idx < markupElms.length; idx++)
-    testNamesForMarkup(markupElms[idx]);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Private section.
-
-/**
- * Process every 'markup' element and test names for it. Used by testNames
- * function.
- */
-function testNamesForMarkup(aMarkupElm)
-{
-  var div = document.createElement("div");
-  div.setAttribute("test", "test");
-
-  var child = aMarkupElm.firstChild;
-  while (child) {
-    var newChild = document.importNode(child, true);
-    div.appendChild(newChild);
-    child = child.nextSibling;
-  }
-  document.body.appendChild(div);
-
-  var serializer = new XMLSerializer();
-
-  var expr = "//html/body/div[@test='test']/" + aMarkupElm.getAttribute("ref");
-  var elms = evaluateXPath(document, expr, htmlDocResolver);
-
-  var ruleId = aMarkupElm.getAttribute("ruleset");
-  var ruleElms = getRuleElmsByRulesetId(ruleId);
-
-  for (var idx = 0; idx < ruleElms.length; idx++)
-    testNameForRule(elms[0], ruleElms[idx]);
-
-  document.body.removeChild(div);
-}
-
-/**
- * Test name for current rule and current 'markup' element. Used by
- * testNamesForMarkup function.
- */
-function testNameForRule(aElm, aRule)
-{
-  var attr = aRule.getAttribute("attr");
-  if (attr) {
-    var name = "";
-    var attrValue = aElm.getAttribute(attr);
-  
-    var type = aRule.getAttribute("type");
-    if (type == "string") {
-      name = attrValue;
-
-    } else if (type == "ref") {
-      var ids = attrValue.split(/\s+/);///\,\s*/);
-      for (var idx = 0; idx < ids.length; idx++) {
-        var labelElm = getNode(ids[idx]);
-        if (name != "")
-          name += " ";
-
-        name += labelElm.getAttribute("a11yname");
-      }
-    }
-
-    var msg = "Attribute '" + attr + "' test. ";
-    testName(aElm, name, msg);
-    aElm.removeAttribute(attr);
-    return;
-  }
-
-  var elm = aRule.getAttribute("elm");
-  var elmattr = aRule.getAttribute("elmattr");
-  if (elm && elmattr) {
-    var filter = {
-      acceptNode: function filter_acceptNode(aNode)
-      {
-        if (aNode.localName == this.mLocalName &&
-            aNode.getAttribute(this.mAttrName) == this.mAttrValue)
-          return NodeFilter.FILTER_ACCEPT;
-
-        return NodeFilter.FILTER_SKIP;
-      },
-
-      mLocalName: elm,
-      mAttrName: elmattr,
-      mAttrValue: aElm.getAttribute("id")
-    };
-
-    var treeWalker = document.createTreeWalker(document.body,
-                                               NodeFilter.SHOW_ELEMENT,
-                                               filter, false);
-    var labelElm = treeWalker.nextNode();
-    var msg = "Element '" + elm + "' test.";
-    testName(aElm, labelElm.getAttribute("a11yname"), msg);
-    labelElm.parentNode.removeChild(labelElm);
-    return;
-  }
-
-  var fromSubtree = aRule.getAttribute("fromsubtree");
-  if (fromSubtree == "true") {
-    var msg = "From subtree test.";
-    testName(aElm, aElm.getAttribute("a11yname"), msg);
-    while (aElm.firstChild)
-      aElm.removeChild(aElm.firstChild);
-    return;
-  }
-}
-
-/**
- * Return array of 'rule' elements. Used in conjunction with
- * getRuleElmsFromRulesetElm() function.
- */
-function getRuleElmsByRulesetId(aRulesetId)
-{
-  var expr = "//rules/ruledfn/ruleset[@id='" + aRulesetId + "']";
-  var rulesetElm = evaluateXPath(gRuleDoc, expr);
-  return getRuleElmsFromRulesetElm(rulesetElm[0]);
-}
-
-function getRuleElmsFromRulesetElm(aRulesetElm)
-{
-  var rulesetId = aRulesetElm.getAttribute("ref");
-  if (rulesetId)
-    return getRuleElmsByRulesetId(rulesetId);
-
-  var ruleElms = [];
-
-  var child = aRulesetElm.firstChild;
-  while (child) {
-    if (child.localName == "ruleset")
-      ruleElms = ruleElms.concat(getRuleElmsFromRulesetElm(child));
-    if (child.localName == "rule")
-      ruleElms.push(child);
-
-    child = child.nextSibling;
-  }
-
-  return ruleElms;
-}
-
-/**
- * Helper method to evaluate xpath expression.
- */
-function evaluateXPath(aNode, aExpr, aResolver)
-{
-  var xpe = new XPathEvaluator();
-
-  var resolver = aResolver;
-  if (!resolver) {
-    var node = aNode.ownerDocument == null ?
-      aNode.documentElement : aNode.ownerDocument.documentElement;
-    resolver = xpe.createNSResolver(node);
-  }
-
-  var result = xpe.evaluate(aExpr, aNode, resolver, 0, null);
-  var found = [];
-  var res;
-  while (res = result.iterateNext())
-    found.push(res);
-
-  return found;
-}
-
-function htmlDocResolver(aPrefix) {
-  var ns = {
-    'html' : 'http://www.w3.org/1999/xhtml'
-  };
-  return ns[aPrefix] || null;
-}
+function testName(aAccOrElmOrID, aName, aMsg)
+{
+  var msg = aMsg ? aMsg : "";
+
+  var acc = getAccessible(aAccOrElmOrID);
+  if (!acc)
+    return;
+
+  try {
+    is(acc.name, aName, msg + "Wrong name of the accessible for " + aAccOrElmOrID);
+  } catch (e) {
+    ok(false, msg + "Can't get name of the accessible for " + aAccOrElmOrID);
+  }
+  return acc;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name tests described by "namerules.xml" file.
+
+var gNameRulesFileURL =
+  "chrome://mochikit/content/a11y/accessible/namerules.xml";
+
+var gRuleDoc = null;
+
+/**
+ * Start name tests. Run through markup elements and test names for test
+ * element (see namerules.xml for details).
+ */
+function testNames()
+{
+  var request = new XMLHttpRequest();
+  request.open("get", gNameRulesFileURL, false);
+  request.send();
+
+  gRuleDoc = request.responseXML;
+
+  var markupElms = evaluateXPath(gRuleDoc, "//rules/rulesample/markup");
+  gTestIterator.iterateMarkups(markupElms);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Private section.
+
+/**
+ * Helper class to interate through name tests.
+ */
+var gTestIterator =
+{
+  iterateMarkups: function gTestIterator_iterateMarkups(aMarkupElms)
+  {
+    this.markupElms = aMarkupElms;
+
+    this.iterateNext();
+  },
+
+  iterateRules: function gTestIterator_iterateRules(aElm, aContainer, aRuleElms)
+  {
+    this.ruleElms = aRuleElms;
+    this.elm = aElm;
+    this.container = aContainer;
+
+    this.iterateNext();
+  },
+
+  iterateNext: function gTestIterator_iterateNext()
+  {
+    if (this.markupIdx == -1) {
+      this.markupIdx++;
+      testNamesForMarkup(this.markupElms[this.markupIdx]);
+      return;
+    }
+
+    this.ruleIdx++;
+    if (this.ruleIdx == this.ruleElms.length) {
+      this.markupIdx++;
+      if (this.markupIdx == this.markupElms.length) {
+        SimpleTest.finish();
+        return;
+      }
+
+      document.body.removeChild(this.container);
+
+      this.ruleIdx = -1;
+      testNamesForMarkup(this.markupElms[this.markupIdx]);
+      return;
+    }
+
+    testNameForRule(this.elm, this.ruleElms[this.ruleIdx]);
+  },
+
+  markupElms: null,
+  markupIdx: -1,
+  ruleElms: null,
+  ruleIdx: -1,
+  elm: null,
+  container: null
+};
+
+/**
+ * Process every 'markup' element and test names for it. Used by testNames
+ * function.
+ */
+function testNamesForMarkup(aMarkupElm)
+{
+  var div = document.createElement("div");
+  div.setAttribute("id", "test");
+
+  var child = aMarkupElm.firstChild;
+  while (child) {
+    var newChild = document.importNode(child, true);
+    div.appendChild(newChild);
+    child = child.nextSibling;
+  }
+
+  waitForEvent(EVENT_REORDER, document, testNamesForMarkupRules,
+                null, aMarkupElm, div);
+
+  document.body.appendChild(div);
+}
+
+function testNamesForMarkupRules(aMarkupElm, aContainer)
+{
+  ensureAccessibleTree(aContainer);
+
+  var serializer = new XMLSerializer();
+
+  var expr = "//html/body/div[@id='test']/" + aMarkupElm.getAttribute("ref");
+  var elms = evaluateXPath(document, expr, htmlDocResolver);
+
+  var ruleId = aMarkupElm.getAttribute("ruleset");
+  var ruleElms = getRuleElmsByRulesetId(ruleId);
+
+  gTestIterator.iterateRules(elms[0], aContainer, ruleElms);
+}
+
+/**
+ * Test name for current rule and current 'markup' element. Used by
+ * testNamesForMarkup function.
+ */
+function testNameForRule(aElm, aRuleElm)
+{
+  if (aRuleElm.hasAttribute("attr"))
+    testNameForAttrRule(aElm, aRuleElm);
+  else if (aRuleElm.hasAttribute("elm") && aRuleElm.hasAttribute("elmattr"))
+    testNameForElmRule(aElm, aRuleElm);
+  else if (aRuleElm.getAttribute("fromsubtree") == "true")
+    testNameForSubtreeRule(aElm, aRuleElm);
+}
+
+function testNameForAttrRule(aElm, aRule)
+{
+  var name = "";
+
+  var attr = aRule.getAttribute("attr");
+  var attrValue = aElm.getAttribute(attr);
+
+  var type = aRule.getAttribute("type");
+  if (type == "string") {
+    name = attrValue;
+
+  } else if (type == "ref") {
+    var ids = attrValue.split(/\s+/);
+    for (var idx = 0; idx < ids.length; idx++) {
+      var labelElm = getNode(ids[idx]);
+      if (name != "")
+        name += " ";
+
+      name += labelElm.getAttribute("a11yname");
+    }
+  }
+
+  var msg = "Attribute '" + attr + "' test. ";
+  testName(aElm, name, msg);
+  aElm.removeAttribute(attr);
+
+  gTestIterator.iterateNext();
+}
+
+function testNameForElmRule(aElm, aRule)
+{  
+  var elm = aRule.getAttribute("elm");
+  var elmattr = aRule.getAttribute("elmattr");
+
+  var filter = {
+    acceptNode: function filter_acceptNode(aNode)
+    {
+      if (aNode.localName == this.mLocalName &&
+          aNode.getAttribute(this.mAttrName) == this.mAttrValue)
+        return NodeFilter.FILTER_ACCEPT;
+
+      return NodeFilter.FILTER_SKIP;
+    },
+
+    mLocalName: elm,
+    mAttrName: elmattr,
+    mAttrValue: aElm.getAttribute("id")
+  };
+
+  var treeWalker = document.createTreeWalker(document.body,
+                                             NodeFilter.SHOW_ELEMENT,
+                                             filter, false);
+  var labelElm = treeWalker.nextNode();
+  var msg = "Element '" + elm + "' test.";
+  testName(aElm, labelElm.getAttribute("a11yname"), msg);
+
+  var parentNode = labelElm.parentNode;
+  waitForEvent(EVENT_REORDER, parentNode,
+               gTestIterator.iterateNext, gTestIterator);
+
+  parentNode.removeChild(labelElm);
+}
+
+function testNameForSubtreeRule(aElm, aRule)
+{
+  var msg = "From subtree test.";
+  testName(aElm, aElm.getAttribute("a11yname"), msg);
+
+  waitForEvent(EVENT_REORDER, aElm, gTestIterator.iterateNext, gTestIterator);
+
+  while (aElm.firstChild)
+    aElm.removeChild(aElm.firstChild);
+}
+
+/**
+ * Return array of 'rule' elements. Used in conjunction with
+ * getRuleElmsFromRulesetElm() function.
+ */
+function getRuleElmsByRulesetId(aRulesetId)
+{
+  var expr = "//rules/ruledfn/ruleset[@id='" + aRulesetId + "']";
+  var rulesetElm = evaluateXPath(gRuleDoc, expr);
+  return getRuleElmsFromRulesetElm(rulesetElm[0]);
+}
+
+function getRuleElmsFromRulesetElm(aRulesetElm)
+{
+  var rulesetId = aRulesetElm.getAttribute("ref");
+  if (rulesetId)
+    return getRuleElmsByRulesetId(rulesetId);
+
+  var ruleElms = [];
+
+  var child = aRulesetElm.firstChild;
+  while (child) {
+    if (child.localName == "ruleset")
+      ruleElms = ruleElms.concat(getRuleElmsFromRulesetElm(child));
+    if (child.localName == "rule")
+      ruleElms.push(child);
+
+    child = child.nextSibling;
+  }
+
+  return ruleElms;
+}
+
+/**
+ * Helper method to evaluate xpath expression.
+ */
+function evaluateXPath(aNode, aExpr, aResolver)
+{
+  var xpe = new XPathEvaluator();
+
+  var resolver = aResolver;
+  if (!resolver) {
+    var node = aNode.ownerDocument == null ?
+      aNode.documentElement : aNode.ownerDocument.documentElement;
+    resolver = xpe.createNSResolver(node);
+  }
+
+  var result = xpe.evaluate(aExpr, aNode, resolver, 0, null);
+  var found = [];
+  var res;
+  while (res = result.iterateNext())
+    found.push(res);
+
+  return found;
+}
+
+function htmlDocResolver(aPrefix) {
+  var ns = {
+    'html' : 'http://www.w3.org/1999/xhtml'
+  };
+  return ns[aPrefix] || null;
+}
--- a/accessible/tests/mochitest/test_aria_token_attrs.html
+++ b/accessible/tests/mochitest/test_aria_token_attrs.html
@@ -50,21 +50,21 @@ https://bugzilla.mozilla.org/show_bug.cg
       
       testStates("native_checkbox_nativeunchecked_ariatrue", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("native_checkbox_nativeunchecked_ariafalse", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("native_checkbox_nativeunchecked_ariaempty", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("native_checkbox_nativeunchecked_ariaundefined", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("native_checkbox_nativeunchecked_ariaabsent", STATE_CHECKABLE, 0, STATE_CHECKED);
 
       // test button aria-pressed states
-      testStates("button_pressed_true", STATE_PRESSED);
-      testStates("button_pressed_false", 0, 0, STATE_PRESSED);
-      testStates("button_pressed_empty", 0, 0, STATE_PRESSED);
-      testStates("button_pressed_undefined", 0, 0, STATE_PRESSED);
-      testStates("button_pressed_absent", 0, 0, STATE_PRESSED);
+      testStates("button_pressed_true", STATE_PRESSED | STATE_CHECKABLE);
+      testStates("button_pressed_false", 0, 0, STATE_PRESSED | STATE_CHECKABLE);
+      testStates("button_pressed_empty", 0, 0, STATE_PRESSED | STATE_CHECKABLE);
+      testStates("button_pressed_undefined", 0, 0, STATE_PRESSED | STATE_CHECKABLE);
+      testStates("button_pressed_absent", 0, 0, STATE_PRESSED | STATE_CHECKABLE);
       
       // test aria-pressed state mapping to roles PUSHBUTTON vs TOGGLEBUTTON
       var aButton = getAccessible("button_pressed_true");
       if (aButton)
         is(aButton.finalRole, ROLE_TOGGLE_BUTTON, "Wrong role for togglebutton!");
       aButton = getAccessible("button_pressed_false");
       if (aButton)
         is(aButton.finalRole, ROLE_TOGGLE_BUTTON, "Wrong role for togglebutton!");
--- a/accessible/tests/mochitest/test_bug420863.html
+++ b/accessible/tests/mochitest/test_bug420863.html
@@ -1,138 +1,138 @@
-<!DOCTYPE html>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=420863
--->
-<head>
-  <title>Table indexes chrome tests</title>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
-
-  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-
-  <script type="application/javascript">
-    var gAccService = null;
-
-    var gTdClickAttr = false;
-    var gTdClickEventHandler = false;
-    var gClickHandler = null;
-
-    var gID = "";
-    var gNode = null;
-    var gAcc = null;
-
-    function doTest()
-    {
-      const nsIAccessibleRetrieval =
-        Components.interfaces.nsIAccessibleRetrieval;
-
-      gAccService = Components.classes["@mozilla.org/accessibleRetrieval;1"].
-                    getService(nsIAccessibleRetrieval);
-
-      // Actions should be exposed on any accessible having related DOM node
-      // with registered 'click' event handler.
-
-      //////////////////////////////////////////////////////////////////////////
-      // generic td
-      gID = "td1";
-      gNode = document.getElementById(gID);
-      gAcc = gAccService.getAccessibleFor(gNode);
-
-      is(gAcc.numActions, 0, gID + ": shouldn't have actions");
-
-      //////////////////////////////////////////////////////////////////////////
-      // td with 'onclick' attribute
-      gID = "td2";
-      gNode = document.getElementById(gID);
-      gAcc = gAccService.getAccessibleFor(gNode);
-
-      is(gAcc.numActions, 1, gID + ": should have one action");
-      is(gAcc.getActionName(0), "click", gID + ": should have 'click' action");
-      gAcc.doAction(0);
-
-      // actions are performed via timeout
-      window.setTimeout(doTest2, 0);
-    }
-
-    function doTest2()
-    {
-      //////////////////////////////////////////////////////////////////////////
-      // td with 'onclick' attribute (sequel, see doTest1())
-      ok(gTdClickAttr, gID + ": 'click' action hasn't been performed");
-
-      //////////////////////////////////////////////////////////////////////////
-      // td with registered 'click' event handler
-      gID = "td3";
-      gNode = document.getElementById(gID);
-      gAcc = gAccService.getAccessibleFor(gNode);
-
-      // register 'click' event handler
-      gClickHandler = {
-        handleEvent: function handleEvent(aEvent)
-        {
-          gTdClickEventHandler = true;
-        }
-      };
-      gNode.addEventListener("click", gClickHandler, false);
-
-      // check actions
-      is(gAcc.numActions, 1, gID + ": should have one action");
-      is(gAcc.getActionName(0), "click", gID + ": should have 'click' action");
-      gAcc.doAction(0);
-
-      // actions are performed via timeout
-      window.setTimeout(doTest3, 0);
-    }
-
-    function doTest3()
-    {
-      //////////////////////////////////////////////////////////////////////////
-      // td with registered 'click' event handler (sequel, see doTest2())
-      ok(gTdClickEventHandler, gID + ": 'click' action hasn't been performed");
-
-      // unregister click event handler
-      gNode.removeEventListener("click", gClickHandler, false);
-
-      // check actions
-      // XXX see bug 456347, sometimes after removing the event listener, the
-      // accessible is no longer valid. When fixing that bug, remove the
-      // try/exception and simply test for the gAcc.numActions value directly.
-      var numActions = -1;
-      try {
-        numActions = gAcc.numActions;
-      } catch(e) {}
-
-      if (numActions == -1)
-        todo(false,
-             "gAcc.numActions should not throw after click handler was removed!");
-      else
-        is(numActions, 0, gID + ": shouldn't have actions");
-
-      SimpleTest.finish();
-    }
-
-    SimpleTest.waitForExplicitFinish();
-    addLoadEvent(doTest);
-  </script>
-</head>
-<body>
-
-  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=420863"
-     title="If an HTML element has an onClick attribute, expose its click action on the element rather than its child text leaf node."
-     target="_blank">Mozilla Bug 420863</a>
-  <p id="display"></p>
-  <div id="content" style="display: none"></div>
-  <pre id="test">
-  </pre>
-
-  <table>
-    <tr>
-      <td id="td1">Can't click this cell</td>
-      <td onclick="gTdClickAttr = true;"
-          id="td2">Cell with 'onclick' attribute</td>
-      <td id="td3">Cell with registered 'click' event handler</td>
-    </tr>
-  </table>
-
-</body>
-</html>
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=420863
+-->
+<head>
+  <title>Table indexes chrome tests</title>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript">
+    var gAccService = null;
+
+    var gTdClickAttr = false;
+    var gTdClickEventHandler = false;
+    var gClickHandler = null;
+
+    var gID = "";
+    var gNode = null;
+    var gAcc = null;
+
+    function doTest()
+    {
+      const nsIAccessibleRetrieval =
+        Components.interfaces.nsIAccessibleRetrieval;
+
+      gAccService = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+                    getService(nsIAccessibleRetrieval);
+
+      // Actions should be exposed on any accessible having related DOM node
+      // with registered 'click' event handler.
+
+      //////////////////////////////////////////////////////////////////////////
+      // generic td
+      gID = "td1";
+      gNode = document.getElementById(gID);
+      gAcc = gAccService.getAccessibleFor(gNode);
+
+      is(gAcc.numActions, 0, gID + ": shouldn't have actions");
+
+      //////////////////////////////////////////////////////////////////////////
+      // td with 'onclick' attribute
+      gID = "td2";
+      gNode = document.getElementById(gID);
+      gAcc = gAccService.getAccessibleFor(gNode);
+
+      is(gAcc.numActions, 1, gID + ": should have one action");
+      is(gAcc.getActionName(0), "click", gID + ": should have 'click' action");
+      gAcc.doAction(0);
+
+      // actions are performed via timeout
+      window.setTimeout(doTest2, 0);
+    }
+
+    function doTest2()
+    {
+      //////////////////////////////////////////////////////////////////////////
+      // td with 'onclick' attribute (sequel, see doTest1())
+      ok(gTdClickAttr, gID + ": 'click' action hasn't been performed");
+
+      //////////////////////////////////////////////////////////////////////////
+      // td with registered 'click' event handler
+      gID = "td3";
+      gNode = document.getElementById(gID);
+      gAcc = gAccService.getAccessibleFor(gNode);
+
+      // register 'click' event handler
+      gClickHandler = {
+        handleEvent: function handleEvent(aEvent)
+        {
+          gTdClickEventHandler = true;
+        }
+      };
+      gNode.addEventListener("click", gClickHandler, false);
+
+      // check actions
+      is(gAcc.numActions, 1, gID + ": should have one action");
+      is(gAcc.getActionName(0), "click", gID + ": should have 'click' action");
+      gAcc.doAction(0);
+
+      // actions are performed via timeout
+      window.setTimeout(doTest3, 0);
+    }
+
+    function doTest3()
+    {
+      //////////////////////////////////////////////////////////////////////////
+      // td with registered 'click' event handler (sequel, see doTest2())
+      ok(gTdClickEventHandler, gID + ": 'click' action hasn't been performed");
+
+      // unregister click event handler
+      gNode.removeEventListener("click", gClickHandler, false);
+
+      // check actions
+      // XXX see bug 456347, sometimes after removing the event listener, the
+      // accessible is no longer valid. When fixing that bug, remove the
+      // try/exception and simply test for the gAcc.numActions value directly.
+      var numActions = -1;
+      try {
+        numActions = gAcc.numActions;
+      } catch(e) {}
+
+      if (numActions == -1)
+        todo(false,
+             "gAcc.numActions should not throw after click handler was removed!");
+      else
+        is(numActions, 0, gID + ": shouldn't have actions");
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=420863"
+     title="If an HTML element has an onClick attribute, expose its click action on the element rather than its child text leaf node."
+     target="_blank">Mozilla Bug 420863</a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <table>
+    <tr>
+      <td id="td1">Can't click this cell</td>
+      <td onclick="gTdClickAttr = true;"
+          id="td2">Cell with 'onclick' attribute</td>
+      <td id="td3">Cell with registered 'click' event handler</td>
+    </tr>
+  </table>
+
+</body>
+</html>
--- a/accessible/tests/mochitest/test_bug434464.html
+++ b/accessible/tests/mochitest/test_bug434464.html
@@ -1,88 +1,88 @@
-<!DOCTYPE html>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=434464
--->
-<head>
-  <title>Test NSIAccessNode cache invalidation</title>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
-
-  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-
-  <script type="application/javascript">
-    function doTest()
-    {
-      var accRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
-                       getService(Components.interfaces.nsIAccessibleRetrieval);
-
-      var parentElm = document.getElementById("parent");
-      if (!parentElm) {
-        ok(false, "no parent element for paragraph!");
-        SimpleTest.finish();
-      }
-
-      var elm = document.getElementById("para");
-      if (!elm) {
-        ok(false, "no element for paragraph!");
-        SimpleTest.finish();
-      }
-
-      // It's currently hidden. Ask for its parent's nsIAccessNode.
-      var parentElmAccNode = null;
-      try {
-        parentElmAccNode = accRetrieval.getAccessibleFor(parentElm).
-                     QueryInterface(Components.interfaces.nsIAccessNode);
-      } catch(e) {}
-
-      if (!parentElmAccNode) {
-        ok(false, "No accessNode for parent of hidden paragraph!");
-        SimpleTest.finish();
-      }
-
-      // Get the paragraph's accessNode.
-      var elmAccNode = null;
-      try {
-        elmAccNode = parentElmAccNode.firstChildNode;
-      } catch(e) {}
-
-      if (!elmAccNode) {
-        ok(false, "No accessNode for hidden paragraph!");
-        SimpleTest.finish();
-      }
-
-      // Now make the paragraph visible. This invalidates the just-retrieved
-      // AccessNode. An nsIAccessible should then be retrievable.
-      elm.style.display = "block";
-
-      // Now, get an accessible for it. Use a timeout so the layout engine can
-      // catch up.
-      window.setTimeout(
-        function()
-        {
-          var elmAcc = null;
-          try {
-            elmAcc = accRetrieval.getAccessibleFor(elm);
-          } catch(e) {}
-    
-          ok(elmAcc, "No accessible for paragraph after it became visible!");
-
-          SimpleTest.finish();
-        },
-      200);
-    }
-
-    SimpleTest.waitForExplicitFinish();
-    addLoadEvent(doTest);
-  </script>
-</head>
-<body>
-
-  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=434464">Mozilla Bug 434464</a>
-  <p id="display"></p>
-  <div id="content" style="display: none"></div>
-  <pre id="test">
-  </pre>
-  <div id="parent"><p style="display: none;" id="para">I'm hidden initially, but then made visible.</p></div>
-</body>
-</html>
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=434464
+-->
+<head>
+  <title>Test NSIAccessNode cache invalidation</title>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript">
+    function doTest()
+    {
+      var accRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+                       getService(Components.interfaces.nsIAccessibleRetrieval);
+
+      var parentElm = document.getElementById("parent");
+      if (!parentElm) {
+        ok(false, "no parent element for paragraph!");
+        SimpleTest.finish();
+      }
+
+      var elm = document.getElementById("para");
+      if (!elm) {
+        ok(false, "no element for paragraph!");
+        SimpleTest.finish();
+      }
+
+      // It's currently hidden. Ask for its parent's nsIAccessNode.
+      var parentElmAccNode = null;
+      try {
+        parentElmAccNode = accRetrieval.getAccessibleFor(parentElm).
+                     QueryInterface(Components.interfaces.nsIAccessNode);
+      } catch(e) {}
+
+      if (!parentElmAccNode) {
+        ok(false, "No accessNode for parent of hidden paragraph!");
+        SimpleTest.finish();
+      }
+
+      // Get the paragraph's accessNode.
+      var elmAccNode = null;
+      try {
+        elmAccNode = parentElmAccNode.firstChildNode;
+      } catch(e) {}
+
+      if (!elmAccNode) {
+        ok(false, "No accessNode for hidden paragraph!");
+        SimpleTest.finish();
+      }
+
+      // Now make the paragraph visible. This invalidates the just-retrieved
+      // AccessNode. An nsIAccessible should then be retrievable.
+      elm.style.display = "block";
+
+      // Now, get an accessible for it. Use a timeout so the layout engine can
+      // catch up.
+      window.setTimeout(
+        function()
+        {
+          var elmAcc = null;
+          try {
+            elmAcc = accRetrieval.getAccessibleFor(elm);
+          } catch(e) {}
+    
+          ok(elmAcc, "No accessible for paragraph after it became visible!");
+
+          SimpleTest.finish();
+        },
+      200);
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=434464">Mozilla Bug 434464</a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+  <div id="parent"><p style="display: none;" id="para">I'm hidden initially, but then made visible.</p></div>
+</body>
+</html>
--- a/accessible/tests/mochitest/test_name_markup.html
+++ b/accessible/tests/mochitest/test_name_markup.html
@@ -1,44 +1,41 @@
 <html>
 
 <head>
-  <title>nsIAccessible::name calculation for HTML buttons</title>
+  <title>nsIAccessible::name calculation for elements</title>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 
   <script type="application/javascript"
           src="chrome://mochikit/content/MochiKit/packed.js"></script>
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript"
           src="chrome://mochikit/content/a11y/accessible/common.js"></script>
   <script type="application/javascript"
+          src="chrome://mochikit/content/a11y/accessible/events.js"></script>
+  <script type="application/javascript"
           src="chrome://mochikit/content/a11y/accessible/nsIAccessible_name.js"></script>
 
   <script type="application/javascript">
-    function doTest()
-    {
-      testNames();
-
-      SimpleTest.finish();
-    }
+    // gA11yEventDumpID = "eventdump";
 
     SimpleTest.waitForExplicitFinish();
-    addLoadEvent(doTest);
+    addA11yLoadEvent(testNames);
   </script>
 
 </head>
 
 <body>
 
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=459635"
-     title="nsIAccessible::name calculation for HTML buttons">
+     title="nsIAccessible::name calculation for elements">
     Mozilla Bug 459635
   </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
-  
+  <div id="eventdump"></div>
 </body>
 </html>
--- a/accessible/tests/mochitest/test_nsIAccessible_name.html
+++ b/accessible/tests/mochitest/test_nsIAccessible_name.html
@@ -30,16 +30,20 @@
       // Single relation. The value of 'aria-labelledby' contains the ID of
       // an element. Gets the name from text node of that element.
       testName("btn_labelledby_text", "text");
 
       // Multiple relations. The value of 'aria-labelledby' contains the IDs
       // of elements. Gets the name from text nodes of those elements.
       testName("btn_labelledby_texts", "text1 text2");
 
+      //////////////////////////////////////////////////////////////////////////
+      // Name from named accessible
+
+      testName("input_labelledby_namedacc", "Data");
 
       //////////////////////////////////////////////////////////////////////////
       // Name from subtree (single relation labelled_by).
       
       // Gets the name from text nodes contained by nested elements
       testName("btn_labelledby_mixed", "nomore text");
 
       // Gets the name from text nodes contained by nested elements, ignores
@@ -124,20 +128,31 @@
 
       // new textarea name should reflect the value change. 
       var elem = document.getElementById("textareawithchild");
       elem.value = "Bar";
 
       testName("textareawithchild", "Story: Bar");
 
       /////////////////////////////////////////////////////////////////////////
-      // label with nested combobox
+      // label with nested combobox (test for 'f' item of name computation guide)
+
+      testName("comboinstart", "One day(s).");
+      testName("combo3", "day(s).");
 
       testName("comboinmiddle", "Subscribe to ATOM feed.");
-	   
+      testName("combo4", "Subscribe to ATOM feed.");
+
+      testName("comboinmiddle2", "Play the Haliluya sound when new mail arrives");
+      testName("combo5", "Play the Haliluya sound when new mail arrives");
+      testName("checkbox", "Play the Haliluya sound when new mail arrives");
+
+      testName("comboinend", "This day was sunny");
+      testName("combo6", "This day was");
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addLoadEvent(doTest);
   </script>
 
 </head>
@@ -170,16 +185,22 @@
 
   <!-- aria-labelledby, multiple relations -->
   <span id="labelledby_text1">text1</span>
   <span id="labelledby_text2">text2</span>
   <button id="btn_labelledby_texts"
           aria-labelledby="labelledby_text1 labelledby_text2">2</button>
   <br/>
 
+  <!-- name from named accessible -->
+  <input id="labelledby_namedacc" type="checkbox"
+         aria-label="Data" />
+  <input id="input_labelledby_namedacc"
+          aria-labelledby="labelledby_namedacc" />
+
   <!-- the name from subtree, mixed content -->
   <span id="labelledby_mixed">no<span>more text</span></span>
   <button id="btn_labelledby_mixed"
           aria-labelledby="labelledby_mixed">3</button>
   <br/>
 
   <!-- the name from subtree, mixed/hidden content -->
   <span id="labelledby_mixed_hidden_child">
@@ -281,22 +302,45 @@
 
   <!-- A textarea nested in a label with a text child (bug #453371). -->
   <form>
     <label>Story: 
       <textarea id="textareawithchild" name="name">Foo</textarea>
     </label>
   </form>
 
-  <!-- A label with a nested control in the middle -->
+  <!-- a label with a nested control in the start, middle and end -->
   <form>
+    <label id="comboinstart"><select id="combo3">
+        <option>One</option>
+        <option>Two</option>
+      </select>
+      day(s).
+    </label>
+
     <label id="comboinmiddle">
       Subscribe to
-      <select id="combo3" name="occupation">
+      <select id="combo4" name="occupation">
         <option>ATOM</option>
         <option>RSS</option>
       </select>
       feed.
     </label>
+
+    <label id="comboinmiddle2" for="checkbox">Play the
+      <select id="combo5">
+        <option>Haliluya</option>
+        <option>Hurra</option>
+      </select>
+      sound when new mail arrives
+    </label>
+    <input id="checkbox" type="checkbox" />
+
+    <label id="comboinend">
+      This day was
+      <select id="combo6" name="occupation">
+        <option>sunny</option>
+        <option>rainy</option>
+      </select></label>
   </form>
 
 </body>
 </html>
--- a/accessible/tests/mochitest/test_nsIAccessible_name.xul
+++ b/accessible/tests/mochitest/test_nsIAccessible_name.xul
@@ -35,16 +35,20 @@
       // Single relation. The value of 'aria-labelledby' contains the ID of
       // an element. Gets the name from text node of that element.
       testName("btn_labelledby_text", "text");
 
       // Multiple relations. The value of 'aria-labelledby' contains the IDs
       // of elements. Gets the name from text nodes of those elements.
       testName("btn_labelledby_texts", "text1 text2");
 
+      // Trick cases. Self and recursive referencing.
+      testName("rememberHistoryDays", "Remember 3 days");
+      testName("historyDays", "Remember 3 days");
+      testName("rememberAfter", null); // XUL labels doesn't allow name from subtree
 
       //////////////////////////////////////////////////////////////////////////
       // Name from subtree (single relation labelled_by).
       
       // Gets the name from text nodes contained by nested elements.
       testName("btn_labelledby_mixed", "nomore text");
 
       // Gets the name from text nodes and selected item of menulist
@@ -96,27 +100,27 @@
 
 
       //////////////////////////////////////////////////////////////////////////
       // Name from the label element in anonymous content (see bug 362365).
 
       // Get the name from anonymous label element for anonymous textbox
       // (@anonid is used).
       var ID = "box_label_anon1";
-      var box1Acc = testName(ID, "");
+      var box1Acc = testName(ID, null);
       if (box1Acc) {
         var textboxAcc = box1Acc.firstChild;
         is(textboxAcc.name, "Label",
            "Wrong label for anonymous textbox of " + ID);
       }
 
       // Get the name from anonymous label element for anonymous textbox
       // (@anonid is used). Nested bindings.
       ID = "box_label_anon2";
-      var box2Acc = testName(ID, "");
+      var box2Acc = testName(ID, null);
       if (box2Acc) {
         var textboxAcc = box2Acc.firstChild;
         is(textboxAcc.name, "Label",
            "Wrong label for anonymous textbox of " + ID);
 
         var topTextboxAcc = box2Acc.lastChild;
         is(topTextboxAcc.name, "Top textbox",
            "Wrong label for anonymous textbox of " + ID);
@@ -190,16 +194,24 @@
           aria-labelledby="labelledby_text"/>
 
   <!-- aria-labelledby, multiple relations -->
   <description id="labelledby_text1">text1</description>
   <description id="labelledby_text2">text2</description>
   <button id="btn_labelledby_texts"
           aria-labelledby="labelledby_text1 labelledby_text2"/>
 
+  <!-- trick aria-labelledby -->
+  <checkbox id="rememberHistoryDays"
+            label="Remember "
+            aria-labelledby="rememberHistoryDays historyDays rememberAfter"/>
+  <textbox id="historyDays" type="number" size="3" value="3"
+           aria-labelledby="rememberHistoryDays historyDays rememberAfter"/>
+  <label id="rememberAfter">days</label>
+
   <!-- the name from subtree, mixed content -->
   <description id="labelledby_mixed">
     no<description>more text</description>
   </description>
   <button id="btn_labelledby_mixed"
           aria-labelledby="labelledby_mixed"/>
 
   <!-- the name from subtree, mixed/hidden content -->
--- a/accessible/tests/mochitest/test_nsIAccessible_selects.html
+++ b/accessible/tests/mochitest/test_nsIAccessible_selects.html
@@ -42,18 +42,18 @@
         (STATE_SELECTED | STATE_FOCUSED) // second, not currently focused, item
       ];
       testSelect("combo1", names, roles, states, undesiredStates);
 
       // Select nested within label element.
       names = [
         "Search in: Newsticker", // label
         "Search in:", // text leaf
-        "Search in: Newsticker", // combobox
-        "Search in:", // combobox_list
+        "Search in:", // combobox
+        "Search in: Newsticker", // combobox_list
         "Newsticker", // option 1
         "Entire site" // Option 2
       ];
       roles = [
         ROLE_LABEL, // root
         ROLE_TEXT_LEAF, // inner text
         ROLE_COMBOBOX, // combobox accessible
         ROLE_COMBOBOX_LIST, // list accessible
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_objectattrs.html
@@ -0,0 +1,95 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=475006
+-->
+<head>
+  <title>Group attributes tests</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/a11y/accessible/common.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/a11y/accessible/attributes.js"></script>
+
+  <script type="application/javascript">
+    function doTest()
+    {
+      // aria
+      testAttrs("atomic", {"atomic" : "true"}, true);
+      testAttrs("autocomplete", {"autocomplete" : "true"}, true);
+      testAttrs("checkbox", {"checkable" : "true"}, true); 
+      testAttrs("checkedCheckbox", {"checkable" : "true"}, true); 
+      testAttrs("checkedMenuitem", {"checkable" : "true"}, true); 
+      testAttrs("checkedOption", {"checkable" : "true"}, true); 
+      testAttrs("checkedRadio", {"checkable" : "true"}, true); 
+      testAttrs("checkedTreeitem", {"checkable" : "true"}, true); 
+      testAttrs("dropeffect", {"dropeffect" : "copy"}, true);
+
+      // live object attribute
+      testAttrs("live", {"live" : "polite"}, true);
+      testAttrs("live2", {"live" : "polite"}, true);
+      testAttrs("log", {"live" : "polite"}, true);
+      testAttrs("marquee", {"live" : "off"}, true);
+      testAttrs("status", {"live" : "polite"}, true);
+      testAttrs("timer", {"live" : "off"}, true);
+
+      // container-live object attribute
+      testAttrs("liveChild", {"container-live" : "polite"}, true);
+      testAttrs("live2Child", {"container-live" : "polite"}, true);
+      testAttrs("logChild", {"container-live" : "polite"}, true);
+      testAttrs("marqueeChild", {"container-live" : "off"}, true);
+      testAttrs("statusChild", {"container-live" : "polite"}, true);
+      testAttrs("timerChild", {"container-live" : "off"}, true);
+
+      // html
+      testAttrs("radio", {"checkable" : "true"}, true); 
+      testAttrs("checkbox", {"checkable" : "true"}, true); 
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(doTest);
+  </script>
+</head>
+<body>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=475006"
+     title="Extend nsARIAMap to capture ARIA attribute characteristics">
+    Mozilla Bug 475006
+  </a>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <!-- aria -->
+  <div id="atomic" aria-atomic="true"></div>
+  <div id="autocomplete" role="textbox" aria-autocomplete="true"></div>
+  <div id="checkbox" role="checkbox"></div>
+  <div id="checkedCheckbox" role="checkbox" aria-checked="true"></div>
+  <div id="checkedMenuitem" role="menuitem" aria-checked="true"></div>
+  <div id="checkedOption" role="option" aria-checked="true"></div>
+  <div id="checkedRadio" role="radio" aria-checked="true"></div>
+  <div id="checkedTreeitem" role="treeitem" aria-checked="true"></div>
+  <div id="dropeffect" aria-dropeffect="copy"></div>
+
+  <div id="live" aria-live="polite">excuse <div id="liveChild">me</div></div>
+  <div id="live2" role="marquee" aria-live="polite">excuse <div id="live2Child">me</div></div>
+  <div id="log" role="log">excuse <div id="logChild">me</div></div>
+  <div id="marquee" role="marquee">excuse <div id="marqueeChild">me</div></div>
+  <div id="status" role="status">excuse <div id="statusChild">me</div></div>
+  <div id="timer" role="timer">excuse <div id="timerChild">me</div></div>
+
+  <!-- html -->
+  <input id="radio" type="radio"/>
+  <input id="checkbox" type="checkbox"/>
+</body>
+</html>
rename from accessible/tests/mochitest/test_nsIAccessible_editabledoc.html
rename to accessible/tests/mochitest/test_states_doc.html
--- a/accessible/tests/mochitest/test_nsIAccessible_editabledoc.html
+++ b/accessible/tests/mochitest/test_states_doc.html
@@ -1,48 +1,67 @@
 <!DOCTYPE html>
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=454997
+https://bugzilla.mozilla.org/show_bug.cgi?id=467387
 -->
 <head>
-  <title>nsIAccessible states tests of editable document</title>
+  <title>states of document</title>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 
   <script type="application/javascript"
           src="chrome://mochikit/content/MochiKit/packed.js"></script>
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 
   <script type="application/javascript"
           src="chrome://mochikit/content/a11y/accessible/common.js"></script>
   <script type="application/javascript"
           src="chrome://mochikit/content/a11y/accessible/nsIAccessible_states.js"></script>
 
   <script type="application/javascript">
     function doTest()
     {
+      testStates(document, STATE_READONLY);
+      testStates("document", STATE_READONLY);
+      testStates("editable_document", 0, EXT_STATE_EDITABLE);
+
       document.designMode = "on";
 
       testStates(document, 0, EXT_STATE_EDITABLE);
       testStates("p", 0, EXT_STATE_EDITABLE);
+      testStates("document", 0, EXT_STATE_EDITABLE);
+      testStates("editable_document", 0, EXT_STATE_EDITABLE);
+
+      document.designMode = "off";
+
+      testStates(document, STATE_READONLY);
+      testStates("document", STATE_READONLY);
+      testStates("editable_document", 0, EXT_STATE_EDITABLE);
 
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addLoadEvent(doTest);
   </script>
 </head>
 
-<body id="body">
+<body>
 
   <a target="_blank"
      title="nsIAccessible states tests of editable document"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=454997">Mozilla Bug 454997</a>
+   <a target="_blank"
+     title="nsIAccessible states tests of editable document"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=467387">Mozilla Bug 467387</a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <p id="p">hello</p>
+
+  <div id="document" role="document">document</div>
+  <div id="editable_document" role="document" contentEditable="true">editable document</doc>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_states_docarticle.html
@@ -0,0 +1,62 @@
+<html>
+<head>
+  <title>states of document article</title>
+
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/a11y/accessible/common.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/a11y/accessible/nsIAccessible_states.js"></script>
+
+  <script type="application/javascript">
+    function doTest()
+    {      
+      var docAcc = getAccessible(document, [nsIAccessibleDocument]);
+      if (docAcc) {
+        testStates(docAcc, STATE_READONLY);
+        testStates("article", STATE_READONLY);
+        testStates("editable_article", 0, EXT_STATE_EDITABLE);
+
+        document.designMode = "on";
+
+        testStates(docAcc, 0, EXT_STATE_EDITABLE);
+        testStates("article", 0, EXT_STATE_EDITABLE);
+        testStates("editable_article", 0, EXT_STATE_EDITABLE);
+  
+        document.designMode = "off";
+
+        testStates(docAcc, STATE_READONLY);
+        testStates("article", STATE_READONLY);
+        testStates("editable_article", 0, EXT_STATE_EDITABLE);
+      }
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(doTest);
+  </script>
+</head>
+
+<body role="article">
+
+  <a target="_blank"
+    href="https://bugzilla.mozilla.org/show_bug.cgi?id=467387"
+    title="Expose non-editable documents as readonly, regardless of role">
+     Mozilla Bug 467387
+  </a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <div id="article" role="article">article</div>
+  <div id="editable_article" role="article" contentEditable="true">editable article</doc>
+</body>
+</html>
rename from accessible/tests/mochitest/test_nsIAccessible_editablebody.html
rename to accessible/tests/mochitest/test_states_editablebody.html
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_states_frames.html
@@ -0,0 +1,76 @@
+<html>
+
+<head>
+  <title>frame based document testing</title>
+
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/a11y/accessible/common.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/a11y/accessible/nsIAccessible_states.js"></script>
+
+  <script type="application/javascript">
+    function doTest()
+    {
+      frameDoc = document.getElementById("frame_doc").contentDocument;
+      frameDocArticle = document.getElementById("frame_doc_article").contentDocument;
+      frameDocCheckbox = document.getElementById("frame_doc_checkbox").contentDocument;
+      frameDocTextbox = document.getElementById("frame_doc_textbox").contentDocument;
+      
+      testStates(frameDoc, STATE_READONLY);
+      testStates(frameDocArticle, STATE_READONLY);
+      testStates(frameDocCheckbox, 0, 0, STATE_READONLY);
+      
+      var works = true;
+      try {
+          testStates(frameDocTextbox, 0, 0, STATE_READONLY);
+      }
+      catch (e) {
+        works = false;
+      }
+      todo(works, "Checking states of a textbox frame doc should not throw (Bug 478810)");
+      
+      frameDoc.designMode = "on";
+      testStates(frameDoc,  0, EXT_STATE_EDITABLE);
+      testStates(frameDocArticle, STATE_READONLY);
+      testStates(frameDocCheckbox, 0, 0, STATE_READONLY);
+
+      frameDocArticle.designMode = "on";
+      testStates(frameDocArticle, 0, EXT_STATE_EDITABLE);
+
+      frameDocCheckbox.designMode = "on";
+      testStates(frameDocCheckbox, 0, 0, STATE_READONLY);
+      
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(doTest);
+  </script>
+</head>
+
+<body>
+
+  <a target="_blank"
+    href="https://bugzilla.mozilla.org/show_bug.cgi?id=467387"
+    title="Expose non-editable documents as readonly, regardless of role">
+     Mozilla Bug 467387
+  </a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+  
+  <iframe id="frame_doc" src="z_states_frame.html"></iframe>
+  <iframe id="frame_doc_article" src="z_states_framearticle.html"></iframe>
+  <iframe id="frame_doc_checkbox" src="z_states_framecheckbox.html"></iframe>
+  <iframe id="frame_doc_textbox" src="z_states_frametextbox.html"></iframe>
+</body>
+</html>
--- a/accessible/tests/mochitest/test_table_indexes.html
+++ b/accessible/tests/mochitest/test_table_indexes.html
@@ -1,262 +1,262 @@
-<!DOCTYPE html>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=410052
--->
-<head>
-  <title>Table indexes chrome tests</title>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
-
-  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-
-  <script type="application/javascript">
-    const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
-    const nsIAccessibleTable = Components.interfaces.nsIAccessibleTable;
-
-    var gAccService = null;
-
-    function doTest()
-    {
-      gAccService = Components.classes["@mozilla.org/accessibleRetrieval;1"].
-                    getService(nsIAccessibleRetrieval);
-
-      //////////////////////////////////////////////////////////////////////////
-      // table
-      var tRow = new Array(0,0,0,1,1,1,2,2,3,3);
-      var tCol = new Array(0,1,2,0,1,2,0,1,1,2);
-
-      testTable("table", 10, tRow, tCol);
-
-      //////////////////////////////////////////////////////////////////////////
-      // tableinsane1
-      tRow = [0,0,0,1,1,1,2,2,3,3];
-      tCol = [0,1,2,0,1,2,0,1,1,2];
-
-      testTable("tableinsane1", 10, tRow, tCol);
-
-      //////////////////////////////////////////////////////////////////////////
-      // tableinsane2
-      tRow = [0,0,0,1,1,1,2,2,3,3,4,4,4];
-      tCol = [0,1,2,0,1,2,0,1,1,2,1,3,4];
-
-      testTable("tableinsane2", 13, tRow, tCol);
-
-      //////////////////////////////////////////////////////////////////////////
-      // tableinsane4
-      tRow = [0,0,0,1,1,1,2,2,3,4];
-      tCol = [0,1,2,0,1,2,0,2,0,0];
-
-      testTable("tableinsane4", 10, tRow, tCol);
-
-      //////////////////////////////////////////////////////////////////////////
-      // tableborder
-      tRow = [0,0,0,1,1,1,2,2,3,3];
-      tCol = [0,1,2,0,1,2,0,1,1,2];
-
-      testTable("tableborder", 10, tRow, tCol);
-
-      SimpleTest.finish();
-    }
-
-    function testTable(aId, aLen, aRowIdxes, aColIdxes)
-    {
-      var table = document.getElementById(aId);
-      var tableAcc = gAccService.getAccessibleFor(table).
-        QueryInterface(nsIAccessibleTable);
-
-      var row, column, index;
-      var cellAcc;
-
-      for (var i = 0; i < aLen; i++) {
-        row = tableAcc.getRowAtIndex(i);
-        column = tableAcc.getColumnAtIndex(i);
-        index = tableAcc.getIndexAt(aRowIdxes[i], aColIdxes[i]);
-
-        is(row, aRowIdxes[i], aId + ": row  for index " + i +" is nor correct");
-        is(column, aColIdxes[i],
-           aId + ": column  for index " + i +"is nor correct");
-        is(index, i,
-           aId + ": row " + row + " /column " + column + " and index " + index + " aren't inconsistent.");
-
-        try {
-          cellAcc = null;
-          cellAcc = tableAcc.cellRefAt(row, column);
-        } catch (e) { }
-
-        ok(cellAcc,
-           aId + ": Can't get cell accessible at row = " + row + ", column = " + column);
-
-        if (cellAcc) {
-          var attrs = cellAcc.attributes;
-          is (parseInt(attrs.getStringProperty("table-cell-index")), index,
-              aId + ": cell index from object attributes of cell accessible isn't corrent.");
-        }
-      }
-    }
-
-    SimpleTest.waitForExplicitFinish();
-    addLoadEvent(doTest);
-  </script>
-</head>
-<body>
-
-  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=410052">Mozilla Bug 410052</a>
-  <p id="display"></p>
-  <div id="content" style="display: none"></div>
-  <pre id="test">
-  </pre>
-
-  <!--
-    If you change the structure of the table please make sure to change
-    the indexes count in 'for' statement in the script above.
-  -->
-  <table border="1" id="table">
-    <caption><strong><b><font size="29">this is a caption for this table</font></b></strong></caption>
-    <thead>
-      <tr>
-        <th>col1</th>
-        <th>col2</th>
-        <th>col3</th>
-      </tr>
-    </thead>
-    <tbody>
-      <tr>
-        <td>1</td>
-        <td>2</td>
-        <td>3</td>
-      </tr>
-      <tr>
-        <td rowspan="0">4</td>
-        <td colspan="2">5</td>
-      </tr>
-      <tr>
-        <td>6</td>
-        <td>7</td>
-      </tr>
-    </tbody>
-  </table>
-
-  <table border="1" id="tableborder" style="border-collapse:collapse">
-    <caption><strong><b><font size="29">this is a caption for this bc table</font></b></strong></caption>
-    <thead>
-      <tr>
-        <th>col1</th>
-        <th>col2</th>
-        <th>col3</th>
-      </tr>
-    </thead>
-    <tbody>
-      <tr>
-        <td>1</td>
-        <td>2</td>
-        <td>3</td>
-      </tr>
-      <tr>
-        <td rowspan="2">4</td>
-        <td colspan="2">5</td>
-      </tr>
-      <tr>
-        <td>6</td>
-        <td>7</td>
-      </tr>
-    </tbody>
-  </table>
-
-  <table border="1" id="tableinsane1">
-    <caption>test empty row groups</caption>
-    <thead>
-      <tr>
-        <th>col1</th>
-        <th>col2</th>
-        <th>col3</th>
-      </tr>
-    </thead>
-    <tbody></tbody>
-    <tbody></tbody>
-    <tbody></tbody>
-    <tbody>
-      <tr>
-        <td>1</td>
-        <td>2</td>
-        <td>3</td>
-      </tr>
-      <tr>
-        <td rowspan="2">4</td>
-        <td colspan="2">5</td>
-      </tr>
-      <tr>
-        <td>6</td>
-        <td>7</td>
-      </tr>
-    </tbody>
-  </table>
-
-  <table border="1" id="tableinsane2" >
-    <caption>empty rowgroup + empty rows</caption>
-    <thead>
-      <tr>
-        <th>col1</th>
-        <th>col2</th>
-        <th>col3</th>
-      </tr>
-    </thead>
-    <tbody><tr></tr></tbody>
-    <tbody></tbody>
-    <tbody></tbody>
-    <tbody>
-      <tr>
-        <td>1</td>
-        <td>2</td>
-        <td>3</td>
-      </tr>
-      <tr>
-        <td rowspan="0">4</td>
-        <td colspan="0">5</td>
-      </tr>
-      <tr>
-        <td>6</td>
-        <td  rowspan="0">7</td>
-      </tr>
-      <tr>
-        <td>8</td>
-        <td>9</td>
-        <td>10</td>
-      </tr>
-
-    </tbody>
-
-  <table border="1" id="tableinsane4" >
-    <caption>test cellmap holes</caption>
-    <thead>
-      <tr>
-        <th>col1</th>
-        <th>col2</th>
-        <th>col3</th>
-      </tr>
-    </thead>
-    <tbody><tr></tr></tbody>
-    <tbody></tbody>
-    <tbody></tbody>
-    <tbody>
-      <tr>
-        <td>1</td>
-        <td>2</td>
-        <td>3</td>
-      </tr>
-      <tr>
-         <td colspan="2">4</td>
-        <td rowspan="2">5</td>
-        </tr>
-      <tr>
-        <td>6</td>
-      </tr>
-      <tr>
-        <td colspan="3">7</td>       
-      </tr>
-
-    </tbody>
-  </table>
-
-</body>
-</html>
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=410052
+-->
+<head>
+  <title>Table indexes chrome tests</title>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript">
+    const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+    const nsIAccessibleTable = Components.interfaces.nsIAccessibleTable;
+
+    var gAccService = null;
+
+    function doTest()
+    {
+      gAccService = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+                    getService(nsIAccessibleRetrieval);
+
+      //////////////////////////////////////////////////////////////////////////
+      // table
+      var tRow = new Array(0,0,0,1,1,1,2,2,3,3);
+      var tCol = new Array(0,1,2,0,1,2,0,1,1,2);
+
+      testTable("table", 10, tRow, tCol);
+
+      //////////////////////////////////////////////////////////////////////////
+      // tableinsane1
+      tRow = [0,0,0,1,1,1,2,2,3,3];
+      tCol = [0,1,2,0,1,2,0,1,1,2];
+
+      testTable("tableinsane1", 10, tRow, tCol);
+
+      //////////////////////////////////////////////////////////////////////////
+      // tableinsane2
+      tRow = [0,0,0,1,1,1,2,2,3,3,4,4,4];
+      tCol = [0,1,2,0,1,2,0,1,1,2,1,3,4];
+
+      testTable("tableinsane2", 13, tRow, tCol);
+
+      //////////////////////////////////////////////////////////////////////////
+      // tableinsane4
+      tRow = [0,0,0,1,1,1,2,2,3,4];
+      tCol = [0,1,2,0,1,2,0,2,0,0];
+
+      testTable("tableinsane4", 10, tRow, tCol);
+
+      //////////////////////////////////////////////////////////////////////////
+      // tableborder
+      tRow = [0,0,0,1,1,1,2,2,3,3];
+      tCol = [0,1,2,0,1,2,0,1,1,2];
+
+      testTable("tableborder", 10, tRow, tCol);
+
+      SimpleTest.finish();
+    }
+
+    function testTable(aId, aLen, aRowIdxes, aColIdxes)
+    {
+      var table = document.getElementById(aId);
+      var tableAcc = gAccService.getAccessibleFor(table).
+        QueryInterface(nsIAccessibleTable);
+
+      var row, column, index;
+      var cellAcc;
+
+      for (var i = 0; i < aLen; i++) {
+        row = tableAcc.getRowAtIndex(i);
+        column = tableAcc.getColumnAtIndex(i);
+        index = tableAcc.getIndexAt(aRowIdxes[i], aColIdxes[i]);
+
+        is(row, aRowIdxes[i], aId + ": row  for index " + i +" is nor correct");
+        is(column, aColIdxes[i],
+           aId + ": column  for index " + i +"is nor correct");
+        is(index, i,
+           aId + ": row " + row + " /column " + column + " and index " + index + " aren't inconsistent.");
+
+        try {
+          cellAcc = null;
+          cellAcc = tableAcc.cellRefAt(row, column);
+        } catch (e) { }
+
+        ok(cellAcc,
+           aId + ": Can't get cell accessible at row = " + row + ", column = " + column);
+
+        if (cellAcc) {
+          var attrs = cellAcc.attributes;
+          is (parseInt(attrs.getStringProperty("table-cell-index")), index,
+              aId + ": cell index from object attributes of cell accessible isn't corrent.");
+        }
+      }
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=410052">Mozilla Bug 410052</a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <!--
+    If you change the structure of the table please make sure to change
+    the indexes count in 'for' statement in the script above.
+  -->
+  <table border="1" id="table">
+    <caption><strong><b><font size="29">this is a caption for this table</font></b></strong></caption>
+    <thead>
+      <tr>
+        <th>col1</th>
+        <th>col2</th>
+        <th>col3</th>
+      </tr>
+    </thead>
+    <tbody>
+      <tr>
+        <td>1</td>
+        <td>2</td>
+        <td>3</td>
+      </tr>
+      <tr>
+        <td rowspan="0">4</td>
+        <td colspan="2">5</td>
+      </tr>
+      <tr>
+        <td>6</td>
+        <td>7</td>
+      </tr>
+    </tbody>
+  </table>
+
+  <table border="1" id="tableborder" style="border-collapse:collapse">
+    <caption><strong><b><font size="29">this is a caption for this bc table</font></b></strong></caption>
+    <thead>
+      <tr>
+        <th>col1</th>
+        <th>col2</th>
+        <th>col3</th>
+      </tr>
+    </thead>
+    <tbody>
+      <tr>
+        <td>1</td>
+        <td>2</td>
+        <td>3</td>
+      </tr>
+      <tr>
+        <td rowspan="2">4</td>
+        <td colspan="2">5</td>
+      </tr>
+      <tr>
+        <td>6</td>
+        <td>7</td>
+      </tr>
+    </tbody>
+  </table>
+
+  <table border="1" id="tableinsane1">
+    <caption>test empty row groups</caption>
+    <thead>
+      <tr>
+        <th>col1</th>
+        <th>col2</th>
+        <th>col3</th>
+      </tr>
+    </thead>
+    <tbody></tbody>
+    <tbody></tbody>
+    <tbody></tbody>
+    <tbody>
+      <tr>
+        <td>1</td>
+        <td>2</td>
+        <td>3</td>
+      </tr>
+      <tr>
+        <td rowspan="2">4</td>
+        <td colspan="2">5</td>
+      </tr>
+      <tr>
+        <td>6</td>
+        <td>7</td>
+      </tr>
+    </tbody>
+  </table>
+
+  <table border="1" id="tableinsane2" >
+    <caption>empty rowgroup + empty rows</caption>
+    <thead>
+      <tr>
+        <th>col1</th>
+        <th>col2</th>
+        <th>col3</th>
+      </tr>
+    </thead>
+    <tbody><tr></tr></tbody>
+    <tbody></tbody>
+    <tbody></tbody>
+    <tbody>
+      <tr>
+        <td>1</td>
+        <td>2</td>
+        <td>3</td>
+      </tr>
+      <tr>
+        <td rowspan="0">4</td>
+        <td colspan="0">5</td>
+      </tr>
+      <tr>
+        <td>6</td>
+        <td  rowspan="0">7</td>
+      </tr>
+      <tr>
+        <td>8</td>
+        <td>9</td>
+        <td>10</td>
+      </tr>
+
+    </tbody>
+
+  <table border="1" id="tableinsane4" >
+    <caption>test cellmap holes</caption>
+    <thead>
+      <tr>
+        <th>col1</th>
+        <th>col2</th>
+        <th>col3</th>
+      </tr>
+    </thead>
+    <tbody><tr></tr></tbody>
+    <tbody></tbody>
+    <tbody></tbody>
+    <tbody>
+      <tr>
+        <td>1</td>
+        <td>2</td>
+        <td>3</td>
+      </tr>
+      <tr>
+         <td colspan="2">4</td>
+        <td rowspan="2">5</td>
+        </tr>
+      <tr>
+        <td>6</td>
+      </tr>
+      <tr>
+        <td colspan="3">7</td>       
+      </tr>
+
+    </tbody>
+  </table>
+
+</body>
+</html>
--- a/accessible/tests/mochitest/test_textattrs.html
+++ b/accessible/tests/mochitest/test_textattrs.html
@@ -61,20 +61,20 @@
           };
           testDefaultTextAttrs(ID, defAttrs);
 
           var attrs = { };
           var misspelledAttrs = {
             "invalid": "spelling"
           };
 
-          testTextAttrs(ID, 0, attrs, 0, 11);
-          testTextAttrs(ID, 11, misspelledAttrs, 11, 17);
-          testTextAttrs(ID, 17, attrs, 17, 18);
-          testTextAttrs(ID, 18, misspelledAttrs, 18, 22);
+          testTextAttrs(ID, 0, attrs, defAttrs, 0, 11);
+          testTextAttrs(ID, 11, misspelledAttrs, defAttrs, 11, 17);
+          testTextAttrs(ID, 17, attrs, defAttrs, 17, 18);
+          testTextAttrs(ID, 18, misspelledAttrs, defAttrs, 18, 22);
 
           is(gTextAttrChangedEventHandler.eventNumber, 2,
              "Wrong count of 'text attribute changed' events for " + ID);
 
           unregisterA11yEventListener(nsIAccessibleEvent.EVENT_TEXT_ATTRIBUTE_CHANGED,
                                       gTextAttrChangedEventHandler);
 
           SimpleTest.finish();
@@ -96,25 +96,25 @@
         "color": gComputedStyle.color,
         "font-family": gComputedStyle.fontFamily,
         "text-position": gComputedStyle.verticalAlign
       };
 
       testDefaultTextAttrs(ID, defAttrs);
 
       var attrs = {};
-      testTextAttrs(ID, 0, attrs, 0, 7);
+      testTextAttrs(ID, 0, attrs, defAttrs, 0, 7);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"font-weight": gComputedStyle.fontWeight};
-      testTextAttrs(ID, 7, attrs, 7, 11);
+      testTextAttrs(ID, 7, attrs, defAttrs, 7, 11);
 
       attrs = {};
-      testTextAttrs(ID, 12, attrs, 11, 18);
+      testTextAttrs(ID, 12, attrs, defAttrs, 11, 18);
 
       //////////////////////////////////////////////////////////////////////////
       // area2
       ID = "area2";
       tempElem = document.getElementById(ID);
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       defAttrs = {
         "font-style": gComputedStyle.fontStyle,
@@ -124,36 +124,36 @@
         "color": gComputedStyle.color,
         "font-family": gComputedStyle.fontFamily,
         "text-position": gComputedStyle.verticalAlign
       };
 
       testDefaultTextAttrs(ID, defAttrs);
 
       attrs = {};
-      testTextAttrs(ID, 0, attrs, 0, 7);
+      testTextAttrs(ID, 0, attrs, defAttrs, 0, 7);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"font-weight": gComputedStyle.fontWeight};
-      testTextAttrs(ID, 7, attrs, 7, 12);
+      testTextAttrs(ID, 7, attrs, defAttrs, 7, 12);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"font-style": gComputedStyle.fontStyle,
                "font-weight": gComputedStyle.fontWeight};
-      testTextAttrs(ID, 13, attrs, 12, 19);
+      testTextAttrs(ID, 13, attrs, defAttrs, 12, 19);
 
       tempElem = tempElem.parentNode;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"font-weight": "401"};
-      testTextAttrs(ID, 20, attrs, 19, 23);
+      testTextAttrs(ID, 20, attrs, defAttrs, 19, 23);
 
       attrs = {};
-      testTextAttrs(ID, 24, attrs, 23, 30);
+      testTextAttrs(ID, 24, attrs, defAttrs, 23, 30);
 
       //////////////////////////////////////////////////////////////////////////
       // area3
       ID = "area3";
       tempElem = document.getElementById(ID);
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       defAttrs = {
         "font-style": gComputedStyle.fontStyle,
@@ -165,33 +165,33 @@
         "text-position": gComputedStyle.verticalAlign
       };
 
       testDefaultTextAttrs(ID, defAttrs);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 0, attrs, 0, 6);
+      testTextAttrs(ID, 0, attrs, defAttrs, 0, 6);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 6, attrs, 6, 26);
+      testTextAttrs(ID, 6, attrs, defAttrs, 6, 26);
 
       tempElem = tempElem.parentNode;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 26, attrs, 26, 27);
+      testTextAttrs(ID, 26, attrs, defAttrs, 26, 27);
 
       tempElem = tempElem.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color,
                "background-color": gComputedStyle.backgroundColor};
-      testTextAttrs(ID, 27, attrs, 27, 50);
+      testTextAttrs(ID, 27, attrs, defAttrs, 27, 50);
 
       //////////////////////////////////////////////////////////////////////////
       // area4
       ID = "area4";
       tempElem = document.getElementById(ID);
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       defAttrs = {
         "font-style": gComputedStyle.fontStyle,
@@ -203,27 +203,27 @@
         "text-position": gComputedStyle.verticalAlign
       };
 
       testDefaultTextAttrs(ID, defAttrs);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 0, attrs, 0, 16);
+      testTextAttrs(ID, 0, attrs, defAttrs, 0, 16);
 
       tempElem = tempElem.nextSibling.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 16, attrs, 16, 33);
+      testTextAttrs(ID, 16, attrs, defAttrs, 16, 33);
 
       tempElem = tempElem.parentNode;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 34, attrs, 33, 46);
+      testTextAttrs(ID, 34, attrs, defAttrs, 33, 46);
 
       //////////////////////////////////////////////////////////////////////////
       // area5
       ID = "area5";
       tempElem = document.getElementById(ID);
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       defAttrs = {
         "font-style": gComputedStyle.fontStyle,
@@ -235,28 +235,28 @@
         "text-position": gComputedStyle.verticalAlign
       };
 
       testDefaultTextAttrs(ID, defAttrs);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 0, attrs, 0, 5);
+      testTextAttrs(ID, 0, attrs, defAttrs, 0, 5);
 
       attrs = {};
-      testTextAttrs(ID, 7, attrs, 5, 8);
+      testTextAttrs(ID, 7, attrs, defAttrs, 5, 8);
 
       tempElem = tempElem.nextSibling.nextSibling.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 9, attrs, 8, 11);
+      testTextAttrs(ID, 9, attrs, defAttrs, 8, 11);
 
       attrs = {};
-      testTextAttrs(ID, 11, attrs, 11, 18);
+      testTextAttrs(ID, 11, attrs, defAttrs, 11, 18);
 
       //////////////////////////////////////////////////////////////////////////
       // area6 (CSS vertical-align property, bug 445938)
       ID = "area6";
       tempElem = document.getElementById(ID);
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       defAttrs = {
         "font-style": gComputedStyle.fontStyle,
@@ -266,105 +266,234 @@
         "color": gComputedStyle.color,
         "font-family": gComputedStyle.fontFamily,
         "text-position": gComputedStyle.verticalAlign
       };
 
       testDefaultTextAttrs(ID, defAttrs);
 
       attrs = {};
-      testTextAttrs(ID, 0, attrs, 0, 5);
+      testTextAttrs(ID, 0, attrs, defAttrs, 0, 5);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"text-position": gComputedStyle.verticalAlign,
                "font-size": "10pt"};
-      testTextAttrs(ID, 5, attrs, 5, 13);
+      testTextAttrs(ID, 5, attrs, defAttrs, 5, 13);
 
       attrs = {};
-      testTextAttrs(ID, 13, attrs, 13, 27);
+      testTextAttrs(ID, 13, attrs, defAttrs, 13, 27);
 
       tempElem = tempElem.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"text-position": gComputedStyle.verticalAlign};
-      testTextAttrs(ID, 27, attrs, 27, 35);
+      testTextAttrs(ID, 27, attrs, defAttrs, 27, 35);
 
       attrs = {};
-      testTextAttrs(ID, 35, attrs, 35, 39);
+      testTextAttrs(ID, 35, attrs, defAttrs, 35, 39);
 
       tempElem = tempElem.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"text-position": gComputedStyle.verticalAlign,
                "font-size": "10pt"};
-      testTextAttrs(ID, 39, attrs, 39, 50);
+      testTextAttrs(ID, 39, attrs, defAttrs, 39, 50);
 
       attrs = {};
-      testTextAttrs(ID, 50, attrs, 50, 55);
+      testTextAttrs(ID, 50, attrs, defAttrs, 50, 55);
 
       tempElem = tempElem.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"text-position": gComputedStyle.verticalAlign};
-      testTextAttrs(ID, 55, attrs, 55, 64);
+      testTextAttrs(ID, 55, attrs, defAttrs, 55, 64);
 
       //////////////////////////////////////////////////////////////////////////
       // area7
       ID = "area7";
       tempElem = document.getElementById(ID);
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       defAttrs = {
+        "language": "en",
+        "font-style": gComputedStyle.fontStyle,
+        "font-size": "12pt",
+        "background-color": "rgb(255, 255, 255)",
+        "font-weight": gComputedStyle.fontWeight,
+        "color": gComputedStyle.color,
+        "font-family": gComputedStyle.fontFamily,
+        "text-position": gComputedStyle.verticalAlign
+      };
+
+      testDefaultTextAttrs(ID, defAttrs);
+
+      attrs = {"language": "ru"};
+      testTextAttrs(ID, 0, attrs, defAttrs, 0, 12);
+
+      attrs = {};
+      testTextAttrs(ID, 12, attrs, defAttrs, 12, 13);
+
+      tempElem = tempElem.firstChild.nextSibling.nextSibling.nextSibling;
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      attrs = { "background-color": gComputedStyle.backgroundColor};
+      testTextAttrs(ID, 13, attrs, defAttrs, 13, 26);
+
+      attrs = {};
+      testTextAttrs(ID, 26, attrs, defAttrs, 26, 27);
+
+      attrs = {"language": "de"};
+      testTextAttrs(ID, 27, attrs, defAttrs, 27, 42);
+
+      attrs = {};
+      testTextAttrs(ID, 42, attrs, defAttrs, 42, 50);
+
+      attrs = {};
+      testTextAttrs(ID, 43, attrs, defAttrs, 42, 50);
+
+      tempElem = tempElem.nextSibling.nextSibling.nextSibling.nextSibling.firstChild.nextSibling;
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      attrs = {"color": gComputedStyle.color};
+      testTextAttrs(ID, 50, attrs, defAttrs, 50, 57);
+
+      tempElem = tempElem.firstChild.nextSibling;
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      attrs = {"font-weight": gComputedStyle.fontWeight,
+               "color": gComputedStyle.color};
+      testTextAttrs(ID, 57, attrs, defAttrs, 57, 61);
+
+      tempElem = tempElem.parentNode;
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      attrs = {"color": gComputedStyle.color};
+      testTextAttrs(ID, 61, attrs, defAttrs, 61, 68);
+
+      //////////////////////////////////////////////////////////////////////////
+      // area9, different single style spans in styled paragraph
+      ID = "area9";
+      tempElem = document.getElementById(ID);
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      defAttrs = {
+        "font-style": gComputedStyle.fontStyle,
+        "font-size": "10pt",
+        "background-color": "rgb(255, 255, 255)",
+        "font-weight": gComputedStyle.fontWeight,
+        "color": gComputedStyle.color,
+        "font-family": gComputedStyle.fontFamily,
+        "text-position": gComputedStyle.verticalAlign
+      };
+
+      testDefaultTextAttrs(ID, defAttrs);
+
+      attrs = {};
+      testTextAttrs(ID, 0, attrs, defAttrs, 0, 6);
+
+      attrs = { "font-size": "12pt" };
+      testTextAttrs(ID, 7, attrs, defAttrs, 6, 12);
+
+      attrs = {};
+      testTextAttrs(ID, 13, attrs, defAttrs, 12, 21);
+
+      // Walk to the span with the different background color
+      tempElem = tempElem.firstChild.nextSibling.nextSibling.nextSibling;
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      attrs = { "background-color": gComputedStyle.backgroundColor };
+      testTextAttrs(ID, 22, attrs, defAttrs, 21, 36);
+
+      attrs = {};
+      testTextAttrs(ID, 37, attrs, defAttrs, 36, 44);
+
+      // Walk from the background color span to the one with font-style
+      tempElem = tempElem.nextSibling.nextSibling;
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      attrs = { "font-style": gComputedStyle.fontStyle };
+      testTextAttrs(ID, 45, attrs, defAttrs, 44, 61);
+
+      attrs = {};
+      testTextAttrs(ID, 62, attrs, defAttrs, 61, 69);
+
+      // Walk from span with font-style to the one with font-family.
+      tempElem = tempElem.nextSibling.nextSibling;
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      attrs = { "font-family": gComputedStyle.fontFamily };
+      testTextAttrs(ID, 70, attrs, defAttrs, 69, 83);
+
+      attrs = {};
+      testTextAttrs(ID, 84, attrs, defAttrs, 83, 91);
+
+      attrs = { "text-underline-style": "solid" };
+      testTextAttrs(ID, 92, attrs, defAttrs, 91, 101);
+
+      attrs = {};
+      testTextAttrs(ID, 102, attrs, defAttrs, 101, 109);
+
+      attrs = { "text-line-through-style": "solid" };
+      testTextAttrs(ID, 110, attrs, defAttrs, 109, 122);
+
+      attrs = {};
+      testTextAttrs(ID, 123, attrs, defAttrs, 122, 130);
+
+      // area10, different single style spans in non-styled paragraph
+      ID = "area10";
+      tempElem = document.getElementById(ID);
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      defAttrs = {
         "font-style": gComputedStyle.fontStyle,
         "font-size": "12pt",
         "background-color": "rgb(255, 255, 255)",
         "font-weight": gComputedStyle.fontWeight,
         "color": gComputedStyle.color,
         "font-family": gComputedStyle.fontFamily,
         "text-position": gComputedStyle.verticalAlign
       };
 
       testDefaultTextAttrs(ID, defAttrs);
 
-      attrs = {"language": "ru"};
-      testTextAttrs(ID, 0, attrs, 0, 12);
+      attrs = {};
+      testTextAttrs(ID, 0, attrs, defAttrs, 0, 7);
 
-      attrs = {"language": "en"};
-      testTextAttrs(ID, 12, attrs, 12, 13);
+      attrs = { "font-size": "14pt" };
+      testTextAttrs(ID, 7, attrs, defAttrs, 7, 13);
 
+      attrs = {};
+      testTextAttrs(ID, 13, attrs, defAttrs, 13, 22);
+
+      // Walk to the span with the different background color
       tempElem = tempElem.firstChild.nextSibling.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = {"language" :"en",
-               "background-color": gComputedStyle.backgroundColor};
-      testTextAttrs(ID, 13, attrs, 13, 26);
+      attrs = { "background-color": gComputedStyle.backgroundColor };
+      testTextAttrs(ID, 23, attrs, defAttrs, 22, 37);
+
+      attrs = {};
+      testTextAttrs(ID, 38, attrs, defAttrs, 37, 45);
 
-      attrs = {"language": "en" };
-      testTextAttrs(ID, 26, attrs, 26, 27);
-
-      attrs = {"language": "de"};
-      testTextAttrs(ID, 27, attrs, 27, 42);
-
-      attrs = {"language": "en"};
-      testTextAttrs(ID, 42, attrs, 42, 43);
+      // Walk from the background color span to the one with font-style
+      tempElem = tempElem.nextSibling.nextSibling;
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      attrs = {"font-style": gComputedStyle.fontStyle};
+      testTextAttrs(ID, 46, attrs, defAttrs, 45, 62);
 
       attrs = {};
-      testTextAttrs(ID, 43, attrs, 43, 50);
+      testTextAttrs(ID, 63, attrs, defAttrs, 62, 70);
 
-      tempElem = tempElem.nextSibling.nextSibling.nextSibling.nextSibling.firstChild.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 50, attrs, 50, 57);
-
-      tempElem = tempElem.firstChild.nextSibling;
+      // Walk from span with font-style to the one with font-family.
+      tempElem = tempElem.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = {"font-weight": gComputedStyle.fontWeight,
-               "color": gComputedStyle.color};
-      testTextAttrs(ID, 57, attrs, 57, 61);
+      attrs = {"font-family": gComputedStyle.fontFamily};
+      testTextAttrs(ID, 71, attrs, defAttrs, 70, 84);
+
+      attrs = {};
+      testTextAttrs(ID, 85, attrs, defAttrs, 84, 92);
+
+      attrs = { "text-underline-style": "solid" };
+      testTextAttrs(ID, 93, attrs, defAttrs, 92, 102);
 
-      tempElem = tempElem.parentNode;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 61, attrs, 61, 68);
+      attrs = {};
+      testTextAttrs(ID, 103, attrs, defAttrs, 102, 110);
+
+      attrs = { "text-line-through-style": "solid" };
+      testTextAttrs(ID, 111, attrs, defAttrs, 110, 123);
+
+      attrs = {};
+      testTextAttrs(ID, 124, attrs, defAttrs, 123, 131);
 
       //////////////////////////////////////////////////////////////////////////
       // test spelling text attributes
       testSpellTextAttrs(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
@@ -420,11 +549,27 @@
     <span lang="en">
       Normal
       <span style="color: magenta">Magenta<b>Bold</b>Magenta</span>
     </span>
   </p>
 
   <input id="area8"/>
 
-  <p id="output"/>
+  <p id="area9" style="font-size: smaller">Small
+    <span style="font-size: 120%">bigger</span> smaller
+    <span style="background-color: blue;">background blue</span> normal
+    <span style="font-style: italic;">Different styling</span> normal
+    <span style="font-family: tahoma;">Different font</span> normal
+    <span style="text-decoration: underline;">underlined</span> normal
+    <span style="text-decoration: line-through;">strikethrough</span> normal
+  </p>
+
+  <p id="area10">Normal
+    <span style="font-size: 120%">bigger</span> smaller
+    <span style="background-color: blue;">background blue</span> normal
+    <span style="font-style: italic;">Different styling</span> normal
+    <span style="font-family: tahoma;">Different font</span> normal
+    <span style="text-decoration: underline;">underlined</span> normal
+    <span style="text-decoration: line-through;">strikethrough</span> normal
+  </p>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/z_states_frame.html
@@ -0,0 +1,11 @@
+<html>
+<!--
+Auxilliary file used as frame source.
+-->
+<head>
+</head>
+<body>
+<p>Frame source body has no role</p>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/z_states_framearticle.html
@@ -0,0 +1,11 @@
+<html>
+<!--
+Auxilliary file used as frame source.
+-->
+<head>
+</head>
+<body role="article">
+<p>Article</p>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/z_states_framecheckbox.html
@@ -0,0 +1,11 @@
+<html>
+<!--
+Auxilliary file used as frame source.
+-->
+<head>
+</head>
+<body role="checkbox">
+<p>Checkbox</p>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/z_states_frametextbox.html
@@ -0,0 +1,11 @@
+<html>
+<!--
+Auxilliary file used as frame source.
+-->
+<head>
+</head>
+<body role="textbox">
+<p>Texbox</p>
+</body>
+</html>
+
--- a/browser/app/firefox-branding.js
+++ b/browser/app/firefox-branding.js
@@ -1,13 +1,16 @@
 pref("startup.homepage_override_url","http://www.mozilla.org/projects/%APP%/%VERSION%/whatsnew/");
 pref("startup.homepage_welcome_url","http://www.mozilla.org/projects/%APP%/%VERSION%/firstrun/");
 // The time interval between checks for a new version (in seconds)
 // nightly=8 hours, official=24 hours
 pref("app.update.interval", 28800);
+// The time interval between the downloading of mar file chunks in the
+// background (in seconds)
+pref("app.update.download.backgroundInterval", 60);
 // URL user can browse to manually if for some reason all update installation
 // attempts fail.
 pref("app.update.url.manual", "http://www.mozilla.org/products/%APP%/");
 // A default value for the "More information about this update" link
 // supplied in the "An update is available" page of the update wizard. 
 pref("app.update.url.details", "http://www.mozilla.org/projects/%APP%/");
 
 // Release notes URL
--- a/browser/base/Makefile.in
+++ b/browser/base/Makefile.in
@@ -15,16 +15,17 @@
 # The Original Code is mozilla.org code.
 #
 # The Initial Developer of the Original Code is
 # Netscape Communications Corporation.
 # Portions created by the Initial Developer are Copyright (C) 1998
 # the Initial Developer. All Rights Reserved.
 #
 # Contributor(s):
+#  Robert Strong <robert.bugzilla@gmail.com>
 #
 # Alternatively, the contents of this file may be used under the terms of
 # either the GNU General Public License Version 2 or later (the "GPL"), or
 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 # in which case the provisions of the GPL or the LGPL are applicable instead
 # of those above. If you wish to allow use of your version of this file only
 # under the terms of either the GPL or the LGPL, and not to allow others to
 # use your version of this file under the terms of the MPL, indicate your
@@ -49,19 +50,25 @@ abs_srcdir = $(shell cd $(srcdir) && pwd
 CHROME_DEPS += $(abs_srcdir)/content/overrides/app-license.html
 
 ifdef ENABLE_TESTS
 DIRS += content/test
 endif
 
 include $(topsrcdir)/config/rules.mk
 
+PRE_RELEASE_SUFFIX = $(shell cat $(srcdir)/../config/version.txt | \
+  sed -e '/pre/s/.*//g' -e '/[ab][0-9]/!s/.*//g' \
+      -e 's/\(.*[0-9]\)a\([0-9]\+\)/ \1 Alpha \2/g' \
+      -e 's/\(.*[0-9]\)b\([0-9]\+\)/ \1 Beta \2/g')
+
 DEFINES += \
 	-DMOZ_APP_VERSION=$(MOZ_APP_VERSION) \
 	-DAPP_LICENSE_BLOCK=$(abs_srcdir)/content/overrides/app-license.html \
+	-DPRE_RELEASE_SUFFIX="$(PRE_RELEASE_SUFFIX)" \
 	$(NULL)
 
 ifndef MOZ_BRANDING_DIRECTORY
 DEFINES += -DMOZ_USE_GENERIC_BRANDING
 endif
 
 ifneq (,$(filter windows gtk2 mac cocoa, $(MOZ_WIDGET_TOOLKIT)))
 DEFINES += -DHAVE_SHELL_SERVICE=1
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1150,16 +1150,20 @@ function prepareForStartup() {
 
   // hook up UI through progress listener
   gBrowser.addProgressListener(window.XULBrowserWindow, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
   gBrowser.addTabsProgressListener(window.TabsProgressListener);
 
   // setup our common DOMLinkAdded listener
   gBrowser.addEventListener("DOMLinkAdded", DOMLinkHandler, false);
 
+  // setup our MozApplicationManifest listener
+  gBrowser.addEventListener("MozApplicationManifest",
+                            OfflineApps, false);
+
   // setup simple gestures support
   gGestureSupport.init(true);
 }
 
 function delayedStartup(isLoadingBlank, mustLoadSidebar) {
   var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
   os.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);
   os.addObserver(gXPInstallObserver, "xpinstall-install-blocked", false);
@@ -2898,29 +2902,32 @@ const DOMLinkHandler = {
 }
 
 const BrowserSearch = {
   addEngine: function(engine, targetDoc) {
     if (!this.searchBar)
       return;
 
     var browser = gBrowser.getBrowserForDocument(targetDoc);
+    // ignore search engines from subframes (see bug 479408)
+    if (!browser)
+      return;
 
     // Check to see whether we've already added an engine with this title
     if (browser.engines) {
       if (browser.engines.some(function (e) e.title == engine.title))
         return;
     }
 
     // Append the URI and an appropriate title to the browser data.
     // Use documentURIObject in the check for shouldLoadFavIcon so that we
     // do the right thing with about:-style error pages.  Bug 453442
     var iconURL = null;
-    if (gBrowser.shouldLoadFavIcon(browser.contentDocument.documentURIObject))
-      iconURL = browser.currentURI.prePath + "/favicon.ico";
+    if (gBrowser.shouldLoadFavIcon(targetDoc.documentURIObject))
+      iconURL = targetDoc.documentURIObject.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);
@@ -3867,20 +3874,16 @@ var XULBrowserWindow = {
     }
     else if (aStateFlags & nsIWebProgressListener.STATE_STOP) {
       if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
         if (aWebProgress.DOMWindow == content) {
           if (aRequest)
             this.endDocumentLoad(aRequest, aStatus);
           if (!gBrowser.mTabbedMode && !gBrowser.mCurrentBrowser.mIconURL)
             gBrowser.useDefaultIcon(gBrowser.mCurrentTab);
-
-          if (Components.isSuccessCode(aStatus) &&
-              content.document.documentElement.getAttribute("manifest"))
-            OfflineApps.offlineAppRequested(content);
         }
       }
 
       // This (thanks to the filter) is a network stop or the last
       // request stop outside of loading the document, stop throbbers
       // and progress bars and such
       if (aRequest) {
         let msg = "";
@@ -4904,17 +4907,17 @@ function middleMousePaste(event)
 var contentAreaDNDObserver = {
   onDrop: function (aEvent, aXferData, aDragSession)
     {
       if (aEvent.getPreventDefault())
         return;
 
       var dragType = aXferData.flavour.contentType;
       var dragData = aXferData.data;
-      if (dragType == "application/x-moz-tabbrowser-tab") {
+      if (dragType == TAB_DROP_TYPE) {
         // If the tab was dragged from some other tab bar, its own dragend
         // handler will take care of detaching the tab
         if (dragData instanceof XULElement && dragData.localName == "tab" &&
             dragData.ownerDocument.defaultView == window) {
           // Detach only if the mouse pointer was released a little
           // bit down in the content area (to be precise, by half the height
           // of a tab)
           if (aEvent.screenY > gBrowser.mPanelContainer.boxObject.screenY +
@@ -4953,17 +4956,17 @@ var contentAreaDNDObserver = {
       // keep the event from being handled by the dragDrop listeners
       // built-in to gecko if they happen to be above us.
       aEvent.preventDefault();
     },
 
   getSupportedFlavours: function ()
     {
       var flavourSet = new FlavourSet();
-      flavourSet.appendFlavour("application/x-moz-tabbrowser-tab");
+      flavourSet.appendFlavour(TAB_DROP_TYPE);
       flavourSet.appendFlavour("text/x-moz-url");
       flavourSet.appendFlavour("text/plain");
       flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
       return flavourSet;
     }
 
 };
 
@@ -5326,16 +5329,22 @@ var OfflineApps = {
   uninit: function ()
   {
     var obs = Cc["@mozilla.org/observer-service;1"].
               getService(Ci.nsIObserverService);
     obs.removeObserver(this, "dom-storage-warn-quota-exceeded");
     obs.removeObserver(this, "offline-cache-update-completed");
   },
 
+  handleEvent: function(event) {
+    if (event.type == "MozApplicationManifest") {
+      this.offlineAppRequested(event.originalTarget.defaultView);
+    }
+  },
+
   /////////////////////////////////////////////////////////////////////////////
   // OfflineApps Implementation Methods
 
   // XXX: _getBrowserWindowForContentWindow and _getBrowserForContentWindow
   // were taken from browser/components/feeds/src/WebContentConverter.
   _getBrowserWindowForContentWindow: function(aContentWindow) {
     return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIWebNavigation)
@@ -5352,16 +5361,17 @@ var OfflineApps = {
     var browsers = aBrowserWindow.getBrowser().browsers;
     for (var i = 0; i < browsers.length; ++i) {
       if (browsers[i].contentWindow == aContentWindow)
         return browsers[i];
     }
   },
 
   _getManifestURI: function(aWindow) {
+    if (!aWindow.document.documentElement) return null;
     var attr = aWindow.document.documentElement.getAttribute("manifest");
     if (!attr) return null;
 
     try {
       var ios = Cc["@mozilla.org/network/io-service;1"].
                 getService(Ci.nsIIOService);
 
       var contentURI = ios.newURI(aWindow.location.href, null, null);
@@ -5421,20 +5431,35 @@ var OfflineApps = {
     // again.
     var pm = Cc["@mozilla.org/permissionmanager;1"].
              getService(Ci.nsIPermissionManager);
     pm.add(aURI, "offline-app",
            Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
   },
 
   // XXX: duplicated in preferences/advanced.js
-  _getOfflineAppUsage: function (host)
+  _getOfflineAppUsage: function (host, groups)
   {
-    // XXX Bug 442810: include offline cache usage.
+    var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
+                       getService(Components.interfaces.nsIApplicationCacheService);
+    if (!groups) {
+      groups = cacheService.getGroups({});
+    }
+    var ios = Components.classes["@mozilla.org/network/io-service;1"].
+              getService(Components.interfaces.nsIIOService);
+
     var usage = 0;
+    for (var i = 0; i < groups.length; i++) {
+      var uri = ios.newURI(groups[i], null, null);
+      if (uri.asciiHost == host) {
+        var cache = cacheService.getActiveCache(groups[i]);
+        usage += cache.usage;
+      }
+    }
+
     var storageManager = Components.classes["@mozilla.org/dom/storagemanager;1"].
                          getService(Components.interfaces.nsIDOMStorageManager);
     usage += storageManager.getUsage(host);
 
     return usage;
   },
 
   _checkUsage: function(aURI) {
@@ -5458,17 +5483,17 @@ var OfflineApps = {
     if (!gPrefService.getBoolPref("browser.offline-apps.notify")) {
       return;
     }
 
     var browserWindow = this._getBrowserWindowForContentWindow(aContentWindow);
     var browser = this._getBrowserForContentWindow(browserWindow,
                                                    aContentWindow);
 
-    var currentURI = browser.webNavigation.currentURI;
+    var currentURI = aContentWindow.document.documentURIObject;
     var pm = Cc["@mozilla.org/permissionmanager;1"].
              getService(Ci.nsIPermissionManager);
 
     // don't bother showing UI if the user has already made a decision
     if (pm.testExactPermission(currentURI, "offline-app") !=
         Ci.nsIPermissionManager.UNKNOWN_ACTION)
       return;
 
@@ -5476,82 +5501,99 @@ var OfflineApps = {
       if (gPrefService.getBoolPref("offline-apps.allow_by_default")) {
         // all pages can use offline capabilities, no need to ask the user
         return;
       }
     } catch(e) {
       // this pref isn't set by default, ignore failures
     }
 
+    var host = currentURI.asciiHost;
     var notificationBox = gBrowser.getNotificationBox(browser);
-    var notification = notificationBox.getNotificationWithValue("offline-app-requested");
-    if (!notification) {
+    var notificationID = "offline-app-requested-" + host;
+    var notification = notificationBox.getNotificationWithValue(notificationID);
+
+    if (notification) {
+      notification.documents.push(aContentWindow.document);
+    } else {
       var bundle_browser = document.getElementById("bundle_browser");
 
       var buttons = [{
         label: bundle_browser.getString("offlineApps.allow"),
         accessKey: bundle_browser.getString("offlineApps.allowAccessKey"),
-        callback: function() { OfflineApps.allowSite(); }
+        callback: function() {
+          for (var i = 0; i < notification.documents.length; i++) {
+            OfflineApps.allowSite(notification.documents[i]);
+          }
+        }
       },{
         label: bundle_browser.getString("offlineApps.never"),
         accessKey: bundle_browser.getString("offlineApps.neverAccessKey"),
-        callback: function() { OfflineApps.disallowSite(); }
+        callback: function() {
+          for (var i = 0; i < notification.documents.length; i++) {
+            OfflineApps.disallowSite(notification.documents[i]);
+          }
+        }
       },{
         label: bundle_browser.getString("offlineApps.notNow"),
         accessKey: bundle_browser.getString("offlineApps.notNowAccessKey"),
         callback: function() { /* noop */ }
       }];
 
       const priority = notificationBox.PRIORITY_INFO_LOW;
       var message = bundle_browser.getFormattedString("offlineApps.available",
-                                                      [ currentURI.host ]);
-      notificationBox.appendNotification(message, "offline-app-requested",
-                                         "chrome://browser/skin/Info.png",
-                                         priority, buttons);
+                                                      [ host ]);
+      notification =
+        notificationBox.appendNotification(message, notificationID,
+                                           "chrome://browser/skin/Info.png",
+                                           priority, buttons);
+      notification.documents = [ aContentWindow.document ];
     }
   },
 
-  allowSite: function() {
-    var currentURI = gBrowser.selectedBrowser.webNavigation.currentURI;
+  allowSite: function(aDocument) {
     var pm = Cc["@mozilla.org/permissionmanager;1"].
              getService(Ci.nsIPermissionManager);
-    pm.add(currentURI, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
-
-    // When a site is enabled while loading, <link rel="offline-resource">
-    // resources will start fetching immediately.  This one time we need to
-    // do it ourselves.
-    this._startFetching();
+    pm.add(aDocument.documentURIObject, "offline-app",
+           Ci.nsIPermissionManager.ALLOW_ACTION);
+
+    // When a site is enabled while loading, manifest resources will
+    // start fetching immediately.  This one time we need to do it
+    // ourselves.
+    this._startFetching(aDocument);
   },
 
-  disallowSite: function() {
-    var currentURI = gBrowser.selectedBrowser.webNavigation.currentURI;
+  disallowSite: function(aDocument) {
     var pm = Cc["@mozilla.org/permissionmanager;1"].
              getService(Ci.nsIPermissionManager);
-    pm.add(currentURI, "offline-app", Ci.nsIPermissionManager.DENY_ACTION);
+    pm.add(aDocument.documentURIObject, "offline-app",
+           Ci.nsIPermissionManager.DENY_ACTION);
   },
 
   manage: function() {
     openAdvancedPreferences("networkTab");
   },
 
-  _startFetching: function() {
-    var manifest = content.document.documentElement.getAttribute("manifest");
+  _startFetching: function(aDocument) {
+    if (!aDocument.documentElement)
+      return;
+
+    var manifest = aDocument.documentElement.getAttribute("manifest");
     if (!manifest)
       return;
 
     var ios = Cc["@mozilla.org/network/io-service;1"].
               getService(Ci.nsIIOService);
 
-    var contentURI = ios.newURI(content.location.href, null, null);
-    var manifestURI = ios.newURI(manifest, content.document.characterSet,
-                                 contentURI);
+    var manifestURI = ios.newURI(manifest, aDocument.characterSet,
+                                 aDocument.documentURIObject);
 
     var updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"].
                         getService(Ci.nsIOfflineCacheUpdateService);
-    updateService.scheduleUpdate(manifestURI, contentURI);
+    updateService.scheduleUpdate(manifestURI, aDocument.documentURIObject);
   },
 
   /////////////////////////////////////////////////////////////////////////////
   // nsIObserver
   observe: function (aSubject, aTopic, aState)
   {
     if (aTopic == "dom-storage-warn-quota-exceeded") {
       if (aSubject) {
@@ -6085,27 +6127,27 @@ var FeedHandler = {
     }
   }, 
 
   addFeed: function(feed, targetDoc) {
     if (feed) {
       // 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..
+        // ignore feeds loaded in subframes (see bug 305472)
         return;
       }
 
       var feeds = [];
       if (browserForLink.feeds != null)
         feeds = browserForLink.feeds;
 
       feeds.push(feed);
       browserForLink.feeds = feeds;
-      if (browserForLink == gBrowser || browserForLink == gBrowser.mCurrentBrowser) {
+      if (browserForLink == gBrowser.mCurrentBrowser) {
         var feedButton = document.getElementById("feed-button");
         if (feedButton)
           feedButton.collapsed = false;
       }
     }
   }
 };
 
@@ -6863,16 +6905,18 @@ let gPrivateBrowsingUI = {
     }
 
     return result;
   },
 
   onEnterPrivateBrowsing: function PBUI_onEnterPrivateBrowsing() {
     this._setPBMenuTitle("stop");
 
+    document.getElementById("menu_import").setAttribute("disabled", "true");
+
     this._privateBrowsingAutoStarted = this._privateBrowsingService.autoStarted;
 
     if (!this._privateBrowsingAutoStarted) {
       // Adjust the window's title
       let docElement = document.documentElement;
       docElement.setAttribute("title",
         docElement.getAttribute("title_privatebrowsing"));
       docElement.setAttribute("titlemodifier",
@@ -6888,16 +6932,18 @@ let gPrivateBrowsingUI = {
               .setAttribute("disabled", "true");
     }
   },
 
   onExitPrivateBrowsing: function PBUI_onExitPrivateBrowsing() {
     if (BrowserSearch.searchBar)
       BrowserSearch.searchBar.textbox.reset();
 
+    document.getElementById("menu_import").removeAttribute("disabled");
+
     gFindBar.getElement("findbar-textbox").reset();
 
     this._setPBMenuTitle("start");
 
     if (!this._privateBrowsingAutoStarted) {
       // Adjust the window's title
       let docElement = document.documentElement;
       docElement.setAttribute("title",
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -1,8 +1,9 @@
+#filter substitution
 <?xml version="1.0"?>
 # -*- Mode: HTML -*-
 #
 # ***** 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
@@ -26,16 +27,17 @@
 #   Blake Ross <blake@cs.stanford.edu>
 #   David Hyatt <hyatt@mozilla.org>
 #   Joe Hewitt <hewitt@netscape.com>
 #   Pierre Chanial <chanial@noos.fr>
 #   Dean Tessman <dean_tessman@hotmail.com>
 #   Johnathan Nightingale <johnath@mozilla.com>
 #   Dão Gottwald <dao@mozilla.com>
 #   Ehsan Akhgari <ehsan.akhgari@gmail.com>
+#   Robert Strong <robert.bugzilla@gmail.com>
 #
 # Alternatively, the contents of this file may be used under the terms of
 # either the GNU General Public License Version 2 or later (the "GPL"), or
 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 # in which case the provisions of the GPL or the LGPL are applicable instead
 # of those above. If you wish to allow use of your version of this file only
 # under the terms of either the GPL or the LGPL, and not to allow others to
 # use your version of this file under the terms of the MPL, indicate your
@@ -43,49 +45,46 @@
 # 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 *****
 
 <?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/places/places.css" type="text/css"?>
-
-<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?> 
-
-<?xml-stylesheet href="chrome://global/skin/toolbar.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
 
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
 <?xul-overlay href="chrome://browser/content/baseMenuOverlay.xul"?>
 <?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
 
 # All DTD information is stored in a separate file so that it can be shared by
 # hiddenWindow.xul.
 #include browser-doctype.inc
 
 <window id="main-window"
         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:svg="http://www.w3.org/2000/svg"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         onload="BrowserStartup()" onunload="BrowserShutdown()" onclose="return WindowIsClosing();"
         ondragleave="gBrowser.browserWindowOnDragLeave(event);"
         ondragenter="gBrowser.browserWindowOnDragEnter(event);"
-        title="&mainWindow.title;"
-        title_normal="&mainWindow.title;"
+        title="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
+        title_normal="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
 #ifdef XP_MACOSX
-        title_privatebrowsing="&mainWindow.title;&mainWindow.titlemodifiermenuseparator;&mainWindow.titlePrivateBrowsingSuffix;"
-        titledefault="&mainWindow.title;"
+        title_privatebrowsing="&mainWindow.title;@PRE_RELEASE_SUFFIX@&mainWindow.titlemodifiermenuseparator;&mainWindow.titlePrivateBrowsingSuffix;"
+        titledefault="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
         titlemodifier=""
         titlemodifier_normal=""
         titlemodifier_privatebrowsing="&mainWindow.titlePrivateBrowsingSuffix;"
 #else
-        title_privatebrowsing="&mainWindow.titlemodifierPrivateBrowsing;"
-        titlemodifier="&mainWindow.titlemodifier;"
-        titlemodifier_normal="&mainWindow.titlemodifier;"
-        titlemodifier_privatebrowsing="&mainWindow.titlemodifierPrivateBrowsing;"
+        title_privatebrowsing="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@ &mainWindow.titlePrivateBrowsingSuffix;"
+        titlemodifier="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@"
+        titlemodifier_normal="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@"
+        titlemodifier_privatebrowsing="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@ &mainWindow.titlePrivateBrowsingSuffix;"
 #endif
         titlemenuseparator="&mainWindow.titlemodifiermenuseparator;"
         windowtype="navigator:browser"
         screenX="4" screenY="4"
         browsingmode="normal"
         persist="screenX screenY width height sizemode"> 
 
 # All JS files which are not content (only) dependent that browser.xul
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1707,16 +1707,17 @@
             this.mTabListeners[ourIndex] = tabListener;
             filter.addProgressListener(tabListener,
               Components.interfaces.nsIWebProgress.NOTIFY_ALL);
 
             ourBrowser.webProgress.addProgressListener(filter,
               Components.interfaces.nsIWebProgress.NOTIFY_ALL);
 
             this.setTabTitle(aOurTab);
+            this.updateIcon(aOurTab);
 
             // If the tab was already selected (this happpens in the scenario
             // of replaceTabWithWindow), notify onLocationChange, etc.
             if (aOurTab == this.selectedTab)
               this.updateCurrentBrowser(true);
           ]]>
         </body>
       </method>
@@ -1906,20 +1907,23 @@
       <method name="_onDragStart">
         <parameter name="aEvent"/>
         <body>
         <![CDATA[
           var target = aEvent.target;
           if (target.localName == "tab" &&
               aEvent.originalTarget.localName != "toolbarbutton") {
             var dt = aEvent.dataTransfer;
-            dt.mozSetDataAt("application/x-moz-tabbrowser-tab", target, 0);
+            dt.mozSetDataAt(TAB_DROP_TYPE, target, 0);
             var uri = this.getBrowserForTab(aEvent.target).currentURI;
             var spec = uri ? uri.spec : "about:blank";
-            dt.mozSetDataAt("text/x-moz-url", spec + "\n" + aEvent.target.label, 0);
+
+            // We must not set text/x-moz-url data, otherwise trying to deatch
+            // the tab by dropping it on the desktop would result in an
+            // "internet shortcut"
             dt.mozSetDataAt("text/plain", spec, 0);
 
             var canvas = tabPreviews.capture(target, false);
             dt.setDragImage(canvas, 0, 0);
             aEvent.stopPropagation();
           }
 
           this._dragLeftWindow = false;
@@ -1941,18 +1945,18 @@
             var dt = aEvent.dataTransfer;
             // Disallow dropping multiple items
             if (dt.mozItemCount > 1)
               return dt.effectAllowed = "none";
 
             var types = dt.mozTypesAt(0);
             var sourceNode = null;
             // tabs are always added as the first type
-            if (types[0] == "application/x-moz-tabbrowser-tab") {
-              var sourceNode = dt.mozGetDataAt("application/x-moz-tabbrowser-tab", 0);
+            if (types[0] == TAB_DROP_TYPE) {
+              var sourceNode = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
               if (sourceNode instanceof XULElement &&
                   sourceNode.localName == "tab" &&
                   (sourceNode.parentNode == this.mTabContainer ||
                    (sourceNode.ownerDocument.defaultView instanceof ChromeWindow &&
                     sourceNode.ownerDocument.documentElement.getAttribute("windowtype") == "navigator:browser"))) {
                 if (sourceNode.parentNode == this.mTabContainer &&
                     (aEvent.screenX >= sourceNode.boxObject.screenX &&
                       aEvent.screenX <= (sourceNode.boxObject.screenX +
@@ -2080,17 +2084,17 @@
       <method name="_onDrop">
         <parameter name="aEvent"/>
         <body>
           <![CDATA[
             var dt = aEvent.dataTransfer;
             var dropEffect = dt.dropEffect;
             var draggedTab;
             if (dropEffect != "link") { // copy or move
-              draggedTab = dt.mozGetDataAt("application/x-moz-tabbrowser-tab", 0);
+              draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
               // not our drop then
               if (!draggedTab)
                 return;
             }
 
             this.mTabDropIndicatorBar.collapsed = true;
             aEvent.stopPropagation();
 
@@ -2203,17 +2207,17 @@
               return;
 
             var dt = aEvent.dataTransfer;
             // The dropEffect == "none" scenarios:
             // 1. Drop-within-the-tabbae
             // 2. Drop on some other tabbar
             // 3. Drop on text fields (even outside our window)
             if (dt.dropEffect == "none") {
-              var draggedTab = dt.mozGetDataAt("application/x-moz-tabbrowser-tab", 0);
+              var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
               this.replaceTabWithWindow(draggedTab);
             }
             aEvent.stopPropagation();
           ]]>
         </body>
       </method>
 
       <method name="browserWindowOnDragEnter">
@@ -2819,28 +2823,69 @@
     <implementation>
       <!-- Override scrollbox.xml method, since our scrollbox's children are
            inherited from the binding parent -->
       <method name="_getScrollableElements">
         <body><![CDATA[
           return document.getBindingParent(this).childNodes;
         ]]></body>
       </method>
-
-#ifndef XP_MACOSX
-    </implementation>
-#else
+#ifdef XP_MACOSX
       <field name="_scrollButtonDownBox">
         document.getAnonymousElementByAttribute(this, "anonid", "down-box");
       </field>
       <field name="_scrollButtonDownBoxAnimate">
         document.getAnonymousElementByAttribute(this, "anonid", "down-box-animate");
       </field>
+#endif
     </implementation>
 
+    <handlers>
+      <handler event="underflow"><![CDATA[
+         if (event.detail == 0)
+           return; // Ignore vertical events
+
+         var tabs = document.getBindingParent(this);
+         tabs.removeAttribute("overflow");
+#ifdef XP_MACOSX
+         this._scrollButtonDownBox.collapsed = true;
+         this._scrollButtonDownBoxAnimate.collapsed = true;
+#endif
+      ]]></handler>
+      <handler event="overflow"><![CDATA[
+         if (event.detail == 0)
+           return; // Ignore vertical events
+
+         var tabs = document.getBindingParent(this);
+         tabs.setAttribute("overflow", "true");
+#ifdef XP_MACOSX
+         this._scrollButtonDownBox.collapsed = false;
+         this._scrollButtonDownBoxAnimate.collapsed = false;
+#endif
+         this.scrollBoxObject.ensureElementIsVisible(tabs.selectedItem);
+      ]]></handler>
+
+#ifdef XP_MACOSX
+      <handler event="UpdatedScrollButtonsDisabledState"><![CDATA[
+        // fix for bug #352353
+        // unlike the scrollup button on the tab strip (which is a 
+        // simple toolbarbutton) the scrolldown button is 
+        // a more complicated stack of boxes and a toolbarbutton
+        // so that we can animate when a tab is opened offscreen.
+        // in order to style the box with the actual background image
+        // we need to manually set the disable state to match the
+        // disable state of the toolbarbutton.
+        this._scrollButtonDownBox
+            .setAttribute("disabled", this._scrollButtonDown.disabled);
+      ]]></handler>
+#endif
+
+    </handlers>
+
+#ifdef XP_MACOSX
     <content>
       <xul:toolbarbutton class="scrollbutton-up" collapsed="true"
                          xbl:inherits="orient"
                          anonid="scrollbutton-up"
                          onclick="_distanceScroll(event);"
                          onmousedown="_startScroll(-1);"
                          onmouseover="_continueScroll(-1);"
                          onmouseup="_stopScroll();"
@@ -2860,64 +2905,16 @@
                            onclick="_distanceScroll(event);"
                            onmousedown="_startScroll(1);"
                            onmouseover="_continueScroll(1);"
                            onmouseup="_stopScroll();"
                            onmouseout="_pauseScroll();"
                            chromedir="&locale.dir;"/>
       </xul:stack>
     </content>
-
-    <handlers>
-      <handler event="underflow"><![CDATA[
-        // filter underflow events which were dispatched on nested scrollboxes
-        if (event.target != this)
-          return;
-
-        // Ignore vertical events.
-        if (event.detail == 0) {
-          return;
-        }
-
-        this._scrollButtonDownBox.collapsed = true;
-        this._scrollButtonDownBoxAnimate.collapsed = true;
-      ]]></handler>
-
-      <handler event="overflow"><![CDATA[
-        // filter underflow events which were dispatched on nested scrollboxes
-        if (event.target != this)
-          return;
-
-        // Ignore vertical events.
-        if (event.detail == 0) {
-          return;
-        }
-
-        this._scrollButtonDownBox.collapsed = false;
-        this._scrollButtonDownBoxAnimate.collapsed = false;
-      ]]></handler>
-
-      <handler event="UpdatedScrollButtonsDisabledState"><![CDATA[
-        // filter underflow events which were dispatched on nested scrollboxes
-        if (event.target != this)
-          return;
-
-        // fix for bug #352353
-        // unlike the scrollup button on the tab strip (which is a 
-        // simple toolbarbutton) the scrolldown button is 
-        // a more complicated stack of boxes and a toolbarbutton
-        // so that we can animate when a tab is opened offscreen.
-        // in order to style the box with the actual background image
-        // we need to manually set the disable state to match the
-        // disable state of the toolbarbutton.
-        this._scrollButtonDownBox
-            .setAttribute("disabled", this._scrollButtonDown.disabled);
-      ]]></handler>
-
-    </handlers>
 #endif
   </binding>
 
   <binding id="tabbrowser-tabs"
            extends="chrome://global/content/bindings/tabbox.xml#tabs">
     <content>
       <xul:stack flex="1" class="tabs-stack">
         <xul:vbox>
@@ -2993,42 +2990,31 @@
           this.firstChild.minWidth = this.mTabMinWidth;
           this.firstChild.maxWidth = this.mTabMaxWidth;
           this.adjustTabstrip();
 
           pb2.addObserver("browser.tabs.closeButtons", 
                           this._prefObserver, false);
 
           window.addEventListener("resize", this, false);
-
-          // Listen to overflow/underflow events on the tabstrip,
-          // we cannot put these as xbl handlers on the entire binding because
-          // they would also get called for the all-tabs popup scrollbox.
-          // Also, we can't rely on event.target becuase these are all
-          // anonymous nodes.
-          this.mTabstrip.addEventListener("overflow", this, false);
-          this.mTabstrip.addEventListener("underflow", this, false);
         ]]>
       </constructor>
 
       <destructor>
         <![CDATA[
           var pb2 =
               Components.classes['@mozilla.org/preferences-service;1'].
               getService(Components.interfaces.nsIPrefBranch2);
           pb2.removeObserver("browser.tabs.closeButtons", this._prefObserver);
 
           // Release timer to avoid reference cycles.
           if (this._animateTimer) {
             this._animateTimer.cancel();
             this._animateTimer = null;
           }
-
-          this.mTabstrip.removeEventListener("overflow", this, false);
-          this.mTabstrip.removeEventListener("underflow", this, false);
         ]]>
       </destructor>
 
       <field name="mTabstripWidth">0</field>
 
       <field name="mTabstrip">
         document.getAnonymousElementByAttribute(this, "anonid", "arrowscrollbox");
       </field>
@@ -3140,24 +3126,16 @@
           } catch (e) {}
         ]]></body>
       </method>
 
       <method name="handleEvent">
         <parameter name="aEvent"/>
         <body><![CDATA[
           switch (aEvent.type) {
-            case "overflow":
-              this.setAttribute("overflow", "true");
-              this.mTabstrip.scrollBoxObject
-                            .ensureElementIsVisible(this.selectedItem);
-              break;
-            case "underflow":
-              this.removeAttribute("overflow");
-              break;
             case "resize":
               var width = this.mTabstrip.boxObject.width;
               if (width != this.mTabstripWidth) {
                 this.adjustTabstrip();
                 this._fillTrailingGap();
                 this._handleTabSelect();
                 this.mTabstripWidth = width;
               }
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -45,16 +45,23 @@ include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES =	test_feed_discovery.html \
 		feed_discovery.html \
 		test_bug395533.html \
 		bug395533-data.txt \
 		test_contextmenu.html \
 		subtst_contextmenu.html \
 		ctxmenu-image.png \
+		test_offlineNotification.html \
+		offlineChild.html \
+		offlineChild.cacheManifest \
+		offlineChild.cacheManifest^headers^ \
+		offlineChild2.html \
+		offlineChild2.cacheManifest \
+		offlineChild2.cacheManifest^headers^ \
 		$(NULL)
 
 # browser_bug423833.js disabled temporarily since it's unreliable: bug 428712
 # browser_sanitize-download-history.js disabled temporarily since it's unreliable: bug 432425
 _BROWSER_FILES = browser_bug321000.js \
                  browser_sanitize-timespans.js \
                  browser_bug405137.js \
                  browser_bug409481.js \
@@ -84,16 +91,18 @@ include $(topsrcdir)/config/rules.mk
                  zoom_test.html \
                  browser_bug416661.js \
                  browser_bug386835.js \
                  dummy_page.html \
                  browser_bug422590.js \
                  browser_sanitize-sitepermissions.js \
                  browser_bug356571.js \
                  browser_sanitize-passwordDisabledHosts.js \
+                 browser_bug479408.js \
+                 browser_bug479408_sample.html \
     $(NULL)
 
 ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
 _BROWSER_FILES += browser_customize.js \
     $(NULL)
 endif
 
 libs:: $(_TEST_FILES)
--- a/browser/base/content/test/browser_alltabslistener.js
+++ b/browser/base/content/test/browser_alltabslistener.js
@@ -1,92 +1,103 @@
 const Ci = Components.interfaces;
 
 const gCompleteState = Ci.nsIWebProgressListener.STATE_STOP +
                        Ci.nsIWebProgressListener.STATE_IS_NETWORK;
 
+function LOG(str) {
+  dump(str + "\n");
+}
+
 var gFrontProgressListener = {
   onProgressChange: function (aWebProgress, aRequest,
                               aCurSelfProgress, aMaxSelfProgress,
                               aCurTotalProgress, aMaxTotalProgress) {
   },
 
   onStateChange: function (aWebProgress, aRequest, aStateFlags, aStatus) {
     var state = "onStateChange";
+    LOG("FrontProgress: " + state + " 0x" + aStateFlags.toString(16));
     ok(gFrontNotificationsPos < gFrontNotifications.length, "Got an expected notification for the front notifications listener");
     is(state, gFrontNotifications[gFrontNotificationsPos], "Got a notification for the front notifications listener");
     gFrontNotificationsPos++;
   },
 
   onLocationChange: function (aWebProgress, aRequest, aLocationURI) {
     var state = "onLocationChange";
+    LOG("FrontProgress: " + state + " " + aLocationURI.spec);
     ok(gFrontNotificationsPos < gFrontNotifications.length, "Got an expected notification for the front notifications listener");
     is(state, gFrontNotifications[gFrontNotificationsPos], "Got a notification for the front notifications listener");
     gFrontNotificationsPos++;
   },
   
   onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
   },
 
   onSecurityChange: function (aWebProgress, aRequest, aState) {
     var state = "onSecurityChange";
+    LOG("FrontProgress: " + state + " 0x" + aState.toString(16));
     ok(gFrontNotificationsPos < gFrontNotifications.length, "Got an expected notification for the front notifications listener");
     is(state, gFrontNotifications[gFrontNotificationsPos], "Got a notification for the front notifications listener");
     gFrontNotificationsPos++;
   }
 }
 
 var gAllProgressListener = {
   onProgressChange: function (aBrowser, aWebProgress, aRequest,
                               aCurSelfProgress, aMaxSelfProgress,
                               aCurTotalProgress, aMaxTotalProgress) {
   },
 
   onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
     var state = "onStateChange";
+    LOG("AllProgress: " + state + " 0x" + aStateFlags.toString(16));
     ok(aBrowser == gTestBrowser, state + " notification came from the correct browser");
     ok(gAllNotificationsPos < gAllNotifications.length, "Got an expected notification for the all notifications listener");
     is(state, gAllNotifications[gAllNotificationsPos], "Got a notification for the all notifications listener");
     gAllNotificationsPos++;
 
     if ((aStateFlags & gCompleteState) == gCompleteState) {
       ok(gAllNotificationsPos == gAllNotifications.length, "Saw the expected number of notifications");
       ok(gFrontNotificationsPos == gFrontNotifications.length, "Saw the expected number of frontnotifications");
       executeSoon(gNextTest);
     }
   },
 
   onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI) {
     var state = "onLocationChange";
+    LOG("AllProgress: " + state + " " + aLocationURI.spec);
     ok(aBrowser == gTestBrowser, state + " notification came from the correct browser");
     ok(gAllNotificationsPos < gAllNotifications.length, "Got an expected notification for the all notifications listener");
     is(state, gAllNotifications[gAllNotificationsPos], "Got a notification for the all notifications listener");
     gAllNotificationsPos++;
   },
   
   onStatusChange: function (aBrowser, aWebProgress, aRequest, aStatus, aMessage) {
     var state = "onStatusChange";
     ok(aBrowser == gTestBrowser, state + " notification came from the correct browser");
   },
 
   onSecurityChange: function (aBrowser, aWebProgress, aRequest, aState) {
     var state = "onSecurityChange";
+    LOG("AllProgress: " + state + " 0x" + aState.toString(16));
     ok(aBrowser == gTestBrowser, state + " notification came from the correct browser");
     ok(gAllNotificationsPos < gAllNotifications.length, "Got an expected notification for the all notifications listener");
     is(state, gAllNotifications[gAllNotificationsPos], "Got a notification for the all notifications listener");
     gAllNotificationsPos++;
   }
 }
 
 var gFrontNotifications, gAllNotifications, gFrontNotificationsPos, gAllNotificationsPos;
 var gBackgroundTab, gForegroundTab, gBackgroundBrowser, gForegroundBrowser, gTestBrowser;
 var gTestPage = "/browser/browser/base/content/test/alltabslistener.html";
 var gNextTest;
 
 function test() {
+  LOG("Running tests from alltabslistener.js");
   waitForExplicitFinish();
 
   gBackgroundTab = gBrowser.addTab("about:blank");
   gForegroundTab = gBrowser.addTab("about:blank");
   gBackgroundBrowser = gBrowser.getBrowserForTab(gBackgroundTab);
   gForegroundBrowser = gBrowser.getBrowserForTab(gForegroundTab);
   gBrowser.selectedTab = gForegroundTab;
 
@@ -104,65 +115,70 @@ function runTest(browser, url, next) {
 }
 
 function startTests() {
   gForegroundBrowser.removeEventListener("load", startTests, true);
   executeSoon(startTest1);
 }
 
 function startTest1() {
+  LOG("\nTest 1");
   gBrowser.addProgressListener(gFrontProgressListener);
   gBrowser.addTabsProgressListener(gAllProgressListener);
 
   gAllNotifications = [
     "onStateChange",
     "onLocationChange",
     "onSecurityChange",
     "onStateChange"
   ];
   gFrontNotifications = gAllNotifications;
   runTest(gForegroundBrowser, "http://example.org" + gTestPage, startTest2);
 }
 
 function startTest2() {
+  LOG("\nTest 2");
   gAllNotifications = [
     "onStateChange",
     "onLocationChange",
     "onSecurityChange",
     "onSecurityChange",
     "onStateChange"
   ];
   gFrontNotifications = gAllNotifications;
   runTest(gForegroundBrowser, "https://example.com" + gTestPage, startTest3);
 }
 
 function startTest3() {
+  LOG("\nTest 3");
   gAllNotifications = [
     "onStateChange",
     "onLocationChange",
     "onSecurityChange",
     "onStateChange"
   ];
   gFrontNotifications = [];
   runTest(gBackgroundBrowser, "http://example.org" + gTestPage, startTest4);
 }
 
 function startTest4() {
+  LOG("\nTest 4");
   gAllNotifications = [
     "onStateChange",
     "onLocationChange",
     "onSecurityChange",
     "onSecurityChange",
     "onStateChange"
   ];
   gFrontNotifications = [];
   runTest(gBackgroundBrowser, "https://example.com" + gTestPage, startTest5);
 }
 
 function startTest5() {
+  LOG("\nTest 5");
   // Switch the foreground browser
   [gForegroundBrowser, gBackgroundBrowser] = [gBackgroundBrowser, gForegroundBrowser];
   [gForegroundTab, gBackgroundTab] = [gBackgroundTab, gForegroundTab];
   // Avoid the onLocationChange this will fire
   gBrowser.removeProgressListener(gFrontProgressListener);
   gBrowser.selectedTab = gForegroundTab;
   gBrowser.addProgressListener(gFrontProgressListener);
 
@@ -172,25 +188,27 @@ function startTest5() {
     "onSecurityChange",
     "onStateChange"
   ];
   gFrontNotifications = gAllNotifications;
   runTest(gForegroundBrowser, "http://example.org" + gTestPage, startTest6);
 }
 
 function startTest6() {
+  LOG("\nTest 6");
   gAllNotifications = [
     "onStateChange",
     "onLocationChange",
     "onSecurityChange",
     "onStateChange"
   ];
   gFrontNotifications = [];
   runTest(gBackgroundBrowser, "http://example.org" + gTestPage, finishTest);
 }
 
 function finishTest() {
+  LOG("\nFinished tests from alltabslistener.js");
   gBrowser.removeProgressListener(gFrontProgressListener);
   gBrowser.removeTabsProgressListener(gAllProgressListener);
   gBrowser.removeTab(gBackgroundTab);
   gBrowser.removeTab(gForegroundTab);
   finish();
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug479408.js
@@ -0,0 +1,17 @@
+function test() {
+  waitForExplicitFinish();
+  let tab = gBrowser.selectedTab = gBrowser.addTab(
+    "http://localhost:8888/browser/browser/base/content/test/browser_bug479408_sample.html");
+  
+  gBrowser.addEventListener("DOMLinkAdded", function(aEvent) {
+    gBrowser.removeEventListener("DOMLinkAdded", arguments.callee, true);
+    
+    executeSoon(function() {
+      ok(!tab.linkedBrowser.engines,
+         "the subframe's search engine wasn't detected");
+      
+      gBrowser.removeTab(tab);
+      finish();
+    });
+  }, true);
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug479408_sample.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<title>Testcase for bug 479408</title>
+
+<iframe src='data:text/html,<link%20rel="search"%20type="application/opensearchdescription+xml"%20title="Search%20bug%20479408"%20href="http://example.com/search.xml">'>
--- a/browser/base/content/test/browser_gestureSupport.js
+++ b/browser/base/content/test/browser_gestureSupport.js
@@ -80,16 +80,25 @@ let test_expectedDelta;
 let test_expectedModifiers;
 
 function test_gestureListener(evt)
 {
   is(evt.type, test_expectedType,
      "evt.type (" + evt.type + ") does not match expected value");
   is(evt.target, test_utils.elementFromPoint(20, 20, false, false),
      "evt.target (" + evt.target + ") does not match expected value");
+  is(evt.clientX, 20,
+     "evt.clientX (" + evt.clientX + ") does not match expected value");
+  is(evt.clientY, 20,
+     "evt.clientY (" + evt.clientY + ") does not match expected value");
+  isnot(evt.screenX, 0,
+        "evt.screenX (" + evt.screenX + ") does not match expected value");
+  isnot(evt.screenY, 0,
+        "evt.screenY (" + evt.screenY + ") does not match expected value");
+
   is(evt.direction, test_expectedDirection,
      "evt.direction (" + evt.direction + ") does not match expected value");
   is(evt.delta, test_expectedDelta,
      "evt.delta (" + evt.delta + ") does not match expected value");
 
   is(evt.shiftKey, (test_expectedModifiers & Components.interfaces.nsIDOMNSEvent.SHIFT_MASK) != 0,
      "evt.shiftKey did not match expected value");
   is(evt.ctrlKey, (test_expectedModifiers & Components.interfaces.nsIDOMNSEvent.CONTROL_MASK) != 0,
@@ -182,33 +191,44 @@ function test_helper2(type, direction, d
     successful = true;
   }
   catch (ex) {
     successful = false;
   }
   ok(successful, "Unable to create SimpleGestureEvent");
 
   try {
-    event.initSimpleGestureEvent(type, true, true, null, 0, direction,
-                                 delta, altKey, ctrlKey, shiftKey, metaKey);
+    event.initSimpleGestureEvent(type, true, true, window, 1,
+                                 10, 10, 10, 10,
+                                 ctrlKey, altKey, shiftKey, metaKey,
+                                 1, window,
+                                 direction, delta);
     successful = true;
   }
   catch (ex) {
     successful = false;
   }
   ok(successful, "event.initSimpleGestureEvent should not fail");
 
   // Make sure the event fields match the expected values
   is(event.type, type, "Mismatch on evt.type");
   is(event.direction, direction, "Mismatch on evt.direction");
   is(event.delta, delta, "Mismatch on evt.delta");
   is(event.altKey, altKey, "Mismatch on evt.altKey");
   is(event.ctrlKey, ctrlKey, "Mismatch on evt.ctrlKey");
   is(event.shiftKey, shiftKey, "Mismatch on evt.shiftKey");
   is(event.metaKey, metaKey, "Mismatch on evt.metaKey");
+  is(event.view, window, "Mismatch on evt.view");
+  is(event.detail, 1, "Mismatch on evt.detail");
+  is(event.clientX, 10, "Mismatch on evt.clientX");
+  is(event.clientY, 10, "Mismatch on evt.clientY");
+  is(event.screenX, 10, "Mismatch on evt.screenX");
+  is(event.screenY, 10, "Mismatch on evt.screenY");
+  is(event.button, 1, "Mismatch on evt.button");
+  is(event.relatedTarget, window, "Mismatch on evt.relatedTarget");
 
   // Test event dispatch
   let expectedEventCount = test_eventCount + 1;
   document.addEventListener(type, test_eventDispatchListener, true);
   document.dispatchEvent(event);
   document.removeEventListener(type, test_eventDispatchListener, true);
   is(expectedEventCount, test_eventCount, "Dispatched event was never received by listener");
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/offlineChild.cacheManifest
@@ -0,0 +1,2 @@
+CACHE MANIFEST
+offlineChild.html
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/offlineChild.cacheManifest^headers^
@@ -0,0 +1,1 @@
+Content-Type: text/cache-manifest
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/offlineChild.html
@@ -0,0 +1,20 @@
+<html manifest="offlineChild.cacheManifest">
+<head>
+<title></title>
+<script type="text/javascript">
+
+function finish(success) {
+  window.parent.postMessage(success ? "success" : "failure", "*");
+}
+
+applicationCache.oncached = function() { finish(true); }
+applicationCache.onnoupdate = function() { finish(true); }
+applicationCache.onerror = function() { finish(false); }
+
+</script>
+</head>
+
+<body>
+<h1>Child</h1>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/offlineChild2.cacheManifest
@@ -0,0 +1,2 @@
+CACHE MANIFEST
+offlineChild2.html
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/offlineChild2.cacheManifest^headers^
@@ -0,0 +1,1 @@
+Content-Type: text/cache-manifest
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/offlineChild2.html
@@ -0,0 +1,20 @@
+<html manifest="offlineChild2.cacheManifest">
+<head>
+<title></title>
+<script type="text/javascript">
+
+function finish(success) {
+  window.parent.postMessage(success ? "success" : "failure", "*");
+}
+
+applicationCache.oncached = function() { finish(true); }
+applicationCache.onnoupdate = function() { finish(true); }
+applicationCache.onerror = function() { finish(false); }
+
+</script>
+</head>
+
+<body>
+<h1>Child</h1>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/test_offlineNotification.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=462856
+-->
+<head>
+  <title>Test offline app notification</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="loaded()">
+<p id="display">
+<!-- Load the test frame twice from the same domain,
+     to make sure we get notifications for both -->
+<iframe name="testFrame" src="offlineChild.html"></iframe>
+<iframe name="testFrame2" src="offlineChild2.html"></iframe>
+<!-- Load from another domain to make sure we get a second allow/deny
+     notification -->
+<iframe name="testFrame3" src="http://example.com/tests/browser/base/content/test/offlineChild.html"></iframe>
+
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var numFinished = 0;
+
+window.addEventListener("message", function(event) {
+    is(event.data, "success", "Child was successfully cached.");
+
+    if (++numFinished == 3) {
+      // Clean up after ourself
+      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+      var pm = Components.classes["@mozilla.org/permissionmanager;1"].
+               getService(Components.interfaces.nsIPermissionManager);
+
+      pm.remove(frames.testFrame.document.documentURIObject.host, "offline-app");
+      pm.remove(frames.testFrame3.document.documentURIObject.host, "offline-app");
+
+      SimpleTest.finish();
+    }
+  }, false);
+
+function loaded() {
+  // Click the notification bar's "Allow" button.  This should kick
+  // off updates, which will eventually lead to getting messages from
+  // the children.
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
+           getService(Components.interfaces.nsIWindowMediator);
+  var win = wm.getMostRecentWindow("navigator:browser");
+  var notificationBox = win.gBrowser.getNotificationBox();
+
+  var notification = notificationBox.getNotificationWithValue("offline-app-requested-localhost");
+  notification.childNodes[0].click();
+
+  notification = notificationBox.getNotificationWithValue("offline-app-requested-example.com");
+  notification.childNodes[0].click();
+}
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -37,16 +37,18 @@
 #
 # ***** END LICENSE BLOCK *****
 
 /**
  * Communicator Shared Utility Library
  * for shared application glue for the Communicator suite of applications
  **/
 
+var TAB_DROP_TYPE = "application/x-moz-tabbrowser-tab";
+
 var gBidiUI = false;
 
 function getBrowserURL()
 {
   return "chrome://browser/content/browser.xul";
 }
 
 function goToggleToolbar( id, elementID )
--- a/browser/branding/unofficial/branding.nsi
+++ b/browser/branding/unofficial/branding.nsi
@@ -32,24 +32,16 @@
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
 # NSIS branding defines for unofficial builds.
 # The official release build branding.nsi is located in other-license/branding/firefox/
 # The nightly build branding.nsi is located in browser/installer/windows/nsis/
-!define BrandShortName        "Shiretoko"
+
 # BrandFullNameInternal is used for some registry and file system values
 # instead of BrandFullName and typically should not be modified.
 !define BrandFullNameInternal "Shiretoko"
 !define CompanyName           "mozilla.org"
 !define URLInfoAbout          "http://www.mozilla.org"
 !define URLUpdateInfo         "http://www.mozilla.org/projects/firefox"
 !define SurveyURL             "https://survey.mozilla.com/1/Mozilla%20Firefox/${AppVersion}/${AB_CD}/exit.html"
-
-# Everything below this line may be modified for Alpha / Beta releases.
-!define BrandFullName         "Shiretoko"
-
-# Add !define NO_INSTDIR_FROM_REG to prevent finding a non-default installation
-# directory in the registry and using that as the default. This prevents
-# Beta releases built with official branding from finding an existing install
-# of an official release and defaulting to its installation directory.
--- a/browser/branding/unofficial/pref/firefox-branding.js
+++ b/browser/branding/unofficial/pref/firefox-branding.js
@@ -1,13 +1,16 @@
 pref("startup.homepage_override_url","http://www.mozilla.org/projects/%APP%/%VERSION%/whatsnew/");
 pref("startup.homepage_welcome_url","http://www.mozilla.org/projects/%APP%/%VERSION%/firstrun/");
 // The time interval between checks for a new version (in seconds)
 // nightly=8 hours, official=24 hours
 pref("app.update.interval", 28800);
+// The time interval between the downloading of mar file chunks in the
+// background (in seconds)
+pref("app.update.download.backgroundInterval", 60);
 // URL user can browse to manually if for some reason all update installation
 // attempts fail.
 pref("app.update.url.manual", "http://www.mozilla.org/products/%APP%/");
 // A default value for the "More information about this update" link
 // supplied in the "An update is available" page of the update wizard. 
 pref("app.update.url.details", "http://www.mozilla.org/projects/%APP%/");
 
 // Release notes URL
--- a/browser/components/build/Makefile.in
+++ b/browser/components/build/Makefile.in
@@ -25,16 +25,17 @@ REQUIRES = \
 	uriloader \
 	intl \
 	necko \
 	shellservice \
 	xulapp \
 	places \
 	browserplaces \
 	microsummaries \
+	privatebrowsing \
 	$(NULL)
 
 EXPORTS = nsBrowserCompsCID.h
 
 CPPSRCS = nsModule.cpp \
           $(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
@@ -42,25 +43,27 @@ DEFINES += -DPSTOREC_DLL=\"$(subst \,\\,
 
 OS_LIBS	+= $(call EXPAND_LIBNAME,ole32 shell32)
 endif
 
 LOCAL_INCLUDES = \
 	-I$(srcdir)/../shell/src \
 	-I$(srcdir)/../feeds/src \
 	-I$(srcdir)/../places/src \
+	-I$(srcdir)/../privatebrowsing/src \
 	$(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
 OS_LIBS += $(call EXPAND_LIBNAME,version)
 endif
 
 SHARED_LIBRARY_LIBS = \
 	../feeds/src/$(LIB_PREFIX)browser_feeds_s.$(LIB_SUFFIX) \
 	../places/src/$(LIB_PREFIX)browserplaces_s.$(LIB_SUFFIX) \
+	../privatebrowsing/src/$(LIB_PREFIX)privatebrowsing_s.$(LIB_SUFFIX) \
 	$(NULL)
 
 ifneq (,$(filter windows mac cocoa gtk2, $(MOZ_WIDGET_TOOLKIT)))
 SHARED_LIBRARY_LIBS += ../shell/src/$(LIB_PREFIX)shellservice_s.$(LIB_SUFFIX)
 endif
 
 EXTRA_DSO_LDOPTS += \
 	$(call EXPAND_LIBNAME_PATH,unicharutil_external_s,$(LIBXUL_DIST)/lib) \
--- a/browser/components/build/nsBrowserCompsCID.h
+++ b/browser/components/build/nsBrowserCompsCID.h
@@ -92,8 +92,12 @@
 { 0x12ff56ec, 0x58be, 0x402c, { 0xb0, 0x57, 0x1, 0xf9, 0x61, 0xde, 0x96, 0x9b } }
 
 // 6fb0c970-e1b1-11db-8314-0800200c9a66
 #define NS_PLACESIMPORTEXPORTSERVICE_CID \
 { 0x6fb0c970, 0xe1b1, 0x11db, { 0x83, 0x14, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }
 
 #define NS_PLACESIMPORTEXPORTSERVICE_CONTRACTID \
   "@mozilla.org/browser/places/import-export-service;1"
+
+// 136e2c4d-c5a4-477c-b131-d93d7d704f64
+#define NS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID \
+{ 0x136e2c4d, 0xc5a4, 0x477c, { 0xb1, 0x31, 0xd9, 0x3d, 0x7d, 0x70, 0x4f, 0x64 } }
--- a/browser/components/build/nsModule.cpp
+++ b/browser/components/build/nsModule.cpp
@@ -72,16 +72,19 @@
 
 #endif // WINCE
 
 #include "rdf.h"
 #include "nsFeedSniffer.h"
 #include "nsAboutFeeds.h"
 #include "nsIAboutModule.h"
 
+#include "nsPrivateBrowsingServiceWrapper.h"
+#include "nsNetCID.h"
+
 /////////////////////////////////////////////////////////////////////////////
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsPlacesImportExportService)
 #if defined(XP_WIN)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindowsShellService)
 #elif defined(XP_MACOSX)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacShellService)
 #elif defined(MOZ_WIDGET_GTK2)
@@ -108,16 +111,18 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacIEPr
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsCaminoProfileMigrator)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsICabProfileMigrator)
 #endif
 
 #endif
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFeedSniffer)
 
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrivateBrowsingServiceWrapper, Init)
+
 /////////////////////////////////////////////////////////////////////////////
 
 static const nsModuleComponentInfo components[] =
 {
 #if defined(XP_WIN)
   { "Browser Shell Service",
     NS_SHELLSERVICE_CID,
     NS_SHELLSERVICE_CONTRACTID,
@@ -212,15 +217,20 @@ static const nsModuleComponentInfo compo
   { "Phoenix Profile Migrator",
     NS_PHOENIXPROFILEMIGRATOR_CID,
     NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "phoenix",
     nsPhoenixProfileMigratorConstructor },
 
   { "Seamonkey Profile Migrator",
     NS_SEAMONKEYPROFILEMIGRATOR_CID,
     NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "seamonkey",
-    nsSeamonkeyProfileMigratorConstructor }
+    nsSeamonkeyProfileMigratorConstructor },
 
 #endif /* WINCE */
+
+  { "PrivateBrowsing Service C++ Wrapper",
+    NS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID,
+    NS_PRIVATE_BROWSING_SERVICE_CONTRACTID,
+    nsPrivateBrowsingServiceWrapperConstructor }
 };
 
 NS_IMPL_NSGETMODULE(nsBrowserCompsModule, components)
 
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -19,16 +19,17 @@
 # the Initial Developer. All Rights Reserved.
 #
 # Contributor(s):
 #   Giorgio Maone <g.maone@informaction.com>
 #   Seth Spitzer <sspitzer@mozilla.com>
 #   Asaf Romano <mano@mozilla.com>
 #   Marco Bonardo <mak77@bonardo.net>
 #   Dietrich Ayala <dietrich@mozilla.com>
+#   Ehsan Akhgari <ehsan.akhgari@gmail.com>
 #
 # Alternatively, the contents of this file may be used under the terms of
 # either the GNU General Public License Version 2 or later (the "GPL"), or
 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 # in which case the provisions of the GPL or the LGPL are applicable instead
 # of those above. If you wish to allow use of your version of this file only
 # under the terms of either the GPL or the LGPL, and not to allow others to
 # use your version of this file under the terms of the MPL, indicate your
@@ -318,17 +319,21 @@ BrowserGlue.prototype = {
       if (sessionWillBeSaved || !this._prefs.getBoolPref("browser.warnOnQuit"))
         showPrompt = false;
       else if (aQuitType == "restart")
         showPrompt = this._prefs.getBoolPref("browser.warnOnRestart");
       else
         showPrompt = this._prefs.getBoolPref("browser.tabs.warnOnClose");
     } catch (ex) {}
 
-    if (!showPrompt)
+    // Never show a prompt inside the private browsing mode
+    var inPrivateBrowsing = Cc["@mozilla.org/privatebrowsing;1"].
+                            getService(Ci.nsIPrivateBrowsingService).
+                            privateBrowsingEnabled;
+    if (!showPrompt || inPrivateBrowsing)
       return false;
 
     var buttonChoice = 0;
     var quitBundle = this._bundleService.createBundle("chrome://browser/locale/quitDialog.properties");
     var brandBundle = this._bundleService.createBundle("chrome://branding/locale/brand.properties");
 
     var appName = brandBundle.GetStringFromName("brandShortName");
     var quitDialogTitle = quitBundle.formatStringFromName(aQuitType + "DialogTitle",
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -1330,16 +1330,29 @@ var PlacesControllerDragHelper = {
     // Check every dragged item
     for (var i = 0; i < dropCount; i++) {
       var flavor = this.getFirstValidFlavor(dt.mozTypesAt(i));
       if (!flavor)
         return false;
 
       var data = dt.mozGetDataAt(flavor, i);
 
+      // urls can be dropped on any insertionpoint
+      // XXXmano: // Remember: this method is called for each dragover event!
+      // Thus we shouldn't use unwrapNodes here at all if possible.
+      // I think it would be OK to accept bogus data here (e.g. text which was
+      // somehow wrapped as TAB_DROP_TYPE, this is not in our control, and
+      // will just case the actual drop to be a no-op), and only rule out valid
+      // expected cases, which are either unsupported flavors, or items which
+      // cannot be dropped in the current insertionpoint. The last case will
+      // likely force us to use unwrapNodes for the private data types of
+      // places.
+      if (flavor == TAB_DROP_TYPE)
+        continue;
+
       try {
         var dragged = PlacesUtils.unwrapNodes(data, flavor)[0];
       } catch (e) {
         return false;
       }
 
       // Only bookmarks and urls can be dropped into tag containers
       if (ip.isTag && ip.orientation == Ci.nsITreeView.DROP_ON &&
@@ -1358,16 +1371,17 @@ var PlacesControllerDragHelper = {
             return false;
           parentId = PlacesUtils.bookmarks.getFolderIdForItem(parentId);
         }
       }
     }
     return true;
   },
 
+  
   /**
    * Determines if a node can be moved.
    * 
    * @param   aNode
    *          A nsINavHistoryResultNode node.
    * @returns True if the node can be moved, false otherwise.
    */
   canMoveNode:
@@ -1439,18 +1453,32 @@ var PlacesControllerDragHelper = {
     var dropCount = dt.mozItemCount;
     var movedCount = 0;
     for (var i = 0; i < dropCount; ++i) {
       var flavor = this.getFirstValidFlavor(dt.mozTypesAt(i));
       if (!flavor)
         return false;
 
       var data = dt.mozGetDataAt(flavor, i);
-      // There's only ever one in the D&D case.
-      var unwrapped = PlacesUtils.unwrapNodes(data, flavor)[0];
+      var unwrapped;
+      if (flavor != TAB_DROP_TYPE) {
+        // There's only ever one in the D&D case.
+        unwrapped = PlacesUtils.unwrapNodes(data, flavor)[0];
+      }
+      else if (data instanceof XULElement && data.localName == "tab" &&
+               data.ownerDocument.defaultView instanceof ChromeWindow) {
+        var uri = data.linkedBrowser.currentURI;
+        var spec = uri ? uri.spec : "about:blank";
+        var title = data.label;
+        unwrapped = { uri: spec,
+                      title: data.label,
+                      type: PlacesUtils.TYPE_X_MOZ_URL};
+      }
+      else
+        throw("bogus data was passed as a tab")
 
       var index = insertionPoint.index;
 
       // Adjust insertion index to prevent reversal of dragged items. When you
       // drag multiple elts upward: need to increment index or each successive
       // elt will be inserted at the same index, each above the previous.
       var dragginUp = insertionPoint.itemId == unwrapped.parent &&
                       index < PlacesUtils.bookmarks.getItemIndex(unwrapped.id);
@@ -1489,20 +1517,22 @@ var PlacesControllerDragHelper = {
     return (!PlacesUtils.nodeIsFolder(aContainer) ||
              PlacesUtils.nodeIsReadOnly(aContainer));
   },
 
   placesFlavors: [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
                   PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR,
                   PlacesUtils.TYPE_X_MOZ_PLACE],
 
+  // The order matters.
   GENERIC_VIEW_DROP_TYPES: [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
                             PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR,
                             PlacesUtils.TYPE_X_MOZ_PLACE,
                             PlacesUtils.TYPE_X_MOZ_URL,
+                            TAB_DROP_TYPE,
                             PlacesUtils.TYPE_UNICODE],
 
   /**
    * Returns our flavourSet
    */
   get flavourSet() {
     delete this.flavourSet;
     var flavourSet = new FlavourSet();
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -412,51 +412,59 @@ var PlacesOrganizer = {
   },
 
   /**
    * Populates the restore menu with the dates of the backups available.
    */
   populateRestoreMenu: function PO_populateRestoreMenu() {
     var restorePopup = document.getElementById("fileRestorePopup");
 
+    var dateSvc = Cc["@mozilla.org/intl/scriptabledateformat;1"].
+                  getService(Ci.nsIScriptableDateFormat);
+
     // remove existing menu items
     // last item is the restoreFromFile item
     while (restorePopup.childNodes.length > 1)
       restorePopup.removeChild(restorePopup.firstChild);
 
     // get list of files
     var localizedFilename = PlacesUtils.getString("bookmarksArchiveFilename");
     var localizedFilenamePrefix = localizedFilename.substr(0, localizedFilename.indexOf("-"));
     var fileList = [];
     var files = this.bookmarksBackupDir.directoryEntries;
     while (files.hasMoreElements()) {
       var f = files.getNext().QueryInterface(Ci.nsIFile);
-      var rx = new RegExp("^(bookmarks|" + localizedFilenamePrefix + ")-.+\.json");
-      if (!f.isHidden() && f.leafName.match(rx))
-        fileList.push(f);
+      var rx = new RegExp("^(bookmarks|" + localizedFilenamePrefix +
+                          ")-([0-9]{4}-[0-9]{2}-[0-9]{2})\.json$");
+      if (!f.isHidden() && f.leafName.match(rx)) {
+        var date = f.leafName.match(rx)[2].replace(/-/g, "/");
+        var dateObj = new Date(date);
+        fileList.push({date: dateObj, filename: f.leafName});
+      }
     }
 
     fileList.sort(function PO_fileList_compare(a, b) {
-      return b.lastModifiedTime - a.lastModifiedTime;
+      return b.date - a.date;
     });
 
     if (fileList.length == 0)
       return;
 
     // populate menu
     for (var i = 0; i < fileList.length; i++) {
       var m = restorePopup.insertBefore
         (document.createElement("menuitem"),
          document.getElementById("restoreFromFile"));
-      var rx = new RegExp("^(bookmarks|" + localizedFilenamePrefix + ")-");
-      var dateStr = fileList[i].leafName.replace(rx, "").replace(/\.json$/, "");
-      if (!dateStr.length)
-        dateStr = fileList[i].leafName;
-      m.setAttribute("label", dateStr);
-      m.setAttribute("value", fileList[i].leafName);
+      m.setAttribute("label",
+                     dateSvc.FormatDate("",
+                                        Ci.nsIScriptableDateFormat.dateFormatLong,
+                                        fileList[i].date.getFullYear(),
+                                        fileList[i].date.getMonth() + 1,
+                                        fileList[i].date.getDate()));
+      m.setAttribute("value", fileList[i].filename);
       m.setAttribute("oncommand",
                      "PlacesOrganizer.onRestoreMenuItemClick(this);");
     }
     restorePopup.insertBefore(document.createElement("menuseparator"),
                               document.getElementById("restoreFromFile"));
   },
 
   /**
@@ -1497,25 +1505,25 @@ var PlacesQueryBuilder = {
       child = child.nextSibling;
     }
 
     // update collection type and get folders
     var folders = [];
     switch (id) {
       case "scopeBarHistory":
         PlacesSearchBox.filterCollection = "history";
-        folders = [];
         break;
       case "scopeBarFolder":
         var selectedFolder = PlacesOrganizer._places.selectedNode.itemId;
         // note "all bookmarks" isn't the concrete parent of the top-level
         // bookmark folders
         if (selectedFolder != PlacesUIUtils.allBookmarksFolderId) {
           PlacesSearchBox.filterCollection = "collection";
-          folders.push(PlacesOrganizer._places.selectedNode.itemId);
+          folders.push(PlacesUtils.getConcreteItemId(
+                         PlacesOrganizer._places.selectedNode));
           break;
         }
       default: // all bookmarks
         PlacesSearchBox.filterCollection = "bookmarks";
         folders.push(PlacesUtils.bookmarksMenuFolderId,
                      PlacesUtils.toolbarFolderId,
                      PlacesUtils.unfiledBookmarksFolderId);
     }
--- a/browser/components/places/content/utils.js
+++ b/browser/components/places/content/utils.js
@@ -381,18 +381,19 @@ var PlacesUIUtils = {
         // inserting a new separator.
         if (copy)
           return this.ptm.createSeparator(container, index);
         // Move the separator otherwise
         return this.ptm.moveItem(data.id, container, index);
         break;
       default:
         if (type == PlacesUtils.TYPE_X_MOZ_URL ||
-            type == PlacesUtils.TYPE_UNICODE) {
-          var title = (type == PlacesUtils.TYPE_X_MOZ_URL) ? data.title :
+            type == PlacesUtils.TYPE_UNICODE ||
+            type == TAB_DROP_TYPE) {
+          var title = (type != PlacesUtils.TYPE_UNICODE) ? data.title :
                                                              data.uri;
           return this.ptm.createItem(PlacesUtils._uri(data.uri),
                                      container, index, title);
         }
     }
     return null;
   },
 
--- a/browser/components/places/tests/unit/tail_bookmarks.js
+++ b/browser/components/places/tests/unit/tail_bookmarks.js
@@ -32,33 +32,33 @@
  * 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 ***** */
 
 // put cleanup of the bookmarks test here.
 
+// Run the event loop to be more like the browser, which normally runs the
+// event loop long before code like this would run.
+// Not doing so could cause us to close the connection before all tasks have
+// been completed, and that would crash badly.
+let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
+while (tm.mainThread.hasPendingEvents())
+  tm.mainThread.processNextEvent(false);
+
 // XPCShell doesn't dispatch quit-application, to ensure cleanup we have to
 // dispatch it after each test run.
 var os = Cc['@mozilla.org/observer-service;1'].
          getService(Ci.nsIObserverService);
 os.notifyObservers(null, "quit-application-granted", null);
 os.notifyObservers(null, "quit-application", null);
 
 // try to close the connection so we can remove places.sqlite
 var pip = Cc["@mozilla.org/browser/nav-history-service;1"].
           getService(Ci.nsINavHistoryService).
           QueryInterface(Ci.nsPIPlacesDatabase);
 if (pip.DBConnection.connectionReady) {
-  // Run the event loop to be more like the browser, which normally runs the
-  // event loop long before code like this would run.
-  // Not doing so could cause us to close the connection between all tasks have
-  // been completed, and that would crash badly.
-  let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
-  while (tm.mainThread.hasPendingEvents())
-    tm.mainThread.processNextEvent(false);
-
   pip.commitPendingChanges();
   pip.finalizeInternalStatements();
   pip.DBConnection.close();
   do_check_false(pip.DBConnection.connectionReady);
 }
--- a/browser/components/places/tests/unit/test_browserGlue_prefs.js
+++ b/browser/components/places/tests/unit/test_browserGlue_prefs.js
@@ -207,24 +207,29 @@ tests.push({
 
     finish_test();
   }
 });
 
 //------------------------------------------------------------------------------
 
 function finish_test() {
+  // Simulate application closing to remove the idle observer and avoid leaks.
+  os.notifyObservers(null, "quit-application-granted", null);
   do_test_finished();
 }
 
 var testIndex = 0;
 function next_test() {
   // Clean up database from all bookmarks.
   remove_all_bookmarks();
 
+  // Simulate application closing to remove the idle observer and avoid leaks.
+  os.notifyObservers(null, "quit-application-granted", null);
+
   // nsBrowserGlue stops observing topics after first notification,
   // so we add back the observer to test additional runs.
   os.addObserver(bg, TOPIC_PLACES_INIT_COMPLETE, false);
 
   // Execute next test.
   let test = tests.shift();
   dump("\nTEST " + (++testIndex) + ": " + test.description);
   test.exec();
--- a/browser/components/preferences/advanced.js
+++ b/browser/components/preferences/advanced.js
@@ -211,20 +211,34 @@ var gAdvancedPane = {
                    windowTitle      : bundlePreferences.getString("offlinepermissionstitle"),
                    introText        : bundlePreferences.getString("offlinepermissionstext") };
     document.documentElement.openWindow("Browser:Permissions",
                                         "chrome://browser/content/preferences/permissions.xul",
                                         "", params);
   },
 
   // XXX: duplicated in browser.js
-  _getOfflineAppUsage: function (host)
+  _getOfflineAppUsage: function (host, groups)
   {
-    // XXX Bug 442710: include offline cache usage.
+    var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
+                       getService(Components.interfaces.nsIApplicationCacheService);
+    if (!groups) {
+      groups = cacheService.getGroups({});
+    }
+    var ios = Components.classes["@mozilla.org/network/io-service;1"].
+              getService(Components.interfaces.nsIIOService);
+
     var usage = 0;
+    for (var i = 0; i < groups.length; i++) {
+      var uri = ios.newURI(groups[i], null, null);
+      if (uri.asciiHost == host) {
+        var cache = cacheService.getActiveCache(groups[i]);
+        usage += cache.usage;
+      }
+    }
 
     var storageManager = Components.classes["@mozilla.org/dom/storagemanager;1"].
                          getService(Components.interfaces.nsIDOMStorageManager);
     usage += storageManager.getUsage(host);
 
     return usage;
   },
 
@@ -236,30 +250,34 @@ var gAdvancedPane = {
     var pm = Components.classes["@mozilla.org/permissionmanager;1"]
                        .getService(Components.interfaces.nsIPermissionManager);
 
     var list = document.getElementById("offlineAppsList");
     while (list.firstChild) {
       list.removeChild(list.firstChild);
     }
 
+    var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
+                       getService(Components.interfaces.nsIApplicationCacheService);
+    var groups = cacheService.getGroups({});
+
     var bundle = document.getElementById("bundlePreferences");
 
     var enumerator = pm.enumerator;
     while (enumerator.hasMoreElements()) {
       var perm = enumerator.getNext().QueryInterface(Components.interfaces.nsIPermission);
       if (perm.type == "offline-app" &&
           perm.capability != Components.interfaces.nsIPermissionManager.DEFAULT_ACTION &&
           perm.capability != Components.interfaces.nsIPermissionManager.DENY_ACTION) {
         var row = document.createElement("listitem");
         row.id = "";
         row.className = "offlineapp";
         row.setAttribute("host", perm.host);
         var converted = DownloadUtils.
-                        convertByteUnits(this._getOfflineAppUsage(perm.host));
+                        convertByteUnits(this._getOfflineAppUsage(perm.host, groups));
         row.setAttribute("usage",
                          bundle.getFormattedString("offlineAppUsage",
                                                    converted));
         list.appendChild(row);
       }
     }
   },
 
@@ -290,24 +308,28 @@ var gAdvancedPane = {
     var prompt = bundle.getFormattedString("offlineAppRemovePrompt", [host]);
     var confirm = bundle.getString("offlineAppRemoveConfirm");
     var result = prompts.confirmEx(window, title, prompt, flags, confirm,
                                    null, null, null, {});
     if (result != 0)
       return;
 
     // clear offline cache entries
-    var cacheService = Components.classes["@mozilla.org/network/cache-service;1"]
-                       .getService(Components.interfaces.nsICacheService);
-    var cacheSession = cacheService.createSession("HTTP-offline",
-                                                  Components.interfaces.nsICache.STORE_OFFLINE,
-                                                  true)
-                       .QueryInterface(Components.interfaces.nsIOfflineCacheSession);
-    cacheSession.clearKeysOwnedByDomain(host);
-    cacheSession.evictUnownedEntries();
+    var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
+                       getService(Components.interfaces.nsIApplicationCacheService);
+    var ios = Components.classes["@mozilla.org/network/io-service;1"].
+              getService(Components.interfaces.nsIIOService);
+    var groups = cacheService.getGroups({});
+    for (var i = 0; i < groups.length; i++) {
+        var uri = ios.newURI(groups[i], null, null);
+        if (uri.asciiHost == host) {
+            var cache = cacheService.getActiveCache(groups[i]);
+            cache.discard();
+        }
+    }
 
     // send out an offline-app-removed signal.  The nsDOMStorage
     // service will clear DOM storage for this host.
     var obs = Components.classes["@mozilla.org/observer-service;1"]
                         .getService(Components.interfaces.nsIObserverService);
     obs.notifyObservers(null, "offline-app-removed", host);
 
     // remove the permission
--- a/browser/components/preferences/cookies.js
+++ b/browser/components/preferences/cookies.js
@@ -548,17 +548,17 @@ var gCookiesWindow = {
                                      this._ds.timeFormatSeconds,
                                      date.getFullYear(),
                                      date.getMonth() + 1,
                                      date.getDate(),
                                      date.getHours(),
                                      date.getMinutes(),
                                      date.getSeconds());
     }
-    return this._bundle.getString("AtEndOfSession");
+    return this._bundle.getString("expireAtEndOfSession");
   },
   
   _updateCookieData: function (aItem)
   {
     var seln = this._view.selection;
     var ids = ["name", "value", "host", "path", "isSecure", "expires"];
     var properties;
     
--- a/browser/components/preferences/main.xul
+++ b/browser/components/preferences/main.xul
@@ -111,17 +111,17 @@
             <menuitem label="&startupBlankPage.label;"    value="0"/>
             <menuitem label="&startupLastSession.label;"  value="3"/>
           </menupopup>
         </menulist>
       </hbox>
       <separator class="thin"/>
       <hbox align="center">
         <label value="&location.label;" accesskey="&location.accesskey;" control="browserHomePage"/>
-        <textbox id="browserHomePage" class="padded" flex="1"
+        <textbox id="browserHomePage" class="padded uri-element" flex="1"
                  type="autocomplete" autocompletesearch="history"
                  preference="browser.startup.homepage"/>
       </hbox>
       <hbox align="center" pack="end">
         <button label="" accesskey="&useCurrentPage.accesskey;"
                 label1="&useCurrentPage.label;"
                 label2="&useMultiple.label;"
                 oncommand="gMainPane.setHomePageToCurrent();"
--- a/browser/components/privatebrowsing/src/Makefile.in
+++ b/browser/components/privatebrowsing/src/Makefile.in
@@ -37,14 +37,36 @@
 
 DEPTH   = ../../../..
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH   = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
+MODULE = privatebrowsing
+LIBRARY_NAME = privatebrowsing_s
+FORCE_STATIC_LIB = 1
+FORCE_USE_PIC = 1
+ifndef MOZ_MEMORY
+USE_STATIC_LIBS = 1
+endif
+
+REQUIRES = \
+	xpcom \
+	string \
+	necko \
+	js \
+	xpconnect \
+	$(NULL)
+
+CPPSRCS = \
+	nsPrivateBrowsingServiceWrapper.cpp \
+	$(NULL)
+
+LOCAL_INCLUDES = -I$(srcdir)/../../build
+
 EXTRA_PP_COMPONENTS = \
 	nsPrivateBrowsingService.js \
 	aboutPrivateBrowsing.js \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
+++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
@@ -75,16 +75,17 @@ const Cu = Components.utils;
 const Cr = Components.results;
 
 ////////////////////////////////////////////////////////////////////////////////
 //// PrivateBrowsingService
 
 function PrivateBrowsingService() {
   this._obs.addObserver(this, "profile-after-change", true);
   this._obs.addObserver(this, "quit-application-granted", true);
+  this._obs.addObserver(this, "private-browsing", true);
 }
 
 PrivateBrowsingService.prototype = {
   // Observer Service
   __obs: null,
   get _obs() {
     if (!this.__obs)
       this.__obs = Cc["@mozilla.org/observer-service;1"].
@@ -127,101 +128,96 @@ PrivateBrowsingService.prototype = {
 
   _unload: function PBS__destroy() {
     // Force an exit from the private browsing mode on shutdown
     this._quitting = true;
     if (this._inPrivateBrowsing)
       this.privateBrowsingEnabled = false;
   },
 
-  _onPrivateBrowsingModeChanged: function PBS__onPrivateBrowsingModeChanged() {
+  _onBeforePrivateBrowsingModeChange: function PBS__onBeforePrivateBrowsingModeChange() {
     // nothing needs to be done here if we're auto-starting
     if (!this._autoStart) {
-      // clear all auth tokens
-      let sdr = Cc["@mozilla.org/security/sdr;1"].
-                getService(Ci.nsISecretDecoderRing);
-      sdr.logoutAndTeardown();
-
-      // clear plain HTTP auth sessions
-      let authMgr = Cc['@mozilla.org/network/http-auth-manager;1'].
-                    getService(Ci.nsIHttpAuthManager);
-      authMgr.clearAll();
-
       let ss = Cc["@mozilla.org/browser/sessionstore;1"].
                getService(Ci.nsISessionStore);
-      if (this.privateBrowsingEnabled) {
+
+      if (this._inPrivateBrowsing) {
         // whether we should save and close the current session
         this._saveSession = true;
         var prefBranch = Cc["@mozilla.org/preferences-service;1"].
                          getService(Ci.nsIPrefBranch);
         try {
           if (prefBranch.getBoolPref("browser.privatebrowsing.keep_current_session"))
             this._saveSession = false;
         } catch (ex) {}
 
         // save the whole browser state in order to restore all windows/tabs later
-        if (this._saveSession && !this._savedBrowserState) {
+        if (this._saveSession && !this._savedBrowserState)
           this._savedBrowserState = ss.getBrowserState();
-
-          // Close all windows
-          this._closeAllWindows();
-
-          // Open about:privatebrowsing
-          this._openAboutPrivateBrowsing();
-        }
       }
-      else {
-        // Clear the error console
-        let consoleService = Cc["@mozilla.org/consoleservice;1"].
-                             getService(Ci.nsIConsoleService);
-        consoleService.logStringMessage(null); // trigger the listeners
-        consoleService.reset();
+      if (!this.quitting && this._saveSession) {
+        // dummy session used to transition from/to pb mode, see bug 476463
+        let transitionState = {
+          "windows": [{
+            "tabs": [{
+              "entries": [{
+                "url": "about:blank"
+              }]
+            }],
+            "_closedTabs": []
+          }]
+        };
+        // load dummy session to get a distinct separation between private and
+        // non-private sessions
+        ss.setBrowserState(JSON.stringify(transitionState));
 
-        // restore the windows/tabs which were open before entering the private mode
-        if (this._saveSession && this._savedBrowserState) {
-          if (!this._quitting) { // don't restore when shutting down!
-            ss.setBrowserState(this._savedBrowserState);
-          }
-          this._savedBrowserState = null;
-        }
+        let browser = Cc["@mozilla.org/appshell/window-mediator;1"].
+                      getService(Ci.nsIWindowMediator).
+                      getMostRecentWindow("navigator:browser").gBrowser;
+        // this ensures a clean slate from which to transition into or out of
+        // private browsing
+        browser.addTab();
+        browser.removeTab(browser.tabContainer.firstChild);
       }
     }
     else