Bug 534136 Part 2: Use 16bit-char buffers inside atoms. r=bz sr=mrbkap
authorJonas Sicking <jonas@sicking.cc>
Mon, 08 Mar 2010 07:45:00 -0800
changeset 39100 cb17f4d9294251cebc73861239603fc87c4c45fd
parent 39099 5b152f233117a9a0dcbb962910fcca3effee5ca6
child 39101 1995edaefd3f79ca174f28635cbdce3d6db0bbe8
push id12012
push usersicking@mozilla.com
push dateMon, 08 Mar 2010 15:47:04 +0000
treeherdermozilla-central@f8dd7b5b02ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, mrbkap
bugs534136
milestone1.9.3a3pre
Bug 534136 Part 2: Use 16bit-char buffers inside atoms. r=bz sr=mrbkap
accessible/src/base/nsAccessible.cpp
accessible/src/base/nsDocAccessible.cpp
accessible/src/msaa/nsAccessNodeWrap.cpp
content/base/public/nsContentUtils.h
content/base/public/nsINodeInfo.h
content/base/src/nsAttrValue.cpp
content/base/src/nsContentSink.cpp
content/base/src/nsContentUtils.cpp
content/base/src/nsDocument.cpp
content/base/src/nsHTMLContentSerializer.cpp
content/base/src/nsNodeInfo.cpp
content/base/src/nsXHTMLContentSerializer.cpp
content/html/document/src/nsHTMLContentSink.cpp
content/smil/nsSMILCompositor.cpp
content/xslt/src/base/txStringUtils.h
content/xslt/src/xpath/txXPCOMExtensionFunction.cpp
content/xul/document/src/nsXULDocument.cpp
content/xul/templates/src/nsXULContentBuilder.cpp
dom/base/nsJSEnvironment.cpp
gfx/thebes/src/gfxWindowsFonts.cpp
gfx/thebes/test/gfxFontSelectionTests.h
gfx/thebes/test/gfxTextRunPerfTest.cpp
gfx/thebes/test/gfxWordCacheTest.cpp
layout/base/nsPresContext.cpp
layout/generic/nsFrame.cpp
layout/generic/nsSelection.cpp
layout/generic/nsTextFrameThebes.cpp
layout/style/nsCSSAnonBoxes.cpp
layout/style/nsCSSRuleProcessor.cpp
layout/style/nsComputedDOMStyle.cpp
parser/html/nsHtml5Atom.cpp
parser/htmlparser/src/nsHTMLTags.cpp
rdf/base/src/nsRDFContentSink.cpp
xpcom/ds/nsAtomService.cpp
xpcom/ds/nsAtomTable.cpp
xpcom/ds/nsAtomTable.h
xpcom/ds/nsCRT.cpp
xpcom/ds/nsCRT.h
xpcom/ds/nsIAtom.idl
xpcom/ds/nsStaticAtom.h
xpcom/tests/TestAtoms.cpp
xpcom/tests/TestPermanentAtoms.cpp
xpcom/tests/TestUTF.cpp
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -1486,29 +1486,28 @@ nsAccessible::GetAttributes(nsIPersisten
     nsAccUtils::SetAccGroupAttrs(attributes, level, setSize, posInSet);
 
   // Expose object attributes from ARIA attributes.
   PRUint32 numAttrs = content->GetAttrCount();
   for (PRUint32 count = 0; count < numAttrs; count ++) {
     const nsAttrName *attr = content->GetAttrNameAt(count);
     if (attr && attr->NamespaceEquals(kNameSpaceID_None)) {
       nsIAtom *attrAtom = attr->Atom();
-      const char *attrStr;
-      attrAtom->GetUTF8String(&attrStr);
-      if (PL_strncmp(attrStr, "aria-", 5)) 
+      nsDependentAtomString attrStr(attrAtom);
+      if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-"))) 
         continue; // Not ARIA
       PRUint8 attrFlags = nsAccUtils::GetAttributeCharacteristics(attrAtom);
       if (attrFlags & ATTR_BYPASSOBJ)
         continue; // No need to handle exposing as obj attribute here
       if ((attrFlags & ATTR_VALTOKEN) &&
           !nsAccUtils::HasDefinedARIAToken(content, attrAtom))
         continue; // only expose token based attributes if they are defined
       nsAutoString value;
       if (content->GetAttr(kNameSpaceID_None, attrAtom, value)) {
-        attributes->SetStringProperty(nsDependentCString(attrStr + 5), value, oldValueUnused);
+        attributes->SetStringProperty(NS_ConvertUTF16toUTF8(Substring(attrStr, 5)), value, oldValueUnused);
       }
     }
   }
 
   // If there is no aria-live attribute then expose default value of 'live'
   // object attribute used for ARIA role of this accessible.
   if (mRoleMapEntry) {
     nsAutoString live;
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -1107,19 +1107,18 @@ nsDocAccessible::AttributeChangedImpl(ns
 
     FireDelayedAccessibleEvent(sensitiveChangeEvent);
     return;
   }
 
   // Check for namespaced ARIA attribute
   if (aNameSpaceID == kNameSpaceID_None) {
     // Check for hyphenated aria-foo property?
-    const char* attributeName;
-    aAttribute->GetUTF8String(&attributeName);
-    if (!PL_strncmp("aria-", attributeName, 5)) {
+    if (StringBeginsWith(nsDependentAtomString(aAttribute),
+                         NS_LITERAL_STRING("aria-"))) {
       ARIAAttributeChanged(aContent, aAttribute);
     }
   }
 
   if (aAttribute == nsAccessibilityAtoms::role ||
       aAttribute == nsAccessibilityAtoms::href ||
       aAttribute == nsAccessibilityAtoms::onclick) {
     // Not worth the expense to ensure which namespace these are in
--- a/accessible/src/msaa/nsAccessNodeWrap.cpp
+++ b/accessible/src/msaa/nsAccessNodeWrap.cpp
@@ -244,22 +244,20 @@ STDMETHODIMP nsAccessNodeWrap::get_attri
 
   if (numAttribs > aMaxAttribs)
     numAttribs = aMaxAttribs;
   *aNumAttribs = static_cast<unsigned short>(numAttribs);
 
   for (PRUint32 index = 0; index < numAttribs; index++) {
     aNameSpaceIDs[index] = 0; aAttribValues[index] = aAttribNames[index] = nsnull;
     nsAutoString attributeValue;
-    const char *pszAttributeName; 
 
     const nsAttrName* name = content->GetAttrNameAt(index);
     aNameSpaceIDs[index] = static_cast<short>(name->NamespaceID());
-    name->LocalName()->GetUTF8String(&pszAttributeName);
-    aAttribNames[index] = ::SysAllocString(NS_ConvertUTF8toUTF16(pszAttributeName).get());
+    aAttribNames[index] = ::SysAllocString(name->LocalName()->GetUTF16String());
     content->GetAttr(name->NamespaceID(), name->LocalName(), attributeValue);
     aAttribValues[index] = ::SysAllocString(attributeValue.get());
   }
 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
 
   return S_OK; 
 }
         
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1451,16 +1451,23 @@ public:
                                       const nsAString &viewportInfo);
 
   static nsIScriptContext* GetContextForEventHandlers(nsINode* aNode,
                                                       nsresult* aRv);
 
   static JSContext *GetCurrentJSContext();
 
   /**
+   * Case insensitive comparison between two strings. However it only ignores
+   * case for ASCII characters a-z.
+   */
+  static PRBool EqualsIgnoreASCIICase(const nsAString& aStr1,
+                                      const nsAString& aStr2);
+
+  /**
    * Convert ASCII A-Z to a-z.
    */
   static void ASCIIToLower(const nsAString& aSource, nsAString& aDest);
 
   /**
    * Convert ASCII a-z to A-Z.
    */
   static void ASCIIToUpper(nsAString& aStr);
--- a/content/base/public/nsINodeInfo.h
+++ b/content/base/public/nsINodeInfo.h
@@ -265,19 +265,17 @@ public:
   virtual PRBool NamespaceEquals(const nsAString& aNamespaceURI) const = 0;
 
   PRBool QualifiedNameEquals(nsIAtom* aNameAtom) const
   {
     NS_PRECONDITION(aNameAtom, "Must have name atom");
     if (!GetPrefixAtom())
       return Equals(aNameAtom);
 
-    const char* utf8;
-    aNameAtom->GetUTF8String(&utf8);
-    return QualifiedNameEqualsInternal(nsDependentCString(utf8));
+    return QualifiedNameEqualsInternal(nsAtomCString(aNameAtom));
   }
 
   PRBool QualifiedNameEquals(const nsACString& aQualifiedName) const
   {
     if (!GetPrefixAtom())
       return mInner.mName->EqualsUTF8(aQualifiedName);
 
     return QualifiedNameEqualsInternal(aQualifiedName);    
--- a/content/base/src/nsAttrValue.cpp
+++ b/content/base/src/nsAttrValue.cpp
@@ -505,17 +505,17 @@ PRUint32
 nsAttrValue::HashValue() const
 {
   switch(BaseType()) {
     case eStringBase:
     {
       nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr());
       if (str) {
         PRUint32 len = str->StorageSize()/sizeof(PRUnichar) - 1;
-        return nsCRT::BufferHashCode(static_cast<PRUnichar*>(str->Data()), len);
+        return nsCRT::HashCode(static_cast<PRUnichar*>(str->Data()), len);
       }
 
       return 0;
     }
     case eOtherBase:
     {
       break;
     }
@@ -771,36 +771,38 @@ nsAttrValue::Contains(nsIAtom* aValue, n
     case eAtomBase:
     {
       nsIAtom* atom = GetAtomValue();
 
       if (aCaseSensitive == eCaseMatters) {
         return aValue == atom;
       }
 
-      const char *val1, *val2;
-      aValue->GetUTF8String(&val1);
-      atom->GetUTF8String(&val2);
-
-      return nsCRT::strcasecmp(val1, val2) == 0;
+      // For performance reasons, don't do a full on unicode case insensitive
+      // string comparison. This is only used for quirks mode anyway.
+      return
+        nsContentUtils::EqualsIgnoreASCIICase(nsDependentAtomString(aValue),
+                                              nsDependentAtomString(atom));
     }
     default:
     {
       if (Type() == eAtomArray) {
         nsCOMArray<nsIAtom>* array = GetAtomArrayValue();
         if (aCaseSensitive == eCaseMatters) {
           return array->IndexOf(aValue) >= 0;
         }
 
-        const char *val1, *val2;
-        aValue->GetUTF8String(&val1);
+        nsDependentAtomString val1(aValue);
 
         for (PRInt32 i = 0, count = array->Count(); i < count; ++i) {
-          array->ObjectAt(i)->GetUTF8String(&val2);
-          if (nsCRT::strcasecmp(val1, val2) == 0) {
+          // For performance reasons, don't do a full on unicode case
+          // insensitive string comparison. This is only used for quirks mode
+          // anyway.
+          if (nsContentUtils::EqualsIgnoreASCIICase(val1,
+                nsDependentAtomString(array->ObjectAt(i)))) {
             return PR_TRUE;
           }
         }
       }
     }
   }
 
   return PR_FALSE;
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -527,21 +527,19 @@ nsContentSink::ProcessHeaderData(nsIAtom
     // so that it can process things like pragma: no-cache or other
     // cache-control headers. Ideally this should also be the way for
     // cookies to be set! But we'll worry about that in the next
     // iteration
     nsCOMPtr<nsIChannel> channel;
     if (NS_SUCCEEDED(mParser->GetChannel(getter_AddRefs(channel)))) {
       nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
       if (httpChannel) {
-        const char* header;
-        (void)aHeader->GetUTF8String(&header);
-        (void)httpChannel->SetResponseHeader(nsDependentCString(header),
-                                             NS_ConvertUTF16toUTF8(aValue),
-                                             PR_TRUE);
+        httpChannel->SetResponseHeader(nsAtomCString(aHeader),
+                                       NS_ConvertUTF16toUTF8(aValue),
+                                       PR_TRUE);
       }
     }
   }
 
   return rv;
 }
 
 
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -1892,20 +1892,17 @@ static inline void KeyAppendInt(PRInt32 
 
   aKey.Append(nsPrintfCString("%d", aInt));
 }
 
 static inline void KeyAppendAtom(nsIAtom* aAtom, nsACString& aKey)
 {
   NS_PRECONDITION(aAtom, "KeyAppendAtom: aAtom can not be null!\n");
 
-  const char* atomString = nsnull;
-  aAtom->GetUTF8String(&atomString);
-
-  KeyAppendString(nsDependentCString(atomString), aKey);
+  KeyAppendString(nsAtomCString(aAtom), aKey);
 }
 
 static inline PRBool IsAutocompleteOff(nsIDOMElement* aElement)
 {
   nsAutoString autocomplete;
   aElement->GetAttribute(NS_LITERAL_STRING("autocomplete"), autocomplete);
   return autocomplete.LowerCaseEqualsLiteral("off");
 }
@@ -3205,18 +3202,17 @@ nsAutoGCRoot::RemoveJSGCRoot(void* aPtr)
 
   return NS_OK;
 }
 
 // static
 PRBool
 nsContentUtils::IsEventAttributeName(nsIAtom* aName, PRInt32 aType)
 {
-  const char* name;
-  aName->GetUTF8String(&name);
+  const PRUnichar* name = aName->GetUTF16String();
   if (name[0] != 'o' || name[1] != 'n')
     return PR_FALSE;
 
   EventNameMapping mapping;
   return (sEventTable->Get(aName, &mapping) && mapping.mType & aType);
 }
 
 // static
@@ -4925,16 +4921,53 @@ nsContentUtils::ASCIIToUpper(nsAString& 
     PRUnichar c = *iter;
     if (c >= 'a' && c <= 'z') {
       *iter = c + ('A' - 'a');
     }
     ++iter;
   }
 }
 
+PRBool
+nsContentUtils::EqualsIgnoreASCIICase(const nsAString& aStr1,
+                                      const nsAString& aStr2)
+{
+  PRUint32 len = aStr1.Length();
+  if (len != aStr2.Length()) {
+    return PR_FALSE;
+  }
+
+  const PRUnichar* str1 = aStr1.BeginReading();
+  const PRUnichar* str2 = aStr2.BeginReading();
+  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 PR_FALSE;
+    }
+
+    // We know they 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 PR_FALSE;
+      }
+    }
+  }
+
+  return PR_TRUE;
+}
+
 /* static */
 void
 nsAutoGCRoot::Shutdown()
 {
   NS_IF_RELEASE(sJSRuntimeService);
 }
 
 nsIAtom*
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -6713,19 +6713,17 @@ nsDocument::CreateElem(nsIAtom *aName, n
                        PRBool aDocumentDefaultType, nsIContent **aResult)
 {
 #ifdef DEBUG
   nsAutoString qName;
   if (aPrefix) {
     aPrefix->ToString(qName);
     qName.Append(':');
   }
-  const char *name;
-  aName->GetUTF8String(&name);
-  AppendUTF8toUTF16(name, qName);
+  qName.Append(nsAtomString(aName));
 
   // Note: "a:b:c" is a valid name in non-namespaces XML, and
   // nsDocument::CreateElement can call us with such a name and no prefix,
   // which would cause an error if we just used PR_TRUE here.
   PRBool nsAware = aPrefix != nsnull || aNamespaceID != GetDefaultNamespaceID();
   NS_ASSERTION(NS_SUCCEEDED(nsContentUtils::CheckQName(qName, nsAware)),
                "Don't pass invalid prefixes to nsDocument::CreateElem, "
                "check caller.");
--- a/content/base/src/nsHTMLContentSerializer.cpp
+++ b/content/base/src/nsHTMLContentSerializer.cpp
@@ -64,18 +64,16 @@
 #include "nsITextToSubURI.h"
 #include "nsCRT.h"
 #include "nsIParserService.h"
 #include "nsContentUtils.h"
 #include "nsLWBrkCIID.h"
 #include "nsIScriptElement.h"
 #include "nsAttrName.h"
 
-static const char kMozStr[] = "moz";
-
 static const PRInt32 kLongLineLen = 128;
 
 nsresult NS_NewHTMLContentSerializer(nsIContentSerializer** aSerializer)
 {
   nsHTMLContentSerializer* it = new nsHTMLContentSerializer();
   if (!it) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
@@ -118,20 +116,19 @@ nsHTMLContentSerializer::SerializeHTMLAt
 
   for (PRInt32 index = count; index > 0;) {
     --index;
     const nsAttrName* name = aContent->GetAttrNameAt(index);
     PRInt32 namespaceID = name->NamespaceID();
     nsIAtom* attrName = name->LocalName();
 
     // Filter out any attribute starting with [-|_]moz
-    const char* sharedName;
-    attrName->GetUTF8String(&sharedName);
-    if ((('_' == *sharedName) || ('-' == *sharedName)) &&
-        !nsCRT::strncmp(sharedName+1, kMozStr, PRUint32(sizeof(kMozStr)-1))) {
+    nsDependentAtomString attrNameStr(attrName);
+    if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) ||
+        StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
       continue;
     }
     aContent->GetAttr(namespaceID, attrName, valueStr);
 
     // 
     // Filter out special case of <br type="_moz"> or <br _moz*>,
     // used by the editor.  Bug 16988.  Yuck.
     //
--- a/content/base/src/nsNodeInfo.cpp
+++ b/content/base/src/nsNodeInfo.cpp
@@ -252,35 +252,32 @@ nsNodeInfo::QualifiedNameEqualsInternal(
 {
   NS_PRECONDITION(mInner.mPrefix, "Must have prefix");
   
   nsACString::const_iterator start;
   aQualifiedName.BeginReading(start);
 
   nsACString::const_iterator colon(start);
 
-  const char* prefix;
-  mInner.mPrefix->GetUTF8String(&prefix);
+  nsAtomCString prefix(mInner.mPrefix);
 
-  PRUint32 len = strlen(prefix);
-
-  if (len >= aQualifiedName.Length()) {
+  if (prefix.Length() >= aQualifiedName.Length()) {
     return PR_FALSE;
   }
 
-  colon.advance(len);
+  colon.advance(prefix.Length());
 
   // If the character at the prefix length index is not a colon,
   // aQualifiedName is not equal to this string.
   if (*colon != ':') {
     return PR_FALSE;
   }
 
   // Compare the prefix to the string from the start to the colon
-  if (!mInner.mPrefix->EqualsUTF8(Substring(start, colon)))
+  if (!prefix.Equals(Substring(start, colon)))
     return PR_FALSE;
 
   ++colon; // Skip the ':'
 
   nsACString::const_iterator end;
   aQualifiedName.EndReading(end);
 
   // Compare the local name to the string between the colon and the
--- a/content/base/src/nsXHTMLContentSerializer.cpp
+++ b/content/base/src/nsXHTMLContentSerializer.cpp
@@ -341,20 +341,19 @@ nsXHTMLContentSerializer::SerializeAttri
     }
 
     const nsAttrName* name = aContent->GetAttrNameAt(index);
     PRInt32 namespaceID = name->NamespaceID();
     nsIAtom* attrName = name->LocalName();
     nsIAtom* attrPrefix = name->GetPrefix();
 
     // Filter out any attribute starting with [-|_]moz
-    const char* sharedName;
-    attrName->GetUTF8String(&sharedName);
-    if ((('_' == *sharedName) || ('-' == *sharedName)) &&
-        !nsCRT::strncmp(sharedName+1, kMozStr, PRUint32(sizeof(kMozStr)-1))) {
+    nsDependentAtomString attrNameStr(attrName);
+    if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) ||
+        StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
       continue;
     }
 
     if (attrPrefix) {
       attrPrefix->ToString(prefixStr);
     }
     else {
       prefixStr.Truncate();
--- a/content/html/document/src/nsHTMLContentSink.cpp
+++ b/content/html/document/src/nsHTMLContentSink.cpp
@@ -937,23 +937,20 @@ SinkContext::CloseContainer(const nsHTML
   if (mNotifyLevel >= mStackPos) {
     // Check to see if new content has been added after our last
     // notification
 
     if (mStack[mStackPos].mNumFlushed < content->GetChildCount()) {
 #ifdef NS_DEBUG
       {
         // Tracing code
-        const char *tagStr;
-        mStack[mStackPos].mContent->Tag()->GetUTF8String(&tagStr);
-
         SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
                    ("SinkContext::CloseContainer: reflow on notifyImmediate "
                     "tag=%s newIndex=%d stackPos=%d",
-                    tagStr,
+                    nsAtomCString(mStack[mStackPos].mContent->Tag()).get(),
                     mStack[mStackPos].mNumFlushed, mStackPos));
       }
 #endif
       mSink->NotifyAppend(content, mStack[mStackPos].mNumFlushed);
       mStack[mStackPos].mNumFlushed = content->GetChildCount();
     }
 
     // Indicate that notification has now happened at this level
@@ -1348,22 +1345,20 @@ SinkContext::FlushTags()
     while (stackPos < mStackPos) {
       content = mStack[stackPos].mContent;
       childCount = content->GetChildCount();
 
       if (!flushed && (mStack[stackPos].mNumFlushed < childCount)) {
 #ifdef NS_DEBUG
         {
           // Tracing code
-          const char* tagStr;
-          mStack[stackPos].mContent->Tag()->GetUTF8String(&tagStr);
-
           SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
                      ("SinkContext::FlushTags: tag=%s from newindex=%d at "
-                      "stackPos=%d", tagStr,
+                      "stackPos=%d",
+                      nsAtomCString(mStack[stackPos].mContent->Tag()).get(),
                       mStack[stackPos].mNumFlushed, stackPos));
         }
 #endif
         if (mStack[stackPos].mInsertionPoint != -1) {
           // We might have popped the child off our stack already
           // but not notified on it yet, which is why we have to get it
           // directly from its parent node.
 
--- a/content/smil/nsSMILCompositor.cpp
+++ b/content/smil/nsSMILCompositor.cpp
@@ -46,20 +46,18 @@ nsSMILCompositor::KeyEquals(KeyTypePoint
 {
   return aKey && aKey->Equals(mKey);
 }
 
 /*static*/ PLDHashNumber
 nsSMILCompositor::HashKey(KeyTypePointer aKey)
 {
   // Combine the 3 values into one numeric value, which will be hashed
-  const char *attrName = nsnull;
-  aKey->mAttributeName->GetUTF8String(&attrName);
-  return NS_PTR_TO_UINT32(aKey->mElement.get()) +
-    HashString(attrName) +
+  return NS_PTR_TO_UINT32(aKey->mElement.get()) >> 4 +
+    NS_PTR_TO_INT32(aKey->mAttributeName.get()) +
     (aKey->mIsCSS ? 1 : 0);
 }
 
 // Cycle-collection support
 void
 nsSMILCompositor::Traverse(nsCycleCollectionTraversalCallback* aCallback)
 {
   if (!mKey.mElement)
--- a/content/xslt/src/base/txStringUtils.h
+++ b/content/xslt/src/base/txStringUtils.h
@@ -44,20 +44,17 @@
 #include "nsIAtom.h"
 
 /**
  * Check equality between a string and an atom containing ASCII.
  */
 inline PRBool
 TX_StringEqualsAtom(const nsASingleFragmentString& aString, nsIAtom* aAtom)
 {
-    const char* ASCIIAtom;
-    aAtom->GetUTF8String(&ASCIIAtom);
-
-    return aString.EqualsASCII(ASCIIAtom);
+  return aAtom->Equals(aString);
 }
 
 #ifndef TX_EXE
 
 #include "nsUnicharUtils.h"
 typedef nsCaseInsensitiveStringComparator txCaseInsensitiveStringComparator;
 
 #define TX_ToLowerCase ToLowerCase
--- a/content/xslt/src/xpath/txXPCOMExtensionFunction.cpp
+++ b/content/xslt/src/xpath/txXPCOMExtensionFunction.cpp
@@ -207,20 +207,19 @@ LookupFunction(const char *aContractID, 
     NS_ENSURE_SUCCESS(rv, rv);
 
     txInterfacesArrayHolder holder(iidArray, iidCount);
 
     // Remove any minus signs and uppercase the following letter (so
     // foo-bar becomes fooBar). Note that if there are any names that already
     // have uppercase letters they might cause false matches (both fooBar and
     // foo-bar matching fooBar).
-    const char *name;
-    aName->GetUTF8String(&name);
+    const PRUnichar *name = aName->GetUTF16String();
     nsCAutoString methodName;
-    char letter;
+    PRUnichar letter;
     PRBool upperNext = PR_FALSE;
     while ((letter = *name)) {
         if (letter == '-') {
             upperNext = PR_TRUE;
         }
         else {
             methodName.Append(upperNext ? nsCRT::ToUpper(letter) : letter);
             upperNext = PR_FALSE;
--- a/content/xul/document/src/nsXULDocument.cpp
+++ b/content/xul/document/src/nsXULDocument.cpp
@@ -1403,30 +1403,27 @@ nsXULDocument::Persist(nsIContent* aElem
     if (NS_FAILED(rv)) return rv;
 
     // No ID, so nothing to persist.
     if (! element)
         return NS_OK;
 
     // Ick. Construct a property from the attribute. Punt on
     // namespaces for now.
-    const char* attrstr;
-    rv = aAttribute->GetUTF8String(&attrstr);
-    if (NS_FAILED(rv)) return rv;
-
     // Don't bother with unreasonable attributes. We clamp long values,
     // but truncating attribute names turns it into a different attribute
     // so there's no point in persisting anything at all
-    if (!attrstr || strlen(attrstr) > kMaxAttrNameLength) {
+    nsAtomCString attrstr(aAttribute);
+    if (attrstr.Length() > kMaxAttrNameLength) {
         NS_WARNING("Can't persist, Attribute name too long");
         return NS_ERROR_ILLEGAL_VALUE;
     }
 
     nsCOMPtr<nsIRDFResource> attr;
-    rv = gRDFService->GetResource(nsDependentCString(attrstr),
+    rv = gRDFService->GetResource(attrstr,
                                   getter_AddRefs(attr));
     if (NS_FAILED(rv)) return rv;
 
     // Turn the value into a literal
     nsAutoString valuestr;
     aElement->GetAttr(kNameSpaceID_None, aAttribute, valuestr);
 
     // prevent over-long attributes that choke the parser (bug 319846)
--- a/content/xul/templates/src/nsXULContentBuilder.cpp
+++ b/content/xul/templates/src/nsXULContentBuilder.cpp
@@ -478,27 +478,24 @@ nsXULContentBuilder::BuildContentFromTem
     nsresult rv;
 
 #ifdef PR_LOGGING
     if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
         PR_LOG(gXULTemplateLog, PR_LOG_ALWAYS,
                ("nsXULContentBuilder::BuildContentFromTemplate (is unique: %d)",
                aIsUnique));
 
-        const char *tmpln, *resn, *realn;
-        aTemplateNode->Tag()->GetUTF8String(&tmpln);
-        aResourceNode->Tag()->GetUTF8String(&resn);
-        aRealNode->Tag()->GetUTF8String(&realn);
-
         nsAutoString id;
         aChild->GetId(id);
 
         PR_LOG(gXULTemplateLog, PR_LOG_ALWAYS,
                ("Tags: [Template: %s  Resource: %s  Real: %s] for id %s",
-               tmpln, resn, realn, NS_ConvertUTF16toUTF8(id).get()));
+                nsAtomCString(aTemplateNode->Tag()).get(), 
+                nsAtomCString(aResourceNode->Tag()).get(),
+                nsAtomCString(aRealNode->Tag()).get(), NS_ConvertUTF16toUTF8(id).get()));
     }
 #endif
 
     // Iterate through all of the template children, constructing
     // "real" content model nodes for each "template" child.
     PRUint32 count = aTemplateNode->GetChildCount();
 
     for (PRUint32 kid = 0; kid < count; kid++) {
@@ -557,21 +554,19 @@ nsXULContentBuilder::BuildContentFromTem
                 isUnique = PR_FALSE;
             }
         }
 
         nsIAtom *tag = tmplKid->Tag();
 
 #ifdef PR_LOGGING
         if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
-            const char *tagname;
-            tag->GetUTF8String(&tagname);
             PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
                    ("xultemplate[%p]     building %s %s %s",
-                    this, tagname,
+                    this, nsAtomCString(tag).get(),
                     (isGenerationElement ? "[resource]" : ""),
                     (isUnique ? "[unique]" : "")));
         }
 #endif
 
         // Set to PR_TRUE if the child we're trying to create now
         // already existed in the content model.
         PRBool realKidAlreadyExisted = PR_FALSE;
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1922,37 +1922,35 @@ nsJSContext::ExecuteScript(void *aScript
 
   // ScriptEvaluated needs to come after we pop the stack
   ScriptEvaluated(PR_TRUE);
 
   return rv;
 }
 
 
-static inline const char *
-AtomToEventHandlerName(nsIAtom *aName)
+#ifdef DEBUG
+PRBool
+AtomIsEventHandlerName(nsIAtom *aName)
 {
-  const char *name;
-
-  aName->GetUTF8String(&name);
-
-#ifdef DEBUG
-  const char *cp;
-  char c;
+  const PRUnichar *name = aName->GetUTF16String();
+
+  const PRUnichar *cp;
+  PRUnichar c;
   for (cp = name; *cp != '\0'; ++cp)
   {
     c = *cp;
-    NS_ASSERTION (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'),
-                  "non-ASCII non-alphabetic event handler name");
+    if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z'))
+      return PR_FALSE;
   }
+
+  return PR_TRUE;
+}
 #endif
 
-  return name;
-}
-
 // Helper function to find the JSObject associated with a (presumably DOM)
 // interface.
 nsresult
 nsJSContext::JSObjectFromInterface(nsISupports* aTarget, void *aScope, JSObject **aRet)
 {
   // It is legal to specify a null target.
   if (!aTarget) {
       *aRet = nsnull;
@@ -1987,49 +1985,48 @@ nsJSContext::CompileEventHandler(nsIAtom
                                  const char** aArgNames,
                                  const nsAString& aBody,
                                  const char *aURL, PRUint32 aLineNo,
                                  PRUint32 aVersion,
                                  nsScriptObjectHolder &aHandler)
 {
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
 
+  NS_PRECONDITION(AtomIsEventHandlerName(aName), "Bad event name");
   NS_PRECONDITION(!::JS_IsExceptionPending(mContext),
                   "Why are we being called with a pending exception?");
 
   if (!sSecurityManager) {
     NS_ERROR("Huh, we need a script security manager to compile "
              "an event handler!");
 
     return NS_ERROR_UNEXPECTED;
   }
 
   // Don't compile if aVersion is unknown.  Since the caller is responsible for
   // parsing the version strings, we just check it isn't JSVERSION_UNKNOWN.
   if ((JSVersion)aVersion == JSVERSION_UNKNOWN) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
-  const char *charName = AtomToEventHandlerName(aName);
-
 #ifdef DEBUG
   JSContext* top = nsContentUtils::GetCurrentJSContext();
   NS_ASSERTION(mContext == top, "Context not properly pushed!");
 #endif
 
   // Event handlers are always shared, and must be bound before use.
   // Therefore we never bother compiling with principals.
   // (that probably means we should avoid JS_CompileUCFunctionForPrincipals!)
   JSAutoRequest ar(mContext);
   nsJSVersionSetter setVersion(mContext, aVersion);
 
   JSFunction* fun =
       ::JS_CompileUCFunctionForPrincipals(mContext,
                                           nsnull, nsnull,
-                                          charName, aArgCount, aArgNames,
+                                          nsAtomCString(aName).get(), aArgCount, aArgNames,
                                           (jschar*)PromiseFlatString(aBody).get(),
                                           aBody.Length(),
                                           aURL, aLineNo);
 
   if (!fun) {
     ReportPendingException();
     return NS_ERROR_ILLEGAL_VALUE;
   }
@@ -2201,17 +2198,17 @@ nsJSContext::CallEventHandler(nsISupport
 nsresult
 nsJSContext::BindCompiledEventHandler(nsISupports* aTarget, void *aScope,
                                       nsIAtom *aName,
                                       void *aHandler)
 {
   NS_ENSURE_ARG(aHandler);
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
 
-  const char *charName = AtomToEventHandlerName(aName);
+  NS_PRECONDITION(AtomIsEventHandlerName(aName), "Bad event name");
   nsresult rv;
 
   // Get the jsobject associated with this target
   JSObject *target = nsnull;
   nsAutoGCRoot root(&target, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = JSObjectFromInterface(aTarget, aScope, &target);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -2235,17 +2232,17 @@ nsJSContext::BindCompiledEventHandler(ns
   if (funobj) { // && ::JS_GetParent(mContext, funobj) != target) {
     funobj = ::JS_CloneFunctionObject(mContext, funobj, target);
     if (!funobj)
       rv = NS_ERROR_OUT_OF_MEMORY;
   }
 
   if (NS_SUCCEEDED(rv) &&
       // Make sure the flags here match those in nsEventReceiverSH::NewResolve
-      !::JS_DefineProperty(mContext, target, charName,
+      !::JS_DefineProperty(mContext, target, nsAtomCString(aName).get(),
                            OBJECT_TO_JSVAL(funobj), nsnull, nsnull,
                            JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
     ReportPendingException();
     rv = NS_ERROR_FAILURE;
   }
 
   // XXXmarkh - ideally we should assert that the wrapped native is now
   // "long lived" - how to do that?
@@ -2257,29 +2254,29 @@ nsJSContext::BindCompiledEventHandler(ns
   return rv;
 }
 
 nsresult
 nsJSContext::GetBoundEventHandler(nsISupports* aTarget, void *aScope,
                                   nsIAtom* aName,
                                   nsScriptObjectHolder &aHandler)
 {
+    NS_PRECONDITION(AtomIsEventHandlerName(aName), "Bad event name");
+
     nsresult rv;
     JSObject *obj = nsnull;
     nsAutoGCRoot root(&obj, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
     JSAutoRequest ar(mContext);
     rv = JSObjectFromInterface(aTarget, aScope, &obj);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    const char *charName = AtomToEventHandlerName(aName);
-
     jsval funval;
     if (!JS_LookupProperty(mContext, obj,
-                           charName, &funval))
+                           nsAtomCString(aName).get(), &funval))
         return NS_ERROR_FAILURE;
 
     if (JS_TypeOfValue(mContext, funval) != JSTYPE_FUNCTION) {
         NS_WARNING("Event handler object not a function");
         aHandler.drop();
         return NS_OK;
     }
     NS_ASSERTION(aHandler.getScriptTypeID()==JAVASCRIPT,
--- a/gfx/thebes/src/gfxWindowsFonts.cpp
+++ b/gfx/thebes/src/gfxWindowsFonts.cpp
@@ -1855,19 +1855,17 @@ gfxWindowsFontGroup::WhichPrefFontSuppor
 
                 nsAutoTArray<nsRefPtr<gfxFontEntry>, 15> fonts;
                 this->GetCJKPrefFonts(fonts);
                 selectedFont = WhichFontSupportsChar(fonts, aCh);
             } else {
                 nsIAtom *langGroup = LangGroupFromUnicodeRange(unicodeRange);
                 if (langGroup) {
 #ifdef PR_LOGGING
-                    const char *langGroupStr;
-                    langGroup->GetUTF8String(&langGroupStr);
-                    PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: %s", langGroupStr));
+                    PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: %s", nsAtomCString(langGroup).get()));
 #endif
                     nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
                     this->GetPrefFonts(langGroup, fonts);
                     selectedFont = WhichFontSupportsChar(fonts, aCh);
                 }
             }
         }
     }
--- a/gfx/thebes/test/gfxFontSelectionTests.h
+++ b/gfx/thebes/test/gfxFontSelectionTests.h
@@ -104,25 +104,25 @@ SetupTests()
 {
     TestEntry *t;
 
     /* some common styles */
     gfxFontStyle style_western_normal_16 (FONT_STYLE_NORMAL,
                                           NS_FONT_STRETCH_NORMAL,
                                           400,
                                           16.0,
-                                          NS_NewPermanentAtom(NS_LITERAL_CSTRING("en")),
+                                          NS_NewPermanentAtom(NS_LITERAL_STRING("en")),
                                           0.0,
                                           PR_FALSE, PR_FALSE, PR_FALSE);
 
     gfxFontStyle style_western_bold_16 (FONT_STYLE_NORMAL,
                                         NS_FONT_STRETCH_NORMAL,
                                         700,
                                         16.0,
-                                        NS_NewPermanentAtom(NS_LITERAL_CSTRING("en")),
+                                        NS_NewPermanentAtom(NS_LITERAL_STRING("en")),
                                         0.0,
                                         PR_FALSE, PR_FALSE, PR_FALSE);
 
     /* Test 0 */
     t = AddTest ("sans-serif",
                  style_western_normal_16,
                  S_ASCII,
                  "ABCD");
--- a/gfx/thebes/test/gfxTextRunPerfTest.cpp
+++ b/gfx/thebes/test/gfxTextRunPerfTest.cpp
@@ -88,17 +88,17 @@ const char* lastFamilies = nsnull;
 
 void
 RunTest (TestEntry *test, gfxContext *ctx) {
     if (!lastFamilies || strcmp(lastFamilies, test->mFamilies)) {
         gfxFontStyle style_western_normal_16 (FONT_STYLE_NORMAL,
                                               NS_FONT_STRETCH_NORMAL,
                                               400,
                                               16.0,
-                                              NS_NewPermanentAtom(NS_LITERAL_CSTRING("en")),
+                                              NS_NewPermanentAtom(NS_LITERAL_STRING("en")),
                                               0.0,
                                               PR_FALSE, PR_FALSE, PR_FALSE);
 
         fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->mFamilies), &style_western_normal_16, nsnull);
     }
 
     nsAutoPtr<gfxTextRun> textRun;
     PRUint32 i;
--- a/gfx/thebes/test/gfxWordCacheTest.cpp
+++ b/gfx/thebes/test/gfxWordCacheTest.cpp
@@ -154,17 +154,17 @@ main (int argc, char **argv) {
    gTextRuns = new FrameTextRunCache();
 
    nsRefPtr<gfxContext> ctx = MakeContext();
    {
        gfxFontStyle style (FONT_STYLE_NORMAL,
                            NS_FONT_STRETCH_NORMAL,
                            139,
                            10.0,
-                           NS_NewPermanentAtom(NS_LITERAL_CSTRING("en")),
+                           NS_NewPermanentAtom(NS_LITERAL_STRING("en")),
                            0.0,
                            PR_FALSE, PR_FALSE, PR_FALSE);
 
        nsRefPtr<gfxFontGroup> fontGroup =
            gfxPlatform::GetPlatform()->CreateFontGroup(NS_LITERAL_STRING("Geneva, MS Sans Serif, Helvetica,serif"), &style, nsnull);
 
        gfxTextRunFactory::Parameters params = {
            ctx, nsnull, nsnull, nsnull, 0, 60
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -426,23 +426,29 @@ nsPresContext::GetFontPreferences()
   font.size-adjust.[generic].[langGroup] = "float" - settable by the user
   font.minimum-size.[langGroup] = integer - settable by the user
   */
 
   mDefaultVariableFont.size = CSSPixelsToAppUnits(16);
   mDefaultFixedFont.size = CSSPixelsToAppUnits(13);
 
   // the font prefs are based on langGroup, not actual language
-  const char *langGroup = "x-western"; // Assume x-western is safe...
+  nsCAutoString langGroup;
   if (mLanguage && mLangService) {
     nsresult rv;
     nsIAtom *group = mLangService->GetLanguageGroup(mLanguage, &rv);
     if (NS_SUCCEEDED(rv) && group) {
-      group->GetUTF8String(&langGroup);
+      group->ToUTF8String(langGroup);
     }
+    else {
+      langGroup.AssignLiteral("x-western"); // Assume x-western is safe...
+    }
+  }
+  else {
+    langGroup.AssignLiteral("x-western"); // Assume x-western is safe...
   }
 
   nsCAutoString pref;
 
   // get the current applicable font-size unit
   enum {eUnit_unknown = -1, eUnit_px, eUnit_pt};
   PRInt32 unit = eUnit_px;
 
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -6729,21 +6729,23 @@ nsFrame::GetBoxName(nsAutoString& aName)
 }
 #endif
 
 #ifdef NS_DEBUG
 static void
 GetTagName(nsFrame* aFrame, nsIContent* aContent, PRIntn aResultSize,
            char* aResult)
 {
-  const char *nameStr = "";
   if (aContent) {
-    aContent->Tag()->GetUTF8String(&nameStr);
-  }
-  PR_snprintf(aResult, aResultSize, "%s@%p", nameStr, aFrame);
+    PR_snprintf(aResult, aResultSize, "%s@%p",
+                nsAtomCString(aContent->Tag()).get(), aFrame);
+  }
+  else {
+    PR_snprintf(aResult, aResultSize, "@%p", aFrame);
+  }
 }
 
 void
 nsFrame::Trace(const char* aMethod, PRBool aEnter)
 {
   if (NS_FRAME_LOG_TEST(gLogModule, NS_FRAME_TRACE_CALLS)) {
     char tagbuf[40];
     GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -4876,19 +4876,18 @@ nsTypedSelection::Collapse(nsINode* aPar
 #ifdef DEBUG_SELECTION
   if (aParentNode)
   {
     nsCOMPtr<nsIContent>content;
     content = do_QueryInterface(aParentNode);
     if (!content)
       return NS_ERROR_FAILURE;
 
-    const char *tagString;
-    content->Tag()->GetUTF8String(&tagString);
-    printf ("Sel. Collapse to %p %s %d\n", content.get(), tagString, aOffset);
+    printf ("Sel. Collapse to %p %s %d\n", content.get(),
+            nsAtomCString(content->Tag()).get(), aOffset);
   }
   else {
     printf ("Sel. Collapse set to null parent.\n");
   }
 #endif
 
 
   result = AddItem(range);
@@ -5269,19 +5268,18 @@ nsTypedSelection::Extend(nsINode* aParen
 #endif
   SetDirection(dir);
 #ifdef DEBUG_SELECTION
   if (aParentNode)
   {
     nsCOMPtr<nsIContent>content;
     content = do_QueryInterface(aParentNode);
 
-    const char *tagString;
-    content->Tag()->GetUTF8String(&tagString);
-    printf ("Sel. Extend to %p %s %d\n", content.get(), tagString, aOffset);
+    printf ("Sel. Extend to %p %s %d\n", content.get(),
+            nsAtomCString(content->Tag()).get(), aOffset);
   }
   else {
     printf ("Sel. Extend set to null parent.\n");
   }
 #endif
   return mFrameSelection->NotifySelectionListeners(GetType());
 }
 
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -2159,20 +2159,20 @@ static PRInt32 FindChar(const nsTextFrag
 }
 
 static PRBool IsChineseOrJapanese(nsIFrame* aFrame)
 {
   nsIAtom* language = aFrame->GetStyleVisibility()->mLanguage;
   if (!language) {
     return PR_FALSE;
   }
-  const char *lang;
-  language->GetUTF8String(&lang);
-  return (!strncmp(lang, "ja", 2) || !strncmp(lang, "zh", 2)) &&
-         (lang[2] == '\0' || lang[2] == '-');
+  const PRUnichar *lang = language->GetUTF16String();
+  return (!nsCRT::strncmp(lang, NS_LITERAL_STRING("ja").get(), 2) ||
+          !nsCRT::strncmp(lang, NS_LITERAL_STRING("zh").get(), 2)) &&
+         (language->GetLength() == 2 || lang[2] == '-');
 }
 
 #ifdef DEBUG
 static PRBool IsInBounds(const gfxSkipCharsIterator& aStart, PRInt32 aContentLength,
                          PRUint32 aOffset, PRUint32 aLength) {
   if (aStart.GetSkippedOffset() > aOffset)
     return PR_FALSE;
   if (aContentLength == PR_INT32_MAX)
--- a/layout/style/nsCSSAnonBoxes.cpp
+++ b/layout/style/nsCSSAnonBoxes.cpp
@@ -73,14 +73,12 @@ PRBool nsCSSAnonBoxes::IsAnonBox(nsIAtom
   return nsAtomListUtils::IsMember(aAtom, CSSAnonBoxes_info,
                                    NS_ARRAY_LENGTH(CSSAnonBoxes_info));
 }
 
 #ifdef MOZ_XUL
 /* static */ PRBool
 nsCSSAnonBoxes::IsTreePseudoElement(nsIAtom* aPseudo)
 {
-  const char* str;
-  aPseudo->GetUTF8String(&str);
-  static const char moz_tree[] = ":-moz-tree-";
-  return nsCRT::strncmp(str, moz_tree, PRInt32(sizeof(moz_tree)-1)) == 0;
+  return StringBeginsWith(nsDependentAtomString(aPseudo),
+                          NS_LITERAL_STRING(":-moz-tree-"));
 }
 #endif
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -191,21 +191,23 @@ RuleHash_CIMatchEntry(PLDHashTable *tabl
                                               (key));
   // Use our extra |getKey| callback to avoid code duplication.
   nsIAtom *entry_atom = ToLocalOps(table->ops)->getKey(table, hdr);
 
   // Check for case-sensitive match first.
   if (match_atom == entry_atom)
     return PR_TRUE;
 
-  const char *match_str, *entry_str;
-  match_atom->GetUTF8String(&match_str);
-  entry_atom->GetUTF8String(&entry_str);
+  // Use EqualsIgnoreASCIICase instead of full on unicode case conversion
+  // in order to save on performance. This is only used in quirks mode
+  // anyway.
 
-  return (nsCRT::strcasecmp(entry_str, match_str) == 0);
+  return
+    nsContentUtils::EqualsIgnoreASCIICase(nsDependentAtomString(entry_atom),
+                                          nsDependentAtomString(match_atom));
 }
 
 static PRBool
 RuleHash_CSMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
                       const void *key)
 {
   nsIAtom *match_atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>
                                               (key));
@@ -1829,23 +1831,23 @@ static PRBool SelectorMatches(RuleProces
       if (isCaseSensitive) {
         do {
           if (IDList->mAtom != data.mContentID) {
             return PR_FALSE;
           }
           IDList = IDList->mNext;
         } while (IDList);
       } else {
-        const char* id1Str;
-        data.mContentID->GetUTF8String(&id1Str);
-        nsDependentCString id1(id1Str);
+        // Use EqualsIgnoreASCIICase instead of full on unicode case conversion
+        // in order to save on performance. This is only used in quirks mode
+        // anyway.
+        nsDependentAtomString id1Str(data.mContentID);
         do {
-          const char* id2Str;
-          IDList->mAtom->GetUTF8String(&id2Str);
-          if (!id1.Equals(id2Str, nsCaseInsensitiveCStringComparator())) {
+          if (!nsContentUtils::EqualsIgnoreASCIICase(id1Str,
+                 nsDependentAtomString(IDList->mAtom))) {
             return PR_FALSE;
           }
           IDList = IDList->mNext;
         } while (IDList);
       }
     } else {
       // Element has no id but we have an id selector
       return PR_FALSE;
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -4289,20 +4289,19 @@ nsComputedDOMStyle::GetTransitionPropert
     }
     nsCSSProperty cssprop = transition->GetProperty();
     if (cssprop == eCSSPropertyExtra_all_properties)
       property->SetIdent(eCSSKeyword_all);
     else if (cssprop == eCSSPropertyExtra_no_properties)
       property->SetIdent(eCSSKeyword_none);
     else if (cssprop == eCSSProperty_UNKNOWN)
     {
-      const char *str;
-      transition->GetUnknownProperty()->GetUTF8String(&str);
       nsAutoString escaped;
-      nsStyleUtil::AppendEscapedCSSIdent(NS_ConvertUTF8toUTF16(str), escaped);
+      nsStyleUtil::AppendEscapedCSSIdent(
+        nsDependentAtomString(transition->GetUnknownProperty()), escaped);
       property->SetString(escaped); // really want SetIdent
     }
     else
       property->SetString(nsCSSProps::GetStringValue(cssprop));
   } while (++i < display->mTransitionPropertyCount);
 
   return CallQueryInterface(valueList, aValue);
 }
--- a/parser/html/nsHtml5Atom.cpp
+++ b/parser/html/nsHtml5Atom.cpp
@@ -77,19 +77,26 @@ nsHtml5Atom::ToString(nsAString& aReturn
 NS_IMETHODIMP
 nsHtml5Atom::ToUTF8String(nsACString& aReturn)
 {
   NS_NOTREACHED("Should not attempt to convert to an UTF-8 string.");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
-nsHtml5Atom::GetUTF8String(const char **aReturn)
+nsHtml5Atom::GetUTF16String(const PRUnichar **aReturn)
 {
-  NS_NOTREACHED("Should not attempt to get a UTF-8 string from nsHtml5Atom");
+  NS_NOTREACHED("Should not attempt to get a UTF-16 string from nsHtml5Atom");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP_(PRUint32)
+nsHtml5Atom::GetLength()
+{
+  NS_NOTREACHED("Should not attempt to get a length from nsHtml5Atom");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP_(PRBool)
 nsHtml5Atom::IsStaticAtom()
 {
   return PR_FALSE;
 }
--- a/parser/htmlparser/src/nsHTMLTags.cpp
+++ b/parser/htmlparser/src/nsHTMLTags.cpp
@@ -363,31 +363,31 @@ nsHTMLTags::AddRefTable(void)
                       NS_INT32_TO_PTR(i + 1));
 
       PL_HashTableAdd(gTagAtomTable, sTagAtomTable[i],
                       NS_INT32_TO_PTR(i + 1));
     }
 
 
 
-#ifdef DEBUG
+#if defined(DEBUG) && defined(NS_STATIC_ATOM_USE_WIDE_STRINGS)
     {
       // let's verify that all names in the the table are lowercase...
       for (i = 0; i < NS_HTML_TAG_MAX; ++i) {
-        nsCAutoString temp1((char*)sTagAtoms_info[i].mStringBuffer->Data());
-        nsCAutoString temp2((char*)sTagAtoms_info[i].mStringBuffer->Data());
+        nsAutoString temp1((PRUnichar*)sTagAtoms_info[i].mStringBuffer->Data());
+        nsAutoString temp2((PRUnichar*)sTagAtoms_info[i].mStringBuffer->Data());
         ToLowerCase(temp1);
         NS_ASSERTION(temp1.Equals(temp2), "upper case char in table");
       }
 
       // let's verify that all names in the unicode strings above are
       // correct.
       for (i = 0; i < NS_HTML_TAG_MAX; ++i) {
         nsAutoString temp1(sTagUnicodeTable[i]);
-        nsAutoString temp2; temp2.AssignWithConversion((char*)sTagAtoms_info[i].mStringBuffer->Data());
+        nsAutoString temp2((PRUnichar*)sTagAtoms_info[i].mStringBuffer->Data());
         NS_ASSERTION(temp1.Equals(temp2), "Bad unicode tag name!");
       }
 
       // let's verify that NS_HTMLTAG_NAME_MAX_LENGTH is correct
       PRUint32 maxTagNameLength = 0;
       for (i = 0; i < NS_HTML_TAG_MAX; ++i) {
         PRUint32 len = nsCRT::strlen(sTagUnicodeTable[i]);
         maxTagNameLength = NS_MAX(len, maxTagNameLength);        
--- a/rdf/base/src/nsRDFContentSink.cpp
+++ b/rdf/base/src/nsRDFContentSink.cpp
@@ -1021,21 +1021,18 @@ RDFContentSinkImpl::AddProperties(const 
       if (localName == kParseTypeAtom) {
           if (nameSpaceURI.IsEmpty() ||
               nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI) ||
               nameSpaceURI.EqualsLiteral(NC_NAMESPACE_URI)) {
               continue;
           }
       }
 
-      const char* attrName;
-      localName->GetUTF8String(&attrName);
-
       NS_ConvertUTF16toUTF8 propertyStr(nameSpaceURI);    
-      propertyStr.Append(attrName);
+      propertyStr.Append(nsAtomCString(localName));
 
       // Add the assertion to RDF
       nsCOMPtr<nsIRDFResource> property;
       gRDFService->GetResource(propertyStr, getter_AddRefs(property));
 
       nsCOMPtr<nsIRDFLiteral> target;
       gRDFService->GetLiteral(aAttributes[1], 
                               getter_AddRefs(target));
@@ -1153,21 +1150,18 @@ RDFContentSinkImpl::OpenObject(const PRU
         else {
             // heh, that's not *in* the RDF namespace: just treat it
             // like a typed node
             isaTypedNode = PR_TRUE;
         }
     }
 
     if (isaTypedNode) {
-        const char* attrName;
-        localName->GetUTF8String(&attrName);
-
         NS_ConvertUTF16toUTF8 typeStr(nameSpaceURI);
-        typeStr.Append(attrName);
+        typeStr.Append(nsAtomCString(localName));
 
         nsCOMPtr<nsIRDFResource> type;
         nsresult rv = gRDFService->GetResource(typeStr, getter_AddRefs(type));
         if (NS_FAILED(rv)) return rv;
 
         rv = mDataSource->Assert(source, kRDF_type, type, PR_TRUE);
         if (NS_FAILED(rv)) return rv;
 
@@ -1185,21 +1179,18 @@ RDFContentSinkImpl::OpenProperty(const P
 
     // an "object" non-terminal is either a "description", a "typed
     // node", or a "container", so this change the content sink's
     // state appropriately.
     nsCOMPtr<nsIAtom> localName;
     const nsDependentSubstring& nameSpaceURI =
         SplitExpatName(aName, getter_AddRefs(localName));
 
-    const char* attrName;
-    localName->GetUTF8String(&attrName);
-
     NS_ConvertUTF16toUTF8 propertyStr(nameSpaceURI);
-    propertyStr.Append(attrName);
+    propertyStr.Append(nsAtomCString(localName));
 
     nsCOMPtr<nsIRDFResource> property;
     rv = gRDFService->GetResource(propertyStr, getter_AddRefs(property));
     if (NS_FAILED(rv)) return rv;
 
     // See if they've specified a 'resource' attribute, in which case
     // they mean *that* to be the object of this property.
     nsCOMPtr<nsIRDFResource> target;
--- a/xpcom/ds/nsAtomService.cpp
+++ b/xpcom/ds/nsAtomService.cpp
@@ -54,17 +54,17 @@ nsAtomService::GetAtom(const nsAString& 
     return NS_ERROR_OUT_OF_MEMORY;
   
   return NS_OK;
 }
 
 nsresult
 nsAtomService::GetPermanentAtom(const nsAString& aString, nsIAtom ** aResult)
 {
-  *aResult = NS_NewPermanentAtom(NS_ConvertUTF16toUTF8(aString));
+  *aResult = NS_NewPermanentAtom(aString);
 
   if (!*aResult)
     return NS_ERROR_OUT_OF_MEMORY;
   
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -76,15 +76,15 @@ nsAtomService::GetAtomUTF8(const char *a
         return NS_ERROR_OUT_OF_MEMORY;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAtomService::GetPermanentAtomUTF8(const char *aValue, nsIAtom* *aResult)
 {
-    *aResult = NS_NewPermanentAtom(nsDependentCString(aValue));
+    *aResult = NS_NewPermanentAtom(NS_ConvertUTF8toUTF16(aValue));
 
     if (!*aResult)
         return NS_ERROR_OUT_OF_MEMORY;
 
     return NS_OK;
 }
--- a/xpcom/ds/nsAtomTable.cpp
+++ b/xpcom/ds/nsAtomTable.cpp
@@ -148,17 +148,17 @@ struct AtomTableEntry : public PLDHashEn
     NS_ASSERTION(keyHash > 1,
                  "GetAtomImpl() called on non-atom AtomTableEntry!");
     return (AtomImpl*) (mBits & ~0x1);
   }
 
   // type-agnostic accessors
 
   // get the string buffer
-  inline const char* getAtomString() const {
+  inline const PRUnichar* getAtomString() const {
     NS_ASSERTION(keyHash > 1,
                  "getAtomString() called on non-atom AtomTableEntry!");
 
     return GetAtomImpl()->mString;
   }
 
   // get the string buffer
   inline const char* getUTF8String() const {
@@ -195,56 +195,56 @@ struct AtomTableEntry : public PLDHashEn
   }
 };
 
 static PLDHashNumber
 AtomTableGetHash(PLDHashTable *table, const void *key)
 {
   const AtomTableEntry *e = static_cast<const AtomTableEntry*>(key);
 
-  if (e->IsUTF16String()) {
-    return nsCRT::HashCodeAsUTF8(e->getUTF16String(), e->getLength());;
+  if (e->IsUTF8String()) {
+    return nsCRT::HashCodeAsUTF16(e->getUTF8String(), e->getLength());;
   }
 
-  NS_ASSERTION(e->IsUTF8String(),
+  NS_ASSERTION(e->IsUTF16String(),
                "AtomTableGetHash() called on non-string-key AtomTableEntry!");
 
-  return nsCRT::HashCode(e->getUTF8String(), e->getLength());
+  return nsCRT::HashCode(e->getUTF16String(), e->getLength());
 }
 
 static PRBool
 AtomTableMatchKey(PLDHashTable *table, const PLDHashEntryHdr *entry,
                   const void *key)
 {
   const AtomTableEntry *he = static_cast<const AtomTableEntry*>(entry);
   const AtomTableEntry *strKey = static_cast<const AtomTableEntry*>(key);
 
-  const char *atomString = he->getAtomString();
+  const PRUnichar *atomString = he->getAtomString();
 
-  if (strKey->IsUTF16String()) {
+  if (strKey->IsUTF8String()) {
     return
-      CompareUTF8toUTF16(nsDependentCSubstring(atomString, atomString + he->getLength()),
-                         nsDependentSubstring(strKey->getUTF16String(),
-                                              strKey->getUTF16String() + strKey->getLength())) == 0;
+      CompareUTF8toUTF16(nsDependentCSubstring(strKey->getUTF8String(),
+                                               strKey->getUTF8String() + strKey->getLength()),
+                         nsDependentSubstring(atomString, atomString + he->getLength())) == 0;
   }
 
   PRUint32 length = he->getLength();
   if (length != strKey->getLength()) {
     return PR_FALSE;
   }
 
-  const char *str;
+  const PRUnichar *str;
 
-  if (strKey->IsUTF8String()) {
-    str = strKey->getUTF8String();
+  if (strKey->IsUTF16String()) {
+    str = strKey->getUTF16String();
   } else {
     str = strKey->getAtomString();
   }
 
-  return memcmp(atomString, str, length * sizeof(char)) == 0;
+  return memcmp(atomString, str, length * sizeof(PRUnichar)) == 0;
 }
 
 static void
 AtomTableClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
 {
   AtomTableEntry *he = static_cast<AtomTableEntry*>(entry);
   
   AtomImpl *atom = he->GetAtomImpl();
@@ -293,19 +293,19 @@ static PLDHashOperator
 DumpAtomLeaks(PLDHashTable *table, PLDHashEntryHdr *he,
               PRUint32 index, void *arg)
 {
   AtomTableEntry *entry = static_cast<AtomTableEntry*>(he);
   
   AtomImpl* atom = entry->GetAtomImpl();
   if (!atom->IsPermanent()) {
     ++*static_cast<PRUint32*>(arg);
-    const char *str;
-    atom->GetUTF8String(&str);
-    fputs(str, stdout);
+    nsCAutoString str;
+    atom->ToUTF8String(str);
+    fputs(str.get(), stdout);
     fputs("\n", stdout);
   }
   return PL_DHASH_NEXT;
 }
 #endif
 
 static inline
 void PromoteToPermanent(AtomImpl* aAtom)
@@ -338,35 +338,35 @@ NS_PurgeAtomTable()
     }
 #endif
     PL_DHashTableFinish(&gAtomTable);
     gAtomTable.entryCount = 0;
     gAtomTable.ops = nsnull;
   }
 }
 
-AtomImpl::AtomImpl(const nsACString& aString)
+AtomImpl::AtomImpl(const nsAString& aString)
   : mLength(aString.Length())
 {
   nsStringBuffer* buf = nsStringBuffer::FromString(aString);
   if (buf) {
     buf->AddRef();
-    mString = static_cast<char*>(buf->Data());
+    mString = static_cast<PRUnichar*>(buf->Data());
   }
   else {
-    buf = nsStringBuffer::Alloc((mLength + 1) * sizeof(char));
-    mString = static_cast<char*>(buf->Data());
-    memcpy(mString, aString.BeginReading(), mLength * sizeof(char));
+    buf = nsStringBuffer::Alloc((mLength + 1) * sizeof(PRUnichar));
+    mString = static_cast<PRUnichar*>(buf->Data());
+    CopyUnicodeTo(aString, 0, mString, mLength);
     mString[mLength] = PRUnichar(0);
   }
 }
 
 AtomImpl::AtomImpl(nsStringBuffer* aStringBuffer, PRUint32 aLength)
   : mLength(aLength),
-    mString(static_cast<char*>(aStringBuffer->Data()))
+    mString(static_cast<PRUnichar*>(aStringBuffer->Data()))
 {
   // Technically we could currently avoid doing this addref by instead making
   // the static atom buffers have an initial refcount of 2.
   aStringBuffer->AddRef();
 }
 
 AtomImpl::~AtomImpl()
 {
@@ -425,47 +425,53 @@ void* PermanentAtomImpl::operator new ( 
 
   // Just let the constructor overwrite the vtable pointer.
   return aAtom;
 }
 
 NS_IMETHODIMP 
 AtomImpl::ToString(nsAString& aBuf)
 {
-  CopyUTF8toUTF16(nsDependentCString(mString, mLength), aBuf);
+  nsStringBuffer::FromData(mString)->ToString(mLength, aBuf);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 AtomImpl::ToUTF8String(nsACString& aBuf)
 {
-  nsStringBuffer::FromData(mString)->ToString(mLength, aBuf);
+  CopyUTF16toUTF8(nsDependentString(mString, mLength), aBuf);
   return NS_OK;
 }
 
 NS_IMETHODIMP 
-AtomImpl::GetUTF8String(const char **aResult)
+AtomImpl::GetUTF16String(const PRUnichar **aResult)
 {
   NS_PRECONDITION(aResult, "null out param");
   *aResult = mString;
   return NS_OK;
 }
 
+NS_IMETHODIMP_(PRUint32)
+AtomImpl::GetLength()
+{
+  return mLength;
+}
+
 NS_IMETHODIMP
 AtomImpl::EqualsUTF8(const nsACString& aString, PRBool* aResult)
 {
-  *aResult = aString.Equals(nsDependentCString(mString, mLength));
+  *aResult = CompareUTF8toUTF16(aString,
+                                nsDependentString(mString, mLength)) == 0;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 AtomImpl::Equals(const nsAString& aString, PRBool* aResult)
 {
-  *aResult = CompareUTF8toUTF16(nsDependentCString(mString, mLength),
-                                aString) == 0;
+  *aResult = aString.Equals(nsDependentString(mString, mLength));
   return NS_OK;
 }
 
 NS_IMETHODIMP_(PRBool)
 AtomImpl::IsStaticAtom()
 {
   return IsPermanent();
 }
@@ -535,24 +541,25 @@ NS_RegisterStaticAtoms(const nsStaticAto
     if (!gStaticAtomTable || !gStaticAtomTable->Init()) {
       delete gStaticAtomTable;
       gStaticAtomTable = nsnull;
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
   
   for (PRUint32 i=0; i<aAtomCount; i++) {
-    NS_ASSERTION(nsCRT::IsAscii((char*)aAtoms[i].mStringBuffer->Data()),
+#ifdef NS_STATIC_ATOM_USE_WIDE_STRINGS
+    NS_ASSERTION(nsCRT::IsAscii((PRUnichar*)aAtoms[i].mStringBuffer->Data()),
                  "Static atoms must be ASCII!");
 
     PRUint32 stringLen =
-      aAtoms[i].mStringBuffer->StorageSize() / sizeof(char) - 1;
+      aAtoms[i].mStringBuffer->StorageSize() / sizeof(PRUnichar) - 1;
 
     AtomTableEntry *he =
-      GetAtomHashEntry((char*)aAtoms[i].mStringBuffer->Data(),
+      GetAtomHashEntry((PRUnichar*)aAtoms[i].mStringBuffer->Data(),
                        stringLen);
 
     if (he->HasValue()) {
       // there already is an atom with this name in the table.. but we
       // still have to update mBits
       if (!he->GetAtomImpl()->IsPermanent()) {
         // since we wanted to create a static atom but there is
         // already one there, we convert it to a non-refcounting
@@ -564,21 +571,35 @@ NS_RegisterStaticAtoms(const nsStaticAto
     }
     else {
       AtomImpl* atom = new PermanentAtomImpl(aAtoms[i].mStringBuffer,
                                              stringLen);
       he->SetAtomImpl(atom);
       *aAtoms[i].mAtom = atom;
 
       if (!gStaticAtomTableSealed) {
-        nsAutoString key;
-        atom->ToString(key);
-        gStaticAtomTable->Put(key, atom);
+        gStaticAtomTable->Put(nsAtomString(atom), atom);
       }
     }
+#else // NS_STATIC_ATOM_USE_WIDE_STRINGS
+    NS_ASSERTION(nsCRT::IsAscii((char*)aAtoms[i].mStringBuffer->Data()),
+                 "Static atoms must be ASCII!");
+
+    PRUint32 stringLen = aAtoms[i].mStringBuffer->StorageSize() - 1;
+
+    NS_ConvertASCIItoUTF16 str((char*)aAtoms[i].mStringBuffer->Data(),
+                               stringLen);
+    nsIAtom* atom = NS_NewPermanentAtom(str);
+    *aAtoms[i].mAtom = atom;
+
+    if (!gStaticAtomTableSealed) {
+      gStaticAtomTable->Put(str, atom);
+    }
+#endif
+
   }
   return NS_OK;
 }
 
 NS_COM nsIAtom*
 NS_NewAtom(const char* aUTF8String)
 {
   return NS_NewAtom(nsDependentCString(aUTF8String));
@@ -589,23 +610,25 @@ NS_NewAtom(const nsACString& aUTF8String
 {
   AtomTableEntry *he = GetAtomHashEntry(aUTF8String.Data(),
                                         aUTF8String.Length());
 
   if (!he) {
     return nsnull;
   }
 
-  NS_ASSERTION(!he->IsUTF8String() && !he->IsUTF16String(),
-               "Atom hash entry is string?  Should be atom!");
-
   if (he->HasValue())
     return he->GetAtom();
 
-  AtomImpl* atom = new AtomImpl(aUTF8String);
+  // This results in an extra addref/release of the nsStringBuffer.
+  // Unfortunately there doesn't seem to be any APIs to avoid that.
+  nsString str;
+  CopyUTF8toUTF16(aUTF8String, str);
+  AtomImpl* atom = new AtomImpl(str);
+
   he->SetAtomImpl(atom);
   NS_ADDREF(atom);
 
   return atom;
 }
 
 NS_COM nsIAtom*
 NS_NewAtom(const PRUnichar* aUTF16String)
@@ -617,43 +640,38 @@ NS_COM nsIAtom*
 NS_NewAtom(const nsAString& aUTF16String)
 {
   AtomTableEntry *he = GetAtomHashEntry(aUTF16String.Data(),
                                         aUTF16String.Length());
 
   if (he->HasValue())
     return he->GetAtom();
 
-  // This results in an extra addref/release of the nsStringBuffer.
-  // Unfortunately there doesn't seem to be any APIs to avoid that.
-  nsCString str;
-  CopyUTF16toUTF8(aUTF16String, str);
-  AtomImpl* atom = new AtomImpl(str);
-
+  AtomImpl* atom = new AtomImpl(aUTF16String);
   he->SetAtomImpl(atom);
   NS_ADDREF(atom);
 
   return atom;
 }
 
 NS_COM nsIAtom*
-NS_NewPermanentAtom(const nsACString& aUTF8String)
+NS_NewPermanentAtom(const nsAString& aUTF16String)
 {
-  AtomTableEntry *he = GetAtomHashEntry(aUTF8String.Data(),
-                                        aUTF8String.Length());
+  AtomTableEntry *he = GetAtomHashEntry(aUTF16String.Data(),
+                                        aUTF16String.Length());
 
   if (he->HasValue()) {
     AtomImpl* atom = he->GetAtomImpl();
     if (!atom->IsPermanent()) {
       PromoteToPermanent(atom);
     }
     return atom;
   }
   
-  AtomImpl* atom = new PermanentAtomImpl(aUTF8String);
+  AtomImpl* atom = new PermanentAtomImpl(aUTF16String);
   he->SetAtomImpl(atom);
 
   // No need to addref since permanent atoms aren't refcounted anyway
 
   return atom;
 }
 
 NS_COM nsrefcnt
--- a/xpcom/ds/nsAtomTable.h
+++ b/xpcom/ds/nsAtomTable.h
@@ -43,29 +43,29 @@
 
 /**
  * Note that AtomImpl objects are sometimes converted into PermanentAtomImpl
  * objects using placement new and just overwriting the vtable pointer.
  */
 
 class AtomImpl : public nsIAtom {
 public:
-  AtomImpl(const nsACString& aString);
+  AtomImpl(const nsAString& aString);
 
   // This is currently only used during startup when creating a permanent atom
   // from NS_RegisterStaticAtoms
   AtomImpl(nsStringBuffer* aData, PRUint32 aLength);
 
 protected:
   // This is only intended to be used when a normal atom is turned into a
   // permanent one.
   AtomImpl() {
     // We can't really assert that mString is a valid nsStringBuffer string,
     // so do the best we can do and check for some consistencies.
-    NS_ASSERTION((mLength + 1) * sizeof(char) <=
+    NS_ASSERTION((mLength + 1) * sizeof(PRUnichar) <=
                  nsStringBuffer::FromData(mString)->StorageSize() &&
                  mString[mLength] == 0,
                  "Not initialized atom");
   }
 
   // We don't need a virtual destructor here because PermanentAtomImpl
   // deletions aren't handled through Release().
   ~AtomImpl();
@@ -85,26 +85,26 @@ public:
 
   // for |#ifdef NS_BUILD_REFCNT_LOGGING| access to reference count
   nsrefcnt GetRefCount() { return mRefCnt; }
 
   // The length of the string in the atom.
   PRUint32 mLength;
 
   // This always points to the data owned by a nsStringBuffer
-  char* mString;
+  PRUnichar* mString;
 };
 
 /**
  * A non-refcounted implementation of nsIAtom.
  */
 
 class PermanentAtomImpl : public AtomImpl {
 public:
-  PermanentAtomImpl(const nsACString& aString)
+  PermanentAtomImpl(const nsAString& aString)
     : AtomImpl(aString)
   {}
   PermanentAtomImpl(nsStringBuffer* aData, PRUint32 aLength)
     : AtomImpl(aData, aLength)
   {}
   PermanentAtomImpl()
   {}
 
--- a/xpcom/ds/nsCRT.cpp
+++ b/xpcom/ds/nsCRT.cpp
@@ -50,16 +50,17 @@
  * routines, we simply return 0.
  */
 
 
 #include "nsCRT.h"
 #include "nsIServiceManager.h"
 #include "nsCharTraits.h"
 #include "prbit.h"
+#include "nsUTF8Utils.h"
 
 #define ADD_TO_HASHVAL(hashval, c) \
     hashval = PR_ROTATE_LEFT32(hashval, 4) ^ (c);
 
 //----------------------------------------------------------------------
 
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -232,135 +233,54 @@ PRUint32 nsCRT::HashCode(const PRUnichar
   while ( (c = *s++) )
     ADD_TO_HASHVAL(h, c);
 
   if ( resultingStrLen )
     *resultingStrLen = (s-str)-1;
   return h;
 }
 
-PRUint32 nsCRT::HashCodeAsUTF8(const PRUnichar* start, PRUint32 length)
+PRUint32 nsCRT::HashCode(const PRUnichar* start, PRUint32 length)
 {
   PRUint32 h = 0;
   const PRUnichar* s = start;
   const PRUnichar* end = start + length;
 
-  PRUint16 W1 = 0;      // the first UTF-16 word in a two word tuple
-  PRUint32 U = 0;       // the current char as UCS-4
-  int code_length = 0;  // the number of bytes in the UTF-8 sequence for the current char
-
-  PRUint16 W;
-  while ( s < end )
-    {
-      W = *s++;
-        /*
-         * On the fly, decoding from UTF-16 (and/or UCS-2) into UTF-8 as per
-         *  http://www.ietf.org/rfc/rfc2781.txt
-         *  http://www.ietf.org/rfc/rfc3629.txt
-         */
-
-      if ( !W1 )
-        {
-          if ( !IS_SURROGATE(W) )
-            {
-              U = W;
-              if ( W <= 0x007F )
-                code_length = 1;
-              else if ( W <= 0x07FF )
-                code_length = 2;
-              else
-                code_length = 3;
-            }
-          else if ( NS_IS_HIGH_SURROGATE(W) && s < end)
-            {
-              W1 = W;
-
-              continue;
-            }
-          else
-            {
-              // Treat broken characters as the Unicode replacement
-              // character 0xFFFD
-              U = 0xFFFD;
-
-              code_length = 3;
-
-              NS_WARNING("Got low surrogate but no previous high surrogate");
-            }
-        }
-      else
-        {
-          // as required by the standard, this code is careful to
-          // throw out illegal sequences
-
-          if ( NS_IS_LOW_SURROGATE(W) )
-            {
-              U = SURROGATE_TO_UCS4(W1, W);
-              NS_ASSERTION(IS_VALID_CHAR(U), "How did this happen?");
-              code_length = 4;
-            }
-          else
-            {
-              // Treat broken characters as the Unicode replacement
-              // character 0xFFFD
-              U = 0xFFFD;
-
-              code_length = 3;
-
-              NS_WARNING("High surrogate not followed by low surrogate");
-
-              // The pointer to the next character points to the second 16-bit
-              // value, not beyond it, as per Unicode 5.0.0 Chapter 3 C10, only
-              // the first code unit of an illegal sequence must be treated as
-              // an illegally terminated code unit sequence (also Chapter 3
-              // D91, "isolated [not paired and ill-formed] UTF-16 code units
-              // in the range D800..DFFF are ill-formed").
-              --s;
-            }
-
-          W1 = 0;
-        }
-
-
-      static const PRUint16 sBytePrefix[5]  = { 0x0000, 0x0000, 0x00C0, 0x00E0, 0x00F0  };
-      static const PRUint16 sShift[5]       = { 0, 0, 6, 12, 18 };
-
-      /*
-       *  Unlike the algorithm in
-       *  http://www.ietf.org/rfc/rfc3629.txt we must calculate the
-       *  bytes in left to right order so that our hash result
-       *  matches what the narrow version would calculate on an
-       *  already UTF-8 string.
-       */
-
-      // hash the first (and often, only, byte)
-      ADD_TO_HASHVAL(h, (sBytePrefix[code_length] | (U>>sShift[code_length])));
-
-      // an unrolled loop for hashing any remaining bytes in this
-      // sequence
-      switch ( code_length )
-        {  // falling through in each case
-          case 4:   ADD_TO_HASHVAL(h, (0x80 | ((U>>12) & 0x003F)));
-          case 3:   ADD_TO_HASHVAL(h, (0x80 | ((U>>6 ) & 0x003F)));
-          case 2:   ADD_TO_HASHVAL(h, (0x80 | ( U      & 0x003F)));
-          default:  code_length = 0;
-            break;
-        }
-    }
+  PRUnichar c;
+  while ( s < end ) {
+    c = *s++;
+    ADD_TO_HASHVAL(h, c);
+  }
 
   return h;
 }
 
-PRUint32 nsCRT::BufferHashCode(const PRUnichar* s, PRUint32 len)
+PRUint32 nsCRT::HashCodeAsUTF16(const char* start, PRUint32 length)
 {
   PRUint32 h = 0;
-  const PRUnichar* done = s + len;
+  const char* s = start;
+  const char* end = start + length;
 
-  while ( s < done )
-    h = PR_ROTATE_LEFT32(h, 4) ^ PRUint16(*s++); // cast to unsigned to prevent possible sign extension
+  while ( s < end )
+    {
+      PRBool err;
+      PRUint32 ucs4 = UTF8CharEnumerator::NextChar(&s, end, &err);
+      if (err) {
+	return 0;
+      }
+
+      if (ucs4 < PLANE1_BASE) {
+        ADD_TO_HASHVAL(h, ucs4);
+      }
+      else {
+        ADD_TO_HASHVAL(h, H_SURROGATE(ucs4));
+        ADD_TO_HASHVAL(h, L_SURROGATE(ucs4));
+      }
+    }
+
   return h;
 }
 
 // This should use NSPR but NSPR isn't exporting its PR_strtoll function
 // Until then...
 PRInt64 nsCRT::atoll(const char *str)
 {
     if (!str)
--- a/xpcom/ds/nsCRT.h
+++ b/xpcom/ds/nsCRT.h
@@ -231,25 +231,23 @@ public:
   // Computes the hashcode for a length number of bytes of c-string data.
   static PRUint32 HashCode(const char* start, PRUint32 length);
 
   // Computes the hashcode for a ucs2 string, returns the string length
   // as an added bonus.
   static PRUint32 HashCode(const PRUnichar* str,
                            PRUint32* resultingStrLen = nsnull);
 
-  // Computes a hashcode for a length number of UTF16
+  // Computes the hashcode for a buffer with a specified length.
+  static PRUint32 HashCode(const PRUnichar* str, PRUint32 strLen);
+
+  // Computes a hashcode for a length number of UTF8
   // characters. Returns the same hash code as the HashCode method
-  // taking a |char*| would if the string were converted to UTF8. This
-  // hash function treats invalid UTF16 data as 0xFFFD (0xEFBFBD in
-  // UTF-8).
-  static PRUint32 HashCodeAsUTF8(const PRUnichar* start, PRUint32 length);
-
-  // Computes the hashcode for a buffer with a specified length.
-  static PRUint32 BufferHashCode(const PRUnichar* str, PRUint32 strLen);
+  // taking a |PRUnichar*| would if the string were converted to UTF16.
+  static PRUint32 HashCodeAsUTF16(const char* start, PRUint32 length);
 
   // String to longlong
   static PRInt64 atoll(const char *str);
   
   static char ToUpper(char aChar) { return NS_ToUpper(aChar); }
   static char ToLower(char aChar) { return NS_ToLower(aChar); }
   
   static PRBool IsUpper(char aChar) { return NS_IsUpper(aChar); }
--- a/xpcom/ds/nsIAtom.idl
+++ b/xpcom/ds/nsIAtom.idl
@@ -43,29 +43,30 @@
 %}
 
 /*
  * Should this really be scriptable?  Using atoms from script or proxies
  * could be dangerous since double-wrapping could lead to loss of
  * pointer identity.
  */
  
-[scriptable, uuid(fbffe332-0856-421a-9b83-aaed0081fc40)]
+[scriptable, uuid(96c82146-56f3-4b43-817f-25d6db1ad8e8)]
 interface nsIAtom : nsISupports
 {
   /**
    * Get the Unicode or UTF8 value for the string
    */
   AString toString(); 
   AUTF8String toUTF8String();
   
   /**
-   * Return a pointer to a zero terminated UTF8 string.
+   * Return a pointer to a zero terminated UTF16 string.
    */
-  [noscript] void getUTF8String([shared, retval] out string aResult);
+  [noscript] void getUTF16String([shared, retval] out wstring aResult);
+  [notxpcom] unsigned long getLength();
 
   /**
    * Compare the atom to a specific string value
    * Note that this will NEVER return/throw an error condition.
    */
   boolean equals(in AString aString);
   
   boolean equalsUTF8(in AUTF8String aString);
@@ -78,16 +79,23 @@ interface nsIAtom : nsISupports
     return result;
   }
 
   inline PRBool EqualsUTF8(const nsACString& s) {
     PRBool result;
     EqualsUTF8(s, &result);
     return result;
   }
+
+  inline const PRUnichar* GetUTF16String() {
+    const PRUnichar* result;
+    GetUTF16String(&result);
+    return result;
+  }
+
 %}
   
   /**
    * Returns true if the atom is static and false otherwise.
    */
   [noscript, notxpcom] boolean isStaticAtom();
 };
 
@@ -118,32 +126,32 @@ extern NS_COM nsIAtom* NS_NewAtom(const 
 
 inline already_AddRefed<nsIAtom> do_GetAtom(const char* aUTF8String)
     { return NS_NewAtom(aUTF8String); }
  
 /**
  * Find an atom that matches the given UTF-8 string.
  */
 extern NS_COM nsIAtom* NS_NewAtom(const nsACString& aUTF8String);
-extern NS_COM nsIAtom* NS_NewPermanentAtom(const nsACString& aUTF8String);
 inline already_AddRefed<nsIAtom> do_GetAtom(const nsACString& aUTF8String)
     { return NS_NewAtom(aUTF8String); }
 
 /**
  * Find an atom that matches the given UTF-16 string.
  * The string is assumed to be zero terminated.
  */
 extern NS_COM nsIAtom* NS_NewAtom(const PRUnichar* aUTF16String);
 inline already_AddRefed<nsIAtom> do_GetAtom(const PRUnichar* aUTF16String)
     { return NS_NewAtom(aUTF16String); }
 
 /**
  * Find an atom that matches the given UTF-16 string.
  */
 extern NS_COM nsIAtom* NS_NewAtom(const nsAString& aUTF16String);
+extern NS_COM nsIAtom* NS_NewPermanentAtom(const nsAString& aUTF16String);
 inline already_AddRefed<nsIAtom> do_GetAtom(const nsAString& aUTF16String)
     { return NS_NewAtom(aUTF16String); }
 
 /**
  * Return a count of the total number of atoms currently
  * alive in the system.
  */
 extern NS_COM nsrefcnt NS_GetNumberOfAtoms(void);
@@ -154,9 +162,36 @@ extern NS_COM nsrefcnt NS_GetNumberOfAto
  */
 extern NS_COM nsIAtom* NS_GetStaticAtom(const nsAString& aUTF16String);
 
 /**
  * Seal the static atom table
  */
 extern NS_COM void NS_SealStaticAtomTable();
 
+class nsAtomString : public nsString
+{
+public:
+  nsAtomString(nsIAtom* aAtom)
+  {
+    aAtom->ToString(*this);
+  }
+};
+
+class nsAtomCString : public nsCString
+{
+public:
+  nsAtomCString(nsIAtom* aAtom)
+  {
+    aAtom->ToUTF8String(*this);
+  }
+};
+
+class nsDependentAtomString : public nsDependentString
+{
+public:
+  nsDependentAtomString(nsIAtom* aAtom)
+    : nsDependentString(aAtom->GetUTF16String(), aAtom->GetLength())
+  {
+  }
+};
+
 %}
--- a/xpcom/ds/nsStaticAtom.h
+++ b/xpcom/ds/nsStaticAtom.h
@@ -38,18 +38,28 @@
 
 #ifndef nsStaticAtom_h__
 #define nsStaticAtom_h__
 
 #include "nsIAtom.h"
 #include "nsStringBuffer.h"
 #include "prlog.h"
 
+#if defined(HAVE_CPP_CHAR16_T)
+#define NS_STATIC_ATOM_USE_WIDE_STRINGS
+typedef char16_t nsStaticAtomStringType;
+#elif defined(HAVE_CPP_2BYTE_WCHAR_T)
+#define NS_STATIC_ATOM_USE_WIDE_STRINGS
+typedef wchar_t nsStaticAtomStringType;
+#else
+typedef char nsStaticAtomStringType;
+#endif
+
 #define NS_STATIC_ATOM(buffer_name, atom_ptr)  { (nsStringBuffer*) &buffer_name, atom_ptr }
-#define NS_STATIC_ATOM_BUFFER(buffer_name, str_data) static nsFakeStringBuffer< sizeof(str_data) > buffer_name = { 1, sizeof(str_data), str_data };
+#define NS_STATIC_ATOM_BUFFER(buffer_name, str_data) static nsFakeStringBuffer< sizeof(str_data) > buffer_name = { 1, sizeof(str_data) * sizeof(nsStaticAtomStringType), NS_L(str_data) };
 
 /**
  * Holds data used to initialize large number of atoms during startup. Use
  * the above macros to initialize these structs. They should never be accessed
  * directly other than from AtomTable.cpp
  */
 struct nsStaticAtom {
     nsStringBuffer* mStringBuffer;
@@ -58,17 +68,16 @@ struct nsStaticAtom {
 
 /**
  * This is a struct with the same binary layout as a nsStringBuffer.
  */
 template <PRUint32 size>
 struct nsFakeStringBuffer {
     PRInt32 mRefCnt;
     PRUint32 mSize;
-    char mStringData[size];
+    nsStaticAtomStringType mStringData[size];
 };
 
-// register your lookup function with the atom table. Your function
-// will be called when at atom is not found in the main atom table.
+// Register static atoms with the atom table
 NS_COM nsresult
 NS_RegisterStaticAtoms(const nsStaticAtom*, PRUint32 aAtomCount);
 
 #endif
--- a/xpcom/tests/TestAtoms.cpp
+++ b/xpcom/tests/TestAtoms.cpp
@@ -76,19 +76,19 @@ int main(int argc, char** argv)
     ids[i] = NS_NewAtom(strings[i]);
   }
   PRUnichar qqs[1]; qqs[0] = 0;
   nsIAtom* qq = NS_NewAtom(qqs);
   PRTime end1 = PR_Now();
 
   // Now make sure we can find all the idents we just made
   for (i = 0; i < count; i++) {
-    const char *utf8String;
-    ids[i]->GetUTF8String(&utf8String);
-    nsIAtom* id = NS_NewAtom(utf8String);
+    const PRUnichar *utf16String;
+    ids[i]->GetUTF16String(&utf16String);
+    nsIAtom* id = NS_NewAtom(utf16String);
     if (id != ids[i]) {
       id->ToString(s1);
       ids[i]->ToString(s2);
       printf("find failed: id='%s' ids[%d]='%s'\n",
              NS_LossyConvertUTF16toASCII(s1).get(), i, NS_LossyConvertUTF16toASCII(s2).get());
       return -1;
     }
     NS_RELEASE(id);
--- a/xpcom/tests/TestPermanentAtoms.cpp
+++ b/xpcom/tests/TestPermanentAtoms.cpp
@@ -46,40 +46,38 @@
 
 static void Assert(PRBool aCondition, const char* aStatement)
 {
     printf("%s: %s\n", aCondition?"PASS":"FAIL", aStatement);
 }
 
 static void AssertString(nsIAtom *aAtom, const nsACString& aString)
 {
-    const char *str;
-    static_cast<AtomImpl*>(aAtom)->GetUTF8String(&str);
-    Assert(nsDependentCString(str) == aString, "string is correct");
+    Assert(aAtom->EqualsUTF8(aString), "string is correct");
 }
 
 static void AssertPermanence(nsIAtom *aAtom, PRBool aPermanence)
 {
     Assert(static_cast<AtomImpl*>(aAtom)->IsPermanent() == aPermanence,
            aPermanence ? "atom is permanent" : "atom is not permanent");
 }
 
 int main()
 {
     nsCOMPtr<nsIAtom> foo = do_GetAtom("foo");
     AssertString(foo, NS_LITERAL_CSTRING("foo"));
     AssertPermanence(foo, PR_FALSE);
 
-    nsCOMPtr<nsIAtom> foop = do_GetPermanentAtom("foo");
+    nsCOMPtr<nsIAtom> foop = NS_NewPermanentAtom(NS_LITERAL_STRING("foo"));
     AssertString(foop, NS_LITERAL_CSTRING("foo"));
     AssertPermanence(foop, PR_TRUE);
     
     Assert(foo == foop, "atoms are equal");
     
-    nsCOMPtr<nsIAtom> barp = do_GetPermanentAtom("bar");
+    nsCOMPtr<nsIAtom> barp = NS_NewPermanentAtom(NS_LITERAL_STRING("bar"));
     AssertString(barp, NS_LITERAL_CSTRING("bar"));
     AssertPermanence(barp, PR_TRUE);
     
     nsCOMPtr<nsIAtom> bar = do_GetAtom("bar");
     AssertString(bar, NS_LITERAL_CSTRING("bar"));
     AssertPermanence(bar, PR_TRUE);
 
     Assert(bar == barp, "atoms are equal");
--- a/xpcom/tests/TestUTF.cpp
+++ b/xpcom/tests/TestUTF.cpp
@@ -135,32 +135,59 @@ test_malformed8()
 
     if (CompareUTF8toUTF16(str8, EmptyString()) == 0)
       return PR_FALSE;
   }
   
   return PR_TRUE;
 }
 
+PRBool
+test_hashas16()
+{
+  for (unsigned int i = 0; i < NS_ARRAY_LENGTH(ValidStrings); ++i) {
+    nsDependentCString str8(ValidStrings[i].m8);
+    if (nsCRT::HashCode(ValidStrings[i].m16) !=
+        nsCRT::HashCodeAsUTF16(str8.get(), str8.Length()))
+      return PR_FALSE;
+  }
+
+  for (unsigned int i = 0; i < NS_ARRAY_LENGTH(Invalid8Strings); ++i) {
+    nsDependentCString str8(Invalid8Strings[i].m8);
+    if (nsCRT::HashCode(Invalid8Strings[i].m16) !=
+        nsCRT::HashCodeAsUTF16(str8.get(), str8.Length()))
+      return PR_FALSE;
+  }
+
+  for (unsigned int i = 0; i < NS_ARRAY_LENGTH(Malformed8Strings); ++i) {
+    nsDependentCString str8(Malformed8Strings[i]);
+    if (nsCRT::HashCodeAsUTF16(str8.get(), str8.Length()) != 0)
+      return PR_FALSE;
+  }
+
+  return PR_TRUE;
+}
+
 typedef PRBool (*TestFunc)();
 
 static const struct Test
   {
     const char* name;
     TestFunc    func;
   }
 tests[] =
   {
     { "test_valid", test_valid },
     { "test_invalid16", test_invalid16 },
     { "test_invalid8", test_invalid8 },
 #ifndef DEBUG
     // Don't run this test in debug builds as that intentionally asserts
     { "test_malformed8", test_malformed8 },
 #endif
+    { "test_hashas16", test_hashas16 },
     { nsnull, nsnull }
   };
 
 }
 
 using namespace TestUTF;
 
 int main(int argc, char **argv)