Merge TM -> JM
authorBrian Hackett <bhackett1024@gmail.com>
Fri, 25 Feb 2011 18:21:43 +1300
changeset 74700 eb1eec3d6c2255f3647c7c3f2d90aa8f50cc6c50
parent 74699 001796fbcc2a9f1b79ab26feb006be513feac5dc (current diff)
parent 63091 05a667873d4b8948eb1e40f562682f5fc6d6de39 (diff)
child 74701 040641eb2a9788aef094b72d5662e9a361fb809c
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone2.0b12pre
Merge TM -> JM
accessible/tests/mochitest/editabletext.js
accessible/tests/mochitest/test_editabletext_1.html
accessible/tests/mochitest/test_editabletext_2.html
accessible/tests/mochitest/test_nsIAccessibleHyperText.html
browser/base/content/tabview/modules/groups.jsm
browser/base/content/test/browser_overLinkInLocationBar.js
browser/base/content/test/tabview/browser_tabview_bug594176.js
browser/themes/gnomestripe/browser/effects.svg
browser/themes/gnomestripe/browser/tabview/edit.png
browser/themes/gnomestripe/browser/urlbar-over-link-arrow.png
browser/themes/pinstripe/browser/effects.svg
browser/themes/pinstripe/browser/tabview/edit.png
browser/themes/pinstripe/browser/urlbar-over-link-arrow.png
browser/themes/winstripe/browser/effects.svg
browser/themes/winstripe/browser/places/bookmark-aero.png
browser/themes/winstripe/browser/places/editBookmark-aero.png
browser/themes/winstripe/browser/tabview/edit.png
browser/themes/winstripe/browser/urlbar-over-link-arrow.png
build/bloaturls.txt
build/pgo/profileserver.py.in
content/canvas/test/webgl/00_testFIXME_list.txt
content/canvas/test/webgl/conformance/00_testFIXME_list.txt
content/canvas/test/webgl/failing_tests.txt
content/events/test/Makefile.in
content/html/content/test/file_bug546995.html
content/html/content/test/test_bug546995-1.html
content/html/content/test/test_bug546995-2.html
content/html/content/test/test_bug546995-3.html
content/html/content/test/test_bug546995-4.html
content/html/content/test/test_bug546995-5.html
content/svg/content/src/nsSVGPoint.cpp
content/svg/content/src/nsSVGPoint.h
content/svg/content/src/nsSVGPointList.cpp
content/svg/content/src/nsSVGPointList.h
content/svg/content/src/nsSVGPreserveAspectRatio.cpp
content/svg/content/src/nsSVGPreserveAspectRatio.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsGlobalWindow.cpp
dom/indexedDB/nsIIDBErrorEvent.idl
dom/indexedDB/nsIIDBEvent.idl
dom/indexedDB/nsIIDBSuccessEvent.idl
dom/indexedDB/nsIIDBTransactionEvent.idl
dom/indexedDB/test/test_null_keys.html
embedding/android/android_strings.dtd
extensions/access-builtin/Makefile.in
extensions/access-builtin/README
extensions/access-builtin/accessproxy/Makefile.in
extensions/access-builtin/accessproxy/nsAccessProxy.cpp
extensions/access-builtin/accessproxy/nsAccessProxy.h
extensions/access-builtin/accessproxy/nsAccessProxyRegistration.cpp
extensions/access-builtin/accessproxy/nsIAccessProxy.idl
extensions/access-builtin/makefiles.sh
extensions/jssh/ChangeLog
extensions/jssh/Makefile.in
extensions/jssh/install.js
extensions/jssh/jar.mn
extensions/jssh/nsIJSSh.idl
extensions/jssh/nsIJSShServer.idl
extensions/jssh/nsJSSh.cpp
extensions/jssh/nsJSSh.h
extensions/jssh/nsJSShModule.cpp
extensions/jssh/nsJSShServer.cpp
extensions/jssh/nsJSShServer.h
extensions/jssh/nsJSShStarter.js
extensions/jssh/resources/content/configure.xul
extensions/jssh/resources/content/contents.rdf
extensions/jssh/resources/content/jssh-debug.js
extensions/jssh/resources/content/tasksOverlay.xul
extensions/jssh/xemacs/moz-jssh.el
extensions/metrics/Makefile.in
extensions/metrics/build/Makefile.in
extensions/metrics/build/nsMetricsModule.cpp
extensions/metrics/content/prefs.xul
extensions/metrics/install.rdf
extensions/metrics/jar.mn
extensions/metrics/locale/en-US/prefs.dtd
extensions/metrics/makefiles.sh
extensions/metrics/metrics.js
extensions/metrics/public/Makefile.in
extensions/metrics/public/nsIMetricsCollector.idl
extensions/metrics/public/nsIMetricsService.idl
extensions/metrics/public/nsMetricsModule.h
extensions/metrics/skin/prefs.css
extensions/metrics/src/Makefile.in
extensions/metrics/src/nsAutoCompleteCollector.cpp
extensions/metrics/src/nsAutoCompleteCollector.h
extensions/metrics/src/nsLoadCollector.cpp
extensions/metrics/src/nsLoadCollector.h
extensions/metrics/src/nsMetricsConfig.cpp
extensions/metrics/src/nsMetricsConfig.h
extensions/metrics/src/nsMetricsEventItem.cpp
extensions/metrics/src/nsMetricsEventItem.h
extensions/metrics/src/nsMetricsService.cpp
extensions/metrics/src/nsMetricsService.h
extensions/metrics/src/nsProfileCollector.cpp
extensions/metrics/src/nsProfileCollector.h
extensions/metrics/src/nsPtrHashKey.h
extensions/metrics/src/nsStringUtils.cpp
extensions/metrics/src/nsStringUtils.h
extensions/metrics/src/nsUICommandCollector.cpp
extensions/metrics/src/nsUICommandCollector.h
extensions/metrics/src/nsWindowCollector.cpp
extensions/metrics/src/nsWindowCollector.h
extensions/metrics/src/nssstubs.c
extensions/metrics/test/Makefile.in
extensions/metrics/test/TestCommon.h
extensions/metrics/test/TestMetricsConfig.cpp
extensions/metrics/test/TestUICommandCollector.cpp
extensions/metrics/test/data/test_config.xml
extensions/metrics/test/unit/head_content.js
extensions/metrics/test/unit/test_event_item.js
intl/lwbrk/src/nsLWBrkConstructors.h
intl/strres/src/nsStrBundleConstructors.h
intl/uconv/ucvko/nsUnicodeToJamoTTF.cpp
intl/uconv/ucvko/nsUnicodeToJamoTTF.h
intl/unicharutil/note.txt
intl/unicharutil/src/nsUcharUtilConstructors.h
js/ipc/ObjectWrapperParent.cpp
js/jetpack/Handle.h
js/src/Makefile.in
js/src/assembler/assembler/MacroAssemblerCodeRef.h
js/src/assembler/assembler/X86Assembler.h
js/src/config/autoconf.mk.in
js/src/configure.in
js/src/jit-test/tests/bug606083.js
js/src/jsanalyze.cpp
js/src/jsapi-tests/Makefile.in
js/src/jsapi-tests/testSetPropertyWithNativeGetterStubSetter.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsatom.cpp
js/src/jsbool.cpp
js/src/jsbuiltins.cpp
js/src/jsbuiltins.h
js/src/jsclone.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsdate.cpp
js/src/jsdbgapi.cpp
js/src/jsemit.cpp
js/src/jsemit.h
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsgcinlines.h
js/src/jshashtable.h
js/src/jsinfer.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsiter.cpp
js/src/jsmath.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsopcode.tbl
js/src/jsparse.cpp
js/src/jsparse.h
js/src/jsprobes.cpp
js/src/jsproxy.cpp
js/src/jspubtd.h
js/src/jsreflect.cpp
js/src/jsregexp.cpp
js/src/jsregexpinlines.h
js/src/jsscope.cpp
js/src/jsscopeinlines.h
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsstr.cpp
js/src/jstracer.cpp
js/src/jstypedarray.cpp
js/src/jsval.h
js/src/jsvalue.h
js/src/jswrapper.cpp
js/src/jsxdrapi.h
js/src/jsxml.cpp
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastArithmetic.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/FrameEntry.h
js/src/methodjit/FrameState.h
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/Logging.h
js/src/methodjit/MachineRegs.h
js/src/methodjit/MethodJIT.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/MonoIC.cpp
js/src/methodjit/MonoIC.h
js/src/methodjit/NunboxAssembler.h
js/src/methodjit/PolyIC.cpp
js/src/methodjit/PunboxAssembler.h
js/src/methodjit/RematInfo.h
js/src/methodjit/Retcon.cpp
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
js/src/methodjit/StubCompiler.cpp
js/src/methodjit/StubCompiler.h
js/src/methodjit/TypedArrayIC.h
js/src/perf/jsperf.cpp
js/src/shell/js.cpp
js/src/tests/ecma_3/Array/jstests.list
js/src/tests/js1_5/Regress/regress-240317.js
js/src/tests/js1_7/decompilation/regress-348904.js
js/src/tracejit/Writer.cpp
js/src/tracejit/Writer.h
js/src/xpconnect/src/xpcdebug.cpp
js/src/xpconnect/src/xpcwrappednative.cpp
js/src/xpconnect/wrappers/WrapperFactory.cpp
layout/reftests/bugs/557087.html
layout/reftests/css-invalid/button/button-button.html
layout/reftests/css-invalid/button/button-disabled-fieldset-1.html
layout/reftests/css-invalid/button/button-disabled-fieldset-2.html
layout/reftests/css-invalid/button/button-disabled.html
layout/reftests/css-invalid/button/button-dyn-disabled.html
layout/reftests/css-invalid/button/button-dyn-not-disabled.html
layout/reftests/css-invalid/button/button-fieldset-legend-ref.html
layout/reftests/css-invalid/button/button-fieldset-legend.html
layout/reftests/css-invalid/button/button-fieldset-ref.html
layout/reftests/css-invalid/button/button-reset.html
layout/reftests/css-invalid/button/button-type-barred.html
layout/reftests/css-invalid/button/button-type-invalid.html
layout/reftests/css-submit-invalid/button-submit/self-invalid.html
layout/reftests/css-submit-invalid/input-image/self-invalid.html
layout/reftests/css-submit-invalid/input-submit/self-invalid.html
layout/reftests/css-ui-invalid/button/button-button.html
layout/reftests/css-ui-invalid/button/button-disabled-fieldset-1.html
layout/reftests/css-ui-invalid/button/button-disabled-fieldset-2.html
layout/reftests/css-ui-invalid/button/button-disabled.html
layout/reftests/css-ui-invalid/button/button-dyn-disabled.html
layout/reftests/css-ui-invalid/button/button-dyn-not-disabled.html
layout/reftests/css-ui-invalid/button/button-fieldset-legend-ref.html
layout/reftests/css-ui-invalid/button/button-fieldset-legend.html
layout/reftests/css-ui-invalid/button/button-fieldset-ref.html
layout/reftests/css-ui-invalid/button/button-reset.html
layout/reftests/css-ui-invalid/button/button-type-barred.html
layout/reftests/css-ui-invalid/button/button-type-invalid.html
layout/reftests/css-ui-invalid/input/input-radio-required-invalid-changed-2.html
layout/reftests/css-ui-invalid/input/input-radio-required-invalid-default-2.html
layout/reftests/css-ui-valid/button/button-button.html
layout/reftests/css-ui-valid/button/button-disabled-fieldset-1.html
layout/reftests/css-ui-valid/button/button-disabled-fieldset-2.html
layout/reftests/css-ui-valid/button/button-disabled.html
layout/reftests/css-ui-valid/button/button-dyn-disabled.html
layout/reftests/css-ui-valid/button/button-dyn-not-disabled.html
layout/reftests/css-ui-valid/button/button-fieldset-legend-ref.html
layout/reftests/css-ui-valid/button/button-fieldset-legend.html
layout/reftests/css-ui-valid/button/button-fieldset-ref.html
layout/reftests/css-ui-valid/button/button-reset.html
layout/reftests/css-ui-valid/button/button-type-barred.html
layout/reftests/css-ui-valid/button/button-type-invalid.html
layout/reftests/css-valid/button/button-button.html
layout/reftests/css-valid/button/button-disabled-fieldset-1.html
layout/reftests/css-valid/button/button-disabled-fieldset-2.html
layout/reftests/css-valid/button/button-disabled.html
layout/reftests/css-valid/button/button-dyn-disabled.html
layout/reftests/css-valid/button/button-dyn-not-disabled.html
layout/reftests/css-valid/button/button-fieldset-legend-ref.html
layout/reftests/css-valid/button/button-fieldset-legend.html
layout/reftests/css-valid/button/button-fieldset-ref.html
layout/reftests/css-valid/button/button-reset.html
layout/reftests/css-valid/button/button-type-barred.html
layout/reftests/css-valid/button/button-type-invalid.html
layout/reftests/ogg-video/undersize-clipped-ref.html
layout/reftests/ogg-video/undersize-clipped.html
layout/reftests/svg/image/image-preserveAspectRatio-01.svg
layout/reftests/svg/image/image-preserveAspectRatio-02.svg
layout/reftests/table-bordercollapse/bordercolor.html
other-licenses/branding/firefox/content/contents.rdf
other-licenses/nsis/Contrib/nsProcess/Readme.txt
other-licenses/nsis/Contrib/nsProcess/Source/ConvFunc.h
other-licenses/nsis/Contrib/nsProcess/Source/nsProcess.c
other-licenses/nsis/Contrib/nsProcess/Source/nsProcess.dsp
other-licenses/nsis/Contrib/nsProcess/Source/nsProcess.dsw
other-licenses/nsis/Plugins/nsProcess.dll
parser/htmlparser/tests/htmlgen/htmlgen.cpp
parser/htmlparser/tests/htmlgen/htmlgen.html
security/manager/boot/public/nsISSLStatusProvider.idl
security/manager/ssl/public/nsISSLStatus.idl
security/manager/ssl/public/nsIX509Cert.idl
services/sync/modules/auth.js
services/sync/modules/base_records/collection.js
services/sync/modules/base_records/crypto.js
services/sync/modules/base_records/wbo.js
services/sync/modules/stores.js
services/sync/modules/trackers.js
services/sync/modules/type_records/bookmark.js
services/sync/modules/type_records/clients.js
services/sync/modules/type_records/forms.js
services/sync/modules/type_records/history.js
services/sync/modules/type_records/passwords.js
services/sync/modules/type_records/prefs.js
services/sync/modules/type_records/tabs.js
services/sync/tests/unit/test_bookmark_predecessor.js
toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_586142_insert_newlines.js
toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_587615_lastTimestamp.js
toolkit/components/places/src/nsPlacesDBFlush.js
toolkit/components/places/tests/sync/head_sync.js
toolkit/components/places/tests/sync/test_bookmarks_sorted_by_none.js
toolkit/components/places/tests/sync/test_database_sync_after_addBookmark.js
toolkit/components/places/tests/sync/test_database_sync_after_addBookmark_batched.js
toolkit/components/places/tests/sync/test_database_sync_after_addVisit.js
toolkit/components/places/tests/sync/test_database_sync_after_addVisit_batched.js
toolkit/components/places/tests/sync/test_database_sync_after_modifyBookmark.js
toolkit/components/places/tests/sync/test_database_sync_after_shutdown.js
toolkit/components/places/tests/sync/test_database_sync_after_shutdown_with_removeAllPages.js
toolkit/components/places/tests/sync/test_database_sync_embed_visits.js
toolkit/components/places/tests/sync/test_database_sync_expireAllFavicons.js
toolkit/components/places/tests/sync/test_database_sync_onitemadded.js
toolkit/components/places/tests/sync/test_database_sync_with_specialHistoryQueries.js
toolkit/components/places/tests/sync/test_multiple_bookmarks_around_sync.js
toolkit/components/places/tests/sync/test_multiple_visits_around_sync.js
toolkit/components/places/tests/unit/test_empty_tags.js
toolkit/components/places/tests/unit/test_vacuum.js
toolkit/components/places/tests/unit/test_vacuum_2.js
toolkit/components/places/tests/unit/test_vacuum_3.js
toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator_test.cc
toolkit/crashreporter/test/nsITestCrasher.idl
toolkit/crashreporter/test/testcrasher.manifest
toolkit/crashreporter/tools/win32/dump_syms.exe
toolkit/themes/gnomestripe/global/icons/folder-item.png
toolkit/themes/gnomestripe/mozapps/extensions/pause.png
toolkit/themes/pinstripe/global/icons/closetab-active.png
toolkit/themes/pinstripe/global/icons/closetab-hover.png
toolkit/themes/pinstripe/global/icons/closetab.png
toolkit/themes/pinstripe/global/icons/information-tabmodal-64.png
toolkit/themes/pinstripe/global/icons/question-tabmodal-64.png
toolkit/themes/pinstripe/mozapps/extensions/pause.png
toolkit/themes/winstripe/global/icons/information-tabmodal-64.png
toolkit/themes/winstripe/global/icons/question-tabmodal-64.png
toolkit/themes/winstripe/mozapps/extensions/pause.png
tools/relic/test/BrowserToolTip.cpp
tools/relic/test/addlicense_inputs/emacs_local_vars_line.c
tools/relic/test/addlicense_inputs/shebang_and_emacs_line.pl
tools/relic/test/addlicense_inputs/shebang_line.pl
tools/relic/test/addlicense_inputs/utf8_xml_file.xml
tools/relic/test/addlicense_inputs/xml_file.rdf
tools/relic/test/addlicense_outputs/emacs_local_vars_line.c
tools/relic/test/addlicense_outputs/shebang_and_emacs_line.pl
tools/relic/test/addlicense_outputs/shebang_line.pl
tools/relic/test/addlicense_outputs/utf8_xml_file.xml
tools/relic/test/addlicense_outputs/xml_file.rdf
tools/relic/test/relicense_inputs/bad_contributor_section.cpp
tools/relic/test/relicense_inputs/ibm_copyright_suffix.c
tools/relic/test/relicense_inputs/just_mpl.xul
tools/relic/test/relicense_inputs/need_to_relicense.h
tools/relic/test/relicense_inputs/no_initialcopyrightyear_section.xml
tools/relic/test/relicense_inputs/no_initialcopyrightyear_section.xml.options
tools/relic/test/relicense_inputs/no_origcodeis_section.h
tools/relic/test/relicense_inputs/no_origcodeis_section.h.options
tools/relic/test/relicense_inputs/npl.h
tools/relic/test/relicense_inputs/separated_license_comment_blocks.pl
tools/relic/test/relicense_inputs/separated_license_comment_blocks.pl.options
tools/relic/test/relicense_inputs/trailing_orig_code_modified.pl
tools/relic/test/relicense_inputs/unknown_license.c
tools/relic/test/relicense_outputs/bad_contributor_section.cpp.error
tools/relic/test/relicense_outputs/ibm_copyright_suffix.c
tools/relic/test/relicense_outputs/just_mpl.xul
tools/relic/test/relicense_outputs/need_to_relicense.h
tools/relic/test/relicense_outputs/no_initialcopyrightyear_section.xml
tools/relic/test/relicense_outputs/no_origcodeis_section.h
tools/relic/test/relicense_outputs/npl.h
tools/relic/test/relicense_outputs/separated_license_comment_blocks.pl
tools/relic/test/relicense_outputs/trailing_orig_code_modified.pl
tools/relic/test/relicense_outputs/unknown_license.c.error
tools/relic/test/test.py
tools/relic/test/test_addlicense_inputs.py
tools/relic/test/test_relicense_inputs.py
tools/relic/test/testsupport.py
--- a/.hgtags
+++ b/.hgtags
@@ -48,8 +48,9 @@ 925595f3c08634cc42e33158ea6858bb55623ef7
 dba2abb7db57078c5a4810884834d3056a5d56c2 last-mozilla-central
 138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R9
 138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R10
 138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R11
 0327e126ea245112c0aa7283fee154e084866fb5 bsmedberg-static-xpcom-registration-base
 0327e126ea245112c0aa7283fee154e084866fb5 bsmedberg-static-xpcom-registration-base
 2f83edbbeef0de7dd901411d270da61106c8afae bsmedberg-static-xpcom-registration-base
 138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R12
+138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R13
--- a/Makefile.in
+++ b/Makefile.in
@@ -137,17 +137,17 @@ ifeq ($(OS_ARCH),WINNT)
 MAKE_SYM_STORE_ARGS := -c
 ifdef PDBSTR_PATH
 MAKE_SYM_STORE_ARGS += -i
 endif
 ifeq (,$(CYGWIN_WRAPPER))
 # this doesn't work with Cygwin Python
 MAKE_SYM_STORE_ARGS += --vcs-info
 endif
-DUMP_SYMS_BIN ?= $(topsrcdir)/toolkit/crashreporter/tools/win32/dump_syms.exe
+DUMP_SYMS_BIN ?= $(topsrcdir)/toolkit/crashreporter/tools/win32/dump_syms_vc$(_MSC_VER).exe
 # PDB files don't get moved to dist, so we need to scan the whole objdir
 MAKE_SYM_STORE_PATH := .
 endif
 ifeq ($(OS_ARCH),Darwin)
 # need to pass arch flags for universal builds
 ifdef UNIVERSAL_BINARY
 MAKE_SYM_STORE_ARGS := -c -a "i386 x86_64" --vcs-info
 MAKE_SYM_STORE_PATH := $(DIST)/universal
@@ -187,17 +187,20 @@ ifdef MOZ_CRASHREPORTER
 	  $(DIST)/crashreporter-symbols                                   \
 	  $(MAKE_SYM_STORE_PATH) >                                        \
 	  $(DIST)/crashreporter-symbols/$(SYMBOL_INDEX_NAME)
 	echo packing symbols
 	$(NSINSTALL) -D $(DIST)/$(PKG_PATH)
 	cd $(DIST)/crashreporter-symbols && \
           zip -r9D "../$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip" .
 	cd $(DIST)/crashreporter-symbols && \
-          zip -r9D "../$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip" . -i "*.sym"
+	grep "sym" $(SYMBOL_INDEX_NAME) > $(SYMBOL_INDEX_NAME).tmp && \
+	  mv $(SYMBOL_INDEX_NAME).tmp $(SYMBOL_INDEX_NAME)
+	cd $(DIST)/crashreporter-symbols && \
+          zip -r9D "../$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip" . -i "*.sym" -i "*.txt"
 else
 ifdef WINCE
 ifdef SYMBOLSTORE_PATH
 	echo building symbol store with symstore.exe
 	$(RM) -rf $(DIST)/symbols
 	$(RM) -f "$(DIST)/$(SYMBOL_ARCHIVE_BASENAME).zip"
 	$(NSINSTALL) -D $(DIST)/symbols
 	$(SYMBOLSTORE_PATH) add -r -f "$(subst /,\,$(shell pwd -W))\*.PDB" \
--- a/accessible/src/atk/nsAccessibleWrap.cpp
+++ b/accessible/src/atk/nsAccessibleWrap.cpp
@@ -454,20 +454,17 @@ nsAccessibleWrap::CreateMaiInterfaces(vo
 
     // HyperLinkAccessible
     if (IsHyperLink()) {
        interfacesBits |= 1 << MAI_INTERFACE_HYPERLINK_IMPL;
     }
 
     if (!nsAccUtils::MustPrune(this)) {  // These interfaces require children
       //nsIAccessibleHypertext
-      nsCOMPtr<nsIAccessibleHyperText> accessInterfaceHypertext;
-      QueryInterface(NS_GET_IID(nsIAccessibleHyperText),
-                     getter_AddRefs(accessInterfaceHypertext));
-      if (accessInterfaceHypertext) {
+      if (IsHyperText()) {
           interfacesBits |= 1 << MAI_INTERFACE_HYPERTEXT;
       }
 
       //nsIAccessibleTable
       nsCOMPtr<nsIAccessibleTable> accessInterfaceTable;
       QueryInterface(NS_GET_IID(nsIAccessibleTable),
                      getter_AddRefs(accessInterfaceTable));
       if (accessInterfaceTable) {
--- a/accessible/src/atk/nsMaiInterfaceHypertext.cpp
+++ b/accessible/src/atk/nsMaiInterfaceHypertext.cpp
@@ -54,17 +54,17 @@ hypertextInterfaceInitCB(AtkHypertextIfa
 
 AtkHyperlink *
 getLinkCB(AtkHypertext *aText, gint aLinkIndex)
 {
     nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
     if (!accWrap)
         return nsnull;
 
-    nsRefPtr<nsHyperTextAccessible> hyperText = do_QueryObject(accWrap);
+    nsHyperTextAccessible* hyperText = accWrap->AsHyperText();
     NS_ENSURE_TRUE(hyperText, nsnull);
 
     nsAccessible* hyperLink = hyperText->GetLinkAt(aLinkIndex);
     if (!hyperLink)
         return nsnull;
 
     AtkObject* hyperLinkAtkObj = nsAccessibleWrap::GetAtkObject(hyperLink);
     nsAccessibleWrap *accChild = GetAccessibleWrap(hyperLinkAtkObj);
@@ -77,30 +77,30 @@ getLinkCB(AtkHypertext *aText, gint aLin
 
 gint
 getLinkCountCB(AtkHypertext *aText)
 {
     nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
     if (!accWrap)
         return -1;
 
-    nsRefPtr<nsHyperTextAccessible> hyperText = do_QueryObject(accWrap);
+    nsHyperTextAccessible* hyperText = accWrap->AsHyperText();
     NS_ENSURE_TRUE(hyperText, -1);
 
     return hyperText->GetLinkCount();
 }
 
 gint
 getLinkIndexCB(AtkHypertext *aText, gint aCharIndex)
 {
     nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
     if (!accWrap)
         return -1;
 
-    nsRefPtr<nsHyperTextAccessible> hyperText = do_QueryObject(accWrap);
+    nsHyperTextAccessible* hyperText = accWrap->AsHyperText();
     NS_ENSURE_TRUE(hyperText, -1);
 
     PRInt32 index = -1;
     nsresult rv = hyperText->GetLinkIndexAtOffset(aCharIndex, &index);
     NS_ENSURE_SUCCESS(rv, -1);
 
     return index;
 }
--- a/accessible/src/atk/nsMaiInterfaceText.cpp
+++ b/accessible/src/atk/nsMaiInterfaceText.cpp
@@ -36,19 +36,18 @@
  * 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 "nsMaiInterfaceText.h"
 
+#include "nsHyperTextAccessible.h"
 #include "nsRoleMap.h"
-#include "nsString.h"
-#include "nsIPersistentProperties2.h"
 
 AtkAttributeSet* ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes);
 
 void
 textInterfaceInitCB(AtkTextIface *aIface)
 {
     NS_ASSERTION(aIface, "Invalid aIface");
     if (!aIface)
@@ -369,24 +368,19 @@ getRangeExtentsCB(AtkText *aText, gint a
 
 gint
 getCharacterCountCB(AtkText *aText)
 {
     nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
     if (!accWrap)
         return 0;
 
-    nsCOMPtr<nsIAccessibleText> accText;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleText),
-                            getter_AddRefs(accText));
-    NS_ENSURE_TRUE(accText, 0);
-
-    PRInt32 count = 0;
-    nsresult rv = accText->GetCharacterCount(&count);
-    return (NS_FAILED(rv)) ? 0 : static_cast<gint>(count);
+    nsHyperTextAccessible* textAcc = accWrap->AsHyperText();
+    return textAcc->IsDefunct() ?
+        0 : static_cast<gint>(textAcc->CharacterCount());
 }
 
 gint
 getOffsetAtPointCB(AtkText *aText,
                    gint aX, gint aY,
                    AtkCoordType aCoords)
 {
     nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
--- a/accessible/src/base/AccEvent.cpp
+++ b/accessible/src/base/AccEvent.cpp
@@ -274,17 +274,17 @@ AccStateChangeEvent::CreateXPCOMObject()
 // we continue to base the event off the accessible object rather than just the
 // node. This means we won't try to create an accessible based on the node when
 // we are ready to fire the event and so we will no longer assert at that point
 // if the node was removed from the document. Either way, the AT won't work with
 // a defunct accessible so the behaviour should be equivalent.
 // XXX revisit this when coalescence is faster (eCoalesceFromSameSubtree)
 AccTextChangeEvent::
   AccTextChangeEvent(nsAccessible* aAccessible, PRInt32 aStart,
-                     nsAString& aModifiedText, PRBool aIsInserted,
+                     const nsAString& aModifiedText, PRBool aIsInserted,
                      EIsFromUserInput aIsFromUserInput)
   : AccEvent(aIsInserted ?
              static_cast<PRUint32>(nsIAccessibleEvent::EVENT_TEXT_INSERTED) :
              static_cast<PRUint32>(nsIAccessibleEvent::EVENT_TEXT_REMOVED),
              aAccessible, aIsFromUserInput, eAllowDupes)
   , mStart(aStart)
   , mIsInserted(aIsInserted)
   , mModifiedText(aModifiedText)
@@ -301,48 +301,44 @@ AccTextChangeEvent::CreateXPCOMObject()
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccMutationEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 AccMutationEvent::
   AccMutationEvent(PRUint32 aEventType, nsAccessible* aTarget,
-                   nsINode* aTargetNode, EIsFromUserInput aIsFromUserInput) :
-  AccEvent(aEventType, aTarget, aIsFromUserInput, eCoalesceFromSameSubtree)
+                   nsINode* aTargetNode) :
+  AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceFromSameSubtree)
 {
   mNode = aTargetNode;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccHideEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 AccHideEvent::
-  AccHideEvent(nsAccessible* aTarget, nsINode* aTargetNode,
-               EIsFromUserInput aIsFromUserInput) :
-  AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget, aTargetNode,
-                   aIsFromUserInput)
+  AccHideEvent(nsAccessible* aTarget, nsINode* aTargetNode) :
+  AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget, aTargetNode)
 {
-  mParent = mAccessible->GetCachedParent();
+  mParent = mAccessible->GetParent();
   mNextSibling = mAccessible->GetCachedNextSibling();
   mPrevSibling = mAccessible->GetCachedPrevSibling();
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccShowEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 AccShowEvent::
-  AccShowEvent(nsAccessible* aTarget, nsINode* aTargetNode,
-               EIsFromUserInput aIsFromUserInput) :
-  AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget, aTargetNode,
-                   aIsFromUserInput)
+  AccShowEvent(nsAccessible* aTarget, nsINode* aTargetNode) :
+  AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget, aTargetNode)
 {
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccCaretMoveEvent
 ////////////////////////////////////////////////////////////////////////////////
 
--- a/accessible/src/base/AccEvent.h
+++ b/accessible/src/base/AccEvent.h
@@ -153,17 +153,17 @@ protected:
   void CaptureIsFromUserInput(EIsFromUserInput aIsFromUserInput);
 
   PRBool mIsFromUserInput;
   PRUint32 mEventType;
   EEventRule mEventRule;
   nsRefPtr<nsAccessible> mAccessible;
   nsCOMPtr<nsINode> mNode;
 
-  friend class nsAccEventQueue;
+  friend class NotificationController;
 };
 
 
 /**
  * Accessible state change event.
  */
 class AccStateChangeEvent: public AccEvent
 {
@@ -201,17 +201,17 @@ private:
 
 /**
  * Accessible text change event.
  */
 class AccTextChangeEvent: public AccEvent
 {
 public:
   AccTextChangeEvent(nsAccessible* aAccessible, PRInt32 aStart,
-                     nsAString& aModifiedText, PRBool aIsInserted,
+                     const nsAString& aModifiedText, PRBool aIsInserted,
                      EIsFromUserInput aIsFromUserInput = eAutoDetect);
 
   // AccEvent
   virtual already_AddRefed<nsAccEvent> CreateXPCOMObject();
 
   static const EventGroup kEventGroup = eTextChangeEvent;
   virtual unsigned int GetEventGroups() const
   {
@@ -225,80 +225,78 @@ public:
   void GetModifiedText(nsAString& aModifiedText)
     { aModifiedText = mModifiedText; }
 
 private:
   PRInt32 mStart;
   PRBool mIsInserted;
   nsString mModifiedText;
 
-  friend class nsAccEventQueue;
+  friend class NotificationController;
 };
 
 
 /**
  * Base class for show and hide accessible events.
  */
 class AccMutationEvent: public AccEvent
 {
 public:
   AccMutationEvent(PRUint32 aEventType, nsAccessible* aTarget,
-                   nsINode* aTargetNode, EIsFromUserInput aIsFromUserInput);
+                   nsINode* aTargetNode);
 
   // Event
   static const EventGroup kEventGroup = eMutationEvent;
   virtual unsigned int GetEventGroups() const
   {
     return AccEvent::GetEventGroups() | (1U << eMutationEvent);
   }
 
   // MutationEvent
   bool IsShow() const { return mEventType == nsIAccessibleEvent::EVENT_SHOW; }
   bool IsHide() const { return mEventType == nsIAccessibleEvent::EVENT_HIDE; }
 
 protected:
   nsRefPtr<AccTextChangeEvent> mTextChangeEvent;
 
-  friend class nsAccEventQueue;
+  friend class NotificationController;
 };
 
 
 /**
  * Accessible hide event.
  */
 class AccHideEvent: public AccMutationEvent
 {
 public:
-  AccHideEvent(nsAccessible* aTarget, nsINode* aTargetNode,
-               EIsFromUserInput aIsFromUserInput);
+  AccHideEvent(nsAccessible* aTarget, nsINode* aTargetNode);
 
   // Event
   static const EventGroup kEventGroup = eHideEvent;
   virtual unsigned int GetEventGroups() const
   {
     return AccMutationEvent::GetEventGroups() | (1U << eHideEvent);
   }
 
 protected:
   nsRefPtr<nsAccessible> mParent;
   nsRefPtr<nsAccessible> mNextSibling;
   nsRefPtr<nsAccessible> mPrevSibling;
 
-  friend class nsAccEventQueue;
+  friend class NotificationController;
 };
 
 
 /**
  * Accessible show event.
  */
 class AccShowEvent: public AccMutationEvent
 {
 public:
-  AccShowEvent(nsAccessible* aTarget, nsINode* aTargetNode,
-               EIsFromUserInput aIsFromUserInput);
+  AccShowEvent(nsAccessible* aTarget, nsINode* aTargetNode);
 
   // Event
   static const EventGroup kEventGroup = eShowEvent;
   virtual unsigned int GetEventGroups() const
   {
     return AccMutationEvent::GetEventGroups() | (1U << eShowEvent);
   }
 };
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -48,16 +48,17 @@ LIBXUL_LIBRARY = 1
 
 
 CPPSRCS = \
   AccCollector.cpp \
   AccEvent.cpp \
   AccGroupInfo.cpp \
   AccIterator.cpp \
   filters.cpp \
+  NotificationController.cpp \
   nsAccDocManager.cpp \
   nsAccessNode.cpp \
   nsARIAGridAccessible.cpp \
   nsARIAMap.cpp \
   nsDocAccessible.cpp \
   nsOuterDocAccessible.cpp \
   nsAccessibilityAtoms.cpp \
   nsCoreUtils.cpp \
@@ -71,20 +72,23 @@ CPPSRCS = \
   nsEventShell.cpp \
   nsFormControlAccessible.cpp \
   nsRootAccessible.cpp \
   nsApplicationAccessible.cpp \
   nsCaretAccessible.cpp \
   nsTextAccessible.cpp \
   nsTextEquivUtils.cpp \
   nsTextAttrs.cpp \
+  TextUpdater.cpp \
   $(NULL)
 
 EXPORTS = \
   a11yGeneric.h \
+  nsAccDocManager.h \
+  nsAccessibilityService.h \
   nsAccessible.h \
   nsAccessNode.h \
   nsARIAMap.h \
   $(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
copy from accessible/src/base/nsEventShell.cpp
copy to accessible/src/base/NotificationController.cpp
--- a/accessible/src/base/nsEventShell.cpp
+++ b/accessible/src/base/NotificationController.cpp
@@ -10,17 +10,17 @@
  * 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 Corporation.
+ * Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2010
  * 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"),
@@ -31,212 +31,308 @@
  * 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 "nsEventShell.h"
+#include "NotificationController.h"
 
+#include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsDocAccessible.h"
+#include "nsEventShell.h"
+#include "nsTextAccessible.h"
+#include "TextUpdater.h"
+
+
+////////////////////////////////////////////////////////////////////////////////
+// NotificationCollector
+////////////////////////////////////////////////////////////////////////////////
+
+NotificationController::NotificationController(nsDocAccessible* aDocument,
+                                               nsIPresShell* aPresShell) :
+  mObservingState(eNotObservingRefresh), mDocument(aDocument),
+  mPresShell(aPresShell), mTreeConstructedState(eTreeConstructionPending)
+{
+  mTextHash.Init();
+
+  // Schedule initial accessible tree construction.
+  ScheduleProcessing();
+}
+
+NotificationController::~NotificationController()
+{
+  NS_ASSERTION(!mDocument, "Controller wasn't shutdown properly!");
+  if (mDocument)
+    Shutdown();
+}
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsEventShell
+// NotificationCollector: AddRef/Release and cycle collection
+
+NS_IMPL_ADDREF(NotificationController)
+NS_IMPL_RELEASE(NotificationController)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(NotificationController)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(NotificationController)
+  if (tmp->mDocument)
+    tmp->Shutdown();
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(NotificationController)
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDocument");
+  cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mDocument.get()));
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(mHangingChildDocuments,
+                                                    nsDocAccessible)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(mContentInsertions,
+                                                    ContentInsertion)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(mEvents, AccEvent)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(NotificationController, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(NotificationController, Release)
+
 ////////////////////////////////////////////////////////////////////////////////
+// NotificationCollector: public
 
 void
-nsEventShell::FireEvent(AccEvent* aEvent)
+NotificationController::Shutdown()
 {
-  if (!aEvent)
-    return;
-
-  nsAccessible *accessible = aEvent->GetAccessible();
-  NS_ENSURE_TRUE(accessible,);
-
-  nsINode* node = aEvent->GetNode();
-  if (node) {
-    sEventTargetNode = node;
-    sEventFromUserInput = aEvent->IsFromUserInput();
+  if (mObservingState != eNotObservingRefresh &&
+      mPresShell->RemoveRefreshObserver(this, Flush_Display)) {
+    mObservingState = eNotObservingRefresh;
   }
 
-  accessible->HandleAccEvent(aEvent);
+  // Shutdown handling child documents.
+  PRInt32 childDocCount = mHangingChildDocuments.Length();
+  for (PRInt32 idx = childDocCount - 1; idx >= 0; idx--)
+    mHangingChildDocuments[idx]->Shutdown();
+
+  mHangingChildDocuments.Clear();
 
-  sEventTargetNode = nsnull;
+  mDocument = nsnull;
+  mPresShell = nsnull;
+
+  mTextHash.Clear();
+  mContentInsertions.Clear();
+  mNotifications.Clear();
+  mEvents.Clear();
 }
 
 void
-nsEventShell::FireEvent(PRUint32 aEventType, nsAccessible *aAccessible,
-                        EIsFromUserInput aIsFromUserInput)
-{
-  NS_ENSURE_TRUE(aAccessible,);
-
-  nsRefPtr<AccEvent> event = new AccEvent(aEventType, aAccessible,
-                                          aIsFromUserInput);
-
-  FireEvent(event);
-}
-
-void 
-nsEventShell::GetEventAttributes(nsINode *aNode,
-                                 nsIPersistentProperties *aAttributes)
-{
-  if (aNode != sEventTargetNode)
-    return;
-
-  nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::eventFromInput,
-                         sEventFromUserInput ? NS_LITERAL_STRING("true") :
-                                               NS_LITERAL_STRING("false"));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// nsEventShell: private
-
-PRBool nsEventShell::sEventFromUserInput = PR_FALSE;
-nsCOMPtr<nsINode> nsEventShell::sEventTargetNode;
-
-
-////////////////////////////////////////////////////////////////////////////////
-// nsAccEventQueue
-////////////////////////////////////////////////////////////////////////////////
-
-nsAccEventQueue::nsAccEventQueue(nsDocAccessible *aDocument):
-  mObservingRefresh(PR_FALSE), mDocument(aDocument)
+NotificationController::QueueEvent(AccEvent* aEvent)
 {
-}
-
-nsAccEventQueue::~nsAccEventQueue()
-{
-  NS_ASSERTION(!mDocument, "Queue wasn't shut down!");
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// nsAccEventQueue: nsISupports and cycle collection
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsAccEventQueue)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsAccEventQueue)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsAccEventQueue)
-  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDocument");
-  cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mDocument.get()));
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(mEvents, AccEvent)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsAccEventQueue)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mEvents)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAccEventQueue)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAccEventQueue)
-
-////////////////////////////////////////////////////////////////////////////////
-// nsAccEventQueue: public
-
-void
-nsAccEventQueue::Push(AccEvent* aEvent)
-{
-  mEvents.AppendElement(aEvent);
+  if (!mEvents.AppendElement(aEvent))
+    return;
 
   // Filter events.
   CoalesceEvents();
 
   // Associate text change with hide event if it wasn't stolen from hiding
   // siblings during coalescence.
   AccMutationEvent* showOrHideEvent = downcast_accEvent(aEvent);
   if (showOrHideEvent && !showOrHideEvent->mTextChangeEvent)
     CreateTextChangeEventFor(showOrHideEvent);
 
-  // Process events.
-  PrepareFlush();
+  ScheduleProcessing();
+}
+
+void
+NotificationController::ScheduleChildDocBinding(nsDocAccessible* aDocument)
+{
+  // Schedule child document binding to the tree.
+  mHangingChildDocuments.AppendElement(aDocument);
+  ScheduleProcessing();
 }
 
 void
