Merge with mozilla-central as of c5dc9d84d476, and restore obj-to-boolean fixes
authorshaver@mozilla.org
Sun, 29 Jun 2008 10:01:59 -0400
changeset 17353 d5babbef5f31c07618ce86d434de50a4c22443f3
parent 17352 5406f43960b997c6782e889a027b50bbd386d7bf (current diff)
parent 15580 c5dc9d84d4763e640d6bdfb92603f28b554d7b0b (diff)
child 17354 2a09d92140a0334e4de9d22c775e11b908355d12
push idunknown
push userunknown
push dateunknown
milestone1.9.1a1pre
Merge with mozilla-central as of c5dc9d84d476, and restore obj-to-boolean fixes from 2b107c27dedf (accidentally backed out during an earlier merge). 22 test suite failures for -L lc2 lc3 spidermonkey-n slow-n, probably needs some guard work in TRY_BRANCH_AFTER_COND.
.hgtags
content/svg/content/src/nsSVGAnimatedString.cpp
content/svg/content/src/nsSVGAnimatedString.h
content/xul/document/src/nsElementMap.cpp
content/xul/document/src/nsElementMap.h
js/src/Makefile.in
js/src/Makefile.ref
js/src/config.mk
js/src/fdlibm/Makefile.in
js/src/fdlibm/Makefile.ref
js/src/fdlibm/e_acos.c
js/src/fdlibm/e_acosh.c
js/src/fdlibm/e_asin.c
js/src/fdlibm/e_atan2.c
js/src/fdlibm/e_atanh.c
js/src/fdlibm/e_cosh.c
js/src/fdlibm/e_exp.c
js/src/fdlibm/e_fmod.c
js/src/fdlibm/e_gamma.c
js/src/fdlibm/e_gamma_r.c
js/src/fdlibm/e_hypot.c
js/src/fdlibm/e_j0.c
js/src/fdlibm/e_j1.c
js/src/fdlibm/e_jn.c
js/src/fdlibm/e_lgamma.c
js/src/fdlibm/e_lgamma_r.c
js/src/fdlibm/e_log.c
js/src/fdlibm/e_log10.c
js/src/fdlibm/e_pow.c
js/src/fdlibm/e_rem_pio2.c
js/src/fdlibm/e_remainder.c
js/src/fdlibm/e_scalb.c
js/src/fdlibm/e_sinh.c
js/src/fdlibm/e_sqrt.c
js/src/fdlibm/fdlibm.h
js/src/fdlibm/fdlibm.mak
js/src/fdlibm/fdlibm.mdp
js/src/fdlibm/k_cos.c
js/src/fdlibm/k_rem_pio2.c
js/src/fdlibm/k_sin.c
js/src/fdlibm/k_standard.c
js/src/fdlibm/k_tan.c
js/src/fdlibm/s_asinh.c
js/src/fdlibm/s_atan.c
js/src/fdlibm/s_cbrt.c
js/src/fdlibm/s_ceil.c
js/src/fdlibm/s_copysign.c
js/src/fdlibm/s_cos.c
js/src/fdlibm/s_erf.c
js/src/fdlibm/s_expm1.c
js/src/fdlibm/s_fabs.c
js/src/fdlibm/s_finite.c
js/src/fdlibm/s_floor.c
js/src/fdlibm/s_frexp.c
js/src/fdlibm/s_ilogb.c
js/src/fdlibm/s_isnan.c
js/src/fdlibm/s_ldexp.c
js/src/fdlibm/s_lib_version.c
js/src/fdlibm/s_log1p.c
js/src/fdlibm/s_logb.c
js/src/fdlibm/s_matherr.c
js/src/fdlibm/s_modf.c
js/src/fdlibm/s_nextafter.c
js/src/fdlibm/s_rint.c
js/src/fdlibm/s_scalbn.c
js/src/fdlibm/s_signgam.c
js/src/fdlibm/s_significand.c
js/src/fdlibm/s_sin.c
js/src/fdlibm/s_tan.c
js/src/fdlibm/s_tanh.c
js/src/fdlibm/w_acos.c
js/src/fdlibm/w_acosh.c
js/src/fdlibm/w_asin.c
js/src/fdlibm/w_atan2.c
js/src/fdlibm/w_atanh.c
js/src/fdlibm/w_cosh.c
js/src/fdlibm/w_exp.c
js/src/fdlibm/w_fmod.c
js/src/fdlibm/w_gamma.c
js/src/fdlibm/w_gamma_r.c
js/src/fdlibm/w_hypot.c
js/src/fdlibm/w_j0.c
js/src/fdlibm/w_j1.c
js/src/fdlibm/w_jn.c
js/src/fdlibm/w_lgamma.c
js/src/fdlibm/w_lgamma_r.c
js/src/fdlibm/w_log.c
js/src/fdlibm/w_log10.c
js/src/fdlibm/w_pow.c
js/src/fdlibm/w_remainder.c
js/src/fdlibm/w_scalb.c
js/src/fdlibm/w_sinh.c
js/src/fdlibm/w_sqrt.c
js/src/js.cpp
js/src/js.mak
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarena.cpp
js/src/jsarray.cpp
js/src/jsatom.cpp
js/src/jsbool.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscpucfg.cpp
js/src/jsdate.cpp
js/src/jsdbgapi.cpp
js/src/jsdhash.cpp
js/src/jsdtoa.cpp
js/src/jsemit.cpp
js/src/jsemit.h
js/src/jsexn.cpp
js/src/jsfile.cpp
js/src/jsfun.cpp
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jshash.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsinterpinlines.h
js/src/jsinvoke.cpp
js/src/jsiter.cpp
js/src/jskwgen.cpp
js/src/jslock.cpp
js/src/jslock.h
js/src/jslog2.cpp
js/src/jslong.cpp
js/src/jsmath.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsopcode.cpp
js/src/jsopcode.h
js/src/jsopcode.tbl
js/src/jsparse.cpp
js/src/jsprf.cpp
js/src/jsregexp.cpp
js/src/jsscan.cpp
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsstr.cpp
js/src/jstracerinlines.h
js/src/jsutil.cpp
js/src/jsxdrapi.cpp
js/src/jsxdrapi.h
js/src/jsxml.cpp
js/src/prmjtime.cpp
js/src/rules.mk
js/tests/create-patterns.pl
js/tests/test-browser.sh
js/tests/test-shell.sh
memory/jemalloc/tree.h
modules/oji/public/nsIJVMAuthTools.idl
modules/oji/src/nsJVMAuthTools.cpp
modules/oji/src/nsJVMAuthTools.h
testing/mochitest/runtests.pl.in
testing/sisyphus/data/download-check,firefox-1.5.0-ftp,mac.data
testing/sisyphus/data/download-check,firefox-1.5.0-ftp,win32.data
testing/sisyphus/data/download-check,firefox-2.0.0-ftp,mac.data
testing/sisyphus/data/download-check,firefox-2.0.0-ftp,win32.data
testing/sisyphus/data/download-check,firefox-all,mac.data
testing/sisyphus/data/download-check,firefox-all,win32.data
testing/sisyphus/data/download-check,firefox-all-older,mac.data
testing/sisyphus/data/download-check,firefox-all-older,win32.data
testing/sisyphus/data/download-check,thunderbird-1.5.0-ftp,mac.data
testing/sisyphus/data/download-check,thunderbird-1.5.0-ftp,win32.data
testing/sisyphus/data/download-check,thunderbird-2.0.0-ftp,mac.data
testing/sisyphus/data/download-check,thunderbird-2.0.0-ftp,win32.data
testing/sisyphus/data/download-check,thunderbird-all,mac.data
testing/sisyphus/data/download-check,thunderbird-all,win32.data
testing/sisyphus/data/download-check,thunderbird-all-older,mac.data
testing/sisyphus/data/download-check,thunderbird-all-older,win32.data
testing/sisyphus/data/firefox,1.8.0,nightly-mac.data
testing/sisyphus/data/firefox,1.8.0,nightly-win32.data
testing/sisyphus/data/firefox,1.8.1,nightly-mac.data
testing/sisyphus/data/firefox,1.8.1,nightly-win32.data
testing/sisyphus/data/firefox,1.9.0,nightly-mac.data
testing/sisyphus/data/firefox,1.9.0,nightly-win32.data
toolkit/mozapps/downloads/tests/browser/Makefile.in
toolkit/mozapps/downloads/tests/browser/browser_basic_functionality.js
toolkit/mozapps/downloads/tests/browser/browser_bug_394039.js
toolkit/mozapps/downloads/tests/browser/browser_bug_397935.js
toolkit/mozapps/downloads/tests/browser/browser_bug_406857.js
toolkit/mozapps/downloads/tests/browser/browser_bug_410289.js
toolkit/mozapps/downloads/tests/browser/browser_bug_411172.js
toolkit/mozapps/downloads/tests/browser/browser_bug_411172_mac.js
toolkit/mozapps/downloads/tests/browser/browser_bug_412360.js
toolkit/mozapps/downloads/tests/browser/browser_bug_413093.js
toolkit/mozapps/downloads/tests/browser/browser_bug_413985.js
toolkit/mozapps/downloads/tests/browser/browser_bug_416303.js
toolkit/mozapps/downloads/tests/browser/browser_cleanup_search.js
toolkit/mozapps/downloads/tests/browser/browser_multi_select.js
toolkit/mozapps/downloads/tests/browser/browser_multiword_search.js
toolkit/mozapps/downloads/tests/browser/browser_search_clearlist.js
toolkit/mozapps/downloads/tests/browser/browser_select_all.js
tools/patcher/MozAUSConfig.pm
tools/patcher/MozAUSLib.pm
tools/patcher/patcher2.cfg
tools/patcher/patcher2.pl
tools/release/Bootstrap/Config.pm
tools/release/Bootstrap/Step.pm
tools/release/Bootstrap/Step/Build.pm
tools/release/Bootstrap/Step/PatcherConfig.pm
tools/release/Bootstrap/Step/Repack.pm
tools/release/Bootstrap/Step/Sign.pm
tools/release/Bootstrap/Step/Source.pm
tools/release/Bootstrap/Step/Stage.pm
tools/release/Bootstrap/Step/Tag.pm
tools/release/Bootstrap/Step/Tag/Bump.pm
tools/release/Bootstrap/Step/Tag/Mozilla.pm
tools/release/Bootstrap/Step/Tag/Talkback.pm
tools/release/Bootstrap/Step/Tag/l10n.pm
tools/release/Bootstrap/Step/TinderConfig.pm
tools/release/Bootstrap/Step/Updates.pm
tools/release/Bootstrap/Util.pm
tools/release/Makefile
tools/release/MozBuild/TinderLogParse.pm
tools/release/MozBuild/Util.pm
tools/release/README
tools/release/bin/backupsnip
tools/release/bin/pushsnip
tools/release/bin/verify-locales.pl
tools/release/bootstrap.cfg.example
tools/release/configs/fx-moz18-bootstrap.cfg
tools/release/configs/fx-moz18-nightly-bootstrap.cfg
tools/release/configs/fx-moz18-nightly-staging-bootstrap.cfg
tools/release/configs/fx-moz18-staging-bootstrap.cfg
tools/release/configs/fx-moz180-bootstrap.cfg
tools/release/configs/fx-moz19-bootstrap.cfg
tools/release/configs/fx-moz19-nightly-bootstrap.cfg
tools/release/configs/fx-moz19-nightly-staging-bootstrap.cfg
tools/release/configs/fx-moz19-staging-bootstrap.cfg
tools/release/configs/tb-moz18-bootstrap.cfg
tools/release/configs/tb-moz18-staging-bootstrap.cfg
tools/release/configs/tb-moz180-bootstrap.cfg
tools/release/configs/tb-moz19-bootstrap.cfg
tools/release/configs/xr-moz19-bootstrap.cfg
tools/release/configs/xr-moz19-staging-bootstrap.cfg
tools/release/release
tools/release/t/Bootstrap/Step/Dummy.pm
tools/release/t/test.pl
tools/release/t/tinder-config.pl.orig
widget/public/nsIMenuBar.h
widget/src/cocoa/nsIMenu.h
widget/src/cocoa/nsIMenuItem.h
--- a/.hgignore
+++ b/.hgignore
@@ -11,23 +11,16 @@
 ^\.mozconfig\.out$
 ^configure$
 ^config\.cache$
 ^config\.log$
 
 # Empty marker file that's generated when we check out NSS
 ^security/manager/\.nss\.checkout$
 
-# subtrees from other repositories
-^nsprpub/
-^dbm/
-^security/nss/
-^security/coreconf/
-^security/dbm/
-
 # Build directories
 ^obj-
 ^objdir-
 
 # Build directories for js shell
 _DBG\.OBJ/
 _OPT\.OBJ/
 
--- a/.hgtags
+++ b/.hgtags
@@ -1,4 +1,4 @@
 df7a3c8ffeeaba229067efee5a20e21dae0dd877 MOZILLA_1_9_a4_BASE
 4209e16b58411750ac73f761023e46b76b793e2c MOZILLA_1_9_a6_BASE
 66a5c7bce7ee86a820d3c0d54fa07cb719be751c MOZILLA_1_9_a7_BASE
-d1a7596d788757799a1aa5f5d09eac32ff811831 tested
+caeba7562e495a9f604984df0b48b6f99bec3e2e FENNEC_M4
--- a/accessible/public/nsIAccessibleTreeCache.idl
+++ b/accessible/public/nsIAccessibleTreeCache.idl
@@ -42,17 +42,17 @@
 
 interface nsIAccessible;
 
 /**
  * A private interface to operate with tree accessible.
  *
  * @status UNDER_REVIEW
  */
-[uuid(7e0f50b0-6444-4372-b00f-4ce81c6b058a)]
+[uuid(1dde5c3b-bede-43d1-aabf-dabc461113bd)]
 interface nsIAccessibleTreeCache : nsISupports
 {
   /**
    * Get tree item from cache according to row and column, create if doesn't
    * exist in cache.
    *
    * @param aRow     the given row index
    * @param aColumn  the given column object. If is is nsnull then primary
@@ -77,16 +77,22 @@ interface nsIAccessibleTreeCache : nsISu
    * @param aStartRow  row index invalidation starts from
    * @param aEndRow    row index invalidation ends, -1 means last row index
    * @param aStartCol  column index invalidation starts from
    * @param aEndCol    column index invalidation ends, -1 mens last column
    *                   index
    */
   void treeViewInvalidated(in long aStartRow, in long aEndRow,
                            in long aStartCol, in long aEndCol);
+
+  /**
+   * Invalidates children created for previous tree view.
+   */
+  void treeViewChanged();
+
 };
 
 [uuid(b71532f9-53b2-4647-a5b2-1c5f57e9aed6)]
 interface nsPIAccessibleTreeItem : nsISupports
 {
   /**
    * Get/set cached name.
    */
--- a/accessible/src/atk/nsAccessibleWrap.cpp
+++ b/accessible/src/atk/nsAccessibleWrap.cpp
@@ -366,18 +366,19 @@ void nsAccessibleWrap::SetMaiHyperlink(M
     }
 }
 
 NS_IMETHODIMP nsAccessibleWrap::GetNativeInterface(void **aOutAccessible)
 {
     *aOutAccessible = nsnull;
 
     if (!mAtkObject) {
-        if (!IsEmbeddedObject(this)) {
-            // We don't create ATK objects for nsIAccessible plain text leaves
+        if (!mWeakShell || !IsEmbeddedObject(this)) {
+            // We don't create ATK objects for node which has been shutdown, or
+            // nsIAccessible plain text leaves
             return NS_ERROR_FAILURE;
         }
 
         GType type = GetMaiAtkType(CreateMaiInterfaces());
         NS_ENSURE_TRUE(type, NS_ERROR_FAILURE);
         mAtkObject =
             reinterpret_cast<AtkObject *>
                             (g_object_new(type, NULL));
@@ -1096,22 +1097,28 @@ nsAccessibleWrap *GetAccessibleWrap(AtkO
 }
 
 NS_IMETHODIMP
 nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
 {
     nsresult rv = nsAccessible::FireAccessibleEvent(aEvent);
     NS_ENSURE_SUCCESS(rv, rv);
 
+    return FirePlatformEvent(aEvent);
+}
+
+nsresult
+nsAccessibleWrap::FirePlatformEvent(nsIAccessibleEvent *aEvent)
+{
     nsCOMPtr<nsIAccessible> accessible;
     aEvent->GetAccessible(getter_AddRefs(accessible));
     NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE);
 
     PRUint32 type = 0;
-    rv = aEvent->GetEventType(&type);
+    nsresult rv = aEvent->GetEventType(&type);
     NS_ENSURE_SUCCESS(rv, rv);
 
     AtkObject *atkObj = nsAccessibleWrap::GetAtkObject(accessible);
 
     // We don't create ATK objects for nsIAccessible plain text leaves,
     // just return NS_OK in such case
     if (!atkObj) {
         NS_ASSERTION(type == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
--- a/accessible/src/atk/nsAccessibleWrap.h
+++ b/accessible/src/atk/nsAccessibleWrap.h
@@ -111,16 +111,18 @@ public:
 
     static const char * ReturnString(nsAString &aString) {
       static nsCString returnedString;
       returnedString = NS_ConvertUTF16toUTF8(aString);
       return returnedString.get();
     }
 
 protected:
+    virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent);
+
     nsresult FireAtkStateChangeEvent(nsIAccessibleEvent *aEvent,
                                      AtkObject *aObject);
     nsresult FireAtkTextChangedEvent(nsIAccessibleEvent *aEvent,
                                      AtkObject *aObject);
     nsresult FireAtkPropChangedEvent(nsIAccessibleEvent *aEvent,
                                      AtkObject *aObject);
     nsresult FireAtkShowHideEvent(nsIAccessibleEvent *aEvent,
                                   AtkObject *aObject, PRBool aIsAdded);
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -58,16 +58,17 @@
 
 static const nsStateMapEntry kEndEntry = {nsnull, 0, 0};  // To fill in array of state mappings
 
 nsRoleMapEntry nsARIAMap::gWAIRoleMap[] = 
 {
   {"alert", nsIAccessibleRole::ROLE_ALERT, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"alertdialog", nsIAccessibleRole::ROLE_ALERT, eNameOkFromChildren, eNoValue, kNoReqStates, kEndEntry},
   {"application", nsIAccessibleRole::ROLE_APPLICATION, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
+  {"article", nsIAccessibleRole::ROLE_DOCUMENT, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
   {"button", nsIAccessibleRole::ROLE_PUSHBUTTON, eNameOkFromChildren, eNoValue, kNoReqStates,
             {&nsAccessibilityAtoms::aria_pressed, kBoolState, nsIAccessibleStates::STATE_PRESSED},
             {&nsAccessibilityAtoms::aria_pressed, "mixed", nsIAccessibleStates::STATE_MIXED}, kEndEntry},
   {"checkbox", nsIAccessibleRole::ROLE_CHECKBUTTON, eNameOkFromChildren, eNoValue, nsIAccessibleStates::STATE_CHECKABLE,
             {&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED},
             {&nsAccessibilityAtoms::aria_checked, "mixed", nsIAccessibleStates::STATE_MIXED},
             {&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
   {"columnheader", nsIAccessibleRole::ROLE_COLUMNHEADER, eNameOkFromChildren, eNoValue, kNoReqStates,
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -1323,39 +1323,36 @@ NS_IMETHODIMP nsAccessibilityService::Ge
   nsCOMPtr<nsIDOMElement> element(do_QueryInterface(aNode));
   if (element) {
     element->GetAttribute(NS_LITERAL_STRING("type"), attrib);
     if (attrib.EqualsLiteral("statusbarpanel"))
       printf("## aaronl debugging attribute\n");
   }
 #endif
 
-  nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
-  if (content && content->Tag() == nsAccessibilityAtoms::map) {
-    // Don't walk into maps, they take up no space.
-    // The nsHTMLAreaAccessible's they contain are attached as
-    // children of the appropriate nsHTMLImageAccessible.
-    *aIsHidden = PR_TRUE;
-    return NS_OK;
-  }
-
   // Check to see if we already have an accessible for this
   // node in the cache
   nsCOMPtr<nsIAccessNode> accessNode;
   GetCachedAccessNode(aNode, aWeakShell, getter_AddRefs(accessNode));
 
   nsCOMPtr<nsIAccessible> newAcc;
   if (accessNode) {
-    // Retrieved from cache
-    // QI might not succeed if it's a node that's not accessible
+    // Retrieved from cache. QI might not succeed if it's a node that's not
+    // accessible. In this case try to create new accessible because one and
+    // the same DOM node may be accessible or not in time (for example,
+    // when it is visible or hidden).
     newAcc = do_QueryInterface(accessNode);
-    NS_IF_ADDREF(*aAccessible = newAcc);
-    return NS_OK;
+    if (newAcc) {
+      NS_ADDREF(*aAccessible = newAcc);
+      return NS_OK;
+    }
   }
 
+  nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
+
   // No cache entry, so we must create the accessible
   // Check to see if hidden first
   nsCOMPtr<nsIDocument> nodeIsDoc;
   if (!content) {
     // This happens when we're on the document node, which will not QI to an
     // nsIContent.
     nodeIsDoc = do_QueryInterface(aNode);
     NS_ENSURE_TRUE(nodeIsDoc, NS_ERROR_FAILURE); // No content, and not doc node
@@ -1456,31 +1453,51 @@ NS_IMETHODIMP nsAccessibilityService::Ge
         *aIsHidden = PR_TRUE;
         return NS_OK;
       }
     }
     frame->GetAccessible(getter_AddRefs(newAcc));
     return InitAccessible(newAcc, aAccessible, nsnull);
   }
 
+  PRBool isHTML = content->IsNodeOfType(nsINode::eHTML);
+  if (isHTML && content->Tag() == nsAccessibilityAtoms::map) {
+    // Create hyper text accessible for HTML map if it is used to group links
+    // (see http://www.w3.org/TR/WCAG10-HTML-TECHS/#group-bypass). If the HTML
+    // map doesn't have 'name' attribute (or has empty name attribute) then we
+    // suppose it is used for links grouping. Otherwise we think it is used in
+    // conjuction with HTML image element and in this case we don't create any
+    // accessible for it and don't walk into it. The accessibles for HTML area
+    // (nsHTMLAreaAccessible) the map contains are attached as children of the
+    // appropriate accessible for HTML image (nsHTMLImageAccessible).
+    nsAutoString name;
+    content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::name, name);
+    if (!name.IsEmpty()) {
+      *aIsHidden = PR_TRUE;
+      return NS_OK;
+    }
+    
+    nsresult rv = CreateHyperTextAccessible(frame, getter_AddRefs(newAcc));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
   nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(aNode);
   if (roleMapEntry && !nsCRT::strcmp(roleMapEntry->roleString, "presentation") &&
       !content->IsFocusable()) { // For presentation only
     // Only create accessible for role of "presentation" if it is focusable --
     // in that case we need an accessible in case it gets focused, we
     // don't want focus ever to be 'lost'
     return NS_OK;
   }
 
   // Elements may implement nsIAccessibleProvider via XBL. This allows them to
   // say what kind of accessible to create.
   nsresult rv = GetAccessibleByType(aNode, getter_AddRefs(newAcc));
   NS_ENSURE_SUCCESS(rv, rv);
-  
-  PRBool isHTML = content->IsNodeOfType(nsINode::eHTML);
+
   if (!newAcc && !isHTML) {
     if (content->GetNameSpaceID() == kNameSpaceID_SVG &&
              content->Tag() == nsAccessibilityAtoms::svg) {
       newAcc = new nsEnumRoleAccessible(aNode, aWeakShell,
                                         nsIAccessibleRole::ROLE_DIAGRAM);
     }
     else if (content->GetNameSpaceID() == kNameSpaceID_MathML &&
              content->Tag() == nsAccessibilityAtoms::math) {
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -2040,16 +2040,19 @@ NS_IMETHODIMP nsAccessible::GetFinalRole
   return mDOMNode ? GetRole(aRole) : NS_ERROR_FAILURE;  // Node already shut down
 }
 
 NS_IMETHODIMP
 nsAccessible::GetAttributes(nsIPersistentProperties **aAttributes)
 {
   NS_ENSURE_ARG_POINTER(aAttributes);  // In/out param. Created if necessary.
   
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
   nsCOMPtr<nsIContent> content = GetRoleContent(mDOMNode);
   if (!content) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIPersistentProperties> attributes = *aAttributes;
   if (!attributes) {
     // Create only if an array wasn't already passed in
@@ -2109,46 +2112,72 @@ nsAccessible::GetAttributes(nsIPersisten
   if (!nsAccUtils::HasAccGroupAttrs(attributes)) {
     // The role of an accessible can be pointed by ARIA attribute but ARIA
     // posinset, level, setsize may be skipped. Therefore we calculate here
     // these properties to map them into description.
 
     // If accessible is invisible we don't want to calculate group ARIA
     // attributes for it.
     if ((role == nsIAccessibleRole::ROLE_LISTITEM ||
-        role == nsIAccessibleRole::ROLE_MENUITEM ||
-        role == nsIAccessibleRole::ROLE_RADIOBUTTON ||
-        role == nsIAccessibleRole::ROLE_PAGETAB ||
-        role == nsIAccessibleRole::ROLE_OPTION ||
-        role == nsIAccessibleRole::ROLE_RADIOBUTTON ||
-        role == nsIAccessibleRole::ROLE_OUTLINEITEM) &&
+         role == nsIAccessibleRole::ROLE_MENUITEM ||
+         role == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
+         role == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM ||
+         role == nsIAccessibleRole::ROLE_RADIOBUTTON ||
+         role == nsIAccessibleRole::ROLE_PAGETAB ||
+         role == nsIAccessibleRole::ROLE_OPTION ||
+         role == nsIAccessibleRole::ROLE_RADIOBUTTON ||
+         role == nsIAccessibleRole::ROLE_OUTLINEITEM) &&
         0 == (State(this) & nsIAccessibleStates::STATE_INVISIBLE)) {
+
+      PRUint32 baseRole = role;
+      if (role == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
+          role == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM)
+        baseRole = nsIAccessibleRole::ROLE_MENUITEM;
+
       nsCOMPtr<nsIAccessible> parent = GetParent();
       NS_ENSURE_TRUE(parent, NS_ERROR_FAILURE);
 
       PRInt32 positionInGroup = 0;
       PRInt32 setSize = 0;
 
       nsCOMPtr<nsIAccessible> sibling, nextSibling;
       parent->GetFirstChild(getter_AddRefs(sibling));
       NS_ENSURE_TRUE(sibling, NS_ERROR_FAILURE);
 
       PRBool foundCurrent = PR_FALSE;
-      PRUint32 siblingRole;
+      PRUint32 siblingRole, siblingBaseRole;
       while (sibling) {
         sibling->GetFinalRole(&siblingRole);
-        if (siblingRole == role &&
+
+        siblingBaseRole = siblingRole;
+        if (siblingRole == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
+            siblingRole == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM)
+          siblingBaseRole = nsIAccessibleRole::ROLE_MENUITEM;
+
+        // If sibling is visible and has the same base role.
+        if (siblingBaseRole == baseRole &&
             !(State(sibling) & nsIAccessibleStates::STATE_INVISIBLE)) {
           ++ setSize;
           if (!foundCurrent) {
             ++ positionInGroup;
             if (sibling == this)
               foundCurrent = PR_TRUE;
           }
         }
+
+        // If the sibling is separator
+        if (siblingRole == nsIAccessibleRole::ROLE_SEPARATOR) {
+          if (foundCurrent) // the our group is ended
+            break;
+
+          // not our group, continue the searching
+          positionInGroup = 0;
+          setSize = 0;
+        }
+
         sibling->GetNextSibling(getter_AddRefs(nextSibling));
         sibling = nextSibling;
       }
 
       PRInt32 groupLevel = 0;
       if (role == nsIAccessibleRole::ROLE_OUTLINEITEM) {
         groupLevel = 1;
         nsCOMPtr<nsIAccessible> nextParent;
@@ -2463,34 +2492,49 @@ nsAccessible::GetARIAState(PRUint32 *aSt
     return NS_OK;
   }
 
   PRUint32 index = 0;
   while (MappedAttrState(content, aState, &nsARIAMap::gWAIUnivStateMap[index])) {
     ++ index;
   }
 
-  if (!mRoleMapEntry)
-    return NS_OK;
-
-  // Once DHTML role is used, we're only readonly if DHTML readonly used
-  *aState &= ~nsIAccessibleStates::STATE_READONLY;
-
-  if (content->HasAttr(kNameSpaceID_None, content->GetIDAttributeName())) {
-    // If has a role & ID and aria-activedescendant on the container, assume focusable
-    nsIContent *ancestorContent = content;
-    while ((ancestorContent = ancestorContent->GetParent()) != nsnull) {
-      if (ancestorContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_activedescendant)) {
-          // ancestor has activedescendant property, this content could be active
-        *aState |= nsIAccessibleStates::STATE_FOCUSABLE;
-        break;
+  if (mRoleMapEntry) {
+    // Once DHTML role is used, we're only readonly if DHTML readonly used
+    *aState &= ~nsIAccessibleStates::STATE_READONLY;
+
+    if (content->HasAttr(kNameSpaceID_None, content->GetIDAttributeName())) {
+      // If has a role & ID and aria-activedescendant on the container, assume focusable
+      nsIContent *ancestorContent = content;
+      while ((ancestorContent = ancestorContent->GetParent()) != nsnull) {
+        if (ancestorContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_activedescendant)) {
+            // ancestor has activedescendant property, this content could be active
+          *aState |= nsIAccessibleStates::STATE_FOCUSABLE;
+          break;
+        }
       }
     }
   }
 
+  if (*aState & nsIAccessibleStates::STATE_FOCUSABLE) {
+    // Special case: aria-disabled propagates from ancestors down to any focusable descendant
+    nsIContent *ancestorContent = content;
+    while ((ancestorContent = ancestorContent->GetParent()) != nsnull) {
+      if (ancestorContent->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::aria_disabled,
+                                       nsAccessibilityAtoms::_true, eCaseMatters)) {
+          // ancestor has aria-disabled property, this is disabled
+        *aState |= nsIAccessibleStates::STATE_UNAVAILABLE;
+        break;
+      }
+    }    
+  }
+
+  if (!mRoleMapEntry)
+    return NS_OK;
+
   *aState |= mRoleMapEntry->state;
   if (MappedAttrState(content, aState, &mRoleMapEntry->attributeMap1) &&
       MappedAttrState(content, aState, &mRoleMapEntry->attributeMap2) &&
       MappedAttrState(content, aState, &mRoleMapEntry->attributeMap3) &&
       MappedAttrState(content, aState, &mRoleMapEntry->attributeMap4) &&
       MappedAttrState(content, aState, &mRoleMapEntry->attributeMap5) &&
       MappedAttrState(content, aState, &mRoleMapEntry->attributeMap6) &&
       MappedAttrState(content, aState, &mRoleMapEntry->attributeMap7)) {
@@ -2654,18 +2698,21 @@ NS_IMETHODIMP
 nsAccessible::GetNumActions(PRUint8 *aNumActions)
 {
   NS_ENSURE_ARG_POINTER(aNumActions);
   *aNumActions = 0;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
+  nsCOMPtr<nsIContent> content = GetRoleContent(mDOMNode);
+  if (!content)
+    return NS_OK;
+
   // Check if it's an simple xlink.
-  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   if (nsAccUtils::IsXLink(content)) {
     *aNumActions = 1;
     return NS_OK;
   }
 
   // Has registered 'click' event handler.
   PRBool isOnclick = nsAccUtils::HasListener(content,
                                              NS_LITERAL_STRING("click"));
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -241,16 +241,26 @@ protected:
    *
    * @param aAriaProperty - the ARIA property we're using
    * @param aValue - value of the attribute
    *
    * @return - NS_OK_NO_ARIA_VALUE if there is no setted ARIA attribute
    */
   nsresult GetAttrValue(nsIAtom *aAriaProperty, double *aValue);
 
+  /**
+   * Fires platform accessible event. It's notification method only. It does
+   * change nothing on Gecko side. Mostly you should use
+   * nsIAccessible::FireAccessibleEvent excepting special cases like we have
+   * in xul:tree accessible to lie to AT. Must be overridden in wrap classes.
+   *
+   * @param aEvent  the accessible event to fire.
+   */
+  virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent) = 0;
+
   // Data Members
   nsCOMPtr<nsIAccessible> mParent;
   nsIAccessible *mFirstChild, *mNextSibling;
   nsRoleMapEntry *mRoleMapEntry; // Non-null indicates author-supplied role; possibly state & value as well
   PRInt32 mAccChildCount;
 };
 
 
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -80,17 +80,18 @@
 PRUint32 nsDocAccessible::gLastFocusedAccessiblesState = 0;
 nsIAtom *nsDocAccessible::gLastFocusedFrameType = nsnull;
 
 //-----------------------------------------------------
 // construction
 //-----------------------------------------------------
 nsDocAccessible::nsDocAccessible(nsIDOMNode *aDOMNode, nsIWeakReference* aShell):
   nsHyperTextAccessibleWrap(aDOMNode, aShell), mWnd(nsnull),
-  mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE), mIsLoadCompleteFired(PR_FALSE)
+  mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE),
+  mIsLoadCompleteFired(PR_FALSE), mInFlushPendingEvents(PR_FALSE)
 {
   // For GTK+ native window, we do nothing here.
   if (!mDOMNode)
     return;
 
   // Because of the way document loading happens, the new nsIWidget is created before
   // the old one is removed. Since it creates the nsDocAccessible, for a brief moment
   // there can be 2 nsDocAccessible's for the content area, although for 2 different
@@ -511,18 +512,30 @@ NS_IMETHODIMP nsDocAccessible::GetCached
     if (privateParent) {
       privateParent->TestChildCache(accessible);
     }
   }
 #endif
   return NS_OK;
 }
 
-NS_IMETHODIMP nsDocAccessible::CacheAccessNode(void *aUniqueID, nsIAccessNode *aAccessNode)
+NS_IMETHODIMP
+nsDocAccessible::CacheAccessNode(void *aUniqueID, nsIAccessNode *aAccessNode)
 {
+  // If there is an access node for the given unique ID then let's shutdown it.
+  // The unique ID may be presented in the cache if originally we created
+  // access node object and then we want to create accessible object when
+  // DOM node is changed.
+  nsCOMPtr<nsIAccessNode> accessNode;
+  GetCacheEntry(mAccessNodeCache, aUniqueID, getter_AddRefs(accessNode));
+  if (accessNode) {
+    nsCOMPtr<nsPIAccessNode> prAccessNode = do_QueryInterface(accessNode);
+    prAccessNode->Shutdown();
+  }
+
   PutCacheEntry(mAccessNodeCache, aUniqueID, aAccessNode);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsDocAccessible::GetParent(nsIAccessible **aParent)
 {
   // Hook up our new accessible with our parent
   *aParent = nsnull;
@@ -584,17 +597,20 @@ NS_IMETHODIMP nsDocAccessible::Shutdown(
   if (mFireEventTimer) {
     // Doc being shut down before events fired,
     mFireEventTimer->Cancel();
     mFireEventTimer = nsnull;
     if (mEventsToFire.Count() > 0 ) {
       mEventsToFire.Clear();
       // Make sure we release the kung fu death grip which is always
       // there when there are still events left to be fired
-      NS_RELEASE_THIS();
+      // If FlushPendingEvents() is in call stack,
+      // kung fu death grip will be released there.
+      if (!mInFlushPendingEvents)
+        NS_RELEASE_THIS();
     }
   }
 
   // Remove from the cache after other parts of Shutdown(), so that Shutdown() procedures
   // can find the doc or root accessible in the cache if they need it.
   // We don't do this during ShutdownAccessibility() because that is already clearing the cache
   if (!gIsShuttingDownApp)
     gGlobalDocAccessibleCache.Remove(static_cast<void*>(kungFuDeathGripDoc));
@@ -1500,16 +1516,17 @@ nsDocAccessible::FireDelayedAccessibleEv
                                           0, nsITimer::TYPE_ONE_SHOT);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
 {
+  mInFlushPendingEvents = PR_TRUE;
   PRUint32 length = mEventsToFire.Count();
   NS_ASSERTION(length, "How did we get here without events to fire?");
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   if (!presShell)
     length = 0; // The doc is now shut down, don't fire events in it anymore
   else
     nsAccEvent::ApplyEventRules(mEventsToFire);
   
@@ -1523,18 +1540,18 @@ NS_IMETHODIMP nsDocAccessible::FlushPend
     nsCOMPtr<nsIAccessible> accessible;
     accessibleEvent->GetAccessible(getter_AddRefs(accessible));
     nsCOMPtr<nsIDOMNode> domNode;
     accessibleEvent->GetDOMNode(getter_AddRefs(domNode));
     PRUint32 eventType = nsAccEvent::EventType(accessibleEvent);
     PRBool isFromUserInput = nsAccEvent::IsFromUserInput(accessibleEvent);
 
     if (domNode == gLastFocusedNode &&
-        eventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE || 
-        eventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW) {
+        (eventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE || 
+        eventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW)) {
       // If frame type didn't change for this event, then we don't actually need to invalidate
       // However, we only keep track of the old frame type for the focus, where it's very
       // important not to destroy and recreate the accessible for minor style changes,
       // such as a:focus { overflow: scroll; }
       nsCOMPtr<nsIContent> focusContent(do_QueryInterface(domNode));
       if (focusContent) {
         nsIFrame *focusFrame = presShell->GetRealPrimaryFrameFor(focusContent);
         nsIAtom *newFrameType =
@@ -1620,17 +1637,18 @@ NS_IMETHODIMP nsDocAccessible::FlushPend
           // Test caret line # -- fire an EVENT_ALERT on the focused node so we can watch the
           // line-number object attribute on it
           nsCOMPtr<nsIAccessible> accForFocus;
           GetAccService()->GetAccessibleFor(gLastFocusedNode, getter_AddRefs(accForFocus));
           nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_ALERT, accForFocus);
 #endif
           nsCOMPtr<nsIAccessibleCaretMoveEvent> caretMoveEvent =
             new nsAccCaretMoveEvent(accessible, caretOffset);
-          NS_ENSURE_TRUE(caretMoveEvent, NS_ERROR_OUT_OF_MEMORY);
+          if (!caretMoveEvent)
+            break; // Out of memory, break out to release kung fu death grip
 
           FireAccessibleEvent(caretMoveEvent);
 
           PRInt32 selectionCount;
           accessibleText->GetSelectionCount(&selectionCount);
           if (selectionCount) {  // There's a selection so fire selection change as well
             nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
                                      accessible, PR_TRUE);
@@ -1656,16 +1674,17 @@ NS_IMETHODIMP nsDocAccessible::FlushPend
     }
   }
   mEventsToFire.Clear(); // Clear out array
   NS_RELEASE_THIS(); // Release kung fu death grip
 
   // After a flood of events, reset so that user input flag is off
   nsAccEvent::ResetLastInputState();
 
+  mInFlushPendingEvents = PR_FALSE;
   return NS_OK;
 }
 
 void nsDocAccessible::FlushEventsCallback(nsITimer *aTimer, void *aClosure)
 {
   nsPIAccessibleDocument *accessibleDoc = static_cast<nsPIAccessibleDocument*>(aClosure);
   NS_ASSERTION(accessibleDoc, "How did we get here without an accessible document?");
   if (accessibleDoc) {
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -216,13 +216,14 @@ class nsDocAccessible : public nsHyperTe
     PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
     PRPackedBool mIsContentLoaded;
     PRPackedBool mIsLoadCompleteFired;
     nsCOMArray<nsIAccessibleEvent> mEventsToFire;
 
 protected:
     PRBool mIsAnchor;
     PRBool mIsAnchorJumped;
+    PRBool mInFlushPendingEvents;
     static PRUint32 gLastFocusedAccessiblesState;
     static nsIAtom *gLastFocusedFrameType;
 };
 
 #endif  
--- a/accessible/src/base/nsOuterDocAccessible.cpp
+++ b/accessible/src/base/nsOuterDocAccessible.cpp
@@ -143,8 +143,40 @@ nsOuterDocAccessible::GetAttributesInter
   aAttributes->GetStringProperty(NS_LITERAL_CSTRING("tag"), tag);
   if (!tag.IsEmpty()) {
     // We're overriding the ARIA attributes on an sub document, but we don't want to
     // override the other attributes
     return NS_OK;
   }
   return nsAccessible::GetAttributesInternal(aAttributes);
 }
+
+// Internal frame, which is the doc's parent, should not have a click action
+NS_IMETHODIMP
+nsOuterDocAccessible::GetNumActions(PRUint8 *aNumActions)
+{
+  NS_ENSURE_ARG_POINTER(aNumActions);
+  *aNumActions = 0;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsOuterDocAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
+{
+  aName.Truncate();
+
+  return NS_ERROR_INVALID_ARG;
+}
+
+NS_IMETHODIMP
+nsOuterDocAccessible::GetActionDescription(PRUint8 aIndex, nsAString& aDescription)
+{
+  aDescription.Truncate();
+
+  return NS_ERROR_INVALID_ARG;
+}
+
+NS_IMETHODIMP
+nsOuterDocAccessible::DoAction(PRUint8 aIndex)
+{
+  return NS_ERROR_INVALID_ARG;
+}
--- a/accessible/src/base/nsOuterDocAccessible.h
+++ b/accessible/src/base/nsOuterDocAccessible.h
@@ -53,11 +53,15 @@ class nsOuterDocAccessible : public nsAc
                          nsIWeakReference* aShell);
 
     NS_IMETHOD GetRole(PRUint32 *aRole);
     NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
     NS_IMETHOD GetChildAtPoint(PRInt32 aX, PRInt32 aY,
                                nsIAccessible **aAccessible);
     void CacheChildren();
     nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
+    NS_IMETHOD GetNumActions(PRUint8 *aNumActions);
+    NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
+    NS_IMETHODIMP GetActionDescription(PRUint8 aIndex, nsAString& aDescription);
+    NS_IMETHOD DoAction(PRUint8 aIndex);
 };
 
 #endif  
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -638,28 +638,16 @@ nsresult nsRootAccessible::HandleEventWi
   if (eventType.EqualsLiteral("DOMContentLoaded")) {
     // Don't create the doc accessible until load scripts have a chance to set
     // role attribute for <body> or <html> element, because the value of 
     // role attribute will be cached when the doc accessible is Init()'d
     TryFireEarlyLoadEvent(aTargetNode);
     return NS_OK;
   }
 
-#ifdef MOZ_XUL
-  if (eventType.EqualsLiteral("TreeViewChanged")) { // Always asynch, always from user input
-    if (!isTree)
-      return NS_OK;
-
-    nsCOMPtr<nsIContent> treeContent = do_QueryInterface(aTargetNode);
-    nsAccEvent::PrepareForEvent(aTargetNode, PR_TRUE);
-    return accService->InvalidateSubtreeFor(eventShell, treeContent,
-                                            nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
-  }
-#endif
-
   if (eventType.EqualsLiteral("popuphiding")) {
     // If accessible focus was on or inside popup that closes,
     // then restore it to true current focus.
     // This is the case when we've been getting DOMMenuItemActive events
     // inside of a combo box that closes. The real focus is on the combo box.
     // It's also the case when a popup gets focus in ATK -- when it closes
     // we need to fire an event to restore focus to where it was
     if (!gLastFocusedNode ||
@@ -673,21 +661,32 @@ nsresult nsRootAccessible::HandleEventWi
   nsCOMPtr<nsIAccessible> accessible;
   accService->GetAccessibleInShell(aTargetNode, eventShell,
                                    getter_AddRefs(accessible));
   nsCOMPtr<nsPIAccessible> privAcc(do_QueryInterface(accessible));
   if (!privAcc)
     return NS_OK;
 
 #ifdef MOZ_XUL
-  if (eventType.EqualsLiteral("TreeRowCountChanged"))
-    return HandleTreeRowCountChangedEvent(aEvent, accessible, localName);
-  
-  if (eventType.EqualsLiteral("TreeInvalidated"))
-    return HandleTreeInvalidatedEvent(aEvent, accessible, localName);
+  if (isTree) {
+    nsCOMPtr<nsIAccessibleTreeCache> treeAcc(do_QueryInterface(accessible));
+    NS_ASSERTION(treeAcc,
+                 "Accessible for xul:tree doesn't implement nsIAccessibleTreeCache interface.");
+
+    if (treeAcc) {
+      if (eventType.EqualsLiteral("TreeViewChanged"))
+        return treeAcc->TreeViewChanged();
+
+      if (eventType.EqualsLiteral("TreeRowCountChanged"))
+        return HandleTreeRowCountChangedEvent(aEvent, treeAcc);
+      
+      if (eventType.EqualsLiteral("TreeInvalidated"))
+        return HandleTreeInvalidatedEvent(aEvent, treeAcc);
+    }
+  }
 #endif
 
   if (eventType.EqualsLiteral("RadioStateChange")) {
     PRUint32 state = State(accessible);
 
     // radiogroup in prefWindow is exposed as a list,
     // and panebutton is exposed as XULListitem in A11y.
     // nsXULListitemAccessible::GetState uses STATE_SELECTED in this case,
@@ -1090,22 +1089,18 @@ NS_IMETHODIMP nsRootAccessible::FireDocL
   mIsContentLoaded = (aEventType == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE ||
                       aEventType == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED);
 
   return NS_OK;
 }
 
 nsresult
 nsRootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
-                                                 nsIAccessible *aAccessible,
-                                                 const nsAString& aTargetName)
+                                                 nsIAccessibleTreeCache *aAccessible)
 {
-  if (!aTargetName.EqualsLiteral("tree"))
-    return NS_OK;
-
   nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
   if (!dataEvent)
     return NS_OK;
 
   nsCOMPtr<nsIVariant> indexVariant;
   dataEvent->GetData(NS_LITERAL_STRING("index"),
                      getter_AddRefs(indexVariant));
   if (!indexVariant)
@@ -1116,30 +1111,23 @@ nsRootAccessible::HandleTreeRowCountChan
                      getter_AddRefs(countVariant));
   if (!countVariant)
     return NS_OK;
 
   PRInt32 index, count;
   indexVariant->GetAsInt32(&index);
   countVariant->GetAsInt32(&count);
 
-  nsCOMPtr<nsIAccessibleTreeCache> treeAccCache(do_QueryInterface(aAccessible));
-  NS_ENSURE_STATE(treeAccCache);
-
-  return treeAccCache->InvalidateCache(index, count);
+  return aAccessible->InvalidateCache(index, count);
 }
 
 nsresult
 nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
-                                             nsIAccessible *aAccessible,
-                                             const nsAString& aTargetName)
+                                             nsIAccessibleTreeCache *aAccessible)
 {
-  if (!aTargetName.EqualsLiteral("tree"))
-    return NS_OK;
-
   nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
   if (!dataEvent)
     return NS_OK;
 
   PRInt32 startRow = 0, endRow = -1, startCol = 0, endCol = -1;
 
   nsCOMPtr<nsIVariant> startRowVariant;
   dataEvent->GetData(NS_LITERAL_STRING("startrow"),
@@ -1160,14 +1148,11 @@ nsRootAccessible::HandleTreeInvalidatedE
     startColVariant->GetAsInt32(&startCol);
 
   nsCOMPtr<nsIVariant> endColVariant;
   dataEvent->GetData(NS_LITERAL_STRING("endcolumn"),
                      getter_AddRefs(endColVariant));
   if (endColVariant)
     endColVariant->GetAsInt32(&endCol);
 
-  nsCOMPtr<nsIAccessibleTreeCache> treeAcc(do_QueryInterface(aAccessible));
-  NS_ENSURE_STATE(treeAcc);
-
-  return treeAcc->TreeViewInvalidated(startRow, endRow, startCol, endCol);
+  return aAccessible->TreeViewInvalidated(startRow, endRow, startCol, endCol);
 }
 
--- a/accessible/src/base/nsRootAccessible.h
+++ b/accessible/src/base/nsRootAccessible.h
@@ -33,19 +33,23 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsRootAccessible_H_
 #define _nsRootAccessible_H_
 
+#include "nsCaretAccessible.h"
 #include "nsDocAccessibleWrap.h"
+
+#include "nsIAccessibleDocument.h"
+#include "nsIAccessibleTreeCache.h"
+
 #include "nsHashtable.h"
-#include "nsIAccessibleDocument.h"
 #include "nsCaretAccessible.h"
 #include "nsIDocument.h"
 #include "nsIDOMFocusListener.h"
 #include "nsIDOMFormListener.h"
 #include "nsIDOMXULListener.h"
 #include "nsITimer.h"
 
 #define NS_ROOTACCESSIBLE_IMPL_CID                      \
@@ -119,25 +123,23 @@ class nsRootAccessible : public nsDocAcc
     void TryFireEarlyLoadEvent(nsIDOMNode *aDocNode);
     void FireCurrentFocusEvent();
     void GetChromeEventHandler(nsIDOMEventTarget **aChromeTarget);
 
     /**
      * Handles 'TreeRowCountChanged' event. Used in HandleEventWithTarget().
      */
     nsresult HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
-                                            nsIAccessible *aAccessible,
-                                            const nsAString& aTargetName);
+                                            nsIAccessibleTreeCache *aAccessible);
 
     /**
      * Handles 'TreeInvalidated' event. Used in HandleEventWithTarget().
      */
     nsresult HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
-                                        nsIAccessible *aAccessible,
-                                        const nsAString& aTargetName);
+                                        nsIAccessibleTreeCache *aAccessible);
 
 #ifdef MOZ_XUL
     PRUint32 GetChromeFlags();
 #endif
     already_AddRefed<nsIDocShellTreeItem>
            GetContentDocShell(nsIDocShellTreeItem *aStart);
     nsRefPtr<nsCaretAccessible> mCaretAccessible;
     nsCOMPtr<nsIDOMNode> mCurrentARIAMenubar;
--- a/accessible/src/html/nsHTMLLinkAccessible.cpp
+++ b/accessible/src/html/nsHTMLLinkAccessible.cpp
@@ -61,17 +61,26 @@ NS_IMETHODIMP
 nsHTMLLinkAccessible::GetName(nsAString& aName)
 { 
   aName.Truncate();
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
-  return AppendFlatStringFromSubtree(content, &aName);
+  nsresult rv = AppendFlatStringFromSubtree(content, &aName);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aName.IsEmpty()) {
+    // Probably an image without alt or title inside, try to get the name on
+    // the link by usual way.
+    return GetHTMLName(aName, PR_FALSE);
+  }
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLLinkAccessible::GetRole(PRUint32 *aRole)
 {
   NS_ENSURE_ARG_POINTER(aRole);
 
   *aRole = nsIAccessibleRole::ROLE_LINK;
@@ -97,19 +106,24 @@ nsHTMLLinkAccessible::GetState(PRUint32 
     *aState |= nsIAccessibleStates::STATE_SELECTABLE;
   }
 
   nsCOMPtr<nsILink> link = do_QueryInterface(mDOMNode);
   NS_ENSURE_STATE(link);
 
   nsLinkState linkState;
   link->GetLinkState(linkState);
-  if (linkState == eLinkState_NotLink) {
-    // This is a named anchor, not a link with also a name attribute. bail out.
-    return NS_OK;
+  if (linkState == eLinkState_NotLink || linkState == eLinkState_Unknown) {
+    // This is a either named anchor (a link with also a name attribute) or
+    // it doesn't have any attributes. Check if 'click' event handler is
+    // registered, otherwise bail out.
+    PRBool isOnclick = nsAccUtils::HasListener(content,
+                                               NS_LITERAL_STRING("click"));
+    if (!isOnclick)
+      return NS_OK;
   }
 
   *aState |= nsIAccessibleStates::STATE_LINKED;
 
   if (linkState == eLinkState_Visited)
     *aState |= nsIAccessibleStates::STATE_TRAVERSED;
 
   return NS_OK;
@@ -133,35 +147,45 @@ nsHTMLLinkAccessible::GetValue(nsAString
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLLinkAccessible::GetNumActions(PRUint8 *aNumActions)
 {
   NS_ENSURE_ARG_POINTER(aNumActions);
 
+  if (!IsLinked())
+    return nsHyperTextAccessible::GetNumActions(aNumActions);
+
   *aNumActions = 1;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLLinkAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
 {
+  aName.Truncate();
+
+  if (!IsLinked())
+    return nsHyperTextAccessible::GetActionName(aIndex, aName);
+
   // Action 0 (default action): Jump to link
-  aName.Truncate();
   if (aIndex != eAction_Jump)
     return NS_ERROR_INVALID_ARG;
 
   aName.AssignLiteral("jump");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLLinkAccessible::DoAction(PRUint8 aIndex)
 {
+  if (!IsLinked())
+    return nsHyperTextAccessible::DoAction(aIndex);
+
   // Action 0 (default action): Jump to link
   if (aIndex != eAction_Jump)
     return NS_ERROR_INVALID_ARG;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
@@ -180,8 +204,25 @@ nsHTMLLinkAccessible::GetURI(PRInt32 aIn
   if (aIndex != 0)
     return NS_ERROR_INVALID_ARG;
 
   nsCOMPtr<nsILink> link(do_QueryInterface(mDOMNode));
   NS_ENSURE_STATE(link);
 
   return link->GetHrefURI(aURI);
 }
+
+////////////////////////////////////////////////////////////////////////////////
+// Protected members
+
+PRBool
+nsHTMLLinkAccessible::IsLinked()
+{
+  nsCOMPtr<nsILink> link(do_QueryInterface(mDOMNode));
+  if (!link)
+    return PR_FALSE;
+
+  nsLinkState linkState;
+  nsresult rv = link->GetLinkState(linkState);
+
+  return NS_SUCCEEDED(rv) && linkState != eLinkState_NotLink &&
+         linkState != eLinkState_Unknown;
+}
--- a/accessible/src/html/nsHTMLLinkAccessible.h
+++ b/accessible/src/html/nsHTMLLinkAccessible.h
@@ -59,11 +59,16 @@ public:
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD DoAction(PRUint8 aIndex);
 
   // nsIAccessibleHyperLink
   NS_IMETHOD GetURI(PRInt32 aIndex, nsIURI **aURI);
 
 protected:
   enum { eAction_Jump = 0 };
+
+  /**
+   * Returns true if the link has href attribute.
+   */
+  PRBool IsLinked();
 };
 
 #endif  
--- a/accessible/src/html/nsHTMLTableAccessible.cpp
+++ b/accessible/src/html/nsHTMLTableAccessible.cpp
@@ -1166,21 +1166,23 @@ NS_IMETHODIMP nsHTMLTableAccessible::IsP
     NS_ENSURE_TRUE(tableFrame , NS_ERROR_FAILURE);
     nsSize tableSize  = tableFrame->GetSize();
     nsCOMPtr<nsIAccessibleDocument> docAccessible = GetDocAccessible();
     nsCOMPtr<nsPIAccessNode> docAccessNode(do_QueryInterface(docAccessible));
     NS_ENSURE_TRUE(docAccessNode, NS_ERROR_FAILURE);
     nsIFrame *docFrame = docAccessNode->GetFrame();
     NS_ENSURE_TRUE(docFrame , NS_ERROR_FAILURE);
     nsSize docSize = docFrame->GetSize();
-    PRInt32 percentageOfDocWidth = (100 * tableSize.width) / docSize.width;
-    if (percentageOfDocWidth > 95) {
-      // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width
-      // Probably for layout
-      RETURN_LAYOUT_ANSWER(PR_TRUE, "<=4 columns, width hardcoded in pixels and 95% of document width");
+    if (docSize.width > 0) {
+      PRInt32 percentageOfDocWidth = (100 * tableSize.width) / docSize.width;
+      if (percentageOfDocWidth > 95) {
+        // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width
+        // Probably for layout
+        RETURN_LAYOUT_ANSWER(PR_TRUE, "<=4 columns, width hardcoded in pixels and 95% of document width");
+      }
     }
   }
 
   // Two column rules
   if (rows * columns <= 10) {
     RETURN_LAYOUT_ANSWER(PR_TRUE, "2-4 columns, 10 cells or less, non-bordered");
   }
 
--- a/accessible/src/mac/nsAccessibleWrap.h
+++ b/accessible/src/mac/nsAccessibleWrap.h
@@ -91,17 +91,19 @@ class nsAccessibleWrap : public nsAccess
       return (state & nsIAccessibleStates::STATE_HASPOPUP);
     }
     
     // return this accessible's all children, adhering to "flat" accessibles by not returning their children.
     void GetUnignoredChildren(nsTArray<nsRefPtr<nsAccessibleWrap> > &aChildrenArray);
     virtual already_AddRefed<nsIAccessible> GetUnignoredParent();
     
   protected:
-    
+
+    virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent);
+
     PRBool AncestorIsFlat() {
       // we don't create a native object if we're child of a "flat" accessible; for example, on OS X buttons 
       // shouldn't have any children, because that makes the OS confused. 
       //
       // to maintain a scripting environment where the XPCOM accessible hierarchy look the same 
       // on all platforms, we still let the C++ objects be created though.
       
       nsCOMPtr<nsIAccessible> curParent = GetParent();
--- a/accessible/src/mac/nsAccessibleWrap.mm
+++ b/accessible/src/mac/nsAccessibleWrap.mm
@@ -164,18 +164,28 @@ nsAccessibleWrap::FireAccessibleEvent(ns
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   NS_ENSURE_ARG_POINTER(aEvent);
 
   nsresult rv = nsAccessible::FireAccessibleEvent(aEvent);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  return FirePlatformEvent(aEvent);
+
+  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
+}
+
+nsresult
+nsAccessibleWrap::FirePlatformEvent(nsIAccessibleEvent *aEvent)
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
+
   PRUint32 eventType;
-  rv = aEvent->GetEventType(&eventType);
+  nsresult rv = aEvent->GetEventType(&eventType);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // ignore everything but focus-changed and value-changed events for now.
   if (eventType != nsIAccessibleEvent::EVENT_FOCUS &&
       eventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE)
     return NS_OK;
 
   nsCOMPtr<nsIAccessible> accessible;
--- a/accessible/src/msaa/nsAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsAccessibleWrap.cpp
@@ -328,16 +328,22 @@ STDMETHODIMP nsAccessibleWrap::get_accVa
   *pszValue = NULL;
   nsCOMPtr<nsIAccessible> xpAccessible;
   GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
   if (xpAccessible) {
     nsAutoString value;
     if (NS_FAILED(xpAccessible->GetValue(value)))
       return E_FAIL;
 
+    // see bug 438784: Need to expose URL on doc's value attribute.
+    // For this, reverting part of fix for bug 425693 to make this MSAA method 
+    // behave IAccessible2-style.
+    if (value.IsEmpty())
+      return S_FALSE;
+
     *pszValue = ::SysAllocStringLen(value.get(), value.Length());
     if (!*pszValue)
       return E_OUTOFMEMORY;
   }
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
   return S_OK;
 }
 
@@ -1685,16 +1691,22 @@ NS_IMETHODIMP nsAccessibleWrap::GetNativ
 NS_IMETHODIMP
 nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
 {
   NS_ENSURE_ARG(aEvent);
 
   nsresult rv = nsAccessible::FireAccessibleEvent(aEvent);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  return FirePlatformEvent(aEvent);
+}
+
+nsresult
+nsAccessibleWrap::FirePlatformEvent(nsIAccessibleEvent *aEvent)
+{
   PRUint32 eventType = 0;
   aEvent->GetEventType(&eventType);
 
   NS_ENSURE_TRUE(eventType > 0 &&
                  eventType < nsIAccessibleEvent::EVENT_LAST_ENTRY,
                  NS_ERROR_FAILURE);
 
   PRUint32 winLastEntry = gWinEventMap[nsIAccessibleEvent::EVENT_LAST_ENTRY];
--- a/accessible/src/msaa/nsAccessibleWrap.h
+++ b/accessible/src/msaa/nsAccessibleWrap.h
@@ -308,16 +308,18 @@ class nsAccessibleWrap : public nsAccess
   // NT4 does not have the oleacc that defines these methods. So we define copies here that automatically
   // load the library only if needed.
   static STDMETHODIMP AccessibleObjectFromWindow(HWND hwnd,DWORD dwObjectID,REFIID riid,void **ppvObject);
   static STDMETHODIMP NotifyWinEvent(DWORD event,HWND hwnd,LONG idObjectType,LONG idObject);
 
   static IDispatch *NativeAccessible(nsIAccessible *aXPAccessible);
 
 protected:
+  virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent);
+
   // mEnumVARIANTPosition not the current accessible's position, but a "cursor" of 
   // where we are in the current list of children, with respect to
   // nsIEnumVariant::Reset(), Skip() and Next().
   PRUint16 mEnumVARIANTPosition;
 
   enum navRelations {
     NAVRELATION_CONTROLLED_BY = 0x1000,
     NAVRELATION_CONTROLLER_FOR = 0x1001,
--- a/accessible/src/other/nsAccessibleWrap.h
+++ b/accessible/src/other/nsAccessibleWrap.h
@@ -46,11 +46,16 @@
 #include "nsCOMPtr.h"
 #include "nsAccessible.h"
 
 class nsAccessibleWrap : public nsAccessible
 {
   public: // construction, destruction
     nsAccessibleWrap(nsIDOMNode*, nsIWeakReference *aShell);
     virtual ~nsAccessibleWrap();
+
+  protected:
+    virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent) {
+      return NS_OK;
+    }
 };
 
 #endif
--- a/accessible/src/xul/nsXULSelectAccessible.cpp
+++ b/accessible/src/xul/nsXULSelectAccessible.cpp
@@ -835,21 +835,23 @@ nsXULListitemAccessible::GetListAccessib
   
   nsCOMPtr<nsIDOMXULSelectControlItemElement> listItem =
     do_QueryInterface(mDOMNode);
   if (!listItem)
     return nsnull;
 
   nsCOMPtr<nsIDOMXULSelectControlElement> list;
   listItem->GetControl(getter_AddRefs(list));
-  if (!list)
+
+  nsCOMPtr<nsIDOMNode> listNode(do_QueryInterface(list));
+  if (!listNode)
     return nsnull;
 
   nsIAccessible *listAcc = nsnull;
-  GetAccService()->GetAccessibleInWeakShell(list, mWeakShell, &listAcc);
+  GetAccService()->GetAccessibleInWeakShell(listNode, mWeakShell, &listAcc);
   return listAcc;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULListitemAccessible. nsIAccessible
 
 /**
   * If there is a Listcell as a child ( not anonymous ) use it, otherwise
--- a/accessible/src/xul/nsXULTreeAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeAccessible.cpp
@@ -631,32 +631,34 @@ nsXULTreeAccessible::InvalidateCache(PRI
 //   treeViewInvalidated(in long aStartRow, in long aEndRow,
 //                       in long aStartCol, in long aEndCol);
 NS_IMETHODIMP
 nsXULTreeAccessible::TreeViewInvalidated(PRInt32 aStartRow, PRInt32 aEndRow,
                                          PRInt32 aStartCol, PRInt32 aEndCol)
 {
   NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
 
-  PRInt32 endRow = aEndRow, endCol = aEndCol;
+  PRInt32 endRow = aEndRow;
 
   nsresult rv;
   if (endRow == -1) {
     PRInt32 rowCount = 0;
     rv = mTreeView->GetRowCount(&rowCount);
     NS_ENSURE_SUCCESS(rv, rv);
 
     endRow = rowCount - 1;
   }
 
   nsCOMPtr<nsITreeColumns> treeColumns;
   mTree->GetColumns(getter_AddRefs(treeColumns));
   NS_ENSURE_STATE(treeColumns);
 
 #ifdef MOZ_ACCESSIBILITY_ATK
+  PRInt32 endCol = aEndCol;
+
   if (endCol == -1) {
     PRInt32 colCount = 0;
     rv = treeColumns->GetCount(&colCount);
     NS_ENSURE_SUCCESS(rv, rv);
 
     endCol = colCount - 1;
   }
 #else
@@ -700,26 +702,58 @@ nsXULTreeAccessible::TreeViewInvalidated
         }
       }
     }
   }
 
   return NS_OK;
 }
 
+// void nsIAccessibleTreeCache::treeViewChanged();
+NS_IMETHODIMP
+nsXULTreeAccessible::TreeViewChanged()
+{
+  if (!mTree)
+    return NS_ERROR_FAILURE;
+
+  // Fire only notification destroy/create events on accessible tree to lie to
+  // AT because it should be expensive to fire destroy events for each tree item
+  // in cache.
+  nsCOMPtr<nsIAccessibleEvent> eventDestroy =
+    new nsAccEvent(nsIAccessibleEvent::EVENT_DOM_DESTROY,
+                   this, PR_FALSE);
+  NS_ENSURE_TRUE(eventDestroy, NS_ERROR_OUT_OF_MEMORY);
+
+  nsresult rv = FirePlatformEvent(eventDestroy);
+
+  ClearCache(*mAccessNodeCache);
+
+  mTree->GetView(getter_AddRefs(mTreeView));
+
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIAccessibleEvent> eventCreate =
+    new nsAccEvent(nsIAccessibleEvent::EVENT_DOM_CREATE,
+                   this, PR_FALSE);
+  NS_ENSURE_TRUE(eventCreate, NS_ERROR_OUT_OF_MEMORY);
+
+  return FirePlatformEvent(eventCreate);
+}
+
 nsresult nsXULTreeAccessible::GetColumnCount(nsITreeBoxObject* aBoxObject, PRInt32* aCount)
 {
   NS_ENSURE_TRUE(aBoxObject, NS_ERROR_FAILURE);
   nsCOMPtr<nsITreeColumns> treeColumns;
   aBoxObject->GetColumns(getter_AddRefs(treeColumns));
   NS_ENSURE_TRUE(treeColumns, NS_ERROR_FAILURE);
   return treeColumns->GetCount(aCount);
 }
 
-// ---------- nsXULTreeitemAccessible ---------- 
+////////////////////////////////////////////////////////////////////////////////
+// nsXULTreeitemAccessible
 
 nsXULTreeitemAccessible::nsXULTreeitemAccessible(nsIAccessible *aParent, nsIDOMNode *aDOMNode, nsIWeakReference *aShell, PRInt32 aRow, nsITreeColumn* aColumn)
   : nsLeafAccessible(aDOMNode, aShell)
 {
   mParent = aParent;  // xxx todo: do we need this? We already have mParent on nsAccessible
 
   nsXULTreeAccessible::GetTreeBoxObject(aDOMNode, getter_AddRefs(mTree));
   if (mTree)
--- a/accessible/tests/mochitest/Makefile.in
+++ b/accessible/tests/mochitest/Makefile.in
@@ -43,26 +43,30 @@ VPATH		= @srcdir@
 relativesrcdir  = accessible
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES =\
 		moz.png \
 		test_aria_activedescendant.html \
+		test_aria_role_article.html \
 		test_bug368835.xul \
 		test_bug420863.html \
 		test_groupattrs.xul \
 		test_table_indexes.html \
 		test_nsIAccessibleTable_1.html \
 		test_nsIAccessibleTable_2.html \
 		test_nsIAccessibleTable_3.html \
 		test_nsIAccessibleTable_4.html \
 		test_nsIAccessibleTable_listboxes.xul \
+		test_nsIAccessibleDocument.html \
 		test_nsIAccessibleHyperLink.html \
 		test_nsIAccessibleHyperLink.xul \
 		test_nsIAccessibleHyperText.html \
 		test_nsIAccessibleImage.html \
+		test_nsOuterDocAccessible.html \
 		test_bug428479.html \
+		test_bug429285.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_aria_role_article.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=429666
+-->
+<head>
+  <title>Expose ROLE_DOCUMENT for ARIA landmarks that inherit from document chrome tests</title>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript">
+    function doTest()
+    {
+      var accRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+                       getService(Components.interfaces.nsIAccessibleRetrieval);
+
+      // Test article exposed as document
+      var articleElement = document.getElementById("testArticle");
+      var articleAcc = null;
+      try {
+        articleAcc = accRetrieval.getAccessibleFor(articleElement);
+      } catch(e) { }
+      ok(articleAcc, "no accessible for article!");
+      if (articleAcc) {
+        is(articleAcc.finalRole,
+           Components.interfaces.nsIAccessibleRole.ROLE_DOCUMENT,
+           "Wrong role for article!");
+        is(articleAcc.name, "Test article", "Wrong name for article!");
+      }
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=429666">Mozilla Bug 429666</a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+  <div id="testArticle" role="article" title="Test article">
+    <p>This is a paragraph inside the article.</p>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_bug429285.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=429285
+-->
+<head>
+  <title>Propagate aria-disabled state to descendants chrome tests</title>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript">
+    // Mapping needed state flags for easier handling.
+    const state_disabled = 
+          Components.interfaces.nsIAccessibleStates.STATE_UNAVAILABLE;
+    const state_focusable = 
+          Components.interfaces.nsIAccessibleStates.STATE_FOCUSABLE;
+
+    const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+    const nsIAccessible = Components.interfaces.nsIAccessible;
+
+    var gAccRetrieval = null;
+
+    function testChildren(aID, aAcc)
+    {
+      // Check state of aAcc first.
+      var state = {}, extraState = {};
+      aAcc.getFinalState(state, extraState);
+      if (state.value & state_focusable) {
+        is(state.value & state_disabled, state_disabled,
+           "Wrong disabled state bit for " + aID + "!");
+      }
+
+      // Iterate over its children to see if they are disabled, too.
+      var children = null;
+      try {
+        children = aAcc.children;
+      } catch(e) {}
+      ok(children, "Could not get children for " + aID +"!");
+
+      if (children) {
+        for (var i=0; i<children.length; i++) {
+          var childAcc = children.queryElementAt(i, nsIAccessible);
+          // Test and recurse over its children as well.
+          testChildren(childAcc.name, childAcc);
+        }
+      }
+    }
+
+    function doTest()
+    {
+      gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+                      getService(nsIAccessibleRetrieval);
+
+      var groupItem = document.getElementById("group");
+      var groupAcc = null;
+      try {
+        groupAcc = gAccRetrieval.getAccessibleFor(groupItem);
+      } catch (e) {}
+      ok (groupAcc,
+          "No accessible for group element!");
+
+      if (groupAcc) {
+        var state = {}, extraState = {};
+        groupAcc.getFinalState(state, extraState);
+        is(state.value & state_disabled, state_disabled,
+          "Wrong disabled state bit for Group element!");
+        testChildren("group", groupAcc);
+      }
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=429285"
+     title="Propagate aria-disabled to descendants">
+    Mozilla Bug 429285
+  </a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <div id="group" role="group" aria-disabled="true">
+    <button>hi</button>
+    <div tabindex="0" role="listbox" aria-activedescendant="item1">
+      <div role="option" id="item1">Item 1</div>
+      <div role="option" id="item2">Item 2</div>
+      <div role="option" id="item3">Item 3</div>
+      <div role="option" id="item4">Item 4</div>
+    </div>
+    <div role="slider" tabindex="0">A slider</div>
+  </div>
+</body>
+</html>
--- a/accessible/tests/mochitest/test_groupattrs.xul
+++ b/accessible/tests/mochitest/test_groupattrs.xul
@@ -25,29 +25,40 @@
           return "";
         }
       }
 
       this.mAcc = gAccService.getAccessibleFor(document.getElementById(aId));
       this.mAttrs = this.mAcc.attributes;
     }
 
+    function testGroupAtts(aID, aPosInSet, aSetSize)
+    {
+      var attrs = new accAttributes(aID);
+      is(attrs.getAttribute("posinset"), aPosInSet, "Wrong posinset on " + aID);
+      is(attrs.getAttribute("setsize"), aSetSize, "Wrong setsize on " + aID);
+    }
+
     function doTest()
     {
       // Activate accessibility, otherwise events aren't fired.
       gAccService = Components.classes["@mozilla.org/accessibleRetrieval;1"].
                     getService(Components.interfaces.nsIAccessibleRetrieval);
 
-      var attrs = new accAttributes("item1");
-      is(attrs.getAttribute("posinset"), "1", "Wrong posinset on item1.");
-      is(attrs.getAttribute("setsize"), "2", "Wrong setsize on item1.");
+      //////////////////////////////////////////////////////////////////////////
+      // xul:listbox (bug 417317)
+      testGroupAtts("item1", "1", "2");
+      testGroupAtts("item2", "2", "2");
 
-      attrs = new accAttributes("item2");
-      is(attrs.getAttribute("posinset"), "2", "Wrong posinset on item2.");
-      is(attrs.getAttribute("setsize"), "2", "Wrong setsize on item2.");
+      //////////////////////////////////////////////////////////////////////////
+      // ARIA menu (bug 441888)
+      testGroupAtts("aria-menuitem", "1", "3");
+      testGroupAtts("aria-menuitemcheckbox", "2", "3");
+      testGroupAtts("aria-menuitemradio", "3", "3");
+      testGroupAtts("aria-menuitem2", "1", "1");
 
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addLoadEvent(doTest);
   ]]>
   </script>
@@ -64,10 +75,24 @@
     <pre id="test">
     </pre>
   </body>
 
   <listbox>
     <listitem label="item1" id="item1"/>
     <listitem label="item2" id="item2"/>
   </listbox>
+
+  <vbox>
+    <description role="menuitem" id="aria-menuitem"
+                 value="conventional menuitem"/>
+    <description role="menuitemcheckbox" id="aria-menuitemcheckbox"
+                 value="conventional checkbox menuitem"/>
+    <description role="menuitem" hidden="true"/>
+    <description role="menuitemradio" id="aria-menuitemradio"
+                 value="conventional radio menuitem"/>
+    <description role="separator"
+                 value="conventional separator"/>
+    <description role="menuitem" id="aria-menuitem2"
+                 value="conventional menuitem"/>
+  </vbox>
 </window>
 
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_nsIAccessibleDocument.html
@@ -0,0 +1,111 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=441737
+-->
+<head>
+  <title>nsIAccessibleDocument chrome tests</title>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript">
+    const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+    const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;
+    const nsIAccessibleDocument = Components.interfaces.nsIAccessibleDocument;
+    const nsIDOMDocument = Components.interfaces.nsIDOMDocument;
+    const nsIDOMWindow = Components.interfaces.nsIDOMWindow;
+
+    // needed state flag
+    const state_focusable =
+          Components.interfaces.nsIAccessibleStates.STATE_FOCUSABLE;
+    const state_readonly =
+          Components.interfaces.nsIAccessibleStates.STATE_READONLY;
+
+    var gAccRetrieval = null;
+
+    function doTest()
+    {
+      gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+                      getService(nsIAccessibleRetrieval);
+
+      // Get accessible for body tag.
+      var docAcc = null;
+      try {
+        docAcc = gAccRetrieval.getAccessibleFor(document).
+                 QueryInterface(nsIAccessibleDocument);
+      } catch(e) {}
+      ok(docAcc, "No accessible with interface for document!");
+
+      if (docAcc) {
+        // nsIAccessible
+        is(docAcc.name, "nsIAccessibleDocument chrome tests",
+           "Name for document accessible not correct!");
+        is(docAcc.role, nsIAccessibleRole.ROLE_DOCUMENT,
+           "Wrong role for document!");
+
+        // check if it is focusable, read-only.
+        var state = {}, extraState = {}
+        docAcc.getFinalState(state, extraState);
+        var desiredStates = (state_focusable | state_readonly);
+        is(state.value & desiredStates, desiredStates,
+           "Wrong state bits for document!");
+
+        // No actions wanted on doc
+        is(docAcc.numActions, 0, "Wrong number of actions for document!");
+
+        // attributes should contain tag:body
+        attributes = docAcc.attributes;
+        is(attributes.getStringProperty("tag"), "BODY",
+           "Wrong attribute on document!");
+
+        // nsIAccessibleDocument
+        is(docAcc.URL, "chrome://mochikit/content/a11y/accessible/test_nsIAccessibleDocument.html",
+           "Wrong URL for document!");
+        is(docAcc.title, "nsIAccessibleDocument chrome tests",        
+           "Wrong title for document!");
+        is(docAcc.mimeType, "text/html",
+           "Wrong mime type for document!");
+        // nsDocAccessible::getDocType currently returns NS_ERROR_FAILURE.
+        // See bug 442005. After fixing, please remove this comment and
+        // uncomment the below two lines to enable the test.
+//        is(docAcc.docType, "HTML",
+//           "Wrong type of document!");
+
+        // Test for correct nsIDOMDocument retrieval.
+        var domDoc = null;
+        try {
+          domDoc = docAcc.document.QueryInterface(nsIDOMDocument);
+        } catch(e) {}
+        ok(domDoc, "no nsIDOMDocument for this doc accessible!");
+        is(domDoc, document, "Document nodes do not match!");
+
+        // Test for correct nsIDOMWindow retrieval.
+        var domWindow = null;
+        try {
+          domWindow = docAcc.window.QueryInterface(nsIDOMWindow);
+        } catch(e) {}
+        ok(domWindow, "no nsIDOMWindow for this doc accessible!");
+        is(domWindow, window, "Window nodes do not match!");
+      }
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=441737"
+     title="nsAccessibleDocument chrome tests">
+    Mozilla Bug 441737
+  </a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+</body>
+</html>
--- a/accessible/tests/mochitest/test_nsIAccessibleHyperLink.html
+++ b/accessible/tests/mochitest/test_nsIAccessibleHyperLink.html
@@ -6,16 +6,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 <head>
   <title>nsIHyperLinkAccessible chrome tests</title>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 
   <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 
   <script type="application/javascript">
+    var gAccRetrieval = null;
+
     function testThis(aID, aAcc, aRole, aAnchors, aName, aValid, aStartIndex,
                       aEndIndex)
     {
       is(aAcc.finalRole, aRole, "Wrong role for ID " + aID + "!");
       is(aAcc.anchorCount, aAnchors, "Wrong number of anchors for ID "
                                       + aID + "!");
       is(aAcc.getAnchor(0).name, aName, "Wrong name for ID "
                                         + aID + "!");
@@ -31,28 +33,56 @@ https://bugzilla.mozilla.org/show_bug.cg
     {
       is(aAcc.selected, aSelectedBefore,
          "Wrong selected state before focus for ID " + aID + "!");
       document.getElementById(aID).focus();
       is(aAcc.selected, aSelectedAfter,
          "Wrong seleccted state after focus for ID " + aID + "!");
     }
 
-    function testStates(aID, aAcc, aState, aExtraState, aAbsentState)
+    function testStates(aID, aAcc, aState, aExtraState, aAbsentState,
+                        aShowStateDebugFlag)
     {
       var state = {}, extraState = {};
       aAcc.getFinalState(state, extraState);
+
+      if (aShowStateDebugFlag) {
+        var list = gAccRetrieval.getStringStates(state.value, 0);
+
+        var str = "";
+        for (var i = 0; i < list.length; i++)
+          str += list.item(i) + "\n";
+
+        alert(str);
+      }
+
       is(state.value & aState, aState, "Wrong state bits for ID " + aID + "!");
       is(extraState.value & aExtraState, aExtraState, 
          "Wrong extra state bits for ID " + aID + "!");
       if (aAbsentState != 0)
         is(state.value & aAbsentState, 0, "state bits should not be present in ID "
            + aID + "!");
     }
-      
+
+    function testAction(aId, aAcc, aActionName)
+    {
+      var numActions = aActionName ? 1 : 0;
+      is(aAcc.numActions, numActions,
+         "Wrong actions number for ID " + aId);
+      try {
+        is(aAcc.getActionName(0), aActionName,
+           "Wrong action name for ID " + aId);
+      } catch (e) {
+        if (numActions)
+          ok(false, "Exception on action name getting for ID " + aId);
+        else
+          ok(true, "Correct action name for ID " + aId);
+      }
+    }
+
     function doTest()
     {
       // Mapping needed state flags for easier handling.
       const state_focusable = 
             Components.interfaces.nsIAccessibleStates.STATE_FOCUSABLE;
       const state_focused = 
             Components.interfaces.nsIAccessibleStates.STATE_FOCUSED;
       const state_selectable = 
@@ -66,25 +96,25 @@ https://bugzilla.mozilla.org/show_bug.cg
             Components.interfaces.nsIAccessibleStates.EXT_STATE_MULTI_LINE;
       const ext_state_horizontal = 
             Components.interfaces.nsIAccessibleStates.EXT_STATE_HORIZONTAL;
       const ext_state_required = 
             Components.interfaces.nsIAccessibleStates.STATE_REQUIRED;
       const ext_state_invalid = 
             Components.interfaces.nsIAccessibleStates.STATE_INVALID;
 
-      var accService = Components.classes["@mozilla.org/accessibleRetrieval;1"].
-                       getService(Components.interfaces.nsIAccessibleRetrieval);
+      gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+                      getService(Components.interfaces.nsIAccessibleRetrieval);
 
       //////////////////////////////////////////////////////////////////////////
       // normal hyperlink
       var normalHyperlinkElement = document.getElementById("NormalHyperlink");
       var normalHyperlinkAcc;
       try {
-        normalHyperlinkAcc = accService.getAccessibleFor(normalHyperlinkElement).
+        normalHyperlinkAcc = gAccRetrieval.getAccessibleFor(normalHyperlinkElement).
               QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
       } catch(e) {
         ok(normalHyperlinkAcc, "no interface for normal hyperlink!");
       }
       testThis("NormalHyperlink", normalHyperlinkAcc,
                Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
                "Mozilla Foundation", true, 18, 19);
       is(normalHyperlinkAcc.getURI(0).spec, "http://www.mozilla.org/", 
@@ -97,40 +127,41 @@ https://bugzilla.mozilla.org/show_bug.cg
                  (state_focusable | state_focused | state_linked),
                  (ext_state_horizontal), (0));
 
       //////////////////////////////////////////////////////////////////////////
       // ARIA hyperlink
       var ariaHyperlinkElement = document.getElementById("AriaHyperlink");
       var ariaHyperlinkAcc;
       try {
-        ariaHyperlinkAcc = accService.getAccessibleFor(ariaHyperlinkElement).
+        ariaHyperlinkAcc = gAccRetrieval.getAccessibleFor(ariaHyperlinkElement).
             QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
       } catch(e) {
         ok(ariaHyperlinkAcc, "no interface for ARIA Hyperlink!");
       }
       testThis("AriaHyperlink", ariaHyperlinkAcc,
                Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
                "Mozilla Foundation Home", true, 32, 33);
       testStates("AriaHyperlink", ariaHyperlinkAcc,
                  (state_focusable | state_linked),
                  (ext_state_horizontal), (0));
       testFocus("AriaHyperlink", ariaHyperlinkAcc, false, true);
       testStates("AriaHyperlink", ariaHyperlinkAcc,
                  (state_focusable | state_focused | state_linked),
                  (ext_state_horizontal), (0));
+      testAction("AriaHyperlink", ariaHyperlinkAcc, "click");
 
       //////////////////////////////////////////////////////////////////////////
       // ARIA hyperlink with status invalid
       var invalidAriaHyperlinkElement =
           document.getElementById("InvalidAriaHyperlink");
       var invalidAriaHyperlinkAcc;
       try {
         invalidAriaHyperlinkAcc =
-               accService.getAccessibleFor(invalidAriaHyperlinkElement).
+               gAccRetrieval.getAccessibleFor(invalidAriaHyperlinkElement).
                QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
       } catch(e) {
         ok(invalidAriaHyperlinkAcc, "no interface for invalid ARIA hyperlink!");
       }
       is(invalidAriaHyperlinkAcc.valid, false, "Should not be valid!");
       testStates("InvalidAriaHyperlink", invalidAriaHyperlinkAcc,
                  (state_linked),
                  (ext_state_horizontal), (state_focusable));
@@ -139,17 +170,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
       //////////////////////////////////////////////////////////////////////////
       // image map and its link children
       var imageMapHyperlinkElement =
           document.getElementById("imgmap");
       var imageMapHyperlinkAcc;
       try {
         imageMapHyperlinkAcc =
-             accService.getAccessibleFor(imageMapHyperlinkElement).
+             gAccRetrieval.getAccessibleFor(imageMapHyperlinkElement).
               QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
       } catch(e) {
         ok(imageMapHyperlinkAcc, "no Image Map interface!");
       }
       testThis("imgmap", imageMapHyperlinkAcc,
                Components.interfaces.nsIAccessibleRole.ROLE_IMAGE_MAP, 2, 
                "b", true, 83, 84);
       is(imageMapHyperlinkAcc.getURI(0).spec,
@@ -197,83 +228,212 @@ https://bugzilla.mozilla.org/show_bug.cg
                  (0), (0));
 
       //////////////////////////////////////////////////////////////////////////
       // empty hyperlink
       var emptyLinkElement = document.getElementById("emptyLink");
       var EmptyHLAcc;
       try {
         EmptyHLAcc =
-             accService.getAccessibleFor(emptyLinkElement).
+             gAccRetrieval.getAccessibleFor(emptyLinkElement).
              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
       } catch (e) {
         ok(EmptyHLAcc, "no interface for empty link!");
       }
       testThis("emptyLink", EmptyHLAcc,
                Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1,
-               "", true, 98, 99);
+               null, true, 98, 99);
       testStates("emptyLink", EmptyHLAcc,
                  (state_focusable | state_linked),
                  (ext_state_horizontal), (0));
+      testAction("emptyLink", EmptyHLAcc, "jump");
 
       //////////////////////////////////////////////////////////////////////////
       // normal hyperlink with embedded span
       var hyperlinkElementWithSpan = document.getElementById("LinkWithSpan");
       var hyperlinkWithSpanAcc;
       try {
         hyperlinkWithSpanAcc =
-              accService.getAccessibleFor(hyperlinkElementWithSpan).
+              gAccRetrieval.getAccessibleFor(hyperlinkElementWithSpan).
               QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
       } catch(e) {
         ok(hyperlinkWithSpanAcc, "no interface for hyperlink with span!");
       }
       testThis("LinkWithSpan", hyperlinkWithSpanAcc,
                Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
                "Heise Online", true, 124, 125);
       is(hyperlinkWithSpanAcc.getURI(0).spec, "http://www.heise.de/", 
          "URI wrong for hyperlinkElementWithSpan!");
       testStates("LinkWithSpan", hyperlinkWithSpanAcc,
                  (state_focusable | state_linked),
                  (ext_state_horizontal), (0));
       testFocus("LinkWithSpan", hyperlinkWithSpanAcc, false, true);
       testStates("LinkWithSpan", hyperlinkWithSpanAcc,
                  (state_focusable | state_focused | state_linked),
                  (ext_state_horizontal), (0));
+      testAction("LinkWithSpan", hyperlinkWithSpanAcc, "jump");
 
       //////////////////////////////////////////////////////////////////////////
       // Named anchor, should never have state_linked
       var namedAnchorElement = document.getElementById("namedAnchor");
       var namedAnchorAcc;
       try {
-        namedAnchorAcc = accService.getAccessibleFor(namedAnchorElement).
+        namedAnchorAcc = gAccRetrieval.getAccessibleFor(namedAnchorElement).
               QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
       } catch(e) {
         ok(namedAnchorAcc, "no interface for named anchor!");
       }
       testThis("namedAnchor", namedAnchorAcc,
                Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
                "This should never be of state_linked", true, 202, 203);
       testStates("namedAnchor", namedAnchorAcc,
                  (state_selectable),
                  (ext_state_horizontal), (state_focusable | state_linked));
+      testAction("namedAnchor", namedAnchorAcc, "");
 
+      //////////////////////////////////////////////////////////////////////////
+      // No link (hasn't any attribute), should never have state_linked
+      var noLinkElement = document.getElementById("noLink");
+      var noLinkAcc;
+      try {
+        noLinkAcc = gAccRetrieval.getAccessibleFor(noLinkElement).
+              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
+      } catch(e) {
+        ok(noLinkAcc, "no interface for named anchor!");
+      }
+      testThis("noLink", noLinkAcc,
+               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
+               "This should never be of state_linked", true, 262, 263);
+      testStates("noLink", noLinkAcc,
+                 0,
+                 (ext_state_horizontal), (state_focusable | state_linked));
+      testAction("noLink", noLinkAcc, "");
+
+      //////////////////////////////////////////////////////////////////////////
+      // Link with registered 'click' event, should have state_linked
+      var linkWithClickElement = document.getElementById("linkWithClick");
+      var linkWithClickAcc;
+      try {
+        linkWithClickAcc = gAccRetrieval.getAccessibleFor(linkWithClickElement).
+              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
+      } catch(e) {
+        ok(linkWithClickAcc, "no interface for named anchor!");
+      }
+      testThis("linkWithClick", linkWithClickAcc,
+               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
+               "This should have state_linked", true, 301, 302);
+      testStates("linkWithClick", linkWithClickAcc,
+                 (state_linked),
+                 (ext_state_horizontal), 0);
+      testAction("linkWithClick", linkWithClickAcc, "click");
+
+      //////////////////////////////////////////////////////////////////////////
+      // Maps to group links (bug 431615).
+      var linksMapElement = document.getElementById("linksmap");
+      var linksMapAcc;
+      try {
+        linksMapAcc = gAccRetrieval.getAccessibleFor(linksMapElement);
+      } catch(e) { }
+
+      ok(linksMapAcc, "no accessible for map grouping links!");
+
+      //////////////////////////////////////////////////////////////////////////
+      // Link with title attribute, no name from the subtree (bug 438325).
+      var id = "linkWithTitleNoNameFromSubtree";
+      var linkElement = document.getElementById(id);
+      var linkAcc;
+      try {
+        linkAcc = gAccRetrieval.getAccessibleFor(linkElement).
+              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
+      } catch(e) {
+        ok(linkAcc, "no interface for link with ID " + id + "!");
+      }
+      testThis(id, linkAcc,
+               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
+               "Link with title", true, 354, 355);
+      testStates(id, linkAcc,
+                 (state_linked),
+                 (ext_state_horizontal), 0);
+      testAction(id, linkAcc, "jump");
+
+      //////////////////////////////////////////////////////////////////////////
+      // Link with title attribute, name from the subtree - onsreen name
+      // (bug 438325).
+      id = "linkWithTitleNameFromSubtree";
+      linkElement = document.getElementById(id);
+      linkAcc;
+      try {
+        linkAcc = gAccRetrieval.getAccessibleFor(linkElement).
+              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
+      } catch(e) {
+        ok(linkAcc, "no interface for link with ID " + id + "!");
+      }
+      testThis(id, linkAcc,
+               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
+               "the name from subtree", true, 403, 404);
+      testStates(id, linkAcc,
+                 (state_linked),
+                 (ext_state_horizontal), 0);
+      testAction(id, linkAcc, "jump");
+
+      //////////////////////////////////////////////////////////////////////////
+      // Link with title attribute, name from the nested html:img (bug 438325).
+      id = "linkWithTitleNameFromImg";
+      linkElement = document.getElementById(id);
+      linkAcc;
+      try {
+        linkAcc = gAccRetrieval.getAccessibleFor(linkElement).
+              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
+      } catch(e) {
+        ok(linkAcc, "no interface for link with ID " + id + "!");
+      }
+      testThis(id, linkAcc,
+               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
+               "The title for link", true, 458, 459);
+      testStates(id, linkAcc,
+                 (state_linked),
+                 (ext_state_horizontal), 0);
+      testAction(id, linkAcc, "jump");
+
+      //////////////////////////////////////////////////////////////////////////
+      // Link with label, no name from the subtree (bug 438325).
+      id = "linkWithLabelNoNameFromSubtree";
+      linkElement = document.getElementById(id);
+      linkAcc;
+      try {
+        linkAcc = gAccRetrieval.getAccessibleFor(linkElement).
+              QueryInterface(Components.interfaces.nsIAccessibleHyperLink);
+      } catch(e) {
+        ok(linkAcc, "no interface for link with ID " + id + "!");
+      }
+      testThis(id, linkAcc,
+               Components.interfaces.nsIAccessibleRole.ROLE_LINK, 1, 
+               "Link with label and nested image:", true, 462, 463);
+      testStates(id, linkAcc,
+                 (state_linked),
+                 (ext_state_horizontal), 0);
+      testAction(id, linkAcc, "jump");
+
+      //////////////////////////////////////////////////////////////////////////
+      //
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addLoadEvent(doTest);
   </script>
 </head>
 <body>
 
   <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418368">Mozilla Bug 418368</a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
+
   <br>Simple link:<br>
   <a id="NormalHyperlink" href="http://www.mozilla.org">Mozilla Foundation</a>
   <br>ARIA link:<br>
   <span id="AriaHyperlink" role="link"
          onclick="window.open('http://www.mozilla.org/');"
          tabindex="0">Mozilla Foundation Home</span>
   <br>Invalid, non-focusable hyperlink:<br>
   <span id="InvalidAriaHyperlink" role="link" aria-invalid="true"
@@ -288,16 +448,51 @@ https://bugzilla.mozilla.org/show_bug.cg
           coords="0,0,13,14"
           alt="a"
           shape="rect"></area>
   </map>
   <img width="447" id="imgmap"
        height="15"
        usemap="#atoz_map"
        src="http://www.bbc.co.uk/radio4/images/letters.gif"></img>
+
   <br>Empty link:<br>
   <a id="emptyLink" href=""><img src=""></img></a>
+
   <br>Link with embedded span<br>
   <a id="LinkWithSpan" href="http://www.heise.de/"><span lang="de">Heise Online</span></a>
+
   <br>Named anchor, must not have "linked" state for it to be exposed correctly:<br>
   <a id="namedAnchor" name="named_anchor">This should never be of state_linked</a>
+
+  <br>Link having no attributes, must not have "linked" state:</br>
+  <a id="noLink">This should never be of state_linked</a>
+
+  <br>Link with registered 'click' event: </br>
+  <a id="linkWithClick" onclick="var clicked = true;">This should have state_linked</a>
+
+  <br>Link with title attribute (no name from subtree): </br>
+  <a id="linkWithTitleNoNameFromSubtree" href="http://www.heise.de/"
+     title="Link with title"><img src=""/></a>
+
+  <br>Link with title attribute (name from subtree): </br>
+  <a id="linkWithTitleNameFromSubtree" href="http://www.heise.de/"
+     title="Link with title">the name from subtree</a>
+
+  <br>Link with title attribute (name from nested image): </br>
+  <a id="linkWithTitleNameFromImg" href="http://www.heise.de/"
+     title="Link with title"><img src="" alt="The title for link"/></a>
+
+  <br><label for="linkWithLabelNoNameFromSubtree">Link with label and nested image: </label></br>
+  <a id="linkWithLabelNoNameFromSubtree"
+     href="http://www.heise.de/"><img src=""/></a>
+
+  <br>Map that is used to group links (www.w3.org/TR/WCAG10-HTML-TECHS/#group-bypass),
+   also see the bug 431615:<br>
+  <map id="linksmap" title="Site navigation">
+    <ul>
+      <li><a href="http://mozilla.org">About the project</a></li>
+      <li><a href="http://mozilla.org">Sites and sounds</a></li>
+    </ul>
+  </map>
+
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_nsOuterDocAccessible.html
@@ -0,0 +1,106 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=441519
+-->
+<head>
+  <title>nsOuterDocAccessible chrome tests</title>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript">
+    const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+    const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;
+
+    // needed state flag
+    const state_focusable =
+          Components.interfaces.nsIAccessibleStates.STATE_FOCUSABLE;
+
+    // needed error return value
+    const ns_error_invalid_arg = Components.results.NS_ERROR_INVALID_ARG;
+
+    var gAccRetrieval = null;
+
+    function doTest()
+    {
+      gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+                      getService(nsIAccessibleRetrieval);
+
+      // Get accessible for body tag.
+      var docAcc = null;
+      try {
+        docAcc = gAccRetrieval.getAccessibleFor(document);
+      } catch(e) {}
+      ok(docAcc, "No accessible for document!");
+
+      if (docAcc) {
+        var outerDocAcc = null;
+        try {
+          outerDocAcc = docAcc.parent;
+        } catch(e) {}
+        ok(outerDocAcc, "No internal frame parent for document!");
+
+        if (outerDocAcc) {
+          is(outerDocAcc.role, nsIAccessibleRole.ROLE_INTERNAL_FRAME,
+             "Wrong role for internal frame!");
+
+          // check if it is focusable, not desired.
+          var state = {}, extraState = {}
+          outerDocAcc.getFinalState(state, extraState);
+          is(state.value & state_focusable, 0,
+             "Wrong focusable state bit for internal frame!");
+
+          // see bug 428954: No name wanted for internal frame
+          is(outerDocAcc.name, "", "Wrong name for internal frame!");
+
+          // see bug 440770, no actions wanted on outer doc
+          is(outerDocAcc.numActions, 0,
+             "Wrong number of actions for internal frame!");
+          var actionTempStr; // not really used, just needs to receive a value
+          try {
+            actionTempStr = outerDocAcc.getActionName(0);
+            do_throw("No exception thrown for actionName!");
+          } catch(e) {
+            ok(e.result, ns_error_invalid_arg,
+               "Wrong return value for actionName call!");
+          }
+
+          try {
+            actionTempStr = outerDocAcc.getActionDescription(0);
+            do_throw("No exception thrown for actionDescription!");
+          } catch(e) {
+            ok(e.result, ns_error_invalid_arg,
+               "Wrong return value for actionDescription call!");
+          }
+
+          try {
+            outerDocAcc.doAction(0);
+            do_throw("No exception thrown for doAction!");
+          } catch(e) {
+            ok(e.result, ns_error_invalid_arg,
+               "Wrong return value for doAction call!");
+          }
+        }
+      }
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=441519"
+     title="nsOuterDocAccessible chrome tests">
+    Mozilla Bug 441519
+  </a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+</body>
+</html>
--- a/allmakefiles.sh
+++ b/allmakefiles.sh
@@ -58,16 +58,17 @@ fi
 add_makefiles "
 Makefile
 build/Makefile
 build/unix/Makefile
 config/Makefile
 config/autoconf.mk
 config/mkdepend/Makefile
 config/doxygen.cfg
+config/tests/src-simple/Makefile
 probes/Makefile
 extensions/Makefile
 "
 
 if [ "$MOZ_MEMORY" ]; then
   add_makefiles "
     memory/jemalloc/Makefile
   "
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -71,19 +71,16 @@ GRE_MILESTONE = $(shell $(PYTHON) $(tops
 GRE_BUILDID = $(shell $(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(LIBXUL_DIST)/bin/platform.ini Build BuildID)
 
 DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DGRE_BUILDID=$(GRE_BUILDID)
 
 ifdef MOZ_MEMORY
 ifneq ($(OS_ARCH),WINNT)
 LIBS += -ljemalloc
 endif
-ifeq ($(OS_ARCH),SunOS)
-SOLARIS_JEMALLOC_LDFLAGS = -L$(LIBXUL_DIST)/bin -lxul
-endif
 endif
 
 ifdef LIBXUL_SDK
 include $(topsrcdir)/config/rules.mk
 else
 # Build a binary bootstrapping with XRE_main
 
 ifeq ($(USE_SHORT_LIBNAME), 1)
@@ -158,26 +155,17 @@ NSDISTMODE = copy
 include $(topsrcdir)/config/config.mk
 
 ifdef _MSC_VER
 # Always enter a Windows program through wmain, whether or not we're
 # a console application.
 WIN32_EXE_LDFLAGS += -ENTRY:wmainCRTStartup
 endif
 
-ifndef BUILD_STATIC_LIBS
-
-ifdef NS_TRACE_MALLOC
-# when libxul is enabled, trace-malloc is part of it
-ifndef MOZ_ENABLE_LIBXUL
-EXTRA_DSO_LIBS += tracemalloc
-endif
-endif
-
-else
+ifdef BUILD_STATIC_LIBS
 include $(topsrcdir)/config/static-config.mk
 
 EXTRA_DEPS	+= \
 	$(STATIC_EXTRA_DEPS) \
 	$(NULL)
 DEFINES		+= $(STATIC_DEFINES)
 CPPSRCS		+= $(STATIC_CPPSRCS)
 EXTRA_DSO_LIBS	+= $(STATIC_EXTRA_DSO_LIBS)
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -234,19 +234,17 @@ pref("browser.urlbar.search.timeout", 10
 pref("browser.download.saveLinkAsFilenameTimeout", 1000);
 
 pref("browser.download.useDownloadDir", true);
 pref("browser.download.folderList", 0);
 pref("browser.download.manager.showAlertOnComplete", true);
 pref("browser.download.manager.showAlertInterval", 2000);
 pref("browser.download.manager.retention", 2);
 pref("browser.download.manager.showWhenStarting", true);
-pref("browser.download.manager.useWindow", true);
 pref("browser.download.manager.closeWhenDone", false);
-pref("browser.download.manager.openDelay", 0);
 pref("browser.download.manager.focusWhenStarting", false);
 pref("browser.download.manager.flashCount", 2);
 pref("browser.download.manager.addToRecentDocs", true);
 pref("browser.download.manager.quitBehavior", 0);
 pref("browser.download.manager.scanWhenDone", true);
 pref("browser.download.manager.resumeOnWakeDelay", 10000);
 
 // search engines URL
@@ -479,17 +477,17 @@ pref("accessibility.typeaheadfind", fals
 pref("accessibility.typeaheadfind.timeout", 5000);
 pref("accessibility.typeaheadfind.linksonly", false);
 pref("accessibility.typeaheadfind.flashBar", 1);
 
 // Disable the default plugin for firefox
 pref("plugin.default_plugin_disabled", true);
 
 // plugin finder service url
-pref("pfs.datasource.url", "https://pfs.mozilla.org/plugins/PluginFinderService.php?mimetype=%PLUGIN_MIMETYPE%&appID=%APP_ID%&appVersion=%APP_VERSION%&clientOS=%CLIENT_OS%&chromeLocale=%CHROME_LOCALE%");
+pref("pfs.datasource.url", "https://pfs.mozilla.org/plugins/PluginFinderService.php?mimetype=%PLUGIN_MIMETYPE%&appID=%APP_ID%&appVersion=%APP_VERSION%&clientOS=%CLIENT_OS%&chromeLocale=%CHROME_LOCALE%&appRelease=%APP_RELEASE%");
 
 // by default we show an infobar message when pages require plugins the user has not installed
 pref("plugins.hide_infobar_for_missing_plugin", false);
 
 #ifdef XP_WIN
 pref("browser.preferences.instantApply", false);
 #else
 pref("browser.preferences.instantApply", true);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -934,18 +934,16 @@ function delayedStartup()
   // initiated by a web page script
   window.addEventListener("fullscreen", onFullScreen, true);
 
   if (gIsLoadingBlank && gURLBar && isElementVisible(gURLBar))
     focusElement(gURLBar);
   else
     focusElement(content);
 
-  SetPageProxyState("invalid");
-
   var navToolbox = getNavToolbox();
   navToolbox.customizeDone = BrowserToolboxCustomizeDone;
   navToolbox.customizeChange = BrowserToolboxCustomizeChange;
 
   // Set up Sanitize Item
   gSanitizeListener = new SanitizeListener();
 
   // Enable/Disable auto-hide tabbar
@@ -2544,23 +2542,18 @@ function FillInHTMLTooltip(tipElement)
   }
 
   return retVal;
 }
 
 var proxyIconDNDObserver = {
   onDragStart: function (aEvent, aXferData, aDragAction)
     {
-      var value = gURLBar.value;
-      // XXX - do we want to allow the user to set a blank page to their homepage?
-      //       if so then we want to modify this a little to set about:blank as
-      //       the homepage in the event of an empty urlbar.
-      if (!value) return;
-
-      var urlString = value + "\n" + window.content.document.title;
+      var value = content.location.href;
+      var urlString = value + "\n" + content.document.title;
       var htmlString = "<a href=\"" + value + "\">" + value + "</a>";
 
       aXferData.data = new TransferData();
       aXferData.data.addDataForFlavour("text/x-moz-url", urlString);
       aXferData.data.addDataForFlavour("text/unicode", value);
       aXferData.data.addDataForFlavour("text/html", htmlString);
 
       // we're copying the URL from the proxy icon, not moving
@@ -4809,36 +4802,16 @@ function asyncOpenWebPanel(event)
          // you to add a sidebar panel.  We support the Opera convention here.  The link's
          // title attribute contains the title that should be used for the sidebar panel.
          PlacesUIUtils.showMinimalAddBookmarkUI(makeURI(wrapper.href),
                                                 wrapper.getAttribute("title"),
                                                 null, null, true, true);
          event.preventDefault();
          return false;
        }
-       else if (target == "_search") {
-         // Used in WinIE as a way of transiently loading pages in a sidebar.  We
-         // mimic that WinIE functionality here and also load the page transiently.
-
-         // DISALLOW_INHERIT_PRINCIPAL is used here in order to also
-         // block javascript and data: links targeting the sidebar.
-         try {
-           const nsIScriptSecurityMan = Ci.nsIScriptSecurityManager;
-           urlSecurityCheck(wrapper.href,
-                            wrapper.ownerDocument.nodePrincipal,
-                            nsIScriptSecurityMan.DISALLOW_INHERIT_PRINCIPAL);
-         }
-         catch(ex) {
-           return false;
-         } 
-
-         openWebPanel(gNavigatorBundle.getString("webPanels"), wrapper.href);
-         event.preventDefault();
-         return false;
-       }
      }
      else {
        handleLinkClick(event, wrapper.href, linkNode);
      }
 
      return true;
    } else {
      // Try simple XLink
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -340,16 +340,17 @@
                chromedir="&locale.dir;"
                onclick="getIdentityHandler().handleIdentityButtonEvent(event);"
                onkeypress="getIdentityHandler().handleIdentityButtonEvent(event);">
             <hbox align="center">
               <stack id="page-proxy-stack"
                      onclick="PageProxyClickHandler(event);">
                 <image id="urlbar-throbber" busy="false"/>
                 <image id="page-proxy-favicon" validate="never"
+                       pageproxystate="invalid"
                        ondraggesture="PageProxyDragGesture(event);"
                        onerror="this.removeAttribute('src');"/>
               </stack>
               <label id="identity-icon-label"/>
             </hbox>
           </box>
           <hbox id="urlbar-icons">
             <button type="menu"
@@ -358,29 +359,24 @@
                     id="feed-button"
                     chromedir="&locale.dir;"
                     onclick="return FeedHandler.onFeedButtonClick(event);">
               <menupopup position="after_end"
                          onpopupshowing="return FeedHandler.buildFeedList(this);"
                          oncommand="return FeedHandler.subscribeToFeed(null, event);"
                          onclick="checkForMiddleClick(this, event);"/>
             </button>
-#ifdef MOZ_SAFE_BROWSING
-            <image id="safebrowsing-urlbar-icon" tooltiptext="&safeb.urlbaricon.tooltip;"
-                   level="safe"
+            <image id="star-button"
                    class="urlbar-icon"
-                   onclick="goDoCommand('safebrowsing-show-warning')"/>
-#endif
-          <image id="star-button"
-                 class="urlbar-icon"
-                 onclick="PlacesStarButton.onClick(event);"/>
-          <image id="go-button" chromedir="&locale.dir;"
-                 class="urlbar-icon"
-                 tooltiptext="&goEndCap.tooltip;"
-                 onclick="handleURLBarCommand(event);"/>
+                   onclick="PlacesStarButton.onClick(event);"/>
+            <image id="go-button"
+                   chromedir="&locale.dir;"
+                   class="urlbar-icon"
+                   tooltiptext="&goEndCap.tooltip;"
+                   onclick="handleURLBarCommand(event);"/>
           </hbox>
         </textbox>
       </toolbaritem>
 
       <toolbaritem id="search-container" title="&searchItem.title;"
                    align="center" class="chromeclass-toolbar-additional"
                    flex="100" persist="width">
         <searchbar id="searchbar" flex="1" chromedir="&locale.dir;"
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -1222,18 +1222,21 @@ nsContextMenu.prototype = {
   isTargetATextBox: function(node) {
     if (node instanceof HTMLInputElement)
       return (node.type == "text" || node.type == "password")
 
     return (node instanceof HTMLTextAreaElement);
   },
 
   isTargetAKeywordField: function(aNode) {
+    if (!(aNode instanceof HTMLInputElement))
+      return false;
+
     var form = aNode.form;
-    if (!form)
+    if (!form || aNode.type == "password")
       return false;
 
     var method = form.method.toUpperCase();
 
     // These are the following types of forms we can create keywords for:
     //
     // method   encoding type       can create keyword
     // GET      *                                 YES
--- a/browser/branding/unofficial/locales/jar.mn
+++ b/browser/branding/unofficial/locales/jar.mn
@@ -1,6 +1,7 @@
 #filter substitution
 
 @AB_CD@.jar:
 % locale branding @AB_CD@ %locale/branding/
-  locale/branding/brand.dtd        (%brand.dtd)
-* locale/branding/brand.properties (%brand.properties)
+# Gran Paradiso branding only exists in en-US
+  locale/branding/brand.dtd        (en-US/brand.dtd)
+* locale/branding/brand.properties (en-US/brand.properties)
--- a/browser/components/places/content/toolbar.xml
+++ b/browser/components/places/content/toolbar.xml
@@ -757,58 +757,67 @@
         // dragging over this menu--insertion point, child index to drop
         // before, and folder to drop into.
         _getDropPoint: function TBV_DO_getDropPoint(event) {
           // Can't drop if the toolbar isn't a folder.
           var result = this._self.getResult();
           if (!PlacesUtils.nodeIsFolder(result.root))
             return null;
 
+          var isRTL = document.defaultView
+                              .getComputedStyle(this._self.parentNode, "")
+                              .direction == "rtl";
+
           var dropPoint = { ip: null, beforeIndex: null, folderNode: null };
           // Loop through all the nodes to see which one this should
           // get dropped in/next to
           for (var i = 0; i < this._self.childNodes.length; i++) {
             var xulNode = this._self.childNodes[i];
             if (PlacesUtils.nodeIsFolder(xulNode.node) &&
                 !PlacesUtils.nodeIsReadOnly(xulNode.node)) {
               // This is a folder. If the mouse is in the left 25% of the
-              // node, drop to the left of the folder.  If it's in the middle
-              // 50%, drop into the folder.  If it's past that, drop to the right.
-              if (event.clientX < xulNode.boxObject.x + (xulNode.boxObject.width * 0.25)) {
+              // node (or 25% of the right, in RTL UI), drop before the folder.
+              // If it's in the middle 50%, drop into the folder. If it's past
+              // that, drop after.
+              if ((isRTL && event.clientX > xulNode.boxObject.x + (xulNode.boxObject.width * 0.75)) ||
+                  (!isRTL && event.clientX < xulNode.boxObject.x + (xulNode.boxObject.width * 0.25))) {
                 // Drop to the left of this folder.
                 dropPoint.ip =
                   new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
                                      i, -1);
                 dropPoint.beforeIndex = i;
                 return dropPoint;
               }
-              else if (event.clientX < xulNode.boxObject.x + (xulNode.boxObject.width * 0.75)) {
+              else if ((isRTL && event.clientX > xulNode.boxObject.x + (xulNode.boxObject.width * 0.25)) ||
+                       (!isRTL && event.clientX < xulNode.boxObject.x + (xulNode.boxObject.width * 0.75))) {
                 // Drop inside this folder.
                 dropPoint.ip =
                   new InsertionPoint(PlacesUtils.getConcreteItemId(xulNode.node),
                                      -1, 1);
                 dropPoint.beforeIndex = i;
                 dropPoint.folderNode = xulNode;
                 return dropPoint;
               }
             }
             else {
-              // This is a non-folder node. If the mouse is left of the middle,
-              // drop to the left of the folder.  If it's right, drop to the right.
-              if (event.clientX < xulNode.boxObject.x + (xulNode.boxObject.width / 2)) {
-                // Drop to the left of this bookmark.
+              // This is a non-folder node. If the mouse is left (or right, in
+              // RTL UI) of the middle, drop before the folder.  Otehrwise,
+              // we'll drop after
+              if ((isRTL && event.clientX > xulNode.boxObject.x + (xulNode.boxObject.width / 2)) ||
+                  (!isRTL && event.clientX < xulNode.boxObject.x + (xulNode.boxObject.width / 2))) {
+                // Drop before this bookmark.
                 dropPoint.ip =
 	                new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
 	                                   i, -1);
                 dropPoint.beforeIndex = i;
                 return dropPoint;
               }
             }
           }
-          // Should drop to the right of the last node.
+          // Should drop after the last node.
           dropPoint.ip =
         	  new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
 	                             -1, 1);
           dropPoint.beforeIndex = -1;
           return dropPoint;
         },
         
         onDragStart: function TBV_DO_onDragStart(event, xferData, dragAction) {
@@ -888,22 +897,29 @@
                 ind.style.marginLeft = this._self.lastChild.boxObject.x + 
                                        this._self.lastChild.boxObject.width - this._self.boxObject.x - halfInd + 'px';
               else
                 ind.style.marginLeft = this._self.childNodes[dropPoint.beforeIndex].boxObject.x -
                                        this._self.boxObject.x - halfInd + 'px';
             }
             else {
               halfInd = Math.floor(halfInd);
-              if (dropPoint.beforeIndex == -1 || !this._self.childNodes.length)
-                ind.style.marginRight = '0px';
-              else
-                ind.style.marginRight = (this._self.childNodes[this._self.childNodes.length - 1].boxObject.x +
-                                         this._self.childNodes[this._self.childNodes.length - 1].boxObject.width) -
-                                        (this._self.childNodes[dropPoint.beforeIndex].boxObject.x) - halfInd + 'px';
+              if (this._self.childNodes.length == 0)
+                ind.style.marginRight = this._self.boxObject.width + 'px';
+              else if (dropPoint.beforeIndex == -1) {
+                ind.style.marginRight = this._self.boxObject.width -
+                                        (this._self.childNodes[this._self.childNodes.length - 1].boxObject.x +
+                                        halfInd) +'px';
+              }
+              else {
+                ind.style.marginRight = this._self.boxObject.width -
+                                        (this._self.childNodes[dropPoint.beforeIndex].boxObject.x +
+                                        this._self.childNodes[dropPoint.beforeIndex].boxObject.width -
+                                        this._self.boxObject.x + halfInd) + 'px';
+              }
             }
             // Clear out old folder information
             this._clearOverFolder();
           }
         },
 
         onDrop: function TBV_DO_onDrop(event, dropData, session) {
           var dropPoint = this._getDropPoint(event);
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -605,20 +605,20 @@ init.d/README
 redo-prebinding.sh
 res/viewer.properties
 res/bloatcycle.html
 #endif
 #ifdef XP_UNIX
 #ifndef XP_MACOSX
 readme.txt
 chrome/icons/default/default.xpm
+dictionaries/PL.dic
+dictionaries/PL.aff
 #endif
 #endif
-dictionaries/PL.dic
-dictionaries/PL.aff
 #ifdef XP_WIN
 #ifdef MOZ_MEMORY
 Microsoft.VC80.CRT.manifest
 msvcm80.dll
 msvcp80.dll
 msvcr80.dll
 #else
 mozcrt19.dll
--- a/browser/locales/en-US/chrome/browser/safebrowsing/phishing-afterload-warning-message.dtd
+++ b/browser/locales/en-US/chrome/browser/safebrowsing/phishing-afterload-warning-message.dtd
@@ -10,18 +10,16 @@
 
 <!ENTITY safeb.palm.accept.label "Get me out of here!">
 <!ENTITY safeb.palm.accept.statustext "Navigate to my home page">
 <!ENTITY safeb.palm.decline.label "Ignore this warning">
 <!ENTITY safeb.palm.decline.statustext "Close warning" >
 <!ENTITY safeb.palm.notforgery.label2 "This isn't a web forgery…">
 <!ENTITY safeb.palm.report.label "Why was this site blocked?">
 
-<!ENTITY safeb.urlbaricon.tooltip "This page might be dangerous; click for details.">
-
 <!ENTITY safeb.blocked.malware.title "Reported Attack Site!">
 <!-- Localization note (safeb.blocked.malware.shortDesc) - Please don't translate the contents of the <span id="malware_sitename"/> tag.  It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
 <!ENTITY safeb.blocked.malware.shortDesc "This web site at <span id='malware_sitename'/> has been reported as an attack site and has been blocked based on your security preferences.">
 <!ENTITY safeb.blocked.malware.longDesc "<p>Attack sites try to install programs that steal private information, use your computer to attack others, or damage your system.</p><p>Some attack sites intentionally distribute harmful software, but many are compromised without the knowledge or permission of their owners.</p>">
 
 <!ENTITY safeb.blocked.phishing.title "Reported Web Forgery!">
 <!-- Localization note (safeb.blocked.phishing.shortDesc) - Please don't translate the contents of the <span id="phishing_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
 <!ENTITY safeb.blocked.phishing.shortDesc "This web site at <span id='phishing_sitename'/> has been reported as a web forgery and has been blocked based on your security preferences.">
--- a/browser/locales/shipped-locales
+++ b/browser/locales/shipped-locales
@@ -32,16 +32,18 @@ nb-NO
 nl
 nn-NO
 pa-IN
 pl
 pt-BR
 pt-PT
 ro
 ru
+si
 sk
+sl
 sq
 sr
 sv-SE
 tr
 uk
 zh-CN
 zh-TW
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -1076,20 +1076,16 @@ toolbar[iconsize="small"] #paste-button[
 }
 
 /* Go button */
 #go-button {
   padding: 3px 2px 2px 2px;
   list-style-image: url("chrome://browser/skin/Go-arrow.png");
 }
 
-#go-button[chromedir="rtl"] {
-  list-style-image: url("chrome://browser/skin/Go-arrow-rtl.png");
-}
-
 /* Star button */
 #star-button {
   padding: 1px;
   list-style-image: url("chrome://browser/skin/places/starPage.png");
 }
 
 #star-button[starred="true"] {
   list-style-image: url("chrome://browser/skin/places/pageStarred.png");
--- a/browser/themes/gnomestripe/browser/engineManager.css
+++ b/browser/themes/gnomestripe/browser/engineManager.css
@@ -35,13 +35,15 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 %endif
 
 #engineList treechildren::-moz-tree-image(engineName) {
   -moz-margin-end: 4px;
   -moz-margin-start: 1px;
+  width: 16px;
+  height: 16px;
 }
 
 #engineList treechildren::-moz-tree-row {
   height: 20px !important;
 }
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -92,21 +92,23 @@
 }
 
 #main-window:not([active="true"]) .tabbrowser-tab[selected="true"] > .tab-image-middle,
 #main-window:not([active="true"]) .tabbrowser-tab[selected="true"] > .tab-closebutton,
 #main-window:not([active="true"]) .tabbrowser-tab[selected="true"] > .tab-close-button {
   background-image: url("chrome://browser/skin/tabbrowser/tab-middle-inactive.png");
 }
 
-#main-window:not([active="true"]) .tabbrowser-tab[selected="true"] > .tab-image-left {
+#main-window:not([active="true"]) .tabbrowser-tab[selected="true"] > .tab-image-left,
+#main-window:not([active="true"]) .tabbrowser-tab[selected="true"][chromedir="rtl"] > .tab-image-right {
   background: url("chrome://browser/skin/tabbrowser/tab-left-inactive.png") no-repeat;
 }
 
-#main-window:not([active="true"]) .tabbrowser-tab[selected="true"] > .tab-image-right {
+#main-window:not([active="true"]) .tabbrowser-tab[selected="true"] > .tab-image-right,
+#main-window:not([active="true"]) .tabbrowser-tab[selected="true"][chromedir="rtl"] > .tab-image-left {
   background: url("chrome://browser/skin/tabbrowser/tab-right-inactive.png") no-repeat;
 }
 
 /* ----- SEARCH FIELD ----- */
 
 #wrapper-search-container #searchbar html|*.textbox-input {
   visibility: hidden;
 }
@@ -1629,22 +1631,22 @@ toolbarbutton.chevron > .toolbarbutton-m
 }
 
 .tabbrowser-tab:not([selected="true"]):hover .tab-icon,
 .tabbrowser-tab[selected="true"] .tab-icon {
   opacity: 1.0;
 }
 
 .tab-text {
-  font: message-box;
   margin-top: 0 !important;
 }
 
 .tab-text,
 .tab-text-shadow {
+  font: message-box;
   font-weight: bold !important;
 }
 
 .tabbrowser-tab[busy] > .tab-icon-image,
 .tabbrowser-tab[busy] > .tab-image-middle > .tab-icon > .tab-icon-image {
  list-style-image: url("chrome://global/skin/icons/loading_16.png") !important; 
 }
 
--- a/browser/themes/pinstripe/browser/engineManager.css
+++ b/browser/themes/pinstripe/browser/engineManager.css
@@ -35,13 +35,15 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 %endif
 
 #engineList treechildren::-moz-tree-image(engineName) {
   -moz-margin-end: 4px;
   -moz-margin-start: 1px;
+  width: 16px;
+  height: 16px;
 }
 
 #engineList treechildren::-moz-tree-row {
   height: 20px !important;
 }
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -1228,20 +1228,16 @@ statusbarpanel#statusbar-display {
 /* ::::: go button ::::: */
 
 #go-button {
   padding: 0 2px;
   list-style-image: url("chrome://browser/skin/Go-arrow.png");
   -moz-image-region: rect(0px 16px 16px 0px);
 }
 
-#go-button[chromedir="rtl"] {
-  list-style-image: url("chrome://browser/skin/Go-arrow-rtl.png");
-}
-
 #go-button:hover {
   -moz-image-region: rect(16px 16px 32px 0px);
 }
 
 /* star button */
 #star-button {
   padding: 0 2px;
   list-style-image: url("chrome://browser/skin/places/bookmark.png");
--- a/browser/themes/winstripe/browser/engineManager.css
+++ b/browser/themes/winstripe/browser/engineManager.css
@@ -35,13 +35,15 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 %endif
 
 #engineList treechildren::-moz-tree-image(engineName) {
   -moz-margin-end: 4px;
   -moz-margin-start: 1px;
+  width: 16px;
+  height: 16px;
 }
 
 #engineList treechildren::-moz-tree-row {
   height: 20px !important;
 }
--- a/browser/themes/winstripe/browser/places/organizer-aero.css
+++ b/browser/themes/winstripe/browser/places/organizer-aero.css
@@ -4,20 +4,33 @@
   border-top: none;
 }
 
 #placesToolbar {
   -moz-appearance: -moz-win-media-toolbox;
   color: -moz-win-mediatext;
 }
 
+#placesToolbar:-moz-system-metric(windows-default-theme) {
+  min-height: 36px;
+  padding-top: 0px;
+  padding-bottom: 0px;
+  -moz-padding-start: 6px;
+  -moz-padding-end: 8px;
+}
+
 #placesMenu > menu {
   color: -moz-win-mediatext;
 }
 
+#placesMenu:-moz-system-metric(windows-default-theme) > menu > label {
+  -moz-padding-end: 15px;
+  background-image: url(chrome://browser/skin/places/dropDown.png);
+}
+
 #placesView > splitter:-moz-system-metric(windows-default-theme) {
   border: 0;
   -moz-border-end: 1px solid;
   -moz-border-right-colors: #A9B7C9;
   -moz-border-left-colors: #A9B7C9;
   min-width: 0;
   width: 3px !important;
   background-color: transparent;
--- a/browser/themes/winstripe/browser/places/organizer.css
+++ b/browser/themes/winstripe/browser/places/organizer.css
@@ -1,13 +1,13 @@
 
 /* Toolbar */
 #placesToolbar {
-  border: none;
-  min-height: 36px;
+  padding: 3px;  /* b/f buttons have a 1px image padding */
+  -moz-padding-end: 4px;
 }
 
 /* back & forward buttons */
 #back-button, #forward-button {
   list-style-image: url(libraryNavigation.png);
   -moz-appearance: none;
   padding: 0;
   border: none;
@@ -16,17 +16,16 @@
 #placesToolbar > toolbarbutton > image,
 #placesToolbar > toolbarbutton > label {
   margin: 0;
   padding: 0;
 }
 
 #back-button,
 #forward-button[chromedir="rtl"] {  
-  -moz-margin-start: 8px;
   -moz-image-region: rect(0px, 24px, 24px, 0px);
 }
 #back-button:not([disabled="true"]):hover,
 #forward-button:not([disabled="true"]):hover[chromedir="rtl"] {
   -moz-image-region: rect(24px, 24px, 48px, 0px);
 }
 #back-button[disabled="true"],
 #forward-button[chromedir="rtl"][disabled="true"] {
@@ -34,17 +33,16 @@
 }
 #back-button:not([disabled="true"]):hover:active,
 #forward-button:not([disabled="true"]):hover:active[chromedir="rtl"] {
   -moz-image-region: rect(72px, 24px, 96px, 0px);
 }
 
 #forward-button,
 #back-button[chromedir="rtl"] {
-  -moz-margin-end: 8px;
   -moz-image-region: rect(0px, 48px, 24px, 24px);
 }
 #forward-button:not([disabled="true"]):hover,
 #back-button:not([disabled="true"]):hover[chromedir="rtl"] {
   -moz-image-region: rect(24px, 48px, 48px, 24px);
 }
 #forward-button[disabled="true"],
 #back-button[chromedir="rtl"][disabled="true"] {
@@ -52,16 +50,17 @@
 }
 #forward-button:not([disabled="true"]):hover:active,
 #back-button:not([disabled="true"]):hover:active[chromedir="rtl"] {
   -moz-image-region: rect(72px, 48px, 96px, 24px);
 }
 
 /* Menu */
 #placesMenu {
+  -moz-margin-start: 8px;
   -moz-appearance: none;
   border: none;
 }
 
 #placesMenu > menu {
   -moz-padding-start: 4px;
   -moz-padding-end: 1px;
   padding-top: 2px;
@@ -181,16 +180,17 @@
 .small .button-text,
 .small .button-box {
   padding: 0px;
   border: 0px;
 }
 
 #searchFilter {
   padding: 0px;
+  margin: 0px;
 }
 
 #searchFilter .textbox-input-box {
   padding: 2px 2px 3px 4px;
 }
 
 %ifdef PLACES_QUERY_BUILDER
 /* Calendar */
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -101,16 +101,17 @@ AUTOMATION_PPARGS += -DIS_CYGWIN=1
 endif
 
 _LEAKTEST_DIR = $(DEPTH)/_leaktest
 
 _LEAKTEST_FILES =    \
 		automation.py \
 		leaktest.py \
 		bloatcycle.html \
+		$(topsrcdir)/build/pgo/server-locations.txt \
 		$(NULL)
 
 automation.py: $(topsrcdir)/build/pgo/automation.py.in
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
 	$(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@
 
 leaktest.py: leaktest.py.in
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $^ > $@
--- a/build/pgo/Makefile.in
+++ b/build/pgo/Makefile.in
@@ -48,16 +48,17 @@ include $(topsrcdir)/config/rules.mk
 # Stuff to make a build with a profile
 _PROFILE_DIR = $(DEPTH)/_profile/pgo
 
 _PGO_FILES = 	\
 		automation.py \
 		profileserver.py \
 		index.html \
 		quit.js \
+		server-locations.txt \
 		$(NULL)
 
 
 ifeq ($(USE_SHORT_LIBNAME), 1)
 PROGRAM = $(MOZ_APP_NAME)$(BIN_SUFFIX)
 else
 PROGRAM = $(MOZ_APP_NAME)-bin$(BIN_SUFFIX)
 endif
--- a/build/pgo/automation.py.in
+++ b/build/pgo/automation.py.in
@@ -32,90 +32,43 @@
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
+import codecs
 from datetime import datetime
 import itertools
 import logging
 import shutil
 import os
+import re
 import signal
 import sys
 import threading
 
 """
 Runs the browser from a script, and provides useful utilities
 for setting up the browser environment.
 """
 
 __all__ = [
            "UNIXISH",
            "IS_WIN32",
+           "IS_MAC",
            "runApp",
            "Process",
            "initializeProfile",
            "DIST_BIN",
            "DEFAULT_APP",
           ]
 
-# Since some tests require cross-domain support in Mochitest, across ports,
-# domains, subdomains, etc. we use a proxy autoconfig hack to map a bunch of
-# servers onto localhost:8888.  We have to grant them the same privileges as
-# localhost:8888 here, since the browser only knows them as the URLs they're
-# pretending to be.  We also have two servers which are set up but don't have
-# privileges, for testing privilege functionality.
-#
-# These lists must be kept in sync with the following list:
-#
-# http://developer.mozilla.org/en/docs/Mochitest#How_do_I_test_issues_which_only_show_up_when_tests_are_run_across_domains.3F
-#
-servers = [
-           "localhost:8888", # MUST be first -- see PAC pref-setting code
-           "example.org:80",
-           "test1.example.org:80",
-           "test2.example.org:80",
-           "sub1.test1.example.org:80",
-           "sub1.test2.example.org:80",
-           "sub2.test1.example.org:80",
-           "sub2.test2.example.org:80",
-           "example.org:8000",
-           "test1.example.org:8000",
-           "test2.example.org:8000",
-           "sub1.test1.example.org:8000",
-           "sub1.test2.example.org:8000",
-           "sub2.test1.example.org:8000",
-           "sub2.test2.example.org:8000",
-           "example.com:80",
-           "test1.example.com:80",
-           "test2.example.com:80",
-           "sub1.test1.example.com:80",
-           "sub1.test2.example.com:80",
-           "sub2.test1.example.com:80",
-           "sub2.test2.example.com:80",
-           "sectest1.example.org:80",
-           "sub.sectest2.example.org:80",
-           "sub1.xn--lt-uia.example.org:8000", # U+00E4 U+006C U+0074
-           "sub2.xn--lt-uia.example.org:80",   # U+00E4 U+006C U+0074
-           "xn--exmple-cua.test:80",
-           "sub1.xn--exmple-cua.test:80",
-           "xn--hxajbheg2az3al.xn--jxalpdlp:80", # Greek IDN for example.test
-           "sub1.xn--hxajbheg2az3al.xn--jxalpdlp:80",
-          ]
-
-unprivilegedServers = [
-                       "sectest2.example.org:80",
-                       "sub.sectest1.example.org:80",
-                      ]
-
-
 # These are generated in mozilla/build/Makefile.in
 #expand DIST_BIN = "./" + __XPC_BIN_PATH__
 #expand IS_WIN32 = len("__WIN32__") != 0
 #expand IS_MAC = __IS_MAC__ != 0
 #ifdef IS_CYGWIN
 #expand IS_CYGWIN = __IS_CYGWIN__ == 1
 #else
 IS_CYGWIN = False
@@ -217,16 +170,98 @@ class Process:
     except:
       pass
 
 
 #################
 # PROFILE SETUP #
 #################
 
+class SyntaxError(Exception):
+  "Signifies a syntax error on a particular line in server-locations.txt."
+
+  def __init__(self, lineno, msg = None):
+    self.lineno = lineno
+    self.msg = msg
+
+  def __str__(self):
+    s = "Syntax error on line " + str(self.lineno)
+    if self.msg:
+      s += ": %s." % self.msg
+    else:
+      s += "."
+    return s
+
+
+class Location:
+  "Represents a location line in server-locations.txt."
+
+  def __init__(self, scheme, host, port, options):
+    self.scheme = scheme
+    self.host = host
+    self.port = port
+    self.options = options
+
+
+def readLocations():
+  """
+  Reads the locations at which the Mochitest HTTP server is available from
+  server-locations.txt.
+  """
+
+  locationFile = codecs.open("server-locations.txt", "r", "UTF-8")
+
+  # Perhaps more detail than necessary, but it's the easiest way to make sure
+  # we get exactly the format we want.  See server-locations.txt for the exact
+  # format guaranteed here.
+  lineRe = re.compile(r"^(?P<scheme>[a-z][-a-z0-9+.]*)"
+                      r"://"
+                      r"(?P<host>"
+                        r"\d+\.\d+\.\d+\.\d+"
+                        r"|"
+                        r"(?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)*"
+                        r"[a-z](?:[-a-z0-9]*[a-z0-9])?"
+                      r")"
+                      r":"
+                      r"(?P<port>\d+)"
+                      r"(?:"
+                      r"\s+"
+                      r"(?P<options>\w+(?:,\w+)*)"
+                      r")?$")
+  locations = []
+  lineno = 0
+  seenPrimary = False
+  for line in locationFile:
+    lineno += 1
+    if line.startswith("#") or line == "\n":
+      continue
+      
+    match = lineRe.match(line)
+    if not match:
+      raise SyntaxError(lineno)
+
+    options = match.group("options")
+    if options:
+      options = options.split(",")
+      if "primary" in options:
+        if seenPrimary:
+          raise SyntaxError(lineno, "multiple primary locations")
+        seenPrimary = True
+    else:
+      options = []
+
+    locations.append(Location(match.group("scheme"), match.group("host"),
+                              match.group("port"), options))
+
+  if not seenPrimary:
+    raise SyntaxError(lineno + 1, "missing primary location")
+
+  return locations
+
+
 def initializeProfile(profileDir):
   "Sets up the standard testing profile."
 
   # Start with a clean slate.
   shutil.rmtree(profileDir, True)
   os.mkdir(profileDir)
 
   prefs = []
@@ -244,52 +279,59 @@ user_pref("accessibility.typeaheadfind.a
 user_pref("javascript.options.showInConsole", true);
 user_pref("layout.debug.enable_data_xbl", true);
 user_pref("browser.EULA.override", true);
 
 user_pref("camino.warn_when_closing", false); // Camino-only, harmless to others
 """
   prefs.append(part)
 
-  # Grant God-power to all the servers on which tests can run.
-  for (i, server) in itertools.izip(itertools.count(1), servers):
+  locations = readLocations()
+
+  # Grant God-power to all the privileged servers on which tests run.
+  privileged = filter(lambda loc: "privileged" in loc.options, locations)
+  for (i, l) in itertools.izip(itertools.count(1), privileged):
     part = """
 user_pref("capability.principal.codebase.p%(i)d.granted",
           "UniversalXPConnect UniversalBrowserRead UniversalBrowserWrite \
            UniversalPreferencesRead UniversalPreferencesWrite \
            UniversalFileRead");
-user_pref("capability.principal.codebase.p%(i)d.id", "http://%(server)s");
+user_pref("capability.principal.codebase.p%(i)d.id", "%(origin)s");
 user_pref("capability.principal.codebase.p%(i)d.subjectName", "");
-"""  % {"i": i, "server": server}
+"""  % { "i": i,
+         "origin": (l.scheme + "://" + l.host + ":" + l.port) }
     prefs.append(part)
 
-  # Now add the two servers that do NOT have God-power so we can properly test
-  # the granting and receiving of God-power.  Strip off the first server because
-  # we proxy all the others to it.
-  allServers = servers[1:] + unprivilegedServers
-
-
-  # Now actually create the preference to make the proxying happen.
-  quotedServers = ", ".join(map(lambda x: "'" + x + "'", allServers))
+  # We need to proxy every server but the primary one.
+  origins = ["'%s://%s:%s'" % (l.scheme, l.host, l.port)
+             for l in filter(lambda l: "primary" not in l.options, locations)]
+  origins = ", ".join(origins)
 
   pacURL = """data:text/plain,
 function FindProxyForURL(url, host)
 {
-  var servers = [%(quotedServers)s];
-  var regex = new RegExp('http://(?:[^/@]*@)?(.*?(:\\\\\\\\d+)?)/');
+  var origins = [%(origins)s];
+  var regex = new RegExp('^([a-z][-a-z0-9+.]*)' +
+                         '://' +
+                         '(?:[^/@]*@)?' +
+                         '(.*?)' +
+                         '(?::(\\\\\\\\d+))?/');
   var matches = regex.exec(url);
   if (!matches)
     return 'DIRECT';
-  var hostport = matches[1], port = matches[2];
-  if (!port)
-    hostport += ':80';
-  if (servers.indexOf(hostport) >= 0)
+  var isHttp = matches[1] == 'http';
+  if (!matches[3])
+    matches[3] = isHttp ? '80' : '443';
+  var origin = matches[1] + '://' + matches[2] + ':' + matches[3];
+  if (origins.indexOf(origin) < 0)
+    return 'DIRECT';
+  if (isHttp)
     return 'PROXY localhost:8888';
   return 'DIRECT';
-}""" % {"quotedServers": quotedServers}
+}""" % { "origins": origins }
   pacURL = "".join(pacURL.splitlines())
 
   part = """
 user_pref("network.proxy.type", 2);
 user_pref("network.proxy.autoconfig_url", "%(pacURL)s");
 
 user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless to others
 """ % {"pacURL": pacURL}
new file mode 100644
--- /dev/null
+++ b/build/pgo/server-locations.txt
@@ -0,0 +1,116 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Jeff Walden <jwalden+code@mit.edu>.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+#
+# This file defines the locations at which this HTTP server may be accessed.
+# It is referred to by the following page, so if this file moves, that page must
+# be modified accordingly:
+#
+# http://developer.mozilla.org/en/docs/Mochitest#How_do_I_test_issues_which_only_show_up_when_tests_are_run_across_domains.3F
+#
+# Empty lines and lines which begin with "#" are ignored and may be used for
+# storing comments.  All other lines consist of an origin followed by whitespace
+# and a comma-separated list of options (if indeed any options are needed).
+#
+# The format of an origin is, referring to RFC 2396, a scheme (either "http" or
+# "https"), followed by "://", followed by a host, followed by ":", followed by
+# a port number.  The colon and port number must be present even if the port
+# number is the default for the protocol.
+#
+# Unrecognized options are ignored.  Recognized options are "primary" and
+# "privileged".  "primary" denotes a location which is the canonical location of
+# the server; this location is the one assumed for requests which don't
+# otherwise identify a particular origin (e.g. HTTP/1.0 requests).  "privileged"
+# denotes a location which should have the ability to request elevated
+# privileges; the default is no privileges.
+#
+
+#
+# This is the primary location from which tests run.
+#
+http://localhost:8888   primary,privileged
+
+#
+# These are a common set of prefixes scattered across one TLD with two ports and
+# another TLD on a single port.
+#
+http://example.org:80                privileged
+http://test1.example.org:80          privileged
+http://test2.example.org:80          privileged
+http://sub1.test1.example.org:80     privileged
+http://sub1.test2.example.org:80     privileged
+http://sub2.test1.example.org:80     privileged
+http://sub2.test2.example.org:80     privileged
+http://example.org:8000              privileged
+http://test1.example.org:8000        privileged
+http://test2.example.org:8000        privileged
+http://sub1.test1.example.org:8000   privileged
+http://sub1.test2.example.org:8000   privileged
+http://sub2.test1.example.org:8000   privileged
+http://sub2.test2.example.org:8000   privileged
+http://example.com:80                privileged
+http://test1.example.com:80          privileged
+http://test2.example.com:80          privileged
+http://sub1.test1.example.com:80     privileged
+http://sub1.test2.example.com:80     privileged
+http://sub2.test1.example.com:80     privileged
+http://sub2.test2.example.com:80     privileged
+
+#
+# These are subdomains of <ält.example.org>.
+#
+http://sub1.xn--lt-uia.example.org:8000   privileged
+http://sub2.xn--lt-uia.example.org:80     privileged
+http://xn--exmple-cua.test:80             privileged
+http://sub1.xn--exmple-cua.test:80        privileged
+
+#
+# These are subdomains of <παράδειγμα.δοκιμή>, the Greek IDN for example.test.
+#
+http://xn--hxajbheg2az3al.xn--jxalpdlp:80        privileged
+http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp:80   privileged
+
+#
+# These hosts are used in tests which exercise privilege-granting functionality;
+# we could reuse some of the names above, but specific names make it easier to
+# distinguish one from the other in tests (as well as what functionality is
+# being tested).
+#
+http://sectest1.example.org:80       privileged
+http://sub.sectest2.example.org:80   privileged
+http://sectest2.example.org:80
+http://sub.sectest1.example.org:80
--- a/build/unix/run-mozilla.sh
+++ b/build/unix/run-mozilla.sh
@@ -108,17 +108,17 @@ moz_get_debugger()
 	debuggers="ddd gdb dbx bdb"
 	debugger="notfound"
 	done="no"
 	for d in $debuggers
 	do
 		moz_test_binary /bin/type
 		if [ $? -eq 1 ]
 		then
-			dpath=`type ${d} | awk '{print $3;}' | sed -e 's/\.$//'`	
+			dpath=`LC_MESSAGES=C type ${d} | awk '{print $3;}' | sed -e 's/\.$//'`	
 		else 	
 			dpath=`which ${d}`	
 		fi
 		if [ -x "$dpath" ]
 		then
 			debugger=$dpath
 			break
 		fi
@@ -139,17 +139,17 @@ moz_run_program()
 	fi
 	##
 	## Use md5sum to crc a core file.  If md5sum is not found on the system,
 	## then don't debug core files.
 	##
 	moz_test_binary /bin/type
 	if [ $? -eq 1 ]
 	then
-		crc_prog=`type md5sum 2>/dev/null | awk '{print $3;}' 2>/dev/null | sed -e 's/\.$//'`
+		crc_prog=`LC_MESSAGES=C type md5sum 2>/dev/null | awk '{print $3;}' 2>/dev/null | sed -e 's/\.$//'`
 	else
 		crc_prog=`which md5sum 2>/dev/null`
 	fi
 	if [ -x "$crc_prog" ]
 	then
 		DEBUG_CORE_FILES=1
 	fi
 	if [ "$DEBUG_CORE_FILES" ]
@@ -207,17 +207,17 @@ moz_debug_program()
 	then
 		moz_bail "Cannot execute $prog."
 	fi
 	if [ -n "$moz_debugger" ]
 	then
 		moz_test_binary /bin/type
 		if [ $? -eq 1 ]
 		then	
-			debugger=`type $moz_debugger | awk '{print $3;}' | sed -e 's/\.$//'` 
+			debugger=`LC_MESSAGES=C type $moz_debugger | awk '{print $3;}' | sed -e 's/\.$//'` 
 		else
 			debugger=`which $moz_debugger` 
 		fi	
 	else
 		debugger=`moz_get_debugger`
 	fi
     if [ -x "$debugger" ] 
     then
--- a/client.mk
+++ b/client.mk
@@ -38,21 +38,20 @@
 #
 # ***** END LICENSE BLOCK *****
 
 # Build a mozilla application.
 #
 # To build a tree,
 #    1. hg clone ssh://hg.mozilla.org/mozilla-central mozilla
 #    2. cd mozilla
-#    3. python client.py checkout
-#    4. create your .mozconfig file with
+#    3. create your .mozconfig file with
 #       mk_add_options MOZ_CO_PROJECT=
 #         suite,browser
-#    5. gmake -f client.mk 
+#    4. gmake -f client.mk 
 #
 # Other targets (gmake -f client.mk [targets...]),
 #    build
 #    clean (realclean is now the same as clean)
 #    distclean
 #
 # See http://developer.mozilla.org/en/docs/Build_Documentation for 
 # more information.
@@ -284,16 +283,17 @@ EXTRA_CONFIG_DEPS := \
 
 $(TOPSRCDIR)/nsprpub/configure: $(TOPSRCDIR)/nsprpub/configure.in $(EXTRA_CONFIG_DEPS)
 	@echo Generating $@ using autoconf
 	cd $(TOPSRCDIR)/nsprpub; $(AUTOCONF)
 endif
 
 CONFIG_STATUS_DEPS := \
 	$(TOPSRCDIR)/configure \
+	$(TOPSRCDIR)/allmakefiles.sh \
 	$(TOPSRCDIR)/.mozconfig.mk \
 	$(wildcard $(TOPSRCDIR)/nsprpub/configure) \
 	$(wildcard $(TOPSRCDIR)/directory/c-sdk/configure) \
 	$(wildcard $(TOPSRCDIR)/config/milestone.txt) \
 	$(wildcard $(TOPSRCDIR)/config/chrome-versions.sh) \
   $(wildcard $(addsuffix confvars.sh,$(wildcard $(TOPSRCDIR)/*/))) \
 	$(NULL)
 
--- a/client.py
+++ b/client.py
@@ -1,24 +1,20 @@
 #!/usr/bin/python
 
-NSPR_CO_TAG = 'NSPR_4_7_1_RTM'
-NSS_CO_TAG  = 'NSS_3_12_RC3'
-
 NSPR_DIRS = ('nsprpub',)
 NSS_DIRS  = ('dbm',
              'security/nss',
              'security/coreconf',
              'security/dbm')
 
-# URL of the default hg repository to clone for Tamarin.
-DEFAULT_TAMARIN_REPO = 'http://hg.mozilla.org/tamarin-central/'
-
 import os
 import sys
+import datetime
+import shutil
 from optparse import OptionParser
 
 topsrcdir = os.path.dirname(__file__)
 if topsrcdir == '':
     topsrcdir = '.'
 
 try:
     from subprocess import check_call
@@ -42,97 +38,59 @@ def do_hg_pull(dir, repository, hg):
     if not os.path.exists(fulldir):
         fulldir = os.path.join(topsrcdir, dir)
         check_call_noisy([hg, 'clone', repository, fulldir])
     else:
         cmd = [hg, 'pull', '-u', '-R', fulldir]
         if repository is not None:
             cmd.append(repository)
         check_call_noisy(cmd)
+    check_call([hg, 'parent', '-R', fulldir,
+                '--template=Updated to revision {node}.\n'])
 
-def do_cvs_checkout(modules, tag, cvsroot, cvs):
-    """Check out a CVS directory.
+def do_cvs_export(modules, tag, cvsroot, cvs):
+    """Check out a CVS directory without CVS metadata, using "export"
     modules is a list of directories to check out, e.g. ['nsprpub']
     """
     for module in modules:
+        fullpath = os.path.join(topsrcdir, module)
+        if os.path.exists(fullpath):
+            print "Removing '%s'" % fullpath
+            shutil.rmtree(fullpath)
+
         (parent, leaf) = os.path.split(module)
+        print "CVS export begin: " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
         check_call_noisy([cvs, '-d', cvsroot,
-                          'checkout', '-P', '-r', tag, '-d', leaf,
+                          'export', '-r', tag, '-d', leaf,
                           'mozilla/%s' % module],
                          cwd=os.path.join(topsrcdir, parent))
+        print "CVS export end: " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
 
-o = OptionParser(usage="client.py [options] checkout")
-o.add_option("-m", "--mozilla-repo", dest="mozilla_repo",
-             default=None,
-             help="URL of Mozilla repository to pull from (default: use hg default in .hg/hgrc)")
+o = OptionParser(usage="client.py [options] update_nspr tagname | update_nss tagname")
 o.add_option("--skip-mozilla", dest="skip_mozilla",
              action="store_true", default=False,
-             help="Skip pulling the Mozilla repository.")
-
-o.add_option("-t", "--tamarin-repo", dest="tamarin_repo",
-             default=None,
-             help="URL of Tamarin repository to pull from (default: use hg default in js/tamarin/.hg/hgrc; or if that file doesn't exist, use \"" + DEFAULT_TAMARIN_REPO + "\".)")
-o.add_option("--skip-tamarin", dest="skip_tamarin",
-             action="store_true", default=False,
-             help="Skip pulling the Tamarin repository.")
+             help="Obsolete")
 
-o.add_option("--skip-nspr", dest="skip_nspr",
-             action="store_true", default=False,
-             help="Skip pulling the NSPR repository.")
-o.add_option("--skip-nss", dest="skip_nss",
-             action="store_true", default=False,
-             help="Skip pulling the NSS repository.")
-
-o.add_option("--hg", dest="hg", default=os.environ.get('HG', 'hg'),
-             help="The location of the hg binary")
 o.add_option("--cvs", dest="cvs", default=os.environ.get('CVS', 'cvs'),
              help="The location of the cvs binary")
 o.add_option("--cvsroot", dest="cvsroot",
              default=os.environ.get('CVSROOT', ':pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot'),
              help="The CVSROOT (default: :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot")
 
-
-def fixup_repo_options(options):
-    """ Check options.mozilla_repo and options.tamarin_repo values;
-    populate tamarin_repo if needed.
-
-    options.mozilla_repo and options.tamarin_repo are normally None.
-    This is fine-- our "hg pull" commands will omit the repo URL.
-    The exception is the initial checkout, which does an "hg clone"
-    for Tamarin.  That command requires a repository URL.
-    """
-
-    if (options.mozilla_repo is None
-            and not os.path.exists(os.path.join(topsrcdir, '.hg'))):
-        o.print_help()
-        print
-        print "*** The -m option is required for the initial checkout."
-        sys.exit(2)
-
-    # Handle special case: initial checkout of Tamarin.
-    if (options.tamarin_repo is None
-            and not os.path.exists(os.path.join(topsrcdir, 'js', 'tamarin'))):
-        options.tamarin_repo = DEFAULT_TAMARIN_REPO
-
 try:
-    (options, (action,)) = o.parse_args()
-except ValueError:
+    options, args = o.parse_args()
+    action = args[0]
+except IndexError:
     o.print_help()
     sys.exit(2)
 
-fixup_repo_options(options)
-
 if action in ('checkout', 'co'):
-    if not options.skip_nspr:
-        do_cvs_checkout(NSPR_DIRS, NSPR_CO_TAG, options.cvsroot, options.cvs)
-
-    if not options.skip_nss:
-        do_cvs_checkout(NSS_DIRS, NSS_CO_TAG, options.cvsroot, options.cvs)
-
-    if not options.skip_tamarin:
-        do_hg_pull('js/tamarin', options.tamarin_repo, options.hg)
-
-    if not options.skip_mozilla:
-        do_hg_pull('.', options.mozilla_repo, options.hg)
-
+    print >>sys.stderr, "Warning: client.py checkout is obsolete."
+    pass
+elif action in ('update_nspr'):
+    tag, = args[1:]
+    do_cvs_export(NSPR_DIRS, tag, options.cvsroot, options.cvs)
+elif action in ('update_nss'):
+    tag, = args[1:]
+    do_cvs_export(NSS_DIRS, tag, options.cvsroot, options.cvs)
 else:
     o.print_help()
     sys.exit(2)
--- a/config/Makefile.in
+++ b/config/Makefile.in
@@ -150,13 +150,23 @@ FORCE:
 
 ifdef MKDEPEND_DIR
 clean clobber realclean clobber_all::
 	cd $(MKDEPEND_DIR); $(MAKE) $@
 endif
 
 PYUNITS := unit-Expression.py unit-Preprocessor.py
 
-check::
+check:: check-preprocessor check-jar-mn
+
+check-preprocessor::
 	@$(EXIT_ON_ERROR) \
 	for test in $(PYUNITS); do \
 	  $(PYTHON) $(srcdir)/tests/$$test ; \
 	done
+
+check-jar-mn::
+	make -C tests/src-simple check-jar
+	make -C tests/src-simple check-flat
+	make -C tests/src-simple check-flat USE_EXTENSION_MANIFEST=1
+ifneq ($(OS_ARCH), WINNT)
+	make -C tests/src-simple check-symlink
+endif
--- a/config/Preprocessor.py
+++ b/config/Preprocessor.py
@@ -142,17 +142,19 @@ class Preprocessor:
       ln = self.context['LINE']
       if self.writtenLines != ln:
         self.out.write('//@line %(line)d "%(file)s"%(le)s'%{'line': ln,
                                                             'file': self.context['FILE'],
                                                             'le': self.LE})
         self.writtenLines = ln
     for f in self.filters:
       aLine = f[1](aLine)
-    aLine = aLine.rstrip('\r\n') + self.LE
+    # ensure our line ending. Only need to handle \n, as we're reading
+    # with universal line ending support, at least for files.
+    aLine = re.sub('\n', self.LE, aLine)
     self.out.write(aLine)
   
   def handleCommandLine(self, args, defaultToStdin = False):
     """
     Parse a commandline into this parser.
     Uses OptionParser internally, no args mean sys.argv[1:].
     """
     includes = []
@@ -342,17 +344,17 @@ class Preprocessor:
       if v in self.context:
         return str(self.context[v])
       return ''
     for i in range(1, len(lst), 2):
       lst[i] = vsubst(lst[i])
     lst.append('\n') # add back the newline
     self.write(reduce(lambda x, y: x+y, lst, ''))
   def do_literal(self, args):
-    self.write(args)
+    self.write(args + self.LE)
   def do_filter(self, args):
     filters = [f for f in args.split(' ') if hasattr(self, 'filter_' + f)]
     if len(filters) == 0:
       return
     current = dict(self.filters)
     for f in filters:
       current[f] = getattr(self, 'filter_' + f)
     filterNames = current.keys()
@@ -412,17 +414,17 @@ class Preprocessor:
     oldWrittenLines = self.writtenLines
     oldCheckLineNumbers = self.checkLineNumbers
     self.checkLineNumbers = False
     if isName:
       try:
         args = str(args)
         if not os.path.isabs(args):
           args = os.path.join(self.context['DIRECTORY'], args)
-        args = open(args)
+        args = open(args, 'rU')
       except:
         raise Preprocessor.Error(self, 'FILE_NOT_FOUND', str(args))
     self.checkLineNumbers = bool(re.search('\.js(?:\.in)?$', args.name))
     oldFile = self.context['FILE']
     oldLine = self.context['LINE']
     oldDir = self.context['DIRECTORY']
     if args.isatty():
       # we're stdin, use '-' and '' for file and dir
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -615,18 +615,16 @@ MOZ_THUNDERBIRD = @MOZ_THUNDERBIRD@
 MOZ_STANDALONE_COMPOSER= @MOZ_STANDALONE_COMPOSER@
 MOZ_STATIC_MAIL_BUILD = @MOZ_STATIC_MAIL_BUILD@
 MOZ_SUNBIRD	= @MOZ_SUNBIRD@
 MOZ_SUITE	= @MOZ_SUITE@
 WINCE		= @WINCE@
 
 MOZ_DISTRIBUTION_ID = @MOZ_DISTRIBUTION_ID@
 
-MINIMO		= @MINIMO@
-
 MACOS_SDK_DIR	= @MACOS_SDK_DIR@
 NEXT_ROOT	= @NEXT_ROOT@
 GCC_VERSION	= @GCC_VERSION@
 XCODEBUILD_VERSION= @XCODEBUILD_VERSION@
 HAS_XCODE_2_1	= @HAS_XCODE_2_1@
 UNIVERSAL_BINARY= @UNIVERSAL_BINARY@
 HAVE_DTRACE= @HAVE_DTRACE@
 
--- a/config/config.mk
+++ b/config/config.mk
@@ -57,16 +57,18 @@ ifndef INCLUDED_AUTOCONF_MK
 include $(DEPTH)/config/autoconf.mk
 endif
 ifndef INCLUDED_INSURE_MK
 ifdef MOZ_INSURIFYING
 include $(topsrcdir)/config/insure.mk
 endif
 endif
 
+COMMA = ,
+
 # Sanity check some variables
 CHECK_VARS := \
  XPI_NAME \
  LIBRARY_NAME \
  MODULE \
  DEPTH \
  SHORT_LIBNAME \
  XPI_PKGNAME \
@@ -405,38 +407,16 @@ DEFINES += \
 		$(NULL)
 
 ifndef MOZ_NATIVE_ZLIB
 DEFINES += -DZLIB_INTERNAL
 endif
 endif
 endif
 
-ifdef MINIMO
-ifdef LIBXUL_LIBRARY
-DEFINES += \
-		-D_IMPL_NS_COM \
-		-DEXPORT_XPT_API \
-		-DEXPORT_XPTC_API \
-		-DEXPORT_XPTI_API \
-		-D_IMPL_NS_COM_OBSOLETE \
-		-D_IMPL_NS_GFX \
-		-D_IMPL_NS_WIDGET \
-		-DIMPL_XREAPI \
-		-DIMPL_NS_NET \
-		-DIMPL_THEBES \
-		$(NULL)
-endif
-
-ifdef WINCE
-DEFINES += -D_NSPR_BUILD_
-endif
-
-endif
-
 # Force _all_ exported methods to be |_declspec(dllexport)| when we're
 # building them into the executable.
 
 ifeq (,$(filter-out WINNT WINCE OS2, $(OS_ARCH)))
 ifdef BUILD_STATIC_LIBS
 DEFINES += \
         -D_IMPL_NS_GFX \
         -D_IMPL_NS_MSG_BASE \
@@ -517,20 +497,36 @@ INCLUDES	= $(LOCAL_INCLUDES) $(REQ_INCLU
 
 ifndef MOZILLA_INTERNAL_API
 INCLUDES	+= -I$(LIBXUL_DIST)/sdk/include
 endif
 
 # The entire tree should be subject to static analysis using the XPCOM
 # script. Additional scripts may be added by specific subdirectories.
 
-DEHYDRA_SCRIPTS = $(topsrcdir)/xpcom/analysis/static-checking.js
+DEHYDRA_SCRIPT = $(topsrcdir)/xpcom/analysis/static-checking.js
+
+DEHYDRA_MODULES = \
+  $(topsrcdir)/xpcom/analysis/stack.js \
+  $(NULL)
+
+TREEHYDRA_MODULES = \
+  $(topsrcdir)/xpcom/analysis/outparams.js \
+  $(NULL)
+
+DEHYDRA_ARGS = \
+  --topsrcdir=$(topsrcdir) \
+  --objdir=$(DEPTH) \
+  --dehydra-modules=$(subst $(NULL) ,$(COMMA),$(strip $(DEHYDRA_MODULES))) \
+  --treehydra-modules=$(subst $(NULL) ,$(COMMA),$(strip $(TREEHYDRA_MODULES))) \
+  $(NULL)
+
+DEHYDRA_FLAGS = -fplugin=$(DEHYDRA_PATH) -fplugin-arg="$(DEHYDRA_SCRIPT) $(DEHYDRA_ARGS)"
 
 ifdef DEHYDRA_PATH
-DEHYDRA_FLAGS = -fplugin=$(DEHYDRA_PATH) $(foreach script,$(DEHYDRA_SCRIPTS),-fplugin-arg=$(script))
 OS_CXXFLAGS += $(DEHYDRA_FLAGS)
 endif
 
 CFLAGS		= $(OS_CFLAGS)
 CXXFLAGS	= $(OS_CXXFLAGS)
 LDFLAGS		= $(OS_LDFLAGS) $(MOZ_FIX_LINK_PATHS)
 
 # Allow each module to override the *default* optimization settings
@@ -775,16 +771,17 @@ ifdef IS_COMPONENT
 LDFLAGS += -IMPLIB:fake.lib
 DELETE_AFTER_LINK = fake.lib fake.exp
 endif
 endif
 
 #
 # Include any personal overrides the user might think are needed.
 #
+-include $(topsrcdir)/$(MOZ_BUILD_APP)/app-config.mk
 -include $(MY_CONFIG)
 
 ######################################################################
 # Now test variables that might have been set or overridden by $(MY_CONFIG).
 
 DEFINES		+= -DOSTYPE=\"$(OS_CONFIG)\"
 DEFINES		+= -DOSARCH=$(OS_ARCH)
 
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1221,16 +1221,22 @@ endef
 
 MAKE_DEPS_AUTO_CC = $(MAKE_DEPS_AUTO)
 MAKE_DEPS_AUTO_CXX = $(MAKE_DEPS_AUTO)
 
 endif # COMPILER_DEPEND
 
 endif # MOZ_AUTO_DEPS
 
+ifdef MOZ_MEMORY
+ifeq ($(OS_ARCH),SunOS)
+SOLARIS_JEMALLOC_LDFLAGS = $(call EXPAND_LIBNAME_PATH,jemalloc,$(DIST)/lib)
+endif
+endif
+
 # Rules for building native targets must come first because of the host_ prefix
 host_%.$(OBJ_SUFFIX): %.c Makefile Makefile.in
 	$(REPORT_BUILD)
 	$(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
 
 host_%.$(OBJ_SUFFIX): %.cpp Makefile Makefile.in
 	$(REPORT_BUILD)
 	$(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
@@ -2040,16 +2046,17 @@ else
 include $(MDDEPEND_FILES)
 endif
 endif
 
 endif
 endif
 #############################################################################
 
+-include $(topsrcdir)/$(MOZ_BUILD_APP)/app-rules.mk
 -include $(MY_RULES)
 
 #
 # This speeds up gmake's processing if these files don't exist.
 #
 $(MY_CONFIG) $(MY_RULES):
 	@touch $@
 
new file mode 100644
--- /dev/null
+++ b/config/tests/chrome.manifest.flat
@@ -0,0 +1,4 @@
+content test chrome/test/one xpcnativewrappers=no
+locale ab-X-stuff chrome/test/three
+overlay chrome://one/file.xml chrome://two/otherfile.xml
+skin test classic chrome/test/one
new file mode 100644
--- /dev/null
+++ b/config/tests/ref-simple/one/file.xml
@@ -0,0 +1,1 @@
+<?xml version="1.0"><doc/>
new file mode 100644
--- /dev/null
+++ b/config/tests/ref-simple/one/preproc
@@ -0,0 +1,2 @@
+
+This is ab-X-stuff.
new file mode 100644
--- /dev/null
+++ b/config/tests/ref-simple/one/some.css
@@ -0,0 +1,6 @@
+#div: {
+/* this is a ID rule, and should stay intact */
+}
+[lang=ab-X-stuff] {
+/* this selector should match content with lang="ab-X-stuff" */
+}
new file mode 100644
--- /dev/null
+++ b/config/tests/ref-simple/three/l10nfile.txt
@@ -0,0 +1,1 @@
+localized content
new file mode 100644
--- /dev/null
+++ b/config/tests/ref-simple/two/otherfile.xml
@@ -0,0 +1,1 @@
+<?xml version="1.0"><otherdoc/>
new file mode 100644
--- /dev/null
+++ b/config/tests/src-simple/Makefile.in
@@ -0,0 +1,73 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+#  Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Axel Hecht <axel@pike.org>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+LOCALE_SRCDIR = $(srcdir)/l10n
+
+include $(DEPTH)/config/autoconf.mk
+
+include $(topsrcdir)/config/config.mk
+
+XPI_NAME = test_jar_mn
+
+DEFINES += \
+	-DAB_CD=ab-X-stuff \
+	$(NULL)
+
+MY_MANIFEST = $(if $(USE_EXTENSION_MANIFEST), $(FINAL_TARGET)/chrome.manifest, $(FINAL_TARGET)/chrome/test.manifest)
+REF_MANIFEST = $(if $(USE_EXTENSION_MANIFEST),chrome.manifest,test.manifest)
+
+check-%::
+	if test -d $(FINAL_TARGET); then rm -rf $(FINAL_TARGET); fi;
+	make realchrome MOZ_CHROME_FILE_FORMAT=$*
+	@echo "Comparing manifests..."
+	@if ! sort $(MY_MANIFEST) | diff -u $(srcdir)/../$(REF_MANIFEST).$* - ; then \
+	  echo "FAIL: different content in manifest!" ; \
+	fi
+	@if [ $* == "jar" ]; then \
+	  $(UNZIP) -d $(FINAL_TARGET)/chrome/test $(FINAL_TARGET)/chrome/test.jar; \
+	fi
+	@echo "Comparing packages..."
+	@if ! diff -ur $(srcdir)/../ref-simple $(FINAL_TARGET)/chrome/test ; then\
+	  echo "FAIL: different content in jar!" ; \
+	fi
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/config/tests/src-simple/jar.mn
@@ -0,0 +1,22 @@
+#filter substitution
+
+test.jar:
+# test chrome with flags and path expansion
+% content test %one xpcnativewrappers=no
+# test locale with variable substitution and path expansion
+% locale @AB_CD@ %three
+# test overlays
+% overlay chrome://one/file.xml chrome://two/otherfile.xml
+# test regular file, preprocessed file, preprocessed css
+  one/file.xml  (thesrcdir/file.xml)
+* one/preproc   (thesrcdir/preproc.in)
+* one/some.css  (thesrcdir/some.css)
+# test reference against topsrcdir
+  two/otherfile.xml (/config/tests/src-simple/thetopsrcdir/otherfile.xml)
+# test reference against localesrcdir
+  three/l10nfile.txt (%l10nfile.txt)
+
+test.jar:
+# test manifest update the locale one was already added above, add skin
+% locale @AB_CD@ %three
+% skin test classic %one
new file mode 100644
--- /dev/null
+++ b/config/tests/src-simple/l10n/l10nfile.txt
@@ -0,0 +1,1 @@
+localized content
new file mode 100644
--- /dev/null
+++ b/config/tests/src-simple/thesrcdir/file.xml
@@ -0,0 +1,1 @@
+<?xml version="1.0"><doc/>
new file mode 100644
--- /dev/null
+++ b/config/tests/src-simple/thesrcdir/preproc.in
@@ -0,0 +1,6 @@
+# This would be an processed out
+# pretty lengthy
+# license header.
+# For example.
+
+#expand This is __AB_CD__.
new file mode 100644
--- /dev/null
+++ b/config/tests/src-simple/thesrcdir/some.css
@@ -0,0 +1,6 @@
+#div: {
+/* this is a ID rule, and should stay intact */
+}
+%expand [lang=__AB_CD__] {
+/* this selector should match content with lang="ab-X-stuff" */
+}
new file mode 100644
--- /dev/null
+++ b/config/tests/src-simple/thetopsrcdir/otherfile.xml
@@ -0,0 +1,1 @@
+<?xml version="1.0"><otherdoc/>
new file mode 100644
--- /dev/null
+++ b/config/tests/test.manifest.flat
@@ -0,0 +1,4 @@
+content test test/one xpcnativewrappers=no
+locale ab-X-stuff test/three
+overlay chrome://one/file.xml chrome://two/otherfile.xml
+skin test classic test/one
new file mode 100644
--- /dev/null
+++ b/config/tests/test.manifest.jar
@@ -0,0 +1,4 @@
+content test jar:test.jar!/one xpcnativewrappers=no
+locale ab-X-stuff jar:test.jar!/three
+overlay chrome://one/file.xml chrome://two/otherfile.xml
+skin test classic jar:test.jar!/one
new file mode 100644
--- /dev/null
+++ b/config/tests/test.manifest.symlink
@@ -0,0 +1,4 @@
+content test test/one xpcnativewrappers=no
+locale ab-X-stuff test/three
+overlay chrome://one/file.xml chrome://two/otherfile.xml
+skin test classic test/one
new file mode 100644
--- /dev/null
+++ b/config/tests/unit-LineEndings.py
@@ -0,0 +1,46 @@
+import unittest
+
+from StringIO import StringIO
+import os
+import sys
+import os.path
+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+
+from Preprocessor import Preprocessor
+
+class TestLineEndings(unittest.TestCase):
+  """
+  Unit tests for the Context class
+  """
+
+  def setUp(self):
+    self.pp = Preprocessor()
+    self.pp.out = StringIO()
+    self.tempnam = os.tempnam('.')
+
+  def tearDown(self):
+    os.remove(self.tempnam)
+
+  def createFile(self, lineendings):
+    f = open(self.tempnam, 'wb')
+    for line, ending in zip(['a', '#literal b', 'c'], lineendings):
+      f.write(line+ending)
+    f.close()
+
+  def testMac(self):
+    self.createFile(['\x0D']*3)
+    self.pp.do_include(self.tempnam)
+    self.assertEquals(self.pp.out.getvalue(), 'a\nb\nc\n')
+
+  def testUnix(self):
+    self.createFile(['\x0A']*3)
+    self.pp.do_include(self.tempnam)
+    self.assertEquals(self.pp.out.getvalue(), 'a\nb\nc\n')
+
+  def testWindows(self):
+    self.createFile(['\x0D\x0A']*3)
+    self.pp.do_include(self.tempnam)
+    self.assertEquals(self.pp.out.getvalue(), 'a\nb\nc\n')
+
+if __name__ == '__main__':
+  unittest.main()
--- a/config/tests/unit-Preprocessor.py
+++ b/config/tests/unit-Preprocessor.py
@@ -172,16 +172,40 @@ BAR
   def test_filter_attemptSubstitution(self):
     f = NamedIO('filter_attemptSubstitution.in', '''#filter attemptSubstitution
 P@VAR@ASS
 #unfilter attemptSubstitution
 ''')
     self.pp.do_include(f)
     self.assertEqual(self.pp.out.getvalue(), "PASS\n")
   
+  def test_filter_emptyLines(self):
+    f = NamedIO('filter_emptyLines.in', '''lines with a
+
+blank line
+#filter emptyLines
+lines with
+
+no blank lines
+#unfilter emptyLines
+yet more lines with
+
+blank lines
+''')
+    self.pp.do_include(f)
+    self.assertEqual(self.pp.out.getvalue(), '''lines with a
+
+blank line
+lines with
+no blank lines
+yet more lines with
+
+blank lines
+''')
+  
   def test_filter_slashslash(self):
     f = NamedIO('filter_slashslash.in', '''#filter slashslash
 PASS//FAIL  // FAIL
 #unfilter slashslash
 PASS // PASS
 ''')
     self.pp.do_include(f)
     self.assertEqual(self.pp.out.getvalue(), "PASS\nPASS // PASS\n")
@@ -367,10 +391,18 @@ FAIL
 PASS
 #else
 FAIL
 #endif
 ''')
     self.pp.do_include(f)
     self.assertEqual(self.pp.out.getvalue(), "PASS\n")
 
+  def test_lineEndings(self):
+    f = NamedIO('lineEndings.in', '''first
+#literal second
+''')
+    self.pp.setLineEndings('cr')
+    self.pp.do_include(f)
+    self.assertEqual(self.pp.out.getvalue(), "first\rsecond\r")
+
 if __name__ == '__main__':
   unittest.main()
--- a/configure.in
+++ b/configure.in
@@ -63,16 +63,21 @@ dnl ====================================
 AC_PREREQ(2.13)
 AC_INIT(config/config.mk)
 AC_CONFIG_AUX_DIR(${srcdir}/build/autoconf)
 AC_CANONICAL_SYSTEM
 TARGET_CPU="${target_cpu}"
 TARGET_VENDOR="${target_vendor}"
 TARGET_OS="${target_os}"
 
+
+MOZ_DEB_TIMESTAMP=`date +"%a, %d  %b %Y %T %z"   2>&1` 
+AC_SUBST(MOZ_DEB_TIMESTAMP)
+
+
 dnl ========================================================
 dnl =
 dnl = Don't change the following two lines.  Doing so breaks:
 dnl =
 dnl = CFLAGS="-foo" ./configure
 dnl =
 dnl ========================================================
 CFLAGS="${CFLAGS=}"
@@ -123,17 +128,17 @@ WINDRES_VERSION=2.14.90
 W32API_VERSION=3.8
 GNOMEVFS_VERSION=2.0
 GNOMEUI_VERSION=2.2.0
 GCONF_VERSION=1.2.1
 LIBGNOME_VERSION=2.0
 STARTUP_NOTIFICATION_VERSION=0.8
 DBUS_VERSION=0.60
 LCMS_VERSION=1.17
-SQLITE_VERSION=3.5.4
+SQLITE_VERSION=3.5.9
 
 MSMANIFEST_TOOL=
 
 dnl Set various checks
 dnl ========================================================
 MISSING_X=
 AC_PROG_AWK
 
@@ -478,16 +483,17 @@ case "$target" in
             elif test $_CC_BUILD -ge 762; then
                _USE_DYNAMICBASE=1
             fi
             AC_DEFINE(_CRT_SECURE_NO_DEPRECATE)
             AC_DEFINE(_CRT_NONSTDC_NO_DEPRECATE)
         elif test "$_CC_MAJOR_VERSION" = "15"; then
             _CC_SUITE=9
             CXXFLAGS="$CXXFLAGS -Zc:wchar_t-"
+            LDFLAGS="$LDFLAGS -MANIFESTUAC:NO"
             _USE_DYNAMICBASE=1
             AC_DEFINE(_CRT_SECURE_NO_WARNINGS)
             AC_DEFINE(_CRT_NONSTDC_NO_WARNINGS)
         else
             AC_MSG_ERROR([This version of the MSVC compiler, $CC_VERSION , is unsupported.])
         fi
 
         _MOZ_RTTI_FLAGS_ON='-GR'
@@ -1663,28 +1669,35 @@ case "$target" in
     LDFLAGS="$LDFLAGS -framework Cocoa"
     # The ExceptionHandling framework is needed for Objective-C exception
     # logging code in nsObjCExceptions.h. Currently we only use that in debug
     # builds.
     MOZ_DEBUG_LDFLAGS="$MOZ_DEBUG_LDFLAGS -framework ExceptionHandling"
     # set MACOSX to generate lib/mac/MoreFiles/Makefile
     MACOSX=1
 
-    dnl check for the presence of the -dead_strip linker flag
-    AC_MSG_CHECKING([for -dead_strip option to ld])
-    _SAVE_LDFLAGS=$LDFLAGS
-    LDFLAGS="$LDFLAGS -Wl,-dead_strip"
-    AC_TRY_LINK(,[return 0;],_HAVE_DEAD_STRIP=1,_HAVE_DEAD_STRIP=)
-    if test -n "$_HAVE_DEAD_STRIP" ; then
-        AC_MSG_RESULT([yes])
-        MOZ_OPTIMIZE_LDFLAGS="-Wl,-dead_strip"
+    dnl DTrace and -dead_strip don't interact well. See bug 403132.
+    dnl ===================================================================
+    if test "x$enable_dtrace" = "xyes"; then
+        echo "Skipping -dead_strip because DTrace is enabled. See bug 403132."
     else
-        AC_MSG_RESULT([no])
-    fi
-    LDFLAGS=$_SAVE_LDFLAGS
+        dnl check for the presence of the -dead_strip linker flag
+        AC_MSG_CHECKING([for -dead_strip option to ld])
+        _SAVE_LDFLAGS=$LDFLAGS
+        LDFLAGS="$LDFLAGS -Wl,-dead_strip"
+        AC_TRY_LINK(,[return 0;],_HAVE_DEAD_STRIP=1,_HAVE_DEAD_STRIP=)
+        if test -n "$_HAVE_DEAD_STRIP" ; then
+            AC_MSG_RESULT([yes])
+            MOZ_OPTIMIZE_LDFLAGS="-Wl,-dead_strip"
+        else
+            AC_MSG_RESULT([no])
+        fi
+        
+        LDFLAGS=$_SAVE_LDFLAGS
+    fi
     ;;
 
 *-freebsd*)
     if test `test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` != "elf"; then
 	DLL_SUFFIX=".so.1.0"
 	DSO_LDOPTS="-shared"
     fi
     if test ! "$GNU_CC"; then
@@ -2114,17 +2127,17 @@ case "$target" in
             fi
         fi
         LIBIDL_LIBS="${LIBIDL_LIBS} ${GLIB_LIBS}"
         ;;
     esac 
 
 
     case "$host_os" in
-    cygwin*)
+    cygwin*|msvc*|mks*)
         AC_MSG_WARN([Using a cygwin build environment is unsupported. Configure cannot check for the presence of necessary headers. Please upgrade to MozillaBuild; see http://developer.mozilla.org/en/docs/Windows_Build_Prerequisites])
         ;;
 
     *)
         AC_CHECK_HEADERS(mmintrin.h oleacc.idl)
 
         AC_LANG_SAVE
         AC_LANG_CPLUSPLUS
@@ -2768,22 +2781,22 @@ dnl Note that we assume that mac & win32
 
     AC_LANG_SAVE
     AC_LANG_CPLUSPLUS
     _SAVE_CXXFLAGS=$CXXFLAGS
     CXXFLAGS="$CXXFLAGS -fshort-wchar"
 
     AC_CACHE_CHECK(for compiler -fshort-wchar option, 
         ac_cv_have_usable_wchar_option_v2,
-        [AC_TRY_COMPILE([#include <stddef.h>
-                         $configure_static_assert_macros],
-                        [CONFIGURE_STATIC_ASSERT(sizeof(wchar_t) == 2);
-                         CONFIGURE_STATIC_ASSERT((wchar_t)-1 > (wchar_t) 0)],
-                        ac_cv_have_usable_wchar_option_v2="yes",
-                        ac_cv_have_usable_wchar_option_v2="no")])
+        [AC_TRY_LINK([#include <stddef.h>
+                      $configure_static_assert_macros],
+                     [CONFIGURE_STATIC_ASSERT(sizeof(wchar_t) == 2);
+                      CONFIGURE_STATIC_ASSERT((wchar_t)-1 > (wchar_t) 0)],
+                     ac_cv_have_usable_wchar_option_v2="yes",
+                     ac_cv_have_usable_wchar_option_v2="no")])
 
     if test "$ac_cv_have_usable_wchar_option_v2" = "yes"; then
         AC_DEFINE(HAVE_CPP_2BYTE_WCHAR_T)
         HAVE_CPP_2BYTE_WCHAR_T=1
     else    
         CXXFLAGS=$_SAVE_CXXFLAGS
     fi
     AC_LANG_RESTORE
@@ -4250,16 +4263,28 @@ MOZ_ARG_WITH_STRING(java-include-path,
     JAVA_INCLUDE_PATH=$withval)
 
 JAVA_BIN_PATH=
 MOZ_ARG_WITH_STRING(java-bin-path,
 [  --with-java-bin-path=dir   Location of Java binaries (java, javac, jar)],
     JAVA_BIN_PATH=$withval)
 
 dnl ========================================================
+dnl Use ARM userspace kernel helpers; tell NSPR to enable
+dnl their usage and use them in spidermonkey.
+dnl ========================================================
+MOZ_ARG_WITH_BOOL(arm-kuser,
+[  --with-arm-kuser         Use kuser helpers (Linux/ARM only -- requires kernel 2.6.13 or later)],
+    USE_ARM_KUSER=1,
+    USE_ARM_KUSER=)
+if test -n "$USE_ARM_KUSER"; then
+   AC_DEFINE(USE_ARM_KUSER)
+fi
+
+dnl ========================================================
 dnl =
 dnl = Application
 dnl =
 dnl ========================================================
 
 MOZ_ARG_HEADER(Application)
 
 BUILD_STATIC_LIBS=
@@ -4360,43 +4385,33 @@ case "$target_os" in
 esac
 
 MOZ_ARG_ENABLE_STRING(application,
 [  --enable-application=APP
                           Options include:
                             suite
                             browser (Firefox)
                             mail (Thunderbird)
-                            minimo
                             composer
                             calendar (Sunbird)
                             xulrunner
                             camino
                             content/xslt (Standalone Transformiix XSLT)
                             netwerk (Standalone Necko)
                             tools/update-packaging (AUS-related packaging tools)
                             standalone (use this for standalone
                               xpcom/xpconnect or to manually drive a build)],
 [ MOZ_BUILD_APP=$enableval ] )
 
 if test "$MOZ_BUILD_APP" = "macbrowser"; then
     AC_MSG_WARN([--enable-application=macbrowser is deprecated. Use --enable-application=camino.])
     MOZ_BUILD_APP=camino
 fi
 
-case "$MOZ_BUILD_APP" in
-minimo)
-  MOZ_EMBEDDING_PROFILE=basic
-  ;;
-
-*)
-  MOZ_EMBEDDING_PROFILE=default
-  ;;
-esac
-
+MOZ_EMBEDDING_PROFILE=default
 MOZ_ARG_WITH_STRING(embedding-profile,
 [  --with-embedding-profile=default|basic|minimal
                        see http://wiki.mozilla.org/Gecko:Small_Device_Support],
 [ MOZ_EMBEDDING_PROFILE=$withval ])
 
 case "$MOZ_EMBEDDING_PROFILE" in
 default)
   MOZ_EMBEDDING_LEVEL_DEFAULT=1
@@ -4575,20 +4590,16 @@ case "$MOZ_BUILD_APP" in
 suite)
   AC_DEFINE(MOZ_SUITE)
   ;;
 
 browser)
   AC_DEFINE(MOZ_PHOENIX)
   ;;
 
-minimo)
-  AC_DEFINE(MINIMO)
-  ;;
-
 mail)
   AC_DEFINE(MOZ_THUNDERBIRD)
   ;;
 
 composer)
   AC_DEFINE(MOZ_STANDALONE_COMPOSER)
   ;;
 
@@ -8258,16 +8269,19 @@ if test -z "$MOZ_NATIVE_NSPR" || test "$
         ac_configure_args="$ac_configure_args --enable-optimize"
     fi
     if test "$OS_ARCH" = "WINNT" && test "$NS_TRACE_MALLOC"; then
        ac_configure_args="$ac_configure_args --enable-debug --disable-optimize"
     fi
     if test -n "$HAVE_64BIT_OS"; then
         ac_configure_args="$ac_configure_args --enable-64bit"
     fi
+    if test -n "$USE_ARM_KUSER"; then
+        ac_configure_args="$ac_configure_args --with-arm-kuser"
+    fi
     AC_OUTPUT_SUBDIRS(nsprpub)
     ac_configure_args="$_SUBDIR_CONFIG_ARGS"
 fi
 
 if test -z "$MOZ_NATIVE_NSPR"; then
     # Hack to deal with the fact that we use NSPR_CFLAGS everywhere
     AC_MSG_WARN([Recreating autoconf.mk with updated nspr-config output])
     if test ! "$VACPP" && test "$OS_ARCH" != "WINNT" && test "$OS_ARCH" != "WINCE"; then
--- a/content/base/public/Makefile.in
+++ b/content/base/public/Makefile.in
@@ -67,20 +67,21 @@ nsIPrivateDOMImplementation.h \
 nsIContentSerializer.h \
 nsIHTMLToTextSink.h \
 nsIXPathEvaluatorInternal.h \
 mozISanitizingSerializer.h \
 nsCaseTreatment.h \
 nsContentCID.h \
 nsCopySupport.h \
 nsContentCreatorFunctions.h \
+nsDOMFile.h \
 nsLineBreaker.h \
+nsPresShellIterator.h \
+nsReferencedElement.h \
 nsXMLNameSpaceMap.h \
-nsPresShellIterator.h \
-nsDOMFile.h \
 $(NULL)
 
 ifndef DISABLE_XFORMS_HOOKS
 EXPORTS += nsIXFormsUtilityService.h
 endif
 
 SDK_XPIDLSRCS   = \
 		nsISelection.idl  \
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -364,16 +364,26 @@ public:
                                                    PRBool aTrimTrailing = PR_TRUE);
 
   /**
    * Returns true if aChar is of class Ps, Pi, Po, Pf, or Pe. (Does not
    * currently handle non-BMP characters.)
    */
   static PRBool IsPunctuationMark(PRUnichar aChar);
 
+  /*
+   * Is the character an HTML whitespace character?
+   *
+   * We define whitespace using the list in HTML5 and css3-selectors:
+   * U+0009, U+000A, U+000C, U+000D, U+0020
+   *
+   * HTML 4.01 also lists U+200B (zero-width space).
+   */
+  static PRBool IsHTMLWhitespace(PRUnichar aChar);
+
   static void Shutdown();
 
   /**
    * Checks whether two nodes come from the same origin. aTrustedNode is
    * considered 'safe' in that a user can operate on it and that it isn't
    * a js-object that implements nsIDOMNode.
    * Never call this function with the first node provided by script, it
    * must always be known to be a 'real' node!
@@ -1196,16 +1206,22 @@ public:
   static void HidePopupsInDocument(nsIDocument* aDocument);
 
   /**
    * Return true if aURI is a local file URI (i.e. file://).
    */
   static PRBool URIIsLocalFile(nsIURI *aURI);
 
   /**
+   * If aContent is an HTML element with a DOM level 0 'name', then
+   * return the name. Otherwise return null.
+   */
+  static nsIAtom* IsNamedItem(nsIContent* aContent);
+
+  /**
    * Get the application manifest URI for this context.  The manifest URI
    * is specified in the manifest= attribute of the root element of the
    * toplevel window.
    *
    * @param aWindow The context to check.
    * @param aURI The manifest URI.
    */
   static void GetOfflineAppManifest(nsIDOMWindow *aWindow, nsIURI **aURI);
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -92,18 +92,18 @@ class nsIDocumentObserver;
 class nsBindingManager;
 class nsIDOMNodeList;
 class mozAutoSubtreeModified;
 struct JSObject;
 class nsFrameLoader;
 
 // IID for the nsIDocument interface
 #define NS_IDOCUMENT_IID      \
-{ 0xc81acf0b, 0x2539, 0x47ab, \
-  { 0xa6, 0x04, 0x64, 0x04, 0x07, 0x63, 0xc8, 0x3d } }
+{ 0xc45a4a53, 0x0485, 0x43d5, \
+  { 0x85, 0x95, 0x9f, 0x0b, 0xf4, 0x0d, 0xe9, 0x34 } }
 
 // Flag for AddStyleSheet().
 #define NS_STYLESHEET_FROM_CATALOG                (1 << 0)
 
 //----------------------------------------------------------------------
 
 // Document interface.  This is implemented by all document objects in
 // Gecko.
@@ -256,16 +256,42 @@ public:
   virtual nsresult AddCharSetObserver(nsIObserver* aObserver) = 0;
 
   /**
    * Remove a charset observer.
    */
   virtual void RemoveCharSetObserver(nsIObserver* aObserver) = 0;
 
   /**
+   * This gets fired when the element that an id refers to changes.
+   * This fires at difficult times. It is generally not safe to do anything
+   * which could modify the DOM in any way. Use
+   * nsContentUtils::AddScriptRunner.
+   * @return PR_TRUE to keep the callback in the callback set, PR_FALSE
+   * to remove it.
+   */
+  typedef PRBool (* IDTargetObserver)(nsIContent* aOldContent,
+                                      nsIContent* aNewContent, void* aData);
+
+  /**
+   * Add an IDTargetObserver for a specific ID. The IDTargetObserver
+   * will be fired whenever the content associated with the ID changes
+   * in the future. At most one (aObserver, aData) pair can be registered
+   * for each ID.
+   * @return the content currently associated with the ID.
+   */
+  virtual nsIContent* AddIDTargetObserver(nsIAtom* aID,
+                                          IDTargetObserver aObserver, void* aData) = 0;
+  /**
+   * Remove the (aObserver, aData) pair for a specific ID, if registered.
+   */
+  virtual void RemoveIDTargetObserver(nsIAtom* aID,
+                                      IDTargetObserver aObserver, void* aData) = 0;
+
+  /**
    * Get the Content-Type of this document.
    * (This will always return NS_OK, but has this signature to be compatible
    *  with nsIDOMNSDocument::GetContentType())
    */
   NS_IMETHOD GetContentType(nsAString& aContentType) = 0;
 
   /**
    * Set the Content-Type of this document.
@@ -293,19 +319,19 @@ public:
   }
 
   /**
    * Indicate the document contains bidi data.
    * Currently, we cannot disable bidi, because once bidi is enabled,
    * it affects a frame model irreversibly, and plays even though
    * the document no longer contains bidi data.
    */
-  void SetBidiEnabled(PRBool aBidiEnabled)
+  void SetBidiEnabled()
   {
-    mBidiEnabled = aBidiEnabled;
+    mBidiEnabled = PR_TRUE;
   }
   
   /**
    * Check if the document contains (or has contained) any MathML elements.
    */
   PRBool GetMathMLEnabled() const
   {
     return mMathMLEnabled;
new file mode 100644
--- /dev/null
+++ b/content/base/public/nsReferencedElement.h
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=78: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla.org.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Robert O'Callahan   <robert@ocallahan.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef NSREFERENCEDELEMENT_H_
+#define NSREFERENCEDELEMENT_H_
+
+#include "nsIContent.h"
+#include "nsIAtom.h"
+#include "nsIDocument.h"
+#include "nsThreadUtils.h"
+#include "nsAutoPtr.h"
+
+class nsIURI;
+class nsCycleCollectionCallback;
+
+/**
+ * Class to track what content is referenced by a given ID.
+ * 
+ * By default this is a single-shot tracker --- i.e., when ContentChanged
+ * fires, we will automatically stop tracking. Override IsPersistent
+ * to return PR_TRUE if you want to keep tracking after the content for
+ * an ID has changed.
+ */
+class nsReferencedElement {
+public:
+  nsReferencedElement() {}
+  ~nsReferencedElement() {
+    Unlink();
+    if (mPendingNotification) {
+      mPendingNotification->Clear();
+    }
+  }
+  nsIContent* get() { return mContent; }
+
+  void Reset(nsIContent* aFrom, nsIURI* aURI, PRBool aWatch = PR_TRUE);
+  void Unlink();
+
+  void Traverse(nsCycleCollectionTraversalCallback* aCB);
+  
+protected:
+  /**
+   * Override this to be notified of content changes. Don't forget
+   * to call this method to change mContent.
+   */
+  virtual void ContentChanged(nsIContent* aFrom, nsIContent* aTo) {
+    mContent = aTo;
+  }
+
+  /**
+   * Override this to convert from a single-shot notification to
+   * a persistent notification.
+   */
+  virtual PRBool IsPersistent() { return PR_FALSE; }
+  
+private:
+  static PRBool Observe(nsIContent* aOldContent,
+                        nsIContent* aNewContent, void* aData);
+
+  class Notification : public nsRunnable {
+  public:
+    Notification(nsReferencedElement* aTarget, nsIContent* aFrom, nsIContent* aTo)
+      : mTarget(aTarget), mFrom(aFrom), mTo(aTo) {}
+    NS_IMETHOD Run() {
+      if (mTarget) {
+        mTarget->mPendingNotification = nsnull;
+        mTarget->ContentChanged(mFrom, mTo);
+      }
+      return NS_OK;
+    }
+    void SetTo(nsIContent* aTo) { mTo = aTo; }
+    void Clear() { mTarget = nsnull; mFrom = nsnull; mTo = nsnull; }
+  private:
+    nsReferencedElement* mTarget;
+    nsCOMPtr<nsIContent> mFrom;
+    nsCOMPtr<nsIContent> mTo;
+  };
+  friend class Notification;
+
+  nsCOMPtr<nsIAtom>      mWatchID;
+  nsCOMPtr<nsIDocument>  mWatchDocument;
+  nsCOMPtr<nsIContent>   mContent;
+  nsRefPtr<Notification> mPendingNotification;
+};
+
+#endif /*NSREFERENCEDELEMENT_H_*/
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -147,16 +147,17 @@ CPPSRCS		= \
 		nsNodeInfo.cpp \
 		nsNodeInfoManager.cpp \
 		nsNodeUtils.cpp \
 		nsObjectLoadingContent.cpp \
 		nsParserUtils.cpp \
 		nsPlainTextSerializer.cpp \
 		nsPropertyTable.cpp \
 		nsRange.cpp \
+		nsReferencedElement.cpp \
 		nsScriptElement.cpp \
 		nsScriptEventManager.cpp \
 		nsScriptLoader.cpp \
 		nsStubDocumentObserver.cpp \
 		nsStubImageDecoderObserver.cpp \
 		nsStubMutationObserver.cpp \
 		nsStyledElement.cpp \
 		nsStyleLinkElement.cpp \
--- a/content/base/src/nsAttrValue.cpp
+++ b/content/base/src/nsAttrValue.cpp
@@ -44,16 +44,17 @@
 #include "nsAttrValue.h"
 #include "nsIAtom.h"
 #include "nsUnicharUtils.h"
 #include "nsICSSStyleRule.h"
 #include "nsCSSDeclaration.h"
 #include "nsIHTMLDocument.h"
 #include "nsIDocument.h"
 #include "nsTPtrArray.h"
+#include "nsContentUtils.h"
 
 #ifdef MOZ_SVG
 #include "nsISVGValue.h"
 #endif
 
 nsTPtrArray<const nsAttrValue::EnumTable>* nsAttrValue::sEnumTableArray = nsnull;
 
 nsAttrValue::nsAttrValue()
@@ -728,40 +729,40 @@ nsAttrValue::ParseAtom(const nsAString& 
 void
 nsAttrValue::ParseAtomArray(const nsAString& aValue)
 {
   nsAString::const_iterator iter, end;
   aValue.BeginReading(iter);
   aValue.EndReading(end);
 
   // skip initial whitespace
-  while (iter != end && nsCRT::IsAsciiSpace(*iter)) {
+  while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
     ++iter;
   }
 
   if (iter == end) {
     ResetIfSet();
     return;
   }
 
   nsAString::const_iterator start(iter);
 
   // get first - and often only - atom
   do {
     ++iter;
-  } while (iter != end && !nsCRT::IsAsciiSpace(*iter));
+  } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter));
 
   nsCOMPtr<nsIAtom> classAtom = do_GetAtom(Substring(start, iter));
   if (!classAtom) {
     Reset();
     return;
   }
 
   // skip whitespace
-  while (iter != end && nsCRT::IsAsciiSpace(*iter)) {
+  while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
     ++iter;
   }
 
   if (iter == end) {
     // we only found one classname so don't bother storing a list
     ResetIfSet();
     nsIAtom* atom = nsnull;
     classAtom.swap(atom);
@@ -781,27 +782,27 @@ nsAttrValue::ParseAtomArray(const nsAStr
   }
 
   // parse the rest of the classnames
   do {
     start = iter;
 
     do {
       ++iter;
-    } while (iter != end && !nsCRT::IsAsciiSpace(*iter));
+    } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter));
 
     classAtom = do_GetAtom(Substring(start, iter));
 
     if (!array->AppendObject(classAtom)) {
       Reset();
       return;
     }
 
     // skip whitespace
-    while (iter != end && nsCRT::IsAsciiSpace(*iter)) {
+    while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
       ++iter;
     }
   } while (iter != end);
 
   return;
 }
 
 void
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -146,16 +146,19 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
 #include "nsIDOMNSUIEvent.h"
 #include "nsIDOMNSEvent.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsXULPopupManager.h"
 #include "nsIPermissionManager.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIRunnable.h"
 #include "nsDOMJSUtils.h"
+#include "nsGenericHTMLElement.h"
+#include "nsAttrValue.h"
+#include "nsReferencedElement.h"
 
 #ifdef IBMBIDI
 #include "nsIBidiKeyboard.h"
 #endif
 #include "nsCycleCollectionParticipant.h"
 
 // for ReportToConsole
 #include "nsIStringBundle.h"
@@ -680,16 +683,28 @@ DEFINE_CCMAP(gPuncCharsCCMap, const);
 // static
 PRBool
 nsContentUtils::IsPunctuationMark(PRUnichar aChar)
 {
   return CCMAP_HAS_CHAR(gPuncCharsCCMap, aChar);
 }
 
 /* static */
+PRBool
+nsContentUtils::IsHTMLWhitespace(PRUnichar aChar)
+{
+  return aChar == PRUnichar(0x0009) ||
+         aChar == PRUnichar(0x000A) ||
+         aChar == PRUnichar(0x000C) ||
+         aChar == PRUnichar(0x000D) ||
+         aChar == PRUnichar(0x0020);
+}
+
+
+/* static */
 void
 nsContentUtils::GetOfflineAppManifest(nsIDOMWindow *aWindow, nsIURI **aURI)
 {
   nsCOMPtr<nsIDOMWindow> top;
   aWindow->GetTop(getter_AddRefs(top));
   if (!top) {
     return;
   }
@@ -3068,130 +3083,23 @@ nsContentUtils::CheckForBOM(const unsign
     aCharset = "UTF-16LE";
   } else {
     found = PR_FALSE;
   }
 
   return found;
 }
 
-static PRBool EqualExceptRef(nsIURL* aURL1, nsIURL* aURL2)
-{
-  nsCOMPtr<nsIURI> u1;
-  nsCOMPtr<nsIURI> u2;
-
-  nsresult rv = aURL1->Clone(getter_AddRefs(u1));
-  if (NS_SUCCEEDED(rv)) {
-    rv = aURL2->Clone(getter_AddRefs(u2));
-  }
-  if (NS_FAILED(rv))
-    return PR_FALSE;
-
-  nsCOMPtr<nsIURL> url1 = do_QueryInterface(u1);
-  nsCOMPtr<nsIURL> url2 = do_QueryInterface(u2);
-  if (!url1 || !url2) {
-    NS_WARNING("Cloning a URL produced a non-URL");
-    return PR_FALSE;
-  }
-  url1->SetRef(EmptyCString());
-  url2->SetRef(EmptyCString());
-
-  PRBool equal;
-  rv = url1->Equals(url2, &equal);
-  return NS_SUCCEEDED(rv) && equal;
-}
-
 /* static */
 nsIContent*
 nsContentUtils::GetReferencedElement(nsIURI* aURI, nsIContent *aFromContent)
 {
-  nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
-  if (!url)
-    return nsnull;
-
-  nsCAutoString refPart;
-  url->GetRef(refPart);
-  // Unescape %-escapes in the reference. The result will be in the
-  // origin charset of the URL, hopefully...
-  NS_UnescapeURL(refPart);
-
-  nsCAutoString charset;
-  url->GetOriginCharset(charset);
-  nsAutoString ref;
-  nsresult rv = ConvertStringFromCharset(charset, refPart, ref);
-  if (NS_FAILED(rv)) {
-    CopyUTF8toUTF16(refPart, ref);
-  }
-  if (ref.IsEmpty())
-    return nsnull;
-
-  // Get the current document
-  nsIDocument *doc = aFromContent->GetCurrentDoc();
-  if (!doc)
-    return nsnull;
-
-  // This will be the URI of the document the content belongs to
-  // (the URI of the XBL document if the content is anonymous
-  // XBL content)
-  nsCOMPtr<nsIURL> documentURL = do_QueryInterface(doc->GetDocumentURI());
-  nsIContent* bindingParent = aFromContent->GetBindingParent();
-  PRBool isXBL = PR_FALSE;
-  if (bindingParent) {
-    nsXBLBinding* binding = doc->BindingManager()->GetBinding(bindingParent);
-    if (binding) {
-      // XXX sXBL/XBL2 issue
-      // If this is an anonymous XBL element then the URI is
-      // relative to the binding document. A full fix requires a
-      // proper XBL2 implementation but for now URIs that are
-      // relative to the binding document should be resolve to the
-      // copy of the target element that has been inserted into the
-      // bound document.
-      documentURL = do_QueryInterface(binding->PrototypeBinding()->DocURI());
-      isXBL = PR_TRUE;
-    }
-  }
-  if (!documentURL)
-    return nsnull;
-
-  if (!EqualExceptRef(url, documentURL)) {
-    // Oops -- we don't support off-document references
-    return nsnull;
-  }
-
-  // Get the element
-  nsCOMPtr<nsIContent> content;
-  if (isXBL) {
-    nsCOMPtr<nsIDOMNodeList> anonymousChildren;
-    doc->BindingManager()->
-      GetAnonymousNodesFor(bindingParent, getter_AddRefs(anonymousChildren));
-
-    if (anonymousChildren) {
-      PRUint32 length;
-      anonymousChildren->GetLength(&length);
-      for (PRUint32 i = 0; i < length && !content; ++i) {
-        nsCOMPtr<nsIDOMNode> node;
-        anonymousChildren->Item(i, getter_AddRefs(node));
-        nsCOMPtr<nsIContent> c = do_QueryInterface(node);
-        if (c) {
-          content = MatchElementId(c, ref);
-        }
-      }
-    }
-  } else {
-    nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc);
-    NS_ASSERTION(domDoc, "Content doesn't reference a dom Document");
-
-    nsCOMPtr<nsIDOMElement> element;
-    rv = domDoc->GetElementById(ref, getter_AddRefs(element));
-    if (element) {
-      content = do_QueryInterface(element);
-    }
-  }
-
-  return content;
+  nsReferencedElement ref;
+  ref.Reset(aFromContent, aURI);
+  return ref.get();
 }
 
 /* static */
 PRBool
 nsContentUtils::HasNonEmptyAttr(nsIContent* aContent, PRInt32 aNameSpaceID,
                                 nsIAtom* aName)
 {
   static nsIContent::AttrValuesArray strings[] = {&nsGkAtoms::_empty, nsnull};
@@ -4276,8 +4184,37 @@ nsContentUtils::URIIsLocalFile(nsIURI *a
 }
 
 /* static */
 void
 nsAutoGCRoot::Shutdown()
 {
   NS_IF_RELEASE(sJSRuntimeService);
 }
+
+nsIAtom*
+nsContentUtils::IsNamedItem(nsIContent* aContent)
+{
+  // Only the content types reflected in Level 0 with a NAME
+  // attribute are registered. Images, layers and forms always get
+  // reflected up to the document. Applets and embeds only go
+  // to the closest container (which could be a form).
+  nsGenericHTMLElement* elm = nsGenericHTMLElement::FromContent(aContent);
+  if (!elm) {
+    return nsnull;
+  }
+
+  nsIAtom* tag = elm->Tag();
+  if (tag != nsGkAtoms::img    &&
+      tag != nsGkAtoms::form   &&
+      tag != nsGkAtoms::applet &&
+      tag != nsGkAtoms::embed  &&
+      tag != nsGkAtoms::object) {
+    return nsnull;
+  }
+
+  const nsAttrValue* val = elm->GetParsedAttr(nsGkAtoms::name);
+  if (val && val->Type() == nsAttrValue::eAtom) {
+    return val->GetAtomValue();
+  }
+
+  return nsnull;
+}
--- a/content/base/src/nsDOMDocumentType.cpp
+++ b/content/base/src/nsDOMDocumentType.cpp
@@ -193,19 +193,17 @@ nsDOMDocumentType::GetSystemId(nsAString
   aSystemId = mSystemId;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMDocumentType::GetInternalSubset(nsAString& aInternalSubset)
 {
-  // XXX: null string
   aInternalSubset = mInternalSubset;
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMDocumentType::GetNodeName(nsAString& aNodeName)
 {
   return mName->ToString(aNodeName);
 }
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -283,16 +283,233 @@ nsUint32ToContentHashEntry::VisitContent
   }
 
   nsIContent* v = GetContent();
   if (v) {
     aVisitor->Visit(v);
   }
 }
 
+#define ID_NOT_IN_DOCUMENT ((nsIContent *)2)
+#define NAME_NOT_VALID ((nsBaseContentList*)1)
+
+nsIdentifierMapEntry::~nsIdentifierMapEntry()
+{
+  if (mNameContentList && mNameContentList != NAME_NOT_VALID) {
+    NS_RELEASE(mNameContentList);
+  }
+}
+
+void
+nsIdentifierMapEntry::Traverse(nsCycleCollectionTraversalCallback* aCallback)
+{
+  if (mNameContentList != NAME_NOT_VALID)
+    aCallback->NoteXPCOMChild(mNameContentList);
+
+  aCallback->NoteXPCOMChild(static_cast<nsIDOMNodeList*>(mDocAllList));
+}
+
+void
+nsIdentifierMapEntry::SetInvalidName()
+{
+  mNameContentList = NAME_NOT_VALID;
+}
+
+PRBool
+nsIdentifierMapEntry::IsInvalidName()
+{
+  return mNameContentList == NAME_NOT_VALID;
+}
+
+nsresult
+nsIdentifierMapEntry::CreateNameContentList()
+{
+  mNameContentList = new nsBaseContentList();
+  NS_ENSURE_TRUE(mNameContentList, NS_ERROR_OUT_OF_MEMORY);
+  NS_ADDREF(mNameContentList);
+  return NS_OK;
+}
+
+nsIContent*
+nsIdentifierMapEntry::GetIdContent(PRBool* aNotInDocument)
+{
+  nsIContent* c = static_cast<nsIContent*>(mIdContentList.SafeElementAt(0));
+  if (aNotInDocument) {
+    *aNotInDocument = c == ID_NOT_IN_DOCUMENT;
+  }
+  return c != ID_NOT_IN_DOCUMENT ? c : nsnull;
+}
+
+void
+nsIdentifierMapEntry::AppendAllIdContent(nsCOMArray<nsIContent>* aElements)
+{
+  for (PRInt32 i = 0; i < mIdContentList.Count(); ++i) {
+    aElements->AppendObject(static_cast<nsIContent*>(mIdContentList[i]));
+  }
+}
+
+void
+nsIdentifierMapEntry::AddContentChangeCallback(nsIDocument::IDTargetObserver aCallback,
+                                               void* aData)
+{
+  if (!mChangeCallbacks) {
+    mChangeCallbacks = new nsTHashtable<ChangeCallbackEntry>;
+    if (!mChangeCallbacks)
+      return;
+    mChangeCallbacks->Init();
+  }
+
+  ChangeCallback cc = { aCallback, aData };
+  mChangeCallbacks->PutEntry(cc);
+}
+
+void
+nsIdentifierMapEntry::RemoveContentChangeCallback(nsIDocument::IDTargetObserver aCallback,
+                                                  void* aData)
+{
+  if (!mChangeCallbacks)
+    return;
+  ChangeCallback cc = { aCallback, aData };
+  mChangeCallbacks->RemoveEntry(cc);
+  if (mChangeCallbacks->Count() == 0) {
+    mChangeCallbacks = nsnull;
+  }
+}
+
+struct FireChangeArgs {
+  nsIContent* mFrom;
+  nsIContent* mTo;
+};
+
+PR_STATIC_CALLBACK(PLDHashOperator)
+FireChangeEnumerator(nsIdentifierMapEntry::ChangeCallbackEntry *aEntry, void *aArg)
+{
+  FireChangeArgs* args = static_cast<FireChangeArgs*>(aArg);
+  return aEntry->mKey.mCallback(args->mFrom, args->mTo, aEntry->mKey.mData)
+      ? PL_DHASH_NEXT : PL_DHASH_REMOVE;
+}
+
+void
+nsIdentifierMapEntry::FireChangeCallbacks(nsIContent* aOldContent,
+                                          nsIContent* aNewContent)
+{
+  if (!mChangeCallbacks)
+    return;
+
+  FireChangeArgs args = { aOldContent, aNewContent };
+  mChangeCallbacks->EnumerateEntries(FireChangeEnumerator, &args);
+}
+
+PRBool
+nsIdentifierMapEntry::AddIdContent(nsIContent* aContent)
+{
+  NS_PRECONDITION(aContent, "Must have content");
+  NS_PRECONDITION(mIdContentList.IndexOf(nsnull) < 0,
+                  "Why is null in our list?");
+  NS_PRECONDITION(aContent != ID_NOT_IN_DOCUMENT,
+                  "Bogus content pointer");
+
+  nsIContent* currentContent = static_cast<nsIContent*>(mIdContentList.SafeElementAt(0));
+  if (currentContent == ID_NOT_IN_DOCUMENT) {
+    NS_ASSERTION(mIdContentList.Count() == 1, "Bogus count");
+    mIdContentList.ReplaceElementAt(aContent, 0);
+    FireChangeCallbacks(nsnull, aContent);
+    return PR_TRUE;
+  }
+
+  // Common case
+  if (mIdContentList.Count() == 0) {
+    if (!mIdContentList.AppendElement(aContent))
+      return PR_FALSE;
+    FireChangeCallbacks(nsnull, aContent);
+    return PR_TRUE;
+  }
+
+  // We seem to have multiple content nodes for the same id, or we're doing our
+  // top-down registration when the id table is going live.  Search for the
+  // right place to insert the content.
+  PRInt32 start = 0;
+  PRInt32 end = mIdContentList.Count();
+  do {
+    NS_ASSERTION(start < end, "Bogus start/end");
+    
+    PRInt32 cur = (start + end) / 2;
+    NS_ASSERTION(cur >= start && cur < end, "What happened here?");
+
+    nsIContent* curContent = static_cast<nsIContent*>(mIdContentList[cur]);
+    if (curContent == aContent) {
+      // Already in the list, so already in the right spot.  Get out of here.
+      return PR_TRUE;
+    }
+
+    if (nsContentUtils::PositionIsBefore(aContent, curContent)) {
+      end = cur;
+    } else {
+      start = cur + 1;
+    }
+  } while (start != end);
+
+  if (!mIdContentList.InsertElementAt(aContent, start))
+    return PR_FALSE;
+  if (start == 0) {
+    FireChangeCallbacks(currentContent, aContent);
+  }
+  return PR_TRUE;
+}
+
+PRBool
+nsIdentifierMapEntry::RemoveIdContent(nsIContent* aContent)
+{
+  // This should only be called while the document is in an update.
+  // Assertions near the call to this method guarantee this.
+
+  // XXXbz should this ever Compact() I guess when all the content is gone
+  // we'll just get cleaned up in the natural order of things...
+  nsIContent* currentContent = static_cast<nsIContent*>(mIdContentList.SafeElementAt(0));
+  if (!mIdContentList.RemoveElement(aContent))
+    return PR_FALSE;
+  if (currentContent == aContent) {
+    FireChangeCallbacks(currentContent,
+                        static_cast<nsIContent*>(mIdContentList.SafeElementAt(0)));
+  }
+  return mIdContentList.Count() == 0 && !mNameContentList && !mChangeCallbacks;
+}
+
+void
+nsIdentifierMapEntry::FlagIDNotInDocument()
+{
+  NS_ASSERTION(mIdContentList.Count() == 0,
+               "Flagging ID not in document when we have content?");
+  // Note that if this fails that's OK; this is just an optimization
+  mIdContentList.AppendElement(ID_NOT_IN_DOCUMENT);
+}
+
+void
+nsIdentifierMapEntry::AddNameContent(nsIContent* aContent)
+{
+  if (!mNameContentList || mNameContentList == NAME_NOT_VALID)
+    return;
+
+  // NOTE: this indexof is absolutely needed, since we don't flush
+  // content notifications when we do document.foo resolution.  So
+  // aContent may be in our list already and just now getting notified
+  // for!
+  if (mNameContentList->IndexOf(aContent, PR_FALSE) < 0) {
+    mNameContentList->AppendElement(aContent);
+  }
+}
+
+void
+nsIdentifierMapEntry::RemoveNameContent(nsIContent* aContent)
+{
+  if (mNameContentList && mNameContentList != NAME_NOT_VALID) {
+    mNameContentList->RemoveElement(aContent);
+  }
+}
+
 // Helper structs for the content->subdoc map
 
 class SubDocMapEntry : public PLDHashEntryHdr
 {
 public:
   // Both of these are strong references
   nsIContent *mKey; // must be first, to look like PLDHashEntryStub
   nsIDocument *mSubDocument;
@@ -695,19 +912,22 @@ nsDOMImplementation::CreateDocumentType(
 {
   *aReturn = nsnull;
 
   nsresult rv = nsContentUtils::CheckQName(aQualifiedName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIAtom> name = do_GetAtom(aQualifiedName);
   NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
-    
+
+  // Indicate that there is no internal subset (not just an empty one)
+  nsAutoString voidString;
+  voidString.SetIsVoid(PR_TRUE);
   return NS_NewDOMDocumentType(aReturn, nsnull, mPrincipal, name, nsnull,
-                               nsnull, aPublicId, aSystemId, EmptyString());
+                               nsnull, aPublicId, aSystemId, voidString);
 }
 
 NS_IMETHODIMP
 nsDOMImplementation::CreateDocument(const nsAString& aNamespaceURI,
                                     const nsAString& aQualifiedName,
                                     nsIDOMDocumentType* aDoctype,
                                     nsIDOMDocument** aReturn)
 {
@@ -1004,31 +1224,42 @@ class LinkMapTraversalVisitor : public n
 public:
   nsCycleCollectionTraversalCallback *mCb;
   virtual void Visit(nsIContent* aContent)
   {
     mCb->NoteXPCOMChild(aContent);
   }
 };
 
-PLDHashOperator PR_CALLBACK
+PR_STATIC_CALLBACK(PLDHashOperator)
 LinkMapTraverser(nsUint32ToContentHashEntry* aEntry, void* userArg)
 {
   LinkMapTraversalVisitor visitor;
   visitor.mCb = static_cast<nsCycleCollectionTraversalCallback*>(userArg);
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*visitor.mCb, "mLinkMap entry");
   aEntry->VisitContent(&visitor);
   return PL_DHASH_NEXT;
 }
 
+PR_STATIC_CALLBACK(PLDHashOperator)
+IdentifierMapEntryTraverse(nsIdentifierMapEntry *aEntry, void *aArg)
+{
+  nsCycleCollectionTraversalCallback *cb =
+    static_cast<nsCycleCollectionTraversalCallback*>(aArg);
+  aEntry->Traverse(cb);
+  return PL_DHASH_NEXT;
+}
+
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDocument)
   if (nsCCUncollectableMarker::InGeneration(tmp->GetMarkedCCGeneration())) {
     return NS_OK;
   }
 
+  tmp->mIdentifierMap.EnumerateEntries(IdentifierMapEntryTraverse, &cb);
+
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNodeInfo)
 
   // Traverse the mChildren nsAttrAndChildArray.
   for (PRInt32 indx = PRInt32(tmp->mChildren.ChildCount()); indx > 0; --indx) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mChildren[i]");
     cb.NoteXPCOMChild(tmp->mChildren.ChildAt(indx - 1));
   }
 
@@ -1119,16 +1350,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 nsresult
 nsDocument::Init()
 {
   if (mCSSLoader || mNodeInfoManager || mScriptLoader) {
     return NS_ERROR_ALREADY_INITIALIZED;
   }
 
+  mIdentifierMap.Init();
   mLinkMap.Init();
   mRadioGroups.Init();
 
   // Force initialization.
   nsINode::nsSlots* slots = GetSlots();
   NS_ENSURE_TRUE(slots,NS_ERROR_OUT_OF_MEMORY);
 
   // Prepend self as mutation-observer whether we need it or not (some
@@ -1213,16 +1445,17 @@ nsDocument::ResetToURI(nsIURI *aURI, nsI
   if (gDocumentLeakPRLog && PR_LOG_TEST(gDocumentLeakPRLog, PR_LOG_DEBUG)) {
     nsCAutoString spec;
     aURI->GetSpec(spec);
     PR_LogPrint("DOCUMENT %p ResetToURI %s", this, spec.get());
   }
 #endif
 
   mDocumentTitle.SetIsVoid(PR_TRUE);
+  mIdentifierMap.Clear();
 
   SetPrincipal(nsnull);
   mSecurityInfo = nsnull;
 
   mDocumentLoadGroup = nsnull;
 
   // Delete references to sub-documents and kill the subdocument map,
   // if any. It holds strong references
@@ -1522,16 +1755,195 @@ nsDocument::GetLastModified(nsAString& a
     // If we for whatever reason failed to find the last modified time
     // (or even the current time), fall back to what NS4.x returned.
     aLastModified.Assign(NS_LITERAL_STRING("01/01/1970 00:00:00"));
   }
 
   return NS_OK;
 }
 
+void
+nsDocument::UpdateNameTableEntry(nsIContent *aContent)
+{
+  if (!mIsRegularHTML)
+    return;
+
+  nsIAtom* name = nsContentUtils::IsNamedItem(aContent);
+  if (!name)
+    return;
+
+  nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(name);
+  if (!entry) {
+    // We're not tracking the elements with this name
+    return;
+  }
+
+  entry->AddNameContent(aContent);
+}
+
+void
+nsDocument::RemoveFromNameTable(nsIContent *aContent)
+{
+  if (!mIsRegularHTML)
+    return;
+
+  nsIAtom* name = nsContentUtils::IsNamedItem(aContent);
+  if (!name)
+    return;
+
+  nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(name);
+  if (!entry) {
+    // We're not tracking the elements with this name
+    return;
+  }
+
+  entry->RemoveNameContent(aContent);
+}
+
+void
+nsDocument::UpdateIdTableEntry(nsIContent *aContent)
+{
+  nsIAtom* id = aContent->GetID();
+  if (!id)
+    return;
+
+  PRBool liveTable = IdTableIsLive();
+  nsIdentifierMapEntry *entry =
+    liveTable ? mIdentifierMap.PutEntry(id) : mIdentifierMap.GetEntry(id);
+
+  if (entry) {
+    entry->AddIdContent(aContent);
+  }
+}
+
+void
+nsDocument::RemoveFromIdTable(nsIContent *aContent)
+{
+  nsIAtom* id = aContent->GetID();
+  if (!id)
+    return;
+
+  nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(id);
+  if (!entry)
+    return;
+
+  if (entry->RemoveIdContent(aContent)) {
+    mIdentifierMap.RemoveEntry(id);
+  }
+}
+
+void
+nsDocument::UnregisterNamedItems(nsIContent *aContent)
+{
+  if (aContent->IsNodeOfType(nsINode::eTEXT)) {
+    // Text nodes are not named items nor can they have children.
+    return;
+  }
+
+  RemoveFromNameTable(aContent);
+  RemoveFromIdTable(aContent);
+
+  PRUint32 i, count = aContent->GetChildCount();
+  for (i = 0; i < count; ++i) {
+    UnregisterNamedItems(aContent->GetChildAt(i));
+  }
+}
+
+void
+nsDocument::RegisterNamedItems(nsIContent *aContent)
+{
+  if (aContent->IsNodeOfType(nsINode::eTEXT)) {
+    // Text nodes are not named items nor can they have children.
+    return;
+  }
+
+  UpdateNameTableEntry(aContent);
+  UpdateIdTableEntry(aContent);
+
+  PRUint32 i, count = aContent->GetChildCount();
+  for (i = 0; i < count; ++i) {
+    RegisterNamedItems(aContent->GetChildAt(i));
+  }
+}
+
+void
+nsDocument::ContentAppended(nsIDocument* aDocument,
+                            nsIContent* aContainer,
+                            PRInt32 aNewIndexInContainer)
+{
+  NS_ASSERTION(aDocument == this, "unexpected doc");
+
+  PRUint32 count = aContainer->GetChildCount();
+  for (PRUint32 i = aNewIndexInContainer; i < count; ++i) {
+    RegisterNamedItems(aContainer->GetChildAt(i));
+  }
+}
+
+void
+nsDocument::ContentInserted(nsIDocument* aDocument,
+                            nsIContent* aContainer,
+                            nsIContent* aContent,
+                            PRInt32 aIndexInContainer)
+{
+  NS_ASSERTION(aDocument == this, "unexpected doc");
+
+  NS_ABORT_IF_FALSE(aContent, "Null content!");
+
+  RegisterNamedItems(aContent);
+}
+
+void
+nsDocument::ContentRemoved(nsIDocument* aDocument,
+                           nsIContent* aContainer,
+                           nsIContent* aChild,
+                           PRInt32 aIndexInContainer)
+{
+  NS_ASSERTION(aDocument == this, "unexpected doc");
+
+  NS_ABORT_IF_FALSE(aChild, "Null content!");
+
+  UnregisterNamedItems(aChild);
+}
+
+void
+nsDocument::AttributeWillChange(nsIContent* aContent, PRInt32 aNameSpaceID,
+                                nsIAtom* aAttribute)
+{
+  NS_ABORT_IF_FALSE(aContent, "Null content!");
+  NS_PRECONDITION(aAttribute, "Must have an attribute that's changing!");
+
+  if (aNameSpaceID != kNameSpaceID_None)
+    return;
+  if (aAttribute == nsGkAtoms::name) {
+    RemoveFromNameTable(aContent);
+  } else if (aAttribute == aContent->GetIDAttributeName()) {
+    RemoveFromIdTable(aContent);
+  }
+}
+
+void
+nsDocument::AttributeChanged(nsIDocument* aDocument,
+                             nsIContent* aContent, PRInt32 aNameSpaceID,
+                             nsIAtom* aAttribute, PRInt32 aModType,
+                             PRUint32 aStateMask)
+{
+  NS_ASSERTION(aDocument == this, "unexpected doc");
+
+  NS_ABORT_IF_FALSE(aContent, "Null content!");
+  NS_PRECONDITION(aAttribute, "Must have an attribute that's changing!");
+
+  if (aNameSpaceID != kNameSpaceID_None)
+    return;
+  if (aAttribute == nsGkAtoms::name) {
+    UpdateNameTableEntry(aContent);
+  } else if (aAttribute == aContent->GetIDAttributeName()) {
+    UpdateIdTableEntry(aContent);
+  }
+}
+
 nsIPrincipal*
 nsDocument::GetPrincipal()
 {
   return NodePrincipal();
 }
 
 void
 nsDocument::SetPrincipal(nsIPrincipal *aNewPrincipal)
@@ -2753,32 +3165,178 @@ nsDocument::BeginLoad()
   // Block onload here to prevent having to deal with blocking and
   // unblocking it while we know the document is loading.
   BlockOnload();
 
   NS_DOCUMENT_NOTIFY_OBSERVERS(BeginLoad, (this));
 }
 
 PRBool
-nsDocument::CheckGetElementByIdArg(const nsAString& aId)
-{
-  if (aId.IsEmpty()) {
+nsDocument::CheckGetElementByIdArg(const nsIAtom* aId)
+{
+  if (aId == nsGkAtoms::_empty) {
     nsContentUtils::ReportToConsole(
         nsContentUtils::eDOM_PROPERTIES,
         "EmptyGetElementByIdParam",
         nsnull, 0,
         nsnull,
         EmptyString(), 0, 0,
         nsIScriptError::warningFlag,
         "DOM");
     return PR_FALSE;
   }
   return PR_TRUE;
 }
 
+static void
+MatchAllElementsId(nsIContent* aContent, nsIAtom* aId, nsIdentifierMapEntry* aEntry)
+{
+  if (aId == aContent->GetID()) {
+    aEntry->AddIdContent(aContent);
+  }
+
+  PRUint32 i, count = aContent->GetChildCount();
+  for (i = 0; i < count; i++) {
+    MatchAllElementsId(aContent->GetChildAt(i), aId, aEntry);
+  }
+}
+
+nsIdentifierMapEntry*
+nsDocument::GetElementByIdInternal(nsIAtom* aID)
+{
+  // We don't have to flush before we do the initial hashtable lookup, since if
+  // the id is already in the hashtable it couldn't have been removed without
+  // us being notified (all removals notify immediately, as far as I can tell).
+  // So do the lookup first.
+  nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(aID);
+  NS_ENSURE_TRUE(entry, nsnull);
+
+  if (entry->GetIdContent())
+    return entry;
+
+  // Now we have to flush.  It could be that we have a cached "not in
+  // document" or know nothing about this ID yet but more content has been
+  // added to the document since.  Note that we have to flush notifications,
+  // so that the entry will get updated properly.
+
+  // Make sure to stash away the current generation so we can check whether
+  // the table changes when we flush.
+  PRUint32 generation = mIdentifierMap.GetGeneration();
+  
+  FlushPendingNotifications(Flush_ContentAndNotify);
+
+  if (generation != mIdentifierMap.GetGeneration()) {
+    // Table changed, so the entry pointer is no longer valid; look up the
+    // entry again, adding if necessary (the adding may be necessary in case
+    // the flush actually deleted entries).
+    entry = mIdentifierMap.PutEntry(aID);
+  }
+  
+  PRBool isNotInDocument;
+  nsIContent *e = entry->GetIdContent(&isNotInDocument);
+  if (e || isNotInDocument)
+    return entry;
+
+  // Status of this id is unknown, search document
+  nsIContent* root = GetRootContent();
+  if (!IdTableIsLive()) {
+    if (IdTableShouldBecomeLive()) {
+      // Just make sure our table is up to date and call this method again
+      // to look up in the hashtable.
+      if (root) {
+        RegisterNamedItems(root);
+      }
+      return GetElementByIdInternal(aID);
+    }
+
+    if (root) {
+      // No-one should have registered an ID change callback yet. We don't
+      // want to fire one as a side-effect of getElementById! This shouldn't
+      // happen, since if someone called AddIDTargetObserver already for
+      // this ID, we should have filled in this entry with content or
+      // not-in-document.
+      NS_ASSERTION(!entry->HasContentChangeCallback(),
+                   "No callbacks should be registered while we set up this entry");
+      MatchAllElementsId(root, aID, entry);
+      e = entry->GetIdContent();
+    }
+  }
+
+  if (!e) {
+#ifdef DEBUG
+    // No reason to call MatchElementId if !IdTableIsLive, since
+    // we'd have done just that already
+    if (IdTableIsLive() && root && aID != nsGkAtoms::_empty) {
+      nsIContent* eDebug =
+        nsContentUtils::MatchElementId(root, aID);
+      NS_ASSERTION(!eDebug,
+                   "We got null for |e| but MatchElementId found something?");
+    }
+#endif
+    // There is no element with the given id in the document, cache
+    // the fact that it's not in the document
+    entry->FlagIDNotInDocument();
+    return entry;
+  }
+
+  return entry;
+}
+
+NS_IMETHODIMP
+nsDocument::GetElementById(const nsAString& aElementId,
+                           nsIDOMElement** aReturn)
+{
+  NS_ENSURE_ARG_POINTER(aReturn);
+  *aReturn = nsnull;
+
+  nsCOMPtr<nsIAtom> idAtom(do_GetAtom(aElementId));
+  NS_ENSURE_TRUE(idAtom, NS_ERROR_OUT_OF_MEMORY);
+  if (!CheckGetElementByIdArg(idAtom))
+    return NS_OK;
+
+  nsIdentifierMapEntry *entry = GetElementByIdInternal(idAtom);
+  NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
+
+  PRBool isNotInDocument;
+  nsIContent *e = entry->GetIdContent(&isNotInDocument);
+  NS_ASSERTION(e || isNotInDocument, "Incomplete map entry!");
+  if (isNotInDocument)
+    return NS_OK;
+
+  return CallQueryInterface(e, aReturn);
+}
+
+nsIContent*
+nsDocument::AddIDTargetObserver(nsIAtom* aID, IDTargetObserver aObserver,
+                                void* aData)
+{
+  if (!CheckGetElementByIdArg(aID))
+    return nsnull;
+
+  nsIdentifierMapEntry *entry = GetElementByIdInternal(aID);
+  NS_ENSURE_TRUE(entry, nsnull);
+
+  entry->AddContentChangeCallback(aObserver, aData);
+  return entry->GetIdContent();
+}
+
+void
+nsDocument::RemoveIDTargetObserver(nsIAtom* aID,
+                                   IDTargetObserver aObserver, void* aData)
+{
+  if (!CheckGetElementByIdArg(aID))
+    return;
+
+  nsIdentifierMapEntry *entry = GetElementByIdInternal(aID);
+  if (!entry)
+    return;
+
+  entry->RemoveContentChangeCallback(aObserver, aData);
+}
+
 void
 nsDocument::DispatchContentLoadedEvents()
 {
   // If you add early returns from this method, make sure you're
   // calling UnblockOnload properly.
   
   // Fire a DOM event notifying listeners that this document has been
   // loaded (excluding images and other loads initiated by this
@@ -2877,23 +3435,16 @@ void
 nsDocument::ContentStatesChanged(nsIContent* aContent1, nsIContent* aContent2,
                                  PRInt32 aStateMask)
 {
   NS_DOCUMENT_NOTIFY_OBSERVERS(ContentStatesChanged,
                                (this, aContent1, aContent2, aStateMask));
 }
 
 void
-nsDocument::AttributeWillChange(nsIContent* aChild, PRInt32 aNameSpaceID,
-                                nsIAtom* aAttribute)
-{
-  NS_ASSERTION(aChild, "Null child!");
-}
-
-void
 nsDocument::StyleRuleChanged(nsIStyleSheet* aStyleSheet,
                              nsIStyleRule* aOldStyleRule,
                              nsIStyleRule* aNewStyleRule)
 {
   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleChanged,
                                (this, aStyleSheet,
                                 aOldStyleRule, aNewStyleRule));
 }
@@ -3209,24 +3760,16 @@ nsDocument::GetElementsByTagNameNS(const
   NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
 
   // transfer ref to aReturn
   *aReturn = list;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocument::GetElementById(const nsAString & elementId,
-                           nsIDOMElement **_retval)
-{
-  // Should be implemented by subclass
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
 nsDocument::GetAsync(PRBool *aAsync)
 {
   NS_ERROR("nsDocument::GetAsync() should be overriden by subclass!");
 
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -85,16 +85,17 @@
 #include "nsIScriptEventManager.h"
 #include "nsILayoutHistoryState.h"
 #include "nsIRequest.h"
 #include "nsILoadGroup.h"
 #include "nsTObserverArray.h"
 #include "nsStubMutationObserver.h"
 #include "nsIChannel.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsContentList.h"
 
 // Put these here so all document impls get them automatically
 #include "nsHTMLStyleSheet.h"
 #include "nsIHTMLCSSStyleSheet.h"
 
 #include "nsStyleSet.h"
 #include "nsXMLEventsManager.h"
 #include "pldhash.h"
@@ -205,16 +206,126 @@ class nsUint32ToContentHashEntry : publi
     void Destroy();
 
   private:
     const PRUint32 mValue;
     /** A hash or nsIContent ptr, depending on the lower bit (0=hash, 1=ptr) */
     void* mValOrHash;
 };
 
+/**
+ * Right now our identifier map entries contain information for 'name'
+ * and 'id' mappings of a given string. This is so that
+ * nsHTMLDocument::ResolveName only has to do one hash lookup instead
+ * of two. It's not clear whether this still matters for performance.
+ * 
+ * We also store the document.all result list here. This is mainly so that
+ * when all elements with the given ID are removed and we remove
+ * the ID's nsIdentifierMapEntry, the document.all result is released too.
+ * Perhaps the document.all results should have their own hashtable
+ * in nsHTMLDocument.
+ */
+class nsIdentifierMapEntry : public nsISupportsHashKey
+{
+public:
+  nsIdentifierMapEntry(const nsISupports* aKey) :
+    nsISupportsHashKey(aKey), mNameContentList(nsnull)
+  {
+  }
+  nsIdentifierMapEntry(const nsIdentifierMapEntry& aOther) :
+    nsISupportsHashKey(GetKey())
+  {
+    NS_ERROR("Should never be called");
+  }
+  ~nsIdentifierMapEntry();
+
+  void SetInvalidName();
+  PRBool IsInvalidName();
+  void AddNameContent(nsIContent* aContent);
+  void RemoveNameContent(nsIContent* aContent);
+  PRBool HasNameContentList() {
+    return mNameContentList != nsnull;
+  }
+  nsBaseContentList* GetNameContentList() {
+    return mNameContentList;
+  }
+  nsresult CreateNameContentList();
+
+  /**
+   * Returns the element if we know the element associated with this
+   * id. Otherwise returns null.
+   * @param aIsNotInDocument if non-null, we set the output to true
+   * if we know for sure the element is not in the document.
+   */
+  nsIContent* GetIdContent(PRBool* aIsNotInDocument = nsnull);
+  void AppendAllIdContent(nsCOMArray<nsIContent>* aElements);
+  /**
+   * This can fire ID change callbacks.
+   * @return true if the content could be added, false if we failed due
+   * to OOM.
+   */
+  PRBool AddIdContent(nsIContent* aContent);
+  /**
+   * This can fire ID change callbacks.
+   * @return true if this map entry should be removed
+   */
+  PRBool RemoveIdContent(nsIContent* aContent);
+  void FlagIDNotInDocument();
+
+  PRBool HasContentChangeCallback() { return mChangeCallbacks != nsnull; }
+  void AddContentChangeCallback(nsIDocument::IDTargetObserver aCallback, void* aData);
+  void RemoveContentChangeCallback(nsIDocument::IDTargetObserver aCallback, void* aData);
+
+  void Traverse(nsCycleCollectionTraversalCallback* aCallback);
+
+  void SetDocAllList(nsContentList* aContentList) { mDocAllList = aContentList; }
+  nsContentList* GetDocAllList() { return mDocAllList; }
+
+  struct ChangeCallback {
+    nsIDocument::IDTargetObserver mCallback;
+    void* mData;
+  };
+
+  struct ChangeCallbackEntry : public PLDHashEntryHdr {
+    typedef const ChangeCallback KeyType;
+    typedef const ChangeCallback* KeyTypePointer;
+
+    ChangeCallbackEntry(const ChangeCallback* key) :
+      mKey(*key) { }
+    ChangeCallbackEntry(const ChangeCallbackEntry& toCopy) :
+      mKey(toCopy.mKey) { }
+
+    KeyType GetKey() const { return mKey; }
+    PRBool KeyEquals(KeyTypePointer aKey) const {
+      return aKey->mCallback == mKey.mCallback &&
+             aKey->mData == mKey.mData;
+    }
+
+    static KeyTypePointer KeyToPointer(KeyType& aKey) { return &aKey; }
+    static PLDHashNumber HashKey(KeyTypePointer aKey)
+    {
+      return NS_PTR_TO_INT32(aKey->mCallback) >> 2 +
+             NS_PTR_TO_INT32(aKey->mData);
+    }
+    enum { ALLOW_MEMMOVE = PR_TRUE };
+    
+    ChangeCallback mKey;
+  };
+
+private:
+  void FireChangeCallbacks(nsIContent* aOldContent, nsIContent* aNewContent);
+
+  // The single element ID_NOT_IN_DOCUMENT, or empty to indicate we
+  // don't know what element(s) have this key as an ID
+  nsSmallVoidArray mIdContentList;
+  // NAME_NOT_VALID if this id cannot be used as a 'name'
+  nsBaseContentList *mNameContentList;
+  nsRefPtr<nsContentList> mDocAllList;
+  nsAutoPtr<nsTHashtable<ChangeCallbackEntry> > mChangeCallbacks;
+};
 
 class nsDocHeaderData
 {
 public:
   nsDocHeaderData(nsIAtom* aField, const nsAString& aData)
     : mField(aField), mData(aData), mNext(nsnull)
   {
   }
@@ -351,16 +462,21 @@ public:
    */
   virtual nsresult AddCharSetObserver(nsIObserver* aObserver);
 
   /**
    * Remove a charset observer.
    */
   virtual void RemoveCharSetObserver(nsIObserver* aObserver);
 
+  virtual nsIContent* AddIDTargetObserver(nsIAtom* aID,
+                                          IDTargetObserver aObserver, void* aData);
+  virtual void RemoveIDTargetObserver(nsIAtom* aID,
+                                      IDTargetObserver aObserver, void* aData);
+
   /**
    * Access HTTP header data (this may also get set from other sources, like
    * HTML META tags).
    */
   virtual void GetHeaderData(nsIAtom* aHeaderField, nsAString& aData) const;
   virtual void SetHeaderData(nsIAtom* aheaderField,
                              const nsAString& aData);
 
@@ -607,16 +723,22 @@ public:
   NS_DECL_NSIDOMEVENTTARGET
 
   // nsIDOM3EventTarget
   NS_DECL_NSIDOM3EVENTTARGET
 
   // nsIDOMNSEventTarget
   NS_DECL_NSIDOMNSEVENTTARGET
 
+  // nsIMutationObserver
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
+  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
+
   // nsIScriptObjectPrincipal
   virtual nsIPrincipal* GetPrincipal();
 
   virtual nsresult Init();
   
   virtual nsresult AddXMLEventsContent(nsIContent * aXMLEventsElement);
 
   virtual nsresult CreateElem(nsIAtom *aName, nsIAtom *aPrefix,
@@ -660,22 +782,30 @@ public:
    * Utility method for getElementsByClassName.  aRootNode is the node (either
    * document or element), which getElementsByClassName was called on.
    */
   static nsresult GetElementsByClassNameHelper(nsINode* aRootNode,
                                                const nsAString& aClasses,
                                                nsIDOMNodeList** aReturn);
 protected:
 
+  void RegisterNamedItems(nsIContent *aContent);
+  void UnregisterNamedItems(nsIContent *aContent);
+  void UpdateNameTableEntry(nsIContent *aContent);
+  void UpdateIdTableEntry(nsIContent *aContent);
+  void RemoveFromNameTable(nsIContent *aContent);
+  void RemoveFromIdTable(nsIContent *aContent);
+
   /**
    * Check that aId is not empty and log a message to the console
    * service if it is.
    * @returns PR_TRUE if aId looks correct, PR_FALSE otherwise.
    */
-  static PRBool CheckGetElementByIdArg(const nsAString& aId);
+  static PRBool CheckGetElementByIdArg(const nsIAtom* aId);
+  nsIdentifierMapEntry* GetElementByIdInternal(nsIAtom* aID);
 
   void DispatchContentLoadedEvents();
 
   void InitializeFinalizeFrameLoaders();
 
   void RetrieveRelevantHeaders(nsIChannel *aChannel);
 
   static PRBool TryChannelCharset(nsIChannel *aChannel,
@@ -767,40 +897,68 @@ protected:
   // is a weak reference to avoid leaks due to circular references.
   nsWeakPtr mScopeObject;
 
   nsCOMPtr<nsIEventListenerManager> mListenerManager;
   nsCOMPtr<nsIDOMStyleSheetList> mDOMStyleSheets;
   nsRefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
   nsRefPtr<nsScriptLoader> mScriptLoader;
   nsDocHeaderData* mHeaderData;
+  /* mIdentifierMap works as follows for IDs:
+   * 1) Attribute changes affect the table immediately (removing and adding
+   *    entries as needed).
+   * 2) Removals from the DOM affect the table immediately
+   * 3) Additions to the DOM always update existing entries, but only add new
+   *    ones if IdTableIsLive() is true.
+   */
+  nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
 
   nsClassHashtable<nsStringHashKey, nsRadioGroupStruct> mRadioGroups;
 
   // True if the document has been detached from its content viewer.
   PRPackedBool mIsGoingAway:1;
   // True if our content viewer has been removed from the docshell
   // (it may still be displayed, but in zombie state). Form control data
   // has been saved.
   PRPackedBool mRemovedFromDocShell:1;
   // True if the document is being destroyed.
   PRPackedBool mInDestructor:1;
   // True if the document "page" is not hidden
   PRPackedBool mVisible:1;
   // True if document has ever had script handling object.
   PRPackedBool mHasHadScriptHandlingObject:1;
+  // True if this is a regular (non-XHTML) HTML document
+  // XXXbz should this be reset if someone manually calls
+  // SetContentType() on this document?
+  PRPackedBool mIsRegularHTML:1;
 
   PRPackedBool mHasWarnedAboutBoxObjects:1;
 
   PRPackedBool mDelayFrameLoaderInitialization:1;
 
   PRUint8 mXMLDeclarationBits;
 
   PRUint8 mDefaultElementType;
 
+  PRBool IdTableIsLive() const {
+    // live if we've had over 63 misses
+    return (mIdMissCount & 0x40) != 0;
+  }
+  void SetIdTableLive() {
+    mIdMissCount = 0x40;
+  }
+  PRBool IdTableShouldBecomeLive() {
+    NS_ASSERTION(!IdTableIsLive(),
+                 "Shouldn't be called if table is already live!");
+    ++mIdMissCount;
+    return IdTableIsLive();
+  }
+
+  PRUint8 mIdMissCount;
+
   nsInterfaceHashtable<nsVoidPtrHashKey, nsPIBoxObject> *mBoxObjectTable;
   nsInterfaceHashtable<nsVoidPtrHashKey, nsISupports> *mContentWrapperHash;
 
   // The channel that got passed to StartDocumentLoad(), if any
   nsCOMPtr<nsIChannel> mChannel;
   nsRefPtr<nsHTMLStyleSheet> mAttrStyleSheet;
   nsCOMPtr<nsIHTMLCSSStyleSheet> mStyleAttrStyleSheet;
   nsRefPtr<nsXMLEventsManager> mXMLEventsManager;
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -627,17 +627,17 @@ nsGenericDOMDataNode::BindToTree(nsIDocu
 
   // XXXbz sXBL/XBL2 issue!
 
   // Set document
   if (aDocument) {
     // XXX See the comment in nsGenericElement::BindToTree
     mParentPtrBits |= PARENT_BIT_INDOCUMENT;
     if (mText.IsBidi()) {
-      aDocument->SetBidiEnabled(PR_TRUE);
+      aDocument->SetBidiEnabled();
     }
   }
 
   nsNodeUtils::ParentChainChanged(this);
 
   UpdateEditableState();
 
   NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document");
@@ -947,16 +947,159 @@ nsGenericDOMDataNode::SplitText(PRUint32
   // No need to handle the case of document being the parent since text
   // isn't allowed as direct child of documents
 
   return CallQueryInterface(newContent, aReturn);
 }
 
 //----------------------------------------------------------------------
 
+// Implementation of the nsGenericDOMDataNode nsIDOM3Text tearoff
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsText3Tearoff)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsText3Tearoff)
+  NS_INTERFACE_MAP_ENTRY(nsIDOM3Text)
+NS_INTERFACE_MAP_END_AGGREGATED(mNode)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsText3Tearoff)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNode)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsText3Tearoff)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mNode, nsIContent)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsText3Tearoff)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsText3Tearoff)
+
+NS_IMETHODIMP
+nsText3Tearoff::GetIsElementContentWhitespace(PRBool *aReturn)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsText3Tearoff::GetWholeText(nsAString& aWholeText)
+{
+  return mNode->GetWholeText(aWholeText);
+}
+
+NS_IMETHODIMP
+nsText3Tearoff::ReplaceWholeText(const nsAString& aContent,
+                                 nsIDOMText **aReturn)
+{
+  return mNode->ReplaceWholeText(PromiseFlatString(aContent), aReturn);
+}
+
+// Implementation of the nsIDOM3Text interface
+
+/* static */ PRUint32
+nsGenericDOMDataNode::FirstLogicallyAdjacentTextNode(nsIContent* aParent,
+                                                     PRUint32 aIndex)
+{
+  while (aIndex-- > 0) {
+    nsIContent* sibling = aParent->GetChildAt(aIndex);
+    if (!sibling->IsNodeOfType(nsINode::eTEXT))
+      return aIndex + 1;
+  }
+  return 0;
+}
+
+/* static */ PRUint32
+nsGenericDOMDataNode::LastLogicallyAdjacentTextNode(nsIContent* aParent,
+                                                    PRUint32 aIndex,
+                                                    PRUint32 aCount)
+{
+  while (++aIndex < aCount) {
+    nsIContent* sibling = aParent->GetChildAt(aIndex);
+    if (!sibling->IsNodeOfType(nsINode::eTEXT))
+      return aIndex - 1;
+  }
+  return aCount - 1;
+}
+
+nsresult
+nsGenericDOMDataNode::GetWholeText(nsAString& aWholeText)
+{
+  nsIContent* parent = GetParent();
+
+  // Handle parent-less nodes
+  if (!parent)
+    return GetData(aWholeText);
+
+  PRUint32 index = parent->IndexOf(this);
+  PRUint32 first =
+    FirstLogicallyAdjacentTextNode(parent, index);
+  PRUint32 last =
+    LastLogicallyAdjacentTextNode(parent, index, parent->GetChildCount());
+
+  aWholeText.Truncate();
+
+  nsCOMPtr<nsIDOMText> node;
+  nsAutoString tmp;
+  do {
+    node = do_QueryInterface(parent->GetChildAt(first));
+    node->GetData(tmp);
+    aWholeText.Append(tmp);
+  } while (first++ < last);
+
+  return NS_OK;
+}
+
+nsresult
+nsGenericDOMDataNode::ReplaceWholeText(const nsAFlatString& aContent,
+                                       nsIDOMText **aReturn)
+{
+  // Batch possible DOMSubtreeModified events.
+  mozAutoSubtreeModified subtree(GetOwnerDoc(), nsnull);
+  mozAutoDocUpdate updateBatch(GetCurrentDoc(), UPDATE_CONTENT_MODEL, PR_TRUE);
+
+  nsCOMPtr<nsIContent> parent = GetParent();
+
+  // Handle parent-less nodes
+  if (!parent) {
+    if (aContent.IsEmpty()) {
+      *aReturn = nsnull;
+      return NS_OK;
+    }
+
+    SetText(aContent.get(), aContent.Length(), PR_TRUE);
+    return CallQueryInterface(this, aReturn);
+  }
+
+  // We don't support entity references or read-only nodes, so remove the
+  // logically adjacent text nodes (which therefore must all be siblings of
+  // this) and set this one to the provided text, if that text isn't empty.
+
+  PRUint32 index = parent->IndexOf(this);
+  PRUint32 first =
+    FirstLogicallyAdjacentTextNode(parent, index);
+  PRUint32 last =
+    LastLogicallyAdjacentTextNode(parent, index, parent->GetChildCount());
+
+  do {
+    if (last == index && !aContent.IsEmpty())
+      continue;
+
+    parent->RemoveChildAt(last, PR_TRUE);
+  } while (last-- > first);
+
+  // Empty string means we removed this node too.
+  if (aContent.IsEmpty()) {
+    *aReturn = nsnull;
+    return NS_OK;
+  }
+
+  SetText(aContent.get(), aContent.Length(), PR_TRUE);
+  return CallQueryInterface(this, aReturn);
+}
+
+//----------------------------------------------------------------------
+
 // Implementation of the nsIContent interface text functions
 
 const nsTextFragment *
 nsGenericDOMDataNode::GetText()
 {
   return &mText;
 }
 
@@ -1019,17 +1162,17 @@ void nsGenericDOMDataNode::SetBidiStatus
   if (document && document->GetBidiEnabled()) {
     // OK, we already know it's Bidi, so we won't test again
     return;
   }
 
   mText.SetBidiFlag();
 
   if (document && mText.IsBidi()) {
-    document->SetBidiEnabled(PR_TRUE);
+    document->SetBidiEnabled();
   }
 }
 
 already_AddRefed<nsIAtom>
 nsGenericDOMDataNode::GetCurrentValueAtom()
 {
   nsAutoString val;
   GetData(val);
--- a/content/base/src/nsGenericDOMDataNode.h
+++ b/content/base/src/nsGenericDOMDataNode.h
@@ -40,16 +40,17 @@
  * nsIDOMCDATASection, and nsIDOMProcessingInstruction nodes.
  */
 
 #ifndef nsGenericDOMDataNode_h___
 #define nsGenericDOMDataNode_h___
 
 #include "nsIDOMCharacterData.h"
 #include "nsIDOMEventTarget.h"
+#include "nsIDOM3Text.h"
 #include "nsTextFragment.h"
 #include "nsVoidArray.h"
 #include "nsDOMError.h"
 #include "nsIEventListenerManager.h"
 #include "nsGenericElement.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsIDOMAttr;
@@ -305,16 +306,29 @@ protected:
 
   nsDataSlots *GetExistingDataSlots() const
   {
     return static_cast<nsDataSlots*>(GetExistingSlots());
   }
 
   nsresult SplitText(PRUint32 aOffset, nsIDOMText** aReturn);
 
+  friend class nsText3Tearoff;
+
+  static PRUint32 FirstLogicallyAdjacentTextNode(nsIContent* aParent,
+                                                 PRUint32 aIndex);
+
+  static PRUint32 LastLogicallyAdjacentTextNode(nsIContent* aParent,
+                                                PRUint32 aIndex,
+                                                PRUint32 aCount);
+
+  nsresult GetWholeText(nsAString& aWholeText);
+
+  nsresult ReplaceWholeText(const nsAFlatString& aContent, nsIDOMText **aReturn);
+
   nsresult SetTextInternal(PRUint32 aOffset, PRUint32 aCount,
                            const PRUnichar* aBuffer, PRUint32 aLength,
                            PRBool aNotify);
 
   /**
    * Method to clone this node. This needs to be overriden by all derived
    * classes. If aCloneText is true the text content will be cloned too.
    *
@@ -328,16 +342,37 @@ protected:
   nsTextFragment mText;
 
 private:
   void SetBidiStatus();
 
   already_AddRefed<nsIAtom> GetCurrentValueAtom();
 };
 
+/** Tearoff class for the nsIDOM3Text portion of nsGenericDOMDataNode. */
+class nsText3Tearoff : public nsIDOM3Text
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+
+  NS_DECL_NSIDOM3TEXT
+
+  NS_DECL_CYCLE_COLLECTION_CLASS(nsText3Tearoff)
+
+  nsText3Tearoff(nsGenericDOMDataNode *aNode) : mNode(aNode)
+  {
+  }
+
+protected:
+  virtual ~nsText3Tearoff() {}
+
+private:
+  nsRefPtr<nsGenericDOMDataNode> mNode;
+};
+
 //----------------------------------------------------------------------
 
 /**
  * Mostly implement the nsIDOMNode API by forwarding the methods to
  * nsGenericDOMDataNode
  *
  * Note that classes using this macro will need to implement:
  *       NS_IMETHOD GetNodeType(PRUint16* aNodeType);
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -2227,62 +2227,85 @@ nsGenericElement::UnbindFromTree(PRBool 
 
 nsresult
 nsGenericElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   return nsGenericElement::doPreHandleEvent(this, aVisitor);
 }
 
 static nsIContent*
-FindFirstNonNativeAnonymousAncestor(nsIContent* aContent)
+FindNativeAnonymousSubtreeOwner(nsIContent* aContent)
 {
-  while (aContent && aContent->IsNativeAnonymous()) {
-    aContent = aContent->GetParent();
+  if (aContent->IsInNativeAnonymousSubtree()) {
+    PRBool isNativeAnon = PR_FALSE;
+    while (aContent && !isNativeAnon) {
+      isNativeAnon = aContent->IsNativeAnonymous();
+      aContent = aContent->GetParent();
+    }
   }
   return aContent;
 }
 
 nsresult
 nsGenericElement::doPreHandleEvent(nsIContent* aContent,
                                    nsEventChainPreVisitor& aVisitor)
 {
   //FIXME! Document how this event retargeting works, Bug 329124.
   aVisitor.mCanHandle = PR_TRUE;
 
   // Don't propagate mouseover and mouseout events when mouse is moving
   // inside native anonymous content.
   PRBool isAnonForEvents = aContent->IsNativeAnonymous();
-  if (aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH ||
-      aVisitor.mEvent->message == NS_MOUSE_EXIT_SYNTH) {
+  if ((aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH ||
+       aVisitor.mEvent->message == NS_MOUSE_EXIT_SYNTH) &&
+      // This is an optimization - try to stop event propagation when
+      // event has just possibly been retargeted.
+      static_cast<nsISupports*>(aContent) == aVisitor.mEvent->target) {
      nsCOMPtr<nsIContent> relatedTarget =
        do_QueryInterface(static_cast<nsMouseEvent*>
                                     (aVisitor.mEvent)->relatedTarget);
     if (relatedTarget &&
         relatedTarget->GetOwnerDoc() == aContent->GetOwnerDoc()) {
 
       // If current target is anonymous for events or we know that related
       // target is descendant of an element which is anonymous for events,
       // we may want to stop event propagation.
       // If aContent is the original target, aVisitor.mRelatedTargetIsInAnon
       // must be updated.
       if (isAnonForEvents || aVisitor.mRelatedTargetIsInAnon ||
           (aVisitor.mEvent->originalTarget == aContent &&
            (aVisitor.mRelatedTargetIsInAnon =
             relatedTarget->IsInNativeAnonymousSubtree()))) {
-        nsIContent* nonAnon = FindFirstNonNativeAnonymousAncestor(aContent);
-        if (nonAnon) {
-          nsIContent* nonAnonRelated =
-            FindFirstNonNativeAnonymousAncestor(relatedTarget);
-          if (nonAnonRelated) {
-            if (nonAnon == nonAnonRelated ||
-                nsContentUtils::ContentIsDescendantOf(nonAnonRelated, nonAnon)) {
-              aVisitor.mParentTarget = nsnull;
-              // Event should not propagate to non-anon content.
-              aVisitor.mCanHandle = isAnonForEvents;
-              return NS_OK;
+        nsIContent* anonOwner = FindNativeAnonymousSubtreeOwner(aContent);
+        if (anonOwner) {
+          nsIContent* anonOwnerRelated =
+            FindNativeAnonymousSubtreeOwner(relatedTarget);
+          if (anonOwnerRelated) {
+            // Note, anonOwnerRelated may still be inside some other
+            // native anonymous subtree. The case where anonOwner is still
+            // inside native anonymous subtree will be handled when event
+            // propagates up in the DOM tree.
+            while (anonOwner != anonOwnerRelated &&
+                   anonOwnerRelated->IsInNativeAnonymousSubtree()) {
+              anonOwnerRelated = FindNativeAnonymousSubtreeOwner(anonOwnerRelated);
+            }
+            if (anonOwner == anonOwnerRelated) {
+              nsCOMPtr<nsIContent> target =
+                do_QueryInterface(aVisitor.mEvent->originalTarget);
+              // Because XBL and native anon content both do event re-targeting,
+              // static_cast<nsISupports*>(aContent) == aVisitor.mEvent->target
+              // optimization may not always work. So be paranoid and make
+              // sure we never stop event propagation when we shouldn't!
+              if (relatedTarget->FindFirstNonNativeAnonymous() ==
+                  target->FindFirstNonNativeAnonymous()) {
+                aVisitor.mParentTarget = nsnull;
+                // Event should not propagate to non-anon content.
+                aVisitor.mCanHandle = isAnonForEvents;
+                return NS_OK;
+              }
             }
           }
         }
       }
     }
   }
 
   nsCOMPtr<nsIContent> parent = aContent->GetParent();
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -133,18 +133,20 @@ GK_ATOM(block, "block")
 GK_ATOM(blockquote, "blockquote")
 GK_ATOM(blur, "blur")
 GK_ATOM(body, "body")
 GK_ATOM(boolean, "boolean")
 GK_ATOM(border, "border")
 GK_ATOM(bordercolor, "bordercolor")
 GK_ATOM(both, "both")
 GK_ATOM(bottom, "bottom")
+GK_ATOM(bottomleft, "bottomleft")
 GK_ATOM(bottommargin, "bottommargin")
 GK_ATOM(bottompadding, "bottompadding")
+GK_ATOM(bottomright, "bottomright")
 GK_ATOM(box, "box")
 GK_ATOM(br, "br")
 GK_ATOM(braille, "braille")
 GK_ATOM(broadcast, "broadcast")
 GK_ATOM(broadcaster, "broadcaster")
 GK_ATOM(broadcasterset, "broadcasterset")
 GK_ATOM(browser, "browser")
 GK_ATOM(bulletList, "Bullet-list")
@@ -392,16 +394,17 @@ GK_ATOM(hspace, "hspace")
 GK_ATOM(html, "html")
 GK_ATOM(htmlBaseHref, "html-base-href")
 GK_ATOM(htmlBaseTarget, "html-base-target")
 GK_ATOM(httpEquiv, "http-equiv")
 GK_ATOM(i, "i")
 GK_ATOM(id, "id")
 GK_ATOM(_if, "if")
 GK_ATOM(iframe, "iframe")
+GK_ATOM(ignore, "ignore")
 GK_ATOM(ignorecase, "ignorecase")
 GK_ATOM(ignorekeys, "ignorekeys")
 GK_ATOM(ilayer, "ilayer")
 GK_ATOM(image, "image")
 GK_ATOM(imageClickedPoint, "image-clicked-point")
 GK_ATOM(img, "img")
 GK_ATOM(implementation, "implementation")
 GK_ATOM(implements, "implements")
@@ -509,16 +512,17 @@ GK_ATOM(mod, "mod")
 GK_ATOM(mode, "mode")
 GK_ATOM(modifiers, "modifiers")
 GK_ATOM(mousedown, "mousedown")
 GK_ATOM(mousemove, "mousemove")
 GK_ATOM(mouseout, "mouseout")
 GK_ATOM(mouseover, "mouseover")
 GK_ATOM(mousethrough, "mousethrough")
 GK_ATOM(mouseup, "mouseup")
+GK_ATOM(moz_opaque, "moz-opaque")
 GK_ATOM(msthemecompatible, "msthemecompatible")
 GK_ATOM(multicol, "multicol")
 GK_ATOM(multiple, "multiple")
 GK_ATOM(name, "name")
 GK_ATOM(_namespace, "namespace")
 GK_ATOM(namespaceAlias, "namespace-alias")
 GK_ATOM(namespaceUri, "namespace-uri")
 GK_ATOM(NaN, "NaN")
@@ -796,16 +800,17 @@ GK_ATOM(start_after, "start_after")
 GK_ATOM(start_before, "start_before")
 GK_ATOM(startsWith, "starts-with")
 GK_ATOM(state, "state")
 GK_ATOM(statedatasource, "statedatasource")
 GK_ATOM(staticHint, "staticHint")
 GK_ATOM(statustext, "statustext")
 GK_ATOM(stop, "stop")
 GK_ATOM(stretch, "stretch")
+GK_ATOM(stretch_to_fit, "stretch-to-fit")
 GK_ATOM(strike, "strike")
 GK_ATOM(string, "string")
 GK_ATOM(stringLength, "string-length")
 GK_ATOM(stripSpace, "strip-space")
 GK_ATOM(strong, "strong")
 GK_ATOM(style, "style")
 GK_ATOM(stylesheet, "stylesheet")
 GK_ATOM(stylesheetPrefix, "stylesheet-prefix")
@@ -850,18 +855,20 @@ GK_ATOM(token, "token")
 GK_ATOM(tokenize, "tokenize")
 GK_ATOM(toolbar, "toolbar")
 GK_ATOM(toolbarbutton, "toolbarbutton")
 GK_ATOM(toolbaritem, "toolbaritem")
 GK_ATOM(toolbox, "toolbox")
 GK_ATOM(tooltip, "tooltip")
 GK_ATOM(tooltiptext, "tooltiptext")
 GK_ATOM(top, "top")
+GK_ATOM(topleft, "topleft")
 GK_ATOM(topmargin, "topmargin")
 GK_ATOM(toppadding, "toppadding")
+GK_ATOM(topright, "topright")
 GK_ATOM(tr, "tr")
 GK_ATOM(trailing, "trailing")
 GK_ATOM(transform, "transform")
 GK_ATOM(transformiix, "transformiix")
 GK_ATOM(translate, "translate")
 GK_ATOM(transparent, "transparent")
 GK_ATOM(tree, "tree")
 GK_ATOM(treecell, "treecell")
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -757,25 +757,37 @@ nsObjectLoadingContent::EnsureInstantiat
   return rv;
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame)
 {
   LOG(("OBJLC [%p]: Got frame %p (mInstantiating=%i)\n", this, aFrame,
        mInstantiating));
-  if (!mInstantiating && aFrame && mType == eType_Plugin) {
+
+  // "revoke" any existing instantiate event as it likely has out of
+  // date data (frame pointer etc).
+  mPendingInstantiateEvent = nsnull;
+
+  nsCOMPtr<nsIPluginInstance> instance;
+  aFrame->GetPluginInstance(*getter_AddRefs(instance));
+
+  if (instance) {
+    // The frame already has a plugin instance, that means the plugin
+    // has already been instantiated.
+
+    return NS_OK;
+  }
+
+  if (!mInstantiating && mType == eType_Plugin) {
     // Asynchronously call Instantiate
     // This can go away once plugin loading moves to content
     // This must be done asynchronously to ensure that the frame is correctly
     // initialized (has a view etc)
 
-    // "revoke" any existing instantiate event.
-    mPendingInstantiateEvent = nsnull;
-
     // When in a plugin document, the document will take care of calling
     // instantiate
     nsCOMPtr<nsIPluginDocument> pDoc (do_QueryInterface(GetOurDocument()));
     if (pDoc) {
       return NS_OK;
     }
 
     nsCOMPtr<nsIRunnable> event =
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -49,20 +49,20 @@
 #include "nsIStreamListener.h"
 #include "nsFrameLoader.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIChannelEventSink.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsIRunnable.h"
 #include "nsIChannelClassifier.h"
 
-struct nsAsyncInstantiateEvent;
-class  AutoNotifier;
-class  AutoFallback;
-class  AutoSetInstantiatingToFalse;
+class nsAsyncInstantiateEvent;
+class AutoNotifier;
+class AutoFallback;
+class AutoSetInstantiatingToFalse;
 
 /**
  * INVARIANTS OF THIS CLASS
  * - mChannel is non-null between asyncOpen and onStopRequest (NOTE: Only needs
  *   to be valid until onStopRequest is called on mFinalListener, not
  *   necessarily until the channel calls onStopRequest on us)
  * - mChannel corresponds to the channel that gets passed to the
  *   nsIRequestObserver/nsIStreamListener methods
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsReferencedElement.cpp
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=78: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla.org.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Robert O'Callahan   <robert@ocallahan.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsReferencedElement.h"
+#include "nsContentUtils.h"
+#include "nsIURI.h"
+#include "nsBindingManager.h"
+#include "nsIURL.h"
+#include "nsEscape.h"
+#include "nsXBLPrototypeBinding.h"
+#include "nsIDOMNode.h"
+#include "nsIDOMDocument.h"
+#include "nsIDOMElement.h"
+#include "nsCycleCollectionParticipant.h"
+
+static PRBool EqualExceptRef(nsIURL* aURL1, nsIURL* aURL2)
+{
+  nsCOMPtr<nsIURI> u1;
+  nsCOMPtr<nsIURI> u2;
+
+  nsresult rv = aURL1->Clone(getter_AddRefs(u1));
+  if (NS_SUCCEEDED(rv)) {
+    rv = aURL2->Clone(getter_AddRefs(u2));
+  }
+  if (NS_FAILED(rv))
+    return PR_FALSE;
+
+  nsCOMPtr<nsIURL> url1 = do_QueryInterface(u1);
+  nsCOMPtr<nsIURL> url2 = do_QueryInterface(u2);
+  if (!url1 || !url2) {
+    NS_WARNING("Cloning a URL produced a non-URL");
+    return PR_FALSE;
+  }
+  url1->SetRef(EmptyCString());
+  url2->SetRef(EmptyCString());
+
+  PRBool equal;
+  rv = url1->Equals(url2, &equal);
+  return NS_SUCCEEDED(rv) && equal;
+}
+
+void
+nsReferencedElement::Reset(nsIContent* aFromContent, nsIURI* aURI, PRBool aWatch)
+{
+  Unlink();
+
+  nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
+  if (!url)
+    return;
+
+  nsCAutoString refPart;
+  url->GetRef(refPart);
+  // Unescape %-escapes in the reference. The result will be in the
+  // origin charset of the URL, hopefully...
+  NS_UnescapeURL(refPart);
+
+  nsCAutoString charset;
+  url->GetOriginCharset(charset);
+  nsAutoString ref;
+  nsresult rv = nsContentUtils::ConvertStringFromCharset(charset, refPart, ref);
+  if (NS_FAILED(rv)) {
+    CopyUTF8toUTF16(refPart, ref);
+  }
+  if (ref.IsEmpty())
+    return;
+
+  // Get the current document
+  nsIDocument *doc = aFromContent->GetCurrentDoc();
+  if (!doc)
+    return;
+
+  // This will be the URI of the document the content belongs to
+  // (the URI of the XBL document if the content is anonymous
+  // XBL content)
+  nsCOMPtr<nsIURL> documentURL = do_QueryInterface(doc->GetDocumentURI());
+  nsIContent* bindingParent = aFromContent->GetBindingParent();
+  PRBool isXBL = PR_FALSE;
+  if (bindingParent) {
+    nsXBLBinding* binding = doc->BindingManager()->GetBinding(bindingParent);
+    if (binding) {
+      // XXX sXBL/XBL2 issue
+      // If this is an anonymous XBL element then the URI is
+      // relative to the binding document. A full fix requires a
+      // proper XBL2 implementation but for now URIs that are
+      // relative to the binding document should be resolve to the
+      // copy of the target element that has been inserted into the
+      // bound document.
+      documentURL = do_QueryInterface(binding->PrototypeBinding()->DocURI());
+      isXBL = PR_TRUE;
+    }
+  }
+  if (!documentURL)
+    return;
+
+  if (!EqualExceptRef(url, documentURL)) {
+    // Oops -- we don't support off-document references
+    return;
+  }
+
+  // Get the element
+  if (isXBL) {
+    nsCOMPtr<nsIDOMNodeList> anonymousChildren;
+    doc->BindingManager()->
+      GetAnonymousNodesFor(bindingParent, getter_AddRefs(anonymousChildren));
+
+    if (anonymousChildren) {
+      PRUint32 length;
+      anonymousChildren->GetLength(&length);
+      for (PRUint32 i = 0; i < length && !mContent; ++i) {
+        nsCOMPtr<nsIDOMNode> node;
+        anonymousChildren->Item(i, getter_AddRefs(node));
+        nsCOMPtr<nsIContent> c = do_QueryInterface(node);
+        if (c) {
+          mContent = nsContentUtils::MatchElementId(c, ref);
+        }
+      }
+    }
+    return;
+  }
+
+  if (aWatch) {
+    nsCOMPtr<nsIAtom> atom = do_GetAtom(ref);
+    if (!atom)
+      return;
+    atom.swap(mWatchID);
+    mWatchDocument = doc;
+    mContent = mWatchDocument->AddIDTargetObserver(mWatchID, Observe, this);
+    return;
+  }
+  
+  nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc);
+  NS_ASSERTION(domDoc, "Content doesn't reference a dom Document");
+
+  nsCOMPtr<nsIDOMElement> element;
+  rv = domDoc->GetElementById(ref, getter_AddRefs(element));
+  if (element) {
+    mContent = do_QueryInterface(element);
+  }
+}
+
+void
+nsReferencedElement::Traverse(nsCycleCollectionTraversalCallback* aCB)
+{
+  aCB->NoteXPCOMChild(mWatchDocument);
+  aCB->NoteXPCOMChild(mContent);
+}
+
+void
+nsReferencedElement::Unlink()
+{
+  if (mWatchDocument && mWatchID) {
+    mWatchDocument->RemoveIDTargetObserver(mWatchID, Observe, this);
+  }
+  mWatchDocument = nsnull;
+  mWatchID = nsnull;
+  mContent = nsnull;
+}
+
+PRBool
+nsReferencedElement::Observe(nsIContent* aOldContent,
+                             nsIContent* aNewContent, void* aData)
+{
+  nsReferencedElement* p = static_cast<nsReferencedElement*>(aData);
+  if (p->mPendingNotification) {
+    p->mPendingNotification->SetTo(aNewContent);
+  } else {
+    NS_ASSERTION(aOldContent == p->mContent, "Failed to track content!");
+    p->mPendingNotification = new Notification(p, aOldContent, aNewContent);
+    nsContentUtils::AddScriptRunner(p->mPendingNotification);
+  }
+  PRBool keepTracking = p->IsPersistent();
+  if (!keepTracking) {
+    p->mWatchDocument = nsnull;
+    p->mWatchID = nsnull;
+  }
+  return keepTracking;
+}
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -532,18 +532,22 @@ nsScriptLoader::EvaluateScript(nsScriptL
 {
   nsresult rv = NS_OK;
 
   // We need a document to evaluate scripts.
   if (!mDocument) {
     return NS_ERROR_FAILURE;
   }
 
-  nsIScriptGlobalObject *globalObject = mDocument->GetScriptGlobalObject();
-  NS_ENSURE_TRUE(globalObject, NS_ERROR_FAILURE);
+  nsPIDOMWindow *pwin = mDocument->GetInnerWindow();
+  if (!pwin || !pwin->IsInnerWindow()) {
+    return NS_ERROR_FAILURE;
+  }
+  nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(pwin);
+  NS_ASSERTION(globalObject, "windows must be global objects");
 
   // Get the script-type to be used by this element.
   nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->mElement));
   NS_ASSERTION(scriptContent, "no content - what is default script-type?");
   PRUint32 stid = scriptContent ? scriptContent->GetScriptTypeID() :
                                   nsIProgrammingLanguage::JAVASCRIPT;
   // and make sure we are setup for this type of script.
   rv = globalObject->EnsureScriptEnvironment(stid);
--- a/content/base/src/nsTextNode.cpp
+++ b/content/base/src/nsTextNode.cpp
@@ -36,16 +36,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * Implementation of DOM Core's nsIDOMText node.
  */
 
 #include "nsGenericDOMDataNode.h"
 #include "nsIDOMText.h"
+#include "nsIDOM3Text.h"
 #include "nsContentUtils.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsIAttribute.h"
 #include "nsIDocument.h"
 #include "nsThreadUtils.h"
 
@@ -177,16 +178,17 @@ NS_IMPL_ADDREF_INHERITED(nsTextNode, nsG
 NS_IMPL_RELEASE_INHERITED(nsTextNode, nsGenericDOMDataNode)
 
 
 // QueryInterface implementation for nsTextNode
 NS_INTERFACE_MAP_BEGIN(nsTextNode)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
   NS_INTERFACE_MAP_ENTRY(nsIDOMText)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCharacterData)
+  NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3Text, new nsText3Tearoff(this))
   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(Text)
 NS_INTERFACE_MAP_END_INHERITING(nsGenericDOMDataNode)
 
 NS_IMETHODIMP
 nsTextNode::GetNodeName(nsAString& aNodeName)
 {
   aNodeName.AssignLiteral("#text");
   return NS_OK;
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -174,17 +174,21 @@ include $(topsrcdir)/config/rules.mk
 		file_XHR_pass3.txt^headers^ \
 		file_XHR_fail1.txt \
 		file_XHR_fail1.txt^headers^ \
 		test_bug428847.html \
 		file_bug428847-1.xhtml \
 		file_bug428847-2.xhtml \
 		test_bug425201.html \
 		test_bug431833.html \
-	$(NULL)
+		test_bug438519.html \
+		test_text_replaceWholeText.html \
+		test_text_wholeText.html \
+		wholeTexty-helper.xml \
+		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
 check::
 	@$(EXIT_ON_ERROR) \
 	for f in $(subst .cpp,,$(CPP_UNIT_TESTS)); do \
 	  XPCOM_DEBUG_BREAK=stack-and-abort $(RUN_TEST_PROGRAM) $(DIST)/bin/$$f; \
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug438519.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=438519
+-->
+<head>
+  <title>Test for Bug 438519</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="doTest()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=438519">Mozilla Bug 438519</a>
+<p id="display"></p>
+<div id="content" style="display:none">
+
+<iframe id="empty" src="data:text/xml,<!DOCTYPE HTML []><html></html>"></iframe>
+<iframe id="missing" src="data:text/xml,<!DOCTYPE HTML><html></html>"></iframe>
+<iframe id="entity" src="data:text/xml,<!DOCTYPE HTML [ <!ENTITY foo 'foo'> ]><html></html>"></iframe>
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 218236 **/
+
+SimpleTest.waitForExplicitFinish();
+
+function doTest() {
+  function checkInternalSubset(id, expected) {
+    var e = document.getElementById(id);
+    is(e.contentDocument.doctype.internalSubset, expected, "checking '" + id + "'");
+  }
+
+  checkInternalSubset("empty", "");
+  checkInternalSubset("missing", null);
+  checkInternalSubset("entity", " <!ENTITY foo 'foo'> ");
+  SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_text_replaceWholeText.html
@@ -0,0 +1,273 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=421765
+-->
+<head>
+  <title>Text.replaceWholeText tests</title>
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=421765">Mozilla Bug 421765</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+
+<iframe id="xmlDocument" src="wholeTexty-helper.xml"></iframe>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 421765 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var xmlDoc;
+
+function entity(n) { return xmlDoc.createEntityReference(n); }
+function text(t) { return document.createTextNode(t); }
+function element() { return document.createElement("div"); }
+function cdata(t)
+{
+  xmlDoc = $("xmlDocument").contentDocument;
+  // document.createCDATASection isn't implemented; clone for the win
+  var node = xmlDoc.documentElement.firstChild.cloneNode(false);
+  is(node.nodeType, Node.CDATA_SECTION_NODE,
+     "er, why isn't this a CDATA section node?");
+  node.data = t;
+  return node;
+}
+
+
+function startTests()
+{
+  var outer = element();
+  var first = text("first");
+  var second = element();
+  second.appendChild(text("element contents"));
+  outer.appendChild(first);
+  outer.appendChild(second);
+
+  is(first.wholeText, "first", "wrong initial wholeText");
+
+  is(first.replaceWholeText("start"), first,
+     "should have gotten first back");
+  is(first.data, "start", "should have modified first's data");
+  is(first.wholeText, "start", "should have gotten new wholeText");
+
+  var cdataNode = cdata("-cdata");
+  outer.insertBefore(cdataNode, second);
+
+  is(first.wholeText, "start-cdata",
+     "should have gotten first+cdataNode as wholeText");
+
+  var outer2 = outer.cloneNode(true); // save
+
+  is(first.replaceWholeText("first"), first,
+     "replaceWholeText on first returned wrong object");
+  is(first.nodeType, Node.TEXT_NODE, "node changed type?");
+  is(first.data, "first", "wrong data in first");
+  is(first.previousSibling, null, "wrong previousSibling for first");
+  is(first.nextSibling, second, "wrong nextSibling for first");
+  is(cdataNode.previousSibling, null, "wrong previousSibling for cdataNode");
+  is(cdataNode.nextSibling, null, "wrong nextSibling for cdataNode");
+
+  ok(first.replaceWholeText("") === null,
+     "empty string should cause a return of null");
+  is(first.data, "first", "wrong data after replacing with empty string");
+
+  is(outer.firstChild, second, "replaceWholeText('') removes the node");
+
+  // switcheroo, with sanity tests
+  outer = outer2;
+  is(outer.nodeType, Node.ELEMENT_NODE, "outer not element?");
+  first = outer.firstChild;
+  is(first.nodeType, Node.TEXT_NODE, "first not text?");
+  cdataNode = first.nextSibling;
+  is(cdataNode.nodeType, Node.CDATA_SECTION_NODE, "cdataNode not cdata?");
+  second = outer.lastChild;
+  is(second.nodeType, Node.ELEMENT_NODE, "second not element?");
+
+  is(cdataNode.replaceWholeText("cdata"), cdataNode,
+     "replaceWholeText on cdataNode returned wrong object");
+  is(cdataNode.nodeType, Node.CDATA_SECTION_NODE, "node changed type?");
+  is(cdataNode.nodeValue, "cdata", "wrong node value?");
+  is(cdataNode.previousSibling, null, "wrong previousSibling");
+  is(cdataNode.nextSibling, second, "wrong nextSibling");
+
+  ok(cdataNode.replaceWholeText("") === null,
+     "empty string should cause a return of null");
+  is(cdataNode.data, "cdata", "wrong data after replacing with empty string");
+  is(outer.firstChild, second, "should be no more text at start");
+}
+
+function middleTests()
+{
+  var outer = element();
+  var first = element();
+  var middle = text("middle");
+  var last = element();
+  first.appendChild(text("first element contents"));
+  last.appendChild(text("last element contents"));
+  outer.appendChild(first);
+  outer.appendChild(middle);
+  outer.appendChild(last);
+
+  is(middle.wholeText, "middle", "wrong initial wholeText");
+
+  is(middle.replaceWholeText("center"), middle,
+     "should have gotten middle back");
+  is(middle.data, "center", "should have modified middle's data");
+  is(middle.wholeText, "center", "should have gotten new wholeText");
+
+  var cdataNode = cdata("-cdata");
+  outer.insertBefore(cdataNode, last);
+
+  is(middle.wholeText, "center-cdata",
+     "should have gotten middle+cdataNode as wholeText");
+
+  var outer2 = outer.cloneNode(true); // save
+
+  is(middle.replaceWholeText("middle"), middle,
+     "replaceWholeText on middle returned wrong object");
+  is(middle.nodeType, Node.TEXT_NODE, "node changed type?");
+  is(middle.data, "middle", "wrong data in middle");
+  is(middle.previousSibling, first, "wrong previousSibling");
+  is(middle.nextSibling, last, "wrong nextSibling");
+
+  ok(middle.replaceWholeText("") === null,
+     "empty string should cause a return of null");
+  is(middle.data, "middle", "wrong data after replacing with empty string");
+
+  // switcheroo, with sanity tests
+  outer = outer2;
+  is(outer.nodeType, Node.ELEMENT_NODE, "outer not element?");
+  first = outer.firstChild;
+  is(first.nodeType, Node.ELEMENT_NODE, "first not element?");
+  middle = first.nextSibling;
+  is(middle.nodeType, Node.TEXT_NODE, "middle not text?");
+  cdataNode = middle.nextSibling;
+  is(cdataNode.nodeType, Node.CDATA_SECTION_NODE, "cdataNode not cdata?");
+  last = outer.lastChild;
+  is(last.nodeType, Node.ELEMENT_NODE, "last not element?");
+
+  is(cdataNode.replaceWholeText("cdata"), cdataNode,
+     "replaceWholeText on cdataNode returned wrong object");
+  is(cdataNode.nodeType, Node.CDATA_SECTION_NODE, "node changed type?");
+  is(cdataNode.nodeValue, "cdata", "wrong node value?");
+  is(cdataNode.previousSibling, first, "wrong previousSibling");
+  is(cdataNode.nextSibling, last, "wrong nextSibling");
+
+  ok(cdataNode.replaceWholeText("") === null,
+     "empty string should cause a return of null");
+  is(cdataNode.data, "cdata", "wrong data after replacing with empty string");
+  is(middle.wholeText, "center", "wrong wholeText after removal");
+  is(first.nextSibling, last, "wrong nextSibling");
+  is(last.previousSibling, first, "wrong previousSibling");
+}
+
+function endTests()
+{
+  var outer = element();
+  var first = element();
+  var second = text("second");
+  first.appendChild(text("element contents"));
+  outer.appendChild(first);
+  outer.appendChild(second);
+
+  is(second.wholeText, "second", "wrong initial wholeText");
+
+  is(second.replaceWholeText("end"), second,
+     "should have gotten second back");
+  is(second.data, "end", "should have modified second's data");
+  is(second.wholeText, "end", "should have gotten new wholeText");
+
+  var cdataNode = cdata("cdata-");
+  outer.insertBefore(cdataNode, second);
+
+  is(second.wholeText, "cdata-end",
+     "should have gotten cdataNode+second as wholeText");
+  is(cdataNode.wholeText, "cdata-end",
+     "should have gotten cdataNode+second as wholeText");
+
+  var outer2 = outer.cloneNode(true); // save
+
+  is(second.replaceWholeText("second"), second,
+     "replaceWholeText on second returned wrong object");
+  is(second.nodeType, Node.TEXT_NODE, "node changed type?");
+  is(second.data, "second", "wrong data in second");
+  is(second.previousSibling, first, "wrong previousSibling for second");
+  is(second.nextSibling, null, "wrong nextSibling for second");
+  is(cdataNode.previousSibling, null, "wrong previousSibling for cdataNode");
+  is(cdataNode.nextSibling, null, "wrong nextSibling for cdataNode");
+
+  ok(second.replaceWholeText("") === null,
+     "empty string should cause a return of null");
+  is(second.data, "second", "wrong data after replacing with empty string");
+
+  is(outer.lastChild, first, "replaceWholeText('') removes the node");
+
+  // switcheroo, with sanity tests
+  outer = outer2;
+  is(outer.nodeType, Node.ELEMENT_NODE, "outer not element?");
+  first = outer.firstChild;
+  is(first.nodeType, Node.ELEMENT_NODE, "first not element?");
+  cdataNode = first.nextSibling;
+  is(cdataNode.nodeType, Node.CDATA_SECTION_NODE, "cdataNode not cdata?");
+  second = outer.lastChild;
+  is(second.nodeType, Node.TEXT_NODE, "middle not text?");
+
+  is(cdataNode.replaceWholeText("cdata"), cdataNode,
+     "replaceWholeText on cdataNode returned wrong object");
+  is(cdataNode.nodeType, Node.CDATA_SECTION_NODE, "node changed type?");
+  is(cdataNode.nodeValue, "cdata", "wrong node value?");
+  is(cdataNode.previousSibling, first, "wrong previousSibling for cdataNode");
+  is(cdataNode.nextSibling, null, "wrong nextSibling for cdataNode");
+  is(second.previousSibling, null, "wrong previousSibling for second");
+  is(second.nextSibling, null, "wrong nextSibling for second");
+
+  ok(cdataNode.replaceWholeText("") === null,
+     "empty string should cause a return of null");
+  is(cdataNode.data, "cdata", "wrong data after replacing with empty string");
+  is(outer.lastChild, first, "should be no more text at end");
+}
+
+function entityTests()
+{
+  todo_isnot(entity("bar"), null,
+             "need implementation update if we ever support entity nodes!");
+
+  var root = xmlDoc.documentElement;
+  is(root.lastChild.firstChild.nodeType, Node.TEXT_NODE,
+     "uh-oh, did we start supporting entity references as nodes?");
+  is(root.lastChild.lastChild.nodeType, Node.ELEMENT_NODE,
+     "uh-oh, did we start supporting entity references as nodes?");
+
+  // If any of the above ever fails, add tests here!
+}
+
+function test()
+{
+  try
+  {
+    startTests();
+    middleTests();
+    endTests();
+    entityTests();
+  }
+  catch (e)
+  {
+    ok(false, "exception thrown: " + e);
+  }
+  finally
+  {
+    SimpleTest.finish();
+  }
+}
+
+window.addEventListener("load", test, false);
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_text_wholeText.html
@@ -0,0 +1,249 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=421765
+-->
+<head>
+  <title>Text.wholeText tests</title>
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=421765">Mozilla Bug 421765</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+
+<iframe id="xmlDocument" src="wholeTexty-helper.xml"></iframe>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 421765 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var xmlDoc;
+
+function entity(n) { return xmlDoc.createEntityReference(n); }
+function text(t) { return document.createTextNode(t); }
+function element() { return document.createElement("div"); }
+function cdata(t)
+{
+  xmlDoc = $("xmlDocument").contentDocument;
+  // document.createCDATASection isn't implemented; clone for the win
+  var node = xmlDoc.documentElement.firstChild.cloneNode(false);
+  is(node.nodeType, Node.CDATA_SECTION_NODE,
+     "er, why isn't this a CDATA section node?");
+  node.data = t;
+  return node;
+}
+
+
+function firstTests()
+{
+  var outer = element();
+  var first = text("first");
+  var second = element();
+  second.appendChild(text("element contents"));
+  outer.appendChild(first);
+  outer.appendChild(second);
+
+  is(first.wholeText, "first", "wrong wholeText for first");
+
+  var insertedText = text("-continued");
+  outer.insertBefore(insertedText, second);
+
+  is(first.wholeText, "first-continued",
+     "wrong wholeText for first after insertedText insertion");
+  is(insertedText.wholeText, "first-continued",
+     "wrong wholeText for insertedText after insertedText insertion");
+
+  var cdataNode = cdata("zero-")
+  outer.insertBefore(cdataNode, first);
+
+  is(first.wholeText, "zero-first-continued",
+     "wrong wholeText for first after cdataNode insertion");
+  is(cdataNode.wholeText, "zero-first-continued",
+     "wrong wholeText for cdataNode after cdataNode insertion");
+  is(insertedText.wholeText, "zero-first-continued",
+     "wrong wholeText for insertedText after cdataNode insertion");
+
+  outer.insertBefore(element(), first);
+
+  is(first.wholeText, "first-continued",
+     "wrong wholeText for first after element insertion");
+  is(cdataNode.wholeText, "zero-",
+     "wrong wholeText for cdataNode after element insertion");
+  is(insertedText.wholeText, "first-continued",
+     "wrong wholeText for insertedText after element insertion");
+
+  var cdataNode2 = cdata("-interrupted");
+  outer.insertBefore(cdataNode2, insertedText);
+
+  is(first.wholeText, "first-interrupted-continued",
+     "wrong wholeText for first after cdataNode2 insertion");
+  is(cdataNode2.wholeText, "first-interrupted-continued",
+     "wrong wholeText for cdataNode2 after cdataNode2 insertion");
+  is(insertedText.wholeText, "first-interrupted-continued",
+     "wrong wholeText for insertedText after cdataNode2 insertion");
+}
+
+function middleTests()
+{
+  var outer = element();
+  var first = element();
+  var last = element();
+  var middle = text("middle");
+  first.appendChild(text("first element contents"));
+  last.appendChild(text("last element contents"));
+  outer.appendChild(first);
+  outer.appendChild(middle);
+  outer.appendChild(last);
+
+  is(middle.wholeText, "middle", "wrong wholeText for middle");
+
+  var beforeMiddle = text("before-");
+  outer.insertBefore(beforeMiddle, middle);
+
+  is(middle.wholeText, "before-middle",
+     "wrong wholeText for middle after beforeMiddle insertion");
+  is(beforeMiddle.wholeText, "before-middle",
+     "wrong wholeText for beforeMiddle after beforeMiddle insertion");
+
+  var midElement = element();
+  midElement.appendChild(text("middle element"));
+  outer.insertBefore(midElement, middle);
+
+  is(middle.wholeText, "middle",
+     "wrong wholeText for middle after midElement insertion");
+  is(beforeMiddle.wholeText, "before-",
+     "wrong wholeText for beforeMiddle after midElement insertion");
+
+  var cdataNode = cdata("after");
+  outer.insertBefore(cdataNode, midElement);
+
+  is(cdataNode.wholeText, "before-after",
+     "wrong wholeText for cdataNode after cdataNode insertion");
+  is(beforeMiddle.wholeText, "before-after",
+     "wrong wholeText for beforeMiddle after cdataNode insertion");
+  is(middle.wholeText, "middle",
+     "wrong wholeText for middle after cdataNode insertion");
+
+  var cdataNode2 = cdata("before-");
+  outer.insertBefore(cdataNode2, middle);
+
+  is(cdataNode.wholeText, "before-after",
+     "wrong wholeText for cdataNode after cdataNode2 insertion");
+  is(beforeMiddle.wholeText, "before-after",
+     "wrong wholeText for beforeMiddle after cdataNode2 insertion");
+  is(cdataNode2.wholeText, "before-middle",
+     "wrong wholeText for middle after cdataNode2 insertion");
+  is(middle.wholeText, "before-middle",
+     "wrong wholeText for middle after cdataNode2 insertion");
+}
+
+function lastTests()
+{
+  var outer = element();
+  var first = element();
+  var second = text("second");
+  first.appendChild(text("element contents"));
+  outer.appendChild(first);
+  outer.appendChild(second);
+
+  is(second.wholeText, "second", "wrong wholeText for second");
+
+  var insertedText = text("before-");
+  outer.insertBefore(insertedText, second);
+
+  is(second.wholeText, "before-second",
+     "wrong wholeText for second after insertedText insertion");
+  is(insertedText.wholeText, "before-second",
+     "wrong wholeText for insertedText after insertedText insertion");
+
+  var cdataNode = cdata("zero-")
+  outer.insertBefore(cdataNode, insertedText);
+
+  is(cdataNode.wholeText, "zero-before-second",
+     "wrong wholeText for cdataNode after cdataNode insertion");
+  is(second.wholeText, "zero-before-second",
+     "wrong wholeText for second after cdataNode insertion");
+  is(insertedText.wholeText, "zero-before-second",
+     "wrong wholeText for insertedText after cdataNode insertion");
+
+  outer.insertBefore(element(), second);
+
+  is(second.wholeText, "second",
+     "wrong wholeText for second after element insertion");
+  is(cdataNode.wholeText, "zero-before-",
+     "wrong wholeText for cdataNode after element insertion");
+  is(insertedText.wholeText, "zero-before-",
+     "wrong wholeText for insertedText after element insertion");
+
+  var cdataNode2 = cdata("interrupted-");
+  outer.insertBefore(cdataNode2, insertedText);
+
+  is(second.wholeText, "second",
+     "wrong wholeText for second after cdataNode2 insertion");
+  is(cdataNode2.wholeText, "zero-interrupted-before-",
+     "wrong wholeText for cdataNode2 after cdataNode2 insertion");
+  is(insertedText.wholeText, "zero-interrupted-before-",
+     "wrong wholeText for insertedText after cdataNode2 insertion");
+}
+
+function noParentTests()
+{
+  var textNode = text("foobar");
+  is(textNode.wholeText, textNode.data,
+     "orphaned textNode should have wholeText == data");
+  is(textNode.wholeText, "foobar",
+     "orphaned textNode should have wholeText == 'foobar'");
+
+  var cdataSection = cdata("baz");
+  is(cdataSection.wholeText, cdataSection.data,
+     "orphaned cdatasection should have wholeText == data");
+  is(cdataSection.wholeText, "baz",
+     "orphaned cdatasection should have wholeText == data");
+}
+
+function entityTests()
+{
+  todo_isnot(entity("bar"), null,
+             "need implementation update if we ever support entity nodes!");
+
+  var root = xmlDoc.documentElement;
+  is(root.lastChild.firstChild.nodeType, Node.TEXT_NODE,
+     "uh-oh, did we start supporting entity references as nodes?");
+  is(root.lastChild.lastChild.nodeType, Node.ELEMENT_NODE,
+     "uh-oh, did we start supporting entity references as nodes?");
+
+  // If any of the above ever fails, add tests here!
+}
+
+function tests()
+{
+  try
+  {
+    firstTests();
+    middleTests();
+    lastTests();
+    noParentTests();
+    entityTests();
+  }
+  catch (e)
+  {
+    ok(false, "error thrown: " + e);
+  }
+  finally
+  {
+    SimpleTest.finish();
+  }
+}
+
+window.addEventListener("load", tests, false);
+</script>
+</pre>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/content/base/test/wholeTexty-helper.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<!DOCTYPE document
+  [
+    <!ENTITY foobar "baz<quux/>">
+  ]>
+<document><![CDATA[]]><entity>&foobar;</entity></document>
--- a/content/canvas/public/nsICanvasRenderingContextInternal.h
+++ b/content/canvas/public/nsICanvasRenderingContextInternal.h
@@ -72,14 +72,20 @@ public:
   // composited on black.
   NS_IMETHOD GetInputStream(const char *aMimeType,
                             const PRUnichar *aEncoderOptions,
                             nsIInputStream **aStream) = 0;
 
   // If this canvas context can be represented with a simple Thebes surface,
   // return the surface.  Otherwise returns an error.
   NS_IMETHOD GetThebesSurface(gfxASurface **surface) = 0;
+
+  // If this context is opaque, the backing store of the canvas should
+  // be created as opaque; all compositing operators should assume the
+  // dst alpha is always 1.0.  If this is never called, the context
+  // defaults to false (not opaque).
+  NS_IMETHOD SetIsOpaque(PRBool isOpaque) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsICanvasRenderingContextInternal,
                               NS_ICANVASRENDERINGCONTEXTINTERNAL_IID)
 
 #endif /* nsICanvasRenderingContextInternal_h___ */
--- a/content/canvas/src/Makefile.in
+++ b/content/canvas/src/Makefile.in
@@ -81,9 +81,13 @@ 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
 
 CXXFLAGS	+= $(MOZ_CAIRO_CFLAGS) $(TK_CFLAGS)
 
+INCLUDES	+= \
+		-I$(srcdir)/../../../layout/style \
+		$(NULL)
+
 DEFINES += -D_IMPL_NS_LAYOUT
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -64,16 +64,17 @@
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIImage.h"
 #include "nsIFrame.h"
 #include "nsDOMError.h"
 #include "nsIScriptError.h"
 
 #include "nsICSSParser.h"
 #include "nsICSSStyleRule.h"
+#include "nsInspectorCSSUtils.h"
 #include "nsStyleSet.h"
 
 #include "nsPrintfCString.h"
 
 #include "nsReadableUtils.h"
 
 #include "nsColor.h"
 #include "nsIRenderingContext.h"
@@ -270,16 +271,53 @@ NS_IMPL_RELEASE(nsCanvasPattern)
 NS_INTERFACE_MAP_BEGIN(nsCanvasPattern)
   NS_INTERFACE_MAP_ENTRY(nsCanvasPattern)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCanvasPattern)
   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CanvasPattern)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 /**
+ ** nsTextMetrics
+ **/
+#define NS_TEXTMETRICS_PRIVATE_IID \
+    { 0xc5b1c2f9, 0xcb4f, 0x4394, { 0xaf, 0xe0, 0xc6, 0x59, 0x33, 0x80, 0x8b, 0xf3 } }
+class nsTextMetrics : public nsIDOMTextMetrics
+{
+public:
+    nsTextMetrics(float w) : width(w) { }
+
+    virtual ~nsTextMetrics() { }
+
+    NS_DECLARE_STATIC_IID_ACCESSOR(NS_TEXTMETRICS_PRIVATE_IID)
+
+    NS_IMETHOD GetWidth(float* w) {
+        *w = width;
+        return NS_OK;
+    }
+
+    NS_DECL_ISUPPORTS
+
+private:
+    float width;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsTextMetrics, NS_TEXTMETRICS_PRIVATE_IID)
+
+NS_IMPL_ADDREF(nsTextMetrics)
+NS_IMPL_RELEASE(nsTextMetrics)
+
+NS_INTERFACE_MAP_BEGIN(nsTextMetrics)
+  NS_INTERFACE_MAP_ENTRY(nsTextMetrics)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMTextMetrics)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(TextMetrics)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+/**
  ** nsCanvasRenderingContext2D
  **/
 class nsCanvasRenderingContext2D :
     public nsIDOMCanvasRenderingContext2D,
     public nsICanvasRenderingContextInternal
 {
 public:
     nsCanvasRenderingContext2D();
@@ -291,16 +329,17 @@ public:
     // nsICanvasRenderingContextInternal
     NS_IMETHOD SetCanvasElement(nsICanvasElement* aParentCanvas);
     NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height);
     NS_IMETHOD Render(gfxContext *ctx);
     NS_IMETHOD GetInputStream(const char* aMimeType,
                               const PRUnichar* aEncoderOptions,
                               nsIInputStream **aStream);
     NS_IMETHOD GetThebesSurface(gfxASurface **surface);
+    NS_IMETHOD SetIsOpaque(PRBool isOpaque);
 
     // nsISupports interface
     NS_DECL_ISUPPORTS
 
     // nsIDOMCanvasRenderingContext2D interface
     NS_DECL_NSIDOMCANVASRENDERINGCONTEXT2D
 
 protected:
@@ -329,48 +368,87 @@ protected:
     // data.  If forceWriteOnly is set, we force write only to be set
     // and ignore aPrincipal.  (This is used for when the original data came
     // from a <canvas> that had write-only set.)
     void DoDrawImageSecurityCheck(nsIPrincipal* aPrincipal,
                                   PRBool forceWriteOnly);
 
     // Member vars
     PRInt32 mWidth, mHeight;
-    PRBool mValid;
+    PRPackedBool mValid;
+    PRPackedBool mOpaque;
 
     // the canvas element informs us when it's going away,
     // so these are not nsCOMPtrs
     nsICanvasElement* mCanvasElement;
 
     // our CSS parser, for colors and whatnot
     nsCOMPtr<nsICSSParser> mCSSParser;
 
     // yay cairo
     nsRefPtr<gfxContext> mThebesContext;
     nsRefPtr<gfxASurface> mThebesSurface;
 
     PRUint32 mSaveCount;
     cairo_t *mCairo;
     cairo_surface_t *mSurface;
 
-    nsString mTextStyle;
-    nsRefPtr<gfxFontGroup> mFontGroup;
+    // text
+    enum TextAlign {
+        TEXT_ALIGN_START,
+        TEXT_ALIGN_END,
+        TEXT_ALIGN_LEFT,
+        TEXT_ALIGN_RIGHT,
+        TEXT_ALIGN_CENTER
+    };
+
+    enum TextBaseline {
+        TEXT_BASELINE_TOP,
+        TEXT_BASELINE_HANGING,
+        TEXT_BASELINE_MIDDLE,
+        TEXT_BASELINE_ALPHABETIC,
+        TEXT_BASELINE_IDEOGRAPHIC,
+        TEXT_BASELINE_BOTTOM
+    };
+
     gfxFontGroup *GetCurrentFontStyle();
+
+    enum TextDrawOperation {
+        TEXT_DRAW_OPERATION_FILL,
+        TEXT_DRAW_OPERATION_STROKE
+    };
+
+    /*
+     * Implementation of the fillText and strokeText functions with the
+     * operation abstracted to a flag. Follows the HTML 5 spec for rendering
+     * text. Will query for the fourth, optional argument.
+     */
+    nsresult drawText(const nsAString& text,
+                      float x,
+                      float y,
+                      float maxWidth,
+                      TextDrawOperation op);
  
     // style handling
     PRInt32 mLastStyle;
     PRPackedBool mDirtyStyle[STYLE_MAX];
 
     // state stack handling
     class ContextState {
     public:
-        ContextState() : globalAlpha(1.0) { }
+        ContextState() : globalAlpha(1.0),
+                         textAlign(TEXT_ALIGN_START),
+                         textBaseline(TEXT_BASELINE_ALPHABETIC) { }
 
         ContextState(const ContextState& other)
-            : globalAlpha(other.globalAlpha)
+            : globalAlpha(other.globalAlpha),
+              font(other.font),
+              fontGroup(other.fontGroup),
+              textAlign(other.textAlign),
+              textBaseline(other.textBaseline)
         {
             for (int i = 0; i < STYLE_MAX; i++) {
                 colorStyles[i] = other.colorStyles[i];
                 gradientStyles[i] = other.gradientStyles[i];
                 patternStyles[i] = other.patternStyles[i];
             }
         }
 
@@ -386,16 +464,22 @@ protected:
         }
 
         inline void SetGradientStyle(int whichStyle, nsCanvasGradient* grad) {
             gradientStyles[whichStyle] = grad;
             patternStyles[whichStyle] = nsnull;
         }
 
         float globalAlpha;
+
+        nsString font;
+        nsRefPtr<gfxFontGroup> fontGroup;
+        TextAlign textAlign;
+        TextBaseline textBaseline;
+
         nscolor colorStyles[STYLE_MAX];
         nsCOMPtr<nsCanvasGradient> gradientStyles[STYLE_MAX];
         nsCOMPtr<nsCanvasPattern> patternStyles[STYLE_MAX];
     };
 
     nsTArray<ContextState> mStyleStack;
 
     inline ContextState& CurrentState() {
@@ -465,17 +549,17 @@ NS_NewCanvasRenderingContext2D(nsIDOMCan
     if (!ctx)
         return NS_ERROR_OUT_OF_MEMORY;
 
     NS_ADDREF(*aResult = ctx);
     return NS_OK;
 }
 
 nsCanvasRenderingContext2D::nsCanvasRenderingContext2D()
-    : mValid(PR_FALSE), mCanvasElement(nsnull),
+    : mValid(PR_FALSE), mOpaque(PR_FALSE), mCanvasElement(nsnull),
       mSaveCount(0), mCairo(nsnull), mSurface(nsnull), mStyleStack(20)
 {
 }
 
 nsCanvasRenderingContext2D::~nsCanvasRenderingContext2D()
 {
     Destroy();
 }
@@ -680,17 +764,22 @@ nsCanvasRenderingContext2D::SetDimension
 {
     Destroy();
 
     mWidth = width;
     mHeight = height;
 
     // Check that the dimensions are sane
     if (gfxASurface::CheckSurfaceSize(gfxIntSize(width, height), 0xffff)) {
-        mThebesSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(width, height), gfxASurface::ImageFormatARGB32);
+        gfxASurface::gfxImageFormat format = gfxASurface::ImageFormatARGB32;
+        if (mOpaque)
+            format = gfxASurface::ImageFormatRGB24;
+
+        mThebesSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface
+            (gfxIntSize(width, height), format);
 
         if (mThebesSurface->CairoStatus() == 0) {
             mThebesContext = new gfxContext(mThebesSurface);
         }
     }
 
     /* Create dummy surfaces here */
     if (mThebesSurface == nsnull || mThebesSurface->CairoStatus() != 0 ||
@@ -727,38 +816,63 @@ nsCanvasRenderingContext2D::SetDimension
     cairo_set_miter_limit(mCairo, 10.0);
     cairo_set_line_cap(mCairo, CAIRO_LINE_CAP_BUTT);
     cairo_set_line_join(mCairo, CAIRO_LINE_JOIN_MITER);
 
     cairo_new_path(mCairo);
 
     return NS_OK;
 }
+
+NS_IMETHODIMP
+nsCanvasRenderingContext2D::SetIsOpaque(PRBool isOpaque)
+{
+    if (isOpaque == mOpaque)
+        return NS_OK;
+
+    mOpaque = isOpaque;
+
+    if (mValid) {
+        /* If we've already been created, let SetDimensions take care of
+         * recreating our surface
+         */
+        return SetDimensions(mWidth, mHeight);
+    }
+
+    return NS_OK;
+}
  
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Render(gfxContext *ctx)
 {
     nsresult rv = NS_OK;
 
     if (!mValid || !mSurface || !mCairo ||
         cairo_surface_status(mSurface) != CAIRO_STATUS_SUCCESS ||
         cairo_status(mCairo) != CAIRO_STATUS_SUCCESS)
         return NS_ERROR_FAILURE;
 
     if (!mThebesSurface)
         return NS_ERROR_FAILURE;
 
     nsRefPtr<gfxPattern> pat = new gfxPattern(mThebesSurface);
 
+    gfxContext::GraphicsOperator op = ctx->CurrentOperator();
+    if (mOpaque)
+        ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
+
     // XXX I don't want to use PixelSnapped here, but layout doesn't guarantee
     // pixel alignment for this stuff!
     ctx->NewPath();
     ctx->PixelSnappedRectangleAndSetPattern(gfxRect(0, 0, mWidth, mHeight), pat);
     ctx->Fill();
 
+    if (mOpaque)
+        ctx->SetOperator(op);
+
     return rv;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetInputStream(const char *aMimeType,
                                            const PRUnichar *aEncoderOptions,
                                            nsIInputStream **aStream)
 {
@@ -1451,106 +1565,544 @@ nsCanvasRenderingContext2D::Rect(float x
 
     cairo_rectangle (mCairo, x, y, w, h);
     return NS_OK;
 }
 
 //
 // text
 //
-NS_IMETHODIMP
-nsCanvasRenderingContext2D::SetMozTextStyle(const nsAString& textStyle)
+
+/**
+ * Helper function for SetFont that creates a style rule for the given font.
+ * @param aFont The CSS font string
+ * @param aCSSParser The CSS parser of the canvas rendering context
+ * @param aNode The canvas element
+ * @param aResult Pointer in which to place the new style rule.
+ * @remark Assumes all pointer arguments are non-null.
+ */
+static nsresult
+CreateFontStyleRule(const nsAString& aFont,
+                    nsICSSParser* aCSSParser,
+                    nsINode* aNode,
+                    nsICSSStyleRule** aResult)
 {
-    if(mTextStyle.Equals(textStyle)) return NS_OK;
-
-    nsCOMPtr<nsINode> elem = do_QueryInterface(mCanvasElement);
-    if (!elem) {
-        NS_WARNING("Canvas element must be an nsINode and non-null");
+    nsresult rv;
+
+    nsCOMPtr<nsICSSStyleRule> rule;
+    PRBool changed;
+
+    nsIPrincipal* principal = aNode->NodePrincipal();
+    nsIDocument* document = aNode->GetOwnerDoc();
+
+    nsIURI* docURL = document->GetDocumentURI();
+    nsIURI* baseURL = document->GetBaseURI();
+
+    rv = aCSSParser->ParseStyleAttribute(
+            EmptyString(),
+            docURL,
+            baseURL,
+            principal,
+            getter_AddRefs(rule));
+    if (NS_FAILED(rv))
+        return rv;
+
+    rv = aCSSParser->ParseProperty(eCSSProperty_font,
+                                   aFont,
+                                   docURL,
+                                   baseURL,
+                                   principal,
+                                   rule->GetDeclaration(),
+                                   &changed);
+    if (NS_FAILED(rv))
+        return rv;
+
+    // set line height to normal, as per spec
+    rv = aCSSParser->ParseProperty(eCSSProperty_line_height,
+                                   NS_LITERAL_STRING("normal"),
+                                   docURL,
+                                   baseURL,
+                                   principal,
+                                   rule->GetDeclaration(),
+                                   &changed);
+    if (NS_FAILED(rv))
+        return rv;
+
+    rule.forget(aResult);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCanvasRenderingContext2D::SetFont(const nsAString& font)
+{
+    nsresult rv;
+
+    /*
+     * If font is defined with relative units (e.g. ems) and the parent
+     * style context changes in between calls, setting the font to the
+     * same value as previous could result in a different computed value,
+     * so we cannot have the optimization where we check if the new font
+     * string is equal to the old one.
+     */
+
+    nsCOMPtr<nsIContent> content = do_QueryInterface(mCanvasElement);
+    if (!content) {
+        NS_WARNING("Canvas element must be an nsIContent and non-null");
         return NS_ERROR_FAILURE;
     }
 
-    nsIPrincipal* elemPrincipal = elem->NodePrincipal();
-    nsIDocument* elemDocument = elem->GetOwnerDoc();
-
-    if (!elemDocument || !elemPrincipal) {
-        NS_WARNING("Element is missing document or principal");
-        return NS_ERROR_FAILURE;
-    }
-
-    nsIPresShell* presShell = elemDocument->GetPrimaryShell();
+    nsIDocument* document = content->GetOwnerDoc();
+
+    nsIPresShell* presShell = document->GetPrimaryShell();
     if (!presShell)
         return NS_ERROR_FAILURE;
 
-    nsIURI *docURL = elemDocument->GetDocumentURI();
-    nsIURI *baseURL = elemDocument->GetBaseURI();
-
     nsCString langGroup;
     presShell->GetPresContext()->GetLangGroup()->ToUTF8String(langGroup);
 
     nsCOMArray<nsIStyleRule> rules;
-    PRBool changed;
 
     nsCOMPtr<nsICSSStyleRule> rule;
-    mCSSParser->ParseStyleAttribute(
-            EmptyString(),
-            docURL,
-            baseURL,
-            elemPrincipal,
-            getter_AddRefs(rule));
-
-    mCSSParser->ParseProperty(eCSSProperty_font,
-                              textStyle,
-                              docURL,
-                              baseURL,
-                              elemPrincipal,
-                              rule->GetDeclaration(),
-                              &changed);
+    rv = CreateFontStyleRule(font, mCSSParser.get(), content.get(), getter_AddRefs(rule));
+    if (NS_FAILED(rv))
+        return rv;
 
     rules.AppendObject(rule);
 
-    nsStyleSet *styleSet = presShell->StyleSet();
-
-    nsRefPtr<nsStyleContext> sc = styleSet->ResolveStyleForRules(nsnull,rules);
+    nsStyleSet* styleSet = presShell->StyleSet();
+
+    // have to get a parent style context for inherit-like relative
+    // values (2em, bolder, etc.)
+    nsRefPtr<nsStyleContext> parentContext;
+
+    if (content->IsInDoc()) {
+        // inherit from the canvas element
+        parentContext = nsInspectorCSSUtils::GetStyleContextForContent(
+                content,
+                nsnull,
+                presShell);
+    } else {
+        // otherwise inherit from default (10px sans-serif)
+        nsCOMPtr<nsICSSStyleRule> parentRule;
+        rv = CreateFontStyleRule(NS_LITERAL_STRING("10px sans-serif"),
+                                 mCSSParser.get(),
+                                 content.get(),
+                                 getter_AddRefs(parentRule));
+        if (NS_FAILED(rv))
+            return rv;
+        nsCOMArray<nsIStyleRule> parentRules;
+        parentRules.AppendObject(parentRule);
+        parentContext = styleSet->ResolveStyleForRules(nsnull, parentRules);
+    }
+
+    if (!parentContext)
+        return NS_ERROR_FAILURE;
+
+    nsRefPtr<nsStyleContext> sc = styleSet->ResolveStyleForRules(parentContext, rules);
+    if (!sc)
+        return NS_ERROR_FAILURE;
     const nsStyleFont *fontStyle = sc->GetStyleFont();
 
     NS_ASSERTION(fontStyle, "Could not obtain font style");
 
     PRUint32 aupdp = presShell->GetPresContext()->AppUnitsPerDevPixel();
 
     gfxFontStyle style(fontStyle->mFont.style,
                        fontStyle->mFont.weight,
                        NSAppUnitsToFloatPixels(fontStyle->mFont.size,aupdp),
                        langGroup,
                        fontStyle->mFont.sizeAdjust,
                        fontStyle->mFont.systemFont,
                        fontStyle->mFont.familyNameQuirks);
 
-    mFontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(fontStyle->mFont.name, &style);
-    NS_ASSERTION(mFontGroup, "Could not get font group");
-    mTextStyle = textStyle;
+    CurrentState().fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(fontStyle->mFont.name, &style);
+    NS_ASSERTION(CurrentState().fontGroup, "Could not get font group");
+    CurrentState().font = font;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCanvasRenderingContext2D::GetFont(nsAString& font)
+{
+    /* will initilize the value if not set, else does nothing */
+    GetCurrentFontStyle();
+
+    font = CurrentState().font;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCanvasRenderingContext2D::SetTextAlign(const nsAString& ta)
+{
+    if (ta.EqualsLiteral("start"))
+        CurrentState().textAlign = TEXT_ALIGN_START;
+    else if (ta.EqualsLiteral("end"))
+        CurrentState().textAlign = TEXT_ALIGN_END;
+    else if (ta.EqualsLiteral("left"))
+        CurrentState().textAlign = TEXT_ALIGN_LEFT;
+    else if (ta.EqualsLiteral("right"))
+        CurrentState().textAlign = TEXT_ALIGN_RIGHT;
+    else if (ta.EqualsLiteral("center"))
+        CurrentState().textAlign = TEXT_ALIGN_CENTER;
+    // spec says to not throw error for invalid arg, but do it anyway
+    else
+        return NS_ERROR_INVALID_ARG;
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCanvasRenderingContext2D::GetTextAlign(nsAString& ta)
+{
+    switch (CurrentState().textAlign)
+    {
+    case TEXT_ALIGN_START:
+        ta.AssignLiteral("start");
+        break;
+    case TEXT_ALIGN_END:
+        ta.AssignLiteral("end");
+        break;
+    case TEXT_ALIGN_LEFT:
+        ta.AssignLiteral("left");
+        break;
+    case TEXT_ALIGN_RIGHT:
+        ta.AssignLiteral("right");
+        break;
+    case TEXT_ALIGN_CENTER:
+        ta.AssignLiteral("center");
+        break;
+    default:
+        NS_ASSERTION(0, "textAlign holds invalid value");
+        return NS_ERROR_FAILURE;
+    }
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCanvasRenderingContext2D::SetTextBaseline(const nsAString& tb)
+{
+    if (tb.EqualsLiteral("top"))
+        CurrentState().textBaseline = TEXT_BASELINE_TOP;
+    else if (tb.EqualsLiteral("hanging"))
+        CurrentState().textBaseline = TEXT_BASELINE_HANGING;
+    else if (tb.EqualsLiteral("middle"))
+        CurrentState().textBaseline = TEXT_BASELINE_MIDDLE;
+    else if (tb.EqualsLiteral("alphabetic"))
+        CurrentState().textBaseline = TEXT_BASELINE_ALPHABETIC;
+    else if (tb.EqualsLiteral("ideographic"))
+        CurrentState().textBaseline = TEXT_BASELINE_IDEOGRAPHIC;
+    else if (tb.EqualsLiteral("bottom"))
+        CurrentState().textBaseline = TEXT_BASELINE_BOTTOM;
+    // spec says to not throw error for invalid arg, but do it anyway
+    else
+        return NS_ERROR_INVALID_ARG;
+    
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCanvasRenderingContext2D::GetTextBaseline(nsAString& tb)
+{
+    switch (CurrentState().textBaseline)
+    {
+    case TEXT_BASELINE_TOP:
+        tb.AssignLiteral("top");
+        break;
+    case TEXT_BASELINE_HANGING:
+        tb.AssignLiteral("hanging");
+        break;
+    case TEXT_BASELINE_MIDDLE:
+        tb.AssignLiteral("middle");
+        break;
+    case TEXT_BASELINE_ALPHABETIC:
+        tb.AssignLiteral("alphabetic");
+        break;
+    case TEXT_BASELINE_IDEOGRAPHIC:
+        tb.AssignLiteral("ideographic");
+        break;
+    case TEXT_BASELINE_BOTTOM:
+        tb.AssignLiteral("bottom");
+        break;
+    default:
+        NS_ASSERTION(0, "textBaseline holds invalid value");
+        return NS_ERROR_FAILURE;
+    }
+
     return NS_OK;
 }
 
+/*
+ * Helper function that replaces the whitespace characters in a string
+ * with U+0020 SPACE. The whitespace characters are defined as U+0020 SPACE,
+ * U+0009 CHARACTER TABULATION (tab), U+000A LINE FEED (LF), U+000B LINE
+ * TABULATION, U+000C FORM FEED (FF), and U+000D CARRIAGE RETURN (CR).
+ * @param str The string whose whitespace characters to replace.
+ */
+static inline void
+TextReplaceWhitespaceCharacters(nsAutoString& str)
+{
+    str.ReplaceChar("\x09\x0A\x0B\x0C\x0D", PRUnichar(' '));
+}
+
+NS_IMETHODIMP
+nsCanvasRenderingContext2D::FillText(const nsAString& text, float x, float y, float maxWidth)
+{
+    return drawText(text, x, y, maxWidth, TEXT_DRAW_OPERATION_FILL);
+}
+
+NS_IMETHODIMP
+nsCanvasRenderingContext2D::StrokeText(const nsAString& text, float x, float y, float maxWidth)
+{
+    return drawText(text, x, y, maxWidth, TEXT_DRAW_OPERATION_STROKE);
+}
+
+nsresult
+nsCanvasRenderingContext2D::drawText(const nsAString& rawText,
+                                     float x,
+                                     float y,
+                                     float maxWidth,
+                                     TextDrawOperation op)
+{
+    if (!FloatValidate(x, y, maxWidth))
+        return NS_ERROR_DOM_SYNTAX_ERR;
+
+    // spec isn't clear on what should happen if maxWidth <= 0, so
+    // treat it as an invalid argument
+    // technically, 0 should be an invalid value as well, but 0 is the default
+    // arg, and there is no way to tell if the default was used
+    if (maxWidth < 0)
+        return NS_ERROR_INVALID_ARG;
+
+    gfxFontGroup* fontgrp = GetCurrentFontStyle();
+    NS_ASSERTION(fontgrp, "font group is null");
+
+    nsCOMPtr<nsIContent> content = do_QueryInterface(mCanvasElement);
+    if (!content) {
+        NS_WARNING("Canvas element must be an nsIContent and non-null");
+        return NS_ERROR_FAILURE;
+    }
+
+    nsIDocument* document = content->GetOwnerDoc();
+
+    nsIPresShell* presShell = document->GetPrimaryShell();
+    if (!presShell)
+        return NS_ERROR_FAILURE;
+
+    // replace all the whitespace characters with U+0020 SPACE
+    nsAutoString textToDraw(rawText);
+    TextReplaceWhitespaceCharacters(textToDraw);
+
+    const PRUnichar* textData;
+    textToDraw.GetData(&textData);
+  
+    // for now, default to ltr if not in doc
+    PRBool isRTL = PR_FALSE;
+    
+    if (content->IsInDoc()) {
+        // try to find the closest context
+        nsRefPtr<nsStyleContext> canvasStyle =
+            nsInspectorCSSUtils::GetStyleContextForContent(content,
+                                                           nsnull,
+                                                           presShell);
+        if (!canvasStyle)
+            return NS_ERROR_FAILURE;
+        isRTL = canvasStyle->GetStyleVisibility()->mDirection ==
+            NS_STYLE_DIRECTION_RTL;
+    }
+
+    PRUint32 textrunflags = isRTL ? gfxTextRunFactory::TEXT_IS_RTL : 0;
+
+    // app units conversion factor
+    PRUint32 aupdp;
+    GetAppUnitsValues(&aupdp, NULL);
+
+    gfxTextRunCache::AutoTextRun textRun;
+    textRun = gfxTextRunCache::MakeTextRun(textData,
+                                           textToDraw.Length(),
+                                           fontgrp,
+                                           mThebesContext,
+                                           aupdp,
+                                           textrunflags);
+
+    if (!textRun.get())
+        return NS_ERROR_FAILURE;
+
+    gfxPoint pt(x, y);
+    
+    // get the text width
+    PRBool tightBoundingBox = PR_FALSE;
+    gfxTextRun::Metrics textRunMetrics = textRun->MeasureText(/* offset = */ 0,
+                                                       textToDraw.Length(),
+                                                       tightBoundingBox,
+                                                       mThebesContext,
+                                                       nsnull);
+    gfxFloat textWidth = textRunMetrics.mAdvanceWidth/gfxFloat(aupdp);
+
+
+    // offset pt x based on text align
+    gfxFloat anchorX;
+
+    if (CurrentState().textAlign == TEXT_ALIGN_CENTER)
+        anchorX = .5;
+    else if (CurrentState().textAlign == TEXT_ALIGN_LEFT ||
+             (!isRTL && CurrentState().textAlign == TEXT_ALIGN_START) ||
+             (isRTL && CurrentState().textAlign == TEXT_ALIGN_END))
+        anchorX = 0;
+    else
+        anchorX = 1;
+
+    if (isRTL)
+        pt.x += (1 - anchorX) * textWidth;
+    else
+        pt.x -= anchorX * textWidth;
+
+    // offset pt y based on text baseline
+    NS_ASSERTION(fontgrp->FontListLength()>0, "font group contains no fonts");
+    const gfxFont::Metrics& fontMetrics = fontgrp->GetFontAt(0)->GetMetrics();
+
+    gfxFloat anchorY;
+
+    switch (CurrentState().textBaseline)
+    {
+    case TEXT_BASELINE_TOP:
+        anchorY = fontMetrics.emAscent;
+        break;
+    case TEXT_BASELINE_HANGING:
+        anchorY = 0; // currently unavailable
+        break;
+    case TEXT_BASELINE_MIDDLE:
+        anchorY = (fontMetrics.emAscent-fontMetrics.emDescent)*.5f;
+        break;
+    case TEXT_BASELINE_ALPHABETIC:
+        anchorY = 0;
+        break;
+    case TEXT_BASELINE_IDEOGRAPHIC:
+        anchorY = 0; // currently unvailable
+        break;
+    case TEXT_BASELINE_BOTTOM:
+        anchorY = -fontMetrics.emDescent;
+        break;
+    default:
+        NS_ASSERTION(0, "mTextBaseline holds invalid value");
+        return NS_ERROR_FAILURE;
+    }
+
+    pt.y += anchorY;
+
+    // if text is over maxWidth, then scale the text horizonally such that its
+    // width is precisely maxWidth
+    if (maxWidth>0 && textWidth > maxWidth) {
+        cairo_save(mCairo);
+        // translate the anchor point to 0, then scale and translate back
+        cairo_translate(mCairo, x, 0);
+        cairo_scale(mCairo, (float)(maxWidth/textWidth), 1);
+        cairo_translate(mCairo, -x, 0);
+    }
+
+    pt.x *= aupdp;
+    pt.y *= aupdp;
+
+    // stroke or fill depending on operation
+    if (op == TEXT_DRAW_OPERATION_STROKE) {
+        cairo_save(mCairo);
+        cairo_new_path(mCairo);
+        textRun->DrawToPath(mThebesContext,
+                            pt,
+                            /* offset = */ 0,
+                            textToDraw.Length(),
+                            nsnull,
+                            nsnull);
+        Stroke();
+        cairo_restore(mCairo);
+    } else {
+        NS_ASSERTION(op == TEXT_DRAW_OPERATION_FILL,
+            "operation should be FILL or STROKE");
+
+        ApplyStyle(STYLE_FILL);
+        textRun->Draw(mThebesContext,
+                      pt,
+                      /* offset = */ 0,
+                      textToDraw.Length(),
+                      nsnull,
+                      nsnull,
+                      nsnull);
+    }
+
+    // have to restore the context if was modified above
+    if (maxWidth>0 && textWidth > maxWidth)
+        cairo_restore(mCairo);
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCanvasRenderingContext2D::MeasureText(const nsAString& rawText,
+                                        nsIDOMTextMetrics** _retval)
+{
+    // replace all the whitespace characters with U+0020 SPACE
+    nsAutoString textToMeasure(rawText);
+    TextReplaceWhitespaceCharacters(textToMeasure);
+
+    const PRUnichar* textdata;
+    textToMeasure.GetData(&textdata);
+
+    PRUint32 textrunflags = 0;
+    PRUint32 aupdp;
+    GetAppUnitsValues(&aupdp, nsnull);
+
+    gfxTextRunCache::AutoTextRun textRun;
+    textRun = gfxTextRunCache::MakeTextRun(textdata,
+                                           textToMeasure.Length(),
+                                           GetCurrentFontStyle(),
+                                           mThebesContext,
+                                           aupdp,
+                                           textrunflags);
+
+    if(!textRun.get())
+        return NS_ERROR_FAILURE;
+
+    PRBool tightBoundingBox = PR_FALSE;
+    gfxTextRun::Metrics metrics = textRun->MeasureText(/* offset = */ 0, textToMeasure.Length(),
+                                                       tightBoundingBox, mThebesContext,
+                                                       nsnull);
+
+    float textWidth = float(metrics.mAdvanceWidth/gfxFloat(aupdp));
+
+    nsTextMetrics *textMetrics = new nsTextMetrics(textWidth);
+    if (!textMetrics)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    NS_ADDREF(*_retval = textMetrics);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsCanvasRenderingContext2D::SetMozTextStyle(const nsAString& textStyle)
+{
+    // font and mozTextStyle are the same value
+    return SetFont(textStyle);
+}
+
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetMozTextStyle(nsAString& textStyle)
 {
-    textStyle = mTextStyle;
-    return NS_OK;
+    // font and mozTextStyle are the same value
+    return GetFont(textStyle);
 }
 
 gfxFontGroup *nsCanvasRenderingContext2D::GetCurrentFontStyle()
 {
-    if(!mFontGroup)
-    {
-        nsString style;
-        style.AssignLiteral("12pt sans-serif");
-        nsresult res = SetMozTextStyle(style);
+    // use lazy initilization for the font group since it's rather expensive
+    if(!CurrentState().fontGroup) {
+        nsresult res = SetMozTextStyle(NS_LITERAL_STRING("10px sans-serif"));
         NS_ASSERTION(res == NS_OK, "Default canvas font is invalid");
     }
-    return mFontGroup;
+
+    return CurrentState().fontGroup;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::MozDrawText(const nsAString& textToDraw)
 {
     const PRUnichar* textdata;
     textToDraw.GetData(&textdata);
 
@@ -1583,40 +2135,22 @@ nsCanvasRenderingContext2D::MozDrawText(
                   nsnull,
                   nsnull);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::MozMeasureText(const nsAString& textToMeasure, float *retVal)
 {
-    const PRUnichar* textdata;
-    textToMeasure.GetData(&textdata);
-
-    PRUint32 textrunflags = 0;
-    PRUint32 aupdp, aupcp;
-    GetAppUnitsValues(&aupdp, &aupcp);
-
-    gfxTextRunCache::AutoTextRun textRun;
-    textRun = gfxTextRunCache::MakeTextRun(textdata,
-                                           textToMeasure.Length(),
-                                           GetCurrentFontStyle(),
-                                           mThebesContext,
-                                           aupdp,
-                                           textrunflags);
-
-    if(!textRun.get())
-        return NS_ERROR_FAILURE;
-
-    PRBool tightBoundingBox = PR_FALSE;
-    gfxTextRun::Metrics metrics = textRun->MeasureText(/* offset = */ 0, textToMeasure.Length(),
-                                                       tightBoundingBox, mThebesContext,
-                                                       nsnull);
-    *retVal = float(metrics.mAdvanceWidth/gfxFloat(aupcp));
-    return NS_OK;
+    nsCOMPtr<nsIDOMTextMetrics> metrics;
+    nsresult rv;
+    rv = MeasureText(textToMeasure, getter_AddRefs(metrics));
+    if (NS_FAILED(rv))
+        return rv;
+    return metrics->GetWidth(retVal);
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::MozPathText(const nsAString& textToPath)
 {
     const PRUnichar* textdata;
     textToPath.GetData(&textdata);
 
@@ -1680,16 +2214,20 @@ nsCanvasRenderingContext2D::MozTextAlong
         PathChar() : draw(PR_FALSE), angle(0.0), pos(0.0,0.0) {}
     };
 
     gfxFloat length = path->GetLength();
     PRUint32 strLength = textToDraw.Length();
 
     PathChar *cp = new PathChar[strLength];
 
+    if (!cp) {
+        return NS_ERROR_OUT_OF_MEMORY;
+    }
+
     gfxPoint position(0.0,0.0);
     gfxFloat x = position.x;
     for (PRUint32 i = 0; i < strLength; i++)
     {
         gfxFloat halfAdvance = textRun->GetAdvanceWidth(i, 1, nsnull) / (2.0 * aupdp);
 
         // Check for end of path
         if(x + halfAdvance > length)
--- a/content/canvas/test/Makefile.in
+++ b/content/canvas/test/Makefile.in
@@ -498,16 +498,21 @@ include $(topsrcdir)/config/rules.mk
 	image_green-redirect^headers^ \
 	image_ggrr-256x256.png \
 	image_yellow75.png \
 	image_broken.png \
 	image_rgrg-256x256.png \
 	image_red.png \
 	image_transparent.png \
 	image_green.png \
+	test_text.font.html \
+	test_text.textAlign.html \
+	test_text.textBaseline.html \
+	test_text.measure.html \
+	test_text.space.replace.html \
 	$(NULL)
 
 # This one test crashes Mac for now.  Bug 407104
 ifneq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 _TEST_FILES_E += \
 	test_2d.gradient.empty.html \
 	$(NULL)
 endif
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/test_text.font.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<title>Canvas test: text.font</title>
+<script src="/MochiKit/MochiKit.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+<body>
+<canvas id="c" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<script>
+var _deferred = false;
+
+SimpleTest.waitForExplicitFinish();
+MochiKit.DOM.addLoadEvent(function () {
+
+var canvas = document.getElementById('c');
+var ctx = canvas.getContext('2d');
+
+is(ctx.font, '10px sans-serif', "default font is not '10px sans-serif'");
+
+ctx.save();
+ctx.font = '20pt serif';
+is(ctx.font, '20pt serif', 'font getter returns incorrect value');
+
+ctx.restore();
+is(ctx.font, '10px sans-serif', 'font not being stored in the context state');
+
+if (!_deferred) SimpleTest.finish();
+});
+</script>
+
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/test_text.measure.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<title>Canvas test: text.measure</title>
+<script src="/MochiKit/MochiKit.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+<body>
+<canvas id="c" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<script>
+var _deferred = false;
+
+SimpleTest.waitForExplicitFinish();
+MochiKit.DOM.addLoadEvent(function () {
+
+var canvas = document.getElementById('c');
+var ctx = canvas.getContext('2d');
+
+ctx.font = "10px sans-serif";
+ctx.textAlign = "left";
+ctx.textBaseline = "top";
+
+var str = 'Test String';
+var wid = ctx.measureText(str).width;
+
+ok(wid > 0, "measureText returns nonpositive value for non-empty string");
+
+ctx.font = "20px sans-serif";
+isnot(wid, ctx.measureText(str).width, "measureText does not change with a different font size");
+
+ctx.font = "10px sans-serif";
+ctx.textAlign = "center";
+ctx.textBaseline = "alphabetic";
+
+is(wid, ctx.measureText(str).width, "measureText changes when alignement/baseline is changed");
+
+
+if (!_deferred) SimpleTest.finish();
+});
+</script>
+
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/test_text.space.replace.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<title>Canvas test: text.space.replace</title>
+<script src="/MochiKit/MochiKit.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+<body>
+<canvas id="c" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<script>
+var _deferred = false;
+
+SimpleTest.waitForExplicitFinish();
+MochiKit.DOM.addLoadEvent(function () {
+
+var canvas = document.getElementById('c');
+var ctx = canvas.getContext('2d');
+
+var swid = ctx.measureText(' ').width;
+ctx.font = "10px sans-serif";
+
+isnot(swid, 0.0, "measureText reutuns zero for a non-empty string");
+is(swid, ctx.measureText('\x09').width, "measureText does not replace whitespace char with a space");
+is(swid, ctx.measureText('\x0A').width, "measureText does not replace whitespace char with a space");
+is(swid, ctx.measureText('\x0B').width, "measureText does not replace whitespace char with a space");
+is(swid, ctx.measureText('\x0C').width, "measureText does not replace whitespace char with a space");
+is(swid, ctx.measureText('\x0D').width, "measureText does not replace whitespace char with a space");
+
+if (!_deferred) SimpleTest.finish();
+});
+</script>
+
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/test_text.textAlign.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<title>Canvas test: text.textAlign</title>
+<script src="/MochiKit/MochiKit.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+<body>
+<canvas id="c" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<script>
+var _deferred = false;
+
+SimpleTest.waitForExplicitFinish();
+MochiKit.DOM.addLoadEvent(function () {
+
+var canvas = document.getElementById('c');
+var ctx = canvas.getContext('2d');
+
+is(ctx.textAlign, 'start', "default textAlign is not 'start'");
+
+ctx.save();
+ctx.textAlign = 'end';
+is(ctx.textAlign, 'end', 'textAlign getter returns incorrect value');
+
+ctx.save();
+ctx.textAlign = 'left';
+is(ctx.textAlign, 'left', 'textAlign getter returns incorrect value');
+
+ctx.save();</