merge m-c to fig
authorMargaret Leibovic <margaret.leibovic@gmail.com>
Tue, 28 May 2013 09:53:47 -0700
changeset 143303 7af5a66a6fceaa13bdb51cf7b3b529ea163dfa83
parent 143302 173cbbdc2e8b96e9497f35731c449ae04b70c0ec (current diff)
parent 133093 6a739f41d1bae71f597eb0ea8111a65ca64c1d31 (diff)
child 143304 762d1865d454eb946cbbdd4945e5407e50e22c8f
push id25130
push userlrocha@mozilla.com
push dateWed, 21 Aug 2013 09:41:27 +0000
treeherdermozilla-central@b2486721572e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge m-c to fig
accessible/build/Makefile.in
accessible/build/moz.build
accessible/build/nsAccessibilityFactory.cpp
accessible/defs.mk
accessible/public/Makefile.in
accessible/public/nsIAccessibleCursorable.idl
accessible/tests/mochitest/text/test_whitespaces.html
addon-sdk/test/Makefile.in
browser/base/content/newtab/preload.xhtml
browser/components/dirprovider/tests/Makefile.in
browser/components/downloads/test/Makefile.in
browser/components/migration/tests/Makefile.in
browser/components/places/tests/Makefile.in
browser/devtools/commandline/test/browser_gcli_keyboard.js
browser/devtools/debugger/test/helpers.js
browser/devtools/inspector/test/helpers.js
browser/devtools/netmonitor/test/browser_net_cyrillic.js
browser/devtools/responsivedesign/test/helpers.js
browser/devtools/styleeditor/test/helpers.js
browser/devtools/webconsole/test/test-bug-595934-dom-events-external2.html
browser/devtools/webconsole/test/test-bug-595934-dom-events-external2.js
browser/devtools/webconsole/test/test-bug-595934-dom-events.html
browser/extensions/pdfjs/content/web/images/toolbarButton-fullscreen.png
browser/metro/components/UpdatePrompt.js
browser/metro/theme/images/closetab-tab.png
browser/metro/theme/images/closetab-tabselected.png
browser/metro/theme/images/locked-hdpi.png
browser/metro/theme/images/tab-selection-left.png
browser/metro/theme/images/tab-selection-right.png
browser/metro/theme/images/unlocked-hdpi.png
build/mobile/robocop/parse_ids.py
build/profile_pageloader.html
build/profile_pageloader.pl
caps/idl/Makefile.in
caps/include/Makefile.in
chrome/test/Makefile.in
content/base/public/Makefile.in
content/canvas/public/Makefile.in
content/events/public/Makefile.in
content/html/content/public/Makefile.in
content/mathml/defs.mk
content/media/webspeech/Makefile.in
content/smil/defs.mk
content/svg/defs.mk
content/test/Makefile.in
content/xml/document/public/Makefile.in
content/xslt/defs.mk
content/xslt/public/Makefile.in
content/xul/document/public/Makefile.in
docshell/shistory/public/Makefile.in
dom/base/nsIDOMDOMError.idl
dom/interfaces/apps/Makefile.in
dom/interfaces/base/Makefile.in
dom/interfaces/canvas/Makefile.in
dom/interfaces/contacts/Makefile.in
dom/interfaces/core/Makefile.in
dom/interfaces/css/Makefile.in
dom/interfaces/events/Makefile.in
dom/interfaces/events/nsIDOMStyleSheetAddedEvent.idl
dom/interfaces/events/nsIDOMStyleSheetRemovedEvent.idl
dom/interfaces/geolocation/Makefile.in
dom/interfaces/html/Makefile.in
dom/interfaces/json/Makefile.in
dom/interfaces/notification/Makefile.in
dom/interfaces/offline/Makefile.in
dom/interfaces/permission/Makefile.in
dom/interfaces/range/Makefile.in
dom/interfaces/settings/Makefile.in
dom/interfaces/sidebar/Makefile.in
dom/interfaces/storage/Makefile.in
dom/interfaces/stylesheets/Makefile.in
dom/interfaces/traversal/Makefile.in
dom/interfaces/xbl/Makefile.in
dom/interfaces/xul/Makefile.in
dom/media/nsIDOMRTCPeerConnection.idl
dom/media/tests/crashtests/837421.html
dom/media/tests/mochitest/test_peerConnection_bug840344.html
dom/mms/Makefile.in
dom/mms/interfaces/moz.build
dom/mms/interfaces/nsIMmsService.idl
dom/mms/interfaces/nsIWapPushApplication.idl
dom/mms/moz.build
dom/mms/src/Makefile.in
dom/mms/src/moz.build
dom/mms/src/ril/MmsPduHelper.jsm
dom/mms/src/ril/MmsService.js
dom/mms/src/ril/MmsService.manifest
dom/mms/src/ril/WapPushManager.js
dom/mms/src/ril/WspPduHelper.jsm
dom/mms/src/ril/mms_consts.js
dom/mms/src/ril/wap_consts.js
dom/mms/tests/header_helpers.js
dom/mms/tests/test_mms_pdu_helper.js
dom/mms/tests/test_mms_service.js
dom/mms/tests/test_wsp_pdu_helper.js
dom/mms/tests/xpcshell.ini
dom/mobilemessage/Makefile.in
dom/payment/tests/Makefile.in
dom/plugins/test/Makefile.in
dom/push/Makefile.in
dom/tests/Makefile.in
dom/webidl/RTCIceServer.webidl
editor/defs.mk
editor/idl/Makefile.in
editor/public/Makefile.in
editor/txmgr/public/Makefile.in
editor/txtsvc/public/Makefile.in
embedding/Makefile.in
embedding/components/webbrowserpersist/public/Makefile.in
embedding/components/windowwatcher/public/Makefile.in
embedding/defs.mk
extensions/cookie/Permission.txt
extensions/spellcheck/hunspell/Makefile.in
gfx/layers/ipc/ShmemYCbCrImage.cpp
gfx/layers/ipc/ShmemYCbCrImage.h
image/defs.mk
image/public/Makefile.in
image/test/Makefile.in
intl/chardet/public/Makefile.in
intl/hyphenation/public/Makefile.in
intl/locale/idl/Makefile.in
intl/locale/public/Makefile.in
intl/locale/tests/Makefile.in
intl/lwbrk/public/Makefile.in
intl/strres/public/Makefile.in
intl/strres/tests/Makefile.in
intl/uconv/idl/Makefile.in
intl/uconv/public/Makefile.in
intl/unicharutil/idl/Makefile.in
intl/unicharutil/public/Makefile.in
ipc/defs.mk
js/ipc/tests/Makefile.in
js/src/jit-test/tests/auto-regress/bug678362.js
js/src/jit-test/tests/parallelarray/map-invalid-mode-specifier.js
js/src/jsnuminlines.h
js/src/tests/ecma_5/extensions/JSON-string-replacer-overflow.js
js/src/tests/js1_8_5/regress/regress-595365-2.js
js/xpconnect/idl/Makefile.in
js/xpconnect/public/Makefile.in
js/xpconnect/tests/mochitest/test_bug809674.html
layout/generic/crashtests/756241-iframe.html
layout/generic/crashtests/756241.html
layout/mathml/defs.mk
layout/reftests/forms/input-file-width-clip-1.html
layout/reftests/forms/input-file-width-clip-ref.html
layout/style/test/test_bug721136.html
layout/svg/defs.mk
layout/tools/layout-debug/tests/Makefile.in
layout/xul/base/public/Makefile.in
media/libcubeb/include/Makefile.in
media/libnestegg/include/Makefile.in
media/libogg/include/ogg/Makefile.in
media/libtheora/include/theora/Makefile.in
media/libtremor/include/tremor/Makefile.in
media/libvorbis/include/vorbis/Makefile.in
media/webrtc/defs.mk
mobile/android/base/AwesomeBar.java
mobile/android/base/BrowserApp.java
mobile/android/base/BrowserToolbar.java
mobile/android/base/Divider.java
mobile/android/base/Favicons.java
mobile/android/base/GeckoMenu.java
mobile/android/base/GeckoMenuInflater.java
mobile/android/base/GeckoMenuItem.java
mobile/android/base/GeckoPopupMenu.java
mobile/android/base/GeckoSubMenu.java
mobile/android/base/Makefile.in
mobile/android/base/MenuItemActionBar.java
mobile/android/base/MenuItemDefault.java
mobile/android/base/MenuPanel.java
mobile/android/base/MenuPopup.java
mobile/android/base/awesomebar/AllPagesTab.java
mobile/android/base/awesomebar/BookmarksTab.java
mobile/android/base/awesomebar/HistoryTab.java
mobile/android/base/locales/en-US/android_strings.dtd
mobile/android/base/resources/layout/gecko_app.xml
mobile/android/base/resources/layout/menu_item.xml
mobile/android/base/resources/values/styles.xml
mobile/android/base/resources/xml/preference_headers.xml
mobile/android/base/resources/xml/preferences_content.xml
mobile/android/base/resources/xml/preferences_general.xml
mobile/android/base/resources/xml/preferences_main.xml
mobile/android/base/resources/xml/preferences_nonfragment.xml.in
mobile/android/base/resources/xml/preferences_privacy.xml
mobile/android/base/strings.xml.in
mobile/android/base/widget/AboutHome.java
modules/libjar/test/Makefile.in
modules/libjar/zipwriter/test/Makefile.in
modules/libpref/public/Makefile.in
modules/libpref/test/Makefile.in
parser/Makefile.in
parser/expat/Makefile.in
parser/htmlparser/defs.mk
parser/htmlparser/public/Makefile.in
parser/xml/test/Makefile.in
profile/dirserviceprovider/public/Makefile.in
rdf/base/idl/Makefile.in
rdf/base/public/Makefile.in
rdf/datasource/public/Makefile.in
rdf/defs.mk
rdf/tests/Makefile.in
rdf/util/public/Makefile.in
security/manager/boot/public/Makefile.in
security/manager/pki/public/Makefile.in
security/manager/ssl/public/Makefile.in
security/manager/ssl/tests/Makefile.in
services/common/tests/Makefile.in
services/crypto/component/tests/Makefile.in
services/crypto/tests/Makefile.in
services/datareporting/tests/Makefile.in
services/healthreport/tests/Makefile.in
services/metrics/tests/Makefile.in
services/sync/tests/Makefile.in
storage/defs.mk
storage/public/Makefile.in
testing/marionette/client/marionette/tests/unit/test_tap.py
testing/marionette/client/marionette/tests/unit/test_touch.py
testing/marionette/client/marionette/www/testTouch.html
testing/mochitest/plain-loop.html
testing/xpcshell/example/Makefile.in
toolkit/components/autocomplete/tests/Makefile.in
toolkit/components/captivedetect/test/Makefile.in
toolkit/components/commandlines/test/Makefile.in
toolkit/components/contentprefs/tests/Makefile.in
toolkit/components/downloads/test/Makefile.in
toolkit/components/jsdownloads/test/Makefile.in
toolkit/components/mediasniffer/test/Makefile.in
toolkit/components/osfile/tests/Makefile.in
toolkit/components/search/tests/Makefile.in
toolkit/components/telemetry/tests/Makefile.in
toolkit/components/urlformatter/tests/Makefile.in
toolkit/content/tests/Makefile.in
toolkit/devtools/debugger/Makefile.in
toolkit/devtools/debugger/dbg-client.jsm
toolkit/devtools/debugger/dbg-transport.js
toolkit/devtools/debugger/moz.build
toolkit/devtools/debugger/nsIJSInspector.idl
toolkit/devtools/debugger/nsJSInspector.cpp
toolkit/devtools/debugger/nsJSInspector.h
toolkit/devtools/debugger/server/dbg-browser-actors.js
toolkit/devtools/debugger/server/dbg-profiler-actors.js
toolkit/devtools/debugger/server/dbg-script-actors.js
toolkit/devtools/debugger/server/dbg-server.js
toolkit/devtools/debugger/server/dbg-server.jsm
toolkit/devtools/debugger/tests/Makefile.in
toolkit/devtools/debugger/tests/mochitest/Makefile.in
toolkit/devtools/debugger/tests/mochitest/moz.build
toolkit/devtools/debugger/tests/mochitest/nonchrome_unsafeDereference.html
toolkit/devtools/debugger/tests/mochitest/test_unsafeDereference.html
toolkit/devtools/debugger/tests/moz.build
toolkit/devtools/debugger/tests/unit/head_dbg.js
toolkit/devtools/debugger/tests/unit/post_init_global_actors.js
toolkit/devtools/debugger/tests/unit/post_init_tab_actors.js
toolkit/devtools/debugger/tests/unit/pre_init_global_actors.js
toolkit/devtools/debugger/tests/unit/pre_init_tab_actors.js
toolkit/devtools/debugger/tests/unit/source-map-data/sourcemapped.coffee
toolkit/devtools/debugger/tests/unit/source-map-data/sourcemapped.map
toolkit/devtools/debugger/tests/unit/sourcemapped.js
toolkit/devtools/debugger/tests/unit/test_add_actors.js
toolkit/devtools/debugger/tests/unit/test_attach.js
toolkit/devtools/debugger/tests/unit/test_breakpoint-01.js
toolkit/devtools/debugger/tests/unit/test_breakpoint-02.js
toolkit/devtools/debugger/tests/unit/test_breakpoint-03.js
toolkit/devtools/debugger/tests/unit/test_breakpoint-04.js
toolkit/devtools/debugger/tests/unit/test_breakpoint-05.js
toolkit/devtools/debugger/tests/unit/test_breakpoint-06.js
toolkit/devtools/debugger/tests/unit/test_breakpoint-07.js
toolkit/devtools/debugger/tests/unit/test_breakpoint-08.js
toolkit/devtools/debugger/tests/unit/test_breakpoint-09.js
toolkit/devtools/debugger/tests/unit/test_breakpoint-10.js
toolkit/devtools/debugger/tests/unit/test_breakpoint-11.js
toolkit/devtools/debugger/tests/unit/test_breakpoint-12.js
toolkit/devtools/debugger/tests/unit/test_breakpointstore.js
toolkit/devtools/debugger/tests/unit/test_dbgactor.js
toolkit/devtools/debugger/tests/unit/test_dbgclient_debuggerstatement.js
toolkit/devtools/debugger/tests/unit/test_dbgglobal.js
toolkit/devtools/debugger/tests/unit/test_dbgsocket.js
toolkit/devtools/debugger/tests/unit/test_eval-01.js
toolkit/devtools/debugger/tests/unit/test_eval-02.js
toolkit/devtools/debugger/tests/unit/test_eval-03.js
toolkit/devtools/debugger/tests/unit/test_eval-04.js
toolkit/devtools/debugger/tests/unit/test_eval-05.js
toolkit/devtools/debugger/tests/unit/test_frameactor-01.js
toolkit/devtools/debugger/tests/unit/test_frameactor-02.js
toolkit/devtools/debugger/tests/unit/test_frameactor-03.js
toolkit/devtools/debugger/tests/unit/test_frameactor-04.js
toolkit/devtools/debugger/tests/unit/test_frameactor-05.js
toolkit/devtools/debugger/tests/unit/test_framearguments-01.js
toolkit/devtools/debugger/tests/unit/test_framebindings-01.js
toolkit/devtools/debugger/tests/unit/test_framebindings-02.js
toolkit/devtools/debugger/tests/unit/test_framebindings-03.js
toolkit/devtools/debugger/tests/unit/test_framebindings-04.js
toolkit/devtools/debugger/tests/unit/test_framebindings-05.js
toolkit/devtools/debugger/tests/unit/test_framebindings-06.js
toolkit/devtools/debugger/tests/unit/test_frameclient-01.js
toolkit/devtools/debugger/tests/unit/test_frameclient-02.js
toolkit/devtools/debugger/tests/unit/test_functiongrips-01.js
toolkit/devtools/debugger/tests/unit/test_getyoungestframe.js
toolkit/devtools/debugger/tests/unit/test_interrupt.js
toolkit/devtools/debugger/tests/unit/test_listsources-01.js
toolkit/devtools/debugger/tests/unit/test_listsources-02.js
toolkit/devtools/debugger/tests/unit/test_listsources-03.js
toolkit/devtools/debugger/tests/unit/test_longstringactor.js
toolkit/devtools/debugger/tests/unit/test_longstringgrips-01.js
toolkit/devtools/debugger/tests/unit/test_longstringgrips-02.js
toolkit/devtools/debugger/tests/unit/test_nativewrappers.js
toolkit/devtools/debugger/tests/unit/test_new_source-01.js
toolkit/devtools/debugger/tests/unit/test_nsjsinspector.js
toolkit/devtools/debugger/tests/unit/test_objectgrips-01.js
toolkit/devtools/debugger/tests/unit/test_objectgrips-02.js
toolkit/devtools/debugger/tests/unit/test_objectgrips-03.js
toolkit/devtools/debugger/tests/unit/test_objectgrips-04.js
toolkit/devtools/debugger/tests/unit/test_pause_exceptions-01.js
toolkit/devtools/debugger/tests/unit/test_pause_exceptions-02.js
toolkit/devtools/debugger/tests/unit/test_pauselifetime-01.js
toolkit/devtools/debugger/tests/unit/test_pauselifetime-02.js
toolkit/devtools/debugger/tests/unit/test_pauselifetime-03.js
toolkit/devtools/debugger/tests/unit/test_pauselifetime-04.js
toolkit/devtools/debugger/tests/unit/test_profiler_actor.js
toolkit/devtools/debugger/tests/unit/test_source-01.js
toolkit/devtools/debugger/tests/unit/test_sourcemaps-01.js
toolkit/devtools/debugger/tests/unit/test_sourcemaps-02.js
toolkit/devtools/debugger/tests/unit/test_sourcemaps-03.js
toolkit/devtools/debugger/tests/unit/test_sourcemaps-04.js
toolkit/devtools/debugger/tests/unit/test_sourcemaps-05.js
toolkit/devtools/debugger/tests/unit/test_sources_backwards_compat-01.js
toolkit/devtools/debugger/tests/unit/test_sources_backwards_compat-02.js
toolkit/devtools/debugger/tests/unit/test_stepping-01.js
toolkit/devtools/debugger/tests/unit/test_stepping-02.js
toolkit/devtools/debugger/tests/unit/test_stepping-03.js
toolkit/devtools/debugger/tests/unit/test_stepping-04.js
toolkit/devtools/debugger/tests/unit/test_stepping-05.js
toolkit/devtools/debugger/tests/unit/test_threadlifetime-01.js
toolkit/devtools/debugger/tests/unit/test_threadlifetime-02.js
toolkit/devtools/debugger/tests/unit/test_threadlifetime-03.js
toolkit/devtools/debugger/tests/unit/test_threadlifetime-04.js
toolkit/devtools/debugger/tests/unit/test_threadlifetime-05.js
toolkit/devtools/debugger/tests/unit/test_threadlifetime-06.js
toolkit/devtools/debugger/tests/unit/test_unsafeDereference.js
toolkit/devtools/debugger/tests/unit/testactors.js
toolkit/devtools/debugger/tests/unit/testcompatactors.js
toolkit/devtools/debugger/tests/unit/xpcshell.ini
toolkit/devtools/gcli/dbg-gcli-actors.js
toolkit/devtools/jar.mn
toolkit/devtools/sourcemap/tests/Makefile.in
toolkit/devtools/styleeditor/Makefile.in
toolkit/devtools/styleeditor/dbg-styleeditor-actors.js
toolkit/devtools/styleeditor/moz.build
toolkit/devtools/webconsole/dbg-webconsole-actors.js
toolkit/forgetaboutsite/test/Makefile.in
toolkit/identity/tests/Makefile.in
toolkit/modules/tests/Makefile.in
toolkit/mozapps/update/test_timermanager/Makefile.in
view/public/Makefile.in
widget/Makefile.in
xpcom/reflect/xptcall/public/Makefile.in
xpcom/tests/static-checker/StackAggrInit.cpp
xpcom/tests/static-checker/StackCond.cpp
xpcom/tests/static-checker/StackCondBad.cpp
xpcom/tests/static-checker/StackConditional.cpp
xpcom/tests/static-checker/StackFalsePositive.cpp
xpcom/tests/static-checker/StackNoConstructor.cpp
xpcom/tests/static-checker/StackPlacementNewOK.cpp
xpcom/tests/static-checker/StackVector.cpp
xpcom/tests/static-checker/TestStack.cpp
xpcom/tests/static-checker/TestStackTemplate.cpp
xpcom/typelib/xpt/public/Makefile.in
xpfe/appshell/public/Makefile.in
--- a/CLOBBER
+++ b/CLOBBER
@@ -12,9 +12,12 @@
 #          O               O
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
-Bug 852687 - changing an idl without clobbering resulted test failures
+Bug 869002 touched webidl, so Windows needs to clobber
+
+Alternative to clobber is to run ./config.status from the objdir and to
+touch the CLOBBER file in the objdir.
--- a/Makefile.in
+++ b/Makefile.in
@@ -12,16 +12,18 @@ ifndef .PYMAKE
 ifeq (,$(MAKE_VERSION))
 $(error GNU Make is required)
 endif
 ifeq (,$(filter-out 3.78 3.79,$(MAKE_VERSION)))
 $(error GNU Make 3.80 or higher is required)
 endif
 endif
 
+export TOPLEVEL_BUILD := 1
+
 include $(DEPTH)/config/autoconf.mk
 
 default::
 
 ifdef COMPILE_ENVIRONMENT
 include $(topsrcdir)/$(MOZ_BUILD_APP)/build.mk
 endif
 
@@ -31,17 +33,19 @@ include $(topsrcdir)/config/config.mk
 GARBAGE_DIRS += dist _javagen _profile _tests staticlib
 DIST_GARBAGE = config.cache config.log config.status* config-defs.h \
    config/autoconf.mk \
    unallmakefiles mozilla-config.h \
    netwerk/necko-config.h xpcom/xpcom-config.h xpcom/xpcom-private.h \
    $(topsrcdir)/.mozconfig.mk $(topsrcdir)/.mozconfig.out
 
 ifndef MOZ_PROFILE_USE
-default alldep all:: CLOBBER $(topsrcdir)/configure config.status
+# We need to explicitly put backend.RecursiveMakeBackend.built here
+# otherwise the rule in rules.mk doesn't run early enough.
+default alldep all:: CLOBBER $(topsrcdir)/configure config.status backend.RecursiveMakeBackend.built
 	$(RM) -r $(DIST)/sdk
 	$(RM) -r $(DIST)/include
 	$(RM) -r $(DIST)/private
 	$(RM) -r $(DIST)/public
 	$(RM) -r $(DIST)/bin
 	$(RM) -r _tests
 endif
 
deleted file mode 100644
--- a/accessible/build/Makefile.in
+++ /dev/null
@@ -1,48 +0,0 @@
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-DEPTH		= @DEPTH@
-topsrcdir	= @top_srcdir@
-srcdir	= @srcdir@
-VPATH		= @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-LIBRARY_NAME	= accessibility
-EXPORT_LIBRARY = 1
-IS_COMPONENT	= 1
-MODULE_NAME	= nsAccessibilityModule
-LIBXUL_LIBRARY	= 1
-
-CPPSRCS		= nsAccessibilityFactory.cpp
-
-LOCAL_INCLUDES	= -I$(srcdir)/../src
-
-SHARED_LIBRARY_LIBS = \
-  ../src/base/$(LIB_PREFIX)accessibility_base_s.$(LIB_SUFFIX) \
-  ../src/generic/$(LIB_PREFIX)accessibility_generic_s.$(LIB_SUFFIX) \
-  ../src/html/$(LIB_PREFIX)accessibility_html_s.$(LIB_SUFFIX) \
-  ../src/xpcom/$(LIB_PREFIX)accessibility_xpcom_s.$(LIB_SUFFIX) \
-  $(NULL)
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
-SHARED_LIBRARY_LIBS += \
-  ../src/windows/msaa/$(LIB_PREFIX)accessibility_toolkit_msaa_s.$(LIB_SUFFIX) \
-  ../src/windows/ia2/$(LIB_PREFIX)accessibility_toolkit_ia2_s.$(LIB_SUFFIX) \
-  ../src/windows/sdn/$(LIB_PREFIX)accessibility_toolkit_sdn_s.$(LIB_SUFFIX) \
-  ../src/windows/uia/$(LIB_PREFIX)accessibility_toolkit_uia_s.$(LIB_SUFFIX) \
-  $(NULL)
-else
-SHARED_LIBRARY_LIBS += \
-  ../src/$(LIB_PREFIX)accessibility_toolkit_s.$(LIB_SUFFIX) \
-  $(NULL)
-endif
-
-ifdef MOZ_XUL
-SHARED_LIBRARY_LIBS += ../src/xul/$(LIB_PREFIX)accessibility_xul_s.$(LIB_SUFFIX)
-endif
-
-include $(topsrcdir)/config/rules.mk
-
deleted file mode 100644
--- a/accessible/build/moz.build
+++ /dev/null
@@ -1,8 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-MODULE = 'accessibility'
-
deleted file mode 100644
--- a/accessible/build/nsAccessibilityFactory.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsCOMPtr.h"
-#include "mozilla/ModuleUtils.h"
-
-#include "nsIServiceManager.h"
-#include "nsIComponentManager.h"
-#include "nsIAccessibilityService.h"
-#include "nsIAccessibleRetrieval.h"
-#include "nscore.h"
-
-static nsresult
-NS_ConstructAccessibilityService(nsISupports *aOuter, REFNSIID aIID, void **aResult)
-{
-    nsresult rv;
-    NS_ASSERTION(aOuter == nullptr, "no aggregation");
-    nsIAccessibilityService* accessibility;
-    rv = NS_GetAccessibilityService(&accessibility);
-    if (NS_FAILED(rv)) {
-        NS_ERROR("Unable to construct accessibility service");
-        return rv;
-    }
-    rv = accessibility->QueryInterface(aIID, aResult);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "unable to find correct interface");
-    NS_RELEASE(accessibility);
-    return rv;
-}
-
-NS_DEFINE_NAMED_CID(NS_ACCESSIBILITY_SERVICE_CID);
-
-static const mozilla::Module::CIDEntry kA11yCIDs[] = {
-    { &kNS_ACCESSIBILITY_SERVICE_CID, false, nullptr, NS_ConstructAccessibilityService },
-    { nullptr }
-};
-
-static const mozilla::Module::ContractIDEntry kA11yContracts[] = {
-    { "@mozilla.org/accessibilityService;1", &kNS_ACCESSIBILITY_SERVICE_CID },
-    { "@mozilla.org/accessibleRetrieval;1", &kNS_ACCESSIBILITY_SERVICE_CID },
-    { nullptr }
-};
-
-static const mozilla::Module kA11yModule = {
-    mozilla::Module::kVersion,
-    kA11yCIDs,
-    kA11yContracts
-};
-
-NSMODULE_DEFN(nsAccessibilityModule) = &kA11yModule;
-
-
deleted file mode 100644
--- a/accessible/defs.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-ifeq ($(OS_TARGET),WINNT)
-NO_PROFILE_GUIDED_OPTIMIZE := 1 # Don't PGO
-endif
--- a/accessible/moz.build
+++ b/accessible/moz.build
@@ -1,11 +1,11 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-DIRS += ['public', 'src', 'build']
+DIRS += ['public', 'src']
 TEST_DIRS += ['tests']
 
 MODULE = 'accessibility'
 
deleted file mode 100644
--- a/accessible/public/Makefile.in
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-DEPTH   = @DEPTH@
-topsrcdir = @top_srcdir@
-srcdir    = @srcdir@
-VPATH   = @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-
-include $(topsrcdir)/config/rules.mk
-
--- a/accessible/public/ia2/Makefile.in
+++ b/accessible/public/ia2/Makefile.in
@@ -21,28 +21,32 @@ GARBAGE       += $(MIDL_GENERATED_FILES)
 FORCE_SHARED_LIB = 1
 
 SRCS_IN_OBJDIR   = 1
 
 # Please keep this list in sync with the moz.build file until the rest of this
 # Makefile is ported over.
 MIDL_INTERFACES = \
   Accessible2.idl \
+  Accessible2_2.idl \
   AccessibleAction.idl \
   AccessibleApplication.idl \
   AccessibleComponent.idl \
+  AccessibleDocument.idl \
   AccessibleEditableText.idl \
   AccessibleHyperlink.idl \
   AccessibleHypertext.idl \
+  AccessibleHypertext2.idl \
   AccessibleImage.idl \
   AccessibleRelation.idl \
   AccessibleTable.idl \
   AccessibleTable2.idl \
   AccessibleTableCell.idl \
   AccessibleText.idl \
+  AccessibleText2.idl \
   AccessibleValue.idl \
   $(NULL)
 
 # Please keep this list in sync with the moz.build file until the rest of this
 # Makefile is ported over.
 MIDL_ENUMS = \
   AccessibleEventId.idl \
   AccessibleRole.idl \
--- a/accessible/public/ia2/moz.build
+++ b/accessible/public/ia2/moz.build
@@ -5,35 +5,46 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MODULE = 'accessibility'
 
 # Please keep this list in sync with the Makefile.in until the rest of that file
 # is ported over.
 midl_interfaces = [
     'Accessible2',
+    'Accessible2_2',
     'AccessibleAction',
     'AccessibleApplication',
     'AccessibleComponent',
+    'AccessibleDocument',
     'AccessibleEditableText',
     'AccessibleHyperlink',
     'AccessibleHypertext',
+    'AccessibleHypertext2',
     'AccessibleImage',
     'AccessibleRelation',
     'AccessibleTable',
     'AccessibleTable2',
     'AccessibleTableCell',
     'AccessibleText',
+    'AccessibleText2',
     'AccessibleValue',
 ]
 
 # Please keep this list in sync with the Makefile.in until the rest of that file
 # is ported over.
 midl_enums = [
     'AccessibleEventId',
     'AccessibleRole',
     'AccessibleStates',
     'IA2CommonTypes',
 ]
 