-nsAccEventQueue::Shutdown()
+NotificationController::ScheduleContentInsertion(nsAccessible* aContainer,
+                                                 nsIContent* aStartChildNode,
+                                                 nsIContent* aEndChildNode)
 {
-  if (mObservingRefresh) {
-    nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
-    if (!shell ||
-        shell->RemoveRefreshObserver(this, Flush_Display)) {
-      mObservingRefresh = PR_FALSE;
-    }
+  // Ignore content insertions until we constructed accessible tree.
+  if (mTreeConstructedState == eTreeConstructionPending)
+    return;
+
+  nsRefPtr<ContentInsertion> insertion =
+    new ContentInsertion(mDocument, aContainer, aStartChildNode, aEndChildNode);
+
+  if (insertion && mContentInsertions.AppendElement(insertion))
+    ScheduleProcessing();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NotificationCollector: protected
+
+void
+NotificationController::ScheduleProcessing()
+{
+  // If notification flush isn't planed yet start notification flush
+  // asynchronously (after style and layout).
+  if (mObservingState == eNotObservingRefresh) {
+    if (mPresShell->AddRefreshObserver(this, Flush_Display))
+      mObservingState = eRefreshObserving;
   }
-  mDocument = nsnull;
-  mEvents.Clear();
+}
+
+bool
+NotificationController::IsUpdatePending()
+{
+  nsCOMPtr<nsIPresShell_MOZILLA_2_0_BRANCH2> presShell =
+    do_QueryInterface(mPresShell);
+  return presShell->IsLayoutFlushObserver() ||
+    mObservingState == eRefreshProcessingForUpdate ||
+    mContentInsertions.Length() != 0 || mNotifications.Length() != 0 ||
+    mTextHash.Count() != 0;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsAccEventQueue: private
+// NotificationCollector: private
 
 void
-nsAccEventQueue::PrepareFlush()
+NotificationController::WillRefresh(mozilla::TimeStamp aTime)
 {
-  // If there are pending events in the queue and events flush isn't planed
-  // yet start events flush asynchronously.
-  if (mEvents.Length() > 0 && !mObservingRefresh) {
-    nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
-    // Use a Flush_Display observer so that it will get called after
-    // style and ayout have been flushed.
-    if (shell &&
-        shell->AddRefreshObserver(this, Flush_Display)) {
-      mObservingRefresh = PR_TRUE;
-    }
-  }
-}
-
-void
-nsAccEventQueue::WillRefresh(mozilla::TimeStamp aTime)
-{
-  // If the document accessible is now shut down, don't fire events in it
-  // anymore.
+  // If the document accessible that notification collector was created for is
+  // now shut down, don't process notifications anymore.
+  NS_ASSERTION(mDocument,
+               "The document was shut down while refresh observer is attached!");
   if (!mDocument)
     return;
 
-  // Process only currently queued events. Newly appended events during events
-  // flushing won't be processed.
-  nsTArray < nsRefPtr<AccEvent> > events;
+  // Any generic notifications should be queued if we're processing content
+  // insertions or generic notifications.
+  mObservingState = eRefreshProcessingForUpdate;
+
+  // Initial accessible tree construction.
+  if (mTreeConstructedState == eTreeConstructionPending) {
+    // If document is not bound to parent at this point then the document is not
+    // ready yet (process notifications later).
+    if (!mDocument->IsBoundToParent())
+      return;
+
+#ifdef DEBUG_NOTIFICATIONS
+    printf("\ninitial tree created, document: %p, document node: %p\n",
+           mDocument.get(), mDocument->GetDocumentNode());
+#endif
+
+    mTreeConstructedState = eTreeConstructed;
+    mDocument->CacheChildrenInSubtree(mDocument);
+
+    NS_ASSERTION(mContentInsertions.Length() == 0,
+                 "Pending content insertions while initial accessible tree isn't created!");
+  }
+
+  // Process content inserted notifications to update the tree. Process other
+  // notifications like DOM events and then flush event queue. If any new
+  // notifications are queued during this processing then they will be processed
+  // on next refresh. If notification processing queues up new events then they
+  // are processed in this refresh. If events processing queues up new events
+  // then new events are processed on next refresh.
+  // Note: notification processing or event handling may shut down the owning
+  // document accessible.
+
+  // Process only currently queued content inserted notifications.
+  nsTArray<nsRefPtr<ContentInsertion> > contentInsertions;
+  contentInsertions.SwapElements(mContentInsertions);
+
+  PRUint32 insertionCount = contentInsertions.Length();
+  for (PRUint32 idx = 0; idx < insertionCount; idx++) {
+    contentInsertions[idx]->Process();
+    if (!mDocument)
+      return;
+  }
+
+  // Process rendered text change notifications.
+  mTextHash.EnumerateEntries(TextEnumerator, mDocument);
+  mTextHash.Clear();
+
+  // Bind hanging child documents.
+  PRUint32 childDocCount = mHangingChildDocuments.Length();
+  for (PRUint32 idx = 0; idx < childDocCount; idx++) {
+    nsDocAccessible* childDoc = mHangingChildDocuments[idx];
+
+    nsIContent* ownerContent = mDocument->GetDocumentNode()->
+      FindContentForSubDocument(childDoc->GetDocumentNode());
+    if (ownerContent) {
+      nsAccessible* outerDocAcc = mDocument->GetAccessible(ownerContent);
+      if (outerDocAcc && outerDocAcc->AppendChild(childDoc)) {
+        if (mDocument->AppendChildDocument(childDoc)) {
+          // Fire reorder event to notify new accessible document has been
+          // attached to the tree.
+          nsRefPtr<AccEvent> reorderEvent =
+              new AccEvent(nsIAccessibleEvent::EVENT_REORDER, outerDocAcc,
+                           eAutoDetect, AccEvent::eCoalesceFromSameSubtree);
+          if (reorderEvent)
+            QueueEvent(reorderEvent);
+
+          continue;
+        }
+        outerDocAcc->RemoveChild(childDoc);
+      }
+
+      // Failed to bind the child document, destroy it.
+      childDoc->Shutdown();
+    }
+  }
+  mHangingChildDocuments.Clear();
+
+  // Process only currently queued generic notifications.
+  nsTArray < nsRefPtr<Notification> > notifications;
+  notifications.SwapElements(mNotifications);
+
+  PRUint32 notificationCount = notifications.Length();
+  for (PRUint32 idx = 0; idx < notificationCount; idx++) {
+    notifications[idx]->Process();
+    if (!mDocument)
+      return;
+  }
+
+  // If a generic notification occurs after this point then we may be allowed to
+  // process it synchronously.
+  mObservingState = eRefreshObserving;
+
+  // Process only currently queued events.
+  nsTArray<nsRefPtr<AccEvent> > events;
   events.SwapElements(mEvents);
-  PRUint32 length = events.Length();
-  NS_ASSERTION(length, "How did we get here without events to fire?");
 
-  for (PRUint32 index = 0; index < length; index ++) {
-
-    AccEvent* accEvent = events[index];
+  PRUint32 eventCount = events.Length();
+  for (PRUint32 idx = 0; idx < eventCount; idx++) {
+    AccEvent* accEvent = events[idx];
     if (accEvent->mEventRule != AccEvent::eDoNotEmit) {
       mDocument->ProcessPendingEvent(accEvent);
 
       AccMutationEvent* showOrhideEvent = downcast_accEvent(accEvent);
       if (showOrhideEvent) {
         if (showOrhideEvent->mTextChangeEvent)
           mDocument->ProcessPendingEvent(showOrhideEvent->mTextChangeEvent);
       }
     }
-
-    // No document means it was shut down during event handling by AT
     if (!mDocument)
       return;
   }
 
-  if (mEvents.Length() == 0) {
-    nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
-    if (!shell ||
-        shell->RemoveRefreshObserver(this, Flush_Display)) {
-      mObservingRefresh = PR_FALSE;
-    }
+  // Stop further processing if there are no newly queued insertions,
+  // notifications or events.
+  if (mContentInsertions.Length() == 0 && mNotifications.Length() == 0 &&
+      mEvents.Length() == 0 &&
+      mPresShell->RemoveRefreshObserver(this, Flush_Display)) {
+    mObservingState = eNotObservingRefresh;
   }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// NotificationController: event queue
+
 void
-nsAccEventQueue::CoalesceEvents()
+NotificationController::CoalesceEvents()
 {
   PRUint32 numQueuedEvents = mEvents.Length();
   PRInt32 tail = numQueuedEvents - 1;
   AccEvent* tailEvent = mEvents[tail];
 
   // No node means this is application accessible (which can be a subject
   // of reorder events), we do not coalesce events for it currently.
   if (!tailEvent->mNode)
@@ -253,25 +349,26 @@ nsAccEventQueue::CoalesceEvents()
 
         // Skip event for application accessible since no coalescence for it
         // is supported. Ignore events from different documents since we don't
         // coalesce them.
         if (!thisEvent->mNode ||
             thisEvent->mNode->GetOwnerDoc() != tailEvent->mNode->GetOwnerDoc())
           continue;
 
+        // Coalesce earlier event for the same target.
+        if (thisEvent->mNode == tailEvent->mNode) {
+          thisEvent->mEventRule = AccEvent::eDoNotEmit;
+          return;
+        }
+
         // If event queue contains an event of the same type and having target
         // that is sibling of target of newly appended event then apply its
         // event rule to the newly appended event.
 
-        // XXX: deal with show events separately because they can't be
-        // coalesced by accessible tree the same as hide events since target
-        // accessibles can't be created at this point because of lazy frame
-        // construction (bug 570275).
-
         // Coalesce hide and show events for sibling targets.
         if (tailEvent->mEventType == nsIAccessibleEvent::EVENT_HIDE) {
           AccHideEvent* tailHideEvent = downcast_accEvent(tailEvent);
           AccHideEvent* thisHideEvent = downcast_accEvent(thisEvent);
           if (thisHideEvent->mParent == tailHideEvent->mParent) {
             tailEvent->mEventRule = thisEvent->mEventRule;
 
             // Coalesce text change events for hide events.
@@ -295,22 +392,16 @@ nsAccEventQueue::CoalesceEvents()
             return;
           }
         }
 
         // Ignore events unattached from DOM since we don't coalesce them.
         if (!thisEvent->mNode->IsInDoc())
           continue;
 
-        // Coalesce earlier event for the same target.
-        if (thisEvent->mNode == tailEvent->mNode) {
-          thisEvent->mEventRule = AccEvent::eDoNotEmit;
-          return;
-        }
-
         // Coalesce events by sibling targets (this is a case for reorder
         // events).
         if (thisEvent->mNode->GetNodeParent() ==
             tailEvent->mNode->GetNodeParent()) {
           tailEvent->mEventRule = thisEvent->mEventRule;
           return;
         }
 
@@ -375,89 +466,90 @@ nsAccEventQueue::CoalesceEvents()
     } break; // case eRemoveDupes
 
     default:
       break; // case eAllowDupes, eDoNotEmit
   } // switch
 }
 
 void
-nsAccEventQueue::ApplyToSiblings(PRUint32 aStart, PRUint32 aEnd,
-                                 PRUint32 aEventType, nsINode* aNode,
-                                 AccEvent::EEventRule aEventRule)
+NotificationController::ApplyToSiblings(PRUint32 aStart, PRUint32 aEnd,
+                                        PRUint32 aEventType, nsINode* aNode,
+                                        AccEvent::EEventRule aEventRule)
 {
   for (PRUint32 index = aStart; index < aEnd; index ++) {
     AccEvent* accEvent = mEvents[index];
     if (accEvent->mEventType == aEventType &&
         accEvent->mEventRule != AccEvent::eDoNotEmit && accEvent->mNode &&
         accEvent->mNode->GetNodeParent() == aNode->GetNodeParent()) {
       accEvent->mEventRule = aEventRule;
     }
   }
 }
 
 void
-nsAccEventQueue::CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
-                                             AccHideEvent* aThisEvent)
+NotificationController::CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
+                                                    AccHideEvent* aThisEvent)
 {
   // XXX: we need a way to ignore SplitNode and JoinNode() when they do not
   // affect the text within the hypertext.
 
   AccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent;
   if (!textEvent)
     return;
 
   if (aThisEvent->mNextSibling == aTailEvent->mAccessible) {
-    aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText,
-                                          0, PR_UINT32_MAX);
+    aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText);
 
   } else if (aThisEvent->mPrevSibling == aTailEvent->mAccessible) {
     PRUint32 oldLen = textEvent->GetLength();
-    aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText,
-                                          0, PR_UINT32_MAX);
+    aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText);
     textEvent->mStart -= textEvent->GetLength() - oldLen;
   }
 
   aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent);
 }
 
 void
-nsAccEventQueue::CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent,
-                                             AccShowEvent* aThisEvent)
+NotificationController::CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent,
+                                                    AccShowEvent* aThisEvent)
 {
   AccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent;
   if (!textEvent)
     return;
 
   if (aTailEvent->mAccessible->GetIndexInParent() ==
       aThisEvent->mAccessible->GetIndexInParent() + 1) {
     // If tail target was inserted after this target, i.e. tail target is next
     // sibling of this target.
-    aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText,
-                                          0, PR_UINT32_MAX);
+    aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText);
 
   } else if (aTailEvent->mAccessible->GetIndexInParent() ==
              aThisEvent->mAccessible->GetIndexInParent() -1) {
     // If tail target was inserted before this target, i.e. tail target is
     // previous sibling of this target.
     nsAutoString startText;
-    aTailEvent->mAccessible->AppendTextTo(startText, 0, PR_UINT32_MAX);
+    aTailEvent->mAccessible->AppendTextTo(startText);
     textEvent->mModifiedText = startText + textEvent->mModifiedText;
     textEvent->mStart -= startText.Length();
   }
 
   aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent);
 }
 
 void
-nsAccEventQueue::CreateTextChangeEventFor(AccMutationEvent* aEvent)
+NotificationController::CreateTextChangeEventFor(AccMutationEvent* aEvent)
 {
-  nsRefPtr<nsHyperTextAccessible> textAccessible = do_QueryObject(
+  nsAccessible* container =
     GetAccService()->GetContainerAccessible(aEvent->mNode,
-                                            aEvent->mAccessible->GetWeakShell()));
+                                            aEvent->mAccessible->GetWeakShell());
+  if (!container)
+    return;
+
+  nsHyperTextAccessible* textAccessible = container->AsHyperText();
   if (!textAccessible)
     return;
 
   // Don't fire event for the first html:br in an editor.
   if (aEvent->mAccessible->Role() == nsIAccessibleRole::ROLE_WHITESPACE) {
     nsCOMPtr<nsIEditor> editor;
     textAccessible->GetAssociatedEditor(getter_AddRefs(editor));
     if (editor) {
@@ -466,16 +558,190 @@ nsAccEventQueue::CreateTextChangeEventFo
       if (isEmpty)
         return;
     }
   }
 
   PRInt32 offset = textAccessible->GetChildOffset(aEvent->mAccessible);
 
   nsAutoString text;
-  aEvent->mAccessible->AppendTextTo(text, 0, PR_UINT32_MAX);
+  aEvent->mAccessible->AppendTextTo(text);
   if (text.IsEmpty())
     return;
 
   aEvent->mTextChangeEvent =
     new AccTextChangeEvent(textAccessible, offset, text, aEvent->IsShow(),
                            aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput);
 }
+
+////////////////////////////////////////////////////////////////////////////////
+// Notification controller: text leaf accessible text update
+
+PLDHashOperator
+NotificationController::TextEnumerator(nsCOMPtrHashKey<nsIContent>* aEntry,
+                                       void* aUserArg)
+{
+  nsDocAccessible* document = static_cast<nsDocAccessible*>(aUserArg);
+  nsIContent* textNode = aEntry->GetKey();
+  nsAccessible* textAcc = document->GetAccessible(textNode);
+
+  // If the text node is not in tree or doesn't have frame then this case should
+  // have been handled already by content removal notifications.
+  nsINode* containerNode = textNode->GetNodeParent();
+  if (!containerNode) {
+    NS_ASSERTION(!textAcc,
+                 "Text node was removed but accessible is kept alive!");
+    return PL_DHASH_NEXT;
+  }
+
+  nsIFrame* textFrame = textNode->GetPrimaryFrame();
+  if (!textFrame) {
+    NS_ASSERTION(!textAcc,
+                 "Text node isn't rendered but accessible is kept alive!");
+    return PL_DHASH_NEXT;
+  }
+
+  nsIContent* containerElm = containerNode->IsElement() ?
+    containerNode->AsElement() : nsnull;
+
+  nsAutoString text;
+  textFrame->GetRenderedText(&text);
+
+  // Remove text accessible if rendered text is empty.
+  if (textAcc) {
+    if (text.IsEmpty()) {
+#ifdef DEBUG_NOTIFICATIONS
+      PRUint32 index = containerNode->IndexOf(textNode);
+
+      nsCAutoString tag;
+      nsCAutoString id;
+      if (containerElm) {
+        containerElm->Tag()->ToUTF8String(tag);
+        nsIAtom* atomid = containerElm->GetID();
+        if (atomid)
+          atomid->ToUTF8String(id);
+      }
+
+      printf("\npending text node removal: container: %s@id='%s', index in container: %d\n\n",
+             tag.get(), id.get(), index);
+#endif
+
+      document->ContentRemoved(containerElm, textNode);
+      return PL_DHASH_NEXT;
+    }
+
+    // Update text of the accessible and fire text change events.
+#ifdef DEBUG_TEXTCHANGE
+      PRUint32 index = containerNode->IndexOf(textNode);
+
+      nsCAutoString tag;
+      nsCAutoString id;
+      if (containerElm) {
+        containerElm->Tag()->ToUTF8String(tag);
+        nsIAtom* atomid = containerElm->GetID();
+        if (atomid)
+          atomid->ToUTF8String(id);
+      }
+
+      printf("\ntext may be changed: container: %s@id='%s', index in container: %d, old text '%s', new text: '%s'\n\n",
+             tag.get(), id.get(), index,
+             NS_ConvertUTF16toUTF8(textAcc->AsTextLeaf()->Text()).get(),
+             NS_ConvertUTF16toUTF8(text).get());
+#endif
+
+    TextUpdater::Run(document, textAcc->AsTextLeaf(), text);
+    return PL_DHASH_NEXT;
+  }
+
+  // Append an accessible if rendered text is not empty.
+  if (!text.IsEmpty()) {
+#ifdef DEBUG_NOTIFICATIONS
+      PRUint32 index = containerNode->IndexOf(textNode);
+
+      nsCAutoString tag;
+      nsCAutoString id;
+      if (containerElm) {
+        containerElm->Tag()->ToUTF8String(tag);
+        nsIAtom* atomid = containerElm->GetID();
+        if (atomid)
+          atomid->ToUTF8String(id);
+      }
+
+      printf("\npending text node insertion: container: %s@id='%s', index in container: %d\n\n",
+             tag.get(), id.get(), index);
+#endif
+
+    nsAccessible* container = document->GetAccessibleOrContainer(containerNode);
+    nsTArray<nsCOMPtr<nsIContent> > insertedContents;
+    insertedContents.AppendElement(textNode);
+    document->ProcessContentInserted(container, &insertedContents);
+  }
+
+  return PL_DHASH_NEXT;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// NotificationController: content inserted notification
+
+NotificationController::ContentInsertion::
+  ContentInsertion(nsDocAccessible* aDocument, nsAccessible* aContainer,
+                   nsIContent* aStartChildNode, nsIContent* aEndChildNode) :
+  mDocument(aDocument), mContainer(aContainer)
+{
+  nsIContent* node = aStartChildNode;
+  while (node != aEndChildNode) {
+    mInsertedContent.AppendElement(node);
+    node = node->GetNextSibling();
+  }
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(NotificationController::ContentInsertion)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(NotificationController::ContentInsertion)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContainer)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(NotificationController::ContentInsertion)
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mContainer");
+  cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mContainer.get()));
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(NotificationController::ContentInsertion,
+                                     AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(NotificationController::ContentInsertion,
+                                       Release)
+
+void
+NotificationController::ContentInsertion::Process()
+{
+#ifdef DEBUG_NOTIFICATIONS
+  nsIContent* firstChildNode = mInsertedContent[0];
+
+  nsCAutoString tag;
+  firstChildNode->Tag()->ToUTF8String(tag);
+
+  nsIAtom* atomid = firstChildNode->GetID();
+  nsCAutoString id;
+  if (atomid)
+    atomid->ToUTF8String(id);
+
+  nsCAutoString ctag;
+  nsCAutoString cid;
+  nsIAtom* catomid = nsnull;
+  if (mContainer->IsContent()) {
+    mContainer->GetContent()->Tag()->ToUTF8String(ctag);
+    catomid = mContainer->GetContent()->GetID();
+    if (catomid)
+      catomid->ToUTF8String(cid);
+  }
+
+  printf("\npending content insertion: %s@id='%s', container: %s@id='%s', inserted content amount: %d\n\n",
+         tag.get(), id.get(), ctag.get(), cid.get(), mInsertedContent.Length());
+#endif
+
+  mDocument->ProcessContentInserted(mContainer, &mInsertedContent);
+
+  mDocument = nsnull;
+  mContainer = nsnull;
+  mInsertedContent.Clear();
+}
+
copy from accessible/src/base/nsEventShell.h
copy to accessible/src/base/NotificationController.h
--- a/accessible/src/base/nsEventShell.h
+++ b/accessible/src/base/NotificationController.h
@@ -10,17 +10,17 @@
  * 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 Corporation.
+ * Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2010
  * 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"),
@@ -31,102 +31,216 @@
  * 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 _nsEventShell_H_
-#define _nsEventShell_H_
+#ifndef NotificationController_h_
+#define NotificationController_h_
 
 #include "AccEvent.h"
+#include "nsCycleCollectionParticipant.h"
 
-#include "a11yGeneric.h"
+class nsAccessible;
+class nsDocAccessible;
+class nsIContent;
 
-#include "nsAutoPtr.h"
+// Uncomment to log notifications processing.
+//#define DEBUG_NOTIFICATIONS
 
-#include "nsRefreshDriver.h"
-
-class nsIPersistentProperties;
+#ifdef DEBUG_NOTIFICATIONS
+#define DEBUG_CONTENTMUTATION
+#define DEBUG_TEXTCHANGE
+#endif
 
 /**
- * Used for everything about events.
+ * Notification interface.
  */
-class nsEventShell
+class Notification
 {
 public:
+  virtual ~Notification() { };
+
+  NS_INLINE_DECL_REFCOUNTING(Notification)
 
   /**
-   * Fire the accessible event.
-   */
-  static void FireEvent(AccEvent* aEvent);
-
-  /**
-   * Fire accessible event of the given type for the given accessible.
-   *
-   * @param  aEventType   [in] the event type
-   * @param  aAccessible  [in] the event target
+   * Process notification.
    */
-  static void FireEvent(PRUint32 aEventType, nsAccessible *aAccessible,
-                        EIsFromUserInput aIsFromUserInput = eAutoDetect);
+  virtual void Process() = 0;
 
-  /**
-   * Append 'event-from-input' object attribute if the accessible event has
-   * been fired just now for the given node.
-   *
-   * @param  aNode        [in] the DOM node
-   * @param  aAttributes  [in, out] the attributes
-   */
-  static void GetEventAttributes(nsINode *aNode,
-                                 nsIPersistentProperties *aAttributes);
+protected:
+  Notification() { }
 
 private:
-  static nsCOMPtr<nsINode> sEventTargetNode;
-  static PRBool sEventFromUserInput;
+  Notification(const Notification&);
+  Notification& operator = (const Notification&);
 };
 
 
 /**
- * Event queue.
+ * Template class for generic notification.
+ *
+ * @note  Instance is kept as a weak ref, the caller must guarantee it exists
+ *        longer than the document accessible owning the notification controller
+ *        that this notification is processed by.
  */
-class nsAccEventQueue : public nsISupports,
-                        public nsARefreshObserver
+template<class Class, class Arg>
+class TNotification : public Notification
 {
 public:
-  nsAccEventQueue(nsDocAccessible *aDocument);
-  ~nsAccEventQueue();
+  typedef void (Class::*Callback)(Arg*);
+
+  TNotification(Class* aInstance, Callback aCallback, Arg* aArg) :
+    mInstance(aInstance), mCallback(aCallback), mArg(aArg) { }
+  virtual ~TNotification() { mInstance = nsnull; }
+
+  virtual void Process()
+  {
+    (mInstance->*mCallback)(mArg);
+
+    mInstance = nsnull;
+    mCallback = nsnull;
+    mArg = nsnull;
+  }
+
+private:
+  TNotification(const TNotification&);
+  TNotification& operator = (const TNotification&);
 
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS(nsAccEventQueue)
+  Class* mInstance;
+  Callback mCallback;
+  nsCOMPtr<Arg> mArg;
+};
+
+/**
+ * Used to process notifications from core for the document accessible.
+ */
+class NotificationController : public nsARefreshObserver
+{
+public:
+  NotificationController(nsDocAccessible* aDocument, nsIPresShell* aPresShell);
+  virtual ~NotificationController();
+
+  NS_IMETHOD_(nsrefcnt) AddRef(void);
+  NS_IMETHOD_(nsrefcnt) Release(void);
+
+  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(NotificationController)
 
   /**
-   * Push event to queue, coalesce it if necessary. Start pending processing.
+   * Return true when tree is constructed.
    */
-  void Push(AccEvent* aEvent);
+  inline bool IsTreeConstructed()
+  {
+    return mTreeConstructedState == eTreeConstructed;
+  }
 
   /**
-   * Shutdown the queue.
+   * Shutdown the notification controller.
    */
   void Shutdown();
 
-private:
+  /**
+   * Put an accessible event into the queue to process it later.
+   */
+  void QueueEvent(AccEvent* aEvent);
+
+  /**
+   * Schedule binding the child document to the tree of this document.
+   */
+  void ScheduleChildDocBinding(nsDocAccessible* aDocument);
+
+  /**
+   * Schedule the accessible tree update because of rendered text changes.
+   */
+  inline void ScheduleTextUpdate(nsIContent* aTextNode)
+  {
+    // Ignore the notification if initial tree construction hasn't been done yet.
+    if (mTreeConstructedState != eTreeConstructionPending &&
+        mTextHash.PutEntry(aTextNode)) {
+      ScheduleProcessing();
+    }
+  }
+
+  /**
+   * Pend accessible tree update for content insertion.
+   */
+  void ScheduleContentInsertion(nsAccessible* aContainer,
+                                nsIContent* aStartChildNode,
+                                nsIContent* aEndChildNode);
 
   /**
-   * Start pending events processing asynchronously.
+   * Process the generic notification synchronously if there are no pending
+   * layout changes and no notifications are pending or being processed right
+   * now. Otherwise, queue it up to process asynchronously.
+   *
+   * @note  The caller must guarantee that the given instance still exists when
+   *        the notification is processed.
+   */
+  template<class Class, class Arg>
+  inline void HandleNotification(Class* aInstance,
+                                 typename TNotification<Class, Arg>::Callback aMethod,
+                                 Arg* aArg)
+  {
+    if (!IsUpdatePending()) {
+#ifdef DEBUG_NOTIFICATIONS
+      printf("\nsync notification processing\n");
+#endif
+      (aInstance->*aMethod)(aArg);
+      return;
+    }
+
+    nsRefPtr<Notification> notification =
+      new TNotification<Class, Arg>(aInstance, aMethod, aArg);
+    if (notification && mNotifications.AppendElement(notification))
+      ScheduleProcessing();
+  }
+
+  /**
+   * Schedule the generic notification to process asynchronously.
+   *
+   * @note  The caller must guarantee that the given instance still exists when
+   *        the notification is processed.
    */
-  void PrepareFlush();
-  
+  template<class Class, class Arg>
+  inline void ScheduleNotification(Class* aInstance,
+                                   typename TNotification<Class, Arg>::Callback aMethod,
+                                   Arg* aArg)
+  {
+    nsRefPtr<Notification> notification =
+      new TNotification<Class, Arg>(aInstance, aMethod, aArg);
+    if (notification && mNotifications.AppendElement(notification))
+      ScheduleProcessing();
+  }
+
+protected:
+  nsAutoRefCnt mRefCnt;
+  NS_DECL_OWNINGTHREAD
+
   /**
-   * Process pending events. It calls nsDocAccessible::ProcessPendingEvent()
-   * where the real event processing is happen.
+   * Start to observe refresh to make notifications and events processing after
+   * layout.
+   */
+  void ScheduleProcessing();
+
+  /**
+   * Return true if the accessible tree state update is pending.
    */
+  bool IsUpdatePending();
+
+private:
+  NotificationController(const NotificationController&);
+  NotificationController& operator = (const NotificationController&);
+
+  // nsARefreshObserver
   virtual void WillRefresh(mozilla::TimeStamp aTime);
 
+  // Event queue processing
   /**
    * Coalesce redundant events from the queue.
    */
   void CoalesceEvents();
 
   /**
    * Apply aEventRule to same type event that from sibling nodes of aDOMNode.
    * @param aEventsToFire    array of pending events
@@ -158,27 +272,133 @@ private:
 
   /**
    * Create text change event caused by hide or show event. When a node is
    * hidden/removed or shown/appended, the text in an ancestor hyper text will
    * lose or get new characters.
    */
   void CreateTextChangeEventFor(AccMutationEvent* aEvent);
 
+private:
   /**
-   * Indicates whether we're waiting on a refresh notification from our
-   * presshell to flush events
+   * Indicates whether we're waiting on an event queue processing from our
+   * notification controller to flush events.
    */
-  PRBool mObservingRefresh;
+  enum eObservingState {
+    eNotObservingRefresh,
+    eRefreshObserving,
+    eRefreshProcessingForUpdate
+  };
+  eObservingState mObservingState;
 
   /**
    * The document accessible reference owning this queue.
    */
   nsRefPtr<nsDocAccessible> mDocument;
 
   /**
-   * Pending events array.  Don't make this an nsAutoTArray; we use
+   * The presshell of the document accessible.
+   */
+  nsIPresShell* mPresShell;
+
+  /**
+   * Indicate whether initial construction of the document's accessible tree
+   * performed or pending. When the document accessible is created then
+   * we construct its initial accessible tree.
+   */
+  enum eTreeConstructedState {
+    eTreeConstructed,
+    eTreeConstructionPending
+  };
+  eTreeConstructedState mTreeConstructedState;
+
+  /**
+   * Child documents that needs to be bound to the tree.
+   */
+  nsTArray<nsRefPtr<nsDocAccessible> > mHangingChildDocuments;
+
+  /**
+   * Storage for content inserted notification information.
+   */
+  class ContentInsertion
+  {
+  public:
+    ContentInsertion(nsDocAccessible* aDocument, nsAccessible* aContainer,
+                     nsIContent* aStartChildNode, nsIContent* aEndChildNode);
+    virtual ~ContentInsertion() { mDocument = nsnull; }
+
+    NS_INLINE_DECL_REFCOUNTING(ContentInsertion)
+    NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ContentInsertion)
+
+    void Process();
+
+  private:
+    ContentInsertion();
+    ContentInsertion(const ContentInsertion&);
+    ContentInsertion& operator = (const ContentInsertion&);
+
+    // The document used to process content insertion, matched to document of
+    // the notification controller that this notification belongs to, therefore
+    // it's ok to keep it as weak ref.
+    nsDocAccessible* mDocument;
+
+    // The container accessible that content insertion occurs within.
+    nsRefPtr<nsAccessible> mContainer;
+
+    // Array of inserted contents.
+    nsTArray<nsCOMPtr<nsIContent> > mInsertedContent;
+  };
+
+  /**
+   * A pending accessible tree update notifications for content insertions.
+   * Don't make this an nsAutoTArray; we use SwapElements() on it.
+   */
+  nsTArray<nsRefPtr<ContentInsertion> > mContentInsertions;
+
+  template<class T>
+  class nsCOMPtrHashKey : public PLDHashEntryHdr
+  {
+  public:
+    typedef T* KeyType;
+    typedef const T* KeyTypePointer;
+
+    nsCOMPtrHashKey(const T* aKey) : mKey(const_cast<T*>(aKey)) {}
+    nsCOMPtrHashKey(const nsPtrHashKey<T> &aToCopy) : mKey(aToCopy.mKey) {}
+    ~nsCOMPtrHashKey() { }
+
+    KeyType GetKey() const { return mKey; }
+    PRBool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; }
+
+    static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
+    static PLDHashNumber HashKey(KeyTypePointer aKey)
+      { return NS_PTR_TO_INT32(aKey) >> 2; }
+
+    enum { ALLOW_MEMMOVE = PR_TRUE };
+
+   protected:
+     nsCOMPtr<T> mKey;
+  };
+
+  /**
+   * A pending accessible tree update notifications for rendered text changes.
+   */
+  nsTHashtable<nsCOMPtrHashKey<nsIContent> > mTextHash;
+
+  /**
+   * Update the accessible tree for pending rendered text change notifications.
+   */
+  static PLDHashOperator TextEnumerator(nsCOMPtrHashKey<nsIContent>* aEntry,
+                                        void* aUserArg);
+
+  /**
+   * Other notifications like DOM events. Don't make this an nsAutoTArray; we
+   * use SwapElements() on it.
+   */
+  nsTArray<nsRefPtr<Notification> > mNotifications;
+
+  /**
+   * Pending events array. Don't make this an nsAutoTArray; we use
    * SwapElements() on it.
    */
   nsTArray<nsRefPtr<AccEvent> > mEvents;
 };
 
 #endif
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/TextUpdater.cpp
@@ -0,0 +1,263 @@
+/* -*- 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) 2011
+ * 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 "TextUpdater.h"
+
+#include "nsDocAccessible.h"
+#include "nsTextAccessible.h"
+
+void
+TextUpdater::Run(nsDocAccessible* aDocument, nsTextAccessible* aTextLeaf,
+                 const nsAString& aNewText)
+{
+  NS_ASSERTION(aTextLeaf, "No text leaf accessible?");
+
+  const nsString& oldText = aTextLeaf->Text();
+  PRUint32 oldLen = oldText.Length(), newLen = aNewText.Length();
+  PRUint32 minLen = NS_MIN(oldLen, newLen);
+
+  // Skip coinciding begin substrings.
+  PRUint32 skipStart = 0;
+  for (; skipStart < minLen; skipStart++) {
+    if (aNewText[skipStart] != oldText[skipStart])
+      break;
+  }
+
+  // The text was changed. Do update.
+  if (skipStart != minLen || oldLen != newLen) {
+    TextUpdater updater(aDocument, aTextLeaf);
+    updater.DoUpdate(aNewText, oldText, skipStart);
+  }
+}
+
+void
+TextUpdater::DoUpdate(const nsAString& aNewText, const nsAString& aOldText,
+                      PRUint32 aSkipStart)
+{
+  nsAccessible* parent = mTextLeaf->GetParent();
+  NS_ASSERTION(parent, "No parent for text leaf!");
+
+  mHyperText = parent->AsHyperText();
+  if (!mHyperText) {
+    NS_ERROR("Text leaf parent is not hypertext!");
+    return;
+  }
+
+  // Get the text leaf accessible offset and invalidate cached offsets after it.
+  mTextOffset = mHyperText->GetChildOffset(mTextLeaf, PR_TRUE);
+  NS_ASSERTION(mTextOffset != -1,
+               "Text leaf hasn't offset within hyper text!");
+
+  PRUint32 oldLen = aOldText.Length(), newLen = aNewText.Length();
+  PRUint32 minLen = NS_MIN(oldLen, newLen);
+
+  // Text was appended or removed to/from the end.
+  if (aSkipStart == minLen) {
+    // If text has been appended to the end, fire text inserted event.
+    if (oldLen < newLen) {
+      UpdateTextNFireEvent(aNewText, Substring(aNewText, oldLen),
+                           oldLen, PR_TRUE);
+      return;
+    }
+
+    // Text has been removed from the end, fire text removed event.
+    UpdateTextNFireEvent(aNewText, Substring(aOldText, newLen),
+                         newLen, PR_FALSE);
+    return;
+  }
+
+  // Trim coinciding substrings from the end.
+  PRUint32 skipEnd = 0;
+  while (minLen - skipEnd > aSkipStart &&
+         aNewText[newLen - skipEnd - 1] == aOldText[oldLen - skipEnd - 1]) {
+    skipEnd++;
+  }
+
+  // Text was appended or removed to/from the start.
+  if (skipEnd == minLen) {
+    // If text has been appended to the start, fire text inserted event.
+    if (oldLen < newLen) {
+      UpdateTextNFireEvent(aNewText, Substring(aNewText, 0, newLen - skipEnd),
+                           0, PR_TRUE);
+      return;
+    }
+
+    // Text has been removed from the start, fire text removed event.
+    UpdateTextNFireEvent(aNewText, Substring(aOldText, 0, oldLen - skipEnd),
+                         0, PR_FALSE);
+    return;
+  }
+
+  // Find the difference between strings and fire events.
+  // Note: we can skip initial and final coinciding characters since they don't
+  // affect the Levenshtein distance.
+
+  PRInt32 strLen1 = oldLen - aSkipStart - skipEnd;
+  PRInt32 strLen2 = newLen - aSkipStart - skipEnd;
+
+  const nsAString& str1 = Substring(aOldText, aSkipStart, strLen1);
+  const nsAString& str2 = Substring(aNewText, aSkipStart, strLen2);
+
+  // Increase offset of the text leaf on skipped characters amount.
+  mTextOffset += aSkipStart;
+
+  // Compute the flat structured matrix need to compute the difference.
+  PRUint32 len1 = strLen1 + 1, len2 = strLen2 + 1;
+  PRUint32* entries = new PRUint32[len1 * len2];
+
+  for (PRUint32 colIdx = 0; colIdx < len1; colIdx++)
+    entries[colIdx] = colIdx;
+
+  PRUint32* row = entries;
+  for (PRUint32 rowIdx = 1; rowIdx < len2; rowIdx++) {
+    PRUint32* prevRow = row;
+    row += len1;
+    row[0] = rowIdx;
+    for (PRUint32 colIdx = 1; colIdx < len1; colIdx++) {
+      if (str1[colIdx - 1] != str2[rowIdx - 1]) {
+        PRUint32 left = row[colIdx - 1];
+        PRUint32 up = prevRow[colIdx];
+        PRUint32 upleft = prevRow[colIdx - 1];
+        row[colIdx] = NS_MIN(upleft, NS_MIN(left, up)) + 1;
+      } else {
+        row[colIdx] = prevRow[colIdx - 1];
+      }
+    }
+  }
+
+  // Compute events based on the difference.
+  nsTArray<nsRefPtr<AccEvent> > events;
+  ComputeTextChangeEvents(str1, str2, entries, events);
+
+  delete [] entries;
+
+  // Fire events.
+  for (PRInt32 idx = events.Length() - 1; idx >= 0; idx--)
+    mDocument->FireDelayedAccessibleEvent(events[idx]);
+
+  if (mHyperText->Role() == nsIAccessibleRole::ROLE_ENTRY) {
+    nsRefPtr<AccEvent> valueChangeEvent =
+      new AccEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, mHyperText,
+                   eAutoDetect, AccEvent::eRemoveDupes);
+    mDocument->FireDelayedAccessibleEvent(valueChangeEvent);
+  }
+
+  // Update the text.
+  mTextLeaf->SetText(aNewText);
+}
+
+void
+TextUpdater::ComputeTextChangeEvents(const nsAString& aStr1,
+                                     const nsAString& aStr2,
+                                     PRUint32* aEntries,
+                                     nsTArray<nsRefPtr<AccEvent> >& aEvents)
+{
+  PRInt32 colIdx = aStr1.Length(), rowIdx = aStr2.Length();
+
+  // Point at which strings last matched.
+  PRInt32 colEnd = colIdx;
+  PRInt32 rowEnd = rowIdx;
+
+  PRInt32 colLen = colEnd + 1;
+  PRUint32* row = aEntries + rowIdx * colLen;
+  PRInt32 dist = row[colIdx]; // current Levenshtein distance
+  while (rowIdx && colIdx) { // stop when we can't move diagonally
+    if (aStr1[colIdx - 1] == aStr2[rowIdx - 1]) { // match
+      if (rowIdx < rowEnd) { // deal with any pending insertion
+        FireInsertEvent(Substring(aStr2, rowIdx, rowEnd - rowIdx),
+                        rowIdx, aEvents);
+      }
+      if (colIdx < colEnd) { // deal with any pending deletion
+        FireDeleteEvent(Substring(aStr1, colIdx, colEnd - colIdx),
+                        rowIdx, aEvents);
+      }
+
+      colEnd = --colIdx; // reset the match point
+      rowEnd = --rowIdx;
+      row -= colLen;
+      continue;
+    }
+    --dist;
+    if (dist == row[colIdx - 1 - colLen]) { // substitution
+      --colIdx;
+      --rowIdx;
+      row -= colLen;
+      continue;
+    }
+    if (dist == row[colIdx - colLen]) { // insertion
+      --rowIdx;
+      row -= colLen;
+      continue;
+    }
+    if (dist == row[colIdx - 1]) { // deletion
+      --colIdx;
+      continue;
+    }
+    NS_NOTREACHED("huh?");
+    return;
+  }
+
+  if (rowEnd)
+    FireInsertEvent(Substring(aStr2, 0, rowEnd), 0, aEvents);
+  if (colEnd)
+    FireDeleteEvent(Substring(aStr1, 0, colEnd), 0, aEvents);
+}
+
+void
+TextUpdater::UpdateTextNFireEvent(const nsAString& aNewText,
+                                  const nsAString& aChangeText,
+                                  PRUint32 aAddlOffset,
+                                  PRBool aIsInserted)
+{
+  // Fire text change event.
+  nsRefPtr<AccEvent> textChangeEvent =
+    new AccTextChangeEvent(mHyperText, mTextOffset + aAddlOffset, aChangeText,
+                           aIsInserted);
+  mDocument->FireDelayedAccessibleEvent(textChangeEvent);
+
+  // Fire value change event.
+  if (mHyperText->Role() == nsIAccessibleRole::ROLE_ENTRY) {
+    nsRefPtr<AccEvent> valueChangeEvent =
+      new AccEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, mHyperText,
+                   eAutoDetect, AccEvent::eRemoveDupes);
+    mDocument->FireDelayedAccessibleEvent(valueChangeEvent);
+  }
+
+  // Update the text.
+  mTextLeaf->SetText(aNewText);
+}
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/TextUpdater.h
@@ -0,0 +1,124 @@
+/* -*- 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) 2011
+ * 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 TextUpdater_h_
+#define TextUpdater_h_
+
+#include "AccEvent.h"
+#include "nsHyperTextAccessible.h"
+
+/**
+ * Used to find a difference between old and new text and fire text change
+ * events.
+ */
+class TextUpdater
+{
+public:
+  /**
+   * Start text of the text leaf update.
+   */
+  static void Run(nsDocAccessible* aDocument, nsTextAccessible* aTextLeaf,
+                  const nsAString& aNewText);
+
+private:
+  TextUpdater(nsDocAccessible* aDocument, nsTextAccessible* aTextLeaf) :
+    mDocument(aDocument), mTextLeaf(aTextLeaf), mHyperText(nsnull),
+    mTextOffset(-1) { }
+
+  ~TextUpdater()
+    { mDocument = nsnull; mTextLeaf = nsnull; mHyperText = nsnull; }
+
+  /**
+   * Update text of the text leaf accessible, fire text change and value change
+   * (if applicable) events for its container hypertext accessible.
+   */
+  void DoUpdate(const nsAString& aNewText, const nsAString& aOldText,
+                PRUint32 aSkipStart);
+
+private:
+  TextUpdater();
+  TextUpdater(const TextUpdater&);
+  TextUpdater& operator=(const TextUpdater&);
+
+  /**
+   * Fire text change events based on difference between strings.
+   */
+  void ComputeTextChangeEvents(const nsAString& aStr1,
+                               const nsAString& aStr2,
+                               PRUint32* aEntries,
+                               nsTArray<nsRefPtr<AccEvent> >& aEvents);
+
+  /**
+   * Helper to create text change events for inserted text.
+   */
+  inline void FireInsertEvent(const nsAString& aText, PRUint32 aAddlOffset,
+                              nsTArray<nsRefPtr<AccEvent> >& aEvents)
+  {
+    nsRefPtr<AccEvent> event =
+      new AccTextChangeEvent(mHyperText, mTextOffset + aAddlOffset,
+                             aText, PR_TRUE);
+    aEvents.AppendElement(event);
+  }
+
+  /**
+   * Helper to create text change events for removed text.
+   */
+  inline void FireDeleteEvent(const nsAString& aText, PRUint32 aAddlOffset,
+                              nsTArray<nsRefPtr<AccEvent> >& aEvents)
+  {
+    nsRefPtr<AccEvent> event =
+      new AccTextChangeEvent(mHyperText, mTextOffset + aAddlOffset,
+                             aText, PR_FALSE);
+    aEvents.AppendElement(event);
+  }
+
+  /**
+   * Update the text and fire text change/value change events.
+   */
+  void UpdateTextNFireEvent(const nsAString& aNewText,
+                            const nsAString& aChangeText, PRUint32 aAddlOffset,
+                            PRBool aIsInserted);
+
+private:
+  nsDocAccessible* mDocument;
+  nsTextAccessible* mTextLeaf;
+  nsHyperTextAccessible* mHyperText;
+  PRInt32 mTextOffset;
+};
+
+#endif
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -711,16 +711,17 @@ nsAttributeCharacteristics nsARIAMap::gW
   {&nsAccessibilityAtoms::aria_controls,          ATTR_BYPASSOBJ                 },
   {&nsAccessibilityAtoms::aria_describedby,       ATTR_BYPASSOBJ                 },
   {&nsAccessibilityAtoms::aria_disabled,          ATTR_BYPASSOBJ | ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_dropeffect,                         ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_expanded,          ATTR_BYPASSOBJ | ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_flowto,            ATTR_BYPASSOBJ                 },  
   {&nsAccessibilityAtoms::aria_grabbed,                            ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_haspopup,          ATTR_BYPASSOBJ | ATTR_VALTOKEN },
