Merge m-c to maple
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 12 Mar 2012 10:41:42 -0400
changeset 91125 e88141f7f64cedd75b1f4304525b64e773e12aa0
parent 91124 1323e2abacce57f14bf4b3be0fcb8970aab19588 (current diff)
parent 90282 c6f26a8dcd084c38f63c282ba77c713c7573e549 (diff)
child 91126 e1a8ff015736d2debc4e602796f9d0baac224036
push idunknown
push userunknown
push dateunknown
milestone13.0a1
Merge m-c to maple
accessible/src/base/nsTextAttrs.cpp
accessible/src/base/nsTextAttrs.h
browser/app/profile/firefox.js
browser/devtools/debugger/debugger.js
browser/themes/gnomestripe/devtools/csshtmltree.css
browser/themes/gnomestripe/jar.mn
browser/themes/pinstripe/devtools/csshtmltree.css
browser/themes/pinstripe/jar.mn
browser/themes/winstripe/devtools/csshtmltree.css
browser/themes/winstripe/jar.mn
configure.in
content/base/public/nsContentUtils.h
content/base/public/nsIDOMFileError.idl
content/base/public/nsIDocument.h
content/base/src/nsAttrValue.cpp
content/base/src/nsContentUtils.cpp
content/base/src/nsDocument.cpp
content/base/src/nsGenericElement.cpp
content/base/src/nsGenericElement.h
content/html/content/src/nsGenericHTMLElement.h
content/html/content/src/nsHTMLLinkElement.cpp
content/html/document/src/nsHTMLDocument.cpp
dom/base/nsGlobalWindow.cpp
gfx/gl/GLContextProviderEGL.cpp
gfx/layers/ImageLayers.h
gfx/layers/basic/BasicLayers.cpp
gfx/layers/d3d10/ImageLayerD3D10.cpp
gfx/layers/d3d9/ImageLayerD3D9.cpp
gfx/layers/opengl/ImageLayerOGL.cpp
js/public/Utility.h
js/src/jsarray.cpp
js/xpconnect/src/xpcprivate.h
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsLayoutUtils.cpp
layout/generic/nsObjectFrame.cpp
layout/generic/nsSelection.cpp
layout/xul/base/src/nsBoxFrame.cpp
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -70,18 +70,18 @@ CPPSRCS = \
   nsBaseWidgetAccessible.cpp \
   nsEventShell.cpp \
   nsFormControlAccessible.cpp \
   nsRootAccessible.cpp \
   nsApplicationAccessible.cpp \
   nsCaretAccessible.cpp \
   nsTextAccessible.cpp \
   nsTextEquivUtils.cpp \
-  nsTextAttrs.cpp \
   StyleInfo.cpp \
+  TextAttrs.cpp \
   TextUpdater.cpp \
   $(NULL)
 
 EXPORTS = \
   a11yGeneric.h \
   nsAccDocManager.h \
   nsAccessibilityService.h \
   nsAccessible.h \
--- a/accessible/src/base/StyleInfo.cpp
+++ b/accessible/src/base/StyleInfo.cpp
@@ -126,8 +126,17 @@ StyleInfo::FormatColor(const nscolor& aV
 
 void
 StyleInfo::FormatFontStyle(const nscoord& aValue, nsAString& aFormattedValue)
 {
   nsCSSKeyword keyword =
     nsCSSProps::ValueToKeywordEnum(aValue, nsCSSProps::kFontStyleKTable);
   AppendUTF8toUTF16(nsCSSKeywords::GetStringValue(keyword), aFormattedValue);
 }
+
+void
+StyleInfo::FormatTextDecorationStyle(PRUint8 aValue, nsAString& aFormattedValue)
+{
+  nsCSSKeyword keyword =
+    nsCSSProps::ValueToKeywordEnum(aValue,
+                                   nsCSSProps::kTextDecorationStyleKTable);
+  AppendUTF8toUTF16(nsCSSKeywords::GetStringValue(keyword), aFormattedValue);
+}
--- a/accessible/src/base/StyleInfo.h
+++ b/accessible/src/base/StyleInfo.h
@@ -57,16 +57,17 @@ public:
   void TextIndent(nsAString& aValue);
   void MarginLeft(nsAString& aValue) { Margin(css::eSideLeft, aValue); }
   void MarginRight(nsAString& aValue) { Margin(css::eSideRight, aValue); }
   void MarginTop(nsAString& aValue) { Margin(css::eSideTop, aValue); }
   void MarginBottom(nsAString& aValue) { Margin(css::eSideBottom, aValue); }
 
   static void FormatColor(const nscolor& aValue, nsString& aFormattedValue);
   static void FormatFontStyle(const nscoord& aValue, nsAString& aFormattedValue);
+  static void FormatTextDecorationStyle(PRUint8 aValue, nsAString& aFormattedValue);
 
 private:
   StyleInfo() MOZ_DELETE;
   StyleInfo(const StyleInfo&) MOZ_DELETE;
   StyleInfo& operator = (const StyleInfo&) MOZ_DELETE;
 
   void Margin(css::Side aSide, nsAString& aValue);
 
rename from accessible/src/base/nsTextAttrs.cpp
rename to accessible/src/base/TextAttrs.cpp
--- a/accessible/src/base/nsTextAttrs.cpp
+++ b/accessible/src/base/TextAttrs.cpp
@@ -31,17 +31,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "nsTextAttrs.h"
+#include "TextAttrs.h"
 
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsHyperTextAccessibleWrap.h"
 #include "StyleInfo.h"
 
 #include "gfxFont.h"
 #include "gfxUserFontSet.h"
@@ -68,52 +68,42 @@ struct nsCSSTextAttrMapItem
 /**
  * The map of CSS properties to text attributes.
  */
 const char* const kAnyValue = nsnull;
 const char* const kCopyValue = nsnull;
 
 static nsCSSTextAttrMapItem gCSSTextAttrsMap[] =
 {
-  // CSS name            CSS value        Attribute name                                Attribute value
-  { "text-decoration",   "line-through",  &nsGkAtoms::textLineThroughStyle,  "solid" },
-  { "text-decoration",   "underline",     &nsGkAtoms::textUnderlineStyle,    "solid" },
+  // CSS name            CSS value        Attribute name                     Attribute value
   { "vertical-align",    kAnyValue,       &nsGkAtoms::textPosition,          kCopyValue }
 };
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsTextAttrs
+// TextAttrsMgr
+////////////////////////////////////////////////////////////////////////////////
 
-nsTextAttrsMgr::nsTextAttrsMgr(nsHyperTextAccessible *aHyperTextAcc,
-                               bool aIncludeDefAttrs,
-                               nsAccessible *aOffsetAcc,
-                               PRInt32 aOffsetAccIdx) :
-  mHyperTextAcc(aHyperTextAcc), mIncludeDefAttrs(aIncludeDefAttrs),
-  mOffsetAcc(aOffsetAcc), mOffsetAccIdx(aOffsetAccIdx)
-{
-}
-
-nsresult
-nsTextAttrsMgr::GetAttributes(nsIPersistentProperties *aAttributes,
-                              PRInt32 *aStartHTOffset,
-                              PRInt32 *aEndHTOffset)
+void
+TextAttrsMgr::GetAttributes(nsIPersistentProperties* aAttributes,
+                            PRInt32* aStartHTOffset,
+                            PRInt32* aEndHTOffset)
 {
   // 1. Hyper text accessible must be specified always.
   // 2. Offset accessible and result hyper text offsets must be specified in
   // the case of text attributes.
   // 3. Offset accessible and result hyper text offsets must not be specified
   // but include default text attributes flag and attributes list must be
   // specified in the case of default text attributes.
   NS_PRECONDITION(mHyperTextAcc &&
                   ((mOffsetAcc && mOffsetAccIdx != -1 &&
                     aStartHTOffset && aEndHTOffset) ||
                   (!mOffsetAcc && mOffsetAccIdx == -1 &&
                     !aStartHTOffset && !aEndHTOffset &&
                    mIncludeDefAttrs && aAttributes)),
-                  "Wrong usage of nsTextAttrsMgr!");
+                  "Wrong usage of TextAttrsMgr!");
 
   // Embedded objects are combined into own range with empty attributes set.
   if (mOffsetAcc && nsAccUtils::IsEmbeddedObject(mOffsetAcc)) {
     for (PRInt32 childIdx = mOffsetAccIdx - 1; childIdx >= 0; childIdx--) {
       nsAccessible *currAcc = mHyperTextAcc->GetChildAt(childIdx);
       if (!nsAccUtils::IsEmbeddedObject(currAcc))
         break;
 
@@ -125,120 +115,107 @@ nsTextAttrsMgr::GetAttributes(nsIPersist
          childIdx++) {
       nsAccessible *currAcc = mHyperTextAcc->GetChildAt(childIdx);
       if (!nsAccUtils::IsEmbeddedObject(currAcc))
         break;
 
       (*aEndHTOffset)++;
     }
 
-    return NS_OK;
+    return;
   }
 
   // Get the content and frame of the accessible. In the case of document
   // accessible it's role content and root frame.
   nsIContent *hyperTextElm = mHyperTextAcc->GetContent();
   nsIFrame *rootFrame = mHyperTextAcc->GetFrame();
   NS_ASSERTION(rootFrame, "No frame for accessible!");
   if (!rootFrame)
-    return NS_OK;
+    return;
 
   nsIContent *offsetNode = nsnull, *offsetElm = nsnull;
   nsIFrame *frame = nsnull;
   if (mOffsetAcc) {
     offsetNode = mOffsetAcc->GetContent();
     offsetElm = nsCoreUtils::GetDOMElementFor(offsetNode);
     frame = offsetElm->GetPrimaryFrame();
   }
 
-  nsTArray<nsITextAttr*> textAttrArray(10);
+  nsTArray<TextAttr*> textAttrArray(9);
 
   // "language" text attribute
-  nsLangTextAttr langTextAttr(mHyperTextAcc, hyperTextElm, offsetNode);
+  LangTextAttr langTextAttr(mHyperTextAcc, hyperTextElm, offsetNode);
   textAttrArray.AppendElement(&langTextAttr);
 
-  // "text-line-through-style" text attribute
-  nsCSSTextAttr lineThroughTextAttr(0, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(&lineThroughTextAttr);
-
-  // "text-underline-style" text attribute
-  nsCSSTextAttr underlineTextAttr(1, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(&underlineTextAttr);
-
   // "text-position" text attribute
-  nsCSSTextAttr posTextAttr(2, hyperTextElm, offsetElm);
+  CSSTextAttr posTextAttr(0, hyperTextElm, offsetElm);
   textAttrArray.AppendElement(&posTextAttr);
 
   // "background-color" text attribute
-  nsBGColorTextAttr bgColorTextAttr(rootFrame, frame);
+  BGColorTextAttr bgColorTextAttr(rootFrame, frame);
   textAttrArray.AppendElement(&bgColorTextAttr);
 
   // "color" text attribute
   ColorTextAttr colorTextAttr(rootFrame, frame);
   textAttrArray.AppendElement(&colorTextAttr);
 
   // "font-family" text attribute
   FontFamilyTextAttr fontFamilyTextAttr(rootFrame, frame);
   textAttrArray.AppendElement(&fontFamilyTextAttr);
 
   // "font-size" text attribute
-  nsFontSizeTextAttr fontSizeTextAttr(rootFrame, frame);
+  FontSizeTextAttr fontSizeTextAttr(rootFrame, frame);
   textAttrArray.AppendElement(&fontSizeTextAttr);
 
   // "font-style" text attribute
   FontStyleTextAttr fontStyleTextAttr(rootFrame, frame);
   textAttrArray.AppendElement(&fontStyleTextAttr);
 
   // "font-weight" text attribute
-  nsFontWeightTextAttr fontWeightTextAttr(rootFrame, frame);
+  FontWeightTextAttr fontWeightTextAttr(rootFrame, frame);
   textAttrArray.AppendElement(&fontWeightTextAttr);
 
+  // "text-underline(line-through)-style(color)" text attributes
+  TextDecorTextAttr textDecorTextAttr(rootFrame, frame);
+  textAttrArray.AppendElement(&textDecorTextAttr);
+
   // Expose text attributes if applicable.
   if (aAttributes) {
     PRUint32 len = textAttrArray.Length();
-    for (PRUint32 idx = 0; idx < len; idx++) {
-      nsITextAttr *textAttr = textAttrArray[idx];
-
-      nsAutoString value;
-      if (textAttr->GetValue(value, mIncludeDefAttrs))
-        nsAccUtils::SetAccAttr(aAttributes, textAttr->GetName(), value);
-    }
+    for (PRUint32 idx = 0; idx < len; idx++)
+      textAttrArray[idx]->Expose(aAttributes, mIncludeDefAttrs);
   }
 
-  nsresult rv = NS_OK;
-
   // Expose text attributes range where they are applied if applicable.
   if (mOffsetAcc)
-    rv = GetRange(textAttrArray, aStartHTOffset, aEndHTOffset);
-
-  textAttrArray.Clear();
-  return rv;
+    GetRange(textAttrArray, aStartHTOffset, aEndHTOffset);
 }
 
-nsresult
-nsTextAttrsMgr::GetRange(const nsTArray<nsITextAttr*>& aTextAttrArray,
-                         PRInt32 *aStartHTOffset, PRInt32 *aEndHTOffset)
+void
+TextAttrsMgr::GetRange(const nsTArray<TextAttr*>& aTextAttrArray,
+                       PRInt32* aStartHTOffset, PRInt32* aEndHTOffset)
 {
   PRUint32 attrLen = aTextAttrArray.Length();
 
   // Navigate backward from anchor accessible to find start offset.
   for (PRInt32 childIdx = mOffsetAccIdx - 1; childIdx >= 0; childIdx--) {
     nsAccessible *currAcc = mHyperTextAcc->GetChildAt(childIdx);
 
     // Stop on embedded accessible since embedded accessibles are combined into
     // own range.
     if (nsAccUtils::IsEmbeddedObject(currAcc))
       break;
 
-    nsIContent *currElm = nsCoreUtils::GetDOMElementFor(currAcc->GetContent());
-    NS_ENSURE_STATE(currElm);
+    nsIContent* currElm = nsCoreUtils::GetDOMElementFor(currAcc->GetContent());
+    if (!currElm)
+      return;
 
     bool offsetFound = false;
     for (PRUint32 attrIdx = 0; attrIdx < attrLen; attrIdx++) {
-      nsITextAttr *textAttr = aTextAttrArray[attrIdx];
+      TextAttr* textAttr = aTextAttrArray[attrIdx];
       if (!textAttr->Equal(currElm)) {
         offsetFound = true;
         break;
       }
     }
 
     if (offsetFound)
       break;
@@ -248,99 +225,99 @@ nsTextAttrsMgr::GetRange(const nsTArray<
 
   // Navigate forward from anchor accessible to find end offset.
   PRInt32 childLen = mHyperTextAcc->GetChildCount();
   for (PRInt32 childIdx = mOffsetAccIdx + 1; childIdx < childLen; childIdx++) {
     nsAccessible *currAcc = mHyperTextAcc->GetChildAt(childIdx);
     if (nsAccUtils::IsEmbeddedObject(currAcc))
       break;
 
-    nsIContent *currElm = nsCoreUtils::GetDOMElementFor(currAcc->GetContent());
-    NS_ENSURE_STATE(currElm);
+    nsIContent* currElm = nsCoreUtils::GetDOMElementFor(currAcc->GetContent());
+    if (!currElm)
+      return;
 
     bool offsetFound = false;
     for (PRUint32 attrIdx = 0; attrIdx < attrLen; attrIdx++) {
-      nsITextAttr *textAttr = aTextAttrArray[attrIdx];
+      TextAttr* textAttr = aTextAttrArray[attrIdx];
 
       // Alter the end offset when text attribute changes its value and stop
       // the search.
       if (!textAttr->Equal(currElm)) {
         offsetFound = true;
         break;
       }
     }
 
     if (offsetFound)
       break;
 
     (*aEndHTOffset) += nsAccUtils::TextLength(currAcc);
   }
+}
 
-  return NS_OK;
-}
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsLangTextAttr
+// LangTextAttr
+////////////////////////////////////////////////////////////////////////////////
 
-nsLangTextAttr::nsLangTextAttr(nsHyperTextAccessible *aRootAcc, 
-                               nsIContent *aRootContent, nsIContent *aContent) :
-  nsTextAttr<nsAutoString>(aContent == nsnull), mRootContent(aRootContent)
+TextAttrsMgr::LangTextAttr::
+  LangTextAttr(nsHyperTextAccessible* aRoot,
+               nsIContent* aRootElm, nsIContent* aElm) :
+  TTextAttr<nsString>(!aElm), mRootContent(aRootElm)
 {
-  aRootAcc->Language(mRootNativeValue);
+  aRoot->Language(mRootNativeValue);
   mIsRootDefined =  !mRootNativeValue.IsEmpty();
 
-  if (aContent)
-    mIsDefined = GetLang(aContent, mNativeValue);
+  if (aElm)
+    mIsDefined = GetLang(aElm, mNativeValue);
 }
 
 bool
-nsLangTextAttr::GetValueFor(nsIContent *aElm, nsAutoString *aValue)
+TextAttrsMgr::LangTextAttr::
+  GetValueFor(nsIContent* aElm, nsString* aValue)
 {
   return GetLang(aElm, *aValue);
 }
 
 void
-nsLangTextAttr::Format(const nsAutoString& aValue, nsAString& aFormattedValue)
+TextAttrsMgr::LangTextAttr::
+  ExposeValue(nsIPersistentProperties* aAttributes, const nsString& aValue)
 {
-  aFormattedValue = aValue;
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::language, aValue);
 }
 
 bool
-nsLangTextAttr::GetLang(nsIContent *aContent, nsAString& aLang)
+TextAttrsMgr::LangTextAttr::
+  GetLang(nsIContent* aElm, nsAString& aLang)
 {
-  nsCoreUtils::GetLanguageFor(aContent, mRootContent, aLang);
+  nsCoreUtils::GetLanguageFor(aElm, mRootContent, aLang);
   return !aLang.IsEmpty();
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsCSSTextAttr
+// CSSTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
-nsCSSTextAttr::nsCSSTextAttr(PRUint32 aIndex, nsIContent *aRootContent,
-                             nsIContent *aContent) :
-  nsTextAttr<nsAutoString>(aContent == nsnull), mIndex(aIndex)
+TextAttrsMgr::CSSTextAttr::
+  CSSTextAttr(PRUint32 aIndex, nsIContent* aRootElm, nsIContent* aElm) :
+  TTextAttr<nsString>(!aElm), mIndex(aIndex)
 {
-  mIsRootDefined = GetValueFor(aRootContent, &mRootNativeValue);
+  mIsRootDefined = GetValueFor(aRootElm, &mRootNativeValue);
 
-  if (aContent)
-    mIsDefined = GetValueFor(aContent, &mNativeValue);
-}
-
-nsIAtom*
-nsCSSTextAttr::GetName() const
-{
-  return *gCSSTextAttrsMap[mIndex].mAttrName;
+  if (aElm)
+    mIsDefined = GetValueFor(aElm, &mNativeValue);
 }
 
 bool
-nsCSSTextAttr::GetValueFor(nsIContent *aContent, nsAutoString *aValue)
+TextAttrsMgr::CSSTextAttr::
+  GetValueFor(nsIContent* aElm, nsString* aValue)
 {
   nsCOMPtr<nsIDOMCSSStyleDeclaration> currStyleDecl =
-    nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), aContent);
+    nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), aElm);
   if (!currStyleDecl)
     return false;
 
   NS_ConvertASCIItoUTF16 cssName(gCSSTextAttrsMap[mIndex].mCSSName);
 
   nsresult rv = currStyleDecl->GetPropertyValue(cssName, *aValue);
   if (NS_FAILED(rv))
     return true;
@@ -348,60 +325,69 @@ nsCSSTextAttr::GetValueFor(nsIContent *a
   const char *cssValue = gCSSTextAttrsMap[mIndex].mCSSValue;
   if (cssValue != kAnyValue && !aValue->EqualsASCII(cssValue))
     return false;
 
   return true;
 }
 
 void
-nsCSSTextAttr::Format(const nsAutoString& aValue, nsAString& aFormattedValue)
+TextAttrsMgr::CSSTextAttr::
+  ExposeValue(nsIPersistentProperties* aAttributes, const nsString& aValue)
 {
-  const char *attrValue = gCSSTextAttrsMap[mIndex].mAttrValue;
-  if (attrValue != kCopyValue)
-    AppendASCIItoUTF16(attrValue, aFormattedValue);
-  else
-    aFormattedValue = aValue;
+  const char* attrValue = gCSSTextAttrsMap[mIndex].mAttrValue;
+  if (attrValue != kCopyValue) {
+    nsAutoString formattedValue;
+    AppendASCIItoUTF16(attrValue, formattedValue);
+    nsAccUtils::SetAccAttr(aAttributes, *gCSSTextAttrsMap[mIndex].mAttrName,
+                           formattedValue);
+    return;
+  }
+
+  nsAccUtils::SetAccAttr(aAttributes, *gCSSTextAttrsMap[mIndex].mAttrName,
+                         aValue);
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsBGColorTextAttr
+// BGColorTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
-nsBGColorTextAttr::nsBGColorTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame) :
-  nsTextAttr<nscolor>(aFrame == nsnull), mRootFrame(aRootFrame)
+TextAttrsMgr::BGColorTextAttr::
+  BGColorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
+  TTextAttr<nscolor>(!aFrame), mRootFrame(aRootFrame)
 {
   mIsRootDefined = GetColor(mRootFrame, &mRootNativeValue);
   if (aFrame)
     mIsDefined = GetColor(aFrame, &mNativeValue);
 }
 
 bool
-nsBGColorTextAttr::GetValueFor(nsIContent *aContent, nscolor *aValue)
+TextAttrsMgr::BGColorTextAttr::
+  GetValueFor(nsIContent* aElm, nscolor* aValue)
 {
-  nsIFrame *frame = aContent->GetPrimaryFrame();
-  if (!frame)
-    return false;
-
-  return GetColor(frame, aValue);
+  nsIFrame* frame = aElm->GetPrimaryFrame();
+  return frame ? GetColor(frame, aValue) : false;
 }
 
 void
-nsBGColorTextAttr::Format(const nscolor& aValue, nsAString& aFormattedValue)
+TextAttrsMgr::BGColorTextAttr::
+  ExposeValue(nsIPersistentProperties* aAttributes, const nscolor& aValue)
 {
-  nsAutoString value;
-  StyleInfo::FormatColor(aValue, value);
-  aFormattedValue = value;
+  nsAutoString formattedValue;
+  StyleInfo::FormatColor(aValue, formattedValue);
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::backgroundColor,
+                         formattedValue);
 }
 
 bool
-nsBGColorTextAttr::GetColor(nsIFrame *aFrame, nscolor *aColor)
+TextAttrsMgr::BGColorTextAttr::
+  GetColor(nsIFrame* aFrame, nscolor* aColor)
 {
-  const nsStyleBackground *styleBackground = aFrame->GetStyleBackground();
+  const nsStyleBackground* styleBackground = aFrame->GetStyleBackground();
 
   if (NS_GET_A(styleBackground->mBackgroundColor) > 0) {
     *aColor = styleBackground->mBackgroundColor;
     return true;
   }
 
   nsIFrame *parentFrame = aFrame->GetParent();
   if (!parentFrame) {
@@ -418,124 +404,131 @@ nsBGColorTextAttr::GetColor(nsIFrame *aF
   return GetColor(parentFrame, aColor);
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // ColorTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
-ColorTextAttr::ColorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
-  nsTextAttr<nscolor>(!aFrame)
+TextAttrsMgr::ColorTextAttr::
+  ColorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
+  TTextAttr<nscolor>(!aFrame)
 {
   mRootNativeValue = aRootFrame->GetStyleColor()->mColor;
   mIsRootDefined = true;
 
   if (aFrame) {
     mNativeValue = aFrame->GetStyleColor()->mColor;
     mIsDefined = true;
   }
 }
 
 bool
-ColorTextAttr::GetValueFor(nsIContent* aContent, nscolor* aValue)
+TextAttrsMgr::ColorTextAttr::
+  GetValueFor(nsIContent* aElm, nscolor* aValue)
 {
-  nsIFrame* frame = aContent->GetPrimaryFrame();
+  nsIFrame* frame = aElm->GetPrimaryFrame();
   if (frame) {
     *aValue = frame->GetStyleColor()->mColor;
     return true;
   }
 
   return false;
 }
 
 void
-ColorTextAttr::Format(const nscolor& aValue, nsAString& aFormattedValue)
+TextAttrsMgr::ColorTextAttr::
+  ExposeValue(nsIPersistentProperties* aAttributes, const nscolor& aValue)
 {
-  nsAutoString value;
-  StyleInfo::FormatColor(aValue, value);
-  aFormattedValue = value;
+  nsAutoString formattedValue;
+  StyleInfo::FormatColor(aValue, formattedValue);
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::color, formattedValue);
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // FontFamilyTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
-FontFamilyTextAttr::FontFamilyTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
-  nsTextAttr<nsAutoString>(aFrame == nsnull)
+TextAttrsMgr::FontFamilyTextAttr::
+  FontFamilyTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
+  TTextAttr<nsString>(!aFrame)
 {
   mIsRootDefined = GetFontFamily(aRootFrame, mRootNativeValue);
 
   if (aFrame)
     mIsDefined = GetFontFamily(aFrame, mNativeValue);
 }
 
 bool
-FontFamilyTextAttr::GetValueFor(nsIContent* aElm, nsAutoString* aValue)
+TextAttrsMgr::FontFamilyTextAttr::
+  GetValueFor(nsIContent* aElm, nsString* aValue)
 {
   nsIFrame* frame = aElm->GetPrimaryFrame();
-  if (!frame)
-    return false;
-
-  return GetFontFamily(frame, *aValue);
+  return frame ? GetFontFamily(frame, *aValue) : false;
 }
 
 void
-FontFamilyTextAttr::Format(const nsAutoString& aValue,
-                           nsAString& aFormattedValue)
+TextAttrsMgr::FontFamilyTextAttr::
+  ExposeValue(nsIPersistentProperties* aAttributes, const nsString& aValue)
 {
-  aFormattedValue = aValue;
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::font_family, aValue);
 }
 
 bool
-FontFamilyTextAttr::GetFontFamily(nsIFrame* aFrame, nsAutoString& aFamily)
+TextAttrsMgr::FontFamilyTextAttr::
+  GetFontFamily(nsIFrame* aFrame, nsString& aFamily)
 {
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm));
 
   gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
   gfxFont* font = fontGroup->GetFontAt(0);
   gfxFontEntry* fontEntry = font->GetFontEntry();
   aFamily = fontEntry->FamilyName();
   return true;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsFontSizeTextAttr
+// FontSizeTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
-nsFontSizeTextAttr::nsFontSizeTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame) :
-  nsTextAttr<nscoord>(aFrame == nsnull)
+TextAttrsMgr::FontSizeTextAttr::
+  FontSizeTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
+  TTextAttr<nscoord>(!aFrame)
 {
   mDC = aRootFrame->PresContext()->DeviceContext();
 
-  mRootNativeValue = GetFontSize(aRootFrame);
+  mRootNativeValue = aRootFrame->GetStyleFont()->mSize;
   mIsRootDefined = true;
 
   if (aFrame) {
-    mNativeValue = GetFontSize(aFrame);
+    mNativeValue = aFrame->GetStyleFont()->mSize;
     mIsDefined = true;
   }
 }
 
 bool
-nsFontSizeTextAttr::GetValueFor(nsIContent *aContent, nscoord *aValue)
+TextAttrsMgr::FontSizeTextAttr::
+  GetValueFor(nsIContent* aElm, nscoord* aValue)
 {
-  nsIFrame *frame = aContent->GetPrimaryFrame();
-  if (!frame)
-    return false;
+  nsIFrame* frame = aElm->GetPrimaryFrame();
+  if (frame) {
+    *aValue = frame->GetStyleFont()->mSize;
+    return true;
+  }
 
-  *aValue = GetFontSize(frame);
-  return true;
+  return false;
 }
 
 void
-nsFontSizeTextAttr::Format(const nscoord& aValue, nsAString& aFormattedValue)
+TextAttrsMgr::FontSizeTextAttr::
+  ExposeValue(nsIPersistentProperties* aAttributes, const nscoord& aValue)
 {
   // Convert from nscoord to pt.
   //
   // Note: according to IA2, "The conversion doesn't have to be exact.
   // The intent is to give the user a feel for the size of the text."
   //
   // ATK does not specify a unit and will likely follow IA2 here.
   //
@@ -543,99 +536,105 @@ nsFontSizeTextAttr::Format(const nscoord
   float px =
     NSAppUnitsToFloatPixels(aValue, nsDeviceContext::AppUnitsPerCSSPixel());
   // Each pt is 4/3 of a CSS pixel.
   int pts = NS_lround(px*3/4);
 
   nsAutoString value;
   value.AppendInt(pts);
   value.Append(NS_LITERAL_STRING("pt"));
-  aFormattedValue = value;
-}
 
-nscoord
-nsFontSizeTextAttr::GetFontSize(nsIFrame *aFrame)
-{
-  return aFrame->GetStyleFont()->mSize;
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::font_size, value);
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // FontStyleTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
-FontStyleTextAttr::FontStyleTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
-  nsTextAttr<nscoord>(!aFrame)
+TextAttrsMgr::FontStyleTextAttr::
+  FontStyleTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
+  TTextAttr<nscoord>(!aFrame)
 {
   mRootNativeValue = aRootFrame->GetStyleFont()->mFont.style;
   mIsRootDefined = true;
 
   if (aFrame) {
     mNativeValue = aFrame->GetStyleFont()->mFont.style;
     mIsDefined = true;
   }
 }
 
 bool
-FontStyleTextAttr::GetValueFor(nsIContent* aContent, nscoord* aValue)
+TextAttrsMgr::FontStyleTextAttr::
+  GetValueFor(nsIContent* aContent, nscoord* aValue)
 {
   nsIFrame* frame = aContent->GetPrimaryFrame();
   if (frame) {
     *aValue = frame->GetStyleFont()->mFont.style;
     return true;
   }
 
   return false;
 }
 
 void
-FontStyleTextAttr::Format(const nscoord& aValue, nsAString& aFormattedValue)
+TextAttrsMgr::FontStyleTextAttr::
+  ExposeValue(nsIPersistentProperties* aAttributes, const nscoord& aValue)
 {
-  StyleInfo::FormatFontStyle(aValue, aFormattedValue);
+  nsAutoString formattedValue;
+  StyleInfo::FormatFontStyle(aValue, formattedValue);
+
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::font_style, formattedValue);
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsFontWeightTextAttr
+// FontWeightTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
-nsFontWeightTextAttr::nsFontWeightTextAttr(nsIFrame *aRootFrame,
-                                           nsIFrame *aFrame) :
-  nsTextAttr<PRInt32>(aFrame == nsnull)
+TextAttrsMgr::FontWeightTextAttr::
+  FontWeightTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
+  TTextAttr<PRInt32>(!aFrame)
 {
   mRootNativeValue = GetFontWeight(aRootFrame);
   mIsRootDefined = true;
 
   if (aFrame) {
     mNativeValue = GetFontWeight(aFrame);
     mIsDefined = true;
   }
 }
 
 bool
-nsFontWeightTextAttr::GetValueFor(nsIContent *aContent, PRInt32 *aValue)
+TextAttrsMgr::FontWeightTextAttr::
+  GetValueFor(nsIContent* aElm, PRInt32* aValue)
 {
-  nsIFrame *frame = aContent->GetPrimaryFrame();
-  if (!frame)
-    return false;
+  nsIFrame* frame = aElm->GetPrimaryFrame();
+  if (frame) {
+    *aValue = GetFontWeight(frame);
+    return true;
+  }
 
-  *aValue = GetFontWeight(frame);
-  return true;
+  return false;
 }
 
 void
-nsFontWeightTextAttr::Format(const PRInt32& aValue, nsAString& aFormattedValue)
+TextAttrsMgr::FontWeightTextAttr::
+  ExposeValue(nsIPersistentProperties* aAttributes, const PRInt32& aValue)
 {
-  nsAutoString value;
-  value.AppendInt(aValue);
-  aFormattedValue = value;
+  nsAutoString formattedValue;
+  formattedValue.AppendInt(aValue);
+
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::fontWeight, formattedValue);
 }
 
 PRInt32
-nsFontWeightTextAttr::GetFontWeight(nsIFrame *aFrame)
+TextAttrsMgr::FontWeightTextAttr::
+  GetFontWeight(nsIFrame* aFrame)
 {
   // nsFont::width isn't suitable here because it's necessary to expose real
   // value of font weight (used font might not have some font weight values).
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm));
 
   gfxFontGroup *fontGroup = fm->GetThebesFontGroup();
   gfxFont *font = fontGroup->GetFontAt(0);
@@ -659,8 +658,87 @@ nsFontWeightTextAttr::GetFontWeight(nsIF
   // may not be the weight of the font face used to render the characters.
   // On Mac, font->GetStyle()->weight will just give the same number as
   // getComputedStyle(). fontEntry->Weight() will give the weight of the font
   // face used.
   gfxFontEntry *fontEntry = font->GetFontEntry();
   return fontEntry->Weight();
 #endif
 }
+
+
+////////////////////////////////////////////////////////////////////////////////
+// TextDecorTextAttr
+////////////////////////////////////////////////////////////////////////////////
+
+TextAttrsMgr::TextDecorValue::
+  TextDecorValue(nsIFrame* aFrame)
+{
+  const nsStyleTextReset* textReset = aFrame->GetStyleTextReset();
+  mStyle = textReset->GetDecorationStyle();
+
+  bool isForegroundColor = false;
+  textReset->GetDecorationColor(mColor, isForegroundColor);
+  if (isForegroundColor)
+    mColor = aFrame->GetStyleColor()->mColor;
+
+  mLine = textReset->mTextDecorationLine &
+    (NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE |
+     NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH);
+}
+
+TextAttrsMgr::TextDecorTextAttr::
+  TextDecorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
+  TTextAttr<TextDecorValue>(!aFrame)
+{
+  mRootNativeValue = TextDecorValue(aRootFrame);
+  mIsRootDefined = mRootNativeValue.IsDefined();
+
+  if (aFrame) {
+    mNativeValue = TextDecorValue(aFrame);
+    mIsDefined = mNativeValue.IsDefined();
+  }
+}
+
+bool
+TextAttrsMgr::TextDecorTextAttr::
+  GetValueFor(nsIContent* aContent, TextDecorValue* aValue)
+{
+  nsIFrame* frame = aContent->GetPrimaryFrame();
+  if (frame) {
+    *aValue = TextDecorValue(frame);
+    return aValue->IsDefined();
+  }
+
+  return false;
+}
+
+void
+TextAttrsMgr::TextDecorTextAttr::
+  ExposeValue(nsIPersistentProperties* aAttributes, const TextDecorValue& aValue)
+{
+  if (aValue.IsUnderline()) {
+    nsAutoString formattedStyle;
+    StyleInfo::FormatTextDecorationStyle(aValue.Style(), formattedStyle);
+    nsAccUtils::SetAccAttr(aAttributes,
+                           nsGkAtoms::textUnderlineStyle,
+                           formattedStyle);
+
+    nsAutoString formattedColor;
+    StyleInfo::FormatColor(aValue.Color(), formattedColor);
+    nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::textUnderlineColor,
+                           formattedColor);
+    return;
+  }
+
+  if (aValue.IsLineThrough()) {
+    nsAutoString formattedStyle;
+    StyleInfo::FormatTextDecorationStyle(aValue.Style(), formattedStyle);
+    nsAccUtils::SetAccAttr(aAttributes,
+                           nsGkAtoms::textLineThroughStyle,
+                           formattedStyle);
+
+    nsAutoString formattedColor;
+    StyleInfo::FormatColor(aValue.Color(), formattedColor);
+    nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::textLineThroughColor,
+                           formattedColor);
+  }
+}
rename from accessible/src/base/nsTextAttrs.h
rename to accessible/src/base/TextAttrs.h
--- a/accessible/src/base/nsTextAttrs.h
+++ b/accessible/src/base/TextAttrs.h
@@ -34,393 +34,410 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsTextAttrs_h_
 #define nsTextAttrs_h_
 
-class nsHyperTextAccessible;
-
 #include "nsIContent.h"
 #include "nsIFrame.h"
 #include "nsIPersistentProperties2.h"
+#include "nsStyleConsts.h"
 
-class nsITextAttr;
+class nsHyperTextAccessible;
+
+namespace mozilla {
+namespace a11y {
 
 /**
  * Used to expose text attributes for the hyper text accessible (see
- * nsHyperTextAccessible class). It is indended for the work with 'language' and
- * CSS based text attributes.
+ * nsHyperTextAccessible class).
  *
- * @note "invalid: spelling" text attrbiute is implemented entirerly in
+ * @note "invalid: spelling" text attribute is implemented entirely in
  *       nsHyperTextAccessible class.
  */
-class nsTextAttrsMgr
+class TextAttrsMgr
 {
 public:
   /**
-   * Constructor. If instance of the class is intended to expose default text
-   * attributes then 'aIncludeDefAttrs' and 'aOffsetNode' argument must be
-   * skiped.
+   * Constructor. Used to expose default text attributes.
+   */
+  TextAttrsMgr(nsHyperTextAccessible* aHyperTextAcc) :
+    mHyperTextAcc(aHyperTextAcc), mIncludeDefAttrs(true),
+    mOffsetAcc(nsnull), mOffsetAccIdx(-1) { }
+
+  /**
+   * Constructor. Used to expose text attributes at the given offset.
    *
-   * @param aHyperTextAcc    hyper text accessible text attributes are
-   *                         calculated for
-   * @param aHyperTextNode   DOM node of the given hyper text accessbile
+   * @param aHyperTextAcc    [in] hyper text accessible text attributes are
+   *                          calculated for
    * @param aIncludeDefAttrs [optional] indicates whether default text
-   *                         attributes should be included into list of exposed
-   *                         text attributes.
-   * @param oOffsetNode      [optional] DOM node represents hyper text offset
-   *                         inside hyper text accessible
+   *                          attributes should be included into list of exposed
+   *                          text attributes
+   * @param oOffsetAcc       [optional] offset an accessible the text attributes
+   *                          should be calculated for
+   * @param oOffsetAccIdx    [optional] index in parent of offset accessible
    */
-  nsTextAttrsMgr(nsHyperTextAccessible *aHyperTextAcc,
-                 bool aIncludeDefAttrs = true,
-                 nsAccessible *aOffsetAcc = nsnull,
-                 PRInt32 aOffsetAccIdx = -1);
+  TextAttrsMgr(nsHyperTextAccessible* aHyperTextAcc,
+               bool aIncludeDefAttrs,
+               nsAccessible* aOffsetAcc,
+               PRInt32 aOffsetAccIdx) :
+    mHyperTextAcc(aHyperTextAcc), mIncludeDefAttrs(aIncludeDefAttrs),
+    mOffsetAcc(aOffsetAcc), mOffsetAccIdx(aOffsetAccIdx) { }
 
   /*
    * Return text attributes and hyper text offsets where these attributes are
    * applied. Offsets are calculated in the case of non default attributes.
    *
    * @note In the case of default attributes pointers on hyper text offsets
-   *       must be skiped.
+   *       must be skipped.
    *
    * @param aAttributes    [in, out] text attributes list
    * @param aStartHTOffset [out, optional] start hyper text offset
    * @param aEndHTOffset   [out, optional] end hyper text offset
    */
-  nsresult GetAttributes(nsIPersistentProperties *aAttributes,
-                         PRInt32 *aStartHTOffset = nsnull,
-                         PRInt32 *aEndHTOffset = nsnull);
+  void GetAttributes(nsIPersistentProperties* aAttributes,
+                     PRInt32* aStartHTOffset = nsnull,
+                     PRInt32* aEndHTOffset = nsnull);
 
 protected:
   /**
    * Calculates range (start and end offsets) of text where the text attributes
    * are stretched. New offsets may be smaller if one of text attributes changes
    * its value before or after the given offsets.
    *
    * @param aTextAttrArray  [in] text attributes array
    * @param aStartHTOffset  [in, out] the start offset
    * @param aEndHTOffset    [in, out] the end offset
    */
-   nsresult GetRange(const nsTArray<nsITextAttr*>& aTextAttrArray,
-                     PRInt32 *aStartHTOffset, PRInt32 *aEndHTOffset);
+  class TextAttr;
+  void GetRange(const nsTArray<TextAttr*>& aTextAttrArray,
+                PRInt32* aStartHTOffset, PRInt32* aEndHTOffset);
 
 private:
-  nsRefPtr<nsHyperTextAccessible> mHyperTextAcc;
+  nsHyperTextAccessible* mHyperTextAcc;
 
   bool mIncludeDefAttrs;
 
-  nsRefPtr<nsAccessible> mOffsetAcc;
+  nsAccessible* mOffsetAcc;
   PRInt32 mOffsetAccIdx;
-};
-
-
-////////////////////////////////////////////////////////////////////////////////
-// Private implementation details
-
-/**
- * Interface class of text attribute class implementations.
- */
-class nsITextAttr
-{
-public:
-  /**
-   * Return the name of text attribute.
-   */
-  virtual nsIAtom* GetName() const = 0;
-
-  /**
-   * Retrieve the value of text attribute in out param, return true if differs
-   * from the default value of text attribute or if include default attribute
-   * value flag is setted.
-   * 
-   * @param aValue                [in, out] the value of text attribute
-   * @param aIncludeDefAttrValue  [in] include default attribute value flag
-   * @return                      true if text attribute value differs from
-   *                              default or include default attribute value
-   *                              flag is applied
-   */
-  virtual bool GetValue(nsAString& aValue, bool aIncludeDefAttrValue) = 0;
-
-  /**
-   * Return true if the text attribute value on the given element equals with
-   * predefined attribute value.
-   */
-  virtual bool Equal(nsIContent *aContent) = 0;
-};
-
-
-/**
- * Base class to work with text attributes. See derived classes below.
- */
-template<class T>
-class nsTextAttr : public nsITextAttr
-{
-public:
-  nsTextAttr(bool aGetRootValue) : mGetRootValue(aGetRootValue) {}
-
-  // nsITextAttr
-  virtual bool GetValue(nsAString& aValue, bool aIncludeDefAttrValue)
-  {
-    if (mGetRootValue) {
-      Format(mRootNativeValue, aValue);
-      return mIsRootDefined;
-    }
-
-    bool isDefined = mIsDefined;
-    T* nativeValue = &mNativeValue;
-
-    if (!isDefined) {
-      if (aIncludeDefAttrValue) {
-        isDefined = mIsRootDefined;
-        nativeValue = &mRootNativeValue;
-      }
-    } else if (!aIncludeDefAttrValue) {
-      isDefined = mRootNativeValue != mNativeValue;
-    }
-
-    if (!isDefined)
-      return false;
-
-    Format(*nativeValue, aValue);
-    return true;
-  }
-
-  virtual bool Equal(nsIContent *aContent)
-  {
-    T nativeValue;
-    bool isDefined = GetValueFor(aContent, &nativeValue);
-
-    if (!mIsDefined && !isDefined)
-      return true;
-
-    if (mIsDefined && isDefined)
-      return nativeValue == mNativeValue;
-
-    if (mIsDefined)
-      return mNativeValue == mRootNativeValue;
-
-    return nativeValue == mRootNativeValue;
-  }
-
-protected:
-
-  // Return native value for the given DOM element.
-  virtual bool GetValueFor(nsIContent *aContent, T *aValue) = 0;
-
-  // Format native value to text attribute value.
-  virtual void Format(const T& aValue, nsAString& aFormattedValue) = 0;
-
-  // Indicates if root value should be exposed.
-  bool mGetRootValue;
-
-  // Native value and flag indicating if the value is defined (initialized in
-  // derived classes). Note, undefined native value means it is inherited
-  // from root.
-  T mNativeValue;
-  bool mIsDefined;
-
-  // Native root value and flag indicating if the value is defined  (initialized
-  // in derived classes).
-  T mRootNativeValue;
-  bool mIsRootDefined;
-};
-
-
-/**
- * Class is used for the work with 'language' text attribute in nsTextAttrsMgr
- * class.
- */
-class nsLangTextAttr : public nsTextAttr<nsAutoString>
-{
-public:
-  nsLangTextAttr(nsHyperTextAccessible *aRootAcc, nsIContent *aRootContent,
-                 nsIContent *aContent);
-
-  // nsITextAttr
-  virtual nsIAtom *GetName() const { return nsGkAtoms::language; }
 
 protected:
 
-  // nsTextAttr
-  virtual bool GetValueFor(nsIContent *aElm, nsAutoString *aValue);
-  virtual void Format(const nsAutoString& aValue, nsAString& aFormattedValue);
-
-private:
-  bool GetLang(nsIContent *aContent, nsAString& aLang);
-  nsCOMPtr<nsIContent> mRootContent;
-};
-
+  /**
+   * Interface class of text attribute class implementations.
+   */
+  class TextAttr
+  {
+  public:
+    /**
+     * Expose the text attribute to the given attribute set.
+     *
+     * @param aAttributes           [in] the given attribute set
+     * @param aIncludeDefAttrValue  [in] if true then attribute is exposed even
+     *                               if its value is the same as default one
+     */
+    virtual void Expose(nsIPersistentProperties* aAttributes,
+                        bool aIncludeDefAttrValue) = 0;
 
-/**
- * Class is used for the work with CSS based text attributes in nsTextAttrsMgr
- * class.
- */
-class nsCSSTextAttr : public nsTextAttr<nsAutoString>
-{
-public:
-  nsCSSTextAttr(PRUint32 aIndex, nsIContent *aRootContent,
-                nsIContent *aContent);
-
-  // nsITextAttr
-  virtual nsIAtom *GetName() const;
-
-protected:
-
-  // nsTextAttr
-  virtual bool GetValueFor(nsIContent *aContent, nsAutoString *aValue);
-  virtual void Format(const nsAutoString& aValue, nsAString& aFormattedValue);
-
-private:
-  PRInt32 mIndex;
-};
+    /**
+     * Return true if the text attribute value on the given element equals with
+     * predefined attribute value.
+     */
+    virtual bool Equal(nsIContent* aElm) = 0;
+  };
 
 
-/**
- * Class is used for the work with 'background-color' text attribute in
- * nsTextAttrsMgr class.
- */
-class nsBGColorTextAttr : public nsTextAttr<nscolor>
-{
-public:
-  nsBGColorTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame);
+  /**
+   * Base class to work with text attributes. See derived classes below.
+   */
+  template<class T>
+  class TTextAttr : public TextAttr
+  {
+  public:
+    TTextAttr(bool aGetRootValue) : mGetRootValue(aGetRootValue) {}
+
+    // ITextAttr
+    virtual void Expose(nsIPersistentProperties* aAttributes,
+                        bool aIncludeDefAttrValue)
+    {
+      if (mGetRootValue) {
+        if (mIsRootDefined)
+          ExposeValue(aAttributes, mRootNativeValue);
+        return;
+      }
+
+      if (mIsDefined) {
+        if (aIncludeDefAttrValue || mRootNativeValue != mNativeValue)
+          ExposeValue(aAttributes, mNativeValue);
+        return;
+      }
+
+      if (aIncludeDefAttrValue && mIsRootDefined)
+        ExposeValue(aAttributes, mRootNativeValue);
+    }
+
+    virtual bool Equal(nsIContent* aElm)
+    {
+      T nativeValue;
+      bool isDefined = GetValueFor(aElm, &nativeValue);
 
-  // nsITextAttr
-  virtual nsIAtom *GetName() const { return nsGkAtoms::backgroundColor; }
+      if (!mIsDefined && !isDefined)
+        return true;
+
+      if (mIsDefined && isDefined)
+        return nativeValue == mNativeValue;
+
+      if (mIsDefined)
+        return mNativeValue == mRootNativeValue;
+
+      return nativeValue == mRootNativeValue;
+    }
+
+  protected:
+
+    // Expose the text attribute with the given value to attribute set.
+    virtual void ExposeValue(nsIPersistentProperties* aAttributes,
+                             const T& aValue) = 0;
 
-protected:
-  // nsTextAttr
-  virtual bool GetValueFor(nsIContent *aContent, nscolor *aValue);
-  virtual void Format(const nscolor& aValue, nsAString& aFormattedValue);
+    // Return native value for the given DOM element.
+    virtual bool GetValueFor(nsIContent* aElm, T* aValue) = 0;
+
+    // Indicates if root value should be exposed.
+    bool mGetRootValue;
 
-private:
-  bool GetColor(nsIFrame *aFrame, nscolor *aColor);
-  nsIFrame *mRootFrame;
-};
+    // Native value and flag indicating if the value is defined (initialized in
+    // derived classes). Note, undefined native value means it is inherited
+    // from root.
+    T mNativeValue;
+    bool mIsDefined;
+
+    // Native root value and flag indicating if the value is defined  (initialized
+    // in derived classes).
+    T mRootNativeValue;
+    bool mIsRootDefined;
+  };
 
 
-/**
- * Class is used for the work with 'color' text attribute in nsTextAttrsMgr
- * class.
- */
-class ColorTextAttr : public nsTextAttr<nscolor>
-{
-public:
-  ColorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
+  /**
+   * Class is used for the work with 'language' text attribute.
+   */
+  class LangTextAttr : public TTextAttr<nsString>
+  {
+  public:
+    LangTextAttr(nsHyperTextAccessible* aRoot, nsIContent* aRootElm,
+                 nsIContent* aElm);
+    virtual ~LangTextAttr() { }
+
+  protected:
+
+    // TextAttr
+    virtual bool GetValueFor(nsIContent* aElm, nsString* aValue);
+    virtual void ExposeValue(nsIPersistentProperties* aAttributes,
+                             const nsString& aValue);
 
-  // nsITextAttr
-  virtual nsIAtom* GetName() const { return nsGkAtoms::color; }
+  private:
+    bool GetLang(nsIContent* aElm, nsAString& aLang);
+    nsCOMPtr<nsIContent> mRootContent;
+  };
+
 
-protected:
-  // nsTextAttr
-  virtual bool GetValueFor(nsIContent* aContent, nscolor* aValue);
-  virtual void Format(const nscolor& aValue, nsAString& aFormattedValue);
-};
+  /**
+   * Class is used for the work with CSS based text attributes.
+   */
+  class CSSTextAttr : public TTextAttr<nsString>
+  {
+  public:
+    CSSTextAttr(PRUint32 aIndex, nsIContent* aRootElm, nsIContent* aElm);
+    virtual ~CSSTextAttr() { }
+
+  protected:
+
+    // TextAttr
+    virtual bool GetValueFor(nsIContent* aElm, nsString* aValue);
+    virtual void ExposeValue(nsIPersistentProperties* aAttributes,
+                             const nsString& aValue);
+
+  private:
+    PRInt32 mIndex;
+  };
 
 
-/**
- * Class is used for the work with "font-family" text attribute in
- * nsTextAttrsMgr class.
- */
-class FontFamilyTextAttr : public nsTextAttr<nsAutoString>
-{
-public:
-  FontFamilyTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
+  /**
+   * Class is used for the work with 'background-color' text attribute.
+   */
+  class BGColorTextAttr : public TTextAttr<nscolor>
+  {
+  public:
+    BGColorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
+    virtual ~BGColorTextAttr() { }
+
+  protected:
+
+    // TextAttr
+    virtual bool GetValueFor(nsIContent* aElm, nscolor* aValue);
+    virtual void ExposeValue(nsIPersistentProperties* aAttributes,
+                             const nscolor& aValue);
 
-  // nsITextAttr
-  virtual nsIAtom* GetName() const { return nsGkAtoms::font_family; }
+  private:
+    bool GetColor(nsIFrame* aFrame, nscolor* aColor);
+    nsIFrame* mRootFrame;
+  };
 
-protected:
 
-  // nsTextAttr
-  virtual bool GetValueFor(nsIContent* aContent, nsAutoString* aValue);
-  virtual void Format(const nsAutoString& aValue, nsAString& aFormattedValue);
+  /**
+   * Class is used for the work with 'color' text attribute.
+   */
+  class ColorTextAttr : public TTextAttr<nscolor>
+  {
+  public:
+    ColorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
+    virtual ~ColorTextAttr() { }
 
-private:
+  protected:
 
-  bool GetFontFamily(nsIFrame* aFrame, nsAutoString& aFamily);
-};
+    // TTextAttr
+    virtual bool GetValueFor(nsIContent* aElm, nscolor* aValue);
+    virtual void ExposeValue(nsIPersistentProperties* aAttributes,
+                             const nscolor& aValue);
+  };
 
 
-/**
- * Class is used for the work with "font-size" text attribute in nsTextAttrsMgr
- * class.
- */
-class nsFontSizeTextAttr : public nsTextAttr<nscoord>
-{
-public:
-  nsFontSizeTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame);
+  /**
+   * Class is used for the work with "font-family" text attribute.
+   */
+  class FontFamilyTextAttr : public TTextAttr<nsString>
+  {
+  public:
+    FontFamilyTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
+    virtual ~FontFamilyTextAttr() { }
+
+  protected:
+
+    // TTextAttr
+    virtual bool GetValueFor(nsIContent* aElm, nsString* aValue);
+    virtual void ExposeValue(nsIPersistentProperties* aAttributes,
+                             const nsString& aValue);
+
+  private:
+
+    bool GetFontFamily(nsIFrame* aFrame, nsString& aFamily);
+  };
 
-  // nsITextAttr
-  virtual nsIAtom *GetName() const { return nsGkAtoms::font_size; }
 
-protected:
+  /**
+   * Class is used for the work with "font-size" text attribute.
+   */
+  class FontSizeTextAttr : public TTextAttr<nscoord>
+  {
+  public:
+    FontSizeTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
+    virtual ~FontSizeTextAttr() { }
 
-  // nsTextAttr
-  virtual bool GetValueFor(nsIContent *aContent, nscoord *aValue);
-  virtual void Format(const nscoord& aValue, nsAString& aFormattedValue);
+  protected:
 
-private:
+    // TTextAttr
+    virtual bool GetValueFor(nsIContent* aElm, nscoord* aValue);
+    virtual void ExposeValue(nsIPersistentProperties* aAttributes,
+                             const nscoord& aValue);
+
+  private:
+    nsDeviceContext* mDC;
+  };
+
 
   /**
-   * Return font size for the given frame.
-   *
-   * @param aFrame      [in] the given frame to query font-size
-   * @return            font size
+   * Class is used for the work with "font-style" text attribute.
    */
-   nscoord GetFontSize(nsIFrame *aFrame);
+  class FontStyleTextAttr : public TTextAttr<nscoord>
+  {
+  public:
+    FontStyleTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
+    virtual ~FontStyleTextAttr() { }
 
-  nsDeviceContext *mDC;
-};
+  protected:
+
+    // TTextAttr
+    virtual bool GetValueFor(nsIContent* aContent, nscoord* aValue);
+    virtual void ExposeValue(nsIPersistentProperties* aAttributes,
+                             const nscoord& aValue);
+  };
 
 
-/**
- * Class is used for the work with "font-style" text attribute in nsTextAttrsMgr
- * class.
- */
-class FontStyleTextAttr : public nsTextAttr<nscoord>
-{
-public:
-  FontStyleTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
+  /**
+   * Class is used for the work with "font-weight" text attribute.
+   */
+  class FontWeightTextAttr : public TTextAttr<PRInt32>
+  {
+  public:
+    FontWeightTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
+    virtual ~FontWeightTextAttr() { }
 
-  // nsITextAttr
-  virtual nsIAtom* GetName() const { return nsGkAtoms::font_style; }
-
-protected:
+  protected:
 
-  // nsTextAttr
-  virtual bool GetValueFor(nsIContent* aContent, nscoord* aValue);
-  virtual void Format(const nscoord &aValue, nsAString &aFormattedValue);
-};
+    // TTextAttr
+    virtual bool GetValueFor(nsIContent* aElm, PRInt32* aValue);
+    virtual void ExposeValue(nsIPersistentProperties* aAttributes,
+                             const PRInt32& aValue);
+
+  private:
+    PRInt32 GetFontWeight(nsIFrame* aFrame);
+  };
 
 
-/**
- * Class is used for the work with "font-weight" text attribute in
- * nsTextAttrsMgr class.
- */
-class nsFontWeightTextAttr : public nsTextAttr<PRInt32>
-{
-public:
-  nsFontWeightTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame);
+  /**
+   * TextDecorTextAttr class is used for the work with
+   * "text-line-through-style", "text-line-through-color",
+   * "text-underline-style" and "text-underline-color" text attributes.
+   */
 
-  // nsITextAttr
-  virtual nsIAtom *GetName() const { return nsGkAtoms::fontWeight; }
+  class TextDecorValue
+  {
+  public:
+    TextDecorValue() { }
+    TextDecorValue(nsIFrame* aFrame);
 
-protected:
+    nscolor Color() const { return mColor; }
+    PRUint8 Style() const { return mStyle; }
+
+    bool IsDefined() const
+      { return IsUnderline() || IsLineThrough(); }
+    bool IsUnderline() const
+      { return mLine & NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE; }
+    bool IsLineThrough() const
+      { return mLine & NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH; }
 
-  // nsTextAttr
-  virtual bool GetValueFor(nsIContent *aElm, PRInt32 *aValue);
-  virtual void Format(const PRInt32& aValue, nsAString& aFormattedValue);
+    bool operator ==(const TextDecorValue& aValue)
+    {
+      return mColor == aValue.mColor && mLine == aValue.mLine &&
+        mStyle == aValue.mStyle;
+    }
+    bool operator !=(const TextDecorValue& aValue)
+      { return !(*this == aValue); }
 
-private:
+  private:
+    nscolor mColor;
+    PRUint8 mLine;
+    PRUint8 mStyle;
+  };
 
-  /**
-   * Return font weight for the given frame.
-   *
-   * @param aFrame      [in] the given frame to query font weight
-   * @return            font weight
-   */
-  PRInt32 GetFontWeight(nsIFrame *aFrame);
-};
+  class TextDecorTextAttr : public TTextAttr<TextDecorValue>
+  {
+  public:
+    TextDecorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
+    virtual ~TextDecorTextAttr() { }
+
+  protected:
+
+    // TextAttr
+    virtual bool GetValueFor(nsIContent* aElm, TextDecorValue* aValue);
+    virtual void ExposeValue(nsIPersistentProperties* aAttributes,
+                             const TextDecorValue& aValue);
+  };
+
+}; // TextAttrMgr
+
+} // namespace a11y
+} // namespace mozilla
 
 #endif
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -37,19 +37,19 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHyperTextAccessible.h"
 
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "nsDocAccessible.h"
-#include "nsTextAttrs.h"
 #include "Role.h"
 #include "States.h"
+#include "TextAttrs.h"
 
 #include "nsIClipboard.h"
 #include "nsContentUtils.h"
 #include "nsFocusManager.h"
 #include "nsIDOMCharacterData.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMRange.h"
 #include "nsIDOMXULDocument.h"
@@ -1125,34 +1125,32 @@ nsHyperTextAccessible::GetTextAttributes
   }
 
   nsAccessible* accAtOffset = GetChildAtOffset(aOffset);
   if (!accAtOffset) {
     // Offset 0 is correct offset when accessible has empty text. Include
     // default attributes if they were requested, otherwise return empty set.
     if (aOffset == 0) {
       if (aIncludeDefAttrs) {
-        nsTextAttrsMgr textAttrsMgr(this, true, nsnull, -1);
-        return textAttrsMgr.GetAttributes(*aAttributes);
+        TextAttrsMgr textAttrsMgr(this);
+        textAttrsMgr.GetAttributes(*aAttributes);
       }
       return NS_OK;
     }
     return NS_ERROR_INVALID_ARG;
   }
 
   PRInt32 accAtOffsetIdx = accAtOffset->IndexInParent();
   PRInt32 startOffset = GetChildOffset(accAtOffsetIdx);
   PRInt32 endOffset = GetChildOffset(accAtOffsetIdx + 1);
   PRInt32 offsetInAcc = aOffset - startOffset;
 
-  nsTextAttrsMgr textAttrsMgr(this, aIncludeDefAttrs, accAtOffset,
-                              accAtOffsetIdx);
-  nsresult rv = textAttrsMgr.GetAttributes(*aAttributes, &startOffset,
-                                           &endOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
+  TextAttrsMgr textAttrsMgr(this, aIncludeDefAttrs, accAtOffset,
+                            accAtOffsetIdx);
+  textAttrsMgr.GetAttributes(*aAttributes, &startOffset, &endOffset);
 
   // Compute spelling attributes on text accessible only.
   nsIFrame *offsetFrame = accAtOffset->GetFrame();
   if (offsetFrame && offsetFrame->GetType() == nsGkAtoms::textFrame) {
     PRInt32 nodeOffset = 0;
     nsresult rv = RenderedToContentOffset(offsetFrame, offsetInAcc,
                                           &nodeOffset);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -1181,18 +1179,19 @@ nsHyperTextAccessible::GetDefaultTextAtt
     return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIPersistentProperties> attributes =
     do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
   NS_ENSURE_TRUE(attributes, NS_ERROR_OUT_OF_MEMORY);
 
   NS_ADDREF(*aAttributes = attributes);
 
-  nsTextAttrsMgr textAttrsMgr(this, true);
-  return textAttrsMgr.GetAttributes(*aAttributes);
+  TextAttrsMgr textAttrsMgr(this);
+  textAttrsMgr.GetAttributes(*aAttributes);
+  return NS_OK;
 }
 
 PRInt32
 nsHyperTextAccessible::GetLevelInternal()
 {
   nsIAtom *tag = mContent->Tag();
   if (tag == nsGkAtoms::h1)
     return 1;
--- a/accessible/tests/mochitest/attributes/test_text.html
+++ b/accessible/tests/mochitest/attributes/test_text.html
@@ -264,23 +264,29 @@
       tempElem = tempElem.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = { "font-family": kMonospaceFontFamily };
       testTextAttrs(ID, 70, attrs, defAttrs, 69, 83);
 
       attrs = {};
       testTextAttrs(ID, 84, attrs, defAttrs, 83, 91);
 
-      attrs = { "text-underline-style": "solid" };
+      attrs = {
+        "text-underline-style": "solid",
+        "text-underline-color": gComputedStyle.color
+      };
       testTextAttrs(ID, 92, attrs, defAttrs, 91, 101);
 
       attrs = {};
       testTextAttrs(ID, 102, attrs, defAttrs, 101, 109);
 
-      attrs = { "text-line-through-style": "solid" };
+      attrs = {
+        "text-line-through-style": "solid",
+        "text-line-through-color": gComputedStyle.color
+      };
       testTextAttrs(ID, 110, attrs, defAttrs, 109, 122);
 
       attrs = {};
       testTextAttrs(ID, 123, attrs, defAttrs, 122, 130);
 
       //////////////////////////////////////////////////////////////////////////
       // area10, different single style spans in non-styled paragraph
       ID = "area10";
@@ -318,23 +324,29 @@
       tempElem = tempElem.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = { "font-family": kMonospaceFontFamily };
       testTextAttrs(ID, 71, attrs, defAttrs, 70, 84);
 
       attrs = {};
       testTextAttrs(ID, 85, attrs, defAttrs, 84, 92);
 
-      attrs = { "text-underline-style": "solid" };
+      attrs = {
+        "text-underline-style": "solid",
+        "text-underline-color": gComputedStyle.color
+      };
       testTextAttrs(ID, 93, attrs, defAttrs, 92, 102);
 
       attrs = {};
       testTextAttrs(ID, 103, attrs, defAttrs, 102, 110);
 
-      attrs = { "text-line-through-style": "solid" };
+      attrs = {
+        "text-line-through-style": "solid",
+        "text-line-through-color": gComputedStyle.color
+      };
       testTextAttrs(ID, 111, attrs, defAttrs, 110, 123);
 
       attrs = {};
       testTextAttrs(ID, 124, attrs, defAttrs, 123, 131);
 
       //////////////////////////////////////////////////////////////////////////
       // area11, "font-weight" tests
       ID = "area11";
@@ -432,35 +444,82 @@
       testTextAttrs(ID, 22, attrs, defAttrs, 22, 27);
 
       attrs = { "font-family": kCursiveFontFamily };
       testTextAttrs(ID, 27, attrs, defAttrs, 27, 31);
 
       attrs = { };
       testTextAttrs(ID, 31, attrs, defAttrs, 31, 45);
 
+      //////////////////////////////////////////////////////////////////////////
+      // area17, "text-decoration" tests
+      ID = "area17";
+      defAttrs = buildDefaultTextAttrs(ID, "12pt");
+      testDefaultTextAttrs(ID, defAttrs);
+
+      attrs = {
+        "text-underline-style": "solid",
+        "text-underline-color": "rgb(0, 0, 0)",
+      };
+      testTextAttrs(ID, 0, attrs, defAttrs, 0, 10);
+
+      attrs = {
+        "text-underline-style": "solid",
+        "text-underline-color": "rgb(0, 0, 255)",
+      };
+      testTextAttrs(ID, 10, attrs, defAttrs, 10, 15);
+
+      attrs = {
+        "text-underline-style": "dotted",
+        "text-underline-color": "rgb(0, 0, 0)",
+      };
+      testTextAttrs(ID, 15, attrs, defAttrs, 15, 22);
+
+      attrs = {
+        "text-line-through-style": "solid",
+        "text-line-through-color": "rgb(0, 0, 0)",
+      };
+      testTextAttrs(ID, 22, attrs, defAttrs, 22, 34);
+
+      attrs = {
+        "text-line-through-style": "solid",
+        "text-line-through-color": "rgb(0, 0, 255)",
+      };
+      testTextAttrs(ID, 34, attrs, defAttrs, 34, 39);
+
+      attrs = {
+        "text-line-through-style": "wavy",
+        "text-line-through-color": "rgb(0, 0, 0)",
+      };
+      testTextAttrs(ID, 39, attrs, defAttrs, 39, 44);
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body style="font-size: 12pt">
 
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=345759"
      title="Implement text attributes">
     Mozilla Bug 345759
-  </a><br>
+  </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=473576"
      title="font-family text attribute should expose actual font used">
     Mozilla Bug 473576
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=523304"
+     title="expose text-underline-color and text-line-through-color text attributes">
+    Mozilla Bug 523304
+  </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <p id="area1" style="font-size: smaller">Normal <b>Bold</b> Normal</p>
   <p id="area2" style="font-size: 120%">Normal <b>Bold <i>Italic </i>Bold</b> Normal</p>
   <p id="area3" style="background-color: blue;">
@@ -541,10 +600,20 @@
 
   <p id="area16" style="font-family: sans-serif;">
     <span style="font-family: monospace;">text</span>text
     <span style="font-family: serif;">text</span>text
     <span style="font-family: BodoniThatDoesntExist;">text</span>text
     <span style="font-family: Comic Sans MS, cursive;">text</span>text
     <span style="font-family: sans-serif, fantasy;">text</span>text
   </p>
+
+  <p id="area17">
+    <span style="-moz-text-decoration-line: underline;">underline
+    </span><span style="text-decoration: underline; -moz-text-decoration-color: blue;">blue
+    </span><span style="text-decoration: underline; -moz-text-decoration-style: dotted;">dotted
+    </span><span style="-moz-text-decoration-line: line-through;">linethrough
+    </span><span style="text-decoration: line-through; -moz-text-decoration-color: blue;">blue
+    </span><span style="text-decoration: line-through; -moz-text-decoration-style: wavy;">wavy
+    </span>
+  </p>
 </body>
 </html>
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -286,22 +286,22 @@
                               accesskey="&fullZoomToggleCmd.accesskey;"
                               type="checkbox"
                               command="cmd_fullZoomToggle"
                               checked="false"/>
                   </menupopup>
                 </menu>
                 <menu id="pageStyleMenu" label="&pageStyleMenu.label;"
                       accesskey="&pageStyleMenu.accesskey;" observes="isImage">
-                  <menupopup onpopupshowing="stylesheetFillPopup(this);"
-                             oncommand="stylesheetSwitchAll(window.content, event.target.getAttribute('data')); setStyleDisabled(false);">
+                  <menupopup onpopupshowing="gPageStyleMenu.fillPopup(this);"
+                             oncommand="gPageStyleMenu.switchStyleSheet(event.target.getAttribute('data'));">
                     <menuitem id="menu_pageStyleNoStyle"
                               label="&pageStyleNoStyle.label;"
                               accesskey="&pageStyleNoStyle.accesskey;"
-                              oncommand="setStyleDisabled(true); event.stopPropagation();"
+                              oncommand="gPageStyleMenu.disableStyle(); event.stopPropagation();"
                               type="radio"/>
                     <menuitem id="menu_pageStylePersistentOnly"
                               label="&pageStylePersistentOnly.label;"
                               accesskey="&pageStylePersistentOnly.accesskey;"
                               type="radio"
                               checked="true"/>
                     <menuseparator/>
                   </menupopup>
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -5326,33 +5326,28 @@ function setToolbarVisibility(toolbar, i
 
 #ifdef MENUBAR_CAN_AUTOHIDE
   updateAppButtonDisplay();
 #endif
 }
 
 var TabsOnTop = {
   init: function TabsOnTop_init() {
-    this._initialized = true;
-    this.syncUI();
     Services.prefs.addObserver(this._prefName, this, false);
   },
 
   uninit: function TabsOnTop_uninit() {
     Services.prefs.removeObserver(this._prefName, this);
   },
 
   toggle: function () {
     this.enabled = !Services.prefs.getBoolPref(this._prefName);
   },
 
   syncUI: function () {
-    if (!this._initialized)
-      return;
-
     let userEnabled = Services.prefs.getBoolPref(this._prefName);
     let enabled = userEnabled && gBrowser.tabContainer.visible;
 
     document.getElementById("cmd_ToggleTabsOnTop")
             .setAttribute("checked", userEnabled);
 
     document.documentElement.setAttribute("tabsontop", enabled);
     document.getElementById("navigator-toolbox").setAttribute("tabsontop", enabled);
@@ -6092,33 +6087,33 @@ function charsetLoadListener(event) {
     gPrevCharset = gLastBrowserCharset;
     gLastBrowserCharset = charset;
   }
 }
 
 
 var gPageStyleMenu = {
 
-  getAllStyleSheets: function (frameset) {
+  _getAllStyleSheets: function (frameset) {
     var styleSheetsArray = Array.slice(frameset.document.styleSheets);
     for (let i = 0; i < frameset.frames.length; i++) {
-      let frameSheets = this.getAllStyleSheets(frameset.frames[i]);
+      let frameSheets = this._getAllStyleSheets(frameset.frames[i]);
       styleSheetsArray = styleSheetsArray.concat(frameSheets);
     }
     return styleSheetsArray;
   },
 
-  stylesheetFillPopup: function (menuPopup) {
+  fillPopup: function (menuPopup) {
     var noStyle = menuPopup.firstChild;
     var persistentOnly = noStyle.nextSibling;
     var sep = persistentOnly.nextSibling;
     while (sep.nextSibling)
       menuPopup.removeChild(sep.nextSibling);
 
-    var styleSheets = this.getAllStyleSheets(window.content);
+    var styleSheets = this._getAllStyleSheets(window.content);
     var currentStyleSheets = {};
     var styleDisabled = getMarkupDocumentViewer().authorStyleDisabled;
     var haveAltSheets = false;
     var altStyleSelected = false;
 
     for (let i = 0; i < styleSheets.length; ++i) {
       let currentStyleSheet = styleSheets[i];
 
@@ -6156,56 +6151,64 @@ var gPageStyleMenu = {
 
     noStyle.setAttribute("checked", styleDisabled);
     persistentOnly.setAttribute("checked", !altStyleSelected && !styleDisabled);
     persistentOnly.hidden = (window.content.document.preferredStyleSheetSet) ? haveAltSheets : false;
     sep.hidden = (noStyle.hidden && persistentOnly.hidden) || !haveAltSheets;
     return true;
   },
 
-  stylesheetInFrame: function (frame, title) {
+  _stylesheetInFrame: function (frame, title) {
     return Array.some(frame.document.styleSheets,
                       function (stylesheet) stylesheet.title == title);
   },
 
-  stylesheetSwitchFrame: function (frame, title) {
+  _stylesheetSwitchFrame: function (frame, title) {
     var docStyleSheets = frame.document.styleSheets;
 
     for (let i = 0; i < docStyleSheets.length; ++i) {
       let docStyleSheet = docStyleSheets[i];
 
       if (title == "_nostyle")
         docStyleSheet.disabled = true;
       else if (docStyleSheet.title)
         docStyleSheet.disabled = (docStyleSheet.title != title);
       else if (docStyleSheet.disabled)
         docStyleSheet.disabled = false;
     }
   },
 
-  stylesheetSwitchAll: function (frameset, title) {
-    if (!title || title == "_nostyle" || this.stylesheetInFrame(frameset, title))
-      this.stylesheetSwitchFrame(frameset, title);
+  _stylesheetSwitchAll: function (frameset, title) {
+    if (!title || title == "_nostyle" || this._stylesheetInFrame(frameset, title))
+      this._stylesheetSwitchFrame(frameset, title);
 
     for (let i = 0; i < frameset.frames.length; i++)
-      this.stylesheetSwitchAll(frameset.frames[i], title);
-  },
-
-  setStyleDisabled: function (disabled) {
-    getMarkupDocumentViewer().authorStyleDisabled = disabled;
+      this._stylesheetSwitchAll(frameset.frames[i], title);
+  },
+
+  switchStyleSheet: function (title, contentWindow) {
+    getMarkupDocumentViewer().authorStyleDisabled = false;
+    this._stylesheetSwitchAll(contentWindow || content, title);
+  },
+
+  disableStyle: function () {
+    getMarkupDocumentViewer().authorStyleDisabled = true;
   },
 };
 
 /* Legacy global page-style functions */
-var getAllStyleSheets     = gPageStyleMenu.getAllStyleSheets;
-var stylesheetFillPopup   = gPageStyleMenu.stylesheetFillPopup;
-var stylesheetInFrame     = gPageStyleMenu.stylesheetInFrame;
-var stylesheetSwitchFrame = gPageStyleMenu.stylesheetSwitchFrame;
-var stylesheetSwitchAll   = gPageStyleMenu.stylesheetSwitchAll;
-var setStyleDisabled      = gPageStyleMenu.setStyleDisabled;
+var getAllStyleSheets   = gPageStyleMenu._getAllStyleSheets.bind(gPageStyleMenu);
+var stylesheetFillPopup = gPageStyleMenu.fillPopup.bind(gPageStyleMenu);
+function stylesheetSwitchAll(contentWindow, title) {
+  gPageStyleMenu.switchStyleSheet(title, contentWindow);
+}
+function setStyleDisabled(disabled) {
+  if (disabled)
+    gPageStyleMenu.disableStyle();
+}
 
 
 var BrowserOffline = {
   _inited: false,
 
   /////////////////////////////////////////////////////////////////////////////
   // BrowserOffline Public Methods
   init: function ()
old mode 100644
new mode 100755
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -2774,19 +2774,17 @@
                            this.tabbrowser.mStringBundle.getString("tabs.emptyTabTitle"));
           tab.setAttribute("crop", "end");
           tab.setAttribute("validate", "never");
           tab.setAttribute("onerror", "this.removeAttribute('image');");
           this.adjustTabstrip();
 
           Services.prefs.addObserver("browser.tabs.", this._prefObserver, false);
           window.addEventListener("resize", this, false);
-
-          this.updateVisibility();
-          this._propagateVisibility();
+          window.addEventListener("load", this, false);
         ]]>
       </constructor>
 
       <destructor>
         <![CDATA[
           Services.prefs.removeObserver("browser.tabs.", this._prefObserver);
         ]]>
       </destructor>
@@ -2836,25 +2834,29 @@
 
       <field name="_dragOverDelay">350</field>
       <field name="_dragTime">0</field>
 
       <field name="_container" readonly="true"><![CDATA[
         this.parentNode && this.parentNode.localName == "toolbar" ? this.parentNode : this;
       ]]></field>
 
+      <field name="_propagatedVisibilityOnce">false</field>
+
       <property name="visible"
                 onget="return !this._container.collapsed;">
         <setter><![CDATA[
-          if (val == this.visible)
+          if (val == this.visible &&
+              this._propagatedVisibilityOnce)
             return val;
 
           this._container.collapsed = !val;
 
           this._propagateVisibility();
+          this._propagatedVisibilityOnce = true;
 
           return val;
         ]]></setter>
       </property>
 
       <method name="_propagateVisibility">
         <body><![CDATA[
           let visible = this.visible;
@@ -3075,16 +3077,19 @@
           this.mTabstrip.ensureElementIsVisible(this.selectedItem, false);
         ]]></body>
       </method>
 
       <method name="handleEvent">
         <parameter name="aEvent"/>
         <body><![CDATA[
           switch (aEvent.type) {
+            case "load":
+              this.updateVisibility();
+              break;
             case "resize":
               if (aEvent.target != window)
                 break;
               var width = this.mTabstrip.boxObject.width;
               if (width != this.mTabstripWidth) {
                 this.adjustTabstrip();
                 this._fillTrailingGap();
                 this._handleTabSelect();
--- a/browser/base/content/test/browser_page_style_menu.js
+++ b/browser/base/content/test/browser_page_style_menu.js
@@ -9,17 +9,17 @@ function test() {
   }, true);
   let rootDir = getRootDirectory(gTestPath);
   content.location = rootDir + "page_style_sample.html";
 }
 
 function checkPageStyleMenu() {
   var menupopup = document.getElementById("pageStyleMenu")
                           .getElementsByTagName("menupopup")[0];
-  stylesheetFillPopup(menupopup);
+  gPageStyleMenu.fillPopup(menupopup);
 
   var items = [];
   var current = menupopup.getElementsByTagName("menuseparator")[0];
   while (current.nextSibling) {
     current = current.nextSibling;
     items.push(current);
   }
 
--- a/browser/components/sessionstore/test/browser_408470.js
+++ b/browser/components/sessionstore/test/browser_408470.js
@@ -45,18 +45,18 @@ function test() {
   let tab = gBrowser.addTab(testUrl);
   
   tab.linkedBrowser.addEventListener("load", function(aEvent) {
     tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
     // enable all stylesheets and verify that they're correctly persisted
     Array.forEach(tab.linkedBrowser.contentDocument.styleSheets, function(aSS, aIx) {
       pendingCount++;
       let ssTitle = aSS.title;
-      stylesheetSwitchAll(tab.linkedBrowser.contentWindow, ssTitle);
-      
+      gPageStyleMenu.switchStyleSheet(ssTitle, tab.linkedBrowser.contentWindow);
+
       let newTab = gBrowser.duplicateTab(tab);
       newTab.linkedBrowser.addEventListener("load", function(aEvent) {
         newTab.linkedBrowser.removeEventListener("load", arguments.callee, true);
         let states = Array.map(newTab.linkedBrowser.contentDocument.styleSheets,
                                function(aSS) !aSS.disabled);
         let correct = states.indexOf(true) == aIx && states.indexOf(true, aIx + 1) == -1;
         
         if (/^fail_/.test(ssTitle))
--- a/browser/devtools/debugger/DebuggerUI.jsm
+++ b/browser/devtools/debugger/DebuggerUI.jsm
@@ -563,16 +563,17 @@ DebuggerUI.prototype = {
    *        The content type of the source script.
    */
   _onSourceLoaded: function DebuggerUI__onSourceLoaded(aSourceUrl,
                                                        aSourceText,
                                                        aContentType) {
     let dbg = this.getDebugger(this.aWindow.gBrowser.selectedTab);
     dbg.debuggerWindow.SourceScripts.setEditorMode(aSourceUrl, aContentType);
     dbg.editor.setText(aSourceText);
+    dbg.editor.resetUndo();
     let doc = dbg.frame.contentDocument;
     let scripts = doc.getElementById("scripts");
     let elt = scripts.getElementsByAttribute("value", aSourceUrl)[0];
     let script = elt.getUserData("sourceScript");
     script.loaded = true;
     script.text = aSourceText;
     script.contentType = aContentType;
     elt.setUserData("sourceScript", script, null);
--- a/browser/devtools/debugger/debugger.js
+++ b/browser/devtools/debugger/debugger.js
@@ -610,16 +610,17 @@ var SourceScripts = {
       var evt = document.createEvent("CustomEvent");
       evt.initCustomEvent("Debugger:LoadSource", true, false, aScript.url);
       document.documentElement.dispatchEvent(evt);
       window.editor.setText(DebuggerView.getStr("loadingText"));
     } else {
       window.editor.setText(aScript.text);
       window.updateEditorBreakpoints();
     }
+    window.editor.resetUndo();
   }
 };
 
 SourceScripts.onPaused = SourceScripts.onPaused.bind(SourceScripts);
 SourceScripts.onScripts = SourceScripts.onScripts.bind(SourceScripts);
 SourceScripts.onNewScript = SourceScripts.onNewScript.bind(SourceScripts);
 SourceScripts.onScriptsCleared = SourceScripts.onScriptsCleared.bind(SourceScripts);
 SourceScripts.onChange = SourceScripts.onChange.bind(SourceScripts);
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -40,20 +40,39 @@
 <?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/orion.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/debugger.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/debugger.css" type="text/css"?>
 <!DOCTYPE window [
 <!ENTITY % debuggerDTD SYSTEM "chrome://browser/locale/devtools/debugger.dtd" >
  %debuggerDTD;
 ]>
+<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
+<?xul-overlay href="chrome://browser/content/source-editor-overlay.xul"?>
 <xul:window xmlns="http://www.w3.org/1999/xhtml"
             xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+    <xul:script type="text/javascript" src="chrome://global/content/globalOverlay.js"/>
     <xul:script type="text/javascript" src="debugger.js"/>
     <xul:script type="text/javascript" src="debugger-view.js"/>
+    <xul:popupset id="debugger-popups">
+      <xul:menupopup id="sourceEditorContextMenu"
+                     onpopupshowing="goUpdateSourceEditorMenuItems()">
+        <xul:menuitem id="se-cMenu-copy"/>
+        <xul:menuseparator/>
+        <xul:menuitem id="se-cMenu-selectAll"/>
+        <xul:menuseparator/>
+        <xul:menuitem id="se-cMenu-find"/>
+        <xul:menuitem id="se-cMenu-findAgain"/>
+        <xul:menuseparator/>
+        <xul:menuitem id="se-cMenu-gotoLine"/>
+      </xul:menupopup>
+    </xul:popupset>
+    <xul:commandset id="editMenuCommands"/>
+    <xul:commandset id="sourceEditorCommands"/>
+    <xul:keyset id="sourceEditorKeys"/>
 
     <div id="body" class="vbox flex">
         <xul:toolbar id="dbg-toolbar">
             <xul:button id="close">&debuggerUI.closeButton;</xul:button>
             <xul:button id="resume"/>
             <xul:menulist id="scripts"/>
         </xul:toolbar>
         <div id="dbg-content" class="hbox flex">
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -69,16 +69,17 @@ include $(topsrcdir)/config/rules.mk
 	browser_dbg_stack-04.js \
 	browser_dbg_location-changes.js \
 	browser_dbg_script-switching.js \
 	browser_dbg_pause-resume.js \
 	browser_dbg_update-editor-mode.js \
 	browser_dbg_select-line.js \
 	browser_dbg_clean-exit.js \
 	browser_dbg_bug723069_editor-breakpoints.js \
+	browser_dbg_bug731394_editor-contextmenu.js \
 	head.js \
 	$(NULL)
 
 _BROWSER_TEST_PAGES = \
 	browser_dbg_tab1.html \
 	browser_dbg_tab2.html \
 	browser_dbg_debuggerstatement.html \
 	browser_dbg_stack.html \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_bug731394_editor-contextmenu.js
@@ -0,0 +1,102 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Bug 731394: test the debugger source editor default context menu.
+ */
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
+
+let gPane = null;
+let gTab = null;
+let gDebuggee = null;
+let gDebugger = null;
+
+function test()
+{
+  let tempScope = {};
+  Cu.import("resource:///modules/source-editor.jsm", tempScope);
+  let SourceEditor = tempScope.SourceEditor;
+
+  let contextMenu = null;
+
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.debuggerWindow;
+
+    gPane.activeThread.addOneTimeListener("scriptsadded", function() {
+      Services.tm.currentThread.dispatch({ run: onScriptsAdded }, 0);
+    });
+    gDebuggee.firstCall();
+  });
+
+  function onScriptsAdded()
+  {
+    let scripts = gDebugger.DebuggerView.Scripts._scripts;
+
+    is(gDebugger.StackFrames.activeThread.state, "paused",
+      "Should only be getting stack frames while paused.");
+
+    is(scripts.itemCount, 2, "Found the expected number of scripts.");
+
+    let editor = gDebugger.editor;
+
+    isnot(editor.getText().indexOf("debugger"), -1,
+          "The correct script was loaded initially.");
+
+    contextMenu = gDebugger.document.getElementById("sourceEditorContextMenu");
+    ok(contextMenu, "source editor context menupopup");
+    ok(editor.readOnly, "editor is read only");
+
+    editor.focus();
+    editor.setSelection(0, 10);
+
+    contextMenu.addEventListener("popupshown", function onPopupShown() {
+      contextMenu.removeEventListener("popupshown", onPopupShown, false);
+      executeSoon(testContextMenu);
+    }, false);
+    contextMenu.openPopup(editor.editorElement, "overlap", 0, 0, true, false);
+  }
+
+  function testContextMenu()
+  {
+    let document = gDebugger.document;
+
+    ok(document.getElementById("editMenuCommands"),
+       "#editMenuCommands found");
+    ok(!document.getElementById("editMenuKeys"),
+       "#editMenuKeys not found");
+    ok(document.getElementById("sourceEditorCommands"),
+       "#sourceEditorCommands found");
+    ok(document.getElementById("sourceEditorKeys"),
+       "#sourceEditorKeys found");
+
+    // Map command ids to their expected disabled state.
+    let commands = {"se-cmd-undo": true, "se-cmd-redo": true,
+                    "se-cmd-cut": true, "se-cmd-paste": true,
+                    "se-cmd-delete": true, "cmd_findAgain": true,
+                    "cmd_findPrevious": true, "cmd_find": false,
+                    "cmd_gotoLine": false, "cmd_copy": false,
+                    "se-cmd-selectAll": false};
+    for (let id in commands) {
+      let element = document.getElementById(id);
+      is(element.hasAttribute("disabled"), commands[id],
+         id + " hasAttribute('disabled') check");
+    }
+
+    executeSoon(function() {
+      contextMenu.hidePopup();
+      gDebugger.StackFrames.activeThread.resume(finish);
+    });
+  }
+
+  registerCleanupFunction(function() {
+    removeTab(gTab);
+    gPane = null;
+    gTab = null;
+    gDebuggee = null;
+    gDebugger = null;
+  });
+}
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -5,14 +5,14 @@ browser.jar:
     content/browser/scratchpad.js                 (scratchpad/scratchpad.js)
     content/browser/splitview.css                 (shared/splitview.css)
 *   content/browser/styleeditor.xul               (styleeditor/styleeditor.xul)
     content/browser/styleeditor.css               (styleeditor/styleeditor.css)
     content/browser/devtools/csshtmltree.xul      (styleinspector/csshtmltree.xul)
     content/browser/devtools/cssruleview.xul      (styleinspector/cssruleview.xul)
     content/browser/devtools/styleinspector.css   (styleinspector/styleinspector.css)
     content/browser/orion.js                      (sourceeditor/orion/orion.js)
-    content/browser/source-editor-overlay.xul     (sourceeditor/source-editor-overlay.xul)
+*   content/browser/source-editor-overlay.xul     (sourceeditor/source-editor-overlay.xul)
 *   content/browser/debugger.xul                  (debugger/debugger.xul)
     content/browser/debugger.css                  (debugger/debugger.css)
     content/browser/debugger.js                   (debugger/debugger.js)
     content/browser/debugger-view.js              (debugger/debugger-view.js)
 
--- a/browser/devtools/scratchpad/scratchpad.xul
+++ b/browser/devtools/scratchpad/scratchpad.xul
@@ -106,31 +106,16 @@
 
   <!-- TODO: bug 650340 - implement printFile
   <key id="sp-key-printFile"
        key="&printCmd.commandkey;"
        command="sp-cmd-printFile"
        modifiers="accel"/>
   -->
 
-  <key id="key_cut"
-       key="&cutCmd.key;"
-       modifiers="accel"/>
-
-  <key id="key_copy"
-       key="&copyCmd.key;"
-       modifiers="accel"/>
-  <key id="key_paste"
-       key="&pasteCmd.key;"
-       modifiers="accel"/>
-  <key id="key_selectAll" key="&selectAllCmd.key;" modifiers="accel"/>
-  <key id="key_undo" key="&undoCmd.key;" modifiers="accel"
-       command="se-cmd-undo"/>
-  <key id="key_redo" key="&undoCmd.key;" modifiers="accel,shift"
-       command="se-cmd-redo"/>
   <key id="sp-key-run"
        key="&run.key;"
        command="sp-cmd-run"
        modifiers="accel"/>
   <key id="sp-key-inspect"
        key="&inspect.key;"
        command="sp-cmd-inspect"
        modifiers="accel"/>
@@ -141,38 +126,16 @@
   <key id="sp-key-errorConsole"
        key="&errorConsoleCmd.commandkey;"
        command="sp-cmd-errorConsole"
        modifiers="accel,shift"/>
   <key id="sp-key-webConsole"
        key="&webConsoleCmd.commandkey;"
        command="sp-cmd-webConsole"
        modifiers="accel,shift"/>
-  <key id="key_find"
-       key="&findCmd.key;"
-       command="cmd_find"
-       modifiers="accel"/>
-#ifdef XP_MACOSX
-  <key id="key_findAgain"
-       key="&findAgainCmd.key;"
-       command="cmd_findAgain"
-       modifiers="accel"/>
-  <key id="key_findPrevious"
-       key="&findPreviousCmd.key;"
-       command="cmd_findPrevious"
-       modifiers="accel,shift"/>
-#else
-  <key id="key_findAgain"
-       keycode="VK_F3"
-       command="cmd_findAgain"/>
-  <key id="key_findPrevious"
-       keycode="VK_F3"
-       command="cmd_findPrevious"
-       modifiers="shift"/>
-#endif
   <key id="key_openHelp"
        keycode="VK_F1"
        command="sp-cmd-documentationLink"/>
 </keyset>
 
 
 <menubar id="sp-menubar">
   <menu id="sp-file-menu" label="&fileMenu.label;"
@@ -214,66 +177,30 @@
                 accesskey="&closeCmd.accesskey;"
                 command="sp-cmd-close"/>
     </menupopup>
   </menu>
 
   <menu id="sp-edit-menu" label="&editMenu.label;"
         accesskey="&editMenu.accesskey;">
     <menupopup id="sp-menu_editpopup"
-               onpopupshowing="goUpdateGlobalEditMenuItems()">
-      <menuitem id="sp-menu-undo"
-                label="&undoCmd.label;"
-                key="key_undo"
-                accesskey="&undoCmd.accesskey;"
-                command="se-cmd-undo"/>
-      <menuitem id="sp-menu-redo"
-                label="&redoCmd.label;"
-                key="key_redo"
-                accesskey="&redoCmd.accesskey;"
-                command="se-cmd-redo"/>
+               onpopupshowing="goUpdateSourceEditorMenuItems()">
+      <menuitem id="se-menu-undo"/>
+      <menuitem id="se-menu-redo"/>
       <menuseparator/>
-      <menuitem id="sp-menu-cut"
-                label="&cutCmd.label;"
-                key="key_cut"
-                accesskey="&cutCmd.accesskey;"
-                command="cmd_cut"/>
-      <menuitem id="sp-menu-copy"
-                label="&copyCmd.label;"
-                key="key_copy"
-                accesskey="&copyCmd.accesskey;"
-                command="cmd_copy"/>
-      <menuitem id="sp-menu-paste"
-                label="&pasteCmd.label;"
-                key="key_paste"
-                accesskey="&pasteCmd.accesskey;"
-                command="cmd_paste"/>
+      <menuitem id="se-menu-cut"/>
+      <menuitem id="se-menu-copy"/>
+      <menuitem id="se-menu-paste"/>
       <menuseparator/>
-      <menuitem id="sp-menu-selectAll"
-                label="&selectAllCmd.label;"
-                key="key_selectAll"
-                accesskey="&selectAllCmd.accesskey;"
-                command="cmd_selectAll"/>
+      <menuitem id="se-menu-selectAll"/>
       <menuseparator/>
-      <menuitem id="sp-menu-find"
-                label="&findCmd.label;"
-                accesskey="&findCmd.accesskey;"
-                key="key_find"
-                command="cmd_find"/>
-      <menuitem id="sp-menu-findAgain"
-                label="&findAgainCmd.label;"
-                accesskey="&findAgainCmd.accesskey;"
-                key="key_findAgain"
-                command="cmd_findAgain"/>
+      <menuitem id="se-menu-find"/>
+      <menuitem id="se-menu-findAgain"/>
       <menuseparator/>
-      <menuitem id="sp-menu-gotoLine"
-                label="&gotoLineCmd.label;"
-                accesskey="&gotoLineCmd.accesskey;"
-                key="key_gotoLine"
-                command="cmd_gotoLine"/>
+      <menuitem id="se-menu-gotoLine"/>
     </menupopup>
   </menu>
 
   <menu id="sp-execute-menu" label="&executeMenu.label;"
         accesskey="&executeMenu.accesskey;">
     <menupopup id="sp-menu_executepopup">
       <menuitem id="sp-text-run"
                 label="&run.label;"
@@ -333,23 +260,23 @@
                 command="sp-cmd-documentationLink"
                 key="key_openHelp"/>
     </menupopup>
   </menu>
 </menubar>
 
 <popupset id="scratchpad-popups">
   <menupopup id="scratchpad-text-popup"
-             onpopupshowing="goUpdateGlobalEditMenuItems()">
-    <menuitem id="menu_cut"/>
-    <menuitem id="menu_copy"/>
-    <menuitem id="menu_paste"/>
-    <menuitem id="menu_delete"/>
+             onpopupshowing="goUpdateSourceEditorMenuItems()">
+    <menuitem id="se-cMenu-cut"/>
+    <menuitem id="se-cMenu-copy"/>
+    <menuitem id="se-cMenu-paste"/>
+    <menuitem id="se-cMenu-delete"/>
     <menuseparator/>
-    <menuitem id="menu_selectAll"/>
+    <menuitem id="se-cMenu-selectAll"/>
     <menuseparator/>
     <menuitem id="sp-text-run"
               label="&run.label;"
               accesskey="&run.accesskey;"
               key="sp-key-run"
               command="sp-cmd-run"/>
     <menuitem id="sp-text-inspect"
               label="&inspect.label;"
@@ -365,12 +292,12 @@
     <menuitem id="sp-text-resetContext"
               label="&resetContext2.label;"
               accesskey="&resetContext2.accesskey;"
               command="sp-cmd-resetContext"/>
   </menupopup>
 </popupset>
 
 <notificationbox id="scratchpad-notificationbox" flex="1">
-  <hbox id="scratchpad-editor" flex="1" context="scratchpad-text-popup" />
+  <hbox id="scratchpad-editor" flex="1"/>
 </notificationbox>
 
 </window>
--- a/browser/devtools/scratchpad/test/browser_scratchpad_bug_699130_edit_ui_updates.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_bug_699130_edit_ui_updates.js
@@ -22,17 +22,17 @@ function test()
 }
 
 function runTests()
 {
   let sp = gScratchpadWindow.Scratchpad;
   let doc = gScratchpadWindow.document;
   let winUtils = gScratchpadWindow.QueryInterface(Ci.nsIInterfaceRequestor).
                  getInterface(Ci.nsIDOMWindowUtils);
-  let OS = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
+  let OS = Services.appinfo.OS;
 
   info("will test the Edit menu");
 
   let pass = 0;
 
   sp.setText("bug 699130: hello world! (edit menu)");
 
   let editMenu = doc.getElementById("sp-edit-menu");
@@ -46,19 +46,19 @@ function runTests()
       editMenuIndex = i;
       break;
     }
   }
   isnot(editMenuIndex, -1, "Edit menu index is correct");
 
   let menuPopup = editMenu.menupopup;
   ok(menuPopup, "the Edit menupopup");
-  let cutItem = doc.getElementById("sp-menu-cut");
+  let cutItem = doc.getElementById("se-menu-cut");
   ok(cutItem, "the Cut menuitem");
-  let pasteItem = doc.getElementById("sp-menu-paste");
+  let pasteItem = doc.getElementById("se-menu-paste");
   ok(pasteItem, "the Paste menuitem");
 
   let anchor = doc.documentElement;
   let isContextMenu = false;
 
   let openMenu = function(aX, aY, aCallback) {
     if (!editMenu || OS != "Darwin") {
       menuPopup.addEventListener("popupshown", function onPopupShown() {
@@ -169,19 +169,19 @@ function runTests()
   let testContextMenu = function() {
     info("will test the context menu");
 
     editMenu = null;
     isContextMenu = true;
 
     menuPopup = doc.getElementById("scratchpad-text-popup");
     ok(menuPopup, "the context menupopup");
-    cutItem = doc.getElementById("menu_cut");
+    cutItem = doc.getElementById("se-cMenu-cut");
     ok(cutItem, "the Cut menuitem");
-    pasteItem = doc.getElementById("menu_paste");
+    pasteItem = doc.getElementById("se-cMenu-paste");
     ok(pasteItem, "the Paste menuitem");
 
     sp.setText("bug 699130: hello world! (context menu)");
     openMenu(10, 10, firstShow);
   };
 
   openMenu(10, 10, firstShow);
 }
--- a/browser/devtools/sourceeditor/source-editor-orion.jsm
+++ b/browser/devtools/sourceeditor/source-editor-orion.jsm
@@ -19,16 +19,17 @@
  * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Mihai Sucan <mihai.sucan@gmail.com> (original author)
  *   Kenny Heaton <kennyheaton@gmail.com>
  *   Spyros Livathinos <livathinos.spyros@gmail.com>
  *   Allen Eubank <adeubank@gmail.com>
+ *   Girish Sharma <scrapmachines@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -59,16 +60,24 @@ const ORION_IFRAME = "data:text/html;cha
   " href='chrome://browser/skin/devtools/orion-container.css'></head>" +
   "<body style='height:100%;margin:0;overflow:hidden'>" +
   "<div id='editor' style='height:100%'></div>" +
   "</body></html>";
 
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 /**
+ * Maximum allowed vertical offset for the line index when you call
+ * SourceEditor.setCaretPosition().
+ *
+ * @type number
+ */
+const VERTICAL_OFFSET = 3;
+
+/**
  * The primary selection update delay. On Linux, the X11 primary selection is
  * updated to hold the currently selected text.
  *
  * @type number
  */
 const PRIMARY_SELECTION_DELAY = 100;
 
 /**
@@ -105,16 +114,20 @@ const ORION_ANNOTATION_TYPES = {
   currentLine: "orion.annotation.currentLine",
 };
 
 /**
  * Default key bindings in the Orion editor.
  */
 const DEFAULT_KEYBINDINGS = [
   {
+    action: "enter",
+    code: Ci.nsIDOMKeyEvent.DOM_VK_ENTER,
+  },
+  {
     action: "undo",
     code: Ci.nsIDOMKeyEvent.DOM_VK_Z,
     accel: true,
   },
   {
     action: "redo",
     code: Ci.nsIDOMKeyEvent.DOM_VK_Z,
     accel: true,
@@ -460,16 +473,20 @@ SourceEditor.prototype = {
 
   /**
    * The "tab" editor action implementation. This adds support for expanded tabs
    * to spaces, and support for the indentation of multiple lines at once.
    * @private
    */
   _doTab: function SE__doTab()
   {
+    if (this.readOnly) {
+      return false;
+    }
+
     let indent = "\t";
     let selection = this.getSelection();
     let model = this._model;
     let firstLine = model.getLineAtOffset(selection.start);
     let firstLineStart = model.getLineStart(firstLine);
     let lastLineOffset = selection.end > selection.start ?
                          selection.end - 1 : selection.end;
     let lastLine = model.getLineAtOffset(lastLineOffset);
@@ -510,16 +527,20 @@ SourceEditor.prototype = {
 
   /**
    * The "Unindent lines" editor action implementation. This method is invoked
    * when the user presses Shift-Tab.
    * @private
    */
   _doUnindentLines: function SE__doUnindentLines()
   {
+    if (this.readOnly) {
+      return true;
+    }
+
     let indent = "\t";
 
     let selection = this.getSelection();
     let model = this._model;
     let firstLine = model.getLineAtOffset(selection.start);
     let lastLineOffset = selection.end > selection.start ?
                          selection.end - 1 : selection.end;
     let lastLine = model.getLineAtOffset(lastLineOffset);
@@ -564,16 +585,20 @@ SourceEditor.prototype = {
 
   /**
    * The editor Enter action implementation, which adds simple automatic
    * indentation based on the previous line when the user presses the Enter key.
    * @private
    */
   _doEnter: function SE__doEnter()
   {
+    if (this.readOnly) {
+      return false;
+    }
+
     let selection = this.getSelection();
     if (selection.start != selection.end) {
       return false;
     }
 
     let model = this._model;
     let lineIndex = model.getLineAtOffset(selection.start);
     let lineText = model.getLine(lineIndex, true);
@@ -1304,20 +1329,66 @@ SourceEditor.prototype = {
 
   /**
    * Set the caret position: line and column.
    *
    * @param number aLine
    *        The new caret line location. Line numbers start from 0.
    * @param number [aColumn=0]
    *        Optional. The new caret column location. Columns start from 0.
+   * @param number [aAlign=0]
+   *        Optional. Position of the line with respect to viewport.
+   *        Allowed values are:
+   *          SourceEditor.VERTICAL_ALIGN.TOP     target line at top of view.
+   *          SourceEditor.VERTICAL_ALIGN.CENTER  target line at center of view.
+   *          SourceEditor.VERTICAL_ALIGN.BOTTOM  target line at bottom of view.
    */
-  setCaretPosition: function SE_setCaretPosition(aLine, aColumn)
+  setCaretPosition: function SE_setCaretPosition(aLine, aColumn, aAlign)
   {
-    this.setCaretOffset(this._model.getLineStart(aLine) + (aColumn || 0));
+    let editorHeight = this._view.getClientArea().height;
+    let lineHeight = this._view.getLineHeight();
+    let linesVisible = Math.floor(editorHeight/lineHeight);
+    let halfVisible = Math.round(linesVisible/2);
+    let firstVisible = this.getTopIndex();
+    let lastVisible = this._view.getBottomIndex();
+    let caretOffset = this._model.getLineStart(aLine) + (aColumn || 0);
+
+    this._view.setSelection(caretOffset, caretOffset, false);
+
+    // If the target line is in view, skip the vertical alignment part.
+    if (aLine <= lastVisible && aLine >= firstVisible) {
+      this._view.showSelection();
+      return;
+    }
+
+    // Setting the offset so that the line always falls in the upper half
+    // of visible lines (lower half for BOTTOM aligned).
+    // VERTICAL_OFFSET is the maximum allowed value.
+    let offset = Math.min(halfVisible, VERTICAL_OFFSET);
+
+    let topIndex;
+    switch (aAlign) {
+      case this.VERTICAL_ALIGN.CENTER:
+        topIndex = Math.max(aLine - halfVisible, 0);
+        break;
+
+      case this.VERTICAL_ALIGN.BOTTOM:
+        topIndex = Math.max(aLine - linesVisible + offset, 0);
+        break;
+
+      default: // this.VERTICAL_ALIGN.TOP.
+        topIndex = Math.max(aLine - offset, 0);
+        break;
+    }
+    // Bringing down the topIndex to total lines in the editor if exceeding.
+    topIndex = Math.min(topIndex, this.getLineCount());
+    this.setTopIndex(topIndex);
+
+    let location = this._view.getLocationAtOffset(caretOffset);
+    this._view.setHorizontalPixel(location.x);
   },
 
   /**
    * Get the line count.
    *
    * @return number
    *         The number of lines in the document being edited.
    */
--- a/browser/devtools/sourceeditor/source-editor-overlay.xul
+++ b/browser/devtools/sourceeditor/source-editor-overlay.xul
@@ -30,85 +30,208 @@
    - 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 ***** -->
-<!DOCTYPE overlay SYSTEM "chrome://browser/locale/devtools/sourceeditor.dtd">
+<!DOCTYPE overlay [
+  <!ENTITY % editMenuStrings SYSTEM "chrome://global/locale/editMenuOverlay.dtd">
+  %editMenuStrings;
+  <!ENTITY % sourceEditorStrings SYSTEM "chrome://browser/locale/devtools/sourceeditor.dtd">
+  %sourceEditorStrings;
+]>
 <overlay id="sourceEditorOverlay"
          xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <!-- This Source Editor overlay requires the editMenuOverlay.xul to be loaded.
        The globalOverlay.js script is also required in the XUL document where
-       the source-editor-overlay.xul is loaded. -->
+       the source-editor-overlay.xul is loaded. Do not use #editMenuKeys to
+       avoid conflicts! -->
+
+  <script type="application/javascript">
+    function goUpdateSourceEditorMenuItems()
+    {
+      goUpdateGlobalEditMenuItems();
+      let commands = ['se-cmd-undo', 'se-cmd-redo', 'se-cmd-cut', 'se-cmd-paste',
+                      'se-cmd-delete'];
+      commands.forEach(goUpdateCommand);
+    }
+  </script>
 
   <commandset id="sourceEditorCommands">
     <command id="cmd_find" oncommand="goDoCommand('cmd_find')"/>
     <command id="cmd_findAgain" oncommand="goDoCommand('cmd_findAgain')" disabled="true"/>
     <command id="cmd_findPrevious" oncommand="goDoCommand('cmd_findPrevious')" disabled="true"/>
     <command id="cmd_gotoLine" oncommand="goDoCommand('cmd_gotoLine')"/>
+    <command id="se-cmd-selectAll" oncommand="goDoCommand('se-cmd-selectAll')"/>
+    <command id="se-cmd-cut" oncommand="goDoCommand('se-cmd-cut')" disabled="true"/>
+    <command id="se-cmd-paste" oncommand="goDoCommand('se-cmd-paste')" disabled="true"/>
+    <command id="se-cmd-delete" oncommand="goDoCommand('se-cmd-delete')" disabled="true"/>
     <command id="se-cmd-undo" oncommand="goDoCommand('se-cmd-undo')" disabled="true"/>
     <command id="se-cmd-redo" oncommand="goDoCommand('se-cmd-redo')" disabled="true"/>
   </commandset>
 
   <keyset id="sourceEditorKeys">
+    <!-- Do not use both #sourceEditorKeys and #editMenuKeys in the same
+    	 document to avoid conflicts! -->
+    <key id="key_undo"
+         key="&undoCmd.key;"
+         modifiers="accel"
+         command="se-cmd-undo"/>
+#ifdef XP_UNIX
+    <key id="key_redo"
+         key="&undoCmd.key;"
+         modifiers="accel,shift"
+         command="se-cmd-redo"/>
+#else
+    <key id="key_redo"
+         key="&redoCmd.key;"
+         modifiers="accel"
+         command="se-cmd-redo"/>
+#endif
+    <key id="key_cut"
+         key="&cutCmd.key;"
+         modifiers="accel"
+         command="se-cmd-cut"/>
+    <key id="key_copy"
+         key="&copyCmd.key;"
+         modifiers="accel"
+         command="cmd_copy"/>
+    <key id="key_paste"
+         key="&pasteCmd.key;"
+         modifiers="accel"
+         command="se-cmd-paste"/>
     <key id="key_gotoLine"
          key="&gotoLineCmd.key;"
          command="cmd_gotoLine"
          modifiers="accel"/>
+    <key id="key_delete"
+         keycode="VK_DELETE"
+         command="se-cmd-delete"/>
+    <key id="key_selectAll"
+         key="&selectAllCmd.key;"
+         modifiers="accel"
+         command="se-cmd-selectAll"/>
+    <key id="key_find"
+         key="&findCmd.key;"
+         modifiers="accel"
+         command="cmd_find"/>
+    <key id="key_findAgain"
+         key="&findAgainCmd.key;"
+         modifiers="accel"
+         command="cmd_findAgain"/>
+    <key id="key_findPrevious"
+         key="&findAgainCmd.key;"
+         modifiers="shift,accel"
+         command="cmd_findPrevious"/>
+    <key id="key_findAgain2"
+         keycode="&findAgainCmd.key2;"
+         command="cmd_findAgain"/>
+    <key id="key_findPrevious2"
+         keycode="&findAgainCmd.key2;"
+         modifiers="shift"
+         command="cmd_findPrevious"/>
   </keyset>
 
-  <menupopup id="sourceEditorContextMenu"
-             onpopupshowing="goUpdateGlobalEditMenuItems()">
-    <menuitem id="se-menu-undo"
-              label="&undoCmd.label;"
-              key="key_undo"
-              accesskey="&undoCmd.accesskey;"
-              command="se-cmd-undo"/>
-    <menuseparator/>
-    <menuitem id="se-menu-cut"
-              label="&cutCmd.label;"
-              key="key_cut"
-              accesskey="&cutCmd.accesskey;"
-              command="cmd_cut"/>
-    <menuitem id="se-menu-copy"
-              label="&copyCmd.label;"
-              key="key_copy"
-              accesskey="&copyCmd.accesskey;"
-              command="cmd_copy"/>
-    <menuitem id="se-menu-paste"
-              label="&pasteCmd.label;"
-              key="key_paste"
-              accesskey="&pasteCmd.accesskey;"
-              command="cmd_paste"/>
-    <menuitem id="se-menu-delete"
-              label="&deleteCmd.label;"
-              key="key_delete"
-              accesskey="&deleteCmd.accesskey;"
-              command="cmd_delete"/>
-    <menuseparator/>
-    <menuitem id="se-menu-selectAll"
-              label="&selectAllCmd.label;"
-              key="key_selectAll"
-              accesskey="&selectAllCmd.accesskey;"
-              command="cmd_selectAll"/>
-    <menuseparator/>
-    <menuitem id="se-menu-find"
-              label="&findCmd.label;"
-              accesskey="&findCmd.accesskey;"
-              key="key_find"
-              command="cmd_find"/>
-    <menuitem id="se-menu-findAgain"
-              label="&findAgainCmd.label;"
-              accesskey="&findAgainCmd.accesskey;"
-              key="key_findAgain"
-              command="cmd_findAgain"/>
-    <menuseparator/>
-    <menuitem id="se-menu-gotoLine"
-              label="&gotoLineCmd.label;"
-              accesskey="&gotoLineCmd.accesskey;"
-              key="key_gotoLine"
-              command="cmd_gotoLine"/>
-  </menupopup>
+  <!-- Items for the Edit menu -->
+
+  <menuitem id="se-menu-undo"
+            label="&undoCmd.label;"
+            key="key_undo"
+            accesskey="&undoCmd.accesskey;"
+            command="se-cmd-undo"/>
+  <menuitem id="se-menu-redo"
+            label="&redoCmd.label;"
+            key="key_redo"
+            accesskey="&redoCmd.accesskey;"
+            command="se-cmd-redo"/>
+  <menuitem id="se-menu-cut"
+            label="&cutCmd.label;"
+            key="key_cut"
+            accesskey="&cutCmd.accesskey;"
+            command="se-cmd-cut"/>
+  <menuitem id="se-menu-copy"
+            label="&copyCmd.label;"
+            key="key_copy"
+            accesskey="&copyCmd.accesskey;"
+            command="cmd_copy"/>
+  <menuitem id="se-menu-paste"
+            label="&pasteCmd.label;"
+            key="key_paste"
+            accesskey="&pasteCmd.accesskey;"
+            command="se-cmd-paste"/>
+  <menuitem id="se-menu-delete"
+            label="&deleteCmd.label;"
+            key="key_delete"
+            accesskey="&deleteCmd.accesskey;"
+            command="se-cmd-delete"/>
+  <menuitem id="se-menu-selectAll"
+            label="&selectAllCmd.label;"
+            key="key_selectAll"
+            accesskey="&selectAllCmd.accesskey;"
+            command="se-cmd-selectAll"/>
+  <menuitem id="se-menu-find"
+            label="&findCmd.label;"
+            accesskey="&findCmd.accesskey;"
+            key="key_find"
+            command="cmd_find"/>
+  <menuitem id="se-menu-findAgain"
+            label="&findAgainCmd.label;"
+            accesskey="&findAgainCmd.accesskey;"
+            key="key_findAgain"
+            command="cmd_findAgain"/>
+  <menuitem id="se-menu-gotoLine"
+            label="&gotoLineCmd.label;"
+            accesskey="&gotoLineCmd.accesskey;"
+            key="key_gotoLine"
+            command="cmd_gotoLine"/>
+
+  <!-- Items for context menus -->
+
+  <menuitem id="se-cMenu-undo"
+            label="&undoCmd.label;"
+            key="key_undo"
+            accesskey="&undoCmd.accesskey;"
+            command="se-cmd-undo"/>
+  <menuitem id="se-cMenu-cut"
+            label="&cutCmd.label;"
+            key="key_cut"
+            accesskey="&cutCmd.accesskey;"
+            command="se-cmd-cut"/>
+  <menuitem id="se-cMenu-copy"
+            label="&copyCmd.label;"
+            key="key_copy"
+            accesskey="&copyCmd.accesskey;"
+            command="cmd_copy"/>
+  <menuitem id="se-cMenu-paste"
+            label="&pasteCmd.label;"
+            key="key_paste"
+            accesskey="&pasteCmd.accesskey;"
+            command="se-cmd-paste"/>
+  <menuitem id="se-cMenu-delete"
+            label="&deleteCmd.label;"
+            key="key_delete"
+            accesskey="&deleteCmd.accesskey;"
+            command="se-cmd-delete"/>
+  <menuitem id="se-cMenu-selectAll"
+            label="&selectAllCmd.label;"
+            key="key_selectAll"
+            accesskey="&selectAllCmd.accesskey;"
+            command="se-cmd-selectAll"/>
+  <menuitem id="se-cMenu-find"
+            label="&findCmd.label;"
+            accesskey="&findCmd.accesskey;"
+            key="key_find"
+            command="cmd_find"/>
+  <menuitem id="se-cMenu-findAgain"
+            label="&findAgainCmd.label;"
+            accesskey="&findAgainCmd.accesskey;"
+            key="key_findAgain"
+            command="cmd_findAgain"/>
+  <menuitem id="se-cMenu-gotoLine"
+            label="&gotoLineCmd.label;"
+            accesskey="&gotoLineCmd.accesskey;"
+            key="key_gotoLine"
+            command="cmd_gotoLine"/>
 </overlay>
--- a/browser/devtools/sourceeditor/source-editor-ui.jsm
+++ b/browser/devtools/sourceeditor/source-editor-ui.jsm
@@ -248,16 +248,20 @@ SourceEditorController.prototype = {
 
     switch (aCommand) {
       case "cmd_find":
       case "cmd_findAgain":
       case "cmd_findPrevious":
       case "cmd_gotoLine":
       case "se-cmd-undo":
       case "se-cmd-redo":
+      case "se-cmd-cut":
+      case "se-cmd-paste":
+      case "se-cmd-delete":
+      case "se-cmd-selectAll":
         result = true;
         break;
       default:
         result = false;
         break;
     }
 
     return result;
@@ -273,28 +277,42 @@ SourceEditorController.prototype = {
    */
   isCommandEnabled: function SEC_isCommandEnabled(aCommand)
   {
     let result;
 
     switch (aCommand) {
       case "cmd_find":
       case "cmd_gotoLine":
+      case "se-cmd-selectAll":
         result = true;
         break;
       case "cmd_findAgain":
       case "cmd_findPrevious":
         result = this._editor.lastFind && this._editor.lastFind.lastFound != -1;
         break;
       case "se-cmd-undo":
         result = this._editor.canUndo();
         break;
       case "se-cmd-redo":
         result = this._editor.canRedo();
         break;
+      case "se-cmd-cut":
+      case "se-cmd-delete": {
+        let selection = this._editor.getSelection();
+        result = selection.start != selection.end && !this._editor.readOnly;
+        break;
+      }
+      case "se-cmd-paste": {
+        let window = this._editor._view._frameWindow;
+        let controller = window.controllers.getControllerForCommand("cmd_paste");
+        result = !this._editor.readOnly &&
+                 controller.isCommandEnabled("cmd_paste");
+        break;
+      }
       default:
         result = false;
         break;
     }
 
     return result;
   },
 
@@ -315,19 +333,33 @@ SourceEditorController.prototype = {
         this._editor.ui.findNext();
         break;
       case "cmd_findPrevious":
         this._editor.ui.findPrevious();
         break;
       case "cmd_gotoLine":
         this._editor.ui.gotoLine();
         break;
+      case "se-cmd-selectAll":
+        this._editor._view.invokeAction("selectAll");
+        break;
       case "se-cmd-undo":
         this._editor.undo();
         break;
       case "se-cmd-redo":
         this._editor.redo();
         break;
+      case "se-cmd-cut":
+        this._editor.ui._ownerWindow.goDoCommand("cmd_cut");
+        break;
+      case "se-cmd-paste":
+        this._editor.ui._ownerWindow.goDoCommand("cmd_paste");
+        break;
+      case "se-cmd-delete": {
+        let selection = this._editor.getSelection();
+        this._editor.setText("", selection.start, selection.end);
+        break;
+      }
     }
   },
 
   onEvent: function() { }
 };
--- a/browser/devtools/sourceeditor/source-editor.jsm
+++ b/browser/devtools/sourceeditor/source-editor.jsm
@@ -308,16 +308,26 @@ SourceEditor.EVENTS = {
    * have not been saved yet. Event object properties: oldValue and newValue.
    * Both are booleans telling the old dirty state and the new state,
    * respectively.
    */
   DIRTY_CHANGED: "DirtyChanged",
 };
 
 /**
+ * Allowed vertical alignment options for the line index
+ * when you call SourceEditor.setCaretPosition().
+ */
+SourceEditor.VERTICAL_ALIGN = {
+  TOP: 0,
+  CENTER: 1,
+  BOTTOM: 2,
+};
+
+/**
  * Extend a destination object with properties from a source object.
  *
  * @param object aDestination
  * @param object aSource
  */
 function extend(aDestination, aSource)
 {
   for (let name in aSource) {
@@ -331,16 +341,17 @@ function extend(aDestination, aSource)
  * Add methods common to all components.
  */
 extend(SourceEditor.prototype, {
   // Expose the static constants on the SourceEditor instances.
   EVENTS: SourceEditor.EVENTS,
   MODES: SourceEditor.MODES,
   THEMES: SourceEditor.THEMES,
   DEFAULTS: SourceEditor.DEFAULTS,
+  VERTICAL_ALIGN: SourceEditor.VERTICAL_ALIGN,
 
   _lastFind: null,
 
   /**
    * Find a string in the editor.
    *
    * @param string aString
    *        The string you want to search for. If |aString| is not given the
--- a/browser/devtools/sourceeditor/test/Makefile.in
+++ b/browser/devtools/sourceeditor/test/Makefile.in
@@ -55,12 +55,13 @@ include $(topsrcdir)/config/rules.mk
 		browser_bug687160_line_api.js \
 		browser_bug650345_find.js \
 		browser_bug703692_focus_blur.js \
 		browser_bug725388_mouse_events.js \
 		browser_bug707987_debugger_breakpoints.js \
 		browser_bug712982_line_ruler_click.js \
 		browser_bug725618_moveLines_shortcut.js \
 		browser_bug700893_dirty_state.js \
+		browser_bug729480_line_vertical_align.js \
 		head.js \
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/sourceeditor/test/browser_bug729480_line_vertical_align.js
@@ -0,0 +1,99 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+let tempScope = {};
+Cu.import("resource:///modules/source-editor.jsm", tempScope);
+let SourceEditor = tempScope.SourceEditor;
+
+let testWin;
+let editor;
+const VERTICAL_OFFSET = 3;
+
+function test()
+{
+  waitForExplicitFinish();
+
+  const windowUrl = "data:application/vnd.mozilla.xul+xml,<?xml version='1.0'?>" +
+    "<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'" +
+    " title='test for bug 729480 - allow setCaretPosition align the target line" +
+    " vertically in view according to a third argument'" +
+    " width='300' height='300'><box flex='1'/></window>";
+  const windowFeatures = "chrome,titlebar,toolbar,centerscreen,dialog=no";
+
+  testWin = Services.ww.openWindow(null, windowUrl, "_blank", windowFeatures, null);
+  testWin.addEventListener("load", function onWindowLoad() {
+    testWin.removeEventListener("load", onWindowLoad, false);
+    waitForFocus(initEditor, testWin);
+  }, false);
+}
+
+function initEditor()
+{
+  let box = testWin.document.querySelector("box");
+
+  editor = new SourceEditor();
+  editor.init(box, {showLineNumbers: true}, editorLoaded);
+}
+
+function editorLoaded()
+{
+  editor.focus();
+
+  // setting 3 pages of lines containing the line number.
+  let view = editor._view;
+
+  let lineHeight = view.getLineHeight();
+  let editorHeight = view.getClientArea().height;
+  let linesPerPage = Math.floor(editorHeight / lineHeight);
+  let totalLines = 3 * linesPerPage;
+
+  let text = "";
+  for (let i = 0; i < totalLines; i++) {
+    text += "Line " + i + "\n";
+  }
+
+  editor.setText(text);
+  editor.setCaretOffset(0);
+
+  let offset = Math.min(Math.round(linesPerPage/2), VERTICAL_OFFSET);
+  // Building the iterator array.
+  // [line, alignment, topIndex_check]
+  let iterateOn = [
+    [0, "TOP", 0],
+    [25, "TOP", 25 - offset],
+    // Case when the target line is already in view.
+    [27, "TOP", 25 - offset],
+    [0, "BOTTOM", 0],
+    [5, "BOTTOM", 0],
+    [38, "BOTTOM", 38 - linesPerPage + offset],
+    [0, "CENTER", 0],
+    [4, "CENTER", 0],
+    [34, "CENTER", 34 - Math.round(linesPerPage/2)]
+  ];
+
+  function testEnd() {
+    editor.destroy();
+    testWin.close();
+    testWin = editor = null;
+    waitForFocus(finish, window);
+  }
+
+  function testPosition(pos) {
+    is(editor.getTopIndex(), iterateOn[pos][2], "scroll is correct for test #" + pos);
+    iterator(++pos);
+  }
+
+  function iterator(i) {
+    if (i == iterateOn.length) {
+      testEnd();
+    } else {
+      editor.setCaretPosition(iterateOn[i][0], 0,
+                              editor.VERTICAL_ALIGN[iterateOn[i][1]]);
+      executeSoon(testPosition.bind(this, i));
+    }
+  }
+  iterator(0);
+}
--- a/browser/devtools/sourceeditor/test/browser_sourceeditor_initialization.js
+++ b/browser/devtools/sourceeditor/test/browser_sourceeditor_initialization.js
@@ -196,21 +196,31 @@ function editorLoaded()
 
   editor.readOnly = true;
   EventUtils.synthesizeKey("b", {}, testWin);
   is(editor.getText(), "foofoo", "editor is now read-only (keyboard)");
 
   editor.setText("foobar");
   is(editor.getText(), "foobar", "editor allows programmatic changes (setText)");
 
+  EventUtils.synthesizeKey("VK_RETURN", {}, testWin);
+  is(editor.getText(), "foobar", "Enter key does nothing");
+
+  EventUtils.synthesizeKey("VK_TAB", {}, testWin);
+  is(editor.getText(), "foobar", "Tab does nothing");
+
+  editor.setText("      foobar");
+  EventUtils.synthesizeKey("VK_TAB", {shiftKey: true}, testWin);
+  is(editor.getText(), "      foobar", "Shift+Tab does nothing");
+
   editor.readOnly = false;
 
   editor.setCaretOffset(editor.getCharCount());
   EventUtils.synthesizeKey("-", {}, testWin);
-  is(editor.getText(), "foobar-", "editor is now editable again");
+  is(editor.getText(), "      foobar-", "editor is now editable again");
 
   // Test the Selection event.
 
   editor.setText("foobarbaz");
 
   editor.setSelection(1, 4);
 
   let event = null;
--- a/browser/devtools/styleeditor/styleeditor.xul
+++ b/browser/devtools/styleeditor/styleeditor.xul
@@ -52,26 +52,40 @@
         id="style-editor-chrome-window"
         title="&window.title;"
         windowtype="Tools:StyleEditor"
         width="800" height="280"
         persist="screenX screenY width height sizemode">
 <xul:script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
 
 <xul:popupset id="style-editor-popups">
-  <xul:menupopup id="sourceEditorContextMenu"/>
+  <xul:menupopup id="sourceEditorContextMenu"
+                 onpopupshowing="goUpdateSourceEditorMenuItems()">
+    <xul:menuitem id="se-cMenu-undo"/>
+    <xul:menuseparator/>
+    <xul:menuitem id="se-cMenu-cut"/>
+    <xul:menuitem id="se-cMenu-copy"/>
+    <xul:menuitem id="se-cMenu-paste"/>
+    <xul:menuitem id="se-cMenu-delete"/>
+    <xul:menuseparator/>
+    <xul:menuitem id="se-cMenu-selectAll"/>
+    <xul:menuseparator/>
+    <xul:menuitem id="se-cMenu-find"/>
+    <xul:menuitem id="se-cMenu-findAgain"/>
+    <xul:menuseparator/>
+    <xul:menuitem id="se-cMenu-gotoLine"/>
+  </xul:menupopup>
 </xul:popupset>
 
 <xul:commandset id="editMenuCommands"/>
 <xul:commandset id="sourceEditorCommands"/>
 <xul:commandset id="style-editor-commandset">
   <xul:command id="style-editor-cmd-close" oncommand="window.close();"/>
 </xul:commandset>
 
-<xul:keyset id="editMenuKeys"/>
 <xul:keyset id="sourceEditorKeys"/>
 <xul:keyset id="style-editor-keyset">
   <xul:key id="style-editor-key-close"
            key="&closeCmd.key;"
            command="style-editor-cmd-close"
            modifiers="accel"/>
 </xul:keyset>
 
--- a/browser/locales/en-US/chrome/browser/devtools/scratchpad.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/scratchpad.dtd
@@ -38,60 +38,16 @@
 
 <!ENTITY closeCmd.label               "Close">
 <!ENTITY closeCmd.key                 "W">
 <!ENTITY closeCmd.accesskey           "C">
 
 <!ENTITY editMenu.label               "Edit">
 <!ENTITY editMenu.accesskey           "E">
 
-<!ENTITY undoCmd.label                "Undo">
-<!ENTITY undoCmd.key                  "Z">
-<!ENTITY undoCmd.accesskey            "U">
-
-<!ENTITY redoCmd.label                "Redo">
-<!ENTITY redoCmd.key                  "Y">
-<!ENTITY redoCmd.accesskey            "R">
-
-<!ENTITY cutCmd.label                 "Cut">
-<!ENTITY cutCmd.key                   "X">
-<!ENTITY cutCmd.accesskey             "t">
-
-<!ENTITY copyCmd.label                "Copy">
-<!ENTITY copyCmd.key                  "C">
-<!ENTITY copyCmd.accesskey            "C">
-
-<!ENTITY pasteCmd.label               "Paste">
-<!ENTITY pasteCmd.key                 "V">
-<!ENTITY pasteCmd.accesskey           "P">
-
-<!ENTITY selectAllCmd.label           "Select All">
-<!ENTITY selectAllCmd.key             "A">
-<!ENTITY selectAllCmd.accesskey       "A">
-
-<!ENTITY findCmd.label                "Find…">
-<!ENTITY findCmd.key                  "F">
-<!ENTITY findCmd.accesskey            "F">
-
-<!ENTITY findAgainCmd.label           "Find Again…">
-<!-- LOCALIZATION NOTE (findAgainCmd.key): This key is used only on Macs.
-  -  Windows and Linux builds use the F3 key which is not localizable on purpose.
-  -->
-<!ENTITY findAgainCmd.key             "G">
-<!ENTITY findAgainCmd.accesskey       "g">
-<!-- LOCALIZATION NOTE (findPreviousCmd.key): This key is used only on Macs.
-  -  Windows and Linux builds use the Shift-F3 key which is not localizable on
-  -  purpose.
-  -->
-<!ENTITY findPreviousCmd.key          "G">
-
-<!ENTITY gotoLineCmd.label            "Jump to line…">
-<!ENTITY gotoLineCmd.key              "J">
-<!ENTITY gotoLineCmd.accesskey        "J">
-
 <!ENTITY run.label                    "Run">
 <!ENTITY run.accesskey                "R">
 <!ENTITY run.key                      "r">
 
 <!ENTITY inspect.label                "Inspect">
 <!ENTITY inspect.accesskey            "I">
 <!ENTITY inspect.key                  "i">
 
--- a/browser/locales/en-US/chrome/browser/devtools/sourceeditor.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/sourceeditor.dtd
@@ -5,28 +5,11 @@
 <!-- LOCALIZATION NOTE : FILE Do not translate commandkeys -->
 
 <!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
   - keep it in English, or another language commonly spoken among web developers.
   - You want to make that choice consistent across the developer tools.
   - A good criteria is the language in which you'd find the best
   - documentation on web development on the web. -->
 
-<!ENTITY undoCmd.label             "Undo">
-<!ENTITY undoCmd.accesskey         "U">
-<!ENTITY cutCmd.label              "Cut">
-<!ENTITY cutCmd.accesskey          "t">
-<!ENTITY copyCmd.label             "Copy">
-<!ENTITY copyCmd.accesskey         "C">
-<!ENTITY pasteCmd.label            "Paste">
-<!ENTITY pasteCmd.accesskey        "P">
-<!ENTITY deleteCmd.label           "Delete">
-<!ENTITY deleteCmd.accesskey       "D">
-<!ENTITY selectAllCmd.label        "Select All">
-<!ENTITY selectAllCmd.accesskey    "A">
-<!ENTITY findCmd.label             "Find…">
-<!ENTITY findCmd.accesskey         "F">
-<!ENTITY findAgainCmd.label        "Find Again…">
-<!ENTITY findAgainCmd.accesskey    "g">
 <!ENTITY gotoLineCmd.label         "Jump to line…">
 <!ENTITY gotoLineCmd.key           "J">
 <!ENTITY gotoLineCmd.accesskey     "J">
-
--- a/browser/themes/gnomestripe/devtools/csshtmltree.css
+++ b/browser/themes/gnomestripe/devtools/csshtmltree.css
@@ -200,17 +200,17 @@
  */
 
 .ruleview {
   background-color: #FFF;
 }
 
 .ruleview-rule-source {
   background-color: -moz-dialog;
-  color: #0091ff;
+  color: -moz-dialogText;
   padding: 2px 5px;
   cursor: pointer;
 }
 
 .ruleview-rule-source:hover {
   text-decoration: underline;
 }
 
--- a/browser/themes/pinstripe/devtools/csshtmltree.css
+++ b/browser/themes/pinstripe/devtools/csshtmltree.css
@@ -202,17 +202,17 @@
  */
 
 .ruleview {
   background-color: #FFF;
 }
 
 .ruleview-rule-source {
   background-color: -moz-dialog;
-  color: #0091ff;
+  color: -moz-dialogText;
   padding: 2px 5px;
   cursor: pointer;
 }
 
 .ruleview-rule-source:hover {
   text-decoration: underline;
 }
 
--- a/browser/themes/winstripe/devtools/csshtmltree.css
+++ b/browser/themes/winstripe/devtools/csshtmltree.css
@@ -200,17 +200,17 @@
  */
 
 .ruleview {
   background-color: #FFF;
 }
 
 .ruleview-rule-source {
   background-color: -moz-dialog;
-  color: #0091ff;
+  color: -moz-dialogText;
   padding: 2px 5px;
   cursor: pointer;
 }
 
 .ruleview-rule-source:hover {
   text-decoration: underline;
 }
 
--- a/configure.in
+++ b/configure.in
@@ -4926,16 +4926,20 @@ MOZ_ARG_HEADER(Toolkit Options)
     then
         dnl nglayout only supports building with one toolkit,
         dnl so ignore everything after the first comma (",").
         MOZ_WIDGET_TOOLKIT=`echo "$_DEFAULT_TOOLKIT" | sed -e "s/,.*$//"`
     else
         AC_MSG_ERROR([You must specify a default toolkit (perhaps $_PLATFORM_DEFAULT_TOOLKIT).])
     fi
 
+MOZ_ARG_WITHOUT_BOOL(x,
+[  --without-x              Build without X11],
+    WITHOUT_X11=1)
+
 dnl ========================================================
 dnl = Enable the toolkit as needed                         =
 dnl ========================================================
 
 case "$MOZ_WIDGET_TOOLKIT" in
 
 cairo-windows)
     MOZ_WIDGET_TOOLKIT=windows
@@ -4960,26 +4964,27 @@ cairo-gtk2|cairo-gtk2-x11)
     AC_DEFINE(MOZ_WIDGET_GTK2)
     MOZ_PDF_PRINTING=1
     MOZ_INSTRUMENT_EVENT_LOOP=1
     ;;
 
 cairo-qt)
     MOZ_WIDGET_TOOLKIT=qt
     MOZ_ENABLE_QT=1
-    MOZ_ENABLE_XREMOTE=1
+    if test -z "$WITHOUT_X11"; then
+      MOZ_ENABLE_XREMOTE=1
+      MOZ_WEBGL_GLX=1
+      MOZ_X11=1
+      AC_DEFINE(MOZ_X11)
+      XT_LIBS=
+    fi
+
     MOZ_WEBGL=1
-    MOZ_WEBGL_GLX=1
     USE_ELF_DYNSTR_GC=
-
-    AC_DEFINE(MOZ_X11)
-    MOZ_X11=1
     USE_FC_FREETYPE=1
-    XT_LIBS=
-
     TK_CFLAGS='$(MOZ_QT_CFLAGS)'
     TK_LIBS='$(MOZ_QT_LIBS)'
     AC_DEFINE(MOZ_WIDGET_QT)
     MOZ_PDF_PRINTING=1
     ;;
 
 cairo-os2)
     MOZ_WIDGET_TOOLKIT=os2
@@ -8838,16 +8843,19 @@ if test "$ac_cv___posix_fallocate" = tru
   AC_MSG_RESULT(yes)
 else
   AC_MSG_RESULT(no)
 fi
 
 dnl Check for missing components
 if test "$COMPILE_ENVIRONMENT"; then
 if test "$MOZ_X11"; then
+    if test "$WITHOUT_X11"; then
+        AC_MSG_ERROR([--without-x specified and MOZ_X11 still defined])
+    fi
     dnl ====================================================
     dnl = Check if X headers exist
     dnl ====================================================
     _SAVE_CFLAGS=$CFLAGS
     CFLAGS="$CFLAGS $XCFLAGS"
     AC_TRY_COMPILE([
         #include <stdio.h>
         #include <stdlib.h>
new file mode 100644
--- /dev/null
+++ b/content/base/public/CORSMode.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef CORSMode_h_
+#define CORSMode_h_
+
+namespace mozilla {
+
+enum CORSMode {
+  /**
+   * The default of not using CORS to validate cross-origin loads.
+   */
+  CORS_NONE,
+
+  /**
+   * Validate cross-site loads using CORS, but do not send any credentials
+   * (cookies, HTTP auth logins, etc) along with the request.
+   */
+  CORS_ANONYMOUS,
+
+  /**
+   * Validate cross-site loads using CORS, and send credentials such as cookies
+   * and HTTP auth logins along with the request.
+   */
+  CORS_USE_CREDENTIALS
+};
+
+} // namespace mozilla
+
+#endif /* CORSMode_h_ */
--- a/content/base/public/Makefile.in
+++ b/content/base/public/Makefile.in
@@ -74,35 +74,38 @@ nsContentCreatorFunctions.h \
 nsDOMFile.h \
 nsLineBreaker.h \
 nsReferencedElement.h \
 nsTreeSanitizer.h \
 nsXMLNameSpaceMap.h \
 nsIXFormsUtilityService.h \
 $(NULL)
 
-EXPORTS_NAMESPACES = mozilla/dom
+EXPORTS_NAMESPACES = mozilla/dom mozilla
 
 EXPORTS_mozilla/dom = \
 		Element.h \
 		FromParser.h \
 		$(NULL)
 
+EXPORTS_mozilla = \
+		CORSMode.h \
+		$(NULL)
+
 SDK_XPIDLSRCS   = \
 		nsISelection.idl  \
 		$(NULL)
 
 XPIDLSRCS	= \
 		nsIContentPolicy.idl        \
 		nsIDocumentEncoder.idl      \
 		nsIDOMFile.idl \
 		nsIDOMFileReader.idl \
 		nsIDOMFileList.idl \
 		nsIDOMFileException.idl \
-		nsIDOMFileError.idl \
 		nsIDOMFormData.idl \
 		nsIDOMParser.idl \
 		nsIDOMSerializer.idl \
 		nsISelectionController.idl  \
 		nsISelectionDisplay.idl  \
 		nsISelectionListener.idl  \
 		nsISelectionPrivate.idl  \
 		nsIScriptLoaderObserver.idl  \
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1614,17 +1614,53 @@ public:
 
   static JSContext *GetCurrentJSContext();
 
   /**
    * Case insensitive comparison between two strings. However it only ignores
    * case for ASCII characters a-z.
    */
   static bool EqualsIgnoreASCIICase(const nsAString& aStr1,
-                                      const nsAString& aStr2);
+                                    const nsAString& aStr2);
+
+  /**
+   * Case insensitive comparison between a string and an ASCII literal.
+   * This must ONLY be applied to an actual literal string. Do not attempt
+   * to use it with a regular char* pointer, or with a char array variable.
+   * The template trick to acquire the array length at compile time without
+   * using a macro is due to Corey Kosak, which much thanks.
+   */
+  static bool EqualsLiteralIgnoreASCIICase(const nsAString& aStr1,
+                                           const char* aStr2,
+                                           const PRUint32 len);
+#ifdef NS_DISABLE_LITERAL_TEMPLATE
+  static inline bool
+  EqualsLiteralIgnoreASCIICase(const nsAString& aStr1,
+                               const char* aStr2)
+  {
+    PRUint32 len = strlen(aStr2);
+    return EqualsLiteralIgnoreASCIICase(aStr1, aStr2, len);
+  }
+#else
+  template<int N>
+  static inline bool
+  EqualsLiteralIgnoreASCIICase(const nsAString& aStr1,
+                               const char (&aStr2)[N])
+  {
+    return EqualsLiteralIgnoreASCIICase(aStr1, aStr2, N-1);
+  }
+  template<int N>
+  static inline bool
+  EqualsLiteralIgnoreASCIICase(const nsAString& aStr1,
+                               char (&aStr2)[N])
+  {
+    const char* s = aStr2;
+    return EqualsLiteralIgnoreASCIICase(aStr1, s, N-1);
+  }
+#endif
 
   /**
    * Convert ASCII A-Z to a-z.
    */
   static void ASCIIToLower(nsAString& aStr);
   static void ASCIIToLower(const nsAString& aSource, nsAString& aDest);
 
   /**
--- a/content/base/public/nsDOMFile.h
+++ b/content/base/public/nsDOMFile.h
@@ -38,33 +38,33 @@
 
 #ifndef nsDOMFile_h__
 #define nsDOMFile_h__
 
 #include "nsICharsetDetectionObserver.h"
 #include "nsIFile.h"
 #include "nsIDOMFile.h"
 #include "nsIDOMFileList.h"
-#include "nsIDOMFileError.h"
 #include "nsIInputStream.h"
 #include "nsIJSNativeInitializer.h"
 #include "nsIMutable.h"
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsIXMLHttpRequest.h"
 #include "prmem.h"
 #include "nsAutoPtr.h"
+
+#include "mozilla/GuardObjects.h"
+#include "mozilla/StandardInteger.h"
+#include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/indexedDB/FileInfo.h"
 #include "mozilla/dom/indexedDB/FileManager.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 
-#include "mozilla/GuardObjects.h"
-#include "mozilla/StandardInteger.h"
-
 class nsIFile;
 class nsIInputStream;
 class nsIClassInfo;
 class nsIBlobBuilder;
 
 nsresult NS_NewBlobBuilder(nsISupports* *aSupports);
 
 class nsDOMFileBase : public nsIDOMFile,
@@ -358,28 +358,16 @@ public:
 
     return static_cast<nsDOMFileList*>(aSupports);
   }
 
 private:
   nsCOMArray<nsIDOMFile> mFiles;
 };
 
-class nsDOMFileError : public nsIDOMFileError
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIDOMFILEERROR
-
-  nsDOMFileError(PRUint16 aErrorCode) : mCode(aErrorCode) {}
-
-private:
-  PRUint16 mCode;
-};
-
 class NS_STACK_CLASS nsDOMFileInternalUrlHolder {
 public:
   nsDOMFileInternalUrlHolder(nsIDOMBlob* aFile, nsIPrincipal* aPrincipal
                              MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
   ~nsDOMFileInternalUrlHolder();
   nsAutoString mUrl;
 private:
   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
deleted file mode 100644
--- a/content/base/public/nsIDOMFileError.idl
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Corporation
- * Portions created by the Initial Developer are Copyright (C) 2007
- * 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 ***** */
-
-#include "domstubs.idl"
-
-[scriptable, uuid(4BDAFB64-15E2-49C1-A090-4315A7884A56)]
-interface nsIDOMFileError : nsISupports
-{
-  const unsigned short NOT_FOUND_ERR = 1;
-  const unsigned short SECURITY_ERR = 2;
-  const unsigned short ABORT_ERR = 3;
-  const unsigned short NOT_READABLE_ERR = 4;
-  const unsigned short ENCODING_ERR = 5;
-
-  readonly attribute unsigned short code;
-};
--- a/content/base/public/nsIDOMFileReader.idl
+++ b/content/base/public/nsIDOMFileReader.idl
@@ -34,19 +34,19 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIDOMEventTarget.idl"
 
 interface nsIDOMEventListener;
 interface nsIDOMBlob;
-interface nsIDOMFileError;
+interface nsIDOMDOMError;
 
-[scriptable, builtinclass, uuid(d158de26-904e-4731-b42c-8b3a4d172703)]
+[scriptable, builtinclass, uuid(faed1779-b523-4060-8c3b-7199f347b273)]
 interface nsIDOMFileReader : nsIDOMEventTarget
 {
   [implicit_jscontext]
   void readAsArrayBuffer(in nsIDOMBlob filedata);
   void readAsBinaryString(in nsIDOMBlob filedata);
   void readAsText(in nsIDOMBlob filedata, [optional] in DOMString encoding);
   void readAsDataURL(in nsIDOMBlob file);
 
@@ -54,17 +54,17 @@ interface nsIDOMFileReader : nsIDOMEvent
 
   const unsigned short EMPTY = 0;
   const unsigned short LOADING = 1;
   const unsigned short DONE = 2;
   readonly attribute unsigned short readyState;
 
   [implicit_jscontext]
   readonly attribute jsval result;
-  readonly attribute nsIDOMFileError error;
+  readonly attribute nsIDOMDOMError error;
 
   attribute nsIDOMEventListener onloadstart;
   attribute nsIDOMEventListener onprogress;
   attribute nsIDOMEventListener onload;
   attribute nsIDOMEventListener onabort;
   attribute nsIDOMEventListener onerror;
   attribute nsIDOMEventListener onloadend;
 };
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -1419,17 +1419,18 @@ public:
    * If this document is a static clone, this returns the original
    * document.
    */
   nsIDocument* GetOriginalDocument() { return mOriginalDocument; }
 
   /**
    * Called by nsParser to preload images. Can be removed and code moved
    * to nsPreloadURIs::PreloadURIs() in file nsParser.cpp whenever the
-   * parser-module is linked with gklayout-module.
+   * parser-module is linked with gklayout-module.  aCrossOriginAttr should
+   * be a void string if the attr is not present.
    */
   virtual void MaybePreLoadImage(nsIURI* uri,
                                  const nsAString& aCrossOriginAttr) = 0;
 
   /**
    * Called by nsParser to preload style sheets.  Can also be merged into
    * the parser if and when the parser is merged with libgklayout.
    */
--- a/content/base/public/nsIScriptElement.h
+++ b/content/base/public/nsIScriptElement.h
@@ -42,16 +42,17 @@
 #include "nsISupports.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
 #include "nsIScriptLoaderObserver.h"
 #include "nsWeakPtr.h"
 #include "nsIParser.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsIDOMHTMLScriptElement.h"
+#include "mozilla/CORSMode.h"
 
 #define NS_ISCRIPTELEMENT_IID \
 { 0x24ab3ff2, 0xd75e, 0x4be4, \
   { 0x8d, 0x50, 0xd6, 0x75, 0x31, 0x29, 0xab, 0x65 } }
 
 /**
  * Internal interface implemented by script elements
  */
@@ -253,16 +254,25 @@ public:
     if (!mAlreadyStarted) {
       // Need to lose parser-insertedness here to allow another script to cause
       // execution later.
       LoseParserInsertedness();
     }
     return block;
   }
 
+  /**
+   * Get the CORS mode of the script element
+   */
+  virtual mozilla::CORSMode GetCORSMode() const
+  {
+    /* Default to no CORS */
+    return mozilla::CORS_NONE;
+  }
+
 protected:
   /**
    * Processes the script if it's in the document-tree and links to or
    * contains a script. Once it has been evaluated there is no way to make it
    * reevaluate the script, you'll have to create a new element. This also means
    * that when adding a src attribute to an element that already contains an
    * inline script, the script referenced by the src attribute will not be
    * loaded.
--- a/content/base/src/FileIOObject.cpp
+++ b/content/base/src/FileIOObject.cpp
@@ -114,23 +114,23 @@ FileIOObject::ClearProgressEventTimer()
 }
 
 void
 FileIOObject::DispatchError(nsresult rv, nsAString& finalEvent)
 {
   // Set the status attribute, and dispatch the error event
   switch (rv) {
   case NS_ERROR_FILE_NOT_FOUND:
-    mError = new nsDOMFileError(nsIDOMFileError::NOT_FOUND_ERR);
+    mError = DOMError::CreateWithName(NS_LITERAL_STRING("NotFoundError"));
     break;
   case NS_ERROR_FILE_ACCESS_DENIED:
-    mError = new nsDOMFileError(nsIDOMFileError::SECURITY_ERR);
+    mError = DOMError::CreateWithName(NS_LITERAL_STRING("SecurityError"));
     break;
   default:
-    mError = new nsDOMFileError(nsIDOMFileError::NOT_READABLE_ERR);
+    mError = DOMError::CreateWithName(NS_LITERAL_STRING("NotReadableError"));
     break;
   }
 
   // Dispatch error event to signify load failure
   DispatchProgressEvent(NS_LITERAL_STRING(ERROR_STR));
   DispatchProgressEvent(finalEvent);
 }
 
@@ -253,24 +253,27 @@ FileIOObject::OnStopRequest(nsIRequest* 
   DispatchProgressEvent(termEvent);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 FileIOObject::Abort()
 {
-  if (mReadyState != 1)
+  if (mReadyState != 1) {
+    // XXX The spec doesn't say this
     return NS_ERROR_DOM_FILE_ABORT_ERR;
+  }
 
   ClearProgressEventTimer();
 
   mReadyState = 2; // There are DONE constants on multiple interfaces,
                    // but they all have value 2.
-  mError = new nsDOMFileError(nsIDOMFileError::ABORT_ERR);
+  // XXX The spec doesn't say this
+  mError = DOMError::CreateWithName(NS_LITERAL_STRING("AbortError"));
 
   nsString finalEvent;
   nsresult rv = DoAbort(finalEvent);
 
   // Dispatch the events
   DispatchProgressEvent(NS_LITERAL_STRING(ABORT_STR));
   DispatchProgressEvent(finalEvent);
 
@@ -280,16 +283,16 @@ FileIOObject::Abort()
 NS_IMETHODIMP
 FileIOObject::GetReadyState(PRUint16 *aReadyState)
 {
   *aReadyState = mReadyState;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-FileIOObject::GetError(nsIDOMFileError** aError)
+FileIOObject::GetError(nsIDOMDOMError** aError)
 {
   NS_IF_ADDREF(*aError = mError);
   return NS_OK;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/base/src/FileIOObject.h
+++ b/content/base/src/FileIOObject.h
@@ -40,18 +40,19 @@
 
 #include "nsIDOMEventTarget.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsIChannel.h"
 #include "nsIFile.h"
 #include "nsIDOMFile.h"
 #include "nsIStreamListener.h"
 #include "nsITimer.h"
+#include "nsCOMPtr.h"
 
-#include "nsCOMPtr.h"
+#include "mozilla/dom/DOMError.h"
 
 #define NS_PROGRESS_EVENT_INTERVAL 50
 
 namespace mozilla {
 namespace dom {
 
 extern const PRUint64 kUnknownSize;
 
@@ -64,17 +65,17 @@ class FileIOObject : public nsDOMEventTa
 public:
   FileIOObject();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // Common methods
   NS_METHOD Abort();
   NS_METHOD GetReadyState(PRUint16* aReadyState);
-  NS_METHOD GetError(nsIDOMFileError** aError);
+  NS_METHOD GetError(nsIDOMDOMError** aError);
 
   NS_DECL_AND_IMPL_EVENT_HANDLER(abort);
   NS_DECL_AND_IMPL_EVENT_HANDLER(error);
   NS_DECL_AND_IMPL_EVENT_HANDLER(progress);
 
   NS_DECL_NSITIMERCALLBACK
 
   NS_DECL_NSISTREAMLISTENER
@@ -103,17 +104,17 @@ protected:
   void ClearProgressEventTimer();
   void DispatchError(nsresult rv, nsAString& finalEvent);
   nsresult DispatchProgressEvent(const nsAString& aType);
 
   nsCOMPtr<nsITimer> mProgressNotifier;
   bool mProgressEventWasDelayed;
   bool mTimerIsActive;
 
-  nsCOMPtr<nsIDOMFileError> mError;
+  nsCOMPtr<nsIDOMDOMError> mError;
   nsCOMPtr<nsIChannel> mChannel;
 
   PRUint16 mReadyState;
 
   PRUint64 mTotal;
   PRUint64 mTransferred;
 };
 
--- a/content/base/src/nsAttrValue.cpp
+++ b/content/base/src/nsAttrValue.cpp
@@ -709,17 +709,17 @@ nsAttrValue::GetEnumString(nsAString& aR
   PRInt16 val = allEnumBits >> NS_ATTRVALUE_ENUMTABLEINDEX_BITS;
   const EnumTable* table = sEnumTableArray->
     ElementAt(allEnumBits & NS_ATTRVALUE_ENUMTABLEINDEX_MASK);
 
   while (table->tag) {
     if (table->value == val) {
       aResult.AssignASCII(table->tag);
       if (!aRealTag && allEnumBits & NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER) {
-        ToUpperCase(aResult);
+        nsContentUtils::ASCIIToUpper(aResult);
       }
       return;
     }
     table++;
   }
 
   NS_NOTREACHED("couldn't find value in EnumTable");
 }
@@ -1311,17 +1311,17 @@ nsAttrValue::ParseEnumValue(const nsAStr
     if (aCaseSensitive ? aValue.EqualsASCII(tableEntry->tag) :
                          aValue.LowerCaseEqualsASCII(tableEntry->tag)) {
       PRInt32 value = EnumTableEntryToValue(aTable, tableEntry);
 
       bool equals = aCaseSensitive || aValue.EqualsASCII(tableEntry->tag);
       if (!equals) {
         nsAutoString tag;
         tag.AssignASCII(tableEntry->tag);
-        ToUpperCase(tag);
+        nsContentUtils::ASCIIToUpper(tag);
         if ((equals = tag.Equals(aValue))) {
           value |= NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER;
         }
       }
       SetIntValueAndType(value, eEnum, equals ? nsnull : &aValue);
       NS_ASSERTION(GetEnumValue() == tableEntry->value,
                    "failed to store enum properly");
 
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -612,18 +612,19 @@ nsContentSink::ProcessLinkHeader(nsICont
             if (type.IsEmpty()) {
               type = value;
               type.StripWhitespace();
             }
           } else if (attr.LowerCaseEqualsLiteral("media")) {
             if (media.IsEmpty()) {
               media = value;
 
-              // HTML4.0 spec is inconsistent, make it case INSENSITIVE
-              ToLowerCase(media);
+              // The HTML5 spec is formulated in terms of the CSS3 spec,
+              // which specifies that media queries are case insensitive.
+              nsContentUtils::ASCIIToLower(media);
             }
           } else if (attr.LowerCaseEqualsLiteral("anchor")) {
             if (anchor.IsEmpty()) {
               anchor = value;
               anchor.StripWhitespace();
             }
           }
         }
@@ -752,29 +753,29 @@ nsContentSink::ProcessMETATag(nsIContent
 
   // set any HTTP-EQUIV data into document's header data as well as url
   nsAutoString header;
   aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
   if (!header.IsEmpty()) {
     nsAutoString result;
     aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
     if (!result.IsEmpty()) {
-      ToLowerCase(header);
+      nsContentUtils::ASCIIToLower(header);
       nsCOMPtr<nsIAtom> fieldAtom(do_GetAtom(header));
       rv = ProcessHeaderData(fieldAtom, result, aContent); 
     }
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
                             nsGkAtoms::handheldFriendly, eIgnoreCase)) {
     nsAutoString result;
     aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
     if (!result.IsEmpty()) {
-      ToLowerCase(result);
+      nsContentUtils::ASCIIToLower(result);
       mDocument->SetHeaderData(nsGkAtoms::handheldFriendly, result);
     }
   }
 
   return rv;
 }
 
 
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5388,16 +5388,17 @@ nsContentUtils::ASCIIToUpper(const nsASt
       *dest = (c >= 'a' && c <= 'z') ?
          c + ('A' - 'a') : c;
       ++iter;
       ++dest;
     }
   }
 }
 
+/* static */
 bool
 nsContentUtils::EqualsIgnoreASCIICase(const nsAString& aStr1,
                                       const nsAString& aStr2)
 {
   PRUint32 len = aStr1.Length();
   if (len != aStr2.Length()) {
     return false;
   }
@@ -5410,32 +5411,70 @@ nsContentUtils::EqualsIgnoreASCIICase(co
     PRUnichar c1 = *str1++;
     PRUnichar c2 = *str2++;
 
     // First check if any bits other than the 0x0020 differs
     if ((c1 ^ c2) & 0xffdf) {
       return false;
     }
 
-    // We know they only differ in the 0x0020 bit.
+    // We know they can only differ in the 0x0020 bit.
     // Likely the two chars are the same, so check that first
     if (c1 != c2) {
       // They do differ, but since it's only in the 0x0020 bit, check if it's
       // the same ascii char, but just differing in case
       PRUnichar c1Upper = c1 & 0xffdf;
       if (!('A' <= c1Upper && c1Upper <= 'Z')) {
         return false;
       }
     }
   }
 
   return true;
 }
 
 /* static */
+bool
+nsContentUtils::EqualsLiteralIgnoreASCIICase(const nsAString& aStr1,
+                                             const char* aStr2,
+                                             const PRUint32 len)
+{
+  if (aStr1.Length() != len) {
+    return false;
+  }
+  
+  const PRUnichar* str1 = aStr1.BeginReading();
+  const char*      str2 = aStr2;
+  const PRUnichar* end = str1 + len;
+  
+  while (str1 < end) {
+    PRUnichar c1 = *str1++;
+    PRUnichar c2 = *str2++;
+
+    // First check if any bits other than the 0x0020 differs
+    if ((c1 ^ c2) & 0xffdf) {
+      return false;
+    }
+    
+    // We know they can only differ in the 0x0020 bit.
+    // Likely the two chars are the same, so check that first
+    if (c1 != c2) {
+      // They do differ, but since it's only in the 0x0020 bit, check if it's
+      // the same ascii char, but just differing in case
+      PRUnichar c1Upper = c1 & 0xffdf;
+      if (!('A' <= c1Upper && c1Upper <= 'Z')) {
+        return false;
+      }
+    }
+  }
+  
+  return true;
+}
+
+/* static */
 nsIInterfaceRequestor*
 nsContentUtils::GetSameOriginChecker()
 {
   if (!sSameOriginChecker) {
     sSameOriginChecker = new nsSameOriginChecker();
     NS_IF_ADDREF(sSameOriginChecker);
   }
   return sSameOriginChecker;
--- a/content/base/src/nsDOMAttribute.cpp
+++ b/content/base/src/nsDOMAttribute.cpp
@@ -205,21 +205,21 @@ nsDOMAttribute::GetName(nsAString& aName
 already_AddRefed<nsIAtom>
 nsDOMAttribute::GetNameAtom(nsIContent* aContent)
 {
   nsIAtom* result = nsnull;
   if (!mNsAware &&
       mNodeInfo->NamespaceID() == kNameSpaceID_None &&
       aContent->IsInHTMLDocument() &&
       aContent->IsHTML()) {
-    nsAutoString name;
-    mNodeInfo->NameAtom()->ToString(name);
-    nsAutoString lower;
-    ToLowerCase(name, lower);
-    nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(lower);
+    nsString name;
+    mNodeInfo->GetName(name);
+    nsAutoString lowercaseName;
+    nsContentUtils::ASCIIToLower(name, lowercaseName);
+    nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(lowercaseName);
     nameAtom.swap(result);
   } else {
     nsCOMPtr<nsIAtom> nameAtom = mNodeInfo->NameAtom();
     nameAtom.swap(result);
   }
   return result;
 }
 
--- a/content/base/src/nsDOMAttributeMap.cpp
+++ b/content/base/src/nsDOMAttributeMap.cpp
@@ -330,19 +330,17 @@ nsDOMAttributeMap::SetNamedItemInternal(
       ni = mContent->GetExistingAttrNameFromQName(name);
       if (ni) {
         rv = RemoveAttribute(ni, getter_AddRefs(tmpReturn));
         NS_ENSURE_SUCCESS(rv, rv);
       }
       else {
         if (mContent->IsInHTMLDocument() &&
             mContent->IsHTML()) {
-          nsAutoString lower;
-          ToLowerCase(name, lower);
-          name = lower;
+          nsContentUtils::ASCIIToLower(name);
         }
 
         rv = mContent->NodeInfo()->NodeInfoManager()->
           GetNodeInfo(name, nsnull, kNameSpaceID_None,
                       nsIDOMNode::ATTRIBUTE_NODE, getter_AddRefs(ni));
         NS_ENSURE_SUCCESS(rv, rv);
         // value is already empty
       }
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -628,37 +628,16 @@ NS_IMETHODIMP
 nsDOMFileList::Item(PRUint32 aIndex, nsIDOMFile **aFile)
 {
   NS_IF_ADDREF(*aFile = GetItemAt(aIndex));
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// nsDOMFileError implementation
-
-DOMCI_DATA(FileError, nsDOMFileError)
-
-NS_INTERFACE_MAP_BEGIN(nsDOMFileError)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFileError)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMFileError)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(FileError)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_ADDREF(nsDOMFileError)
-NS_IMPL_RELEASE(nsDOMFileError)
-
-NS_IMETHODIMP
-nsDOMFileError::GetCode(PRUint16* aCode)
-{
-  *aCode = mCode;
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////////
 // nsDOMFileInternalUrlHolder implementation
 
 nsDOMFileInternalUrlHolder::nsDOMFileInternalUrlHolder(nsIDOMBlob* aFile,
                                                        nsIPrincipal* aPrincipal
                                                        MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) {
   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
   aFile->GetInternalUrl(aPrincipal, mUrl);
 }
--- a/content/base/src/nsDOMFileReader.cpp
+++ b/content/base/src/nsDOMFileReader.cpp
@@ -250,17 +250,17 @@ nsDOMFileReader::GetResult(JSContext* aC
   nsString tmpResult = mResult;
   if (!xpc::StringToJsval(aCx, tmpResult, aResult)) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMFileReader::GetError(nsIDOMFileError** aError)
+nsDOMFileReader::GetError(nsIDOMDOMError** aError)
 {
   return FileIOObject::GetError(aError);
 }
 
 NS_IMETHODIMP
 nsDOMFileReader::ReadAsArrayBuffer(nsIDOMBlob* aFile, JSContext* aCx)
 {
   return ReadFileContent(aCx, aFile, EmptyString(), FILE_AS_ARRAYBUFFER);
--- a/content/base/src/nsDOMFileReader.h
+++ b/content/base/src/nsDOMFileReader.h
@@ -49,17 +49,16 @@
 #include "prtime.h"                
 #include "nsITimer.h"              
 #include "nsICharsetDetector.h"
 #include "nsICharsetDetectionObserver.h"
 
 #include "nsIDOMFile.h"
 #include "nsIDOMFileReader.h"
 #include "nsIDOMFileList.h"
-#include "nsIDOMFileError.h"
 #include "nsIInputStream.h"
 #include "nsCOMPtr.h"
 #include "nsIStreamLoader.h"
 #include "nsIChannel.h"
 #include "prmem.h"
 
 #include "FileIOObject.h"
 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -3242,24 +3242,37 @@ nsDocument::MaybeRescheduleAnimationFram
 
 void
 nsIDocument::TakeFrameRequestCallbacks(FrameRequestCallbackList& aCallbacks)
 {
   aCallbacks.AppendElements(mFrameRequestCallbacks);
   mFrameRequestCallbacks.Clear();
 }
 
+PLDHashOperator RequestDiscardEnumerator(imgIRequest* aKey,
+                                         PRUint32 aData,
+                                         void* userArg)
+{
+  aKey->RequestDiscard();
+  return PL_DHASH_NEXT;
+}
+
 void
 nsDocument::DeleteShell()
 {
   mExternalResourceMap.HideViewers();
   if (IsEventHandlingEnabled()) {
     RevokeAnimationFrameNotifications();
   }
 
+  // When our shell goes away, request that all our images be immediately
+  // discarded, so we don't carry around decoded image data for a document we
+  // no longer intend to paint.
+  mImageTracker.EnumerateRead(RequestDiscardEnumerator, nsnull);
+
   mPresShell = nsnull;
 }
 
 void
 nsDocument::RevokeAnimationFrameNotifications()
 {
   if (!mFrameRequestCallbacks.IsEmpty()) {
     mPresShell->GetPresContext()->RefreshDriver()->
@@ -4409,17 +4422,17 @@ nsDocument::CreateElement(const nsAStrin
   *aReturn = nsnull;
 
   nsresult rv = nsContentUtils::CheckQName(aTagName, false);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool needsLowercase = IsHTML() && !IsLowercaseASCII(aTagName);
   nsAutoString lcTagName;
   if (needsLowercase) {
-    ToLowerCase(aTagName, lcTagName);
+    nsContentUtils::ASCIIToLower(aTagName, lcTagName);
   }
 
   rv = CreateElem(needsLowercase ? lcTagName : aTagName,
                   nsnull, mDefaultElementType, aReturn);
   return rv;
 }
 
 NS_IMETHODIMP
@@ -7719,24 +7732,30 @@ nsDocument::MaybePreLoadImage(nsIURI* ur
   PRInt16 blockingStatus;
   if (nsContentUtils::IsImageInCache(uri) ||
       !nsContentUtils::CanLoadImage(uri, static_cast<nsIDocument *>(this),
                                     this, NodePrincipal(), &blockingStatus)) {
     return;
   }
 
   nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
-  if (aCrossOriginAttr.LowerCaseEqualsLiteral("anonymous")) {
+  switch (nsGenericElement::StringToCORSMode(aCrossOriginAttr)) {
+  case CORS_NONE:
+    // Nothing to do
+    break;
+  case CORS_ANONYMOUS:
     loadFlags |= imgILoader::LOAD_CORS_ANONYMOUS;
-  } else if (aCrossOriginAttr.LowerCaseEqualsLiteral("use-credentials")) {
+    break;
+  case CORS_USE_CREDENTIALS:
     loadFlags |= imgILoader::LOAD_CORS_USE_CREDENTIALS;
-  }
-  // else should we err on the side of not doing the preload if
-  // aCrossOriginAttr is nonempty?  Let's err on the side of doing the
-  // preload as CORS_NONE.
+    break;
+  default:
+    /* should never happen */
+    MOZ_NOT_REACHED("Unknown CORS mode!");
+  }
 
   // Image not in cache - trigger preload
   nsCOMPtr<imgIRequest> request;
   nsresult rv =
     nsContentUtils::LoadImage(uri,
                               this,
                               NodePrincipal(),
                               mDocumentURI, // uri of document used as referrer
@@ -8304,36 +8323,42 @@ nsDocument::RemoveImage(imgIRequest* aIm
   NS_ABORT_IF_FALSE(found, "Removing image that wasn't in the tracker!");
   NS_ABORT_IF_FALSE(count > 0, "Entry in the cache tracker with count 0!");
 
   // We're removing, so decrement the count.
   count--;
 
   // If the count is now zero, remove from the tracker.
   // Otherwise, set the new value.
-  if (count == 0) {
-    mImageTracker.Remove(aImage);
-  } else {
+  if (count != 0) {
     mImageTracker.Put(aImage, count);
-  }
+    return NS_OK;
+  }
+
+  mImageTracker.Remove(aImage);
 
   nsresult rv = NS_OK;
 
-  // If we removed the image from the tracker and we're locking images, unlock
-  // this image.
-  if (count == 0 && mLockingImages)
+  // Now that we're no longer tracking this image, unlock it if we'd
+  // previously locked it.
+  if (mLockingImages) {
     rv = aImage->UnlockImage();
-
-  // If we removed the image from the tracker and we're animating images,
-  // remove our request to animate this image.
-  if (count == 0 && mAnimatingImages) {
+  }
+
+  // If we're animating images, remove our request to animate this one.
+  if (mAnimatingImages) {
     nsresult rv2 = aImage->DecrementAnimationConsumers();
     rv = NS_SUCCEEDED(rv) ? rv2 : rv;
   }
 
+  // Request that the image be discarded if nobody else holds a lock on it.
+  // Do this even if !mLockingImages, because even if we didn't just unlock
+  // this image, it might still be a candidate for discarding.
+  aImage->RequestDiscard();
+
   return rv;
 }
 
 PLDHashOperator LockEnumerator(imgIRequest* aKey,
                                PRUint32 aData,
                                void*    userArg)
 {
   aKey->LockImage();
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -154,16 +154,18 @@
 #include "nsSVGFeatures.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsCycleCollector.h"
 #include "xpcpublic.h"
 #include "xpcprivate.h"
 #include "nsLayoutStatics.h"
 #include "mozilla/Telemetry.h"
 
+#include "mozilla/CORSMode.h"
+
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_DEFINE_IID(kThisPtrOffsetsSID, NS_THISPTROFFSETS_SID);
 
 PRInt32 nsIContent::sTabFocusModel = eTabFocus_any;
 bool nsIContent::sTabFocusModelAppliesToXUL = false;
 PRUint32 nsMutationGuard::sMutationCount = 0;
@@ -2848,25 +2850,26 @@ nsresult
 nsGenericElement::GetAttributeNS(const nsAString& aNamespaceURI,
                                  const nsAString& aLocalName,
                                  nsAString& aReturn)
 {
   PRInt32 nsid =
     nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
 
   if (nsid == kNameSpaceID_Unknown) {
-    // Unknown namespace means no attr...
-
-    aReturn.Truncate();
-
+    // Unknown namespace means no attribute.
+    SetDOMStringToNull(aReturn);
     return NS_OK;
   }
 
   nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
-  GetAttr(nsid, name, aReturn);
+  bool hasAttr = GetAttr(nsid, name, aReturn);
+  if (!hasAttr) {
+    SetDOMStringToNull(aReturn);
+  }
 
   return NS_OK;
 }
 
 nsresult
 nsGenericElement::SetAttributeNS(const nsAString& aNamespaceURI,
                                  const nsAString& aQualifiedName,
                                  const nsAString& aValue)
@@ -6230,16 +6233,58 @@ nsINode::SizeOfExcludingThis(nsMallocSiz
 
 size_t
 nsGenericElement::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
 {
   return Element::SizeOfExcludingThis(aMallocSizeOf) +
          mAttrsAndChildren.SizeOfExcludingThis(aMallocSizeOf);
 }
 
+static const nsAttrValue::EnumTable kCORSAttributeTable[] = {
+  // Order matters here
+  // See ParseCORSValue
+  { "anonymous",       CORS_ANONYMOUS       },
+  { "use-credentials", CORS_USE_CREDENTIALS },
+  { 0 }
+};
+
+/* static */ void
+nsGenericElement::ParseCORSValue(const nsAString& aValue,
+                                 nsAttrValue& aResult)
+{
+  DebugOnly<bool> success =
+    aResult.ParseEnumValue(aValue, kCORSAttributeTable, false,
+                           // default value is anonymous if aValue is
+                           // not a value we understand
+                           &kCORSAttributeTable[0]);
+  MOZ_ASSERT(success);
+}
+
+/* static */ CORSMode
+nsGenericElement::StringToCORSMode(const nsAString& aValue)
+{
+  if (aValue.IsVoid()) {
+    return CORS_NONE;
+  }
+
+  nsAttrValue val;
+  nsGenericElement::ParseCORSValue(aValue, val);
+  return CORSMode(val.GetEnumValue());
+}
+
+/* static */ CORSMode
+nsGenericElement::AttrValueToCORSMode(const nsAttrValue* aValue)
+{
+  if (!aValue) {
+    return CORS_NONE;
+  }
+
+  return CORSMode(aValue->GetEnumValue());
+}
+
 #define EVENT(name_, id_, type_, struct_)                                    \
   NS_IMETHODIMP nsINode::GetOn##name_(JSContext *cx, jsval *vp) {            \
     nsEventListenerManager *elm = GetListenerManager(false);              \
     if (elm) {                                                               \
       elm->GetJSEventListener(nsGkAtoms::on##name_, vp);                     \
     } else {                                                                 \
       *vp = JSVAL_NULL;                                                      \
     }                                                                        \
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -60,16 +60,17 @@
 #include "nsIDOMNodeSelector.h"
 #include "nsIDOMXPathNSResolver.h"
 #include "nsPresContext.h"
 #include "nsIDOMDOMStringMap.h"
 #include "nsContentList.h"
 #include "nsDOMClassInfoID.h" // DOMCI_DATA
 #include "nsIDOMTouchEvent.h"
 #include "nsIInlineEventHandlers.h"
+#include "mozilla/CORSMode.h"
 
 #include "nsISMILAttr.h"
 
 class nsIDOMAttr;
 class nsIDOMEventListener;
 class nsIFrame;
 class nsIDOMNamedNodeMap;
 class nsICSSDeclaration;
@@ -635,16 +636,35 @@ public:
   static bool CanSkipInCC(nsINode* aNode);
   static bool CanSkipThis(nsINode* aNode);
   static void MarkNodeChildren(nsINode* aNode);
   static void InitCCCallbacks();
   static void MarkUserData(void* aObject, nsIAtom* aKey, void* aChild,
                            void *aData);
   static void MarkUserDataHandler(void* aObject, nsIAtom* aKey, void* aChild,
                                   void* aData);
+
+  /**
+   * Parse a string into an nsAttrValue for a CORS attribute.  This
+   * never fails.  The resulting value is an enumerated value whose
+   * GetEnumValue() returns one of the above constants.
+   */
+  static void ParseCORSValue(const nsAString& aValue, nsAttrValue& aResult);
+
+  /**
+   * Return the CORS mode for a given string
+   */
+  static mozilla::CORSMode StringToCORSMode(const nsAString& aValue);
+  
+  /**
+   * Return the CORS mode for a given nsAttrValue (which may be null,
+   * but if not should have been parsed via ParseCORSValue).
+   */
+  static mozilla::CORSMode AttrValueToCORSMode(const nsAttrValue* aValue);
+
 protected:
   /*
    * Named-bools for use with SetAttrAndNotify to make call sites easier to
    * read.
    */
   static const bool kFireMutationEvent           = true;
   static const bool kDontFireMutationEvent       = false;
   static const bool kNotifyDocumentObservers     = true;
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1999,18 +1999,20 @@ GK_ATOM(mixed, "mixed")
 GK_ATOM(multiline, "multiline")
 GK_ATOM(password, "password")
 GK_ATOM(posinset, "posinset") 
 GK_ATOM(select1, "select1")
 GK_ATOM(setsize, "setsize")
 GK_ATOM(tableCellIndex, "table-cell-index")
 GK_ATOM(textAlign, "text-align")
 GK_ATOM(textIndent, "text-indent")
+GK_ATOM(textLineThroughColor, "text-line-through-color")
 GK_ATOM(textLineThroughStyle, "text-line-through-style")
 GK_ATOM(textPosition, "text-position")
+GK_ATOM(textUnderlineColor, "text-underline-color")
 GK_ATOM(textUnderlineStyle, "text-underline-style")
 GK_ATOM(toolbarname, "toolbarname")
 GK_ATOM(toolbarseparator, "toolbarseparator")
 GK_ATOM(toolbarspacer, "toolbarspacer")
 GK_ATOM(toolbarspring, "toolbarspring")
 GK_ATOM(_undefined, "undefined")
 GK_ATOM(xmlroles, "xml-roles")
 #endif
--- a/content/base/src/nsImageLoadingContent.cpp
+++ b/content/base/src/nsImageLoadingContent.cpp
@@ -55,17 +55,17 @@
 #include "nsContentPolicyUtils.h"
 #include "nsIURI.h"
 #include "nsILoadGroup.h"
 #include "imgIContainer.h"
 #include "imgILoader.h"
 #include "nsThreadUtils.h"
 #include "nsNetUtil.h"
 #include "nsAsyncDOMEvent.h"
-#include "nsGenericHTMLElement.h"
+#include "nsGenericElement.h"
 
 #include "nsIPresShell.h"
 #include "nsEventStates.h"
 #include "nsGUIEvent.h"
 
 #include "nsIChannel.h"
 #include "nsIStreamListener.h"
 
@@ -77,16 +77,18 @@
 #include "nsIContentPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsEventDispatcher.h"
 #include "nsSVGEffects.h"
 
 #include "mozAutoDocUpdate.h"
 #include "mozilla/dom/Element.h"
 
+using namespace mozilla;
+
 #ifdef DEBUG_chb
 static void PrintReqURL(imgIRequest* req) {
   if (!req) {
     printf("(null req)\n");
     return;
   }
 
   nsCOMPtr<nsIURI> uri;
@@ -770,19 +772,19 @@ nsImageLoadingContent::LoadImage(nsIURI*
   if (!NS_CP_ACCEPTED(cpDecision)) {
     FireEvent(NS_LITERAL_STRING("error"));
     SetBlockedRequest(aNewURI, cpDecision);
     return NS_OK;
   }
 
   nsLoadFlags loadFlags = aLoadFlags;
   PRInt32 corsmode = GetCORSMode();
-  if (corsmode == nsGenericHTMLElement::CORS_ANONYMOUS) {
+  if (corsmode == CORS_ANONYMOUS) {
     loadFlags |= imgILoader::LOAD_CORS_ANONYMOUS;
-  } else if (corsmode == nsGenericHTMLElement::CORS_USE_CREDENTIALS) {
+  } else if (corsmode == CORS_USE_CREDENTIALS) {
     loadFlags |= imgILoader::LOAD_CORS_USE_CREDENTIALS;
   }
 
   // Not blocked. Do the load.
   nsCOMPtr<imgIRequest>& req = PrepareNextRequest();
   nsresult rv;
   rv = nsContentUtils::LoadImage(aNewURI, aDocument,
                                  aDocument->NodePrincipal(),
@@ -1182,13 +1184,13 @@ nsImageLoadingContent::CreateStaticImage
   aDest->mStateChangerDepth = mStateChangerDepth;
   aDest->mIsImageStateForced = mIsImageStateForced;
   aDest->mLoading = mLoading;
   aDest->mBroken = mBroken;
   aDest->mUserDisabled = mUserDisabled;
   aDest->mSuppressed = mSuppressed;
 }
 
-nsGenericHTMLElement::CORSMode
+CORSMode
 nsImageLoadingContent::GetCORSMode()
 {
-  return nsGenericHTMLElement::CORS_NONE;
+  return CORS_NONE;
 }
--- a/content/base/src/nsImageLoadingContent.h
+++ b/content/base/src/nsImageLoadingContent.h
@@ -49,16 +49,17 @@
 #include "nsINode.h"
 #include "imgIRequest.h"
 #include "prtypes.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h" // NS_CONTENT_DELETE_LIST_MEMBER
 #include "nsString.h"
 #include "nsEventStates.h"
 #include "nsGenericHTMLElement.h"
+#include "mozilla/CORSMode.h"
 
 class nsIURI;
 class nsIDocument;
 class imgILoader;
 class nsIIOService;
 
 class nsImageLoadingContent : public nsIImageLoadingContent
 {
@@ -178,17 +179,17 @@ protected:
   // Sets blocking state only if the desired state is different from the
   // current one. See the comment for mBlockingOnload for more information.
   void SetBlockingOnload(bool aBlocking);
 
   /**
    * Returns the CORS mode that will be used for all future image loads. The
    * default implementation returns CORS_NONE unconditionally.
    */
-  virtual nsGenericHTMLElement::CORSMode GetCORSMode();
+  virtual mozilla::CORSMode GetCORSMode();
 
 private:
   /**
    * Struct used to manage the image observers.
    */
   struct ImageObserver {
     ImageObserver(imgIDecoderObserver* aObserver) :
       mObserver(aObserver),
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -69,37 +69,44 @@
 #include "nsThreadUtils.h"
 #include "nsDocShellCID.h"
 #include "nsIContentSecurityPolicy.h"
 #include "prlog.h"
 #include "nsIChannelPolicy.h"
 #include "nsChannelPolicy.h"
 #include "nsCRT.h"
 #include "nsContentCreatorFunctions.h"
+#include "nsGenericElement.h"
+#include "nsCrossSiteListenerProxy.h"
 
 #include "mozilla/FunctionTimer.h"
+#include "mozilla/CORSMode.h"
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gCspPRLog;
 #endif
 
+using namespace mozilla;
 using namespace mozilla::dom;
 
 //////////////////////////////////////////////////////////////
 // Per-request data structure
 //////////////////////////////////////////////////////////////
 
 class nsScriptLoadRequest : public nsISupports {
 public:
   nsScriptLoadRequest(nsIScriptElement* aElement,
-                      PRUint32 aVersion)
+                      PRUint32 aVersion,
+                      CORSMode aCORSMode)
     : mElement(aElement),
       mLoading(true),
       mIsInline(true),
-      mJSVersion(aVersion), mLineNo(1)
+      mJSVersion(aVersion),
+      mLineNo(1),
+      mCORSMode(aCORSMode)
   {
   }
 
   NS_DECL_ISUPPORTS
 
   void FireScriptAvailable(nsresult aResult)
   {
     mElement->ScriptAvailable(aResult, mElement, mIsInline, mURI, mLineNo);
@@ -117,16 +124,17 @@ public:
   nsCOMPtr<nsIScriptElement> mElement;
   bool mLoading;             // Are we still waiting for a load to complete?
   bool mIsInline;            // Is the script inline or loaded?
   nsString mScriptText;              // Holds script for loaded scripts
   PRUint32 mJSVersion;
   nsCOMPtr<nsIURI> mURI;
   nsCOMPtr<nsIPrincipal> mOriginPrincipal;
   PRInt32 mLineNo;
+  const CORSMode mCORSMode;
 };
 
 // The nsScriptLoadRequest is passed as the context to necko, and thus
 // it needs to be threadsafe. Necko won't do anything with this
 // context, but it will AddRef and Release it on other threads.
 NS_IMPL_THREADSAFE_ISUPPORTS0(nsScriptLoadRequest)
 
 //////////////////////////////////////////////////////////////
@@ -288,17 +296,16 @@ nsScriptLoader::StartLoad(nsScriptLoadRe
                          ? static_cast<nsISupports *>(aRequest->mElement.get())
                          : static_cast<nsISupports *>(mDocument);
   nsresult rv = ShouldLoadScript(mDocument, context, aRequest->mURI, aType);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   nsCOMPtr<nsILoadGroup> loadGroup = mDocument->GetDocumentLoadGroup();
-  nsCOMPtr<nsIStreamLoader> loader;
 
   nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mDocument->GetScriptGlobalObject()));
   if (!window) {
     return NS_ERROR_NULL_POINTER;
   }
 
   nsIDocShell *docshell = window->GetDocShell();
 
@@ -327,20 +334,31 @@ nsScriptLoader::StartLoad(nsScriptLoadRe
   if (httpChannel) {
     // HTTP content negotation has little value in this context.
     httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
                                   NS_LITERAL_CSTRING("*/*"),
                                   false);
     httpChannel->SetReferrer(mDocument->GetDocumentURI());
   }
 
+  nsCOMPtr<nsIStreamLoader> loader;
   rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = channel->AsyncOpen(loader, aRequest);
+  nsCOMPtr<nsIStreamListener> listener = loader.get();
+
+  if (aRequest->mCORSMode != CORS_NONE) {
+    bool withCredentials = (aRequest->mCORSMode == CORS_USE_CREDENTIALS);
+    listener =
+      new nsCORSListenerProxy(listener, mDocument->NodePrincipal(), channel,
+                              withCredentials, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  rv = channel->AsyncOpen(listener, aRequest);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 bool
 nsScriptLoader::PreloadURIComparator::Equals(const PreloadInfo &aPi,
                                              nsIURI * const &aURI) const
@@ -546,42 +564,44 @@ nsScriptLoader::ProcessScriptElement(nsI
 
   nsRefPtr<nsScriptLoadRequest> request;
   if (aElement->GetScriptExternal()) {
     // external script
     nsCOMPtr<nsIURI> scriptURI = aElement->GetScriptURI();
     if (!scriptURI) {
       return false;
     }
+    CORSMode ourCORSMode = aElement->GetCORSMode();
     nsTArray<PreloadInfo>::index_type i =
       mPreloads.IndexOf(scriptURI.get(), 0, PreloadURIComparator());
     if (i != nsTArray<PreloadInfo>::NoIndex) {
       // preloaded
       // note that a script-inserted script can steal a preload!
       request = mPreloads[i].mRequest;
       request->mElement = aElement;
       nsString preloadCharset(mPreloads[i].mCharset);
       mPreloads.RemoveElementAt(i);
 
       // Double-check that the charset the preload used is the same as
       // the charset we have now.
       nsAutoString elementCharset;
       aElement->GetScriptCharset(elementCharset);
-      if (elementCharset.Equals(preloadCharset)) {
+      if (elementCharset.Equals(preloadCharset) &&
+          ourCORSMode == request->mCORSMode) {
         rv = CheckContentPolicy(mDocument, aElement, request->mURI, type);
         NS_ENSURE_SUCCESS(rv, false);
       } else {
         // Drop the preload
         request = nsnull;
       }
     }
 
     if (!request) {
       // no usable preload
-      request = new nsScriptLoadRequest(aElement, version);
+      request = new nsScriptLoadRequest(aElement, version, ourCORSMode);
       request->mURI = scriptURI;
       request->mIsInline = false;
       request->mLoading = true;
       rv = StartLoad(request, type);
       NS_ENSURE_SUCCESS(rv, false);
     }
 
     request->mJSVersion = version;
@@ -692,17 +712,18 @@ nsScriptLoader::ProcessScriptElement(nsI
       csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT,
                                NS_ConvertUTF8toUTF16(asciiSpec),
                                scriptText,
                                aElement->GetScriptLineNumber());
       return false;
     }
   }
 
-  request = new nsScriptLoadRequest(aElement, version);
+  // Inline scripts ignore ther CORS mode and are always CORS_NONE
+  request = new nsScriptLoadRequest(aElement, version, CORS_NONE);
   request->mJSVersion = version;
   request->mLoading = false;
   request->mIsInline = true;
   request->mURI = mDocument->GetDocumentURI();
   request->mLineNo = aElement->GetScriptLineNumber();
 
   if (aElement->GetParserCreated() == FROM_PARSER_XSLT &&
       (!ReadyToExecuteScripts() || !mXSLTRequests.IsEmpty())) {
@@ -1223,19 +1244,24 @@ nsScriptLoader::PrepareLoadedRequest(nsS
     bool requestSucceeded;
     rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
     if (NS_SUCCEEDED(rv) && !requestSucceeded) {
       return NS_ERROR_NOT_AVAILABLE;
     }
   }
 
   nsCOMPtr<nsIChannel> channel = do_QueryInterface(req);
-  rv = nsContentUtils::GetSecurityManager()->
-    GetChannelPrincipal(channel, getter_AddRefs(aRequest->mOriginPrincipal));
-  NS_ENSURE_SUCCESS(rv, rv);
+  // If this load was subject to a CORS check; don't flag it with a
+  // separate origin principal, so that it will treat our document's
+  // principal as the origin principal
+  if (aRequest->mCORSMode == CORS_NONE) {
+    rv = nsContentUtils::GetSecurityManager()->
+      GetChannelPrincipal(channel, getter_AddRefs(aRequest->mOriginPrincipal));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
 
   if (aStringLen) {
     // Check the charset attribute to determine script charset.
     nsAutoString hintCharset;
     if (!aRequest->IsPreload()) {
       aRequest->mElement->GetScriptCharset(hintCharset);
     } else {
       nsTArray<PreloadInfo>::index_type i =
@@ -1320,24 +1346,27 @@ nsScriptLoader::ParsingComplete(bool aTe
 
   // Have to call this even if aTerminated so we'll correctly unblock
   // onload and all.
   ProcessPendingRequests();
 }
 
 void
 nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
-                           const nsAString &aType)
+                           const nsAString &aType,
+                           const nsAString &aCrossOrigin)
 {
   // Check to see if scripts has been turned off.
   if (!mEnabled || !mDocument->IsScriptEnabled()) {
     return;
   }
 
-  nsRefPtr<nsScriptLoadRequest> request = new nsScriptLoadRequest(nsnull, 0);
+  nsRefPtr<nsScriptLoadRequest> request =
+    new nsScriptLoadRequest(nsnull, 0,
+                            nsGenericElement::StringToCORSMode(aCrossOrigin));
   request->mURI = aURI;
   request->mIsInline = false;
   request->mLoading = true;
   nsresult rv = StartLoad(request, aType);
   if (NS_FAILED(rv)) {
     return;
   }
 
--- a/content/base/src/nsScriptLoader.h
+++ b/content/base/src/nsScriptLoader.h
@@ -233,19 +233,22 @@ public:
   }
 
   /**
    * Adds aURI to the preload list and starts loading it.
    *
    * @param aURI The URI of the external script.
    * @param aCharset The charset parameter for the script.
    * @param aType The type parameter for the script.
+   * @param aCrossOrigin The crossorigin attribute for the script.
+   *                     Void if not present.
    */
   virtual void PreloadURI(nsIURI *aURI, const nsAString &aCharset,
-                          const nsAString &aType);
+                          const nsAString &aType,
+                          const nsAString &aCrossOrigin);
 
 private:
   /**
    * Unblocks the creator parser of the parser-blocking scripts.
    */
   void UnblockParser(nsScriptLoadRequest* aParserBlockingRequest);
 
   /**
--- a/content/base/src/nsStyleLinkElement.cpp
+++ b/content/base/src/nsStyleLinkElement.cpp
@@ -180,32 +180,32 @@ PRUint32 nsStyleLinkElement::ParseLinkTy
 
   nsAString::const_iterator current(start);
   bool inString = !nsContentUtils::IsHTMLWhitespace(*current);
   nsAutoString subString;
   
   while (current != done) {
     if (nsContentUtils::IsHTMLWhitespace(*current)) {
       if (inString) {
-        ToLowerCase(Substring(start, current), subString);
+        nsContentUtils::ASCIIToLower(Substring(start, current), subString);
         linkMask |= ToLinkMask(subString);
         inString = false;
       }
     }
     else {
       if (!inString) {
         start = current;
         inString = true;
       }
     }
     ++current;
   }
   if (inString) {
-    ToLowerCase(Substring(start, current), subString);
-     linkMask |= ToLinkMask(subString);
+    nsContentUtils::ASCIIToLower(Substring(start, current), subString);
+    linkMask |= ToLinkMask(subString);
   }
   return linkMask;
 }
 
 NS_IMETHODIMP
 nsStyleLinkElement::UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
                                      bool* aWillNotify,
                                      bool* aIsAlternate)
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -557,16 +557,21 @@ include $(topsrcdir)/config/rules.mk
 		test_bug717511.html \
 		file_bug717511.html \
 		file_bug717511.html^headers^ \
 		file_bug717511_2.html \
 		file_bug717511_2.html^headers^ \
 		test_bug726364.html \
 		test_bug698381.html \
 		test_bug711047.html \
+		test_bug696301-1.html \
+		test_bug696301-2.html \
+		bug696301-script-1.js \
+		bug696301-script-1.js^headers^ \
+		bug696301-script-2.js \
 		$(NULL)
 
 _CHROME_FILES =	\
 		test_bug357450.js \
 		$(NULL)
 
 # This test fails on the Mac for some reason
 ifneq (,$(filter gtk2 windows,$(MOZ_WIDGET_TOOLKIT)))
copy from content/base/test/bug461735-post-redirect.js
copy to content/base/test/bug696301-script-1.js
--- a/content/base/test/bug461735-post-redirect.js
+++ b/content/base/test/bug696301-script-1.js
@@ -1,3 +1,3 @@
 var a = 0;
-var b = 0;
+var global = "ran";
 c();
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/content/base/test/bug696301-script-1.js^headers^
@@ -0,0 +1,1 @@
+Access-Control-Allow-Origin: *
copy from content/base/test/bug461735-post-redirect.js
copy to content/base/test/bug696301-script-2.js
--- a/content/base/test/bug461735-post-redirect.js
+++ b/content/base/test/bug696301-script-2.js
@@ -1,3 +1,3 @@
 var a = 0;
-var b = 0;
+var global = "ran";
 c();
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug696301-1.html
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=696301
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 696301</title>
+  <script type="application/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=696301">Mozilla Bug 696301</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+var errorFired = false;
+var global = "";
+window.onerror = function(message, uri, line) {
+  is(message, "Script error.", "Should have empty error message");
+  is(uri,
+     "http://example.com/tests/content/base/test/bug696301-script-1.js",
+     "Should have correct script URI");
+  is(line, 0, "Shouldn't have a line here");
+  errorFired = true;
+}
+</script>
+<script src="http://example.com/tests/content/base/test/bug696301-script-1.js"></script>
+<script>
+  is(errorFired, true, "Should have error in different origin script");
+  is(global, "ran", "Different origin script should have run");
+</script>
+
+<script type="application/javascript">
+errorFired = false;
+global = "";
+window.onerror = function(message, uri, line) {
+  is(message, "c is not defined", "Should have correct error message");
+  is(uri,
+     "http://example.com/tests/content/base/test/bug696301-script-1.js",
+     "Should also have correct script URI");
+  is(line, 3, "Should have a line here");
+  errorFired = true;
+}
+</script>
+<script src="http://example.com/tests/content/base/test/bug696301-script-1.js"
+        crossorigin></script>
+<script>
+  is(errorFired, true, "Should have error in different origin script with CORS");
+  is(global, "ran", "Different origin script with CORS should have run");
+</script>
+
+<script type="application/javascript">
+errorFired = false;
+global = "";
+window.onerror = function(message, uri, line) {
+  is(message, "Error loading script", "Should have correct error message");
+  is(uri,
+     "http://example.com/tests/content/base/test/bug696301-script-2.js",
+     "Should still have correct script URI even when failing CORS");
+  is(line, 1, "Load failures seem to count as line 1");
+  errorFired = true;
+}
+</script>
+<script src="http://example.com/tests/content/base/test/bug696301-script-2.js"
+        crossorigin></script>
+<script>
+  is(errorFired, true,
+     "Should have error when different origin script fails CORS check");
+  is(global, "", "Different origin script that fails CORS should not have run");
+</script>
+
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug696301-2.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=696301
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 696301</title>
+  <script type="application/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=696301">Mozilla Bug 696301</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<!-- Test SVG script here -->
+<svg>
+<script type="application/javascript">
+var errorFired = false;
+var global = "";
+window.onerror = function(message, uri, line) {
+  is(message, "Script error.", "Should have empty error message");
+  is(uri,
+     "http://example.com/tests/content/base/test/bug696301-script-1.js",
+     "Should have correct script URI");
+  is(line, 0, "Shouldn't have a line here");
+  errorFired = true;
+}
+</script>
+<script xlink:href="http://example.com/tests/content/base/test/bug696301-script-1.js"></script>
+<script>
+  is(errorFired, true, "Should have error in different origin script");
+  is(global, "ran", "Different origin script should have run");
+</script>
+
+<script type="application/javascript">
+errorFired = false;
+global = "";
+window.onerror = function(message, uri, line) {
+  is(message, "c is not defined", "Should have correct error message");
+  is(uri,
+     "http://example.com/tests/content/base/test/bug696301-script-1.js",
+     "Should also have correct script URI");
+  is(line, 3, "Should have a line here");
+  errorFired = true;
+}
+</script>
+<script xlink:href="http://example.com/tests/content/base/test/bug696301-script-1.js"
+        crossorigin></script>
+<script>
+  is(errorFired, true, "Should have error in different origin script with CORS");
+  is(global, "ran", "Different origin script with CORS should have run");
+</script>
+
+<script type="application/javascript">
+errorFired = false;
+global = "";
+window.onerror = function(message, uri, line) {
+  is(message, "Error loading script", "Should have correct error message");
+  is(uri,
+     "http://example.com/tests/content/base/test/bug696301-script-2.js",
+     "Should still have correct script URI even when failing CORS");
+  is(line, 1, "Load failures seem to count as line 1");
+  errorFired = true;
+}
+</script>
+<script xlink:href="http://example.com/tests/content/base/test/bug696301-script-2.js"
+        crossorigin></script>
+<script>
+  is(errorFired, true,
+     "Should have error when different origin script fails CORS check");
+  is(global, "", "Different origin script that fails CORS should not have run");
+</script>
+</svg>
+</pre>
+</body>
+</html>
--- a/content/canvas/crashtests/crashtests.list
+++ b/content/canvas/crashtests/crashtests.list
@@ -1,6 +1,7 @@
 load 360293-1.html
 load 421715-1.html
 load 553938-1.html
 load 647480.html
 load 0px-size-font-667225.html
+load texImage2D.html
 load 729116.html
new file mode 100644
--- /dev/null
+++ b/content/canvas/crashtests/texImage2D.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<canvas></canvas>
+<script>
+var canvas = document.body.firstChild,
+    gl = canvas.getContext("experimental-webgl");
+gl.texImage2D(0, 0, 0, 0, 0, { get width() { throw 7 }, get height() { throw 7 }, data: new Uint8ClampedArray(10) });
+gl.texSubImage2D(0, 0, 0, 0, 0, 0, { get width() { throw 7 }, get height() { throw 7 }, data: new Uint8ClampedArray(10) });
+</script>
--- a/content/canvas/src/CustomQS_WebGL.h
+++ b/content/canvas/src/CustomQS_WebGL.h
@@ -377,16 +377,143 @@ nsIDOMWebGLRenderingContext_ReadPixels(J
     if (NS_FAILED(rv))
         return xpc_qsThrowMethodFailed(cx, rv, vp);
 
     *vp = JSVAL_VOID;
     return JS_TRUE;
 }
 
 
+class CallTexImage2D
+{
+private:
+    nsIDOMWebGLRenderingContext* self;
+    WebGLenum target;
+    WebGLint level;
+    WebGLenum internalformat;
+    WebGLenum format;
+    WebGLenum type;
+
+public:
+    explicit CallTexImage2D(nsIDOMWebGLRenderingContext* aSelf,
+                            WebGLenum aTarget,
+                            WebGLint aLevel,
+                            WebGLenum aInternalformat,
+                            WebGLenum aFormat,
+                            WebGLenum aType)
+        : self(aSelf)
+        , target(aTarget)
+        , level(aLevel)
+        , internalformat(aInternalformat)
+        , format(aFormat)
+        , type(aType)
+    {}
+
+    nsresult DoCallForImageData(WebGLsizei width, WebGLsizei height,
+                                JSObject* pixels)
+    {
+        return self->TexImage2D_imageData(target, level, internalformat, width,
+                                          height, 0, format, type, pixels);
+    }
+    nsresult DoCallForElement(mozilla::dom::Element* elt)
+    {
+        return self->TexImage2D_dom(target, level, internalformat, format, type,
+                                    elt);
+    }
+};
+
+class CallTexSubImage2D
+{
+private:
+    nsIDOMWebGLRenderingContext* self;
+    WebGLenum target;
+    WebGLint level;
+    WebGLint xoffset;
+    WebGLint yoffset;
+    WebGLenum format;
+    WebGLenum type;
+
+public:
+    explicit CallTexSubImage2D(nsIDOMWebGLRenderingContext* aSelf,
+                               WebGLenum aTarget,
+                               WebGLint aLevel,
+                               WebGLint aXoffset,
+                               WebGLint aYoffset,
+                               WebGLenum aFormat,
+                               WebGLenum aType)
+
+        : self(aSelf)
+        , target(aTarget)
+        , level(aLevel)
+        , xoffset(aXoffset)
+        , yoffset(aYoffset)
+        , format(aFormat)
+        , type(aType)
+    {}
+
+    nsresult DoCallForImageData(WebGLsizei width, WebGLsizei height,
+                                JSObject* pixels)
+    {
+        return self->TexSubImage2D_imageData(target, level, xoffset, yoffset,
+                                             width, height, format, type,
+                                             pixels);
+    }
+    nsresult DoCallForElement(mozilla::dom::Element* elt)
+    {
+        return self->TexSubImage2D_dom(target, level, xoffset, yoffset, format,
+                                       type, elt);
+    }
+};
+
+template<class T>
+static bool
+TexImage2DImageDataOrElement(JSContext* cx, T& self, JS::Value* object)
+{
+    MOZ_ASSERT(object && object->isObject());
+
+    nsGenericElement* elt;
+    xpc_qsSelfRef eltRef;
+    if (NS_SUCCEEDED(xpc_qsUnwrapArg<nsGenericElement>(
+            cx, *object, &elt, &eltRef.ptr, object))) {
+        nsresult rv = self.DoCallForElement(elt);
+        return NS_SUCCEEDED(rv) || xpc_qsThrow(cx, rv);
+    }
+
+    // Failed to interpret object as an Element, now try to interpret it as
+    // ImageData.
+    JSObject* imageData = &object->toObject();
+
+    jsval js_width, js_height, js_data;
+    if (!JS_GetProperty(cx, imageData, "width", &js_width) ||
+        !JS_GetProperty(cx, imageData, "height", &js_height) ||
+        !JS_GetProperty(cx, imageData, "data", &js_data)) {
+        return false;
+    }
+    if (js_width  == JSVAL_VOID ||
+        js_height == JSVAL_VOID ||
+        !js_data.isObject())
+    {
+        return xpc_qsThrow(cx, NS_ERROR_FAILURE);
+    }
+    int32_t int_width, int_height;
+    JSObject *obj_data = JSVAL_TO_OBJECT(js_data);
+    if (!JS_ValueToECMAInt32(cx, js_width, &int_width) ||
+        !JS_ValueToECMAInt32(cx, js_height, &int_height))
+    {
+        return false;
+    }
+    if (!js_IsTypedArray(obj_data))
+    {
+        return xpc_qsThrow(cx, NS_ERROR_FAILURE);
+    }
+
+    nsresult rv = self.DoCallForImageData(int_width, int_height, obj_data);
+    return NS_SUCCEEDED(rv) || xpc_qsThrow(cx, rv);
+}
+
 /*
  * TexImage2D takes:
  *    TexImage2D(uint, int, uint, int, int, int, uint, uint, ArrayBufferView)
  *    TexImage2D(uint, int, uint, uint, uint, nsIDOMElement)
  *    TexImage2D(uint, int, uint, uint, uint, ImageData)
  */
 static JSBool
 nsIDOMWebGLRenderingContext_TexImage2D(JSContext *cx, unsigned argc, jsval *vp)
@@ -407,75 +534,31 @@ nsIDOMWebGLRenderingContext_TexImage2D(J
     if (argc < 6 || argc == 7 || argc == 8)
         return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
 
     jsval *argv = JS_ARGV(cx, vp);
 
     // arguments common to all cases
     GET_UINT32_ARG(argv0, 0);
     GET_INT32_ARG(argv1, 1);
+    GET_UINT32_ARG(argv2, 2);
 
-    if (argc > 5 &&
-        !JSVAL_IS_PRIMITIVE(argv[5]))
-    {
+    if (argc > 5 && !JSVAL_IS_PRIMITIVE(argv[5])) {
         // implement the variants taking a DOMElement as argv[5]
-        GET_UINT32_ARG(argv2, 2);
         GET_UINT32_ARG(argv3, 3);
         GET_UINT32_ARG(argv4, 4);
 
-        nsIDOMElement *elt;
-        xpc_qsSelfRef eltRef;
-        rv = xpc_qsUnwrapArg<nsIDOMElement>(cx, argv[5], &elt, &eltRef.ptr, &argv[5]);
-        if (NS_FAILED(rv)) return JS_FALSE;
-
-        rv = self->TexImage2D_dom(argv0, argv1, argv2, argv3, argv4, elt);
-
-        // NS_ERROR_DOM_SECURITY_ERR indicates we tried to load a cross-domain element, so
-        // bail out immediately, don't try to interprete as ImageData
-        if (rv == NS_ERROR_DOM_SECURITY_ERR) {
-            xpc_qsThrowBadArg(cx, rv, vp, 5);
-            return JS_FALSE;
+        CallTexImage2D selfCaller(self, argv0, argv1, argv2, argv3, argv4);
+        if (!TexImage2DImageDataOrElement(cx, selfCaller, argv + 5)) {
+            return false;
         }
-
-        if (NS_FAILED(rv)) {
-            // failed to interprete argv[5] as a DOMElement, now try to interprete it as ImageData
-            JSObject *argv5 = JSVAL_TO_OBJECT(argv[5]);
-
-            jsval js_width, js_height, js_data;
-            JS_GetProperty(cx, argv5, "width", &js_width);
-            JS_GetProperty(cx, argv5, "height", &js_height);
-            JS_GetProperty(cx, argv5, "data", &js_data);
-            if (js_width  == JSVAL_VOID ||
-                js_height == JSVAL_VOID ||
-                !js_data.isObject())
-            {
-                xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 5);
-                return JS_FALSE;
-            }
-            int32_t int_width, int_height;
-            JSObject *obj_data = JSVAL_TO_OBJECT(js_data);
-            if (!JS_ValueToECMAInt32(cx, js_width, &int_width) ||
-                !JS_ValueToECMAInt32(cx, js_height, &int_height))
-            {
-                return JS_FALSE;
-            }
-            if (!js_IsTypedArray(obj_data))
-            {
-                xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 5);
-                return JS_FALSE;
-            }
-            rv = self->TexImage2D_imageData(argv0, argv1, argv2,
-                                            int_width, int_height, 0,
-                                            argv3, argv4, js::TypedArray::getTypedArray(obj_data));
-        }
-    } else if (argc > 8 &&
-               JSVAL_IS_OBJECT(argv[8])) // here, we allow null !
-    {
+        rv = NS_OK;
+    } else if (argc > 8 && JSVAL_IS_OBJECT(argv[8])) {
+        // here, we allow null !
         // implement the variants taking a buffer/array as argv[8]
-        GET_UINT32_ARG(argv2, 2);
         GET_INT32_ARG(argv3, 3);
         GET_INT32_ARG(argv4, 4);
         GET_INT32_ARG(argv5, 5);
         GET_UINT32_ARG(argv6, 6);
         GET_UINT32_ARG(argv7, 7);
 
         JSObject *argv8 = JSVAL_TO_OBJECT(argv[8]);
 
@@ -531,71 +614,27 @@ nsIDOMWebGLRenderingContext_TexSubImage2
     jsval *argv = JS_ARGV(cx, vp);
 
     // arguments common to all cases
     GET_UINT32_ARG(argv0, 0);
     GET_INT32_ARG(argv1, 1);
     GET_INT32_ARG(argv2, 2);
     GET_INT32_ARG(argv3, 3);
 
-    if (argc > 6 &&
-        !JSVAL_IS_PRIMITIVE(argv[6]))
-    {
-        // implement the variants taking a DOMElement as argv[6]
+    if (argc > 6 && !JSVAL_IS_PRIMITIVE(argv[6])) {
+        // implement the variants taking a DOMElement or an ImageData as argv[6]
         GET_UINT32_ARG(argv4, 4);
         GET_UINT32_ARG(argv5, 5);
 
-        nsIDOMElement *elt;
-        xpc_qsSelfRef eltRef;
-        rv = xpc_qsUnwrapArg<nsIDOMElement>(cx, argv[6], &elt, &eltRef.ptr, &argv[6]);
-        if (NS_FAILED(rv)) return JS_FALSE;
-
-        rv = self->TexSubImage2D_dom(argv0, argv1, argv2, argv3, argv4, argv5, elt);
-        
-        // NS_ERROR_DOM_SECURITY_ERR indicates we tried to load a cross-domain element, so
-        // bail out immediately, don't try to interprete as ImageData
-        if (rv == NS_ERROR_DOM_SECURITY_ERR) {
-            xpc_qsThrowBadArg(cx, rv, vp, 6);
-            return JS_FALSE;
+        CallTexSubImage2D selfCaller(self, argv0, argv1, argv2, argv3, argv4, argv5);
+        if (!TexImage2DImageDataOrElement(cx, selfCaller, argv + 6)) {
+            return false;
         }
-
-        if (NS_FAILED(rv)) {
-            // failed to interprete argv[6] as a DOMElement, now try to interprete it as ImageData
-            JSObject *argv6 = JSVAL_TO_OBJECT(argv[6]);
-            jsval js_width, js_height, js_data;
-            JS_GetProperty(cx, argv6, "width", &js_width);
-            JS_GetProperty(cx, argv6, "height", &js_height);
-            JS_GetProperty(cx, argv6, "data", &js_data);
-            if (js_width  == JSVAL_VOID ||
-                js_height == JSVAL_VOID ||
-                !js_data.isObject())
-            {
-                xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 6);
-                return JS_FALSE;
-            }
-            int32_t int_width, int_height;
-            JSObject *obj_data = JSVAL_TO_OBJECT(js_data);
-            if (!JS_ValueToECMAInt32(cx, js_width, &int_width) ||
-                !JS_ValueToECMAInt32(cx, js_height, &int_height))
-            {
-                return JS_FALSE;
-            }
-            if (!js_IsTypedArray(obj_data))
-            {
-                xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 6);
-                return JS_FALSE;
-            }
-            rv = self->TexSubImage2D_imageData(argv0, argv1, argv2, argv3,
-                                               int_width, int_height,
-                                               argv4, argv5,
-                                               js::TypedArray::getTypedArray(obj_data));
-        }
-    } else if (argc > 8 &&
-               !JSVAL_IS_PRIMITIVE(argv[8]))
-    {
+        rv = NS_OK;
+    } else if (argc > 8 && !JSVAL_IS_PRIMITIVE(argv[8])) {
         // implement the variants taking a buffer/array as argv[8]
         GET_INT32_ARG(argv4, 4);
         GET_INT32_ARG(argv5, 5);
         GET_UINT32_ARG(argv6, 6);
         GET_UINT32_ARG(argv7, 7);
 
         JSObject *argv8 = JSVAL_TO_OBJECT(argv[8]);
         // try to grab a js::TypedArray
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -810,17 +810,17 @@ protected:
                                WebGLint *intParamPtr, WebGLfloat *floatParamPtr);
 
     void ConvertImage(size_t width, size_t height, size_t srcStride, size_t dstStride,
                       const PRUint8*src, PRUint8 *dst,
                       int srcFormat, bool srcPremultiplied,
                       int dstFormat, bool dstPremultiplied,
                       size_t dstTexelSize);
 
-    nsresult DOMElementToImageSurface(nsIDOMElement *imageOrCanvas,
+    nsresult DOMElementToImageSurface(dom::Element* imageOrCanvas,
                                       gfxImageSurface **imageOut,
                                       int *format);
 
     nsresult CopyTexSubImage2D_base(WebGLenum target,
                                     WebGLint level,
                                     WebGLenum internalformat,
                                     WebGLint xoffset,
                                     WebGLint yoffset,
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -65,16 +65,17 @@
 #include "WebGLValidateStrings.h"
 
 // needed to check if current OS is lower than 10.7
 #if defined(MOZ_WIDGET_COCOA)
 #include "nsCocoaFeatures.h"
 #endif
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 static bool BaseTypeAndSizeFromUniformType(WebGLenum uType, WebGLenum *baseType, WebGLint *unitSize);
 static WebGLenum InternalFormatForFormatAndType(WebGLenum format, WebGLenum type, bool isGLES2);
 
 /* Helper macros for when we're just wrapping a gl method, so that
  * we can avoid having to type this 500 times.  Note that these MUST
  * NOT BE USED if we need to check any of the parameters.
  */
@@ -3961,35 +3962,34 @@ WebGLContext::ConvertImage(size_t width,
         HANDLE_FLOAT_SRCFORMAT(A32F,     4, unpackA32FToRGBA32F)
         default:
             NS_ASSERTION(false, "Coding error?! Should never reach this point.");
             return;
     }
 }
 
 nsresult
-WebGLContext::DOMElementToImageSurface(nsIDOMElement *imageOrCanvas,
+WebGLContext::DOMElementToImageSurface(Element* imageOrCanvas,
                                        gfxImageSurface **imageOut, int *format)
 {
-    nsCOMPtr<nsIContent> content = do_QueryInterface(imageOrCanvas);
-    if (!content) {
+    if (!imageOrCanvas) {
         return NS_ERROR_FAILURE;
     }        
 
     PRUint32 flags =
         nsLayoutUtils::SFE_WANT_NEW_SURFACE |
         nsLayoutUtils::SFE_WANT_IMAGE_SURFACE;
 
     if (mPixelStoreColorspaceConversion == LOCAL_GL_NONE)
         flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
     if (!mPixelStorePremultiplyAlpha)
         flags |= nsLayoutUtils::SFE_NO_PREMULTIPLY_ALPHA;
 
     nsLayoutUtils::SurfaceFromElementResult res =
-        nsLayoutUtils::SurfaceFromElement(content->AsElement(), flags);
+        nsLayoutUtils::SurfaceFromElement(imageOrCanvas, flags);
     if (!res.mSurface)
         return NS_ERROR_FAILURE;
     if (res.mSurface->GetType() != gfxASurface::SurfaceTypeImage) {
         // SurfaceFromElement lied!
         return NS_ERROR_FAILURE;
     }
 
     // We disallow loading cross-domain images and videos that have not been validated
@@ -4011,17 +4011,17 @@ WebGLContext::DOMElementToImageSurface(n
                                 "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
             return NS_ERROR_DOM_SECURITY_ERR;
         }
     }
 
     // part 2: if the DOM element is a canvas, check that it's not write-only.
     // That would indicate a tainted canvas, i.e. a canvas that could contain
     // cross-domain image data.
-    if (nsHTMLCanvasElement* canvas = nsHTMLCanvasElement::FromContent(content)) {
+    if (nsHTMLCanvasElement* canvas = nsHTMLCanvasElement::FromContent(imageOrCanvas)) {
         if (canvas->IsWriteOnly()) {
             LogMessageIfVerbose("The canvas used as source for texImage2D here is tainted (write-only). It is forbidden "
                                 "to load a WebGL texture from a tainted canvas. A Canvas becomes tainted for example "
                                 "when a cross-domain image is drawn on it. "
                                 "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
             return NS_ERROR_DOM_SECURITY_ERR;
         }
     }
@@ -5077,17 +5077,17 @@ WebGLContext::TexImage2D_imageData(WebGL
                            pixels ? JS_GetTypedArrayData(pixels) : 0,
                            pixels ? JS_GetTypedArrayByteLength(pixels) : 0,
                            -1,
                            WebGLTexelFormat::RGBA8, false);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexImage2D_dom(WebGLenum target, WebGLint level, WebGLenum internalformat,
-                             WebGLenum format, GLenum type, nsIDOMElement *elt)
+                             WebGLenum format, GLenum type, Element* elt)
 {
     if (!IsContextStable())
         return NS_OK;
 
     nsRefPtr<gfxImageSurface> isurf;
 
     int srcFormat;
     nsresult rv = DOMElementToImageSurface(elt, getter_AddRefs(isurf), &srcFormat);
@@ -5267,17 +5267,17 @@ WebGLContext::TexSubImage2D_imageData(We
                               -1,
                               WebGLTexelFormat::RGBA8, false);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexSubImage2D_dom(WebGLenum target, WebGLint level,
                                 WebGLint xoffset, WebGLint yoffset,
                                 WebGLenum format, WebGLenum type,
-                                nsIDOMElement *elt)
+                                Element *elt)
 {
     if (!IsContextStable())
         return NS_OK;
 
     nsRefPtr<gfxImageSurface> isurf;
 
     int srcFormat;
     nsresult rv = DOMElementToImageSurface(elt, getter_AddRefs(isurf), &srcFormat);
--- a/content/canvas/test/test_canvas.html
+++ b/content/canvas/test/test_canvas.html
@@ -7586,67 +7586,67 @@ ok(!_thrown_outer, ctx.canvas.id + ' sho
 
 
 }
 </script>
 
 <!-- [[[ test_2d.imageData.create.type.html ]]] -->
 
 <p>Canvas test: 2d.imageData.create.type - bug 433004</p>
-<!-- Testing: createImageData() returns an ImageData object containing a CanvasPixelArray object -->
+<!-- Testing: createImageData() returns an ImageData object containing a Uint8ClampedArray object -->
 <canvas id="c261" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
 <script>
 
 function test_2d_imageData_create_type() {
 
 var canvas = document.getElementById('c261');
 var ctx = canvas.getContext('2d');
 
 var _thrown_outer = false;
 try {
 
 todo(window.ImageData !== undefined, "window.ImageData !== undefined");
-todo(window.CanvasPixelArray !== undefined, "window.CanvasPixelArray !== undefined");
+ok(window.Uint8ClampedArray !== undefined, "window.Uint8ClampedArray !== undefined");
 window.ImageData.prototype.thisImplementsImageData = true;
-window.CanvasPixelArray.prototype.thisImplementsCanvasPixelArray = true;
+window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true;
 var imgdata = ctx.createImageData(1, 1);
 ok(imgdata.thisImplementsImageData, "imgdata.thisImplementsImageData");
-ok(imgdata.data.thisImplementsCanvasPixelArray, "imgdata.data.thisImplementsCanvasPixelArray");
+ok(imgdata.data.thisImplementsUint8ClampedArray, "imgdata.data.thisImplementsUint8ClampedArray");
 
 } catch (e) {
     _thrown_outer = true;
 }
 todo(!_thrown_outer, ctx.canvas.id + ' should not throw exception');
 
 
 }
 </script>
 
 <!-- [[[ test_2d.imageData.create1.type.html ]]] -->
 
 <p>Canvas test: 2d.imageData.create1.type - bug 630040</p>
-<!-- Testing: createImageData(imgdata) returns an ImageData object containing a CanvasPixelArray object -->
+<!-- Testing: createImageData(imgdata) returns an ImageData object containing a Uint8ClampedArray object -->
 <canvas id="c261a" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
 <script>
 
 function test_2d_imageData_create1_type() {
 
 var canvas = document.getElementById('c261a');
 var ctx = canvas.getContext('2d');
 
 var _thrown_outer = false;
 try {
 
 todo(window.ImageData !== undefined, "window.ImageData !== undefined");
-todo(window.CanvasPixelArray !== undefined, "window.CanvasPixelArray !== undefined");
+ok(window.Uint8ClampedArray !== undefined, "window.Uint8ClampedArray !== undefined");
 window.ImageData.prototype.thisImplementsImageData = true;
-window.CanvasPixelArray.prototype.thisImplementsCanvasPixelArray = true;
+window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true;
 var imgdata = ctx.createImageData(ctx.createImageData(1, 1));
 todo(imgdata.thisImplementsImageData, "imgdata.thisImplementsImageData");
-todo(imgdata.data.thisImplementsCanvasPixelArray, "imgdata.data.thisImplementsCanvasPixelArray");
+ok(imgdata.data.thisImplementsUint8ClampedArray, "imgdata.data.thisImplementsUint8ClampedArray");
 
 } catch (e) {
     _thrown_outer = true;
 }
 todo(!_thrown_outer, ctx.canvas.id + ' should not throw exception');
 
 
 }
@@ -8224,35 +8224,35 @@ ok(!_thrown_outer, ctx.canvas.id + ' sho
 
 
 }
 </script>
 
 <!-- [[[ test_2d.imageData.get.type.html ]]] -->
 
 <p>Canvas test: 2d.imageData.get.type</p>
-<!-- Testing: getImageData() returns an ImageData object containing a CanvasPixelArray object -->
+<!-- Testing: getImageData() returns an ImageData object containing a Uint8ClampedArray object -->
 <canvas id="c276" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
 <script>
 
 function test_2d_imageData_get_type() {
 
 var canvas = document.getElementById('c276');
 var ctx = canvas.getContext('2d');
 
 var _thrown_outer = false;
 try {
 
 todo(window.ImageData !== undefined, "window.ImageData !== undefined");
-todo(window.CanvasPixelArray !== undefined, "window.CanvasPixelArray !== undefined");
+ok(window.Uint8ClampedArray !== undefined, "window.Uint8ClampedArray !== undefined");
 window.ImageData.prototype.thisImplementsImageData = true;
-window.CanvasPixelArray.prototype.thisImplementsCanvasPixelArray = true;
+window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true;
 var imgdata = ctx.getImageData(0, 0, 1, 1);
 ok(imgdata.thisImplementsImageData, "imgdata.thisImplementsImageData");
-ok(imgdata.data.thisImplementsCanvasPixelArray, "imgdata.data.thisImplementsCanvasPixelArray");
+ok(imgdata.data.thisImplementsUint8ClampedArray, "imgdata.data.thisImplementsUint8ClampedArray");
 
 } catch (e) {
     _thrown_outer = true;
 }
 todo(!_thrown_outer, ctx.canvas.id + ' should not throw exception');
 
 
 }
--- a/content/events/crashtests/crashtests.list
+++ b/content/events/crashtests/crashtests.list
@@ -1,10 +1,11 @@
 load 104310-1.html
 load 116206-1.html
 load 135345-1.html
 load 422009-1.xhtml
 load 457776-1.html
 load 496308-1.html
 load 682637-1.html
 load eventctor-nulldictionary.html
+load eventctor-nullstorage.html
 load recursive-onload.html
 load recursive-DOMNodeInserted.html
new file mode 100644
--- /dev/null
+++ b/content/events/crashtests/eventctor-nullstorage.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<script>
+new StorageEvent("").storageArea;
+</script>
--- a/content/html/content/public/nsHTMLMediaElement.h
+++ b/content/html/content/public/nsHTMLMediaElement.h
@@ -45,16 +45,17 @@
 #include "nsIHttpChannel.h"
 #include "nsThreadUtils.h"
 #include "nsIDOMRange.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsILoadGroup.h"
 #include "nsIObserver.h"
 #include "nsAudioStream.h"
 #include "VideoFrameContainer.h"
+#include "mozilla/CORSMode.h"
 
 // Define to output information on decoding and painting framerate
 /* #define DEBUG_FRAME_RATE 1 */
 
 typedef PRUint16 nsMediaNetworkState;
 typedef PRUint16 nsMediaReadyState;
 
 class nsHTMLMediaElement : public nsGenericHTMLElement,
@@ -66,17 +67,17 @@ public:
   typedef mozilla::VideoFrameContainer VideoFrameContainer;
 
   enum CanPlayStatus {
     CANPLAY_NO,
     CANPLAY_MAYBE,
     CANPLAY_YES
   };
 
-  CORSMode GetCORSMode() {
+  mozilla::CORSMode GetCORSMode() {
     return mCORSMode;
   }
 
   nsHTMLMediaElement(already_AddRefed<nsINodeInfo> aNodeInfo);
   virtual ~nsHTMLMediaElement();
 
   /**
    * This is used when the browser is constructing a video element to play
@@ -776,12 +777,12 @@ protected:
   // load when the user initiates either playback or an explicit load is
   // stored in mPreloadURI.
   bool mLoadIsSuspended;
 
   // True if a same-origin check has been done for the media element and resource.
   bool mMediaSecurityVerified;
 
   // The CORS mode when loading the media element
-  CORSMode mCORSMode;
+  mozilla::CORSMode mCORSMode;
 };
 
 #endif
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -2483,34 +2483,35 @@ nsGenericHTMLElement::GetContentEditable
   }
 
   return NS_OK;
 }
 
 nsresult
 nsGenericHTMLElement::SetContentEditable(const nsAString& aContentEditable)
 {
-  nsString contentEditable;
-  ToLowerCase(aContentEditable, contentEditable);
-
-  if (contentEditable.EqualsLiteral("inherit")) {
+  if (nsContentUtils::EqualsLiteralIgnoreASCIICase(aContentEditable, "inherit")) {
     UnsetAttr(kNameSpaceID_None, nsGkAtoms::contenteditable, true);
 
     return NS_OK;
   }
 
-  if (!contentEditable.EqualsLiteral("true") &&
-      !contentEditable.EqualsLiteral("false")) {
-    return NS_ERROR_DOM_SYNTAX_ERR;
+  if (nsContentUtils::EqualsLiteralIgnoreASCIICase(aContentEditable, "true")) {
+    SetAttr(kNameSpaceID_None, nsGkAtoms::contenteditable, NS_LITERAL_STRING("true"), true);
+    
+    return NS_OK;
   }
-
-  SetAttr(kNameSpaceID_None, nsGkAtoms::contenteditable, contentEditable,
-          true);
-
-  return NS_OK;
+  
+  if (nsContentUtils::EqualsLiteralIgnoreASCIICase(aContentEditable, "false")) {
+    SetAttr(kNameSpaceID_None, nsGkAtoms::contenteditable, NS_LITERAL_STRING("false"), true);
+
+    return NS_OK;
+  }
+
+  return NS_ERROR_DOM_SYNTAX_ERR;
 }
 
 nsresult
 nsGenericHTMLElement::GetIsContentEditable(bool* aContentEditable)
 {
   NS_ENSURE_ARG_POINTER(aContentEditable);
 
   for (nsIContent* node = this; node; node = node->GetParent()) {
@@ -2881,24 +2882,16 @@ nsGenericHTMLFormElement::PreHandleEvent
         break;
       }
     }
   }
 
   return nsGenericHTMLElement::PreHandleEvent(aVisitor);
 }
 
-const nsAttrValue::EnumTable nsGenericHTMLElement::kCORSAttributeTable[] = {
-  // Order matters here
-  // See ParseAttribute in nsHTMLImageElement or nsHTMLMediaElement
-  { "anonymous",       nsGenericHTMLElement::CORS_ANONYMOUS       },
-  { "use-credentials", nsGenericHTMLElement::CORS_USE_CREDENTIALS },
-  { 0 }
-};
-
 /* virtual */
 bool
 nsGenericHTMLFormElement::IsDisabled() const
 {
   return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled) ||
          (mFieldSet && mFieldSet->IsDisabled());
 }
 
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -525,50 +525,24 @@ public:
    * @param aResult    result value [out]
    */
   NS_HIDDEN_(nsresult) GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, nsAString& aResult);
 
   /**
    * Returns the current disabled state of the element.
    */
   virtual bool IsDisabled() const {
-    return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
+    return false;
   }
 
   bool IsHidden() const
   {
     return HasAttr(kNameSpaceID_None, nsGkAtoms::hidden);
   }
 
-  /**
-   * Shared cross-origin resource sharing attributes so they don't get
-   * duplicated on every CORS-enabled element
-   */
-
-  enum CORSMode {
-    /**
-     * The default of not using CORS to validate cross-origin loads.
-     */
-    CORS_NONE,
-
-    /**
-     * Validate cross-site loads using CORS, but do not send any credentials
-     * (cookies, HTTP auth logins, etc) along with the request.
-     */
-    CORS_ANONYMOUS,
-
-    /**
-     * Validate cross-site loads using CORS, and send credentials such as cookies
-     * and HTTP auth logins along with the request.
-     */
-    CORS_USE_CREDENTIALS
-  };
-
-  const static nsAttrValue::EnumTable kCORSAttributeTable[];
-
 protected:
   /**
    * Add/remove this element to the documents name cache
    */
   void AddToNameTable(nsIAtom* aName) {
     NS_ASSERTION(HasName(), "Node doesn't have name?");
     nsIDocument* doc = GetCurrentDoc();
     if (doc && !IsInAnonymousSubtree()) {
--- a/content/html/content/src/nsHTMLImageElement.cpp
+++ b/content/html/content/src/nsHTMLImageElement.cpp
@@ -358,20 +358,18 @@ nsHTMLImageElement::ParseAttribute(PRInt
                                    const nsAString& aValue,
                                    nsAttrValue& aResult)
 {
   if (aNamespaceID == kNameSpaceID_None) {
     if (aAttribute == nsGkAtoms::align) {
       return ParseAlignValue(aValue, aResult);
     }
     if (aAttribute == nsGkAtoms::crossorigin) {
-      return aResult.ParseEnumValue(aValue, nsGenericHTMLElement::kCORSAttributeTable, false,
-                                    // default value is anonymous if aValue is
-                                    // not a value we understand
-                                    &nsGenericHTMLElement::kCORSAttributeTable[0]);
+      ParseCORSValue(aValue, aResult);
+      return true;
     }
     if (ParseImageAttribute(aAttribute, aValue, aResult)) {
       return true;
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
@@ -657,22 +655,13 @@ nsresult
 nsHTMLImageElement::CopyInnerTo(nsGenericElement* aDest) const
 {
   if (aDest->OwnerDoc()->IsStaticDocument()) {
     CreateStaticImageClone(static_cast<nsHTMLImageElement*>(aDest));
   }
   return nsGenericHTMLElement::CopyInnerTo(aDest);
 }
 
-nsGenericHTMLElement::CORSMode
+CORSMode
 nsHTMLImageElement::GetCORSMode()
 {
-  nsGenericHTMLElement::CORSMode ret = nsGenericHTMLElement::CORS_NONE;
-
-  const nsAttrValue* value = GetParsedAttr(nsGkAtoms::crossorigin);
-  if (value) {
-    NS_ASSERTION(value->Type() == nsAttrValue::eEnum,
-                 "Why is this not an enum value?");
-    ret = nsGenericHTMLElement::CORSMode(value->GetEnumValue());
-  }
-
-  return ret;
+  return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
 }
--- a/content/html/content/src/nsHTMLLinkElement.cpp
+++ b/content/html/content/src/nsHTMLLinkElement.cpp
@@ -431,17 +431,19 @@ nsHTMLLinkElement::GetStyleSheetInfo(nsA
     if (aTitle.IsEmpty()) { // alternates must have title
       return;
     } else {
       *aIsAlternate = true;
     }
   }
 
   GetAttr(kNameSpaceID_None, nsGkAtoms::media, aMedia);
-  ToLowerCase(aMedia); // HTML4.0 spec is inconsistent, make it case INSENSITIVE
+  // The HTML5 spec is formulated in terms of the CSSOM spec, which specifies
+  // that media queries should be ASCII lowercased during serialization.
+  nsContentUtils::ASCIIToLower(aMedia);
 
   nsAutoString mimeType;
   nsAutoString notUsed;
   GetAttr(kNameSpaceID_None, nsGkAtoms::type, aType);
   nsContentUtils::SplitMimeType(aType, mimeType, notUsed);
   if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) {
     return;
   }
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -946,24 +946,17 @@ nsresult nsHTMLMediaElement::LoadResourc
   }
 
   if (mChannel) {
     mChannel->Cancel(NS_BINDING_ABORTED);
     mChannel = nsnull;
   }
 
   // Set the media element's CORS mode only when loading a resource
-  // By default, it's CORS_NONE
-  mCORSMode = CORS_NONE;
-  const nsAttrValue* value = GetParsedAttr(nsGkAtoms::crossorigin);
-  if (value) {
-    NS_ASSERTION(value->Type() == nsAttrValue::eEnum,
-                 "Why is this not an enum value?");
-    mCORSMode = CORSMode(value->GetEnumValue());
-  }
+  mCORSMode = AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
 
   nsHTMLMediaElement* other = LookupMediaElementURITable(mLoadingSrc);
   if (other) {
     // Clone it.
     nsresult rv = InitializeDecoderAsClone(other->mDecoder);
     if (NS_SUCCEEDED(rv))
       return rv;
   }
@@ -1599,20 +1592,18 @@ bool nsHTMLMediaElement::ParseAttribute(
     { 0 }
   };
 
   if (aNamespaceID == kNameSpaceID_None) {
     if (ParseImageAttribute(aAttribute, aValue, aResult)) {
       return true;
     }
     if (aAttribute == nsGkAtoms::crossorigin) {
-      return aResult.ParseEnumValue(aValue, kCORSAttributeTable, false,
-                                    // default value is anonymous if aValue is
-                                    // not a value we understand
-                                    &kCORSAttributeTable[0]);
+      ParseCORSValue(aValue, aResult);
+      return true;
     }
     if (aAttribute == nsGkAtoms::preload) {
       return aResult.ParseEnumValue(aValue, kPreloadTable, false);
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
--- a/content/html/content/src/nsHTMLOptGroupElement.cpp
+++ b/content/html/content/src/nsHTMLOptGroupElement.cpp
@@ -80,16 +80,20 @@ public:
   // nsIContent
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
   virtual nsEventStates IntrinsicState() const;
  
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   virtual nsXPCClassInfo* GetClassInfo();
+
+  virtual bool IsDisabled() const {
+    return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
+  }
 protected:
 
   /**
    * Get the select content element that contains this option
    * @param aSelectElement the select element [OUT]
    */
   nsIContent* GetSelect();
 };
--- a/content/html/content/src/nsHTMLOptionElement.h
+++ b/content/html/content/src/nsHTMLOptionElement.h
@@ -99,16 +99,20 @@ public:
   // nsIContent
   virtual nsEventStates IntrinsicState() const;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   nsresult CopyInnerTo(nsGenericElement* aDest) const;
 
   virtual nsXPCClassInfo* GetClassInfo();
+
+  virtual bool IsDisabled() const {
+    return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
+  }
 protected:
   /**
    * Get the select content element that contains this option, this
    * intentionally does not return nsresult, all we care about is if
    * there's a select associated with this option or not.
    */
   nsHTMLSelectElement* GetSelect();
 
--- a/content/html/content/src/nsHTMLScriptElement.cpp
+++ b/content/html/content/src/nsHTMLScriptElement.cpp
@@ -52,16 +52,17 @@
 #include "nsIXPConnect.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIDOMDocument.h"
 #include "nsContentErrors.h"
 #include "nsIArray.h"
 #include "nsTArray.h"
 #include "nsDOMJSUtils.h"
 
+using namespace mozilla;
 using namespace mozilla::dom;
 
 class nsHTMLScriptElement : public nsGenericHTMLElement,
                             public nsIDOMHTMLScriptElement,
                             public nsScriptElement
 {
 public:
   using nsGenericElement::GetText;
@@ -103,21 +104,26 @@ public:
   // nsIDOMHTMLScriptElement
   NS_DECL_NSIDOMHTMLSCRIPTELEMENT
 
   // nsIScriptElement
   virtual void GetScriptType(nsAString& type);
   virtual void GetScriptText(nsAString& text);
   virtual void GetScriptCharset(nsAString& charset);
   virtual void FreezeUriAsyncDefer();
+  virtual CORSMode GetCORSMode() const;
 
   // nsIContent
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers);
+  virtual bool ParseAttribute(PRInt32 aNamespaceID,
+                              nsIAtom* aAttribute,
+                              const nsAString& aValue,
+                              nsAttrValue& aResult);
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   // nsGenericElement
   virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify);
 
   virtual nsXPCClassInfo* GetClassInfo();
@@ -173,16 +179,32 @@ nsHTMLScriptElement::BindToTree(nsIDocum
 
   if (aDocument) {
     MaybeProcessScript();
   }
 
   return NS_OK;
 }
 
+bool
+nsHTMLScriptElement::ParseAttribute(PRInt32 aNamespaceID,
+                                    nsIAtom* aAttribute,
+                                    const nsAString& aValue,
+                                    nsAttrValue& aResult)
+{
+  if (aNamespaceID == kNameSpaceID_None &&
+      aAttribute == nsGkAtoms::crossorigin) {
+    ParseCORSValue(aValue, aResult);
+    return true;
+  }
+
+  return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
+                                              aResult);
+}
+
 nsresult
 nsHTMLScriptElement::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
 {
   *aResult = nsnull;
 
   nsCOMPtr<nsINodeInfo> ni = aNodeInfo;
   nsHTMLScriptElement* it =
     new nsHTMLScriptElement(ni.forget(), NOT_FROM_PARSER);
@@ -306,14 +328,20 @@ nsHTMLScriptElement::FreezeUriAsyncDefer
 
     mDefer = !async && defer;
     mAsync = async;
   }
   
   mFrozen = true;
 }
 
+CORSMode
+nsHTMLScriptElement::GetCORSMode() const
+{
+  return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
+}
+
 bool
 nsHTMLScriptElement::HasScriptContent()
 {
   return (mFrozen ? mExternal : HasAttr(kNameSpaceID_None, nsGkAtoms::src)) ||
          nsContentUtils::HasNonEmptyTextContent(this);
 }
--- a/content/html/content/src/nsHTMLStyleElement.cpp
+++ b/content/html/content/src/nsHTMLStyleElement.cpp
@@ -335,17 +335,19 @@ nsHTMLStyleElement::GetStyleSheetInfo(ns
   *aIsAlternate = false;
 
   nsAutoString title;
   GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
   title.CompressWhitespace();
   aTitle.Assign(title);
 
   GetAttr(kNameSpaceID_None, nsGkAtoms::media, aMedia);
-  ToLowerCase(aMedia); // HTML4.0 spec is inconsistent, make it case INSENSITIVE
+  // The HTML5 spec is formulated in terms of the CSSOM spec, which specifies
+  // that media queries should be ASCII lowercased during serialization.
+  nsContentUtils::ASCIIToLower(aMedia);
 
   GetAttr(kNameSpaceID_None, nsGkAtoms::type, aType);
 
   nsAutoString mimeType;
   nsAutoString notUsed;
   nsContentUtils::SplitMimeType(aType, mimeType, notUsed);
   if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) {
     return;
--- a/content/html/content/test/test_bug430351.html
+++ b/content/html/content/test/test_bug430351.html
@@ -56,16 +56,17 @@ var focusableElements = [
     "<button type=\"submit\" tabindex=\"0\"></button>",
     "<button type=\"submit\" tabindex=\"1\"></button>",
     "<button type=\"submit\" contenteditable=\"true\"></button>",
 
     "<div tabindex=\"-1\"></div>",
     "<div tabindex=\"0\"></div>",
     "<div tabindex=\"1\"></div>",
     "<div contenteditable=\"true\"></div>",
+    "<div tabindex=\"0\" disabled></div>",
 
     "<embed>",
     "<embed tabindex=\"-1\">",
     "<embed tabindex=\"0\">",
     "<embed tabindex=\"0\" disabled>",
     "<embed tabindex=\"1\">",
     "<embed disabled>",
     "<embed contenteditable=\"true\">",
@@ -160,34 +161,43 @@ var focusableElements = [
     "<object classid=\"java:a\" tabindex=\"1\"></object>",
     "<object classid=\"java:a\" disabled></object>",
     "<object classid=\"java:a\" contenteditable=\"true\"></object>",
 
     "<select></select>",
     "<select tabindex=\"-1\"></select>",
     "<select tabindex=\"0\"></select>",
     "<select tabindex=\"1\"></select>",
-    "<select contenteditable=\"true\"></select>"
+    "<select contenteditable=\"true\"></select>",
+
+    "<option tabindex='-1'></option>",
+    "<option tabindex='0'></option>",
+    "<option tabindex='1'></option>",
+    "<option contenteditable></option>",
+
+    "<optgroup tabindex='-1'></optgroup>",
+    "<optgroup tabindex='0'></optgroup>",
+    "<optgroup tabindex='1'></optgroup>",
+    "<optgroup contenteditable></optgroup>"
 ];
 
 var nonFocusableElements = [
     "<a></a>",
     "<a disabled></a>",
 
     "<button tabindex=\"0\" disabled></button>",
     "<button disabled></button>",
 
     "<button type=\"reset\" tabindex=\"0\" disabled></button>",
     "<button type=\"reset\" disabled></button>",
 
     "<button type=\"submit\" tabindex=\"0\" disabled></button>",
     "<button type=\"submit\" disabled></button>",
 
     "<div></div>",
-    "<div tabindex=\"0\" disabled></div>",
     "<div disabled></div>",
 
     "<img>",
     "<img disabled>",
     "<img contenteditable=\"true\">",
 
     "<img usemap=\"#map\">",
     "<img usemap=\"#map\" tabindex=\"-1\">",
@@ -238,17 +248,23 @@ var nonFocusableElements = [
     "<input type=\"submit\" disabled>",
 
     "<input type=\"text\" tabindex=\"0\" disabled>",
     "<input type=\"text\" disabled>",
 
     "<object></object>",
 
     "<select tabindex=\"0\" disabled></select>",
-    "<select disabled></select>"
+    "<select disabled></select>",
+
+    "<option></option>",
+    "<option tabindex='1' disabled></option>",
+
+    "<optgroup></optgroup>",
+    "<optgroup tabindex='1' disabled></optgroup>"
 ];
 
 var focusableInContentEditable = [
     "<button></button>",
     "<button tabindex=\"-1\"></button>",
     "<button tabindex=\"0\"></button>",
     "<button tabindex=\"1\"></button>",
     "<button contenteditable=\"true\"></button>",
@@ -263,16 +279,17 @@ var focusableInContentEditable = [
     "<button type=\"submit\" tabindex=\"-1\"></button>",
     "<button type=\"submit\" tabindex=\"0\"></button>",
     "<button type=\"submit\" tabindex=\"1\"></button>",
     "<button type=\"submit\" contenteditable=\"true\"></button>",
 
     "<div tabindex=\"-1\"></div>",
     "<div tabindex=\"0\"></div>",
     "<div tabindex=\"1\"></div>",
+    "<div tabindex=\"0\" disabled></div>",
 
     "<embed>",
     "<embed tabindex=\"-1\">",
     "<embed tabindex=\"0\">",
     "<embed tabindex=\"0\" disabled>",
     "<embed tabindex=\"1\">",
     "<embed disabled>",
     "<embed contenteditable=\"true\">",
@@ -360,17 +377,25 @@ var focusableInContentEditable = [
     // Disabled doesn't work for <object>.
     "<object tabindex=\"0\" disabled></object>",
     "<object disabled></object>",
 
     "<select></select>",
     "<select tabindex=\"-1\"></select>",
     "<select tabindex=\"0\"></select>",
     "<select tabindex=\"1\"></select>",
-    "<select contenteditable=\"true\"></select>"
+    "<select contenteditable=\"true\"></select>",
+
+    "<option tabindex='-1'></option>",
+    "<option tabindex='0'></option>",
+    "<option tabindex='1'></option>",
+
+    "<optgroup tabindex='-1'></optgroup>",
+    "<optgroup tabindex='0'></optgroup>",
+    "<optgroup tabindex='1'></optgroup>"
 ];
 
 var focusableInDesignMode = [
     "<embed>",
     "<embed tabindex=\"-1\">",
     "<embed tabindex=\"0\">",
     "<embed tabindex=\"0\" disabled>",
     "<embed tabindex=\"1\">",
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -1353,17 +1353,17 @@ nsHTMLDocument::Open(const nsAString& aC
     // No calling document.open() on XHTML
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   nsCAutoString contentType;
   contentType.AssignLiteral("text/html");
   if (aOptionalArgCount > 0) {
     nsAutoString type;
-    ToLowerCase(aContentTypeOrUrl, type);
+    nsContentUtils::ASCIIToLower(aContentTypeOrUrl, type);
     nsCAutoString actualType, dummy;
     NS_ParseContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy);
     if (!actualType.EqualsLiteral("text/html") &&
         !type.EqualsLiteral("replace")) {
       contentType.AssignLiteral("text/plain");
     }
   }
 
--- a/content/svg/content/src/nsSVGScriptElement.cpp
+++ b/content/svg/content/src/nsSVGScriptElement.cpp
@@ -81,26 +81,31 @@ public:
   NS_FORWARD_NSIDOMELEMENT(nsSVGScriptElementBase::)
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGScriptElementBase::)
 
   // nsIScriptElement
   virtual void GetScriptType(nsAString& type);
   virtual void GetScriptText(nsAString& text);
   virtual void GetScriptCharset(nsAString& charset);
   virtual void FreezeUriAsyncDefer();
+  virtual CORSMode GetCORSMode() const;
   
   // nsScriptElement
   virtual bool HasScriptContent();
 
   // nsIContent specializations:
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers);
   virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify);
+  virtual bool ParseAttribute(PRInt32 aNamespaceID,
+                              nsIAtom* aAttribute,
+                              const nsAString& aValue,
+                              nsAttrValue& aResult);
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   virtual nsXPCClassInfo* GetClassInfo();
 protected:
   virtual StringAttributesInfo GetStringInfo();
 
   enum { HREF };
@@ -283,8 +288,31 @@ nsSVGScriptElement::AfterSetAttr(PRInt32
                                  const nsAttrValue* aValue, bool aNotify)
 {
   if (aNamespaceID == kNameSpaceID_XLink && aName == nsGkAtoms::href) {
     MaybeProcessScript();
   }
   return nsSVGScriptElementBase::AfterSetAttr(aNamespaceID, aName,
                                               aValue, aNotify);
 }
+
+bool
+nsSVGScriptElement::ParseAttribute(PRInt32 aNamespaceID,
+                                   nsIAtom* aAttribute,
+                                   const nsAString& aValue,
+                                   nsAttrValue& aResult)
+{
+  if (aNamespaceID == kNameSpaceID_None &&
+      aAttribute == nsGkAtoms::crossorigin) {
+    ParseCORSValue(aValue, aResult);
+    return true;
+  }
+
+  return nsSVGScriptElementBase::ParseAttribute(aNamespaceID, aAttribute,
+                                                aValue, aResult);
+}
+
+CORSMode
+nsSVGScriptElement::GetCORSMode() const
+{
+  return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
+}
+
--- a/content/svg/content/src/nsSVGStyleElement.cpp
+++ b/content/svg/content/src/nsSVGStyleElement.cpp
@@ -332,19 +332,19 @@ nsSVGStyleElement::GetStyleSheetInfo(nsA
   *aIsAlternate = false;
 
   nsAutoString title;
   GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
   title.CompressWhitespace();
   aTitle.Assign(title);
 
   GetAttr(kNameSpaceID_None, nsGkAtoms::media, aMedia);
-  // SVG spec refers to the HTML4.0 spec which is inconsistent, make it
-  // case INSENSITIVE
-  ToLowerCase(aMedia);
+  // The SVG spec is formulated in terms of the CSS2 spec,
+  // which specifies that media queries are case insensitive.
+  nsContentUtils::ASCIIToLower(aMedia);
 
   GetAttr(kNameSpaceID_None, nsGkAtoms::type, aType);
   if (aType.IsEmpty()) {
     aType.AssignLiteral("text/css");
   }
 
   return;
 }
--- a/content/xbl/src/nsXBLPrototypeHandler.cpp
+++ b/content/xbl/src/nsXBLPrototypeHandler.cpp
@@ -927,31 +927,28 @@ nsXBLPrototypeHandler::ConstructPrototyp
       if (key.IsEmpty()) 
         aKeyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::charcode, key);
     }
   }
 
   if (!key.IsEmpty()) {
     if (mKeyMask == 0)
       mKeyMask = cAllModifiers;
-    ToLowerCase(key);
+    nsContentUtils::ASCIIToLower(key);
 
     // We have a charcode.
     mMisc = 1;
     mDetail = key[0];
     const PRUint8 GTK2Modifiers = cShift | cControl | cShiftMask | cControlMask;
     if ((mKeyMask & GTK2Modifiers) == GTK2Modifiers &&
-        modifiers.First() != PRUnichar(',') &&
-        (mDetail == 'u' || mDetail == 'U'))
+        modifiers.First() != PRUnichar(',') && mDetail == 'u')
       ReportKeyConflict(key.get(), modifiers.get(), aKeyElement, "GTK2Conflict");
     const PRUint8 WinModifiers = cControl | cAlt | cControlMask | cAltMask;
     if ((mKeyMask & WinModifiers) == WinModifiers &&
-        modifiers.First() != PRUnichar(',') &&
-        (('A' <= mDetail && mDetail <= 'Z') ||
-         ('a' <= mDetail && mDetail <= 'z')))
+        modifiers.First() != PRUnichar(',') && ('a' <= mDetail && mDetail <= 'z'))
       ReportKeyConflict(key.get(), modifiers.get(), aKeyElement, "WinConflict");
   }
   else {
     key.Assign(aKeyCode);
     if (mType & NS_HANDLER_TYPE_XUL)
       aKeyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::keycode, key);
     
     if (!key.IsEmpty()) {
--- a/content/xslt/src/base/txStringUtils.h
+++ b/content/xslt/src/base/txStringUtils.h
@@ -39,31 +39,29 @@
 
 #ifndef txStringUtils_h__
 #define txStringUtils_h__
 
 #include "nsAString.h"
 #include "nsIAtom.h"
 #include "nsUnicharUtils.h"
 
-#define TX_ToLowerCase ToLowerCase
-
 typedef nsCaseInsensitiveStringComparator txCaseInsensitiveStringComparator;
 
 /**
  * Check equality between a string and an atom containing ASCII.
  */
 inline bool
 TX_StringEqualsAtom(const nsASingleFragmentString& aString, nsIAtom* aAtom)
 {
   return aAtom->Equals(aString);
 }
 
 inline already_AddRefed<nsIAtom>
 TX_ToLowerCaseAtom(nsIAtom* aAtom)
 {
   nsAutoString str;
   aAtom->ToString(str);
-  TX_ToLowerCase(str);
+  nsContentUtils::ASCIIToLower(str);
   return do_GetAtom(str);
 }
 
 #endif // txStringUtils_h__
--- a/content/xslt/src/xpath/txExprParser.cpp
+++ b/content/xslt/src/xpath/txExprParser.cpp
@@ -933,17 +933,17 @@ txExprParser::resolveQName(const nsAStri
             return NS_ERROR_OUT_OF_MEMORY;
         }
         return aContext->resolveNamespacePrefix(*aPrefix, aNamespace);
     }
     // the lexer dealt with idx == 0
     *aPrefix = 0;
     if (aIsNameTest && aContext->caseInsensitiveNameTests()) {
         nsAutoString lcname;
-        TX_ToLowerCase(aQName, lcname);
+        nsContentUtils::ASCIIToLower(aQName, lcname);
         *aLocalName = NS_NewAtom(lcname);
     }
     else {
         *aLocalName = NS_NewAtom(aQName);
     }
     if (!*aLocalName) {
         return NS_ERROR_OUT_OF_MEMORY;
     }
--- a/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp
+++ b/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp
@@ -448,17 +448,17 @@ txXPathNodeUtils::getLocalName(const txX
     }
 
     aNode.Content()->GetAttrNameAt(aNode.mIndex)->LocalName()->
       ToString(aLocalName);
 
     // Check for html
     if (aNode.Content()->NodeInfo()->NamespaceEquals(kNameSpaceID_None) &&
         aNode.Content()->IsHTML()) {
-        ToUpperCase(aLocalName);
+        nsContentUtils::ASCIIToUpper(aLocalName);
     }
 }
 
 /* static */
 void
 txXPathNodeUtils::getNodeName(const txXPathNode& aNode, nsAString& aName)
 {
     if (aNode.isDocument()) {
--- a/content/xslt/src/xpath/txResultRecycler.cpp
+++ b/content/xslt/src/xpath/txResultRecycler.cpp
@@ -224,33 +224,16 @@ txResultRecycler::getNodeSet(const txXPa
         *aResult = nodes;
     }
     NS_ADDREF(*aResult);
 
     return NS_OK;
 }
 
 nsresult
-txResultRecycler::getNodeSet(const txXPathNode& aNode, txNodeSet** aResult)
-{
-    if (mNodeSetResults.isEmpty()) {
-        *aResult = new txNodeSet(aNode, this);
-        NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
-    }
-    else {
-        *aResult = static_cast<txNodeSet*>(mNodeSetResults.pop());
-        (*aResult)->append(aNode);
-        (*aResult)->mRecycler = this;
-    }
-    NS_ADDREF(*aResult);
-
-    return NS_OK;
-}
-
-nsresult
 txResultRecycler::getNumberResult(double aValue, txAExprResult** aResult)
 {
     if (mNumberResults.isEmpty()) {
         *aResult = new NumberResult(aValue, this);
         NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
     }
     else {
         NumberResult* numRes =
--- a/content/xslt/src/xpath/txResultRecycler.h
+++ b/content/xslt/src/xpath/txResultRecycler.h
@@ -81,17 +81,16 @@ public:
      * Functions to return results that will be fully used by the caller.
      * Returns nsnull on out-of-memory and an inited result otherwise.
      */
     nsresult getStringResult(StringResult** aResult);
     nsresult getStringResult(const nsAString& aValue, txAExprResult** aResult);
     nsresult getNodeSet(txNodeSet** aResult);
     nsresult getNodeSet(txNodeSet* aNodeSet, txNodeSet** aResult);
     nsresult getNodeSet(const txXPathNode& aNode, txAExprResult** aResult);
-    nsresult getNodeSet(const txXPathNode& aNode, txNodeSet** aResult);
     nsresult getNumberResult(double aValue, txAExprResult** aResult);
 
     /**
      * Functions to return a txAExprResult that is shared across several
      * clients and must not be modified. Never returns nsnull.
      */
     void getEmptyStringResult(txAExprResult** aResult);
     void getBoolResult(bool aValue, txAExprResult** aResult);
--- a/content/xslt/src/xslt/txMozillaXMLOutput.cpp
+++ b/content/xslt/src/xslt/txMozillaXMLOutput.cpp
@@ -155,17 +155,17 @@ txMozillaXMLOutput::attribute(nsIAtom* a
                               const nsSubstring& aLocalName,
                               const PRInt32 aNsID,
                               const nsString& aValue)
 {
     nsCOMPtr<nsIAtom> lname;
 
     if (mOpenedElementIsHTML && aNsID == kNameSpaceID_None) {
         nsAutoString lnameStr;
-        ToLowerCase(aLocalName, lnameStr);
+        nsContentUtils::ASCIIToLower(aLocalName, lnameStr);
         lname = do_GetAtom(lnameStr);
     }
     else {
         lname = do_GetAtom(aLocalName);
     }
 
     NS_ENSURE_TRUE(lname, NS_ERROR_OUT_OF_MEMORY);
 
@@ -494,17 +494,17 @@ txMozillaXMLOutput::startElement(nsIAtom
 {
     PRInt32 nsId = aNsID;
     nsCOMPtr<nsIAtom> lname;
 
     if (mOutputFormat.mMethod == eHTMLOutput && aNsID == kNameSpaceID_None) {
         nsId = kNameSpaceID_XHTML;
 
         nsAutoString lnameStr;
-        ToLowerCase(aLocalName, lnameStr);
+        nsContentUtils::ASCIIToLower(aLocalName, lnameStr);
         lname = do_GetAtom(lnameStr);
     }
     else {
         lname = do_GetAtom(aLocalName);
     }
 
     // No biggie if we lose the prefix due to OOM
     NS_ENSURE_TRUE(lname, NS_ERROR_OUT_OF_MEMORY);
@@ -797,17 +797,17 @@ txMozillaXMLOutput::endHTMLElement(nsICo
     else if (mCreatingNewDocument && atom == nsGkAtoms::meta) {
         // handle HTTP-EQUIV data
         nsAutoString httpEquiv;
         aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, httpEquiv);
         if (!httpEquiv.IsEmpty()) {
             nsAutoString value;
             aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::content, value);
             if (!value.IsEmpty()) {
-                ToLowerCase(httpEquiv);
+                nsContentUtils::ASCIIToLower(httpEquiv);
                 nsCOMPtr<nsIAtom> header = do_GetAtom(httpEquiv);
                 processHTTPEquiv(header, value);
             }
         }
     }
     
     return NS_OK;
 }
--- a/content/xul/document/src/nsXULPrototypeDocument.cpp
+++ b/content/xul/document/src/nsXULPrototypeDocument.cpp
@@ -783,21 +783,17 @@ void
 nsXULPDGlobalObject::ClearGlobalObjectOwner()
 {
   NS_ASSERTION(!mCachedPrincipal, "This shouldn't ever be set until now!");
 
   // Cache mGlobalObjectOwner's principal if possible.
   if (this != nsXULPrototypeDocument::gSystemGlobal)
     mCachedPrincipal = mGlobalObjectOwner->DocumentPrincipal();
 
-  if (mContext) {
-    mContext->FinalizeContext();
-    mContext = NULL;
-  }
-
+  mContext = NULL;
   mGlobalObjectOwner = NULL;
 }
 
 
 void
 nsXULPDGlobalObject::OnFinalize(JSObject* aObject)
 {
   mJSObject = NULL;
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -447,17 +447,16 @@
 #include "nsIDOMGeoPositionError.h"
 
 // Workers
 #include "mozilla/dom/workers/Workers.h"
 
 #include "nsDOMFile.h"
 #include "nsDOMFileReader.h"
 #include "nsIDOMFileException.h"
-#include "nsIDOMFileError.h"
 #include "nsIDOMFormData.h"
 
 #include "nsIDOMDOMStringMap.h"
 
 #include "nsIDOMDesktopNotification.h"
 #include "nsIDOMNavigatorDesktopNotification.h"
 #include "nsIDOMNavigatorGeolocation.h"
 #include "Navigator.h"
@@ -1389,18 +1388,16 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(FileList, nsFileListSH,
                            ARRAY_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(Blob, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(File, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(FileException, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(FileError, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(FileReader, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MozURLProperty, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MozBlobBuilder, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(DOMStringMap, nsDOMStringMapSH,
@@ -3959,20 +3956,16 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(ClientRectList, nsIDOMClientRectList)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMClientRectList)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(FileList, nsIDOMFileList)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMFileList)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(FileError, nsIDOMFileError)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMFileError)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(Blob, nsIDOMBlob)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBlob)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(File, nsIDOMFile)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBlob)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMFile)
   DOM_CLASSINFO_MAP_END
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -397,17 +397,16 @@ DOMCI_CLASS(SVGForeignObjectElement)
 DOMCI_CLASS(XULCommandEvent)
 DOMCI_CLASS(CommandEvent)
 DOMCI_CLASS(OfflineResourceList)
 
 DOMCI_CLASS(FileList)
 DOMCI_CLASS(Blob)
 DOMCI_CLASS(File)
 DOMCI_CLASS(FileException)
-DOMCI_CLASS(FileError)
 DOMCI_CLASS(FileReader)
 DOMCI_CLASS(MozURLProperty)
 DOMCI_CLASS(MozBlobBuilder)
 
 DOMCI_CLASS(DOMStringMap)
 
 // DOM modal content window class, almost identical to Window
 DOMCI_CLASS(ModalContentWindow)
--- a/dom/base/nsDOMJSUtils.h
+++ b/dom/base/nsDOMJSUtils.h
@@ -1,15 +1,17 @@
 
 #ifndef nsDOMJSUtils_h__
 #define nsDOMJSUtils_h__
 
 #include "jsapi.h"
 #include "nsIScriptContext.h"
 
+class nsIJSArgArray;
+
 // seems like overkill for just this 1 function - but let's see what else
 // falls out first.
 inline nsIScriptContext *
 GetScriptContextFromJSContext(JSContext *cx)
 {
   if (!(::JS_GetOptions(cx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)) {
     return nsnull;
   }
@@ -45,11 +47,11 @@ GetScriptContextPrincipalFromJSContext(J
 // jsval* and the args are found at:
 //    ((jsval*)aArgv)[0], ..., ((jsval*)aArgv)[aArgc - 1]
 // The resulting object will take a copy of the array, and ensure each
 // element is rooted.
 // Optionally, aArgv may be NULL, in which case the array is allocated and
 // rooted, but all items remain NULL.  This presumably means the caller will
 // then QI us for nsIJSArgArray, and set our array elements.
 nsresult NS_CreateJSArgv(JSContext *aContext, PRUint32 aArgc, void *aArgv,
-                         nsIArray **aArray);
+                         nsIJSArgArray **aArray);
 
 #endif // nsDOMJSUtils_h__
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2397,17 +2397,16 @@ nsGlobalWindow::SetDocShell(nsIDocShell*
       // SetArguments(), drop our reference to the arguments.
       mArguments = nsnull;
       mArgumentsLast = nsnull;
       mArgumentsOrigin = nsnull;
     }
 
     if (mContext) {
       mContext->GC(js::gcreason::SET_DOC_SHELL);
-      mContext->FinalizeContext();
       mContext = nsnull;
     }
 
 #ifdef DEBUG
     nsCycleCollector_DEBUG_shouldBeFreed(mContext);
     nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
 #endif
   }
@@ -5927,17 +5926,17 @@ nsGlobalWindow::OpenDialog(const nsAStri
   jsval *argv = nsnull;
 
   // XXX - need to get this as nsISupports?
   ncc->GetArgc(&argc);
   ncc->GetArgvPtr(&argv);
 
   // Strip the url, name and options from the args seen by scripts.
   PRUint32 argOffset = argc < 3 ? argc : 3;
-  nsCOMPtr<nsIArray> argvArray;
+  nsCOMPtr<nsIJSArgArray> argvArray;
   rv = NS_CreateJSArgv(cx, argc - argOffset, argv + argOffset,
                        getter_AddRefs(argvArray));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return OpenInternal(aUrl, aName, aOptions,
                       true,             // aDialog
                       false,            // aContentModal
                       false,            // aCalledNoScript
@@ -6527,65 +6526,50 @@ nsGlobalWindow::ForceClose()
   DispatchCustomEvent("DOMWindowClose");
 
   return FinalClose();
 }
 
 nsresult
 nsGlobalWindow::FinalClose()
 {
-  nsresult rv;
   // Flag that we were closed.
   mIsClosed = true;
 
   nsCOMPtr<nsIJSContextStack> stack =
     do_GetService(sJSStackContractID);
 
   JSContext *cx = nsnull;
 
   if (stack) {
     stack->Peek(&cx);
   }
 
   if (cx) {
     nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
 
     if (currentCX && currentCX == GetContextInternal()) {
-      // We ignore the return value here.  If setting the termination function
-      // fails, it's better to fail to close the window than it is to crash
-      // (which is what would tend to happen if we did this synchronously
-      // here).
-      rv = currentCX->SetTerminationFunction(CloseWindow,
-                                             static_cast<nsIDOMWindow *>
-                                                        (this));
-      if (NS_SUCCEEDED(rv)) {
-        mHavePendingClose = true;
-      }
+      currentCX->SetTerminationFunction(CloseWindow, this);
+      mHavePendingClose = true;
       return NS_OK;
     }
   }
 
-  
   // We may have plugins on the page that have issued this close from their
   // event loop and because we currently destroy the plugin window with
   // frames, we crash. So, if we are called from Javascript, post an event
   // to really close the window.
-  rv = NS_ERROR_FAILURE;
-  if (!nsContentUtils::IsCallerChrome()) {
-    rv = nsCloseEvent::PostCloseEvent(this);
-  }
-  
-  if (NS_FAILED(rv)) {
+  if (nsContentUtils::IsCallerChrome() ||
+      NS_FAILED(nsCloseEvent::PostCloseEvent(this))) {
     ReallyCloseWindow();
-    rv = NS_OK;
   } else {
     mHavePendingClose = true;
   }
-  
-  return rv;
+
+  return NS_OK;
 }
 
 
 void
 nsGlobalWindow::ReallyCloseWindow()
 {
   FORWARD_TO_OUTER_VOID(ReallyCloseWindow, ());
 
@@ -8862,18 +8846,17 @@ nsGlobalWindow::OpenInternal(const nsASt
         // If script in some other window is doing a window.open on us and
         // it's being blocked, then it's OK to close us afterwards, probably.
         // But if we're doing a window.open on ourselves and block the popup,
         // prevent this window from closing until after this script terminates
         // so that whatever popup blocker UI the app has will be visible.
         if (mContext == GetScriptContextFromJSContext(aJSCallerContext)) {
           mBlockScriptedClosingFlag = true;
           mContext->SetTerminationFunction(CloseBlockScriptTerminationFunc,
-                                           static_cast<nsPIDOMWindow*>
-                                                      (this));
+                                           this);
         }
       }
 
       FireAbuseEvents(true, false, aUrl, aName, aOptions);
       return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
     }
   }    
 
--- a/dom/base/nsIScriptContext.h
+++ b/dom/base/nsIScriptContext.h
@@ -51,16 +51,17 @@ class nsIScriptSecurityManager;
 class nsIPrincipal;
 class nsIAtom;
 class nsIArray;
 class nsIVariant;
 class nsIObjectInputStream;
 class nsIObjectOutputStream;
 template<class> class nsScriptObjectHolder;
 class nsIScriptObjectPrincipal;
+class nsIDOMWindow;
 
 typedef void (*nsScriptTerminationFunc)(nsISupports* aRef);
 
 #define NS_ISCRIPTCONTEXTPRINCIPAL_IID \
   { 0xd012cdb3, 0x8f1e, 0x4440, \
     { 0x8c, 0xbd, 0x32, 0x7f, 0x98, 0x1d, 0x37, 0xb4 } }
 
 class nsIScriptContextPrincipal : public nsISupports
@@ -70,18 +71,18 @@ public:
 
   virtual nsIScriptObjectPrincipal* GetObjectPrincipal() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptContextPrincipal,
                               NS_ISCRIPTCONTEXTPRINCIPAL_IID)
 
 #define NS_ISCRIPTCONTEXT_IID \
-{ 0x6d69fbee, 0x0723, 0x48f5, \
- { 0x82, 0x48, 0xcd, 0xcf, 0x88, 0xac, 0x25, 0x74 } }
+{ 0xdfaea249, 0xaaad, 0x48bd, \
+  { 0xb8, 0x04, 0x92, 0xad, 0x30, 0x88, 0xd0, 0xc6 } }
 
 /* This MUST match JSVERSION_DEFAULT.  This version stuff if we don't
    know what language we have is a little silly... */
 #define SCRIPTVERSION_DEFAULT JSVERSION_DEFAULT
 
 /**
  * It is used by the application to initialize a runtime and run scripts.
  * A script runtime would implement this interface.
@@ -340,21 +341,16 @@ public:
    * reentrancy issues during the initialization process.
    *
    * @return true if initialized, false if not
    *
    */
   virtual bool IsContextInitialized() = 0;
 
   /**
-   * Called as the global object discards its reference to the context.
-   */
-  virtual void FinalizeContext() = 0;
-
-  /**
    * For garbage collected systems, do a synchronous collection pass.
    * May be a no-op on other systems
    *
    * @return NS_OK if the method is successful
    */
   virtual void GC(js::gcreason::Reason aReason) = 0;
 
   /**
@@ -384,28 +380,28 @@ public:
    * than JS (ie, this should be moved to a private interface!)
    * Called to specify a function that should be called when the current
    * script (if there is one) terminates. Generally used if breakdown
    * of script state needs to happen, but should be deferred till
    * the end of script evaluation.
    *
    * @throws NS_ERROR_OUT_OF_MEMORY if that happens
    */
-  virtual nsresult SetTerminationFunction(nsScriptTerminationFunc aFunc,
-                                          nsISupports* aRef) = 0;
+  virtual void SetTerminationFunction(nsScriptTerminationFunc aFunc,
+                                      nsIDOMWindow* aRef) = 0;
 
   /**
    * Called to disable/enable script execution in this context.
    */
   virtual bool GetScriptsEnabled() = 0;
   virtual void SetScriptsEnabled(bool aEnabled, bool aFireTimeouts) = 0;
 
   // SetProperty is suspect and jst believes should not be needed.  Currenly
   // used only for "arguments".
-  virtual nsresult SetProperty(void *aTarget, const char *aPropName, nsISupports *aVal) = 0;
+  virtual nsresult SetProperty(JSObject* aTarget, const char* aPropName, nsISupports* aVal) = 0;
   /** 
    * Called to set/get information if the script context is
    * currently processing a script tag
    */
   virtual bool GetProcessingScriptTag() = 0;
   virtual void SetProcessingScriptTag(bool aResult) = 0;
 
   /**
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2288,27 +2288,27 @@ nsJSContext::InitializeExternalClasses()
 {
   nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager();
   NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
 
   return nameSpaceManager->InitForContext(this);
 }
 
 nsresult
-nsJSContext::SetProperty(void *aTarget, const char *aPropName, nsISupports *aArgs)
+nsJSContext::SetProperty(JSObject* aTarget, const char* aPropName, nsISupports* aArgs)
 {
   PRUint32  argc;
   jsval    *argv = nsnull;
 
   JSAutoRequest ar(mContext);
 
   Maybe<nsRootedJSValueArray> tempStorage;
 
-  nsresult rv;
-  rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc, &argv, tempStorage);
+  nsresult rv =
+    ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc, &argv, tempStorage);
   NS_ENSURE_SUCCESS(rv, rv);
 
   jsval vargs;
 
   // got the arguments, now attach them.
 
   // window.dialogArguments is supposed to be an array if a JS array
   // was passed to showModalDialog(), deal with that here.
@@ -2322,21 +2322,19 @@ nsJSContext::SetProperty(void *aTarget, 
     }
 
     JSObject *args = ::JS_NewArrayObject(mContext, argc, argv);
     vargs = OBJECT_TO_JSVAL(args);
   }
 
   // Make sure to use JS_DefineProperty here so that we can override
   // readonly XPConnect properties here as well (read dialogArguments).
-  rv = ::JS_DefineProperty(mContext, reinterpret_cast<JSObject *>(aTarget),
-                           aPropName, vargs, nsnull, nsnull, 0) ?
-       NS_OK : NS_ERROR_FAILURE;
-
-  return rv;
+  return JS_DefineProperty(mContext, aTarget, aPropName, vargs, NULL, NULL, 0)
+    ? NS_OK
+    : NS_ERROR_FAILURE;
 }
 
 nsresult
 nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs,
                                      JSObject *aScope,
                                      PRUint32 *aArgc,
                                      jsval **aArgv,
                                      Maybe<nsRootedJSValueArray> &aTempStorage)
@@ -2355,17 +2353,17 @@ nsJSContext::ConvertSupportsTojsvals(nsI
   *aArgv = nsnull;
   *aArgc = 0;
 
   nsIXPConnect *xpc = nsContentUtils::XPConnect();
   NS_ENSURE_TRUE(xpc, NS_ERROR_UNEXPECTED);
 
   if (!aArgs)
     return NS_OK;
-  PRUint32 argCtr, argCount;
+  PRUint32 argCount;
   // This general purpose function may need to convert an arg array
   // (window.arguments, event-handler args) and a generic property.
   nsCOMPtr<nsIArray> argsArray(do_QueryInterface(aArgs));
 
   if (argsArray) {
     rv = argsArray->GetLength(&argCount);
     NS_ENSURE_SUCCESS(rv, rv);
     if (argCount == 0)
@@ -2376,17 +2374,17 @@ nsJSContext::ConvertSupportsTojsvals(nsI
 
   // Use the caller's auto guards to release and unroot.
   aTempStorage.construct(mContext);
   bool ok = aTempStorage.ref().SetCapacity(mContext, argCount);
   NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
   jsval *argv = aTempStorage.ref().Elements();
 
   if (argsArray) {
-    for (argCtr = 0; argCtr < argCount && NS_SUCCEEDED(rv); argCtr++) {
+    for (PRUint32 argCtr = 0; argCtr < argCount && NS_SUCCEEDED(rv); argCtr++) {
       nsCOMPtr<nsISupports> arg;
       jsval *thisval = argv + argCtr;
       argsArray->QueryElementAt(argCtr, NS_GET_IID(nsISupports),
                                 getter_AddRefs(arg));
       if (!arg) {
         *thisval = JSVAL_NULL;
         continue;
       }
@@ -2971,22 +2969,16 @@ nsJSContext::DidInitializeContext()
 
 bool
 nsJSContext::IsContextInitialized()
 {
   return mIsInitialized;
 }
 
 void
-nsJSContext::FinalizeContext()
-{
-  ;
-}
-
-void
 nsJSContext::ScriptEvaluated(bool aTerminated)
 {
   if (aTerminated && mTerminations) {
     // Make sure to null out mTerminations before doing anything that
     // might cause new termination funcs to be added!
     nsJSContext::TerminationFuncClosure* start = mTerminations;
     mTerminations = nsnull;
 
@@ -3001,30 +2993,25 @@ nsJSContext::ScriptEvaluated(bool aTermi
   JS_MaybeGC(mContext);
 
   if (aTerminated) {
     mOperationCallbackTime = 0;
     mModalStateTime = 0;
   }
 }
 
-nsresult
+void
 nsJSContext::SetTerminationFunction(nsScriptTerminationFunc aFunc,
-                                    nsISupports* aRef)
+                                    nsIDOMWindow* aRef)
 {
   NS_PRECONDITION(GetExecutingScript(), "should be executing script");
 
   nsJSContext::TerminationFuncClosure* newClosure =
     new nsJSContext::TerminationFuncClosure(aFunc, aRef, mTerminations);
-  if (!newClosure) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
   mTerminations = newClosure;
-  return NS_OK;
 }
 
 bool
 nsJSContext::GetScriptsEnabled()
 {
   return mScriptsEnabled;
 }
 
@@ -3917,17 +3904,17 @@ nsresult NS_CreateJSRuntime(nsIScriptRun
 }
 
 // A fast-array class for JS.  This class supports both nsIJSScriptArray and
 // nsIArray.  If it is JS itself providing and consuming this class, all work
 // can be done via nsIJSScriptArray, and avoid the conversion of elements
 // to/from nsISupports.
 // When consumed by non-JS (eg, another script language), conversion is done
 // on-the-fly.
-class nsJSArgArray : public nsIJSArgArray, public nsIArray {
+class nsJSArgArray : public nsIJSArgArray {
 public:
   nsJSArgArray(JSContext *aContext, PRUint32 argc, jsval *argv, nsresult *prv);
   ~nsJSArgArray();
   // nsISupports
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSArgArray,
                                                          nsIJSArgArray)
 
@@ -4057,17 +4044,17 @@ NS_IMETHODIMP nsJSArgArray::IndexOf(PRUi
 /* nsISimpleEnumerator enumerate (); */
 NS_IMETHODIMP nsJSArgArray::Enumerate(nsISimpleEnumerator **_retval)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 // The factory function
 nsresult NS_CreateJSArgv(JSContext *aContext, PRUint32 argc, void *argv,
-                         nsIArray **aArray)
+                         nsIJSArgArray **aArray)
 {
   nsresult rv;
   nsJSArgArray *ret = new nsJSArgArray(aContext, argc,
                                        static_cast<jsval *>(argv), &rv);
   if (ret == nsnull)
     return NS_ERROR_OUT_OF_MEMORY;
   if (NS_FAILED(rv)) {
     delete ret;
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -42,16 +42,17 @@
 #include "nsCOMPtr.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "nsIObserver.h"
 #include "nsIXPCScriptNotify.h"
 #include "prtime.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIXPConnect.h"
+#include "nsIArray.h"
 
 class nsIXPConnectJSObjectHolder;
 class nsRootedJSValueArray;
 class nsScriptNameSpaceManager;
 namespace mozilla {
 template <class> class Maybe;
 }
 
@@ -138,25 +139,24 @@ public:
   virtual nsresult ConnectToInner(nsIScriptGlobalObject *aNewInner,
                                   JSObject *aOuterGlobal);
   virtual nsresult InitContext();
   virtual nsresult CreateOuterObject(nsIScriptGlobalObject *aGlobalObject,
                                      nsIScriptGlobalObject *aCurrentInner);
   virtual nsresult SetOuterObject(JSObject* aOuterObject);
   virtual nsresult InitOuterWindow();
   virtual bool IsContextInitialized();
-  virtual void FinalizeContext();
 
   virtual void ScriptEvaluated(bool aTerminated);
-  virtual nsresult SetTerminationFunction(nsScriptTerminationFunc aFunc,
-                                          nsISupports* aRef);
+  virtual void SetTerminationFunction(nsScriptTerminationFunc aFunc,
+                                      nsIDOMWindow* aRef);
   virtual bool GetScriptsEnabled();
   virtual void SetScriptsEnabled(bool aEnabled, bool aFireTimeouts);
 
-  virtual nsresult SetProperty(void *aTarget, const char *aPropName, nsISupports *aVal);
+  virtual nsresult SetProperty(JSObject* aTarget, const char* aPropName, nsISupports* aVal);
 
   virtual bool GetProcessingScriptTag();
   virtual void SetProcessingScriptTag(bool aResult);
 
   virtual bool GetExecutingScript();
 
   virtual void SetGCOnDestruction(bool aGCOnDestruction);
 
@@ -343,21 +343,20 @@ public:
   static nsScriptNameSpaceManager* GetNameSpaceManager();
 };
 
 // An interface for fast and native conversion to/from nsIArray. If an object
 // supports this interface, JS can reach directly in for the argv, and avoid
 // nsISupports conversion. If this interface is not supported, the object will
 // be queried for nsIArray, and everything converted via xpcom objects.
 #define NS_IJSARGARRAY_IID \
- { /*{E96FB2AE-CB4F-44a0-81F8-D91C80AFE9A3} */ \
- 0xe96fb2ae, 0xcb4f, 0x44a0, \
- { 0x81, 0xf8, 0xd9, 0x1c, 0x80, 0xaf, 0xe9, 0xa3 } }
+{ 0xb6acdac8, 0xf5c6, 0x432c, \
+  { 0xa8, 0x6e, 0x33, 0xee, 0xb1, 0xb0, 0xcd, 0xdc } }
 
-class nsIJSArgArray: public nsISupports
+class nsIJSArgArray : public nsIArray
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IJSARGARRAY_IID)
   // Bug 312003 describes why this must be "void **", but after calling argv
   // may be cast to jsval* and the args found at:
   //    ((jsval*)argv)[0], ..., ((jsval*)argv)[argc - 1]
   virtual nsresult GetArgs(PRUint32 *argc, void **argv) = 0;
 };
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -96,17 +96,17 @@ private:
 
   nsCOMPtr<nsIScriptContext> mContext;
 
   // filename, line number and JS language version string of the
   // caller of setTimeout()
   nsCString mFileName;
   PRUint32 mLineNo;
   PRUint32 mVersion;
-  nsCOMPtr<nsIArray> mArgv;
+  nsCOMPtr<nsIJSArgArray> mArgv;
 
   // The JS expression to evaluate or function to call, if !mExpr
   JSFlatString *mExpr;
   JSObject *mFunObj;
 };
 
 
 // nsJSScriptTimeoutHandler
@@ -321,28 +321,27 @@ nsJSScriptTimeoutHandler::Init(nsGlobalW
     NS_ENSURE_SUCCESS(rv, rv);
 
     mFunObj = funobj;
 
     // Create our arg array.  argc is the number of arguments passed
     // to setTimeout or setInterval; the first two are our callback
     // and the delay, so only arguments after that need to go in our
     // array.
-    nsCOMPtr<nsIArray> array;
+    nsCOMPtr<nsIJSArgArray> array;
     // NS_MAX(argc - 2, 0) wouldn't work right because argc is unsigned.
     rv = NS_CreateJSArgv(cx, NS_MAX(argc, 2u) - 2, nsnull,
                          getter_AddRefs(array));
     if (NS_FAILED(rv)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     PRUint32 dummy;
     jsval *jsargv = nsnull;
-    nsCOMPtr<nsIJSArgArray> jsarray(do_QueryInterface(array));
-    jsarray->GetArgs(&dummy, reinterpret_cast<void **>(&jsargv));
+    array->GetArgs(&dummy, reinterpret_cast<void **>(&jsargv));
 
     // jsargv might be null if we have argc <= 2
     if (jsargv) {
       for (PRInt32 i = 2; (PRUint32)i < argc; ++i) {
         jsargv[i - 2] = argv[i];
       }
     } else {
       NS_ASSERTION(argc <= 2, "Why do we have no jsargv when we have arguments?");
--- a/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
+++ b/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
@@ -54,26 +54,28 @@ typedef long           WebGLsizeiptr;
 typedef unsigned long  WebGLuint;
 typedef float          WebGLfloat;
 typedef float          WebGLclampf;
 
 %{C++
 // for jsval
 #include "jsapi.h"
 
-namespace js {
-struct ArrayBuffer;
-struct TypedArray;
-}
+namespace mozilla {
+namespace dom {
+class Element;
+} // namespace dom
+} // namespace mozilla
 
 /* Avoid conflict with WinAPI */
 #undef NO_ERROR
 %}
 
 [ptr] native WebGLJSObjectPtr (JSObject);
+[ptr] native Element (mozilla::dom::Element);
 
 //
 // OpenGL object wrappers
 //
 
 [scriptable, builtinclass, uuid(0df9f4ed-f5ff-4e51-a6ff-2bd9785a7639)]
 interface nsIWebGLTexture : nsISupports
 {
@@ -170,17 +172,17 @@ interface nsIWebGLExtensionLoseContext :
 
 [scriptable, uuid(73bfb64d-94bd-4a7a-9eab-6b6d32e57aa0)]
 interface nsIWebGLExtensionTextureFilterAnisotropic : nsIWebGLExtension
 {
   const WebGLenum TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
   const WebGLenum MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
 };
 
-[scriptable, builtinclass, uuid(f000afac-11b3-4c06-a35f-8db411f1cf54)]
+[scriptable, builtinclass, uuid(020474b1-2d3f-403b-b85d-11d9082ccd92)]
 interface nsIDOMWebGLRenderingContext : nsISupports
 {
   //
   //  CONSTANTS
   //
 
   /* ClearBufferMask */
   const unsigned long DEPTH_BUFFER_BIT               = 0x00000100;
@@ -781,29 +783,29 @@ interface nsIDOMWebGLRenderingContext : 
                                    in WebGLsizei width, in WebGLsizei height,
                                    in WebGLint border, in WebGLenum format, in WebGLenum type, in WebGLJSObjectPtr pixels);
   [noscript] void texImage2D_imageData(in WebGLenum target, in WebGLint level, in WebGLenum internalformat,
                                    in WebGLsizei width, in WebGLsizei height,
                                    in WebGLint border, in WebGLenum format, in WebGLenum type, in WebGLJSObjectPtr pixels);
 
   // HTMLImageElement, HTMLCanvasElement, HTMLVideoElement
   [noscript] void texImage2D_dom(in WebGLenum target, in WebGLint level, in WebGLenum internalformat,
-                                 in WebGLenum format, in WebGLenum type, in nsIDOMElement element);
+                                 in WebGLenum format, in WebGLenum type, in Element element);
 
   void texSubImage2D([optional] in long dummy);
   [noscript] void texSubImage2D_array(in WebGLenum target, in WebGLint level,
                                       in WebGLint xoffset, in WebGLint yoffset, in WebGLsizei width, in WebGLsizei height,
                                       in WebGLenum format, in WebGLenum type, in WebGLJSObjectPtr pixels);
   [noscript] void texSubImage2D_imageData(in WebGLenum target, in WebGLint level,
                                       in WebGLint xoffset, in WebGLint yoffset, in WebGLsizei width, in WebGLsizei height,
                                       in WebGLenum format, in WebGLenum type, in WebGLJSObjectPtr pixels);
   // HTMLImageElement, HTMLCanvasElement, HTMLVideoElement
   [noscript] void texSubImage2D_dom(in WebGLenum target, in WebGLint level,
                                     in WebGLint xoffset, in WebGLint yoffset, in WebGLenum format, in WebGLenum type,
-                                    in nsIDOMElement element);
+                                    in Element element);
 
   // Modified: This replaces glTexParameterf, glTexParameterfv, glTexParameteri and glTexParameteriv
   void texParameterf(in WebGLenum target, in WebGLenum pname, in WebGLfloat param);
   void texParameteri(in WebGLenum target, in WebGLenum pname, in WebGLint param);
   //void glTexParameter(in WebGLenum target, in WebGLenum pname, in nsIWebGLArray params);
 
   // Modified: All the glUniform*v forms below are modified by replacing 'count' and 'v' with a nsIWebGLArray
   void uniform1f (in nsIWebGLUniformLocation location, in WebGLfloat x);
--- a/dom/src/storage/nsDOMStorage.cpp
+++ b/dom/src/storage/nsDOMStorage.cpp
@@ -2358,17 +2358,17 @@ NS_IMETHODIMP nsDOMStorageEvent::GetUrl(
   return NS_OK;
 }
 
 /* readonly attribute nsIDOMStorage storageArea; */
 NS_IMETHODIMP nsDOMStorageEvent::GetStorageArea(nsIDOMStorage * *aStorageArea)
 {
   NS_ENSURE_ARG_POINTER(aStorageArea);
 
-  NS_ADDREF(*aStorageArea = mStorageArea);
+  NS_IF_ADDREF(*aStorageArea = mStorageArea);
   return NS_OK;
 }
 
 /* void initStorageEvent (in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in DOMString oldValueArg, in DOMString newValueArg, in DOMString urlArg, in nsIDOMStorage storageAreaArg); */
 NS_IMETHODIMP nsDOMStorageEvent::InitStorageEvent(const nsAString & typeArg,
                                                   bool canBubbleArg,
                                                   bool cancelableArg,
                                                   const nsAString & keyArg,
--- a/dom/system/nsDeviceMotion.cpp
+++ b/dom/system/nsDeviceMotion.cpp
@@ -194,22 +194,25 @@ NS_IMETHODIMP nsDeviceMotion::RemoveList
 
   mListeners.RemoveObject(aListener);
   StartDisconnectTimer();
   return NS_OK;
 }
 
 NS_IMETHODIMP nsDeviceMotion::AddWindowListener(nsIDOMWindow *aWindow)
 {
+  if (mWindowListeners.IndexOf(aWindow) != NoIndex)
+      return NS_OK;
+
   if (mStarted == false) {
     mStarted = true;
     Startup();
   }
-  if (mWindowListeners.IndexOf(aWindow) == NoIndex)
-    mWindowListeners.AppendElement(aWindow);
+
+  mWindowListeners.AppendElement(aWindow);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsDeviceMotion::RemoveWindowListener(nsIDOMWindow *aWindow)
 {
   if (mWindowListeners.IndexOf(aWindow) == NoIndex)
     return NS_OK;
 
@@ -219,38 +222,44 @@ NS_IMETHODIMP nsDeviceMotion::RemoveWind
 }
 
 NS_IMETHODIMP
 nsDeviceMotion::DeviceMotionChanged(PRUint32 type, double x, double y, double z)
 {
   if (!mEnabled)
     return NS_ERROR_NOT_INITIALIZED;
 
-  for (PRUint32 i = mListeners.Count(); i > 0 ; ) {
+  nsCOMArray<nsIDeviceMotionListener> listeners = mListeners;
+  for (PRUint32 i = listeners.Count(); i > 0 ; ) {
     --i;
     nsRefPtr<nsDeviceMotionData> a = new nsDeviceMotionData(type, x, y, z);
-    mListeners[i]->OnMotionChange(a);
+    listeners[i]->OnMotionChange(a);
   }
 
-  for (PRUint32 i = mWindowListeners.Length(); i > 0 ; ) {
+  nsCOMArray<nsIDOMWindow> windowListeners;
+  for (PRUint32 i = 0; i < mWindowListeners.Length(); i++) {
+    windowListeners.AppendObject(mWindowListeners[i]);
+  }
+
+  for (PRUint32 i = windowListeners.Count(); i > 0 ; ) {
     --i;
 
     // check to see if this window is in the background.  if
     // it is, don't send any device motion to it.
-    nsCOMPtr<nsPIDOMWindow> pwindow = do_QueryInterface(mWindowListeners[i]);
+    nsCOMPtr<nsPIDOMWindow> pwindow = do_QueryInterface(windowListeners[i]);
     if (!pwindow ||
         !pwindow->GetOuterWindow() ||
         pwindow->GetOuterWindow()->IsBackground())
       continue;
 
     nsCOMPtr<nsIDOMDocument> domdoc;
-    mWindowListeners[i]->GetDocument(getter_AddRefs(domdoc));
+    windowListeners[i]->GetDocument(getter_AddRefs(domdoc));
 
     if (domdoc) {
-      nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mWindowListeners[i]);
+      nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(windowListeners[i]);
       if (type == nsIDeviceMotionData::TYPE_ACCELERATION)
         FireDOMMotionEvent(domdoc, target, x, y, z);
       else if (type == nsIDeviceMotionData::TYPE_ORIENTATION)
         FireDOMOrientationEvent(domdoc, target, x, y, z);
     }
   }
   return NS_OK;
 }
--- a/dom/tests/mochitest/dom-level2-core/test_getAttributeNS03.html
+++ b/dom/tests/mochitest/dom-level2-core/test_getAttributeNS03.html
@@ -100,17 +100,17 @@ function getAttributeNS03() {
         docRef = this.doc;
       }
       doc = load(docRef, "doc", "staffNS");
       elementList = doc.getElementsByTagName("emp:address");
       testAddr = elementList.item(0);
       assertNotNull("empAddrNotNull",testAddr);
 testAddr.removeAttributeNS(namespaceURI,localName);
       attrValue = testAddr.getAttributeNS(namespaceURI,localName);
-      assertEquals("throw_Equals","",attrValue);
+      assertEquals("throw_Equals",null,attrValue);
        
 }
 
 </script>
 </head>
 <body>
 <h2>Test http://www.w3.org/2001/DOM-Test-Suite/level2/core/getAttributeNS03</h2>
 <p></p>
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -5,20 +5,16 @@ as we have Makefile.in's that integrate 
 documentation and similar, please see the official tarballs at
 http://www.cairographics.org/.
 
 VERSIONS:
 
   cairo (12d521df8acc483b2daa844d4f05dc2fe2765ba6)
   pixman (2f4f2fb4859931bf6dc5632d8c919e7296736427)
 
-***** NOTE FOR VISUAL C++ 6.0 *****
-
-VC6 is not supported.  Please upgrade to VC8.
-
 ==== Patches ====
 
 Some specific things:
 
 max-font-size.patch: Clamp freetype font size to 1000 to avoid overflow issues
 
 win32-logical-font-scale.patch: set CAIRO_WIN32_LOGICAL_FONT_SCALE to 1
 
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -2082,17 +2082,17 @@ protected:
 already_AddRefed<TextureImage>
 GLContextEGL::CreateTextureImage(const nsIntSize& aSize,
                                  TextureImage::ContentType aContentType,
                                  GLenum aWrapMode,
                                  bool aUseNearestFilter)
 {
     nsRefPtr<TextureImage> t = new gl::TiledTextureImage(this, aSize, aContentType, aUseNearestFilter);
     return t.forget();
-};
+}
 
 already_AddRefed<TextureImage>
 GLContextEGL::TileGenFunc(const nsIntSize& aSize,
                                  TextureImage::ContentType aContentType,
                                  bool aUseNearestFilter)
 {
   MakeCurrent();
 
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -414,22 +414,17 @@ gfxWindowsPlatform::UpdateRenderMode()
     bool d2dForceEnabled = false;
     bool d2dBlocked = false;
 
     nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
     if (gfxInfo) {
         PRInt32 status;
         if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT2D, &status))) {
             if (status != nsIGfxInfo::FEATURE_NO_INFO) {
-                d2dDisabled = true;
-                if (status == nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION ||
-                    status == nsIGfxInfo::FEATURE_BLOCKED_DEVICE)
-                {
-                    d2dBlocked = true;
-                }
+                d2dBlocked = true;
             }
         }
     }
 
     d2dDisabled = Preferences::GetBool("gfx.direct2d.disabled", false);
     d2dForceEnabled = Preferences::GetBool("gfx.direct2d.force-enabled", false);
 
     bool tryD2D = !d2dBlocked || d2dForceEnabled;
@@ -521,17 +516,16 @@ gfxWindowsPlatform::VerifyD2DDevice(bool
                                             getter_AddRefs(factory1));
 
             if (FAILED(hr) || !factory1) {
               // This seems to happen with some people running the iZ3D driver.
               // They won't get acceleration.
               return;
             }
     
-            nsRefPtr<IDXGIAdapter1> adapter1; 
             hr = factory1->EnumAdapters1(0, getter_AddRefs(adapter1));
 
             if (SUCCEEDED(hr) && adapter1) {
                 hr = adapter1->CheckInterfaceSupport(__uuidof(ID3D10Device1),
                                                      nsnull);
                 if (FAILED(hr)) {
                     adapter1 = nsnull;
                 }
--- a/image/public/imgIContainer.idl
+++ b/image/public/imgIContainer.idl
@@ -88,17 +88,17 @@ native gfxGraphicsFilter(gfxPattern::Gra
 /**
  * imgIContainer is the interface that represents an image. It allows
  * access to frames as Thebes surfaces, and permits users to extract subregions
  * as other imgIContainers. It also allows drawing of images on to Thebes
  * contexts.
  *
  * Internally, imgIContainer also manages animation of images.
  */
-[scriptable, uuid(2506249c-e0a1-4d8f-846c-2d478247f8d8)]
+[scriptable, uuid(8bf87433-be67-413b-9497-00071c5002bd)]
 interface imgIContainer : nsISupports
 {
   /**
    * The width of the container rectangle.  In the case of any error,
    * zero is returned, and an exception will be thrown.
    */
   readonly attribute PRInt32 width;
 
@@ -279,16 +279,22 @@ interface imgIContainer : nsISupports
     *
     * Upon instantiation images have a lock count of zero. It is an error to
     * call this method without first having made a matching lockImage() call.
     * In other words, the lock count is not allowed to be negative.
     */
   void unlockImage();
 
   /**
+   * If this image is unlocked, discard its decoded data.  If the image is
+   * locked or has already been discarded, do nothing.
+   */
+  void requestDiscard();
+
+  /**
     * Indicates that this imgIContainer has been triggered to update
     * its internal animation state. Likely this should only be called
     * from within nsImageFrame or objects of similar type.
     */
   [notxpcom] void requestRefresh([const] in TimeStamp aTime);
 
   /**
    * Animation mode Constants
--- a/image/public/imgIRequest.idl
+++ b/image/public/imgIRequest.idl
@@ -47,17 +47,17 @@ interface nsIPrincipal;
 
 /**
  * imgIRequest interface
  *
  * @author Stuart Parmenter <stuart@mozilla.com>
  * @version 0.1
  * @see imagelib2
  */
-[scriptable, uuid(c3bf4e2a-f64b-4ac1-a84e-18631b1802ab)]
+[scriptable, uuid(d35a9adb-8328-4b64-b06f-72a165acd080)]
 interface imgIRequest : nsIRequest
 {
   /**
    * the image container...
    * @return the image object associated with the request.
    * @attention NEED DOCS
    */
   readonly attribute imgIContainer image;
@@ -190,16 +190,22 @@ interface imgIRequest : nsIRequest
   /**
    * Unlocks an image.
    *
    * @see imgIContainer::unlockImage for documentation of the underlying call.
    */
   void unlockImage();
 
   /**
+   * If this image is unlocked, discard the image's decoded data.  If the image
+   * is locked or is already discarded, do nothing.
+   */
+  void requestDiscard();
+
+  /**
    * If this request is for an animated image, the method creates a new
    * request which contains the current frame of the image.
    * Otherwise returns the same request.
    */
   imgIRequest getStaticRequest();
 
   /**
    * Requests that the image animate (if it has an animation).
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -2691,16 +2691,28 @@ RasterImage::UnlockImage()
   if (CanDiscard()) {
     nsresult rv = DiscardTracker::Reset(&mDiscardTrackerNode);
     CONTAINER_ENSURE_SUCCESS(rv);
   }
 
   return NS_OK;
 }
 
+//******************************************************************************
+/* void requestDiscard() */
+NS_IMETHODIMP
+RasterImage::RequestDiscard()
+{
+  if (CanDiscard()) {
+    ForceDiscard();
+  }
+
+  return NS_OK;
+}
+
 // Flushes up to aMaxBytes to the decoder.
 nsresult
 RasterImage::DecodeSomeData(PRUint32 aMaxBytes)
 {
   // We should have a decoder if we get here
   NS_ABORT_IF_FALSE(mDecoder, "trying to decode without decoder!");
 
   // If we have nothing to decode, return
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -193,16 +193,17 @@ public:
   NS_IMETHOD GetImageContainer(mozilla::layers::ImageContainer **_retval NS_OUTPARAM);
   NS_IMETHOD CopyFrame(PRUint32 aWhichFrame, PRUint32 aFlags, gfxImageSurface **_retval NS_OUTPARAM);
   NS_IMETHOD ExtractFrame(PRUint32 aWhichFrame, const nsIntRect & aRect, PRUint32 aFlags, imgIContainer **_retval NS_OUTPARAM);
   NS_IMETHOD Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter, const gfxMatrix & aUserSpaceToImageSpace, const gfxRect & aFill, const nsIntRect & aSubimage, const nsIntSize & aViewportSize, PRUint32 aFlags);
   NS_IMETHOD_(nsIFrame *) GetRootLayoutFrame(void);
   NS_SCRIPTABLE NS_IMETHOD RequestDecode(void);
   NS_SCRIPTABLE NS_IMETHOD LockImage(void);
   NS_SCRIPTABLE NS_IMETHOD UnlockImage(void);
+  NS_SCRIPTABLE NS_IMETHOD RequestDiscard(void);
   NS_SCRIPTABLE NS_IMETHOD ResetAnimation(void);
   NS_IMETHOD_(void) RequestRefresh(const mozilla::TimeStamp& aTime);
   // END NS_DECL_IMGICONTAINER
 
   RasterImage(imgStatusTracker* aStatusTracker = nsnull);
   virtual ~RasterImage();
 
   virtual nsresult StartAnimation();
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -622,16 +622,25 @@ VectorImage::LockImage()
 NS_IMETHODIMP
 VectorImage::UnlockImage()
 {
   // This method is for image-discarding, which only applies to RasterImages.
   return NS_OK;
 }
 
 //******************************************************************************
+/* void requestDiscard() */
+NS_IMETHODIMP
+VectorImage::RequestDiscard()
+{
+  // This method is for image-discarding, which only applies to RasterImages.
+  return NS_OK;
+}
+
+//******************************************************************************
 /* void resetAnimation (); */
 NS_IMETHODIMP
 VectorImage::ResetAnimation()
 {
   if (mError)
     return NS_ERROR_FAILURE;
 
   if (!mIsFullyLoaded || !mHaveAnimations) {
--- a/image/src/VectorImage.h
+++ b/image/src/VectorImage.h
@@ -76,16 +76,17 @@ public:
   NS_IMETHOD GetImageContainer(mozilla::layers::ImageContainer **_retval NS_OUTPARAM) { *_retval = NULL; return NS_OK; }
   NS_IMETHOD CopyFrame(PRUint32 aWhichFrame, PRUint32 aFlags, gfxImageSurface **_retval NS_OUTPARAM);
   NS_IMETHOD ExtractFrame(PRUint32 aWhichFrame, const nsIntRect & aRect, PRUint32 aFlags, imgIContainer **_retval NS_OUTPARAM);
   NS_IMETHOD Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter, const gfxMatrix & aUserSpaceToImageSpace, const gfxRect & aFill, const nsIntRect & aSubimage, const nsIntSize & aViewportSize, PRUint32 aFlags);
   NS_IMETHOD_(nsIFrame *) GetRootLayoutFrame(void);
   NS_SCRIPTABLE NS_IMETHOD RequestDecode(void);
   NS_SCRIPTABLE NS_IMETHOD LockImage(void);
   NS_SCRIPTABLE NS_IMETHOD UnlockImage(void);
+  NS_SCRIPTABLE NS_IMETHOD RequestDiscard(void);
   NS_SCRIPTABLE NS_IMETHOD ResetAnimation(void);
   NS_IMETHOD_(void) RequestRefresh(const mozilla::TimeStamp& aTime);
   // END NS_DECL_IMGICONTAINER
 
   VectorImage(imgStatusTracker* aStatusTracker = nsnull);
   virtual ~VectorImage();
 
   // Methods inherited from Image
--- a/image/src/imgRequestProxy.cpp
+++ b/image/src/imgRequestProxy.cpp
@@ -365,16 +365,26 @@ imgRequestProxy::UnlockImage()
   NS_ABORT_IF_FALSE(mLockCount > 0, "calling unlock but no locks!");
 
   mLockCount--;
   if (mImage)
     return mImage->UnlockImage();
   return NS_OK;
 }
 
+/* void requestDiscard (); */
+NS_IMETHODIMP
+imgRequestProxy::RequestDiscard()
+{
+  if (mImage) {
+    return mImage->RequestDiscard();
+  }
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 imgRequestProxy::IncrementAnimationConsumers()
 {
   mAnimationConsumers++;
   if (mImage)
     mImage->IncrementAnimationConsumers();
   return NS_OK;
 }
--- a/image/test/mochitest/Makefile.in
+++ b/image/test/mochitest/Makefile.in
@@ -83,16 +83,17 @@ include $(topsrcdir)/config/rules.mk
                 test_bug552605-1.html \
                 test_bug552605-2.html \
                 bug552605.sjs \
                 bug671906-iframe.html \
                 bug671906.sjs \
                 test_bug671906.html \
 		test_error_events.html \
 		error-early.png \
+		test_drawDiscardedImage.html \
                 $(NULL)
 
 # Tests disabled due to intermittent orange
 # test_bug435296.html disabled - See bug 578591
 # test_bug478398.html disabled - See bug 579139
 
 _CHROME_FILES = imgutils.js \
                 animationPolling.js \
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/test_drawDiscardedImage.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=731419
+-->
+<head>
+  <title>Test for Bug 731419 - Draw an ostensibly discarded image to a canvas</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<body>
+
+<!--
+  Load an image in an iframe, then draw that image to a canvas.  Then set the
+  iframe to display:none (after bug 731419, this causes the image's decoded
+  data to be discarded) and draw the image to a canvas again.  We should draw
+  the same image data both times.
+-->
+
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+var data1;
+
+function drawImage()
+{
+  var canvas = document.getElementById('canvas');
+  var ctx = canvas.getContext('2d');
+  var iframeDoc = document.getElementById('iframe').contentDocument;
+
+  ctx.clearRect(0, 0, canvas.height, canvas.width);
+  ctx.drawImage(iframeDoc.getElementById('image'), 0, 0);
+  return canvas.toDataURL();
+}
+
+function iframeLoad()
+{
+  data1 = drawImage();
+  document.getElementById('iframe').style.display = 'none';
+
+  // Spin the event loop a few times to give the image in the display:none
+  // iframe a chance to be discarded.
+  SimpleTest.executeSoon(function() {
+    SimpleTest.executeSoon(function() {
+      SimpleTest.executeSoon(function() {
+        step2();
+      });
+    });
+  });
+}
+
+function step2()
+{
+  is(drawImage(), data1, "Same image before and after iframe display:none");
+  SimpleTest.finish();
+}
+
+</script>
+
+<canvas id='canvas'></canvas>
+
+<iframe id='iframe' onload='iframeLoad()' src='data:text/html,<img id="image"
+src="data:image/png;base64,
+iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADRElEQVQ4EQXBTWgcZQCA4ff7ZmZ3
+NpvNZLObTWpCuoZGIxWJplAKbVUKavUiHrQHaRG1XrV4SNuD4MFcRDwUoR4qEq2gFUlBEWmtppYi
+acSmMakxtfkx/5tNdmd35/8bn0cAzJ7IXwKGH/q8NDF48vy+7vk/3tzVXDs8nj9cAAiDcD70gwVi
+vvvr4tsjAAAAAmD2RD4GOL34wge21XHsnHWh9/aUjX1pC4C1UpXrP08zN7vMvvujPx3P/PD+0VH3
+BoAcTspXAbK9iuGe78+csy70ZnsVvh+xWQ8p1QI8dNK7CiT9CmeO28/4ZsuVX9/IvQwgmzLaU9LS
+AGh/3KJ5jw6A6ynyL7Xx7UCORiwQGRN0g7C4m4FX9poNV35681ShU6ZbxKDRLJVuZQl9RdSQRB4c
+OtDGoQNtPGHBuh0SaAa+ZvLjHYt8fwfZrpTl2cFp2ZwVDyQzSgLgVIndGN/tIP/c61y/WWb14gaV
+asTWioPSDabnfCqVkK7BHKHtPK0n06oFGQHgewJtbw8AujGNkYTNpTJxbYfaygqR0piYkaRkhMya
+eI2oX9dTQRIFmtrmz7EGpS9vESZjAN7tfo/UL2PouoZwbfxIo9jaoLWlzI7jEPmhLjVEbXs5IPAE
+jx5M0Z5RZDJwqjCENFN8XBtmOP0FXq1O6NR5snsRtsv4C+voCdHQpcfVtTn/xUKXTrMlyfck6BCC
+a02fkDZDqirF5JVrRA8ewagu8NbADN6az9btMoTqjnasKDTHjp5PSM3I5DQy7UliZbCz7bCwFDD/
+b52h3BCviVHOHv2bvmydyvwOM5MSmch9Ji4/SxMNcaNJTw707zdJmBqeo+G5BuO/V6AzQ5Oo01MI
+KBaTOOis3rPZrKeqrbn2hwXA10fY7zvicqeZKPQ8YpKxJCgIpEQXisBVhG6MYcQ0pGJp2XWnSpx8
+52o0ogF8c5/ltMlGIlYHo0qQrq9HxHWFvx3RqCoCFzwn4L+tiIVV5Y5MhWc/mlDnATQAgMkynbMb
+opoN4z2hUAlPBdpO6FNp+JTtkPVaHE7NYX94K/xqrBT/BvwDIAAAgALQAfT1aWJwtyYea9VEXoAo
+RfHGYhTfvRfF48BdYB3YAPgfnOuE39kFlREAAAAASUVORK5CYII=">'></iframe>
+
+</body>
+</html>
+
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -40,16 +40,21 @@
 #ifndef js_utility_h__
 #define js_utility_h__
 
 #include "mozilla/Assertions.h"
 
 #include <stdlib.h>
 #include <string.h>
 
+#ifdef JS_OOM_DO_BACKTRACES
+#include <stdio.h>
+#include <execinfo.h>
+#endif
+
 #include "jstypes.h"
 
 #ifdef __cplusplus
 
 /* The public JS engine namespace. */
 namespace JS {}
 
 /* The mozilla-shared reusable template/utility namespace. */
@@ -107,20 +112,53 @@ extern JS_PUBLIC_API(void) JS_Abort(void
 #else
 # ifdef DEBUG
 /*
  * In order to test OOM conditions, when the shell command-line option
  * |-A NUM| is passed, we fail continuously after the NUM'th allocation.
  */
 extern JS_PUBLIC_DATA(uint32_t) OOM_maxAllocations; /* set from shell/js.cpp */
 extern JS_PUBLIC_DATA(uint32_t) OOM_counter; /* data race, who cares. */
+
+#ifdef JS_OOM_DO_BACKTRACES
+#define JS_OOM_BACKTRACE_SIZE 32
+static JS_ALWAYS_INLINE void
+PrintBacktrace()
+{
+    void* OOM_trace[JS_OOM_BACKTRACE_SIZE];
+    char** OOM_traceSymbols = NULL;
+    int32_t OOM_traceSize = 0;
+    int32_t OOM_traceIdx = 0;
+    OOM_traceSize = backtrace(OOM_trace, JS_OOM_BACKTRACE_SIZE);
+    OOM_traceSymbols = backtrace_symbols(OOM_trace, OOM_traceSize);
+    
+    if (!OOM_traceSymbols)
+        return;
+
+    for (OOM_traceIdx = 0; OOM_traceIdx < OOM_traceSize; ++OOM_traceIdx) {
+        fprintf(stderr, "#%d %s\n", OOM_traceIdx, OOM_traceSymbols[OOM_traceIdx]);
+    }
+
+    free(OOM_traceSymbols);
+}
+
+#define JS_OOM_EMIT_BACKTRACE() \
+    do {\
+        fprintf(stderr, "Forcing artificial memory allocation function failure:\n");\
+	PrintBacktrace();\
+    } while (0)
+# else
+#  define JS_OOM_EMIT_BACKTRACE() do {} while(0)
+#endif /* JS_OOM_DO_BACKTRACES */
+
 #  define JS_OOM_POSSIBLY_FAIL() \
     do \
     { \
         if (++OOM_counter > OOM_maxAllocations) { \
+            JS_OOM_EMIT_BACKTRACE();\
             return NULL; \
         } \
     } while (0)
 
 # else
 #  define JS_OOM_POSSIBLY_FAIL() do {} while(0)
 # endif
 
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -4522,16 +4522,28 @@ MOZ_ARG_ENABLE_BOOL(more-deterministic,
 [  --enable-more-deterministic
                           Enable changes that make the shell more deterministic],
     JS_MORE_DETERMINISTIC=1,
     JS_MORE_DETERMINISTIC= )
 if test -n "$JS_MORE_DETERMINISTIC"; then
     AC_DEFINE(JS_MORE_DETERMINISTIC)
 fi
 
+dnl ========================================================
+dnl Enable output of backtraces on artificial OOMs
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(oom-backtrace,
+[  --enable-oom-backtrace
+                          Enable output of backtraces on artificial OOMs (-A)],
+    JS_OOM_DO_BACKTRACES=1,
+    JS_OOM_DO_BACKTRACES= )
+if test -n "$JS_OOM_DO_BACKTRACES"; then
+    AC_DEFINE(JS_OOM_DO_BACKTRACES)
+fi
+
 dnl ======================================================
 dnl = Enable compiling with ccache
 dnl ======================================================
 MOZ_ARG_WITH_STRING(ccache,
 [  --with-ccache[=path/to/ccache]
                           Enable compiling with ccache],
     CCACHE=$withval, CCACHE="no")
 
--- a/js/src/ds/LifoAlloc.h
+++ b/js/src/ds/LifoAlloc.h
@@ -216,16 +216,18 @@ class LifoAlloc
     /* Frees all held memory. */
     void freeAll();
 
     /* Should be called on GC in order to release any held chunks. */
     void freeUnused();
 
     JS_ALWAYS_INLINE
     void *alloc(size_t n) {
+        JS_OOM_POSSIBLY_FAIL();
+
         void *result;
         if (latest && (result = latest->tryAlloc(n)))
             return result;
 
         if (!getOrCreateChunk(n))
             return NULL;
 
         return latest->allocInfallible(n);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3841,20 +3841,19 @@ NewDenseUnallocatedArray(JSContext *cx, 
 }
 
 #ifdef JS_METHODJIT
 JSObject * JS_FASTCALL
 mjit::stubs::NewDenseUnallocatedArray(VMFrame &f, uint32_t length)
 {
     JSObject *proto = (JSObject *) f.scratch;
     JSObject *obj = NewArray<false>(f.cx, length, proto);
-    if (!obj) {
-        js_ReportOutOfMemory(f.cx);
+    if (!obj)
         THROWV(NULL);
-    }
+
     return obj;
 }
 #endif
 
 JSObject *
 NewDenseCopiedArray(JSContext *cx, uint32_t length, const Value *vp, JSObject *proto /* = NULL */)
 {
     JSObject* obj = NewArray<true>(cx, length, proto);
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -402,16 +402,19 @@ NewGCThing(JSContext *cx, js::gc::AllocK
     JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
 #ifdef JS_THREADSAFE
     JS_ASSERT_IF((cx->compartment == cx->runtime->atomsCompartment),
                  kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
 #endif
     JS_ASSERT(!cx->runtime->gcRunning);
     JS_ASSERT(!cx->runtime->noGCOrAllocationCheck);
 
+    /* For testing out of memory conditions */
+    JS_OOM_POSSIBLY_FAIL();
+
 #ifdef JS_GC_ZEAL
     if (cx->runtime->needZealousGC())
         js::gc::RunDebugGC(cx);
 #endif
 
     js::gc::MaybeCheckStackRoots(cx);
 
     JSCompartment *comp = cx->compartment;
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -1071,18 +1071,20 @@ JSObject::createDenseArray(JSContext *cx
      * The array initially stores its elements inline, there must be enough
      * space for an elements header.
      */
     JS_ASSERT(js::gc::GetGCKindSlots(kind) >= js::ObjectElements::VALUES_PER_HEADER);
 
     uint32_t capacity = js::gc::GetGCKindSlots(kind) - js::ObjectElements::VALUES_PER_HEADER;
 
     JSObject *obj = js_NewGCObject(cx, kind);
-    if (!obj)
+    if (!obj) {
+        js_ReportOutOfMemory(cx);
         return NULL;
+    }
 
     obj->shape_.init(shape);
     obj->type_.init(type);
     obj->slots = NULL;
     obj->setFixedElements();
     new (obj->getElementsHeader()) js::ObjectElements(capacity, length);
 
     return obj;
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -446,33 +446,37 @@ JSObject::toDictionaryMode(JSContext *cx
 
     RootedVarShape shape(cx);
     shape = lastProperty();
 
     while (shape) {
         JS_ASSERT(!shape->inDictionary());
 
         Shape *dprop = js_NewGCShape(cx);
-        if (!dprop)
+        if (!dprop) {
+            js_ReportOutOfMemory(cx);
             return false;
+        }
 
         HeapPtrShape *listp = dictionaryShape
                               ? &dictionaryShape->parent
                               : (HeapPtrShape *) root.address();
 
         StackShape child(shape);
         dprop->initDictionaryShape(child, self->numFixedSlots(), listp);
 
         JS_ASSERT(!dprop->hasTable());
         dictionaryShape = dprop;
         shape = shape->previous();
     }
 
-    if (!root->hashify(cx))
+    if (!root->hashify(cx)) {
+        js_ReportOutOfMemory(cx);
         return false;
+    }
 
     JS_ASSERT((Shape **) root->listp == root.address());
     root->listp = &self->shape_;
     self->shape_ = root;
 
     JS_ASSERT(self->inDictionaryMode());
     root->base()->setSlotSpan(span);
 
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -403,18 +403,20 @@ mjit::Compiler::scanInlineCalls(uint32_t
 
 CompileStatus
 mjit::Compiler::pushActiveFrame(JSScript *script, uint32_t argc)
 {
     if (cx->runtime->profilingScripts && !script->pcCounters)
         script->initCounts(cx);
 
     ActiveFrame *newa = OffTheBooks::new_<ActiveFrame>(cx);
-    if (!newa)
+    if (!newa) {
+        js_ReportOutOfMemory(cx);
         return Compile_Error;
+    }
 
     newa->parent = a;
     if (a)
         newa->parentPC = PC;
     newa->script = script;
     newa->mainCodeStart = masm.size();
     newa->stubCodeStart = stubcc.size();
 
@@ -619,18 +621,20 @@ mjit::Compiler::prepareInferenceTypes(JS
      * When we get to a branch and need to know a variable's value at the
      * branch target, we know it will either be a phi node at the target or
      * the variable's current value, as no phi node is created at the target
      * only if a variable has the same value on all incoming edges.
      */
 
     a->varTypes = (VarType *)
         OffTheBooks::calloc_(TotalSlots(script) * sizeof(VarType));
-    if (!a->varTypes)
+    if (!a->varTypes) {
+        js_ReportOutOfMemory(cx);
         return Compile_Error;
+    }
 
     for (uint32_t slot = ArgSlot(0); slot < TotalSlots(script); slot++) {
         VarType &vt = a->varTypes[slot];
         vt.setTypes(types::TypeScript::SlotTypes(script, slot));
     }
 
     return Compile_Okay;
 }
@@ -6993,18 +6997,20 @@ mjit::Compiler::startLoop(jsbytecode *he
          * We don't keep track of which registers the inner loop uses, so the only
          * registers that can be carried in the outer loop must be mentioned before
          * the inner loop starts.
          */
         loop->clearLoopRegisters();
     }
 
     LoopState *nloop = OffTheBooks::new_<LoopState>(cx, &ssa, this, &frame);
-    if (!nloop || !nloop->init(head, entry, entryTarget))
+    if (!nloop || !nloop->init(head, entry, entryTarget)) {
+        js_ReportOutOfMemory(cx);
         return false;
+    }
 
     nloop->outer = loop;
     loop = nloop;
     frame.setLoop(loop);
 
     return true;
 }
 
@@ -7170,18 +7176,20 @@ mjit::Compiler::jumpAndRun(Jump j, jsbyt
      * must have been called and ensured an allocation at the target.
      */
     RegisterAllocation *lvtarget = NULL;
     bool consistent = true;
     if (cx->typeInferenceEnabled()) {
         RegisterAllocation *&alloc = analysis->getAllocation(target);
         if (!alloc) {
             alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(false);
-            if (!alloc)
+            if (!alloc) {
+                js_ReportOutOfMemory(cx);
                 return false;
+            }
         }
         lvtarget = alloc;
         consistent = frame.consistentRegisters(target);
     }
 
     if (!lvtarget || lvtarget->synced()) {
         JS_ASSERT(consistent);
         if (!jumpInScript(j, target))
--- a/js/src/methodjit/FrameState.cpp
+++ b/js/src/methodjit/FrameState.cpp
@@ -570,18 +570,20 @@ FrameState::dumpAllocation(RegisterAlloc
 }
 #endif
 
 RegisterAllocation *
 FrameState::computeAllocation(jsbytecode *target)
 {
     JS_ASSERT(cx->typeInferenceEnabled());
     RegisterAllocation *alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(false);
-    if (!alloc)
+    if (!alloc) {
+        js_ReportOutOfMemory(cx);
         return NULL;
+    }
 
     /*
      * State must be synced at exception and switch targets, at traps and when
      * crossing between compilation chunks.
      */
     if (a->analysis->getCode(target).safePoint ||
         (!a->parent && !cc.bytecodeInChunk(target))) {
 #ifdef DEBUG
@@ -851,18 +853,20 @@ FrameState::discardForJoin(RegisterAlloc
     }
 
     if (!alloc) {
         /*
          * This shows up for loop entries which are not reachable from the
          * loop head, and for exception, switch target and trap safe points.
          */
         alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(false);
-        if (!alloc)
+        if (!alloc) {
+            js_ReportOutOfMemory(cx);
             return false;
+        }
     }
 
     resetInternalState();
     PodArrayZero(regstate_);
 
     Registers regs(Registers::AvailAnyRegs);
     while (!regs.empty()) {
         AnyRegisterID reg = regs.takeAnyReg();
--- a/js/src/methodjit/LoopState.cpp
+++ b/js/src/methodjit/LoopState.cpp
@@ -153,18 +153,20 @@ LoopState::init(jsbytecode *head, Jump e
                    types::TypeString(types::Type::ObjectType(modifiedProperties[i].object)),
                    TypeIdString(modifiedProperties[i].id));
     }
 
     RegisterAllocation *&alloc = outerAnalysis->getAllocation(head);
     JS_ASSERT(!alloc);
 
     alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(true);
-    if (!alloc)
+    if (!alloc) {
+        js_ReportOutOfMemory(cx);
         return false;
+    }
 
     this->alloc = alloc;
     this->loopRegs = Registers::AvailAnyRegs;
 
     /*
      * Don't hoist bounds checks or loop invariant code in scripts that have
      * had indirect modification of their arguments.
      */
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -1,11 +1,10 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** 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,
@@ -250,40 +249,22 @@ XPCWrappedNativeScope::SetGlobal(XPCCall
             native = static_cast<XPCWrappedNative*>(native)->GetIdentityObject();
     }
 
     // Now init our script object principal, if the new global has one.
     nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(native);
     mScriptObjectPrincipal = sop;
 
     // Lookup 'globalObject.Object.prototype' for our wrapper's proto
-    {
-        AutoJSErrorAndExceptionEater eater(ccx); // scoped error eater
-
-        jsval val;
-        jsid idObj = mRuntime->GetStringID(XPCJSRuntime::IDX_OBJECT);
-        jsid idProto = mRuntime->GetStringID(XPCJSRuntime::IDX_PROTOTYPE);
-
-        // When creating a new scope to boostrap a new global, we don't yet have
-        // an XPCWrappedNative associated with the global object. However, the
-        // resolve hook on the JSClass assumes there is one. So we need to avoid
-        // resolving anything on the global object until things get a bit further
-        // along. As such, we manually resolve |Object| before accessing it below.
-        JSBool didResolve;
-
-        if (JS_ResolveStandardClass(ccx, aGlobal, idObj, &didResolve) &&
-            JS_GetPropertyById(ccx, aGlobal, idObj, &val) &&
-            !JSVAL_IS_PRIMITIVE(val) &&
-            JS_GetPropertyById(ccx, JSVAL_TO_OBJECT(val), idProto, &val) &&
-            !JSVAL_IS_PRIMITIVE(val)) {
-            mPrototypeJSObject = JSVAL_TO_OBJECT(val);
-        } else {
-            NS_ERROR("Can't get globalObject.Object.prototype");
-        }
-    }
+    JSObject *objectPrototype =
+        JS_GetObjectPrototype(ccx.GetJSContext(), aGlobal);
+    if (objectPrototype)
+        mPrototypeJSObject = objectPrototype;
+    else
+        NS_ERROR("Can't get globalObject.Object.prototype");
 
     // Clear the no helper wrapper prototype object so that a new one
     // gets created if needed.
     mPrototypeNoHelper = nsnull;
 }
 
 XPCWrappedNativeScope::~XPCWrappedNativeScope()
 {
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -3949,40 +3949,16 @@ private:
     PRUint32 mColumnNumber;
     PRUint32 mFlags;
     nsCString mCategory;
     PRUint64 mOuterWindowID;
     PRUint64 mInnerWindowID;
     PRInt64 mTimeStamp;
 };
 
-/***************************************************************************/
-
-class NS_STACK_CLASS AutoJSErrorAndExceptionEater
-{
-public:
-    AutoJSErrorAndExceptionEater(JSContext* aCX
-                                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-        : mCX(aCX),
-          mOldErrorReporter(JS_SetErrorReporter(mCX, nsnull)),
-          mOldExceptionState(JS_SaveExceptionState(mCX)) {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-    ~AutoJSErrorAndExceptionEater()
-    {
-        JS_SetErrorReporter(mCX, mOldErrorReporter);
-        JS_RestoreExceptionState(mCX, mOldExceptionState);
-    }
-private:
-    JSContext*        mCX;
-    JSErrorReporter   mOldErrorReporter;
-    JSExceptionState* mOldExceptionState;
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 /******************************************************************************
  * Handles pre/post script processing and the setting/resetting the error
  * reporter
  */
 class NS_STACK_CLASS AutoScriptEvaluate
 {
 public:
     /**
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -3529,17 +3529,25 @@ nsCSSFrameConstructor::FindObjectData(El
                        sObjectData, ArrayLength(sObjectData));
 }
 
 /* static */
 const nsCSSFrameConstructor::FrameConstructionData*
 nsCSSFrameConstructor::FindCanvasData(Element* aElement,
                                       nsStyleContext* aStyleContext)
 {
-  if (!aElement->OwnerDoc()->IsScriptEnabled()) {
+  // We want to check whether script is enabled on the document that
+  // could be painting to the canvas.  That's the owner document of
+  // the canvas, except when the owner document is a static document,
+  // in which case it's the original document it was cloned from.
+  nsIDocument* doc = aElement->OwnerDoc();
+  if (doc->IsStaticDocument()) {
+    doc = doc->GetOriginalDocument();
+  }
+  if (!doc->IsScriptEnabled()) {
     return nsnull;
   }
 
   static const FrameConstructionData sCanvasData =
     FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewHTMLCanvasFrame,
                                nsCSSAnonBoxes::htmlCanvasContent);
   return &sCanvasData;
 }
@@ -3901,24 +3909,32 @@ bool IsXULDisplayType(const nsStyleDispl
 
 // XUL frames are not allowed to be out of flow.
 #define SIMPLE_XUL_FCDATA(_func)                                        \
   FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH,    \
               _func)
 #define SCROLLABLE_XUL_FCDATA(_func)                                    \
   FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_SKIP_ABSPOS_PUSH |   \
               FCDATA_MAY_NEED_SCROLLFRAME, _func)
+// .. but we allow some XUL frames to be _containers_ for out-of-flow content
+// (This is the same as SCROLLABLE_XUL_FCDATA, but w/o FCDATA_SKIP_ABSPOS_PUSH)
+#define SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func)                   \
+  FCDATA_DECL(FCDATA_DISALLOW_OUT_OF_FLOW |                             \
+              FCDATA_MAY_NEED_SCROLLFRAME, _func)
+
 #define SIMPLE_XUL_CREATE(_tag, _func)            \
   { &nsGkAtoms::_tag, SIMPLE_XUL_FCDATA(_func) }
 #define SCROLLABLE_XUL_CREATE(_tag, _func)            \
   { &nsGkAtoms::_tag, SCROLLABLE_XUL_FCDATA(_func) }
 #define SIMPLE_XUL_INT_CREATE(_int, _func)      \
   { _int, SIMPLE_XUL_FCDATA(_func) }
 #define SCROLLABLE_XUL_INT_CREATE(_int, _func)                          \
   { _int, SCROLLABLE_XUL_FCDATA(_func) }
+#define SCROLLABLE_ABSPOS_CONTAINER_XUL_INT_CREATE(_int, _func)         \
+  { _int, SCROLLABLE_ABSPOS_CONTAINER_XUL_FCDATA(_func) }
 
 static
 nsIFrame* NS_NewGridBoxFrame(nsIPresShell* aPresShell,
                              nsStyleContext* aStyleContext)
 {
   nsCOMPtr<nsBoxLayout> layout;
   NS_NewGridLayout2(aPresShell, getter_AddRefs(layout));
   if (!layout) {
@@ -4104,18 +4120,20 @@ nsCSSFrameConstructor::FindXULListItemDa
 
 /* static */
 const nsCSSFrameConstructor::FrameConstructionData*
 nsCSSFrameConstructor::FindXULDisplayData(const nsStyleDisplay* aDisplay,
                                           Element* aElement,
                                           nsStyleContext* aStyleContext)
 {
   static const FrameConstructionDataByInt sXULDisplayData[] = {
-    SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_BOX, NS_NewBoxFrame),
-    SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_BOX, NS_NewBoxFrame),
+    SCROLLABLE_ABSPOS_CONTAINER_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_BOX,
+                                               NS_NewBoxFrame),
+    SCROLLABLE_ABSPOS_CONTAINER_XUL_INT_CREATE(NS_STYLE_DISPLAY_BOX,
+                                               NS_NewBoxFrame),
 #ifdef MOZ_XUL
     SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_INLINE_GRID, NS_NewGridBoxFrame),
     SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GRID, NS_NewGridBoxFrame),
     SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GRID_GROUP,
                               NS_NewGridRowGroupFrame),
     SCROLLABLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_GRID_LINE,
                               NS_NewGridRowLeafFrame),
     SIMPLE_XUL_INT_CREATE(NS_STYLE_DISPLAY_DECK, NS_NewDeckFrame),
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -85,17 +85,16 @@
 #include "nsTArray.h"
 #include "nsHTMLCanvasElement.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "gfxPlatform.h"
 #include "nsClientRect.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLVideoElement.h"
 #endif
-#include "nsGenericHTMLElement.h"
 #include "imgIRequest.h"
 #include "nsIImageLoadingContent.h"
 #include "nsCOMPtr.h"
 #include "nsListControlFrame.h"
 #include "ImageLayers.h"
 #include "mozilla/arm.h"
 #include "mozilla/dom/Element.h"
 #include "nsCanvasFrame.h"
@@ -4197,17 +4196,17 @@ nsLayoutUtils::SurfaceFromElement(dom::E
         new gfxImageSurface(size, gfxASurface::ImageFormatARGB32);
 
       nsRefPtr<gfxContext> ctx = new gfxContext(imgSurf);
       ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
       ctx->DrawSurface(surf, size);
       surf = imgSurf;
     }
 
-    result.mCORSUsed = video->GetCORSMode() != nsGenericHTMLElement::CORS_NONE;
+    result.mCORSUsed = video->GetCORSMode() != CORS_NONE;
     result.mSurface = surf;
     result.mSize = size;
     result.mPrincipal = principal.forget();
     result.mIsWriteOnly = false;
 
     return result;
   }
 #endif
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -2264,17 +2264,17 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
         }
         isOverflowLine = true;
       }
 
       if (pulledFrames.IsEmpty()) {
         // The line is empty. Try the next one.
         NS_ASSERTION(pulledLine->GetChildCount() == 0 &&
                      !pulledLine->mFirstChild, "bad empty line");
-        aState.FreeLineBox(pulledLine);
+        FreeLineBox(pulledLine);
         continue;
       }
 
       ReparentFrames(pulledFrames, nextInFlow, this);
 
       NS_ASSERTION(pulledFrames.LastChild() == pulledLine->LastChild(),
                    "Unexpected last frame");
       NS_ASSERTION(aState.mPrevChild || mLines.empty(), "should have a prevchild here");
@@ -2459,17 +2459,17 @@ nsBlockFrame::DeleteLine(nsBlockReflowSt
 {
   NS_PRECONDITION(0 == aLine->GetChildCount(), "can't delete !empty line");
   if (0 == aLine->GetChildCount()) {
     NS_ASSERTION(aState.mCurrentLine == aLine,
                  "using function more generally than designed, "
                  "but perhaps OK now");
     nsLineBox *line = aLine;
     aLine = mLines.erase(aLine);
-    aState.FreeLineBox(line);
+    FreeLineBox(line);
     // Mark the previous margin of the next line dirty since we need to
     // recompute its top position.
     if (aLine != aLineEnd)
       aLine->MarkPreviousMarginDirty();
   }
 }
 
 static void
@@ -2666,42 +2666,40 @@ nsBlockFrame::PullFrameFrom(nsBlockReflo
     mFrames.InsertFrame(nsnull, aState.mPrevChild, frame);
 
     // The frame might have (or contain) floats that need to be
     // brought over too.
     ReparentFloats(frame, aFromContainer, aFromOverflowLine, true);
   }
   // when aFromContainer is 'this', then aLine->LastChild()'s next sibling
   // is already set correctly.
-  aLine->SetChildCount(aLine->GetChildCount() + 1);
-    
-  PRInt32 fromLineChildCount = fromLine->GetChildCount();
-  if (0 != --fromLineChildCount) {
+  aLine->NoteFrameAdded(frame);
+
+  if (fromLine->GetChildCount() > 1) {
     // Mark line dirty now that we pulled a child
-    fromLine->SetChildCount(fromLineChildCount);
+    fromLine->NoteFrameRemoved(frame);
     fromLine->MarkDirty();
     fromLine->mFirstChild = newFirstChild;
-  }
-  else {
+  } else {
     // Free up the fromLine now that it's empty
     // Its bounds might need to be redrawn, though.
     // XXX WHY do we invalidate the bounds AND the combined area? doesn't
     // the combined area always enclose the bounds?
     Invalidate(fromLine->mBounds);
     FrameLines* overflowLines =
       aFromOverflowLine ? aFromContainer->RemoveOverflowLines() : nsnull;
     nsLineList* fromLineList =
       aFromOverflowLine ? &overflowLines->mLines : &aFromContainer->mLines;
     if (aFromLine.next() != fromLineList->end())
       aFromLine.next()->MarkPreviousMarginDirty();
 
     Invalidate(fromLine->GetVisualOverflowArea());
     fromLineList->erase(aFromLine);
     // aFromLine is now invalid
-    aState.FreeLineBox(fromLine);
+    FreeLineBox(fromLine);
 
     // Put any remaining overflow lines back.
     if (aFromOverflowLine) {
       if (!fromLineList->empty()) {
         aFromContainer->SetOverflowLines(overflowLines);
       } else {
         delete overflowLines;
         // Now any iterators into fromLineList are invalid (but
@@ -3300,17 +3298,17 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
               mFrames.InsertFrame(nsnull, frame, nextFrame);
               madeContinuation = true; // needs to be added to mLines
               nextFrame->RemoveStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
               frameReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
             }
 
             // Push continuation to a new line, but only if we actually made one.
             if (madeContinuation) {
-              nsLineBox* line = aState.NewLineBox(nextFrame, 1, true);
+              nsLineBox* line = NewLineBox(nextFrame, true);
               NS_ENSURE_TRUE(line, NS_ERROR_OUT_OF_MEMORY);
               mLines.after_insert(aLine, line);
             }
 
             PushLines(aState, aLine);
             NS_FRAME_SET_INCOMPLETE(aState.mReflowStatus);
 
             // If we need to reflow the continuation of the block child,
@@ -3634,17 +3632,17 @@ nsBlockFrame::DoReflowInlineFrames(nsBlo
       // in case we are finished.
       ++aLine;
       while ((aLine != end_lines()) && (0 == aLine->GetChildCount())) {
         // XXX Is this still necessary now that DeleteNextInFlowChild
         // uses DoRemoveFrame?
         nsLineBox *toremove = aLine;
         aLine = mLines.erase(aLine);
         NS_ASSERTION(nsnull == toremove->mFirstChild, "bad empty line");
-        aState.FreeLineBox(toremove);
+        FreeLineBox(toremove);
       }
       --aLine;
 
       NS_ASSERTION(lineReflowStatus != LINE_REFLOW_TRUNCATED,
                    "ReflowInlineFrame should never determine that a line "
                    "needs to go to the next page/column");
     }
   }
@@ -3971,17 +3969,17 @@ nsBlockFrame::CreateContinuationFor(nsBl
       CreateContinuingFrame(aState.mPresContext, aFrame, this, &newFrame);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     mFrames.InsertFrame(nsnull, aFrame, newFrame);
 
     if (aLine) { 
-      aLine->SetChildCount(aLine->GetChildCount() + 1);
+      aLine->NoteFrameAdded(newFrame);
     }
 
     aMadeNewFrame = true;
   }
 #ifdef DEBUG
   VerifyLines(false);
 #endif
   return NS_OK;
@@ -4094,22 +4092,21 @@ nsBlockFrame::SplitLine(nsBlockReflowSta
         f = f->GetNextSibling();
         --count;
       }
       NS_ASSERTION(count == 0, "Not enough frames to push");
     }
 #endif
 
     // Put frames being split out into their own line
-    nsLineBox* newLine = aState.NewLineBox(aFrame, pushCount, false);
+    nsLineBox* newLine = NewLineBox(aLine, aFrame, pushCount);
     if (!newLine) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
     mLines.after_insert(aLine, newLine);
-    aLine->SetChildCount(aLine->GetChildCount() - pushCount);
 #ifdef DEBUG
     if (gReallyNoisyReflow) {
       newLine->List(stdout, gNoiseIndent+1);
     }
 #endif
 
     // Let line layout know that some frames are no longer part of its
     // state.
@@ -4869,18 +4866,16 @@ nsBlockFrame::AddFrames(nsFrameList& aFr
   }
 
   // If we're inserting at the beginning of our list and we have an
   // inside bullet, insert after that bullet.
   if (!aPrevSibling && HasInsideBullet()) {
     aPrevSibling = GetInsideBullet();
   }
   
-  nsIPresShell *presShell = PresContext()->PresShell();
-
   // Attempt to find the line that contains the previous sibling
   FrameLines* overflowLines;
   nsLineList* lineList = &mLines;
   nsLineList::iterator prevSibLine = lineList->end();
   PRInt32 prevSiblingIndex = -1;
   if (aPrevSibling) {
     // XXX_perf This is technically O(N^2) in some cases, but by using
     // RFind instead of Find, we make it O(N) in the most common case,
@@ -4917,22 +4912,21 @@ nsBlockFrame::AddFrames(nsFrameList& aFr
   // Find the frame following aPrevSibling so that we can join up the
   // two lists of frames.
   if (aPrevSibling) {
     // Split line containing aPrevSibling in two if the insertion
     // point is somewhere in the middle of the line.
     PRInt32 rem = prevSibLine->GetChildCount() - prevSiblingIndex - 1;
     if (rem) {
       // Split the line in two where the frame(s) are being inserted.
-      nsLineBox* line = NS_NewLineBox(presShell, aPrevSibling->GetNextSibling(), rem, false);
+      nsLineBox* line = NewLineBox(prevSibLine, aPrevSibling->GetNextSibling(), rem);
       if (!line) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
       lineList->after_insert(prevSibLine, line);
-      prevSibLine->SetChildCount(prevSibLine->GetChildCount() - rem);
       // Mark prevSibLine dirty and as needing textrun invalidation, since
       // we may be breaking up text in the line. Its previous line may also
       // need to be invalidated because it may be able to pull some text up.
       MarkLineDirty(prevSibLine);
       // The new line will also need its textruns recomputed because of the
       // frame changes.
       line->MarkDirty();
       line->SetInvalidateTextRuns(true);
@@ -4963,33 +4957,33 @@ nsBlockFrame::AddFrames(nsFrameList& aFr
     // previous line is a block line we need to make a new line.  We also make
     // a new line, as an optimization, in the two cases we know we'll need it:
     // if the previous line ended with a <br>, or if it has significant whitespace
     // and ended in a newline.
     if (isBlock || prevSibLine == lineList->end() || prevSibLine->IsBlock() ||
         (aPrevSibling && ShouldPutNextSiblingOnNewLine(aPrevSibling))) {
       // Create a new line for the frame and add its line to the line
       // list.
-      nsLineBox* line = NS_NewLineBox(presShell, newFrame, 1, isBlock);
+      nsLineBox* line = NewLineBox(newFrame, isBlock);
       if (!line) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
       if (prevSibLine != lineList->end()) {
         // Append new line after prevSibLine
         lineList->after_insert(prevSibLine, line);
         ++prevSibLine;
       }
       else {
         // New line is going before the other lines
         lineList->push_front(line);
         prevSibLine = lineList->begin();
       }
     }
     else {
-      prevSibLine->SetChildCount(prevSibLine->GetChildCount() + 1);
+      prevSibLine->NoteFrameAdded(newFrame);
       // We're adding inline content to prevSibLine, so we need to mark it
       // dirty, ensure its textruns are recomputed, and possibly do the same
       // to its previous line since that line may be able to pull content up.
       MarkLineDirty(prevSibLine);
     }
 
     aPrevSibling = newFrame;
   }
@@ -5501,19 +5495,17 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aD
     // first frame in the main or overflow list.
     if (searchingOverflowList) {
       overflowLines->mFrames.RemoveFrame(aDeletedFrame);
     } else {
       mFrames.RemoveFrame(aDeletedFrame);
     }
 
     // Update the child count of the line to be accurate
-    PRInt32 lineChildCount = line->GetChildCount();
-    lineChildCount--;
-    line->SetChildCount(lineChildCount);
+    line->NoteFrameRemoved(aDeletedFrame);
 
     // Destroy frame; capture its next continuation first in case we need
     // to destroy that too.
     nsIFrame* deletedNextContinuation = (aFlags & REMOVE_FIXED_CONTINUATIONS) ?
         aDeletedFrame->GetNextContinuation() : aDeletedFrame->GetNextInFlow();
 #ifdef NOISY_REMOVE_FRAME
     printf("DoRemoveFrame: %s line=%p frame=",
            searchingOverflowList?"overflow":"normal", line.get());
@@ -5530,17 +5522,17 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aD
       deletedNextContinuation = nsnull;
     }
 
     aDeletedFrame->Destroy();
     aDeletedFrame = deletedNextContinuation;
 
     bool haveAdvancedToNextLine = false;
     // If line is empty, remove it now.
-    if (0 == lineChildCount) {
+    if (0 == line->GetChildCount()) {
 #ifdef NOISY_REMOVE_FRAME
         printf("DoRemoveFrame: %s line=%p became empty so it will be removed\n",
                searchingOverflowList?"overflow":"normal", line.get());
 #endif
       nsLineBox *cur = line;
       if (!searchingOverflowList) {
         line = mLines.erase(line);
         // Invalidate the space taken up by the line.
@@ -5683,22 +5675,20 @@ nsBlockFrame::StealFrame(nsPresContext* 
         }
         if (searchingOverflowList) {
           overflowLines->mFrames.RemoveFrame(frame);
         } else {
           mFrames.RemoveFrame(frame);
         }
 
         // Register removal with the line boxes
-        PRInt32 count = line->GetChildCount();
-        line->SetChildCount(--count);
-        if (count > 0) {
+        line->NoteFrameRemoved(frame);
+        if (line->GetChildCount() > 0) {
            line->MarkDirty();
-        }
-        else {
+        } else {
           // Remove the line box
           nsLineBox* lineBox = line;
           if (searchingOverflowList) {
             // Erase line, but avoid making the overflow line list empty
             // XXX update overflowLines directly, remove only when empty
             RemoveOverflowLines();
             line = overflowLines->mLines.erase(line);
             if (!overflowLines->mLines.empty()) {
@@ -5707,18 +5697,17 @@ nsBlockFrame::StealFrame(nsPresContext* 
               delete overflowLines;
               // We just invalidated our iterators.  Since we were in
               // the overflow lines list, which is now empty, set them
               // so we're at the end of the regular line list.
               line_start = mLines.begin();
               line_end = mLines.end();
               line = line_end;
             }
-          }
-          else {
+          } else {
             line = mLines.erase(line);
           }
           lineBox->Destroy(aPresContext->PresShell());
           if (line != line_end) {
             // Line disappeared, so tell next line it may have to change position
             line->MarkPreviousMarginDirty();
           }
         }
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -349,16 +349,26 @@ protected:
     return aPresContext->StyleSet()->
       ProbePseudoElementStyle(mContent->AsElement(),
                               nsCSSPseudoElements::ePseudo_firstLetter,
                               mStyleContext);
   }
 #endif
 #endif
 
+  nsLineBox* NewLineBox(nsIFrame* aFrame, bool aIsBlock) {
+    return NS_NewLineBox(PresContext()->PresShell(), aFrame, aIsBlock);
+  }
+  nsLineBox* NewLineBox(nsLineBox* aFromLine, nsIFrame* aFrame, PRInt32 aCount) {
+    return NS_NewLineBox(PresContext()->PresShell(), aFromLine, aFrame, aCount);
+  }
+  void FreeLineBox(nsLineBox* aLine) {
+    aLine->Destroy(PresContext()->PresShell());
+  }
+
   void TryAllLines(nsLineList::iterator* aIterator,
                    nsLineList::iterator* aStartIterator,
                    nsLineList::iterator* aEndIterator,
                    bool*        aInOverflowLines,
                    FrameLines** aOverflowLines);
 
   void SetFlags(nsFrameState aFlags) {
     mState &= ~NS_BLOCK_FLAGS_MASK;
--- a/layout/generic/nsBlockReflowState.cpp
+++ b/layout/generic/nsBlockReflowState.cpp
@@ -144,32 +144,16 @@ nsBlockReflowState::nsBlockReflowState(c
   mY = mContentArea.y = borderPadding.top;
 
   mPrevChild = nsnull;
   mCurrentLine = aFrame->end_lines();
 
   mMinLineHeight = aReflowState.CalcLineHeight();
 }
 
-nsLineBox*
-nsBlockReflowState::NewLineBox(nsIFrame* aFrame,
-                               PRInt32 aCount,
-                               bool aIsBlock)
-{
-  return NS_NewLineBox(mPresContext->PresShell(), aFrame, aCount, aIsBlock);
-}
-
-void
-nsBlockReflowState::FreeLineBox(nsLineBox* aLine)
-{
-  if (aLine) {
-    aLine->Destroy(mPresContext->PresShell());
-  }
-}
-
 void
 nsBlockReflowState::ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame,
                                                          const nsRect& aFloatAvailableSpace,
                                                          nscoord& aLeftResult,
                                                          nscoord& aRightResult)
 {
   // The frame is clueless about the float manager and therefore we
   // only give it free space. An example is a table frame - the
--- a/layout/generic/nsBlockReflowState.h
+++ b/layout/generic/nsBlockReflowState.h
@@ -174,20 +174,16 @@ public:
   void AdvanceToNextLine() {
     if (GetFlag(BRS_LINE_LAYOUT_EMPTY)) {
       SetFlag(BRS_LINE_LAYOUT_EMPTY, false);
     } else {
       mLineNumber++;
     }
   }
 
-  nsLineBox* NewLineBox(nsIFrame* aFrame, PRInt32 aCount, bool aIsBlock);
-
-  void FreeLineBox(nsLineBox* aLine);
-
   //----------------------------------------
 
   // This state is the "global" state computed once for the reflow of
   // the block.
 
   // The block frame that is using this object
   nsBlockFrame* mBlock;
 
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -7555,16 +7555,30 @@ nsFrame::DoLayout(nsBoxLayoutState& aSta
     }
   }
 
   // Should we do this if IsCollapsed() is true?
   nsSize size(GetSize());
   desiredSize.width = size.width;
   desiredSize.height = size.height;
   desiredSize.UnionOverflowAreasWithDesiredBounds();
+
+  if (HasAbsolutelyPositionedChildren()) {
+    // Set up a |reflowState| to pass into ReflowAbsoluteFrames
+    nsHTMLReflowState reflowState(aState.PresContext(), this,
+                                  aState.GetRenderingContext(),
+                                  nsSize(size.width, NS_UNCONSTRAINEDSIZE));
+
+    // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames
+    // (just a dummy value; hopefully that's OK)
+    nsReflowStatus reflowStatus = NS_FRAME_COMPLETE;
+    ReflowAbsoluteFrames(aState.PresContext(), desiredSize,
+                         reflowState, reflowStatus);
+  }
+
   FinishAndStoreOverflow(desiredSize.mOverflowAreas, size);
 
   SyncLayout(aState);
 
   return rv;
 }
 
 nsresult
--- a/layout/generic/nsLineBox.cpp
+++ b/layout/generic/nsLineBox.cpp
@@ -50,16 +50,21 @@
 #include "nsBidiPresUtils.h"
 #endif
 
 #ifdef DEBUG
 static PRInt32 ctorCount;
 PRInt32 nsLineBox::GetCtorCount() { return ctorCount; }
 #endif
 
+#ifndef _MSC_VER
+// static nsLineBox constant; initialized in the header file.
+const PRUint32 nsLineBox::kMinChildCountForHashtable;
+#endif
+
 nsLineBox::nsLineBox(nsIFrame* aFrame, PRInt32 aCount, bool aIsBlock)
   : mFirstChild(aFrame),
     mBounds(0, 0, 0, 0),
     mAscent(0),
     mData(nsnull)
 {
   MOZ_COUNT_CTOR(nsLineBox);
 #ifdef DEBUG
@@ -71,57 +76,121 @@ nsLineBox::nsLineBox(nsIFrame* aFrame, P
                  "wrong kind of child frame");
   }
 #endif
 
   mAllFlags = 0;
 #if NS_STYLE_CLEAR_NONE > 0
   mFlags.mBreakType = NS_STYLE_CLEAR_NONE;
 #endif
-  SetChildCount(aCount);
+  mChildCount = aCount;
   MarkDirty();
   mFlags.mBlock = aIsBlock;
 }
 
 nsLineBox::~nsLineBox()
 {
   MOZ_COUNT_DTOR(nsLineBox);
+  if (NS_UNLIKELY(mFlags.mHasHashedFrames)) {
+    delete mFrames;
+  }  
   Cleanup();
 }
 
 nsLineBox*
-NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame,
-              PRInt32 aCount, bool aIsBlock)
+NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame, bool aIsBlock)
+{
+  return new (aPresShell) nsLineBox(aFrame, 1, aIsBlock);
+}
+
+nsLineBox*
+NS_NewLineBox(nsIPresShell* aPresShell, nsLineBox* aFromLine,
+              nsIFrame* aFrame, PRInt32 aCount)
+{
+  nsLineBox* newLine = new (aPresShell) nsLineBox(aFrame, aCount, false);
+  if (newLine) {
+    newLine->NoteFramesMovedFrom(aFromLine);
+  }
+  return newLine;
+}
+
+void
+nsLineBox::StealHashTableFrom(nsLineBox* aFromLine, PRUint32 aFromLineNewCount)
+{
+  MOZ_ASSERT(!mFlags.mHasHashedFrames);
+  MOZ_ASSERT(GetChildCount() >= PRInt32(aFromLineNewCount));
+  mFrames = aFromLine->mFrames;
+  mFlags.mHasHashedFrames = 1;
+  aFromLine->mFlags.mHasHashedFrames = 0;
+  aFromLine->mChildCount = aFromLineNewCount;
+  // remove aFromLine's frames that aren't on this line
+  nsIFrame* f = aFromLine->mFirstChild;
+  for (PRUint32 i = 0; i < aFromLineNewCount; f = f->GetNextSibling(), ++i) {
+    mFrames->RemoveEntry(f);
+  }
+}
+
+void
+nsLineBox::NoteFramesMovedFrom(nsLineBox* aFromLine)
 {
-  return new (aPresShell)nsLineBox(aFrame, aCount, aIsBlock);
+  PRUint32 fromCount = aFromLine->GetChildCount();
+  PRUint32 toCount = GetChildCount();
+  MOZ_ASSERT(toCount <= fromCount, "moved more frames than aFromLine has");
+  PRUint32 fromNewCount = fromCount - toCount;
+  if (NS_LIKELY(!aFromLine->mFlags.mHasHashedFrames)) {
+    aFromLine->mChildCount = fromNewCount;
+    MOZ_ASSERT(toCount < kMinChildCountForHashtable);
+  } else if (fromNewCount < kMinChildCountForHashtable) {
+    // aFromLine has a hash table but will not have it after moving the frames
+    // so this line can steal the hash table if it needs it.
+    if (toCount >= kMinChildCountForHashtable) {
+      StealHashTableFrom(aFromLine, fromNewCount);
+    } else {
+      delete aFromLine->mFrames;
+      aFromLine->mFlags.mHasHashedFrames = 0;
+      aFromLine->mChildCount = fromNewCount;
+    }
+  } else {
+    // aFromLine still needs a hash table.
+    if (toCount < kMinChildCountForHashtable) {
+      // remove the moved frames from it
+      nsIFrame* f = mFirstChild;
+      for (PRUint32 i = 0; i < toCount; f = f->GetNextSibling(), ++i) {
+        aFromLine->mFrames->RemoveEntry(f);
+      }
+    } else if (toCount <= fromNewCount) {
+      // This line needs a hash table, allocate a hash table for it since that
+      // means fewer hash ops.
+      nsIFrame* f = mFirstChild;
+      for (PRUint32 i = 0; i < toCount; f = f->GetNextSibling(), ++i) {
+        aFromLine->mFrames->RemoveEntry(f); // toCount RemoveEntry
+      }
+      SwitchToHashtable(); // toCount PutEntry
+    } else {
+      // This line needs a hash table, but it's fewer hash ops to steal
+      // aFromLine's hash table and allocate a new hash table for that line.
+      StealHashTableFrom(aFromLine, fromNewCount); // fromNewCount RemoveEntry
+      aFromLine->SwitchToHashtable(); // fromNewCount PutEntry
+    }
+  }
 }
 
 // Overloaded new operator. Uses an arena (which comes from the presShell)
 // to perform the allocation.
 void*
 nsLineBox::operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW
 {
   return aPresShell->AllocateMisc(sz);
 }
 
-// Overloaded delete operator. Doesn't actually free the memory, because we
-// use an arena
-void
-nsLineBox::operator delete(void* aPtr, size_t sz)
-{
-}
-
 void
 nsLineBox::Destroy(nsIPresShell* aPresShell)
 {
-  // Destroy the object. This won't actually free the memory, though
-  delete this;
-
-  // Have the pres shell recycle the memory
-  aPresShell->FreeMisc(sizeof(*this), (void*)this);
+  this->nsLineBox::~nsLineBox();
+  aPresShell->FreeMisc(sizeof(*this), this);
 }
 
 void
 nsLineBox::Cleanup()
 {
   if (mData) {
     if (IsBlock()) {
       delete mBlockData;
@@ -360,30 +429,39 @@ nsLineBox::DeleteLineList(nsPresContext*
 bool
 nsLineBox::RFindLineContaining(nsIFrame* aFrame,
                                const nsLineList::iterator& aBegin,
                                nsLineList::iterator& aEnd,
                                nsIFrame* aLastFrameBeforeEnd,
                                PRInt32* aFrameIndexInLine)
 {
   NS_PRECONDITION(aFrame, "null ptr");
+
   nsIFrame* curFrame = aLastFrameBeforeEnd;
   while (aBegin != aEnd) {
     --aEnd;
     NS_ASSERTION(aEnd->LastChild() == curFrame, "Unexpected curFrame");
+    if (NS_UNLIKELY(aEnd->mFlags.mHasHashedFrames) &&
+        !aEnd->Contains(aFrame)) {
+      if (aEnd->mFirstChild) {
+        curFrame = aEnd->mFirstChild->GetPrevSibling();
+      }
+      continue;
+    }
     // i is the index of curFrame in aEnd
     PRInt32 i = aEnd->GetChildCount() - 1;
     while (i >= 0) {
       if (curFrame == aFrame) {
         *aFrameIndexInLine = i;
         return true;
       }
       --i;
       curFrame = curFrame->GetPrevSibling();
     }
+    MOZ_ASSERT(!aEnd->mFlags.mHasHashedFrames, "Contains lied to us!");
   }
   *aFrameIndexInLine = -1;
   return false;
 }
 
 nsCollapsingMargin
 nsLineBox::GetCarriedOutBottomMargin() const
 {
--- a/layout/generic/nsLineBox.h
+++ b/layout/generic/nsLineBox.h
@@ -177,19 +177,31 @@ protected:
 
 #define LINE_MAX_BREAK_TYPE  ((1 << 4) - 1)
 #define LINE_MAX_CHILD_COUNT PR_INT32_MAX
 
 #if NS_STYLE_CLEAR_LAST_VALUE > 15
 need to rearrange the mBits bitfield;
 #endif
 
-// Funtion to create a line box
+/**
+ * Function to create a line box and initialize it with a single frame.
+ * If the frame was moved from another line then you're responsible
+ * for notifying that line using NoteFrameRemoved().  Alternatively,
+ * it's better to use the next function that does that for you in an
+ * optimal way.
+ */
 nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame,
-                         PRInt32 aCount, bool aIsBlock);
+                         bool aIsBlock);
+/**
+ * Function to create a line box and initialize it with aCount frames
+ * that are currently on aFromLine.
+ */
+nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsLineBox* aFromLine,
+                         nsIFrame* aFrame, PRInt32 aCount);
 
 class nsLineList;
 
 // don't use the following names outside of this file.  Instead, use
 // nsLineList::iterator, etc.  These are just here to allow them to
 // be specified as parameters to methods of nsLineBox.
 class nsLineList_iterator;
 class nsLineList_const_iterator;
@@ -227,23 +239,24 @@ class nsLineLink {
 class nsLineBox : public nsLineLink {
 private:
   nsLineBox(nsIFrame* aFrame, PRInt32 aCount, bool aIsBlock);
   ~nsLineBox();
   
   // Overloaded new operator. Uses an arena (which comes from the presShell)
   // to perform the allocation.
   void* operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW;
-  void operator delete(void* aPtr, size_t sz);
+  void operator delete(void* aPtr, size_t sz) MOZ_DELETE;
 
 public:
-  // Use these two functions to allocate and destroy line boxes
+  // Use these functions to allocate and destroy line boxes
   friend nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame,
-                                  PRInt32 aCount, bool aIsBlock);
-
+                                  bool aIsBlock);
+  friend nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsLineBox* aFromLine,
+                                  nsIFrame* aFrame, PRInt32 aCount);
   void Destroy(nsIPresShell* aPresShell);
 
   // mBlock bit
   bool IsBlock() const {
     return mFlags.mBlock;
   }
   bool IsInline() const {
     return 0 == mFlags.mBlock;
@@ -279,35 +292,32 @@ public:
     mFlags.mHasClearance = 0;
   }
   bool HasClearance() const {
     return mFlags.mHasClearance;
   }
 
   // mImpactedByFloat bit
   void SetLineIsImpactedByFloat(bool aValue) {
-    NS_ASSERTION((false==aValue || true==aValue), "somebody is playing fast and loose with bools and bits!");
     mFlags.mImpactedByFloat = aValue;
   }
   bool IsImpactedByFloat() const {
     return mFlags.mImpactedByFloat;
   }
 
   // mLineWrapped bit
   void SetLineWrapped(bool aOn) {
-    NS_ASSERTION((false==aOn || true==aOn), "somebody is playing fast and loose with bools and bits!");
     mFlags.mLineWrapped = aOn;
   }
   bool IsLineWrapped() const {
     return mFlags.mLineWrapped;
   }
 
   // mInvalidateTextRuns bit
   void SetInvalidateTextRuns(bool aOn) {
-    NS_ASSERTION((false==aOn || true==aOn), "somebody is playing fast and loose with bools and bits!");
     mFlags.mInvalidateTextRuns = aOn;
   }
   bool GetInvalidateTextRuns() const {
     return mFlags.mInvalidateTextRuns;
   }
 
   // mResizeReflowOptimizationDisabled bit
   void DisableResizeReflowOptimization() {
@@ -339,30 +349,86 @@ public:
   }
   void ClearHadFloatPushed() {
     mFlags.mHadFloatPushed = false;
   }
   bool HadFloatPushed() const {
     return mFlags.mHadFloatPushed;
   }
 
+private:
+  // Add a hash table for fast lookup when the line has more frames than this.
+  static const PRUint32 kMinChildCountForHashtable = 200;
 
-  // mChildCount value
-  PRInt32 GetChildCount() const {
-    return (PRInt32) mFlags.mChildCount;
+  /**
+   * Take ownership of aFromLine's hash table and remove the frames that
+   * stay on aFromLine from it, i.e. aFromLineNewCount frames starting with
+   * mFirstChild.  This method is used to optimize moving a large number
+   * of frames from one line to the next.
+   */
+  void StealHashTableFrom(nsLineBox* aFromLine, PRUint32 aFromLineNewCount);
+
+  /**
+   * Does the equivalent of this->NoteFrameAdded and aFromLine->NoteFrameRemoved
+   * for each frame on this line, but in a optimized way.
+   */
+  void NoteFramesMovedFrom(nsLineBox* aFromLine);
+
+  void SwitchToHashtable()
+  {
+    MOZ_ASSERT(!mFlags.mHasHashedFrames);
+    PRUint32 count = GetChildCount();
+    mFrames = new nsTHashtable< nsPtrHashKey<nsIFrame> >();
+    mFlags.mHasHashedFrames = 1;
+    PRUint32 minSize =
+      NS_MAX(kMinChildCountForHashtable, PRUint32(PL_DHASH_MIN_SIZE));
+    mFrames->Init(NS_MAX(count, minSize));
+    for (nsIFrame* f = mFirstChild; count-- > 0; f = f->GetNextSibling()) {
+      mFrames->PutEntry(f);
+    }
   }
-  void SetChildCount(PRInt32 aNewCount) {
-    if (aNewCount < 0) {
-      NS_WARNING("negative child count");
-      aNewCount = 0;
+  void SwitchToCounter() {
+    MOZ_ASSERT(mFlags.mHasHashedFrames);
+    PRUint32 count = GetChildCount();
+    delete mFrames;
+    mFlags.mHasHashedFrames = 0;
+    mChildCount = count;
+  }
+
+public:
+  PRInt32 GetChildCount() const {
+    return NS_UNLIKELY(mFlags.mHasHashedFrames) ? mFrames->Count() : mChildCount;
+  }
+
+  /**
+   * Register that aFrame is now on this line.
+   */
+  void NoteFrameAdded(nsIFrame* aFrame) {
+    if (NS_UNLIKELY(mFlags.mHasHashedFrames)) {
+      mFrames->PutEntry(aFrame);
+    } else {
+      if (++mChildCount >= kMinChildCountForHashtable) {
+        SwitchToHashtable();
+      }
     }
-    if (aNewCount > LINE_MAX_CHILD_COUNT) {
-      aNewCount = LINE_MAX_CHILD_COUNT;
+  }
+
+  /**
+   * Register that aFrame is not on this line anymore.
+   */
+  void NoteFrameRemoved(nsIFrame* aFrame) {
+    MOZ_ASSERT(GetChildCount() > 0);
+    if (NS_UNLIKELY(mFlags.mHasHashedFrames)) {
+      mFrames->RemoveEntry(aFrame);
+      if (mFrames->Count() < kMinChildCountForHashtable) {
+        SwitchToCounter();
+      }
+    } else {
+      --mChildCount;
     }
-    mFlags.mChildCount = aNewCount;
   }
 
   // mBreakType value
   // Break information is applied *before* the line if the line is a block,
   // or *after* the line if the line is an inline. Confusing, I know, but
   // using different names should help.
   bool HasBreakBefore() const {
     return IsBlock() && NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
@@ -468,20 +534,23 @@ public:
 
 #ifdef DEBUG
   char* StateToString(char* aBuf, PRInt32 aBufSize) const;
 
   void List(FILE* out, PRInt32 aIndent) const;
   nsIFrame* LastChild() const;
 #endif
 
+private:
   PRInt32 IndexOf(nsIFrame* aFrame) const;
+public:
 
   bool Contains(nsIFrame* aFrame) const {
-    return IndexOf(aFrame) >= 0;
+    return NS_UNLIKELY(mFlags.mHasHashedFrames) ? mFrames->Contains(aFrame)
+                                                : IndexOf(aFrame) >= 0;
   }
 
   // whether the line box is "logically" empty (just like nsIFrame::IsEmpty)
   bool IsEmpty() const;
 
   // Call this only while in Reflow() for the block the line belongs
   // to, only between reflowing the line (or sliding it, if we skip
   // reflowing it) and the end of reflowing the block.
@@ -499,16 +568,22 @@ public:
 #ifdef DEBUG
   static PRInt32 GetCtorCount();
 #endif
 
   nsIFrame* mFirstChild;
 
   nsRect mBounds;
 
+  // mFlags.mHasHashedFrames says which one to use
+  union {
+    nsTHashtable< nsPtrHashKey<nsIFrame> >* mFrames;
+    PRUint32 mChildCount;
+  };
+
   struct FlagBits {
     PRUint32 mDirty : 1;
     PRUint32 mPreviousMarginDirty : 1;
     PRUint32 mHasClearance : 1;
     PRUint32 mBlock : 1;
     PRUint32 mImpactedByFloat : 1;
     PRUint32 mLineWrapped: 1;
     PRUint32 mInvalidateTextRuns : 1;
@@ -516,20 +591,18 @@ public:
     PRUint32 mEmptyCacheValid: 1;
     PRUint32 mEmptyCacheState: 1;
     // mHasBullet indicates that this is an inline line whose block's
     // bullet is adjacent to this line and non-empty.
     PRUint32 mHasBullet : 1;
     // Indicates that this line *may* have a placeholder for a float
     // that was pushed to a later column or page.
     PRUint32 mHadFloatPushed : 1;
+    PRUint32 mHasHashedFrames: 1;
     PRUint32 mBreakType : 4;
-
-    // FIXME: Move this out of FlagBits
-    PRUint32 mChildCount;
   };
 
   struct ExtraData {
     ExtraData(const nsRect& aBounds) : mOverflowAreas(aBounds, aBounds) {
     }
     nsOverflowAreas mOverflowAreas;
   };
 
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -5687,34 +5687,33 @@ nsTypedSelection::RemoveSelectionListene
 
 
 nsresult
 nsTypedSelection::NotifySelectionListeners()
 {
   if (!mFrameSelection)
     return NS_OK;//nothing to do
  
-  if (mFrameSelection->GetBatching()){
+  if (mFrameSelection->GetBatching()) {
     mFrameSelection->SetDirty();
     return NS_OK;
   }
-  PRInt32 cnt = mSelectionListeners.Count();
   nsCOMArray<nsISelectionListener> selectionListeners(mSelectionListeners);
-  
+  PRInt32 cnt = selectionListeners.Count();
+  if (cnt != mSelectionListeners.Count()) {
+    return NS_ERROR_OUT_OF_MEMORY;  // nsCOMArray is fallible
+  }
   nsCOMPtr<nsIDOMDocument> domdoc;
   nsCOMPtr<nsIPresShell> shell;
   nsresult rv = GetPresShell(getter_AddRefs(shell));
   if (NS_SUCCEEDED(rv) && shell)
     domdoc = do_QueryInterface(shell->GetDocument());
   short reason = mFrameSelection->PopReason();
-  for (PRInt32 i = 0; i < cnt; i++)
-  {
-    nsISelectionListener* thisListener = selectionListeners[i];
-    if (thisListener)
-      thisListener->NotifySelectionChanged(domdoc, this, reason);
+  for (PRInt32 i = 0; i < cnt; i++) {
+    selectionListeners[i]->NotifySelectionChanged(domdoc, this, reason);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTypedSelection::StartBatchChanges()
 {
   if (mFrameSelection)
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box/flexbox-abspos-container-1-ref.html
@@ -0,0 +1,27 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+  <head>
+    <style>
+      .relpos_parent {
+        position: relative;
+        width: 100px;
+        height: 100px;
+        background: lightblue;
+      }
+      .abspos_child {
+        position: absolute;
+        left: 30px;
+        bottom: 10px;
+        width: 20px;
+        height: 20px;
+        background: purple;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="relpos_parent">
+      <div class="abspos_child"></div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box/flexbox-abspos-container-1a.html
@@ -0,0 +1,30 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!-- This testcase has a relatively-positioned -moz-box element, which should
+     form a containing block for its absolutely positioned child. -->
+<html>
+  <head>
+    <style>
+      .box { display: -moz-box }
+      .relpos_parent {
+        position: relative;
+        width: 100px;
+        height: 100px;
+        background: lightblue;
+      }
+      .abspos_child {
+        position: absolute;
+        left: 30px;
+        bottom: 10px;
+        width: 20px;
+        height: 20px;
+        background: purple;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="box relpos_parent">
+      <div class="abspos_child"></div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box/flexbox-abspos-container-1b.html
@@ -0,0 +1,29 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!-- This testcase is the same as the -1a version, but with -moz-inline-box. -->
+<html>
+  <head>
+    <style>
+      .box { display: -moz-inline-box }
+      .relpos_parent {
+        position: relative;
+        width: 100px;
+        height: 100px;
+        background: lightblue;
+      }
+      .abspos_child {
+        position: absolute;
+        left: 30px;
+        bottom: 10px;
+        width: 20px;
+        height: 20px;
+        background: purple;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="box relpos_parent">
+      <div class="abspos_child"></div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box/flexbox-abspos-container-1c.html
@@ -0,0 +1,33 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!-- This testcase is the same as the -1a version, but with an additional
+     -moz-box wrapper, so that our relatively positioned box will never get a
+     call to Reflow. -->
+<html>
+  <head>
+    <style>
+      .box { display: -moz-box }
+      .relpos_parent {
+        position: relative;
+        width: 100px;
+        height: 100px;
+        background: lightblue;
+      }
+      .abspos_child {
+        position: absolute;
+        left: 30px;
+        bottom: 10px;
+        width: 20px;
+        height: 20px;
+        background: purple;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="box">
+      <div class="box relpos_parent">
+        <div class="abspos_child"></div>
+      </div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box/flexbox-abspos-container-1d.html
@@ -0,0 +1,31 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!-- This testcase is the same as the -1c version, but with -moz-inline-box. -->
+<html>
+  <head>
+    <style>
+      .box { display: -moz-inline-box }
+      .relpos_parent {
+        position: relative;
+        width: 100px;
+        height: 100px;
+        background: lightblue;
+      }
+      .abspos_child {
+        position: absolute;
+        left: 30px;
+        bottom: 10px;
+        width: 20px;
+        height: 20px;
+        background: purple;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="box">
+      <div class="box relpos_parent">
+        <div class="abspos_child"></div>
+      </div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box/flexbox-abspos-container-2-ref.html
@@ -0,0 +1,27 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+  <head>
+    <style>
+      .relpos_parent {
+        position: relative;
+        width: 100px;
+        height: 100px;
+        background: lightblue;
+      }
+      .abspos_child {
+        position: absolute;
+        left: 30px;
+        top: 10px;
+        width: 20px;
+        height: 150px;
+        background: purple;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="relpos_parent">
+      <div class="abspos_child"></div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box/flexbox-abspos-container-2.html
@@ -0,0 +1,31 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!-- This testcase has a relatively-positioned -moz-box element, which should
+     form a containing block for its absolutely positioned child. Also: in
+     this case, the child is taller than its container. -->
+<html>
+  <head>
+    <style>
+      .box { display: -moz-box }
+      .relpos_parent {
+        position: relative;
+        width: 100px;
+        height: 100px;
+        background: lightblue;
+      }
+      .abspos_child {
+        position: absolute;
+        left: 30px;
+        top: 10px;
+        width: 20px;
+        height: 150px;
+        background: purple;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="box relpos_parent">
+      <div class="abspos_child"></div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box/flexbox-child-is-abspos-container-1-ref.html
@@ -0,0 +1,29 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+  <head>
+    <style>
+      .relpos_parent {
+        position: relative;
+        width: 100px;
+        height: 100px;
+        background: lightblue;
+      }
+      .abspos_child {
+        position: absolute;
+        left: 30px;
+        bottom: 10px;
+        width: 20px;
+        height: 20px;
+        background: purple;
+      }
+    </style>
+  </head>
+  <body>
+    <div>
+      <div class="relpos_parent">
+        <div class="abspos_child"></div>
+      </div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box/flexbox-child-is-abspos-container-1.html
@@ -0,0 +1,32 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!-- This testcase has a -moz-box element with a block as its only child, which
+     forms a containing block for an absolutely positioned grandchild. -->
+<html>
+  <head>
+    <style>
+      .box { display: -moz-box }
+      .relpos_parent {
+        position: relative;
+        width: 100px;
+        height: 100px;
+        background: lightblue;
+      }
+      .abspos_child {
+        position: absolute;
+        left: 30px;
+        bottom: 10px;
+        width: 20px;
+        height: 20px;
+        background: purple;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="box">
+      <div class="relpos_parent">
+        <div class="abspos_child"></div>
+      </div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box/flexbox-child-is-abspos-container-2-ref.html
@@ -0,0 +1,30 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+  <head>
+    <style>
+      body { margin-top: 50px }
+      .relpos_parent {
+        position: relative;
+        width: 100px;
+        height: 100px;
+        background: lightblue;
+      }
+      .abspos_child {
+        position: absolute;
+        left: 30px;
+        bottom: 10px;
+        width: 20px;
+        height: 130px;
+        background: purple;
+      }
+    </style>
+  </head>
+  <body>
+    <div>
+      <div class="relpos_parent">
+        <div class="abspos_child"></div>
+      </div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box/flexbox-child-is-abspos-container-2.html
@@ -0,0 +1,34 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!-- This testcase has a -moz-box element with a block as its only child, which
+     forms a containing block for an absolutely positioned grandchild. Also, in
+     this case, the grandchild is taller than its parent and grandparent. -->
+<html>
+  <head>
+    <style>
+      body { margin-top: 50px }
+      .box { display: -moz-box }
+      .relpos_parent {
+        position: relative;
+        width: 100px;
+        height: 100px;
+        background: lightblue;
+      }
+      .abspos_child {
+        position: absolute;
+        left: 30px;
+        bottom: 10px;
+        width: 20px;
+        height: 130px;
+        background: purple;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="box">
+      <div class="relpos_parent">
+        <div class="abspos_child"></div>
+      </div>
+    </div>
+  </body>
+</html>
--- a/layout/reftests/box/reftest.list
+++ b/layout/reftests/box/reftest.list
@@ -1,4 +1,11 @@
+== flexbox-abspos-container-1a.html flexbox-abspos-container-1-ref.html
+== flexbox-abspos-container-1b.html flexbox-abspos-container-1-ref.html
+== flexbox-abspos-container-1c.html flexbox-abspos-container-1-ref.html
+== flexbox-abspos-container-1d.html flexbox-abspos-container-1-ref.html
+== flexbox-abspos-container-2.html  flexbox-abspos-container-2-ref.html
 == flexbox-attributes-no-box-horizontal.xhtml flexbox-attributes-no-box-horizontal-ref.xhtml
 == flexbox-attributes-no-box-vertical.xhtml flexbox-attributes-no-box-vertical-ref.xhtml
 == flexbox-attributes-no-input-horizontal.xhtml flexbox-attributes-no-input-horizontal-ref.xhtml
 == flexbox-attributes-no-input-vertical.xhtml flexbox-attributes-no-input-vertical-ref.xhtml
+== flexbox-child-is-abspos-container-1.html flexbox-child-is-abspos-container-1-ref.html
+== flexbox-child-is-abspos-container-2.html flexbox-child-is-abspos-container-2-ref.html
--- a/layout/svg/base/src/nsISVGChildFrame.h
+++ b/layout/svg/base/src/nsISVGChildFrame.h
@@ -52,16 +52,23 @@ class nsRenderingContext;
 namespace mozilla {
 class SVGAnimatedNumberList;
 class SVGNumberList;
 class SVGAnimatedLengthList;
 class SVGLengthList;
 class SVGUserUnitList;
 }
 
+/**
+ * This class is not particularly well named. It is inherited by some, but
+ * not all SVG frame classes that can be descendants of an
+ * nsSVGOuterSVGFrame in the frame tree. Note specifically that SVG container
+ * frames that do not inherit nsSVGDisplayContainerFrame do not inherit this
+ * class (so that's classes that only inherit nsSVGContainerFrame).
+ */
 class nsISVGChildFrame : public nsQueryFrame
 {
 public:
   typedef mozilla::SVGAnimatedNumberList SVGAnimatedNumberList;
   typedef mozilla::SVGNumberList SVGNumberList;
   typedef mozilla::SVGAnimatedLengthList SVGAnimatedLengthList;
   typedef mozilla::SVGLengthList SVGLengthList;
   typedef mozilla::SVGUserUnitList SVGUserUnitList;
@@ -86,23 +93,26 @@ public:
   // Called once on SVG child frames except descendants of <defs>, either
   // when their nsSVGOuterSVGFrame receives its initial reflow (i.e. once
   // the SVG viewport dimensions are known), or else when they're inserted
   // into the frame tree (if they're inserted after the initial reflow).
   NS_IMETHOD InitialUpdate()=0;
 
   // Flags to pass to NotifySVGChange:
   //
-  // SUPPRESS_INVALIDATION - do not invalidate rendered areas (only to be
-  //                           used in conjunction with TRANSFORM_CHANGED)
+  // DO_NOT_NOTIFY_RENDERING_OBSERVERS - this should only be used when
+  //                           updating the descendant frames of a clipPath,
+  //                           mask, pattern or marker frame (or other similar
+  //                           NS_STATE_SVG_NONDISPLAY_CHILD frame) immediately
+  //                           prior to painting that frame's descendants.
   // TRANSFORM_CHANGED     - the current transform matrix for this frame has changed
   // COORD_CONTEXT_CHANGED - the dimensions of this frame's coordinate context has
   //                           changed (percentage lengths must be reevaluated)
   enum SVGChangedFlags {
-    SUPPRESS_INVALIDATION = 0x01,
+    DO_NOT_NOTIFY_RENDERING_OBSERVERS = 0x01,
     TRANSFORM_CHANGED     = 0x02,
     COORD_CONTEXT_CHANGED = 0x04
   };
   virtual void NotifySVGChanged(PRUint32 aFlags)=0;
   virtual void NotifyRedrawSuspended()=0;
   virtual void NotifyRedrawUnsuspended()=0;
 
   /**
--- a/layout/svg/base/src/nsSVGAFrame.cpp
+++ b/layout/svg/base/src/nsSVGAFrame.cpp
@@ -154,16 +154,23 @@ nsSVGAFrame::GetType() const
 }
 
 //----------------------------------------------------------------------
 // nsISVGChildFrame methods
 
 void
 nsSVGAFrame::NotifySVGChanged(PRUint32 aFlags)
 {
+  NS_ABORT_IF_FALSE(!(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS) ||
+                    (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD),
+                    "Must be NS_STATE_SVG_NONDISPLAY_CHILD!");
+
+  NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
+                    "Invalidation logic may need adjusting");
+
   if (aFlags & TRANSFORM_CHANGED) {
     // make sure our cached transform matrix gets (lazily) updated
     mCanvasTM = nsnull;
   }
 
   nsSVGAFrameBase::NotifySVGChanged(aFlags);
 }
 
--- a/layout/svg/base/src/nsSVGClipPathFrame.cpp
+++ b/layout/svg/base/src/nsSVGClipPathFrame.cpp
@@ -97,18 +97,19 @@ nsSVGClipPathFrame::ClipPaint(nsRenderin
     }
   }
 
   for (nsIFrame* kid = mFrames.FirstChild(); kid;
        kid = kid->GetNextSibling()) {
     nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
     if (SVGFrame) {
       // The CTM of each frame referencing us can be different.
-      SVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION | 
-                                 nsISVGChildFrame::TRANSFORM_CHANGED);
+      SVGFrame->NotifySVGChanged(
+                          nsISVGChildFrame::DO_NOT_NOTIFY_RENDERING_OBSERVERS | 
+                          nsISVGChildFrame::TRANSFORM_CHANGED);
 
       bool isOK = true;
       nsSVGClipPathFrame *clipPathFrame =
         nsSVGEffects::GetEffectProperties(kid).GetClipPathFrame(&isOK);
       if (!isOK) {
         continue;
       }
 
--- a/layout/svg/base/src/nsSVGClipPathFrame.h
+++ b/layout/svg/base/src/nsSVGClipPathFrame.h
@@ -44,19 +44,22 @@ class nsRenderingContext;
 
 typedef nsSVGContainerFrame nsSVGClipPathFrameBase;
 
 class nsSVGClipPathFrame : public nsSVGClipPathFrameBase
 {
   friend nsIFrame*
   NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
-  nsSVGClipPathFrame(nsStyleContext* aContext) :
-    nsSVGClipPathFrameBase(aContext),
-    mInUse(false) {}
+  nsSVGClipPathFrame(nsStyleContext* aContext)
+    : nsSVGClipPathFrameBase(aContext)
+    , mInUse(false)
+  {
+    AddStateBits(NS_STATE_SVG_NONDISPLAY_CHILD);
+  }
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   // nsSVGClipPathFrame methods:
   nsresult ClipPaint(nsRenderingContext* aContext,
                      nsIFrame* aParent,
                      const gfxMatrix &aMatrix);
--- a/layout/svg/base/src/nsSVGContainerFrame.cpp
+++ b/layout/svg/base/src/nsSVGContainerFrame.cpp
@@ -46,17 +46,22 @@ NS_QUERYFRAME_HEAD(nsSVGDisplayContainer
   NS_QUERYFRAME_ENTRY(nsSVGDisplayContainerFrame)
   NS_QUERYFRAME_ENTRY(nsISVGChildFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsSVGContainerFrame)
 
 nsIFrame*
 NS_NewSVGContainerFrame(nsIPresShell* aPresShell,
                         nsStyleContext* aContext)
 {
-  return new (aPresShell) nsSVGContainerFrame(aContext);
+  nsIFrame *frame = new (aPresShell) nsSVGContainerFrame(aContext);
+  // If we were called directly, then the frame is for a <defs> or
+  // an unknown element type. In both cases we prevent the content
+  // from displaying directly.
+  frame->AddStateBits(NS_STATE_SVG_NONDISPLAY_CHILD);
+  return frame;
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsSVGContainerFrame)
 NS_IMPL_FRAMEARENA_HELPERS(nsSVGDisplayContainerFrame)
 
 NS_IMETHODIMP
 nsSVGContainerFrame::AppendFrames(ChildListID  aListID,
                                   nsFrameList& aFrameList)
@@ -84,36 +89,26 @@ nsSVGContainerFrame::RemoveFrame(ChildLi
 {
   NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
 
   mFrames.DestroyFrame(aOldFrame);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSVGContainerFrame::Init(nsIContent* aContent,
-                          nsIFrame* aParent,
-                          nsIFrame* aPrevInFlow)
-{
-  AddStateBits(NS_STATE_SVG_NONDISPLAY_CHILD);
-  nsresult rv = nsSVGContainerFrameBase::Init(aContent, aParent, aPrevInFlow);
-  return rv;
-}
-
-NS_IMETHODIMP
 nsSVGDisplayContainerFrame::Init(nsIContent* aContent,
                                  nsIFrame* aParent,
                                  nsIFrame* aPrevInFlow)
 {
   if (!(GetStateBits() & NS_STATE_IS_OUTER_SVG)) {
     AddStateBits(aParent->GetStateBits() &
       (NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD |
        NS_STATE_SVG_REDRAW_SUSPENDED));
   }
-  nsresult rv = nsSVGContainerFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsresult rv = nsSVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
   return rv;
 }
 
 NS_IMETHODIMP
 nsSVGDisplayContainerFrame::InsertFrames(ChildListID aListID,
                                          nsIFrame* aPrevFrame,
                                          nsFrameList& aFrameList)
 {
@@ -227,18 +222,22 @@ nsSVGDisplayContainerFrame::InitialUpdat
               NS_FRAME_HAS_DIRTY_CHILDREN);
   
   return NS_OK;
 }  
 
 void
 nsSVGDisplayContainerFrame::NotifySVGChanged(PRUint32 aFlags)
 {
-  NS_ASSERTION(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
-               "Invalidation logic may need adjusting");
+  NS_ABORT_IF_FALSE(!(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS) ||
+                    (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD),
+                    "Must be NS_STATE_SVG_NONDISPLAY_CHILD!");
+
+  NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
+                    "Invalidation logic may need adjusting");
 
   nsSVGUtils::NotifyChildrenOfSVGChange(this, aFlags);
 }
 
 void
 nsSVGDisplayContainerFrame::NotifyRedrawSuspended()
 {
   nsSVGUtils::NotifyRedrawSuspended(this);
--- a/layout/svg/base/src/nsSVGContainerFrame.h
+++ b/layout/svg/base/src/nsSVGContainerFrame.h
@@ -42,16 +42,23 @@
 #include "nsSVGSVGElement.h"
 #include "gfxRect.h"
 #include "gfxMatrix.h"
 
 class nsRenderingContext;
 
 typedef nsContainerFrame nsSVGContainerFrameBase;
 
+/**
+ * Base class for SVG container frames. Frame sub-classes that do not
+ * display their contents directly (such as the frames for <marker> or
+ * <pattern>) just inherit this class. Frame sub-classes that do or can
+ * display their contents directly (such as the frames for inner-<svg> or
+ * <g>) inherit our nsDisplayContainerFrame sub-class.
+ */
 class nsSVGContainerFrame : public nsSVGContainerFrameBase
 {
   friend nsIFrame* NS_NewSVGContainerFrame(nsIPresShell* aPresShell,
                                            nsStyleContext* aContext);
 protected:
   nsSVGContainerFrame(nsStyleContext* aContext) :
     nsSVGContainerFrameBase(aContext) {}
 
@@ -66,27 +73,28 @@ public:
   // nsIFrame:
   NS_IMETHOD AppendFrames(ChildListID     aListID,
                           nsFrameList&    aFrameList);
   NS_IMETHOD InsertFrames(ChildListID     aListID,
                           nsIFrame*       aPrevFrame,
                           nsFrameList&    aFrameList);
   NS_IMETHOD RemoveFrame(ChildListID     aListID,
                          nsIFrame*       aOldFrame);
-  NS_IMETHOD Init(nsIContent*      aContent,
-                  nsIFrame*        aParent,
-                  nsIFrame*        aPrevInFlow);
 
   virtual bool IsFrameOfType(PRUint32 aFlags) const
   {
     return nsSVGContainerFrameBase::IsFrameOfType(
             aFlags & ~(nsIFrame::eSVG | nsIFrame::eSVGContainer));
   }
 };
 
+/**
+ * Frame class or base-class for SVG containers that can or do display their
+ * contents directly.
+ */
 class nsSVGDisplayContainerFrame : public nsSVGContainerFrame,
                                    public nsISVGChildFrame
 {
 protected:
   nsSVGDisplayContainerFrame(nsStyleContext* aContext) :
     nsSVGContainerFrame(aContext) {}
 
 public:
--- a/layout/svg/base/src/nsSVGFilterFrame.h
+++ b/layout/svg/base/src/nsSVGFilterFrame.h
@@ -44,17 +44,21 @@ class nsRenderingContext;
 class nsSVGFilterPaintCallback;
 
 typedef nsSVGContainerFrame nsSVGFilterFrameBase;
 class nsSVGFilterFrame : public nsSVGFilterFrameBase
 {
   friend nsIFrame*
   NS_NewSVGFilterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
-  nsSVGFilterFrame(nsStyleContext* aContext) : nsSVGFilterFrameBase(aContext) {}
+  nsSVGFilterFrame(nsStyleContext* aContext)
+    : nsSVGFilterFrameBase(aContext)
+  {
+    AddStateBits(NS_STATE_SVG_NONDISPLAY_CHILD);
+  }
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   NS_IMETHOD AttributeChanged(PRInt32         aNameSpaceID,
                               nsIAtom*        aAttribute,
                               PRInt32         aModType);
 
--- a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp
+++ b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp
@@ -389,28 +389,35 @@ nsSVGForeignObjectFrame::InitialUpdate()
               NS_FRAME_HAS_DIRTY_CHILDREN);
 
   return NS_OK;
 }
 
 void
 nsSVGForeignObjectFrame::Notify