-EXPORTS += [x + '.h' for x in midl_enums]
-EXPORTS += [x + '.h' for x in midl_interfaces]
-EXPORTS += [x + '_i.c' for x in midl_interfaces]
+headers = ['%s.h' % x for x in midl_enums]
+interfaces_h = ['%s.h' % x for x in midl_interfaces]
+interfaces_c = ['%s_i.c' % x for x in midl_interfaces]
+
+# The underscore throws off sorting and EXPORTS expects sorted lists.
+interfaces_c.sort()
+
+EXPORTS += headers
+EXPORTS += interfaces_h
+EXPORTS += interfaces_c
--- a/accessible/public/moz.build
+++ b/accessible/public/moz.build
@@ -6,17 +6,16 @@
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     DIRS += ['msaa', 'ia2']
 
 XPIDL_SOURCES += [
     'nsIAccessible.idl',
     'nsIAccessibleApplication.idl',
     'nsIAccessibleCaretMoveEvent.idl',
-    'nsIAccessibleCursorable.idl',
     'nsIAccessibleDocument.idl',
     'nsIAccessibleEditableText.idl',
     'nsIAccessibleEvent.idl',
     'nsIAccessibleHideEvent.idl',
     'nsIAccessibleHyperLink.idl',
     'nsIAccessibleHyperText.idl',
     'nsIAccessibleImage.idl',
     'nsIAccessiblePivot.idl',
deleted file mode 100644
--- a/accessible/public/nsIAccessibleCursorable.idl
+++ /dev/null
@@ -1,26 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsISupports.idl"
-
-interface nsIAccessiblePivot;
-
-/**
- * An interface implemented by an accessible object that has an associated
- * virtual cursor. Typically, a top-level application or content document.
- * A virtual cursor is an implementation of nsIAccessiblePivot that provides an
- * exclusive spot in the cursorable's subtree, this could be used to create a
- * pseudo-focus or caret browsing experience that is centered around the
- * accessibility API.
- */
-[scriptable, uuid(5452dea5-d235-496f-8757-3ca016ff49ff)]
-interface nsIAccessibleCursorable : nsISupports
-{
-  /**
-   * The virtual cursor pivot this object manages.
-   */
-  readonly attribute nsIAccessiblePivot virtualCursor;
-};
--- a/accessible/public/nsIAccessibleDocument.idl
+++ b/accessible/public/nsIAccessibleDocument.idl
@@ -1,32 +1,33 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIAccessible;
+interface nsIAccessiblePivot;
 interface nsIDOMDocument;
 interface nsIDOMNode;
 interface nsIDOMWindow;
 
 /**
  * An interface for in-process accessibility clients
  * that wish to retrieve information about a document.
  * When accessibility is turned on in Gecko,
  * there is an nsIAccessibleDocument for each document
  * whether it is XUL, HTML or whatever.
  * You can QueryInterface to nsIAccessibleDocument from the nsIAccessible for
  * the root node of a document. You can also get one from 
  * nsIAccessible::GetAccessibleDocument() or 
  * nsIAccessibleEvent::GetAccessibleDocument()
  */
-[scriptable, uuid(451242bd-8a0c-4198-ae88-c053609a4e5d)]
+[scriptable, uuid(fe5b3886-2b6a-491a-80cd-a3e6342c451d)]
 interface nsIAccessibleDocument : nsISupports
 {
   /**
    * The URL of the document
    */
   readonly attribute AString URL;
 
   /**
@@ -71,12 +72,17 @@ interface nsIAccessibleDocument : nsISup
   readonly attribute nsIAccessibleDocument parentDocument;
 
   /**
    * Return the count of child document accessibles.
    */
   readonly attribute unsigned long childDocumentCount;
 
   /**
+   * The virtual cursor pivot this document manages.
+   */
+  readonly attribute nsIAccessiblePivot virtualCursor;
+
+  /**
    * Return the child document accessible at the given index.
    */
   nsIAccessibleDocument getChildDocumentAt(in unsigned long index);
 };
--- a/accessible/public/nsIAccessiblePivot.idl
+++ b/accessible/public/nsIAccessiblePivot.idl
@@ -15,17 +15,17 @@ interface nsIAccessibleTraversalRule;
 interface nsIAccessiblePivotObserver;
 
 /**
  * The pivot interface encapsulates a reference to a single place in an accessible
  * subtree. The pivot is a point or a range in the accessible tree. This interface
  * provides traversal methods to move the pivot to next/prev state that complies 
  * to a given rule.
  */
-[scriptable, uuid(15ff23de-879e-47ea-b536-6532466108c5)]
+[scriptable, uuid(c2938033-e240-4fe5-9cb6-e7ad649ccd10)]
 interface nsIAccessiblePivot : nsISupports
 {
   const TextBoundaryType CHAR_BOUNDARY = 0;
   const TextBoundaryType WORD_BOUNDARY = 1;
   const TextBoundaryType LINE_BOUNDARY = 2;
   const TextBoundaryType ATTRIBUTE_RANGE_BOUNDARY = 3;
 
   const PivotMoveReason REASON_NONE = 0;
@@ -42,16 +42,21 @@ interface nsIAccessiblePivot : nsISuppor
   attribute nsIAccessible position;
 
   /**
    * The root of the subtree in which the pivot traverses.
    */
   readonly attribute nsIAccessible root;
 
   /**
+   * The temporary modal root to which traversal is limited to.
+   */
+  attribute nsIAccessible modalRoot;
+
+  /**
    * The start offset of the text range the pivot points at, otherwise -1.
    */
   readonly attribute long startOffset;
 
   /**
    * The end offset of the text range the pivot points at, otherwise -1.
    */
   readonly attribute long endOffset;
@@ -176,30 +181,31 @@ interface nsIAccessiblePivotObserver : n
    * @param aReason        [in] the reason for the pivot change.
    */
   void onPivotChanged(in nsIAccessiblePivot aPivot,
                       in nsIAccessible aOldAccessible,
                       in long aOldStart, in long aOldEnd,
                       in PivotMoveReason aReason);
 };
 
-[scriptable, uuid(307d98b6-dba9-49cf-ba17-ef8b053044eb)]
+[scriptable, uuid(366fe92b-44c9-4769-ae40-7c2a075d3b16)]
 interface nsIAccessibleTraversalRule : nsISupports
 {
   /* Ignore this accessible object */
   const unsigned short FILTER_IGNORE = 0x0;
   /* Accept this accessible object */
   const unsigned short FILTER_MATCH = 0x1;
   /* Don't traverse accessibles children */
   const unsigned short FILTER_IGNORE_SUBTREE = 0x2;
 
   /* Pre-filters */
   const unsigned long PREFILTER_INVISIBLE     = 0x00000001;
   const unsigned long PREFILTER_OFFSCREEN     = 0x00000002;
   const unsigned long PREFILTER_NOT_FOCUSABLE = 0x00000004;
+  const unsigned long PREFILTER_ARIA_HIDDEN   = 0x00000008;
 
   /**
    * Pre-filter bitfield to filter out obviously ignorable nodes and lighten
    * the load on match().
    */
   readonly attribute unsigned long preFilter;
 
   /**
--- a/accessible/src/atk/AccessibleWrap.cpp
+++ b/accessible/src/atk/AccessibleWrap.cpp
@@ -946,22 +946,16 @@ GetAccessibleWrap(AtkObject* aAtkObj)
 }
 
 nsresult
 AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
 {
   nsresult rv = Accessible::HandleAccEvent(aEvent);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return FirePlatformEvent(aEvent);
-}
-
-nsresult
-AccessibleWrap::FirePlatformEvent(AccEvent* aEvent)
-{
     Accessible* accessible = aEvent->GetAccessible();
     NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE);
 
     uint32_t type = aEvent->GetEventType();
 
     AtkObject* atkObj = AccessibleWrap::GetAtkObject(accessible);
 
     // We don't create ATK objects for nsIAccessible plain text leaves,
--- a/accessible/src/atk/AccessibleWrap.h
+++ b/accessible/src/atk/AccessibleWrap.h
@@ -70,17 +70,16 @@ public:
 
   static const char * ReturnString(nsAString &aString) {
     static nsCString returnedString;
     returnedString = NS_ConvertUTF16toUTF8(aString);
     return returnedString.get();
   }
 
 protected:
-  virtual nsresult FirePlatformEvent(AccEvent* aEvent);
 
   nsresult FireAtkStateChangeEvent(AccEvent* aEvent, AtkObject *aObject);
   nsresult FireAtkTextChangedEvent(AccEvent* aEvent, AtkObject *aObject);
   nsresult FireAtkShowHideEvent(AccEvent* aEvent, AtkObject *aObject,
                                 bool aIsAdded);
 
   AtkObject *mAtkObject;
 
--- a/accessible/src/atk/Makefile.in
+++ b/accessible/src/atk/Makefile.in
@@ -8,39 +8,16 @@ srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME = accessibility_toolkit_s
 EXPORT_LIBRARY = ..
 LIBXUL_LIBRARY = 1
 
-
-CPPSRCS = \
-  AccessibleWrap.cpp \
-  ApplicationAccessibleWrap.cpp \
-  AtkSocketAccessible.cpp \
-  DocAccessibleWrap.cpp \
-  nsMaiInterfaceComponent.cpp \
-  nsMaiInterfaceAction.cpp \
-  nsMaiInterfaceText.cpp \
-  nsMaiInterfaceEditableText.cpp \
-  nsMaiInterfaceSelection.cpp \
-  nsMaiInterfaceValue.cpp \
-  nsMaiHyperlink.cpp \
-  nsMaiInterfaceHypertext.cpp \
-  nsMaiInterfaceHyperlinkImpl.cpp \
-  nsMaiInterfaceTable.cpp \
-  nsMaiInterfaceDocument.cpp \
-  nsMaiInterfaceImage.cpp \
-  Platform.cpp \
-  RootAccessibleWrap.cpp \
-  UtilInterface.cpp \
-  $(NULL)
-
 # we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 CFLAGS  	+= $(MOZ_GTK2_CFLAGS)
 CXXFLAGS  += $(MOZ_GTK2_CFLAGS)
 
--- a/accessible/src/atk/moz.build
+++ b/accessible/src/atk/moz.build
@@ -6,8 +6,30 @@
 
 MODULE = 'accessibility'
 
 EXPORTS.mozilla.a11y += [
     'AccessibleWrap.h',
     'HyperTextAccessibleWrap.h',
 ]
 
+CPP_SOURCES += [
+    'AccessibleWrap.cpp',
+    'ApplicationAccessibleWrap.cpp',
+    'AtkSocketAccessible.cpp',
+    'DocAccessibleWrap.cpp',
+    'Platform.cpp',
+    'RootAccessibleWrap.cpp',
+    'UtilInterface.cpp',
+    'nsMaiHyperlink.cpp',
+    'nsMaiInterfaceAction.cpp',
+    'nsMaiInterfaceComponent.cpp',
+    'nsMaiInterfaceDocument.cpp',
+    'nsMaiInterfaceEditableText.cpp',
+    'nsMaiInterfaceHyperlinkImpl.cpp',
+    'nsMaiInterfaceHypertext.cpp',
+    'nsMaiInterfaceImage.cpp',
+    'nsMaiInterfaceSelection.cpp',
+    'nsMaiInterfaceTable.cpp',
+    'nsMaiInterfaceText.cpp',
+    'nsMaiInterfaceValue.cpp',
+]
+
--- a/accessible/src/base/AccGroupInfo.cpp
+++ b/accessible/src/base/AccGroupInfo.cpp
@@ -105,62 +105,79 @@ AccGroupInfo::AccGroupInfo(Accessible* a
 
   if (mParent)
     return;
 
   roles::Role parentRole = parent->Role();
   if (IsConceptualParent(aRole, parentRole))
     mParent = parent;
 
-  // In the case of ARIA tree (not ARIA treegrid) a tree can be arranged by
-  // using ARIA groups to organize levels. In this case the parent of the tree
-  // item will be a group and the previous treeitem of that should be the tree
-  // item parent.
-  if (parentRole != roles::GROUPING || aRole != roles::OUTLINEITEM)
-    return;
-
-  Accessible* parentPrevSibling = parent->PrevSibling();
-  if (!parentPrevSibling)
+  // ARIA tree and list can be arranged by using ARIA groups to organize levels.
+  if (parentRole != roles::GROUPING)
     return;
 
-  roles::Role parentPrevSiblingRole = parentPrevSibling->Role();
-  if (parentPrevSiblingRole == roles::TEXT_LEAF) {
-    // XXX Sometimes an empty text accessible is in the hierarchy here,
-    // although the text does not appear to be rendered, GetRenderedText()
-    // says that it is so we need to skip past it to find the true
-    // previous sibling.
-    parentPrevSibling = parentPrevSibling->PrevSibling();
-    if (parentPrevSibling)
-      parentPrevSiblingRole = parentPrevSibling->Role();
+  // Way #1 for ARIA tree (not ARIA treegrid): previous sibling of a group is a
+  // parent. In other words the parent of the tree item will be a group and
+  // the previous tree item of the group is a conceptual parent of the tree
+  // item.
+  if (aRole == roles::OUTLINEITEM) {
+    Accessible* parentPrevSibling = parent->PrevSibling();
+    if (parentPrevSibling && parentPrevSibling->Role() == aRole) {
+      mParent = parentPrevSibling;
+      return;
+    }
   }
 
-  // Previous sibling of parent group is a tree item, this is the
-  // conceptual tree item parent.
-  if (parentPrevSiblingRole == roles::OUTLINEITEM)
-    mParent = parentPrevSibling;
+  // Way #2 for ARIA list and tree: group is a child of an item. In other words
+  // the parent of the item will be a group and containing item of the group is
+  // a conceptual parent of the item.
+  if (aRole == roles::LISTITEM || aRole == roles::OUTLINEITEM) {
+    Accessible* grandParent = parent->Parent();
+    if (grandParent && grandParent->Role() == aRole)
+      mParent = grandParent;
+  }
 }
 
 Accessible*
 AccGroupInfo::FirstItemOf(Accessible* aContainer)
 {
-  // ARIA trees can be arranged by ARIA groups, otherwise aria-level works.
+  // ARIA tree can be arranged by ARIA groups case #1 (previous sibling of a
+  // group is a parent) or by aria-level.
   a11y::role containerRole = aContainer->Role();
   Accessible* item = aContainer->NextSibling();
   if (item) {
     if (containerRole == roles::OUTLINEITEM && item->Role() == roles::GROUPING)
       item = item->FirstChild();
 
-    AccGroupInfo* itemGroupInfo = item->GetGroupInfo();
-    if (itemGroupInfo && itemGroupInfo->ConceptualParent() == aContainer)
-      return item;
+    if (item) {
+      AccGroupInfo* itemGroupInfo = item->GetGroupInfo();
+      if (itemGroupInfo && itemGroupInfo->ConceptualParent() == aContainer)
+        return item;
+    }
+  }
+
+  // ARIA list and tree can be arranged by ARIA groups case #2 (group is
+  // a child of an item).
+  item = aContainer->LastChild();
+  if (!item)
+    return nullptr;
+
+  if (item->Role() == roles::GROUPING &&
+      (containerRole == roles::LISTITEM || containerRole == roles::OUTLINEITEM)) {
+    item = item->FirstChild();
+    if (item) {
+      AccGroupInfo* itemGroupInfo = item->GetGroupInfo();
+      if (itemGroupInfo && itemGroupInfo->ConceptualParent() == aContainer)
+        return item;
+    }
   }
 
   // Otherwise it can be a direct child.
   item = aContainer->FirstChild();
-  if (item && IsConceptualParent(BaseRole(item->Role()), containerRole))
+  if (IsConceptualParent(BaseRole(item->Role()), containerRole))
     return item;
 
   return nullptr;
 }
 
 Accessible*
 AccGroupInfo::NextItemTo(Accessible* aItem)
 {
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -7,50 +7,16 @@ topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME = accessibility_base_s
 LIBXUL_LIBRARY = 1
 
-
-CPPSRCS = \
-  AccCollector.cpp \
-  AccEvent.cpp \
-  AccGroupInfo.cpp \
-  AccIterator.cpp \
-  Filters.cpp \
-  ARIAMap.cpp \
-  ARIAStateMap.cpp \
-  DocManager.cpp \
-  EventQueue.cpp \
-  FocusManager.cpp \
-  NotificationController.cpp \
-  nsAccessNode.cpp \
-  nsCoreUtils.cpp \
-  nsAccUtils.cpp \
-  nsAccessibilityService.cpp \
-  nsAccessiblePivot.cpp \
-  nsEventShell.cpp \
-  nsTextEquivUtils.cpp \
-  RoleAsserts.cpp \
-  SelectionManager.cpp \
-  StyleInfo.cpp \
-  TextAttrs.cpp \
-  TextUpdater.cpp \
-  TreeWalker.cpp \
-  $(NULL)
-
-ifneq ($(A11Y_LOG),0)
-CPPSRCS += \
-  Logging.cpp \
-  $(NULL)
-endif
-
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
   -I$(srcdir)/../generic \
--- a/accessible/src/base/moz.build
+++ b/accessible/src/base/moz.build
@@ -1,14 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+include('../shared.mozbuild')
+
 MODULE = 'accessibility'
 
 EXPORTS += [
     'AccEvent.h',
     'nsAccessNode.h',
     'nsAccessibilityService.h',
 ]
 
@@ -21,8 +23,40 @@ EXPORTS.mozilla.a11y += [
     'SelectionManager.h',
     'States.h',
 ]
 
 if CONFIG['MOZ_DEBUG']:
     EXPORTS.mozilla.a11y += [
         'Logging.h',
     ]
+
+CPP_SOURCES += [
+    'AccCollector.cpp',
+    'AccEvent.cpp',
+    'AccGroupInfo.cpp',
+    'AccIterator.cpp',
+    'ARIAMap.cpp',
+    'ARIAStateMap.cpp',
+    'DocManager.cpp',
+    'EventQueue.cpp',
+    'Filters.cpp',
+    'FocusManager.cpp',
+    'NotificationController.cpp',
+    'nsAccessibilityService.cpp',
+    'nsAccessiblePivot.cpp',
+    'nsAccessNode.cpp',
+    'nsAccUtils.cpp',
+    'nsCoreUtils.cpp',
+    'nsEventShell.cpp',
+    'nsTextEquivUtils.cpp',
+    'RoleAsserts.cpp',
+    'SelectionManager.cpp',
+    'StyleInfo.cpp',
+    'TextAttrs.cpp',
+    'TextUpdater.cpp',
+    'TreeWalker.cpp',
+]
+
+if a11y_log:
+    CPP_SOURCES += [
+        'Logging.cpp',
+    ]
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -282,21 +282,20 @@ nsAccessibilityService::CreatePluginAcce
     // reentrancy.  When the timer fires it calls
     // DocAccessible::ContentInserted() which does the work async.
     sPendingPlugins->RemoveElement(aContent);
 
     // Note: pluginPort will be null if windowless.
     HWND pluginPort = nullptr;
     aFrame->GetPluginPort(&pluginPort);
 
-    Accessible* accessible =
+    nsRefPtr<Accessible> accessible =
       new HTMLWin32ObjectOwnerAccessible(aContent, aContext->Document(),
                                          pluginPort);
-    NS_ADDREF(accessible);
-    return accessible;
+    return accessible.forget();
 
 #elif MOZ_ACCESSIBILITY_ATK
     if (!AtkSocketAccessible::gCanEmbed)
       return nullptr;
 
     // Note this calls into the plugin, so crazy things may happen and aFrame
     // may go away.
     nsCString plugId;
--- a/accessible/src/base/nsAccessiblePivot.cpp
+++ b/accessible/src/base/nsAccessiblePivot.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsAccessiblePivot.h"
 
-#include "Accessible-inl.h"
 #include "DocAccessible.h"
 #include "HyperTextAccessible.h"
 #include "nsAccUtils.h"
 #include "States.h"
 
 #include "nsArrayUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsISupportsPrimitives.h"
@@ -40,17 +39,17 @@ private:
   uint32_t mAcceptRolesLength;
   uint32_t mPreFilter;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessiblePivot
 
 nsAccessiblePivot::nsAccessiblePivot(Accessible* aRoot) :
-  mRoot(aRoot), mPosition(nullptr),
+  mRoot(aRoot), mModalRoot(nullptr), mPosition(nullptr),
   mStartOffset(-1), mEndOffset(-1)
 {
   NS_ASSERTION(aRoot, "A root accessible is required");
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsISupports
 
@@ -90,31 +89,57 @@ nsAccessiblePivot::GetPosition(nsIAccess
 
 NS_IMETHODIMP
 nsAccessiblePivot::SetPosition(nsIAccessible* aPosition)
 {
   nsRefPtr<Accessible> secondPosition;
 
   if (aPosition) {
     secondPosition = do_QueryObject(aPosition);
-    if (!secondPosition || !IsRootDescendant(secondPosition))
+    if (!secondPosition || !IsDescendantOf(secondPosition, GetActiveRoot()))
       return NS_ERROR_INVALID_ARG;
   }
 
   // Swap old position with new position, saves us an AddRef/Release.
   mPosition.swap(secondPosition);
   int32_t oldStart = mStartOffset, oldEnd = mEndOffset;
   mStartOffset = mEndOffset = -1;
   NotifyOfPivotChange(secondPosition, oldStart, oldEnd,
                       nsIAccessiblePivot::REASON_NONE);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsAccessiblePivot::GetModalRoot(nsIAccessible** aModalRoot)
+{
+  NS_ENSURE_ARG_POINTER(aModalRoot);
+
+  NS_IF_ADDREF(*aModalRoot = mModalRoot);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAccessiblePivot::SetModalRoot(nsIAccessible* aModalRoot)
+{
+  nsRefPtr<Accessible> modalRoot;
+
+  if (aModalRoot) {
+    modalRoot = do_QueryObject(aModalRoot);
+    if (!modalRoot || !IsDescendantOf(modalRoot, mRoot))
+      return NS_ERROR_INVALID_ARG;
+  }
+
+  mModalRoot.swap(modalRoot);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsAccessiblePivot::GetStartOffset(int32_t* aStartOffset)
 {
   NS_ENSURE_ARG_POINTER(aStartOffset);
 
   *aStartOffset = mStartOffset;
 
   return NS_OK;
 }
@@ -141,17 +166,17 @@ nsAccessiblePivot::SetTextRange(nsIAcces
                  (aStartOffset >= 0 || (aStartOffset != -1 && aEndOffset != -1)),
                  NS_ERROR_INVALID_ARG);
 
   nsRefPtr<Accessible> acc(do_QueryObject(aTextAccessible));
   if (!acc)
     return NS_ERROR_INVALID_ARG;
 
   HyperTextAccessible* newPosition = acc->AsHyperText();
-  if (!newPosition || !IsRootDescendant(newPosition))
+  if (!newPosition || !IsDescendantOf(newPosition, GetActiveRoot()))
     return NS_ERROR_INVALID_ARG;
 
   // Make sure the given offsets don't exceed the character count.
   int32_t charCount = newPosition->CharacterCount();
 
   if (aEndOffset > charCount)
     return NS_ERROR_FAILURE;
 
@@ -175,19 +200,20 @@ nsAccessiblePivot::MoveNext(nsIAccessibl
                             nsIAccessible* aAnchor, bool aIncludeStart,
                             uint8_t aArgc, bool* aResult)
 {
   NS_ENSURE_ARG(aResult);
   NS_ENSURE_ARG(aRule);
 
   *aResult = false;
 
+  Accessible* root = GetActiveRoot();
   nsRefPtr<Accessible> anchor =
     (aArgc > 0) ? do_QueryObject(aAnchor) : mPosition;
-  if (anchor && (anchor->IsDefunct() || !IsRootDescendant(anchor)))
+  if (anchor && (anchor->IsDefunct() || !IsDescendantOf(anchor, root)))
     return NS_ERROR_NOT_IN_TREE;
 
   nsresult rv = NS_OK;
   Accessible* accessible =
     SearchForward(anchor, aRule, (aArgc > 1) ? aIncludeStart : false, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (accessible)
@@ -202,19 +228,20 @@ nsAccessiblePivot::MovePrevious(nsIAcces
                                 bool aIncludeStart,
                                 uint8_t aArgc, bool* aResult)
 {
   NS_ENSURE_ARG(aResult);
   NS_ENSURE_ARG(aRule);
 
   *aResult = false;
 
+  Accessible* root = GetActiveRoot();
   nsRefPtr<Accessible> anchor =
     (aArgc > 0) ? do_QueryObject(aAnchor) : mPosition;
-  if (anchor && (anchor->IsDefunct() || !IsRootDescendant(anchor)))
+  if (anchor && (anchor->IsDefunct() || !IsDescendantOf(anchor, root)))
     return NS_ERROR_NOT_IN_TREE;
 
   nsresult rv = NS_OK;
   Accessible* accessible =
     SearchBackward(anchor, aRule, (aArgc > 1) ? aIncludeStart : false, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (accessible)
@@ -224,44 +251,45 @@ nsAccessiblePivot::MovePrevious(nsIAcces
 }
 
 NS_IMETHODIMP
 nsAccessiblePivot::MoveFirst(nsIAccessibleTraversalRule* aRule, bool* aResult)
 {
   NS_ENSURE_ARG(aResult);
   NS_ENSURE_ARG(aRule);
 
-  if (mRoot && mRoot->IsDefunct())
-    return NS_ERROR_NOT_IN_TREE;
+  Accessible* root = GetActiveRoot();
+  NS_ENSURE_TRUE(root && !root->IsDefunct(), NS_ERROR_NOT_IN_TREE);
 
   nsresult rv = NS_OK;
-  Accessible* accessible = SearchForward(mRoot, aRule, true, &rv);
+  Accessible* accessible = SearchForward(root, aRule, true, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (accessible)
     *aResult = MovePivotInternal(accessible, nsIAccessiblePivot::REASON_FIRST);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsAccessiblePivot::MoveLast(nsIAccessibleTraversalRule* aRule, bool* aResult)
+nsAccessiblePivot::MoveLast(nsIAccessibleTraversalRule* aRule,
+                            bool* aResult)
 {
   NS_ENSURE_ARG(aResult);
   NS_ENSURE_ARG(aRule);
 
-  if (mRoot && mRoot->IsDefunct())
-    return NS_ERROR_NOT_IN_TREE;
+  Accessible* root = GetActiveRoot();
+  NS_ENSURE_TRUE(root && !root->IsDefunct(), NS_ERROR_NOT_IN_TREE);
 
   *aResult = false;
   nsresult rv = NS_OK;
-  Accessible* lastAccessible = mRoot;
+  Accessible* lastAccessible = root;
   Accessible* accessible = nullptr;
 
-  // First got to the last accessible in pre-order
+  // First go to the last accessible in pre-order
   while (lastAccessible->HasChildren())
     lastAccessible = lastAccessible->LastChild();
 
   // Search backwards from last accessible and find the last occurrence in the doc
   accessible = SearchBackward(lastAccessible, aRule, true, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (accessible)
@@ -297,23 +325,23 @@ nsAccessiblePivot::MoveToPoint(nsIAccess
                                int32_t aX, int32_t aY, bool aIgnoreNoMatch,
                                bool* aResult)
 {
   NS_ENSURE_ARG_POINTER(aResult);
   NS_ENSURE_ARG_POINTER(aRule);
 
   *aResult = false;
 
-  if (mRoot && mRoot->IsDefunct())
-    return NS_ERROR_NOT_IN_TREE;
+  Accessible* root = GetActiveRoot();
+  NS_ENSURE_TRUE(root && !root->IsDefunct(), NS_ERROR_NOT_IN_TREE);
 
   RuleCache cache(aRule);
   Accessible* match = nullptr;
-  Accessible* child = mRoot->ChildAtPoint(aX, aY, Accessible::eDeepestChild);
-  while (child && mRoot != child) {
+  Accessible* child = root->ChildAtPoint(aX, aY, Accessible::eDeepestChild);
+  while (child && root != child) {
     uint16_t filtered = nsIAccessibleTraversalRule::FILTER_IGNORE;
     nsresult rv = cache.ApplyFilter(child, &filtered);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Ignore any matching nodes that were below this one
     if (filtered & nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE)
       match = nullptr;
 
@@ -355,25 +383,25 @@ nsAccessiblePivot::RemoveObserver(nsIAcc
   NS_ENSURE_ARG(aObserver);
 
   return mObservers.RemoveElement(aObserver) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 // Private utility methods
 
 bool
-nsAccessiblePivot::IsRootDescendant(Accessible* aAccessible)
+nsAccessiblePivot::IsDescendantOf(Accessible* aAccessible, Accessible* aAncestor)
 {
-  if (!mRoot || mRoot->IsDefunct())
+  if (!aAncestor || aAncestor->IsDefunct())
     return false;
 
   // XXX Optimize with IsInDocument() when appropriate. Blocked by bug 759875.
   Accessible* accessible = aAccessible;
   do {
-    if (accessible == mRoot)
+    if (accessible == aAncestor)
       return true;
   } while ((accessible = accessible->Parent()));
 
   return false;
 }
 
 bool
 nsAccessiblePivot::MovePivotInternal(Accessible* aPosition,
@@ -406,17 +434,18 @@ nsAccessiblePivot::SearchBackward(Access
 
   if (aSearchCurrent) {
     *aResult = cache.ApplyFilter(accessible, &filtered);
     NS_ENSURE_SUCCESS(*aResult, nullptr);
     if (filtered & nsIAccessibleTraversalRule::FILTER_MATCH)
       return accessible;
   }
 
-  while (accessible != mRoot) {
+  Accessible* root = GetActiveRoot();
+  while (accessible != root) {
     Accessible* parent = accessible->Parent();
     int32_t idxInParent = accessible->IndexInParent();
     while (idxInParent > 0) {
       if (!(accessible = parent->GetChildAt(--idxInParent)))
         continue;
 
       *aResult = cache.ApplyFilter(accessible, &filtered);
       NS_ENSURE_SUCCESS(*aResult, nullptr);
@@ -452,17 +481,18 @@ Accessible*
 nsAccessiblePivot::SearchForward(Accessible* aAccessible,
                                  nsIAccessibleTraversalRule* aRule,
                                  bool aSearchCurrent,
                                  nsresult* aResult)
 {
   *aResult = NS_OK;
 
   // Initial position could be not set, in that case begin search from root.
-  Accessible* accessible = (!aAccessible) ? mRoot.get() : aAccessible;
+  Accessible* root = GetActiveRoot();
+  Accessible* accessible = (!aAccessible) ? root : aAccessible;
 
   RuleCache cache(aRule);
 
   uint16_t filtered = nsIAccessibleTraversalRule::FILTER_IGNORE;
   *aResult = cache.ApplyFilter(accessible, &filtered);
   NS_ENSURE_SUCCESS(*aResult, nullptr);
   if (aSearchCurrent && (filtered & nsIAccessibleTraversalRule::FILTER_MATCH))
     return accessible;
@@ -477,17 +507,17 @@ nsAccessiblePivot::SearchForward(Accessi
 
       if (filtered & nsIAccessibleTraversalRule::FILTER_MATCH)
         return accessible;
     }
 
     Accessible* sibling = nullptr;
     Accessible* temp = accessible;
     do {
-      if (temp == mRoot)
+      if (temp == root)
         break;
 
       sibling = temp->NextSibling();
 
       if (sibling)
         break;
     } while ((temp = temp->Parent()));
 
@@ -544,16 +574,26 @@ RuleCache::ApplyFilter(Accessible* aAcce
 
     if ((nsIAccessibleTraversalRule::PREFILTER_OFFSCREEN & mPreFilter) &&
         (state & states::OFFSCREEN))
       return NS_OK;
 
     if ((nsIAccessibleTraversalRule::PREFILTER_NOT_FOCUSABLE & mPreFilter) &&
         !(state & states::FOCUSABLE))
       return NS_OK;
+
+    if (nsIAccessibleTraversalRule::PREFILTER_ARIA_HIDDEN & mPreFilter) {
+      nsIContent* content = aAccessible->GetContent();
+      if (nsAccUtils::HasDefinedARIAToken(content, nsGkAtoms::aria_hidden) &&
+          !content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_hidden,
+                                nsGkAtoms::_false, eCaseMatters)) {
+        *aResult |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
+        return NS_OK;
+      }
+    }
   }
 
   if (mAcceptRolesLength > 0) {
     uint32_t accessibleRole = aAccessible->Role();
     bool matchesRole = false;
     for (uint32_t idx = 0; idx < mAcceptRolesLength; idx++) {
       matchesRole = mAcceptRoles[idx] == accessibleRole;
       if (matchesRole)
--- a/accessible/src/base/nsAccessiblePivot.h
+++ b/accessible/src/base/nsAccessiblePivot.h
@@ -4,29 +4,22 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _nsAccessiblePivot_H_
 #define _nsAccessiblePivot_H_
 
 #include "nsIAccessiblePivot.h"
 
+#include "Accessible-inl.h"
 #include "nsAutoPtr.h"
 #include "nsTObserverArray.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
 
-namespace mozilla {
-namespace a11y {
-
-class Accessible;
-
-} // namespace a11y
-} // namespace mozilla
-
 class nsIAccessibleTraversalRule;
 
 /**
  * Class represents an accessible pivot.
  */
 class nsAccessiblePivot MOZ_FINAL : public nsIAccessiblePivot
 {
 public:
@@ -53,19 +46,19 @@ private:
    * Notify all observers on a pivot change. Return true if it has changed and
    * observers have been notified.
    */
   bool NotifyOfPivotChange(Accessible* aOldAccessible,
                            int32_t aOldStart, int32_t aOldEnd,
                            PivotMoveReason aReason);
 
   /*
-   * Check to see that the given accessible is in the pivot's subtree.
+   * Check to see that the given accessible is a descendant of given ancestor
    */
-  bool IsRootDescendant(Accessible* aAccessible);
+  bool IsDescendantOf(Accessible* aAccessible, Accessible* aAncestor);
 
 
   /*
    * Search in preorder for the first accessible to match the rule.
    */
   Accessible* SearchForward(Accessible* aAccessible,
                             nsIAccessibleTraversalRule* aRule,
                             bool aSearchCurrent,
@@ -75,26 +68,44 @@ private:
    * Reverse search in preorder for the first accessible to match the rule.
    */
   Accessible* SearchBackward(Accessible* aAccessible,
                              nsIAccessibleTraversalRule* aRule,
                              bool aSearchCurrent,
                              nsresult* aResult);
 
   /*
+   * Get the effective root for this pivot, either the true root or modal root.
+   */
+  Accessible* GetActiveRoot() const
+  {
+    if (mModalRoot) {
+      NS_ENSURE_FALSE(mModalRoot->IsDefunct(), mRoot);
+      return mModalRoot;
+    }
+
+    return mRoot;
+  }
+
+  /*
    * Update the pivot, and notify observers. Return true if it moved.
    */
   bool MovePivotInternal(Accessible* aPosition, PivotMoveReason aReason);
 
   /*
    * The root accessible.
    */
   nsRefPtr<Accessible> mRoot;
 
   /*
+   * The temporary modal root accessible.
+   */
+  nsRefPtr<Accessible> mModalRoot;
+
+  /*
    * The current pivot position.
    */
   nsRefPtr<Accessible> mPosition;
 
   /*
    * The text start offset ofthe pivot.
    */
   int32_t mStartOffset;
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -2019,17 +2019,18 @@ Accessible::RelationByType(uint32_t aTyp
     }
 
     case nsIAccessibleRelation::RELATION_NODE_CHILD_OF: {
       Relation rel(new RelatedAccIterator(Document(), mContent,
                                           nsGkAtoms::aria_owns));
 
       // This is an ARIA tree or treegrid that doesn't use owns, so we need to
       // get the parent the hard way.
-      if (mRoleMapEntry && (mRoleMapEntry->role == roles::OUTLINEITEM || 
+      if (mRoleMapEntry && (mRoleMapEntry->role == roles::OUTLINEITEM ||
+                            mRoleMapEntry->role == roles::LISTITEM ||
                             mRoleMapEntry->role == roles::ROW)) {
         rel.AppendTarget(GetGroupInfo()->ConceptualParent());
       }
 
       // If accessible is in its own Window, or is the root of a document,
       // then we should provide NODE_CHILD_OF relation so that MSAA clients
       // can easily get to true parent instead of getting to oleacc's
       // ROLE_WINDOW accessible which will prevent us from going up further
@@ -2050,18 +2051,20 @@ Accessible::RelationByType(uint32_t aTyp
 
     case nsIAccessibleRelation::RELATION_NODE_PARENT_OF: {
       Relation rel(new IDRefsIterator(mDoc, mContent, nsGkAtoms::aria_owns));
 
       // ARIA tree or treegrid can do the hierarchy by @aria-level, ARIA trees
       // also can be organized by groups.
       if (mRoleMapEntry &&
           (mRoleMapEntry->role == roles::OUTLINEITEM ||
+           mRoleMapEntry->role == roles::LISTITEM ||
            mRoleMapEntry->role == roles::ROW ||
            mRoleMapEntry->role == roles::OUTLINE ||
+           mRoleMapEntry->role == roles::LIST ||
            mRoleMapEntry->role == roles::TREE_TABLE)) {
         rel.AppendIter(new ItemIterator(this));
       }
 
       return rel;
     }
 
     case nsIAccessibleRelation::RELATION_CONTROLLED_BY:
@@ -3251,45 +3254,48 @@ Accessible::GetLevelInternal()
       if (parentRole == roles::OUTLINE)
         break;
       if (parentRole == roles::GROUPING)
         ++ level;
 
     }
 
   } else if (role == roles::LISTITEM) {
-    // Expose 'level' attribute on nested lists. We assume nested list is a last
-    // child of listitem of parent list. We don't handle the case when nested
-    // lists have more complex structure, for example when there are accessibles
-    // between parent listitem and nested list.
+    // Expose 'level' attribute on nested lists. We support two hierarchies:
+    // a) list -> listitem -> list -> listitem (nested list is a last child
+    //   of listitem of the parent list);
+    // b) list -> listitem -> group -> listitem (nested listitems are contained
+    //   by group that is a last child of the parent listitem).
 
     // Calculate 'level' attribute based on number of parent listitems.
     level = 0;
     Accessible* parent = this;
     while ((parent = parent->Parent())) {
       roles::Role parentRole = parent->Role();
 
       if (parentRole == roles::LISTITEM)
         ++ level;
-      else if (parentRole != roles::LIST)
+      else if (parentRole != roles::LIST && parentRole != roles::GROUPING)
         break;
-
     }
 
     if (level == 0) {
       // If this listitem is on top of nested lists then expose 'level'
       // attribute.
       parent = Parent();
       uint32_t siblingCount = parent->ChildCount();
       for (uint32_t siblingIdx = 0; siblingIdx < siblingCount; siblingIdx++) {
         Accessible* sibling = parent->GetChildAt(siblingIdx);
 
         Accessible* siblingChild = sibling->LastChild();
-        if (siblingChild && siblingChild->Role() == roles::LIST)
-          return 1;
+        if (siblingChild) {
+          roles::Role lastChildRole = siblingChild->Role();
+          if (lastChildRole == roles::LIST || lastChildRole == roles::GROUPING)
+            return 1;
+        }
       }
     } else {
       ++ level; // level is 1-index based
     }
   }
 
   return level;
 }
--- a/accessible/src/generic/Accessible.h
+++ b/accessible/src/generic/Accessible.h
@@ -876,26 +876,16 @@ protected:
    */
   uint32_t GetActionRule();
 
   /**
    * Return group info.
    */
   AccGroupInfo* GetGroupInfo();
 
-  /**
-   * Fires platform accessible event. It's notification method only. It does
-   * change nothing on Gecko side. Don't use it until you're sure what you do
-   * (see example in XUL tree accessible), use nsEventShell::FireEvent()
-   * instead. MUST be overridden in wrap classes.
-   *
-   * @param aEvent  the accessible event to fire.
-   */
-  virtual nsresult FirePlatformEvent(AccEvent* aEvent) = 0;
-
   // Data Members
   nsRefPtr<Accessible> mParent;
   nsTArray<nsRefPtr<Accessible> > mChildren;
   int32_t mIndexInParent;
 
   static const uint8_t kChildrenFlagsBits = 2;
   static const uint8_t kStateFlagsBits = 5;
   static const uint8_t kTypeBits = 6;
--- a/accessible/src/generic/DocAccessible.cpp
+++ b/accessible/src/generic/DocAccessible.cpp
@@ -125,18 +125,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DocAccessible)
   NS_INTERFACE_MAP_ENTRY(nsIAccessibleDocument)
   NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY(nsIAccessiblePivotObserver)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAccessibleDocument)
-  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAccessibleCursorable,
-                                     (mDocFlags & eCursorable))
     foundInterface = 0;
 
   nsresult status;
   if (!foundInterface) {
     // HTML document accessible must inherit from HyperTextAccessible 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 DocAccessible to inherit from AccessibleWrap.
@@ -472,29 +470,25 @@ DocAccessible::GetChildDocumentAt(uint32
 
   if (IsDefunct())
     return NS_OK;
 
   NS_IF_ADDREF(*aDocument = GetChildDocumentAt(aIndex));
   return *aDocument ? NS_OK : NS_ERROR_INVALID_ARG;
 }
 
-// nsIAccessibleVirtualCursor method
 NS_IMETHODIMP
 DocAccessible::GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor)
 {
   NS_ENSURE_ARG_POINTER(aVirtualCursor);
   *aVirtualCursor = nullptr;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
-  if (!(mDocFlags & eCursorable))
-    return NS_OK;
-
   if (!mVirtualCursor) {
     mVirtualCursor = new nsAccessiblePivot(this);
     mVirtualCursor->AddObserver(this);
   }
 
   NS_ADDREF(*aVirtualCursor = mVirtualCursor);
   return NS_OK;
 }
@@ -1460,20 +1454,16 @@ DocAccessible::NotifyOfLoading(bool aIsR
 }
 
 void
 DocAccessible::DoInitialUpdate()
 {
   if (nsCoreUtils::IsTabDocument(mDocumentNode))
     mDocFlags |= eTabDocument;
 
-  // We provide a virtual cursor if this is a root doc or if it's a tab doc.
-  if (!mDocumentNode->GetParentDocument() || (mDocFlags & eTabDocument))
-    mDocFlags |= eCursorable;
-
   mLoadState |= eTreeConstructed;
 
   // The content element may be changed before the initial update and then we
   // miss the notification (since content tree change notifications are ignored
   // prior to initial update). Make sure the content element is valid.
   nsIContent* contentElm = nsCoreUtils::GetRoleContent(mDocumentNode);
   if (mContent != contentElm) {
     mContent = contentElm;
--- a/accessible/src/generic/DocAccessible.h
+++ b/accessible/src/generic/DocAccessible.h
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_DocAccessible_h__
 #define mozilla_a11y_DocAccessible_h__
 
-#include "nsIAccessibleCursorable.h"
 #include "nsIAccessibleDocument.h"
 #include "nsIAccessiblePivot.h"
 
 #include "AccEvent.h"
 #include "HyperTextAccessibleWrap.h"
 
 #include "nsClassHashtable.h"
 #include "nsDataHashtable.h"
@@ -40,28 +39,25 @@ template<class Class, class Arg>
 class TNotification;
 
 class DocAccessible : public HyperTextAccessibleWrap,
                       public nsIAccessibleDocument,
                       public nsIDocumentObserver,
                       public nsIObserver,
                       public nsIScrollPositionListener,
                       public nsSupportsWeakReference,
-                      public nsIAccessibleCursorable,
                       public nsIAccessiblePivotObserver
 {
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocAccessible, Accessible)
 
   NS_DECL_NSIACCESSIBLEDOCUMENT
 
   NS_DECL_NSIOBSERVER
 
-  NS_DECL_NSIACCESSIBLECURSORABLE
-
   NS_DECL_NSIACCESSIBLEPIVOTOBSERVER
 
 public:
 
   DocAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
                 nsIPresShell* aPresShell);
   virtual ~DocAccessible();
 
@@ -487,21 +483,18 @@ protected:
 
   /**
    * State and property flags, kept by mDocFlags.
    */
   enum {
     // Whether scroll listeners were added.
     eScrollInitialized = 1 << 0,
 
-    // Whether we support nsIAccessibleCursorable.
-    eCursorable = 1 << 1,
-
     // Whether the document is a tab document.
-    eTabDocument = 1 << 2
+    eTabDocument = 1 << 1
   };
 
   /**
    * Cache of accessibles within this document accessible.
    */
   AccessibleHashtable mAccessibleCache;
   nsDataHashtable<nsPtrHashKey<const nsINode>, Accessible*>
     mNodeToAccessibleMap;
@@ -534,17 +527,17 @@ protected:
    * Keep the ARIA attribute old value that is initialized by
    * AttributeWillChange and used by AttributeChanged notifications.
    */
   nsIAtom* mARIAAttrOldValue;
 
   nsTArray<nsRefPtr<DocAccessible> > mChildDocuments;
 
   /**
-   * The virtual cursor of the document when it supports nsIAccessibleCursorable.
+   * The virtual cursor of the document.
    */
   nsRefPtr<nsAccessiblePivot> mVirtualCursor;
 
   /**
    * A storage class for pairing content with one of its relation attributes.
    */
   class AttrRelProvider
   {
--- a/accessible/src/generic/HyperTextAccessible.cpp
+++ b/accessible/src/generic/HyperTextAccessible.cpp
@@ -1009,42 +1009,34 @@ HyperTextAccessible::GetTextBeforeOffset
     return NS_ERROR_INVALID_ARG;
 
   switch (aBoundaryType) {
     case BOUNDARY_CHAR:
       GetCharAt(offset, eGetBefore, aText, aStartOffset, aEndOffset);
       return NS_OK;
 
     case BOUNDARY_WORD_START: {
-      if (offset == 0) { // no word before 0 offset
-        *aStartOffset = *aEndOffset = 0;
-        return NS_OK;
+      // If the offset is a word start (except text length offset) then move
+      // backward to find a start offset (end offset is the given offset).
+      // Otherwise move backward twice to find both start and end offsets.
+      if (offset == CharacterCount()) {
+        *aEndOffset = FindWordBoundary(offset, eDirPrevious, eStartWord);
+        *aStartOffset = FindWordBoundary(*aEndOffset, eDirPrevious, eStartWord);
+      } else {
+        *aStartOffset = FindWordBoundary(offset, eDirPrevious, eStartWord);
+        *aEndOffset = FindWordBoundary(*aStartOffset, eDirNext, eStartWord);
+        if (*aEndOffset != offset) {
+          *aEndOffset = *aStartOffset;
+          *aStartOffset = FindWordBoundary(*aEndOffset, eDirPrevious, eStartWord);
+        }
       }
-
-      // If the offset is a word start then move backward to find start offset
-      // (end offset is the given offset). Otherwise move backward twice to find
-      // both start and end offsets.
-      int32_t midOffset = FindWordBoundary(offset, eDirPrevious, eStartWord);
-      *aEndOffset = FindWordBoundary(midOffset, eDirNext, eStartWord);
-      if (*aEndOffset == offset) {
-        *aStartOffset = midOffset;
-        return GetText(*aStartOffset, *aEndOffset, aText);
-      }
-
-      *aStartOffset = FindWordBoundary(midOffset, eDirPrevious, eStartWord);
-      *aEndOffset = midOffset;
       return GetText(*aStartOffset, *aEndOffset, aText);
     }
 
     case BOUNDARY_WORD_END: {
-      if (offset == 0) { // no word before 0 offset
-        *aStartOffset = *aEndOffset = 0;
-        return NS_OK;
-      }
-
       // Move word backward twice to find start and end offsets.
       *aEndOffset = FindWordBoundary(offset, eDirPrevious, eEndWord);
       *aStartOffset = FindWordBoundary(*aEndOffset, eDirPrevious, eEndWord);
       return GetText(*aStartOffset, *aEndOffset, aText);
     }
 
     case BOUNDARY_LINE_START:
     case BOUNDARY_LINE_END:
--- a/accessible/src/generic/Makefile.in
+++ b/accessible/src/generic/Makefile.in
@@ -7,32 +7,16 @@ topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME = accessibility_generic_s
 LIBXUL_LIBRARY = 1
 
-
-CPPSRCS = \
-  Accessible.cpp \
-  ApplicationAccessible.cpp \
-  ARIAGridAccessible.cpp \
-  BaseAccessibles.cpp \
-  DocAccessible.cpp \
-  FormControlAccessible.cpp \
-  HyperTextAccessible.cpp \
-  ImageAccessible.cpp \
-  OuterDocAccessible.cpp \
-  RootAccessible.cpp \
-  TableCellAccessible.cpp \
-  TextLeafAccessible.cpp \
-  $(NULL)
-
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES = \
   -I$(srcdir)/../xpcom \
   -I$(srcdir)/../base \
--- a/accessible/src/generic/moz.build
+++ b/accessible/src/generic/moz.build
@@ -7,8 +7,23 @@
 MODULE = 'accessibility'
 
 EXPORTS.mozilla.a11y += [
     'Accessible.h',
     'DocAccessible.h',
     'HyperTextAccessible.h',
 ]
 
+CPP_SOURCES += [
+    'ARIAGridAccessible.cpp',
+    'Accessible.cpp',
+    'ApplicationAccessible.cpp',
+    'BaseAccessibles.cpp',
+    'DocAccessible.cpp',
+    'FormControlAccessible.cpp',
+    'HyperTextAccessible.cpp',
+    'ImageAccessible.cpp',
+    'OuterDocAccessible.cpp',
+    'RootAccessible.cpp',
+    'TableCellAccessible.cpp',
+    'TextLeafAccessible.cpp',
+]
+
--- a/accessible/src/html/HTMLFormControlAccessible.cpp
+++ b/accessible/src/html/HTMLFormControlAccessible.cpp
@@ -7,18 +7,20 @@
 
 #include "Accessible-inl.h"
 #include "nsAccUtils.h"
 #include "nsEventShell.h"
 #include "nsTextEquivUtils.h"
 #include "Relation.h"
 #include "Role.h"
 #include "States.h"
+#include "TreeWalker.h"
 
 #include "nsContentList.h"
+#include "nsCxPusher.h"
 #include "mozilla/dom/HTMLInputElement.h"
 #include "nsIAccessibleRelation.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIDOMHTMLTextAreaElement.h"
 #include "nsIEditor.h"
 #include "nsIFormControl.h"
 #include "nsIFrame.h"
 #include "nsINameSpaceManager.h"
@@ -474,16 +476,32 @@ HTMLTextFieldAccessible::GetEditor() con
   pusher.PushNull();
 
   nsCOMPtr<nsIEditor> editor;
   editableElt->GetEditor(getter_AddRefs(editor));
 
   return editor.forget();
 }
 
+void
+HTMLTextFieldAccessible::CacheChildren()
+{
+  // XXX: textarea shouldn't contain anything but text leafs. Currently it may
+  // contain a trailing fake HTML br element added for layout needs. We don't
+  // need to expose it since it'd be confusing for AT.
+  TreeWalker walker(this, mContent);
+  Accessible* child = nullptr;
+  while ((child = walker.NextChild())) {
+    if (child->IsTextLeaf())
+      AppendChild(child);
+    else
+      Document()->UnbindFromDocument(child);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLTextFieldAccessible: Widgets
 
 bool
 HTMLTextFieldAccessible::IsWidget() const
 {
   return true;
 }
--- a/accessible/src/html/HTMLFormControlAccessible.h
+++ b/accessible/src/html/HTMLFormControlAccessible.h
@@ -89,17 +89,18 @@ public:
 
 protected:
   // Accessible
   virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
 };
 
 
 /**
- * Accessible for HTML input@type="text" element.
+ * Accessible for HTML input@type="text", input@type="password", textarea and
+ * other HTML text controls.
  */
 class HTMLTextFieldAccessible : public HyperTextAccessibleWrap
 {
 
 public:
   enum { eAction_Click = 0 };
 
   HTMLTextFieldAccessible(nsIContent* aContent, DocAccessible* aDoc);
@@ -124,16 +125,18 @@ public:
 
   // Widgets
   virtual bool IsWidget() const;
   virtual Accessible* ContainerWidget() const;
 
 protected:
   // Accessible
   virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
+
+  virtual void CacheChildren() MOZ_OVERRIDE;
 };
 
 
 /**
  * Accessible for input@type="file" element.
  */
 class HTMLFileInputAccessible : public HyperTextAccessibleWrap
 {
--- a/accessible/src/html/Makefile.in
+++ b/accessible/src/html/Makefile.in
@@ -8,29 +8,16 @@ topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME = accessibility_html_s
 LIBXUL_LIBRARY = 1
 
-
-
-CPPSRCS = \
-  HTMLCanvasAccessible.cpp \
-  HTMLElementAccessibles.cpp \
-  HTMLFormControlAccessible.cpp \
-  HTMLImageMapAccessible.cpp \
-  HTMLLinkAccessible.cpp \
-  HTMLListAccessible.cpp \
-  HTMLSelectAccessible.cpp \
-  HTMLTableAccessible.cpp \
-  $(NULL)
-
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES = \
   -I$(srcdir)/../base \
   -I$(srcdir)/../generic \
--- a/accessible/src/html/moz.build
+++ b/accessible/src/html/moz.build
@@ -1,8 +1,19 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MODULE = 'accessibility'
 
+CPP_SOURCES += [
+    'HTMLCanvasAccessible.cpp',
+    'HTMLElementAccessibles.cpp',
+    'HTMLFormControlAccessible.cpp',
+    'HTMLImageMapAccessible.cpp',
+    'HTMLLinkAccessible.cpp',
+    'HTMLListAccessible.cpp',
+    'HTMLSelectAccessible.cpp',
+    'HTMLTableAccessible.cpp',
+]
+
--- a/accessible/src/jsat/AccessFu.jsm
+++ b/accessible/src/jsat/AccessFu.jsm
@@ -23,47 +23,30 @@ this.AccessFu = {
   /**
    * Initialize chrome-layer accessibility functionality.
    * If accessibility is enabled on the platform, then a special accessibility
    * mode is started.
    */
   attach: function attach(aWindow) {
     Utils.init(aWindow);
 
-    this.prefsBranch = Cc['@mozilla.org/preferences-service;1']
-      .getService(Ci.nsIPrefService).getBranch('accessibility.accessfu.');
-    this.prefsBranch.addObserver('activate', this, false);
-
     try {
       Cc['@mozilla.org/android/bridge;1'].
         getService(Ci.nsIAndroidBridge).handleGeckoMessage(
           JSON.stringify({ type: 'Accessibility:Ready' }));
       Services.obs.addObserver(this, 'Accessibility:Settings', false);
     } catch (x) {
       // Not on Android
       if (Utils.MozBuildApp === 'b2g') {
         aWindow.addEventListener('ContentStart', this, false);
       }
     }
 
-    try {
-      this._activatePref = this.prefsBranch.getIntPref('activate');
-    } catch (x) {
-      this._activatePref = ACCESSFU_DISABLE;
-    }
-
-    try {
-      this._notifyOutput = this.prefsBranch.getBoolPref('notify_output');
-    } catch (x) {
-      this._notifyOutput = false;
-    }
-
-    this.Input.quickNavMode.updateModes(this.prefsBranch);
-
-    this._enableOrDisable();
+    this._activatePref = new PrefCache(
+      'accessibility.accessfu.activate', this._enableOrDisable.bind(this), true);
   },
 
   /**
    * Shut down chrome-layer accessibility functionality from the outside.
    */
   detach: function detach() {
     // Avoid disabling twice.
     if (this._enabled) {
@@ -71,17 +54,17 @@ this.AccessFu = {
     }
     if (Utils.MozBuildApp === 'mobile/android') {
       Services.obs.removeObserver(this, 'Accessibility:Settings');
     } else if (Utils.MozBuildApp === 'b2g') {
       Utils.win.shell.contentBrowser.contentWindow.removeEventListener(
         'mozContentEvent', this);
       Utils.win.removeEventListener('ContentStart', this);
     }
-    this.prefsBranch.removeObserver('activate', this);
+    delete this._activatePref;
     Utils.uninit();
   },
 
   /**
    * Start AccessFu mode, this primarily means controlling the virtual cursor
    * with arrow keys.
    */
   _enable: function _enable() {
@@ -102,25 +85,42 @@ this.AccessFu = {
 
     // Add stylesheet
     let stylesheetURL = 'chrome://global/content/accessibility/AccessFu.css';
     let stylesheet = Utils.win.document.createProcessingInstruction(
       'xml-stylesheet', 'href="' + stylesheetURL + '" type="text/css"');
     Utils.win.document.insertBefore(stylesheet, Utils.win.document.firstChild);
     this.stylesheet = Cu.getWeakReference(stylesheet);
 
+
+    // Populate quicknav modes
+    this._quicknavModesPref =
+      new PrefCache(
+        'accessibility.accessfu.quicknav_modes',
+        (aName, aValue) => {
+          this.Input.quickNavMode.updateModes(aValue);
+        }, true);
+
+    // Check for output notification
+    this._notifyOutputPref =
+      new PrefCache('accessibility.accessfu.notify_output');
+
+
     this.Input.start();
     Output.start();
     TouchAdapter.start();
 
     Services.obs.addObserver(this, 'remote-browser-frame-shown', false);
+    Services.obs.addObserver(this, 'in-process-browser-or-app-frame-shown', false);
     Services.obs.addObserver(this, 'Accessibility:NextObject', false);
     Services.obs.addObserver(this, 'Accessibility:PreviousObject', false);
     Services.obs.addObserver(this, 'Accessibility:Focus', false);
+    Services.obs.addObserver(this, 'Accessibility:ActivateObject', false);
     Utils.win.addEventListener('TabOpen', this);
+    Utils.win.addEventListener('TabClose', this);
     Utils.win.addEventListener('TabSelect', this);
 
     if (this.readyCallback) {
       this.readyCallback();
       delete this.readyCallback;
     }
   },
 
@@ -142,33 +142,37 @@ this.AccessFu = {
       this._removeMessageListeners(mm);
     }
 
     this.Input.stop();
     Output.stop();
     TouchAdapter.stop();
 
     Utils.win.removeEventListener('TabOpen', this);
+    Utils.win.removeEventListener('TabClose', this);
     Utils.win.removeEventListener('TabSelect', this);
 
     Services.obs.removeObserver(this, 'remote-browser-frame-shown');
+    Services.obs.removeObserver(this, 'in-process-browser-or-app-frame-shown');
     Services.obs.removeObserver(this, 'Accessibility:NextObject');
     Services.obs.removeObserver(this, 'Accessibility:PreviousObject');
     Services.obs.removeObserver(this, 'Accessibility:Focus');
+    Services.obs.removeObserver(this, 'Accessibility:ActivateObject');
 
     if (this.doneCallback) {
       this.doneCallback();
       delete this.doneCallback;
     }
   },
 
   _enableOrDisable: function _enableOrDisable() {
     try {
-      if (this._activatePref == ACCESSFU_ENABLE ||
-          this._systemPref && this._activatePref == ACCESSFU_AUTO)
+      let activatePref = this._activatePref.value;
+      if (activatePref == ACCESSFU_ENABLE ||
+          this._systemPref && activatePref == ACCESSFU_AUTO)
         this._enable();
       else
         this._disable();
     } catch (x) {
       dump('Error ' + x.message + ' ' + x.fileName + ':' + x.lineNumber);
     }
   },
 
@@ -200,17 +204,17 @@ this.AccessFu = {
 
       try {
         Output[presenter.type](presenter.details, aBrowser);
       } catch (x) {
         Logger.logException(x);
       }
     }
 
-    if (this._notifyOutput) {
+    if (this._notifyOutputPref.value) {
       Services.obs.notifyObservers(null, 'accessfu-output',
                                    JSON.stringify(aPresentationData));
     }
   },
 
   _loadFrameScript: function _loadFrameScript(aMessageManager) {
     if (this._processedMessageManagers.indexOf(aMessageManager) < 0) {
       aMessageManager.loadFrameScript(
@@ -250,41 +254,29 @@ this.AccessFu = {
         this._enableOrDisable();
         break;
       case 'Accessibility:NextObject':
         this.Input.moveCursor('moveNext', 'Simple', 'gesture');
         break;
       case 'Accessibility:PreviousObject':
         this.Input.moveCursor('movePrevious', 'Simple', 'gesture');
         break;
+      case 'Accessibility:ActivateObject':
+        this.Input.activateCurrent();
+        break;
       case 'Accessibility:Focus':
         this._focused = JSON.parse(aData);
         if (this._focused) {
           let mm = Utils.getMessageManager(Utils.CurrentBrowser);
           mm.sendAsyncMessage('AccessFu:VirtualCursor',
                               {action: 'whereIsIt', move: true});
         }
         break;
-      case 'nsPref:changed':
-        switch (aData) {
-          case 'activate':
-            this._activatePref = this.prefsBranch.getIntPref('activate');
-            this._enableOrDisable();
-            break;
-          case 'quicknav_modes':
-            this.Input.quickNavMode.updateModes(this.prefsBranch);
-            break;
-          case 'notify_output':
-            this._notifyOutput = this.prefsBranch.getBoolPref('notify_output');
-            break;
-          default:
-            break;
-        }
-        break;
       case 'remote-browser-frame-shown':
+      case 'in-process-browser-or-app-frame-shown':
       {
         let mm = aSubject.QueryInterface(Ci.nsIFrameLoader).messageManager;
         this._handleMessageManager(mm);
         break;
       }
     }
   },
 
@@ -305,16 +297,26 @@ this.AccessFu = {
         break;
       }
       case 'TabOpen':
       {
         let mm = Utils.getMessageManager(aEvent.target);
         this._handleMessageManager(mm);
         break;
       }
+      case 'TabClose':
+      {
+        let mm = Utils.getMessageManager(aEvent.target);
+        let mmIndex = this._processedMessageManagers.indexOf(mm);
+        if (mmIndex > -1) {
+          this._removeMessageListeners(mm);
+          this._processedMessageManagers.splice(mmIndex, 1);
+        }
+        break;
+      }
       case 'TabSelect':
       {
         if (this._focused) {
           let mm = Utils.getMessageManager(Utils.CurrentBrowser);
           // We delay this for half a second so the awesomebar could close,
           // and we could use the current coordinates for the content item.
           // XXX TODO figure out how to avoid magic wait here.
           Utils.win.setTimeout(
@@ -459,19 +461,30 @@ var Output = {
     Utils.win.navigator.vibrate(aDetails.pattern);
   },
 
   _adjustBounds: function(aJsonBounds, aBrowser) {
     let bounds = new Rect(aJsonBounds.left, aJsonBounds.top,
                           aJsonBounds.right - aJsonBounds.left,
                           aJsonBounds.bottom - aJsonBounds.top);
     let vp = Utils.getViewport(Utils.win) || { zoom: 1.0, offsetY: 0 };
-    let browserOffset = aBrowser.getBoundingClientRect();
+    let root = Utils.win;
+    let offset = { left: -root.mozInnerScreenX, top: -root.mozInnerScreenY };
+    let scale = 1 / Utils.getPixelsPerCSSPixel(Utils.win);
 
-    return bounds.translate(browserOffset.left, browserOffset.top).
+    if (!aBrowser.contentWindow) {
+      // OOP browser, add offset of browser.
+      // The offset of the browser element in relation to its parent window.
+      let clientRect = aBrowser.getBoundingClientRect();
+      let win = aBrowser.ownerDocument.defaultView;
+      offset.left += clientRect.left + win.mozInnerScreenX;
+      offset.top += clientRect.top + win.mozInnerScreenY;
+    }
+
+    return bounds.scale(scale, scale).translate(offset.left, offset.top).
       scale(vp.zoom, vp.zoom).expandToIntegers();
   }
 };
 
 var Input = {
   editState: {},
 
   start: function start() {
@@ -702,21 +715,20 @@ var Input = {
         this._currentIndex = this.modes.length - 1;
     },
 
     next: function quickNavMode_next() {
       if (++this._currentIndex >= this.modes.length)
         this._currentIndex = 0;
     },
 
-    updateModes: function updateModes(aPrefsBranch) {
-      try {
-        this.modes = aPrefsBranch.getCharPref('quicknav_modes').split(',');
-      } catch (x) {
-        // Fallback
+    updateModes: function updateModes(aModes) {
+      if (aModes) {
+        this.modes = aModes.split(',');
+      } else {
         this.modes = [];
       }
     },
 
     _currentIndex: -1
   }
 };
 AccessFu.Input = Input;
--- a/accessible/src/jsat/EventManager.jsm
+++ b/accessible/src/jsat/EventManager.jsm
@@ -1,54 +1,91 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-var Cr = Components.results;
+'use strict';
+
+const Ci = Components.interfaces;
+const Cu = Components.utils;
 
-Cu.import('resource://gre/modules/accessibility/Utils.jsm');
-Cu.import('resource://gre/modules/accessibility/Presentation.jsm');
-Cu.import('resource://gre/modules/accessibility/TraversalRules.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Services',
+  'resource://gre/modules/Services.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Utils',
+  'resource://gre/modules/accessibility/Utils.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Logger',
+  'resource://gre/modules/accessibility/Utils.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Presentation',
+  'resource://gre/modules/accessibility/Presentation.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'TraversalRules',
+  'resource://gre/modules/accessibility/TraversalRules.jsm');
 
 this.EXPORTED_SYMBOLS = ['EventManager'];
 
-this.EventManager = {
+this.EventManager = function EventManager(aContentScope) {
+  this.contentScope = aContentScope;
+  this.addEventListener = this.contentScope.addEventListener.bind(
+    this.contentScope);
+  this.removeEventListener = this.contentScope.removeEventListener.bind(
+    this.contentScope);
+  this.sendMsgFunc = this.contentScope.sendAsyncMessage.bind(
+    this.contentScope);
+  this.webProgress = this.contentScope.docShell.
+    QueryInterface(Ci.nsIInterfaceRequestor).
+    getInterface(Ci.nsIWebProgress);
+};
+
+this.EventManager.prototype = {
   editState: {},
 
-  start: function start(aSendMsgFunc) {
+  start: function start() {
     try {
       if (!this._started) {
-        this.sendMsgFunc = aSendMsgFunc || function() {};
-
         Logger.info('EventManager.start', Utils.MozBuildApp);
 
         this._started = true;
-        Services.obs.addObserver(this, 'accessible-event', false);
+
+        AccessibilityEventObserver.addListener(this);
+
+        this.webProgress.addProgressListener(this,
+          (Ci.nsIWebProgress.NOTIFY_STATE_ALL |
+           Ci.nsIWebProgress.NOTIFY_LOCATION));
+        this.addEventListener('scroll', this, true);
+        this.addEventListener('resize', this, true);
+        // XXX: Ideally this would be an a11y event. Bug #742280.
+        this.addEventListener('DOMActivate', this, true);
       }
-
       this.present(Presentation.tabStateChanged(null, 'newtab'));
 
     } catch (x) {
       Logger.error('Failed to start EventManager');
       Logger.logException(x);
     }
   },
 
+  // XXX: Stop is not called when the tab is closed (|TabClose| event is too
+  // late). It is only called when the AccessFu is disabled explicitly.
   stop: function stop() {
     if (!this._started) {
       return;
     }
     Logger.info('EventManager.stop', Utils.MozBuildApp);
-    Services.obs.removeObserver(this, 'accessible-event');
-    this._started = false;
+    AccessibilityEventObserver.removeListener(this);
+    try {
+      this.webProgress.removeProgressListener(this);
+      this.removeEventListener('scroll', this, true);
+      this.removeEventListener('resize', this, true);
+      // XXX: Ideally this would be an a11y event. Bug #742280.
+      this.removeEventListener('DOMActivate', this, true);
+    } catch (x) {
+      // contentScope is dead.
+    } finally {
+      this._started = false;
+    }
   },
 
   handleEvent: function handleEvent(aEvent) {
     try {
       switch (aEvent.type) {
       case 'DOMActivate':
       {
         let activatedAcc =
@@ -80,48 +117,33 @@ this.EventManager = {
       }
       }
     } catch (x) {
       Logger.error('Error handling DOM event');
       Logger.logException(x);
     }
   },
 
-  observe: function observe(aSubject, aTopic, aData) {
-    switch (aTopic) {
-      case 'accessible-event':
-        var event;
-        try {
-          event = aSubject.QueryInterface(Ci.nsIAccessibleEvent);
-          this.handleAccEvent(event);
-        } catch (x) {
-          Logger.error('Error handing accessible event');
-          Logger.logException(x);
-          return;
-        }
-    }
-  },
-
   handleAccEvent: function handleAccEvent(aEvent) {
     if (Logger.logLevel >= Logger.DEBUG)
       Logger.debug('A11yEvent', Logger.eventToString(aEvent),
                    Logger.accessibleToString(aEvent.accessible));
 
     // Don't bother with non-content events in firefox.
     if (Utils.MozBuildApp == 'browser' &&
         aEvent.eventType != Ci.nsIAccessibleEvent.EVENT_VIRTUALCURSOR_CHANGED &&
         aEvent.accessibleDocument != Utils.CurrentContentDoc) {
       return;
     }
 
     switch (aEvent.eventType) {
       case Ci.nsIAccessibleEvent.EVENT_VIRTUALCURSOR_CHANGED:
       {
         let pivot = aEvent.accessible.
-          QueryInterface(Ci.nsIAccessibleCursorable).virtualCursor;
+          QueryInterface(Ci.nsIAccessibleDocument).virtualCursor;
         let position = pivot.position;
         if (position.role == Ci.nsIAccessibleRole.ROLE_INTERNAL_FRAME)
           break;
         let event = aEvent.
           QueryInterface(Ci.nsIAccessibleVirtualCursorChangeEvent);
         let reason = event.reason;
 
         if (this.editState.editing)
@@ -222,21 +244,16 @@ this.EventManager = {
       }
     }
   },
 
   present: function present(aPresentationData) {
     this.sendMsgFunc("AccessFu:Present", aPresentationData);
   },
 
-  presentVirtualCursorPosition: function presentVirtualCursorPosition(aVirtualCursor) {
-    this.present(Presentation.pivotChanged(aVirtualCursor.position, null,
-                                           Ci.nsIAccessiblePivot.REASON_NONE));
-  },
-
   onStateChange: function onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
     let tabstate = '';
 
     let loadingState = Ci.nsIWebProgressListener.STATE_TRANSFERRING |
       Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
     let loadedState = Ci.nsIWebProgressListener.STATE_STOP |
       Ci.nsIWebProgressListener.STATE_IS_NETWORK;
 
@@ -264,8 +281,150 @@ this.EventManager = {
 
   onSecurityChange: function onSecurityChange() {},
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
                                          Ci.nsISupportsWeakReference,
                                          Ci.nsISupports,
                                          Ci.nsIObserver])
 };
+
+const AccessibilityEventObserver = {
+
+  /**
+   * A WeakMap containing [content, EventManager] pairs.
+   */
+  eventManagers: new WeakMap(),
+
+  /**
+   * A total number of registered eventManagers.
+   */
+  listenerCount: 0,
+
+  /**
+   * An indicator of an active 'accessible-event' observer.
+   */
+  started: false,
+
+  /**
+   * Start an AccessibilityEventObserver.
+   */
+  start: function start() {
+    if (this.started || this.listenerCount === 0) {
+      return;
+    }
+    Services.obs.addObserver(this, 'accessible-event', false);
+    this.started = true;
+  },
+
+  /**
+   * Stop an AccessibilityEventObserver.
+   */
+  stop: function stop() {
+    if (!this.started) {
+      return;
+    }
+    Services.obs.removeObserver(this, 'accessible-event');
+    // Clean up all registered event managers.
+    this.eventManagers.clear();
+    this.listenerCount = 0;
+    this.started = false;
+  },
+
+  /**
+   * Register an EventManager and start listening to the
+   * 'accessible-event' messages.
+   *
+   * @param aEventManager EventManager
+   *        An EventManager object that was loaded into the specific content.
+   */
+  addListener: function addListener(aEventManager) {
+    let content = aEventManager.contentScope.content;
+    if (!this.eventManagers.has(content)) {
+      this.listenerCount++;
+    }
+    this.eventManagers.set(content, aEventManager);
+    // Since at least one EventManager was registered, start listening.
+    Logger.debug('AccessibilityEventObserver.addListener. Total:',
+      this.listenerCount);
+    this.start();
+  },
+
+  /**
+   * Unregister an EventManager and, optionally, stop listening to the
+   * 'accessible-event' messages.
+   *
+   * @param aEventManager EventManager
+   *        An EventManager object that was stopped in the specific content.
+   */
+  removeListener: function removeListener(aEventManager) {
+    let content = aEventManager.contentScope.content;
+    if (!this.eventManagers.delete(content)) {
+      return;
+    }
+    this.listenerCount--;
+    Logger.debug('AccessibilityEventObserver.removeListener. Total:',
+      this.listenerCount);
+    if (this.listenerCount === 0) {
+      // If there are no EventManagers registered at the moment, stop listening
+      // to the 'accessible-event' messages.
+      this.stop();
+    }
+  },
+
+  /**
+   * Lookup an EventManager for a specific content. If the EventManager is not
+   * found, walk up the hierarchy of parent windows.
+   * @param content Window
+   *        A content Window used to lookup the corresponding EventManager.
+   */
+  getListener: function getListener(content) {
+    let eventManager = this.eventManagers.get(content);
+    if (eventManager) {
+      return eventManager;
+    }
+    let parent = content.parent;
+    if (parent === content) {
+      // There is no parent or the parent is of a different type.
+      return null;
+    }
+    return this.getListener(parent);
+  },
+
+  /**
+   * Handle the 'accessible-event' message.
+   */
+  observe: function observe(aSubject, aTopic, aData) {
+    if (aTopic !== 'accessible-event') {
+      return;
+    }
+    let event = aSubject.QueryInterface(Ci.nsIAccessibleEvent);
+    if (!event.accessibleDocument) {
+      Logger.warning(
+        'AccessibilityEventObserver.observe: no accessible document:',
+        Logger.eventToString(event), "accessible:",
+        Logger.accessibleToString(event.accessible));
+      return;
+    }
+    let content = event.accessibleDocument.window;
+    // Match the content window to its EventManager.
+    let eventManager = this.getListener(content);
+    if (!eventManager || !eventManager._started) {
+      if (Utils.MozBuildApp === 'browser' &&
+          !(content instanceof Ci.nsIDOMChromeWindow)) {
+        Logger.warning(
+          'AccessibilityEventObserver.observe: ignored event:',
+          Logger.eventToString(event), "accessible:",
+          Logger.accessibleToString(event.accessible), "document:",
+          Logger.accessibleToString(event.accessibleDocument));
+      }
+      return;
+    }
+    try {
+      eventManager.handleAccEvent(event);
+    } catch (x) {
+      Logger.error('Error handing accessible event');
+      Logger.logException(x);
+    } finally {
+      return;
+    }
+  }
+};
--- a/accessible/src/jsat/Presentation.jsm
+++ b/accessible/src/jsat/Presentation.jsm
@@ -212,32 +212,43 @@ AndroidPresenter.prototype = {
       this.ANDROID_VIEW_FOCUSED;
 
     if (isExploreByTouch) {
       // This isn't really used by TalkBack so this is a half-hearted attempt
       // for now.
       androidEvents.push({eventType: this.ANDROID_VIEW_HOVER_EXIT, text: []});
     }
 
+    let state = Utils.getStates(aContext.accessible)[0];
+
     androidEvents.push({eventType: (isExploreByTouch) ?
                           this.ANDROID_VIEW_HOVER_ENTER : focusEventType,
                         text: UtteranceGenerator.genForContext(aContext),
-                        bounds: aContext.bounds});
+                        bounds: aContext.bounds,
+                        clickable: aContext.accessible.actionCount > 0,
+                        checkable: !!(state &
+                                      Ci.nsIAccessibleStates.STATE_CHECKABLE),
+                        checked: !!(state &
+                                    Ci.nsIAccessibleStates.STATE_CHECKED)});
+
+
     return {
       type: this.type,
       details: androidEvents
     };
   },
 
   actionInvoked: function AndroidPresenter_actionInvoked(aObject, aActionName) {
+    let state = Utils.getStates(aObject)[0];
     return {
       type: this.type,
       details: [{
         eventType: this.ANDROID_VIEW_CLICKED,
-        text: UtteranceGenerator.genForAction(aObject, aActionName)
+        text: UtteranceGenerator.genForAction(aObject, aActionName),
+        checked: !!(state & Ci.nsIAccessibleStates.STATE_CHECKED)
       }]
     };
   },
 
   tabSelected: function AndroidPresenter_tabSelected(aDocContext, aVCContext) {
     // Send a pivot change message with the full context utterance for this doc.
     return this.pivotChanged(aVCContext, Ci.nsIAccessiblePivot.REASON_NONE);
   },
--- a/accessible/src/jsat/TraversalRules.jsm
+++ b/accessible/src/jsat/TraversalRules.jsm
@@ -26,19 +26,19 @@ BaseTraversalRule.prototype = {
     },
 
     preFilter: Ci.nsIAccessibleTraversalRule.PREFILTER_DEFUNCT |
     Ci.nsIAccessibleTraversalRule.PREFILTER_INVISIBLE,
 
     match: function BaseTraversalRule_match(aAccessible)
     {
       if (aAccessible.role == Ci.nsIAccessibleRole.ROLE_INTERNAL_FRAME) {
-        return (aAccessible.childCount) ?
-          Ci.nsIAccessibleTraversalRule.FILTER_IGNORE :
-          Ci.nsIAccessibleTraversalRule.FILTER_MATCH;
+        return (Utils.getMessageManager(aAccessible.DOMNode)) ?
+          Ci.nsIAccessibleTraversalRule.FILTER_MATCH :
+          Ci.nsIAccessibleTraversalRule.FILTER_IGNORE;
       }
 
       if (this._matchFunc)
         return this._matchFunc(aAccessible);
 
       return Ci.nsIAccessibleTraversalRule.FILTER_MATCH;
     },
 
--- a/accessible/src/jsat/Utils.jsm
+++ b/accessible/src/jsat/Utils.jsm
@@ -3,20 +3,23 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 'use strict';
 
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
-Cu.import('resource://gre/modules/Services.jsm');
-Cu.import('resource://gre/modules/Geometry.jsm');
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, 'Services',
+  'resource://gre/modules/Services.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Rect',
+  'resource://gre/modules/Geometry.jsm');
 
-this.EXPORTED_SYMBOLS = ['Utils', 'Logger', 'PivotContext'];
+this.EXPORTED_SYMBOLS = ['Utils', 'Logger', 'PivotContext', 'PrefCache'];
 
 this.Utils = {
   _buildAppMap: {
     '{3c2e2abc-06d4-11e1-ac3b-374f68613e61}': 'b2g',
     '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}': 'browser',
     '{aa3c5121-dab2-40e2-81ca-7ea25febc110}': 'mobile/android',
     '{a23983c0-fd0e-11dc-95ff-0800200c9a66}': 'mobile/xul'
   },
@@ -32,16 +35,19 @@ this.Utils = {
   uninit: function Utils_uninit() {
     if (!this._win) {
       return;
     }
     delete this._win;
   },
 
   get win() {
+    if (!this._win) {
+      return null;
+    }
     return this._win.get();
   },
 
   get AccRetrieval() {
     if (!this._AccRetrieval) {
       this._AccRetrieval = Cc['@mozilla.org/accessibleRetrieval;1'].
         getService(Ci.nsIAccessibleRetrieval);
     }
@@ -85,29 +91,35 @@ this.Utils = {
   },
 
   set AndroidSdkVersion(value) {
     // When we want to mimic another version.
     this._AndroidSdkVersion = value;
   },
 
   get BrowserApp() {
+    if (!this.win) {
+      return null;
+    }
     switch (this.MozBuildApp) {
       case 'mobile/android':
         return this.win.BrowserApp;
       case 'browser':
         return this.win.gBrowser;
       case 'b2g':
         return this.win.shell;
       default:
         return null;
     }
   },
 
   get CurrentBrowser() {
+    if (!this.BrowserApp) {
+      return null;
+    }
     if (this.MozBuildApp == 'b2g')
       return this.BrowserApp.contentBrowser;
     return this.BrowserApp.selectedBrowser;
   },
 
   get CurrentContentDoc() {
     let browser = this.CurrentBrowser;
     return browser ? browser.contentDocument : null;
@@ -117,25 +129,37 @@ this.Utils = {
     let messageManagers = [];
 
     for (let i = 0; i < this.win.messageManager.childCount; i++)
       messageManagers.push(this.win.messageManager.getChildAt(i));
 
     let document = this.CurrentContentDoc;
 
     if (document) {
-      let remoteframes = document.querySelectorAll('iframe[remote=true]');
+      let remoteframes = document.querySelectorAll('iframe');
 
-      for (let i = 0; i < remoteframes.length; ++i)
-        messageManagers.push(this.getMessageManager(remoteframes[i]));
+      for (let i = 0; i < remoteframes.length; ++i) {
+        let mm = this.getMessageManager(remoteframes[i]);
+        if (mm) {
+          messageManagers.push(mm);
+        }
+      }
+
     }
 
     return messageManagers;
   },
 
+  get isContentProcess() {
+    delete this.isContentProcess;
+    this.isContentProcess =
+      Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
+    return this.isContentProcess;
+  },
+
   getMessageManager: function getMessageManager(aBrowser) {
     try {
       return aBrowser.QueryInterface(Ci.nsIFrameLoaderOwner).
          frameLoader.messageManager;
     } catch (x) {
       Logger.logException(x);
       return null;
     }
@@ -159,25 +183,22 @@ this.Utils = {
     aAccessible.getState(state, extState);
     return [state.value, extState.value];
   },
 
   getVirtualCursor: function getVirtualCursor(aDocument) {
     let doc = (aDocument instanceof Ci.nsIAccessible) ? aDocument :
       this.AccRetrieval.getAccessibleFor(aDocument);
 
-    while (doc) {
-      try {
-        return doc.QueryInterface(Ci.nsIAccessibleCursorable).virtualCursor;
-      } catch (x) {
-        doc = doc.parentDocument;
-      }
-    }
+    return doc.QueryInterface(Ci.nsIAccessibleDocument).virtualCursor;
+  },
 
-    return null;
+  getPixelsPerCSSPixel: function getPixelsPerCSSPixel(aWindow) {
+    return aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+      .getInterface(Ci.nsIDOMWindowUtils).screenPixelsPerCSSPixel;
   }
 };
 
 this.Logger = {
   DEBUG: 0,
   INFO: 1,
   WARNING: 2,
   ERROR: 3,
@@ -223,19 +244,20 @@ this.Logger = {
 
   error: function error() {
     this.log.apply(
       this, [this.ERROR].concat(Array.prototype.slice.call(arguments)));
   },
 
   logException: function logException(aException) {
     try {
-      this.error(
-        aException.message,
-        '(' + aException.fileName + ':' + aException.lineNumber + ')');
+      let args = [aException.message];
+      args.push.apply(args, aException.stack ? ['\n', aException.stack] :
+        ['(' + aException.fileName + ':' + aException.lineNumber + ')']);
+      this.error.apply(this, args);
     } catch (x) {
       this.error(x);
     }
   },
 
   accessibleToString: function accessibleToString(aAccessible) {
     let str = '[ defunct ]';
     try {
@@ -387,32 +409,75 @@ PivotContext.prototype = {
   },
 
   get bounds() {
     if (!this._bounds) {
       let objX = {}, objY = {}, objW = {}, objH = {};
 
       this._accessible.getBounds(objX, objY, objW, objH);
 
-      // XXX: OOP content provides a screen offset of 0, while in-process provides a real
-      // offset. Removing the offset and using content-relative coords normalizes this.
-      let docX = {}, docY = {};
-      let docRoot = this._accessible.rootDocument.
-        QueryInterface(Ci.nsIAccessible);
-      docRoot.getBounds(docX, docY, {}, {});
-
-      this._bounds = new Rect(objX.value, objY.value, objW.value, objH.value).
-        translate(-docX.value, -docY.value);
+      this._bounds = new Rect(objX.value, objY.value, objW.value, objH.value);
     }
 
     return this._bounds.clone();
   },
 
   _isDefunct: function _isDefunct(aAccessible) {
     try {
       let extstate = {};
       aAccessible.getState({}, extstate);
       return !!(aAccessible.value & Ci.nsIAccessibleStates.EXT_STATE_DEFUNCT);
     } catch (x) {
       return true;
     }
   }
+};
+
+this.PrefCache = function PrefCache(aName, aCallback, aRunCallbackNow) {
+  this.name = aName;
+  this.callback = aCallback;
+
+  let branch = Services.prefs;
+  this.value = this._getValue(branch);
+
+  if (this.callback && aRunCallbackNow) {
+    try {
+      this.callback(this.name, this.value);
+    } catch (x) {
+      Logger.logException(x);
+    }
+  }
+
+  branch.addObserver(aName, this, true);
+};
+
+PrefCache.prototype = {
+  _getValue: function _getValue(aBranch) {
+    if (!this.type) {
+      this.type = aBranch.getPrefType(this.name);
+    }
+
+    switch (this.type) {
+      case Ci.nsIPrefBranch.PREF_STRING:
+        return aBranch.getCharPref(this.name);
+      case Ci.nsIPrefBranch.PREF_INT:
+        return aBranch.getIntPref(this.name);
+      case Ci.nsIPrefBranch.PREF_BOOL:
+        return aBranch.getBoolPref(this.name);
+      default:
+        return null;
+    }
+  },
+
+  observe: function observe(aSubject, aTopic, aData) {
+    this.value = this._getValue(aSubject.QueryInterface(Ci.nsIPrefBranch));
+    if (this.callback) {
+      try {
+        this.callback(this.name, this.value);
+      } catch (x) {
+        Logger.logException(x);
+      }
+    }
+  },
+
+  QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference])
 };
\ No newline at end of file
--- a/accessible/src/jsat/UtteranceGenerator.jsm
+++ b/accessible/src/jsat/UtteranceGenerator.jsm
@@ -10,39 +10,26 @@ const Cu = Components.utils;
 const Cr = Components.results;
 
 const INCLUDE_DESC = 0x01;
 const INCLUDE_NAME = 0x02;
 const INCLUDE_CUSTOM = 0x04;
 
 const UTTERANCE_DESC_FIRST = 0;
 
-// Read and observe changes to a setting for utterance order.
-let gUtteranceOrder;
-let prefsBranch = Cc['@mozilla.org/preferences-service;1']
-  .getService(Ci.nsIPrefService).getBranch('accessibility.accessfu.');
-let observeUtterance = function observeUtterance(aSubject, aTopic, aData) {
-  try {
-    gUtteranceOrder = prefsBranch.getIntPref('utterance');
-  } catch (x) {
-    gUtteranceOrder = UTTERANCE_DESC_FIRST;
-  }
-};
-// Set initial gUtteranceOrder.
-observeUtterance();
-prefsBranch.addObserver('utterance', observeUtterance, false);
+Cu.import('resource://gre/modules/accessibility/Utils.jsm');
+
+let gUtteranceOrder = new PrefCache('accessibility.accessfu.utterance');
 
 var gStringBundle = Cc['@mozilla.org/intl/stringbundle;1'].
   getService(Ci.nsIStringBundleService).
   createBundle('chrome://global/locale/AccessFu.properties');
 
-
 this.EXPORTED_SYMBOLS = ['UtteranceGenerator'];
 
-Cu.import('resource://gre/modules/accessibility/Utils.jsm');
 
 /**
  * Generates speech utterances from objects, actions and state changes.
  * An utterance is an array of strings.
  *
  * It should not be assumed that flattening an utterance array would create a
  * gramatically correct sentence. For example, {@link genForObject} might
  * return: ['graphic', 'Welcome to my home page'].
@@ -83,17 +70,19 @@ this.UtteranceGenerator = {
    */
   genForContext: function genForContext(aContext) {
     let utterance = [];
     let addUtterance = function addUtterance(aAccessible) {
       utterance.push.apply(utterance,
         UtteranceGenerator.genForObject(aAccessible));
     };
 
-    if (gUtteranceOrder === UTTERANCE_DESC_FIRST) {
+    let utteranceOrder = gUtteranceOrder.value || UTTERANCE_DESC_FIRST;
+
+    if (utteranceOrder === UTTERANCE_DESC_FIRST) {
       aContext.newAncestry.forEach(addUtterance);
       addUtterance(aContext.accessible);
       aContext.subtreePreorder.forEach(addUtterance);
     } else {
       aContext.subtreePostorder.forEach(addUtterance);
       addUtterance(aContext.accessible);
       aContext.newAncestry.reverse().forEach(addUtterance);
     }
@@ -112,17 +101,17 @@ this.UtteranceGenerator = {
    *    {@link verbosityRoleMap}.
    */
   genForObject: function genForObject(aAccessible) {
     let roleString = Utils.AccRetrieval.getStringRole(aAccessible.role);
 
     let func = this.objectUtteranceFunctions[roleString] ||
       this.objectUtteranceFunctions.defaultFunc;
 
-    let flags = this.verbosityRoleMap[roleString] || 0;
+    let flags = this.verbosityRoleMap[roleString] || UTTERANCE_DESC_FIRST;
 
     if (aAccessible.childCount == 0)
       flags |= INCLUDE_NAME;
 
     let state = {};
     let extState = {};
     aAccessible.getState(state, extState);
     let states = {base: state.value, ext: extState.value};
@@ -321,18 +310,20 @@ this.UtteranceGenerator = {
           [aAccessible, aRoleStr, aStates, aFlags]);
 
       return [];
     }
   },
 
   _addName: function _addName(utterance, aAccessible, aFlags) {
     let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : '';
+    let utteranceOrder = gUtteranceOrder.value || 0;
+
     if (name) {
-      utterance[gUtteranceOrder === UTTERANCE_DESC_FIRST ?
+      utterance[utteranceOrder === UTTERANCE_DESC_FIRST ?
         "push" : "unshift"](name);
     }
   },
 
   _getLocalizedRole: function _getLocalizedRole(aRoleStr) {
     try {
       return gStringBundle.GetStringFromName(aRoleStr.replace(' ', ''));
     } catch (x) {
@@ -342,17 +333,21 @@ this.UtteranceGenerator = {
 
   _getLocalizedStates: function _getLocalizedStates(aStates) {
     let stateUtterances = [];
 
     if (aStates.base & Ci.nsIAccessibleStates.STATE_UNAVAILABLE) {
       stateUtterances.push(gStringBundle.GetStringFromName('stateUnavailable'));
     }
 
-    if (aStates.base & Ci.nsIAccessibleStates.STATE_CHECKABLE) {
+    // Don't utter this in Jelly Bean, we let TalkBack do it for us there.
+    // This is because we expose the checked information on the node itself.
+    // XXX: this means the checked state is always appended to the end, regardless
+    // of the utterance ordering preference.
+    if (Utils.AndroidSdkVersion < 16 && aStates.base & Ci.nsIAccessibleStates.STATE_CHECKABLE) {
       let stateStr = (aStates.base & Ci.nsIAccessibleStates.STATE_CHECKED) ?
         'stateChecked' : 'stateNotChecked';
       stateUtterances.push(gStringBundle.GetStringFromName(stateStr));
     }
 
     if (aStates.ext & Ci.nsIAccessibleStates.EXT_STATE_EXPANDABLE) {
       let stateStr = (aStates.base & Ci.nsIAccessibleStates.STATE_EXPANDED) ?
         'stateExpanded' : 'stateCollapsed';
--- a/accessible/src/jsat/content-script.js
+++ b/accessible/src/jsat/content-script.js
@@ -1,24 +1,31 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-var Cr = Components.results;
+let Ci = Components.interfaces;
+let Cu = Components.utils;
 
-Cu.import('resource://gre/modules/accessibility/Utils.jsm');
-Cu.import('resource://gre/modules/accessibility/EventManager.jsm');
-Cu.import('resource://gre/modules/accessibility/TraversalRules.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Logger',
+  'resource://gre/modules/accessibility/Utils.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Presentation',
+  'resource://gre/modules/accessibility/Presentation.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'TraversalRules',
+  'resource://gre/modules/accessibility/TraversalRules.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Utils',
+  'resource://gre/modules/accessibility/Utils.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'EventManager',
+  'resource://gre/modules/accessibility/EventManager.jsm');
 
 Logger.debug('content-script.js');
 
+let eventManager = null;
+
 function virtualCursorControl(aMessage) {
   if (Logger.logLevel >= Logger.DEBUG)
     Logger.debug(aMessage.name, JSON.stringify(aMessage.json));
 
   try {
     let vc = Utils.getVirtualCursor(content.document);
     let origin = aMessage.json.origin;
     if (origin != 'child') {
@@ -47,24 +54,31 @@ function virtualCursorControl(aMessage) 
         }
       } catch (x) {
         let acc = Utils.AccRetrieval.
           getAccessibleFor(content.document.activeElement);
         moved = vc.moveNext(rule, acc, true);
       }
       break;
     case 'moveToPoint':
-      moved = vc.moveToPoint(rule, details.x, details.y, true);
+      if (!this._ppcp) {
+        this._ppcp = Utils.getPixelsPerCSSPixel(content);
+      }
+      moved = vc.moveToPoint(rule,
+                             details.x * this._ppcp, details.y * this._ppcp,
+                             true);
       break;
     case 'whereIsIt':
       if (!forwardMessage(vc, aMessage)) {
         if (!vc.position && aMessage.json.move)
           vc.moveFirst(TraversalRules.Simple);
-        else
-          EventManager.presentVirtualCursorPosition(vc);
+        else {
+          sendAsyncMessage('AccessFu:Present', Presentation.pivotChanged(
+            vc.position, null, Ci.nsIAccessiblePivot.REASON_NONE));
+        }
       }
 
       break;
     default:
       break;
     }
 
     if (moved == true) {
@@ -83,20 +97,22 @@ function virtualCursorControl(aMessage) 
 
 function forwardMessage(aVirtualCursor, aMessage) {
   try {
     let acc = aVirtualCursor.position;
     if (acc && acc.role == Ci.nsIAccessibleRole.ROLE_INTERNAL_FRAME) {
       let mm = Utils.getMessageManager(acc.DOMNode);
       mm.addMessageListener(aMessage.name, virtualCursorControl);
       aMessage.json.origin = 'parent';
-      // XXX: OOP content's screen offset is 0,
-      // so we remove the real screen offset here.
-      aMessage.json.x -= content.mozInnerScreenX;
-      aMessage.json.y -= content.mozInnerScreenY;
+      if (Utils.isContentProcess) {
+        // XXX: OOP content's screen offset is 0,
+        // so we remove the real screen offset here.
+        aMessage.json.x -= content.mozInnerScreenX;
+        aMessage.json.y -= content.mozInnerScreenY;
+      }
       mm.sendAsyncMessage(aMessage.name, aMessage.json);
       return true;
     }
   } catch (x) {
     // Frame may be hidden, we regard this case as false.
   }
   return false;
 }
@@ -119,24 +135,24 @@ function activateCurrent(aMessage) {
       aAccessible.getBounds(objX, objY, objW, objH);
 
       let x = Math.round((objX.value - docX.value) + objW.value / 2);
       let y = Math.round((objY.value - docY.value) + objH.value / 2);
 
       let node = aAccessible.DOMNode || aAccessible.parent.DOMNode;
 
       function dispatchMouseEvent(aEventType) {
-        let evt = content.document.createEvent("MouseEvents");
+        let evt = content.document.createEvent('MouseEvents');
         evt.initMouseEvent(aEventType, true, true, content,
                            x, y, 0, 0, 0, false, false, false, false, 0, null);
         node.dispatchEvent(evt);
       }
 
-      dispatchMouseEvent("mousedown");
-      dispatchMouseEvent("mouseup");
+      dispatchMouseEvent('mousedown');
+      dispatchMouseEvent('mouseup');
     }
   }
 
   let vc = Utils.getVirtualCursor(content.document);
   if (!forwardMessage(vc, aMessage))
     activateAccessible(vc.position);
 }
 
@@ -229,45 +245,27 @@ addMessageListener(
     Logger.debug('AccessFu:Start');
     if (m.json.buildApp)
       Utils.MozBuildApp = m.json.buildApp;
 
     addMessageListener('AccessFu:VirtualCursor', virtualCursorControl);
     addMessageListener('AccessFu:Activate', activateCurrent);
     addMessageListener('AccessFu:Scroll', scroll);
 
-    EventManager.start(
-      function sendMessage(aName, aDetails) {
-        sendAsyncMessage(aName, aDetails);
-      });
-
-    docShell.QueryInterface(Ci.nsIInterfaceRequestor).
-      getInterface(Ci.nsIWebProgress).
-      addProgressListener(EventManager,
-                          (Ci.nsIWebProgress.NOTIFY_STATE_ALL |
-                           Ci.nsIWebProgress.NOTIFY_LOCATION));
-    addEventListener('scroll', EventManager, true);
-    addEventListener('resize', EventManager, true);
-    // XXX: Ideally this would be an a11y event. Bug #742280.
-    addEventListener('DOMActivate', EventManager, true);
+    if (!eventManager) {
+      eventManager = new EventManager(this);
+    }
+    eventManager.start();
   });
 
 addMessageListener(
   'AccessFu:Stop',
   function(m) {
     Logger.debug('AccessFu:Stop');
 
     removeMessageListener('AccessFu:VirtualCursor', virtualCursorControl);
     removeMessageListener('AccessFu:Activate', activateCurrent);
     removeMessageListener('AccessFu:Scroll', scroll);
 
-    EventManager.stop();
-
-    docShell.QueryInterface(Ci.nsIInterfaceRequestor).
-      getInterface(Ci.nsIWebProgress).
-      removeProgressListener(EventManager);
-    removeEventListener('scroll', EventManager, true);
-    removeEventListener('resize', EventManager, true);
-    // XXX: Ideally this would be an a11y event. Bug #742280.
-    removeEventListener('DOMActivate', EventManager, true);
+    eventManager.stop();
   });
 
 sendAsyncMessage('AccessFu:Ready');
--- a/accessible/src/jsat/moz.build
+++ b/accessible/src/jsat/moz.build
@@ -1,8 +1,12 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MODULE = 'alerts'
 
+CPP_SOURCES += [
+    'nsAccessibilityFactory.cpp',
+]
+
--- a/accessible/src/mac/AccessibleWrap.h
+++ b/accessible/src/mac/AccessibleWrap.h
@@ -68,18 +68,16 @@ public: // construction, destruction
    * Returns this accessible's all children, adhering to "flat" accessibles by 
    * not returning their children.
    */
   void GetUnignoredChildren(nsTArray<Accessible*>* aChildrenArray);
   Accessible* GetUnignoredParent() const;
 
 protected:
 
-  virtual nsresult FirePlatformEvent(AccEvent* aEvent);
-
   /**
    * Return true if the parent doesn't have children to expose to AT.
    */
   bool AncestorIsFlat();
 
   /**
    * Get the native object. Create it if needed.
    */
--- a/accessible/src/mac/AccessibleWrap.mm
+++ b/accessible/src/mac/AccessibleWrap.mm
@@ -134,26 +134,16 @@ AccessibleWrap::Shutdown ()
 nsresult
 AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   nsresult rv = Accessible::HandleAccEvent(aEvent);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return FirePlatformEvent(aEvent);
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-nsresult
-AccessibleWrap::FirePlatformEvent(AccEvent* aEvent)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
   uint32_t eventType = aEvent->GetEventType();
 
   // ignore everything but focus-changed, value-changed, caret and selection
   // events for now.
   if (eventType != nsIAccessibleEvent::EVENT_FOCUS &&
       eventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE &&
       eventType != nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED &&
       eventType != nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED)
--- a/accessible/src/other/AccessibleWrap.h
+++ b/accessible/src/other/AccessibleWrap.h
@@ -16,20 +16,14 @@
 namespace mozilla {
 namespace a11y {
 
 class AccessibleWrap : public Accessible
 {
 public: // construction, destruction
   AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc);
   virtual ~AccessibleWrap();
-
-  protected:
-    virtual nsresult FirePlatformEvent(AccEvent* aEvent)
-    {
-      return NS_OK;
-    }
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/src/other/Makefile.in
+++ b/accessible/src/other/Makefile.in
@@ -8,22 +8,16 @@ srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME = accessibility_toolkit_s
 EXPORT_LIBRARY = ..
 LIBXUL_LIBRARY = 1
 
-
-CPPSRCS = \
-  AccessibleWrap.cpp \
-  Platform.cpp \
-  $(NULL)
-
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
   -I$(srcdir)/../base \
--- a/accessible/src/other/moz.build
+++ b/accessible/src/other/moz.build
@@ -6,8 +6,13 @@
 
 MODULE = 'accessibility'
 
 EXPORTS.mozilla.a11y += [
     'AccessibleWrap.h',
     'HyperTextAccessibleWrap.h',
 ]
 
+CPP_SOURCES += [
+    'AccessibleWrap.cpp',
+    'Platform.cpp',
+]
+
new file mode 100644
--- /dev/null
+++ b/accessible/src/shared.mozbuild
@@ -0,0 +1,12 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+a11y_log = 0
+if CONFIG['MOZ_DEBUG']:
+    a11y_log = 1
+
+if CONFIG['MOZ_UPDATE_CHANNEL'] not in ('aurora', 'beta', 'release', 'esr'):
+    a11y_log = 1
--- a/accessible/src/windows/ia2/Makefile.in
+++ b/accessible/src/windows/ia2/Makefile.in
@@ -8,31 +8,16 @@ srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME = accessibility_toolkit_ia2_s
 EXPORT_LIBRARY = 1
 LIBXUL_LIBRARY = 1
 
-
-CPPSRCS += \
-  ia2AccessibleAction.cpp \
-  ia2AccessibleComponent.cpp \
-  ia2AccessibleEditableText.cpp \
-  ia2AccessibleHyperlink.cpp \
-  ia2AccessibleHypertext.cpp \
-  ia2AccessibleImage.cpp \
-  ia2AccessibleRelation.cpp \
-  ia2AccessibleTable.cpp \
-  ia2AccessibleTableCell.cpp \
-  ia2AccessibleText.cpp \
-  ia2AccessibleValue.cpp \
-  $(NULL)
-
 # The midl generated code include Windows headers which defines min and max
 # macros which conflicts with std::min/max.  Suppress the macros:
 OS_CXXFLAGS += -DNOMINMAX
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/config.mk
--- a/accessible/src/windows/ia2/ia2AccessibleRelation.cpp
+++ b/accessible/src/windows/ia2/ia2AccessibleRelation.cpp
@@ -104,16 +104,19 @@ ia2AccessibleRelation::get_relationType(
       *aRelationType = ::SysAllocString(IA2_RELATION_LABELED_BY);
       break;
     case nsIAccessibleRelation::RELATION_MEMBER_OF:
       *aRelationType = ::SysAllocString(IA2_RELATION_MEMBER_OF);
       break;
     case nsIAccessibleRelation::RELATION_NODE_CHILD_OF:
       *aRelationType = ::SysAllocString(IA2_RELATION_NODE_CHILD_OF);
       break;
+    case nsIAccessibleRelation::RELATION_NODE_PARENT_OF:
+      *aRelationType = ::SysAllocString(IA2_RELATION_NODE_PARENT_OF);
+      break;
     case nsIAccessibleRelation::RELATION_PARENT_WINDOW_OF:
       *aRelationType = ::SysAllocString(IA2_RELATION_PARENT_WINDOW_OF);
       break;
     case nsIAccessibleRelation::RELATION_POPUP_FOR:
       *aRelationType = ::SysAllocString(IA2_RELATION_POPUP_FOR);
       break;
     case nsIAccessibleRelation::RELATION_SUBWINDOW_OF:
       *aRelationType = ::SysAllocString(IA2_RELATION_SUBWINDOW_OF);
--- a/accessible/src/windows/ia2/ia2AccessibleRelation.h
+++ b/accessible/src/windows/ia2/ia2AccessibleRelation.h
@@ -66,16 +66,17 @@ private:
  * Relations exposed to IAccessible2.
  */
 static const uint32_t sRelationTypesForIA2[] = {
   nsIAccessibleRelation::RELATION_LABELLED_BY,
   nsIAccessibleRelation::RELATION_LABEL_FOR,
   nsIAccessibleRelation::RELATION_DESCRIBED_BY,
   nsIAccessibleRelation::RELATION_DESCRIPTION_FOR,
   nsIAccessibleRelation::RELATION_NODE_CHILD_OF,
+  nsIAccessibleRelation::RELATION_NODE_PARENT_OF,
   nsIAccessibleRelation::RELATION_CONTROLLED_BY,
   nsIAccessibleRelation::RELATION_CONTROLLER_FOR,
   nsIAccessibleRelation::RELATION_FLOWS_TO,
   nsIAccessibleRelation::RELATION_FLOWS_FROM,
   nsIAccessibleRelation::RELATION_MEMBER_OF,
   nsIAccessibleRelation::RELATION_SUBWINDOW_OF,
   nsIAccessibleRelation::RELATION_EMBEDS,
   nsIAccessibleRelation::RELATION_EMBEDDED_BY,
--- a/accessible/src/windows/ia2/moz.build
+++ b/accessible/src/windows/ia2/moz.build
@@ -11,8 +11,22 @@ EXPORTS += [
     'ia2AccessibleComponent.h',
     'ia2AccessibleEditableText.h',
     'ia2AccessibleHyperlink.h',
     'ia2AccessibleHypertext.h',
     'ia2AccessibleText.h',
     'ia2AccessibleValue.h',
 ]
 
+CPP_SOURCES += [
+    'ia2AccessibleAction.cpp',
+    'ia2AccessibleComponent.cpp',
+    'ia2AccessibleEditableText.cpp',
+    'ia2AccessibleHyperlink.cpp',
+    'ia2AccessibleHypertext.cpp',
+    'ia2AccessibleImage.cpp',
+    'ia2AccessibleRelation.cpp',
+    'ia2AccessibleTable.cpp',
+    'ia2AccessibleTableCell.cpp',
+    'ia2AccessibleText.cpp',
+    'ia2AccessibleValue.cpp',
+]
+
--- a/accessible/src/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/src/windows/msaa/AccessibleWrap.cpp
@@ -1500,25 +1500,16 @@ AccessibleWrap::GetNativeInterface(void 
 // Accessible
 
 nsresult
 AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
 {
   nsresult rv = Accessible::HandleAccEvent(aEvent);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return FirePlatformEvent(aEvent);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// AccessibleWrap
-
-nsresult
-AccessibleWrap::FirePlatformEvent(AccEvent* aEvent)
-{
   // Don't fire native MSAA events or mess with the system caret
   // when running in metro mode. This confuses input focus tracking
   // in metro's UIA implementation.
   if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) {
     return NS_OK;
   }
 
   uint32_t eventType = aEvent->GetEventType();
@@ -1578,16 +1569,19 @@ AccessibleWrap::FirePlatformEvent(AccEve
       accessible->Role() == roles::COMBOBOX_OPTION) {
       ::NotifyWinEvent(EVENT_OBJECT_FOCUS, hWnd, OBJID_CLIENT, childID);
     }
   }
 
   return NS_OK;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// AccessibleWrap
+
 //------- Helper methods ---------
 
 int32_t
 AccessibleWrap::GetChildIDFor(Accessible* aAccessible)
 {
   // A child ID of the window is required, when we use NotifyWinEvent,
   // so that the 3rd party application can call back and get the IAccessible
   // the event occurred on.
--- a/accessible/src/windows/msaa/AccessibleWrap.h
+++ b/accessible/src/windows/msaa/AccessibleWrap.h
@@ -238,17 +238,16 @@ public: // construction, destruction
    */
   Accessible* GetXPAccessibleFor(const VARIANT& aVarChild);
 
   NS_IMETHOD GetNativeInterface(void **aOutAccessible);
 
   static IDispatch *NativeAccessible(nsIAccessible *aXPAccessible);
 
 protected:
-  virtual nsresult FirePlatformEvent(AccEvent* aEvent);
 
   /**
    * Creates ITypeInfo for LIBID_Accessibility if it's needed and returns it.
    */
   static ITypeInfo* GetTI(LCID lcid);
 
   static ITypeInfo* gTypeInfo;
 
--- a/accessible/src/windows/msaa/Makefile.in
+++ b/accessible/src/windows/msaa/Makefile.in
@@ -8,44 +8,16 @@ srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME = accessibility_toolkit_msaa_s
 EXPORT_LIBRARY = 1
 LIBXUL_LIBRARY = 1
 
-
-CPPSRCS = \
-  AccessibleWrap.cpp \
-  ApplicationAccessibleWrap.cpp \
-  ARIAGridAccessibleWrap.cpp \
-  DocAccessibleWrap.cpp \
-  HTMLTableAccessibleWrap.cpp \
-  HTMLWin32ObjectAccessible.cpp \
-  HyperTextAccessibleWrap.cpp \
-  ImageAccessibleWrap.cpp \
-  IUnknownImpl.cpp \
-  nsWinUtils.cpp \
-  Compatibility.cpp \
-  EnumVariant.cpp \
-  Platform.cpp \
-  ServiceProvider.cpp \
-  RootAccessibleWrap.cpp \
-  TextLeafAccessibleWrap.cpp \
-  $(NULL)
-
-ifdef MOZ_XUL
-CPPSRCS += \
-  XULListboxAccessibleWrap.cpp \
-  XULMenuAccessibleWrap.cpp \
-  XULTreeGridAccessibleWrap.cpp \
-  $(NULL)
-endif
-
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
--- a/accessible/src/windows/msaa/moz.build
+++ b/accessible/src/windows/msaa/moz.build
@@ -11,8 +11,33 @@ EXPORTS += [
 ]
 
 EXPORTS.mozilla.a11y += [
     'AccessibleWrap.h',
     'Compatibility.h',
     'HyperTextAccessibleWrap.h',
 ]
 
+CPP_SOURCES += [
+    'AccessibleWrap.cpp',
+    'ApplicationAccessibleWrap.cpp',
+    'ARIAGridAccessibleWrap.cpp',
+    'DocAccessibleWrap.cpp',
+    'HTMLTableAccessibleWrap.cpp',
+    'HTMLWin32ObjectAccessible.cpp',
+    'HyperTextAccessibleWrap.cpp',
+    'ImageAccessibleWrap.cpp',
+    'IUnknownImpl.cpp',
+    'nsWinUtils.cpp',
+    'Compatibility.cpp',
+    'EnumVariant.cpp',
+    'Platform.cpp',
+    'ServiceProvider.cpp',
+    'RootAccessibleWrap.cpp',
+    'TextLeafAccessibleWrap.cpp',
+]
+
+if CONFIG['MOZ_XUL']:
+    CPP_SOURCES += [
+        'XULListboxAccessibleWrap.cpp',
+        'XULMenuAccessibleWrap.cpp',
+        'XULTreeGridAccessibleWrap.cpp',
+    ]
--- a/accessible/src/windows/sdn/Makefile.in
+++ b/accessible/src/windows/sdn/Makefile.in
@@ -11,21 +11,16 @@ include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME = accessibility_toolkit_sdn_s
 EXPORT_LIBRARY = 1
 LIBXUL_LIBRARY = 1
 # The midl generated code include Windows headers which defines min and max
 # macros which conflicts with std::min/max.  Suppress the macros:
 OS_CXXFLAGS += -DNOMINMAX
 
-CPPSRCS += \
-  sdnAccessible.cpp \
-  sdnTextAccessible.cpp \
-  $(NULL)
-
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
--- a/accessible/src/windows/sdn/moz.build
+++ b/accessible/src/windows/sdn/moz.build
@@ -1,8 +1,13 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MODULE = 'accessibility'
 
+CPP_SOURCES += [
+    'sdnAccessible.cpp',
+    'sdnTextAccessible.cpp',
+]
+
--- a/accessible/src/windows/uia/Makefile.in
+++ b/accessible/src/windows/uia/Makefile.in
@@ -11,21 +11,16 @@ include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME = accessibility_toolkit_uia_s
 EXPORT_LIBRARY = ..
 LIBXUL_LIBRARY = 1
 # The midl generated code include Windows headers which defines min and max
 # macros which conflicts with std::min/max.  Suppress the macros:
 OS_CXXFLAGS += -DNOMINMAX
 
-
-CPPSRCS += \
-  uiaRawElmProvider.cpp \
-  $(NULL)
-
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
--- a/accessible/src/windows/uia/moz.build
+++ b/accessible/src/windows/uia/moz.build
@@ -1,8 +1,12 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MODULE = 'accessibility'
 
+CPP_SOURCES += [
+    'uiaRawElmProvider.cpp',
+]
+
--- a/accessible/src/xpcom/Makefile.in
+++ b/accessible/src/xpcom/Makefile.in
@@ -8,23 +8,16 @@ topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME = accessibility_xpcom_s
 LIBXUL_LIBRARY = 1
 
-CPPSRCS = \
-  xpcAccEvents.cpp \
-  nsAccessibleRelation.cpp \
-  xpcAccessibleTable.cpp \
-  xpcAccessibleTableCell.cpp \
-  $(NULL)
-
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 EXTRA_MDDEPEND_FILES = xpcAccEvents.pp
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES = \
--- a/accessible/src/xpcom/moz.build
+++ b/accessible/src/xpcom/moz.build
@@ -5,8 +5,15 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MODULE = 'accessibility'
 
 EXPORTS += [
     'xpcAccEvents.h',
 ]
 
+CPP_SOURCES += [
+    'nsAccessibleRelation.cpp',
+    'xpcAccEvents.cpp',
+    'xpcAccessibleTable.cpp',
+    'xpcAccessibleTableCell.cpp',
+]
+
--- a/accessible/src/xul/Makefile.in
+++ b/accessible/src/xul/Makefile.in
@@ -8,33 +8,16 @@ topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME = accessibility_xul_s
 LIBXUL_LIBRARY = 1
 
-
-
-CPPSRCS = \
-  XULAlertAccessible.cpp \
-  XULColorPickerAccessible.cpp \
-  XULComboboxAccessible.cpp \
-  XULElementAccessibles.cpp \
-  XULFormControlAccessible.cpp \
-  XULListboxAccessible.cpp \
-  XULMenuAccessible.cpp \
-  XULSelectControlAccessible.cpp \
-  XULSliderAccessible.cpp \
-  XULTabAccessible.cpp \
-  XULTreeAccessible.cpp \
-  XULTreeGridAccessible.cpp \
-  $(NULL)
-
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES = \
   -I$(srcdir) \
   -I$(srcdir)/../base \
--- a/accessible/src/xul/moz.build
+++ b/accessible/src/xul/moz.build
@@ -1,8 +1,23 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MODULE = 'accessibility'
 
+CPP_SOURCES += [
+    'XULAlertAccessible.cpp',
+    'XULColorPickerAccessible.cpp',
+    'XULComboboxAccessible.cpp',
+    'XULElementAccessibles.cpp',
+    'XULFormControlAccessible.cpp',
+    'XULListboxAccessible.cpp',
+    'XULMenuAccessible.cpp',
+    'XULSelectControlAccessible.cpp',
+    'XULSliderAccessible.cpp',
+    'XULTabAccessible.cpp',
+    'XULTreeAccessible.cpp',
+    'XULTreeGridAccessible.cpp',
+]
+
--- a/accessible/tests/mochitest/attributes/test_obj_group.html
+++ b/accessible/tests/mochitest/attributes/test_obj_group.html
@@ -63,26 +63,35 @@
 
       //////////////////////////////////////////////////////////////////////////
       // ARIA list
       testGroupAttrs("li7", 1, 3);
       testGroupAttrs("li8", 2, 3);
       testGroupAttrs("li9", 3, 3);
 
       //////////////////////////////////////////////////////////////////////////
-      // ARIA list (nested lists)
+      // ARIA list (nested lists: list -> listitem -> list -> listitem)
       testGroupAttrs("li10", 1, 3, 1);
       testGroupAttrs("li11", 2, 3, 1);
       testGroupAttrs("li12", 3, 3, 1);
 
       testGroupAttrs("n_li10", 1, 3, 2);
       testGroupAttrs("n_li11", 2, 3, 2);
       testGroupAttrs("n_li12", 3, 3, 2);
 
       //////////////////////////////////////////////////////////////////////////
+      // ARIA list (nested lists: list -> listitem -> group -> listitem)
+      testGroupAttrs("lgt_li1", 1, 2, 1);
+      testGroupAttrs("lgt_li1_nli1", 1, 2, 2);
+      testGroupAttrs("lgt_li1_nli2", 2, 2, 2);
+      testGroupAttrs("lgt_li2", 2, 2, 1);
+      testGroupAttrs("lgt_li2_nli1", 1, 2, 2);
+      testGroupAttrs("lgt_li2_nli2", 2, 2, 2);
+
+      //////////////////////////////////////////////////////////////////////////
       // ARIA menu (menuitem, separator, menuitemradio and menuitemcheckbox)
       testGroupAttrs("menu_item1", 1, 2);
       testGroupAttrs("menu_item2", 2, 2);
       testGroupAttrs("menu_item1.1", 1, 2);
       testGroupAttrs("menu_item1.2", 2, 2);
       testGroupAttrs("menu_item1.3", 1, 3);
       testGroupAttrs("menu_item1.4", 2, 3);
       testGroupAttrs("menu_item1.5", 3, 3);
@@ -106,16 +115,34 @@
       testGroupAttrs("ti3", 2, 2, 2);
       testGroupAttrs("ti4", 2, 3, 1);
       testGroupAttrs("ti5", 1, 3, 2);
       testGroupAttrs("ti6", 2, 3, 2);
       testGroupAttrs("ti7", 3, 3, 2);
       testGroupAttrs("ti8", 3, 3, 1);
 
       //////////////////////////////////////////////////////////////////////////
+      // ARIA tree (tree -> treeitem -> group -> treeitem)
+      testGroupAttrs("tree2_ti1", 1, 2, 1);
+      testGroupAttrs("tree2_ti1a", 1, 2, 2);
+      testGroupAttrs("tree2_ti1b", 2, 2, 2);
+      testGroupAttrs("tree2_ti2", 2, 2, 1);
+      testGroupAttrs("tree2_ti2a", 1, 2, 2);
+      testGroupAttrs("tree2_ti2b", 2, 2, 2);
+
+      //////////////////////////////////////////////////////////////////////////
+      // ARIA tree (tree -> treeitem, group -> treeitem)
+      testGroupAttrs("tree3_ti1", 1, 2, 1);
+      testGroupAttrs("tree3_ti1a", 1, 2, 2);
+      testGroupAttrs("tree3_ti1b", 2, 2, 2);
+      testGroupAttrs("tree3_ti2", 2, 2, 1);
+      testGroupAttrs("tree3_ti2a", 1, 2, 2);
+      testGroupAttrs("tree3_ti2b", 2, 2, 2);
+
+      //////////////////////////////////////////////////////////////////////////
       // ARIA grid
       testGroupAttrs("grid_row1", 1, 2);
       testGroupAttrs("grid_cell1", 1, 2);
       testGroupAttrs("grid_cell2", 2, 2);
 
       testGroupAttrs("grid_row2", 2, 2);
       testGroupAttrs("grid_cell3", 1, 2);
       testGroupAttrs("grid_cell4", 2, 2);
@@ -159,16 +186,21 @@
 </head>
 <body>
 
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=468418"
      title="Expose level for nested lists in HTML">
     Mozilla Bug 468418
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=864224"
+     title="Support nested ARIA listitems structured by role='group'">
+    Bug 864224
+  </a>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <select size="4">
     <option id="opt1">option1</option>
@@ -223,16 +255,31 @@
       <span role="list">
         <span role="listitem" id="n_li10">Oranges</span>
         <span role="listitem" id="n_li11">Apples</span>
         <span role="listitem" id="n_li12">Bananas</span>
       </span>
     </span>
   </span>
 
+  <div role="list">
+    <div role="listitem" id="lgt_li1">Item 1
+      <div role="group">
+        <div role="listitem" id="lgt_li1_nli1">Item 1A</div>
+        <div role="listitem" id="lgt_li1_nli2">Item 1B</div>
+      </div>
+    </div>
+    <div role="listitem" id="lgt_li2">Item 2
+      <div role="group">
+        <div role="listitem" id="lgt_li2_nli1">Item 2A</div>
+        <div role="listitem" id="lgt_li2_nli2">Item 2B</div>
+      </div>
+    </div>
+  </div>
+
   <ul role="menubar">
     <li role="menuitem" aria-haspopup="true" id="menu_item1">File
       <ul role="menu">
         <li role="menuitem" id="menu_item1.1">New</li>
         <li role="menuitem" id="menu_item1.2">Open…</li>
         <li role="separator">-----</li>
         <li role="menuitem" id="menu_item1.3">Item</li>
         <li role="menuitemradio" id="menu_item1.4">Radio</li>
@@ -278,16 +325,44 @@
     <tr role="presentation">
       <td role="treeitem" aria-level="2" id="ti7">Audi</td>
     </tr>
     <tr role="presentation">
       <td role="treeitem" aria-level="1" id="ti8">people</td>
     </tr>
   </table>
 
+  <ul role="tree">
+    <li role="treeitem" id="tree2_ti1">Item 1
+      <ul role="group">
+        <li role="treeitem" id="tree2_ti1a">Item 1A</li>
+        <li role="treeitem" id="tree2_ti1b">Item 1B</li>
+      </ul>
+    </li>
+    <li role="treeitem" id="tree2_ti2">Item 2
+      <ul role="group">
+        <li role="treeitem" id="tree2_ti2a">Item 2A</li>
+        <li role="treeitem" id="tree2_ti2b">Item 2B</li>
+      </ul>
+    </li>
+  </div>
+
+  <div role="tree">
+    <div role="treeitem" id="tree3_ti1">Item 1</div>
+    <div role="group">
+      <li role="treeitem" id="tree3_ti1a">Item 1A</li>
+      <li role="treeitem" id="tree3_ti1b">Item 1B</li>
+    </div>
+    <div role="treeitem" id="tree3_ti2">Item 2</div>
+    <div role="group">
+      <div role="treeitem" id="tree3_ti2a">Item 2A</div>
+      <div role="treeitem" id="tree3_ti2b">Item 2B</div>
+    </div>
+  </div>
+
   <table role="grid">
     <tr role="row" id="grid_row1">
       <td role="gridcell" id="grid_cell1">cell1</td>
       <td role="gridcell" id="grid_cell2">cell2</td>
     </tr>
     <tr role="row" id="grid_row2">
       <td role="gridcell" id="grid_cell3">cell3</td>
       <td role="gridcell" id="grid_cell4">cell4</td>
--- a/accessible/tests/mochitest/jsat/test_alive.html
+++ b/accessible/tests/mochitest/jsat/test_alive.html
@@ -33,31 +33,33 @@
         }
       };
     }
 
     function testEventManagerStartStop() {
       // Firs listen for initial 'EventManager.start' and disable AccessFu.
       var initialStartListener = makeEventManagerListener("EventManager.start",
         function () {
-          ok(EventManager._started, "EventManager was started.");
+          ok(true, "EventManager was started.");
           Services.console.registerListener(stopListener);
           AccessFu._disable();
         });
       // Listen for 'EventManager.stop' and enable AccessFu again.
       var stopListener = makeEventManagerListener("EventManager.stop",
         function () {
-          isnot(EventManager._started, true, "EventManager was stopped.");
+          ok(true, "EventManager was stopped.");
+          isnot(AccessFu._enabled, true, "AccessFu was disabled.");
           Services.console.registerListener(finalStartListener);
           AccessFu._enable();
         });
       // Make sure EventManager is started again.
       var finalStartListener = makeEventManagerListener("EventManager.start",
         function () {
-          ok(EventManager._started, "EventManager was started again.");
+          ok(true, "EventManager was started again.");
+          ok(AccessFu._enabled, "AccessFu was enabled again.");
           AccessFuTest.finish();
         });
 
       Services.console.registerListener(initialStartListener);
     }
 
     function doTest() {
       AccessFuTest.addFunc(confirmAccessFuStart);
--- a/accessible/tests/mochitest/jsat/test_utterance_order.html
+++ b/accessible/tests/mochitest/jsat/test_utterance_order.html
@@ -53,19 +53,19 @@ https://bugzilla.mozilla.org/show_bug.cg
         // Note: each aAccOrElmOrID entry maps to a unique object utterance
         // generator function within the UtteranceGenerator.
         var tests = [{
           aAccOrElmOrID: "anchor",
           expected: [["link", "title"], ["title", "link"]]
         }, {
           aAccOrElmOrID: "textarea",
           expected: [[
-            "text area", "Test Text Area", "This is the text area text.", "\n"
+            "text area", "Test Text Area", "This is the text area text."
           ], [
-            "This is the text area text.", "\n", "Test Text Area", "text area"
+            "This is the text area text.", "Test Text Area", "text area"
           ]]
         }, {
           aAccOrElmOrID: "heading",
           expected: [
             ["heading level 1", "Test heading"],
             ["Test heading", "heading level 1"]
           ]
         }, {
@@ -176,9 +176,9 @@ https://bugzilla.mozilla.org/show_bug.cg
               <li><a href="#">Peaches</a></li>
               <li><a href="#">Plums</a></li>
             </ul>
           </td>
         </tr>
       </table>
     </div>
   </body>
-</html>
\ No newline at end of file
+</html>
--- a/accessible/tests/mochitest/pivot.js
+++ b/accessible/tests/mochitest/pivot.js
@@ -1,19 +1,21 @@
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constants
 
 const PREFILTER_INVISIBLE = nsIAccessibleTraversalRule.PREFILTER_INVISIBLE;
+const PREFILTER_ARIA_HIDDEN = nsIAccessibleTraversalRule.PREFILTER_ARIA_HIDDEN;
 const FILTER_MATCH = nsIAccessibleTraversalRule.FILTER_MATCH;
 const FILTER_IGNORE = nsIAccessibleTraversalRule.FILTER_IGNORE;
 const FILTER_IGNORE_SUBTREE = nsIAccessibleTraversalRule.FILTER_IGNORE_SUBTREE;
 
 const NS_ERROR_NOT_IN_TREE = 0x80780026;
+const NS_ERROR_INVALID_ARG = 0x80070057;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Traversal rules
 
 /**
  * Rule object to traverse all focusable nodes and text nodes.
  */
 var HeadersTraversalRule =
@@ -40,17 +42,17 @@ var HeadersTraversalRule =
 var ObjectTraversalRule =
 {
   getMatchRoles: function(aRules)
   {
     aRules.value = [];
     return 0;
   },
 
-  preFilter: PREFILTER_INVISIBLE,
+  preFilter: PREFILTER_INVISIBLE | PREFILTER_ARIA_HIDDEN,
 
   match: function(aAccessible)
   {
     var rv = FILTER_IGNORE;
     var role = aAccessible.role;
     if (hasState(aAccessible, STATE_FOCUSABLE) &&
         (role != ROLE_DOCUMENT && role != ROLE_INTERNAL_FRAME))
       rv = FILTER_IGNORE_SUBTREE | FILTER_MATCH;
@@ -256,29 +258,69 @@ function moveVCCoordInvoker(aDocAcc, aX,
     this.eventSeq = [];
     this.unexpectedEventSeq = [
       new invokerChecker(EVENT_VIRTUALCURSOR_CHANGED, aDocAcc)
     ];
   }
 }
 
 /**
+ * Change the pivot modalRoot
+ *
+ * @param aDocAcc         [in] document that manages the virtual cursor
+ * @param aModalRootAcc   [in] accessible of the modal root, or null
+ * @param aExpectedResult [in] error result expected. 0 if expecting success
+ */
+function setModalRootInvoker(aDocAcc, aModalRootAcc, aExpectedResult)
+{
+  this.invoke = function setModalRootInvoker_invoke()
+  {
+    var errorResult = 0;
+    try {
+      aDocAcc.virtualCursor.modalRoot = aModalRootAcc;
+    } catch (x) {
+      SimpleTest.ok(
+        x.result, "Unexpected exception when changing modal root: " + x);
+      errorResult = x.result;
+    }
+
+    SimpleTest.is(errorResult, aExpectedResult,
+                  "Did not get expected result when changing modalRoot");
+  };
+
+  this.getID = function setModalRootInvoker_getID()
+  {
+    return "Set modalRoot to " + prettyName(aModalRootAcc);
+  };
+
+  this.eventSeq = [];
+  this.unexpectedEventSeq = [
+    new invokerChecker(EVENT_VIRTUALCURSOR_CHANGED, aDocAcc)
+  ];
+}
+
+/**
  * Add invokers to a queue to test a rule and an expected sequence of element ids
  * or accessible names for that rule in the given document.
  *
- * @param aQueue    [in] event queue in which to push invoker sequence.
- * @param aDocAcc   [in] the managing document of the virtual cursor we are testing
- * @param aRule     [in] the traversal rule to use in the invokers
- * @param aSequence [in] a sequence of accessible names or element ids to expect with
- *                  the given rule in the given document
+ * @param aQueue     [in] event queue in which to push invoker sequence.
+ * @param aDocAcc    [in] the managing document of the virtual cursor we are
+ *                   testing
+ * @param aRule      [in] the traversal rule to use in the invokers
+ * @param aModalRoot [in] a modal root to use in this traversal sequence
+ * @param aSequence  [in] a sequence of accessible names or element ids to expect
+ *                   with the given rule in the given document
  */
-function queueTraversalSequence(aQueue, aDocAcc, aRule, aSequence)
+function queueTraversalSequence(aQueue, aDocAcc, aRule, aModalRoot, aSequence)
 {
   aDocAcc.virtualCursor.position = null;
 
+  // Add modal root (if any)
+  aQueue.push(new setModalRootInvoker(aDocAcc, aModalRoot, 0));
+
   for (var i = 0; i < aSequence.length; i++) {
     var invoker =
       new setVCPosInvoker(aDocAcc, "moveNext", aRule, aSequence[i]);
     aQueue.push(invoker);
   }
 
   // No further more matches for given rule, expect no virtual cursor changes.
   aQueue.push(new setVCPosInvoker(aDocAcc, "moveNext", aRule, false));
@@ -297,16 +339,19 @@ function queueTraversalSequence(aQueue, 
 
   // No further more matches for given rule, expect no virtual cursor changes.
   aQueue.push(new setVCPosInvoker(aDocAcc, "moveNext", aRule, false));
 
   aQueue.push(new setVCPosInvoker(aDocAcc, "moveFirst", aRule, aSequence[0]));
 
   // No previous more matches for given rule, expect no virtual cursor changes.
   aQueue.push(new setVCPosInvoker(aDocAcc, "movePrevious", aRule, false));
+
+  // Remove modal root (if any).
+  aQueue.push(new setModalRootInvoker(aDocAcc, null, 0));
 }
 
 /**
  * A checker for removing an accessible while the virtual cursor is on it.
  */
 function removeVCPositionChecker(aDocAcc, aHiddenParentAcc)
 {
   this.__proto__ = new invokerChecker(EVENT_REORDER, aHiddenParentAcc);
--- a/accessible/tests/mochitest/pivot/doc_virtualcursor.html
+++ b/accessible/tests/mochitest/pivot/doc_virtualcursor.html
@@ -1,29 +1,33 @@
 <!DOCTYPE html>
 <html>
 <head>
   <title>Pivot test document</title>
   <meta charset="utf-8" />
 </head>
 <body>
   <h1 id="heading-1-1">Main Title</h1>
-  <h2 id="heading-2-1">First Section Title</h2>
+  <h2 id="heading-2-1" aria-hidden="true">First Section Title</h2>
   <p id="paragraph-1">
     Lorem ipsum <strong>dolor</strong> sit amet. Integer vitae urna
     leo, id <a href="#">semper</a> nulla.
   </p>
-  <h2 id="heading-2-2">Second Section Title</h2>
-  <p id="paragraph-2">
+  <h2 id="heading-2-2" aria-hidden="undefined">Second Section Title</h2>
+  <p id="paragraph-2" aria-hidden="">
     Sed accumsan luctus lacus, vitae mollis arcu tristique vulputate.</p>
+  <p id="paragraph-3" aria-hidden="true">
+    Maybe it was the other <i>George Michael</i>.
+    You know, the <a href="#">singer-songwriter</a>.
+  </p>
   <iframe
      src="data:text/html,<html><body>An <i>embedded</i> document.</body></html>">
   </iframe>
   <div id="hide-me">Hide me</div>
-  <p id="links">
+  <p id="links" aria-hidden="false">
     <a href="http://mozilla.org" title="Link 1 title">Link 1</a>
     <a href="http://mozilla.org" title="Link 2 title">Link 2</a>
     <a href="http://mozilla.org" title="Link 3 title">Link 3</a>
   </p>
   <ul>
     <li>Hello<span> </span></li>
     <li>World</li>
   </ul>
--- a/accessible/tests/mochitest/pivot/test_virtualcursor.html
+++ b/accessible/tests/mochitest/pivot/test_virtualcursor.html
@@ -21,51 +21,41 @@
   <script type="application/javascript" src="../layout.js"></script>
 
   <script type="application/javascript">
     var gBrowserWnd = null;
     var gQueue = null;
 
     function doTest()
     {
-      var rootAcc = getRootAccessible(browserWindow().document);
-      try {
-        rootAcc.QueryInterface(nsIAccessibleCursorable);
-      } catch (e) {
-        ok(false, "Root accessible does not support nsIAccessibleCursorable");
-      }
-      var doc = currentTabDocument();
-      var docAcc = getAccessible(doc, [nsIAccessibleDocument,
-                                       nsIAccessibleCursorable]);
+      var rootAcc = getAccessible(browserDocument(), [nsIAccessibleDocument]);
+      ok(rootAcc.virtualCursor,
+         "root document does not have virtualCursor");
 
-      // Test that embedded documents don't have their own virtual cursor.
+      var doc = currentTabDocument();
+      var docAcc = getAccessible(doc, [nsIAccessibleDocument]);
+
+      // Test that embedded documents have their own virtual cursor.
       is(docAcc.childDocumentCount, 1, "Expecting one child document");
-      var childDoc = docAcc.getChildDocumentAt(0);
-      var supportsVC = true;
-      try {
-        childDoc.QueryInterface(nsIAccessibleCursorable);
-      } catch (e) {
-        supportsVC = false;
-      }
-
-      ok(!supportsVC, "no nsIAccessibleCursorable support in child document");
+      ok(docAcc.getChildDocumentAt(0).virtualCursor,
+         "child document does not have virtualCursor");
 
       gQueue = new eventQueue();
 
       gQueue.onFinish = function onFinish()
       {
         closeBrowserWindow();
       }
 
-      queueTraversalSequence(gQueue, docAcc, HeadersTraversalRule,
+      queueTraversalSequence(gQueue, docAcc, HeadersTraversalRule, null,
                              ['heading-1-1', 'heading-2-1', 'heading-2-2']);
 
       queueTraversalSequence(
-        gQueue, docAcc, ObjectTraversalRule,
-        ['Main Title', 'First Section Title', 'Lorem ipsum ',
+        gQueue, docAcc, ObjectTraversalRule, null,
+        ['Main Title', 'Lorem ipsum ',
          'dolor', ' sit amet. Integer vitae urna leo, id ',
          'semper', ' nulla. ', 'Second Section Title',
          'Sed accumsan luctus lacus, vitae mollis arcu tristique vulputate.',
          'An ', 'embedded', ' document.', 'Hide me', 'Link 1', 'Link 2',
          'Link 3', 'Hello', 'World']);
 
       // Just a random smoke test to see if our setTextRange works.
       gQueue.push(
@@ -91,16 +81,25 @@
       // Attempting a coordinate outside any header, should not move.
       gQueue.push(new moveVCCoordInvoker(docAcc, x - 1, y - 1, true,
                                          HeadersTraversalRule, false));
 
       // Attempting a coordinate outside any header, should move to null
       gQueue.push(new moveVCCoordInvoker(docAcc, x - 1, y - 1, false,
                                          HeadersTraversalRule, null));
 
+      queueTraversalSequence(
+        gQueue, docAcc, ObjectTraversalRule,
+        getAccessible(doc.getElementById('paragraph-1')),
+        ['Lorem ipsum ', 'dolor', ' sit amet. Integer vitae urna leo, id ',
+         'semper', ' nulla. ']);
+
+      gQueue.push(new setModalRootInvoker(docAcc, docAcc.parent,
+                                          NS_ERROR_INVALID_ARG));
+
       gQueue.invoke();
     }
 
     SimpleTest.waitForExplicitFinish();
     addLoadEvent(function () {
       /* We open a new browser because we need to test with a top-level content
          document. */
       openBrowserWindow(
--- a/accessible/tests/mochitest/relations/test_general.html
+++ b/accessible/tests/mochitest/relations/test_general.html
@@ -68,43 +68,60 @@
       testRelation("treeitem2", RELATION_NODE_CHILD_OF, "tree");
 
       // 'node child of' relation for outlineitem role
       testRelation("treeitem3", RELATION_NODE_CHILD_OF, "tree");
       testRelation("treeitem4", RELATION_NODE_CHILD_OF, "tree");
       testRelation("treeitem5", RELATION_NODE_CHILD_OF, "treeitem4");
       testRelation("treeitem6", RELATION_NODE_CHILD_OF, "tree");
       testRelation("treeitem7", RELATION_NODE_CHILD_OF, "treeitem6");
+      testRelation("tree2_ti1", RELATION_NODE_CHILD_OF, "tree2");
+      testRelation("tree2_ti1a", RELATION_NODE_CHILD_OF, "tree2_ti1");
+      testRelation("tree2_ti1b", RELATION_NODE_CHILD_OF, "tree2_ti1");
 
       // 'node child of' relation for row role of treegrid
       testRelation("treegridrow1", RELATION_NODE_CHILD_OF, "treegrid");
       testRelation("treegridrow2", RELATION_NODE_CHILD_OF, "treegrid");
       testRelation("treegridrow3", RELATION_NODE_CHILD_OF, "treegridrow2");
 
+      // 'node child of' relation for lists organized by groups
+      testRelation("listitem1", RELATION_NODE_CHILD_OF, "list");
+      testRelation("listitem1.1", RELATION_NODE_CHILD_OF, "listitem1");
+      testRelation("listitem1.2", RELATION_NODE_CHILD_OF, "listitem1");
+
       // 'node child of' relation for the document having window, returns
       // direct accessible parent (fixed in bug 419770).
       var iframeElmObj = {};
       var iframeAcc = getAccessible("iframe", null, iframeElmObj);
       var iframeDoc = iframeElmObj.value.contentDocument;
       var iframeDocAcc = getAccessible(iframeDoc);
       testRelation(iframeDocAcc, RELATION_NODE_CHILD_OF, iframeAcc);
 
       // 'node parent of' relation on ARIA tree and treegrid.
       testRelation("tree", RELATION_NODE_PARENT_OF,
                     ["treeitem1", "treeitem2", // aria-owns
                      "treeitem3", "treeitem4", "treeitem6"]); // children
       testRelation("treeitem4", RELATION_NODE_PARENT_OF,
                    "treeitem5"); // aria-level
       testRelation("treeitem6", RELATION_NODE_PARENT_OF,
                    "treeitem7"); // // group role
+      testRelation("tree2", RELATION_NODE_PARENT_OF, "tree2_ti1"); // group role
+      testRelation("tree2_ti1", RELATION_NODE_PARENT_OF,
+                   ["tree2_ti1a", "tree2_ti1b"]); // group role
 
       testRelation("treegridrow2", RELATION_NODE_PARENT_OF, "treegridrow3");
       testRelation("treegrid", RELATION_NODE_PARENT_OF,
                    ["treegridrow1", "treegridrow2"]);
 
+      // 'node parent of' relation on ARIA list structured by groups
+      testRelation("list", RELATION_NODE_PARENT_OF,
+                   "listitem1");
+      testRelation("listitem1", RELATION_NODE_PARENT_OF,
+                   [ "listitem1.1", "listitem1.2" ]);
+
       // aria-controls
       getAccessible("tab");
       todo(false,
            "Getting an accessible tab, otherwise relations for tabpanel aren't cached. Bug 606924 will fix that.");
       testRelation("tabpanel", RELATION_CONTROLLED_BY, "tab");
       testRelation("tab", RELATION_CONTROLLER_FOR, "tabpanel");
 
       // aria-controls, multiple relations
@@ -173,16 +190,21 @@
      title="Ignore implicit label association when it's associated explicitly">
     Bug 682790
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=687393"
      title="HTML select options gets relation from containing label">
     Bug 687393
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=864224"
+     title="Support nested ARIA listitems structured by role='group'">
+    Bug 864224
+  </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <label id="label1_1" for="control1_1">label</label>
   <input id="control1_1">
 
@@ -248,28 +270,46 @@
     <div role="treeitem" id="treeitem4" aria-level="1">Green</div>
     <div role="treeitem" id="treeitem5" aria-level="2">Light green</div>
     <div role="treeitem" id="treeitem6" aria-level="1">Green2</div>
     <div role="group">
       <div role="treeitem" id="treeitem7">Super light green</div>
     </div>
   </div>
 
+  <ul role="tree" id="tree2">
+    <li role="treeitem" id="tree2_ti1">Item 1
+      <ul role="group">
+        <li role="treeitem" id="tree2_ti1a">Item 1A</li>
+        <li role="treeitem" id="tree2_ti1b">Item 1B</li>
+      </ul>
+    </li>
+  </ul>
+
   <div role="treegrid" id="treegrid">
     <div role="row" id="treegridrow1">
       <span role="gridcell">cell1</span><span role="gridcell">cell2</span>
     </div>
     <div role="row" id="treegridrow2" aria-level="1">
       <span role="gridcell">cell3</span><span role="gridcell">cell4</span>
     </div>
     <div role="row" id="treegridrow3" aria-level="2">
       <span role="gridcell">cell5</span><span role="gridcell">cell6</span>
     </div>
   </div>
 
+  <div role="list" id="list">
+    <div role="listitem" id="listitem1">Item 1
+      <div role="group">
+        <div role="listitem" id="listitem1.1">Item 1A</div>
+        <div role="listitem" id="listitem1.2">Item 1B</div>
+      </div>
+    </div>
+  </div>
+
   <iframe id="iframe"></iframe>
 
   <div id="tablist" role="tablist">
     <div id="tab" role="tab" aria-controls="tabpanel">tab</div>
   </div>
   <div id="tabpanel" role="tabpanel">tabpanel</div>
 
   <div id="lr1" aria-live="assertive">1</div>
--- a/accessible/tests/mochitest/text.js
+++ b/accessible/tests/mochitest/text.js
@@ -6,55 +6,61 @@ const BOUNDARY_WORD_START = nsIAccessibl
 const BOUNDARY_WORD_END = nsIAccessibleText.BOUNDARY_WORD_END;
 const BOUNDARY_LINE_START = nsIAccessibleText.BOUNDARY_LINE_START;
 const BOUNDARY_LINE_END = nsIAccessibleText.BOUNDARY_LINE_END;
 const BOUNDARY_ATTRIBUTE_RANGE = nsIAccessibleText.BOUNDARY_ATTRIBUTE_RANGE;
 
 const kTextEndOffset = nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT;
 const kCaretOffset = nsIAccessibleText.TEXT_OFFSET_CARET;
 
-const kTodo = 1;
-const kOk = 2;
+const kTodo = 1; // a test is expected to fail
+const kOk = 2; // a test doesn't fail
 
 /**
  * Test characterCount for the given array of accessibles.
  *
- * @param aCount  [in] the expected character count
- * @param aIDs    [in] array of accessible identifiers to test
+ * @param aCount    [in] the expected character count
+ * @param aIDs      [in] array of accessible identifiers to test
+ * @param aTodoFlag [in, optional] either kOk or kTodo
  */
-function testCharacterCount(aIDs, aCount)
+function testCharacterCount(aIDs, aCount, aTodoFlag)
 {
-  for (var i = 0; i < aIDs.length; i++) {
-    var textacc = getAccessible(aIDs[i], [nsIAccessibleText]);
-    is(textacc.characterCount, aCount,
-       "Wrong character count for " + prettyName(aIDs[i]));
+  var ids = (aIDs instanceof Array) ? aIDs : [ aIDs ];
+  var isFunc = (aTodoFlag == kTodo) ? todo_is : is;
+  for (var i = 0; i < ids.length; i++) {
+    var textacc = getAccessible(ids[i], [nsIAccessibleText]);
+    isFunc(textacc.characterCount, aCount,
+           "Wrong character count for " + prettyName(ids[i]));
   }
 }
 
 /**
- * Test text between two given offsets
+ * Test text between two given offsets.
  *
  * @param aIDs          [in] an array of accessible IDs to test
  * @param aStartOffset  [in] the start offset within the text to test
  * @param aEndOffset    [in] the end offset up to which the text is tested
  * @param aText         [in] the expected result from the test
+ * @param aTodoFlag     [in, optional] either kOk or kTodo
  */
-function testText(aIDs, aStartOffset, aEndOffset, aText)
+function testText(aIDs, aStartOffset, aEndOffset, aText, aTodoFlag)
 {
-  for (var i = 0; i < aIDs.length; i++)
-  {
-    var acc = getAccessible(aIDs[i], nsIAccessibleText);
+  var ids = (aIDs instanceof Array) ? aIDs : [ aIDs ];
+  var isFunc = (aTodoFlag == kTodo) ? todo_is : is;
+  for (var i = 0; i < ids.length; i++) {
+    var acc = getAccessible(ids[i], nsIAccessibleText);
     try {
-      is(acc.getText(aStartOffset, aEndOffset), aText,
-         "getText: wrong text between start and end offsets '" + aStartOffset +
-         "', '" + aEndOffset + " for '" + prettyName(aIDs[i]) + "'");
+      isFunc(acc.getText(aStartOffset, aEndOffset), aText,
+             "getText: wrong text between start and end offsets '" +
+             aStartOffset + "', '" + aEndOffset + " for '" +
+             prettyName(ids[i]) + "'");
     } catch (e) {
       ok(false,
-         "getText fails between start and end offsets '" + aStartOffset +
-         "', '" + aEndOffset + " for '" + prettyName(aIDs[i]) + "'");
+        "getText fails between start and end offsets '" + aStartOffset +
+        "', '" + aEndOffset + " for '" + prettyName(ids[i]) + "'");
     }
   }
 }
 
 /**
  * Test password text between two given offsets
  *
  * @param aIDs          [in] an array of accessible IDs to test
@@ -100,58 +106,42 @@ function testCharAtOffset(aIDs, aOffset,
     testTextHelper(IDs[i], aOffset, BOUNDARY_CHAR,
                    aChar, aStartOffset, aEndOffset,
                    kOk, kOk, kOk,
                    acc.getTextAtOffset, "getTextAtOffset ");
   }
 }
 
 /**
- * Test getTextAtOffset function over different elements
+ * Test getTextAtOffset function over different elements.
+ *
+ * @param aIDs            [in] ID or array of IDs
+ * @param aBoundaryType   [in] boundary type for text to be retrieved
+ * @param aTestList       [in] array of sets:
+ *                              offset1 and offset2 defining the offset range
+ *                              the text in the range
+ *                              start offset of the text in the range
+ *                              end offset of the text in the range
+ *
+ * or
  *
  * @param aOffset         [in] the offset to get the text at
  * @param aBoundaryType   [in] Boundary type for text to be retrieved
  * @param aText           [in] expected return text for getTextAtOffset
  * @param aStartOffset    [in] expected return start offset for getTextAtOffset
  * @param aEndOffset      [in] expected return end offset for getTextAtOffset
  * @param ...             [in] list of ids or list of tuples made of:
  *                              element identifier
  *                              kTodo or kOk for returned text
  *                              kTodo or kOk for returned start offset
  *                              kTodo or kOk for returned offset result
  */
-function testTextAtOffset(aOffset, aBoundaryType, aText,
-                          aStartOffset, aEndOffset)
+function testTextAtOffset()
 {
-  // List of IDs.
-  if (arguments[5] instanceof Array) {
-    var ids = arguments[5];
-    for (var i = 0; i < ids.length; i++) {
-      var acc = getAccessible(ids[i], nsIAccessibleText);
-      testTextHelper(ids[i], aOffset, aBoundaryType,
-                     aText, aStartOffset, aEndOffset,
-                     kOk, kOk, kOk,
-                     acc.getTextAtOffset, "getTextAtOffset ");
-    }
-
-    return;
-  }
-
-  for (var i = 5; i < arguments.length; i = i + 4) {
-    var ID = arguments[i];
-    var acc = getAccessible(ID, nsIAccessibleText);
-    var toDoFlag1 = arguments[i + 1];
-    var toDoFlag2 = arguments[i + 2];
-    var toDoFlag3 = arguments[i + 3];
-
-    testTextHelper(ID, aOffset, aBoundaryType,
-                   aText, aStartOffset, aEndOffset,
-                   toDoFlag1, toDoFlag2, toDoFlag3,
-                   acc.getTextAtOffset, "getTextAtOffset ");
-  }
+  testTextSuperHelper("getTextAtOffset", arguments);
 }
 
 /**
  * Test getTextAfterOffset for BOUNDARY_CHAR over different elements.
  *
  * @param aIDs          [in] the accessible identifier or array of accessible
  *                        identifiers
  * @param aOffset       [in] the offset to get a character after it
@@ -169,57 +159,41 @@ function testCharAfterOffset(aIDs, aOffs
                    kOk, kOk, kOk,
                    acc.getTextAfterOffset, "getTextAfterOffset ");
   }
 }
 
 /**
  * Test getTextAfterOffset function over different elements
  *
+ * @param aIDs            [in] ID or array of IDs
+ * @param aBoundaryType   [in] boundary type for text to be retrieved
+ * @param aTestList       [in] array of sets:
+ *                              offset1 and offset2 defining the offset range
+ *                              the text in the range
+ *                              start offset of the text in the range
+ *                              end offset of the text in the range
+ *
+ * or
+ *
  * @param aOffset         [in] the offset to get the text after
  * @param aBoundaryType   [in] Boundary type for text to be retrieved
  * @param aText           [in] expected return text for getTextAfterOffset
  * @param aStartOffset    [in] expected return start offset for getTextAfterOffset
  * @param aEndOffset      [in] expected return end offset for getTextAfterOffset
  * @param ...             [in] list of ids or list of tuples made of:
  *                              element identifier
  *                              kTodo or kOk for returned text
  *                              kTodo or kOk for returned start offset
  *                              kTodo or kOk for returned offset result
  */
 function testTextAfterOffset(aOffset, aBoundaryType,
                              aText, aStartOffset, aEndOffset)
 {
-  // List of IDs.
-  if (arguments[5] instanceof Array) {
-    var ids = arguments[5];
-    for (var i = 0; i < ids.length; i++) {
-      var acc = getAccessible(ids[i], nsIAccessibleText);
-      testTextHelper(ids[i], aOffset, aBoundaryType,
-                     aText, aStartOffset, aEndOffset,
-                     kOk, kOk, kOk,
-                     acc.getTextAfterOffset, "getTextAfterOffset ");
-    }
-
-    return;
-  }
-
-  // List of tuples.
-  for (var i = 5; i < arguments.length; i = i + 4) {
-    var ID = arguments[i];
-    var acc = getAccessible(ID, nsIAccessibleText);
-    var toDoFlag1 = arguments[i + 1];
-    var toDoFlag2 = arguments[i + 2];
-    var toDoFlag3 = arguments[i + 3];
-
-    testTextHelper(ID, aOffset, aBoundaryType,
-                   aText, aStartOffset, aEndOffset,
-                   toDoFlag1, toDoFlag2, toDoFlag3, 
-                   acc.getTextAfterOffset, "getTextAfterOffset ");
-  }
+  testTextSuperHelper("getTextAfterOffset", arguments);
 }
 
 /**
  * Test getTextBeforeOffset for BOUNDARY_CHAR over different elements.
  *
  * @param aIDs          [in] the accessible identifier or array of accessible
  *                        identifiers
  * @param aOffset       [in] the offset to get a character before it
@@ -237,56 +211,41 @@ function testCharBeforeOffset(aIDs, aOff
                    kOk, kOk, kOk,
                    acc.getTextBeforeOffset, "getTextBeforeOffset ");
   }
 }
 
 /**
  * Test getTextBeforeOffset function over different elements
  *
+ * @param aIDs            [in] ID or array of IDs
+ * @param aBoundaryType   [in] boundary type for text to be retrieved
+ * @param aTestList       [in] array of sets:
+ *                              offset1 and offset2 defining the offset range
+ *                              the text in the range
+ *                              start offset of the text in the range
+ *                              end offset of the text in the range
+ *
+ * or
+ *
  * @param aOffset         [in] the offset to get the text before
  * @param aBoundaryType   [in] Boundary type for text to be retrieved
  * @param aText           [in] expected return text for getTextBeforeOffset
  * @param aStartOffset    [in] expected return start offset for getTextBeforeOffset
  * @param aEndOffset      [in] expected return end offset for getTextBeforeOffset
  * @param ...             [in] list of ids or list of tuples made of:
  *                              element identifier
  *                              kTodo or kOk for returned text
  *                              kTodo or kOk for returned start offset
  *                              kTodo or kOk for returned offset result
  */
 function testTextBeforeOffset(aOffset, aBoundaryType,
                               aText, aStartOffset, aEndOffset)
 {
-  // List of IDs.
-  if (arguments[5] instanceof Array) {
-    var ids = arguments[5];
-    for (var i = 0; i < ids.length; i++) {
-      var acc = getAccessible(ids[i], nsIAccessibleText);
-      testTextHelper(ids[i], aOffset, aBoundaryType,
-                     aText, aStartOffset, aEndOffset,
-                     kOk, kOk, kOk,
-                     acc.getTextBeforeOffset, "getTextBeforeOffset ");
-    }
-
-    return;
-  }
-
-  for (var i = 5; i < arguments.length; i = i + 4) {
-    var ID = arguments[i];
-    var acc = getAccessible(ID, nsIAccessibleText);
-    var toDoFlag1 = arguments[i + 1];
-    var toDoFlag2 = arguments[i + 2];
-    var toDoFlag3 = arguments[i + 3];
-
-    testTextHelper(ID, aOffset, aBoundaryType,
-                   aText, aStartOffset, aEndOffset,
-                   toDoFlag1, toDoFlag2, toDoFlag3,
-                   acc.getTextBeforeOffset, "getTextBeforeOffset ");
-  }
+  testTextSuperHelper("getTextBeforeOffset", arguments);
 }
 
 /**
  * Test word count for an element.
  *
  * @param aElement   [in] element identifier
  * @param aCount     [in] Expected word count
  * @param aToDoFlag  [in] kTodo or kOk for returned text
@@ -497,16 +456,88 @@ function testTextGetSelection(aID, aStar
      aSelectionIndex + "'");
   is(endObj.value, aEndOffset, text + ": wrong end offset for index '" +
      aSelectionIndex + "'");
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Private
 
+function testTextSuperHelper(aFuncName, aArgs)
+{
+  // List of tests.
+  if (aArgs[2] instanceof Array) {
+    var ids = (aArgs[0] instanceof Array) ? aArgs[0] : [ aArgs[0] ];
+    var boundaryType = aArgs[1];
+    var list = aArgs[2];
+    for (var i = 0; i < list.length; i++) {
+      var offset1 = list[i][0], offset2 = list[i][1];
+      var text = list[i][2], startOffset = list[i][3], endOffset = list[i][4];
+      var failureList = list[i][5];
+      for (var offset = offset1; offset <= offset2; offset++) {
+        for (var idIdx = 0; idIdx < ids.length; idIdx++) {
+          var id = ids[idIdx];
+
+          var flagOk1 = kOk, flagOk2 = kOk, flagOk3 = kOk;
+          if (failureList) {
+            for (var fIdx = 0; fIdx < failureList.length; fIdx++) {
+              if (offset == failureList[fIdx][0] && id == failureList[fIdx][1]) {
+                flagOk1 = failureList[fIdx][2];
+                flagOk2 = failureList[fIdx][3];
+                flagOk3 = failureList[fIdx][4];
+                break;
+              }
+            }
+          }
+
+          var acc = getAccessible(id, nsIAccessibleText);
+          testTextHelper(id, offset, boundaryType,
+                         text, startOffset, endOffset,
+                         flagOk1, flagOk2, flagOk3,
+                         acc[aFuncName], aFuncName + " ");
+        }
+      }
+    }
+    return;
+  }
+
+  // Test at single offset. List of IDs.
+  var offset = aArgs[0];
+  var boundaryType = aArgs[1];
+  var text = aArgs[2];
+  var startOffset = aArgs[3];
+  var endOffset = aArgs[4];
+  if (aArgs[5] instanceof Array) {
+    var ids = aArgs[5];
+    for (var i = 0; i < ids.length; i++) {
+      var acc = getAccessible(ids[i], nsIAccessibleText);
+      testTextHelper(ids[i], offset, boundaryType,
+                     text, startOffset, endOffset,
+                     kOk, kOk, kOk,
+                     acc[aFuncName], aFuncName + " ");
+    }
+
+    return;
+  }
+
+  // Each ID is tested separately.
+  for (var i = 5; i < aArgs.length; i = i + 4) {
+    var ID = aArgs[i];
+    var acc = getAccessible(ID, nsIAccessibleText);
+    var toDoFlag1 = aArgs[i + 1];
+    var toDoFlag2 = aArgs[i + 2];
+    var toDoFlag3 = aArgs[i + 3];
+
+    testTextHelper(ID, offset, boundaryType,
+                   text, startOffset, endOffset,
+                   toDoFlag1, toDoFlag2, toDoFlag3,
+                   acc[aFuncName], aFuncName + " ");
+  }
+}
+
 function testTextHelper(aID, aOffset, aBoundaryType,
                         aText, aStartOffset, aEndOffset,
                         aToDoFlag1, aToDoFlag2, aToDoFlag3,
                         aTextFunc, aTextFuncName)
 {
   var exceptionFlag = aToDoFlag1 == undefined ||
                       aToDoFlag2 == undefined ||
                       aToDoFlag3 == undefined;
--- a/accessible/tests/mochitest/text/Makefile.in
+++ b/accessible/tests/mochitest/text/Makefile.in
@@ -9,20 +9,22 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir	= @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_A11Y_FILES = \
 		doc.html \
 		test_atcaretoffset.html \
+		test_charboundary.html \
 		test_doc.html \
+		test_gettext.html \
 		test_hypertext.html \
 		test_label.xul \
 		test_multiline.html \
 		test_passwords.html \
 		test_selection.html \
 		test_singleline.html \
-		test_whitespaces.html \
+		test_wordboundary.html \
 		test_words.html \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/accessible/tests/mochitest/text/test_atcaretoffset.html
+++ b/accessible/tests/mochitest/text/test_atcaretoffset.html
@@ -36,23 +36,23 @@
 
     function moveToLastLineEnd()
     {
       this.__proto__ = new synthFocus("textarea");
 
       this.finalCheck = function moveToLastLineEnd_finalCheck()
       {
         testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_START, "", 15, 15,
-                            "textarea", kTodo, kOk, kTodo);
+                            ["textarea"]);
 
         testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_END, "", 15, 15,
-                            "textarea", kTodo, kOk, kTodo);
+                            "textarea", kOk, kTodo, kTodo);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_START, "", 15, 15,
-                         "textarea", kTodo, kTodo, kTodo);
+                         "textarea", kTodo, kTodo, kOk);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_END, "words", 10, 15,
                          "textarea", kTodo, kTodo, kTodo);
 
         testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_START, "words", 10, 15,
                              "textarea", kOk, kOk, kOk);
 
         testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_END, "\ntwo ", 5, 10,
@@ -67,23 +67,23 @@
 
     function moveToLastLineStart()
     {
       this.__proto__ = new moveToLineStart("textarea", 10);
 
       this.finalCheck = function moveToLastLineStart_finalCheck()
       {
         testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_START, "", 15, 15,
-                            "textarea", kTodo, kTodo, kTodo);
+                            "textarea", kTodo, kTodo, kOk);
 
         testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_END, "", 15, 15,
                             "textarea", kTodo, kTodo, kOk);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_START, "words", 10, 15,
-                         "textarea", kTodo, kOk, kTodo);
+                         [ "textarea" ]);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_END, "\ntwo ", 5, 10,
                          "textarea", kTodo, kTodo, kTodo);
 
         testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_START, "two ", 6, 10,
                              "textarea", kTodo, kTodo, kOk);
 
         testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_END, "\ntwo ", 5, 10,
@@ -219,17 +219,17 @@
       {
         return "move to first line end";
       }
     }
 
     var gQueue = null;
     function doTest()
     {
-      SimpleTest.expectAssertions(5);
+      SimpleTest.expectAssertions(7);
 
       gQueue = new eventQueue();
       gQueue.push(new moveToLastLineEnd());
       gQueue.push(new moveToLastLineStart());
       gQueue.push(new moveToMiddleLineStart());
       gQueue.push(new moveToMiddleLineEnd());
       gQueue.push(new moveToFirstLineStart());
       gQueue.push(new moveToFirstLineEnd());
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/text/test_charboundary.html
@@ -0,0 +1,148 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Char boundary text tests</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../text.js"></script>
+
+  <script type="application/javascript">
+    function doTest()
+    {
+      //////////////////////////////////////////////////////////////////////////
+      //
+      // __h__e__l__l__o__ __m__y__ __f__r__i__e__n__d__
+      //  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
+
+      var IDs = [ "i1", "d1", "e1", "t1" ];
+
+      testCharBeforeOffset(IDs, 0, "", 0, 0);
+      testCharBeforeOffset(IDs, 1, "h", 0, 1);
+      testCharBeforeOffset(IDs, 14, "n", 13, 14);
+      testCharBeforeOffset(IDs, 15, "d", 14, 15);
+
+      testCharAtOffset(IDs, 0, "h", 0, 1);
+      testCharAtOffset(IDs, 1, "e", 1, 2);
+      testCharAtOffset(IDs, 14, "d", 14, 15);
+      testCharAtOffset(IDs, 15, "", 15, 15);
+
+      testCharAfterOffset(IDs, 0, "e", 1, 2);
+      testCharAfterOffset(IDs, 1, "l", 2, 3);
+      testCharAfterOffset(IDs, 14, "", 15, 15);
+
+      // 15 is out of range offset for get text after, keep todos until we
+      // decide how to handle out of range values (ATK and IA2 seems to have
+      // different expectations.
+      testTextAfterOffset(15, BOUNDARY_CHAR, "", 15, 15,
+                          "i1", kOk, kTodo, kTodo,
+                          "d1", kOk, kTodo, kTodo,
+                          "e1", kOk, kTodo, kTodo,
+                          "t1", kOk, kTodo, kTodo);
+
+      //////////////////////////////////////////////////////////////////////////
+      //
+      // __B__r__a__v__e__ __S__i__r__ __ __R__o__b__i__n__ __ __ __r__a__n
+      //  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21
+
+      IDs = [ "i2", "d2", "e2", "t2" ];
+
+      testCharBeforeOffset(IDs, 0, "", 0, 0);
+      testCharBeforeOffset(IDs, 1, "B", 0, 1);
+      testCharBeforeOffset(IDs, 6, " ", 5, 6);
+      testCharBeforeOffset(IDs, 10, " ", 9, 10);
+      testCharBeforeOffset(IDs, 11, " ", 10, 11);
+      testCharBeforeOffset(IDs, 17, " ", 16, 17);
+      testCharBeforeOffset(IDs, 19, " ", 18, 19);
+
+      testCharAtOffset(IDs, 0, "B", 0, 1);
+      testCharAtOffset(IDs, 1, "r", 1, 2);
+      testCharAtOffset(IDs, 5, " ", 5, 6);
+      testCharAtOffset(IDs, 9, " ", 9, 10);
+      testCharAtOffset(IDs, 10, " ", 10, 11);
+      testCharAtOffset(IDs, 17, " ", 17, 18);
+
+      testCharAfterOffset(IDs, 0, "r", 1, 2);
+      testCharAfterOffset(IDs, 1, "a", 2, 3);
+      testCharAfterOffset(IDs, 4, " ", 5, 6);
+      testCharAfterOffset(IDs, 5, "S", 6, 7);
+      testCharAfterOffset(IDs, 8, " ", 9, 10);
+      testCharAfterOffset(IDs, 9, " ", 10, 11);
+      testCharAfterOffset(IDs, 10, "R", 11, 12);
+      testCharAfterOffset(IDs, 15, " ", 16, 17);
+      testCharAfterOffset(IDs, 16, " ", 17, 18);
+      testCharAfterOffset(IDs, 17, " ", 18, 19);
+      testCharAfterOffset(IDs, 18, "r", 19, 20);
+
+      //////////////////////////////////////////////////////////////////////////
+      //
+      // __o__n__e__w__o__r__d__\n
+      //  0  1  2  3  4  5  6  7
+      // __\n
+      //  8
+      // __t__w__o__ __w__o__r__d__s__\n
+      //  9 10 11 12 13 14 15 16 17 18
+
+      IDs = ["d3", "dbr3", "e3", "ebr3", "t3"];
+
+      testCharBeforeOffset(IDs, 8, "\n", 7, 8);
+      testCharBeforeOffset(IDs, 9, "\n", 8, 9);
+      testCharBeforeOffset(IDs, 10, "t", 9, 10);
+
+      testCharAtOffset(IDs, 7, "\n", 7, 8);
+      testCharAtOffset(IDs, 8, "\n", 8, 9);
+      testCharAtOffset(IDs, 9, "t", 9, 10);
+
+      testCharAfterOffset(IDs, 6, "\n", 7, 8);
+      testCharAfterOffset(IDs, 7, "\n", 8, 9);
+      testCharAfterOffset(IDs, 8, "t", 9, 10);
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <input id="i1" value="hello my friend"/>
+  <div id="d1">hello my friend</div>
+  <div id="e1" contenteditable="true">hello my friend</div>
+  <textarea id="t1" contenteditable="true">hello my friend</textarea>
+
+  <input id="i2" value="Brave Sir  Robin   ran"/>
+  <pre>
+    <div id="d2">Brave Sir  Robin   ran</div>
+    <div id="e2" contenteditable="true">Brave Sir  Robin   ran</div>
+  </pre>
+  <textarea id="t2" cols="300">Brave Sir  Robin   ran</textarea>
+
+  <pre>
+    <div id="d3">oneword
+
+two words
+</div>
+    <div id="dbr3">oneword<br/><br/>two words<br/></div>
+    <div id="e3" contenteditable="true">oneword
+
+two words
+</div>
+    <div id="ebr3" contenteditable="true">oneword<br/><br/>two words<br/></div>
+    <textarea id="t3" cols="300">oneword
+
+two words</textarea>
+  </pre>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/text/test_gettext.html
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Get text between offsets tests</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../text.js"></script>
+
+  <script type="application/javascript">
+    function doTest()
+    {
+      //////////////////////////////////////////////////////////////////////////
+      //
+      // __h__e__l__l__o__ __m__y__ __f__r__i__e__n__d__
+      //  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
+
+      var IDs = [ "i1", "d1", "e1", "t1" ];
+
+      testCharacterCount(IDs, 15);
+
+      testText(IDs, 0, 1, "h");
+      testText(IDs, 1, 3, "el");
+      testText(IDs, 14, 15, "d");
+      testText(IDs, 0, 15, "hello my friend");
+      testText(IDs, 0, -1, "hello my friend");
+
+      //////////////////////////////////////////////////////////////////////////
+      //
+      // __B__r__a__v__e__ __S__i__r__ __ __R__o__b__i__n__ __ __ __r__a__n
+      //  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21
+
+      IDs = [ "i2", "dpre2", "epre2", "t2" ];
+
+      testCharacterCount(IDs, 22);
+
+      testText(IDs, 0, 1, "B");
+      testText(IDs, 5, 6, " ");
+      testText(IDs, 9, 11, "  ");
+      testText(IDs, 16, 19, "   ");
+      testText(IDs, 0, 22, "Brave Sir  Robin   ran");
+      testText(IDs, 0, -1, "Brave Sir  Robin   ran");
+
+      testCharacterCount(["d2", "e2"], 19);
+      testText(["d2", "e2"], 0, 19, "Brave Sir Robin ran");
+
+      //////////////////////////////////////////////////////////////////////////
+      //
+      // __o__n__e__w__o__r__d__\n
+      //  0  1  2  3  4  5  6  7
+      // __\n
+      //  8
+      // __t__w__o__ __w__o__r__d__s__\n
+      //  9 10 11 12 13 14 15 16 17 18
+
+      var IDs = ["d3", "dbr3", "e3", "ebr3", "t3"];
+
+      testCharacterCount(IDs, 19);
+
+      testText(IDs, 0, 19, "oneword\n\ntwo words\n");
+      testText(IDs, 0, -1, "oneword\n\ntwo words\n");
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <input id="i1" value="hello my friend"/>
+  <div id="d1">hello my friend</div>
+  <div id="e1" contenteditable="true">hello my friend</div>
+  <textarea id="t1">hello my friend</textarea>
+
+  <input id="i2" value="Brave Sir  Robin   ran"/>
+  <pre><div id="dpre2">Brave Sir  Robin   ran</div></pre>
+  <pre><div id="epre2" contenteditable="true">Brave Sir  Robin   ran</div></pre>
+  <textarea id="t2" cols="300">Brave Sir  Robin   ran</textarea>
+  <div id="d2">Brave Sir  Robin   ran</div>
+  <div id="e2" contenteditable="true">Brave Sir  Robin   ran</div>
+
+  <pre>
+  <div id="d3">oneword
+
+two words
+</div>
+  <div id="dbr3">oneword<br/><br/>two words<br/></div>
+  <div id="e3" contenteditable="true">oneword
+
+two words
+</div>
+  <div id="ebr3" contenteditable="true">oneword<br/><br/>two words<br/></div>
+  <textarea id="t3" cols="300">oneword
+
+two words
+</textarea>
+  </pre>
+
+</body>
+</html>
--- a/accessible/tests/mochitest/text/test_multiline.html
+++ b/accessible/tests/mochitest/text/test_multiline.html
@@ -11,73 +11,33 @@
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../text.js"></script>
   <script type="application/javascript">
 
     function doTest()
     {
-      SimpleTest.expectAssertions(44);
+      SimpleTest.expectAssertions(46);
 
       // __o__n__e__w__o__r__d__\n
       //  0  1  2  3  4  5  6  7
       // __\n
       //  8
       // __t__w__o__ __w__o__r__d__s__\n
       //  9 10 11 12 13 14 15 16 17 18
 
-      // Note: HTML textarea adds an extra "\n" at the end of the text at
-      //  the layount/content level.
-
       ////////////////////////////////////////////////////////////////////////
       // getText
 
       var IDs = ["div", "divbr", "editable", "editablebr", "textarea"];
-      testText(IDs, 0, 19, "oneword\n\ntwo words\n");
 
       ////////////////////////////////////////////////////////////////////////
       // getTextAfterOffset
 
-      // BOUNDARY_CHAR
-      testTextAfterOffset(6, BOUNDARY_CHAR, "\n", 7, 8,
-                          "div", kOk, kOk, kOk,
-                          "divbr", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "editablebr", kOk, kOk, kOk,
-                          "textarea", kOk, kOk, kOk);
-      testTextAfterOffset(7, BOUNDARY_CHAR, "\n", 8, 9,
-                          "div", kOk, kOk, kOk,
-                          "divbr", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "editablebr", kOk, kOk, kOk,
-                          "textarea", kOk, kOk, kOk);
-      testTextAfterOffset(8, BOUNDARY_CHAR, "t", 9, 10,
-                          "div", kOk, kOk, kOk,
-                          "divbr", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "editablebr", kOk, kOk, kOk,
-                          "textarea", kOk, kOk, kOk);
-
-      // BOUNDARY_WORD_START
-      testTextAfterOffset(0, BOUNDARY_WORD_START, "two ", 9, 13, IDs);
-      testTextAfterOffset(8, BOUNDARY_WORD_START, "two ", 9, 13,
-                          "div", kOk, kOk, kOk,
-                          "divbr", kTodo, kTodo, kTodo,
-                          "editable", kOk, kOk, kOk,
-                          "editablebr", kTodo, kTodo, kTodo,
-                          "textarea", kOk, kOk, kOk);
-      testTextAfterOffset(9, BOUNDARY_WORD_START, "words\n", 13, 19, IDs);
-
-      // BOUNDARY_WORD_END
-      testTextAfterOffset(0, BOUNDARY_WORD_END, "\n\ntwo", 7, 12, IDs);
-      testTextAfterOffset(6, BOUNDARY_WORD_END, "\n\ntwo", 7, 12, IDs);
-      testTextAfterOffset(7, BOUNDARY_WORD_END, "\n\ntwo", 7, 12, IDs);
-      testTextAfterOffset(8, BOUNDARY_WORD_END, " words", 12, 18, IDs);
-
       // BOUNDARY_LINE_START
       testTextAfterOffset(0, BOUNDARY_LINE_START, "\n", 8, 9,
                           "div", kTodo, kTodo, kTodo,
                           "divbr", kTodo, kTodo, kTodo,
                           "editable", kTodo, kTodo, kTodo,
                           "editablebr", kTodo, kTodo, kTodo,
                           "textarea", kTodo, kTodo, kTodo);
       testTextAfterOffset(7, BOUNDARY_LINE_START, "\n", 8, 9,
@@ -92,23 +52,23 @@
                           "editable", kTodo, kTodo, kTodo,
                           "editablebr", kTodo, kTodo, kTodo,
                           "textarea", kTodo, kTodo, kTodo);
       testTextAfterOffset(9, BOUNDARY_LINE_START, "", 19, 19,
                           "div", kTodo, kTodo, kTodo,
                           "divbr", kTodo, kTodo, kOk,
                           "editable", kTodo, kTodo, kTodo,
                           "editablebr", kTodo, kTodo, kOk,
-                          "textarea", kTodo, kTodo, kOk);
+                          "textarea", kTodo, kTodo, kTodo);
       testTextAfterOffset(19, BOUNDARY_LINE_START, "", 19, 19,
                           "div", kOk, kOk, kTodo,
                           "divbr", kOk, kOk, kOk,
                           "editable", kOk, kOk, kTodo,
                           "editablebr", kOk, kOk, kOk,
-                          "textarea", kOk, kOk, kOk);
+                          "textarea", kOk, kOk, kTodo);
 
       // BOUNDARY_LINE_END
       testTextAfterOffset(0, BOUNDARY_LINE_END, "\n", 7, 8,
                           "div", kTodo, kTodo, kTodo,
                           "divbr", kTodo, kTodo, kTodo,
                           "editable", kTodo, kTodo, kTodo,
                           "editablebr", kTodo, kTodo, kTodo,
                           "textarea", kTodo, kTodo, kTodo);
@@ -118,93 +78,39 @@
                           "editable", kOk, kOk, kOk,
                           "editablebr", kOk, kOk, kOk,
                           "textarea", kOk, kOk, kOk);
       testTextAfterOffset(8, BOUNDARY_LINE_END, "\ntwo words", 8, 18,
                           "div", kTodo, kOk, kTodo,
                           "divbr", kOk, kOk, kOk,
                           "editable", kTodo, kOk, kTodo,
                           "editablebr", kOk, kOk, kOk,
-                          "textarea", kOk, kOk, kOk);
+                          "textarea", kTodo, kOk, kTodo);
       testTextAfterOffset(9, BOUNDARY_LINE_END, "\n", 18, 19,
                           "div", kTodo, kTodo, kTodo,
                           "divbr", kTodo, kTodo, kTodo,
                           "editable", kTodo, kTodo, kTodo,
                           "editablebr", kTodo, kTodo, kTodo,
                           "textarea", kTodo, kTodo, kTodo);
       testTextAfterOffset(18, BOUNDARY_LINE_END, "\n", 18, 19,
                           "div", kTodo, kOk, kTodo,
                           "divbr", kOk, kOk, kOk,
                           "editable", kTodo, kOk, kTodo,
                           "editablebr", kOk, kOk, kOk,
-                          "textarea", kOk, kOk, kOk);
+                          "textarea", kTodo, kOk, kTodo);
       testTextAfterOffset(19, BOUNDARY_LINE_END, "", 19, 19,
                           "div", kOk, kTodo, kTodo,
                           "divbr", kOk, kTodo, kTodo,
                           "editable", kOk, kTodo, kTodo,
                           "editablebr", kOk, kTodo, kTodo,
                           "textarea", kOk, kTodo, kTodo);
 
       ////////////////////////////////////////////////////////////////////////
       // getTextBeforeOffset
 
-      // BOUNDARY_CHAR
-      testTextBeforeOffset(8, BOUNDARY_CHAR, "\n", 7, 8,
-                           "div", kOk, kOk, kOk,
-                           "divbr", kOk, kOk, kOk,
-                           "editable", kOk, kOk, kOk,
-                           "editablebr", kOk, kOk, kOk,
-                           "textarea", kOk, kOk, kOk);
-      testTextBeforeOffset(9, BOUNDARY_CHAR, "\n", 8, 9,
-                           "div", kOk, kOk, kOk,
-                           "divbr", kOk, kOk, kOk,
-                           "editable", kOk, kOk, kOk,
-                           "editablebr", kOk, kOk, kOk,
-                           "textarea", kOk, kOk, kOk);
-      testTextBeforeOffset(10, BOUNDARY_CHAR, "t", 9, 10,
-                           "div", kOk, kOk, kOk,
-                           "divbr", kOk, kOk, kOk,
-                           "editable", kOk, kOk, kOk,
-                           "editablebr", kOk, kOk, kOk,
-                           "textarea", kOk, kOk, kOk);
-
-      // BOUNDARY_WORD_START
-      testTextBeforeOffset(0, BOUNDARY_WORD_START, "", 0, 0, IDs);
-      testTextBeforeOffset(7, BOUNDARY_WORD_START, "", 0, 0, IDs);
-      testTextBeforeOffset(8, BOUNDARY_WORD_START, "", 0, 0, IDs);
-      testTextBeforeOffset(9, BOUNDARY_WORD_START, "oneword\n\n", 0, 9, IDs);
-      testTextBeforeOffset(13, BOUNDARY_WORD_START, "two ", 9, 13, IDs);
-      testTextBeforeOffset(18, BOUNDARY_WORD_START, "two ", 9, 13, IDs);
-      testTextBeforeOffset(19, BOUNDARY_WORD_START, "words\n", 13, 19, IDs);
-
-      // BOUNDARY_WORD_END
-      testTextBeforeOffset(0, BOUNDARY_WORD_END, "", 0, 0, IDs);
-      testTextBeforeOffset(7, BOUNDARY_WORD_END, "", 0, 0, IDs);
-      testTextBeforeOffset(8, BOUNDARY_WORD_END, "oneword", 0, 7,
-                           "div", kOk, kOk, kOk,
-                           "divbr", kTodo, kOk, kTodo,
-                           "editable", kOk, kOk, kOk,
-                           "editablebr", kTodo, kOk, kTodo,
-                           "textarea", kOk, kOk, kOk);
-      testTextBeforeOffset(9, BOUNDARY_WORD_END, "oneword", 0, 7,
-                           "div", kOk, kOk, kOk,
-                           "divbr", kTodo, kOk, kTodo,
-                           "editable", kOk, kOk, kOk,
-                           "editablebr", kTodo, kOk, kTodo,
-                           "textarea", kOk, kOk, kOk);
-      testTextBeforeOffset(12, BOUNDARY_WORD_END, "oneword", 0, 7, IDs);
-      testTextBeforeOffset(13, BOUNDARY_WORD_END, "\n\ntwo", 7, 12, IDs);
-      testTextBeforeOffset(18, BOUNDARY_WORD_END, "\n\ntwo", 7, 12, IDs);
-      testTextBeforeOffset(19, BOUNDARY_WORD_END, " words", 12, 18,
-                           "div", kOk, kOk, kOk,
-                           "divbr", kTodo, kTodo, kTodo,
-                           "editable", kOk, kOk, kOk,
-                           "editablebr", kTodo, kTodo, kTodo,
-                           "textarea", kTodo, kTodo, kTodo);
-
       // BOUNDARY_LINE_START
       testTextBeforeOffset(0, BOUNDARY_LINE_START, "", 0, 0,
                            "div", kOk, kOk, kOk,
                            "divbr", kOk, kOk, kOk,
                            "editable", kOk, kOk, kOk,
                            "editablebr", kOk, kOk, kOk,
                            "textarea", kOk, kOk, kOk);
       testTextBeforeOffset(8, BOUNDARY_LINE_START, "oneword\n", 0, 8,
@@ -268,59 +174,16 @@
                            "divbr", kTodo, kTodo, kTodo,
                            "editable", kTodo, kTodo, kTodo,
                            "editablebr", kTodo, kTodo, kTodo,
                            "textarea", kTodo, kTodo, kTodo);
 
       ////////////////////////////////////////////////////////////////////////
       // getTextAtOffset
 
-      // BOUNDARY_CHAR
-      testTextAtOffset(7, BOUNDARY_CHAR, "\n", 7, 8,
-                       "div", kOk, kOk, kOk,
-                       "divbr", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "editablebr", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(8, BOUNDARY_CHAR, "\n", 8, 9,
-                       "div", kOk, kOk, kOk,
-                       "divbr", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "editablebr", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(9, BOUNDARY_CHAR, "t", 9, 10,
-                       "div", kOk, kOk, kOk,
-                       "divbr", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "editablebr", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-
-      // BOUNDARY_WORD_START
-      testTextAtOffset(0, BOUNDARY_WORD_START, "oneword\n\n", 0, 9, IDs);
-      testTextAtOffset(8, BOUNDARY_WORD_START, "oneword\n\n", 0, 9,
-                       "div", kOk, kOk, kOk,
-                       "divbr", kTodo, kTodo, kTodo,
-                       "editable", kOk, kOk, kOk,
-                       "editablebr", kTodo, kTodo, kTodo,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(9, BOUNDARY_WORD_START, "two ", 9, 13, IDs);
-      testTextAtOffset(13, BOUNDARY_WORD_START, "words\n", 13, 19, IDs);
-
-      // BOUNDARY_WORD_END
-      testTextAtOffset(0, BOUNDARY_WORD_END, "oneword", 0, 7, IDs);
-      testTextAtOffset(8, BOUNDARY_WORD_END, "\n\ntwo", 7, 12, IDs);
-      testTextAtOffset(9, BOUNDARY_WORD_END, "\n\ntwo", 7, 12, IDs);
-      testTextAtOffset(12, BOUNDARY_WORD_END, " words", 12, 18, IDs);
-      testTextAtOffset(13, BOUNDARY_WORD_END, " words", 12, 18,
-                       "div", kOk, kOk, kOk,
-                       "divbr", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "editablebr", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-
       // BOUNDARY_LINE_START
       testTextAtOffset(0, BOUNDARY_LINE_START, "oneword\n", 0, 8,
                        "div", kTodo, kOk, kTodo,
                        "divbr", kOk, kOk, kOk,
                        "editable", kTodo, kOk, kTodo,
                        "editablebr", kOk, kOk, kOk,
                        "textarea", kTodo, kOk, kTodo);
       testTextAtOffset(7, BOUNDARY_LINE_START, "oneword\n", 0, 8,
@@ -335,35 +198,35 @@
                        "editable", kOk, kOk, kOk,
                        "editablebr", kOk, kOk, kOk,
                        "textarea", kOk, kOk, kOk);
       testTextAtOffset(9, BOUNDARY_LINE_START, "two words\n", 9, 19,
                        "div", kTodo, kOk, kTodo,
                        "divbr", kOk, kOk, kOk,
                        "editable", kTodo, kOk, kTodo,
                        "editablebr", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
+                       "textarea", kTodo, kOk, kTodo);
       testTextAtOffset(13, BOUNDARY_LINE_START, "two words\n", 9, 19,
                        "div", kTodo, kOk, kTodo,
                        "divbr", kOk, kOk, kOk,
                        "editable", kTodo, kOk, kTodo,
                        "editablebr", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
+                       "textarea", kTodo, kOk, kTodo);
       testTextAtOffset(18, BOUNDARY_LINE_START, "two words\n", 9, 19,
                        "div", kOk, kOk, kOk,
                        "divbr", kOk, kOk, kOk,
                        "editable", kOk, kOk, kOk,
                        "editablebr", kOk, kOk, kOk,
                        "textarea", kOk, kOk, kOk);
       testTextAtOffset(19, BOUNDARY_LINE_START, "", 19, 19,
                        "div", kTodo, kTodo, kTodo,
                        "divbr", kTodo, kTodo, kOk,
                        "editable", kTodo, kTodo, kTodo,
                        "editablebr", kTodo, kTodo, kOk,
-                       "textarea", kTodo, kTodo, kOk);
+                       "textarea", kTodo, kTodo, kTodo);
 
       // BOUNDARY_LINE_END
       testTextAtOffset(0, BOUNDARY_LINE_END, "oneword", 0, 7,
                        "div", kTodo, kOk, kTodo,
                        "divbr", kOk, kOk, kOk,
                        "editable", kTodo, kOk, kTodo,
                        "editablebr", kOk, kOk, kOk,
                        "textarea", kTodo, kOk, kTodo);
@@ -379,17 +242,17 @@
                        "editable", kTodo, kTodo, kTodo,
                        "editablebr", kTodo, kTodo, kTodo,
                        "textarea", kTodo, kTodo, kTodo);
       testTextAtOffset(9, BOUNDARY_LINE_END, "\ntwo words", 8, 18,
                        "div", kTodo, kOk, kTodo,
                        "divbr", kOk, kOk, kOk,
                        "editable", kTodo, kOk, kTodo,
                        "editablebr", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
+                       "textarea", kTodo, kOk, kTodo);
       testTextAtOffset(17, BOUNDARY_LINE_END, "\ntwo words", 8, 18,
                        "div", kOk, kOk, kOk,
                        "divbr", kOk, kOk, kOk,
                        "editable", kOk, kOk, kOk,
                        "editablebr", kOk, kOk, kOk,
                        "textarea", kOk, kOk, kOk);
       testTextAtOffset(18, BOUNDARY_LINE_END, "\ntwo words", 8, 18,
                        "div", kTodo, kOk, kTodo,
@@ -439,12 +302,13 @@ two words
   <div id="divbr">oneword<br/><br/>two words<br/></div>
   <div id="editable" contenteditable="true">oneword
 
 two words
 </div>
   <div id="editablebr" contenteditable="true">oneword<br/><br/>two words<br/></div>
   <textarea id="textarea" cols="300">oneword
 
-two words</textarea>
+two words
+</textarea>
   </pre>
 </body>
 </html>
--- a/accessible/tests/mochitest/text/test_singleline.html
+++ b/accessible/tests/mochitest/text/test_singleline.html
@@ -7,107 +7,53 @@
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../text.js"></script>
   <script type="application/javascript">
     if (navigator.platform.startsWith("Mac")) {
-      SimpleTest.expectAssertions(0, 14);
+      SimpleTest.expectAssertions(0, 16);
     } else {
-      SimpleTest.expectAssertions(14);
+      SimpleTest.expectAssertions(16);
     }
 
     function doTest()
     {
       // __h__e__l__l__o__ __m__y__ __f__r__i__e__n__d__
       //  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
 
       ////////////////////////////////////////////////////////////////////////
-      // characterCount
-
-      testCharacterCount(["input", "div"], 15);
-      testCharacterCount(["textarea"], 16);
-
-      ////////////////////////////////////////////////////////////////////////
-      // getText
-
-      var IDs = ["input", "div", "textarea"];
-      testText(IDs, 0, 1, "h");
-      testText(IDs, 1, 3, "el");
-      testText(IDs, 14, 15, "d");
-      testText(IDs, 0, 15, "hello my friend");
-
-      ////////////////////////////////////////////////////////////////////////
       // getTextAfterOffset
 
       var IDs = [ "input", "div", "editable", "textarea" ];
       var regularIDs = [ "input", "div", "editable" ];
 
-      // BOUNDARY_CHAR
-
-      testCharAfterOffset(IDs, 0, "e", 1, 2);
-      testCharAfterOffset(IDs, 1, "l", 2, 3);
-      testCharAfterOffset(regularIDs, 14, "", 15, 15);
-      testCharAfterOffset("textarea", 14, "\n", 15, 16);
-
-      // XXX: why are 15/15 expected? there's no 16 offset we are trying to
-      // get an offset for?
-      testTextAfterOffset(15, BOUNDARY_CHAR, "", 15, 15,
-			  "input", kOk, kTodo, kTodo,
-			  "div", kOk, kTodo, kTodo,
-			  "editable", kOk, kTodo, kTodo);
-      testCharAfterOffset("textarea", 15, "", 16, 16);
-
-      // BOUNDARY_WORD_START
-      testTextAfterOffset(0, BOUNDARY_WORD_START, "my ", 6, 9, IDs);
-      testTextAfterOffset(1, BOUNDARY_WORD_START, "my ", 6, 9, IDs);
-      testTextAfterOffset(5, BOUNDARY_WORD_START, "my ", 6, 9, IDs);
-      testTextAfterOffset(6, BOUNDARY_WORD_START, "friend", 9, 15, IDs);
-      testTextAfterOffset(7, BOUNDARY_WORD_START, "friend", 9, 15, IDs);
-      testTextAfterOffset(8, BOUNDARY_WORD_START, "friend", 9, 15, IDs);
-      testTextAfterOffset(9, BOUNDARY_WORD_START, "", 15, 15, IDs);
-      testTextAfterOffset(11, BOUNDARY_WORD_START, "", 15, 15, IDs);
-      testTextAfterOffset(14, BOUNDARY_WORD_START, "", 15, 15, IDs);
-      testTextAfterOffset(15, BOUNDARY_WORD_START, "", 15, 15, IDs);
-
-      // BOUNDARY_WORD_END
-      testTextAfterOffset(0, BOUNDARY_WORD_END, " my", 5, 8, IDs);
-      testTextAfterOffset(1, BOUNDARY_WORD_END, " my", 5, 8, IDs);
-      testTextAfterOffset(5, BOUNDARY_WORD_END, " my", 5, 8, IDs);
-      testTextAfterOffset(6, BOUNDARY_WORD_END, " friend", 8, 15, IDs);
-      testTextAfterOffset(7, BOUNDARY_WORD_END, " friend", 8, 15, IDs);
-      testTextAfterOffset(8, BOUNDARY_WORD_END, " friend", 8, 15, IDs);
-      testTextAfterOffset(9, BOUNDARY_WORD_END, "", 15, 15, IDs);
-      testTextAfterOffset(11, BOUNDARY_WORD_END, "", 15, 15, IDs);
-      testTextAfterOffset(14, BOUNDARY_WORD_END, "", 15, 15, IDs);
-      testTextAfterOffset(15, BOUNDARY_WORD_END, "", 15, 15, IDs);
-
       // BOUNDARY_LINE_START
       testTextAfterOffset(0, BOUNDARY_LINE_START, "", 15, 15,
                           "input", kTodo, kTodo, kOk,
                           "div", kTodo, kTodo, kOk,
                           "editable", kTodo, kTodo, kOk,
-                          "textarea", kTodo, kTodo, kTodo);
+                          "textarea", kTodo, kTodo, kOk);
       testTextAfterOffset(1, BOUNDARY_LINE_START, "", 15, 15,
                           "input", kTodo, kTodo, kOk,
                           "div", kTodo, kTodo, kOk,
                           "editable", kTodo, kTodo, kOk,
-                          "textarea", kTodo, kTodo, kTodo);
+                          "textarea", kTodo, kTodo, kOk);
       testTextAfterOffset(14, BOUNDARY_LINE_START, "", 15, 15,
                           "input", kTodo, kTodo, kOk,
                           "div", kTodo, kTodo, kOk,
                           "editable", kTodo, kTodo, kOk,
-                          "textarea", kTodo, kTodo, kTodo);
+                          "textarea", kTodo, kTodo, kOk);
       testTextAfterOffset(15, BOUNDARY_LINE_START, "", 15, 15,
                           "input", kOk, kOk, kOk,
                           "div", kOk, kOk, kOk,
                           "editable", kOk, kOk, kOk,
-                          "textarea", kTodo, kOk, kTodo);
+                          "textarea", kOk, kOk, kOk);
 
       // BOUNDARY_LINE_END
       testTextAfterOffset(0, BOUNDARY_LINE_END, "", 15, 15,
                           "input", kTodo, kTodo, kOk,
                           "div", kTodo, kTodo, kOk,
                           "editable", kTodo, kTodo, kOk,
                           "textarea", kTodo, kTodo, kOk);
       testTextAfterOffset(1, BOUNDARY_LINE_END, "", 15, 15,
@@ -119,53 +65,23 @@
                           "input", kTodo, kTodo, kOk,
                           "div", kTodo, kTodo, kOk,
                           "editable", kTodo, kTodo, kOk,
                           "textarea", kTodo, kTodo, kOk);
       testTextAfterOffset(15, BOUNDARY_LINE_END, "", 15, 15,
                           "input", kOk, kTodo, kTodo,
                           "div", kOk, kTodo, kTodo,
                           "editable", kOk, kTodo, kTodo,
-                          "textarea", kTodo, kOk, kTodo);
+                          "textarea", kOk, kTodo, kTodo);
 
       ////////////////////////////////////////////////////////////////////////
       // getTextBeforeOffset
 
       var IDs = [ "input", "div", "editable", "textarea" ];
 
-      // BOUNDARY_CHAR
-      testCharBeforeOffset(IDs, 0, "", 0, 0);
-      testCharBeforeOffset(IDs, 1, "h", 0, 1);
-      testCharBeforeOffset(IDs, 14, "n", 13, 14);
-      testCharBeforeOffset(IDs, 15, "d", 14, 15);
-
-      // BOUNDARY_WORD_START
-      testTextBeforeOffset(0, BOUNDARY_WORD_START, "", 0, 0, IDs);
-      testTextBeforeOffset(1, BOUNDARY_WORD_START, "", 0, 0, IDs);
-      testTextBeforeOffset(5, BOUNDARY_WORD_START, "", 0, 0, IDs);
-      testTextBeforeOffset(6, BOUNDARY_WORD_START, "hello ", 0, 6, IDs);
-      testTextBeforeOffset(7, BOUNDARY_WORD_START, "hello ", 0, 6, IDs);
-      testTextBeforeOffset(8, BOUNDARY_WORD_START, "hello ", 0, 6, IDs);
-      testTextBeforeOffset(9, BOUNDARY_WORD_START, "my ", 6, 9, IDs);
-      testTextBeforeOffset(10, BOUNDARY_WORD_START, "my ", 6, 9, IDs);
-      testTextBeforeOffset(14, BOUNDARY_WORD_START, "my ", 6, 9, IDs);
-      testTextBeforeOffset(15, BOUNDARY_WORD_START, "friend", 9, 15, IDs);
-
-      // BOUNDARY_WORD_END
-      testTextBeforeOffset(0, BOUNDARY_WORD_END, "", 0, 0, IDs);
-      testTextBeforeOffset(1, BOUNDARY_WORD_END, "", 0, 0, IDs);
-      testTextBeforeOffset(5, BOUNDARY_WORD_END, "", 0, 0, IDs);
-      testTextBeforeOffset(6, BOUNDARY_WORD_END, "hello", 0, 5, IDs);
-      testTextBeforeOffset(7, BOUNDARY_WORD_END, "hello", 0, 5, IDs);
-      testTextBeforeOffset(8, BOUNDARY_WORD_END, "hello", 0, 5, IDs);
-      testTextBeforeOffset(9, BOUNDARY_WORD_END, " my", 5, 8, IDs);
-      testTextBeforeOffset(10, BOUNDARY_WORD_END, " my", 5, 8, IDs);
-      testTextBeforeOffset(14, BOUNDARY_WORD_END, " my", 5, 8, IDs);
-      testTextBeforeOffset(15, BOUNDARY_WORD_END, " my", 5, 8, IDs);
-
       // BOUNDARY_LINE_START
       testTextBeforeOffset(0, BOUNDARY_LINE_START, "", 0, 0,
                            "input", kOk, kOk, kOk,
                            "div", kOk, kOk, kOk,
                            "editable", kOk, kOk, kOk,
                            "textarea", kOk, kOk, kOk);
       testTextBeforeOffset(1, BOUNDARY_LINE_START, "", 0, 0,
                            "input", kTodo, kOk, kTodo,
@@ -194,82 +110,29 @@
                            "div", kTodo, kOk, kTodo,
                            "editable", kTodo, kOk, kTodo,
                            "textarea", kTodo, kOk, kTodo);
       testTextBeforeOffset(14, BOUNDARY_LINE_END, "", 0, 0,
                            "input", kTodo, kOk, kTodo,
                            "div", kTodo, kOk, kTodo,
                            "editable", kTodo, kOk, kTodo,
                            "textarea", kTodo, kOk, kTodo);
-      testTextBeforeOffset(15, BOUNDARY_LINE_END, "", 0, 0,
-                           "input", kOk, kOk, kOk,
-                           "div", kOk, kOk, kOk,
-                           "editable", kOk, kOk, kOk,
-                           "textarea", kTodo, kOk, kTodo);
+      testTextBeforeOffset(15, BOUNDARY_LINE_END, "", 0, 0, IDs);
 
       ////////////////////////////////////////////////////////////////////////
       // getTextAtOffset
 
       IDs = [ "input", "div", "editable", "textarea" ];
       regularIDs = [ "input", "div", "editable" ];
 
-      // BOUNDARY_CHAR
-
-      testCharAtOffset(IDs, 0, "h", 0, 1);
-      testCharAtOffset(IDs, 1, "e", 1, 2);
-      testCharAtOffset(IDs, 14, "d", 14, 15);
-      testCharAtOffset(regularIDs, 15, "", 15, 15);
-      testCharAtOffset("textarea", 15, "\n", 15, 16);
-      testCharAtOffset("textarea", 16, "", 16, 16);
-
-      // BOUNDARY_WORD_START
-      testTextAtOffset(0, BOUNDARY_WORD_START, "hello ", 0, 6, IDs);
-      testTextAtOffset(1, BOUNDARY_WORD_START, "hello ", 0, 6, IDs);
-      testTextAtOffset(5, BOUNDARY_WORD_START, "hello ", 0, 6, IDs);
-      testTextAtOffset(6, BOUNDARY_WORD_START, "my ", 6, 9, IDs);
-      testTextAtOffset(7, BOUNDARY_WORD_START, "my ", 6, 9, IDs);
-      testTextAtOffset(8, BOUNDARY_WORD_START, "my ", 6, 9, IDs);
-      testTextAtOffset(9, BOUNDARY_WORD_START, "friend", 9, 15, IDs);
-      testTextAtOffset(10, BOUNDARY_WORD_START, "friend", 9, 15, IDs);
-      testTextAtOffset(14, BOUNDARY_WORD_START, "friend", 9, 15, IDs);
-      testTextAtOffset(15, BOUNDARY_WORD_START, "friend", 9, 15, IDs);
-
-      // BOUNDARY_WORD_END
-      testTextAtOffset(0, BOUNDARY_WORD_END, "hello", 0, 5, IDs);
-      testTextAtOffset(1, BOUNDARY_WORD_END, "hello", 0, 5, IDs);
-      testTextAtOffset(5, BOUNDARY_WORD_END, " my", 5, 8, IDs);
-      testTextAtOffset(6, BOUNDARY_WORD_END, " my", 5, 8, IDs);
-      testTextAtOffset(7, BOUNDARY_WORD_END, " my", 5, 8, IDs);
-      testTextAtOffset(8, BOUNDARY_WORD_END, " friend", 8, 15, IDs);
-      testTextAtOffset(9, BOUNDARY_WORD_END, " friend", 8, 15, IDs);
-      testTextAtOffset(10, BOUNDARY_WORD_END, " friend", 8, 15, IDs);
-      testTextAtOffset(14, BOUNDARY_WORD_END, " friend", 8, 15, IDs);
-      testTextAtOffset(15, BOUNDARY_WORD_END, " friend", 8, 15, IDs);
-
       // BOUNDARY_LINE_START
-      testTextAtOffset(0, BOUNDARY_LINE_START, "hello my friend", 0, 15,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kTodo, kOk, kTodo);
-      testTextAtOffset(1, BOUNDARY_LINE_START, "hello my friend", 0, 15,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kTodo, kOk, kTodo);
-      testTextAtOffset(14, BOUNDARY_LINE_START, "hello my friend", 0, 15,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kTodo, kOk, kTodo);
-      testTextAtOffset(15, BOUNDARY_LINE_START, "hello my friend", 0, 15,
-		       "input", kOk, kOk, kOk,
-		       "div", kOk, kOk, kOk,
-		       "editable", kOk, kOk, kOk,
-		       "textarea", kTodo, kOk, kTodo);
+      testTextAtOffset(0, BOUNDARY_LINE_START, "hello my friend", 0, 15, IDs);
+      testTextAtOffset(1, BOUNDARY_LINE_START, "hello my friend", 0, 15, IDs);
+      testTextAtOffset(14, BOUNDARY_LINE_START, "hello my friend", 0, 15, IDs);
+      testTextAtOffset(15, BOUNDARY_LINE_START, "hello my friend", 0, 15, IDs);
 
       // BOUNDARY_LINE_END
       testTextAtOffset(0, BOUNDARY_LINE_END, "hello my friend", 0, 15,
 		       "input", kOk, kOk, kOk,
 		       "div", kOk, kOk, kOk,
 		       "editable", kOk, kOk, kOk,
 		       "textarea", kOk, kOk, kOk);
       testTextAtOffset(1, BOUNDARY_LINE_END, "hello my friend", 0, 15,
deleted file mode 100644
--- a/accessible/tests/mochitest/text/test_whitespaces.html
+++ /dev/null
@@ -1,329 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <title>getText... methods tests on string with whitespaces for plain text containers</title>
-  <link rel="stylesheet" type="text/css"
-        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
-
-  <script type="application/javascript"
-          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="application/javascript"
-          src="../common.js"></script>
-
-  <script type="application/javascript"
-          src="../text.js"></script>
-  <script type="application/javascript">
-    function doTest()
-    {
-      // __B__r__a__v__e__ __S__i__r__ __ __R__o__b__i__n__ __ __ __r__a__n
-      //  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21
-
-      ////////////////////////////////////////////////////////////////////////
-      // characterCount
-
-      testCharacterCount(["input", "div", "editable"], 22);
-      testCharacterCount(["textarea"], 23);
-
-      ////////////////////////////////////////////////////////////////////////
-      // getText
-
-      var IDs = ["input", "div", "editable", "textarea"];
-
-      testText(IDs, 0, 1, "B");
-      testText(IDs, 5, 6, " ");
-      testText(IDs, 9, 11, "  ");
-      testText(IDs, 16, 19, "   ");
-      testText(IDs, 0, 22, "Brave Sir  Robin   ran");
-
-      ////////////////////////////////////////////////////////////////////////
-      // getTextAfterOffset
-
-      var IDs = [ "input", "div", "editable", "textarea" ];
-
-      // BOUNDARY_CHAR
-      testCharAfterOffset(IDs, 0, "r", 1, 2);
-      testCharAfterOffset(IDs, 1, "a", 2, 3);
-      testCharAfterOffset(IDs, 4, " ", 5, 6);
-      testCharAfterOffset(IDs, 5, "S", 6, 7);
-      testCharAfterOffset(IDs, 8, " ", 9, 10);
-      testCharAfterOffset(IDs, 9, " ", 10, 11);
-      testCharAfterOffset(IDs, 10, "R", 11, 12);
-      testCharAfterOffset(IDs, 15, " ", 16, 17);
-      testCharAfterOffset(IDs, 16, " ", 17, 18);
-      testCharAfterOffset(IDs, 17, " ", 18, 19);
-      testCharAfterOffset(IDs, 18, "r", 19, 20);
-
-      // BOUNDARY_WORD_START
-      testTextAfterOffset(0, BOUNDARY_WORD_START, "Sir  ", 6, 11, IDs);
-      testTextAfterOffset(5, BOUNDARY_WORD_START, "Sir  ", 6, 11, IDs);
-      testTextAfterOffset(6, BOUNDARY_WORD_START, "Robin   ", 11, 19, IDs);
-      testTextAfterOffset(9, BOUNDARY_WORD_START, "Robin   ", 11, 19, IDs);
-      testTextAfterOffset(10, BOUNDARY_WORD_START, "Robin   ", 11, 19, IDs);
-      testTextAfterOffset(11, BOUNDARY_WORD_START, "ran", 19, 22,
-                          "input", kOk, kOk, kOk,
-                          "div", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "textarea", kTodo, kOk, kTodo);
-      testTextAfterOffset(16, BOUNDARY_WORD_START, "ran", 19, 22,
-                          "input", kOk, kOk, kOk,
-                          "div", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "textarea", kTodo, kOk, kTodo);
-      testTextAfterOffset(18, BOUNDARY_WORD_START, "ran", 19, 22,
-                          "input", kOk, kOk, kOk,
-                          "div", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "textarea", kTodo, kOk, kTodo);
-      testTextAfterOffset(19, BOUNDARY_WORD_START, "", 22, 22,
-                          "input", kOk, kOk, kOk,
-                          "div", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "textarea", kOk, kTodo, kTodo);
-
-      // BOUNDARY_WORD_END
-      testTextAfterOffset(0, BOUNDARY_WORD_END, " Sir", 5, 9, IDs);
-      testTextAfterOffset(4, BOUNDARY_WORD_END, " Sir", 5, 9, IDs);
-      testTextAfterOffset(5, BOUNDARY_WORD_END, " Sir", 5, 9, IDs);
-      testTextAfterOffset(6, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
-      testTextAfterOffset(8, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
-      testTextAfterOffset(9, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
-      testTextAfterOffset(10, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
-      testTextAfterOffset(11, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
-      testTextAfterOffset(15, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
-      testTextAfterOffset(16, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
-      testTextAfterOffset(17, BOUNDARY_WORD_END, "", 22, 22,
-                          "input", kOk, kOk, kOk,
-                          "div", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "textarea", kTodo, kOk, kTodo);
-      testTextAfterOffset(18, BOUNDARY_WORD_END, "", 22, 22,
-                          "input", kOk, kOk, kOk,
-                          "div", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "textarea", kTodo, kOk, kTodo);
-      testTextAfterOffset(19, BOUNDARY_WORD_END, "", 22, 22,
-                          "input", kOk, kOk, kOk,
-                          "div", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "textarea", kTodo, kOk, kTodo);
-      testTextAfterOffset(21, BOUNDARY_WORD_END, "", 22, 22,
-                          "input", kOk, kOk, kOk,
-                          "div", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "textarea", kTodo, kOk, kTodo);
-      testTextAfterOffset(22, BOUNDARY_WORD_END, "", 22, 22,
-                          "input", kOk, kOk, kOk,
-                          "div", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "textarea", kOk, kTodo, kTodo);
-
-      ////////////////////////////////////////////////////////////////////////
-      // getTextBeforeOffset
-
-      var IDs = [ "input", "div", "editable", "textarea" ];
-
-      // BOUNDARY_CHAR
-      testCharBeforeOffset(IDs, 0, "", 0, 0);
-      testCharBeforeOffset(IDs, 1, "B", 0, 1);
-      testCharBeforeOffset(IDs, 6, " ", 5, 6);
-      testCharBeforeOffset(IDs, 10, " ", 9, 10);
-      testCharBeforeOffset(IDs, 11, " ", 10, 11);
-      testCharBeforeOffset(IDs, 17, " ", 16, 17);
-      testCharBeforeOffset(IDs, 19, " ", 18, 19);
-
-      // BOUNDARY_WORD_START
-      testTextBeforeOffset(0, BOUNDARY_WORD_START, "", 0, 0, IDs);
-      testTextBeforeOffset(1, BOUNDARY_WORD_START, "", 0, 0, IDs);
-      testTextBeforeOffset(5, BOUNDARY_WORD_START, "", 0, 0, IDs);
-      testTextBeforeOffset(6, BOUNDARY_WORD_START, "Brave ", 0, 6, IDs);
-      testTextBeforeOffset(9, BOUNDARY_WORD_START, "Brave ", 0, 6, IDs);
-      testTextBeforeOffset(10, BOUNDARY_WORD_START, "Brave ", 0, 6, IDs);
-      testTextBeforeOffset(11, BOUNDARY_WORD_START, "Sir  ", 6, 11, IDs);
-      testTextBeforeOffset(15, BOUNDARY_WORD_START, "Sir  ", 6, 11, IDs);
-      testTextBeforeOffset(16, BOUNDARY_WORD_START, "Sir  ", 6, 11, IDs);
-      testTextBeforeOffset(17, BOUNDARY_WORD_START, "Sir  ", 6, 11, IDs);
-      testTextBeforeOffset(18, BOUNDARY_WORD_START, "Sir  ", 6, 11, IDs);
-      testTextBeforeOffset(19, BOUNDARY_WORD_START, "Robin   ", 11, 19, IDs);
-      testTextBeforeOffset(20, BOUNDARY_WORD_START, "Robin   ", 11, 19, IDs);
-      testTextBeforeOffset(21, BOUNDARY_WORD_START, "Robin   ", 11, 19, IDs);
-
-      // BOUNDARY_WORD_END
-      testTextBeforeOffset(0, BOUNDARY_WORD_END, "", 0, 0, IDs);
-      testTextBeforeOffset(1, BOUNDARY_WORD_END, "", 0, 0, IDs);
-      testTextBeforeOffset(4, BOUNDARY_WORD_END, "", 0, 0, IDs);
-      testTextBeforeOffset(5, BOUNDARY_WORD_END, "", 0, 0, IDs);
-      testTextBeforeOffset(6, BOUNDARY_WORD_END, "Brave", 0, 5, IDs);
-      testTextBeforeOffset(7, BOUNDARY_WORD_END, "Brave", 0, 5, IDs);
-      testTextBeforeOffset(8, BOUNDARY_WORD_END, "Brave", 0, 5, IDs);
-      testTextBeforeOffset(9, BOUNDARY_WORD_END, "Brave", 0, 5, IDs);
-      testTextBeforeOffset(10, BOUNDARY_WORD_END, " Sir", 5, 9, IDs);
-      testTextBeforeOffset(11, BOUNDARY_WORD_END, " Sir", 5, 9, IDs);
-      testTextBeforeOffset(15, BOUNDARY_WORD_END, " Sir", 5, 9, IDs);
-      testTextBeforeOffset(16, BOUNDARY_WORD_END, " Sir", 5, 9, IDs);
-      testTextBeforeOffset(17, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
-      testTextBeforeOffset(18, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
-      testTextBeforeOffset(19, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
-      testTextBeforeOffset(21, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
-      testTextBeforeOffset(22, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
-
-      ////////////////////////////////////////////////////////////////////////
-      // getTextAtOffset
-
-      // BOUNDARY_CHAR
-      testTextAtOffset(0, BOUNDARY_CHAR, "B", 0, 1,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(1, BOUNDARY_CHAR, "r", 1, 2,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(5, BOUNDARY_CHAR, " ", 5, 6,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(9, BOUNDARY_CHAR, " ", 9, 10,
-                        "input", kOk, kOk, kOk,
-                        "div", kOk, kOk, kOk,
-                        "editable", kOk, kOk, kOk,
-                        "textarea", kOk, kOk, kOk);
-      testTextAtOffset(10, BOUNDARY_CHAR, " ", 10, 11,
-                        "input", kOk, kOk, kOk,
-                        "div", kOk, kOk, kOk,
-                        "editable", kOk, kOk, kOk,
-                        "textarea", kOk, kOk, kOk);
-      testTextAtOffset(17, BOUNDARY_CHAR, " ", 17, 18,
-                        "input", kOk, kOk, kOk,
-                        "div", kOk, kOk, kOk,
-                        "editable", kOk, kOk, kOk,
-                        "textarea", kOk, kOk, kOk);
-
-      // BOUNDARY_WORD_START
-      testTextAtOffset(0, BOUNDARY_WORD_START, "Brave ", 0, 6,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(5, BOUNDARY_WORD_START, "Brave ", 0, 6,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(6, BOUNDARY_WORD_START, "Sir  ", 6, 11,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(8, BOUNDARY_WORD_START, "Sir  ", 6, 11,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(9, BOUNDARY_WORD_START, "Sir  ", 6, 11,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(10, BOUNDARY_WORD_START, "Sir  ", 6, 11,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(11, BOUNDARY_WORD_START, "Robin   ", 11, 19,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(15, BOUNDARY_WORD_START, "Robin   ", 11, 19,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(16, BOUNDARY_WORD_START, "Robin   ", 11, 19,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(17, BOUNDARY_WORD_START, "Robin   ", 11, 19,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(18, BOUNDARY_WORD_START, "Robin   ", 11, 19,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kOk, kOk, kOk);
-      testTextAtOffset(19, BOUNDARY_WORD_START, "ran", 19, 22,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kTodo, kOk, kTodo);
-      testTextAtOffset(21, BOUNDARY_WORD_START, "ran", 19, 22,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kTodo, kOk, kTodo);
-      testTextAtOffset(22, BOUNDARY_WORD_START, "ran", 19, 22,
-                       "input", kOk, kOk, kOk,
-                       "div", kOk, kOk, kOk,
-                       "editable", kOk, kOk, kOk,
-                       "textarea", kTodo, kOk, kTodo);
-
-      // BOUNDARY_WORD_END
-      testTextAtOffset(0, BOUNDARY_WORD_END, "Brave", 0, 5, IDs);
-      testTextAtOffset(4, BOUNDARY_WORD_END, "Brave", 0, 5, IDs);
-      testTextAtOffset(5, BOUNDARY_WORD_END, " Sir", 5, 9, IDs);
-      testTextAtOffset(6, BOUNDARY_WORD_END, " Sir", 5, 9, IDs);
-      testTextAtOffset(8, BOUNDARY_WORD_END, " Sir", 5, 9, IDs);
-      testTextAtOffset(9, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
-      testTextAtOffset(10, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
-      testTextAtOffset(11, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
-      testTextAtOffset(15, BOUNDARY_WORD_END, "  Robin", 9, 16, IDs);
-      testTextAtOffset(16, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
-      testTextAtOffset(17, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
-      testTextAtOffset(18, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
-      testTextAtOffset(19, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
-      testTextAtOffset(20, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
-      testTextAtOffset(21, BOUNDARY_WORD_END, "   ran", 16, 22, IDs);
-      testTextAtOffset(22, BOUNDARY_WORD_END, "   ran", 16, 22, ["input", "div", "editable"]);
-      testTextAtOffset(22, BOUNDARY_WORD_END, "   ran\n", 16, 23, [ "textarea" ]);
-
-      SimpleTest.finish();
-    }
-
-    SimpleTest.waitForExplicitFinish();
-    addA11yLoadEvent(doTest);
-  </script>
-</head>
-<body>
-
-  <a target="_blank"
-     title="getText... methods tests on string with whitespaces for plain text containers"
-     href="https://bugzilla.mozilla.org/show_bug.cgi?id=610568">
-    Bug 610568
-  </a>
-  <a target="_blank"
-     title="getTextAtOffset for word boundaries: beginning of a new life"
-     href="https://bugzilla.mozilla.org/show_bug.cgi?id=853340">
-    Bug 853340
-  </a>
-  <a target="_blank"
-     title="getTextBeforeOffset for word boundaries: evolving"
-     href="https://bugzilla.mozilla.org/show_bug.cgi?id=855732">
-    Bug 855732
-  </a>
-  <p id="display"></p>
-  <div id="content" style="display: none"></div>
-  <pre id="test">
-  <input id="input" value="Brave Sir  Robin   ran"/>
-  <div id="div">Brave Sir  Robin   ran</div>
-  <div id="editable" contenteditable="true">Brave Sir  Robin   ran</div>
-  <textarea id="textarea" cols="300">Brave Sir  Robin   ran</textarea>
-  </pre>
-
-</body>
-</html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/text/test_wordboundary.html
@@ -0,0 +1,284 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Word boundary text tests</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../text.js"></script>
+
+  <script type="application/javascript">
+    function doTest()
+    {
+      // "hello"
+      // __h__e__l__l__o__
+      //  0  1  2  3  4  5
+      var ids = [ "i1", "d1", "e1", "t1" ];
+      testTextBeforeOffset(ids, BOUNDARY_WORD_START,
+                           [ [ 0, 5, "", 0, 0 ] ]);
+      testTextBeforeOffset(ids, BOUNDARY_WORD_END,
+                           [ [ 0, 5, "", 0, 0 ] ]);
+
+      testTextAtOffset(ids, BOUNDARY_WORD_START,
+                       [ [ 0, 5, "hello", 0, 5 ] ]);
+      testTextAtOffset(ids, BOUNDARY_WORD_END,
+                       [ [ 0, 5, "hello", 0, 5 ] ]);
+
+      testTextAfterOffset(ids, BOUNDARY_WORD_START,
+                          [ [ 0, 5, "", 5, 5 ] ]);
+      testTextAfterOffset(ids, BOUNDARY_WORD_END,
+                          [ [ 0, 5, "", 5, 5 ] ]);
+
+      // "hello "
+      // __h__e__l__l__o__ __
+      //  0  1  2  3  4  5  6
+      var ids = [ "i2", "d2", "e2", "t2" ];
+      testTextBeforeOffset(ids, BOUNDARY_WORD_START,
+                           [ [ 0, 6, "", 0, 0 ] ]);
+      testTextBeforeOffset(ids, BOUNDARY_WORD_END,
+                           [ [ 0, 5, "", 0, 0 ],
+                             [ 6, 6, "hello", 0, 5,
+                               [ [6, "e2", kTodo, kOk, kTodo ] ]
+                             ]
+                           ]);
+
+      testTextAtOffset(ids, BOUNDARY_WORD_START,
+                       [ [ 0, 6, "hello ", 0, 6 ] ]);
+      testTextAtOffset(ids, BOUNDARY_WORD_END,
+                       [ [ 0, 4, "hello", 0, 5 ],
+                         [ 5, 6, " ", 5, 6,
+                           [ [ 5, "e2", kTodo, kTodo, kOk ],
+                             [ 6, "e2", kTodo, kTodo, kOk ] ]
+                         ]
+                       ]);
+
+      testTextAfterOffset(ids, BOUNDARY_WORD_START,
+                          [ [ 0, 6, "", 6, 6 ] ]);
+      testTextAfterOffset(ids, BOUNDARY_WORD_END,
+                          [ [ 0, 5, " ", 5, 6,
+                              [ [ 5, "e2", kTodo, kTodo, kOk ] ]
+                            ],
+                            [ 6, 6, "", 6, 6 ]
+                          ]);
+
+      // "hello all"
+      // __h__e__l__l__o__ __a__l__l__
+      //  0  1  2  3  4  5  6  7  8  9
+      ids = [ "i6", "d6", "e6", "t6" ];
+      testTextBeforeOffset(ids, BOUNDARY_WORD_START,
+                           [ [ 0, 5, "", 0, 0 ],
+                             [ 6, 9, "hello ", 0, 6 ]]);
+      testTextBeforeOffset(ids, BOUNDARY_WORD_END,
+                           [ [ 0, 5, "", 0, 0 ],
+                             [ 6, 9, "hello", 0, 5 ] ]);
+
+      testTextAtOffset(ids, BOUNDARY_WORD_START,
+                       [ [ 0, 5, "hello ", 0, 6 ],
+                         [ 6, 9, "all", 6, 9 ] ]);
+      testTextAtOffset(ids, BOUNDARY_WORD_END,
+                       [ [ 0, 4, "hello", 0, 5 ],
+                         [ 5, 9, " all", 5, 9 ] ]);
+
+      testTextAfterOffset(ids, BOUNDARY_WORD_START,
+                          [ [ 0, 5, "all", 6, 9 ],
+                            [ 6, 9, "", 9, 9 ] ]);
+      testTextAfterOffset(ids, BOUNDARY_WORD_END,
+                          [ [ 0, 5, " all", 5, 9 ],
+                            [ 6, 9, "", 9, 9 ] ]);
+
+      // "hello my friend"
+      // __h__e__l__l__o__ __m__y__ __f__r__i__e__n__d__
+      //  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
+      ids = [ "i7", "d7", "e7", "t7" ];
+      testTextBeforeOffset(ids, BOUNDARY_WORD_START,
+                           [ [ 0, 5, "", 0, 0 ],
+                             [ 6, 8, "hello ", 0, 6 ],
+                             [ 9, 15, "my ", 6, 9 ] ]);
+      testTextBeforeOffset(ids, BOUNDARY_WORD_END,
+                           [ [ 0, 5, "", 0, 0 ],
+                             [ 6, 8, "hello", 0, 5 ],
+                             [ 9, 15, " my", 5, 8 ] ]);
+
+      testTextAtOffset(ids, BOUNDARY_WORD_START,
+                       [ [ 0, 5, "hello ", 0, 6 ],
+                         [ 6, 8, "my ", 6, 9 ],
+                         [ 9, 15, "friend", 9, 15] ]);
+      testTextAtOffset(ids, BOUNDARY_WORD_END,
+                       [ [ 0, 4, "hello", 0, 5 ],
+                         [ 5, 7, " my", 5, 8 ],
+                         [ 8, 15, " friend", 8, 15] ]);
+
+      testTextAfterOffset(ids, BOUNDARY_WORD_START,
+                          [ [ 0, 5, "my ", 6, 9 ],
+                            [ 6, 8, "friend", 9, 15 ],
+                            [ 9, 15, "", 15, 15 ] ]);
+      testTextAfterOffset(ids, BOUNDARY_WORD_END,
+                          [ [ 0, 5, " my", 5, 8 ],
+                            [ 6, 8, " friend", 8, 15 ],
+                            [ 9, 15, "", 15, 15 ] ]);
+
+      // "Brave Sir  Robin   ran"
+      // __B__r__a__v__e__ __S__i__r__ __ __R__o__b__i__n__ __ __ __r__a__n__
+      //  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22
+      ids = [ "i8", "d8", "e8", "t8" ];
+      testTextBeforeOffset(ids, BOUNDARY_WORD_START,
+                           [ [ 0, 5, "", 0, 0 ],
+                             [ 6, 10, "Brave ", 0, 6 ],
+                             [ 11, 18, "Sir  ", 6, 11 ],
+                             [ 19, 22, "Robin   ", 11, 19 ] ]);
+      testTextBeforeOffset(ids, BOUNDARY_WORD_END,
+                           [ [ 0, 5, "", 0, 0 ],
+                             [ 6, 9, "Brave", 0, 5 ],
+                             [ 10, 16, " Sir", 5, 9 ],
+                             [ 17, 22, "  Robin", 9, 16 ] ]);
+
+      testTextAtOffset(ids, BOUNDARY_WORD_START,
+                       [ [ 0, 5, "Brave ", 0, 6 ],
+                         [ 6, 10, "Sir  ", 6, 11 ],
+                         [ 11, 18, "Robin   ", 11, 19 ],
+                         [ 19, 22, "ran", 19, 22 ] ]);
+      testTextAtOffset(ids, BOUNDARY_WORD_END,
+                       [ [ 0, 4, "Brave", 0, 5 ],
+                         [ 5, 8, " Sir", 5, 9 ],
+                         [ 9, 15, "  Robin", 9, 16 ],
+                         [ 16, 22, "   ran", 16, 22 ] ]);
+
+      testTextAfterOffset(ids, BOUNDARY_WORD_START,
+                          [ [ 0, 5, "Sir  ", 6, 11 ],
+                            [ 6, 10, "Robin   ", 11, 19 ],
+                            [ 11, 18, "ran", 19, 22 ],
+                            [ 19, 22, "", 22, 22 ] ]);
+      testTextAfterOffset(ids, BOUNDARY_WORD_END,
+                          [ [ 0, 5, " Sir", 5, 9 ],
+                            [ 6, 9, "  Robin", 9, 16 ],
+                            [ 10, 16, "   ran", 16, 22 ],
+                            [ 17, 22, "", 22, 22 ] ]);
+
+      // 'oneword
+      // '
+      // 'two words
+      // '
+      // __o__n__e__w__o__r__d__\n
+      //  0  1  2  3  4  5  6  7
+      // __\n
+      //  8
+      // __t__w__o__ __w__o__r__d__s__\n__
+      //  9 10 11 12 13 14 15 16 17 18  19
+
+      ids = ["ml_div1", "ml_divbr1", "ml_ediv1", "ml_edivbr1", "ml_t1"];
+      testTextBeforeOffset(ids, BOUNDARY_WORD_START,
+                           [ [ 0, 8, "", 0, 0 ],
+                             [ 9, 12, "oneword\n\n", 0, 9 ],
+                             [ 13, 19, "two ", 9, 13 ] ]);
+      testTextBeforeOffset(ids, BOUNDARY_WORD_END,
+                           [ [ 0, 7, "", 0, 0 ],
+                             [ 8, 12, "oneword", 0, 7,
+                               [ [ 8, "ml_divbr1", kTodo, kOk, kTodo ],
+                                 [ 8, "ml_edivbr1", kTodo, kOk, kTodo ],
+                                 [ 9, "ml_divbr1", kTodo, kOk, kTodo ],
+                                 [ 9, "ml_edivbr1", kTodo, kOk, kTodo ] ] ],
+                             [ 13, 18, "\n\ntwo", 7, 12 ],
+                             [ 19, 19, " words", 12, 18,
+                               [ [ 19, "ml_divbr1", kTodo, kTodo, kTodo, ],
+                                 [ 19, "ml_edivbr1", kTodo, kTodo, kTodo, ] ] ]
+                           ] );
+
+      testTextAtOffset(ids, BOUNDARY_WORD_START,
+                       [ [ 0, 8, "oneword\n\n", 0, 9,
+                           [ [ 7, "ml_divbr1", kTodo, kTodo, kTodo ],
+                             [ 7, "ml_edivbr1", kTodo, kTodo, kTodo ],
+                             [ 8, "ml_divbr1", kTodo, kTodo, kTodo ],
+                             [ 8, "ml_edivbr1", kTodo, kTodo, kTodo ] ] ],
+                         [ 9, 12, "two ", 9, 13 ],
+                         [ 13, 19, "words\n", 13, 19 ] ]);
+      testTextAtOffset(ids, BOUNDARY_WORD_END,
+                       [ [ 0, 6, "oneword", 0, 7 ],
+                         [ 7, 11, "\n\ntwo", 7, 12 ],
+                         [ 12, 17, " words", 12, 18 ],
+                         [ 18, 19, "\n", 18, 19,
+                           [ [ 18, "ml_divbr1", kTodo, kTodo, kOk ],
+                             [ 18, "ml_edivbr1", kTodo, kTodo, kOk ],
+                             [ 19, "ml_divbr1", kTodo, kTodo, kOk ],
+                             [ 19, "ml_edivbr1", kTodo, kTodo, kOk ] ] ] ]);
+
+      testTextAfterOffset(ids, BOUNDARY_WORD_START,
+                           [ [ 0, 8, "two ", 9, 13,
+                               [ [ 7, "ml_divbr1", kTodo, kTodo, kTodo ],
+                                 [ 7, "ml_edivbr1", kTodo, kTodo, kTodo ],
+                                 [ 8, "ml_divbr1", kTodo, kTodo, kTodo ],
+                                 [ 8, "ml_edivbr1", kTodo, kTodo, kTodo ] ] ],
+                             [ 9, 12, "words\n", 13, 19 ],
+                             [ 13, 19, "", 19, 19 ] ]);
+      testTextAfterOffset(ids, BOUNDARY_WORD_END,
+                           [ [ 0, 7, "\n\ntwo", 7, 12 ],
+                             [ 8, 12, " words", 12, 18 ],
+                             [ 13, 18, "\n", 18, 19,
+                               [ [ 18, "ml_divbr1", kTodo, kTodo, kOk ],
+                                 [ 18, "ml_edivbr1", kTodo, kTodo, kOk ] ] ],
+                             [ 19, 19, "", 19, 19 ] ]);
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <input id="i1" value="hello"/>
+  <div id="d1">hello</div>
+  <div id="e1" contenteditable="true">hello</div>
+  <textarea id="t1">hello</textarea>
+
+  <input id="i2" value="hello "/>
+  <pre><div id="d2">hello </div></pre>
+  <div id="e2" contenteditable="true">hello </div>
+  <textarea id="t2">hello </textarea>
+
+  <input id="i6" value="hello all"/>
+  <div id="d6">hello all</div>
+  <div id="e6" contenteditable="true">hello all</div>
+  <textarea id="t6">hello all</textarea>
+
+  <input id="i7" value="hello my friend"/>
+  <div id="d7">hello my friend</div>
+  <div id="e7" contenteditable="true">hello my friend</div>
+  <textarea id="t7">hello my friend</textarea>
+
+  <input id="i8" value="Brave Sir  Robin   ran"/>
+  <pre>
+    <div id="d8">Brave Sir  Robin   ran</div>
+    <div id="e8" contenteditable="true">Brave Sir  Robin   ran</div>
+  </pre>
+  <textarea id="t8" cols="300">Brave Sir  Robin   ran</textarea>
+
+  <pre>
+<div id="ml_div1">oneword
+
+two words
+</div>
+<div id="ml_divbr1">oneword<br/><br/>two words<br/></div>
+<div id="ml_ediv1" contenteditable="true">oneword
+
+two words
+</div>
+<div id="ml_edivbr1" contenteditable="true">oneword<br/><br/>two words<br/></div>
+<textarea id="ml_t1" cols="300">oneword
+
+two words
+</textarea>
+  </pre>
+
+</body>
+</html>
--- a/accessible/tests/mochitest/tree/test_txtctrl.html
+++ b/accessible/tests/mochitest/tree/test_txtctrl.html
@@ -50,19 +50,16 @@
       testAccessibleTree("txc3", accTree);
 
       // textarea
       accTree = {
         role: ROLE_ENTRY,
         children: [
           {
             role: ROLE_TEXT_LEAF // hello1\nhello2 text
-          },
-          {
-            role: ROLE_WHITESPACE
           }
         ]
       };
 
       testAccessibleTree("txc4", accTree);
 
       // input@type="password"
       accTree = {
--- a/addon-sdk/source/doc/dev-guide-source/cfx-tool.md
+++ b/addon-sdk/source/doc/dev-guide-source/cfx-tool.md
@@ -15,22 +15,79 @@ development servers as well as testing, 
 "Options" are global options applicable to the tool itself or to all
 commands (for example `--help`). `cfx` supports the following global options:
 
 <pre>
   -h, --help        - show a help message and exit
   -v, --verbose     - enable lots of output
 </pre>
 
-"Command-specific options" are only
-applicable to a subset of the commands.
+"Command-specific options" are documented alongside the commands.
+
+There are five supported cfx commands:
+
+<table>
+  <colgroup>
+    <col width="10%">
+    <col width="90%">
+  </colgroup>
+
+  <tr>
+    <td>
+      <a href="dev-guide/cfx-tool.html#cfx-docs"><code>cfx docs</code></a>
+    </td>
+    <td>
+      Display the documentation for the SDK.
+    </td>
+  </tr>
+
+  <tr>
+    <td>
+      <a href="dev-guide/cfx-tool.html#cfx-init"><code>cfx init</code></a>
+    </td>
+    <td>
+      Create a skeleton add-on as a starting point for your own add-on.
+    </td>
+  </tr>
 
-## Supported Commands ##
+  <tr>
+    <td>
+      <a href="dev-guide/cfx-tool.html#cfx-run"><code>cfx run</code></a>
+    </td>
+    <td>
+      Launch an instance of Firefox with your add-on installed.
+    </td>
+  </tr>
+
+  <tr>
+    <td>
+      <a href="dev-guide/cfx-tool.html#cfx-test"><code>cfx test</code></a>
+    </td>
+    <td>
+      Runs your add-on's unit tests.
+    </td>
+  </tr>
 
-### cfx docs ###
+  <tr>
+    <td>
+      <a href="dev-guide/cfx-tool.html#cfx-xpi"><code>cfx xpi</code></a>
+    </td>
+    <td>
+      Package your add-on as an <a href="https://developer.mozilla.org/en/XPI">XPI</a>
+      file, which is the install file format for Firefox add-ons.
+    </td>
+  </tr>
+
+</table>
+
+There are also a number of
+[internal commands](dev-guide/cfx-tool.html#internal-commands),
+which are more likely to be useful to SDK developers than to add-on developers.
+
+## <a name="cfx-docs">cfx docs</a> ##
 
 This command displays the documentation for the SDK. The documentation is
 shipped with the SDK in [Markdown](http://daringfireball.net/projects/markdown/)
 format. The first time this command is executed, and any time after the
 Markdown files on disk have changed, `cfx docs` will generate a set of HTML
 pages from them and launch a web browser to display them. If the Markdown files
 haven't changed, `cfx docs` just launches a browser initialized to the set of
 generated pages.
@@ -41,17 +98,18 @@ specify the file as an argument. For exa
 <pre>
   cfx docs doc/dev-guide-source/addon-development/cfx-tool.md 
 </pre>
 
 This command will regenerate only the HTML page you're reading.
 This is useful if you're iteratively editing a single file, and don't want to wait for cfx to
 regenerate the complete documentation tree.
 
-### cfx init ####
+## <a name="cfx-init">cfx init</a> ##
+
 Create a new directory called "my-addon", change into it, and run `cfx init`.
 
 This command will create an skeleton add-on, as a starting point for your
 own add-on development, with the following file structure:
 
 <ul class="tree">
   <li>my-addon
     <ul>
@@ -68,24 +126,23 @@ own add-on development, with the followi
       <ul><li>test-main.js</li></ul>
     </li>
     </ul>
   </li>
 </ul>
 
 <div style="clear:both"></div>
 
-### cfx run ###
-
+## <a name="cfx-run">cfx run</a> ##
 This command is used to run the add-on. Called with no options it looks for a
 file called `package.json` in the current directory, loads the corresponding
 add-on, and runs it under the version of Firefox it finds in the platform's
 default install path.
 
-#### Supported Options #####
+### Supported Options ####
 
 You can point `cfx run` at a different `package.json` file using the
 `--pkgdir` option, and pass arguments to your add-on using the
 `--static-args` option.
 
 You can specify a different version of the
 <a href="dev-guide/glossary.html#host-application">host application</a>
 using the `--binary` option, passing in the path to the application binary to
@@ -185,17 +242,17 @@ See <a href="dev-guide/cfx-tool.html#pro
   <td>
     <a href="dev-guide/cfx-tool.html#arguments">Pass arguments to your add-on</a>,
     in JSON format.
   </td>
 </tr>
 
 </table>
 
-#### Experimental Options ####
+### Experimental Options ###
 
 <table>
 <colgroup>
 <col width="30%">
 <col width="70%">
 </colgroup>
 
 <tr>
@@ -230,31 +287,50 @@ To launch the application, enter the fol
     <p>This enables you to run the add-on without going through
     <code>cfx</code>, which might be useful if you want to run it
     inside a debugger like GDB.</p>
   </td>
 </tr>
 
 <tr>
   <td>
+    <code>-o, --overload-modules</code>
+  </td>
+  <td>
+    <p>In early versions of the SDK, the SDK modules used by an add-on
+    were themselves included in the add-on. The SDK modules now ship as
+    part of Firefox. From Firefox 21 onwards, SDK add-ons built with
+    SDK 1.14 or higher will use the SDK modules that are built into Firefox,
+    even if the add-on includes its own copies of the SDK modules.</p>
+    <p>Use this flag to reverse that behavior: if this flag is set and
+    the add-on includes its own copies of the SDK modules, then the add-on
+    will use the SDK modules in the add-on, not the ones built into Firefox.</p>
+    <p>This flag is particularly useful for SDK developers or people working with
+    the development version of the SDK, who may want to run an add-on using newer
+    versions of the modules than than those shipping in Firefox.</p>
+  </td>
+</tr>
+
+<tr>
+  <td>
     <code>--templatedir=TEMPLATEDIR</code>
   </td>
   <td>
     The <code>cfx run</code> command constructs the add-on using a extension
     template which you can find under the SDK root, in
     <code>app-extension</code>.
     Use the <code>--templatedir</code> option to specify a different template.
     TEMPLATEDIR may be specified as a full path or as a path relative to the
     current directory.
   </td>
 </tr>
 
 </table>
 
-#### Internal Options ####
+### Internal Options ###
 
 <table>
 <colgroup>
 <col width="30%">
 <col width="70%">
 </colgroup>
 
 <tr>
@@ -286,18 +362,17 @@ To launch the application, enter the fol
     <a href="dev-guide/guides/program-id.html">signing keys</a>.
     KEYDIR may be specified as a full path or as a path relative to the
     current directory.
   </td>
 </tr>
 
 </table>
 
-### cfx test ###
-
+## <a name="cfx-test">cfx test</a> ##
 Run available tests for the specified package.
 
 <span class="aside">Note the hyphen after "test" in the module name.
 `cfx test` will include a module called "test-myCode.js", but will exclude
 modules called "test_myCode.js" or "testMyCode.js".</span>
 
 Called with no options this command will look for a file called `package.json`
 in the current directory. If `package.json` exists, `cfx` will load the
@@ -305,17 +380,17 @@ corresponding add-on, load from the `tes
 any modules that start with the word `test-` and run the unit tests
 they contain.
 
 See the
 [tutorial on unit testing](dev-guide/tutorials/unit-testing.html) and the
 [reference documentation for the `assert` module](modules/sdk/test/assert.html)
 for details.
 
-#### Supported Options #####
+### Supported Options ###
 
 As with `cfx run` you can use options to control which host application binary
 version to use, and to select a profile.
 
 You can also control which tests are run: you
 can test dependent packages, filter the tests by name and run tests multiple
 times.
 
@@ -411,17 +486,17 @@ times.
   </td>
   <td>
     Execute tests ITERATIONS number of times.
   </td>
 </tr>
 
 </table>
 
-#### Experimental Options ####
+### Experimental Options ###
 
 <table>
 <colgroup>
 <col width="30%">
 <col width="70%">
 </colgroup>
 
 <tr>
@@ -456,26 +531,36 @@ To launch the application, enter the fol
     <p>This enables you to run the add-on without going through
     <code>cfx</code>, which might be useful if you want to run it
     inside a debugger like GDB.</p>
   </td>
 </tr>
 
 <tr>
   <td>
-    <code>--use-server</code>
+    <code>-o, --overload-modules</code>
   </td>
   <td>
-    Run tests using a server previously started with <code>cfx develop</code>.
+    <p>In early versions of the SDK, the SDK modules used by an add-on
+    were themselves included in the add-on. The SDK modules now ship as
+    part of Firefox. From Firefox 21 onwards, SDK add-ons built with
+    SDK 1.14 or higher will use the SDK modules that are built into Firefox,
+    even if the add-on includes its own copies of the SDK modules.</p>
+    <p>Use this flag to reverse that behavior: if this flag is set and
+    the add-on includes its own copies of the SDK modules, then the add-on
+    will use the SDK modules in the add-on, not the ones built into Firefox.</p>
+    <p>This flag is particularly useful for SDK developers or people working with
+    the development version of the SDK, who may want to run an add-on using newer
+    versions of the modules than than those shipping in Firefox.</p>
   </td>
 </tr>
 
 </table>
 
-#### Internal Options ####
+### Internal Options ###
 
 <table>
 <colgroup>
 <col width="30%">
 <col width="70%">
 </colgroup>
 
 <tr>
@@ -540,29 +625,28 @@ To launch the application, enter the fol
   <td>
     Name of package containing test runner program. Defaults to
     <code>test-harness</code>.
   </td>
 </tr>
 
 </table>
 
-### cfx xpi ###
-
+## <a name="cfx-xpi">cfx xpi</a> ##
 This tool is used to package your add-on as an
 [XPI](https://developer.mozilla.org/en/XPI) file, which is the install file
 format for Mozilla add-ons.
 
 Called with no options, this command looks for a file called `package.json` in
 the current directory and creates the corresponding XPI file.
 
 Once you have built an XPI file you can distribute your add-on by submitting
 it to [addons.mozilla.org](http://addons.mozilla.org).
 
-#### updateURL and updateLink ####
+### updateURL and updateLink ###
 
 If you choose to host the XPI yourself you should enable the host application
 to find new versions of your add-on.
 
 To do this, include a URL in the XPI called the
 [updateURL](https://developer.mozilla.org/en/install_manifests#updateURL): the
 host application will go here to get information about updates. At the
 `updateURL` you host a file in the
@@ -592,17 +676,17 @@ So if we run the following command:
 
 `cfx` will create two files:
 
 * an XPI file which embeds
 `https://example.com/addon/update_rdf` as the value of `updateURL`
 * an RDF file which embeds `https://example.com/addon/latest` as the value of
 `updateLink`.
 
-#### Supported Options ####
+### Supported Options ###
 
 As with `cfx run` you can point `cfx` at a different `package.json` file using
 the `--pkgdir` option. You can also embed arguments in the XPI using the
 `--static-args` option: if you do this the arguments will be passed to your
 add-on whenever it is run.
 
 <table>
 <colgroup>
@@ -670,17 +754,17 @@ add-on whenever it is run.
   <td>
     Embed the URL supplied in UPDATE_URL in the XPI file, as the value
     of <code>updateURL</code>.
   </td>
 </tr>
 
 </table>
 
-#### Experimental Options ####
+### Experimental Options ###
 
 <table>
 <colgroup>
 <col width="50%">
 <col width="50%">
 </colgroup>
 
 <tr>
@@ -694,17 +778,17 @@ add-on whenever it is run.
     Use the <code>--templatedir</code> option to specify a different template.
     TEMPLATEDIR may be specified as a full path or as a path relative to the
     current directory.
   </td>
 </tr>
 
 </table>
 
-#### Internal Options ####
+### Internal Options ###
 
 <table>
 <colgroup>
 <col width="50%">
 <col width="50%">
 </colgroup>
 
 <tr>
@@ -716,45 +800,17 @@ add-on whenever it is run.
     <a href="dev-guide/guides/program-id.html">signing keys</a>.
     KEYDIR may be specified as a full path or as a path relative to the
     current directory.
   </td>
 </tr>
 
 </table>
 
-## Experimental Commands ##
-
-### cfx develop ###
-
-This initiates an instance of a host application in development mode,
-and allows you to pipe commands into it from another shell without
-having to constantly restart it. Aside from convenience, for SDK
-Platform developers this has the added benefit of making it easier to
-detect leaks.
-
-For example, in shell A, type:
-
-<pre>
-  cfx develop
-</pre>
-
-In shell B, type:
-
-<pre>
-  cfx test --use-server
-</pre>
-
-This will send `cfx test --use-server` output to shell A. If you repeat the
-command in shell B, `cfx test --use-server` output will appear again in shell A
-without restarting the host application.
-
-`cfx develop` doesn't take any options.
-
-## Internal Commands ##
+## <a name="internal-commands">Internal Commands</a> ##
 
 ### cfx sdocs ###
 
 Executing this command builds a static HTML version of the SDK documentation
 that can be hosted on a web server without the special application support
 required by `cfx docs`.
 
 #### Options ####
--- a/addon-sdk/source/doc/module-source/sdk/request.md
+++ b/addon-sdk/source/doc/module-source/sdk/request.md
@@ -1,30 +1,32 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 The `request` module lets you make simple yet powerful network requests.
 
 <api name="Request">
 @class
-The `Request` object is used to make `GET`, `POST` or `PUT` network requests.
-It is constructed with a URL to which the request is sent. Optionally the user
-may specify a collection of headers and content to send alongside the request
-and a callback which will be executed once the request completes.
+The `Request` object is used to make `GET`, `POST`, `PUT`, or `HEAD`
+network requests.  It is constructed with a URL to which the request is sent.
+Optionally the user may specify a collection of headers and content to send
+alongside the request and a callback which will be executed once the
+request completes.
 
 Once a `Request` object has been created a `GET` request can be executed by
 calling its `get()` method, a `POST` request by calling its `post()` method,
-or a `PUT` request by calling its `put()` method.
+a `PUT` request by calling its `put()` method, or a `HEAD` request by calling
+its `head()` method.
 
 When the server completes the request, the `Request` object emits a "complete"
 event.  Registered event listeners are passed a `Response` object.
 
-Each `Request` object is designed to be used once. Once `GET`, `POST` or `PUT`
-are called, attempting to call either will throw an error.
+Each `Request` object is designed to be used once. Once `GET`, `POST`, `PUT`,
+or `HEAD` are called, attempting to call either will throw an error.
 
 Since the request is not being made by any particular website, requests made
 here are not subject to the same-domain restriction that requests made in web
 pages are subject to.
 
 With the exception of `response`, all of a `Request` object's properties
 correspond with the options in the constructor. Each can be set by simply
 performing an assignment. However, keep in mind that the same validation rules
@@ -145,33 +147,39 @@ Make a `POST` request.
 </api>
 
 <api name="put">
 @method
 Make a `PUT` request.
 @returns {Request}
 </api>
 
+<api name="head">
+@method
+Make a `HEAD` request.
+@returns {Request}
+</api>
+
 <api name="complete">
 @event
 The `Request` object emits this event when the request has completed and a
 response has been received.
 
 @argument {Response}
 Listener functions are passed the response to the request as a `Response` object.
 </api>
 
 </api>
 
 
 <api name="Response">
 @class
 The Response object contains the response to a network request issued using a
-`Request` object. It is returned by the `get()`, `post()` or `put()` method of a
-`Request` object.
+`Request` object. It is returned by the `get()`, `post()`, `put()`, or `head()`
+method of a `Request` object.
 
 All members of a `Response` object are read-only.
 <api name="text">
 @property {string}
 The content of the response as plain text.
 </api>
 
 <api name="json">
--- a/addon-sdk/source/lib/sdk/addon/runner.js
+++ b/addon-sdk/source/lib/sdk/addon/runner.js
@@ -6,35 +6,43 @@
 
 module.metadata = {
   "stability": "experimental"
 };
 
 const { Cc, Ci } = require('chrome');
 const { descriptor, Sandbox, evaluate, main, resolveURI } = require('toolkit/loader');
 const { once } = require('../system/events');
-const { exit, env, staticArgs, name } = require('../system');
+const { exit, env, staticArgs } = require('../system');
 const { when: unload } = require('../system/unload');
 const { loadReason } = require('../self');
 const { rootURI } = require("@loader/options");
 const globals = require('../system/globals');
+const xulApp = require('../system/xul-app');
 const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
                         getService(Ci.nsIAppShellService);
 
 const NAME2TOPIC = {
   'Firefox': 'sessionstore-windows-restored',
   'Fennec': 'sessionstore-windows-restored',
   'SeaMonkey': 'sessionstore-windows-restored',
-  'Thunderbird': 'mail-startup-done',
-  '*': 'final-ui-startup'
+  'Thunderbird': 'mail-startup-done'
 };
 
+// Set 'final-ui-startup' as default topic for unknown applications
+let appStartup = 'final-ui-startup';
+
 // Gets the topic that fit best as application startup event, in according with
 // the current application (e.g. Firefox, Fennec, Thunderbird...)
-const APP_STARTUP = NAME2TOPIC[name] || NAME2TOPIC['*'];
+for (let name of Object.keys(NAME2TOPIC)) {
+  if (xulApp.is(name)) {
+    appStartup = NAME2TOPIC[name];
+    break;
+  }
+}
 
 // Initializes default preferences
 function setDefaultPrefs(prefsURI) {
   const prefs = Cc['@mozilla.org/preferences-service;1'].
                 getService(Ci.nsIPrefService).
                 QueryInterface(Ci.nsIPrefBranch2);
   const branch = prefs.getDefaultBranch('');
   const sandbox = Sandbox({
@@ -61,17 +69,17 @@ function setDefaultPrefs(prefsURI) {
 }
 
 function definePseudo(loader, id, exports) {
   let uri = resolveURI(id, loader.mapping);
   loader.modules[uri] = { exports: exports };
 }
 
 function wait(reason, options) {
-  once(APP_STARTUP, function() {
+  once(appStartup, function() {
     startup(null, options);
   });
 }
 
 function startup(reason, options) {
   // Try accessing hidden window to guess if we are running during firefox
   // startup, so that we should wait for session restore event before
   // running the addon
@@ -140,20 +148,20 @@ function run(options) {
 
     if (typeof(program.onUnload) === 'function')
       unload(program.onUnload);
 
     if (typeof(program.main) === 'function') {
 
       program.main({
         loadReason: loadReason,
-        staticArgs: staticArgs 
-      }, { 
+        staticArgs: staticArgs
+      }, {
         print: function print(_) { dump(_ + '\n') },
-        quit: exit 
+        quit: exit
       });
     }
   } catch (error) {
     console.exception(error);
     throw error;
   }
 }
 exports.startup = startup;
--- a/addon-sdk/source/lib/sdk/deprecated/tab-browser.js
+++ b/addon-sdk/source/lib/sdk/deprecated/tab-browser.js
@@ -561,27 +561,27 @@ function ModuleTabTracker(delegate, wind
   this._tabs = [];
   this._tracker = new Tracker(this, window);
   require("../system/unload").ensure(this);
 }
 ModuleTabTracker.prototype = {
   _TAB_EVENTS: ["TabOpen", "TabClose", "TabSelect", "DOMContentLoaded",
                 "load", "MozAfterPaint"],
   _safeTrackTab: function safeTrackTab(tab) {
-    tab.addEventListener("load", this, false);
+    tab.linkedBrowser.addEventListener("load", this, true);
     tab.linkedBrowser.addEventListener("MozAfterPaint", this, false);
     this._tabs.push(tab);
     try {
       this._delegate.onTrack(tab);
     } catch (e) {
       console.exception(e);
     }
   },
   _safeUntrackTab: function safeUntrackTab(tab) {
-    tab.removeEventListener("load", this, false);
+    tab.linkedBrowser.removeEventListener("load", this, true);
     tab.linkedBrowser.removeEventListener("MozAfterPaint", this, false);
     var index = this._tabs.indexOf(tab);
     if (index == -1)
       throw new Error("internal error: tab not found");
     this._tabs.splice(index, 1);
     try {
       this._delegate.onUntrack(tab);
     } catch (e) {
@@ -612,17 +612,21 @@ ModuleTabTracker.prototype = {
     try {
       if (this._delegate.onReady)
         this._delegate.onReady(tab);
     } catch (e) {
       console.exception(e);
     }
   },
   _safeLoad: function safeLoad(event) {
-    let tab = event.target;
+    let win = event.currentTarget.ownerDocument.defaultView;
+    let tabIndex = win.gBrowser.getBrowserIndexForDocument(event.target);
+    if (tabIndex == -1)
+      return;
+    let tab = win.gBrowser.tabContainer.getItemAtIndex(tabIndex);
     let index = this._tabs.indexOf(tab);
     if (index == -1)
       console.error("internal error: tab not found");
     try {
       if (this._delegate.onLoad)
         this._delegate.onLoad(tab);
     } catch (e) {
       console.exception(e);
--- a/addon-sdk/source/lib/sdk/deprecated/window-utils.js
+++ b/addon-sdk/source/lib/sdk/deprecated/window-utils.js
@@ -6,16 +6,17 @@
 module.metadata = {
   'stability': 'deprecated'
 };
 
 const { Cc, Ci } = require('chrome');
 const { EventEmitter } = require('../deprecated/events');
 const { Trait } = require('../deprecated/traits');
 const { when } = require('../system/unload');
+const events = require('../system/events');
 const { getInnerId, getOuterId, windows, isDocumentLoaded, isBrowser,
         getMostRecentBrowserWindow, getMostRecentWindow } = require('../window/utils');
 const errors = require('../deprecated/errors');
 const { deprecateFunction } = require('../util/deprecate');
 const { ignoreWindow, isGlobalPBSupported } = require('sdk/private-browsing/utils');
 const { isPrivateBrowsingSupported } = require('../self');
 
 const windowWatcher = Cc['@mozilla.org/embedcomp/window-watcher;1'].
@@ -63,16 +64,18 @@ function WindowTracker(delegate) {
    }
 
   this._delegate = delegate;
   this._loadingWindows = [];
 
   for each (let window in getWindows())
     this._regWindow(window);
   windowWatcher.registerNotification(this);
+  this._onToplevelWindowReady = this._onToplevelWindowReady.bind(this);
+  events.on('toplevel-window-ready', this._onToplevelWindowReady);
 
   require('../system/unload').ensure(this);
 
   return this;
 };
 
 WindowTracker.prototype = {
   _regLoadingWindow: function _regLoadingWindow(window) {
@@ -111,36 +114,43 @@ WindowTracker.prototype = {
         this._delegate.onUntrack(window);
     } else {
       this._unregLoadingWindow(window);
     }
   },
 
   unload: function unload() {
     windowWatcher.unregisterNotification(this);
+    events.off('toplevel-window-ready', this._onToplevelWindowReady);
     for each (let window in getWindows())
       this._unregWindow(window);
   },
 
   handleEvent: errors.catchAndLog(function handleEvent(event) {
     if (event.type == 'load' && event.target) {
       var window = event.target.defaultView;
       if (window)
         this._regWindow(window);
     }
   }),
 
+  _onToplevelWindowReady: function _onToplevelWindowReady({subject}) {
+    let window = subject;
+    // ignore private windows if they are not supported
+    if (ignoreWindow(window))
+      return;
+    this._regWindow(window);
+  },
+
   observe: errors.catchAndLog(function observe(subject, topic, data) {
     var window = subject.QueryInterface(Ci.nsIDOMWindow);
     // ignore private windows if they are not supported
     if (ignoreWindow(window))
       return;
-    if (topic == 'domwindowopened')
-      this._regWindow(window);
-    else
+    if (topic == 'domwindowclosed')
       this._unregWindow(window);
   })
 };
 exports.WindowTracker = WindowTracker;
 
 const WindowTrackerTrait = Trait.compose({
   _onTrack: Trait.required,
   _onUntrack: Trait.required,
--- a/addon-sdk/source/lib/sdk/panel.js
+++ b/addon-sdk/source/lib/sdk/panel.js
@@ -14,47 +14,30 @@ module.metadata = {
 
 const { Ci } = require("chrome");
 const { validateOptions: valid } = require('./deprecated/api-utils');
 const { setTimeout } = require('./timers');
 const { isPrivateBrowsingSupported } = require('./self');
 const { isWindowPBSupported } = require('./private-browsing/utils');
 const { Class } = require("./core/heritage");
 const { merge } = require("./util/object");
-const { WorkerHost, Worker, detach, attach } = require("./worker/utils");
+const { WorkerHost, Worker, detach, attach,
+        requiresAddonGlobal } = require("./worker/utils");
 const { Disposable } = require("./core/disposable");
 const { contract: loaderContract } = require("./content/loader");
 const { contract } = require("./util/contract");
 const { on, off, emit, setListeners } = require("./event/core");
 const { EventTarget } = require("./event/target");
 const domPanel = require("./panel/utils");
 const { events } = require("./panel/events");
 const systemEvents = require("./system/events");
 const { filter, pipe } = require("./event/utils");
 const { getNodeView, getActiveView } = require("./view/core");
 const { isNil, isObject } = require("./lang/type");
 
-let isArray = Array.isArray;
-let assetsURI = require("./self").data.url();
-
-function isAddonContent({ contentURL }) {
-  return typeof(contentURL) === "string" && contentURL.indexOf(assetsURI) === 0;
-}
-
-function hasContentScript({ contentScript, contentScriptFile }) {
-  return (isArray(contentScript) ? contentScript.length > 0 :
-         !!contentScript) ||
-         (isArray(contentScriptFile) ? contentScriptFile.length > 0 :
-         !!contentScriptFile);
-}
-
-function requiresAddonGlobal(model) {
-  return isAddonContent(model) && !hasContentScript(model);
-}
-
 function getAttachEventType(model) {
   let when = model.contentScriptWhen;
   return requiresAddonGlobal(model) ? "sdk-panel-content-changed" :
          when === "start" ? "sdk-panel-content-changed" :
          when === "end" ? "sdk-panel-document-loaded" :
          when === "ready" ? "sdk-panel-content-loaded" :
          null;
 }
--- a/addon-sdk/source/lib/sdk/request.js
+++ b/addon-sdk/source/lib/sdk/request.js
@@ -45,34 +45,36 @@ const { validateOptions, validateSingleO
     map: function(v) v || null,
     is: ["string", "null"],
   }
 });
 
 const REUSE_ERROR = "This request object has been used already. You must " +
                     "create a new one to make a new request."
 
-// Utility function to prep the request since it's the same between GET and
-// POST
+// Utility function to prep the request since it's the same between
+// request types
 function runRequest(mode, target) {
   let source = request(target)
   let { xhr, url, content, contentType, headers, overrideMimeType } = source;
 
+  let isGetOrHead = (mode == "GET" || mode == "HEAD");
+
   // If this request has already been used, then we can't reuse it.
   // Throw an error.
   if (xhr)
     throw new Error(REUSE_ERROR);
 
   xhr = source.xhr = new XMLHttpRequest();
 
-  // Build the data to be set. For GET requests, we want to append that to
-  // the URL before opening the request.
+  // Build the data to be set. For GET or HEAD requests, we want to append that
+  // to the URL before opening the request.
   let data = stringify(content);
   // If the URL already has ? in it, then we want to just use &
-  if (mode == "GET" && data)
+  if (isGetOrHead && data)
     url = url + (/\?/.test(url) ? "&" : "?") + data;
 
   // open the request
   xhr.open(mode, url);
 
   xhr.forceAllowThirdPartyCookie();
 
   // request header must be set after open, but before send
@@ -92,18 +94,18 @@ function runRequest(mode, target) {
     if (xhr.readyState === 4) {
       let response = Response(xhr);
       source.response = response;
       emit(target, 'complete', response);
     }
   };
 
   // actually send the request.
-  // We don't want to send data on GET requests.
-  xhr.send(mode !== "GET" ? data : null);
+  // We don't want to send data on GET or HEAD requests.
+  xhr.send(!isGetOrHead ? data : null);
 }
 
 const Request = Class({
   extends: EventTarget,
   initialize: function initialize(options) {
     // `EventTarget.initialize` will set event listeners that are named
     // like `onEvent` in this case `onComplete` listener will be set to
     // `complete` event.
@@ -133,16 +135,20 @@ const Request = Class({
   },
   post: function() {
     runRequest('POST', this);
     return this;
   },
   put: function() {
     runRequest('PUT', this);
     return this;
+  },
+  head: function() {
+    runRequest('HEAD', this);
+    return this;
   }
 });
 exports.Request = Request;
 
 const Response = Class({
   initialize: function initialize(request) {
     response(this).request = request;
   },
--- a/addon-sdk/source/lib/sdk/url.js
+++ b/addon-sdk/source/lib/sdk/url.js
@@ -7,23 +7,28 @@
 module.metadata = {
   "stability": "experimental"
 };
 
 const { Cc, Ci, Cr } = require("chrome");
 
 const { Class } = require("./core/heritage");
 const base64 = require("./base64");
+var tlds = Cc["@mozilla.org/network/effective-tld-service;1"]
+          .getService(Ci.nsIEffectiveTLDService);
 
 var ios = Cc['@mozilla.org/network/io-service;1']
           .getService(Ci.nsIIOService);
 
 var resProt = ios.getProtocolHandler("resource")
               .QueryInterface(Ci.nsIResProtocolHandler);
 
+var URLParser = Cc["@mozilla.org/network/url-parser;1?auth=no"]
+                .getService(Ci.nsIURLParser);
+
 function newURI(uriStr, base) {
   try {
     let baseURI = base ? ios.newURI(base, null, null) : null;
     return ios.newURI(uriStr, null, baseURI);
   }
   catch (e if e.result == Cr.NS_ERROR_MALFORMED_URI) {
     throw new Error("malformed URI: " + uriStr);
   }
@@ -87,21 +92,39 @@ function URL(url, base) {
     host = uri.host;
   } catch (e if e.result == Cr.NS_ERROR_FAILURE) {}
 
   var port = null;
   try {
     port = uri.port == -1 ? null : uri.port;
   } catch (e if e.result == Cr.NS_ERROR_FAILURE) {}
 
+  let uriData = [uri.path, uri.path.length, {}, {}, {}, {}, {}, {}];
+  URLParser.parsePath.apply(URLParser, uriData);
+  let [{ value: filepathPos }, { value: filepathLen },
+    { value: queryPos }, { value: queryLen },
+    { value: refPos }, { value: refLen }] = uriData.slice(2);
+
+  let hash = uri.ref ? "#" + uri.ref : "";
+  let pathname = uri.path.substr(filepathPos, filepathLen);
+  let search = uri.path.substr(queryPos, queryLen);
+  search = search ? "?" + search : "";
+
   this.__defineGetter__("scheme", function() uri.scheme);
   this.__defineGetter__("userPass", function() userPass);
   this.__defineGetter__("host", function() host);
+  this.__defineGetter__("hostname", function() host);
   this.__defineGetter__("port", function() port);
   this.__defineGetter__("path", function() uri.path);
+  this.__defineGetter__("pathname", function() pathname);
+  this.__defineGetter__("hash", function() hash);
+  this.__defineGetter__("href", function() uri.spec);
+  this.__defineGetter__("origin", function() uri.prePath);
+  this.__defineGetter__("protocol", function() uri.scheme + ":");
+  this.__defineGetter__("search", function() search);
 
   Object.defineProperties(this, {
     toString: {
       value: function URL_toString() new String(uri.spec).toString(),
       enumerable: false
     },
     valueOf: {
       value: function() new String(uri.spec).valueOf(),
@@ -230,16 +253,27 @@ const DataURL = Class({
       this.mimeType +
       parametersList.join(";") + "," +
       encodeURIComponent(data);
   }
 });
 
 exports.DataURL = DataURL;
 
+let getTLD = exports.getTLD = function getTLD (url) {
+  let uri = newURI(url.toString());
+  let tld = null;
+  try {
+    tld = tlds.getPublicSuffix(uri);
+  } catch (e if
+      e.result == Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS ||
+      e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS) {}
+  return tld;
+};
+
 let isValidURI = exports.isValidURI = function (uri) {
   try {
     newURI(uri);
   } catch(e) {
     return false;
   }
   return true;
 }
--- a/addon-sdk/source/lib/sdk/worker/utils.js
+++ b/addon-sdk/source/lib/sdk/worker/utils.js
@@ -12,20 +12,44 @@ module.metadata = {
 // code depending on workers could be de-trait-ified without changing worker
 // implementation.
 
 const { Worker: WorkerTrait } = require("../content/worker");
 const { Loader } = require("../content/loader");
 const { merge } = require("../util/object");
 const { emit } = require("../event/core");
 
-const LegacyWorker = WorkerTrait.resolve({
+let assetsURI = require("../self").data.url();
+let isArray = Array.isArray;
+
+function isAddonContent({ contentURL }) {
+  return typeof(contentURL) === "string" && contentURL.indexOf(assetsURI) === 0;
+}
+
+function hasContentScript({ contentScript, contentScriptFile }) {
+  return (isArray(contentScript) ? contentScript.length > 0 :
+         !!contentScript) ||
+         (isArray(contentScriptFile) ? contentScriptFile.length > 0 :
+         !!contentScriptFile);
+}
+
+function requiresAddonGlobal(model) {
+  return isAddonContent(model) && !hasContentScript(model);
+}
+exports.requiresAddonGlobal = requiresAddonGlobal;
+
+
+const LegacyWorker = WorkerTrait.compose(Loader).resolve({
   _setListeners: "__setListeners",
-}).compose(Loader, {
+  _injectInDocument: "__injectInDocument",
+  contentURL: "__contentURL"
+}).compose({
   _setListeners: function() {},
+  get contentURL() this._window.document.URL,
+  get _injectInDocument() requiresAddonGlobal(this),
   attach: function(window) this._attach(window),
   detach: function() this._workerCleanup()
 });
 
 // Weak map that stores mapping between regular worker instances and
 // legacy trait based worker instances.
 let traits = new WeakMap();
 
--- a/addon-sdk/source/test/addons/private-browsing-supported/test-selection.js
+++ b/addon-sdk/source/test/addons/private-browsing-supported/test-selection.js
@@ -44,28 +44,28 @@ function open(url, options) {
     openNewWindow("", {
       features: merge({ toolbar: true }, options)
     }).then(function(chromeWindow) {
       if (isPrivate(chromeWindow) !== !!options.private)
         throw new Error("Window should have Private set to " + !!options.private);
 
       let tab = getActiveTab(chromeWindow);
 
-      tab.addEventListener("load", function ready(event) {
-        let { document } = getTabContentWindow(this);
+      tab.linkedBrowser.addEventListener("load", function ready(event) {
+        let { document } = getTabContentWindow(tab);
 
         if (document.readyState === "complete" && document.URL === url) {
           this.removeEventListener(event.type, ready);
 
           if (options.title)
             document.title = options.title;
 
           resolve(document.defaultView);
         }
-      })
+      }, true);
 
       setTabURL(tab, url);
     });
 
     return promise;
   };
 
   tabs.open({
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/privileged-panel/data/index.html
@@ -0,0 +1,3 @@
+<script>
+  addon.postMessage("hello addon")
+</script>
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/privileged-panel/main.js
@@ -0,0 +1,26 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { Panel } = require("sdk/panel")
+const { data } = require("sdk/self")
+
+exports["test addon global"] = function(assert, done) {
+  let panel = Panel({
+    contentURL: //"data:text/html,now?",
+                data.url("./index.html"),
+    onMessage: function(message) {
+      assert.pass("got message from panel script");
+      panel.destroy();
+      done();
+    },
+    onError: function(error) {
+      asser.fail(Error("failed to recieve message"));
+      done();
+    }
+  });
+};
+
+require("sdk/test/runner").runTestsFromModule(module);
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/privileged-panel/package.json
@@ -0,0 +1,3 @@
+{
+  "id": "test-privileged-addon"
+}
--- a/addon-sdk/source/test/test-request.js
+++ b/addon-sdk/source/test/test-request.js
@@ -213,16 +213,36 @@ exports.testInvalidJSON = function (test
   runMultipleURLs(srv, test, {
     url: "http://localhost:" + port + "/" + basename,
     onComplete: function (response) {
       test.assertEqual(response.json, null);
     }
   });
 }
 
+exports.testHead = function (test) {
+  let srv = startServerAsync(port, basePath);
+
+  srv.registerPathHandler("/test-head",
+      function handle(request, response) {
+    response.setHeader("Content-Type", "text/plain", false);
+  });
+
+  test.waitUntilDone();
+  Request({
+    url: "http://localhost:" + port + "/test-head",
+    onComplete: function (response) {
+      test.assertEqual(response.text, "");
+      test.assertEqual(response.statusText, "OK");
+      test.assertEqual(response.headers["Content-Type"], "text/plain");
+      srv.stop(function() test.done());
+    }
+  }).head();
+}
+
 function runMultipleURLs (srv, test, options) {
   let urls = [options.url, URL(options.url)];
   let cb = options.onComplete;
   let ran = 0;
   let onComplete = function (res) {
     cb(res);
     if (++ran === urls.length)
       srv ? srv.stop(function () test.done()) : test.done();
--- a/addon-sdk/source/test/test-selection.js
+++ b/addon-sdk/source/test/test-selection.js
@@ -45,25 +45,25 @@ function open(url, options) {
     openNewWindow("", {
       features: merge({ toolbar: true }, options)
     }).then(function(chromeWindow) {
       if (isPrivate(chromeWindow) !== !!options.private)
         throw new Error("Window should have Private set to " + !!options.private);
 
       let tab = getActiveTab(chromeWindow);
 
-      tab.addEventListener("load", function ready(event) {
-        let { document } = getTabContentWindow(this);
+      tab.linkedBrowser.addEventListener("load", function ready(event) {
+        let { document } = getTabContentWindow(tab);
 
         if (document.readyState === "complete" && document.URL === url) {
           this.removeEventListener(event.type, ready);
 
           resolve(document.defaultView);
         }
-      })
+      }, true);
 
       setTabURL(tab, url);
     });
 
     return promise;
   };
 
   tabs.open({
--- a/addon-sdk/source/test/test-url.js
+++ b/addon-sdk/source/test/test-url.js
@@ -1,13 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 var url = require("sdk/url");
+var { Loader } = require("sdk/test/loader");
+var { pathFor } = require("sdk/system");
+var file = require("sdk/io/file");
+var loader = Loader(module);
+var httpd = loader.require("sdk/test/httpd");
+var port = 8099;
+var tabs = require("sdk/tabs");
 
 exports.testResolve = function(test) {
   test.assertEqual(url.URL("bar", "http://www.foo.com/").toString(),
                    "http://www.foo.com/bar");
 
   test.assertEqual(url.URL("bar", "http://www.foo.com"),
                    "http://www.foo.com/bar");
 
@@ -28,22 +35,59 @@ exports.testResolve = function(test) {
                     "url.resolve() should throw on bad chrome URI");
 
   test.assertEqual(url.URL("", "http://www.foo.com"),
                    "http://www.foo.com/",
                    "url.resolve() should add slash to end of domain");
 };
 
 exports.testParseHttp = function(test) {
-  var info = url.URL("http://foo.com/bar");
+  var aUrl = "http://sub.foo.com/bar?locale=en-US&otherArg=%20x%20#myhash"; 
+  var info = url.URL(aUrl);
   test.assertEqual(info.scheme, "http");
-  test.assertEqual(info.host, "foo.com");
+  test.assertEqual(info.protocol, "http:");
+  test.assertEqual(info.host, "sub.foo.com");
+  test.assertEqual(info.hostname, "sub.foo.com");
   test.assertEqual(info.port, null);
   test.assertEqual(info.userPass, null);
-  test.assertEqual(info.path, "/bar");
+  test.assertEqual(info.path, "/bar?locale=en-US&otherArg=%20x%20#myhash");
+  test.assertEqual(info.pathname, "/bar");
+  test.assertEqual(info.href, aUrl);
+  test.assertEqual(info.hash, "#myhash");
+  test.assertEqual(info.search, "?locale=en-US&otherArg=%20x%20");
+};
+
+exports.testParseHttpSearchAndHash = function (test) {
+  var info = url.URL("https://www.moz.com/some/page.html");
+  test.assertEqual(info.hash, "");
+  test.assertEqual(info.search, "");
+  
+  var hashOnly = url.URL("https://www.sub.moz.com/page.html#justhash");
+  test.assertEqual(hashOnly.search, "");
+  test.assertEqual(hashOnly.hash, "#justhash");
+  
+  var queryOnly = url.URL("https://www.sub.moz.com/page.html?my=query");
+  test.assertEqual(queryOnly.search, "?my=query");
+  test.assertEqual(queryOnly.hash, "");
+
+  var qMark = url.URL("http://www.moz.org?");
+  test.assertEqual(qMark.search, "");
+  test.assertEqual(qMark.hash, "");
+  
+  var hash = url.URL("http://www.moz.org#");
+  test.assertEqual(hash.search, "");
+  test.assertEqual(hash.hash, "");
+  
+  var empty = url.URL("http://www.moz.org?#");
+  test.assertEqual(hash.search, "");
+  test.assertEqual(hash.hash, "");
+
+  var strange = url.URL("http://moz.org?test1#test2?test3");
+  test.assertEqual(strange.search, "?test1");
+  test.assertEqual(strange.hash, "#test2?test3");
 };
 
 exports.testParseHttpWithPort = function(test) {
   var info = url.URL("http://foo.com:5/bar");
   test.assertEqual(info.port, 5);
 };
 
 exports.testParseChrome = function(test) {
@@ -158,20 +202,22 @@ exports.testURL = function(test) {
 };
 
 exports.testStringInterface = function(test) {
   let URL = url.URL;
   var EM = "about:addons";
   var a = URL(EM);
 
   // make sure the standard URL properties are enumerable and not the String interface bits
-  test.assertEqual(Object.keys(a), "scheme,userPass,host,port,path", "enumerable key list check for URL.");
+  test.assertEqual(Object.keys(a),
+    "scheme,userPass,host,hostname,port,path,pathname,hash,href,origin,protocol,search",
+    "enumerable key list check for URL.");
   test.assertEqual(
       JSON.stringify(a),
-      "{\"scheme\":\"about\",\"userPass\":null,\"host\":null,\"port\":null,\"path\":\"addons\"}",
+      "{\"scheme\":\"about\",\"userPass\":null,\"host\":null,\"hostname\":null,\"port\":null,\"path\":\"addons\",\"pathname\":\"addons\",\"hash\":\"\",\"href\":\"about:addons\",\"origin\":\"about:\",\"protocol\":\"about:\",\"search\":\"\"}",
       "JSON.stringify should return a object with correct props and vals.");
 
   // make sure that the String interface exists and works as expected
   test.assertEqual(a.indexOf(":"), EM.indexOf(":"), "indexOf on URL works");
   test.assertEqual(a.valueOf(), EM.valueOf(), "valueOf on URL works.");
   test.assertEqual(a.toSource(), EM.toSource(), "toSource on URL works.");
   test.assertEqual(a.lastIndexOf("a"), EM.lastIndexOf("a"), "lastIndexOf on URL works.");
   test.assertEqual(a.match("t:").toString(), EM.match("t:").toString(), "match on URL works.");
@@ -256,16 +302,63 @@ exports.testIsInvalidURI = function (tes
 };
 
 exports.testURLFromURL = function(test) {
   let aURL = url.URL('http://mozilla.org');
   let bURL = url.URL(aURL);
   test.assertEqual(aURL.toString(), bURL.toString(), 'Making a URL from a URL works');
 };
 
+exports.testTLD = function(test) {
+  let urls = [
+    { url: 'http://my.sub.domains.mozilla.co.uk', tld: 'co.uk' },
+    { url: 'http://my.mozilla.com', tld: 'com' },
+    { url: 'http://my.domains.mozilla.org.hk', tld: 'org.hk' },
+    { url: 'chrome://global/content/blah', tld: 'global' },
+    { url: 'data:text/plain;base64,QXdlc29tZSE=', tld: null },
+    { url: 'https://1.2.3.4', tld: null }
+  ];
+
+  urls.forEach(function (uri) {
+    test.assertEqual(url.getTLD(uri.url), uri.tld);
+    test.assertEqual(url.getTLD(url.URL(uri.url)), uri.tld);
+  });
+}
+
+exports.testWindowLocationMatch = function (test) {
+  let srv = serve();
+  let aUrl = 'http://localhost:' + port + '/index.html?q=aQuery#somehash';
+  let urlObject = url.URL(aUrl);
+  test.waitUntilDone();
+
+  tabs.open({
+    url: aUrl,
+    onReady: function (tab) {
+      tab.attach({
+        onMessage: function (loc) {
+          for (let prop in loc) {
+            test.assertEqual(urlObject[prop], loc[prop], prop + ' matches');
+          }
+          tab.close();
+          srv.stop(test.done.bind(test));
+        },
+        contentScript: '(' + function () {
+          let res = {};
+          // `origin` is `null` in this context???
+          let props = 'hostname,port,pathname,hash,href,protocol,search'.split(',');
+          props.forEach(function (prop) {
+            res[prop] = window.location[prop];
+          });
+          self.postMessage(res);
+        } + ')()'
+      });
+    }
+  })
+};
+
 function validURIs() {
   return [
   'http://foo.com/blah_blah',
   'http://foo.com/blah_blah/',
   'http://foo.com/blah_blah_(wikipedia)',
   'http://foo.com/blah_blah_(wikipedia)_(again)',
   'http://www.example.com/wpstyle/?p=364',
   'https://www.example.com/foo/?bar=baz&amp;inga=42&amp;quux',
@@ -347,8 +440,21 @@ function invalidURIs () {
 //  'http://3628126748',
 //  'http://.www.foo.bar/',
 //  'http://www.foo.bar./',
 //  'http://.www.foo.bar./',
 //  'http://10.1.1.1',
 //  'http://10.1.1.254'
   ];
 }
+
+function serve () {
+  let basePath = pathFor("ProfD");
+  let filePath = file.join(basePath, 'index.html');
+  let content = "<html><head></head><body><h1>url tests</h1></body></html>";
+  let fileStream = file.open(filePath, 'w');
+  fileStream.write(content);
+  fileStream.close();
+
+  let srv = httpd.startServerAsync(port, basePath);
+  return srv;
+}
+
deleted file mode 100644
--- a/addon-sdk/test/Makefile.in
+++ /dev/null
@@ -1,12 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-DEPTH            = @DEPTH@
-topsrcdir        = @top_srcdir@
-srcdir           = @srcdir@
-VPATH            = @srcdir@
-relativesrcdir   = @relativesrcdir@
-
-include $(DEPTH)/config/autoconf.mk
-include $(topsrcdir)/config/rules.mk
--- a/b2g/app/Makefile.in
+++ b/b2g/app/Makefile.in
@@ -14,18 +14,16 @@ include $(topsrcdir)/config/makefiles/rc
 PREF_JS_EXPORTS = $(srcdir)/b2g.js
 
 ifdef ENABLE_MARIONETTE
 DEFINES += -DENABLE_MARIONETTE=1
 endif
 
 ifndef LIBXUL_SDK
 
-CPPSRCS = nsBrowserApp.cpp
-
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 LIBS += \
   -lui \
   -lEGL \
   -lhardware_legacy \
   -lhardware \
   -lcutils \
   $(DEPTH)/media/libpng/$(LIB_PREFIX)mozpng.$(LIB_SUFFIX) \
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -232,27 +232,23 @@ pref("editor.singleLine.pasteNewlines", 
 pref("ui.dragThresholdX", 25);
 pref("ui.dragThresholdY", 25);
 
 // Layers Acceleration.  We can only have nice things on gonk, because
 // they're not maintained anywhere else.
 #ifndef MOZ_WIDGET_GONK
 pref("dom.ipc.tabs.disabled", true);
 pref("layers.offmainthreadcomposition.enabled", false);
-pref("layers.offmainthreadcomposition.animate-opacity", false);
-pref("layers.offmainthreadcomposition.animate-transform", false);
-pref("layers.offmainthreadcomposition.throttle-animations", false);
+pref("layers.offmainthreadcomposition.async-animations", false);
 pref("layers.async-video.enabled", false);
 #else
 pref("dom.ipc.tabs.disabled", false);
 pref("layers.offmainthreadcomposition.enabled", true);
 pref("layers.acceleration.disabled", false);
-pref("layers.offmainthreadcomposition.animate-opacity", true);
-pref("layers.offmainthreadcomposition.animate-transform", true);
-pref("layers.offmainthreadcomposition.throttle-animations", true);
+pref("layers.offmainthreadcomposition.async-animations", true);
 pref("layers.async-video.enabled", true);
 pref("layers.async-pan-zoom.enabled", true);
 #endif
 
 // Web Notifications
 pref("notification.feature.enabled", true);
 pref("dom.webnotifications.enabled", false);
 
@@ -588,17 +584,17 @@ pref("hal.processPriorityManager.gonk.FO
 pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.Nice", 0);
 
 pref("hal.processPriorityManager.gonk.FOREGROUND.OomScoreAdjust", 134);
 pref("hal.processPriorityManager.gonk.FOREGROUND.KillUnderMB", 6);
 pref("hal.processPriorityManager.gonk.FOREGROUND.Nice", 1);
 
 pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.OomScoreAdjust", 200);
 pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.KillUnderMB", 7);
-pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.Nice", 10);
+pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.Nice", 7);
 
 pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.OomScoreAdjust", 267);
 pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.KillUnderMB", 8);
 pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.Nice", 18);
 
 pref("hal.processPriorityManager.gonk.BACKGROUND.OomScoreAdjust", 400);
 pref("hal.processPriorityManager.gonk.BACKGROUND.KillUnderMB", 20);
 pref("hal.processPriorityManager.gonk.BACKGROUND.Nice", 18);
--- a/b2g/app/moz.build
+++ b/b2g/app/moz.build
@@ -4,8 +4,11 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 if not CONFIG['LIBXUL_SDK']:
     if CONFIG['GAIADIR']:
         PROGRAM = CONFIG['MOZ_APP_NAME'] + "-bin"
     else:
         PROGRAM = CONFIG['MOZ_APP_NAME']
+    CPP_SOURCES += [
+        'nsBrowserApp.cpp',
+    ]
--- a/b2g/chrome/content/content.css
+++ b/b2g/chrome/content/content.css
@@ -56,125 +56,126 @@ xul|scrollbarbutton {
 }
 
 xul|scrollbarbutton[sbattr="scrollbar-up-top"],
 xul|scrollbarbutton[sbattr="scrollbar-bottom-top"] {
   display: none;
 }
 
 xul|thumb {
+  -moz-appearance: none !important;
   background-color: rgba(0, 0, 0, 0.4) !important;
   -moz-border-top-colors: none !important;
   -moz-border-bottom-colors: none !important;
   -moz-border-right-colors: none !important;
   -moz-border-left-colors: none !important;
   border: 1px solid rgba(255, 255, 255, 0.4) !important;
   border-radius: 3px;
 }
 
 /* -moz-touch-enabled? media elements */
 :-moz-any(video, audio) > xul|videocontrols {
   -moz-binding: url("chrome://global/content/bindings/videocontrols.xml#touchControls");
 }
 
-select:not([size]):not([multiple]) > xul|scrollbar,
-select[size="1"] > xul|scrollbar,
-select:not([size]):not([multiple]) xul|scrollbarbutton,
-select[size="1"] xul|scrollbarbutton {
+html select:not([size]):not([multiple]) > xul|scrollbar,
+html select[size="1"] > xul|scrollbar,
+html select:not([size]):not([multiple]) xul|scrollbarbutton,
+html select[size="1"] xul|scrollbarbutton {
   display: block;
   margin-left: 0;
   min-width: 16px;
 }
 
 /* Override inverse OS themes */
-select,
-textarea,
-button,
-xul|button,
-* > input:not([type="image"]) {
+html select,
+html textarea,
+html button,
+html xul|button,
+html * > input:not([type="image"]) {
   -moz-appearance: none !important;  /* See bug 598421 for fixing the platform */
   border-radius: 3px;
 }
 
-select[size],
-select[multiple],
-select[size][multiple],
-textarea,
-* > input:not([type="image"]) {
+html select[size],
+html select[multiple],
+html select[size][multiple],
+html textarea,
+html * > input:not([type="image"]) {
   border-style: solid;
   border-color: #7d7d7d;
   color: #414141;
   background: white linear-gradient(rgba(115,115,115,0.5) 0, rgba(215,215,215,0.5) 3px, rgba(255,255,255,0.2) 16px);
 }
 
 /* Selects are handled by the form helper, see bug 685197 */
-select option, select optgroup {
+html select option, html select optgroup {
   pointer-events: none;
 }
 
-select:not([size]):not([multiple]),
-select[size="0"],
-select[size="1"],
-* > input[type="button"],
-* > input[type="submit"],
-* > input[type="reset"],
-button {
+html select:not([size]):not([multiple]),
+html select[size="0"],
+html select[size="1"],
+html * > input[type="button"],
+html * > input[type="submit"],
+html * > input[type="reset"],
+html button {
   border-style: solid;
   border-color: #7d7d7d;
   color: #414141;
   background: white linear-gradient(rgba(255,255,255,0.2) 0, rgba(215,215,215,0.5) 18px, rgba(115,115,115,0.5) 100%);
 }
 
-input[type="checkbox"] {
+html input[type="checkbox"] {
   background: white linear-gradient(rgba(115,115,115,0.5) 0, rgba(215,215,215,0.5) 2px, rgba(255,255,255,0.2) 6px);
 }
 
-input[type="radio"] {
+html input[type="radio"] {
   background: radial-gradient(at 6px 6px, rgba(255,255,255,0.2) 3px, rgba(195,195,195,0.5) 5px, rgba(115,115,115,0.5) 100%);
 }
 
-select {
+html select {
   border-width: 1px;
   padding: 1px;
 }
 
-select:not([size]):not([multiple]),
-select[size="0"],
-select[size="1"] {
+html select:not([size]):not([multiple]),
+html select[size="0"],
+html select[size="1"] {
   padding: 0 1px 0 1px;
 }
 
-* > input:not([type="image"]) {
+html * > input:not([type="image"]) {
   border-width: 1px;
   padding: 1px;
 }
 
-textarea {
+html textarea {
   resize: none;
   border-width: 1px;
   padding: 2px 1px 2px 1px;
 }
 
-input[type="button"],
-input[type="submit"],
-input[type="reset"],
-button {
+html input[type="button"],
+html input[type="submit"],
+html input[type="reset"],
+html button {
   border-width: 1px;
   padding: 0 7px 0 7px;
 }
 
-input[type="radio"],
-input[type="checkbox"] {
+html input[type="radio"],
+html input[type="checkbox"] {
   max-width: 14px;
   max-height: 14px;
   border: 1px solid #a7a7a7 !important;
   padding: 2px 1px 2px 1px;
 }
 
-select > button {
+html select > button {
   border-width: 0px !important;
   margin: 0px !important;
   padding: 0px !important;
   border-radius: 0;
   color: #414141;
 
   background-image: radial-gradient(at bottom left, #bbbbbb 40%, #f5f5f5), url(arrow.svg) !important;
   background-color: transparent;
@@ -182,109 +183,109 @@ select > button {
   background-repeat: no-repeat, no-repeat !important;
   background-size: 100% 90%, auto auto;
 
   -moz-binding: none !important;
   position: relative !important;
   font-size: inherit;
 }
 
-select[size]:focus,
-select[multiple]:focus,
-select[size][multiple]:focus,
-textarea:focus,
-input[type="file"]:focus > input[type="text"],
-* > input:not([type="image"]):focus {
+html select[size]:focus,
+html select[multiple]:focus,
+html select[size][multiple]:focus,
+html textarea:focus,
+html input[type="file"]:focus > input[type="text"],
+html * > input:not([type="image"]):focus {
   outline: 0px !important;
   border-style: solid;
   border-color: rgb(94,128,153);
   background: white linear-gradient(rgba(27,113,177,0.5) 0, rgba(198,225,246,0.2) 3px, rgba(255,255,255,0.2) 16px);
 }
 
-select:not([size]):not([multiple]):focus,
-select[size="0"]:focus,
-select[size="1"]:focus,
-input[type="button"]:focus,
-input[type="submit"]:focus,