+  {&nsAccessibilityAtoms::aria_hidden,                             ATTR_VALTOKEN },/* always expose obj attr */
   {&nsAccessibilityAtoms::aria_invalid,           ATTR_BYPASSOBJ | ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_label,             ATTR_BYPASSOBJ                 },
   {&nsAccessibilityAtoms::aria_labelledby,        ATTR_BYPASSOBJ                 },
   {&nsAccessibilityAtoms::aria_level,             ATTR_BYPASSOBJ                 }, /* handled via groupPosition */
   {&nsAccessibilityAtoms::aria_live,                               ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_multiline,         ATTR_BYPASSOBJ | ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_multiselectable,   ATTR_BYPASSOBJ | ATTR_VALTOKEN },
   {&nsAccessibilityAtoms::aria_owns,              ATTR_BYPASSOBJ                 },
--- a/accessible/src/base/nsAccDocManager.cpp
+++ b/accessible/src/base/nsAccDocManager.cpp
@@ -327,17 +327,16 @@ void
 nsAccDocManager::HandleDOMDocumentLoad(nsIDocument *aDocument,
                                        PRUint32 aLoadEventType)
 {
   // Document accessible can be created before we were notified the DOM document
   // was loaded completely. However if it's not created yet then create it.
   nsDocAccessible* docAcc = mDocAccessibleCache.GetWeak(aDocument);
   if (!docAcc) {
     docAcc = CreateDocOrRootAccessible(aDocument);
-    NS_ASSERTION(docAcc, "Can't create document accessible!");
     if (!docAcc)
       return;
   }
 
   // Mark the document as loaded to drop off the busy state flag on it.
   docAcc->MarkAsLoaded();
 
   // Do not fire document complete/stop events for root chrome document
@@ -424,68 +423,68 @@ nsAccDocManager::CreateDocOrRootAccessib
   // Do not create document accessible until role content is loaded, otherwise
   // we get accessible document with wrong role.
   nsIContent *rootElm = nsCoreUtils::GetRoleContent(aDocument);
   if (!rootElm)
     return nsnull;
 
   PRBool isRootDoc = nsCoreUtils::IsRootDocument(aDocument);
 
-  // Ensure the document container node is accessible, otherwise do not create
-  // document accessible.
-  nsAccessible *outerDocAcc = nsnull;
-  if (isRootDoc) {
-    outerDocAcc = nsAccessNode::GetApplicationAccessible();
-
-  } else {
-    nsIDocument* parentDoc = aDocument->GetParentDocument();
-    if (!parentDoc)
-      return nsnull;
-
-    nsIContent* ownerContent = parentDoc->FindContentForSubDocument(aDocument);
-    if (!ownerContent)
-      return nsnull;
-
+  nsDocAccessible* parentDocAcc = nsnull;
+  if (!isRootDoc) {
     // XXXaaronl: ideally we would traverse the presshell chain. Since there's
     // no easy way to do that, we cheat and use the document hierarchy.
     // GetAccessible() is bad because it doesn't support our concept of multiple
     // presshells per doc. It should be changed to use
     // GetAccessibleInWeakShell().
-    outerDocAcc = GetAccService()->GetAccessible(ownerContent);
+    parentDocAcc = GetDocAccessible(aDocument->GetParentDocument());
+    NS_ASSERTION(parentDocAcc,
+                 "Can't create an accessible for the document!");
+    if (!parentDocAcc)
+      return nsnull;
   }
 
-  if (!outerDocAcc)
-    return nsnull;
-
   // We only create root accessibles for the true root, otherwise create a
   // doc accessible.
   nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(presShell));
   nsRefPtr<nsDocAccessible> docAcc = isRootDoc ?
     new nsRootAccessibleWrap(aDocument, rootElm, weakShell) :
     new nsDocAccessibleWrap(aDocument, rootElm, weakShell);
 
   // Cache the document accessible into document cache.
   if (!docAcc || !mDocAccessibleCache.Put(aDocument, docAcc))
     return nsnull;
 
-  // Bind the document accessible into tree.
-  if (!outerDocAcc->AppendChild(docAcc)) {
-    mDocAccessibleCache.Remove(aDocument);
-    return nsnull;
-  }
-
-  // Initialize the document accessible. Note, Init() should be called after
-  // the document accessible is bound to the tree.
+  // Initialize the document accessible.
   if (!docAcc->Init()) {
     docAcc->Shutdown();
-    mDocAccessibleCache.Remove(aDocument);
     return nsnull;
   }
   docAcc->SetRoleMapEntry(nsAccUtils::GetRoleMapEntry(aDocument));
 
+  // Bind the document to the tree.
+  if (isRootDoc) {
+    nsAccessible* appAcc = nsAccessNode::GetApplicationAccessible();
+    if (!appAcc->AppendChild(docAcc)) {
+      docAcc->Shutdown();
+      return nsnull;
+    }
+
+    // Fire reorder event to notify new accessible document has been attached to
+    // the tree.
+    nsRefPtr<AccEvent> reorderEvent =
+      new AccEvent(nsIAccessibleEvent::EVENT_REORDER, appAcc, eAutoDetect,
+                   AccEvent::eCoalesceFromSameSubtree);
+    if (reorderEvent)
+      docAcc->FireDelayedAccessibleEvent(reorderEvent);
+
+  } else {
+    parentDocAcc->BindChildDocument(docAcc);
+  }
+
   NS_LOG_ACCDOCCREATE("document creation finished", aDocument)
 
   AddListeners(aDocument, isRootDoc);
   return docAcc;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccDocManager static
@@ -518,15 +517,15 @@ nsAccDocManager::SearchAccessibleInDocCa
                                             void* aUserArg)
 {
   NS_ASSERTION(aDocAccessible,
                "No doc accessible for the object in doc accessible cache!");
 
   if (aDocAccessible) {
     nsSearchAccessibleInCacheArg* arg =
       static_cast<nsSearchAccessibleInCacheArg*>(aUserArg);
-    arg->mAccessible = aDocAccessible->GetCachedAccessible(arg->mNode);
+    arg->mAccessible = aDocAccessible->GetAccessible(arg->mNode);
     if (arg->mAccessible)
       return PL_DHASH_STOP;
   }
 
   return PL_DHASH_NEXT;
 }
--- a/accessible/src/base/nsAccDocManager.h
+++ b/accessible/src/base/nsAccDocManager.h
@@ -33,24 +33,24 @@
  * 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 nsAccDocManager_h_
 #define nsAccDocManager_h_
 
-#include "nsAccessible.h"
-
 #include "nsIDocument.h"
 #include "nsIDOMEventListener.h"
+#include "nsRefPtrHashtable.h"
 #include "nsIWebProgress.h"
 #include "nsIWebProgressListener.h"
 #include "nsWeakReference.h"
 
+class nsAccessible;
 class nsDocAccessible;
 
 //#define DEBUG_ACCDOCMGR
 
 /**
  * Manage the document accessible life cycle.
  */
 class nsAccDocManager : public nsIWebProgressListener,
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -39,22 +39,22 @@
 #include "nsCoreUtils.h"
 #include "nsAccUtils.h"
 
 #include "nsIAccessibleStates.h"
 #include "nsIAccessibleTypes.h"
 
 #include "nsAccessibilityService.h"
 #include "nsAccessibilityAtoms.h"
-#include "nsAccessible.h"
 #include "nsAccTreeWalker.h"
 #include "nsARIAMap.h"
 #include "nsDocAccessible.h"
 #include "nsHyperTextAccessible.h"
 #include "nsHTMLTableAccessible.h"
+#include "nsTextAccessible.h"
 #include "nsXULTreeGridAccessible.h"
 
 #include "nsIDOMXULContainerElement.h"
 #include "nsIDOMXULSelectCntrlEl.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsWhitespaceTokenizer.h"
 #include "nsComponentManagerUtils.h"
 
@@ -399,17 +399,17 @@ nsAccUtils::GetMultiSelectableContainer(
 PRBool
 nsAccUtils::IsARIASelected(nsAccessible *aAccessible)
 {
   return aAccessible->GetContent()->
     AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::aria_selected,
                 nsAccessibilityAtoms::_true, eCaseMatters);
 }
 
-already_AddRefed<nsHyperTextAccessible>
+nsHyperTextAccessible*
 nsAccUtils::GetTextAccessibleFromSelection(nsISelection* aSelection)
 {
   // Get accessible from selection's focus DOM point (the DOM point where
   // selection is ended).
 
   nsCOMPtr<nsIDOMNode> focusDOMNode;
   aSelection->GetFocusNode(getter_AddRefs(focusDOMNode));
   if (!focusDOMNode)
@@ -427,18 +427,17 @@ nsAccUtils::GetTextAccessibleFromSelecti
   nsAccessible* accessible =
     GetAccService()->GetAccessibleOrContainer(resultNode, weakShell);
   if (!accessible) {
     NS_NOTREACHED("No nsIAccessibleText for selection change event!");
     return nsnull;
   }
 
   do {
-    nsHyperTextAccessible* textAcc = nsnull;
-    CallQueryInterface(accessible, &textAcc);
+    nsHyperTextAccessible* textAcc = accessible->AsHyperText();
     if (textAcc)
       return textAcc;
 
   } while (accessible = accessible->GetParent());
 
   NS_NOTREACHED("We must reach document accessible implementing nsIAccessibleText!");
   return nsnull;
 }
@@ -634,40 +633,26 @@ nsAccUtils::IsTextInterfaceSupportCorrec
 #endif
 
 PRUint32
 nsAccUtils::TextLength(nsAccessible *aAccessible)
 {
   if (!IsText(aAccessible))
     return 1;
 
-  nsIFrame *frame = aAccessible->GetFrame();
-  if (frame && frame->GetType() == nsAccessibilityAtoms::textFrame) {
-    // Ensure that correct text length is calculated (with non-rendered
-    // whitespace chars not counted).
-    nsIContent *content = frame->GetContent();
-    if (content) {
-      PRUint32 length;
-      nsresult rv = nsHyperTextAccessible::
-        ContentToRenderedOffset(frame, content->TextLength(), &length);
-      if (NS_FAILED(rv)) {
-        NS_NOTREACHED("Failed to get rendered offset!");
-        return 0;
-      }
-
-      return length;
-    }
-  }
+  nsTextAccessible* textLeaf = aAccessible->AsTextLeaf();
+  if (textLeaf)
+    return textLeaf->Text().Length();
 
   // For list bullets (or anything other accessible which would compute its own
   // text. They don't have their own frame.
   // XXX In the future, list bullets may have frame and anon content, so 
   // we should be able to remove this at that point
   nsAutoString text;
-  aAccessible->AppendTextTo(text, 0, PR_UINT32_MAX); // Get all the text
+  aAccessible->AppendTextTo(text); // Get all the text
   return text.Length();
 }
 
 PRBool
 nsAccUtils::MustPrune(nsIAccessible *aAccessible)
 { 
   PRUint32 role = nsAccUtils::Role(aAccessible);
 
--- a/accessible/src/base/nsAccUtils.h
+++ b/accessible/src/base/nsAccUtils.h
@@ -220,17 +220,17 @@ public:
 
   /**
    * Return text accessible containing focus point of the given selection.
    * Used for normal and misspelling selection changes processing.
    *
    * @param aSelection  [in] the given selection
    * @return            text accessible
    */
-  static already_AddRefed<nsHyperTextAccessible>
+  static nsHyperTextAccessible*
     GetTextAccessibleFromSelection(nsISelection* aSelection);
 
   /**
    * Converts the given coordinates to coordinates relative screen.
    *
    * @param aX               [in] the given x coord
    * @param aY               [in] the given y coord
    * @param aCoordinateType  [in] specifies coordinates origin (refer to
--- a/accessible/src/base/nsAccessNode.h
+++ b/accessible/src/base/nsAccessNode.h
@@ -161,16 +161,21 @@ public:
 
   /**
    * Return node type information of DOM node associated with the accessible.
    */
   PRBool IsContent() const
   {
     return GetNode() && GetNode()->IsNodeOfType(nsINode::eCONTENT);
   }
+  bool IsElement() const
+  {
+    nsINode* node = GetNode();
+    return node && node->IsElement();
+  }
   PRBool IsDocument() const
   {
     return GetNode() && GetNode()->IsNodeOfType(nsINode::eDOCUMENT);
   }
 
   /**
    * Return the corresponding press shell for this accessible.
    */
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -249,16 +249,17 @@ ACCESSIBILITY_ATOM(aria_checked, "aria-c
 ACCESSIBILITY_ATOM(aria_controls, "aria-controls")
 ACCESSIBILITY_ATOM(aria_describedby, "aria-describedby")
 ACCESSIBILITY_ATOM(aria_disabled, "aria-disabled")
 ACCESSIBILITY_ATOM(aria_dropeffect, "aria-dropeffect")
 ACCESSIBILITY_ATOM(aria_expanded, "aria-expanded")
 ACCESSIBILITY_ATOM(aria_flowto, "aria-flowto")
 ACCESSIBILITY_ATOM(aria_grabbed, "aria-grabbed")
 ACCESSIBILITY_ATOM(aria_haspopup, "aria-haspopup")
+ACCESSIBILITY_ATOM(aria_hidden, "aria-hidden")
 ACCESSIBILITY_ATOM(aria_invalid, "aria-invalid")
 ACCESSIBILITY_ATOM(aria_label, "aria-label")
 ACCESSIBILITY_ATOM(aria_labelledby, "aria-labelledby")
 ACCESSIBILITY_ATOM(aria_level, "aria-level")
 ACCESSIBILITY_ATOM(aria_live, "aria-live")
 ACCESSIBILITY_ATOM(aria_multiline, "aria-multiline")
 ACCESSIBILITY_ATOM(aria_multiselectable, "aria-multiselectable")
 ACCESSIBILITY_ATOM(aria_orientation, "aria-orientation")
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -138,36 +138,24 @@ nsAccessibilityService::Observe(nsISuppo
   if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID))
     Shutdown();
 
   return NS_OK;
 }
 
 // nsIAccessibilityService
 void
-nsAccessibilityService::NotifyOfAnchorJumpTo(nsIContent *aTarget)
+nsAccessibilityService::NotifyOfAnchorJumpTo(nsIContent* aTargetNode)
 {
-  nsIDocument *document = aTarget->GetCurrentDoc();
-  if (!document)
-    return;
-
-  // If the jump target is not accessible then fire an event for nearest
-  // accessible in parent chain.
-  nsCOMPtr<nsIWeakReference> weakShell(nsCoreUtils::GetWeakShellFor(aTarget));
-  nsAccessible* targetAcc = GetAccessibleOrContainer(aTarget, weakShell);
-  if (!targetAcc)
-    return;
-
-  nsINode* targetNode = targetAcc->GetNode();
-
-  // XXX note in rare cases the node could go away before we flush the queue,
-  // for example if the node becomes inaccessible, or is removed from the DOM.
-  GetDocAccessible(document)->
-    FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_SCROLLING_START,
-                               targetNode);
+  nsIDocument* documentNode = aTargetNode->GetCurrentDoc();
+  if (documentNode) {
+    nsDocAccessible* document = GetDocAccessible(documentNode);
+    if (document)
+      document->HandleAnchorJump(aTargetNode);
+  }
 }
 
 // nsIAccessibilityService
 void
 nsAccessibilityService::FireAccessibleEvent(PRUint32 aEvent,
                                             nsAccessible* aTarget)
 {
   nsEventShell::FireEvent(aEvent, aTarget);
@@ -498,17 +486,17 @@ nsAccessibilityService::ContentRangeInse
 
   printf("\ncontent inserted: %s@id='%s', container: %s@id='%s', end node: %p\n\n",
          NS_ConvertUTF16toUTF8(tag).get(), id.get(),
          NS_ConvertUTF16toUTF8(ctag).get(), cid.get(), aEndChild);
 #endif
 
   nsDocAccessible* docAccessible = GetDocAccessible(aPresShell->GetDocument());
   if (docAccessible)
-    docAccessible->UpdateTree(aContainer, aStartChild, aEndChild, PR_TRUE);
+    docAccessible->ContentInserted(aContainer, aStartChild, aEndChild);
 }
 
 void
 nsAccessibilityService::ContentRemoved(nsIPresShell* aPresShell,
                                        nsIContent* aContainer,
                                        nsIContent* aChild)
 {
 #ifdef DEBUG_CONTENTMUTATION
@@ -532,18 +520,26 @@ nsAccessibilityService::ContentRemoved(n
 
   printf("\ncontent removed: %s@id='%s', container: %s@id='%s'\n\n",
            NS_ConvertUTF16toUTF8(tag).get(), id.get(),
            NS_ConvertUTF16toUTF8(ctag).get(), cid.get());
 #endif
 
   nsDocAccessible* docAccessible = GetDocAccessible(aPresShell->GetDocument());
   if (docAccessible)
-    docAccessible->UpdateTree(aContainer, aChild, aChild->GetNextSibling(),
-                              PR_FALSE);
+    docAccessible->ContentRemoved(aContainer, aChild);
+}
+
+void
+nsAccessibilityService::UpdateText(nsIPresShell* aPresShell,
+                                   nsIContent* aContent)
+{
+  nsDocAccessible* document = GetDocAccessible(aPresShell->GetDocument());
+  if (document)
+    document->UpdateText(aContent);
 }
 
 void
 nsAccessibilityService::PresShellDestroyed(nsIPresShell *aPresShell)
 {
   // Presshell destruction will automatically destroy shells for descendant
   // documents, so no need to worry about those. Just shut down the accessible
   // for this one document. That keeps us from having bad behavior in case of
@@ -563,27 +559,20 @@ nsAccessibilityService::PresShellDestroy
     docAccessible->Shutdown();
 }
 
 void
 nsAccessibilityService::RecreateAccessible(nsIPresShell* aPresShell,
                                            nsIContent* aContent)
 {
   nsDocAccessible* document = GetDocAccessible(aPresShell->GetDocument());
-  if (document)
-    document->RecreateAccessible(aContent);
-}
-
-// nsAccessibilityService protected
-nsAccessible *
-nsAccessibilityService::GetCachedAccessible(nsINode *aNode,
-                                            nsIWeakReference *aWeakShell)
-{
-  nsDocAccessible *docAccessible = GetDocAccessible(aNode->GetOwnerDoc());
-  return docAccessible ? docAccessible->GetCachedAccessible(aNode) : nsnull;
+  if (document) {
+    document->HandleNotification<nsDocAccessible, nsIContent>
+      (document, &nsDocAccessible::RecreateAccessible, aContent);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIAccessibleRetrieval
 
 NS_IMETHODIMP
 nsAccessibilityService::GetApplicationAccessible(nsIAccessible **aAccessibleApplication)
 {
@@ -791,55 +780,39 @@ nsAccessibilityService::GetAccessibleFro
 nsAccessible*
 nsAccessibilityService::GetAccessibleInShell(nsINode* aNode,
                                              nsIPresShell* aPresShell)
 {
   if (!aNode || !aPresShell)
     return nsnull;
 
   nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(aPresShell));
-  return GetAccessibleByRule(aNode, weakShell, eGetAccForNode);
+  return GetAccessibleInWeakShell(aNode, weakShell);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibilityService public
 
 nsAccessible*
 nsAccessibilityService::GetAccessible(nsINode* aNode)
 {
-  if (aNode) {
-    nsCOMPtr<nsIWeakReference> weakShell(nsCoreUtils::GetWeakShellFor(aNode));
-    if (weakShell)
-      return GetAccessibleByRule(aNode, weakShell, eGetAccForNode);
-  }
-  return nsnull;
+  nsDocAccessible* document = GetDocAccessible(aNode->GetOwnerDoc());
+  return document ? document->GetAccessible(aNode) : nsnull;
 }
 
 nsAccessible*
-nsAccessibilityService::GetCachedAccessibleOrContainer(nsINode* aNode)
+nsAccessibilityService::GetAccessibleOrContainer(nsINode* aNode,
+                                                 nsIWeakReference* aWeakShell)
 {
   if (!aNode)
     return nsnull;
 
-  nsIDocument *document = aNode->GetCurrentDoc();
-  if (!document)
-    return nsnull;
-
-  nsIPresShell *presShell = document->GetShell();
-  if (!presShell)
-    return nsnull;
-
-  nsINode *currNode = aNode;
-  nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(presShell));
-
-  nsAccessible *accessible = nsnull;
-  while (!(accessible = GetCachedAccessible(currNode, weakShell)) &&
-         (currNode = currNode->GetNodeParent()));
-
-  return accessible;
+  // XXX: weak shell is ignored until multiple shell documents are supported.
+  nsDocAccessible* document = GetDocAccessible(aNode->GetOwnerDoc());
+  return document ? document->GetAccessibleOrContainer(aNode) : nsnull;
 }
 
 static PRBool HasRelatedContent(nsIContent *aContent)
 {
   nsAutoString id;
   if (!aContent || !nsCoreUtils::GetID(aContent, id) || id.IsEmpty()) {
     return PR_FALSE;
   }
@@ -869,17 +842,17 @@ nsAccessibilityService::GetOrCreateAcces
 {
   if (!aPresShell || !aWeakShell || !aNode || gIsShutdown)
     return nsnull;
 
   if (aIsSubtreeHidden)
     *aIsSubtreeHidden = false;
 
   // Check to see if we already have an accessible for this node in the cache.
-  nsAccessible *cachedAccessible = GetCachedAccessible(aNode, aWeakShell);
+  nsAccessible* cachedAccessible = GetAccessibleInWeakShell(aNode, aWeakShell);
   if (cachedAccessible) {
     NS_ADDREF(cachedAccessible);
     return cachedAccessible;
   }
 
   // No cache entry, so we must create the accessible.
 
   if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) {
@@ -937,35 +910,32 @@ nsAccessibilityService::GetOrCreateAcces
     GetAccService()->GetDocAccessible(aNode->GetOwnerDoc());
   if (!docAcc) {
     NS_NOTREACHED("No document for accessible being created!");
     return nsnull;
   }
 
   // Attempt to create an accessible based on what we know.
   nsRefPtr<nsAccessible> newAcc;
+
+  // Create accessible for visible text frames.
   if (content->IsNodeOfType(nsINode::eTEXT)) {
-    // --- Create HTML for visible text frames ---
-    nsIFrame* f = weakFrame.GetFrame();
-    if (f && f->IsEmpty()) {
-      nsAutoString renderedWhitespace;
-      f->GetRenderedText(&renderedWhitespace, nsnull, nsnull, 0, 1);
-      if (renderedWhitespace.IsEmpty()) {
-        // Really empty -- nothing is rendered
-        if (aIsSubtreeHidden)
-          *aIsSubtreeHidden = true;
+    nsAutoString text;
+    weakFrame->GetRenderedText(&text, nsnull, nsnull, 0, PR_UINT32_MAX);
+    if (text.IsEmpty()) {
+      if (aIsSubtreeHidden)
+        *aIsSubtreeHidden = true;
 
-        return nsnull;
-      }
+      return nsnull;
     }
-    if (weakFrame.IsAlive()) {
-      newAcc = weakFrame.GetFrame()->CreateAccessible();
-      if (docAcc->BindToDocument(newAcc, nsnull))
-        return newAcc.forget();
-      return nsnull;
+
+    newAcc = weakFrame->CreateAccessible();
+    if (docAcc->BindToDocument(newAcc, nsnull)) {
+      newAcc->AsTextLeaf()->SetText(text);
+      return newAcc.forget();
     }
 
     return nsnull;
   }
 
   PRBool isHTML = content->IsHTML();
   if (isHTML && content->Tag() == nsAccessibilityAtoms::map) {
     // Create hyper text accessible for HTML map if it is used to group links
@@ -1236,107 +1206,44 @@ nsAccessibilityService::HasUniversalAria
          nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_busy) ||
          aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_controls) ||
          aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_describedby) ||
          aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_disabled) ||
          nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_dropeffect) ||
          aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_flowto) ||
          nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_grabbed) ||
          nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_haspopup) ||
-         // purposely ignore aria-hidden; since we use gecko for detecting this anyways
+         aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_hidden) ||
          nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_invalid) ||
          aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_label) ||
          aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_labelledby) ||
          nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_live) ||
          nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_owns) ||
          nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_relevant);
 }
 
 nsAccessible*
