merge m-c to fig
authorMargaret Leibovic <margaret.leibovic@gmail.com>
Tue, 28 May 2013 09:53:47 -0700
changeset 151287 7af5a66a6fceaa13bdb51cf7b3b529ea163dfa83
parent 151286 173cbbdc2e8b96e9497f35731c449ae04b70c0ec (current diff)
parent 140211 6a739f41d1bae71f597eb0ea8111a65ca64c1d31 (diff)
child 151288 762d1865d454eb946cbbdd4945e5407e50e22c8f
push idunknown
push userunknown
push dateunknown
milestone24.0a1
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,
-input[type="reset"]:focus,
-button:focus {
+html select:not([size]):not([multiple]):focus,
+html select[size="0"]:focus,
+html select[size="1"]:focus,
+html input[type="button"]:focus,
+html input[type="submit"]:focus,
+html input[type="reset"]:focus,
+html button:focus {
   outline: 0px !important;
   border-style: solid;
   border-color: rgb(94,128,153);
   background: white linear-gradient(rgba(255,255,255,0.2) 0, rgba(198,225,256,0.2) 18px, rgba(27,113,177,0.5) 100%);
 }
 
-input[type="checkbox"]:focus,
-input[type="radio"]:focus {
+html input[type="checkbox"]:focus,
+html input[type="radio"]:focus {
   border-color: #99c6e0 !important;
 }
 
-input[type="checkbox"]:focus {
+html input[type="checkbox"]:focus {
   background: white linear-gradient(rgba(27,113,177,0.5) 0, rgba(198,225,246,0.2) 2px, rgba(255,255,255,0.2) 6px);
 }
 
-input[type="radio"]:focus {
+html input[type="radio"]:focus {
   background: radial-gradient(at 6px 6px, rgba(255,255,255,0.2) 3px, rgba(198,225,246,0.2) 5px, rgba(27,113,177,0.5) 100%);
 }
 
 /* we need to be specific for selects because the above rules are specific too */
-textarea[disabled],
-select[size][disabled],
-select[multiple][disabled],
-select[size][multiple][disabled],
-select:not([size]):not([multiple])[disabled],
-select[size="0"][disabled],
-select[size="1"][disabled],
-button[disabled],
-* > input:not([type="image"])[disabled] {
+html textarea[disabled],
+html select[size][disabled],
+html select[multiple][disabled],
+html select[size][multiple][disabled],
+html select:not([size]):not([multiple])[disabled],
+html select[size="0"][disabled],
+html select[size="1"][disabled],
+html button[disabled],
+html * > input:not([type="image"])[disabled] {
   color: rgba(0,0,0,0.3);
   border-color: rgba(125,125,125,0.4);
   border-style: solid;
   border-width: 1px;
   background: transparent linear-gradient(rgba(185,185,185,0.4) 0, rgba(235,235,235,0.4) 3px, rgba(255,255,255,0.4) 100%);
 }
 
-select:not([size]):not([multiple])[disabled],
-select[size="0"][disabled],
-select[size="1"][disabled] {
+html select:not([size]):not([multiple])[disabled],
+html select[size="0"][disabled],
+html select[size="1"][disabled] {
   background: transparent linear-gradient(rgba(255,255,255,0.4) 0, rgba(235,235,235,0.4) 3px, rgba(185,185,185,0.4) 100%);
 }
 
-input[type="button"][disabled],
-input[type="submit"][disabled],
-input[type="reset"][disabled],
-button[disabled="true"] {
+html input[type="button"][disabled],
+html input[type="submit"][disabled],
+html input[type="reset"][disabled],
+html button[disabled="true"] {
   padding: 0 7px 0 7px;
   background: transparent linear-gradient(rgba(255,255,255,0.4) 0, rgba(235,235,235,0.4) 3px, rgba(185,185,185,0.4) 100%);
 }
 
-input[type="radio"][disabled],
-input[type="radio"][disabled]:active,
-input[type="radio"][disabled]:hover,
-input[type="radio"][disabled]:hover:active,
-input[type="checkbox"][disabled],
-input[type="checkbox"][disabled]:active,
-input[type="checkbox"][disabled]:hover,
-input[type="checkbox"][disabled]:hover:active {
+html input[type="radio"][disabled],
+html input[type="radio"][disabled]:active,
+html input[type="radio"][disabled]:hover,
+html input[type="radio"][disabled]:hover:active,
+html input[type="checkbox"][disabled],
+html input[type="checkbox"][disabled]:active,
+html input[type="checkbox"][disabled]:hover,
+html input[type="checkbox"][disabled]:hover:active {
   border:1px solid rgba(125,125,125,0.4) !important;
 }
 
-select[disabled] > button {
+html select[disabled] > button {
   opacity: 0.6;