-nsAccessibilityService::GetAccessibleByRule(nsINode* aNode,
-                                            nsIWeakReference* aWeakShell,
-                                            EWhatAccToGet aWhatToGet)
-{
-  if (!aNode || !aWeakShell)
-    return nsnull;
-
-  if (aWhatToGet & eGetAccForNode) {
-    nsAccessible* cachedAcc = GetCachedAccessible(aNode, aWeakShell);
-    if (cachedAcc && cachedAcc->IsBoundToParent())
-      return cachedAcc;
-  }
-
-  // Go up looking for the nearest accessible container having cached children.
-  nsTArray<nsINode*> nodes;
-
-  nsINode* node = aNode;
-  nsAccessible* cachedAcc = nsnull;
-  while ((node = node->GetNodeParent())) {
-    cachedAcc = GetCachedAccessible(node, aWeakShell);
-    if (cachedAcc && cachedAcc->IsBoundToParent())
-      break;
-
-    nodes.AppendElement(node);
-  }
-
-  // Node is not in accessible document.
-  if (!cachedAcc)
-    return nsnull;
-
-  // If children of the cached accessible weren't initialized then go down to
-  // the given node and create accessible tree.
-  nsAccessible* containerAcc = cachedAcc;
-  if (!cachedAcc->AreChildrenCached()) {
-    cachedAcc->EnsureChildren();
-    for (PRInt32 idx = nodes.Length() - 1; idx >= 0; idx--) {
-      cachedAcc = GetCachedAccessible(nodes[idx], aWeakShell);
-      if (cachedAcc) {
-        cachedAcc->EnsureChildren();
-        containerAcc = cachedAcc;
-      }
-    }
-  }
-
-  // If the given node is accessible then it should be cached at this point.
-  // Exception is an area element because area and imagemap nodes aren't in
-  // the same parent chain.
-  cachedAcc = GetCachedAccessible(aNode, aWeakShell);
-  if (!cachedAcc && aNode->IsElement()) {
-    nsIFrame* frame = aNode->AsElement()->GetPrimaryFrame();
-    if (frame && frame->GetContent() != aNode)
-      cachedAcc = GetAreaAccessible(frame, aNode, aWeakShell, &containerAcc);
-  }
-
-  if ((aWhatToGet & eGetAccForNode) && cachedAcc)
-    return cachedAcc;
-  else if (aWhatToGet & eGetAccForContainer)
-    return containerAcc;
-
-  return nsnull;
-}
-
-nsAccessible*
 nsAccessibilityService::GetAreaAccessible(nsIFrame* aImageFrame,
                                           nsINode* aAreaNode,
                                           nsIWeakReference* aWeakShell,
                                           nsAccessible** aImageAccessible)
 {
   // Check if frame is an image frame, and content is <area>.
   nsIImageFrame *imageFrame = do_QueryFrame(aImageFrame);
   if (!imageFrame)
     return nsnull;
 
   nsCOMPtr<nsIDOMHTMLAreaElement> areaElmt = do_QueryInterface(aAreaNode);
   if (!areaElmt)
     return nsnull;
 
   // Try to get image map accessible from the global cache or create it
   // if failed.
-  nsRefPtr<nsAccessible> image = GetCachedAccessible(aImageFrame->GetContent(),
-                                                     aWeakShell);
+  nsRefPtr<nsAccessible> image =
+    GetAccessibleInWeakShell(aImageFrame->GetContent(), aWeakShell);
   if (!image) {
     image = CreateHTMLImageAccessible(aImageFrame->GetContent(),
                                       aImageFrame->PresContext()->PresShell());
 
     nsDocAccessible* document =
       GetAccService()->GetDocAccessible(aAreaNode->GetOwnerDoc());
     if (!document) {
       NS_NOTREACHED("No document for accessible being created!");
@@ -1349,17 +1256,17 @@ nsAccessibilityService::GetAreaAccessibl
 
   if (aImageAccessible)
     *aImageAccessible = image;
 
   // Make sure <area> accessible children of the image map are cached so
   // that they should be available in global cache.
   image->EnsureChildren();
 
-  return GetCachedAccessible(aAreaNode, aWeakShell);
+  return GetAccessibleInWeakShell(aAreaNode, aWeakShell);
 }
 
 already_AddRefed<nsAccessible>
 nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
                                                nsIWeakReference* aWeakShell)
 {
   nsCOMPtr<nsIAccessibleProvider> accessibleProvider(do_QueryInterface(aContent));
   if (!accessibleProvider)
--- a/accessible/src/base/nsAccessibilityService.h
+++ b/accessible/src/base/nsAccessibilityService.h
@@ -113,16 +113,18 @@ public:
   virtual void ContentRangeInserted(nsIPresShell* aPresShell,
                                     nsIContent* aContainer,
                                     nsIContent* aStartChild,
                                     nsIContent* aEndChild);
 
   virtual void ContentRemoved(nsIPresShell* aPresShell, nsIContent* aContainer,
                               nsIContent* aChild);
 
+  virtual void UpdateText(nsIPresShell* aPresShell, nsIContent* aContent);
+
   virtual void NotifyOfAnchorJumpTo(nsIContent *aTarget);
 
   virtual void PresShellDestroyed(nsIPresShell* aPresShell);
 
   virtual void RecreateAccessible(nsIPresShell* aPresShell,
                                   nsIContent* aContent);
 
   virtual void FireAccessibleEvent(PRUint32 aEvent, nsAccessible* aTarget);
@@ -158,67 +160,37 @@ public:
    * Return an accessible for a DOM node in the given presshell.
    *
    * @param aNode       [in] the given node
    * @param aWeakShell  [in] the presentation shell for the given node
    */
   inline nsAccessible* GetAccessibleInWeakShell(nsINode* aNode,
                                                 nsIWeakReference* aWeakShell)
   {
-    return GetAccessibleByRule(aNode, aWeakShell, eGetAccForNode);
+    // XXX: weak shell is ignored until multiple shell documents are supported.
+    return GetAccessible(aNode);
   }
 
   /**
    * Return an accessible for the given DOM node or container accessible if
    * the node is not accessible.
    */
-  inline nsAccessible* GetAccessibleOrContainer(nsINode* aNode,
-                                                nsIWeakReference* aWeakShell)
-  {
-    return GetAccessibleByRule(aNode, aWeakShell, eGetAccForNodeOrContainer);
-  }
+  nsAccessible* GetAccessibleOrContainer(nsINode* aNode,
+                                         nsIWeakReference* aWeakShell);
 
   /**
    * Return a container accessible for the given DOM node.
    */
   inline nsAccessible* GetContainerAccessible(nsINode* aNode,
                                               nsIWeakReference* aWeakShell)
   {
-    return GetAccessibleByRule(aNode, aWeakShell, eGetAccForContainer);
+    return aNode ?
+      GetAccessibleOrContainer(aNode->GetNodeParent(), aWeakShell) : nsnull;
   }
 
-  /**
-   * Return cached accessible for the given DOM node or cached container
-   * accessible if there's no cached accessible for the given node.
-   */
-  nsAccessible* GetCachedAccessibleOrContainer(nsINode* aNode);
-
-  /**
-   * Return the first cached accessible parent of a DOM node.
-   *
-   * @param aDOMNode    [in] the DOM node to get an accessible for
-   */
-  inline nsAccessible* GetCachedContainerAccessible(nsINode *aNode)
-  {
-    return aNode ?
-      GetCachedAccessibleOrContainer(aNode->GetNodeParent()) : nsnull;
-  }
-
-protected:
-  /**
-   * Return an accessible for the DOM node in the given presentation shell if
-   * the accessible already exists, otherwise null.
-   *
-   * @param  aNode       [in] the DOM node to get an access node for
-   * @param  aPresShell  [in] the presentation shell which contains layout info
-   *                       for the DOM node
-   */
-  nsAccessible *GetCachedAccessible(nsINode *aNode,
-                                    nsIWeakReference *aShell);
-
 private:
   // nsAccessibilityService creation is controlled by friend
   // NS_GetAccessibilityService, keep constructors private.
   nsAccessibilityService();
   nsAccessibilityService(const nsAccessibilityService&);
   nsAccessibilityService& operator =(const nsAccessibilityService&);
 
 private:
@@ -227,29 +199,16 @@ private:
    */
   PRBool Init();
 
   /**
    * Shutdowns accessibility service.
    */
   void Shutdown();
 
-  enum EWhatAccToGet {
-    eGetAccForNode = 0x1,
-    eGetAccForContainer = 0x2,
-    eGetAccForNodeOrContainer = eGetAccForNode | eGetAccForContainer
-  };
-
-  /**
-   * Return accessible or accessible container for the given node in presshell.
-   */
-  nsAccessible* GetAccessibleByRule(nsINode* aNode,
-                                    nsIWeakReference* aWeakShell,
-                                    EWhatAccToGet aWhatToGet);
-
   /**
    * Return accessible for HTML area element associated with an image map.
    *
    * @param  aImageFrame       [in] image frame
    * @param  aAreaNode         [in] area node
    * @param  aWeakShell        [in] presshell of image frame
    * @param  aImageAccessible  [out, optional] image accessible, isn't addrefed
    */
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -180,17 +180,17 @@ nsresult nsAccessible::QueryInterface(RE
     return NS_ERROR_NO_INTERFACE;
   }
 
   return nsAccessNodeWrap::QueryInterface(aIID, aInstancePtr);
 }
 
 nsAccessible::nsAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
   nsAccessNodeWrap(aContent, aShell),
-  mParent(nsnull), mIndexInParent(-1), mChildrenFlags(eChildrenUninitialized),
+  mParent(nsnull), mIndexInParent(-1), mFlags(eChildrenUninitialized),
   mIndexOfEmbeddedChild(-1), mRoleMapEntry(nsnull)
 {
 #ifdef NS_DEBUG_X
    {
      nsCOMPtr<nsIPresShell> shell(do_QueryReferent(aShell));
      printf(">>> %p Created Acc - DOM: %p  PS: %p", 
             (void*)static_cast<nsIAccessible*>(this), (void*)aNode,
             (void*)shell.get());
@@ -1000,21 +1000,17 @@ nsAccessible::GetBounds(PRInt32* aX, PRI
   NS_ENSURE_ARG_POINTER(aWidth);
   *aWidth = 0;
   NS_ENSURE_ARG_POINTER(aHeight);
   *aHeight = 0;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
-  // Flush layout so that all the frame construction, reflow, and styles are
-  // up-to-date since we rely on frames, and styles when calculating state.
-  // We don't flush the display because we don't care about painting.
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
-  presShell->FlushPendingNotifications(Flush_Layout);
 
   // This routine will get the entire rectangle for all the frames in this node.
   // -------------------------------------------------------------------------
   //      Primary Frame for node
   //  Another frame, same node                <- Example
   //  Another frame, same node
 
   nsRect unionRectTwips;
@@ -1520,24 +1516,16 @@ nsAccessible::GroupPosition(PRInt32 *aGr
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
 {
   NS_ENSURE_ARG_POINTER(aState);
 
-  if (!IsDefunct()) {
-    // Flush layout so that all the frame construction, reflow, and styles are
-    // up-to-date since we rely on frames, and styles when calculating state.
-    // We don't flush the display because we don't care about painting.
-    nsCOMPtr<nsIPresShell> presShell = GetPresShell();
-    presShell->FlushPendingNotifications(Flush_Layout);
-  }
-
   nsresult rv = GetStateInternal(aState, aExtraState);
   NS_ENSURE_A11Y_SUCCESS(rv, rv);
 
   // Apply ARIA states to be sure accessible states will be overriden.
   GetARIAState(aState, aExtraState);
 
   if (mRoleMapEntry && mRoleMapEntry->role == nsIAccessibleRole::ROLE_PAGETAB) {
     if (*aState & nsIAccessibleStates::STATE_FOCUSED) {
@@ -2636,38 +2624,39 @@ nsAccessible::GetSelected(PRBool *aSelec
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   *aSelected = IsSelected();
   return NS_OK;
 
 }
 
-nsresult
-nsAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset, PRUint32 aLength)
+void
+nsAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset,
+                           PRUint32 aLength)
 {
   // Return text representation of non-text accessible within hypertext
   // accessible. Text accessible overrides this method to return enclosed text.
-  if (aStartOffset != 0)
-    return NS_OK;
+  if (aStartOffset != 0 || aLength == 0)
+    return;
 
   nsIFrame *frame = GetFrame();
-  NS_ENSURE_STATE(frame);
+  if (!frame)
+    return;
 
   if (frame->GetType() == nsAccessibilityAtoms::brFrame) {
     aText += kForcedNewLineChar;
-  } else if (nsAccUtils::MustPrune(this)) {
-    // Expose imaginary embedded object character if the accessible hans't
-    // children.
+  } else if (nsAccUtils::MustPrune(GetParent())) {
+    // Expose the embedded object accessible as imaginary embedded object
+    // character if its parent hypertext accessible doesn't expose children to
+    // AT.
     aText += kImaginaryEmbeddedObjectChar;
   } else {
     aText += kEmbeddedObjectChar;
   }
-
-  return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNode public methods
 
 void
 nsAccessible::Shutdown()
 {
@@ -2753,30 +2742,30 @@ nsAccessible::InvalidateChildren()
   PRInt32 childCount = mChildren.Length();
   for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
     nsAccessible* child = mChildren.ElementAt(childIdx);
     child->UnbindFromParent();
   }
 
   mEmbeddedObjCollector = nsnull;
   mChildren.Clear();
-  mChildrenFlags = eChildrenUninitialized;
+  SetChildrenFlag(eChildrenUninitialized);
 }
 
 PRBool
 nsAccessible::AppendChild(nsAccessible* aChild)
 {
   if (!aChild)
     return PR_FALSE;
 
   if (!mChildren.AppendElement(aChild))
     return PR_FALSE;
 
   if (!nsAccUtils::IsEmbeddedObject(aChild))
-    mChildrenFlags = eMixedChildren;
+    SetChildrenFlag(eMixedChildren);
 
   aChild->BindToParent(this, mChildren.Length() - 1);
   return PR_TRUE;
 }
 
 PRBool
 nsAccessible::InsertChildAt(PRUint32 aIndex, nsAccessible* aChild)
 {
@@ -2787,17 +2776,17 @@ nsAccessible::InsertChildAt(PRUint32 aIn
     return PR_FALSE;
 
   for (PRUint32 idx = aIndex + 1; idx < mChildren.Length(); idx++) {
     NS_ASSERTION(mChildren[idx]->mIndexInParent == idx - 1, "Accessible child index doesn't match");
     mChildren[idx]->mIndexInParent = idx;
   }
 
   if (nsAccUtils::IsText(aChild))
-    mChildrenFlags = eMixedChildren;
+    SetChildrenFlag(eMixedChildren);
 
   mEmbeddedObjCollector = nsnull;
 
   aChild->BindToParent(this, aIndex);
   return PR_TRUE;
 }
 
 PRBool
@@ -2824,47 +2813,16 @@ nsAccessible::RemoveChild(nsAccessible* 
   aChild->UnbindFromParent();
   mChildren.RemoveElementAt(index);
   mEmbeddedObjCollector = nsnull;
 
   return PR_TRUE;
 }
 
 nsAccessible*
-nsAccessible::GetParent()
-{
-  if (mParent)
-    return mParent;
-
-  if (IsDefunct())
-    return nsnull;
-
-  // XXX: mParent can be null randomly because supposedly we get layout
-  // notification and invalidate parent-child relations, this accessible stays
-  // unattached. This should gone after bug 572951.
-  NS_WARNING("Bad accessible tree!");
-
-#ifdef DEBUG
-  nsDocAccessible *docAccessible = GetDocAccessible();
-  NS_ASSERTION(docAccessible, "No document accessible for valid accessible!");
-#endif
-
-  nsAccessible* parent = GetAccService()->GetContainerAccessible(mContent,
-                                                                 mWeakShell);
-  NS_ASSERTION(parent, "No accessible parent for valid accessible!");
-  if (!parent)
-    return nsnull;
-
-  // Repair parent-child relations.
-  parent->EnsureChildren();
-  NS_ASSERTION(parent == mParent, "Wrong children repair!");
-  return parent;
-}
-
-nsAccessible*
 nsAccessible::GetChildAt(PRUint32 aIndex)
 {
   if (EnsureChildren())
     return nsnull;
 
   nsAccessible *child = mChildren.SafeElementAt(aIndex, nsnull);
   if (!child)
     return nsnull;
@@ -2887,61 +2845,59 @@ nsAccessible::GetChildCount()
 PRInt32
 nsAccessible::GetIndexOf(nsAccessible* aChild)
 {
   return EnsureChildren() || (aChild->mParent != this) ?
     -1 : aChild->GetIndexInParent();
 }
 
 PRInt32
-nsAccessible::GetIndexInParent()
+nsAccessible::GetIndexInParent() const
 {
-  // XXX: call GetParent() to repair the tree if it's broken.
-  GetParent();
   return mIndexInParent;
 }
 
 PRInt32
 nsAccessible::GetEmbeddedChildCount()
 {
   if (EnsureChildren())
     return -1;
 
-  if (mChildrenFlags == eMixedChildren) {
+  if (IsChildrenFlag(eMixedChildren)) {
     if (!mEmbeddedObjCollector)
       mEmbeddedObjCollector = new EmbeddedObjCollector(this);
     return mEmbeddedObjCollector ? mEmbeddedObjCollector->Count() : -1;
   }
 
   return GetChildCount();
 }
 
 nsAccessible*
 nsAccessible::GetEmbeddedChildAt(PRUint32 aIndex)
 {
   if (EnsureChildren())
     return nsnull;
 
-  if (mChildrenFlags == eMixedChildren) {
+  if (IsChildrenFlag(eMixedChildren)) {
     if (!mEmbeddedObjCollector)
       mEmbeddedObjCollector = new EmbeddedObjCollector(this);
     return mEmbeddedObjCollector ?
       mEmbeddedObjCollector->GetAccessibleAt(aIndex) : nsnull;
   }
 
   return GetChildAt(aIndex);
 }
 
 PRInt32
 nsAccessible::GetIndexOfEmbeddedChild(nsAccessible* aChild)
 {
   if (EnsureChildren())
     return -1;
 
-  if (mChildrenFlags == eMixedChildren) {
+  if (IsChildrenFlag(eMixedChildren)) {
     if (!mEmbeddedObjCollector)
       mEmbeddedObjCollector = new EmbeddedObjCollector(this);
     return mEmbeddedObjCollector ?
       mEmbeddedObjCollector->GetIndexAt(aChild) : -1;
   }
 
   return GetIndexOf(aChild);
 }
@@ -2949,35 +2905,34 @@ nsAccessible::GetIndexOfEmbeddedChild(ns
 ////////////////////////////////////////////////////////////////////////////////
 // HyperLinkAccessible methods
 
 bool
 nsAccessible::IsHyperLink()
 {
   // Every embedded accessible within hypertext accessible implements
   // hyperlink interface.
-  nsRefPtr<nsHyperTextAccessible> hyperText = do_QueryObject(GetParent());
-  return hyperText && nsAccUtils::IsEmbeddedObject(this);
+  return mParent && mParent->IsHyperText() && nsAccUtils::IsEmbeddedObject(this);
 }
 
 PRUint32
 nsAccessible::StartOffset()
 {
   NS_PRECONDITION(IsHyperLink(), "StartOffset is called not on hyper link!");
 
-  nsRefPtr<nsHyperTextAccessible> hyperText(do_QueryObject(GetParent()));
+  nsHyperTextAccessible* hyperText = mParent ? mParent->AsHyperText() : nsnull;
   return hyperText ? hyperText->GetChildOffset(this) : 0;
 }
 
 PRUint32
 nsAccessible::EndOffset()
 {
   NS_PRECONDITION(IsHyperLink(), "EndOffset is called on not hyper link!");
 
-  nsRefPtr<nsHyperTextAccessible> hyperText(do_QueryObject(GetParent()));
+  nsHyperTextAccessible* hyperText = mParent ? mParent->AsHyperText() : nsnull;
   return hyperText ? (hyperText->GetChildOffset(this) + 1) : 0;
 }
 
 bool
 nsAccessible::IsValid()
 {
   NS_PRECONDITION(IsHyperLink(), "IsValid is called on not hyper link!");
 
@@ -3175,22 +3130,22 @@ nsAccessible::CacheChildren()
 {
   nsAccTreeWalker walker(mWeakShell, mContent, GetAllowsAnonChildAccessibles());
 
   nsRefPtr<nsAccessible> child;
   while ((child = walker.GetNextChild()) && AppendChild(child));
 }
 
 void
-nsAccessible::TestChildCache(nsAccessible *aCachedChild)
+nsAccessible::TestChildCache(nsAccessible* aCachedChild) const
 {
 #ifdef DEBUG
   PRInt32 childCount = mChildren.Length();
   if (childCount == 0) {
-    NS_ASSERTION(mChildrenFlags == eChildrenUninitialized,
+    NS_ASSERTION(IsChildrenFlag(eChildrenUninitialized),
                  "No children but initialized!");
     return;
   }
 
   nsAccessible *child = nsnull;
   for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
     child = mChildren[childIdx];
     if (child == aCachedChild)
@@ -3198,41 +3153,41 @@ nsAccessible::TestChildCache(nsAccessibl
   }
 
   NS_ASSERTION(child == aCachedChild,
                "[TestChildCache] cached accessible wasn't found. Wrong accessible tree!");  
 #endif
 }
 
 // nsAccessible public
-PRBool
+bool
 nsAccessible::EnsureChildren()
 {
   if (IsDefunct()) {
-    mChildrenFlags = eChildrenUninitialized;
-    return PR_TRUE;
+    SetChildrenFlag(eChildrenUninitialized);
+    return true;
   }
 
-  if (mChildrenFlags != eChildrenUninitialized)
-    return PR_FALSE;
+  if (!IsChildrenFlag(eChildrenUninitialized))
+    return false;
 
   // State is embedded children until text leaf accessible is appended.
-  mChildrenFlags = eEmbeddedChildren; // Prevent reentry
+  SetChildrenFlag(eEmbeddedChildren); // Prevent reentry
 
   // Notify the document about caching status.
   nsDocAccessible* document = GetDocAccessible();
   if (document)
     document->NotifyOfCachingStart(this);
 
   CacheChildren();
 
   if (document)
     document->NotifyOfCachingEnd(this);
 
-  return PR_FALSE;
+  return false;
 }
 
 nsAccessible*
 nsAccessible::GetSiblingAtOffset(PRInt32 aOffset, nsresult* aError)
 {
   if (IsDefunct()) {
     if (aError)
       *aError = NS_ERROR_FAILURE;
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -48,21 +48,23 @@
 #include "nsIAccessibleRole.h"
 #include "nsIAccessibleStates.h"
 
 #include "nsARIAMap.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 #include "nsRefPtrHashtable.h"
 
+class AccEvent;
 class AccGroupInfo;
 class EmbeddedObjCollector;
 class nsAccessible;
-class AccEvent;
+class nsHyperTextAccessible;
 struct nsRoleMapEntry;
+class nsTextAccessible;
 
 struct nsRect;
 class nsIContent;
 class nsIFrame;
 class nsIAtom;
 class nsIView;
 
 typedef nsRefPtrHashtable<nsVoidPtrHashKey, nsAccessible>
@@ -221,19 +223,28 @@ public:
    * For a newly created accessible, specify which role map entry should be used.
    *
    * @param aRoleMapEntry The ARIA nsRoleMapEntry* for the accessible, or 
    *                      nsnull if none.
    */
   virtual void SetRoleMapEntry(nsRoleMapEntry *aRoleMapEntry);
 
   /**
+   * Update the children cache.
+   */
+  inline bool UpdateChildren()
+  {
+    InvalidateChildren();
+    return EnsureChildren();
+  }
+
+  /**
    * Cache children if necessary. Return true if the accessible is defunct.
    */
-  PRBool EnsureChildren();
+  bool EnsureChildren();
 
   /**
    * Set the child count to -1 (unknown) and null out cached child pointers.
    * Should be called when accessible tree is changed because document has
    * transformed. Note, if accessible cares about its parent relation chain
    * itself should override this method to do nothing.
    */
   virtual void InvalidateChildren();
@@ -246,17 +257,17 @@ public:
   virtual PRBool RemoveChild(nsAccessible* aChild);
 
   //////////////////////////////////////////////////////////////////////////////
   // Accessible tree traverse methods
 
   /**
    * Return parent accessible.
    */
-  nsAccessible* GetParent();
+  nsAccessible* GetParent() const { return mParent; }
 
   /**
    * Return child accessible at the given index.
    */
   virtual nsAccessible* GetChildAt(PRUint32 aIndex);
 
   /**
    * Return child accessible count.
@@ -266,17 +277,17 @@ public:
   /**
    * Return index of the given child accessible.
    */
   virtual PRInt32 GetIndexOf(nsAccessible* aChild);
 
   /**
    * Return index in parent accessible.
    */
-  virtual PRInt32 GetIndexInParent();
+  virtual PRInt32 GetIndexInParent() const;
 
   /**
    * Return true if accessible has children;
    */
   PRBool HasChildren() { return !!GetChildAt(0); }
 
   /**
    * Return embedded accessible children count.
@@ -291,31 +302,31 @@ public:
   /**
    * Return index of the given embedded accessible child.
    */
   PRInt32 GetIndexOfEmbeddedChild(nsAccessible* aChild);
 
   /**
    * Return cached accessible of parent-child relatives.
    */
-  nsAccessible* GetCachedParent() const { return mParent; }
   nsAccessible* GetCachedNextSibling() const
   {
     return mParent ?
       mParent->mChildren.SafeElementAt(mIndexInParent + 1, nsnull).get() : nsnull;
   }
   nsAccessible* GetCachedPrevSibling() const
   {
     return mParent ?
       mParent->mChildren.SafeElementAt(mIndexInParent - 1, nsnull).get() : nsnull;
   }
   PRUint32 GetCachedChildCount() const { return mChildren.Length(); }
   nsAccessible* GetCachedChildAt(PRUint32 aIndex) const { return mChildren.ElementAt(aIndex); }
-  PRBool AreChildrenCached() const { return mChildrenFlags != eChildrenUninitialized; }
-  bool IsBoundToParent() const { return mParent; }
+  inline bool AreChildrenCached() const
+    { return !IsChildrenFlag(eChildrenUninitialized); }
+  bool IsBoundToParent() const { return !!mParent; }
 
   //////////////////////////////////////////////////////////////////////////////
   // Miscellaneous methods
 
   /**
    * Handle accessible event, i.e. process it, notifies observers and fires
    * platform specific event.
    */
@@ -325,28 +336,39 @@ public:
    * Return true if there are accessible children in anonymous content
    */
   virtual PRBool GetAllowsAnonChildAccessibles();
 
   /**
    * Returns text of accessible if accessible has text role otherwise empty
    * string.
    *
-   * @param aText         returned text of the accessible
-   * @param aStartOffset  start offset inside of the accesible
-   * @param aLength       required lenght of text
+   * @param aText         [in] returned text of the accessible
+   * @param aStartOffset  [in, optional] start offset inside of the accessible,
+   *                        if missed entire text is appended
+   * @param aLength       [in, optional] required length of text, if missed
+   *                        then text form start offset till the end is appended
    */
-  virtual nsresult AppendTextTo(nsAString& aText, PRUint32 aStartOffset,
-                                PRUint32 aLength);
+  virtual void AppendTextTo(nsAString& aText, PRUint32 aStartOffset = 0,
+                            PRUint32 aLength = PR_UINT32_MAX);
 
   /**
    * Assert if child not in parent's cache if the cache was initialized at this
    * point.
    */
-  void TestChildCache(nsAccessible *aCachedChild);
+  void TestChildCache(nsAccessible* aCachedChild) const;
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Downcasting
+
+  inline bool IsHyperText() const { return mFlags & eHyperTextAccessible; }
+  nsHyperTextAccessible* AsHyperText();
+
+  inline bool IsTextLeaf() const { return mFlags & eTextLeafAccessible; }
+  nsTextAccessible* AsTextLeaf();
 
   //////////////////////////////////////////////////////////////////////////////
   // HyperLinkAccessible
 
   /**
    * Return true if the accessible is hyper link accessible.
    */
   virtual bool IsHyperLink();
@@ -452,16 +474,46 @@ protected:
   void UnbindFromParent();
 
   /**
    * Return sibling accessible at the given offset.
    */
   virtual nsAccessible* GetSiblingAtOffset(PRInt32 aOffset,
                                            nsresult *aError = nsnull);
 
+  /**
+   * Flags used to describe the state and type of children.
+   */
+  enum ChildrenFlags {
+    eChildrenUninitialized = 0, // children aren't initialized
+    eMixedChildren = 1 << 0, // text leaf children are presented
+    eEmbeddedChildren = 1 << 1 // all children are embedded objects
+  };
+
+  /**
+   * Return true if the children flag is set.
+   */
+  inline bool IsChildrenFlag(ChildrenFlags aFlag) const
+    { return (mFlags & kChildrenFlagsMask) == aFlag; }
+
+  /**
+   * Set children flag.
+   */
+  inline void SetChildrenFlag(ChildrenFlags aFlag)
+    { mFlags = (mFlags & ~kChildrenFlagsMask) | aFlag; }
+
+  /**
+   * Flags describing the accessible itself.
+   * @note keep these flags in sync with ChildrenFlags
+   */
+  enum AccessibleTypes {
+    eHyperTextAccessible = 1 << 2,
+    eTextLeafAccessible = 1 << 3
+  };
+
   //////////////////////////////////////////////////////////////////////////////
   // Miscellaneous helpers
 
   /**
    * Return ARIA role (helper method).
    */
   PRUint32 ARIARoleInternal();
 
@@ -566,22 +618,20 @@ protected:
    */
   virtual nsresult FirePlatformEvent(AccEvent* aEvent) = 0;
 
   // Data Members
   nsRefPtr<nsAccessible> mParent;
   nsTArray<nsRefPtr<nsAccessible> > mChildren;
   PRInt32 mIndexInParent;
 
-  enum ChildrenFlags {
-    eChildrenUninitialized = 0x00,
-    eMixedChildren = 0x01,
-    eEmbeddedChildren = 0x02
-  };
-  ChildrenFlags mChildrenFlags;
+  static const PRUint32 kChildrenFlagsMask =
+    eChildrenUninitialized | eMixedChildren | eEmbeddedChildren;
+
+  PRUint32 mFlags;
 
   nsAutoPtr<EmbeddedObjCollector> mEmbeddedObjCollector;
   PRInt32 mIndexOfEmbeddedChild;
   friend class EmbeddedObjCollector;
 
   nsAutoPtr<AccGroupInfo> mGroupInfo;
   friend class AccGroupInfo;
 
--- a/accessible/src/base/nsCaretAccessible.cpp
+++ b/accessible/src/base/nsCaretAccessible.cpp
@@ -46,17 +46,16 @@
 #include "nsIDOMDocument.h"
 #include "nsIDOMHTMLAnchorElement.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMHTMLTextAreaElement.h"
 #include "nsIFrame.h"
 #include "nsIPresShell.h"
 #include "nsRootAccessible.h"
 #include "nsISelectionPrivate.h"
-#include "nsISelection2.h"
 #include "nsServiceManagerUtils.h"
 
 class nsIWidget;
 
 NS_IMPL_ISUPPORTS1(nsCaretAccessible, nsISelectionListener)
   
 nsCaretAccessible::nsCaretAccessible( nsRootAccessible *aRootAccessible):
 mLastCaretOffset(-1), mRootAccessible(aRootAccessible)
@@ -206,48 +205,76 @@ nsCaretAccessible::NotifySelectionChange
                                           PRInt16 aReason)
 {
   NS_ENSURE_ARG(aDOMDocument);
   NS_ENSURE_STATE(mRootAccessible);
 
   nsCOMPtr<nsIDocument> documentNode(do_QueryInterface(aDOMDocument));
   nsDocAccessible* document = GetAccService()->GetDocAccessible(documentNode);
 
+#ifdef DEBUG_NOTIFICATIONS
+  nsCOMPtr<nsISelection2> sel2(do_QueryInterface(aSelection));
+
+  PRInt16 type = 0;
+  sel2->GetType(&type);
+
+  if (type == nsISelectionController::SELECTION_NORMAL ||
+      type == nsISelectionController::SELECTION_SPELLCHECK) {
+
+    bool isNormalSelection =
+      (type == nsISelectionController::SELECTION_NORMAL);
+
+    bool isIgnored = !document || !document->IsContentLoaded();
+    printf("\nSelection changed, selection type: %s, notification %s\n",
+           (isNormalSelection ? "normal" : "spellcheck"),
+           (isIgnored ? "ignored" : "pending"));
+  }
+#endif
+
   // Don't fire events until document is loaded.
-  if (!document || !document->IsContentLoaded())
-    return NS_OK;
+  if (document && document->IsContentLoaded()) {
+    // The caret accessible has the same lifetime as the root accessible, and
+    // this outlives all its descendant document accessibles, so that we are
+    // guaranteed that the notification is processed before the caret accessible
+    // is destroyed.
+    document->HandleNotification<nsCaretAccessible, nsISelection>
+      (this, &nsCaretAccessible::ProcessSelectionChanged, aSelection);
+  }
 
+  return NS_OK;
+}
+
+void
+nsCaretAccessible::ProcessSelectionChanged(nsISelection* aSelection)
+{
   nsCOMPtr<nsISelection2> sel2(do_QueryInterface(aSelection));
 
   PRInt16 type = 0;
   sel2->GetType(&type);
 
   if (type == nsISelectionController::SELECTION_NORMAL)
-    NormalSelectionChanged(document, aSelection);
+    NormalSelectionChanged(aSelection);
 
   else if (type == nsISelectionController::SELECTION_SPELLCHECK)
-    SpellcheckSelectionChanged(document, aSelection);
-
-  return NS_OK;
+    SpellcheckSelectionChanged(aSelection);
 }
 
 void
-nsCaretAccessible::NormalSelectionChanged(nsDocAccessible* aDocument,
-                                          nsISelection* aSelection)
+nsCaretAccessible::NormalSelectionChanged(nsISelection* aSelection)
 {
   mLastUsedSelection = do_GetWeakReference(aSelection);
 
   PRInt32 rangeCount = 0;
   aSelection->GetRangeCount(&rangeCount);
   if (rangeCount == 0) {
     mLastTextAccessible = nsnull;
     return; // No selection
   }
 
-  nsRefPtr<nsHyperTextAccessible> textAcc =
+  nsHyperTextAccessible* textAcc =
     nsAccUtils::GetTextAccessibleFromSelection(aSelection);
   if (!textAcc)
     return;
 
   PRInt32 caretOffset = -1;
   nsresult rv = textAcc->GetCaretOffset(&caretOffset);
   if (NS_FAILED(rv))
     return;
@@ -255,43 +282,42 @@ nsCaretAccessible::NormalSelectionChange
   if (textAcc == mLastTextAccessible && caretOffset == mLastCaretOffset) {
     PRInt32 selectionCount = 0;
     textAcc->GetSelectionCount(&selectionCount);   // Don't swallow similar events when selecting text
     if (!selectionCount)
       return;  // Swallow duplicate caret event
   }
 
   mLastCaretOffset = caretOffset;
-  mLastTextAccessible.swap(textAcc);
+  mLastTextAccessible = textAcc;
 
   nsRefPtr<AccEvent> event =
     new AccCaretMoveEvent(mLastTextAccessible->GetNode());
   if (event)
-    aDocument->FireDelayedAccessibleEvent(event);
+    mLastTextAccessible->GetDocAccessible()->FireDelayedAccessibleEvent(event);
 }
 
 void
-nsCaretAccessible::SpellcheckSelectionChanged(nsDocAccessible* aDocument,
-                                              nsISelection* aSelection)
+nsCaretAccessible::SpellcheckSelectionChanged(nsISelection* aSelection)
 {
   // XXX: fire an event for accessible of focus node of the selection. If
   // spellchecking is enabled then we will fire the number of events for
   // the same accessible for newly appended range of the selection (for every
   // misspelled word). If spellchecking is disabled (for example,
   // @spellcheck="false" on html:body) then we won't fire any event.
 
-  nsRefPtr<nsHyperTextAccessible> textAcc =
+  nsHyperTextAccessible* textAcc =
     nsAccUtils::GetTextAccessibleFromSelection(aSelection);
   if (!textAcc)
     return;
 
   nsRefPtr<AccEvent> event =
     new AccEvent(nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED, textAcc);
   if (event)
-    aDocument->FireDelayedAccessibleEvent(event);
+    textAcc->GetDocAccessible()->FireDelayedAccessibleEvent(event);
 }
 
 nsIntRect
 nsCaretAccessible::GetCaretRect(nsIWidget **aOutWidget)
 {
   nsIntRect caretRect;
   NS_ENSURE_TRUE(aOutWidget, caretRect);
   *aOutWidget = nsnull;
--- a/accessible/src/base/nsCaretAccessible.h
+++ b/accessible/src/base/nsCaretAccessible.h
@@ -33,19 +33,21 @@
  * 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 __nsCaretAccessible_h__
 #define __nsCaretAccessible_h__
 
+#include "NotificationController.h"
 #include "nsHyperTextAccessible.h"
 
 #include "nsISelectionListener.h"
+#include "nsISelection2.h"
 
 class nsRootAccessible;
 
 /*
  * This special accessibility class is for the caret, which is really the currently focused selection.
  * There is only 1 visible caret per top level window (nsRootAccessible),
  * However, there may be several visible selections.
  *
@@ -112,27 +114,30 @@ public:
    * @param aShell   PresShell for document to no longer listen to selection events from.
    */
   nsresult RemoveDocSelectionListener(nsIPresShell *aShell);
 
   nsIntRect GetCaretRect(nsIWidget **aOutWidget);
 
 protected:
   /**
+   * Process DOM selection change. Fire selection and caret move events.
+   */
+  void ProcessSelectionChanged(nsISelection* aSelection);
+
+  /**
    * Process normal selection change and fire caret move event.
    */
-  void NormalSelectionChanged(nsDocAccessible* aDocument,
-                              nsISelection* aSelection);
+  void NormalSelectionChanged(nsISelection* aSelection);
 
   /**
    * Process spellcheck selection change and fire text attribute changed event
    * for invalid text attribute.
    */
-  void SpellcheckSelectionChanged(nsDocAccessible* aDocument,
-                                  nsISelection* aSelection);
+  void SpellcheckSelectionChanged(nsISelection* aSelection);
 
   /**
    * Return selection controller for the given node.
    */
   already_AddRefed<nsISelectionController>
     GetSelectionControllerForNode(nsIContent *aNode);
 
 private:
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -108,16 +108,20 @@ nsDocAccessible::
   mDocument(aDocument), mScrollPositionChangedTicks(0), mIsLoaded(PR_FALSE),
   mCacheRoot(nsnull), mIsPostCacheProcessing(PR_FALSE)
 {
   mDependentIDsHash.Init();
   // XXX aaronl should we use an algorithm for the initial cache size?
   mAccessibleCache.Init(kDefaultCacheSize);
   mNodeToAccessibleMap.Init(kDefaultCacheSize);
 
+  // If this is a XUL Document, it should not implement nsHyperText
+  if (mDocument && mDocument->IsXUL())
+    mFlags &= ~eHyperTextAccessible;
+
   // For GTK+ native window, we do nothing here.
   if (!mDocument)
     return;
 
   // nsAccDocManager creates document accessible when scrollable frame is
   // available already, it should be safe time to add scroll listener.
   AddScrollListener();
 }
@@ -128,30 +132,30 @@ nsDocAccessible::~nsDocAccessible()
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsISupports
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocAccessible)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
-  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEventQueue");
-  cb.NoteXPCOMChild(tmp->mEventQueue.get());
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNotificationController,
+                                                  NotificationController)
 
   PRUint32 i, length = tmp->mChildDocuments.Length();
   for (i = 0; i < length; ++i) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mChildDocuments[i]");
     cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mChildDocuments[i].get()));
   }
 
   CycleCollectorTraverseCache(tmp->mAccessibleCache, &cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mEventQueue)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNotificationController)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mChildDocuments)
   tmp->mDependentIDsHash.Clear();
   tmp->mNodeToAccessibleMap.Clear();
   ClearCache(tmp->mAccessibleCache);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDocAccessible)
   NS_INTERFACE_MAP_STATIC_AMBIGUOUS(nsDocAccessible)
@@ -165,21 +169,20 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
 
   nsresult status;
   if (!foundInterface) {
     // HTML document accessible must inherit from nsHyperTextAccessible to get
     // support text interfaces. XUL document accessible doesn't need this.
     // However at some point we may push <body> to implement the interfaces and
     // return nsDocAccessible to inherit from nsAccessibleWrap.
 
-    if (mDocument && mDocument->IsXUL())
-      status = nsAccessible::QueryInterface(aIID, (void**)&foundInterface);
-    else
-      status = nsHyperTextAccessible::QueryInterface(aIID,
-                                                     (void**)&foundInterface);
+    status = IsHyperText() ? 
+      nsHyperTextAccessible::QueryInterface(aIID,
+                                            (void**)&foundInterface) :
+      nsAccessible::QueryInterface(aIID, (void**)&foundInterface);
   } else {
     NS_ADDREF(foundInterface);
     status = NS_OK;
   }
 
   *aInstancePtr = foundInterface;
   return status;
 }
@@ -314,17 +317,18 @@ nsDocAccessible::GetStateInternal(PRUint
     // XXX Need to invent better check to see if doc is focusable,
     // which it should be if it is scrollable. A XUL document could be focusable.
     // See bug 376803.
     *aState |= nsIAccessibleStates::STATE_FOCUSABLE;
     if (gLastFocusedNode == mDocument)
       *aState |= nsIAccessibleStates::STATE_FOCUSED;
   }
 
-  if (!mIsLoaded) {
+  // Expose state busy until the document is loaded or tree is constructed.
+  if (!mIsLoaded || !mNotificationController->IsTreeConstructed()) {
     *aState |= nsIAccessibleStates::STATE_BUSY;
     if (aExtraState) {
       *aExtraState |= nsIAccessibleStates::EXT_STATE_STALE;
     }
   }
  
   nsIFrame* frame = GetFrame();
   while (frame != nsnull && !frame->HasView()) {
@@ -581,86 +585,72 @@ NS_IMETHODIMP nsDocAccessible::GetAssoci
   editor->GetIsDocumentEditable(&isEditable);
   if (isEditable) {
     NS_ADDREF(*aEditor = editor);
   }
   return NS_OK;
 }
 
 // nsDocAccessible public method
-nsAccessible *
-nsDocAccessible::GetCachedAccessible(nsINode *aNode)
+nsAccessible*
+nsDocAccessible::GetAccessible(nsINode* aNode) const
 {
   nsAccessible* accessible = mNodeToAccessibleMap.Get(aNode);
 
   // No accessible in the cache, check if the given ID is unique ID of this
   // document accessible.
   if (!accessible) {
     if (GetNode() != aNode)
       return nsnull;
 
-    accessible = this;
+    accessible = const_cast<nsDocAccessible*>(this);
   }
 
 #ifdef DEBUG
   // All cached accessible nodes should be in the parent
   // It will assert if not all the children were created
   // when they were first cached, and no invalidation
   // ever corrected parent accessible's child cache.
-  nsAccessible* parent(accessible->GetCachedParent());
+  nsAccessible* parent(accessible->GetParent());
   if (parent)
     parent->TestChildCache(accessible);
 #endif
 
   return accessible;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNode
 
 PRBool
 nsDocAccessible::Init()
 {
   NS_LOG_ACCDOCCREATE_FOR("document initialize", mDocument, this)
 
-  // Initialize event queue.
-  mEventQueue = new nsAccEventQueue(this);
-  if (!mEventQueue)
+  // Initialize notification controller.
+  nsCOMPtr<nsIPresShell> shell(GetPresShell());
+  mNotificationController = new NotificationController(this, shell);
+  if (!mNotificationController)
     return PR_FALSE;
 
   AddEventListeners();
-
-  nsDocAccessible* parentDocument = mParent->GetDocAccessible();
-  if (parentDocument)
-    parentDocument->AppendChildDocument(this);
-
-  // Fire reorder event to notify new accessible document has been created and
-  // attached to the tree.
-  nsRefPtr<AccEvent> reorderEvent =
-    new AccEvent(nsIAccessibleEvent::EVENT_REORDER, mParent, eAutoDetect,
-                 AccEvent::eCoalesceFromSameSubtree);
-  if (reorderEvent) {
-    FireDelayedAccessibleEvent(reorderEvent);
-    return PR_TRUE;
-  }
-
-  return PR_FALSE;
+  return PR_TRUE;
 }
 
 void
 nsDocAccessible::Shutdown()
 {
   if (!mWeakShell) // already shutdown
     return;
 
   NS_LOG_ACCDOCDESTROY_FOR("document shutdown", mDocument, this)
 
-  if (mEventQueue) {
-    mEventQueue->Shutdown();
-    mEventQueue = nsnull;
+  if (mNotificationController) {
+    mNotificationController->Shutdown();
+    mNotificationController = nsnull;
   }
 
   RemoveEventListeners();
 
   if (mParent) {
     nsDocAccessible* parentDocument = mParent->GetDocAccessible();
     if (parentDocument)
       parentDocument->RemoveChildDocument(this);
@@ -944,50 +934,67 @@ nsDocAccessible::AttributeWillChange(nsI
                                      PRInt32 aNameSpaceID,
                                      nsIAtom* aAttribute, PRInt32 aModType)
 {
   // XXX TODO: bugs 467143, 472142, 472143.
   // Here we will want to cache whatever state we are potentially interested in,
   // such as the existence of aria-pressed for button (so we know if we need to
   // newly expose it as a toggle button) etc.
 
-  // Update dependent IDs cache.
+  // Update dependent IDs cache. Take care of elements that are accessible
+  // because dependent IDs cache doesn't contain IDs from non accessible
+  // elements.
   if (aModType == nsIDOMMutationEvent::MODIFICATION ||
       aModType == nsIDOMMutationEvent::REMOVAL) {
-    nsAccessible* accessible =
-      GetAccService()->GetAccessibleInWeakShell(aElement, mWeakShell);
+    nsAccessible* accessible = GetAccessible(aElement);
     if (accessible)
       RemoveDependentIDsFor(accessible, aAttribute);
   }
 }
 
 void
 nsDocAccessible::AttributeChanged(nsIDocument *aDocument,
                                   dom::Element* aElement,
                                   PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                                   PRInt32 aModType)
 {
+  NS_ASSERTION(!IsDefunct(),
+               "Attribute changed called on defunct document accessible!");
+
+  // Proceed even if the element is not accessible because element may become
+  // accessible if it gets certain attribute.
+  if (UpdateAccessibleOnAttrChange(aElement, aAttribute))
+    return;
+
+  // Ignore attribute change if the element doesn't have an accessible (at all
+  // or still) iff the element is not a root content of this document accessible
+  // (which is treated as attribute change on this document accessible).
+  // Note: we don't bail if all the content hasn't finished loading because
+  // these attributes are changing for a loaded part of the content.
+  nsAccessible* accessible = GetAccessible(aElement);
+  if (!accessible && (mContent != aElement))
+    return;
+
+  // Fire accessible events iff there's an accessible, otherwise we consider
+  // the accessible state wasn't changed, i.e. its state is initial state.
   AttributeChangedImpl(aElement, aNameSpaceID, aAttribute);
 
-  // Update dependent IDs cache.
+  // Update dependent IDs cache. Take care of accessible elements because no
+  // accessible element means either the element is not accessible at all or
+  // its accessible will be created later. It doesn't make sense to keep
+  // dependent IDs for non accessible elements. For the second case we'll update
+  // dependent IDs cache when its accessible is created.
   if (aModType == nsIDOMMutationEvent::MODIFICATION ||
       aModType == nsIDOMMutationEvent::ADDITION) {
-    nsAccessible* accessible =
-      GetAccService()->GetAccessibleInWeakShell(aElement, mWeakShell);
-
-    if (accessible)
-      AddDependentIDsFor(accessible, aAttribute);
+    AddDependentIDsFor(accessible, aAttribute);
   }
 
-  // If it was the focused node, cache the new state
-  if (aElement == gLastFocusedNode) {
-    nsAccessible *focusedAccessible = GetAccService()->GetAccessible(aElement);
-    if (focusedAccessible)
-      gLastFocusedAccessiblesState = nsAccUtils::State(focusedAccessible);
-  }
+  // If it was the focused node, cache the new state.
+  if (aElement == gLastFocusedNode)
+    gLastFocusedAccessiblesState = nsAccUtils::State(accessible);
 }
 
 // nsDocAccessible protected member
 void
 nsDocAccessible::AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID, nsIAtom* aAttribute)
 {
   // Fire accessible event after short timer, because we need to wait for
   // DOM attribute & resulting layout to actually change. Otherwise,
@@ -999,32 +1006,16 @@ nsDocAccessible::AttributeChangedImpl(ns
   // Otherwise it may just be a state change, for example an object changing
   // its visibility
   // 
   // XXX todo: report aria state changes for "undefined" literal value changes
   // filed as bug 472142
   //
   // XXX todo:  invalidate accessible when aria state changes affect exposed role
   // filed as bug 472143
-  
-  nsCOMPtr<nsISupports> container = mDocument->GetContainer();
-  nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
-  if (!docShell) {
-    return;
-  }
-
-  if (!IsContentLoaded())
-    return; // Still loading, ignore setting of initial attributes
-
-  nsCOMPtr<nsIPresShell> shell = GetPresShell();
-  if (!shell) {
-    return; // Document has been shut down
-  }
-
-  NS_ASSERTION(aContent, "No node for attr modified");
 
   // Universal boolean properties that don't require a role. Fire the state
   // change when disabled or aria-disabled attribute is set.
   if (aAttribute == nsAccessibilityAtoms::disabled ||
       aAttribute == nsAccessibilityAtoms::aria_disabled) {
 
     // Note. Checking the XUL or HTML namespace would not seem to gain us
     // anything, because disabled attribute really is going to mean the same
@@ -1053,39 +1044,16 @@ nsDocAccessible::AttributeChangedImpl(ns
   if (aNameSpaceID == kNameSpaceID_None) {
     // Check for hyphenated aria-foo property?
     if (StringBeginsWith(nsDependentAtomString(aAttribute),
                          NS_LITERAL_STRING("aria-"))) {
       ARIAAttributeChanged(aContent, aAttribute);
     }
   }
 
-  if (aAttribute == nsAccessibilityAtoms::role) {
-    if (mContent == aContent) {
-      // It is common for js libraries to set the role of the body element after
-      // the doc has loaded. In this case we just update the role map entry. 
-      SetRoleMapEntry(nsAccUtils::GetRoleMapEntry(aContent));
-    }
-    else {
-      // Recreate the accessible when role is changed because we might require a
-      // different accessible class for the new role or the accessible may
-      // expose a different sets of interfaces (COM restriction).
-      RecreateAccessible(aContent);
-    }
-  }
-
-  if (aAttribute == nsAccessibilityAtoms::href ||
-      aAttribute == nsAccessibilityAtoms::onclick) {
-    // Not worth the expense to ensure which namespace these are in
-    // It doesn't kill use to recreate the accessible even if the attribute was used
-    // in the wrong namespace or an element that doesn't support it
-    RecreateAccessible(aContent);
-    return;
-  }
-  
   if (aAttribute == nsAccessibilityAtoms::alt ||
       aAttribute == nsAccessibilityAtoms::title ||
       aAttribute == nsAccessibilityAtoms::aria_label ||
       aAttribute == nsAccessibilityAtoms::aria_labelledby) {
     FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE,
                                aContent);
     return;
   }
@@ -1155,28 +1123,30 @@ nsDocAccessible::ARIAAttributeChanged(ns
     return;
   }
 
   if (aAttribute == nsAccessibilityAtoms::aria_activedescendant) {
     // The activedescendant universal property redirects accessible focus events
     // to the element with the id that activedescendant points to
     nsCOMPtr<nsINode> focusedNode = GetCurrentFocus();
     if (nsCoreUtils::GetRoleContent(focusedNode) == aContent) {
+      nsAccessible* focusedAcc = GetAccService()->GetAccessible(focusedNode);
       nsRefPtr<nsRootAccessible> rootAcc = GetRootAccessible();
-      if (rootAcc) {
-        rootAcc->FireAccessibleFocusEvent(nsnull, focusedNode, nsnull, PR_TRUE);
+      if (rootAcc && focusedAcc) {
+        rootAcc->FireAccessibleFocusEvent(focusedAcc, nsnull, PR_TRUE);
       }
     }
     return;
   }
 
   // For aria drag and drop changes we fire a generic attribute change event;
   // at least until native API comes up with a more meaningful event.
   if (aAttribute == nsAccessibilityAtoms::aria_grabbed ||
-      aAttribute == nsAccessibilityAtoms::aria_dropeffect) {
+      aAttribute == nsAccessibilityAtoms::aria_dropeffect ||
+      aAttribute == nsAccessibilityAtoms::aria_hidden) {
     FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED,
                                aContent);
   }
 
   // We treat aria-expanded as a global ARIA state for historical reasons
   if (aAttribute == nsAccessibilityAtoms::aria_expanded) {
     nsRefPtr<AccEvent> event =
       new AccStateChangeEvent(aContent, nsIAccessibleStates::STATE_EXPANDED,
@@ -1239,25 +1209,16 @@ nsDocAccessible::ARIAAttributeChanged(ns
            nsAccessibilityAtoms::aria_valuetext) ||
         aContent->AttrValueIs(kNameSpaceID_None,
             nsAccessibilityAtoms::aria_valuetext, nsAccessibilityAtoms::_empty,
             eCaseMatters)))) {
     FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
                                aContent);
     return;
   }
-
-  if (aAttribute == nsAccessibilityAtoms::aria_multiselectable &&
-      aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::role)) {
-    // This affects whether the accessible supports SelectAccessible.
-    // COM says we cannot change what interfaces are supported on-the-fly,
-    // so invalidate this object. A new one will be created on demand.
-    RecreateAccessible(aContent);
-    return;
-  }
 }
 
 void nsDocAccessible::ContentAppended(nsIDocument *aDocument,
                                       nsIContent* aContainer,
                                       nsIContent* aFirstNewContent,
                                       PRInt32 /* unused */)
 {
 }
@@ -1284,24 +1245,22 @@ void nsDocAccessible::DocumentStatesChan
                                             nsEventStates aStateMask)
 {
 }
 
 void nsDocAccessible::CharacterDataWillChange(nsIDocument *aDocument,
                                               nsIContent* aContent,
                                               CharacterDataChangeInfo* aInfo)
 {
-  FireTextChangeEventForText(aContent, aInfo, PR_FALSE);
 }
 
 void nsDocAccessible::CharacterDataChanged(nsIDocument *aDocument,
                                            nsIContent* aContent,
                                            CharacterDataChangeInfo* aInfo)
 {
-  FireTextChangeEventForText(aContent, aInfo, PR_TRUE);
 }
 
 void
 nsDocAccessible::ContentInserted(nsIDocument *aDocument, nsIContent* aContainer,
                                  nsIContent* aChild, PRInt32 /* unused */)
 {
 }
 
@@ -1345,33 +1304,47 @@ nsDocAccessible::GetNativeWindow() const
     vm->GetRootWidget(getter_AddRefs(widget));
     if (widget)
       return widget->GetNativeData(NS_NATIVE_WINDOW);
   }
   return nsnull;
 }
 
 nsAccessible*
-nsDocAccessible::GetCachedAccessibleByUniqueIDInSubtree(void* aUniqueID)
+nsDocAccessible::GetAccessibleByUniqueIDInSubtree(void* aUniqueID)
 {
-  nsAccessible* child = GetCachedAccessibleByUniqueID(aUniqueID);
+  nsAccessible* child = GetAccessibleByUniqueID(aUniqueID);
   if (child)
     return child;
 
   PRUint32 childDocCount = mChildDocuments.Length();
   for (PRUint32 childDocIdx= 0; childDocIdx < childDocCount; childDocIdx++) {
     nsDocAccessible* childDocument = mChildDocuments.ElementAt(childDocIdx);
-    child = childDocument->GetCachedAccessibleByUniqueIDInSubtree(aUniqueID);
+    child = childDocument->GetAccessibleByUniqueIDInSubtree(aUniqueID);
     if (child)
       return child;
   }
 
   return nsnull;
 }
 
+nsAccessible*
+nsDocAccessible::GetAccessibleOrContainer(nsINode* aNode)
+{
+  if (!aNode || !aNode->IsInDoc())
+    return nsnull;
+
+  nsINode* currNode = aNode;
+  nsAccessible* accessible = nsnull;
+  while (!(accessible = GetAccessible(currNode)) &&
+         (currNode = currNode->GetNodeParent()));
+
+  return accessible;
+}
+
 bool
 nsDocAccessible::BindToDocument(nsAccessible* aAccessible,
                                 nsRoleMapEntry* aRoleMapEntry)
 {
   if (!aAccessible)
     return false;
 
   // Put into DOM node cache.
@@ -1391,207 +1364,88 @@ nsDocAccessible::BindToDocument(nsAccess
   if (!aAccessible->Init()) {
     NS_ERROR("Failed to initialize an accessible!");
 
     UnbindFromDocument(aAccessible);
     return false;
   }
 
   aAccessible->SetRoleMapEntry(aRoleMapEntry);
-  AddDependentIDsFor(aAccessible);
+  if (aAccessible->IsElement())
+    AddDependentIDsFor(aAccessible);
+
   return true;
 }
 
 void
 nsDocAccessible::UnbindFromDocument(nsAccessible* aAccessible)
 {
   NS_ASSERTION(mAccessibleCache.GetWeak(aAccessible->UniqueID()),
                "Unbinding the unbound accessible!");
 
   // Remove an accessible from node-to-accessible map if it exists there.
   if (aAccessible->IsPrimaryForNode() &&
       mNodeToAccessibleMap.Get(aAccessible->GetNode()) == aAccessible)
     mNodeToAccessibleMap.Remove(aAccessible->GetNode());
 
-  if (!aAccessible->IsDefunct())
-    RemoveDependentIDsFor(aAccessible);
-
   void* uniqueID = aAccessible->UniqueID();
 
   NS_ASSERTION(!aAccessible->IsDefunct(), "Shutdown the shutdown accessible!");
   aAccessible->Shutdown();
 
   mAccessibleCache.Remove(uniqueID);
 }
 
 void
-nsDocAccessible::UpdateTree(nsIContent* aContainerNode,
-                            nsIContent* aStartNode,
-                            nsIContent* aEndNode,
-                            PRBool aIsInsert)
+nsDocAccessible::ContentInserted(nsIContent* aContainerNode,
+                                 nsIContent* aStartChildNode,
+                                 nsIContent* aEndChildNode)
 {
-  // Content change notification mostly are async, thus we can't detect whether
-  // these actions are from user. This information is used to fire or do not
-  // fire events to avoid events that are generated because of document loading.
-  // Since this information may be not correct then we need to fire some events
-  // regardless the document loading state.
-
-  // Update the whole tree of this document accessible when the container is
-  // null (document element is inserted or removed).
-
-  nsCOMPtr<nsIPresShell> presShell = GetPresShell();
-  nsIEventStateManager* esm = presShell->GetPresContext()->EventStateManager();
-  PRBool fireAllEvents = PR_TRUE;//IsContentLoaded() || esm->IsHandlingUserInputExternal();
-
-  // XXX: bug 608887 reconsider accessible tree update logic because
-  // 1) elements appended outside the HTML body don't get accessibles;
-  // 2) the document having elements that should be accessible may function
-  // without body.
-  nsAccessible* container = nsnull;
-  if (aIsInsert) {
-    container = aContainerNode ?
-      GetAccService()->GetAccessibleOrContainer(aContainerNode, mWeakShell) :
-      this;
-
-    // The document children were changed; the root content might be affected.
-    if (container == this) {
-      // If new root content has been inserted then update it.
-      nsIContent* rootContent = nsCoreUtils::GetRoleContent(mDocument);
-      if (rootContent && rootContent != mContent)
-        mContent = rootContent;
-
-      // Continue to update the tree even if we don't have root content.
-      // For example, elements may be inserted under the document element while
-      // there is no HTML body element.
-    }
-
-    // XXX: Invalidate parent-child relations for container accessible and its
-    // children because there's no good way to find insertion point of new child
-    // accessibles into accessible tree. We need to invalidate children even
-    // there's no inserted accessibles in the end because accessible children
-    // are created while parent recaches child accessibles.
-    container->InvalidateChildren();
-
-  } else {
-    // Don't create new accessibles on content removal.
-    container = aContainerNode ?
-      GetAccService()->GetCachedAccessibleOrContainer(aContainerNode) :
-      this;
-  }
+  /// Pend tree update on content insertion until layout.
+  if (mNotificationController) {
+    // Update the whole tree of this document accessible when the container is
+    // null (document element is inserted or removed).
+    nsAccessible* container = aContainerNode ?
+      GetAccessibleOrContainer(aContainerNode) : this;
 
-  EIsFromUserInput fromUserInput = esm->IsHandlingUserInputExternal() ?
-    eFromUserInput : eNoUserInput;
-
-  // Update the accessible tree in the case of content removal and fire events
-  // if allowed.
-  PRUint32 updateFlags =
-    UpdateTreeInternal(container, aStartNode, aEndNode,
-                       aIsInsert, fireAllEvents, fromUserInput);
-
-  // Content insertion/removal is not cause of accessible tree change.
-  if (updateFlags == eNoAccessible)
-    return;
-
-  // Check to see if change occurred inside an alert, and fire an EVENT_ALERT
-  // if it did.
-  if (aIsInsert && !(updateFlags & eAlertAccessible)) {
-    // XXX: tree traversal is perf issue, accessible should know if they are
-    // children of alert accessible to avoid this.
-    nsAccessible* ancestor = container;
-    while (ancestor) {
-      if (ancestor->ARIARole() == nsIAccessibleRole::ROLE_ALERT) {
-        FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_ALERT,
-                                   ancestor->GetNode(), AccEvent::eRemoveDupes,
-                                   fromUserInput);
-        break;
-      }
-
-      // Don't climb above this document.
-      if (ancestor == this)
-        break;
-
-      ancestor = ancestor->GetParent();
-    }
+    mNotificationController->ScheduleContentInsertion(container,
+                                                      aStartChildNode,
+                                                      aEndChildNode);
   }
-
-  // Fire nether value change nor reorder events if action is not from user
-  // input and document is loading. We are notified about changes in editor
-  // synchronously, so from user input flag is correct for value change events.
-  if (!fireAllEvents)
-    return;
-
-  // Fire value change event.
-  if (container->Role() == nsIAccessibleRole::ROLE_ENTRY) {
-    nsRefPtr<AccEvent> valueChangeEvent =
-      new AccEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, container,
-                   fromUserInput, AccEvent::eRemoveDupes);
-    FireDelayedAccessibleEvent(valueChangeEvent);
-  }
-
-  // Fire reorder event so the MSAA clients know the children have changed. Also
-  // the event is used internally by MSAA part.
-  nsRefPtr<AccEvent> reorderEvent =
-    new AccEvent(nsIAccessibleEvent::EVENT_REORDER, container->GetNode(),
-                 fromUserInput, AccEvent::eCoalesceFromSameSubtree);
-  if (reorderEvent)
-    FireDelayedAccessibleEvent(reorderEvent);
 }
 
 void
-nsDocAccessible::RecreateAccessible(nsINode* aNode)
+nsDocAccessible::ContentRemoved(nsIContent* aContainerNode,
+                                nsIContent* aChildNode)
 {
-  // XXX: we shouldn't recreate whole accessible subtree that happens when
-  // hide event is handled, instead we should subclass hide and show events
-  // to handle them separately and implement their coalescence with normal hide
-  // and show events.
-
-  nsAccessible* parent = nsnull;
+  // Update the whole tree of this document accessible when the container is
+  // null (document element is removed).
+  nsAccessible* container = aContainerNode ?
+    GetAccessibleOrContainer(aContainerNode) : this;
 
-  // Fire hide event for old accessible.
-  nsAccessible* oldAccessible =
-    GetAccService()->GetAccessibleInWeakShell(aNode, mWeakShell);
-  if (oldAccessible) {
-    parent = oldAccessible->GetParent();
-
-    nsRefPtr<AccEvent> hideEvent = new AccHideEvent(oldAccessible, aNode,
-                                                    eAutoDetect);
-    if (hideEvent)
-      FireDelayedAccessibleEvent(hideEvent);
-
-    // Unbind old accessible from tree.
-    parent->RemoveChild(oldAccessible);
+  UpdateTree(container, aChildNode, PR_FALSE);
+}
 
-    if (oldAccessible->IsPrimaryForNode() &&
-        mNodeToAccessibleMap.Get(oldAccessible->GetNode()) == oldAccessible)
-      mNodeToAccessibleMap.Remove(oldAccessible->GetNode());
-
-  } else {
-    parent = GetAccService()->GetContainerAccessible(aNode, mWeakShell);
-  }
-
-  // Get new accessible and fire show event.
-  parent->InvalidateChildren();
+void
+nsDocAccessible::RecreateAccessible(nsIContent* aContent)
+{
+  // XXX: we shouldn't recreate whole accessible subtree, instead we should
+  // subclass hide and show events to handle them separately and implement their
+  // coalescence with normal hide and show events. Note, in this case they
+  // should be coalesced with normal show/hide events.
 
-  nsAccessible* newAccessible =
-    GetAccService()->GetAccessibleInWeakShell(aNode, mWeakShell);
-  if (newAccessible) {
-    nsRefPtr<AccEvent> showEvent = new AccShowEvent(newAccessible, aNode,
-                                                    eAutoDetect);
-    if (showEvent)
-      FireDelayedAccessibleEvent(showEvent);
-  }
+  // Check if the node is in DOM still.
+  nsIContent* parentContent = aContent->GetParent();
+  if (parentContent && parentContent->IsInDoc()) {
+    nsAccessible* container = GetAccessibleOrContainer(parentContent);
 
-  // Fire reorder event.
-  if (oldAccessible || newAccessible) {
-    nsRefPtr<AccEvent> reorderEvent =
-      new AccEvent(nsIAccessibleEvent::EVENT_REORDER, parent->GetNode(),
-                   eAutoDetect, AccEvent::eCoalesceFromSameSubtree);
-
-    if (reorderEvent)
-      FireDelayedAccessibleEvent(reorderEvent);
+    // Remove and reinsert.
+    UpdateTree(container, aContent, PR_FALSE);
+    container->UpdateChildren();
+    UpdateTree(container, aContent, PR_TRUE);
   }
 }
 
 void
 nsDocAccessible::NotifyOfCachingStart(nsAccessible* aAccessible)
 {
   if (!mCacheRoot)
     mCacheRoot = aAccessible;
@@ -1603,23 +1457,22 @@ nsDocAccessible::NotifyOfCachingEnd(nsAc
   if (mCacheRoot == aAccessible && !mIsPostCacheProcessing) {
     // Allow invalidation list insertions while container children are recached.
     mIsPostCacheProcessing = PR_TRUE;
 
     // Invalidate children of container accessible for each element in
     // invalidation list.
     for (PRUint32 idx = 0; idx < mInvalidationList.Length(); idx++) {
       nsIContent* content = mInvalidationList[idx];
-      nsAccessible* container =
-        GetAccService()->GetCachedContainerAccessible(content);
-      container->InvalidateChildren();
-
-      // Make sure we keep children updated. While we're inside of caching loop
-      // then we must exist it with cached children.
-      container->EnsureChildren();
+      if (!HasAccessible(content)) {
+        // Make sure we keep children updated. While we're inside of caching
+        // loop then we must exist it with cached children.
+        nsAccessible* container = GetContainerAccessible(content);
+        container->UpdateChildren();
+      }
     }
     mInvalidationList.Clear();
 
     mCacheRoot = nsnull;
     mIsPostCacheProcessing = PR_FALSE;
   }
 }
 
@@ -1686,17 +1539,17 @@ nsDocAccessible::AddDependentIDsFor(nsAc
         if (provider) {
           providers->AppendElement(provider);
 
           // We've got here during the children caching. If the referenced
           // content is not accessible then store it to pend its container
           // children invalidation (this happens immediately after the caching
           // is finished).
           nsIContent* dependentContent = iter.GetElem(id);
-          if (dependentContent && !GetCachedAccessible(dependentContent)) {
+          if (dependentContent && !HasAccessible(dependentContent)) {
             mInvalidationList.AppendElement(dependentContent);
           }
         }
       }
     }
 
     // If the relation attribute is given then we don't have anything else to
     // check.
@@ -1737,86 +1590,63 @@ nsDocAccessible::RemoveDependentIDsFor(n
 
     // If the relation attribute is given then we don't have anything else to
     // check.
     if (aRelAttr)
       break;
   }
 }
 
-void
-nsDocAccessible::FireValueChangeForTextFields(nsAccessible *aAccessible)
+bool
+nsDocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement,
+                                              nsIAtom* aAttribute)
 {
-  if (aAccessible->Role() != nsIAccessibleRole::ROLE_ENTRY)
-    return;
-
-  // Dependent value change event for text changes in textfields
-  nsRefPtr<AccEvent> valueChangeEvent =
-    new AccEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible,
-                 eAutoDetect, AccEvent::eRemoveDupes);
-  FireDelayedAccessibleEvent(valueChangeEvent);
-}
+  if (aAttribute == nsAccessibilityAtoms::role) {
+    // It is common for js libraries to set the role on the body element after
+    // the document has loaded. In this case we just update the role map entry.
+    if (mContent == aElement) {
+      SetRoleMapEntry(nsAccUtils::GetRoleMapEntry(aElement));
+      return true;
+    }
 
-void
-nsDocAccessible::FireTextChangeEventForText(nsIContent *aContent,
-                                            CharacterDataChangeInfo* aInfo,
-                                            PRBool aIsInserted)
-{
-  if (!IsContentLoaded())
-    return;
+    // Recreate the accessible when role is changed because we might require a
+    // different accessible class for the new role or the accessible may expose
+    // a different sets of interfaces (COM restriction).
+    HandleNotification<nsDocAccessible, nsIContent>
+      (this, &nsDocAccessible::RecreateAccessible, aElement);
 
-  PRInt32 contentOffset = aInfo->mChangeStart;
-  PRUint32 contentLength = aIsInserted ?
-    aInfo->mReplaceLength: // text has been added
-    aInfo->mChangeEnd - contentOffset; // text has been removed
-
-  if (contentLength == 0)
-    return;
-
-  nsAccessible *accessible = GetAccService()->GetAccessible(aContent);
-  if (!accessible)
-    return;
+    return true;
+  }
 
-  nsRefPtr<nsHyperTextAccessible> textAccessible =
-    do_QueryObject(accessible->GetParent());
-  if (!textAccessible)
-    return;
+  if (aAttribute == nsAccessibilityAtoms::href ||
+      aAttribute == nsAccessibilityAtoms::onclick) {
+    // Not worth the expense to ensure which namespace these are in. It doesn't
+    // kill use to recreate the accessible even if the attribute was used in
+    // the wrong namespace or an element that doesn't support it.
 
-  // Get offset within hypertext accessible and invalidate cached offsets after
-  // this child accessible.
-  PRInt32 offset = textAccessible->GetChildOffset(accessible, PR_TRUE);
-
-  // Get added or removed text.
-  nsIFrame* frame = aContent->GetPrimaryFrame();
-  if (!frame)
-    return;
+    // Recreate accessible asynchronously to allow the content to handle
+    // the attribute change.
+    mNotificationController->ScheduleNotification<nsDocAccessible, nsIContent>
+      (this, &nsDocAccessible::RecreateAccessible, aElement);
 
-  PRUint32 textOffset = 0;
-  nsresult rv = textAccessible->ContentToRenderedOffset(frame, contentOffset,
-                                                        &textOffset);
-  if (NS_FAILED(rv))
-    return;
-
-  nsAutoString text;
-  rv = accessible->AppendTextTo(text, textOffset, contentLength);
-  if (NS_FAILED(rv))
-    return;
+    return true;
+  }
 
-  if (text.IsEmpty())
-    return;
+  if (aAttribute == nsAccessibilityAtoms::aria_multiselectable &&
+      aElement->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::role)) {
+    // This affects whether the accessible supports SelectAccessible.
+    // COM says we cannot change what interfaces are supported on-the-fly,
+    // so invalidate this object. A new one will be created on demand.
+    HandleNotification<nsDocAccessible, nsIContent>
+      (this, &nsDocAccessible::RecreateAccessible, aElement);
 
-  // Normally we only fire delayed events created from the node, not an
-  // accessible object. See the AccTextChangeEvent constructor for details
-  // about this exceptional case.
-  nsRefPtr<AccEvent> event =
-    new AccTextChangeEvent(textAccessible, offset + textOffset, text,
-                          aIsInserted);
-  FireDelayedAccessibleEvent(event);
+    return true;
+  }
 
-  FireValueChangeForTextFields(textAccessible);
+  return false;
 }
 
 // nsDocAccessible public member
 nsresult
 nsDocAccessible::FireDelayedAccessibleEvent(PRUint32 aEventType, nsINode *aNode,
                                             AccEvent::EEventRule aAllowDupes,
                                             EIsFromUserInput aIsFromUserInput)
 {
@@ -1829,23 +1659,22 @@ nsDocAccessible::FireDelayedAccessibleEv
 
 // nsDocAccessible public member
 nsresult
 nsDocAccessible::FireDelayedAccessibleEvent(AccEvent* aEvent)
 {
   NS_ENSURE_ARG(aEvent);
   NS_LOG_ACCDOCLOAD_FIREEVENT(aEvent)
 
-  if (mEventQueue)
-    mEventQueue->Push(aEvent);
+  if (mNotificationController)
+    mNotificationController->QueueEvent(aEvent);
 
   return NS_OK;
 }
 
-// nsDocAccessible public member
 void
 nsDocAccessible::ProcessPendingEvent(AccEvent* aEvent)
 {
   nsAccessible* accessible = aEvent->GetAccessible();
   if (!accessible)
     return;
 
   PRUint32 eventType = aEvent->GetEventType();
@@ -1886,48 +1715,151 @@ nsDocAccessible::ProcessPendingEvent(Acc
     nsEventShell::FireEvent(aEvent);
 
     // Post event processing
     if (eventType == nsIAccessibleEvent::EVENT_HIDE)
       ShutdownChildrenInSubtree(accessible);
   }
 }
 
+void
+nsDocAccessible::ProcessAnchorJump(nsIContent* aTargetNode)
+{
+  // If the jump target is not accessible then fire an event for nearest
+  // accessible in parent chain.
+  nsAccessible* target = GetAccessibleOrContainer(aTargetNode);
+  if (!target)
+    return;
+
+  // XXX: bug 625699, note in some cases the node could go away before we flush
+  // the queue, for example if the node becomes inaccessible, or is removed from
+  // the DOM.
+  FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_SCROLLING_START,
+                             target->GetNode());
+}
+
+void
+nsDocAccessible::ProcessContentInserted(nsAccessible* aContainer,
+                                        const nsTArray<nsCOMPtr<nsIContent> >* aInsertedContent)
+{
+  // Process the notification if the container accessible is still in tree.
+  if (!HasAccessible(aContainer->GetNode()))
+    return;
+
+  if (aContainer == this) {
+    // If new root content has been inserted then update it.
+    nsIContent* rootContent = nsCoreUtils::GetRoleContent(mDocument);
+    if (rootContent && rootContent != mContent)
+      mContent = rootContent;
+
+    // Continue to update the tree even if we don't have root content.
+    // For example, elements may be inserted under the document element while
+    // there is no HTML body element.
+  }
+
+  // XXX: Invalidate parent-child relations for container accessible and its
+  // children because there's no good way to find insertion point of new child
+  // accessibles into accessible tree. We need to invalidate children even
+  // there's no inserted accessibles in the end because accessible children
+  // are created while parent recaches child accessibles.
+  aContainer->UpdateChildren();
+
+  // The container might be changed, for example, because of the subsequent
+  // overlapping content insertion (i.e. other content was inserted between this
+  // inserted content and its container or the content was reinserted into
+  // different container of unrelated part of tree). These cases result in
+  // double processing, however generated events are coalesced and we don't
+  // harm an AT.
+  // Theoretically the element might be not in tree at all at this point what
+  // means there's no container.
+  for (PRUint32 idx = 0; idx < aInsertedContent->Length(); idx++) {
+    nsAccessible* directContainer =
+      GetContainerAccessible(aInsertedContent->ElementAt(idx));
+    if (directContainer)
+      UpdateTree(directContainer, aInsertedContent->ElementAt(idx), PR_TRUE);
+  }
+}
+
+void
+nsDocAccessible::UpdateTree(nsAccessible* aContainer, nsIContent* aChildNode,
+                            PRBool aIsInsert)
+{
+  PRUint32 updateFlags =
+    UpdateTreeInternal(aChildNode, aChildNode->GetNextSibling(), aIsInsert);
+
+  // Content insertion/removal is not cause of accessible tree change.
+  if (updateFlags == eNoAccessible)
+    return;
+
+  // Check to see if change occurred inside an alert, and fire an EVENT_ALERT
+  // if it did.
+  if (aIsInsert && !(updateFlags & eAlertAccessible)) {
+    // XXX: tree traversal is perf issue, accessible should know if they are
+    // children of alert accessible to avoid this.
+    nsAccessible* ancestor = aContainer;
+    while (ancestor) {
+      if (ancestor->ARIARole() == nsIAccessibleRole::ROLE_ALERT) {
+        FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_ALERT,
+                                   ancestor->GetNode());
+        break;
+      }
+
+      // Don't climb above this document.
+      if (ancestor == this)
+        break;
+
+      ancestor = ancestor->GetParent();
+    }
+  }
+
+  // Fire value change event.
+  if (aContainer->Role() == nsIAccessibleRole::ROLE_ENTRY) {
+    FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
+                               aContainer->GetNode());
+  }
+
+  // Fire reorder event so the MSAA clients know the children have changed. Also
+  // the event is used internally by MSAA layer.
+  nsRefPtr<AccEvent> reorderEvent =
+    new AccEvent(nsIAccessibleEvent::EVENT_REORDER, aContainer->GetNode(),
+                 eAutoDetect, AccEvent::eCoalesceFromSameSubtree);
+  if (reorderEvent)
+    FireDelayedAccessibleEvent(reorderEvent);
+}
+
 PRUint32
-nsDocAccessible::UpdateTreeInternal(nsAccessible* aContainer,
-                                    nsIContent* aStartNode,
+nsDocAccessible::UpdateTreeInternal(nsIContent* aStartNode,
                                     nsIContent* aEndNode,
-                                    PRBool aIsInsert,
-                                    PRBool aFireAllEvents,
-                                    EIsFromUserInput aFromUserInput)
+                                    PRBool aIsInsert)
 {
   PRUint32 updateFlags = eNoAccessible;
   for (nsIContent* node = aStartNode; node != aEndNode;
        node = node->GetNextSibling()) {
 
     // Tree update triggers for content insertion even if no content was
     // inserted actually, check if the given content has a frame to discard
     // this case early.
     if (aIsInsert && !node->GetPrimaryFrame())
       continue;
 
-    nsAccessible* accessible = aIsInsert ?
-      GetAccService()->GetAccessibleInWeakShell(node, mWeakShell) :
-      GetCachedAccessible(node);
+    nsAccessible* accessible = GetAccessible(node);
 
     if (!accessible) {
-      updateFlags |= UpdateTreeInternal(aContainer, node->GetFirstChild(),
-                                        nsnull, aIsInsert, aFireAllEvents,
-                                        aFromUserInput);
+      updateFlags |= UpdateTreeInternal(node->GetFirstChild(), nsnull,
+                                        aIsInsert);
       continue;
     }
 
     updateFlags |= eAccessible;
 
-    if (!aIsInsert) {
+    if (aIsInsert) {
+      // Create accessible tree for shown accessible.
+      CacheChildrenInSubtree(accessible);
+
+    } else {
       // Fire menupopup end event before hide event if a menu goes away.
 
       // XXX: We don't look into children of hidden subtree to find hiding
       // menupopup (as we did prior bug 570275) because we don't do that when
       // menu is showing (and that's impossible until bug 606924 is fixed).
       // Nevertheless we should do this at least because layout coalesces
       // the changes before our processing and we may miss some menupopup
       // events. Now we just want to be consistent in content insertion/removal
@@ -1937,63 +1869,84 @@ nsDocAccessible::UpdateTreeInternal(nsAc
           new AccEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END, accessible);
 
         if (event)
           FireDelayedAccessibleEvent(event);
       }
     }
 
     // Fire show/hide event.
-    if (aFireAllEvents) {
-      nsRefPtr<AccEvent> event;
-      if (aIsInsert)
-        event = new AccShowEvent(accessible, node, aFromUserInput);
-      else
-        event = new AccHideEvent(accessible, node, aFromUserInput);
+    nsRefPtr<AccEvent> event;
+    if (aIsInsert)
+      event = new AccShowEvent(accessible, node);
+    else
+      event = new AccHideEvent(accessible, node);
 
-      if (event)
-        FireDelayedAccessibleEvent(event);
-    }
+    if (event)
+      FireDelayedAccessibleEvent(event);
 
     if (aIsInsert) {
       PRUint32 ariaRole = accessible->ARIARole();
       if (ariaRole == nsIAccessibleRole::ROLE_MENUPOPUP) {
         // Fire EVENT_MENUPOPUP_START if ARIA menu appears.
         FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
-                                   node, AccEvent::eRemoveDupes, aFromUserInput);
+                                   node, AccEvent::eRemoveDupes);
 
       } else if (ariaRole == nsIAccessibleRole::ROLE_ALERT) {
         // Fire EVENT_ALERT if ARIA alert appears.
         updateFlags = eAlertAccessible;
         FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_ALERT, node,
-                                   AccEvent::eRemoveDupes, aFromUserInput);
+                                   AccEvent::eRemoveDupes);
       }
 
       // If focused node has been shown then it means its frame was recreated
       // while it's focused. Fire focus event on new focused accessible. If
       // the queue contains focus event for this node then it's suppressed by
       // this one.
       if (node == gLastFocusedNode) {
         FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_FOCUS,
-                                   node, AccEvent::eCoalesceFromSameDocument,
-                                   aFromUserInput);
+                                   node, AccEvent::eCoalesceFromSameDocument);
       }
     } else {
       // Update the tree for content removal.
-      aContainer->RemoveChild(accessible);
+      // The accessible parent may differ from container accessible if
+      // the parent doesn't have own DOM node like list accessible for HTML
+      // selects.
+      nsAccessible* parent = accessible->GetParent();
+      NS_ASSERTION(parent, "No accessible parent?!");
+      if (parent)
+        parent->RemoveChild(accessible);
+
       UncacheChildrenInSubtree(accessible);
     }
   }
 
   return updateFlags;
 }
 
 void
+nsDocAccessible::CacheChildrenInSubtree(nsAccessible* aRoot)
+{
+  aRoot->EnsureChildren();
+
+  PRUint32 count = aRoot->GetChildCount();
+  for (PRUint32 idx = 0; idx < count; idx++)  {
+    nsAccessible* child = aRoot->GetChildAt(idx);
+    // Don't cross document boundaries.
+    if (child->IsContent())
+      CacheChildrenInSubtree(child);
+  }
+}
+
+void
 nsDocAccessible::UncacheChildrenInSubtree(nsAccessible* aRoot)
 {
+  if (aRoot->IsElement())
+    RemoveDependentIDsFor(aRoot);
+
   PRUint32 count = aRoot->GetCachedChildCount();
   for (PRUint32 idx = 0; idx < count; idx++)
     UncacheChildrenInSubtree(aRoot->GetCachedChildAt(idx));
 
   if (aRoot->IsPrimaryForNode() &&
       mNodeToAccessibleMap.Get(aRoot->GetNode()) == aRoot)
     mNodeToAccessibleMap.Remove(aRoot->GetNode());
 }
@@ -2013,9 +1966,8 @@ nsDocAccessible::ShutdownChildrenInSubtr
       jdx++;
     }
 
     ShutdownChildrenInSubtree(child);
   }
 
   UnbindFromDocument(aAccessible);
 }
-
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -36,18 +36,19 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsDocAccessible_H_
 #define _nsDocAccessible_H_
 
 #include "nsIAccessibleDocument.h"
 
+#include "nsEventShell.h"
 #include "nsHyperTextAccessibleWrap.h"
-#include "nsEventShell.h"
+#include "NotificationController.h"
 
 #include "nsClassHashtable.h"
 #include "nsDataHashtable.h"
 #include "nsIDocument.h"
 #include "nsIDocumentObserver.h"
 #include "nsIEditor.h"
 #include "nsIObserver.h"
 #include "nsIScrollPositionListener.h"
@@ -184,41 +185,98 @@ public:
   /**
    * Fire accessible event after timeout.
    *
    * @param aEvent  [in] the event to fire
    */
   nsresult FireDelayedAccessibleEvent(AccEvent* aEvent);
 
   /**
+   * Handle anchor jump when page is loaded.
+   */
+  inline void HandleAnchorJump(nsIContent* aTargetNode)
+  {
+    HandleNotification<nsDocAccessible, nsIContent>
+      (this, &nsDocAccessible::ProcessAnchorJump, aTargetNode);
+  }
+
+  /**
+   * Bind the child document to the tree.
+   */
+  inline void BindChildDocument(nsDocAccessible* aDocument)
+  {
+    mNotificationController->ScheduleChildDocBinding(aDocument);
+  }
+
+  /**
+   * Process the generic notification.
+   *
+   * @note  The caller must guarantee that the given instance still exists when
+   *          notification is processed.
+   * @see   NotificationController::HandleNotification
+   */
+  template<class Class, class Arg>
+  inline void HandleNotification(Class* aInstance,
+                                 typename TNotification<Class, Arg>::Callback aMethod,
+                                 Arg* aArg)
+  {
+    if (mNotificationController) {
+      mNotificationController->HandleNotification<Class, Arg>(aInstance,
+                                                              aMethod, aArg);
+    }
+  }
+
+  /**
    * Return the cached accessible by the given DOM node if it's in subtree of
    * this document accessible or the document accessible itself, otherwise null.
    *
    * @return the accessible object
    */
-  nsAccessible* GetCachedAccessible(nsINode* aNode);
+  nsAccessible* GetAccessible(nsINode* aNode) const;
+
+  /**
+   * Return whether the given DOM node has an accessible or not.
+   */
+  inline bool HasAccessible(nsINode* aNode)
+  {
+    return GetAccessible(aNode);
+  }
 
   /**
    * Return the cached accessible by the given unique ID within this document.
    *
    * @note   the unique ID matches with the uniqueID() of nsAccessNode
    *
    * @param  aUniqueID  [in] the unique ID used to cache the node.
    */
-  nsAccessible* GetCachedAccessibleByUniqueID(void* aUniqueID)
+  inline nsAccessible* GetAccessibleByUniqueID(void* aUniqueID)
   {
     return UniqueID() == aUniqueID ?
       this : mAccessibleCache.GetWeak(aUniqueID);
   }
 
   /**
    * Return the cached accessible by the given unique ID looking through
    * this and nested documents.
    */
-  nsAccessible* GetCachedAccessibleByUniqueIDInSubtree(void* aUniqueID);
+  nsAccessible* GetAccessibleByUniqueIDInSubtree(void* aUniqueID);
+
+  /**
+   * Return an accessible for the given DOM node or container accessible if
+   * the node is not accessible.
+   */
+  nsAccessible* GetAccessibleOrContainer(nsINode* aNode);
+
+  /**
+   * Return a container accessible for the given DOM node.
+   */
+  inline nsAccessible* GetContainerAccessible(nsINode* aNode)
+  {
+    return aNode ? GetAccessibleOrContainer(aNode->GetNodeParent()) : nsnull;
+  }
 
   /**
    * Return true if the given ID is referred by relation attribute.
    *
    * @note Different elements may share the same ID if they are hosted inside
    *       XBL bindings. Be careful the result of this method may be  senseless
    *       while it's called for XUL elements (where XBL is used widely).
    */
@@ -235,31 +293,42 @@ public:
   bool BindToDocument(nsAccessible* aAccessible, nsRoleMapEntry* aRoleMapEntry);
 
   /**
    * Remove from document and shutdown the given accessible.
    */
   void UnbindFromDocument(nsAccessible* aAccessible);
 
   /**
-   * Process the event when the queue of pending events is untwisted. Fire
-   * accessible events as result of the processing.
+   * Notify the document accessible that content was inserted.
    */
-  void ProcessPendingEvent(AccEvent* aEvent);
+  void ContentInserted(nsIContent* aContainerNode,
+                       nsIContent* aStartChildNode,
+                       nsIContent* aEndChildNode);
 
   /**
-   * Update the accessible tree.
+   * Notify the document accessible that content was removed.
+   */
+  void ContentRemoved(nsIContent* aContainerNode, nsIContent* aChildNode);
+
+  /**
+   * Updates accessible tree when rendered text is changed.
    */
-  void UpdateTree(nsIContent* aContainerNode, nsIContent* aStartChildNode,
-                  nsIContent* aEndChildNode, PRBool aIsInsert);
+  inline void UpdateText(nsIContent* aTextNode)
+  {
+    NS_ASSERTION(mNotificationController, "The document was shut down!");
+
+    if (mNotificationController)
+      mNotificationController->ScheduleTextUpdate(aTextNode);
+  }
 
   /**
    * Recreate an accessible, results in hide/show events pair.
    */
-  void RecreateAccessible(nsINode* aNode);
+  void RecreateAccessible(nsIContent* aContent);
 
   /**
    * Used to notify the document that the accessible caching is started or
    * finished.
    *
    * While children are cached we may encounter the case there's no accessible
    * for referred content by related accessible. Keep the caching root and
    * these related nodes to invalidate their containers after root caching.
@@ -314,17 +383,25 @@ protected:
    * attributes are checked.
    *
    * @param aRelProvider [in] accessible that element has relation attribute
    * @param aRelAttr     [in, optional] relation attribute
    */
   void RemoveDependentIDsFor(nsAccessible* aRelProvider,
                              nsIAtom* aRelAttr = nsnull);
 
-    static void ScrollTimerCallback(nsITimer *aTimer, void *aClosure);
+  /**
+   * Update or recreate an accessible depending on a changed attribute.
+   *
+   * @param aElement   [in] the element the attribute was changed on
+   * @param aAttribute [in] the changed attribute
+   * @return            true if an action was taken on the attribute change
+   */
+  bool UpdateAccessibleOnAttrChange(mozilla::dom::Element* aElement,
+                                    nsIAtom* aAttribute);
 
     /**
      * Fires accessible events when attribute is changed.
      *
      * @param aContent - node that attribute is changed for
      * @param aNameSpaceID - namespace of changed attribute
      * @param aAttribute - changed attribute
      */
@@ -333,87 +410,98 @@ protected:
     /**
      * Fires accessible events when ARIA attribute is changed.
      *
      * @param aContent - node that attribute is changed for
      * @param aAttribute - changed attribute
      */
     void ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute);
 
-    /**
-     * Fire text changed event for character data changed. The method is used
-     * from nsIMutationObserver methods.
-     *
-     * @param aContent     the text node holding changed data
-     * @param aInfo        info structure describing how the data was changed
-     * @param aIsInserted  the flag pointed whether removed or inserted
-     *                     characters should be cause of event
-     */
-    void FireTextChangeEventForText(nsIContent *aContent,
-                                    CharacterDataChangeInfo* aInfo,
-                                    PRBool aIsInserted);
+  /**
+   * Process the event when the queue of pending events is untwisted. Fire
+   * accessible events as result of the processing.
+   */
+  void ProcessPendingEvent(AccEvent* aEvent);
 
   /**
-   * Fire a value change event for the the given accessible if it is a text
-   * field (has a ROLE_ENTRY).
+   * Process anchor jump notification and fire scrolling end event.
+   */
+  void ProcessAnchorJump(nsIContent* aTargetNode);
+
+  /**
+   * Update the accessible tree for inserted content.
    */
-  void FireValueChangeForTextFields(nsAccessible *aAccessible);
+  void ProcessContentInserted(nsAccessible* aContainer,
+                              const nsTArray<nsCOMPtr<nsIContent> >* aInsertedContent);
+
+  /**
+   * Update the accessible tree for content insertion or removal.
+   */
+  void UpdateTree(nsAccessible* aContainer, nsIContent* aChildNode,
+                  PRBool aIsInsert);
 
   /**
    * Helper for UpdateTree() method. Go down to DOM subtree and updates
    * accessible tree. Return one of these flags.
    */
   enum EUpdateTreeFlags {
     eNoAccessible = 0,
     eAccessible = 1,
     eAlertAccessible = 2
   };
 
-  PRUint32 UpdateTreeInternal(nsAccessible* aContainer,
-                              nsIContent* aStartNode,
+  PRUint32 UpdateTreeInternal(nsIContent* aStartNode,
                               nsIContent* aEndNode,
-                              PRBool aIsInsert,
-                              PRBool aFireEvents,
-                              EIsFromUserInput aFromUserInput);
+                              PRBool aIsInsert);
+
+  /**
+   * Create accessible tree.
+   */
+  void CacheChildrenInSubtree(nsAccessible* aRoot);
 
   /**
    * Remove accessibles in subtree from node to accessible map.
    */
   void UncacheChildrenInSubtree(nsAccessible* aRoot);
 
   /**
    * Shutdown any cached accessible in the subtree.
    *
    * @param aAccessible  [in] the root of the subrtee to invalidate accessible
    *                      child/parent refs in
    */
   void ShutdownChildrenInSubtree(nsAccessible *aAccessible);
 
   /**
+   * Used to fire scrolling end event after page scroll.
+   *
+   * @param aTimer    [in] the timer object
+   * @param aClosure  [in] the document accessible where scrolling happens
+   */
+  static void ScrollTimerCallback(nsITimer* aTimer, void* aClosure);
+
+  /**
    * Cache of accessibles within this document accessible.
    */
   nsAccessibleHashtable mAccessibleCache;
   nsDataHashtable<nsPtrHashKey<const nsINode>, nsAccessible*>
     mNodeToAccessibleMap;
 
     nsCOMPtr<nsIDocument> mDocument;
     nsCOMPtr<nsITimer> mScrollWatchTimer;
     PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
 
 protected:
 
-  nsRefPtr<nsAccEventQueue> mEventQueue;
-
   /**
    * Specifies if the document was loaded, used for error pages only.
    */
   PRPackedBool mIsLoaded;
 
     static PRUint32 gLastFocusedAccessiblesState;
-    static nsIAtom *gLastFocusedFrameType;
 
   nsTArray<nsRefPtr<nsDocAccessible> > mChildDocuments;
 
   /**
    * A storage class for pairing content with one of its relation attributes.
    */
   class AttrRelProvider
   {
@@ -443,14 +531,20 @@ protected:
    * caching, the list of nodes that should be invalidated, and whether we are
    * processing the invalidation list.
    *
    * @see NotifyOfCachingStart/NotifyOfCachingEnd
    */
   nsAccessible* mCacheRoot;
   nsTArray<nsIContent*> mInvalidationList;
   PRBool mIsPostCacheProcessing;
+
+  /**
+   * Used to process notification from core and accessible events.
+   */
+  nsRefPtr<NotificationController> mNotificationController;
+  friend class NotificationController;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsDocAccessible,
                               NS_DOCACCESSIBLE_IMPL_CID)
 
 #endif
--- a/accessible/src/base/nsEventShell.cpp
+++ b/accessible/src/base/nsEventShell.cpp
@@ -34,18 +34,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsEventShell.h"
 
 #include "nsAccUtils.h"
-#include "nsCoreUtils.h"
-#include "nsDocAccessible.h"
+//#include "nsDocAccessible.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsEventShell
 ////////////////////////////////////////////////////////////////////////////////
 
 void
 nsEventShell::FireEvent(AccEvent* aEvent)
 {
@@ -90,392 +89,8 @@ nsEventShell::GetEventAttributes(nsINode
                                                NS_LITERAL_STRING("false"));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsEventShell: private
 
 PRBool nsEventShell::sEventFromUserInput = PR_FALSE;
 nsCOMPtr<nsINode> nsEventShell::sEventTargetNode;
-
-
-////////////////////////////////////////////////////////////////////////////////
-// nsAccEventQueue
-////////////////////////////////////////////////////////////////////////////////
-
-nsAccEventQueue::nsAccEventQueue(nsDocAccessible *aDocument):
-  mObservingRefresh(PR_FALSE), mDocument(aDocument)
-{
-}
-
-nsAccEventQueue::~nsAccEventQueue()
-{
-  NS_ASSERTION(!mDocument, "Queue wasn't shut down!");
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// nsAccEventQueue: nsISupports and cycle collection
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsAccEventQueue)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsAccEventQueue)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsAccEventQueue)
-  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDocument");
-  cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mDocument.get()));
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(mEvents, AccEvent)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsAccEventQueue)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mEvents)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAccEventQueue)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAccEventQueue)
-
-////////////////////////////////////////////////////////////////////////////////
-// nsAccEventQueue: public
-
-void
-nsAccEventQueue::Push(AccEvent* aEvent)
-{
-  mEvents.AppendElement(aEvent);
-
-  // Filter events.
-  CoalesceEvents();
-
-  // Associate text change with hide event if it wasn't stolen from hiding
-  // siblings during coalescence.
-  AccMutationEvent* showOrHideEvent = downcast_accEvent(aEvent);
-  if (showOrHideEvent && !showOrHideEvent->mTextChangeEvent)
-    CreateTextChangeEventFor(showOrHideEvent);
-
-  // Process events.
-  PrepareFlush();
-}
-
-void
-nsAccEventQueue::Shutdown()
-{
-  if (mObservingRefresh) {
-    nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
-    if (!shell ||
-        shell->RemoveRefreshObserver(this, Flush_Display)) {
-      mObservingRefresh = PR_FALSE;
-    }
-  }
-  mDocument = nsnull;
-  mEvents.Clear();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// nsAccEventQueue: private
-
-void
-nsAccEventQueue::PrepareFlush()
-{
-  // If there are pending events in the queue and events flush isn't planed
-  // yet start events flush asynchronously.
-  if (mEvents.Length() > 0 && !mObservingRefresh) {
-    nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
-    // Use a Flush_Display observer so that it will get called after
-    // style and ayout have been flushed.
-    if (shell &&
-        shell->AddRefreshObserver(this, Flush_Display)) {
-      mObservingRefresh = PR_TRUE;
-    }
-  }
-}
-
-void
-nsAccEventQueue::WillRefresh(mozilla::TimeStamp aTime)
-{
-  // If the document accessible is now shut down, don't fire events in it
-  // anymore.
-  if (!mDocument)
-    return;
-
-  // Process only currently queued events. Newly appended events during events
-  // flushing won't be processed.
-  nsTArray < nsRefPtr<AccEvent> > events;
-  events.SwapElements(mEvents);
-  PRUint32 length = events.Length();
-  NS_ASSERTION(length, "How did we get here without events to fire?");
-
-  for (PRUint32 index = 0; index < length; index ++) {
-
-    AccEvent* accEvent = events[index];
-    if (accEvent->mEventRule != AccEvent::eDoNotEmit) {
-      mDocument->ProcessPendingEvent(accEvent);
-
-      AccMutationEvent* showOrhideEvent = downcast_accEvent(accEvent);
-      if (showOrhideEvent) {
-        if (showOrhideEvent->mTextChangeEvent)
-          mDocument->ProcessPendingEvent(showOrhideEvent->mTextChangeEvent);
-      }
-    }
-
-    // No document means it was shut down during event handling by AT
-    if (!mDocument)
-      return;
-  }
-
-  if (mEvents.Length() == 0) {
-    nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
-    if (!shell ||
-        shell->RemoveRefreshObserver(this, Flush_Display)) {
-      mObservingRefresh = PR_FALSE;
-    }
-  }
-}
-
-void
-nsAccEventQueue::CoalesceEvents()
-{
-  PRUint32 numQueuedEvents = mEvents.Length();
-  PRInt32 tail = numQueuedEvents - 1;
-  AccEvent* tailEvent = mEvents[tail];
-
-  // No node means this is application accessible (which can be a subject
-  // of reorder events), we do not coalesce events for it currently.
-  if (!tailEvent->mNode)
-    return;
-
-  switch(tailEvent->mEventRule) {
-    case AccEvent::eCoalesceFromSameSubtree:
-    {
-      for (PRInt32 index = tail - 1; index >= 0; index--) {
-        AccEvent* thisEvent = mEvents[index];
-
-        if (thisEvent->mEventType != tailEvent->mEventType)
-          continue; // Different type
-
-        // Skip event for application accessible since no coalescence for it
-        // is supported. Ignore events from different documents since we don't
-        // coalesce them.
-        if (!thisEvent->mNode ||
-            thisEvent->mNode->GetOwnerDoc() != tailEvent->mNode->GetOwnerDoc())
-          continue;
-
-        // If event queue contains an event of the same type and having target
-        // that is sibling of target of newly appended event then apply its
-        // event rule to the newly appended event.
-
-        // XXX: deal with show events separately because they can't be
-        // coalesced by accessible tree the same as hide events since target
-        // accessibles can't be created at this point because of lazy frame
-        // construction (bug 570275).
-
-        // Coalesce hide and show events for sibling targets.
-        if (tailEvent->mEventType == nsIAccessibleEvent::EVENT_HIDE) {
-          AccHideEvent* tailHideEvent = downcast_accEvent(tailEvent);
-          AccHideEvent* thisHideEvent = downcast_accEvent(thisEvent);
-          if (thisHideEvent->mParent == tailHideEvent->mParent) {
-            tailEvent->mEventRule = thisEvent->mEventRule;
-
-            // Coalesce text change events for hide events.
-            if (tailEvent->mEventRule != AccEvent::eDoNotEmit)
-              CoalesceTextChangeEventsFor(tailHideEvent, thisHideEvent);
-
-            return;
-          }
-        } else if (tailEvent->mEventType == nsIAccessibleEvent::EVENT_SHOW) {
-          if (thisEvent->mAccessible->GetParent() ==
-              tailEvent->mAccessible->GetParent()) {
-            tailEvent->mEventRule = thisEvent->mEventRule;
-
-            // Coalesce text change events for show events.
-            if (tailEvent->mEventRule != AccEvent::eDoNotEmit) {
-              AccShowEvent* tailShowEvent = downcast_accEvent(tailEvent);
-              AccShowEvent* thisShowEvent = downcast_accEvent(thisEvent);
-              CoalesceTextChangeEventsFor(tailShowEvent, thisShowEvent);
-            }
-
-            return;
-          }
-        }
-
-        // Ignore events unattached from DOM since we don't coalesce them.
-        if (!thisEvent->mNode->IsInDoc())
-          continue;
-
-        // Coalesce earlier event for the same target.
-        if (thisEvent->mNode == tailEvent->mNode) {
-          thisEvent->mEventRule = AccEvent::eDoNotEmit;
-          return;
-        }
-
-        // Coalesce events by sibling targets (this is a case for reorder
-        // events).
-        if (thisEvent->mNode->GetNodeParent() ==
-            tailEvent->mNode->GetNodeParent()) {
-          tailEvent->mEventRule = thisEvent->mEventRule;
-          return;
-        }
-
-        // This and tail events can be anywhere in the tree, make assumptions
-        // for mutation events.
-
-        // Coalesce tail event if tail node is descendant of this node. Stop
-        // processing if tail event is coalesced since all possible descendants
-        // of this node was coalesced before.
-        // Note: more older hide event target (thisNode) can't contain recent
-        // hide event target (tailNode), i.e. be ancestor of tailNode. Skip
-        // this check for hide events.
-        if (tailEvent->mEventType != nsIAccessibleEvent::EVENT_HIDE &&
-            nsCoreUtils::IsAncestorOf(thisEvent->mNode, tailEvent->mNode)) {
-          tailEvent->mEventRule = AccEvent::eDoNotEmit;
-          return;
-        }
-
-        // If this node is a descendant of tail node then coalesce this event,
-        // check other events in the queue. Do not emit thisEvent, also apply
-        // this result to sibling nodes of thisNode.
-        if (nsCoreUtils::IsAncestorOf(tailEvent->mNode, thisEvent->mNode)) {
-          thisEvent->mEventRule = AccEvent::eDoNotEmit;
-          ApplyToSiblings(0, index, thisEvent->mEventType,
-                          thisEvent->mNode, AccEvent::eDoNotEmit);
-          continue;
-        }
-
-      } // for (index)
-
-    } break; // case eCoalesceFromSameSubtree
-
-    case AccEvent::eCoalesceFromSameDocument:
-    {
-      // Used for focus event, coalesce more older event since focus event
-      // for accessible can be duplicated by event for its document, we are
-      // interested in focus event for accessible.
-      for (PRInt32 index = tail - 1; index >= 0; index--) {
-        AccEvent* thisEvent = mEvents[index];
-        if (thisEvent->mEventType == tailEvent->mEventType &&
-            thisEvent->mEventRule == tailEvent->mEventRule &&
-            thisEvent->GetDocAccessible() == tailEvent->GetDocAccessible()) {
-          thisEvent->mEventRule = AccEvent::eDoNotEmit;
-          return;
-        }
-      }
-    } break; // case eCoalesceFromSameDocument
-
-    case AccEvent::eRemoveDupes:
-    {
-      // Check for repeat events, coalesce newly appended event by more older
-      // event.
-      for (PRInt32 index = tail - 1; index >= 0; index--) {
-        AccEvent* accEvent = mEvents[index];
-        if (accEvent->mEventType == tailEvent->mEventType &&
-            accEvent->mEventRule == tailEvent->mEventRule &&
-            accEvent->mNode == tailEvent->mNode) {
-          tailEvent->mEventRule = AccEvent::eDoNotEmit;
-          return;
-        }
-      }
-    } break; // case eRemoveDupes
-
-    default:
-      break; // case eAllowDupes, eDoNotEmit
-  } // switch
-}
-
-void
-nsAccEventQueue::ApplyToSiblings(PRUint32 aStart, PRUint32 aEnd,
-                                 PRUint32 aEventType, nsINode* aNode,
-                                 AccEvent::EEventRule aEventRule)
-{
-  for (PRUint32 index = aStart; index < aEnd; index ++) {
-    AccEvent* accEvent = mEvents[index];
-    if (accEvent->mEventType == aEventType &&
-        accEvent->mEventRule != AccEvent::eDoNotEmit && accEvent->mNode &&
-        accEvent->mNode->GetNodeParent() == aNode->GetNodeParent()) {
-      accEvent->mEventRule = aEventRule;
-    }
-  }
-}
-
-void
-nsAccEventQueue::CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
-                                             AccHideEvent* aThisEvent)
-{
-  // XXX: we need a way to ignore SplitNode and JoinNode() when they do not
-  // affect the text within the hypertext.
-
-  AccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent;
-  if (!textEvent)
-    return;
-
-  if (aThisEvent->mNextSibling == aTailEvent->mAccessible) {
-    aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText,
-                                          0, PR_UINT32_MAX);
-
-  } else if (aThisEvent->mPrevSibling == aTailEvent->mAccessible) {
-    PRUint32 oldLen = textEvent->GetLength();
-    aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText,
-                                          0, PR_UINT32_MAX);
-    textEvent->mStart -= textEvent->GetLength() - oldLen;
-  }
-
-  aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent);
-}
-
-void
-nsAccEventQueue::CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent,
-                                             AccShowEvent* aThisEvent)
-{
-  AccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent;
-  if (!textEvent)
-    return;
-
-  if (aTailEvent->mAccessible->GetIndexInParent() ==
-      aThisEvent->mAccessible->GetIndexInParent() + 1) {
-    // If tail target was inserted after this target, i.e. tail target is next
-    // sibling of this target.
-    aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText,
-                                          0, PR_UINT32_MAX);
-
-  } else if (aTailEvent->mAccessible->GetIndexInParent() ==
-             aThisEvent->mAccessible->GetIndexInParent() -1) {
-    // If tail target was inserted before this target, i.e. tail target is
-    // previous sibling of this target.
-    nsAutoString startText;
-    aTailEvent->mAccessible->AppendTextTo(startText, 0, PR_UINT32_MAX);
-    textEvent->mModifiedText = startText + textEvent->mModifiedText;
-    textEvent->mStart -= startText.Length();
-  }
-
-  aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent);
-}
-
-void
-nsAccEventQueue::CreateTextChangeEventFor(AccMutationEvent* aEvent)
-{
-  nsRefPtr<nsHyperTextAccessible> textAccessible = do_QueryObject(
-    GetAccService()->GetContainerAccessible(aEvent->mNode,
-                                            aEvent->mAccessible->GetWeakShell()));
-  if (!textAccessible)
-    return;
-
-  // Don't fire event for the first html:br in an editor.
-  if (aEvent->mAccessible->Role() == nsIAccessibleRole::ROLE_WHITESPACE) {
-    nsCOMPtr<nsIEditor> editor;
-    textAccessible->GetAssociatedEditor(getter_AddRefs(editor));
-    if (editor) {
-      PRBool isEmpty = PR_FALSE;
-      editor->GetDocumentIsEmpty(&isEmpty);
-      if (isEmpty)
-        return;
-    }
-  }
-
-  PRInt32 offset = textAccessible->GetChildOffset(aEvent->mAccessible);
-
-  nsAutoString text;
-  aEvent->mAccessible->AppendTextTo(text, 0, PR_UINT32_MAX);
-  if (text.IsEmpty())
-    return;
-
-  aEvent->mTextChangeEvent =
-    new AccTextChangeEvent(textAccessible, offset, text, aEvent->IsShow(),
-                           aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput);
-}
--- a/accessible/src/base/nsEventShell.h
+++ b/accessible/src/base/nsEventShell.h
@@ -36,22 +36,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsEventShell_H_
 #define _nsEventShell_H_
 
 #include "AccEvent.h"
 
-#include "a11yGeneric.h"
-
-#include "nsAutoPtr.h"
-
-#include "nsRefreshDriver.h"
-
 class nsIPersistentProperties;
 
 /**
  * Used for everything about events.
  */
 class nsEventShell
 {
 public:
@@ -80,105 +74,9 @@ public:
   static void GetEventAttributes(nsINode *aNode,
                                  nsIPersistentProperties *aAttributes);
 
 private:
   static nsCOMPtr<nsINode> sEventTargetNode;
   static PRBool sEventFromUserInput;
 };
 
-
-/**
- * Event queue.
- */
-class nsAccEventQueue : public nsISupports,
-                        public nsARefreshObserver
-{
-public:
-  nsAccEventQueue(nsDocAccessible *aDocument);
-  ~nsAccEventQueue();
-
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS(nsAccEventQueue)
-
-  /**
-   * Push event to queue, coalesce it if necessary. Start pending processing.
-   */
-  void Push(AccEvent* aEvent);
-
-  /**
-   * Shutdown the queue.
-   */
-  void Shutdown();
-
-private:
-
-  /**
-   * Start pending events processing asynchronously.
-   */
-  void PrepareFlush();
-  
-  /**
-   * Process pending events. It calls nsDocAccessible::ProcessPendingEvent()
-   * where the real event processing is happen.
-   */
-  virtual void WillRefresh(mozilla::TimeStamp aTime);
-
-  /**
-   * Coalesce redundant events from the queue.
-   */
-  void CoalesceEvents();
-
-  /**
-   * Apply aEventRule to same type event that from sibling nodes of aDOMNode.
-   * @param aEventsToFire    array of pending events
-   * @param aStart           start index of pending events to be scanned
-   * @param aEnd             end index to be scanned (not included)
-   * @param aEventType       target event type
-   * @param aDOMNode         target are siblings of this node
-   * @param aEventRule       the event rule to be applied
-   *                         (should be eDoNotEmit or eAllowDupes)
-   */
-  void ApplyToSiblings(PRUint32 aStart, PRUint32 aEnd,
-                       PRUint32 aEventType, nsINode* aNode,
-                       AccEvent::EEventRule aEventRule);
-
-  /**
-   * Do not emit one of two given reorder events fired for DOM nodes in the case
-   * when one DOM node is in parent chain of second one.
-   */
-  void CoalesceReorderEventsFromSameTree(AccEvent* aAccEvent,
-                                         AccEvent* aDescendantAccEvent);
-
-  /**
-   * Coalesce text change events caused by sibling hide events.
-   */
-  void CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
-                                   AccHideEvent* aThisEvent);
-  void CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent,
-                                   AccShowEvent* aThisEvent);
-
-  /**
-   * Create text change event caused by hide or show event. When a node is
-   * hidden/removed or shown/appended, the text in an ancestor hyper text will
-   * lose or get new characters.
-   */
-  void CreateTextChangeEventFor(AccMutationEvent* aEvent);
-
-  /**
-   * Indicates whether we're waiting on a refresh notification from our
-   * presshell to flush events
-   */
-  PRBool mObservingRefresh;
-
-  /**
-   * The document accessible reference owning this queue.
-   */
-  nsRefPtr<nsDocAccessible> mDocument;
-
-  /**
-   * Pending events array.  Don't make this an nsAutoTArray; we use
-   * SwapElements() on it.
-   */
-  nsTArray<nsRefPtr<AccEvent> > mEvents;
-};
-
 #endif
--- a/accessible/src/base/nsOuterDocAccessible.cpp
+++ b/accessible/src/base/nsOuterDocAccessible.cpp
@@ -185,17 +185,17 @@ nsOuterDocAccessible::InvalidateChildren
   // document accessible lifetime when DOM document is created or destroyed. If
   // DOM document isn't destroyed but its presshell is destroyed (for example,
   // when DOM node of outerdoc accessible is hidden), then outerdoc accessible
   // notifies nsAccDocManager about this. If presshell is created for existing
   // DOM document (for example when DOM node of outerdoc accessible is shown)
   // then allow nsAccDocManager to handle this case since the document
   // accessible is created and appended as a child when it's requested.
 
-  mChildrenFlags = eChildrenUninitialized;
+  SetChildrenFlag(eChildrenUninitialized);
 }
 
 PRBool
 nsOuterDocAccessible::AppendChild(nsAccessible *aAccessible)
 {
   // We keep showing the old document for a bit after creating the new one,
   // and while building the new DOM and frame tree. That's done on purpose
   // to avoid weird flashes of default background color.
@@ -238,21 +238,16 @@ nsOuterDocAccessible::RemoveChild(nsAcce
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible protected
 
 void
 nsOuterDocAccessible::CacheChildren()
 {
   // Request document accessible for the content document to make sure it's
-  // created because once it's created it appends itself as a child.
-  nsIDocument *outerDoc = mContent->GetCurrentDoc();
-  if (!outerDoc)
-    return;
-
-  nsIDocument *innerDoc = outerDoc->GetSubDocumentFor(mContent);
-  if (!innerDoc)
-    return;
-
-  nsDocAccessible *docAcc = GetAccService()->GetDocAccessible(innerDoc);
-  NS_ASSERTION(docAcc && docAcc->GetParent() == this,
-               "Document accessible isn't a child of outerdoc accessible!");
+  // created. It will appended to outerdoc accessible children asynchronously.
+  nsIDocument* outerDoc = mContent->GetCurrentDoc();
+  if (outerDoc) {
+    nsIDocument* innerDoc = outerDoc->GetSubDocumentFor(mContent);
+    if (innerDoc)
+      GetAccService()->GetDocAccessible(innerDoc);
+  }
 }
--- a/accessible/src/base/nsRelUtils.cpp
+++ b/accessible/src/base/nsRelUtils.cpp
@@ -34,17 +34,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsRelUtils.h"
 
 #include "nsAccessibilityService.h"
-#include "nsAccessNode.h"
+#include "nsAccessible.h"
 #include "nsCoreUtils.h"
 
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMDocumentXBL.h"
 
 #include "nsAutoPtr.h"
 #include "nsArrayUtils.h"
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -309,142 +309,107 @@ nsresult nsRootAccessible::RemoveEventLi
 }
 
 nsCaretAccessible*
 nsRootAccessible::GetCaretAccessible()
 {
   return mCaretAccessible;
 }
 
-PRBool
-nsRootAccessible::FireAccessibleFocusEvent(nsAccessible *aAccessible,
-                                           nsINode *aNode,
-                                           nsIDOMEvent *aFocusEvent,
+void
+nsRootAccessible::FireAccessibleFocusEvent(nsAccessible* aFocusAccessible,
+                                           nsIContent* aRealFocusContent,
                                            PRBool aForceEvent,
                                            EIsFromUserInput aIsFromUserInput)
 {
   // Implementors: only fire delayed/async events from this method.
 
-  if (mCaretAccessible) {
-    nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aFocusEvent));
-    if (nsevent) {
-      // Use the originally focused node where the selection lives.
-      // For example, use the anonymous HTML:input instead of the containing
-      // XUL:textbox. In this case, sometimes it is a later focus event
-      // which points to the actual anonymous child with focus, so to be safe 
-      // we need to reset the selection listener every time.
-      // This happens because when some bindings handle focus, they retarget
-      // focus to the appropriate child inside of themselves, but DOM focus
-      // stays outside on that binding parent.
-      nsCOMPtr<nsIDOMEventTarget> domEventTarget;
-      nsevent->GetOriginalTarget(getter_AddRefs(domEventTarget));
-      nsCOMPtr<nsIContent> realFocusedNode(do_QueryInterface(domEventTarget));
-      if (!realFocusedNode) {
-        // When FireCurrentFocusEvent() synthesizes a focus event,
-        // the orignal target does not exist, so use the passed-in node
-        // which is the relevant focused node
-        realFocusedNode = do_QueryInterface(aNode);
-      }
-      if (realFocusedNode) {
-        mCaretAccessible->SetControlSelectionListener(realFocusedNode);
+  // Set selection listener for focused element.
+  if (mCaretAccessible && aRealFocusContent)
+    mCaretAccessible->SetControlSelectionListener(aRealFocusContent);
+
+  nsAccessible* focusAccessible = aFocusAccessible;
+
+  // Check for aria-activedescendant, which changes which element has focus.
+  // For activedescendant, the ARIA spec does not require that the user agent
+  // checks whether pointed node is actually a DOM descendant of the element
+  // with the aria-activedescendant attribute.
+  nsIContent* content = focusAccessible->GetContent();
+  if (content) {
+    nsAutoString id;
+    if (content->GetAttr(kNameSpaceID_None,
+                         nsAccessibilityAtoms::aria_activedescendant, id)) {
+      nsIDocument* DOMDoc = content->GetOwnerDoc();
+      nsIContent* activeDescendantContent = DOMDoc->GetElementById(id);
+
+      // If aria-activedescendant is set to nonexistant ID, then treat as focus
+      // on the activedescendant container (which has real DOM focus).
+      if (activeDescendantContent) {
+        nsAccessible* activeDescendant = 
+          GetAccService()->GetAccessible(activeDescendantContent);
+        if (activeDescendant) {
+          focusAccessible = activeDescendant;
+        }
       }
     }
   }
 
-  // Check for aria-activedescendant, which changes which element has focus
-  nsINode *finalFocusNode = aNode;
-  nsAccessible *finalFocusAccessible = aAccessible;
+  // Fire focus only if it changes, but always fire focus events when
+  // aForceEvent == PR_TRUE
+  nsINode* focusNode = focusAccessible->GetNode();
+  if (gLastFocusedNode == focusNode && !aForceEvent)
+    return;
 
-  nsIContent *finalFocusContent = nsCoreUtils::GetRoleContent(finalFocusNode);
-  if (finalFocusContent) {
-    nsAutoString id;
-    if (finalFocusContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_activedescendant, id)) {
-      nsIDocument *doc = aNode->GetOwnerDoc();
-      finalFocusNode = doc->GetElementById(id);
-      if (!finalFocusNode) {
-        // If aria-activedescendant is set to nonexistant ID, then treat as focus
-        // on the activedescendant container (which has real DOM focus)
-        finalFocusNode = aNode;
-      }
-      finalFocusAccessible = nsnull;
-    }
-  }
+  nsDocAccessible* focusDocument = focusAccessible->GetDocAccessible();
+  NS_ASSERTION(focusDocument, "No document while accessible is in document?!");
 
-  // Fire focus only if it changes, but always fire focus events when aForceEvent == PR_TRUE
-  if (gLastFocusedNode == finalFocusNode && !aForceEvent) {
-    return PR_FALSE;
-  }
+  gLastFocusedAccessiblesState = nsAccUtils::State(focusAccessible);
 
-  if (!finalFocusAccessible) {
-    finalFocusAccessible = GetAccService()->GetAccessible(finalFocusNode);
-    // For activedescendant, the ARIA spec does not require that the user agent
-    // checks whether finalFocusNode is actually a DOM descendant of the element
-    // with the aria-activedescendant attribute.
-    if (!finalFocusAccessible) {
-      return PR_FALSE;
-    }
-  }
-
-  gLastFocusedAccessiblesState = nsAccUtils::State(finalFocusAccessible);
-  PRUint32 role = finalFocusAccessible->Role();
-  if (role == nsIAccessibleRole::ROLE_MENUITEM) {
-    if (!mCurrentARIAMenubar) {  // Entering menus
-      // The natural role is the role that this type of element normally has
-      if (role != finalFocusAccessible->NativeRole()) { // Must be a DHTML menuitem
-        nsAccessible *menuBarAccessible =
-          nsAccUtils::GetAncestorWithRole(finalFocusAccessible,
-                                          nsIAccessibleRole::ROLE_MENUBAR);
-        if (menuBarAccessible) {
-          mCurrentARIAMenubar = menuBarAccessible->GetNode();
-          if (mCurrentARIAMenubar) {
-            nsRefPtr<AccEvent> menuStartEvent =
-              new AccEvent(nsIAccessibleEvent::EVENT_MENU_START,
-                           menuBarAccessible, aIsFromUserInput,
-                           AccEvent::eAllowDupes);
-            if (menuStartEvent) {
-              FireDelayedAccessibleEvent(menuStartEvent);
-            }
-          }
+  // Fire menu start/end events for ARIA menus.
+  if (focusAccessible->ARIARole() == nsIAccessibleRole::ROLE_MENUITEM) {
+    // The focus is inside a menu.
+    if (!mCurrentARIAMenubar) {
+      // Entering ARIA menu. Fire menu start event.
+      nsAccessible* menuBarAccessible =
+        nsAccUtils::GetAncestorWithRole(focusAccessible,
+                                        nsIAccessibleRole::ROLE_MENUBAR);
+      if (menuBarAccessible) {
+        mCurrentARIAMenubar = menuBarAccessible->GetNode();
+        if (mCurrentARIAMenubar) {
+          nsRefPtr<AccEvent> menuStartEvent =
+            new AccEvent(nsIAccessibleEvent::EVENT_MENU_START,
+                         menuBarAccessible, aIsFromUserInput,
+                         AccEvent::eAllowDupes);
+          if (menuStartEvent)
+            focusDocument->FireDelayedAccessibleEvent(menuStartEvent);
         }
       }
     }
   }
   else if (mCurrentARIAMenubar) {
+    // Focus left a menu. Fire menu end event.
     nsRefPtr<AccEvent> menuEndEvent =
       new AccEvent(nsIAccessibleEvent::EVENT_MENU_END, mCurrentARIAMenubar,
                    aIsFromUserInput, AccEvent::eAllowDupes);
     if (menuEndEvent) {
-      FireDelayedAccessibleEvent(menuEndEvent);
+      focusDocument->FireDelayedAccessibleEvent(menuEndEvent);
     }
     mCurrentARIAMenubar = nsnull;
   }
 
-  nsCOMPtr<nsIContent> focusContent = do_QueryInterface(finalFocusNode);
-  nsIFrame *focusFrame = nsnull;
-  if (focusContent) {
-    nsIPresShell *shell = nsCoreUtils::GetPresShellFor(finalFocusNode);
-
-    NS_ASSERTION(shell, "No pres shell for final focus node!");
-    if (!shell)
-      return PR_FALSE;
-
-    focusFrame = focusContent->GetPrimaryFrame();
-  }
-
   NS_IF_RELEASE(gLastFocusedNode);
-  gLastFocusedNode = finalFocusNode;
+  gLastFocusedNode = focusNode;
   NS_IF_ADDREF(gLastFocusedNode);
 
   // Coalesce focus events from the same document, because DOM focus event might
   // be fired for the document node and then for the focused DOM element.
-  FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_FOCUS,
-                             finalFocusNode, AccEvent::eCoalesceFromSameDocument,
-                             aIsFromUserInput);
-
-  return PR_TRUE;
+  focusDocument->FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_FOCUS,
+                                            focusNode,
+                                            AccEvent::eCoalesceFromSameDocument,
+                                            aIsFromUserInput);
 }
 
 void
 nsRootAccessible::FireCurrentFocusEvent()
 {
   if (IsDefunct())
     return;
 
@@ -469,67 +434,122 @@ nsRootAccessible::FireCurrentFocusEvent(
     }
   }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIDOMEventListener
 
 NS_IMETHODIMP
-nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
+nsRootAccessible::HandleEvent(nsIDOMEvent* aDOMEvent)
 {
-  nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aEvent));
-  NS_ENSURE_STATE(nsevent);
+  nsCOMPtr<nsIDOMNSEvent> DOMNSEvent(do_QueryInterface(aDOMEvent));
+  nsCOMPtr<nsIDOMEventTarget> DOMEventTarget;
+  DOMNSEvent->GetOriginalTarget(getter_AddRefs(DOMEventTarget));
+  nsCOMPtr<nsINode> origTargetNode(do_QueryInterface(DOMEventTarget));
+  if (!origTargetNode)
+    return NS_OK;
+
+  nsDocAccessible* document =
+    GetAccService()->GetDocAccessible(origTargetNode->GetOwnerDoc());
+
+  if (document) {
+#ifdef DEBUG_NOTIFICATIONS
+    if (origTargetNode->IsElement()) {
+      nsIContent* elm = origTargetNode->AsElement();
+
+      nsAutoString tag;
+      elm->Tag()->ToString(tag);
+
+      nsIAtom* atomid = elm->GetID();
+      nsCAutoString id;
+      if (atomid)
+        atomid->ToUTF8String(id);
 
-  nsCOMPtr<nsIDOMEventTarget> domEventTarget;
-  nsevent->GetOriginalTarget(getter_AddRefs(domEventTarget));
-  nsCOMPtr<nsINode> origTarget(do_QueryInterface(domEventTarget));
-  NS_ENSURE_STATE(origTarget);
+      nsAutoString eventType;
+      aDOMEvent->GetType(eventType);
+
+      printf("\nPend DOM event processing for %s@id='%s', type: %s\n\n",
+             NS_ConvertUTF16toUTF8(tag).get(), id.get(),
+             NS_ConvertUTF16toUTF8(eventType).get());
+    }
+#endif
+
+    // Root accessible exists longer than any of its descendant documents so
+    // that we are guaranteed notification is processed before root accessible
+    // is destroyed.
+    document->HandleNotification<nsRootAccessible, nsIDOMEvent>
+      (this, &nsRootAccessible::ProcessDOMEvent, aDOMEvent);
+  }
+
+  return NS_OK;
+}
+
+// nsRootAccessible protected
+void
+nsRootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
+{
+  nsCOMPtr<nsIDOMNSEvent> DOMNSEvent(do_QueryInterface(aDOMEvent));
+  nsCOMPtr<nsIDOMEventTarget> DOMEventTarget;
+  DOMNSEvent->GetOriginalTarget(getter_AddRefs(DOMEventTarget));
+  nsCOMPtr<nsINode> origTargetNode(do_QueryInterface(DOMEventTarget));
 
   nsAutoString eventType;
-  aEvent->GetType(eventType);
+  aDOMEvent->GetType(eventType);
 
   nsCOMPtr<nsIWeakReference> weakShell =
-    nsCoreUtils::GetWeakShellFor(origTarget);
+    nsCoreUtils::GetWeakShellFor(origTargetNode);
   if (!weakShell)
-    return NS_OK;
+    return;
 
   nsAccessible* accessible =
-    GetAccService()->GetAccessibleOrContainer(origTarget, weakShell);
+    GetAccService()->GetAccessibleOrContainer(origTargetNode, weakShell);
 
-  if (eventType.EqualsLiteral("popuphiding"))
-    return HandlePopupHidingEvent(origTarget, accessible);
+  if (eventType.EqualsLiteral("popuphiding")) {
+    HandlePopupHidingEvent(origTargetNode, accessible);
+    return;
+  }
 
   if (!accessible)
-    return NS_OK;
+    return;
+
+  nsDocAccessible* targetDocument = accessible->GetDocAccessible();
+  NS_ASSERTION(targetDocument, "No document while accessible is in document?!");
 
   nsINode* targetNode = accessible->GetNode();
   nsIContent* targetContent = targetNode->IsElement() ?
     targetNode->AsElement() : nsnull;
+  nsIContent* origTargetContent = origTargetNode->IsElement() ?
+    origTargetNode->AsElement() : nsnull;
+
 #ifdef MOZ_XUL
   PRBool isTree = targetContent ?
     targetContent->NodeInfo()->Equals(nsAccessibilityAtoms::tree,
                                       kNameSpaceID_XUL) : PR_FALSE;
 
   if (isTree) {
     nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(accessible);
     NS_ASSERTION(treeAcc,
                  "Accessible for xul:tree isn't nsXULTreeAccessible.");
 
     if (treeAcc) {
       if (eventType.EqualsLiteral("TreeViewChanged")) {
         treeAcc->TreeViewChanged();
-        return NS_OK;
+        return;
       }
 
-      if (eventType.EqualsLiteral("TreeRowCountChanged"))
-        return HandleTreeRowCountChangedEvent(aEvent, treeAcc);
+      if (eventType.EqualsLiteral("TreeRowCountChanged")) {
+        HandleTreeRowCountChangedEvent(aDOMEvent, treeAcc);
+        return;
+      }
       
-      if (eventType.EqualsLiteral("TreeInvalidated"))
-        return HandleTreeInvalidatedEvent(aEvent, treeAcc);
+      if (eventType.EqualsLiteral("TreeInvalidated")) {
+        HandleTreeInvalidatedEvent(aDOMEvent, treeAcc);
+        return;
+      }
     }
   }
 #endif
 
   if (eventType.EqualsLiteral("RadioStateChange")) {
     PRUint32 state = nsAccUtils::State(accessible);
 
     // radiogroup in prefWindow is exposed as a list,
@@ -540,32 +560,32 @@ nsRootAccessible::HandleEvent(nsIDOMEven
                         nsIAccessibleStates::STATE_SELECTED)) != 0;
 
     nsRefPtr<AccEvent> accEvent =
       new AccStateChangeEvent(accessible, nsIAccessibleStates::STATE_CHECKED,
                               PR_FALSE, isEnabled);
     nsEventShell::FireEvent(accEvent);
 
     if (isEnabled)
-      FireAccessibleFocusEvent(accessible, targetNode, aEvent);
+      FireAccessibleFocusEvent(accessible, origTargetContent);
 
-    return NS_OK;
+    return;
   }
 
   if (eventType.EqualsLiteral("CheckboxStateChange")) {
     PRUint32 state = nsAccUtils::State(accessible);
 
     PRBool isEnabled = !!(state & nsIAccessibleStates::STATE_CHECKED);
 
     nsRefPtr<AccEvent> accEvent =
       new AccStateChangeEvent(accessible, nsIAccessibleStates::STATE_CHECKED,
                               PR_FALSE, isEnabled);
 
     nsEventShell::FireEvent(accEvent);
-    return NS_OK;
+    return;
   }
 
   nsAccessible *treeItemAccessible = nsnull;
 #ifdef MOZ_XUL
   // If it's a tree element, need the currently selected item
   if (isTree) {
     nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelect =
       do_QueryInterface(targetNode);
@@ -588,39 +608,39 @@ nsRootAccessible::HandleEvent(nsIDOMEven
   if (treeItemAccessible && eventType.EqualsLiteral("OpenStateChange")) {
     PRUint32 state = nsAccUtils::State(accessible); // collapsed/expanded changed
     PRBool isEnabled = (state & nsIAccessibleStates::STATE_EXPANDED) != 0;
 
     nsRefPtr<AccEvent> accEvent =
       new AccStateChangeEvent(accessible, nsIAccessibleStates::STATE_EXPANDED,
                               PR_FALSE, isEnabled);
     nsEventShell::FireEvent(accEvent);
-    return NS_OK;
+    return;
   }
 
   if (treeItemAccessible && eventType.EqualsLiteral("select")) {
     // If multiselect tree, we should fire selectionadd or selection removed
     if (gLastFocusedNode == targetNode) {
       nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSel =
         do_QueryInterface(targetNode);
       nsAutoString selType;
       multiSel->GetSelType(selType);
       if (selType.IsEmpty() || !selType.EqualsLiteral("single")) {
         // XXX: We need to fire EVENT_SELECTION_ADD and EVENT_SELECTION_REMOVE
         // for each tree item. Perhaps each tree item will need to cache its
         // selection state and fire an event after a DOM "select" event when
         // that state changes. nsXULTreeAccessible::UpdateTreeSelection();
         nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN,
                                 accessible);
-        return NS_OK;
+        return;
       }
 
       nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION,
                               treeItemAccessible);
-      return NS_OK;
+      return;
     }
   }
   else
 #endif
   if (eventType.EqualsLiteral("focus")) {
     // Keep a reference to the target node. We might want to change
     // it to the individual radio button or selected item, and send
     // the focus event to that.
@@ -635,26 +655,26 @@ nsRootAccessible::HandleEvent(nsIDOMEven
           // Don't do this for menu lists, the items only get focused
           // when the list is open, based on DOMMenuitemActive events
           nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem;
           selectControl->GetSelectedItem(getter_AddRefs(selectedItem));
           if (selectedItem)
             focusedItem = do_QueryInterface(selectedItem);
 
           if (!focusedItem)
-            return NS_OK;
+            return;
 
           accessible = GetAccService()->GetAccessibleInWeakShell(focusedItem,
                                                                  weakShell);
           if (!accessible)
-            return NS_OK;
+            return;
         }
       }
     }
-    FireAccessibleFocusEvent(accessible, focusedItem, aEvent);
+    FireAccessibleFocusEvent(accessible, origTargetContent);
   }
   else if (eventType.EqualsLiteral("blur")) {
     NS_IF_RELEASE(gLastFocusedNode);
     gLastFocusedAccessiblesState = 0;
   }
   else if (eventType.EqualsLiteral("AlertActive")) { 
     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_ALERT, accessible);
   }
@@ -667,42 +687,45 @@ nsRootAccessible::HandleEvent(nsIDOMEven
                               accessible);
     }
   }
   else if (eventType.EqualsLiteral("DOMMenuItemActive")) {
     PRBool fireFocus = PR_FALSE;
     if (!treeItemAccessible) {
 #ifdef MOZ_XUL
       if (isTree) {
-        return NS_OK; // Tree with nothing selected
+        return; // Tree with nothing selected
       }
 #endif
       nsIFrame* menuFrame = accessible->GetFrame();
-      NS_ENSURE_TRUE(menuFrame, NS_ERROR_FAILURE);
+      if (!menuFrame)
+        return;
 
       nsIMenuFrame* imenuFrame = do_QueryFrame(menuFrame);
       if (imenuFrame)
         fireFocus = PR_TRUE;
       // QI failed for nsIMenuFrame means it's not on menu bar
       if (imenuFrame && imenuFrame->IsOnMenuBar() &&
                        !imenuFrame->IsOnActiveMenuBar()) {
         // It is a top level menuitem. Only fire a focus event when the menu bar
         // is active.
-        return NS_OK;
+        return;
       } else {
         nsAccessible *containerAccessible = accessible->GetParent();
-        NS_ENSURE_TRUE(containerAccessible, NS_ERROR_FAILURE);
+        if (!containerAccessible)
+          return;
         // It is not top level menuitem
         // Only fire focus event if it is not inside collapsed popup
         // and not a listitem of a combo box
         if (nsAccUtils::State(containerAccessible) & nsIAccessibleStates::STATE_COLLAPSED) {
           nsAccessible *containerParent = containerAccessible->GetParent();
-          NS_ENSURE_TRUE(containerParent, NS_ERROR_FAILURE);
+          if (!containerParent)
+            return;
           if (containerParent->Role() != nsIAccessibleRole::ROLE_COMBOBOX) {
-            return NS_OK;
+            return;
           }
         }
       }
     }
     if (!fireFocus) {
       nsCOMPtr<nsINode> realFocusedNode = GetCurrentFocus();
       nsIContent* realFocusedContent =
         realFocusedNode->IsElement() ? realFocusedNode->AsElement() : nsnull;
@@ -715,40 +738,40 @@ nsRootAccessible::HandleEvent(nsIDOMEven
           fireFocus = PR_TRUE;
           break;
         }
         containerContent = containerContent->GetParent();
       }
     }
     if (fireFocus) {
       // Always asynch, always from user input.
-      FireAccessibleFocusEvent(accessible, targetNode, aEvent, PR_TRUE,
+      FireAccessibleFocusEvent(accessible, origTargetContent, PR_TRUE,
                                eFromUserInput);
     }
   }
   else if (eventType.EqualsLiteral("DOMMenuBarActive")) {  // Always from user input
     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_START,
                             accessible, eFromUserInput);
   }
   else if (eventType.EqualsLiteral("DOMMenuBarInactive")) {  // Always from user input
     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_END,
                             accessible, eFromUserInput);
     FireCurrentFocusEvent();
   }
   else if (eventType.EqualsLiteral("ValueChange")) {
-    FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
-                               targetNode, AccEvent::eRemoveDupes);
+    targetDocument->
+      FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
+                                 targetNode, AccEvent::eRemoveDupes);
   }
 #ifdef DEBUG_DRAGDROPSTART
   else if (eventType.EqualsLiteral("mouseover")) {
     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_DRAGDROP_START,
                             accessible);
   }
 #endif
-  return NS_OK;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNode
 
 void
 nsRootAccessible::Shutdown()
@@ -837,137 +860,128 @@ nsRootAccessible::GetRelationByType(PRUi
   }
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Protected members
 
-nsresult
-nsRootAccessible::HandlePopupShownEvent(nsAccessible *aAccessible)
+void
+nsRootAccessible::HandlePopupShownEvent(nsAccessible* aAccessible)
 {
   PRUint32 role = aAccessible->Role();
 
   if (role == nsIAccessibleRole::ROLE_MENUPOPUP) {
     // Don't fire menupopup events for combobox and autocomplete lists.
     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
                             aAccessible);
-    return NS_OK;
+    return;
   }
 
   if (role == nsIAccessibleRole::ROLE_TOOLTIP) {
     // There is a single <xul:tooltip> node which Mozilla moves around.
     // The accessible for it stays the same no matter where it moves. 
     // AT's expect to get an EVENT_SHOW for the tooltip. 
     // In event callback the tooltip's accessible will be ready.
     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SHOW, aAccessible);
-    return NS_OK;
+    return;
   }
 
   if (role == nsIAccessibleRole::ROLE_COMBOBOX_LIST) {
     // Fire expanded state change event for comboboxes and autocompeletes.
     nsAccessible* combobox = aAccessible->GetParent();
-    NS_ENSURE_STATE(combobox);
+    if (!combobox)
+      return;
 
     PRUint32 comboboxRole = combobox->Role();
     if (comboboxRole == nsIAccessibleRole::ROLE_COMBOBOX ||
         comboboxRole == nsIAccessibleRole::ROLE_AUTOCOMPLETE) {
       nsRefPtr<AccEvent> event =
         new AccStateChangeEvent(combobox,
                                 nsIAccessibleStates::STATE_EXPANDED,
                                 PR_FALSE, PR_TRUE);
-      NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
-
-      nsEventShell::FireEvent(event);
-      return NS_OK;
+      if (event)
+        nsEventShell::FireEvent(event);
     }
   }
-
-  return NS_OK;
 }
 
-nsresult
-nsRootAccessible::HandlePopupHidingEvent(nsINode *aNode,
-                                         nsAccessible *aAccessible)
+void
+nsRootAccessible::HandlePopupHidingEvent(nsINode* aNode,
+                                         nsAccessible* aAccessible)
 {
   // If accessible focus was on or inside popup that closes, then restore it
   // to true current focus. This is the case when we've been getting
   // DOMMenuItemActive events inside of a combo box that closes. The real focus
   // is on the combo box. It's also the case when a popup gets focus in ATK --
   // when it closes we need to fire an event to restore focus to where it was.
 
   if (gLastFocusedNode &&
       nsCoreUtils::IsAncestorOf(aNode, gLastFocusedNode)) {
     // Focus was on or inside of a popup that's being hidden
     FireCurrentFocusEvent();
   }
 
   // Fire expanded state change event for comboboxes and autocompletes.
-  if (!aAccessible)
-    return NS_OK;
-
-  if (aAccessible->Role() != nsIAccessibleRole::ROLE_COMBOBOX_LIST)
-    return NS_OK;
+  if (!aAccessible ||
+      aAccessible->Role() != nsIAccessibleRole::ROLE_COMBOBOX_LIST)
+    return;
 
   nsAccessible* combobox = aAccessible->GetParent();
-  NS_ENSURE_STATE(combobox);
+  if (!combobox)
+    return;
 
   PRUint32 comboboxRole = combobox->Role();
   if (comboboxRole == nsIAccessibleRole::ROLE_COMBOBOX ||
       comboboxRole == nsIAccessibleRole::ROLE_AUTOCOMPLETE) {
     nsRefPtr<AccEvent> event =
       new AccStateChangeEvent(combobox,
                               nsIAccessibleStates::STATE_EXPANDED,
                               PR_FALSE, PR_FALSE);
-    NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
-
-    nsEventShell::FireEvent(event);
-    return NS_OK;
+    if (event)
+      nsEventShell::FireEvent(event);
   }
-
-  return NS_OK;
 }
 
 #ifdef MOZ_XUL
-nsresult
-nsRootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
-                                                 nsXULTreeAccessible *aAccessible)
+void
+nsRootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent* aEvent,
+                                                 nsXULTreeAccessible* aAccessible)
 {
   nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
   if (!dataEvent)
-    return NS_OK;
+    return;
 
   nsCOMPtr<nsIVariant> indexVariant;
   dataEvent->GetData(NS_LITERAL_STRING("index"),
                      getter_AddRefs(indexVariant));
   if (!indexVariant)
-    return NS_OK;
+    return;
 
   nsCOMPtr<nsIVariant> countVariant;
   dataEvent->GetData(NS_LITERAL_STRING("count"),
                      getter_AddRefs(countVariant));
   if (!countVariant)
-    return NS_OK;
+    return;
 
   PRInt32 index, count;
   indexVariant->GetAsInt32(&index);
   countVariant->GetAsInt32(&count);
 
   aAccessible->InvalidateCache(index, count);
-  return NS_OK;
 }
 
-nsresult
-nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
-                                             nsXULTreeAccessible *aAccessible)
+void
+nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent* aEvent,
+                                             nsXULTreeAccessible* aAccessible)
 {
   nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
   if (!dataEvent)
-    return NS_OK;
+    return;
 
   PRInt32 startRow = 0, endRow = -1, startCol = 0, endCol = -1;
 
   nsCOMPtr<nsIVariant> startRowVariant;
   dataEvent->GetData(NS_LITERAL_STRING("startrow"),
                      getter_AddRefs(startRowVariant));
   if (startRowVariant)
     startRowVariant->GetAsInt32(&startRow);
@@ -986,12 +1000,10 @@ nsRootAccessible::HandleTreeInvalidatedE
 
   nsCOMPtr<nsIVariant> endColVariant;
   dataEvent->GetData(NS_LITERAL_STRING("endcolumn"),
                      getter_AddRefs(endColVariant));
   if (endColVariant)
     endColVariant->GetAsInt32(&endCol);
 
   aAccessible->TreeViewInvalidated(startRow, endRow, startCol, endCol);
-  return NS_OK;
 }
 #endif
-
--- a/accessible/src/base/nsRootAccessible.h
+++ b/accessible/src/base/nsRootAccessible.h
@@ -86,66 +86,82 @@ public:
   // nsAccessible
   virtual PRUint32 NativeRole();
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
 
   // nsRootAccessible
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ROOTACCESSIBLE_IMPL_CID)
 
   /**
-   * Fire an accessible focus event for the current focusAccssible
-   * and attach a new selection listener, if necessary.
+   * Fire an accessible focus event for the focused accessible and attach a new
+   * selection listener to real focused element, if necessary.
+   *
+   * @param  aFocusAccessible   [in] the accessible which has received focus
+   * @param  aRealFocusContent  [in] the actual DOM element which has received
+   *                              focus (see @note section)
+   * @param  aForceEvent        [in, optional] fire a focus event even if
+   *                              the last focused item was the same
+   * @param  aIsFromUserInput   [in, optional] specifies whether the event is
+   *                              from user input
    *
-   * @param  aFocusAccessible  [in] the accessible which has received focus
-   * @param  aFocusNode        [in] the DOM node which has received focus
-   * @param  aFocusEvent       [in] DOM focus event that caused
-   *                             the node/accessible to receive focus
-   * @param  aForceEvent       [in] fire a focus event even if the last focused
-   *                             item was the same
-   * @return                    boolean -- was a focus event actually fired
+   * @note  Use the originally focused node where the selection lives as real
+   *         focus node. For example, use the anonymous HTML:input instead of
+   *         the containing XUL:textbox. In this case, sometimes it is a later
+   *         focus event which points to the actual anonymous child with focus,
+   *         so to be safe we need to reset the selection listener every time.
+   *         This happens because when some bindings handle focus, they
+   *         retarget focus to the appropriate child inside of themselves, but
+   *         DOM focus stays outside on that binding parent.
    */
-  PRBool FireAccessibleFocusEvent(nsAccessible *aFocusAccessible,
-                                  nsINode *aFocusNode,
-                                  nsIDOMEvent *aFocusEvent,
-                                  PRBool aForceEvent = PR_FALSE,
-                                  EIsFromUserInput aIsFromUserInput = eAutoDetect);
+  void FireAccessibleFocusEvent(nsAccessible* aFocusAccessible,
+                                nsIContent* aRealFocusContent,
+                                PRBool aForceEvent = PR_FALSE,
+                                EIsFromUserInput aIsFromUserInput = eAutoDetect);
 
     /**
       * Fire an accessible focus event for the current focused node,
       * if there is a focus.
       */
     void FireCurrentFocusEvent();
 
     nsCaretAccessible *GetCaretAccessible();
 
 protected:
   NS_DECL_RUNNABLEMETHOD(nsRootAccessible, FireCurrentFocusEvent)
 
-    nsresult AddEventListeners();
-    nsresult RemoveEventListeners();
+  /**
+   * Add/remove DOM event listeners.
+   */
+  virtual nsresult AddEventListeners();
+  virtual nsresult RemoveEventListeners();
+
+  /**
+   * Process the DOM event.
+   */
+  void ProcessDOMEvent(nsIDOMEvent* aEvent);
 
   /**
    * Process "popupshown" event. Used by HandleEvent().
    */
+  void HandlePopupShownEvent(nsAccessible* aAccessible);
 
-  nsresult HandlePopupShownEvent(nsAccessible *aAccessible);
   /*
    * Process "popuphiding" event. Used by HandleEvent().
    */
-  nsresult HandlePopupHidingEvent(nsINode *aNode, nsAccessible *aAccessible);
+  void HandlePopupHidingEvent(nsINode* aNode, nsAccessible* aAccessible);
 
 #ifdef MOZ_XUL
-    nsresult HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
-                                            nsXULTreeAccessible *aAccessible);
-    nsresult HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
-                                        nsXULTreeAccessible *aAccessible);
+    void HandleTreeRowCountChangedEvent(nsIDOMEvent* aEvent,
+                                        nsXULTreeAccessible* aAccessible);
+    void HandleTreeInvalidatedEvent(nsIDOMEvent* aEvent,
+                                    nsXULTreeAccessible* aAccessible);
 
     PRUint32 GetChromeFlags();
 #endif
     already_AddRefed<nsIDocShellTreeItem>
            GetContentDocShell(nsIDocShellTreeItem *aStart);
     nsRefPtr<nsCaretAccessible> mCaretAccessible;
   nsCOMPtr<nsINode> mCurrentARIAMenubar;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsRootAccessible, NS_ROOTACCESSIBLE_IMPL_CID)
 
-#endif  
+#endif
--- a/accessible/src/base/nsTextAccessible.cpp
+++ b/accessible/src/base/nsTextAccessible.cpp
@@ -43,30 +43,29 @@
 ////////////////////////////////////////////////////////////////////////////////
 // nsTextAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsTextAccessible::
   nsTextAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
   nsLinkableAccessible(aContent, aShell)
 {
+  mFlags |= eTextLeafAccessible;
 }
 
 PRUint32
 nsTextAccessible::NativeRole()
 {
   return nsIAccessibleRole::ROLE_TEXT_LEAF;
 }
 
-nsresult
-nsTextAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset, PRUint32 aLength)
+void
+nsTextAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset,
+                               PRUint32 aLength)
 {
-  nsIFrame *frame = GetFrame();
-  if (!frame) return NS_ERROR_FAILURE;//NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
-
-  return frame->GetRenderedText(&aText, nsnull, nsnull, aStartOffset, aLength);
+  aText.Append(Substring(mText, aStartOffset, aLength));
 }
 
 void
 nsTextAccessible::CacheChildren()
 {
   // No children for text accessible.
 }
--- a/accessible/src/base/nsTextAccessible.h
+++ b/accessible/src/base/nsTextAccessible.h
@@ -46,20 +46,36 @@
  */
 class nsTextAccessible : public nsLinkableAccessible
 {
 public:
   nsTextAccessible(nsIContent *aContent, nsIWeakReference *aShell);
 
   // nsAccessible
   virtual PRUint32 NativeRole();
-  virtual nsresult AppendTextTo(nsAString& aText, PRUint32 aStartOffset,
-                                PRUint32 aLength);
+  virtual void AppendTextTo(nsAString& aText, PRUint32 aStartOffset = 0,
+                            PRUint32 aLength = PR_UINT32_MAX);
+
+  // nsTextAccessible
+  void SetText(const nsAString& aText) { mText = aText; }
+  const nsString& Text() const { return mText; }
 
 protected:
-
   // nsAccessible
   virtual void CacheChildren();
+
+protected:
+  nsString mText;
 };
 
 
+////////////////////////////////////////////////////////////////////////////////
+// nsAccessible downcast method
+
+inline nsTextAccessible*
+nsAccessible::AsTextLeaf()
+{
+  return mFlags & eTextLeafAccessible ?
+    static_cast<nsTextAccessible*>(this) : nsnull;
+}
+
 #endif
 
--- a/accessible/src/html/nsHTMLSelectAccessible.cpp
+++ b/accessible/src/html/nsHTMLSelectAccessible.cpp
@@ -670,16 +670,25 @@ nsHTMLComboboxAccessible::
 
 PRUint32
 nsHTMLComboboxAccessible::NativeRole()
 {
   return nsIAccessibleRole::ROLE_COMBOBOX;
 }
 
 void
+nsHTMLComboboxAccessible::InvalidateChildren()
+{
+  nsAccessibleWrap::InvalidateChildren();
+
+  if (mListAccessible)
+    mListAccessible->InvalidateChildren();
+}
+
+void
 nsHTMLComboboxAccessible::CacheChildren()
 {
   nsIFrame* frame = GetFrame();
   if (!frame)
     return;
 
   nsIComboboxControlFrame *comboFrame = do_QueryFrame(frame);
   if (!comboFrame)
--- a/accessible/src/html/nsHTMLSelectAccessible.h
+++ b/accessible/src/html/nsHTMLSelectAccessible.h
@@ -191,16 +191,17 @@ public:
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
 
   // nsAccessNode
   virtual void Shutdown();
 
   // nsAccessible
   virtual PRUint32 NativeRole();
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
+  virtual void InvalidateChildren();
 
 protected:
   // nsAccessible
   virtual void CacheChildren();
 
   // nsHTMLComboboxAccessible
 
   /**
--- a/accessible/src/html/nsHTMLTextAccessible.cpp
+++ b/accessible/src/html/nsHTMLTextAccessible.cpp
@@ -62,18 +62,18 @@ nsHTMLTextAccessible::
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLTextAccessible, nsTextAccessible)
 
 NS_IMETHODIMP
 nsHTMLTextAccessible::GetName(nsAString& aName)
 {
   // Text node, ARIA can't be used.
-  aName.Truncate();
-  return AppendTextTo(aName, 0, PR_UINT32_MAX);
+  aName = mText;
+  return NS_OK;
 }
 
 PRUint32
 nsHTMLTextAccessible::NativeRole()
 {
   nsIFrame *frame = GetFrame();
   // Don't return on null frame -- we still return a role
   // after accessible is shutdown/DEFUNCT
@@ -385,32 +385,31 @@ nsHTMLListBulletAccessible::GetStateInte
   nsresult rv = nsLeafAccessible::GetStateInternal(aState, aExtraState);
   NS_ENSURE_A11Y_SUCCESS(rv, rv);
 
   *aState &= ~nsIAccessibleStates::STATE_FOCUSABLE;
   *aState |= nsIAccessibleStates::STATE_READONLY;
   return NS_OK;
 }
 
-nsresult
+void
 nsHTMLListBulletAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset,
                                          PRUint32 aLength)
 {
   nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
   if (blockFrame) {
     nsAutoString bulletText;
     blockFrame->GetBulletText(bulletText);
 
     PRUint32 maxLength = bulletText.Length() - aStartOffset;
     if (aLength > maxLength)
       aLength = maxLength;
 
     aText += Substring(bulletText, aStartOffset, aLength);
   }
-  return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLListAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsHTMLListAccessible::
   nsHTMLListAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
--- a/accessible/src/html/nsHTMLTextAccessible.h
+++ b/accessible/src/html/nsHTMLTextAccessible.h
@@ -137,18 +137,18 @@ public:
 
   // nsAccessNode
   virtual void Shutdown();
   virtual bool IsPrimaryForNode() const;
 
   // nsAccessible
   virtual PRUint32 NativeRole();
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
-  virtual nsresult AppendTextTo(nsAString& aText, PRUint32 aStartOffset,
-                                PRUint32 aLength);
+  virtual void AppendTextTo(nsAString& aText, PRUint32 aStartOffset = 0,
+                            PRUint32 aLength = PR_UINT32_MAX);
 
 protected:
   // XXX: Ideally we'd get the bullet text directly from the bullet frame via
   // nsBulletFrame::GetListItemText(), but we'd need an interface for getting
   // text from contentless anonymous frames. Perhaps something like
   // nsIAnonymousFrame::GetText() ? However, in practice storing the bullet text
   // here should not be a problem if we invalidate the right parts of
   // the accessibility cache when mutation events occur.
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -75,16 +75,17 @@ static NS_DEFINE_IID(kRangeCID, NS_RANGE
 ////////////////////////////////////////////////////////////////////////////////
 // nsHyperTextAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsHyperTextAccessible::
   nsHyperTextAccessible(nsIContent *aNode, nsIWeakReference *aShell) :
   nsAccessibleWrap(aNode, aShell)
 {
+  mFlags |= eHyperTextAccessible;
 }
 
 NS_IMPL_ADDREF_INHERITED(nsHyperTextAccessible, nsAccessibleWrap)
 NS_IMPL_RELEASE_INHERITED(nsHyperTextAccessible, nsAccessibleWrap)
 
 nsresult nsHyperTextAccessible::QueryInterface(REFNSIID aIID, void** aInstancePtr)
 {
   *aInstancePtr = nsnull;
@@ -277,23 +278,23 @@ nsIntRect nsHyperTextAccessible::GetBoun
 nsIFrame*
 nsHyperTextAccessible::GetPosAndText(PRInt32& aStartOffset, PRInt32& aEndOffset,
                                      nsAString *aText, nsIFrame **aEndFrame,
                                      nsIntRect *aBoundsRect,
                                      nsAccessible **aStartAcc,
                                      nsAccessible **aEndAcc)
 {
   if (aStartOffset == nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT) {
-    GetCharacterCount(&aStartOffset);
+    aStartOffset = CharacterCount();
   }
   if (aStartOffset == nsIAccessibleText::TEXT_OFFSET_CARET) {
     GetCaretOffset(&aStartOffset);
   }
   if (aEndOffset == nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT) {
-    GetCharacterCount(&aEndOffset);
+    aEndOffset = CharacterCount();
   }
   if (aEndOffset == nsIAccessibleText::TEXT_OFFSET_CARET) {
     GetCaretOffset(&aEndOffset);
   }
 
   PRInt32 startOffset = aStartOffset;
   PRInt32 endOffset = aEndOffset;
   // XXX this prevents text interface usage on <input type="password">
@@ -468,65 +469,99 @@ nsHyperTextAccessible::GetPosAndText(PRI
     *aEndFrame = startFrame;
     if (aStartAcc && aEndAcc)
       NS_IF_ADDREF(*aEndAcc = *aStartAcc);
   }
 
   return startFrame;
 }
 
-NS_IMETHODIMP nsHyperTextAccessible::GetText(PRInt32 aStartOffset, PRInt32 aEndOffset, nsAString &aText)
+NS_IMETHODIMP
+nsHyperTextAccessible::GetText(PRInt32 aStartOffset, PRInt32 aEndOffset,
+                               nsAString &aText)
 {
+  aText.Truncate();
+
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
-  return GetPosAndText(aStartOffset, aEndOffset, &aText) ? NS_OK : NS_ERROR_FAILURE;
+  PRInt32 startOffset = ConvertMagicOffset(aStartOffset);
+  PRInt32 startChildIdx = GetChildIndexAtOffset(startOffset);
+  if (startChildIdx == -1)
+    return NS_ERROR_INVALID_ARG;
+
+  PRInt32 endOffset = ConvertMagicOffset(aEndOffset);
+  PRInt32 endChildIdx = GetChildIndexAtOffset(endOffset);
+  if (endChildIdx == -1)
+    return NS_ERROR_INVALID_ARG;
+
+  if (startChildIdx == endChildIdx) {
+    PRInt32 childOffset =  GetChildOffset(startChildIdx);
+    NS_ENSURE_STATE(childOffset != -1);
+
+    nsAccessible* child = GetChildAt(startChildIdx);
+    child->AppendTextTo(aText, startOffset - childOffset,
+                        endOffset - startOffset);
+
+    return NS_OK;
+  }
+
+  PRInt32 startChildOffset =  GetChildOffset(startChildIdx);
+  NS_ENSURE_STATE(startChildOffset != -1);
+
+  nsAccessible* startChild = GetChildAt(startChildIdx);
+  startChild->AppendTextTo(aText, startOffset - startChildOffset);
+
+  for (PRInt32 childIdx = startChildIdx + 1; childIdx < endChildIdx; childIdx++) {
+    nsAccessible* child = GetChildAt(childIdx);
+    child->AppendTextTo(aText);
+  }
+
+  PRInt32 endChildOffset =  GetChildOffset(endChildIdx);
+  NS_ENSURE_STATE(endChildOffset != -1);
+
+  nsAccessible* endChild = GetChildAt(endChildIdx);
+  endChild->AppendTextTo(aText, 0, endOffset - endChildOffset);
+
+  return NS_OK;
 }
 
 /*
  * Gets the character count.
  */
 NS_IMETHODIMP nsHyperTextAccessible::GetCharacterCount(PRInt32 *aCharacterCount)
 {
   NS_ENSURE_ARG_POINTER(aCharacterCount);
   *aCharacterCount = 0;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
-  PRInt32 childCount = GetChildCount();
-  for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
-    nsAccessible *childAcc = mChildren[childIdx];
-
-    PRInt32 textLength = nsAccUtils::TextLength(childAcc);
-    NS_ENSURE_TRUE(textLength >= 0, nsnull);
-    *aCharacterCount += textLength;
-  }
+  *aCharacterCount = CharacterCount();
   return NS_OK;
 }
 
 /*
  * Gets the specified character.
  */
 NS_IMETHODIMP nsHyperTextAccessible::GetCharacterAtOffset(PRInt32 aOffset, PRUnichar *aCharacter)
 {
+  NS_ENSURE_ARG_POINTER(aCharacter);
+  *aCharacter = nsnull;
+
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
-  nsAutoString text;
-  nsresult rv = GetText(aOffset, aOffset + 1, text);
-  if (NS_FAILED(rv)) {
-    return rv;
+  nsAutoString character;
+  if (GetCharAt(aOffset, eGetAt, character)) {
+    *aCharacter = character.First();
+    return NS_OK;
   }
 
-  if (text.IsEmpty()) {
-    return NS_ERROR_FAILURE;
-  }
-  *aCharacter = text.First();
-  return NS_OK;
+  return NS_ERROR_INVALID_ARG;
 }
 
 nsAccessible*
 nsHyperTextAccessible::DOMPointToHypertextOffset(nsINode *aNode,
                                                  PRInt32 aNodeOffset,
                                                  PRInt32 *aHyperTextOffset,
                                                  PRBool aIsEndOffset)
 {
@@ -869,17 +904,17 @@ nsresult nsHyperTextAccessible::GetTextH
   *aStartOffset = *aEndOffset = 0;
 
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   if (!presShell) {
     return NS_ERROR_FAILURE;
   }
 
   if (aOffset == nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT) {
-    GetCharacterCount(&aOffset);
+    aOffset = CharacterCount();
   }
   if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET) {
     GetCaretOffset(&aOffset);
     if (aOffset > 0 && (aBoundaryType == BOUNDARY_LINE_START ||
                         aBoundaryType == BOUNDARY_LINE_END)) {
       // It is the same character offset when the caret is visually at the very end of a line
       // or the start of a new line. Getting text at the line should provide the line with the visual caret,
       // otherwise screen readers will announce the wrong line as the user presses up or down arrow and land
@@ -902,17 +937,17 @@ nsresult nsHyperTextAccessible::GetTextH
   else if (aOffset < 0) {
     return NS_ERROR_FAILURE;
   }
 
   nsSelectionAmount amount;
   PRBool needsStart = PR_FALSE;
   switch (aBoundaryType) {
     case BOUNDARY_CHAR:
-      amount = eSelectCharacter;
+      amount = eSelectCluster;
       if (aType == eGetAt)
         aType = eGetAfter; // Avoid returning 2 characters
       break;
 
     case BOUNDARY_WORD_START:
       needsStart = PR_TRUE;
       amount = eSelectWord;
       break;
@@ -953,18 +988,17 @@ nsresult nsHyperTextAccessible::GetTextH
   PRInt32 endOffset = startOffset;
 
   // Convert offsets to frame-relative
   nsRefPtr<nsAccessible> startAcc;
   nsIFrame *startFrame = GetPosAndText(startOffset, endOffset, nsnull, nsnull,
                                        nsnull, getter_AddRefs(startAcc));
 
   if (!startFrame) {
-    PRInt32 textLength;
-    GetCharacterCount(&textLength);
+    PRInt32 textLength = CharacterCount();
     if (aBoundaryType == BOUNDARY_LINE_START && aOffset > 0 && aOffset == textLength) {
       // Asking for start of line, while on last character
       if (startAcc)
         startFrame = startAcc->GetFrame();
     }
     if (!startFrame) {
       return aOffset > textLength ? NS_ERROR_FAILURE : NS_OK;
     }
@@ -1018,18 +1052,17 @@ nsresult nsHyperTextAccessible::GetTextH
     NS_ENSURE_TRUE(endOffset >= 0, NS_ERROR_FAILURE);
     if (finalEndOffset == aOffset) {
       if (aType == eGetAt && amount == eSelectWord) { 
         // Fix word error for the first character in word: PeekOffset() will return the previous word when 
         // aOffset points to the first character of the word, but accessibility APIs want the current word 
         // that the first character is in
         return GetTextHelper(eGetAfter, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
       }
-      PRInt32 textLength;
-      GetCharacterCount(&textLength);
+      PRInt32 textLength = CharacterCount();
       if (finalEndOffset < textLength) {
         // This happens sometimes when current character at finalStartOffset 
         // is an embedded object character representing another hypertext, that
         // the AT really needs to dig into separately
         ++ finalEndOffset;
       }
     }
   }
@@ -1045,28 +1078,43 @@ nsresult nsHyperTextAccessible::GetTextH
 }
 
 /**
   * nsIAccessibleText impl.
   */
 NS_IMETHODIMP nsHyperTextAccessible::GetTextBeforeOffset(PRInt32 aOffset, nsAccessibleTextBoundary aBoundaryType,
                                                          PRInt32 *aStartOffset, PRInt32 *aEndOffset, nsAString & aText)
 {
+  if (aBoundaryType == BOUNDARY_CHAR) {
+    GetCharAt(aOffset, eGetBefore, aText, aStartOffset, aEndOffset);
+    return NS_OK;
+  }
+
   return GetTextHelper(eGetBefore, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
 }
 
 NS_IMETHODIMP nsHyperTextAccessible::GetTextAtOffset(PRInt32 aOffset, nsAccessibleTextBoundary aBoundaryType,
                                                      PRInt32 *aStartOffset, PRInt32 *aEndOffset, nsAString & aText)
 {
+  if (aBoundaryType == BOUNDARY_CHAR) {
+    GetCharAt(aOffset, eGetAt, aText, aStartOffset, aEndOffset);
+    return NS_OK;
+  }
+
   return GetTextHelper(eGetAt, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
 }
 
 NS_IMETHODIMP nsHyperTextAccessible::GetTextAfterOffset(PRInt32 aOffset, nsAccessibleTextBoundary aBoundaryType,
                                                         PRInt32 *aStartOffset, PRInt32 *aEndOffset, nsAString & aText)
 {
+  if (aBoundaryType == BOUNDARY_CHAR) {
+    GetCharAt(aOffset, eGetAfter, aText, aStartOffset, aEndOffset);
+    return NS_OK;
+  }
+
   return GetTextHelper(eGetAfter, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
 }
 
 // nsIPersistentProperties
 // nsIAccessibleText::getTextAttributes(in boolean includeDefAttrs,
 //                                      in long offset,
 //                                      out long rangeStartOffset,
 //                                      out long rangeEndOffset);
@@ -1414,18 +1462,17 @@ nsHyperTextAccessible::GetLinkIndexAtOff
 NS_IMETHODIMP nsHyperTextAccessible::SetAttributes(PRInt32 aStartPos, PRInt32 aEndPos,
                                                    nsISupports *aAttributes)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP nsHyperTextAccessible::SetTextContents(const nsAString &aText)
 {
-  PRInt32 numChars;
-  GetCharacterCount(&numChars);
+  PRInt32 numChars = CharacterCount();
   if (numChars == 0 || NS_SUCCEEDED(DeleteText(0, numChars))) {
     return InsertText(aText, 0);
   }
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsHyperTextAccessible::InsertText(const nsAString &aText, PRInt32 aPosition)
@@ -2047,16 +2094,27 @@ nsHyperTextAccessible::ScrollSubstringTo
 void
 nsHyperTextAccessible::InvalidateChildren()
 {
   mOffsets.Clear();
 
   nsAccessibleWrap::InvalidateChildren();
 }
 
+PRBool
+nsHyperTextAccessible::RemoveChild(nsAccessible* aAccessible)
+{
+  PRInt32 childIndex = aAccessible->GetIndexInParent();
+  PRInt32 count = mOffsets.Length() - childIndex;
+  if (count > 0)
+    mOffsets.RemoveElementsAt(childIndex, count);
+
+  return nsAccessible::RemoveChild(aAccessible);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsHyperTextAccessible public static
 
 nsresult nsHyperTextAccessible::ContentToRenderedOffset(nsIFrame *aFrame, PRInt32 aContentOffset,
                                                         PRUint32 *aRenderedOffset)
 {
   if (!aFrame) {
     // Current frame not rendered -- this can happen if text is set on
@@ -2107,22 +2165,49 @@ nsresult nsHyperTextAccessible::Rendered
   *aContentOffset = iter.ConvertSkippedToOriginal(aRenderedOffset + ourRenderedStart) - ourContentStart;
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHyperTextAccessible public
 
+bool
+nsHyperTextAccessible::GetCharAt(PRInt32 aOffset, EGetTextType aShift,
+                                 nsAString& aChar, PRInt32* aStartOffset,
+                                 PRInt32* aEndOffset)
+{
+  aChar.Truncate();
+
+  PRInt32 offset = ConvertMagicOffset(aOffset) + static_cast<PRInt32>(aShift);
+  PRInt32 childIdx = GetChildIndexAtOffset(offset);
+  if (childIdx == -1)
+    return false;
+
+  nsAccessible* child = GetChildAt(childIdx);
+  child->AppendTextTo(aChar, offset - GetChildOffset(childIdx), 1);
+
+  if (aStartOffset)
+    *aStartOffset = offset;
+  if (aEndOffset)
+    *aEndOffset = aChar.IsEmpty() ? offset : offset + 1;
+
+  return true;
+}
+
 PRInt32
 nsHyperTextAccessible::GetChildOffset(PRUint32 aChildIndex,
                                       PRBool aInvalidateAfter)
 {
-  if (aChildIndex == 0)
+  if (aChildIndex == 0) {
+    if (aInvalidateAfter)
+      mOffsets.Clear();
+
     return aChildIndex;
+  }
 
   PRInt32 count = mOffsets.Length() - aChildIndex;
   if (count > 0) {
     if (aInvalidateAfter)
       mOffsets.RemoveElementsAt(aChildIndex, count);
 
     return mOffsets[aChildIndex - 1];
   }
--- a/accessible/src/html/nsHyperTextAccessible.h
+++ b/accessible/src/html/nsHyperTextAccessible.h
@@ -85,27 +85,31 @@ public:
 
   // nsAccessible
   virtual PRInt32 GetLevelInternal();
   virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
   virtual PRUint32 NativeRole();
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
 
   virtual void InvalidateChildren();
+  virtual PRBool RemoveChild(nsAccessible* aAccessible);
 
-  // nsHyperTextAccessible
+  // nsHyperTextAccessible (static helper method)
 
   // Convert content offset to rendered text offset  
   static nsresult ContentToRenderedOffset(nsIFrame *aFrame, PRInt32 aContentOffset,
                                           PRUint32 *aRenderedOffset);
   
   // Convert rendered text offset to content offset
   static nsresult RenderedToContentOffset(nsIFrame *aFrame, PRUint32 aRenderedOffset,
                                           PRInt32 *aContentOffset);
 
+  //////////////////////////////////////////////////////////////////////////////
+  // HyperLinkAccessible
+
   /**
    * Return link count within this hypertext accessible.
    */
   inline PRUint32 GetLinkCount()
   {
     return GetEmbeddedChildCount();
   }
 
@@ -129,16 +133,19 @@ public:
    * Return link accessible at the given text offset.
    */
   inline PRInt32 GetLinkIndexAtOffset(PRUint32 aOffset)
   {
     nsAccessible* child = GetChildAtOffset(aOffset);
     return child ? GetLinkIndex(child) : -1;
   }
 
+  //////////////////////////////////////////////////////////////////////////////
+  // nsHyperTextAccessible: DOM point to text offset conversions.
+
   /**
     * Turn a DOM Node and offset into a character offset into this hypertext.
     * Will look for closest match when the DOM node does not have an accessible
     * object associated with it. Will return an offset for the end of
     * the string if the node is not found.
     *
     * @param aNode - the node to look for
     * @param aNodeOffset - the offset to look for
@@ -187,16 +194,41 @@ public:
    */
   nsresult HypertextOffsetsToDOMRange(PRInt32 aStartHTOffset,
                                       PRInt32 aEndHTOffset,
                                       nsIDOMNode **aStartNode,
                                       PRInt32 *aStartOffset,
                                       nsIDOMNode **aEndNode,
                                       PRInt32 *aEndOffset);
 
+  //////////////////////////////////////////////////////////////////////////////
+  // TextAccessible
+
+  /**
+   * Return character count within the hypertext accessible.
+   */
+  inline PRUint32 CharacterCount()
+  {
+    return GetChildOffset(GetChildCount());
+  }
+
+  /**
+   * Get a character before/at/after the given offset.
+   *
+   * @param aOffset       [in] the given offset
+   * @param aShift        [in] specifies whether to get a char before/at/after
+   *                        offset
+   * @param aChar         [out] the character
+   * @param aStartOffset  [out, optional] the start offset of the character
+   * @param aEndOffset    [out, optional] the end offset of the character
+   * @return               false if offset at the given shift is out of range
+   */
+  bool GetCharAt(PRInt32 aOffset, EGetTextType aShift, nsAString& aChar,
+                 PRInt32* aStartOffset = nsnull, PRInt32* aEndOffset = nsnull);
+
   /**
    * Return text offset of the given child accessible within hypertext
    * accessible.
    *
    * @param  aChild           [in] accessible child to get text offset for
    * @param  aInvalidateAfter [in, optional] indicates whether invalidate
    *                           cached offsets for next siblings of the child
    */
@@ -228,16 +260,33 @@ public:
   nsAccessible* GetChildAtOffset(PRUint32 aOffset)
   {
     return GetChildAt(GetChildIndexAtOffset(aOffset));
   }
 
 protected:
   // nsHyperTextAccessible
 
+  /**
+   * Transform magic offset into text offset.
+   */
+  inline PRInt32 ConvertMagicOffset(PRInt32 aOffset)
+  {
+    if (aOffset == nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT)
+      return CharacterCount();
+
+    if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET) {
+      PRInt32 caretOffset = -1;
+      GetCaretOffset(&caretOffset);
+      return caretOffset;
+    }
+
+    return aOffset;
+  }
+
   /*
    * This does the work for nsIAccessibleText::GetText[At|Before|After]Offset
    * @param aType, eGetBefore, eGetAt, eGetAfter
    * @param aBoundaryType, char/word-start/word-end/line-start/line-end/paragraph/attribute
    * @param aOffset, offset into the hypertext to start from
    * @param *aStartOffset, the resulting start offset for the returned substring
    * @param *aEndOffset, the resulting end offset for the returned substring
    * @param aText, the resulting substring
@@ -367,23 +416,29 @@ protected:
    */
   nsresult GetSpellTextAttribute(nsIDOMNode *aNode, PRInt32 aNodeOffset,
                                  PRInt32 *aStartOffset,
                                  PRInt32 *aEndOffset,
                                  nsIPersistentProperties *aAttributes);
 
 private:
   /**
-   * Embedded objects collector.
-   */
-  nsAutoPtr<AccCollector> mLinks;
-
-  /**
    * End text offsets array.
    */
   nsTArray<PRUint32> mOffsets;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsHyperTextAccessible,
                               NS_HYPERTEXTACCESSIBLE_IMPL_CID)
 
+
+////////////////////////////////////////////////////////////////////////////////
+// nsAccessible downcasting method
+
+inline nsHyperTextAccessible*
+nsAccessible::AsHyperText()
+{
+  return mFlags & eHyperTextAccessible ?
+    static_cast<nsHyperTextAccessible*>(this) : nsnull;
+}
+
 #endif  // _nsHyperTextAccessible_H_
 
--- a/accessible/src/mac/mozTextAccessible.h
+++ b/accessible/src/mac/mozTextAccessible.h
@@ -1,18 +1,17 @@
 #import "mozAccessible.h"
 
-#import "nsIAccessibleText.h"
-#import "nsIAccessibleEditableText.h"
+#import "nsHyperTextAccessible.h"
 
 @interface mozTextAccessible : mozAccessible
 {
   // both of these are the same old mGeckoAccessible, but already
   // QI'd for us, to the right type, for convenience.
-  nsIAccessibleText         *mGeckoTextAccessible;         // strong
+  nsHyperTextAccessible     *mGeckoTextAccessible;         // strong
   nsIAccessibleEditableText *mGeckoEditableTextAccessible; // strong
 }
 @end
 
 /* A combobox (in the mac world) is a textfield with an associated menu, for example
    the location bar. */
 @interface mozComboboxAccessible : mozTextAccessible
 // equivalent to pressing return key in this textfield.
--- a/accessible/src/mac/mozTextAccessible.mm
+++ b/accessible/src/mac/mozTextAccessible.mm
@@ -159,22 +159,17 @@ extern const NSString *kTopLevelUIElemen
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 - (long)textLength
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
-  if (mGeckoTextAccessible) {
-    PRInt32 charCount = 0;
-    mGeckoTextAccessible->GetCharacterCount(&charCount);
-    return charCount;
-  }
-  return 0;
+  return mGeckoTextAccessible ? mGeckoTextAccessible->CharacterCount() : 0;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
 }
 
 - (long)selectedTextLength
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
--- a/accessible/src/msaa/CAccessibleText.cpp
+++ b/accessible/src/msaa/CAccessibleText.cpp
@@ -38,33 +38,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "CAccessibleText.h"
 
 #include "Accessible2.h"
 #include "AccessibleText_i.c"
 
-#include "nsIAccessible.h"
-#include "nsIAccessibleText.h"
-#include "nsIAccessibleTypes.h"
-#include "nsIWinAccessNode.h"
-#include "nsAccessNodeWrap.h"
-#include "nsAccessibleWrap.h"
-
-#include "nsCOMPtr.h"
-#include "nsIPersistentProperties2.h"
-#include "nsString.h"
-
-#define GET_NSIACCESSIBLETEXT \
-nsCOMPtr<nsIAccessibleText> textAcc(do_QueryObject(this));\
-NS_ASSERTION(textAcc,\
-             "Subclass of CAccessibleText doesn't implement nsIAccessibleText");\
-if (!textAcc)\
-  return E_FAIL;\
+#include "nsHyperTextAccessible.h"
 
 // IUnknown
 
 STDMETHODIMP
 CAccessibleText::QueryInterface(REFIID iid, void** ppv)
 {
   *ppv = NULL;
 
@@ -82,18 +66,17 @@ CAccessibleText::QueryInterface(REFIID i
 }
 
 // IAccessibleText
 
 STDMETHODIMP
 CAccessibleText::addSelection(long aStartOffset, long aEndOffset)
 {
 __try {
-  GET_NSIACCESSIBLETEXT
-
+  nsRefPtr<nsHyperTextAccessible> textAcc(do_QueryObject(this));
   nsresult rv = textAcc->AddSelection(aStartOffset, aEndOffset);
   return GetHRESULT(rv);
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
@@ -103,17 +86,17 @@ CAccessibleText::get_attributes(long aOf
 __try {
   if (!aStartOffset || !aEndOffset || !aTextAttributes)
     return E_INVALIDARG;
 
   *aStartOffset = 0;
   *aEndOffset = 0;
   *aTextAttributes = NULL;
 
-  GET_NSIACCESSIBLETEXT
+  nsRefPtr<nsHyperTextAccessible> textAcc(do_QueryObject(this));
 
   PRInt32 startOffset = 0, endOffset = 0;
   nsCOMPtr<nsIPersistentProperties> attributes;
   nsresult rv = textAcc->GetTextAttributes(PR_TRUE, aOffset,
                                            &startOffset, &endOffset,
                                            getter_AddRefs(attributes));
   if (NS_FAILED(rv))
     return GetHRESULT(rv);
@@ -133,17 +116,17 @@ CAccessibleText::get_attributes(long aOf
 }
 
 STDMETHODIMP
 CAccessibleText::get_caretOffset(long *aOffset)
 {
 __try {
   *aOffset = -1;
 
-  GET_NSIACCESSIBLETEXT
+  nsRefPtr<nsHyperTextAccessible> textAcc(do_QueryObject(this));
 
   PRInt32 offset = 0;
   nsresult rv = textAcc->GetCaretOffset(&offset);
   if (NS_FAILED(rv))
     return GetHRESULT(rv);
 
   *aOffset = offset;
   return offset != -1 ? S_OK : S_FALSE;
@@ -159,17 +142,17 @@ CAccessibleText::get_characterExtents(lo
                                       long *aWidth, long *aHeight)
 {
 __try {
   *aX = 0;
   *aY = 0;
   *aWidth = 0;
   *aHeight = 0;
 
-  GET_NSIACCESSIBLETEXT
+  nsRefPtr<nsHyperTextAccessible> textAcc(do_QueryObject(this));
 
   PRUint32 geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
     nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
     nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
 
   PRInt32 x = 0, y =0, width = 0, height = 0;
   nsresult rv = textAcc->GetCharacterExtents (aOffset, &x, &y, &width, &height,
                                               geckoCoordType);
@@ -187,17 +170,17 @@ CAccessibleText::get_characterExtents(lo
 }
 
 STDMETHODIMP
 CAccessibleText::get_nSelections(long *aNSelections)
 {
 __try {
   *aNSelections = 0;
 
-  GET_NSIACCESSIBLETEXT
+  nsRefPtr<nsHyperTextAccessible> textAcc(do_QueryObject(this));
 
   PRInt32 selCount = 0;
   nsresult rv = textAcc->GetSelectionCount(&selCount);
   if (NS_FAILED(rv))
     return GetHRESULT(rv);
 
   *aNSelections = selCount;
   return S_OK;
@@ -209,17 +192,17 @@ CAccessibleText::get_nSelections(long *a
 STDMETHODIMP
 CAccessibleText::get_offsetAtPoint(long aX, long aY,
                                    enum IA2CoordinateType aCoordType,
                                    long *aOffset)
 {
 __try {
   *aOffset = 0;
 
-  GET_NSIACCESSIBLETEXT
+  nsRefPtr<nsHyperTextAccessible> textAcc(do_QueryObject(this));
 
   PRUint32 geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
     nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
     nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
 
   PRInt32 offset = 0;
   nsresult rv = textAcc->GetOffsetAtPoint(aX, aY, geckoCoordType, &offset);
   if (NS_FAILED(rv))
@@ -235,17 +218,17 @@ CAccessibleText::get_offsetAtPoint(long 
 STDMETHODIMP
 CAccessibleText::get_selection(long aSelectionIndex, long *aStartOffset,
                                long *aEndOffset)
 {
 __try {
   *aStartOffset = 0;
   *aEndOffset = 0;
 
-  GET_NSIACCESSIBLETEXT
+  nsRefPtr<nsHyperTextAccessible> textAcc(do_QueryObject(this));
 
   PRInt32 startOffset = 0, endOffset = 0;
   nsresult rv = textAcc->GetSelectionBounds(aSelectionIndex,
                                             &startOffset, &endOffset);
   if (NS_FAILED(rv))
     return GetHRESULT(rv);
 
   *aStartOffset = startOffset;
@@ -257,17 +240,17 @@ CAccessibleText::get_selection(long aSel
 }
 
 STDMETHODIMP
 CAccessibleText::get_text(long aStartOffset, long aEndOffset, BSTR *aText)
 {
 __try {
   *aText = NULL;
 
-  GET_NSIACCESSIBLETEXT
+  nsRefPtr<nsHyperTextAccessible> textAcc(do_QueryObject(this));
 
   nsAutoString text;
   nsresult rv = textAcc->GetText(aStartOffset, aEndOffset, text);
   if (NS_FAILED(rv))
     return GetHRESULT(rv);
 
   if (text.IsEmpty())
     return S_FALSE;
@@ -285,25 +268,27 @@ CAccessibleText::get_textBeforeOffset(lo
                                       long *aStartOffset, long *aEndOffset,
                                       BSTR *aText)
 {
 __try {
   *aStartOffset = 0;
   *aEndOffset = 0;
   *aText = NULL;
 
-  GET_NSIACCESSIBLETEXT
+  nsRefPtr<nsHyperTextAccessible> textAcc(do_QueryObject(this));
+  if (textAcc->IsDefunct())
+    return E_FAIL;
 
   nsresult rv = NS_OK;
   nsAutoString text;
   PRInt32 startOffset = 0, endOffset = 0;
 
   if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) {
     startOffset = 0;
-    textAcc->GetCharacterCount(&endOffset);
+    endOffset = textAcc->CharacterCount();
     rv = textAcc->GetText(startOffset, endOffset, text);
   } else {
     nsAccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType);
     if (boundaryType == -1)
       return S_FALSE;
     rv = textAcc->GetTextBeforeOffset(aOffset, boundaryType,
                                       &startOffset, &endOffset, text);
   }
@@ -330,25 +315,27 @@ CAccessibleText::get_textAfterOffset(lon
                                      long *aStartOffset, long *aEndOffset,
                                      BSTR *aText)
 {
 __try {
   *aStartOffset = 0;
   *aEndOffset = 0;
   *aText = NULL;
 
-  GET_NSIACCESSIBLETEXT
+  nsRefPtr<nsHyperTextAccessible> textAcc(do_QueryObject(this));
+  if (textAcc->IsDefunct())
+    return E_FAIL;
 
   nsresult rv = NS_OK;
   nsAutoString text;
   PRInt32 startOffset = 0, endOffset = 0;
 
   if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) {
     startOffset = 0;
-    textAcc->GetCharacterCount(&endOffset);
+    endOffset = textAcc->CharacterCount();
     rv = textAcc->GetText(startOffset, endOffset, text);
   } else {
     nsAccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType);
     if (boundaryType == -1)
       return S_FALSE;
     rv = textAcc->GetTextAfterOffset(aOffset, boundaryType,
                                      &startOffset, &endOffset, text);
   }
@@ -375,25 +362,27 @@ CAccessibleText::get_textAtOffset(long a
                                   long *aStartOffset, long *aEndOffset,
                                   BSTR *aText)
 {
 __try {
   *aStartOffset = 0;
   *aEndOffset = 0;
   *aText = NULL;
 
-  GET_NSIACCESSIBLETEXT
+  nsRefPtr<nsHyperTextAccessible> textAcc(do_QueryObject(this));
+  if (textAcc->IsDefunct())
+    return E_FAIL;
 
   nsresult rv = NS_OK;
   nsAutoString text;
   PRInt32 startOffset = 0, endOffset = 0;
 
   if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) {
     startOffset = 0;
-    textAcc->GetCharacterCount(&endOffset);
+    endOffset = textAcc->CharacterCount();
     rv = textAcc->GetText(startOffset, endOffset, text);
   } else {
     nsAccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType);
     if (boundaryType == -1)
       return S_FALSE;
     rv = textAcc->GetTextAtOffset(aOffset, boundaryType,
                                   &startOffset, &endOffset, text);
   }
@@ -413,94 +402,91 @@ CAccessibleText::get_textAtOffset(long a
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
 CAccessibleText::removeSelection(long aSelectionIndex)
 {
 __try {
-  GET_NSIACCESSIBLETEXT
+  nsRefPtr<nsHyperTextAccessible> textAcc(do_QueryObject(this));
 
   nsresult rv = textAcc->RemoveSelection(aSelectionIndex);
   return GetHRESULT(rv);
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return E_FAIL;
 }
 
 STDMETHODIMP
 CAccessibleText::setCaretOffset(long aOffset)
 {
 __try {
-  GET_NSIACCESSIBLETEXT
+  nsRefPtr<nsHyperTextAccessible> textAcc(do_QueryObject(this));
 
   nsresult rv = textAcc->SetCaretOffset(aOffset);
   return GetHRESULT(rv);
 
 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(