Merge m-i to m-c.
authorKyle Huey <khuey@kylehuey.com>
Tue, 01 Nov 2011 10:31:53 -0400
changeset 79519 cd9add22f090445f1d73e999aaa4c0050b8e4e16
parent 79472 6e219763ddd0f9519f7b2a99c52694507f89b043 (current diff)
parent 79518 d9cc2539a85dfbdd9b27b94731e77b0cba6e23ae (diff)
child 79520 978002c0b0ad34190bfef375d6fb70be834a085d
child 79530 84d20e63f8bdd17fbc639f204577bc6d84499148
push id21408
push userkhuey@mozilla.com
push dateTue, 01 Nov 2011 14:32:20 +0000
treeherdermozilla-central@cd9add22f090 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone10.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-i to m-c.
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -734,42 +734,66 @@ user_pref("camino.use_system_proxy_setti
         # and re-raise any others
         if err.errno == errno.ESRCH or err.errno == errno.ECHILD:
           return False
         raise
 
     def killPid(self, pid):
       os.kill(pid, signal.SIGKILL)
 
-  if UNIXISH:
     def dumpScreen(self, utilityPath):
       self.haveDumpedScreen = True;
 
-      screentopng = os.path.join(utilityPath, "screentopng")
+      # Need to figure out what tool and whether it write to a file or stdout
+      if UNIXISH:
+        utility = [os.path.join(utilityPath, "screentopng")]
+        imgoutput = 'stdout'
+      elif IS_MAC:
+        utility = ['/usr/sbin/screencapture', '-C', '-x', '-t', 'png']
+        imgoutput = 'file'
+      elif IS_WIN32:
+        self.log.info("If you fixed bug 589668, you'd get a screenshot here")
+        return
+
+      # Run the capture correctly for the type of capture
       try:
-        dumper = self.Process([screentopng], bufsize=-1,
-                              stdout=subprocess.PIPE, close_fds=True)
+        if imgoutput == 'file':
+          tmpfd, imgfilename = tempfile.mkstemp(prefix='mozilla-test-fail_')
+          os.close(tmpfd)
+          dumper = self.Process(utility + [imgfilename])
+        elif imgoutput == 'stdout':
+          dumper = self.Process(utility, bufsize=-1,
+                                stdout=subprocess.PIPE, close_fds=True)
       except OSError, err:
         self.log.info("Failed to start %s for screenshot: %s",
-                      screentopng, err.strerror)
+                      utility[0], err.strerror)
+        return
+
+      # Check whether the capture utility ran successfully
+      dumper_out, dumper_err = dumper.communicate()
+      if dumper.returncode != 0:
+        self.log.info("%s exited with code %d", utility, dumper.returncode)
         return
 
-      image = dumper.stdout.read()
-      status = dumper.wait()
-      if status != 0:
-        self.log.info("screentopng exited with code %d", status)
-        return
+      try:
+        if imgoutput == 'stdout':
+          image = dumper_out
+        elif imgoutput == 'file':
+          with open(imgfilename) as imgfile:
+            image = imgfile.read()
+      except IOError, err:
+          self.log.info("Failed to read image from %s", imgoutput)
 
       import base64
       encoded = base64.b64encode(image)
       self.log.info("SCREENSHOT: data:image/png;base64,%s", encoded)
 
   def killAndGetStack(self, proc, utilityPath, debuggerInfo):
     """Kill the process, preferrably in a way that gets us a stack trace."""
-    if self.UNIXISH and not debuggerInfo and not self.haveDumpedScreen:
+    if not debuggerInfo and not self.haveDumpedScreen:
       self.dumpScreen(utilityPath)
 
     if self.CRASHREPORTER and not debuggerInfo:
       if self.UNIXISH:
         # ABRT will get picked up by Breakpad's signal handler
         os.kill(proc.pid, signal.SIGABRT)
         return
       elif self.IS_WIN32:
@@ -815,17 +839,17 @@ user_pref("camino.use_system_proxy_setti
 
       (line, didTimeout) = self.readWithTimeout(logsource, timeout)
       while line != "" and not didTimeout:
         if "TEST-START" in line and "|" in line:
           self.lastTestSeen = line.split("|")[1].strip()
         if stackFixerFunction:
           line = stackFixerFunction(line)
         self.log.info(line.rstrip().decode("UTF-8", "ignore"))
-        if self.UNIXISH and not debuggerInfo and not self.haveDumpedScreen and "TEST-UNEXPECTED-FAIL" in line and "Test timed out" in line:
+        if not debuggerInfo and not self.haveDumpedScreen and "TEST-UNEXPECTED-FAIL" in line and "Test timed out" in line:
           self.dumpScreen(utilityPath)
 
         (line, didTimeout) = self.readWithTimeout(logsource, timeout)
         if not hitMaxTime and maxTime and datetime.now() - startTime > timedelta(seconds = maxTime):
           # Kill the application, but continue reading from stack fixer so as not to deadlock on stackFixerProcess.wait().
           hitMaxTime = True
           self.log.info("TEST-UNEXPECTED-FAIL | %s | application ran for longer than allowed maximum time of %d seconds", self.lastTestSeen, int(maxTime))
           self.killAndGetStack(proc, utilityPath, debuggerInfo)
--- a/configure.in
+++ b/configure.in
@@ -2249,20 +2249,17 @@ case "$target" in
     esac
     ;;
 
 *-darwin*)
     MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@'
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@'
     MOZ_OPTIMIZE_FLAGS="-O3"
     _PEDANTIC=
-    # Due to performance regressions, statically disable jemalloc on 10.5. See bug 414946.
-    if test "$HAVE_64BIT_OS"; then
-        MOZ_MEMORY=1
-    fi
+    MOZ_MEMORY=1
     CFLAGS="$CFLAGS -fno-common"
     CXXFLAGS="$CXXFLAGS -fno-common"
     DLL_SUFFIX=".dylib"
     DSO_LDOPTS=''
     STRIP="$STRIP -x -S"
     # Check whether we're targeting OS X or iOS
     AC_CACHE_CHECK(for iOS target,
                    ac_cv_ios_target,
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -754,16 +754,17 @@ public:
   enum PropertiesFile {
     eCSS_PROPERTIES,
     eXBL_PROPERTIES,
     eXUL_PROPERTIES,
     eLAYOUT_PROPERTIES,
     eFORMS_PROPERTIES,
     ePRINTING_PROPERTIES,
     eDOM_PROPERTIES,
+    eHTMLPARSER_PROPERTIES,
     eSVG_PROPERTIES,
     eBRAND_PROPERTIES,
     eCOMMON_DIALOG_PROPERTIES,
     PropertiesFile_COUNT
   };
   static nsresult ReportToConsole(PropertiesFile aFile,
                                   const char *aMessageName,
                                   const PRUnichar **aParams,
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -121,18 +121,18 @@ class Loader;
 
 namespace dom {
 class Link;
 class Element;
 } // namespace dom
 } // namespace mozilla
 
 #define NS_IDOCUMENT_IID \
-{ 0x3d24831e, 0x2a2b, 0x42f4, \
-  { 0x9d, 0x98, 0x17, 0x60, 0x18, 0xab, 0x6e, 0xfb } }
+{ 0xc3e40e8e, 0x8b91, 0x424c, \
+  { 0xbe, 0x9c, 0x9c, 0xc1, 0x76, 0xa7, 0xf7, 0x24 } }
 
 // Flag for AddStyleSheet().
 #define NS_STYLESHEET_FROM_CATALOG                (1 << 0)
 
 // Document states
 
 // RTL locale: specific to the XUL localedir attribute
 #define NS_DOCUMENT_STATE_RTL_LOCALE              NS_DEFINE_EVENT_STATE_MACRO(0)
@@ -732,48 +732,36 @@ public:
    * Add/Remove an element to the document's id and name hashes
    */
   virtual void AddToIdTable(Element* aElement, nsIAtom* aId) = 0;
   virtual void RemoveFromIdTable(Element* aElement, nsIAtom* aId) = 0;
   virtual void AddToNameTable(Element* aElement, nsIAtom* aName) = 0;
   virtual void RemoveFromNameTable(Element* aElement, nsIAtom* aName) = 0;
 
   /**
-   * Resets the current full-screen element to nsnull.
-   */
-  virtual void ResetFullScreenElement() = 0;
-
-  /**
-   * Returns the element which either is the full-screen element, or
-   * contains the full-screen element if a child of this document contains
-   * the fullscreen element.
+   * Returns the element which either requested DOM full-screen mode, or
+   * contains the element which requested DOM full-screen mode if the
+   * requestee is in a subdocument. Note this element must be *in*
+   * this document.
    */
   virtual Element* GetFullScreenElement() = 0;
 
   /**
    * Requests that the document make aElement the full-screen element,
    * and move into full-screen mode.
    */
   virtual void RequestFullScreen(Element* aElement) = 0;
 
   /**
    * Requests that the document, and all documents in its hierarchy exit
    * from DOM full-screen mode.
    */
   virtual void CancelFullScreen() = 0;
 
   /**
-   * Updates the full-screen status on this document, setting the full-screen
-   * mode to aIsFullScreen. This doesn't affect the window's full-screen mode,
-   * this updates the document's internal state which determines whether the
-   * document reports as being in full-screen mode.
-   */
-  virtual void UpdateFullScreenStatus(bool aIsFullScreen) = 0;
-
-  /**
    * Returns true if this document is in full-screen mode.
    */
   virtual bool IsFullScreenDoc() = 0;
 
   //----------------------------------------------------------------------
 
   // Document notification API's
 
@@ -1506,16 +1494,23 @@ public:
    * This method is similar to GetElementById() from nsIDOMDocument but it
    * returns a mozilla::dom::Element instead of a nsIDOMElement.
    * It prevents converting nsIDOMElement to mozill:dom::Element which is
    * already converted from mozilla::dom::Element.
    */
   virtual Element* GetElementById(const nsAString& aElementId) = 0;
 
   /**
+   * This method returns _all_ the elements in this document which
+   * have id aElementId, if there are any.  Otherwise it returns null.
+   * The entries of the nsSmallVoidArray are Element*
+   */
+  virtual const nsSmallVoidArray* GetAllElementsForId(const nsAString& aElementId) const = 0;
+
+  /**
    * Lookup an image element using its associated ID, which is usually provided
    * by |-moz-element()|. Similar to GetElementById, with the difference that
    * elements set using mozSetImageElement have higher priority.
    * @param aId the ID associated the element we want to lookup
    * @return the element associated with |aId|
    */
   virtual Element* LookupImageElement(const nsAString& aElementId) = 0;
 
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -63,30 +63,29 @@
 #include "nsIContentIterator.h"
 nsresult
 NS_NewPreContentIterator(nsIContentIterator** aInstancePtrResult);
 #define ASSERT_IN_SYNC AssertInSync()
 #else
 #define ASSERT_IN_SYNC PR_BEGIN_MACRO PR_END_MACRO
 #endif
 
-
 using namespace mozilla::dom;
 
 nsBaseContentList::~nsBaseContentList()
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsBaseContentList)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsBaseContentList)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mElements)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mElements)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBaseContentList)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mElements)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mElements)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsBaseContentList)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 #define NS_CONTENT_LIST_INTERFACES(_class)                                    \
     NS_INTERFACE_TABLE_ENTRY(_class, nsINodeList)                             \
@@ -108,17 +107,17 @@ NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsBaseContentList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsBaseContentList)
 
 
 NS_IMETHODIMP
 nsBaseContentList::GetLength(PRUint32* aLength)
 {
-  *aLength = mElements.Count();
+  *aLength = mElements.Length();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsBaseContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
 {
   nsISupports *tmp = GetNodeAt(aIndex);
@@ -130,49 +129,32 @@ nsBaseContentList::Item(PRUint32 aIndex,
   }
 
   return CallQueryInterface(tmp, aReturn);
 }
 
 nsIContent*
 nsBaseContentList::GetNodeAt(PRUint32 aIndex)
 {
-  return mElements.SafeObjectAt(aIndex);
+  return mElements.SafeElementAt(aIndex);
 }
 
 
 PRInt32
 nsBaseContentList::IndexOf(nsIContent *aContent, bool aDoFlush)
 {
   return mElements.IndexOf(aContent);
 }
 
 PRInt32
 nsBaseContentList::IndexOf(nsIContent* aContent)
 {
   return IndexOf(aContent, true);
 }
 
-void nsBaseContentList::AppendElement(nsIContent *aContent) 
-{
-  mElements.AppendObject(aContent);
-}
-
-void nsBaseContentList::RemoveElement(nsIContent *aContent) 
-{
-  mElements.RemoveObject(aContent);
-}
-
-void nsBaseContentList::InsertElementAt(nsIContent* aContent, PRInt32 aIndex)
-{
-  NS_ASSERTION(aContent, "Element to insert must not be null");
-  mElements.InsertObjectAt(aContent, aIndex);
-}
-
-
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsSimpleContentList)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsSimpleContentList,
                                                   nsBaseContentList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsSimpleContentList,
                                                 nsBaseContentList)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRoot)
@@ -528,17 +510,17 @@ NS_INTERFACE_MAP_END_INHERITING(nsBaseCo
 NS_IMPL_ADDREF_INHERITED(nsContentList, nsBaseContentList)
 NS_IMPL_RELEASE_INHERITED(nsContentList, nsBaseContentList)
 
 PRUint32
 nsContentList::Length(bool aDoFlush)
 {
   BringSelfUpToDate(aDoFlush);
     
-  return mElements.Count();
+  return mElements.Length();
 }
 
 nsIContent *
 nsContentList::Item(PRUint32 aIndex, bool aDoFlush)
 {
   if (mRootNode && aDoFlush && mFlushesNeeded) {
     // XXX sXBL/XBL2 issue
     nsIDocument* doc = mRootNode->GetCurrentDoc();
@@ -550,25 +532,25 @@ nsContentList::Item(PRUint32 aIndex, boo
 
   if (mState != LIST_UP_TO_DATE)
     PopulateSelf(NS_MIN(aIndex, PR_UINT32_MAX - 1) + 1);
 
   ASSERT_IN_SYNC;
   NS_ASSERTION(!mRootNode || mState != LIST_DIRTY,
                "PopulateSelf left the list in a dirty (useless) state!");
 
-  return mElements.SafeObjectAt(aIndex);
+  return mElements.SafeElementAt(aIndex);
 }
 
 nsIContent *
 nsContentList::NamedItem(const nsAString& aName, bool aDoFlush)
 {
   BringSelfUpToDate(aDoFlush);
     
-  PRInt32 i, count = mElements.Count();
+  PRUint32 i, count = mElements.Length();
 
   // Typically IDs and names are atomized
   nsCOMPtr<nsIAtom> name = do_GetAtom(aName);
   NS_ENSURE_TRUE(name, nsnull);
 
   for (i = 0; i < count; i++) {
     nsIContent *content = mElements[i];
     // XXX Should this pass eIgnoreCase?
@@ -672,28 +654,28 @@ nsContentList::AttributeChanged(nsIDocum
       !MayContainRelevantNodes(aElement->GetNodeParent()) ||
       !nsContentUtils::IsInSameAnonymousTree(mRootNode, aElement)) {
     // Either we're already dirty or this notification doesn't affect
     // whether we might match aElement.
     return;
   }
   
   if (Match(aElement)) {
-    if (mElements.IndexOf(aElement) == -1) {
+    if (mElements.IndexOf(aElement) == mElements.NoIndex) {
       // We match aElement now, and it's not in our list already.  Just dirty
       // ourselves; this is simpler than trying to figure out where to insert
       // aElement.
       SetDirty();
     }
   } else {
     // We no longer match aElement.  Remove it from our list.  If it's
     // already not there, this is a no-op (though a potentially
     // expensive one).  Either way, no change of mState is required
     // here.
-    mElements.RemoveObject(aElement);
+    mElements.RemoveElement(aElement);
   }
 }
 
 void
 nsContentList::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer,
                                nsIContent* aFirstNewContent,
                                PRInt32 aNewIndexInContainer)
 {
@@ -717,17 +699,17 @@ nsContentList::ContentAppended(nsIDocume
    * should come during pageload and be at the end of the document.
    * Do a bit of work to see whether we could just append to what we
    * already have.
    */
   
   PRInt32 count = aContainer->GetChildCount();
 
   if (count > 0) {
-    PRInt32 ourCount = mElements.Count();
+    PRUint32 ourCount = mElements.Length();
     bool appendToList = false;
     if (ourCount == 0) {
       appendToList = true;
     } else {
       nsIContent* ourLastContent = mElements[ourCount - 1];
       /*
        * We want to append instead of invalidating if the first thing
        * that got appended comes after ourLastContent.
@@ -767,23 +749,23 @@ nsContentList::ContentAppended(nsIDocume
      * We're up to date.  That means someone's actively using us; we
      * may as well grab this content....
      */
     if (mDeep) {
       for (nsIContent* cur = aFirstNewContent;
            cur;
            cur = cur->GetNextNode(aContainer)) {
         if (cur->IsElement() && Match(cur->AsElement())) {
-          mElements.AppendObject(cur);
+          mElements.AppendElement(cur);
         }
       }
     } else {
       for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
         if (cur->IsElement() && Match(cur->AsElement())) {
-          mElements.AppendObject(cur);
+          mElements.AppendElement(cur);
         }
       }
     }
 
     ASSERT_IN_SYNC;
   }
 }
 
@@ -896,54 +878,55 @@ void
 nsContentList::PopulateSelf(PRUint32 aNeededLength)
 {
   if (!mRootNode) {
     return;
   }
 
   ASSERT_IN_SYNC;
 
-  PRUint32 count = mElements.Count();
+  PRUint32 count = mElements.Length();
   NS_ASSERTION(mState != LIST_DIRTY || count == 0,
                "Reset() not called when setting state to LIST_DIRTY?");
 
   if (count >= aNeededLength) // We're all set
     return;
 
   PRUint32 elementsToAppend = aNeededLength - count;
 #ifdef DEBUG
-  PRUint32 invariant = elementsToAppend + mElements.Count();
+  PRUint32 invariant = elementsToAppend + mElements.Length();
 #endif
 
   if (mDeep) {
     // If we already have nodes start searching at the last one, otherwise
     // start searching at the root.
     nsINode* cur = count ? mElements[count - 1] : mRootNode;
     do {
       cur = cur->GetNextNode(mRootNode);
       if (!cur) {
         break;
       }
       if (cur->IsElement() && Match(cur->AsElement())) {
-        mElements.AppendObject(cur->AsElement());
+        // Append AsElement() to get nsIContent instead of nsINode
+        mElements.AppendElement(cur->AsElement());
         --elementsToAppend;
       }
     } while (elementsToAppend);
   } else {
     nsIContent* cur =
       count ? mElements[count-1]->GetNextSibling() : mRootNode->GetFirstChild();
     for ( ; cur && elementsToAppend; cur = cur->GetNextSibling()) {
       if (cur->IsElement() && Match(cur->AsElement())) {
-        mElements.AppendObject(cur);
+        mElements.AppendElement(cur);
         --elementsToAppend;
       }
     }
   }
 
-  NS_ASSERTION(elementsToAppend + mElements.Count() == invariant,
+  NS_ASSERTION(elementsToAppend + mElements.Length() == invariant,
                "Something is awry!");
 
   if (elementsToAppend != 0)
     mState = LIST_UP_TO_DATE;
   else
     mState = LIST_LAZY;
 
   ASSERT_IN_SYNC;
@@ -1019,17 +1002,17 @@ nsCacheableFuncStringContentList::Remove
 void
 nsContentList::AssertInSync()
 {
   if (mState == LIST_DIRTY) {
     return;
   }
 
   if (!mRootNode) {
-    NS_ASSERTION(mElements.Count() == 0 && mState == LIST_DIRTY,
+    NS_ASSERTION(mElements.Length() == 0 && mState == LIST_DIRTY,
                  "Empty iterator isn't quite empty?");
     return;
   }
 
   // XXX This code will need to change if nsContentLists can ever match
   // elements that are outside of the document element.
   nsIContent *root;
   if (mRootNode->IsNodeOfType(nsINode::eDOCUMENT)) {
@@ -1041,34 +1024,34 @@ nsContentList::AssertInSync()
 
   nsCOMPtr<nsIContentIterator> iter;
   if (mDeep) {
     NS_NewPreContentIterator(getter_AddRefs(iter));
     iter->Init(root);
     iter->First();
   }
 
-  PRInt32 cnt = 0, index = 0;
+  PRUint32 cnt = 0, index = 0;
   while (true) {
-    if (cnt == mElements.Count() && mState == LIST_LAZY) {
+    if (cnt == mElements.Length() && mState == LIST_LAZY) {
       break;
     }
 
     nsIContent *cur = mDeep ? iter->GetCurrentNode() :
                               mRootNode->GetChildAt(index++);
     if (!cur) {
       break;
     }
 
     if (cur->IsElement() && Match(cur->AsElement())) {
-      NS_ASSERTION(cnt < mElements.Count() && mElements[cnt] == cur,
+      NS_ASSERTION(cnt < mElements.Length() && mElements[cnt] == cur,
                    "Elements is out of sync");
       ++cnt;
     }
 
     if (mDeep) {
       iter->Next();
     }
   }
 
-  NS_ASSERTION(cnt == mElements.Count(), "Too few elements");
+  NS_ASSERTION(cnt == mElements.Length(), "Too few elements");
 }
 #endif
--- a/content/base/src/nsContentList.h
+++ b/content/base/src/nsContentList.h
@@ -40,17 +40,17 @@
  * is a commonly used NodeList implementation (used for
  * getElementsByTagName, some properties on nsIDOMHTMLDocument, etc).
  */
 
 #ifndef nsContentList_h___
 #define nsContentList_h___
 
 #include "nsISupports.h"
-#include "nsCOMArray.h"
+#include "nsTArray.h"
 #include "nsString.h"
 #include "nsIHTMLCollection.h"
 #include "nsIDOMNodeList.h"
 #include "nsINodeList.h"
 #include "nsStubMutationObserver.h"
 #include "nsIAtom.h"
 #include "nsINameSpaceManager.h"
 #include "nsCycleCollectionParticipant.h"
@@ -95,49 +95,59 @@ public:
 
   // nsIDOMNodeList
   NS_DECL_NSIDOMNODELIST
 
   // nsINodeList
   virtual PRInt32 IndexOf(nsIContent* aContent);
   
   PRUint32 Length() const { 
-    return mElements.Count();
+    return mElements.Length();
   }
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsBaseContentList)
 
-  void AppendElement(nsIContent *aContent);
+  void AppendElement(nsIContent *aContent)
+  {
+    mElements.AppendElement(aContent);
+  }
   void MaybeAppendElement(nsIContent* aContent)
   {
     if (aContent)
       AppendElement(aContent);
   }
 
   /**
    * Insert the element at a given index, shifting the objects at
    * the given index and later to make space.
    * @param aContent Element to insert, must not be null
    * @param aIndex Index to insert the element at.
    */
-  void InsertElementAt(nsIContent* aContent, PRInt32 aIndex);
+  void InsertElementAt(nsIContent* aContent, PRInt32 aIndex)
+  {
+    NS_ASSERTION(aContent, "Element to insert must not be null");
+    mElements.InsertElementAt(aIndex, aContent);
+  }
 
-  void RemoveElement(nsIContent *aContent); 
+  void RemoveElement(nsIContent *aContent)
+  {
+    mElements.RemoveElement(aContent);
+  }
 
   void Reset() {
     mElements.Clear();
   }
 
   virtual PRInt32 IndexOf(nsIContent *aContent, bool aDoFlush);
 
   virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
                                bool *triedToWrap) = 0;
 
 protected:
-  nsCOMArray<nsIContent> mElements;
+  nsTArray< nsCOMPtr<nsIContent> > mElements;
 };
 
 
 class nsSimpleContentList : public nsBaseContentList
 {
 public:
   nsSimpleContentList(nsINode *aRoot) : nsBaseContentList(),
                                         mRoot(aRoot)
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -2703,16 +2703,17 @@ static const char gPropertiesFiles[nsCon
   // Must line up with the enum values in |PropertiesFile| enum.
   "chrome://global/locale/css.properties",
   "chrome://global/locale/xbl.properties",
   "chrome://global/locale/xul.properties",
   "chrome://global/locale/layout_errors.properties",
   "chrome://global/locale/layout/HtmlForm.properties",
   "chrome://global/locale/printing.properties",
   "chrome://global/locale/dom/dom.properties",
+  "chrome://global/locale/layout/htmlparser.properties",
   "chrome://global/locale/svg/svg.properties",
   "chrome://branding/locale/brand.properties",
   "chrome://global/locale/commonDialogs.properties"
 };
 
 /* static */ nsresult
 nsContentUtils::EnsureStringBundle(PropertiesFile aFile)
 {
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -209,16 +209,17 @@
 #include "imgILoader.h"
 #include "nsWrapperCacheInlines.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 typedef nsTArray<Link*> LinkArray;
 
+nsWeakPtr nsDocument::sFullScreenDoc = nsnull;
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gDocumentLeakPRLog;
 static PRLogModuleInfo* gCspPRLog;
 #endif
 
 #define NAME_NOT_VALID ((nsSimpleContentList*)1)
 
@@ -4031,16 +4032,27 @@ nsDocument::GetElementById(const nsAStri
   if (!CheckGetElementByIdArg(aElementId)) {
     return nsnull;
   }
 
   nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId);
   return entry ? entry->GetIdElement() : nsnull;
 }
 
+const nsSmallVoidArray*
+nsDocument::GetAllElementsForId(const nsAString& aElementId) const
+{
+  if (aElementId.IsEmpty()) {
+    return nsnull;
+  }
+
+  nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId);
+  return entry ? entry->GetIdElements() : nsnull;  
+}
+
 NS_IMETHODIMP
 nsDocument::GetElementById(const nsAString& aId, nsIDOMElement** aReturn)
 {
   Element *content = GetElementById(aId);
   if (content) {
     return CallQueryInterface(content, aReturn);
   }
 
@@ -5995,17 +6007,17 @@ nsDocument::AdoptNode(nsIDOMNode *aAdopt
   NS_ENSURE_ARG(aAdoptedNode);
 
   *aResult = nsnull;
 
   nsresult rv = nsContentUtils::CheckSameOrigin(this, aAdoptedNode);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsINode> adoptedNode = do_QueryInterface(aAdoptedNode);
-  
+
   // Scope firing mutation events so that we don't carry any state that
   // might be stale
   {
     nsINode* parent = adoptedNode->GetNodeParent();
     if (parent) {
       nsContentUtils::MaybeFireNodeRemoved(adoptedNode, parent,
                                            adoptedNode->OwnerDoc());
     }
@@ -8342,227 +8354,263 @@ nsIDocument::SizeOf() const
   for (nsIContent* node = GetFirstChild(); node;
        node = node->GetNextNode(this)) {
     size += node->SizeOf();
   }
 
   return size;
 }
 
-// Returns the root document in a document hierarchy.
-static nsIDocument*
-GetRootDocument(nsIDocument* aDoc)
-{
-  if (!aDoc) {
-    return nsnull;
-  }
-  nsCOMPtr<nsIPresShell> shell = aDoc->GetShell();
-  if (!shell) {
-    return nsnull;
-  }
-  nsPresContext* ctx = shell->GetPresContext();
-  if (!ctx) {
-    return nsnull;
-  }
-  nsRootPresContext* rpc = ctx->GetRootPresContext();
-  if (!rpc) {
-    return nsnull;
-  }
-  return rpc->Document();
-}
-
 class nsDispatchFullScreenChange : public nsRunnable
 {
 public:
-  nsDispatchFullScreenChange(nsIDocument *aDoc)
-    : mDoc(aDoc)
-  {
-    mTarget = aDoc->GetFullScreenElement();
-    if (!mTarget) {
-      mTarget = aDoc;
-    }
-  }
+  nsDispatchFullScreenChange(nsIDocument *aDoc, nsINode* aElement)
+    : mDoc(aDoc),
+      mTarget(aElement ? aElement : aDoc) {}
 
   NS_IMETHOD Run()
   {
     nsContentUtils::DispatchTrustedEvent(mDoc,
                                          mTarget,
                                          NS_LITERAL_STRING("mozfullscreenchange"),
                                          true,
                                          false);
     return NS_OK;
   }
 
   nsCOMPtr<nsIDocument> mDoc;
   nsCOMPtr<nsISupports> mTarget;
 };
 
-void
-nsDocument::UpdateFullScreenStatus(bool aIsFullScreen)
-{
-  if (mIsFullScreen != aIsFullScreen) {
-    nsCOMPtr<nsIRunnable> event(new nsDispatchFullScreenChange(this));
-    NS_DispatchToCurrentThread(event);
+static void DispatchFullScreenChange(nsIDocument* aDocument, Element* aElement)
+{
+  nsCOMPtr<nsIRunnable> event(
+    new nsDispatchFullScreenChange(aDocument, aElement));
+  NS_DispatchToCurrentThread(event);
+}
+
+bool
+nsDocument::SetFullScreenState(Element* aElement, bool aIsFullScreen)
+{
+  if (mFullScreenElement) {
+    // Reset the ancestor and full-screen styles on the outgoing full-screen
+    // element in the current document.
+    nsEventStateManager::SetFullScreenState(mFullScreenElement, false);
+    mFullScreenElement = nsnull;
+  }
+  if (aElement) {
+    nsEventStateManager::SetFullScreenState(aElement, aIsFullScreen);
+  }
+  mFullScreenElement = aElement;
+
+  if (mIsFullScreen == aIsFullScreen) {
+    return false;
   }
   mIsFullScreen = aIsFullScreen;
-  if (!mIsFullScreen) {
-    // Full-screen is being turned off. Reset the full-screen element, to
-    // save us from having to traverse the document hierarchy again in
-    // MozCancelFullScreen().
-    ResetFullScreenElement();
-  }
-}
-
+  return true;
+}
+
+// Wrapper for the nsIDocument -> nsDocument cast required to call
+// nsDocument::SetFullScreenState().
 static bool
-UpdateFullScreenStatus(nsIDocument* aDocument, void* aData)
-{
-  aDocument->UpdateFullScreenStatus(*static_cast<bool*>(aData));
-  aDocument->EnumerateSubDocuments(UpdateFullScreenStatus, aData);
-  return true;
-}
-
-static void
-UpdateFullScreenStatusInDocTree(nsIDocument* aDoc, bool aIsFullScreen)
-{
-  nsIDocument* root = GetRootDocument(aDoc);
-  if (root) {
-    UpdateFullScreenStatus(root, static_cast<void*>(&aIsFullScreen));
-  }
-}
-
-void
-nsDocument::ResetFullScreenElement()
-{
-  if (mFullScreenElement) {
-    nsEventStateManager::SetFullScreenState(mFullScreenElement, false);
-  }
-  mFullScreenElement = nsnull;
-}
-
-static bool
-ResetFullScreenElement(nsIDocument* aDocument, void* aData)
-{
-  aDocument->ResetFullScreenElement();
-  aDocument->EnumerateSubDocuments(ResetFullScreenElement, aData);
-  return true;
-}
-
-static void
-ResetFullScreenElementInDocTree(nsIDocument* aDoc)
-{
-  nsIDocument* root = GetRootDocument(aDoc);
-  if (root) {
-    ResetFullScreenElement(root, nsnull);
-  }
+SetFullScreenState(nsIDocument* aDoc, Element* aElement, bool aIsFullScreen)
+{
+  return static_cast<nsDocument*>(aDoc)->
+    SetFullScreenState(aElement, aIsFullScreen);
 }
 
 NS_IMETHODIMP
 nsDocument::MozCancelFullScreen()
 {
   if (!nsContentUtils::IsRequestFullScreenAllowed()) {
     return NS_OK;
   }
   CancelFullScreen();
   return NS_OK;
 }
 
+// Runnable to set window full-screen mode. Used as a script runner
+// to ensure we only call nsGlobalWindow::SetFullScreen() when it's safe to 
+// run script. nsGlobalWindow::SetFullScreen() dispatches a synchronous event
+// (handled in chome code) which is unsafe to run if this is called in
+// nsGenericElement::UnbindFromTree().
+class nsSetWindowFullScreen : public nsRunnable {
+public:
+  nsSetWindowFullScreen(nsIDocument* aDoc, bool aValue)
+    : mDoc(aDoc), mValue(aValue) {}
+
+  NS_IMETHOD Run()
+  {
+    if (mDoc->GetWindow()) {
+      mDoc->GetWindow()->SetFullScreen(mValue);
+    }
+    return NS_OK;
+  }
+
+private:
+  nsCOMPtr<nsIDocument> mDoc;
+  bool mValue;
+};
+
+static void
+SetWindowFullScreen(nsIDocument* aDoc, bool aValue)
+{
+  nsContentUtils::AddScriptRunner(new nsSetWindowFullScreen(aDoc, aValue));
+}
+
 void
 nsDocument::CancelFullScreen()
 {
-  if (!nsContentUtils::IsFullScreenApiEnabled() ||
-      !IsFullScreenDoc() ||
-      !GetWindow()) {
+  NS_ASSERTION(!IsFullScreenDoc() || sFullScreenDoc != nsnull,
+               "Should have a full-screen doc when full-screen!");
+
+  if (!IsFullScreenDoc() || !GetWindow() || !sFullScreenDoc) {
     return;
   }
 
-  // Disable full-screen mode in all documents in this hierarchy.
-  UpdateFullScreenStatusInDocTree(this, false);
+  // Reset full-screen state in all full-screen documents.
+  nsCOMPtr<nsIDocument> doc(do_QueryReferent(sFullScreenDoc));
+  while (doc != nsnull) {
+    if (::SetFullScreenState(doc, nsnull, false)) {
+      DispatchFullScreenChange(doc, nsnull);
+    }
+    doc = doc->GetParentDocument();
+  }
+  sFullScreenDoc = nsnull;
 
   // Move the window out of full-screen mode.
-  GetWindow()->SetFullScreen(false);
+  SetWindowFullScreen(this, false);
 
   return;
 }
 
 bool
 nsDocument::IsFullScreenDoc()
 {
-  return nsContentUtils::IsFullScreenApiEnabled() && mIsFullScreen;
+  return mIsFullScreen;
+}
+
+static nsIDocument*
+GetCommonAncestor(nsIDocument* aDoc1, nsIDocument* aDoc2)
+{
+  nsIDocument* doc1 = aDoc1;
+  nsIDocument* doc2 = aDoc2;
+
+  nsAutoTArray<nsIDocument*, 30> parents1, parents2;
+  do {
+    parents1.AppendElement(doc1);
+    doc1 = doc1->GetParentDocument();
+  } while (doc1);
+  do {
+    parents2.AppendElement(doc2);
+    doc2 = doc2->GetParentDocument();
+  } while (doc2);
+
+  PRUint32 pos1 = parents1.Length();
+  PRUint32 pos2 = parents2.Length();
+  nsIDocument* parent = nsnull;
+  PRUint32 len;
+  for (len = NS_MIN(pos1, pos2); len > 0; --len) {
+    nsIDocument* child1 = parents1.ElementAt(--pos1);
+    nsIDocument* child2 = parents2.ElementAt(--pos2);
+    if (child1 != child2) {
+      break;
+    }
+    parent = child1;
+  }
+  return parent;
 }
 
 void
 nsDocument::RequestFullScreen(Element* aElement)
 {
   if (!aElement || !nsContentUtils::IsFullScreenApiEnabled() || !GetWindow()) {
     return;
   }
 
-  // Reset the full-screen elements of every document in this document
-  // hierarchy.
-  ResetFullScreenElementInDocTree(this);
-  
-  if (aElement->IsInDoc()) {
-    // Propagate up the document hierarchy, setting the full-screen element as
-    // the element's container in ancestor documents. Note we don't propagate
-    // down the document hierarchy, the full-screen element (or its container)
-    // is not visible there.
-    mFullScreenElement = aElement;
-    // Set the full-screen state on the element, so the css-pseudo class
-    // applies to the element.
-    nsEventStateManager::SetFullScreenState(mFullScreenElement, true);
-    nsIDocument* child = this;
-    nsIDocument* parent;
-    while (parent = child->GetParentDocument()) {
-      Element* element = parent->FindContentForSubDocument(child);
-      // Containing frames also need the css-pseudo class applied.
-      nsEventStateManager::SetFullScreenState(element, true);
-      static_cast<nsDocument*>(parent)->mFullScreenElement = element;
-      child = parent;
-    }
-  }
-
-  // Set all documents in hierarchy to full-screen mode.
-  UpdateFullScreenStatusInDocTree(this, true);
+  // Turn off full-screen state in all documents which were previously
+  // full-screen but which shouldn't be after this request is granted.
+  // Note commonAncestor will be null when in a separate browser window
+  // to the requesting document.
+  nsIDocument* commonAncestor = nsnull;
+  nsCOMPtr<nsIDocument> fullScreenDoc(do_QueryReferent(sFullScreenDoc));
+  if (fullScreenDoc) {
+    commonAncestor = GetCommonAncestor(fullScreenDoc, this);
+  }
+  nsIDocument* doc = fullScreenDoc;
+  while (doc != commonAncestor) {
+    if (::SetFullScreenState(doc, nsnull, false)) {
+      DispatchFullScreenChange(doc, nsnull);
+    }
+    doc = doc->GetParentDocument();
+  }
+  if (!commonAncestor && fullScreenDoc) {
+    // Other doc is in another browser window. Move it out of full-screen.
+    // Note that nsGlobalWindow::SetFullScreen() proxies to the root window
+    // in its hierarchy, and does not operate on the a per-nsIDOMWindow basis.
+    SetWindowFullScreen(fullScreenDoc, false);
+  }
+
+  // Set the full-screen element. This sets the full-screen style on the
+  // element, and the full-screen-ancestor styles on ancestors of the element
+  // in this document.
+  if (SetFullScreenState(aElement, true)) {
+    DispatchFullScreenChange(this, aElement);
+  }
+
+  // Propagate up the document hierarchy, setting the full-screen element as
+  // the element's container in ancestor documents. This also sets the
+  // appropriate css styles as well. Note we don't propagate down the
+  // document hierarchy, the full-screen element (or its container) is not
+  // visible there.  
+  nsIDocument* child = this;
+  nsIDocument* parent;
+  while ((parent = child->GetParentDocument())) {
+    Element* element = parent->FindContentForSubDocument(child)->AsElement();
+    if (::SetFullScreenState(parent, element, true)) {
+      DispatchFullScreenChange(parent, element);
+    }
+    child = parent;
+  }
 
   // Make the window full-screen. Note we must make the state changes above
   // before making the window full-screen, as then the document reports as
-  // being in full-screen mode when the Chrome "fullscreen" event fires,
-  // enabling browser.js to distinguish between browser and dom full-screen
+  // being in full-screen mode when the chrome "fullscreen" event fires,
+  // enabling chrome to distinguish between browser and dom full-screen
   // modes.
-  GetWindow()->SetFullScreen(true);
+  SetWindowFullScreen(this, true);
+
+  // Remember this is the requesting full-screen document.
+  sFullScreenDoc = do_GetWeakReference(static_cast<nsIDocument*>(this));
 }
 
 NS_IMETHODIMP
 nsDocument::GetMozFullScreenElement(nsIDOMHTMLElement **aFullScreenElement)
 {
   NS_ENSURE_ARG_POINTER(aFullScreenElement);
-  if (!nsContentUtils::IsFullScreenApiEnabled() || !IsFullScreenDoc()) {
-    *aFullScreenElement = nsnull;
-    return NS_OK;
-  }
-  nsCOMPtr<nsIDOMHTMLElement> e(do_QueryInterface(GetFullScreenElement()));
-  NS_IF_ADDREF(*aFullScreenElement = e);
+  *aFullScreenElement = nsnull;
+  if (IsFullScreenDoc()) {
+    // Must have a full-screen element while in full-screen mode.
+    NS_ENSURE_STATE(GetFullScreenElement());
+    CallQueryInterface(GetFullScreenElement(), aFullScreenElement);
+  }
   return NS_OK;
 }
 
 Element*
 nsDocument::GetFullScreenElement()
 {
-  if (!nsContentUtils::IsFullScreenApiEnabled() ||
-      (mFullScreenElement && !mFullScreenElement->IsInDoc())) {
-    return nsnull;
-  }
   return mFullScreenElement;
 }
 
 NS_IMETHODIMP
 nsDocument::GetMozFullScreen(bool *aFullScreen)
 {
   NS_ENSURE_ARG_POINTER(aFullScreen);
-  *aFullScreen = nsContentUtils::IsFullScreenApiEnabled() && IsFullScreenDoc();
+  *aFullScreen = IsFullScreenDoc();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::GetMozFullScreenEnabled(bool *aFullScreen)
 {
   NS_ENSURE_ARG_POINTER(aFullScreen);
   *aFullScreen = false;
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -167,16 +167,22 @@ public:
   }
 
   /**
    * Returns the element if we know the element associated with this
    * id. Otherwise returns null.
    */
   Element* GetIdElement();
   /**
+   * Returns the list of all elements associated with this id.
+   */
+  const nsSmallVoidArray* GetIdElements() const {
+    return &mIdContentList;
+  }
+  /**
    * If this entry has a non-null image element set (using SetImageElement),
    * the image element will be returned, otherwise the same as GetIdElement().
    */
   Element* GetImageIdElement();
   /**
    * Append all the elements with this id to aElements
    */
   void AppendAllIdContent(nsCOMArray<nsIContent>* aElements);
@@ -239,17 +245,17 @@ public:
     
     ChangeCallback mKey;
   };
 
 private:
   void FireChangeCallbacks(Element* aOldElement, Element* aNewElement,
                            bool aImageOnly = false);
 
-  // empty if there are no elementswith this ID.
+  // empty if there are no elements with this ID.
   // The elements are stored as weak pointers.
   nsSmallVoidArray mIdContentList;
   nsRefPtr<nsBaseContentList> mNameContentList;
   nsRefPtr<nsContentList> mDocAllList;
   nsAutoPtr<nsTHashtable<ChangeCallbackEntry> > mChangeCallbacks;
   nsRefPtr<Element> mImageElement;
 };
 
@@ -921,37 +927,40 @@ public:
   GetElementsByTagName(const nsAString& aTagName) {
     return NS_GetContentList(this, kNameSpaceID_Unknown, aTagName);
   }
   already_AddRefed<nsContentList>
     GetElementsByTagNameNS(const nsAString& aNamespaceURI,
                            const nsAString& aLocalName);
 
   virtual Element *GetElementById(const nsAString& aElementId);
+  virtual const nsSmallVoidArray* GetAllElementsForId(const nsAString& aElementId) const;
 
   virtual Element *LookupImageElement(const nsAString& aElementId);
 
   virtual NS_HIDDEN_(nsresult) AddImage(imgIRequest* aImage);
   virtual NS_HIDDEN_(nsresult) RemoveImage(imgIRequest* aImage);
   virtual NS_HIDDEN_(nsresult) SetImageLockingState(bool aLocked);
 
   virtual nsresult GetStateObject(nsIVariant** aResult);
 
   virtual nsDOMNavigationTiming* GetNavigationTiming() const;
   virtual nsresult SetNavigationTiming(nsDOMNavigationTiming* aTiming);
 
   virtual Element* FindImageMap(const nsAString& aNormalizedMapName);
 
-  virtual void ResetFullScreenElement();
   virtual Element* GetFullScreenElement();
   virtual void RequestFullScreen(Element* aElement);
   virtual void CancelFullScreen();
-  virtual void UpdateFullScreenStatus(bool aIsFullScreen);
   virtual bool IsFullScreenDoc();
 
+  // Returns true if making this change results in a change in the full-screen
+  // state of this document.
+  bool SetFullScreenState(Element* aElement, bool aIsFullScreen);
+ 
   // This method may fire a DOM event; if it does so it will happen
   // synchronously.
   void UpdateVisibilityState();
   // Posts an event to call UpdateVisibilityState
   virtual void PostVisibilityUpdateEvent();
 
 protected:
   friend class nsNodeUtils;
@@ -1061,16 +1070,20 @@ protected:
   // the script global object of the original document.
   nsWeakPtr mScriptObject;
 
   // Weak reference to the scope object (aka the script global object)
   // that, unlike mScriptGlobalObject, is never unset once set. This
   // is a weak reference to avoid leaks due to circular references.
   nsWeakPtr mScopeObject;
 
+  // The document which requested (and was granted) full-screen. All ancestors
+  // of this document will also be full-screen.
+  static nsWeakPtr sFullScreenDoc;
+
   nsRefPtr<nsEventListenerManager> mListenerManager;
   nsCOMPtr<nsIDOMStyleSheetList> mDOMStyleSheets;
   nsRefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
   nsRefPtr<nsScriptLoader> mScriptLoader;
   nsDocHeaderData* mHeaderData;
   /* mIdentifierMap works as follows for IDs:
    * 1) Attribute changes affect the table immediately (removing and adding
    *    entries as needed).
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -3051,27 +3051,40 @@ nsGenericElement::BindToTree(nsIDocument
   NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document");
   NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
   NS_POSTCONDITION(aBindingParent == GetBindingParent(),
                    "Bound to wrong binding parent");
 
   return NS_OK;
 }
 
+static bool
+IsFullScreenAncestor(Element* aElement)
+{
+  nsEventStates state = aElement->State();
+  return state.HasAtLeastOneOfStates(NS_EVENT_STATE_FULL_SCREEN_ANCESTOR |
+                                     NS_EVENT_STATE_FULL_SCREEN);
+}
+
 void
 nsGenericElement::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   NS_PRECONDITION(aDeep || (!GetCurrentDoc() && !GetBindingParent()),
                   "Shallow unbind won't clear document and binding parent on "
                   "kids!");
   // Make sure to unbind this node before doing the kids
   nsIDocument *document =
     HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetCurrentDoc();
 
   if (aNullParent) {
+    if (IsFullScreenAncestor(this)) {
+      // The element being removed is an ancestor of the full-screen element,
+      // exit full-screen state.
+      OwnerDoc()->CancelFullScreen();
+    }
     if (GetParent()) {
       NS_RELEASE(mParent);
     } else {
       mParent = nsnull;
     }
     SetParentIsContent(false);
   }
   ClearInDocument();
@@ -5347,76 +5360,129 @@ ParseSelectorList(nsINode* aNode,
       slot = &cur->mNext;
     }
   } while (*slot);
   *aSelectorList = selectorList;
 
   return NS_OK;
 }
 
-/* static */
-nsIContent*
-nsGenericElement::doQuerySelector(nsINode* aRoot, const nsAString& aSelector,
-                                  nsresult *aResult)
-{
-  NS_PRECONDITION(aResult, "Null out param?");
-
+// Actually find elements matching aSelectorList (which must not be
+// null) and which are descendants of aRoot and put them in Alist.  If
+// onlyFirstMatch, then stop once the first one is found.
+template<bool onlyFirstMatch, class T>
+inline static nsresult FindMatchingElements(nsINode* aRoot,
+                                            const nsAString& aSelector,
+                                            T &aList)
+{
   nsAutoPtr<nsCSSSelectorList> selectorList;
-  *aResult = ParseSelectorList(aRoot, aSelector,
-                               getter_Transfers(selectorList));
-  NS_ENSURE_SUCCESS(*aResult, nsnull);
-
-  TreeMatchContext matchingContext(false,
-                                   nsRuleWalker::eRelevantLinkUnvisited,
-                                   aRoot->OwnerDoc());
+  nsresult rv = ParseSelectorList(aRoot, aSelector,
+                                  getter_Transfers(selectorList));
+  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_TRUE(selectorList, NS_OK);
+
+  NS_ASSERTION(selectorList->mSelectors,
+               "How can we not have any selectors?");
+
+  nsIDocument* doc = aRoot->OwnerDoc();  
+  TreeMatchContext matchingContext(false, nsRuleWalker::eRelevantLinkUnvisited,
+                                   doc);
+
+  // Fast-path selectors involving IDs.  We can only do this if aRoot
+  // is in the document and the document is not in quirks mode, since
+  // ID selectors are case-insensitive in quirks mode.  Also, only do
+  // this if selectorList only has one selector, because otherwise
+  // ordering the elements correctly is a pain.
+  NS_ASSERTION(aRoot->IsElement() || aRoot->IsNodeOfType(nsINode::eDOCUMENT),
+               "Unexpected root node");
+  if (aRoot->IsInDoc() &&
+      doc->GetCompatibilityMode() != eCompatibility_NavQuirks &&
+      !selectorList->mNext &&
+      selectorList->mSelectors->mIDList) {
+    nsIAtom* id = selectorList->mSelectors->mIDList->mAtom;
+    const nsSmallVoidArray* elements =
+      doc->GetAllElementsForId(nsDependentAtomString(id));
+
+    // XXXbz: Should we fall back to the tree walk if aRoot is not the
+    // document and |elements| is long, for some value of "long"?
+    if (elements) {
+      for (PRUint32 i = 0; i < elements->Count(); ++i) {
+        Element *element = static_cast<Element*>(elements->ElementAt(i));
+        if (!aRoot->IsElement() ||
+            nsContentUtils::ContentIsDescendantOf(element, aRoot)) {
+          // We have an element with the right id and it's a descendant
+          // of aRoot.  Make sure it really matches the selector.
+          if (nsCSSRuleProcessor::SelectorListMatches(element, matchingContext,
+                                                      selectorList)) {
+            aList.AppendElement(element);
+            if (onlyFirstMatch) {
+              return NS_OK;
+            }
+          }
+        }
+      }
+    }
+
+    // No elements with this id, or none of them are our descendants,
+    // or none of them match.  We're done here.
+    return NS_OK;
+  }
+
   for (nsIContent* cur = aRoot->GetFirstChild();
        cur;
        cur = cur->GetNextNode(aRoot)) {
     if (cur->IsElement() &&
         nsCSSRuleProcessor::SelectorListMatches(cur->AsElement(),
                                                 matchingContext,
                                                 selectorList)) {
-      return cur;
+      aList.AppendElement(cur->AsElement());
+      if (onlyFirstMatch) {
+        return NS_OK;
+      }
     }
   }
 
-  return nsnull;
+  return NS_OK;
+}
+
+struct ElementHolder {
+  ElementHolder() : mElement(nsnull) {}
+  void AppendElement(Element* aElement) {
+    NS_ABORT_IF_FALSE(!mElement, "Should only get one element");
+    mElement = aElement;
+  }
+  Element* mElement;
+};
+
+/* static */
+nsIContent*
+nsGenericElement::doQuerySelector(nsINode* aRoot, const nsAString& aSelector,
+                                  nsresult *aResult)
+{
+  NS_PRECONDITION(aResult, "Null out param?");
+
+  ElementHolder holder;
+  *aResult = FindMatchingElements<true>(aRoot, aSelector, holder);
+
+  return holder.mElement;
 }
 
 /* static */
 nsresult
 nsGenericElement::doQuerySelectorAll(nsINode* aRoot,
                                      const nsAString& aSelector,
                                      nsIDOMNodeList **aReturn)
 {
   NS_PRECONDITION(aReturn, "Null out param?");
 
   nsSimpleContentList* contentList = new nsSimpleContentList(aRoot);
   NS_ENSURE_TRUE(contentList, NS_ERROR_OUT_OF_MEMORY);
   NS_ADDREF(*aReturn = contentList);
   
-  nsAutoPtr<nsCSSSelectorList> selectorList;
-  nsresult rv = ParseSelectorList(aRoot, aSelector,
-                                  getter_Transfers(selectorList));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  TreeMatchContext matchingContext(false,
-                                   nsRuleWalker::eRelevantLinkUnvisited,
-                                   aRoot->OwnerDoc());
-  for (nsIContent* cur = aRoot->GetFirstChild();
-       cur;
-       cur = cur->GetNextNode(aRoot)) {
-    if (cur->IsElement() &&
-        nsCSSRuleProcessor::SelectorListMatches(cur->AsElement(),
-                                                matchingContext,
-                                                selectorList)) {
-      contentList->AppendElement(cur);
-    }
-  }
-  return NS_OK;
+  return FindMatchingElements<false>(aRoot, aSelector, *contentList);
 }
 
 
 bool
 nsGenericElement::MozMatchesSelector(const nsAString& aSelector, nsresult* aResult)
 {
   nsAutoPtr<nsCSSSelectorList> selectorList;
   bool matches = false;
--- a/content/canvas/src/CustomQS_WebGL.h
+++ b/content/canvas/src/CustomQS_WebGL.h
@@ -254,20 +254,17 @@ nsIDOMWebGLRenderingContext_ReadPixels(J
     GET_INT32_ARG(argv3, 3);
     GET_UINT32_ARG(argv4, 4);
     GET_UINT32_ARG(argv5, 5);
 
     if (argc == 7 &&
         !JSVAL_IS_PRIMITIVE(argv[6]))
     {
         JSObject *argv6 = JSVAL_TO_OBJECT(argv[6]);
-        if (js_IsArrayBuffer(argv6)) {
-            rv = self->ReadPixels_buf(argv0, argv1, argv2, argv3,
-                                      argv4, argv5, js::ArrayBuffer::getArrayBuffer(argv6));
-        } else if (js_IsTypedArray(argv6)) {
+        if (js_IsTypedArray(argv6)) {
             rv = self->ReadPixels_array(argv0, argv1, argv2, argv3,
                                         argv4, argv5,
                                         js::TypedArray::getTypedArray(argv6));
         } else {
             xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 6);
             return JS_FALSE;
         }
     } else {
@@ -375,25 +372,21 @@ nsIDOMWebGLRenderingContext_TexImage2D(J
         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]);
 
-        // then try to grab either a js::ArrayBuffer, js::TypedArray, or null
+        // then try to grab either a js::TypedArray, or null
         if (argv8 == nsnull) {
-            rv = self->TexImage2D_buf(argv0, argv1, argv2, argv3,
-                                      argv4, argv5, argv6, argv7,
-                                      nsnull);
-        } else if (js_IsArrayBuffer(argv8)) {
-            rv = self->TexImage2D_buf(argv0, argv1, argv2, argv3,
-                                      argv4, argv5, argv6, argv7,
-                                      js::ArrayBuffer::getArrayBuffer(argv8));
+            rv = self->TexImage2D_array(argv0, argv1, argv2, argv3,
+                                        argv4, argv5, argv6, argv7,
+                                        nsnull);
         } else if (js_IsTypedArray(argv8)) {
             rv = self->TexImage2D_array(argv0, argv1, argv2, argv3,
                                         argv4, argv5, argv6, argv7,
                                         js::TypedArray::getTypedArray(argv8));
         } else {
             xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 8);
             return JS_FALSE;
         }
@@ -498,22 +491,18 @@ nsIDOMWebGLRenderingContext_TexSubImage2
     {
         // 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 either a js::ArrayBuffer or js::TypedArray
-        if (js_IsArrayBuffer(argv8)) {
-            rv = self->TexSubImage2D_buf(argv0, argv1, argv2, argv3,
-                                         argv4, argv5, argv6, argv7,
-                                         js::ArrayBuffer::getArrayBuffer(argv8));
-        } else if (js_IsTypedArray(argv8)) {
+        // try to grab a js::TypedArray
+        if (js_IsTypedArray(argv8)) {
             rv = self->TexSubImage2D_array(argv0, argv1, argv2, argv3,
                                            argv4, argv5, argv6, argv7,
                                            js::TypedArray::getTypedArray(argv8));
         } else {
             xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 8);
             return JS_FALSE;
         }
     } else {
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -806,29 +806,42 @@ WebGLContext::GetInputStream(const char*
 NS_IMETHODIMP
 WebGLContext::GetThebesSurface(gfxASurface **surface)
 {
     return NS_ERROR_NOT_AVAILABLE;
 }
 
 static PRUint8 gWebGLLayerUserData;
 
+namespace mozilla {
+
 class WebGLContextUserData : public LayerUserData {
 public:
     WebGLContextUserData(nsHTMLCanvasElement *aContent)
     : mContent(aContent) {}
+
+  /** DidTransactionCallback gets called by the Layers code everytime the WebGL canvas gets composite,
+    * so it really is the right place to put actions that have to be performed upon compositing
+    */
   static void DidTransactionCallback(void* aData)
   {
-    static_cast<WebGLContextUserData*>(aData)->mContent->MarkContextClean();
+    WebGLContextUserData *userdata = static_cast<WebGLContextUserData*>(aData);
+    nsHTMLCanvasElement *canvas = userdata->mContent;
+    WebGLContext *context = static_cast<WebGLContext*>(canvas->GetContextAtIndex(0));
+
+    context->mBackbufferClearingStatus = BackbufferClearingStatus::NotClearedSinceLastPresented;
+    canvas->MarkContextClean();
   }
 
 private:
   nsRefPtr<nsHTMLCanvasElement> mContent;
 };
 
+} // end namespace mozilla
+
 already_AddRefed<layers::CanvasLayer>
 WebGLContext::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                              CanvasLayer *aOldLayer,
                              LayerManager *aManager)
 {
     if (mContextLost)
         return nsnull;
 
@@ -882,18 +895,16 @@ WebGLContext::GetCanvasLayer(nsDisplayLi
 
     canvasLayer->Initialize(data);
     PRUint32 flags = gl->CreationFormat().alpha == 0 ? Layer::CONTENT_OPAQUE : 0;
     canvasLayer->SetContentFlags(flags);
     canvasLayer->Updated();
 
     mResetLayer = false;
 
-    mBackbufferClearingStatus = BackbufferClearingStatus::NotClearedSinceLastPresented;
-
     return canvasLayer.forget().get();
 }
 
 NS_IMETHODIMP
 WebGLContext::GetContextAttributes(jsval *aResult)
 {
     if (mContextLost)
     {
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -339,16 +339,17 @@ struct WebGLContextOptions {
 class WebGLContext :
     public nsIDOMWebGLRenderingContext,
     public nsICanvasRenderingContextInternal,
     public nsSupportsWeakReference,
     public nsITimerCallback
 {
     friend class WebGLMemoryReporter;
     friend class WebGLExtensionLoseContext;
+    friend class WebGLContextUserData;
 
 public:
     WebGLContext();
     virtual ~WebGLContext();
 
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
     NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(WebGLContext, nsIDOMWebGLRenderingContext)
@@ -574,17 +575,17 @@ protected:
     nsresult TexSubImage2D_base(WebGLenum target, WebGLint level,
                                 WebGLint xoffset, WebGLint yoffset,
                                 WebGLsizei width, WebGLsizei height, WebGLsizei srcStrideOrZero,
                                 WebGLenum format, WebGLenum type,
                                 void *pixels, PRUint32 byteLength,
                                 int jsArrayType,
                                 int srcFormat, bool srcPremultiplied);
     nsresult ReadPixels_base(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height,
-                             WebGLenum format, WebGLenum type, void *data, PRUint32 byteLength);
+                             WebGLenum format, WebGLenum type, JSObject* pixels);
     nsresult TexParameter_base(WebGLenum target, WebGLenum pname,
                                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);
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -1529,33 +1529,38 @@ WebGLContext::NeedFakeBlack()
 void
 WebGLContext::BindFakeBlackTextures()
 {
     // this is the generic case: try to return early
     if (!NeedFakeBlack())
         return;
 
     if (!mBlackTexturesAreInitialized) {
+        GLuint bound2DTex = 0;
+        GLuint boundCubeTex = 0;
+        gl->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, (GLint*) &bound2DTex);
+        gl->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_CUBE_MAP, (GLint*) &boundCubeTex);
+
         const PRUint8 black[] = {0, 0, 0, 255};
 
         gl->fGenTextures(1, &mBlackTexture2D);
         gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBlackTexture2D);
         gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 1, 1,
                         0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, &black);
 
         gl->fGenTextures(1, &mBlackTextureCubeMap);
         gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBlackTextureCubeMap);
         for (WebGLuint i = 0; i < 6; ++i) {
             gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, LOCAL_GL_RGBA, 1, 1,
                             0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, &black);
         }
 
-        // return the texture bindings to the 0 texture to prevent the user from modifying our black textures
-        gl->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
-        gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, 0);
+        // Reset bound textures
+        gl->fBindTexture(LOCAL_GL_TEXTURE_2D, bound2DTex);
+        gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, boundCubeTex);
 
         mBlackTexturesAreInitialized = true;
     }
 
     for (PRInt32 i = 0; i < mGLMaxTextureUnits; ++i) {
         if (mBound2DTextures[i] && mBound2DTextures[i]->NeedFakeBlack()) {
             gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
             gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBlackTexture2D);
@@ -3335,98 +3340,135 @@ WebGLContext::ReadPixels(PRInt32)
     if (mContextLost)
         return NS_OK;
 
     return NS_ERROR_FAILURE;
 }
 
 nsresult
 WebGLContext::ReadPixels_base(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height,
-                              WebGLenum format, WebGLenum type, void *data, PRUint32 byteLength)
+                              WebGLenum format, WebGLenum type, JSObject* pixels)
 {
     if (HTMLCanvasElement()->IsWriteOnly() && !nsContentUtils::IsCallerTrustedForRead()) {
         LogMessageIfVerbose("ReadPixels: Not allowed");
         return NS_ERROR_DOM_SECURITY_ERR;
     }
 
     if (width < 0 || height < 0)
         return ErrorInvalidValue("ReadPixels: negative size passed");
 
-    // there's nothing to do in this case, since we won't read any pixels
-    if (width == 0 || height == 0)
-        return NS_OK;
+    if (!pixels)
+        return ErrorInvalidValue("ReadPixels: null array passed");
 
     WebGLsizei boundWidth = mBoundFramebuffer ? mBoundFramebuffer->width() : mWidth;
     WebGLsizei boundHeight = mBoundFramebuffer ? mBoundFramebuffer->height() : mHeight;
 
-    PRUint32 size = 0;
-    bool badFormat = false, badType = false;
+    void* data = JS_GetTypedArrayData(pixels);
+    PRUint32 dataByteLen = JS_GetTypedArrayByteLength(pixels);
+    int dataType = JS_GetTypedArrayType(pixels);
+
+    PRUint32 channels = 0;
+
+    // Check the format param
     switch (format) {
-    case LOCAL_GL_RGBA:
-        size = 4;
-        break;
-    default:
-        badFormat = true;
-        break;
+        case LOCAL_GL_ALPHA:
+            channels = 1;
+            break;
+        case LOCAL_GL_RGB:
+            channels = 3;
+            break;
+        case LOCAL_GL_RGBA:
+            channels = 4;
+            break;
+        default:
+            return ErrorInvalidEnum("readPixels: Bad format");
     }
 
+    PRUint32 bytesPerPixel = 0;
+    int requiredDataType = 0;
+
+    // Check the type param
     switch (type) {
-    case LOCAL_GL_UNSIGNED_BYTE:
-        break;
-    default:
-        badType = true;
-        break;
+        case LOCAL_GL_UNSIGNED_BYTE:
+            bytesPerPixel = 1 * channels;
+            requiredDataType = js::TypedArray::TYPE_UINT8;
+            break;
+        case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
+        case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
+        case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
+            bytesPerPixel = 2;
+            requiredDataType = js::TypedArray::TYPE_UINT16;
+            break;
+        default:
+            return ErrorInvalidEnum("readPixels: Bad type");
     }
 
-    if (badFormat && badType)
-        return ErrorInvalidOperation("readPixels: bad format and type");
-    if (badFormat)
-        return ErrorInvalidEnumInfo("readPixels: format", format);
-    if (badType)
-        return ErrorInvalidEnumInfo("ReadPixels: type", type);
-
+    // Check the pixels param type
+    if (dataType != requiredDataType)
+        return ErrorInvalidOperation("readPixels: Mismatched type/pixels types");
+
+    // Check the pixels param size
     CheckedUint32 checked_neededByteLength =
-        GetImageSize(height, width, size, mPixelStorePackAlignment);
-
-    CheckedUint32 checked_plainRowSize = CheckedUint32(width) * size;
-
-    CheckedUint32 checked_alignedRowSize = 
+        GetImageSize(height, width, bytesPerPixel, mPixelStorePackAlignment);
+
+    CheckedUint32 checked_plainRowSize = CheckedUint32(width) * bytesPerPixel;
+
+    CheckedUint32 checked_alignedRowSize =
         RoundedToNextMultipleOf(checked_plainRowSize, mPixelStorePackAlignment);
 
     if (!checked_neededByteLength.valid())
         return ErrorInvalidOperation("ReadPixels: integer overflow computing the needed buffer size");
 
-    if (checked_neededByteLength.value() > byteLength)
+    if (checked_neededByteLength.value() > dataByteLen)
         return ErrorInvalidOperation("ReadPixels: buffer too small");
 
+    // Check the format and type params to assure they are an acceptable pair (as per spec)
+    switch (format) {
+        case LOCAL_GL_RGBA: {
+            switch (type) {
+                case LOCAL_GL_UNSIGNED_BYTE:
+                    break;
+                default:
+                    return ErrorInvalidOperation("readPixels: Invalid format/type pair");
+            }
+            break;
+        }
+        default:
+            return ErrorInvalidOperation("readPixels: Invalid format/type pair");
+    }
+
     MakeContextCurrent();
 
     if (mBoundFramebuffer) {
         // prevent readback of arbitrary video memory through uninitialized renderbuffers!
         if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
             return NS_OK;
     } else {
         EnsureBackbufferClearedAsNeeded();
     }
-
+    // Now that the errors are out of the way, on to actually reading
+
+    // If we won't be reading any pixels anyways, just skip the actual reading
+    if (width == 0 || height == 0)
+        return NS_OK;
 
     if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, boundWidth, boundHeight)) {
         // the easy case: we're not reading out-of-range pixels
         gl->fReadPixels(x, y, width, height, format, type, data);
     } else {
         // the rectangle doesn't fit entirely in the bound buffer. We then have to set to zero the part
         // of the buffer that correspond to out-of-range pixels. We don't want to rely on system OpenGL
         // to do that for us, because passing out of range parameters to a buggy OpenGL implementation
         // could conceivably allow to read memory we shouldn't be allowed to read. So we manually initialize
         // the buffer to zero and compute the parameters to pass to OpenGL. We have to use an intermediate buffer
         // to accomodate the potentially different strides (widths).
 
         // zero the whole destination buffer. Too bad for the part that's going to be overwritten, we're not
         // 100% efficient here, but in practice this is a quite rare case anyway.
-        memset(data, 0, byteLength);
+        memset(data, 0, dataByteLen);
 
         if (   x >= boundWidth
             || x+width <= 0
             || y >= boundHeight
             || y+height <= 0)
         {
             // we are completely outside of range, can exit now with buffer filled with zeros
             return NS_OK;
@@ -3444,33 +3486,33 @@ WebGLContext::ReadPixels_base(WebGLint x
         if (subrect_width < 0 || subrect_height < 0 ||
             subrect_width > width || subrect_height > height)
             return ErrorInvalidOperation("ReadPixels: integer overflow computing clipped rect size");
 
         // now we know that subrect_width is in the [0..width] interval, and same for heights.
 
         // now, same computation as above to find the size of the intermediate buffer to allocate for the subrect
         // no need to check again for integer overflow here, since we already know the sizes aren't greater than before
-        PRUint32 subrect_plainRowSize = subrect_width * size;
+        PRUint32 subrect_plainRowSize = subrect_width * bytesPerPixel;
 	// There are checks above to ensure that this doesn't overflow.
         PRUint32 subrect_alignedRowSize = 
             RoundedToNextMultipleOf(subrect_plainRowSize, mPixelStorePackAlignment).value();
         PRUint32 subrect_byteLength = (subrect_height-1)*subrect_alignedRowSize + subrect_plainRowSize;
 
         // create subrect buffer, call glReadPixels, copy pixels into destination buffer, delete subrect buffer
         GLubyte *subrect_data = new GLubyte[subrect_byteLength];
         gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height, format, type, subrect_data);
 
         // notice that this for loop terminates because we already checked that subrect_height is at most height
         for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) {
             GLint subrect_x_in_dest_buffer = subrect_x - x;
             GLint subrect_y_in_dest_buffer = subrect_y - y;
             memcpy(static_cast<GLubyte*>(data)
                      + checked_alignedRowSize.value() * (subrect_y_in_dest_buffer + y_inside_subrect)
-                     + size * subrect_x_in_dest_buffer, // destination
+                     + bytesPerPixel * subrect_x_in_dest_buffer, // destination
                    subrect_data + subrect_alignedRowSize * y_inside_subrect, // source
                    subrect_plainRowSize); // size
         }
         delete [] subrect_data;
     }
 
     // if we're reading alpha, we may need to do fixup.  Note that we don't allow
     // GL_ALPHA to readpixels currently, but we had the code written for it already.
@@ -3522,31 +3564,17 @@ WebGLContext::ReadPixels_base(WebGLint x
 
 NS_IMETHODIMP
 WebGLContext::ReadPixels_array(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height,
                                WebGLenum format, WebGLenum type, JSObject *pixels)
 {
     if (mContextLost)
         return NS_OK;
 
-    return ReadPixels_base(x, y, width, height, format, type,
-                           pixels ? JS_GetTypedArrayData(pixels) : 0,
-                           pixels ? JS_GetTypedArrayByteLength(pixels) : 0);
-}
-
-NS_IMETHODIMP
-WebGLContext::ReadPixels_buf(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height,
-                             WebGLenum format, WebGLenum type, JSObject *pixels)
-{
-    if (mContextLost)
-        return NS_OK;
-
-    return ReadPixels_base(x, y, width, height, format, type,
-                           pixels ? JS_GetArrayBufferData(pixels) : 0,
-                           pixels ? JS_GetArrayBufferByteLength(pixels) : 0);
+    return ReadPixels_base(x, y, width, height, format, type, pixels);
 }
 
 NS_IMETHODIMP
 WebGLContext::RenderbufferStorage(WebGLenum target, WebGLenum internalformat, WebGLsizei width, WebGLsizei height)
 {
     if (mContextLost)
         return NS_OK;
 
@@ -4906,44 +4934,28 @@ WebGLContext::TexImage2D_base(WebGLenum 
     }
 
     tex->SetImageInfo(target, level, width, height, format, type);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
-WebGLContext::TexImage2D_buf(WebGLenum target, WebGLint level, WebGLenum internalformat,
-                             WebGLsizei width, WebGLsizei height, WebGLint border,
-                             WebGLenum format, WebGLenum type,
-                             JSObject *pixels)
-{
-    if (mContextLost)
-        return NS_OK;
-
-    return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type,
-                           pixels ? JS_GetArrayBufferData(pixels) : 0,
-                           pixels ? JS_GetArrayBufferByteLength(pixels) : 0,
-                           -1,
-                           WebGLTexelFormat::Auto, false);
-}
-
-NS_IMETHODIMP
 WebGLContext::TexImage2D_array(WebGLenum target, WebGLint level, WebGLenum internalformat,
                                WebGLsizei width, WebGLsizei height, WebGLint border,
                                WebGLenum format, WebGLenum type,
                                JSObject *pixels)
 {
     if (mContextLost)
         return NS_OK;
 
     return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type,
                            pixels ? JS_GetTypedArrayData(pixels) : 0,
                            pixels ? JS_GetTypedArrayByteLength(pixels) : 0,
-                           (int) JS_GetTypedArrayType(pixels),
+                           pixels ? (int)JS_GetTypedArrayType(pixels) : -1,
                            WebGLTexelFormat::Auto, false);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexImage2D_imageData(WebGLenum target, WebGLint level, WebGLenum internalformat,
                                WebGLsizei width, WebGLsizei height, WebGLint border,
                                WebGLenum format, WebGLenum type,
                                JSObject *pixels)
@@ -5102,36 +5114,16 @@ WebGLContext::TexSubImage2D_base(WebGLen
 
         gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, convertedData);
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
-WebGLContext::TexSubImage2D_buf(WebGLenum target, WebGLint level,
-                                WebGLint xoffset, WebGLint yoffset,
-                                WebGLsizei width, WebGLsizei height,
-                                WebGLenum format, WebGLenum type,
-                                JSObject *pixels)
-{
-    if (mContextLost)
-        return NS_OK;
-
-    if (!pixels)
-        return ErrorInvalidValue("TexSubImage2D: pixels must not be null!");
-
-    return TexSubImage2D_base(target, level, xoffset, yoffset,
-                              width, height, 0, format, type,
-                              JS_GetArrayBufferData(pixels), JS_GetArrayBufferByteLength(pixels),
-                              -1,
-                              WebGLTexelFormat::Auto, false);
-}
-
-NS_IMETHODIMP
 WebGLContext::TexSubImage2D_array(WebGLenum target, WebGLint level,
                                   WebGLint xoffset, WebGLint yoffset,
                                   WebGLsizei width, WebGLsizei height,
                                   WebGLenum format, WebGLenum type,
                                   JSObject *pixels)
 {
     if (mContextLost)
         return NS_OK;
--- a/content/canvas/test/webgl/failing_tests_linux.txt
+++ b/content/canvas/test/webgl/failing_tests_linux.txt
@@ -1,14 +1,10 @@
 conformance/context/premultiplyalpha-test.html
 conformance/glsl/misc/glsl-long-variable-names.html
 conformance/glsl/misc/shader-with-256-character-identifier.frag.html
 conformance/glsl/misc/shader-with-long-line.html
 conformance/misc/uninitialized-test.html
 conformance/programs/gl-get-active-attribute.html
-conformance/reading/read-pixels-test.html
-conformance/renderbuffers/framebuffer-object-attachment.html
 conformance/textures/texture-mips.html
 conformance/uniforms/gl-uniform-bool.html
 conformance/more/conformance/quickCheckAPI-S_V.html
-conformance/more/functions/copyTexImage2D.html
-conformance/more/functions/copyTexSubImage2D.html
 conformance/more/functions/uniformfArrayLen1.html
--- a/content/canvas/test/webgl/failing_tests_mac.txt
+++ b/content/canvas/test/webgl/failing_tests_mac.txt
@@ -1,19 +1,12 @@
-conformance/canvas/buffer-preserve-test.html
-conformance/context/context-attributes-alpha-depth-stencil-antialias.html
 conformance/context/premultiplyalpha-test.html
 conformance/glsl/misc/glsl-function-nodes.html
 conformance/glsl/misc/glsl-long-variable-names.html
 conformance/glsl/misc/shader-with-256-character-identifier.frag.html
 conformance/glsl/misc/shader-with-long-line.html
 conformance/programs/program-test.html
-conformance/reading/read-pixels-test.html
-conformance/renderbuffers/framebuffer-object-attachment.html
 conformance/state/gl-object-get-calls.html
-conformance/textures/tex-input-validation.html
 conformance/textures/texture-mips.html
 conformance/textures/texture-npot.html
 conformance/more/conformance/quickCheckAPI-S_V.html
-conformance/more/functions/copyTexImage2D.html
-conformance/more/functions/copyTexSubImage2D.html
 conformance/more/functions/uniformfBadArgs.html
 conformance/more/functions/uniformiBadArgs.html
--- a/content/canvas/test/webgl/failing_tests_windows.txt
+++ b/content/canvas/test/webgl/failing_tests_windows.txt
@@ -1,14 +1,9 @@
-conformance/canvas/buffer-preserve-test.html
 conformance/context/premultiplyalpha-test.html
 conformance/glsl/functions/glsl-function-atan.html
 conformance/glsl/functions/glsl-function-atan-xy.html
 conformance/glsl/functions/glsl-function-mod-gentype.html
 conformance/glsl/misc/glsl-long-variable-names.html
 conformance/glsl/misc/shader-with-256-character-identifier.frag.html
 conformance/glsl/misc/shader-with-long-line.html
-conformance/reading/read-pixels-test.html
-conformance/renderbuffers/framebuffer-object-attachment.html
 conformance/more/conformance/quickCheckAPI-S_V.html
-conformance/more/functions/copyTexImage2D.html
-conformance/more/functions/copyTexSubImage2D.html
 conformance/more/functions/uniformfArrayLen1.html
--- a/content/events/public/nsEventStates.h
+++ b/content/events/public/nsEventStates.h
@@ -259,24 +259,26 @@ private:
 #define NS_EVENT_STATE_MOZ_SUBMITINVALID NS_DEFINE_EVENT_STATE_MACRO(31)
 // UI friendly version of :invalid pseudo-class.
 #define NS_EVENT_STATE_MOZ_UI_INVALID NS_DEFINE_EVENT_STATE_MACRO(32)
 // UI friendly version of :valid pseudo-class.
 #define NS_EVENT_STATE_MOZ_UI_VALID NS_DEFINE_EVENT_STATE_MACRO(33)
 // Content is the full screen element, or a frame containing the
 // current full-screen element.
 #define NS_EVENT_STATE_FULL_SCREEN   NS_DEFINE_EVENT_STATE_MACRO(34)
+// Content is an ancestor of the DOM full-screen element.
+#define NS_EVENT_STATE_FULL_SCREEN_ANCESTOR   NS_DEFINE_EVENT_STATE_MACRO(35)
 // Handler for click to play plugin
-#define NS_EVENT_STATE_TYPE_CLICK_TO_PLAY NS_DEFINE_EVENT_STATE_MACRO(35)
+#define NS_EVENT_STATE_TYPE_CLICK_TO_PLAY NS_DEFINE_EVENT_STATE_MACRO(36)
 
 /**
  * NOTE: do not go over 63 without updating nsEventStates::InternalType!
  */
 
 #define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS |     \
                             NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER |   \
                             NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING | \
-                            NS_EVENT_STATE_FULL_SCREEN)
+                            NS_EVENT_STATE_FULL_SCREEN | NS_EVENT_STATE_FULL_SCREEN_ANCESTOR)
 
 #define INTRINSIC_STATES (~ESM_MANAGED_STATES)
 
 #endif // nsEventStates_h__
 
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -4440,22 +4440,32 @@ static nsIContent* FindCommonAncestor(ns
         anc2 = anc2->GetParent();
       }
       return anc1;
     }
   }
   return nsnull;
 }
 
+static Element*
+GetParentElement(Element* aElement)
+{
+  nsIContent* p = aElement->GetParent();
+  return (p && p->IsElement()) ? p->AsElement() : nsnull;
+}
+
 /* static */
 void
-nsEventStateManager::SetFullScreenState(Element* aElement,
-                                        bool aIsFullScreen)
+nsEventStateManager::SetFullScreenState(Element* aElement, bool aIsFullScreen)
 {
   DoStateChange(aElement, NS_EVENT_STATE_FULL_SCREEN, aIsFullScreen);
+  Element* ancestor = aElement;
+  while ((ancestor = GetParentElement(ancestor))) {
+    DoStateChange(ancestor, NS_EVENT_STATE_FULL_SCREEN_ANCESTOR, aIsFullScreen);
+  }
 }
 
 /* static */
 inline void
 nsEventStateManager::DoStateChange(Element* aElement, nsEventStates aState,
                                    bool aAddState)
 {
   if (aAddState) {
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -3398,36 +3398,33 @@ nsGenericHTMLElement::Focus()
 
 nsresult nsGenericHTMLElement::MozRequestFullScreen()
 {
   // Only grant full-screen requests if this is called from inside a trusted
   // event handler (i.e. inside an event handler for a user initiated event).
   // This stops the full-screen from being abused similar to the popups of old,
   // and it also makes it harder for bad guys' script to go full-screen and
   // spoof the browser chrome/window and phish logins etc.
-  if (!nsContentUtils::IsRequestFullScreenAllowed()) {
+  if (!nsContentUtils::IsRequestFullScreenAllowed() ||
+      !IsInDoc()) {
     return NS_OK;
   }
 
   nsIDocument* doc = OwnerDoc();
   nsCOMPtr<nsIDOMDocument> domDocument(do_QueryInterface(doc));
   NS_ENSURE_STATE(domDocument);
   bool fullScreenEnabled;
   domDocument->GetMozFullScreenEnabled(&fullScreenEnabled);
   if (!fullScreenEnabled) {
     return NS_OK;
   }
 
   doc->RequestFullScreen(this);
 #ifdef DEBUG
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(doc->GetWindow());
-  NS_ENSURE_STATE(window);
   bool fullscreen;
-  window->GetFullScreen(&fullscreen);
-  NS_ASSERTION(fullscreen, "Windows should report fullscreen");
   domDocument->GetMozFullScreen(&fullscreen);
   NS_ASSERTION(fullscreen, "Document should report fullscreen");
   NS_ASSERTION(doc->IsFullScreenDoc(), "Should be in full screen state!");
 #endif
   return NS_OK;
 }
 
 nsresult nsGenericHTMLElement::Click()
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -277,16 +277,17 @@ include $(topsrcdir)/config/rules.mk
 		test_checked.html \
 		test_bug677658.html \
 		test_bug677463.html \
 		test_bug682886.html \
 		file_fullscreen-api.html \
 		file_fullscreen-api-keys.html \
 		test_fullscreen-api.html \
 		file_fullscreen-plugins.html \
+		file_fullscreen-denied.html \
 		test_li_attributes_reflection.html \
 		test_ol_attributes_reflection.html \
 		test_bug651956.html \
 		test_bug694503.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
--- a/content/html/content/test/file_fullscreen-api-keys.html
+++ b/content/html/content/test/file_fullscreen-api-keys.html
@@ -1,250 +1,116 @@
- <!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=545812
-
-Test that restricted key pressed drop documents out of DOM full-screen mode.
-
--->
-<head>
-  <title>Test for Bug 545812</title>
-  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
-</head>
-<body onload="document.body.mozRequestFullScreen();">
-
-<script type="application/javascript">
-
-/** Test for Bug 545812 **/
-
-// List of key codes, and whether they're restricted in full-screen mode.
-var keyList = [
-  // Allowed: DOM_VK_CANCEL to DOM_VK_CAPS_LOCK, inclusive
-  { code: "VK_CANCEL",        allowed: true},
-  { code: "VK_HELP",          allowed: true},
-  { code: "VK_BACK_SPACE",    allowed: true},
-  { code: "VK_TAB",           allowed: true},
-  { code: "VK_CLEAR",         allowed: true},
-  { code: "VK_RETURN",        allowed: true},
-  { code: "VK_ENTER",         allowed: true},
-  { code: "VK_SHIFT",         allowed: true},
-  { code: "VK_CONTROL",       allowed: true},
-  { code: "VK_ALT",           allowed: true},
-  { code: "VK_PAUSE",         allowed: true},
-  { code: "VK_CAPS_LOCK",     allowed: true},
-
-  { code: "VK_KANA",          allowed: false},
-  { code: "VK_HANGUL",        allowed: false},
-  { code: "VK_JUNJA",         allowed: false},
-  { code: "VK_FINAL",         allowed: false},
-  { code: "VK_HANJA",         allowed: false},
-  { code: "VK_KANJI",         allowed: false},
-  { code: "VK_ESCAPE",        allowed: false},
-  { code: "VK_CONVERT",       allowed: false},
-  { code: "VK_NONCONVERT",    allowed: false},
-  { code: "VK_ACCEPT",        allowed: false},
-  { code: "VK_MODECHANGE",    allowed: false},
-
-  // Allowed: DOM_VK_SPACE to DOM_VK_DELETE, inclusive
-  { code: "VK_SPACE",         allowed: true},
-  { code: "VK_PAGE_UP",       allowed: true},
-  { code: "VK_PAGE_DOWN",     allowed: true},
-  { code: "VK_END",           allowed: true},
-  { code: "VK_HOME",          allowed: true},
-  { code: "VK_LEFT",          allowed: true},
-  { code: "VK_UP",            allowed: true},
-  { code: "VK_RIGHT",         allowed: true},
-  { code: "VK_DOWN",          allowed: true},
-  { code: "VK_SELECT",        allowed: true},
-  { code: "VK_PRINT",         allowed: true},
-  { code: "VK_EXECUTE",       allowed: true},
-  { code: "VK_PRINTSCREEN",   allowed: true},
-  { code: "VK_INSERT",        allowed: true},
-  { code: "VK_DELETE",        allowed: true},
-
-  { code: "VK_0",             allowed: false},
-  { code: "VK_1",             allowed: false},
-  { code: "VK_2",             allowed: false},
-  { code: "VK_3",             allowed: false},
-  { code: "VK_4",             allowed: false},
-  { code: "VK_5",             allowed: false},
-  { code: "VK_6",             allowed: false},
-  { code: "VK_7",             allowed: false},
-  { code: "VK_8",             allowed: false},
-  { code: "VK_9",             allowed: false},
-
-  // Allowed: DOM_VK_SPACE to DOM_VK_DELETE, inclusive
-  { code: "VK_SEMICOLON",     allowed: true},
-  { code: "VK_EQUALS",        allowed: true},
-
-  { code: "VK_A",             allowed: false},
-  { code: "VK_B",             allowed: false},
-  { code: "VK_C",             allowed: false},
-  { code: "VK_D",             allowed: false},
-  { code: "VK_E",             allowed: false},
-  { code: "VK_F",             allowed: false},
-  { code: "VK_G",             allowed: false},
-  { code: "VK_H",             allowed: false},
-  { code: "VK_I",             allowed: false},
-  { code: "VK_J",             allowed: false},
-  { code: "VK_K",             allowed: false},
-  { code: "VK_L",             allowed: false},
-  { code: "VK_M",             allowed: false},
-  { code: "VK_N",             allowed: false},
-  { code: "VK_O",             allowed: false},
-  { code: "VK_P",             allowed: false},
-  { code: "VK_Q",             allowed: false},
-  { code: "VK_R",             allowed: false},
-  { code: "VK_S",             allowed: false},
-  { code: "VK_T",             allowed: false},
-  { code: "VK_U",             allowed: false},
-  { code: "VK_V",             allowed: false},
-  { code: "VK_W",             allowed: false},
-  { code: "VK_X",             allowed: false},
-  { code: "VK_Y",             allowed: false},
-  { code: "VK_Z",             allowed: false},
-  { code: "VK_CONTEXT_MENU",  allowed: false},
-  { code: "VK_SLEEP",         allowed: false},
-  { code: "VK_NUMPAD0",       allowed: false},
-  { code: "VK_NUMPAD1",       allowed: false},
-  { code: "VK_NUMPAD2",       allowed: false},
-  { code: "VK_NUMPAD3",       allowed: false},
-  { code: "VK_NUMPAD4",       allowed: false},
-  { code: "VK_NUMPAD5",       allowed: false},
-  { code: "VK_NUMPAD6",       allowed: false},
-  { code: "VK_NUMPAD7",       allowed: false},
-  { code: "VK_NUMPAD8",       allowed: false},
-  { code: "VK_NUMPAD9",       allowed: false},
-
-  // Allowed: DOM_VK_MULTIPLY to DOM_VK_META, inclusive
-  { code: "VK_MULTIPLY",      allowed: true},
-  { code: "VK_ADD",           allowed: true},
-  { code: "VK_SEPARATOR",     allowed: true},
-  { code: "VK_SUBTRACT",      allowed: true},
-  { code: "VK_DECIMAL",       allowed: true},
-  { code: "VK_DIVIDE",        allowed: true},
-  { code: "VK_F1",            allowed: true},
-  { code: "VK_F2",            allowed: true},
-  { code: "VK_F3",            allowed: true},
-  { code: "VK_F4",            allowed: true},
-  { code: "VK_F5",            allowed: true},
-  { code: "VK_F6",            allowed: true},
-  { code: "VK_F7",            allowed: true},
-  { code: "VK_F8",            allowed: true},
-  { code: "VK_F9",            allowed: true},
-  { code: "VK_F10",           allowed: true},
-  { code: "VK_F11",           allowed: true},
-  { code: "VK_F12",           allowed: true},
-  { code: "VK_F13",           allowed: true},
-  { code: "VK_F14",           allowed: true},
-  { code: "VK_F15",           allowed: true},
-  { code: "VK_F16",           allowed: true},
-  { code: "VK_F17",           allowed: true},
-  { code: "VK_F18",           allowed: true},
-  { code: "VK_F19",           allowed: true},
-  { code: "VK_F20",           allowed: true},
-  { code: "VK_F21",           allowed: true},
-  { code: "VK_F22",           allowed: true},
-  { code: "VK_F23",           allowed: true},
-  { code: "VK_F24",           allowed: true},
-  { code: "VK_NUM_LOCK",      allowed: true},
-  { code: "VK_SCROLL_LOCK",   allowed: true},
-  { code: "VK_COMMA",         allowed: true},
-  { code: "VK_PERIOD",        allowed: true},
-  { code: "VK_SLASH",         allowed: true},
-  { code: "VK_BACK_QUOTE",    allowed: true},
-  { code: "VK_OPEN_BRACKET",  allowed: true},
-  { code: "VK_BACK_SLASH",    allowed: true},
-  { code: "VK_CLOSE_BRACKET", allowed: true},
-  { code: "VK_QUOTE",         allowed: true},
-  { code: "VK_META",          allowed: true},
-];
-
-function ok(condition, msg) {
-  opener.ok(condition, msg);
-}
-
-function is(a, b, msg) {
-  opener.is(a, b, msg);
-}
-
-var gKeyTestIndex = 0;
-var gKeyName;
-var gKeyCode;
-var gKeyAllowed;
-var gKeyReceived = false;
-
-function keyHandler(event) {
-  event.preventDefault()
-  gKeyReceived = true;
-}
-
-function checkKeyEffect() {
-  is(document.mozFullScreen, gKeyAllowed,
-     (gKeyAllowed ? ("Should remain in full-screen mode for allowed key press " + gKeyName)
-                  : ("Should drop out of full-screen mode for restricted key press " + gKeyName)));
-
-  if (gKeyTestIndex < keyList.length) {
-    setTimeout(testNextKey, 0);
-  } else {
-    opener.keysTestFinished();
-  }
-}
-
-function testTrustedKeyEvents() {
-  document.body.focus();
-  gKeyReceived = false;
-  synthesizeKey(gKeyName, {});
-  setTimeout(checkKeyEffect, 0);
-}
-
-function testScriptInitiatedKeyEvents() {
-  // Script initiated untrusted key events should not be blocked.
-  document.body.focus();
-  gKeyReceived = false;
-  var evt = document.createEvent("KeyEvents");
-  evt.initKeyEvent("keydown", true, true, window,
-                   false, false, false, false,
-                   gKeyCode, 0);
-  document.body.dispatchEvent(evt);
-
-  evt = document.createEvent("KeyEvents");
-  evt.initKeyEvent("keypress", true, true, window,
-                   false, false, false, false,
-                   gKeyCode, 0);
-  document.body.dispatchEvent(evt);
-
-  evt = document.createEvent("KeyEvents");
-  evt.initKeyEvent("keyup", true, true, window,
-                   false, false, false, false,
-                   gKeyCode, 0);
-  document.body.dispatchEvent(evt);
-  
-  ok(gKeyReceived, "dispatchEvent should dispatch events synchronously");
-  ok(document.mozFullScreen,
-     "Should remain in full-screen mode for script initiated key events for " + gKeyName);
-}
-
-function testNextKey() {
-  if (!document.mozFullScreen) {
-    document.body.mozRequestFullScreen();
-  }
-  ok(document.mozFullScreen, "Must be in full-screen mode");
-
-  gKeyName = keyList[gKeyTestIndex].code;
-  gKeyCode = KeyEvent["DOM_" + gKeyName];
-  gKeyAllowed = keyList[gKeyTestIndex].allowed;
-  gKeyTestIndex++;
-
-  testScriptInitiatedKeyEvents();
-  testTrustedKeyEvents();
-}
-
-window.addEventListener("keydown", keyHandler, true);
-window.addEventListener("keyup", keyHandler, true);
-window.addEventListener("keypress", keyHandler, true);
-setTimeout(testNextKey, 0);
-
-</script>
-</pre>
-</body>
-</html>
+ <!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=545812
+
+Test that restricted key pressed drop documents out of DOM full-screen mode.
+
+-->
+<head>
+  <title>Test for Bug 545812</title>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <style>
+  body {
+    background-color: black;
+  }
+  </style>
+</head>
+<body onload="document.body.mozRequestFullScreen();">
+
+<script type="application/javascript">
+
+/** Test for Bug 545812 **/
+
+// List of key codes which should exit full-screen mode.
+var keyList = [
+  { code: "VK_ESCAPE", suppressed: true},
+  { code: "VK_F11",    suppressed: false},
+];
+
+function ok(condition, msg) {
+  opener.ok(condition, msg);
+}
+
+function is(a, b, msg) {
+  opener.is(a, b, msg);
+}
+
+var gKeyTestIndex = 0;
+var gKeyName;
+var gKeyCode;
+var gKeySuppressed;
+var gKeyReceived = false;
+
+function keyHandler(event) {
+  gKeyReceived = true;
+}
+
+function checkKeyEffect() {
+  is(gKeySuppressed, !gKeyReceived, "Should not receive key events for " + gKeyName);
+  is(document.mozFullScreen, false, "Should exit full-screen mode for " + gKeyName + " press");
+  if (gKeyTestIndex < keyList.length) {
+    setTimeout(testNextKey, 0);
+  } else {
+    document.mozCancelFullScreen();
+    opener.nextTest();
+  }
+}
+
+function testTrustedKeyEvents() {
+  document.body.focus();
+  gKeyReceived = false;
+  synthesizeKey(gKeyName, {});
+  setTimeout(checkKeyEffect, 0);
+}
+
+function testScriptInitiatedKeyEvents() {
+  // Script initiated untrusted key events should not cause full-screen exit.
+  document.body.focus();
+  gKeyReceived = false;
+  var evt = document.createEvent("KeyEvents");
+  evt.initKeyEvent("keydown", true, true, window,
+                   false, false, false, false,
+                   gKeyCode, 0);
+  document.body.dispatchEvent(evt);
+
+  evt = document.createEvent("KeyEvents");
+  evt.initKeyEvent("keypress", true, true, window,
+                   false, false, false, false,
+                   gKeyCode, 0);
+  document.body.dispatchEvent(evt);
+
+  evt = document.createEvent("KeyEvents");
+  evt.initKeyEvent("keyup", true, true, window,
+                   false, false, false, false,
+                   gKeyCode, 0);
+  document.body.dispatchEvent(evt);
+  
+  ok(gKeyReceived, "dispatchEvent should dispatch events synchronously");
+  ok(document.mozFullScreen,
+     "Should remain in full-screen mode for script initiated key events for " + gKeyName);
+}
+
+function testNextKey() {
+  if (!document.mozFullScreen) {
+    document.body.mozRequestFullScreen();
+  }
+  ok(document.mozFullScreen, "Must be in full-screen mode");
+
+  gKeyName = keyList[gKeyTestIndex].code;
+  gKeyCode = KeyEvent["DOM_" + gKeyName];
+  gKeySuppressed = keyList[gKeyTestIndex].suppressed;
+  gKeyTestIndex++;
+
+  testScriptInitiatedKeyEvents();
+  testTrustedKeyEvents();
+}
+
+window.addEventListener("keydown", keyHandler, true);
+window.addEventListener("keyup", keyHandler, true);
+window.addEventListener("keypress", keyHandler, true);
+setTimeout(testNextKey, 0);
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/html/content/test/file_fullscreen-api.html
+++ b/content/html/content/test/file_fullscreen-api.html
@@ -1,177 +1,210 @@
- <!DOCTYPE HTML>
+<!DOCTYPE HTML>
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=545812
 
 Test DOM full-screen API.
 
 -->
 <head>
   <title>Test for Bug 545812</title>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <style>
-  body:-moz-full-screen, div:-moz-full-screen {
-    background-color: red;
+  body {
+    background-color: black;
   }
   </style>
 </head>
-<body onload="document.body.mozRequestFullScreen();">
+<body onload="fullScreenElement().mozRequestFullScreen();">
 
 <script type="application/javascript">
 
 /** Test for Bug 545812 **/
 
 function ok(condition, msg) {
   opener.ok(condition, msg);
 }
 
 function is(a, b, msg) {
   opener.is(a, b, msg);
 }
 
 /*
 <html>
   <body onload='document.body.mozRequestFullScreen();'>
+  <iframe id='inner-frame'></iframe>
   </body>
 </html>
 */
-var iframeContents = "data:text/html;charset=utf-8,<html>%0D%0A  <body onload%3D'document.body.mozRequestFullScreen()%3B'>%0D%0A  <%2Fbody>%0D%0A<%2Fhtml>";
+var iframeContents = "data:text/html;charset=utf-8,<html><body onload%3D'document.body.mozRequestFullScreen()%3B'><iframe id%3D'inner-frame'><%2Fiframe><%2Fbody><%2Fhtml>";
 
 var iframe = null;
 var outOfDocElement = null;
 var inDocElement = null;
+var container = null;
 var button = null;
 
 var fullScreenChangeCount = 0;
 
 function sendMouseClick(element) {
   synthesizeMouseAtCenter(element, {});
 }
 
 function setRequireTrustedContext(value) {
   opener.SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", value);
 }
 
+function fullScreenElement() {
+  return document.getElementById('full-screen-element');
+}
+
 function fullScreenChange(event) {
   switch (fullScreenChangeCount) {
     case 0: {
       ok(document.mozFullScreen, "Should be in full-screen mode (first time)");
-      is(event.target, document.body, "Event target should be full-screen element");
-      is(document.mozFullScreenElement, document.body,
-         "Full-screen element should be body element.");
-      document.mozCancelFullScreen();
+      is(event.target, fullScreenElement(), "Event target should be full-screen element");
+      is(document.mozFullScreenElement, fullScreenElement(),
+         "Full-screen element should be div element.");
+      ok(document.mozFullScreenElement.mozMatchesSelector(":-moz-full-screen"),
+         "FSE should match :-moz-full-screen");
+      var fse = fullScreenElement();
+      fse.parentNode.removeChild(fse);
+      is(document.mozFullScreenElement, null,
+         "Full-screen element should be null after removing.");
+      ok(!document.mozFullScreen, "Should have left full-screen mode when we remove full-screen element");
+      document.body.appendChild(fse);
+      ok(!document.mozFullScreen, "Should not return to full-screen mode when re-adding former FSE");
+      is(document.mozFullScreenElement, null,
+         "Full-screen element should still be null after re-adding former FSE.");
       break;
     }
     case 1: {
       ok(!document.mozFullScreen, "Should have left full-screen mode (first time)");
-      is(event.target, document.body, "Event target should be full-screen element");
+      is(event.target, document, "Event target should be document when we exit via removing from doc");
       is(document.mozFullScreenElement, null, "Full-screen element should be null.");
       iframe = document.createElement("iframe");
       iframe.mozAllowFullScreen = true;
       document.body.appendChild(iframe);
       iframe.src = iframeContents;
       break;
     }
     case 2: {
       ok(document.mozFullScreen, "Should be back in full-screen mode (second time)");
       is(event.target, iframe,
          "Event target should be full-screen element container");
       is(document.mozFullScreenElement, iframe,
         "Full-screen element should be iframe element.");
-      document.mozCancelFullScreen();
+      var fse = fullScreenElement();
+      fse.mozRequestFullScreen();
+      ok(document.mozFullScreen, "Should still be full-screen mode after re-requesting.");
+      is(document.mozFullScreenElement, fse, "Full-screen element should have switched to requestee.");
+      var _innerFrame = iframe.contentDocument.getElementById("inner-frame");
+      _innerFrame.contentDocument.body.appendChild(fse);
+      ok(!document.mozFullScreen, "Should exit full-screen after transplanting FSE");
+      is(document.mozFullScreenElement, null, "Full-screen element transplanted, should be null.");
+      is(iframe.contentDocument.mozFullScreenElement, null, "Full-screen element in outer frame should be null.");
+      is(_innerFrame.contentDocument.mozFullScreenElement, null, "Full-screen element in inner frame should be null.");
+      ok(!iframe.contentDocument.mozFullScreen, "Outer frame should not acquire full-screen status.");
+      ok(!_innerFrame.contentDocument.mozFullScreen, "Inner frame should not acquire full-screen status.");
+      
+      document.body.appendChild(fse);
       break;
     }
     case 3: {
       ok(!document.mozFullScreen, "Should be back in non-full-screen mode (second time)");
-      is(event.target, iframe,
+      is(event.target, document,
          "Event target should be full-screen element container");
       is(document.mozFullScreenElement, null, "Full-screen element should be null.");
       document.body.removeChild(iframe);
       iframe = null;
       outOfDocElement = document.createElement("div");
       outOfDocElement.mozRequestFullScreen();
+      ok(!document.mozFullScreen, "Requests for full-screen from not-in-doc elements should fail.");
+
+      container = document.createElement("div");
+      inDocElement = document.createElement("div");
+      container.appendChild(inDocElement);
+      fullScreenElement().appendChild(container);
+      
+      inDocElement.mozRequestFullScreen();
+      ok(document.mozFullScreen, "Should grant request to return to full-screen mode (third time)");
       break;
     }
     case 4: {
-      ok(document.mozFullScreen, "Should be back in full-screen mode (third time)");
-      is(event.target, document, "Event target should be document");
-      is(document.mozFullScreenElement, null,
-        "Should not have a full-screen element when element not in document requests full-screen.");
-       
-      // Set another element to be the full-screen element. It should immediately
-      // become the current full-screen element.
-      inDocElement = document.createElement("div");
-      document.body.appendChild(inDocElement);
-      inDocElement.mozRequestFullScreen();
-       
-      ok(document.mozFullScreen, "Should remain in full-screen mode (third and a half time)");
+      ok(document.mozFullScreen, "Should still be in full-screen mode (third time)");
+      is(event.target, inDocElement, "Event target should be inDocElement");
       is(document.mozFullScreenElement, inDocElement,
-        "Full-screen element should be in doc again.");
-
-      // Remove full-screen element from document before exiting full screen.
-      document.body.removeChild(inDocElement);
-      ok(document.mozFullScreen,
-         "Should remain in full-screen mode after removing full-screen element from document");
+        "FSE should be inDocElement.");       
+      
+      var n = container;
+      do {
+        ok(n.mozMatchesSelector(":-moz-full-screen-ancestor"), "Ancestor " + n + " should match :-moz-full-screen-ancestor")
+        n = n.parentNode;
+      } while (n && n.mozMatchesSelector);
+        
+      // Remove full-screen ancestor element from document, verify it stops being reported as current FSE.
+      container.parentNode.removeChild(container);
+      ok(!document.mozFullScreen,
+         "Should exit full-screen mode after removing full-screen element ancestor from document");
       is(document.mozFullScreenElement, null,
         "Should not have a full-screen element again.");
-
-      document.mozCancelFullScreen();
       break;
     }
     case 5: {
       ok(!document.mozFullScreen, "Should be back in non-full-screen mode (third time)");
       setRequireTrustedContext(true);
-      document.body.mozRequestFullScreen();
+      fullScreenElement().mozRequestFullScreen();
       ok(!document.mozFullScreen, "Should still be in normal mode, because calling context isn't trusted.");
 
       button = document.createElement("button");
-      button.onclick = function(){document.body.mozRequestFullScreen();}
-      document.body.appendChild(button);
+      button.onclick = function(){fullScreenElement().mozRequestFullScreen();}
+      fullScreenElement().appendChild(button);
       sendMouseClick(button);
       break;
     }
     case 6: {
       ok(document.mozFullScreen, "Moved to full-screen after mouse click");
       document.mozCancelFullScreen();
       ok(document.mozFullScreen, "Should still be in full-screen mode, because calling context isn't trusted.");
       setRequireTrustedContext(false);
       document.mozCancelFullScreen();
       ok(!document.mozFullScreen, "Should have left full-screen mode.");
       break;
     }
     case 7: {
       ok(!document.mozFullScreen, "Should have left full-screen mode (last time).");
 
-      SpecialPowers.setBoolPref("full-screen-api.enabled", false);
-      is(document.mozFullScreenEnabled, false, "document.mozFullScreenEnabled should be false if full-screen-api.enabled is false");
-      document.body.mozRequestFullScreen();
+      SpecialPowers.setBoolPref("full-screen-api.enabled", false);
+      is(document.mozFullScreenEnabled, false, "document.mozFullScreenEnabled should be false if full-screen-api.enabled is false");
+      fullScreenElement().mozRequestFullScreen();
       ok(!document.mozFullScreen, "Should still be in normal mode, because pref is not enabled.");
-
-      SpecialPowers.setBoolPref("full-screen-api.enabled", true);
-      is(document.mozFullScreenEnabled, true, "document.mozFullScreenEnabled should be true if full-screen-api.enabled is true");
-
+
+      SpecialPowers.setBoolPref("full-screen-api.enabled", true);
+      is(document.mozFullScreenEnabled, true, "document.mozFullScreenEnabled should be true if full-screen-api.enabled is true");
+
       iframe = document.createElement("iframe");
-      document.body.appendChild(iframe);
+      fullScreenElement().appendChild(iframe);
       iframe.src = iframeContents;
       ok(!document.mozFullScreen, "Should still be in normal mode, because iframe did not have mozallowfullscreen attribute.");
-      document.body.removeChild(iframe);
-      iframe = null;
+      fullScreenElement().removeChild(iframe);
+      iframe = null;
 
       // Set timeout for calling finish(), so that any pending "mozfullscreenchange" events
       // would have a chance to fire.
-      setTimeout(function(){opener.apiTestFinished();}, 0);
+      setTimeout(function(){opener.nextTest();}, 0);
       break;
     }
     default: {
       ok(false, "Should not receive any more fullscreenchange events!");
     }
   }
   fullScreenChangeCount++;
 }
 
 document.addEventListener("mozfullscreenchange", fullScreenChange, false);
 
 </script>
 </pre>
+<div id="full-screen-element"></div>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_fullscreen-denied.html
@@ -0,0 +1,96 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=545812
+
+Test DOM full-screen API.
+
+-->
+<head>
+  <title>Test for Bug 545812</title>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <style>
+  body {
+    background-color: black;
+  }
+  </style>
+</head>
+<body onload="run();">
+
+<script type="application/javascript">
+
+/** Test for Bug 545812 **/
+
+function ok(condition, msg) {
+  opener.ok(condition, msg);
+}
+
+function is(a, b, msg) {
+  opener.is(a, b, msg);
+}
+
+/*
+<html>
+  <body onload='document.body.mozRequestFullScreen();'>
+  </body>
+</html>
+*/
+var requestFullScreenContents = "data:text/html;charset=utf-8,<html>%0D%0A  <body onload%3D'document.body.mozRequestFullScreen()%3B'>%0D%0A  <%2Fbody>%0D%0A<%2Fhtml>";
+
+
+var gotFullScreenChange = false;
+
+function run() {
+  document.addEventListener("mozfullscreenchange",
+    function() {
+      ok(false, "Should never receive a mozfullscreenchange event in the main window.");
+      gotFullScreenChange = true;
+    },
+    false);
+
+  // Request full-screen from a non trusted context (this script isn't a user
+  // generated event!).
+  SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", true);
+  document.body.mozRequestFullScreen();
+  ok(!document.mozFullScreen, "Should not grant request in non-truested context");
+
+  // Test requesting full-screen mode in a long-running user-generated event handler.
+  // The request in the key handler should not be granted.
+  window.addEventListener("keypress", keyHandler, false);
+  synthesizeKey("VK_A", {});
+}
+
+function keyHandler(event) {
+  window.removeEventListener("keypress", keyHandler, false);
+  
+  // Busy loop until 2s has passed. We should then be past the 1 second threshold, and so
+  // our request for full-screen mode should be rejected.
+  var end = (new Date()).getTime() + 2000;
+  while ((new Date()).getTime() < end) {
+    ; // Wait...
+  }
+  document.body.mozRequestFullScreen();
+  ok(!document.mozFullScreen, "Should not grant request in long-running event handler.");
+  
+  // Disable the requirement for trusted contexts only, so the tests are easier
+  // to write.
+  SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);  
+  
+  // Create an iframe without a mozallowfullscreen sttribute, whose contents requests
+  // full-screen. The request should be denied.
+  var iframe = document.createElement("iframe");
+  iframe.src = requestFullScreenContents;
+  document.body.appendChild(iframe);
+ 
+  setTimeout(
+    function() {
+      ok(!gotFullScreenChange, "Should not ever grant a fullscreen request in this doc.");
+      opener.nextTest();
+    }, 0);
+}
+
+</script>
+</pre>
+<div id="full-screen-element"></div>
+</body>
+</html>
--- a/content/html/content/test/file_fullscreen-plugins.html
+++ b/content/html/content/test/file_fullscreen-plugins.html
@@ -114,17 +114,17 @@ function macFullScreenChange(event) {
           ok(document.mozFullScreen, "Adding windowed plugin to document should not cause full-screen to exit on MacOS.");
           document.mozCancelFullScreen();
         }, 0);
           
       break;
     }
     case 1: {
       ok(!document.mozFullScreen, "Should have left full-screen mode after calling document.mozCancelFullScreen().");
-      opener.pluginTestFinished();
+      opener.nextTest();
       break;
     }
     default: {
       ok(false, "Should not receive any more fullscreenchange events!");
     }
   }
   fullScreenChangeCount++;
 }
@@ -159,17 +159,17 @@ function fullScreenChange(event) {
     }
     case 4: {
       ok(document.mozFullScreen, "Should have (again) reentered full-screen mode");
       document.body.appendChild(windowedPlugin);
       break;
     }
     case 5: {
       ok(!document.mozFullScreen, "Should have left full-screen mode after adding windowed plugin created before going full-screen to document");
-      opener.pluginTestFinished();
+      opener.nextTest();
       break;
     }
     default: {
       ok(false, "Should not receive any more fullscreenchange events!");
     }
   }
   fullScreenChangeCount++;
 }
--- a/content/html/content/test/test_fullscreen-api.html
+++ b/content/html/content/test/test_fullscreen-api.html
@@ -1,106 +1,68 @@
- <!DOCTYPE HTML>
-<html>
-<head>
-  <title>Test for Bug 545812</title>
-  <script type="application/javascript" src="/MochiKit/packed.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=545812">Mozilla Bug 545812</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 545812 **/
-var testWindow = null;
-
-/*
-<html>
-  <body onload='document.body.mozRequestFullScreen();'>
-  </body>
-</html>
-*/
-var requestFullScreenContents = "data:text/html;charset=utf-8,<html>%0D%0A  <body onload%3D'document.body.mozRequestFullScreen()%3B'>%0D%0A  <%2Fbody>%0D%0A<%2Fhtml>";
-
-var prevTrusted = false;
-var prevEnabled = false;
-
-function run() {
-  document.addEventListener("mozfullscreenchange",
-    function(){ok(false, "Should never receive a mozfullscreenchange event in the main window.");},
-    false);
-
-  // Ensure the full-screen api is enabled, and will be disabled on test exit.
-  prevEnabled = SpecialPowers.getBoolPref("full-screen-api.enabled");
-  SpecialPowers.setBoolPref("full-screen-api.enabled", true);
-
-  // Test requesting full-screen mode in a long-running user-generated event handler.
-  // The request in the key handler should not be granted.
-  window.addEventListener("keypress", keyHandler, false);
-  synthesizeKey("VK_A", {});
-}
-
-function keyHandler(event) {
-  window.removeEventListener("keypress", keyHandler, false);
-  
-  // Busy loop until 2s has passed. We should then be past the 1 second threshold, and so
-  // our request for full-screen mode should be rejected.
-  var end = (new Date()).getTime() + 2000;
-  while ((new Date()).getTime() < end) {
-    ; // Wait...
-  }
-  document.body.mozRequestFullScreen();
-
-  prevTrusted = SpecialPowers.getBoolPref("full-screen-api.allow-trusted-requests-only");
-
-  // Request full-screen from a non trusted context (this script isn't a user
-  // generated event!). We should not receive a "mozfullscreenchange" event.
-  SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", true);
-  document.body.mozRequestFullScreen();
-
-  // Disable the requirement for trusted contexts only, so the tests are easier
-  // to write.
-  SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
-
-  // Load an iframe whose contents requests full-screen. This request should
-  // fail, and we should never receive a "mozfullscreenchange" event, because the
-  // iframe doesn't have a mozallowfullscreen attribute.
-  var iframe = document.createElement("iframe");
-  iframe.src = requestFullScreenContents;
-  document.body.appendChild(iframe);
- 
-  // Run the tests which go full-screen in a new window, as mochitests normally
-  // run in an iframe, which by default will not have the mozallowfullscreen
-  // attribute set, so full-screen won't work.
-  testWindow = window.open("file_fullscreen-api.html", "", "width=500,height=500");
-}
-
-function apiTestFinished() {
-  testWindow.close();
-  testWindow = window.open("file_fullscreen-api-keys.html", "", "width=500,height=500");
-}
-
-function keysTestFinished() {
-  testWindow.close();
-  testWindow = window.open("file_fullscreen-plugins.html", "", "width=500,height=500");
-}
-
-function pluginTestFinished() {
-  testWindow.close();
-  SpecialPowers.setBoolPref("full-screen-api.enabled", prevEnabled);
-  SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", prevTrusted);	
-  SimpleTest.finish();
-}
-
-addLoadEvent(run);
-SimpleTest.waitForExplicitFinish();
-
-</script>
-</pre>
-</body>
-</html>
+ <!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Bug 545812</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <style>
+  body {
+    background-color: black;
+  }
+  </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=545812">Mozilla Bug 545812</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Tests for Bug 545812 **/
+
+// Ensure the full-screen api is enabled, and will be disabled on test exit.
+var prevEnabled = SpecialPowers.getBoolPref("full-screen-api.enabled");
+SpecialPowers.setBoolPref("full-screen-api.enabled", true);
+
+// Disable the requirement for trusted contexts only, so the tests are easier
+// to write.
+var prevTrusted = SpecialPowers.getBoolPref("full-screen-api.allow-trusted-requests-only");
+SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
+
+// Run the tests which go full-screen in new windows, as mochitests normally
+// run in an iframe, which by default will not have the mozallowfullscreen
+// attribute set, so full-screen won't work.
+var gTestWindows = [
+  "file_fullscreen-denied.html",
+  "file_fullscreen-api.html",
+  "file_fullscreen-api-keys.html",
+  "file_fullscreen-plugins.html"
+];
+
+var testWindow = null;
+var gTestIndex = 0;
+
+function nextTest() {
+  if (testWindow) {
+    testWindow.close();
+  }
+  if (gTestIndex < gTestWindows.length) {
+    testWindow = window.open(gTestWindows[gTestIndex], "", "width=500,height=500");
+    gTestIndex++;
+  } else {
+    SpecialPowers.setBoolPref("full-screen-api.enabled", prevEnabled);
+    SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", prevTrusted);	
+    SimpleTest.finish();
+  }
+}
+
+addLoadEvent(nextTest);
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -156,16 +156,18 @@ static bool gPlugDetector = false;
 #include "prtime.h"
 
 // Find/Search Includes
 const PRInt32 kForward  = 0;
 const PRInt32 kBackward = 1;
 
 //#define DEBUG_charset
 
+#define NS_USE_NEW_VIEW_SOURCE 1
+
 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
 
 PRUint32       nsHTMLDocument::gWyciwygSessionCnt = 0;
 
 // this function will return false if the command is not recognized
 // inCommandID will be converted as necessary for internal operations
 // inParam will be converted as necessary for internal operations
 // outParam will be Empty if no parameter is needed or if returning a boolean
@@ -571,17 +573,18 @@ nsHTMLDocument::TryDefaultCharset( nsIMa
 
 void
 nsHTMLDocument::StartAutodetection(nsIDocShell *aDocShell, nsACString& aCharset,
                                    const char* aCommand)
 {
   if (mIsRegularHTML && 
       nsHtml5Module::sEnabled && 
       aCommand && 
-      !nsCRT::strcmp(aCommand, "view")) {
+      (!nsCRT::strcmp(aCommand, "view") ||
+       !nsCRT::strcmp(aCommand, "view-source"))) {
     return; // the HTML5 parser uses chardet directly
   }
   nsCOMPtr <nsIParserFilter> cdetflt;
 
   nsresult rv_detect;
   if(!gInitDetector) {
     const nsAdoptingCString& detector_name =
       Preferences::GetLocalizedCString("intl.charset.detector");
@@ -644,48 +647,48 @@ nsresult
 nsHTMLDocument::StartDocumentLoad(const char* aCommand,
                                   nsIChannel* aChannel,
                                   nsILoadGroup* aLoadGroup,
                                   nsISupports* aContainer,
                                   nsIStreamListener **aDocListener,
                                   bool aReset,
                                   nsIContentSink* aSink)
 {
-  bool loadAsHtml5 = nsHtml5Module::sEnabled;
+  bool viewSource = aCommand && !nsCRT::strcmp(aCommand, "view-source") &&
+    NS_USE_NEW_VIEW_SOURCE;
+  bool loadAsHtml5 = nsHtml5Module::sEnabled || viewSource;
+
   if (aSink) {
     loadAsHtml5 = false;
   }
 
   nsCAutoString contentType;
   aChannel->GetContentType(contentType);
 
-  if (contentType.Equals("application/xhtml+xml") &&
-      (!aCommand || nsCRT::strcmp(aCommand, "view-source") != 0)) {
+  if (contentType.Equals("application/xhtml+xml") && !viewSource) {
     // We're parsing XHTML as XML, remember that.
 
     mIsRegularHTML = false;
     mCompatMode = eCompatibility_FullStandards;
     loadAsHtml5 = false;
   }
 #ifdef DEBUG
   else {
     NS_ASSERTION(mIsRegularHTML,
                  "Hey, someone forgot to reset mIsRegularHTML!!!");
   }
 #endif
   
-  if (loadAsHtml5 && 
-      !(contentType.EqualsLiteral("text/html") && 
-        aCommand && 
-        !nsCRT::strcmp(aCommand, "view"))) {
+  if (loadAsHtml5 && !viewSource && !(contentType.EqualsLiteral("text/html") &&
+      aCommand && !nsCRT::strcmp(aCommand, "view"))) {
     loadAsHtml5 = false;
   }
   
   // TODO: Proper about:blank treatment is bug 543435
-  if (loadAsHtml5) {
+  if (loadAsHtml5 && !viewSource) {
     // mDocumentURI hasn't been set, yet, so get the URI from the channel
     nsCOMPtr<nsIURI> uri;
     aChannel->GetOriginalURI(getter_AddRefs(uri));
     // Adapted from nsDocShell:
     // GetSpec can be expensive for some URIs, so check the scheme first.
     bool isAbout = false;
     if (uri && NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) {
       nsCAutoString str;
@@ -723,17 +726,19 @@ nsHTMLDocument::StartDocumentLoad(const 
     return rv;
   }
 
   nsCOMPtr<nsICachingChannel> cachingChan = do_QueryInterface(aChannel);
 
   if (needsParser) {
     if (loadAsHtml5) {
       mParser = nsHtml5Module::NewHtml5Parser();
-      mParser->MarkAsNotScriptCreated();
+      mParser->MarkAsNotScriptCreated((viewSource &&
+        !contentType.EqualsLiteral("text/html")) ?
+        "view-source-xml": aCommand);
     } else {
       mParser = do_CreateInstance(kCParserCID, &rv);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   PRInt32 textType = GET_BIDI_OPTION_TEXTTYPE(GetBidiOptions());
 
--- a/docshell/shistory/src/nsSHEntry.cpp
+++ b/docshell/shistory/src/nsSHEntry.cpp
@@ -61,31 +61,33 @@ static PRUint32 gEntryID = 0;
 //*****************************************************************************
 
 
 nsSHEntry::nsSHEntry()
   : mLoadType(0)
   , mID(gEntryID++)
   , mScrollPositionX(0)
   , mScrollPositionY(0)
+  , mParent(nsnull)
   , mURIWasModified(false)
 {
   mShared = new nsSHEntryShared();
 }
 
 nsSHEntry::nsSHEntry(const nsSHEntry &other)
   : mShared(other.mShared)
   , mURI(other.mURI)
   , mReferrerURI(other.mReferrerURI)
   , mTitle(other.mTitle)
   , mPostData(other.mPostData)
   , mLoadType(0)         // XXX why not copy?
   , mID(other.mID)
   , mScrollPositionX(0)  // XXX why not copy?
   , mScrollPositionY(0)  // XXX why not copy?
+  , mParent(other.mParent)
   , mURIWasModified(other.mURIWasModified)
   , mStateData(other.mStateData)
 {
 }
 
 static bool
 ClearParentPtr(nsISHEntry* aEntry, void* /* aData */)
 {
@@ -412,30 +414,30 @@ nsSHEntry::Clone(nsISHEntry ** aResult)
   NS_ADDREF(*aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHEntry::GetParent(nsISHEntry ** aResult)
 {
   NS_ENSURE_ARG_POINTER(aResult);
-  *aResult = mShared->mParent;
+  *aResult = mParent;
   NS_IF_ADDREF(*aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHEntry::SetParent(nsISHEntry * aParent)
 {
   /* parent not Addrefed on purpose to avoid cyclic reference
    * Null parent is OK
    *
    * XXX this method should not be scriptable if this is the case!!
    */
-  mShared->mParent = aParent;
+  mParent = aParent;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHEntry::SetWindowState(nsISupports *aState)
 {
   mShared->mWindowState = aState;
   return NS_OK;
--- a/docshell/shistory/src/nsSHEntry.h
+++ b/docshell/shistory/src/nsSHEntry.h
@@ -85,14 +85,15 @@ private:
   nsCOMPtr<nsIURI>         mURI;
   nsCOMPtr<nsIURI>         mReferrerURI;
   nsString                 mTitle;
   nsCOMPtr<nsIInputStream> mPostData;
   PRUint32                 mLoadType;
   PRUint32                 mID;
   PRInt32                  mScrollPositionX;
   PRInt32                  mScrollPositionY;
+  nsISHEntry*              mParent;
   nsCOMArray<nsISHEntry>   mChildren;
   bool                     mURIWasModified;
   nsCOMPtr<nsIStructuredCloneContainer> mStateData;
 };
 
 #endif /* nsSHEntry_h */
--- a/docshell/shistory/src/nsSHEntryShared.cpp
+++ b/docshell/shistory/src/nsSHEntryShared.cpp
@@ -88,17 +88,16 @@ void
 nsSHEntryShared::Shutdown()
 {
   delete gHistoryTracker;
   gHistoryTracker = nsnull;
 }
 
 nsSHEntryShared::nsSHEntryShared()
   : mDocShellID(0)
-  , mParent(nsnull)
   , mIsFrameNavigation(false)
   , mSaveLayoutState(true)
   , mSticky(true)
   , mDynamicallyCreated(false)
   , mLastTouched(0)
   , mID(gSHEntrySharedID++)
   , mExpired(false)
   , mViewerBounds(0, 0, 0, 0)
@@ -131,17 +130,16 @@ NS_IMPL_ISUPPORTS2(nsSHEntryShared, nsIB
 already_AddRefed<nsSHEntryShared>
 nsSHEntryShared::Duplicate(nsSHEntryShared *aEntry)
 {
   nsRefPtr<nsSHEntryShared> newEntry = new nsSHEntryShared();
 
   newEntry->mDocShellID = aEntry->mDocShellID;
   newEntry->mChildShells.AppendObjects(aEntry->mChildShells);
   newEntry->mOwner = aEntry->mOwner;
-  newEntry->mParent = aEntry->mParent;
   newEntry->mContentType.Assign(aEntry->mContentType);
   newEntry->mIsFrameNavigation = aEntry->mIsFrameNavigation;
   newEntry->mSaveLayoutState = aEntry->mSaveLayoutState;
   newEntry->mSticky = aEntry->mSticky;
   newEntry->mDynamicallyCreated = aEntry->mDynamicallyCreated;
   newEntry->mCacheKey = aEntry->mCacheKey;
   newEntry->mLastTouched = aEntry->mLastTouched;
 
--- a/docshell/shistory/src/nsSHEntryShared.h
+++ b/docshell/shistory/src/nsSHEntryShared.h
@@ -94,17 +94,16 @@ class nsSHEntryShared : public nsIBFCach
 
     // See nsISHEntry.idl for an explanation of these members.
 
     // These members are copied by nsSHEntryShared::Duplicate().  If you add a
     // member here, be sure to update the Duplicate() implementation.
     PRUint64                        mDocShellID;
     nsCOMArray<nsIDocShellTreeItem> mChildShells;
     nsCOMPtr<nsISupports>           mOwner;
-    nsISHEntry*                     mParent;
     nsCString                       mContentType;
     bool                            mIsFrameNavigation;
     bool                            mSaveLayoutState;
     bool                            mSticky;
     bool                            mDynamicallyCreated;
     nsCOMPtr<nsISupports>           mCacheKey;
     PRUint32                        mLastTouched;
 
--- a/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
+++ b/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
@@ -730,18 +730,16 @@ interface nsIDOMWebGLRenderingContext : 
   void lineWidth(in WebGLfloat width);
   void linkProgram([optional] in nsIWebGLProgram program);
   void pixelStorei(in WebGLenum pname, in WebGLint param);
   void polygonOffset(in WebGLfloat factor, in WebGLfloat units);
 
   void readPixels([optional] in long dummy);
   [noscript] void readPixels_array(in WebGLint x, in WebGLint y, in WebGLsizei width, in WebGLsizei height,
                                    in WebGLenum format, in WebGLenum type, in WebGLJSObjectPtr pixels);
-  [noscript] void readPixels_buf(in WebGLint x, in WebGLint y, in WebGLsizei width, in WebGLsizei height,
-                                 in WebGLenum format, in WebGLenum type, in WebGLJSObjectPtr pixels);
 
   //void glReleaseShaderCompiler();
 
   void renderbufferStorage(in WebGLenum target, in WebGLenum internalformat, in WebGLsizei width, in WebGLsizei height);
   void sampleCoverage(in WebGLclampf value, in WebGLboolean invert);
   void scissor(in WebGLint x, in WebGLint y, in WebGLsizei width, in WebGLsizei height);
 
   // Modified: void glShaderSource(WebGLuint shader, WebGLsizei count, const char** string, const WebGLint* length);
@@ -750,34 +748,28 @@ interface nsIDOMWebGLRenderingContext : 
   void stencilFunc(in WebGLenum func, in WebGLint ref, in WebGLuint mask);
   void stencilFuncSeparate(in WebGLenum face, in WebGLenum func, in WebGLint ref, in WebGLuint mask);
   void stencilMask(in WebGLuint mask);
   void stencilMaskSeparate(in WebGLenum face, in WebGLuint mask);
   void stencilOp(in WebGLenum fail, in WebGLenum zfail, in WebGLenum zpass);
   void stencilOpSeparate(in WebGLenum face, in WebGLenum fail, in WebGLenum zfail, in WebGLenum zpass);
 
   void texImage2D([optional] in long dummy);
-  [noscript] void texImage2D_buf(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);
   [noscript] void texImage2D_array(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);
   [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);
 
   void texSubImage2D([optional] in long dummy);
-  [noscript] void texSubImage2D_buf(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_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,
new file mode 100644
--- /dev/null
+++ b/dom/locales/en-US/chrome/layout/htmlparser.properties
@@ -0,0 +1,152 @@
+# ***** 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 HTML parser error reporting code.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Henri Sivonen <hsivonen@iki.fi>
+#
+# 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 *****
+
+# The bulk of the messages in this file are derived from 
+# http://hg.mozilla.org/projects/htmlparser/file/1f633cef7de7/src/nu/validator/htmlparser/impl/ErrorReportingTokenizer.java
+# which is available under the MIT license.
+
+# Tokenizer errors
+errGarbageAfterLtSlash=Garbage after \u201C</\u201D.
+errLtSlashGt=Saw \u201C</>\u201D. Probable causes: Unescaped \u201C<\u201D (escape as \u201C&lt;\u201D) or mistyped end tag.
+errCharRefLacksSemicolon=Character reference was not terminated by a semicolon.
+errNoDigitsInNCR=No digits in numeric character reference.
+errGtInSystemId=\u201C>\u201D in system identifier.
+errGtInPublicId=\u201C>\u201D in public identifier.
+errNamelessDoctype=Nameless doctype.
+errConsecutiveHyphens=Consecutive hyphens did not terminate a comment. \u201C--\u201D is not permitted inside a comment, but e.g. \u201C- -\u201D is.
+errPrematureEndOfComment=Premature end of comment. Use \u201C-->\u201D to end a comment properly.
+errBogusComment=Bogus comment.
+errUnquotedAttributeLt=\u201C<\u201D in an unquoted attribute value. Probable cause: Missing \u201C>\u201D immediately before.
+errUnquotedAttributeGrave=\u201C`\u201D in an unquoted attribute value. Probable cause: Using the wrong character as a quote.
+errUnquotedAttributeQuote=Quote in an unquoted attribute value. Probable causes: Attributes running together or a URL query string in an unquoted attribute value.
+errUnquotedAttributeEquals=\u201C=\u201D in an unquoted attribute value. Probable causes: Attributes running together or a URL query string in an unquoted attribute value.
+errSlashNotFollowedByGt=A slash was not immediate followed by \u201C>\u201D.
+errNoSpaceBetweenAttributes=No space between attributes.
+errUnquotedAttributeStartLt=\u201C<\u201D at the start of an unquoted attribute value. Probable cause: Missing \u201C>\u201D immediately before
+errUnquotedAttributeStartGrave=\u201C`\u201D at the start of an unquoted attribute value. Probable cause: Using the wrong character as a quote.
+errUnquotedAttributeStartEquals=\u201C=\u201D at the start of an unquoted attribute value. Probable cause: Stray duplicate equals sign.
+errAttributeValueMissing=Attribute value missing.
+errBadCharBeforeAttributeNameLt=Saw \u201C<\u201D when expecting an attribute name. Probable cause: Missing \u201C>\u201D immediately before.
+errEqualsSignBeforeAttributeName=Saw \u201C=\u201D when expecting an attribute name. Probable cause: Attribute name missing.
+errBadCharAfterLt=Bad character after \u201C<\u201D. Probable cause: Unescaped \u201C<\u201D. Try escaping it as \u201C&lt;\u201D.
+errLtGt=Saw \u201C<>\u201D. Probable causes: Unescaped \u201C<\u201D (escape as \u201C&lt;\u201D) or mistyped start tag.
+errProcessingInstruction=Saw \u201C<?\u201D. Probable cause: Attempt to use an XML processing instruction in HTML. (XML processing instructions are not supported in HTML.)
+errUnescapedAmpersandInterpretedAsCharacterReference=The string following \u201C&\u201D was interpreted as a character reference. (\u201C&\u201D probably should have been escaped as \u201C&amp;\u201D.)
+errNotSemicolonTerminated=Named character reference was not terminated by a semicolon. (Or \u201C&\u201D should have been escaped as \u201C&amp;\u201D.)
+errNoNamedCharacterMatch=\u201C&\u201D did not start a character reference. (\u201C&\u201D probably should have been escaped as \u201C&amp;\u201D.)
+errQuoteBeforeAttributeName=Saw a quote when expecting an attribute name. Probable cause: \u201C=\u201D missing immediately before.
+errLtInAttributeName=\u201C<\u201D in attribute name. Probable cause: \u201C>\u201D missing immediately before.
+errQuoteInAttributeName=Quote in attribute name. Probable cause: Matching quote missing somewhere earlier.
+errExpectedPublicId=Expected a public identifier but the doctype ended.
+errBogusDoctype=Bogus doctype.
+maybeErrAttributesOnEndTag=End tag had attributes.
+maybeErrSlashInEndTag=Stray \u201C/\u201D at the end of an end tag.
+errNcrNonCharacter=Character reference expands to a non-character.
+errAstralNonCharacter=Character reference expands to an astral non-character.
+errNcrSurrogate=Character reference expands to a surrogate.
+errNcrControlChar=Character reference expands to a control character.
+errNcrCr=A numeric character reference expanded to carriage return.
+errNcrInC1Range=A numeric character reference expanded to the C1 controls range.
+errEofInPublicId=End of file inside public identifier.
+errEofInComment=End of file inside comment.
+errEofInDoctype=End of file inside doctype.
+errEofInAttributeValue=End of file reached when inside an attribute value. Ignoring tag.
+errEofInAttributeName=End of file occurred in an attribute name. Ignoring tag.
+errEofWithoutGt=Saw end of file without the previous tag ending with \u201C>\u201D. Ignoring tag.
+errEofInTagName=End of file seen when looking for tag name. Ignoring tag.
+errEofInEndTag=End of file inside end tag. Ignoring tag.
+errEofAfterLt=End of file after \u201C<\u201D.
+errNcrOutOfRange=Character reference outside the permissible Unicode range.
+errNcrUnassigned=Character reference expands to a permanently unassigned code point.
+errDuplicateAttribute=Duplicate attribute.
+errEofInSystemId=End of file inside system identifier.
+errExpectedSystemId=Expected a system identifier but the doctype ended.
+errMissingSpaceBeforeDoctypeName=Missing space before doctype name.
+errHyphenHyphenBang=\u201C--!\u201D found in comment.
+errNcrControlChar=Character reference expands to a control character.
+errNcrZero=Character reference expands to zero.
+errNoSpaceBetweenDoctypeSystemKeywordAndQuote=No space between the doctype \u201CSYSTEM\u201D keyword and the quote.
+errNoSpaceBetweenPublicAndSystemIds=No space between the doctype public and system identifiers.
+errNoSpaceBetweenDoctypePublicKeywordAndQuote=No space between the doctype \u201CPUBLIC\u201D keyword and the quote.
+
+# Tree builder errors
+errStrayStartTag=Stray end tag \u201C%1$S\u201D.
+errStrayEndTag=Stray end tag \u201C%1$S\u201D.
+errUnclosedElements=End tag \u201C%1$S\u201D seen, but there were open elements.
+errUnclosedElementsImplied=End tag \u201C%1$S\u201D implied, but there were open elements.
+errUnclosedElementsCell=A table cell was implicitly closed, but there were open elements.
+errStrayDoctype=Stray doctype.
+errAlmostStandardsDoctype=Almost standards mode doctype. Expected \u201C<!DOCTYPE html>\u201D.
+errQuirkyDoctype=Quirky doctype. Expected \u201C<!DOCTYPE html>\u201D.
+errNonSpaceInTrailer=Non-space character in page trailer.
+errNonSpaceAfterFrameset=Non-space after \u201Cframeset\u201D.
+errNonSpaceInFrameset=Non-space in \u201Cframeset\u201D.
+errNonSpaceAfterBody=Non-space character after body.
+errNonSpaceInColgroupInFragment=Non-space in \u201Ccolgroup\u201D when parsing fragment.
+errNonSpaceInNoscriptInHead=Non-space character inside \u201Cnoscript\u201D inside \u201Chead\u201D.
+errFooBetweenHeadAndBody=\u201C%1$S\u201D element between \u201Chead\u201D and \u201Cbody\u201D.
+errStartTagWithoutDoctype=Start tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.
+errNoSelectInTableScope=No \u201Cselect\u201D in table scope.
+errStartSelectWhereEndSelectExpected=\u201Cselect\u201D start tag where end tag expected.
+errStartTagWithSelectOpen=\u201C%1$S\u201D start tag with \u201Cselect\u201D open.
+errBadStartTagInHead=Bad start tag in \u201C%1$S\u201D in \u201Chead\u201D.
+errImage=Saw a start tag \u201Cimage\u201D.
+errIsindex=\u201Cisindex\u201D seen.
+errFooSeenWhenFooOpen=An \u201C%1$S\u201D start tag seen but an element of the same type was already open.
+errHeadingWhenHeadingOpen=Heading cannot be a child of another heading.
+errFramesetStart=\u201Cframeset\u201D start tag seen.
+errNoCellToClose=No cell to close.
+errStartTagInTable=Start tag \u201C%1$S\u201D seen in \u201Ctable\u201D.
+errFormWhenFormOpen=Saw a \u201Cform\u201D start tag, but there was already an active \u201Cform\u201D element. Nested forms are not allowed. Ignoring the tag.
+errTableSeenWhileTableOpen=Start tag for \u201Ctable\u201D seen but the previous \u201Ctable\u201D is still open.
+errStartTagInTableBody=\u201C%1$S\u201D start tag in table body.
+errEndTagSeenWithoutDoctype=End tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.
+errEndTagAfterBody=Saw an end tag after \u201Cbody\u201D had been closed.
+errEndTagSeenWithSelectOpen=\u201C%1$S\u201D end tag with \u201Cselect\u201D open.
+errGarbageInColgroup=Garbage in \u201Ccolgroup\u201D fragment.
+errEndTagBr=End tag \u201Cbr\u201D.
+errNoElementToCloseButEndTagSeen=No \u201C%1$S\u201D element in scope but a \u201C%1$S\u201D end tag seen.
+errHtmlStartTagInForeignContext=HTML start tag \u201C%1$S\u201D in a foreign namespace context.
+errTableClosedWhileCaptionOpen=\u201Ctable\u201D closed but \u201Ccaption\u201D was still open.
+errNoTableRowToClose=No table row to close.
+errNonSpaceInTable=Misplaced non-space characters insided a table.
+errUnclosedChildrenInRuby=Unclosed children in \u201Cruby\u201D.
+errStartTagSeenWithoutRuby=Start tag \u201C%1$S\u201D seen without a \u201Cruby\u201D element being open.
+errSelfClosing=Self-closing syntax (\u201C/>\u201D) used on a non-void HTML element. Ignoring the slash and treating as a start tag.
+errNoCheckUnclosedElementsOnStack=Unclosed elements on stack.
+errEndTagDidNotMatchCurrentOpenElement=End tag \u201C%1$S\u201D did not match the name of the current open element (\u201C%2$S\u201D).
+errEndTagViolatesNestingRules=End tag \u201C%1$S\u201D violates nesting rules.
\ No newline at end of file
--- a/dom/locales/jar.mn
+++ b/dom/locales/jar.mn
@@ -13,15 +13,16 @@
   locale/@AB_CD@/global/charsetTitles.properties               (%chrome/charsetTitles.properties)
   locale/@AB_CD@/global/global-strres.properties               (%chrome/global-strres.properties)
   locale/@AB_CD@/global/plugins.properties                     (%chrome/plugins.properties)
   locale/@AB_CD@/global/nsWebBrowserPersist.properties         (%chrome/nsWebBrowserPersist.properties)
   locale/@AB_CD@/global/xslt/xslt.properties                   (%chrome/xslt/xslt.properties)
   locale/@AB_CD@/global/dom/dom.properties                     (%chrome/dom/dom.properties)
   locale/@AB_CD@/global/svg/svg.properties                     (%chrome/svg/svg.properties)
   locale/@AB_CD@/global/layout/MediaDocument.properties        (%chrome/layout/MediaDocument.properties)
+  locale/@AB_CD@/global/layout/htmlparser.properties           (%chrome/layout/htmlparser.properties)
   locale/@AB_CD@/global/layout/xmlparser.properties            (%chrome/layout/xmlparser.properties)
   locale/@AB_CD@/global/layout/HtmlForm.properties             (%chrome/layout/HtmlForm.properties)
   locale/@AB_CD@/global/security/caps.properties               (%chrome/security/caps.properties)
   locale/@AB_CD@/global/xml/prettyprint.dtd                    (%chrome/xml/prettyprint.dtd)
   locale/@AB_CD@/global-platform/win/accessible.properties     (%chrome/accessibility/win/accessible.properties)
   locale/@AB_CD@/global-platform/mac/accessible.properties     (%chrome/accessibility/mac/accessible.properties)
   locale/@AB_CD@/global-platform/unix/accessible.properties    (%chrome/accessibility/unix/accessible.properties)
--- a/dom/tests/mochitest/chrome/Makefile.in
+++ b/dom/tests/mochitest/chrome/Makefile.in
@@ -40,16 +40,18 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = dom/tests/mochitest/chrome
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = \
+		test_dom_fullscreen_warning.xul \
+		dom_fullscreen_warning.xul \
 		test_fullscreen.xul \
 		fullscreen.xul \
 		test_fullscreen_preventdefault.xul \
 		fullscreen_preventdefault.xul \
 		test_domstorage.xul \
 		domstorage_global.xul \
 		domstorage_global.js \
 		focus_window2.xul \
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/chrome/dom_fullscreen_warning.xul
@@ -0,0 +1,267 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+  Test that "MozShowFullScreenWarning" is dispatched to chrome on restricted keypress.
+-->
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="start();">
+
+<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+<script type="application/javascript"><![CDATA[
+
+// List of key codes, and whether they should cause a warning in full-screen mode.
+var keyList = [
+  // Allowed: DOM_VK_CANCEL to DOM_VK_CAPS_LOCK, inclusive
+  { code: "VK_CANCEL",        warn: false},
+  { code: "VK_HELP",          warn: false},
+  { code: "VK_BACK_SPACE",    warn: false},
+  { code: "VK_TAB",           warn: false},
+  { code: "VK_CLEAR",         warn: false},
+  { code: "VK_RETURN",        warn: false},
+  { code: "VK_ENTER",         warn: false},
+  { code: "VK_SHIFT",         warn: false},
+  { code: "VK_CONTROL",       warn: false},
+  { code: "VK_ALT",           warn: false},
+  { code: "VK_PAUSE",         warn: false},
+  { code: "VK_CAPS_LOCK",     warn: false},
+
+  { code: "VK_KANA",          warn: true},
+  { code: "VK_HANGUL",        warn: true},
+  { code: "VK_JUNJA",         warn: true},
+  { code: "VK_FINAL",         warn: true},
+  { code: "VK_HANJA",         warn: true},
+  { code: "VK_KANJI",         warn: true},
+  { code: "VK_ESCAPE",        warn: false, exit: true},
+  { code: "VK_CONVERT",       warn: true},
+  { code: "VK_NONCONVERT",    warn: true},
+  { code: "VK_ACCEPT",        warn: true},
+  { code: "VK_MODECHANGE",    warn: true},
+
+  // Allowed: DOM_VK_SPACE to DOM_VK_DELETE, inclusive
+  { code: "VK_SPACE",         warn: false},
+  { code: "VK_PAGE_UP",       warn: false},
+  { code: "VK_PAGE_DOWN",     warn: false},
+  { code: "VK_END",           warn: false},
+  { code: "VK_HOME",          warn: false},
+  { code: "VK_LEFT",          warn: false},
+  { code: "VK_UP",            warn: false},
+  { code: "VK_RIGHT",         warn: false},
+  { code: "VK_DOWN",          warn: false},
+  { code: "VK_SELECT",        warn: false},
+  { code: "VK_PRINT",         warn: false},
+  { code: "VK_EXECUTE",       warn: false},
+  { code: "VK_PRINTSCREEN",   warn: false},
+  { code: "VK_INSERT",        warn: false},
+  { code: "VK_DELETE",        warn: false},
+
+  { code: "VK_0",             warn: true},
+  { code: "VK_1",             warn: true},
+  { code: "VK_2",             warn: true},
+  { code: "VK_3",             warn: true},
+  { code: "VK_4",             warn: true},
+  { code: "VK_5",             warn: true},
+  { code: "VK_6",             warn: true},
+  { code: "VK_7",             warn: true},
+  { code: "VK_8",             warn: true},
+  { code: "VK_9",             warn: true},
+
+  // Allowed: DOM_VK_SPACE to DOM_VK_DELETE, inclusive
+  { code: "VK_SEMICOLON",     warn: false},
+  { code: "VK_EQUALS",        warn: false},
+
+  { code: "VK_A",             warn: true},
+  { code: "VK_B",             warn: true},
+  { code: "VK_C",             warn: true},
+  { code: "VK_D",             warn: true},
+  { code: "VK_E",             warn: true},
+  { code: "VK_F",             warn: true},
+  { code: "VK_G",             warn: true},
+  { code: "VK_H",             warn: true},
+  { code: "VK_I",             warn: true},
+  { code: "VK_J",             warn: true},
+  { code: "VK_K",             warn: true},
+  { code: "VK_L",             warn: true},
+  { code: "VK_M",             warn: true},
+  { code: "VK_N",             warn: true},
+  { code: "VK_O",             warn: true},
+  { code: "VK_P",             warn: true},
+  { code: "VK_Q",             warn: true},
+  { code: "VK_R",             warn: true},
+  { code: "VK_S",             warn: true},
+  { code: "VK_T",             warn: true},
+  { code: "VK_U",             warn: true},
+  { code: "VK_V",             warn: true},
+  { code: "VK_W",             warn: true},
+  { code: "VK_X",             warn: true},
+  { code: "VK_Y",             warn: true},
+  { code: "VK_Z",             warn: true},
+  { code: "VK_CONTEXT_MENU",  warn: true},
+  { code: "VK_SLEEP",         warn: true},
+  { code: "VK_NUMPAD0",       warn: true},
+  { code: "VK_NUMPAD1",       warn: true},
+  { code: "VK_NUMPAD2",       warn: true},
+  { code: "VK_NUMPAD3",       warn: true},
+  { code: "VK_NUMPAD4",       warn: true},
+  { code: "VK_NUMPAD5",       warn: true},
+  { code: "VK_NUMPAD6",       warn: true},
+  { code: "VK_NUMPAD7",       warn: true},
+  { code: "VK_NUMPAD8",       warn: true},
+  { code: "VK_NUMPAD9",       warn: true},
+
+  // Allowed: DOM_VK_MULTIPLY to DOM_VK_META, inclusive
+  { code: "VK_MULTIPLY",      warn: false},
+  { code: "VK_ADD",           warn: false},
+  { code: "VK_SEPARATOR",     warn: false},
+  { code: "VK_SUBTRACT",      warn: false},
+  { code: "VK_DECIMAL",       warn: false},
+  { code: "VK_DIVIDE",        warn: false},
+  { code: "VK_F1",            warn: false},
+  { code: "VK_F2",            warn: false},
+  { code: "VK_F3",            warn: false},
+  { code: "VK_F4",            warn: false},
+  { code: "VK_F5",            warn: false},
+  { code: "VK_F6",            warn: false},
+  { code: "VK_F7",            warn: false},
+  { code: "VK_F8",            warn: false},
+  { code: "VK_F9",            warn: false},
+  { code: "VK_F10",           warn: false},
+  { code: "VK_F11",           warn: false}, // F11 exit full-screen handler is in browser.js, so won't cause exit here.
+  { code: "VK_F12",           warn: false},
+  { code: "VK_F13",           warn: false},
+  { code: "VK_F14",           warn: false},
+  { code: "VK_F15",           warn: false},
+  { code: "VK_F16",           warn: false},
+  { code: "VK_F17",           warn: false},
+  { code: "VK_F18",           warn: false},
+  { code: "VK_F19",           warn: false},
+  { code: "VK_F20",           warn: false},
+  { code: "VK_F21",           warn: false},
+  { code: "VK_F22",           warn: false},
+  { code: "VK_F23",           warn: false},
+  { code: "VK_F24",           warn: false},
+  { code: "VK_NUM_LOCK",      warn: false},
+  { code: "VK_SCROLL_LOCK",   warn: false},
+  { code: "VK_COMMA",         warn: false},
+  { code: "VK_PERIOD",        warn: false},
+  { code: "VK_SLASH",         warn: false},
+  { code: "VK_BACK_QUOTE",    warn: false},
+  { code: "VK_OPEN_BRACKET",  warn: false},
+  { code: "VK_BACK_SLASH",    warn: false},
+  { code: "VK_CLOSE_BRACKET", warn: false},
+  { code: "VK_QUOTE",         warn: false},
+  { code: "VK_META",          warn: false},
+];
+
+function ok(condition, msg) {
+  window.opener.wrappedJSObject.ok(condition, msg);
+}
+
+function is(a, b, msg) {
+  window.opener.wrappedJSObject.is(a, b, msg);
+}
+
+var gKeyTestIndex = 0;
+var gKeyName;
+var gKeyCode;
+var gWarningEventReceived = false;
+var gExpectWarning;
+var gExpectExit;
+var gBrowser;
+
+function checkKeyEffect() {
+  is(gBrowser.contentDocument.mozFullScreen, !gExpectExit,
+     (gExpectExit ? ("Should exit full-screen for " + gKeyName + " press ")
+                  : ("Should remain in full-screen for " + gKeyName + " press")));
+  is(gWarningEventReceived, gExpectWarning, "Should " + (gExpectWarning ? "" : "not ") +
+     "receive MozShowFullScreenWarning for " + gKeyName + " press");
+  if (gKeyTestIndex < keyList.length) {
+    setTimeout(startNextTest, 0);
+  } else {
+    gBrowser.contentDocument.mozCancelFullScreen();
+    window.opener.wrappedJSObject.done();
+  }
+}
+
+function testTrustedKeyEvents() {
+  gBrowser.contentWindow.focus();
+  gWarningEventReceived = false;
+  synthesizeKey(gKeyName, {});
+  setTimeout(checkKeyEffect, 0);
+}
+
+function testScriptInitiatedKeyEvents() {
+  // Script initiated untrusted key events should not cause the warning to show.
+  gBrowser.contentWindow.focus();
+  gWarningEventReceived = false;
+  var evt = gBrowser.contentDocument.createEvent("KeyEvents");
+  evt.initKeyEvent("keydown", true, true, window,
+                   false, false, false, false,
+                   gKeyCode, 0);
+  gBrowser.contentDocument.body.dispatchEvent(evt);
+
+  evt = gBrowser.contentDocument.createEvent("KeyEvents");
+  evt.initKeyEvent("keypress", true, true, window,
+                   false, false, false, false,
+                   gKeyCode, 0);
+  gBrowser.contentDocument.body.dispatchEvent(evt);
+
+  evt = gBrowser.contentDocument.createEvent("KeyEvents");
+  evt.initKeyEvent("keyup", true, true, window,
+                   false, false, false, false,
+                   gKeyCode, 0);
+  gBrowser.contentDocument.body.dispatchEvent(evt);
+  
+  setTimeout(checkScriptInitiatedEvents, 0);
+}
+
+function checkScriptInitiatedEvents() {
+  is(gWarningEventReceived, false, "Should not receive MozShowFullScreenWarning on synthesized key events.");
+  ok(gBrowser.contentDocument.mozFullScreen,
+     "Should remain in full-screen mode for script initiated key events for " + gKeyName);
+  testTrustedKeyEvents();
+}
+
+function testNextKey() {
+  ok(gBrowser.contentDocument.mozFullScreen, "Must be in full-screen mode");
+
+  gKeyName = keyList[gKeyTestIndex].code;
+  gKeyCode = KeyEvent["DOM_" + gKeyName];
+  gExpectWarning = keyList[gKeyTestIndex].warn;
+  gExpectExit = (keyList[gKeyTestIndex].exit != undefined) ?
+                 keyList[gKeyTestIndex].exit : false;
+  gKeyTestIndex++;
+
+  testScriptInitiatedKeyEvents();
+}
+
+function startNextTest() {
+  if (!gBrowser.contentDocument.mozFullScreen) {
+    gBrowser.contentDocument.body.mozRequestFullScreen();
+  }
+  // mozRequestFullScreen is async...
+  setTimeout(testNextKey, 0);
+}
+
+function keyHandler(event) {
+  event.preventDefault();
+}
+
+window.addEventListener("MozShowFullScreenWarning", function(){ gWarningEventReceived = true; }, true);
+
+window.addEventListener("keydown", keyHandler, true);
+window.addEventListener("keyup", keyHandler, true);
+window.addEventListener("keypress", keyHandler, true);
+
+function start() {
+  gBrowser = document.getElementById("browser");
+  gBrowser.contentDocument.body.mozRequestFullScreen();
+  setTimeout(startNextTest, 0);
+}
+
+]]>
+</script>
+
+<browser type="content" id="browser" width="400" height="400"/>
+
+</window>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/chrome/test_dom_fullscreen_warning.xul
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+  Test that "MozShowFullScreenWarning" is dispatched to chrome on restricted keypress.
+  -->
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" width="400" height="400">
+
+  <script type="application/javascript" 
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>      
+
+<script>
+SimpleTest.waitForExplicitFinish();
+
+// Ensure the full-screen api is enabled, and will be disabled on test exit.
+var gPrevEnabled = SpecialPowers.getBoolPref("full-screen-api.enabled");
+SpecialPowers.setBoolPref("full-screen-api.enabled", true);
+
+var gPrevTrusted = SpecialPowers.getBoolPref("full-screen-api.allow-trusted-requests-only");
+SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
+
+
+newwindow = window.open("dom_fullscreen_warning.xul", "_blank","chrome,resizable=yes,width=400,height=400");
+
+function done()
+{
+  newwindow.close();
+  SpecialPowers.setBoolPref("full-screen-api.enabled", gPrevEnabled);
+  SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", gPrevTrusted);
+  SimpleTest.finish();
+}
+
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+</window>
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -640,16 +640,17 @@ LayerManagerOGL::FPSState::DrawFPS(GLCon
     (v1 * 4.f + 4) / 64, 7.f / 8,
     (v1 * 4.f + 4) / 64, 0.0f,
   };
 
   // Turn necessary features on
   context->fEnable(LOCAL_GL_BLEND);
   context->fBlendFunc(LOCAL_GL_ONE, LOCAL_GL_SRC_COLOR);
 
+  context->fActiveTexture(LOCAL_GL_TEXTURE0);
   context->fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
 
   copyprog->Activate();
   copyprog->SetTextureUnit(0);
 
   // we're going to use client-side vertex arrays for this.
   context->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 
--- a/gfx/thebes/GLContextProviderCGL.mm
+++ b/gfx/thebes/GLContextProviderCGL.mm
@@ -492,16 +492,30 @@ CreateOffscreenPBufferContext(const gfxI
     printf_stderr("colorbits: %d alpha: %d depth: %d stencil: %d\n", aFormat.colorBits(), aFormat.alpha, aFormat.depth, aFormat.stencil);
 
     NSOpenGLPixelFormat *pbFormat = [[NSOpenGLPixelFormat alloc]
                                      initWithAttributes:attribs.Elements()];
     if (!pbFormat) {
         return nsnull;
     }
 
+    // If we ask for any of these to be on/off and we get the opposite, we stop
+    // creating a pbuffer and instead create an FBO.
+    GLint alphaBits, depthBits, stencilBits;
+    [pbFormat getValues: &alphaBits forAttribute: NSOpenGLPFAAlphaSize forVirtualScreen: 0];
+    [pbFormat getValues: &depthBits forAttribute: NSOpenGLPFADepthSize forVirtualScreen: 0];
+    [pbFormat getValues: &stencilBits forAttribute: NSOpenGLPFAStencilSize forVirtualScreen: 0];
+    if ((alphaBits && !aFormat.alpha) || (!alphaBits && aFormat.alpha) ||
+        (depthBits && !aFormat.alpha) || (!depthBits && aFormat.depth) ||
+        (stencilBits && !aFormat.stencil) || (!stencilBits && aFormat.stencil)) 
+    {
+        [pbFormat release];
+        return nsnull;
+    }
+
     NSOpenGLPixelBuffer *pb = [[NSOpenGLPixelBuffer alloc]
                                initWithTextureTarget:LOCAL_GL_TEXTURE_2D
                                textureInternalFormat:(aFormat.alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB)
                                textureMaxMipMapLevel:0
                                pixelsWide:aSize.width
                                pixelsHigh:aSize.height];
     if (!pb) {
         [pbFormat release];
--- a/intl/locale/src/mac/nsMacCharset.cpp
+++ b/intl/locale/src/mac/nsMacCharset.cpp
@@ -82,17 +82,17 @@ nsPlatformCharset::MapToCharset(nsAStrin
 
 nsresult
 nsPlatformCharset::InitGetCharset(nsACString &oString)
 {
   return NS_OK;
 }
 
 nsresult
-nsPlatformCharset::ConvertLocaleToCharsetUsingDeprecatedConfig(nsAString& locale, nsACString& oResult)
+nsPlatformCharset::ConvertLocaleToCharsetUsingDeprecatedConfig(nsACString& locale, nsACString& oResult)
 {
   return NS_OK;
 }
 
 nsresult
 nsPlatformCharset::VerifyCharset(nsCString &aCharset)
 {
   return NS_OK;
--- a/intl/locale/src/nsLanguageAtomService.cpp
+++ b/intl/locale/src/nsLanguageAtomService.cpp
@@ -124,20 +124,18 @@ nsLanguageAtomService::GetLocaleLanguage
         break;
       }
 
       nsCOMPtr<nsILocale> locale;
       res = localeService->GetApplicationLocale(getter_AddRefs(locale));
       if (NS_FAILED(res))
         break;
 
-      nsAutoString category;
-      category.AssignWithConversion(NSILOCALE_MESSAGE);
       nsAutoString loc;
-      res = locale->GetCategory(category, loc);
+      res = locale->GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), loc);
       if (NS_FAILED(res))
         break;
 
       ToLowerCase(loc); // use lowercase for all language atoms
       mLocaleLanguage = do_GetAtom(loc);
     }
   } while (0);
 
--- a/intl/locale/src/nsLocaleService.cpp
+++ b/intl/locale/src/nsLocaleService.cpp
@@ -221,17 +221,17 @@ nsLocaleService::nsLocaleService(void)
         }
         char* lc_temp;
         for( i = 0; i < LocaleListLength; i++ ) {
             lc_temp = nsnull;
             UniQueryLocaleObject(locale_object,
                                  posix_locale_category[i],
                                  UNI_MBS_STRING_POINTER,
                                  (void **)&lc_temp);
-            category.AssignWithConversion(LocaleList[i]);
+            category.AssignASCII(LocaleList[i]);
             nsresult result;
             if (lc_temp != nsnull)
                 result = os2Converter->GetXPLocale(lc_temp, xpLocale);
             else {
                 char* lang = getenv("LANG");
                 if ( lang == nsnull ) {
                     result = os2Converter->GetXPLocale("en-US", xpLocale);
                 }
@@ -295,17 +295,17 @@ nsLocaleService::NewLocale(const nsAStri
     nsresult result;
 
     *_retval = nsnull;
 
     nsRefPtr<nsLocale> resultLocale(new nsLocale());
     if (!resultLocale) return NS_ERROR_OUT_OF_MEMORY;
 
     for (PRInt32 i = 0; i < LocaleListLength; i++) {
-      nsString category; category.AssignWithConversion(LocaleList[i]);
+      NS_ConvertASCIItoUTF16 category(LocaleList[i]);
       result = resultLocale->AddCategory(category, aLocale);
       if (NS_FAILED(result)) return result;
 #if defined(XP_UNIX) && !defined(XP_MACOSX)
       category.AppendLiteral("##PLATFORM");
       result = resultLocale->AddCategory(category, aLocale);
       if (NS_FAILED(result)) return result;
 #endif
     }
--- a/intl/locale/src/nsPlatformCharset.h
+++ b/intl/locale/src/nsPlatformCharset.h
@@ -53,15 +53,15 @@ public:
   NS_IMETHOD GetDefaultCharsetForLocale(const nsAString& localeName, nsACString& oResult);
 
 private:
   nsCString mCharset;
   nsString mLocale; // remember the locale & charset
 
   nsresult MapToCharset(nsAString& inANSICodePage, nsACString& outCharset);
   nsresult InitGetCharset(nsACString& oString);
-  nsresult ConvertLocaleToCharsetUsingDeprecatedConfig(nsAString& locale, nsACString& oResult);
+  nsresult ConvertLocaleToCharsetUsingDeprecatedConfig(nsACString& locale, nsACString& oResult);
   nsresult VerifyCharset(nsCString &aCharset);
 };
 
 #endif // nsPlatformCharset_h__
 
 
--- a/intl/locale/src/os2/nsOS2Charset.cpp
+++ b/intl/locale/src/os2/nsOS2Charset.cpp
@@ -145,17 +145,17 @@ nsPlatformCharset::Init()
 
 nsresult
 nsPlatformCharset::InitGetCharset(nsACString &oString)
 {
   return NS_OK;
 }
 
 nsresult
-nsPlatformCharset::ConvertLocaleToCharsetUsingDeprecatedConfig(nsAString& locale, nsACString& oResult)
+nsPlatformCharset::ConvertLocaleToCharsetUsingDeprecatedConfig(nsACString& locale, nsACString& oResult)
 {
   return NS_OK;
 }
 
 nsresult
 nsPlatformCharset::VerifyCharset(nsCString &aCharset)
 {
   return NS_OK;
--- a/intl/locale/src/unix/nsAndroidCharset.cpp
+++ b/intl/locale/src/unix/nsAndroidCharset.cpp
@@ -63,17 +63,17 @@ nsPlatformCharset::GetCharset(nsPlatform
 NS_IMETHODIMP 
 nsPlatformCharset::GetDefaultCharsetForLocale(const nsAString& localeName, nsACString &oResult)
 {
   oResult.AssignLiteral("UTF-8");
   return NS_OK;
 }
 
 nsresult
-nsPlatformCharset::ConvertLocaleToCharsetUsingDeprecatedConfig(nsAString& locale, nsACString& oResult)
+nsPlatformCharset::ConvertLocaleToCharsetUsingDeprecatedConfig(nsACString& locale, nsACString& oResult)
 {
   return NS_OK;
 }
 
 nsresult
 nsPlatformCharset::InitGetCharset(nsACString &oString)
 {
   return NS_OK;
--- a/intl/locale/src/unix/nsUNIXCharset.cpp
+++ b/intl/locale/src/unix/nsUNIXCharset.cpp
@@ -71,34 +71,34 @@ static const char* kUnixCharsets[][3] = 
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsPlatformCharset, nsIPlatformCharset)
 
 nsPlatformCharset::nsPlatformCharset()
 {
 }
 
 nsresult
-nsPlatformCharset::ConvertLocaleToCharsetUsingDeprecatedConfig(nsAString& locale, nsACString& oResult)
+nsPlatformCharset::ConvertLocaleToCharsetUsingDeprecatedConfig(nsACString& locale, nsACString& oResult)
 {
   if (!(locale.IsEmpty())) {
     nsCAutoString platformLocaleKey;
     // note: NS_LITERAL_STRING("locale." OSTYPE ".") does not compile on AIX
     platformLocaleKey.AssignLiteral("locale.");
     platformLocaleKey.Append(OSTYPE);
     platformLocaleKey.AppendLiteral(".");
-    platformLocaleKey.AppendWithConversion(locale);
+    platformLocaleKey.Append(locale);
 
     nsresult res = nsUConvPropertySearch::SearchPropertyValue(kUnixCharsets,
         ArrayLength(kUnixCharsets), platformLocaleKey, oResult);
     if (NS_SUCCEEDED(res))  {
       return NS_OK;
     }
     nsCAutoString localeKey;
     localeKey.AssignLiteral("locale.all.");
-    localeKey.AppendWithConversion(locale);
+    localeKey.Append(locale);
     res = nsUConvPropertySearch::SearchPropertyValue(kUnixCharsets,
         ArrayLength(kUnixCharsets), localeKey, oResult);
     if (NS_SUCCEEDED(res))  {
       return NS_OK;
     }
    }
    NS_ERROR("unable to convert locale to charset using deprecated config");
    mCharset.AssignLiteral("ISO-8859-1");
@@ -155,17 +155,17 @@ nsPlatformCharset::GetDefaultCharsetForL
   // until we add multi locale support: use the the charset of the user's locale
   oResult = mCharset;
   return NS_SUCCESS_USING_FALLBACK_LOCALE;
 #else
   //
   // convert from locale to charset
   // using the deprecated locale to charset mapping 
   //
-  nsAutoString localeStr(localeName);
+  NS_LossyConvertUTF16toASCII localeStr(localeName);
   nsresult res = ConvertLocaleToCharsetUsingDeprecatedConfig(localeStr, oResult);
   if (NS_SUCCEEDED(res))
     return res;
 
   NS_ERROR("unable to convert locale to charset using deprecated config");
   oResult.AssignLiteral("ISO-8859-1");
   return NS_SUCCESS_USING_FALLBACK_LOCALE;
 #endif
@@ -196,18 +196,18 @@ nsPlatformCharset::InitGetCharset(nsACSt
 
   NS_ERROR("unable to use nl_langinfo(CODESET)");
 #endif
 
   //
   // try falling back on a deprecated (locale based) name
   //
   char* locale = setlocale(LC_CTYPE, nsnull);
-  nsAutoString localeStr;
-  localeStr.AssignWithConversion(locale);
+  nsCAutoString localeStr;
+  localeStr.Assign(locale);
   res = ConvertLocaleToCharsetUsingDeprecatedConfig(localeStr, oString);
   if (NS_SUCCEEDED(res)) {
     return res; // succeeded
   }
 
   oString.Truncate();
   return res;
 }
--- a/intl/locale/src/windows/nsWinCharset.cpp
+++ b/intl/locale/src/windows/nsWinCharset.cpp
@@ -124,17 +124,17 @@ nsPlatformCharset::Init()
 
 nsresult
 nsPlatformCharset::InitGetCharset(nsACString &oString)
 {
   return NS_OK;
 }
 
 nsresult
-nsPlatformCharset::ConvertLocaleToCharsetUsingDeprecatedConfig(nsAString& locale, nsACString& oResult)
+nsPlatformCharset::ConvertLocaleToCharsetUsingDeprecatedConfig(nsACString& locale, nsACString& oResult)
 {
   return NS_OK;
 }
 
 nsresult
 nsPlatformCharset::VerifyCharset(nsCString &aCharset)
 {
   return NS_OK;
--- a/intl/uconv/tests/nsTestUConv.cpp
+++ b/intl/uconv/tests/nsTestUConv.cpp
@@ -102,26 +102,26 @@ nsresult testCharsetConverterManager()
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 // Helper functions and macros for testing decoders and encoders
 
 #define CREATE_DECODER(_charset)                                \
     nsIUnicodeDecoder * dec;                                    \
-    nsAutoString str;str.AssignWithConversion(_charset);        \
+    nsAutoString str;str.AssignASCII(_charset);                 \
     nsresult res = ccMan->GetUnicodeDecoder(&str,&dec);         \
     if (NS_FAILED(res)) {                                       \
       printf("ERROR at GetUnicodeDecoder() code=0x%x.\n",res);  \
       return res;                                               \
     }
 
 #define CREATE_ENCODER(_charset)                                \
     nsIUnicodeEncoder * enc;                                    \
-    nsAutoString str; str.AssignWithConversion(_charset);       \
+    nsAutoString str; str.AssignASCII(_charset);                \
     nsresult res = ccMan->GetUnicodeEncoder(&str,&enc);         \
     if (NS_FAILED(res)) {                                       \
       printf("ERROR at GetUnicodeEncoder() code=0x%x.\n",res);  \
       return res;                                               \
     }
 
 /**
  * Decoder test.
--- a/js/jsd/jsd_step.c
+++ b/js/jsd/jsd_step.c
@@ -185,17 +185,17 @@ JSBool
                         }
                         /* make sure we're called for the return too. */
                         hookresult = JS_TRUE;
                     } else if (!pdata->recurseDepth && pdata->lastCallStart) {
                         int64 now, ll_delta;
                         jsdouble delta;
                         now = JS_Now();
                         ll_delta = now - pdata->lastCallStart;
-                        delta = (JSFloat64) ll_delta;
+                        delta = ll_delta;
                         delta /= 1000.0;
                         pdata->totalExecutionTime += delta;
                         /* minExecutionTime starts as 0, so we need to overwrite
                          * it on the first call always. */
                         if ((0 == pdata->callCount) ||
                             delta < pdata->minExecutionTime)
                         {
                             pdata->minExecutionTime = delta;
@@ -209,17 +209,17 @@ JSBool
                          * return, and use the running total instead of the
                          * delta calculated above. */
                         if (jsdc->lastReturnTime)
                         {
                             /* Add last chunk to running time, and use total
                              * running time as 'delta'. */
                             ll_delta = now - jsdc->lastReturnTime;
                             pdata->runningTime += ll_delta;
-                            delta = (JSFloat64) pdata->runningTime;
+                            delta = pdata->runningTime;
                             delta /= 1000.0;
                         }
                         
                         pdata->totalOwnExecutionTime += delta;
                         /* See minExecutionTime comment above. */
                         if ((0 == pdata->callCount) ||
                             delta < pdata->minOwnExecutionTime)
                         {
--- a/js/src/assembler/assembler/ARMAssembler.cpp
+++ b/js/src/assembler/assembler/ARMAssembler.cpp
@@ -346,41 +346,40 @@ void ARMAssembler::dataTransferN(bool is
         moveImm(offset, ARMRegisters::S0);
         mem_reg_off(isLoad, isSigned, size, posOffset, rt, base, ARMRegisters::S0);
     }
 }
 
 void ARMAssembler::dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset)
 {
     if (offset >= 0) {
-        if (offset <= 0xfff)
+        if (offset <= 0xfff) {
             // LDR rd, [rb, +offset]
             dtr_u(isLoad, srcDst, base, offset);
-        else if (offset <= 0xfffff) {
+        } else if (offset <= 0xfffff) {
             // Add upper bits of offset to the base, and store the result into the temp register.
             add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | getOp2RotLSL(12));
             // Load using the lower bits of the register.
             dtr_u(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff));
         } else {
             // For even bigger offsets, load the entire offset into a register, then do an
             // indexed load using the base register and the index register.
             moveImm(offset, ARMRegisters::S0);
             dtr_ur(isLoad, srcDst, base, ARMRegisters::S0);
         }
     } else {
         // Negative offsets.
-        offset = -offset;
-        if (offset <= 0xfff)
-            dtr_d(isLoad, srcDst, base, offset);
-        else if (offset <= 0xfffff) {
-            sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | getOp2RotLSL(12));
-            dtr_d(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff));
+        if (offset >= -0xfff) {
+            dtr_d(isLoad, srcDst, base, -offset);
+        } else if (offset >= -0xfffff) {
+            sub_r(ARMRegisters::S0, base, OP2_IMM | (-offset >> 12) | getOp2RotLSL(12));
+            dtr_d(isLoad, srcDst, ARMRegisters::S0, (-offset & 0xfff));
         } else {
             moveImm(offset, ARMRegisters::S0);
-            dtr_dr(isLoad, srcDst, base, ARMRegisters::S0);
+            dtr_ur(isLoad, srcDst, base, ARMRegisters::S0);
         }
     }
 }
 /* this is large, ugly and obsolete.  dataTransferN is superior.*/
 void ARMAssembler::dataTransfer8(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset, bool isSigned)
 {
     if (offset >= 0) {
         if (offset <= 0xfff) {
@@ -397,36 +396,34 @@ void ARMAssembler::dataTransfer8(bool is
         } else {
             moveImm(offset, ARMRegisters::S0);
             if (isSigned)
                 mem_reg_off(isLoad, true, 8, true, srcDst, base, ARMRegisters::S0);
             else
                 dtrb_ur(isLoad, srcDst, base, ARMRegisters::S0);
         }
     } else {
-        offset = -offset;
-        if (offset <= 0xfff) {
+        if (offset >= -0xfff) {
             if (isSigned)
-                mem_imm_off(isLoad, true, 8, false, srcDst, base, offset);
+                mem_imm_off(isLoad, true, 8, false, srcDst, base, -offset);
             else
-                dtrb_d(isLoad, srcDst, base, offset);
-        }
-        else if (offset <= 0xfffff) {
-            sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | getOp2RotLSL(12));
+                dtrb_d(isLoad, srcDst, base, -offset);
+        } else if (offset >= -0xfffff) {
+            sub_r(ARMRegisters::S0, base, OP2_IMM | (-offset >> 12) | getOp2RotLSL(12));
             if (isSigned)
-                mem_imm_off(isLoad, true, 8, false, srcDst, ARMRegisters::S0, (offset & 0xfff));
+                mem_imm_off(isLoad, true, 8, false, srcDst, ARMRegisters::S0, (-offset & 0xfff));
             else
-                dtrb_d(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff));
+                dtrb_d(isLoad, srcDst, ARMRegisters::S0, (-offset & 0xfff));
 
         } else {
             moveImm(offset, ARMRegisters::S0);
             if (isSigned)
-                mem_reg_off(isLoad, true, 8, false, srcDst, base, ARMRegisters::S0);
+                mem_reg_off(isLoad, true, 8, true, srcDst, base, ARMRegisters::S0);
             else
-                dtrb_dr(isLoad, srcDst, base, ARMRegisters::S0);
+                dtrb_ur(isLoad, srcDst, base, ARMRegisters::S0);
                 
         }
     }
 }
 
 // rather X86-like, implements dest <- [base, index * shift + offset]
 void ARMAssembler::baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset)
 {
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/fromCharCode.js
@@ -0,0 +1,8 @@
+/*
+* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/licenses/publicdomain/
+*/
+
+for (var i = 0; i <= 0xFFFF; i++) {
+    assertEq(String.fromCharCode(i).charCodeAt(0), i);
+}
--- a/js/src/jscompat.h
+++ b/js/src/jscompat.h
@@ -45,10 +45,9 @@
  * the NSPR typedef names may be.
  */
 #include "jstypes.h"
 
 typedef JSIntn intN;
 typedef JSUintn uintN;
 typedef JSUword jsuword;
 typedef JSWord jsword;
-typedef float float32;
 #endif /* jscompat_h___ */
--- a/js/src/jsgcmark.h
+++ b/js/src/jsgcmark.h
@@ -173,12 +173,49 @@ void
 MarkChildren(JSTracer *trc, const Shape *shape);
 
 void
 MarkChildren(JSTracer *trc, JSScript *script);
 
 void
 MarkChildren(JSTracer *trc, JSXML *xml);
 
+/*
+ * Use function overloading to decide which function should be called based on
+ * the type of the object. The static type is used at compile time to link to
+ * the corresponding Mark/IsMarked function.
+ */
+inline void
+Mark(JSTracer *trc, const js::Value &v, const char *name)
+{
+    MarkValue(trc, v, name);
+}
+
+inline void
+Mark(JSTracer *trc, JSObject *o, const char *name)
+{
+    MarkObject(trc, *o, name);
+}
+
+inline bool
+IsMarked(JSContext *cx, const js::Value &v)
+{
+    if (v.isMarkable())
+        return !IsAboutToBeFinalized(cx, v.toGCThing());
+    return true;
+}
+
+inline bool
+IsMarked(JSContext *cx, JSObject *o)
+{
+    return !IsAboutToBeFinalized(cx, o);
+}
+
+inline bool
+IsMarked(JSContext *cx, Cell *cell)
+{
+    return !IsAboutToBeFinalized(cx, cell);
+}
+
 }
 }
 
 #endif
--- a/js/src/jsotypes.h
+++ b/js/src/jsotypes.h
@@ -88,11 +88,9 @@ typedef signed char int8;
 typedef JSInt64 int64;
 
 /* /usr/include/model.h on HP-UX defines int8, int16, and int32 */
 typedef JSInt32 int32;
 typedef JSInt16 int16;
 typedef JSInt8 int8;
 #endif /* AIX && HAVE_SYS_INTTYPES_H */
 
-typedef JSFloat64 float64;
-
 #endif /* !defined(PROTYPES_H) */
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -91,17 +91,17 @@ typedef ptrdiff_t jsid;
 # define JSID_BITS(id) (id)
 #endif
 
 JS_BEGIN_EXTERN_C
 
 /* Scalar typedefs. */
 typedef JSInt32   jsint;
 typedef JSUint32  jsuint;
-typedef float64   jsdouble;
+typedef double    jsdouble;
 typedef JSInt32   jsrefcount;   /* PRInt32 if JS_THREADSAFE, see jslock.h */
 
 #ifdef WIN32
 typedef wchar_t   jschar;
 #else
 typedef JSUint16  jschar;
 #endif
 
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -2933,18 +2933,18 @@ js_String(JSContext *cx, uintN argc, Val
             return false;
         vp->setObject(*strobj);
     } else {
         vp->setString(str);
     }
     return true;
 }
 
-static JSBool
-str_fromCharCode(JSContext *cx, uintN argc, Value *vp)
+JSBool
+js::str_fromCharCode(JSContext *cx, uintN argc, Value *vp)
 {
     Value *argv = JS_ARGV(cx, vp);
     JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
     if (argc == 1) {
         uint16_t code;
         if (!ValueToUint16(cx, argv[0], &code))
             return JS_FALSE;
         if (StaticStrings::hasUnit(code)) {
@@ -2969,33 +2969,34 @@ str_fromCharCode(JSContext *cx, uintN ar
     if (!str) {
         cx->free_(chars);
         return JS_FALSE;
     }
     vp->setString(str);
     return JS_TRUE;
 }
 
+
 #ifdef JS_TRACER
 static JSString* FASTCALL
 String_fromCharCode(JSContext* cx, int32 i)
 {
     JS_ASSERT(JS_ON_TRACE(cx));
     jschar c = (jschar)i;
     if (StaticStrings::hasUnit(c))
         return cx->runtime->staticStrings.getUnit(c);
     return js_NewStringCopyN(cx, &c, 1);
 }
 #endif
 
 JS_DEFINE_TRCINFO_1(str_fromCharCode,
     (2, (static, STRING_RETRY, String_fromCharCode, CONTEXT, INT32, 1, nanojit::ACCSET_NONE)))
 
 static JSFunctionSpec string_static_methods[] = {
-    JS_TN("fromCharCode", str_fromCharCode, 1, 0, &str_fromCharCode_trcinfo),
+    JS_TN("fromCharCode", js::str_fromCharCode, 1, 0, &str_fromCharCode_trcinfo),
     JS_FS_END
 };
 
 const Shape *
 StringObject::assignInitialShape(JSContext *cx)
 {
     JS_ASSERT(!cx->compartment->initialStringShape);
     JS_ASSERT(nativeEmpty());
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -199,17 +199,17 @@ extern bool
 CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result);
 
 /*
  * Return true if the string matches the given sequence of ASCII bytes.
  */
 extern bool
 StringEqualsAscii(JSLinearString *str, const char *asciiBytes);
 
-} /* namespacejs */
+} /* namespace js */
 
 extern size_t
 js_strlen(const jschar *s);
 
 extern jschar *
 js_strchr(const jschar *s, jschar c);
 
 extern jschar *
@@ -270,26 +270,27 @@ DeflateStringToBuffer(JSContext *cx, con
 /*
  * Same as DeflateStringToBuffer, but treats 'bytes' as UTF-8 or CESU-8.
  */
 extern bool
 DeflateStringToUTF8Buffer(JSContext *cx, const jschar *chars,
                           size_t charsLength, char *bytes, size_t *length,
                           FlationCoding fc = NormalEncoding);
 
-} /* namespace js */
-
 /*
  * The String.prototype.replace fast-native entry point is exported for joined
  * function optimization in js{interp,tracer}.cpp.
  */
-namespace js {
 extern JSBool
 str_replace(JSContext *cx, uintN argc, js::Value *vp);
-}
+
+extern JSBool
+str_fromCharCode(JSContext *cx, uintN argc, Value *vp);
+
+} /* namespace js */
 
 extern JSBool
 js_str_toString(JSContext *cx, uintN argc, js::Value *vp);
 
 extern JSBool
 js_str_charAt(JSContext *cx, uintN argc, js::Value *vp);
 
 extern JSBool
--- a/js/src/jstypes.h
+++ b/js/src/jstypes.h
@@ -336,23 +336,16 @@ JS_BEGIN_EXTERN_C
 **      define them to be wider (e.g., 32 or even 64 bits). These types are
 **      never valid for fields of a structure.
 ************************************************************************/
 
 typedef int JSIntn;
 typedef unsigned int JSUintn;
 
 /************************************************************************
-** TYPES:       JSFloat64
-** DESCRIPTION:
-**  NSPR's floating point type is always 64 bits.
-************************************************************************/
-typedef double          JSFloat64;
-
-/************************************************************************
 ** TYPES:       JSSize
 ** DESCRIPTION:
 **  A type for representing the size of objects.
 ************************************************************************/
 typedef size_t JSSize;
 
 /************************************************************************
 ** TYPES:       JSPtrDiff
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -771,16 +771,18 @@ private:
     CompileStatus compileArrayWithLength(uint32 argc);
     CompileStatus compileArrayWithArgs(uint32 argc);
 
     enum RoundingMode { Floor, Round };
     CompileStatus compileRound(FrameEntry *arg, RoundingMode mode);
 
     enum GetCharMode { GetChar, GetCharCode };
     CompileStatus compileGetChar(FrameEntry *thisValue, FrameEntry *arg, GetCharMode mode);
+    
+    CompileStatus compileStringFromCode(FrameEntry *arg);
 
     void prepareStubCall(Uses uses);
     Call emitStubCall(void *ptr, DataLabelPtr *pinline);
 };
 
 // Given a stub call, emits the call into the inline assembly path. rejoin
 // indicates how to rejoin should this call trigger expansion/discarding.
 #define INLINE_STUBCALL(stub, rejoin)                                       \
--- a/js/src/methodjit/FastBuiltins.cpp
+++ b/js/src/methodjit/FastBuiltins.cpp
@@ -404,16 +404,49 @@ mjit::Compiler::compileGetChar(FrameEntr
         JS_NOT_REACHED("unknown getchar mode");
     }
 
     stubcc.rejoin(Changes(1));
     return Compile_Okay;
 }
 
 CompileStatus
+mjit::Compiler::compileStringFromCode(FrameEntry *arg)
+{
+    /* Load Char-Code into argReg */
+    RegisterID argReg;
+    if (arg->isConstant()) {
+        argReg = frame.allocReg();
+        masm.move(Imm32(arg->getValue().toInt32()), argReg);
+    } else {
+        argReg = frame.copyDataIntoReg(arg);
+    }
+
+    /* Slow path if there's no unit string for this character. */
+    Jump notUnitString = masm.branch32(Assembler::AboveOrEqual, argReg,
+                                       Imm32(StaticStrings::UNIT_STATIC_LIMIT));
+    stubcc.linkExit(notUnitString, Uses(3));
+
+    /* Load unit string in reg. */
+    masm.lshiftPtr(Imm32(sizeof(JSAtom *) == 4 ? 2 : 3), argReg);
+    masm.addPtr(ImmPtr(&cx->runtime->staticStrings.unitStaticTable), argReg);
+    masm.loadPtr(Address(argReg), argReg);
+
+    stubcc.leave();
+    stubcc.masm.move(Imm32(1), Registers::ArgReg1);
+    OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
+
+    frame.popn(3);
+    frame.pushTypedPayload(JSVAL_TYPE_STRING, argReg);
+
+    stubcc.rejoin(Changes(1));
+    return Compile_Okay;
+}
+
+CompileStatus
 mjit::Compiler::compileArrayPush(FrameEntry *thisValue, FrameEntry *arg)
 {
     /* This behaves like an assignment this[this.length] = arg; */
 
     /* Filter out silly cases. */
     if (frame.haveSameBacking(thisValue, arg) || thisValue->isConstant())
         return Compile_InlineAbort;
 
@@ -867,16 +900,20 @@ mjit::Compiler::inlineNativeFunction(uin
         if (native == js_str_charCodeAt && argType == JSVAL_TYPE_INT32 &&
             thisType == JSVAL_TYPE_STRING && type == JSVAL_TYPE_INT32) {
             return compileGetChar(thisValue, arg, GetCharCode);
         }
         if (native == js_str_charAt && argType == JSVAL_TYPE_INT32 &&
             thisType == JSVAL_TYPE_STRING && type == JSVAL_TYPE_STRING) {
             return compileGetChar(thisValue, arg, GetChar);
         }
+        if (native == js::str_fromCharCode && argType == JSVAL_TYPE_INT32 &&
+            type == JSVAL_TYPE_STRING) {
+            return compileStringFromCode(arg);
+        }
         if (native == js::array_push &&
             thisType == JSVAL_TYPE_OBJECT && type == JSVAL_TYPE_INT32) {
             /*
              * Constraints propagating properties into the 'this' object are
              * generated by TypeConstraintCall during inference.
              */
             if (!thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
                 !arrayPrototypeHasIndexedProperty()) {
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -197,16 +197,17 @@
 #include "imgIEncoder.h"
 #include "gfxPlatform.h"
 
 #include "mozilla/FunctionTimer.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 
 #include "Layers.h"
+#include "nsPLDOMEvent.h"
 
 #ifdef NS_FUNCTION_TIMER
 #define NS_TIME_FUNCTION_DECLARE_DOCURL                \
   nsCAutoString docURL__("N/A");                       \
   nsIURI *uri__ = mDocument->GetDocumentURI();         \
   if (uri__) uri__->GetSpec(docURL__);
 #define NS_TIME_FUNCTION_WITH_DOCURL                   \
   NS_TIME_FUNCTION_DECLARE_DOCURL                      \
@@ -6339,27 +6340,48 @@ PresShell::HandleEventInternal(nsEvent* 
   if (!NS_EVENT_NEEDS_FRAME(aEvent) || GetCurrentEventFrame()) {
     bool isHandlingUserInput = false;
 
     // XXX How about IME events and input events for plugins?
     if (NS_IS_TRUSTED_EVENT(aEvent)) {
       switch (aEvent->message) {
       case NS_KEY_PRESS:
       case NS_KEY_DOWN:
-      case NS_KEY_UP:
-        if (IsFullScreenAndRestrictedKeyEvent(mCurrentEventContent, aEvent) &&
-            aEvent->message == NS_KEY_DOWN) {
-          // We're in DOM full-screen mode, and a key with a restricted key
-          // code has been pressed. Exit full-screen mode.
-          NS_DispatchToCurrentThread(
-            NS_NewRunnableMethod(mCurrentEventContent->OwnerDoc(),
-                                 &nsIDocument::CancelFullScreen));
+      case NS_KEY_UP: {
+        nsIDocument *doc = mCurrentEventContent ?
+                           mCurrentEventContent->OwnerDoc() : nsnull;
+        if (doc &&
+            doc->IsFullScreenDoc() &&
+            static_cast<const nsKeyEvent*>(aEvent)->keyCode == NS_VK_ESCAPE) {
+          // Prevent default action on ESC key press when exiting
+          // DOM full-screen mode. This prevents the browser ESC key
+          // handler from stopping all loads in the document, which
+          // would cause <video> loads to stop.
+          aEvent->flags |= (NS_EVENT_FLAG_NO_DEFAULT |
+                            NS_EVENT_FLAG_ONLY_CHROME_DISPATCH);
+
+          if (aEvent->message == NS_KEY_UP) {
+           // ESC key released while in DOM full-screen mode.
+           // Exit full-screen mode.
+           NS_DispatchToCurrentThread(
+             NS_NewRunnableMethod(mCurrentEventContent->OwnerDoc(),
+                                  &nsIDocument::CancelFullScreen));
+          }
+        } else if (IsFullScreenAndRestrictedKeyEvent(mCurrentEventContent, aEvent)) {
+          // Restricted key press while in DOM full-screen mode. Dispatch
+          // an event to chrome so it knows to show a warning message
+          // informing the user how to exit full-screen.
+          nsRefPtr<nsPLDOMEvent> e =
+            new nsPLDOMEvent(doc, NS_LITERAL_STRING("MozShowFullScreenWarning"),
+                             true, true);
+          e->PostDOMEvent();
         }
         // Else not full-screen mode or key code is unrestricted, fall
         // through to normal handling.
+      }
       case NS_MOUSE_BUTTON_DOWN:
       case NS_MOUSE_BUTTON_UP:
         isHandlingUserInput = true;
         break;
       case NS_DRAGDROP_DROP:
         nsCOMPtr<nsIDragSession> session = nsContentUtils::GetDragSession();
         if (session) {
           bool onlyChromeDrop = false;
--- a/layout/style/nsCSSPseudoClassList.h
+++ b/layout/style/nsCSSPseudoClassList.h
@@ -139,16 +139,20 @@ CSS_STATE_PSEUDO_CLASS(mozDragOver, ":-m
 CSS_STATE_PSEUDO_CLASS(target, ":target", NS_EVENT_STATE_URLTARGET)
 CSS_STATE_PSEUDO_CLASS(indeterminate, ":indeterminate",
                        NS_EVENT_STATE_INDETERMINATE)
 
 // Matches the element which is being displayed full-screen, and
 // any containing frames.
 CSS_STATE_PSEUDO_CLASS(mozFullScreen, ":-moz-full-screen", NS_EVENT_STATE_FULL_SCREEN)
 
+// Matches any element which is an ancestor of the DOM full-screen element,
+// or an ancestor of a containing frame of the full-screen element.
+CSS_STATE_PSEUDO_CLASS(mozFullScreenAncestor, ":-moz-full-screen-ancestor", NS_EVENT_STATE_FULL_SCREEN_ANCESTOR)
+
 // Matches if the element is focused and should show a focus ring
 CSS_STATE_PSEUDO_CLASS(mozFocusRing, ":-moz-focusring", NS_EVENT_STATE_FOCUSRING)
 
 // Image, object, etc state pseudo-classes
 CSS_STATE_PSEUDO_CLASS(mozBroken, ":-moz-broken", NS_EVENT_STATE_BROKEN)
 CSS_STATE_PSEUDO_CLASS(mozUserDisabled, ":-moz-user-disabled",
                        NS_EVENT_STATE_USERDISABLED)
 CSS_STATE_PSEUDO_CLASS(mozSuppressed, ":-moz-suppressed",
--- a/layout/style/ua.css
+++ b/layout/style/ua.css
@@ -236,27 +236,50 @@
 
   * {
     cursor: default !important;
   }
 
 }
 
 *|*:-moz-full-screen {
-  position:fixed;
-  top:0;
-  left:0;
-  right:0;
-  bottom:0;
-  z-index:2147483647;
-  background:black;
+  position: fixed !important;
+  top: 0 !important;
+  left: 0 !important;
+  right: 0 !important;
+  bottom: 0 !important;
+  z-index: 2147483647 !important;
+  background: black;
   width: 100% !important;
   height: 100% !important;
 }
 
+/* If there is a full-screen element that is not the root then
+   we should hide the viewport scrollbar. */
+*|*:root:-moz-full-screen-ancestor {
+  overflow: hidden !important;
+}
+
+*|*:-moz-full-screen-ancestor {
+  /* Ancestors of a full-screen element should not induce stacking contexts
+     that would prevent the full-screen element from being on top. */
+  z-index:auto !important;
+  /* Ancestors of a full-screen element should not be partially transparent,
+     since that would apply to the full-screen element and make the page visible
+     behind it. It would also create a pseudo-stacking-context that would let content
+     draw on top of the full-screen element. */
+  opacity:1 !important;
+  /* Ancestors of a full-screen element should not apply SVG masking, clipping, or
+     filtering, since that would affect the full-screen element and create a pseudo-
+     stacking context. */
+  mask:none !important;
+  clip:none !important;
+  filter:none !important;
+}
+
 /* XML parse error reporting */
 
 parsererror|parsererror {
   display: block;
   font-family: sans-serif;
   font-weight: bold;
   white-space: pre;
   margin: 1em;
--- a/layout/style/viewsource.css
+++ b/layout/style/viewsource.css
@@ -95,17 +95,17 @@ pre {
 .attribute-value {
  color: blue;
  font-weight: normal;
 }
 .markupdeclaration {
  color: steelblue;
  font-style: italic;
 }
-span:not(.error) {
+span:not(.error), a:not(.error) {
  unicode-bidi: embed;
 }
 .error, 
 .error > :-moz-any(.start-tag, .end-tag, .comment, .cdata, .doctype, .pi,
                    .entity, .attribute-name, .attribute-value) {
   color: red;
   font-weight: bold;
 }
--- a/memory/jemalloc/jemalloc.c
+++ b/memory/jemalloc/jemalloc.c
@@ -5937,17 +5937,18 @@ MALLOC_OUT:
 
     /*
      * We only use jemalloc with the 10.6 SDK:
      *   - With the 10.5 SDK, madvise doesn't work, leading to a 20% memory
      *     usage regression (bug 670492).
      *   - With the 10.7 SDK, jemalloc causes the browser to hang (bug 670175).
      */
 
-    osx_use_jemalloc = (default_zone->version == SNOW_LEOPARD_MALLOC_ZONE_T_VERSION);
+    osx_use_jemalloc = (default_zone->version == LEOPARD_MALLOC_ZONE_T_VERSION ||
+                        default_zone->version == SNOW_LEOPARD_MALLOC_ZONE_T_VERSION);
 
     /* Allow us dynamically turn off jemalloc for testing. */
 	if (getenv("NO_MAC_JEMALLOC"))
         osx_use_jemalloc = false;
 
     if (osx_use_jemalloc) {
         size_t size;
 
--- a/other-licenses/nsis/Contrib/ApplicationID/ApplicationID.rc
+++ b/other-licenses/nsis/Contrib/ApplicationID/ApplicationID.rc
@@ -1,11 +1,11 @@
 // Microsoft Visual C++ generated resource script.
 //
-#include "resource1.h"
+#include "resource.h"
 
 #define APSTUDIO_READONLY_SYMBOLS
 /////////////////////////////////////////////////////////////////////////////
 //
 // Generated from the TEXTINCLUDE 2 resource.
 //
 #include "afxres.h"
 
@@ -24,17 +24,17 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_U
 #ifdef APSTUDIO_INVOKED
 /////////////////////////////////////////////////////////////////////////////
 //
 // TEXTINCLUDE
 //
 
 1 TEXTINCLUDE 
 BEGIN
-    "resource1.h\0"
+    "resource.h\0"
 END
 
 2 TEXTINCLUDE 
 BEGIN
     "#include ""afxres.h""\r\n"
     "\0"
 END
 
--- a/parser/html/Makefile.in
+++ b/parser/html/Makefile.in
@@ -102,16 +102,17 @@ CPPSRCS		= \
 		nsHtml5TreeOperation.cpp \
 		nsHtml5TreeOpStage.cpp \
 		nsHtml5StateSnapshot.cpp \
 		nsHtml5TreeOpExecutor.cpp \
 		nsHtml5StreamParser.cpp \
 		nsHtml5Speculation.cpp \
 		nsHtml5SpeculativeLoad.cpp \
 		nsHtml5SVGLoadDispatcher.cpp \
+		nsHtml5Highlighter.cpp \
 		$(NULL)
 
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 INCLUDES	+= \
 		-I$(srcdir)/../../content/base/src \
--- a/parser/html/javasrc/Tokenizer.java
+++ b/parser/html/javasrc/Tokenizer.java
@@ -211,16 +211,20 @@ public class Tokenizer implements Locato
     public static final int SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN = 69;
 
     public static final int SCRIPT_DATA_DOUBLE_ESCAPED_DASH = 70;
 
     public static final int SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH = 71;
 
     public static final int SCRIPT_DATA_DOUBLE_ESCAPE_END = 72;
 
+    public static final int PROCESSING_INSTRUCTION = 73;
+
+    public static final int PROCESSING_INSTRUCTION_QUESTION_MARK = 74;
+
     /**
      * Magic value for UTF-16 operations.
      */
     private static final int LEAD_OFFSET = (0xD800 - (0x10000 >> 10));
 
     /**
      * UTF-16 code unit array containing less than and greater than for emitting
      * those characters on certain parse errors.
@@ -500,16 +504,18 @@ public class Tokenizer implements Locato
     private boolean shouldSuspend;
 
     protected boolean confident;
 
     private int line;
 
     private Interner interner;
 
+    // CPPONLY: private boolean viewingXmlSource;
+
     // [NOCPP[
 
     protected LocatorImpl ampersandLocation;
 
     public Tokenizer(TokenHandler tokenHandler, boolean newAttributesEachTime) {
         this.tokenHandler = tokenHandler;
         this.encodingDeclarationHandler = null;
         this.newAttributesEachTime = newAttributesEachTime;
@@ -526,42 +532,49 @@ public class Tokenizer implements Locato
     // ]NOCPP]
 
     /**
      * The constructor.
      * 
      * @param tokenHandler
      *            the handler for receiving tokens
      */
-    public Tokenizer(TokenHandler tokenHandler) {
+    public Tokenizer(TokenHandler tokenHandler
+    // CPPONLY: , boolean viewingXmlSource        
+    ) {
         this.tokenHandler = tokenHandler;
         this.encodingDeclarationHandler = null;
         // [NOCPP[
         this.newAttributesEachTime = false;
         // ]NOCPP]
         this.bmpChar = new char[1];
         this.astralChar = new char[2];
         this.tagName = null;
         this.attributeName = null;
         this.doctypeName = null;
         this.publicIdentifier = null;
         this.systemIdentifier = null;
         this.attributes = null;
+    // CPPONLY: this.viewingXmlSource = viewingXmlSource;
     }
 
     public void setInterner(Interner interner) {
         this.interner = interner;
     }
 
     public void initLocation(String newPublicId, String newSystemId) {
         this.systemId = newSystemId;
         this.publicId = newPublicId;
 
     }
 
+    // CPPONLY: boolean isViewingXmlSource() {
+    // CPPONLY: return viewingXmlSource;
+    // CPPONLY: }
+
     // [NOCPP[
 
     /**
      * Returns the mappingLangToXmlLang.
      * 
      * @return the mappingLangToXmlLang
      */
     public boolean isMappingLangToXmlLang() {
@@ -1113,20 +1126,26 @@ public class Tokenizer implements Locato
         HtmlAttributes attrs = (attributes == null ? HtmlAttributes.EMPTY_ATTRIBUTES
                 : attributes);
         if (endTag) {
             /*
              * When an end tag token is emitted, the content model flag must be
              * switched to the PCDATA state.
              */
             maybeErrAttributesOnEndTag(attrs);
+            // CPPONLY: if (!viewingXmlSource) {
             tokenHandler.endTag(tagName);
+            // CPPONLY: }
             Portability.delete(attributes);
         } else {
+            // CPPONLY: if (viewingXmlSource) {
+            // CPPONLY: Portability.delete(attributes);
+            // CPPONLY: } else {
             tokenHandler.startTag(tagName, attrs, selfClosing);
+            // CPPONLY: }
         }
         tagName.release();
         tagName = null;
         resetAttributes();
         /*
          * The token handler may have called setStateAndEndTagExpectation
          * and changed stateSave since the start of this method.
          */
@@ -1215,16 +1234,19 @@ public class Tokenizer implements Locato
         if (metaBoundaryPassed && ElementName.META == tagName
                 && AttributeName.CHARSET == attributeName) {
             err("A \u201Ccharset\u201D attribute on a \u201Cmeta\u201D element found after the first 512 bytes.");
         }
         // ]NOCPP]
         if (attributeName != null) {
             String val = longStrBufToString(); // Ownership transferred to
             // HtmlAttributes
+            // CPPONLY: if (mViewSource) {
+            // CPPONLY:   mViewSource.MaybeLinkifyAttributeValue(attributeName, val);
+            // CPPONLY: }
             // [NOCPP[
             if (!endTag && html4 && html4ModeCompatibleWithXhtml1Schemata
                     && attributeName.isCaseFolded()) {
                 val = newAsciiLowerCaseStringFromString(val);
             }
             // ]NOCPP]
             attributes.addAttribute(attributeName, val
             // [NOCPP[
@@ -1311,18 +1333,27 @@ public class Tokenizer implements Locato
                 break;
         }
 
         /**
          * The number of <code>char</code>s in <code>buf</code> that have
          * meaning. (The rest of the array is garbage and should not be
          * examined.)
          */
+        // CPPONLY: if (mViewSource) {
+        // CPPONLY:   mViewSource.SetBuffer(buffer);
+        // CPPONLY:   pos = stateLoop(state, c, pos, buffer.getBuffer(), false, returnState, buffer.getEnd());
+        // CPPONLY:   mViewSource.DropBuffer((pos == buffer.getEnd()) ? pos : pos + 1);
+        // CPPONLY: } else {
+        // CPPONLY:   pos = stateLoop(state, c, pos, buffer.getBuffer(), false, returnState, buffer.getEnd());
+        // CPPONLY: }
+        // [NOCPP[
         pos = stateLoop(state, c, pos, buffer.getBuffer(), false, returnState,
                 buffer.getEnd());
+        // ]NOCPP]
         if (pos == buffer.getEnd()) {
             // exiting due to end of buffer
             buffer.setStart(pos);
         } else {
             buffer.setStart(pos + 1);
         }
         return lastCR;
     }
@@ -1517,16 +1548,23 @@ public class Tokenizer implements Locato
                             case '/':
                                 /*
                                  * U+002F SOLIDUS (/) Switch to the close tag
                                  * open state.
                                  */
                                 state = transition(state, Tokenizer.CLOSE_TAG_OPEN, reconsume, pos);
                                 continue stateloop;
                             case '?':
+                                // CPPONLY: if (viewingXmlSource) {
+                                // CPPONLY: state = transition(state,
+                                // CPPONLY: Tokenizer.PROCESSING_INSTRUCTION,
+                                // CPPONLY: reconsume,
+                                // CPPONLY: pos);
+                                // CPPONLY: continue stateloop;
+                                // CPPONLY: }
                                 /*
                                  * U+003F QUESTION MARK (?) Parse error.
                                  */
                                 errProcessingInstruction();
                                 /*
                                  * Switch to the bogus comment state.
                                  */
                                 clearLongStrBufAndAppend(c);
@@ -3144,16 +3182,17 @@ public class Tokenizer implements Locato
                         }
 
                         /*
                          * Otherwise, return a character token for the character
                          * corresponding to the entity name (as given by the
                          * second column of the named character references
                          * table).
                          */
+                        // CPPONLY: completedNamedCharacterReference();
                         @Const @NoLength char[] val = NamedCharacters.VALUES[candidate];
                         if (
                         // [NOCPP[
                         val.length == 1
                         // ]NOCPP]
                         // CPPONLY: val[1] == 0
                         ) {
                             emitOrAppendOne(val, returnState);
@@ -5698,16 +5737,51 @@ public class Tokenizer implements Locato
                                 appendLongStrBuf(c);
                                 /*
                                  * Stay in the DOCTYPE public identifier
                                  * (single-quoted) state.
                                  */
                                 continue;
                         }
                     }
+                    // XXX reorder point
+                case PROCESSING_INSTRUCTION:
+                    processinginstructionloop: for (;;) {
+                        if (++pos == endPos) {
+                            break stateloop;
+                        }
+                        c = checkChar(buf, pos);
+                        switch (c) {
+                            case '?':
+                                state = transition(
+                                        state,
+                                        Tokenizer.PROCESSING_INSTRUCTION_QUESTION_MARK,
+                                        reconsume, pos);
+                                break processinginstructionloop;
+                            // continue stateloop;
+                            default:
+                                continue;
+                        }
+                    }
+                case PROCESSING_INSTRUCTION_QUESTION_MARK:
+                    if (++pos == endPos) {
+                        break stateloop;
+                    }
+                    c = checkChar(buf, pos);
+                    switch (c) {
+                        case '>':
+                            state = transition(state, Tokenizer.DATA,
+                                    reconsume, pos);
+                            continue stateloop;
+                        default:
+                            state = transition(state,
+                                    Tokenizer.PROCESSING_INSTRUCTION,
+                                    reconsume, pos);
+                            continue stateloop;
+                    }
                     // END HOTSPOT WORKAROUND
             }
         }
         flushChars(buf, pos);
         /*
          * if (prevCR && pos != endPos) { // why is this needed? pos--; col--; }
          */
         // Save locals
--- a/parser/html/javasrc/TreeBuilder.java
+++ b/parser/html/javasrc/TreeBuilder.java
@@ -471,103 +471,25 @@ public abstract class TreeBuilder<T> imp
      *            the message
      * @throws SAXException
      */
     final void errNoCheck(String message) throws SAXException {
         SAXParseException spe = new SAXParseException(message, tokenizer);
         errorHandler.error(spe);
     }
 
-    /**
-     * Reports a stray start tag.
-     * @param name the name of the stray tag
-     * 
-     * @throws SAXException
-     */
-    private void errStrayStartTag(String name) throws SAXException {
-        err("Stray end tag \u201C" + name + "\u201D.");
-    }
-
-    /**
-     * Reports a stray end tag.
-     * @param name the name of the stray tag
-     * 
-     * @throws SAXException
-     */
-    private void errStrayEndTag(String name) throws SAXException {
-        err("Stray end tag \u201C" + name + "\u201D.");
-    }
-    
-    /**
-     * Reports a state when elements expected to be closed were not.
-     * 
-     * @param eltPos the position of the start tag on the stack of the element
-     * being closed.
-     * @param name the name of the end tag
-     * 
-     * @throws SAXException
-     */
-    private void errUnclosedElements(int eltPos, String name) throws SAXException {
-        errNoCheck("End tag \u201C" + name + "\u201D seen, but there were open elements.");
-        errListUnclosedStartTags(eltPos);
-    }
-
-    /**
-     * Reports a state when elements expected to be closed ahead of an implied 
-     * end tag but were not.
-     * 
-     * @param eltPos the position of the start tag on the stack of the element
-     * being closed.
-     * @param name the name of the end tag
-     * 
-     * @throws SAXException
-     */
-    private void errUnclosedElementsImplied(int eltPos, String name) throws SAXException {
-        errNoCheck("End tag \u201C" + name + "\u201D implied, but there were open elements.");
-        errListUnclosedStartTags(eltPos);
-    }
-
-    /**
-     * Reports a state when elements expected to be closed ahead of an implied 
-     * table cell close.
-     * 
-     * @param eltPos the position of the start tag on the stack of the element
-     * being closed.
-     * @throws SAXException
-     */
-    private void errUnclosedElementsCell(int eltPos) throws SAXException {
-        errNoCheck("A table cell was implicitly closed, but there were open elements.");
-        errListUnclosedStartTags(eltPos);
-    }
-    
     private void errListUnclosedStartTags(int eltPos) throws SAXException {
         if (currentPtr != -1) {
             for (int i = currentPtr; i > eltPos; i--) {
                 reportUnclosedElementNameAndLocation(i);
             }
         }
     }
 
     /**
-     * Reports arriving at/near end of document with unclosed elements remaining.
-     * 
-     * @param message
-     *            the message
-     * @throws SAXException
-     */
-    private void errEndWithUnclosedElements(String message) throws SAXException {
-        if (errorHandler == null) {
-            return;
-        }
-        errNoCheck(message);
-        // just report all remaining unclosed elements
-        errListUnclosedStartTags(0);
-    }
-
-    /**
      * Reports the name and location of an unclosed element.
      * 
      * @throws SAXException
      */
     private final void reportUnclosedElementNameAndLocation(int pos) throws SAXException {
         StackNode<T> node = stack[pos];
         if (node.isOptionalEndTag()) {
             return;
@@ -648,16 +570,28 @@ public abstract class TreeBuilder<T> imp
                         contextName);
             } else {
                 tokenizer.setStateAndEndTagExpectation(Tokenizer.DATA, contextName);
             }
             contextName = null;
             contextNode = null;
         } else {
             mode = INITIAL;
+            // If we are viewing XML source, put a foreign element permanently
+            // on the stack so that cdataSectionAllowed() returns true.
+            // CPPONLY: if (tokenizer.isViewingXmlSource()) {
+            // CPPONLY: T elt = createElement("http://www.w3.org/2000/svg",
+            // CPPONLY: "svg",
+            // CPPONLY: tokenizer.emptyAttributes());
+            // CPPONLY: StackNode<T> node = new StackNode<T>(ElementName.SVG,
+            // CPPONLY: "svg",
+            // CPPONLY: elt);
+            // CPPONLY: currentPtr++;
+            // CPPONLY: stack[currentPtr] = node;
+            // CPPONLY: }
         }
     }
 
     public final void doctype(@Local String name, String publicIdentifier,
             String systemIdentifier, boolean forceQuirks) throws SAXException {
         needToDropLF = false;
         if (!isInForeign()) {
             switch (mode) {
@@ -674,23 +608,23 @@ public abstract class TreeBuilder<T> imp
                         Portability.releaseString(emptyString);
                         // [NOCPP[
                     }
                     switch (doctypeExpectation) {
                         case HTML:
                             // ]NOCPP]
                             if (isQuirky(name, publicIdentifier,
                                     systemIdentifier, forceQuirks)) {
-                                err("Quirky doctype. Expected \u201C<!DOCTYPE html>\u201D.");
+                                errQuirkyDoctype();
                                 documentModeInternal(DocumentMode.QUIRKS_MODE,
                                         publicIdentifier, systemIdentifier,
                                         false);
                             } else if (isAlmostStandards(publicIdentifier,
                                     systemIdentifier)) {
-                                err("Almost standards mode doctype. Expected \u201C<!DOCTYPE html>\u201D.");
+                                errAlmostStandardsDoctype();
                                 documentModeInternal(
                                         DocumentMode.ALMOST_STANDARDS_MODE,
                                         publicIdentifier, systemIdentifier,
                                         false);
                             } else {
                                 // [NOCPP[
                                 if ((Portability.literalEqualsString(
                                         "-//W3C//DTD HTML 4.0//EN",
@@ -859,17 +793,17 @@ public abstract class TreeBuilder<T> imp
                     return;
                 default:
                     break;
             }
         }
         /*
          * A DOCTYPE token Parse error.
          */
-        err("Stray doctype.");
+        errStrayDoctype();
         /*
          * Ignore the token.
          */
         return;
     }
 
     // [NOCPP[
 
@@ -929,16 +863,21 @@ public abstract class TreeBuilder<T> imp
     }
 
     /**
      * @see nu.validator.htmlparser.common.TokenHandler#characters(char[], int,
      *      int)
      */
     public final void characters(@Const @NoLength char[] buf, int start, int length)
             throws SAXException {
+        // Note: Can't attach error messages to EOF in C++ yet
+
+        // CPPONLY: if (tokenizer.isViewingXmlSource()) {
+        // CPPONLY: return;
+        // CPPONLY: }
         if (needToDropLF) {
             needToDropLF = false;
             if (buf[start] == '\n') {
                 start++;
                 length--;
                 if (length == 0) {
                     return;
                 }
@@ -1059,16 +998,17 @@ public abstract class TreeBuilder<T> imp
                                      * Parse error.
                                      */
                                     // [NOCPP[
                                     switch (doctypeExpectation) {
                                         case AUTO:
                                             err("Non-space characters found without seeing a doctype first. Expected e.g. \u201C<!DOCTYPE html>\u201D.");
                                             break;
                                         case HTML:
+                                            // XXX figure out a way to report this in the Gecko View Source case
                                             err("Non-space characters found without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.");
                                             break;
                                         case HTML401_STRICT:
                                             err("Non-space characters found without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\u201D.");
                                             break;
                                         case HTML401_TRANSITIONAL:
                                             err("Non-space characters found without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D.");
                                             break;
@@ -1155,17 +1095,17 @@ public abstract class TreeBuilder<T> imp
                                         accumulateCharacters(buf, start, i
                                                 - start);
                                         start = i;
                                     }
                                     /*
                                      * Parse error. Act as if an end tag with
                                      * the tag name "noscript" had been seen
                                      */
-                                    err("Non-space character inside \u201Cnoscript\u201D inside \u201Chead\u201D.");
+                                    errNonSpaceInNoscriptInHead();
                                     flushCharacters();
                                     pop();
                                     mode = IN_HEAD;
                                     /*
                                      * and reprocess the current token.
                                      */
                                     i--;
                                     continue;
@@ -1228,81 +1168,78 @@ public abstract class TreeBuilder<T> imp
                                     }
                                     /*
                                      * Act as if an end tag with the tag name
                                      * "colgroup" had been seen, and then, if
                                      * that token wasn't ignored, reprocess the
                                      * current token.
                                      */
                                     if (currentPtr == 0) {
-                                        err("Non-space in \u201Ccolgroup\u201D when parsing fragment.");
+                                        errNonSpaceInColgroupInFragment();
                                         start = i + 1;
                                         continue;
                                     }
                                     flushCharacters();
                                     pop();
                                     mode = IN_TABLE;
                                     i--;
                                     continue;
                                 case IN_SELECT:
                                 case IN_SELECT_IN_TABLE:
                                     break charactersloop;
                                 case AFTER_BODY:
-                                    err("Non-space character after body.");
+                                    errNonSpaceAfterBody();
                                     fatal();
                                     mode = framesetOk ? FRAMESET_OK : IN_BODY;
                                     i--;
                                     continue;
                                 case IN_FRAMESET:
                                     if (start < i) {
                                         accumulateCharacters(buf, start, i
                                                 - start);
                                         start = i;
                                     }
                                     /*
                                      * Parse error.
                                      */
-                                    err("Non-space in \u201Cframeset\u201D.");
+                                    errNonSpaceInFrameset();
                                     /*
                                      * Ignore the token.
                                      */
                                     start = i + 1;
                                     continue;
                                 case AFTER_FRAMESET:
                                     if (start < i) {
                                         accumulateCharacters(buf, start, i
                                                 - start);
                                         start = i;
                                     }
                                     /*
                                      * Parse error.
                                      */
-                                    err("Non-space after \u201Cframeset\u201D.");
+                                    errNonSpaceAfterFrameset();
                                     /*
                                      * Ignore the token.
                                      */
                                     start = i + 1;
                                     continue;
                                 case AFTER_AFTER_BODY:
                                     /*
                                      * Parse error.
                                      */
-                                    err("Non-space character in page trailer.");
+                                    errNonSpaceInTrailer();
                                     /*
                                      * Switch back to the main mode and
                                      * reprocess the token.
                                      */
                                     mode = framesetOk ? FRAMESET_OK : IN_BODY;
                                     i--;
                                     continue;
                                 case AFTER_AFTER_FRAMESET:
-                                    /*
-                                     * Parse error.
-                                     */
-                                    err("Non-space character in page trailer.");
+                                    errNonSpaceInTrailer();
                                     /*
                                      * Switch back to the main mode and
                                      * reprocess the token.
                                      */
                                     mode = IN_FRAMESET;
                                     i--;
                                     continue;
                             }
@@ -1331,19 +1268,22 @@ public abstract class TreeBuilder<T> imp
                 return;
             }
             accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1);
         }
     }
 
     public final void eof() throws SAXException {
         flushCharacters();
+        // Note: Can't attach error messages to EOF in C++ yet
         eofloop: for (;;) {
             if (isInForeign()) {
+                // [NOCPP[
                 err("End of file in a foreign namespace context.");
+                // ]NOCPP]
                 break eofloop;
             }
             switch (mode) {
                 case INITIAL:
                     /*
                      * Parse error.
                      */
                     // [NOCPP[
@@ -1391,26 +1331,30 @@ public abstract class TreeBuilder<T> imp
                      * reprocess the current token.
                      */
                     continue;
                 case BEFORE_HEAD:
                     appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES);
                     mode = IN_HEAD;
                     continue;
                 case IN_HEAD:
+                    // [NOCPP[
                     if (errorHandler != null && currentPtr > 1) {
-                        errEndWithUnclosedElements("End of file seen and there were open elements.");
+                        errEofWithUnclosedElements();
                     }
+                    // ]NOCPP]
                     while (currentPtr > 0) {
                         popOnEof();
                     }
                     mode = AFTER_HEAD;
                     continue;
                 case IN_HEAD_NOSCRIPT:
-                    errEndWithUnclosedElements("End of file seen and there were open elements.");
+                    // [NOCPP[
+                    errEofWithUnclosedElements();
+                    // ]NOCPP]
                     while (currentPtr > 1) {
                         popOnEof();
                     }
                     mode = IN_HEAD;
                     continue;
                 case AFTER_HEAD:
                     appendToCurrentNodeAndPushBodyElement();
                     mode = IN_BODY;
@@ -1436,43 +1380,47 @@ public abstract class TreeBuilder<T> imp
                             case LI:
                             case P:
                             case TBODY_OR_THEAD_OR_TFOOT:
                             case TD_OR_TH:
                             case BODY:
                             case HTML:
                                 break;
                             default:
-                                errEndWithUnclosedElements("End of file seen and there were open elements.");
+                                errEofWithUnclosedElements();
                                 break openelementloop;
                         }
                     }
                     // ]NOCPP]
                     break eofloop;
                 case TEXT:
+                    // [NOCPP[
                     if (errorHandler != null) {
                         errNoCheck("End of file seen when expecting text or an end tag.");
                         errListUnclosedStartTags(0);
                     }
+                    // ]NOCPP]
                     // XXX mark script as already executed
                     if (originalMode == AFTER_HEAD) {
                         popOnEof();
                     }
                     popOnEof();
                     mode = originalMode;
                     continue;
                 case IN_TABLE_BODY:
                 case IN_ROW:
                 case IN_TABLE:
                 case IN_SELECT:
                 case IN_SELECT_IN_TABLE:
                 case IN_FRAMESET:
+                    // [NOCPP[
                     if (errorHandler != null && currentPtr > 0) {
-                        errEndWithUnclosedElements("End of file seen and there were open elements.");
+                        errEofWithUnclosedElements();
                     }
+                    // ]NOCPP]
                     break eofloop;
                 case AFTER_BODY:
                 case AFTER_FRAMESET:
                 case AFTER_AFTER_BODY:
                 case AFTER_AFTER_FRAMESET:
                 default:
                     // [NOCPP[
                     if (currentPtr == 0) { // This silliness is here to poison
@@ -1567,30 +1515,26 @@ public abstract class TreeBuilder<T> imp
                         case HEAD:
                         case HR:
                         case LI:
                         case META:
                         case NOBR:
                         case P:
                         case PRE_OR_LISTING:
                         case TABLE:
-                            err("HTML start tag \u201C"
-                                    + name
-                                    + "\u201D in a foreign namespace context.");
+                            errHtmlStartTagInForeignContext(name);
                             while (!isSpecialParentInForeign(stack[currentPtr])) {
                                 pop();
                             }
                             continue starttagloop;
                         case FONT:
                             if (attributes.contains(AttributeName.COLOR)
                                     || attributes.contains(AttributeName.FACE)
                                     || attributes.contains(AttributeName.SIZE)) {
-                                err("HTML start tag \u201C"
-                                        + name
-                                        + "\u201D in a foreign namespace context.");
+                                errHtmlStartTagInForeignContext(name);
                                 while (!isSpecialParentInForeign(stack[currentPtr])) {
                                     pop();
                                 }
                                 continue starttagloop;
                             }
                             // else fall thru
                         default:
                             if ("http://www.w3.org/2000/svg" == currNs) {
@@ -1628,18 +1572,17 @@ public abstract class TreeBuilder<T> imp
                             clearStackBackTo(findLastInTableScopeOrRootTbodyTheadTfoot());
                             appendToCurrentNodeAndPushElement(
                                     elementName,
                                     attributes);
                             mode = IN_ROW;
                             attributes = null; // CPP
                             break starttagloop;
                         case TD_OR_TH:
-                            err("\u201C" + name
-                                    + "\u201D start tag in table body.");
+                            errStartTagInTableBody(name);
                             clearStackBackTo(findLastInTableScopeOrRootTbodyTheadTfoot());
                             appendToCurrentNodeAndPushElement(
                                     ElementName.TR,
                                     HtmlAttributes.EMPTY_ATTRIBUTES);
                             mode = IN_ROW;
                             continue;
                         case CAPTION:
                         case COL:
@@ -1672,17 +1615,17 @@ public abstract class TreeBuilder<T> imp
                         case CAPTION:
                         case COL:
                         case COLGROUP:
                         case TBODY_OR_THEAD_OR_TFOOT:
                         case TR:
                             eltPos = findLastOrRoot(TreeBuilder.TR);
                             if (eltPos == 0) {
                                 assert fragment;
-                                err("No table row to close.");
+                                errNoTableRowToClose();
                                 break starttagloop;
                             }
                             clearStackBackTo(eltPos);
                             pop();
                             mode = IN_TABLE_BODY;
                             continue;
                         default:
                             // fall through to IN_TABLE
@@ -1726,26 +1669,26 @@ public abstract class TreeBuilder<T> imp
                             case TD_OR_TH:
                                 clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE));
                                 appendToCurrentNodeAndPushElement(
                                         ElementName.TBODY,
                                         HtmlAttributes.EMPTY_ATTRIBUTES);
                                 mode = IN_TABLE_BODY;
                                 continue starttagloop;
                             case TABLE:
-                                err("Start tag for \u201Ctable\u201D seen but the previous \u201Ctable\u201D is still open.");
+                                errTableSeenWhileTableOpen();
                                 eltPos = findLastInTableScope(name);
                                 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                     assert fragment;
                                     break starttagloop;
                                 }
                                 generateImpliedEndTags();
                                 // XXX is the next if dead code?
                                 if (errorHandler != null && !isCurrent("table")) {
-                                    errNoCheck("Unclosed elements on stack.");
+                                    errNoCheckUnclosedElementsOnStack();
                                 }
                                 while (currentPtr >= eltPos) {
                                     pop();
                                 }
                                 resetTheInsertionMode();
                                 continue starttagloop;
                             case SCRIPT:
                                 // XXX need to manage much more stuff
@@ -1780,27 +1723,26 @@ public abstract class TreeBuilder<T> imp
                                 appendVoidElementToCurrent(
                                         name, attributes,
                                         formPointer);
                                 selfClosing = false;
                                 attributes = null; // CPP
                                 break starttagloop;
                             case FORM:
                                 if (formPointer != null) {
-                                    err("Saw a \u201Cform\u201D start tag, but there was already an active \u201Cform\u201D element. Nested forms are not allowed. Ignoring the tag.");
+                                    errFormWhenFormOpen();
                                     break starttagloop;
                                 } else {
-                                    err("Start tag \u201Cform\u201D seen in \u201Ctable\u201D.");
+                                    errStartTagInTable(name);
                                     appendVoidFormToCurrent(attributes);
                                     attributes = null; // CPP
                                     break starttagloop;
                                 }
                             default:
-                                err("Start tag \u201C" + name
-                                        + "\u201D seen in \u201Ctable\u201D.");
+                                errStartTagInTable(name);
                                 // fall through to IN_BODY
                                 break intableloop;
                         }
                     }
                 case IN_CAPTION:
                     switch (group) {
                         case CAPTION:
                         case COL:
@@ -1810,17 +1752,17 @@ public abstract class TreeBuilder<T> imp
                         case TD_OR_TH:
                             errStrayStartTag(name);
                             eltPos = findLastInTableScope("caption");
                             if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                 break starttagloop;
                             }
                             generateImpliedEndTags();
                             if (errorHandler != null && currentPtr != eltPos) {
-                                errNoCheck("Unclosed elements on stack.");
+                                errNoCheckUnclosedElementsOnStack();
                             }
                             while (currentPtr >= eltPos) {
                                 pop();
                             }
                             clearTheListOfActiveFormattingElementsUpToTheLastMarker();
                             mode = IN_TABLE;
                             continue;
                         default:
@@ -1831,17 +1773,17 @@ public abstract class TreeBuilder<T> imp
                         case CAPTION:
                         case COL:
                         case COLGROUP:
                         case TBODY_OR_THEAD_OR_TFOOT:
                         case TR:
                         case TD_OR_TH:
                             eltPos = findLastInTableScopeTdTh();
                             if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
-                                err("No cell to close.");
+                                errNoCellToClose();
                                 break starttagloop;
                             } else {
                                 closeTheCell(eltPos);
                                 continue;
                             }
                         default:
                             // fall through to IN_BODY
                     }
@@ -1849,17 +1791,17 @@ public abstract class TreeBuilder<T> imp
                     switch (group) {
                         case FRAMESET:
                             if (mode == FRAMESET_OK) {
                                 if (currentPtr == 0 || stack[1].getGroup() != BODY) {
                                     assert fragment;
                                     errStrayStartTag(name);
                                     break starttagloop;
                                 } else {
-                                    err("\u201Cframeset\u201D start tag seen.");
+                                    errFramesetStart();
                                     detachFromParent(stack[1].node);
                                     while (currentPtr > 0) {
                                         pop();
                                     }
                                     appendToCurrentNodeAndPushElement(
                                             elementName,
                                             attributes);
                                     mode = IN_FRAMESET;
@@ -1920,17 +1862,17 @@ public abstract class TreeBuilder<T> imp
                                 break inbodyloop;
                             case BODY:
                                 if (currentPtr == 0
                                         || stack[1].getGroup() != BODY) {
                                     assert fragment;
                                     errStrayStartTag(name);
                                     break starttagloop;
                                 }
-                                err("\u201Cbody\u201D start tag found but the \u201Cbody\u201D element is already open.");
+                                errFooSeenWhenFooOpen(name);
                                 framesetOk = false;
                                 if (mode == FRAMESET_OK) {
                                     mode = IN_BODY;
                                 }
                                 if (addAttributesToBody(attributes)) {
                                     attributes = null; // CPP
                                 }
                                 break starttagloop;
@@ -1942,17 +1884,17 @@ public abstract class TreeBuilder<T> imp
                                 appendToCurrentNodeAndPushElementMayFoster(
                                         elementName,
                                         attributes);
                                 attributes = null; // CPP
                                 break starttagloop;
                             case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6:
                                 implicitlyCloseP();
                                 if (stack[currentPtr].getGroup() == H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) {
-                                    err("Heading cannot be a child of another heading.");
+                                    errHeadingWhenHeadingOpen();
                                     pop();
                                 }
                                 appendToCurrentNodeAndPushElementMayFoster(
                                         elementName,
                                         attributes);
                                 attributes = null; // CPP
                                 break starttagloop;
                             case FIELDSET:
@@ -1967,17 +1909,17 @@ public abstract class TreeBuilder<T> imp
                                 appendToCurrentNodeAndPushElementMayFoster(
                                         elementName,
                                         attributes);
                                 needToDropLF = true;
                                 attributes = null; // CPP
                                 break starttagloop;
                             case FORM:
                                 if (formPointer != null) {
-                                    err("Saw a \u201Cform\u201D start tag, but there was already an active \u201Cform\u201D element. Nested forms are not allowed. Ignoring the tag.");
+                                    errFormWhenFormOpen();
                                     break starttagloop;
                                 } else {
                                     implicitlyCloseP();
                                     appendToCurrentNodeAndPushFormElementMayFoster(attributes);
                                     attributes = null; // CPP
                                     break starttagloop;
                                 }
                             case LI:
@@ -2018,17 +1960,17 @@ public abstract class TreeBuilder<T> imp
                                         attributes);
                                 tokenizer.setStateAndEndTagExpectation(
                                         Tokenizer.PLAINTEXT, elementName);
                                 attributes = null; // CPP
                                 break starttagloop;
                             case A:
                                 int activeAPos = findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker("a");
                                 if (activeAPos != -1) {
-                                    err("An \u201Ca\u201D start tag seen with already an active \u201Ca\u201D element.");
+                                    errFooSeenWhenFooOpen(name);
                                     StackNode<T> activeA = listOfActiveFormattingElements[activeAPos];
                                     activeA.retain();
                                     adoptionAgencyEndTag("a");
                                     removeFromStack(activeA);
                                     activeAPos = findInListOfActiveFormattingElements(activeA);
                                     if (activeAPos != -1) {
                                         removeFromListOfActiveFormattingElements(activeAPos);
                                     }
@@ -2047,30 +1989,29 @@ public abstract class TreeBuilder<T> imp
                                 appendToCurrentNodeAndPushFormattingElementMayFoster(
                                         elementName,
                                         attributes);
                                 attributes = null; // CPP
                                 break starttagloop;
                             case NOBR:
                                 reconstructTheActiveFormattingElements();
                                 if (TreeBuilder.NOT_FOUND_ON_STACK != findLastInScope("nobr")) {
-                                    err("\u201Cnobr\u201D start tag seen when there was an open \u201Cnobr\u201D element in scope.");
+                                    errFooSeenWhenFooOpen(name);
                                     adoptionAgencyEndTag("nobr");
                                     reconstructTheActiveFormattingElements();
                                 }
                                 appendToCurrentNodeAndPushFormattingElementMayFoster(
                                         elementName,
                                         attributes);
                                 attributes = null; // CPP
                                 break starttagloop;
                             case BUTTON:
                                 eltPos = findLastInScope(name);
                                 if (eltPos != TreeBuilder.NOT_FOUND_ON_STACK) {
-                                    err("\u201Cbutton\u201D start tag seen when there was an open \u201Cbutton\u201D element in scope.");
-
+                                    errFooSeenWhenFooOpen(name);
                                     generateImpliedEndTags();
                                     if (errorHandler != null
                                             && !isCurrent(name)) {
                                         errUnclosedElementsImplied(eltPos, name);
                                     }
                                     while (currentPtr >= eltPos) {
                                         pop();
                                     }
@@ -2127,30 +2068,30 @@ public abstract class TreeBuilder<T> imp
                                 implicitlyCloseP();
                                 appendVoidElementToCurrentMayFoster(
                                         elementName,
                                         attributes);
                                 selfClosing = false;
                                 attributes = null; // CPP
                                 break starttagloop;
                             case IMAGE:
-                                err("Saw a start tag \u201Cimage\u201D.");
+                                errImage();
                                 elementName = ElementName.IMG;
                                 continue starttagloop;
                             case KEYGEN:
                             case INPUT:
                                 reconstructTheActiveFormattingElements();
                                 appendVoidElementToCurrentMayFoster(
                                         name, attributes,
                                         formPointer);
                                 selfClosing = false;
                                 attributes = null; // CPP
                                 break starttagloop;
                             case ISINDEX:
-                                err("\u201Cisindex\u201D seen.");
+                                errIsindex();
                                 if (formPointer != null) {
                                     break starttagloop;
                                 }
                                 implicitlyCloseP();
                                 HtmlAttributes formAttrs = new HtmlAttributes(0);
                                 int actionIndex = attributes.getIndex(AttributeName.ACTION);
                                 if (actionIndex > -1) {
                                     formAttrs.addAttribute(
@@ -2305,25 +2246,20 @@ public abstract class TreeBuilder<T> imp
                                  * 
                                  * Insert an HTML element for the token.
                                  */
                                 eltPos = findLastInScope("ruby");
                                 if (eltPos != NOT_FOUND_ON_STACK) {
                                     generateImpliedEndTags();
                                 }
                                 if (eltPos != currentPtr) {
-                                    if (errorHandler != null) {
-                                        if (eltPos != NOT_FOUND_ON_STACK) {
-
-                                            errNoCheck("Start tag \u201C"
-                                                    + name
-                                                    + "\u201D seen without a \u201Cruby\u201D element being open.");
-                                        } else {
-                                            errNoCheck("Unclosed children in \u201Cruby\u201D.");
-                                        }
+                                    if (eltPos != NOT_FOUND_ON_STACK) {
+                                        errStartTagSeenWithoutRuby(name);
+                                    } else {
+                                        errUnclosedChildrenInRuby();
                                     }
                                     while (currentPtr > eltPos) {
                                         pop();
                                     }
                                 }
                                 appendToCurrentNodeAndPushElementMayFoster(
                                         elementName,
                                         attributes);
@@ -2454,17 +2390,17 @@ public abstract class TreeBuilder<T> imp
                                 originalMode = mode;
                                 mode = TEXT;
                                 tokenizer.setStateAndEndTagExpectation(
                                         Tokenizer.RAWTEXT, elementName);
                                 attributes = null; // CPP
                                 break starttagloop;
                             case HEAD:
                                 /* Parse error. */
-                                err("Start tag for \u201Chead\u201D seen when \u201Chead\u201D was already open.");
+                                errFooSeenWhenFooOpen(name);
                                 /* Ignore the token. */
                                 break starttagloop;
                             default:
                                 pop();
                                 mode = AFTER_HEAD;
                                 continue starttagloop;
                         }
                     }
@@ -2501,24 +2437,23 @@ public abstract class TreeBuilder<T> imp
                                     attributes);
                             originalMode = mode;
                             mode = TEXT;
                             tokenizer.setStateAndEndTagExpectation(
                                     Tokenizer.RAWTEXT, elementName);
                             attributes = null; // CPP
                             break starttagloop;
                         case HEAD:
-                            err("Start tag for \u201Chead\u201D seen when \u201Chead\u201D was already open.");
+                            errFooSeenWhenFooOpen(name);
                             break starttagloop;
                         case NOSCRIPT:
-                            err("Start tag for \u201Cnoscript\u201D seen when \u201Cnoscript\u201D was already open.");
+                            errFooSeenWhenFooOpen(name);
                             break starttagloop;
                         default:
-                            err("Bad start tag in \u201C" + name
-                                    + "\u201D in \u201Chead\u201D.");
+                            errBadStartTagInHead(name);
                             pop();
                             mode = IN_HEAD;
                             continue;
                     }
                 case IN_COLUMN_GROUP:
                     switch (group) {
                         case HTML:
                             errStrayStartTag(name);
@@ -2532,33 +2467,31 @@ public abstract class TreeBuilder<T> imp
                                     elementName,
                                     attributes);
                             selfClosing = false;
                             attributes = null; // CPP
                             break starttagloop;
                         default:
                             if (currentPtr == 0) {
                                 assert fragment;
-                                err("Garbage in \u201Ccolgroup\u201D fragment.");
+                                errGarbageInColgroup();
                                 break starttagloop;
                             }
                             pop();
                             mode = IN_TABLE;
                             continue;
                     }
                 case IN_SELECT_IN_TABLE:
                     switch (group) {
                         case CAPTION:
                         case TBODY_OR_THEAD_OR_TFOOT:
                         case TR:
                         case TD_OR_TH:
                         case TABLE:
-                            err("\u201C"
-                                    + name
-                                    + "\u201D start tag with \u201Cselect\u201D open.");
+                            errStartTagWithSelectOpen(name);
                             eltPos = findLastInTableScope("select");
                             if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                 assert fragment;
                                 break starttagloop; // http://www.w3.org/Bugs/Public/show_bug.cgi?id=8375
                             }
                             while (currentPtr >= eltPos) {
                                 pop();
                             }
@@ -2593,35 +2526,33 @@ public abstract class TreeBuilder<T> imp
                                 pop();
                             }
                             appendToCurrentNodeAndPushElement(
                                     elementName,
                                     attributes);
                             attributes = null; // CPP
                             break starttagloop;
                         case SELECT:
-                            err("\u201Cselect\u201D start tag where end tag expected.");
+                            errStartSelectWhereEndSelectExpected();
                             eltPos = findLastInTableScope(name);
                             if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                 assert fragment;
-                                err("No \u201Cselect\u201D in table scope.");
+                                errNoSelectInTableScope();
                                 break starttagloop;
                             } else {
                                 while (currentPtr >= eltPos) {
                                     pop();
                                 }
                                 resetTheInsertionMode();
                                 break starttagloop;
                             }
                         case INPUT:
                         case TEXTAREA:
                         case KEYGEN:
-                            err("\u201C"
-                                    + name
-                                    + "\u201D start tag seen in \u201Cselect\2201D.");
+                            errStartTagWithSelectOpen(name);
                             eltPos = findLastInTableScope("select");
                             if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                 assert fragment;
                                 break starttagloop;
                             }
                             while (currentPtr >= eltPos) {
                                 pop();
                             }
@@ -2705,17 +2636,19 @@ public abstract class TreeBuilder<T> imp
                      * Parse error.
                      */
                     // [NOCPP[
                     switch (doctypeExpectation) {
                         case AUTO:
                             err("Start tag seen without seeing a doctype first. Expected e.g. \u201C<!DOCTYPE html>\u201D.");
                             break;
                         case HTML:
-                            err("Start tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.");
+                            // ]NOCPP]
+                            errStartTagWithoutDoctype();
+                            // [NOCPP[
                             break;
                         case HTML401_STRICT:
                             err("Start tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\u201D.");
                             break;
                         case HTML401_TRANSITIONAL:
                             err("Start tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D.");
                             break;
                         case NO_DOCTYPE_ERRORS:
@@ -2841,75 +2774,73 @@ public abstract class TreeBuilder<T> imp
                         case FRAMESET:
                             appendToCurrentNodeAndPushElement(
                                     elementName,
                                     attributes);
                             mode = IN_FRAMESET;
                             attributes = null; // CPP
                             break starttagloop;
                         case BASE:
-                            err("\u201Cbase\u201D element outside \u201Chead\u201D.");
+                            errFooBetweenHeadAndBody(name);
                             pushHeadPointerOntoStack();
                             appendVoidElementToCurrentMayFoster(
                                     elementName,
                                     attributes);
                             selfClosing = false;
                             pop(); // head
                             attributes = null; // CPP
                             break starttagloop;
                         case LINK_OR_BASEFONT_OR_BGSOUND:
-                            err("\u201Clink\u201D element outside \u201Chead\u201D.");
+                            errFooBetweenHeadAndBody(name);
                             pushHeadPointerOntoStack();
                             appendVoidElementToCurrentMayFoster(
                                     elementName,
                                     attributes);
                             selfClosing = false;
                             pop(); // head
                             attributes = null; // CPP
                             break starttagloop;
                         case META:
-                            err("\u201Cmeta\u201D element outside \u201Chead\u201D.");
+                            errFooBetweenHeadAndBody(name);
                             checkMetaCharset(attributes);
                             pushHeadPointerOntoStack();
                             appendVoidElementToCurrentMayFoster(
                                     elementName,
                                     attributes);
                             selfClosing = false;
                             pop(); // head
                             attributes = null; // CPP
                             break starttagloop;
                         case SCRIPT:
-                            err("\u201Cscript\u201D element between \u201Chead\u201D and \u201Cbody\u201D.");
+                            errFooBetweenHeadAndBody(name);
                             pushHeadPointerOntoStack();
                             appendToCurrentNodeAndPushElement(
                                     elementName,
                                     attributes);
                             originalMode = mode;
                             mode = TEXT;
                             tokenizer.setStateAndEndTagExpectation(
                                     Tokenizer.SCRIPT_DATA, elementName);
                             attributes = null; // CPP
                             break starttagloop;
                         case STYLE:
                         case NOFRAMES:
-                            err("\u201C"
-                                    + name
-                                    + "\u201D element between \u201Chead\u201D and \u201Cbody\u201D.");
+                            errFooBetweenHeadAndBody(name);
                             pushHeadPointerOntoStack();
                             appendToCurrentNodeAndPushElement(
                                     elementName,
                                     attributes);
                             originalMode = mode;
                             mode = TEXT;
                             tokenizer.setStateAndEndTagExpectation(
                                     Tokenizer.RAWTEXT, elementName);
                             attributes = null; // CPP
                             break starttagloop;
                         case TITLE:
-                            err("\u201Ctitle\u201D element outside \u201Chead\u201D.");
+                            errFooBetweenHeadAndBody(name);
                             pushHeadPointerOntoStack();
                             appendToCurrentNodeAndPushElement(
                                     elementName,
                                     attributes);
                             originalMode = mode;
                             mode = TEXT;
                             tokenizer.setStateAndEndTagExpectation(
                                     Tokenizer.RCDATA, elementName);
@@ -2962,18 +2893,18 @@ public abstract class TreeBuilder<T> imp
                             break starttagloop;
                     }
                 case TEXT:
                     assert false;
                     break starttagloop; // Avoid infinite loop if the assertion
                                         // fails
             }
         }
-        if (errorHandler != null && selfClosing) {
-            errNoCheck("Self-closing syntax (\u201C/>\u201D) used on a non-void HTML element. Ignoring the slash and treating as a start tag.");
+        if (selfClosing) {
+            errSelfClosing();
         }
         if (attributes != HtmlAttributes.EMPTY_ATTRIBUTES) {
             Portability.delete(attributes);
         }
     }
 
     private boolean isSpecialParentInForeign(StackNode<T> stackNode) {
         @NsUri String ns = stackNode.ns;
@@ -3179,21 +3110,18 @@ public abstract class TreeBuilder<T> imp
     public final void endTag(ElementName elementName) throws SAXException {
         flushCharacters();
         needToDropLF = false;
         int eltPos;
         int group = elementName.getGroup();
         @Local String name = elementName.name;
         endtagloop: for (;;) {
             if (isInForeign()) {
-                if (errorHandler != null && stack[currentPtr].name != name) {
-                    errNoCheck("End tag \u201C"
-                            + name
-                            + "\u201D did not match the name of the current open element (\u201C"
-                            + stack[currentPtr].popName + "\u201D).");
+                if (stack[currentPtr].name != name) {
+                    errEndTagDidNotMatchCurrentOpenElement(name, stack[currentPtr].popName);
                 }
                 eltPos = currentPtr;
                 for (;;) {
                     if (stack[eltPos].name == name) {
                         while (currentPtr >= eltPos) {
                             pop();
                         }
                         break endtagloop;
@@ -3205,43 +3133,43 @@ public abstract class TreeBuilder<T> imp
             }
             switch (mode) {
                 case IN_ROW:
                     switch (group) {
                         case TR:
                             eltPos = findLastOrRoot(TreeBuilder.TR);
                             if (eltPos == 0) {
                                 assert fragment;
-                                err("No table row to close.");
+                                errNoTableRowToClose();
                                 break endtagloop;
                             }
                             clearStackBackTo(eltPos);
                             pop();
                             mode = IN_TABLE_BODY;
                             break endtagloop;
                         case TABLE:
                             eltPos = findLastOrRoot(TreeBuilder.TR);
                             if (eltPos == 0) {
                                 assert fragment;
-                                err("No table row to close.");
+                                errNoTableRowToClose();
                                 break endtagloop;
                             }
                             clearStackBackTo(eltPos);
                             pop();
                             mode = IN_TABLE_BODY;
                             continue;
                         case TBODY_OR_THEAD_OR_TFOOT:
                             if (findLastInTableScope(name) == TreeBuilder.NOT_FOUND_ON_STACK) {
                                 errStrayEndTag(name);
                                 break endtagloop;
                             }
                             eltPos = findLastOrRoot(TreeBuilder.TR);
                             if (eltPos == 0) {
                                 assert fragment;
-                                err("No table row to close.");
+                                errNoTableRowToClose();
                                 break endtagloop;
                             }
                             clearStackBackTo(eltPos);
                             pop();
                             mode = IN_TABLE_BODY;
                             continue;
                         case BODY:
                         case CAPTION:
@@ -3330,17 +3258,17 @@ public abstract class TreeBuilder<T> imp
                             }
                             while (currentPtr >= eltPos) {
                                 pop();
                             }
                             clearTheListOfActiveFormattingElementsUpToTheLastMarker();
                             mode = IN_TABLE;
                             break endtagloop;
                         case TABLE:
-                            err("\u201Ctable\u201D closed but \u201Ccaption\u201D was still open.");
+                            errTableClosedWhileCaptionOpen();
                             eltPos = findLastInTableScope("caption");
                             if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                 break endtagloop;
                             }
                             generateImpliedEndTags();
                             if (errorHandler != null && currentPtr != eltPos) {
                                 errUnclosedElements(eltPos, name);
                             }
@@ -3417,17 +3345,17 @@ public abstract class TreeBuilder<T> imp
                                         case OPTGROUP:
                                         case OPTION: // is this possible?
                                         case P:
                                         case RT_OR_RP:
                                         case TD_OR_TH:
                                         case TBODY_OR_THEAD_OR_TFOOT:
                                             break;
                                         default:
-                                            errEndWithUnclosedElements("End tag for \u201Cbody\u201D seen but there were unclosed elements.");
+                                            errEndWithUnclosedElements(name);
                                             break uncloseloop1;
                                     }
                                 }
                             }
                             mode = AFTER_BODY;
                             break endtagloop;
                         case HTML:
                             if (!isSecondOnStackBody()) {
@@ -3442,17 +3370,17 @@ public abstract class TreeBuilder<T> imp
                                         case LI:
                                         case P:
                                         case TBODY_OR_THEAD_OR_TFOOT:
                                         case TD_OR_TH:
                                         case BODY:
                                         case HTML:
                                             break;
                                         default:
-                                            errEndWithUnclosedElements("End tag for \u201Chtml\u201D seen but there were unclosed elements.");
+                                            errEndWithUnclosedElements(name);
                                             break uncloseloop2;
                                     }
                                 }
                             }
                             mode = AFTER_BODY;
                             continue;
                         case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
                         case UL_OR_OL_OR_DL:
@@ -3488,22 +3416,20 @@ public abstract class TreeBuilder<T> imp
                             if (errorHandler != null && !isCurrent(name)) {
                                 errUnclosedElements(eltPos, name);
                             }
                             removeFromStack(eltPos);
                             break endtagloop;
                         case P:
                             eltPos = findLastInButtonScope("p");
                             if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
-                                err("No \u201Cp\u201D element in scope but a \u201Cp\u201D end tag seen.");
+                                errNoElementToCloseButEndTagSeen("p");
                                 // XXX Can the 'in foreign' case happen anymore?
                                 if (isInForeign()) {
-                                    err("HTML start tag \u201C"
-                                            + name
-                                            + "\u201D in a foreign namespace context.");
+                                    errHtmlStartTagInForeignContext(name);
                                     while (stack[currentPtr].ns != "http://www.w3.org/1999/xhtml") {
                                         pop();
                                     }
                                 }
                                 appendVoidElementToCurrentMayFoster(
                                         elementName,
                                         HtmlAttributes.EMPTY_ATTRIBUTES);
                                 break endtagloop;
@@ -3515,35 +3441,32 @@ public abstract class TreeBuilder<T> imp
                             }
                             while (currentPtr >= eltPos) {
                                 pop();
                             }
                             break endtagloop;
                         case LI:
                             eltPos = findLastInListScope(name);
                             if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
-                                err("No \u201Cli\u201D element in list scope but a \u201Cli\u201D end tag seen.");
+                                errNoElementToCloseButEndTagSeen(name);
                             } else {
                                 generateImpliedEndTagsExceptFor(name);
                                 if (errorHandler != null
                                         && eltPos != currentPtr) {
                                     errUnclosedElements(eltPos, name);
                                 }
                                 while (currentPtr >= eltPos) {
                                     pop();
                                 }
                             }
                             break endtagloop;
                         case DD_OR_DT:
                             eltPos = findLastInScope(name);
                             if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
-                                err("No \u201C"
-                                        + name
-                                        + "\u201D element in scope but a \u201C"
-                                        + name + "\u201D end tag seen.");
+                                errNoElementToCloseButEndTagSeen(name);
                             } else {
                                 generateImpliedEndTagsExceptFor(name);
                                 if (errorHandler != null
                                         && eltPos != currentPtr) {
                                     errUnclosedElements(eltPos, name);
                                 }
                                 while (currentPtr >= eltPos) {
                                     pop();
@@ -3576,21 +3499,19 @@ public abstract class TreeBuilder<T> imp
                                 }
                                 while (currentPtr >= eltPos) {
                                     pop();
                                 }
                                 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
                             }
                             break endtagloop;
                         case BR:
-                            err("End tag \u201Cbr\u201D.");
+                            errEndTagBr();
                             if (isInForeign()) {
-                                err("HTML start tag \u201C"
-                                        + name
-                                        + "\u201D in a foreign namespace context.");
+                                errHtmlStartTagInForeignContext(name);
                                 while (stack[currentPtr].ns != "http://www.w3.org/1999/xhtml") {
                                     pop();
                                 }
                             }
                             reconstructTheActiveFormattingElements();
                             appendVoidElementToCurrentMayFoster(
                                     elementName,
                                     HtmlAttributes.EMPTY_ATTRIBUTES);
@@ -3652,45 +3573,43 @@ public abstract class TreeBuilder<T> imp
                                 eltPos--;
                             }
                     }
                 case IN_COLUMN_GROUP:
                     switch (group) {
                         case COLGROUP:
                             if (currentPtr == 0) {
                                 assert fragment;
-                                err("Garbage in \u201Ccolgroup\u201D fragment.");
+                                errGarbageInColgroup();
                                 break endtagloop;
                             }
                             pop();
                             mode = IN_TABLE;
                             break endtagloop;
                         case COL:
                             errStrayEndTag(name);
                             break endtagloop;
                         default:
                             if (currentPtr == 0) {
                                 assert fragment;
-                                err("Garbage in \u201Ccolgroup\u201D fragment.");
+                                errGarbageInColgroup();
                                 break endtagloop;
                             }
                             pop();
                             mode = IN_TABLE;
                             continue;
                     }
                 case IN_SELECT_IN_TABLE:
                     switch (group) {
                         case CAPTION:
                         case TABLE:
                         case TBODY_OR_THEAD_OR_TFOOT:
                         case TR:
                         case TD_OR_TH:
-                            err("\u201C"
-                                    + name
-                                    + "\u201D end tag with \u201Cselect\u201D open.");
+                            errEndTagSeenWithSelectOpen(name);
                             if (findLastInTableScope(name) != TreeBuilder.NOT_FOUND_ON_STACK) {
                                 eltPos = findLastInTableScope("select");
                                 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                     assert fragment;
                                     break endtagloop; // http://www.w3.org/Bugs/Public/show_bug.cgi?id=8375
                                 }
                                 while (currentPtr >= eltPos) {
                                     pop();
@@ -3746,17 +3665,17 @@ public abstract class TreeBuilder<T> imp
                             if (fragment) {
                                 errStrayEndTag(name);
                                 break endtagloop;
                             } else {
                                 mode = AFTER_AFTER_BODY;
                                 break endtagloop;
                             }
                         default:
-                            err("Saw an end tag after \u201Cbody\u201D had been closed.");
+                            errEndTagAfterBody();
                             mode = framesetOk ? FRAMESET_OK : IN_BODY;
                             continue;
                     }
                 case IN_FRAMESET:
                     switch (group) {
                         case FRAMESET:
                             if (currentPtr == 0) {
                                 assert fragment;
@@ -3786,17 +3705,19 @@ public abstract class TreeBuilder<T> imp
                      * Parse error.
                      */
                     // [NOCPP[
                     switch (doctypeExpectation) {
                         case AUTO:
                             err("End tag seen without seeing a doctype first. Expected e.g. \u201C<!DOCTYPE html>\u201D.");
                             break;
                         case HTML:
-                            err("End tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.");
+                            // ]NOCPP]
+                            errEndTagSeenWithoutDoctype();
+                            // [NOCPP[
                             break;
                         case HTML401_STRICT:
                             err("End tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\u201D.");
                             break;
                         case HTML401_TRANSITIONAL:
                             err("End tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D.");
                             break;
                         case NO_DOCTYPE_ERRORS:
@@ -4372,27 +4293,27 @@ public abstract class TreeBuilder<T> imp
                 if (node == formattingElt) {
                     break;
                 } else if (node.isScoping()) {
                     inScope = false;
                 }
                 formattingEltStackPos--;
             }
             if (formattingEltStackPos == -1) {
-                err("No element \u201C" + name + "\u201D to close.");
+                errNoElementToCloseButEndTagSeen(name);
                 removeFromListOfActiveFormattingElements(formattingEltListPos);
                 return true;
             }
             if (!inScope) {
-                err("No element \u201C" + name + "\u201D to close.");
+                errNoElementToCloseButEndTagSeen(name);
                 return true;
             }
             // stackPos now points to the formatting element and it is in scope
-            if (errorHandler != null && formattingEltStackPos != currentPtr) {
-                errNoCheck("End tag \u201C" + name + "\u201D violates nesting rules.");
+            if (formattingEltStackPos != currentPtr) {
+                errEndTagViolatesNestingRules(name);
             }
             int furthestBlockPos = formattingEltStackPos + 1;
             while (furthestBlockPos <= currentPtr) {
                 StackNode<T> node = stack[furthestBlockPos]; // weak ref
                 if (node.isSpecial()) {
                     break;
                 }
                 furthestBlockPos++;
@@ -5405,17 +5326,17 @@ public abstract class TreeBuilder<T> imp
     /**
      * Flushes the pending characters. Public for document.write use cases only.
      * @throws SAXException
      */
     public final void flushCharacters() throws SAXException {
         if (charBufferLen > 0) {
             if ((mode == IN_TABLE || mode == IN_TABLE_BODY || mode == IN_ROW)
                     && charBufferContainsNonWhitespace()) {
-                err("Misplaced non-space characters insided a table.");
+                errNonSpaceInTable();
                 reconstructTheActiveFormattingElements();
                 if (!stack[currentPtr].isFosterParenting()) {
                     // reconstructing gave us a new current node
                     appendCharacters(currentNode(), charBuffer, 0,
                             charBufferLen);
                     charBufferLen = 0;
                     return;
                 }
@@ -5712,9 +5633,318 @@ public abstract class TreeBuilder<T> imp
 
     /**
      * @see nu.validator.htmlparser.impl.TreeBuilderState#getStackLength()
      */
     public int getStackLength() {
         return currentPtr + 1;
     }
 
+    /**
+     * Reports a stray start tag.
+     * @param name the name of the stray tag
+     * 
+     * @throws SAXException
+     */
+    private void errStrayStartTag(@Local String name) throws SAXException {
+        err("Stray end tag \u201C" + name + "\u201D.");
+    }
+
+    /**
+     * Reports a stray end tag.
+     * @param name the name of the stray tag
+     * 
+     * @throws SAXException
+     */
+    private void errStrayEndTag(@Local String name) throws SAXException {
+        err("Stray end tag \u201C" + name + "\u201D.");
+    }
+    
+    /**
+     * Reports a state when elements expected to be closed were not.
+     * 
+     * @param eltPos the position of the start tag on the stack of the element
+     * being closed.
+     * @param name the name of the end tag
+     * 
+     * @throws SAXException
+     */
+    private void errUnclosedElements(int eltPos, @Local String name) throws SAXException {
+        errNoCheck("End tag \u201C" + name + "\u201D seen, but there were open elements.");
+        errListUnclosedStartTags(eltPos);
+    }
+
+    /**
+     * Reports a state when elements expected to be closed ahead of an implied 
+     * end tag but were not.
+     * 
+     * @param eltPos the position of the start tag on the stack of the element
+     * being closed.
+     * @param name the name of the end tag
+     * 
+     * @throws SAXException
+     */
+    private void errUnclosedElementsImplied(int eltPos, String name) throws SAXException {
+        errNoCheck("End tag \u201C" + name + "\u201D implied, but there were open elements.");
+        errListUnclosedStartTags(eltPos);
+    }
+
+    /**
+     * Reports a state when elements expected to be closed ahead of an implied 
+     * table cell close.
+     * 
+     * @param eltPos the position of the start tag on the stack of the element
+     * being closed.
+     * @throws SAXException
+     */
+    private void errUnclosedElementsCell(int eltPos) throws SAXException {
+        errNoCheck("A table cell was implicitly closed, but there were open elements.");
+        errListUnclosedStartTags(eltPos);
+    }
+    
+    private void errStrayDoctype() throws SAXException {
+        err("Stray doctype.");
+    }
+
+    private void errAlmostStandardsDoctype() throws SAXException {
+        err("Almost standards mode doctype. Expected \u201C<!DOCTYPE html>\u201D.");
+    }
+
+    private void errQuirkyDoctype() throws SAXException {
+        err("Quirky doctype. Expected \u201C<!DOCTYPE html>\u201D.");
+    }
+
+    private void errNonSpaceInTrailer() throws SAXException {
+        err("Non-space character in page trailer.");
+    }
+
+    private void errNonSpaceAfterFrameset() throws SAXException {
+        err("Non-space after \u201Cframeset\u201D.");
+    }
+
+    private void errNonSpaceInFrameset() throws SAXException {
+        err("Non-space in \u201Cframeset\u201D.");
+    }
+
+    private void errNonSpaceAfterBody() throws SAXException {
+        err("Non-space character after body.");
+    }
+
+    private void errNonSpaceInColgroupInFragment() throws SAXException {
+        err("Non-space in \u201Ccolgroup\u201D when parsing fragment.");
+    }
+
+    private void errNonSpaceInNoscriptInHead() throws SAXException {
+        err("Non-space character inside \u201Cnoscript\u201D inside \u201Chead\u201D.");
+    }
+
+    private void errFooBetweenHeadAndBody(@Local String name) throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("\u201C" + name + "\u201D element between \u201Chead\u201D and \u201Cbody\u201D.");
+    }
+
+    private void errStartTagWithoutDoctype() throws SAXException {
+        err("Start tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.");
+    }
+
+    private void errNoSelectInTableScope() throws SAXException {
+        err("No \u201Cselect\u201D in table scope.");
+    }
+
+    private void errStartSelectWhereEndSelectExpected() throws SAXException {
+        err("\u201Cselect\u201D start tag where end tag expected.");
+    }
+
+    private void errStartTagWithSelectOpen(@Local String name)
+            throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("\u201C" + name
+                + "\u201D start tag with \u201Cselect\u201D open.");
+    }
+
+    private void errBadStartTagInHead(@Local String name) throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("Bad start tag in \u201C" + name
+                + "\u201D in \u201Chead\u201D.");
+    }
+
+    private void errImage() throws SAXException {
+        err("Saw a start tag \u201Cimage\u201D.");
+    }
+
+    private void errIsindex() throws SAXException {
+        err("\u201Cisindex\u201D seen.");
+    }
+
+    private void errFooSeenWhenFooOpen(@Local String name) throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("An \u201C" + name + "\u201D start tag seen but an element of the same type was already open.");
+    }
+
+    private void errHeadingWhenHeadingOpen() throws SAXException {
+        err("Heading cannot be a child of another heading.");
+    }
+
+    private void errFramesetStart() throws SAXException {
+        err("\u201Cframeset\u201D start tag seen.");
+    }
+
+    private void errNoCellToClose() throws SAXException {
+        err("No cell to close.");
+    }
+
+    private void errStartTagInTable(@Local String name) throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("Start tag \u201C" + name
+                + "\u201D seen in \u201Ctable\u201D.");
+    }
+
+    private void errFormWhenFormOpen() throws SAXException {
+        err("Saw a \u201Cform\u201D start tag, but there was already an active \u201Cform\u201D element. Nested forms are not allowed. Ignoring the tag.");
+    }
+
+    private void errTableSeenWhileTableOpen() throws SAXException {
+        err("Start tag for \u201Ctable\u201D seen but the previous \u201Ctable\u201D is still open.");
+    }
+
+    private void errStartTagInTableBody(@Local String name) throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("\u201C" + name + "\u201D start tag in table body.");
+    }
+
+    private void errEndTagSeenWithoutDoctype() throws SAXException {
+        err("End tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.");
+    }
+
+    private void errEndTagAfterBody() throws SAXException {
+        err("Saw an end tag after \u201Cbody\u201D had been closed.");
+    }
+
+    private void errEndTagSeenWithSelectOpen(@Local String name) throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("\u201C" + name
+                + "\u201D end tag with \u201Cselect\u201D open.");
+    }
+
+    private void errGarbageInColgroup() throws SAXException {
+        err("Garbage in \u201Ccolgroup\u201D fragment.");
+    }
+
+    private void errEndTagBr() throws SAXException {
+        err("End tag \u201Cbr\u201D.");
+    }
+
+    private void errNoElementToCloseButEndTagSeen(@Local String name)
+            throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("No \u201C" + name + "\u201D element in scope but a \u201C"
+                + name + "\u201D end tag seen.");
+    }
+
+    private void errHtmlStartTagInForeignContext(@Local String name)
+            throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("HTML start tag \u201C" + name
+                + "\u201D in a foreign namespace context.");
+    }
+
+    private void errTableClosedWhileCaptionOpen() throws SAXException {
+        err("\u201Ctable\u201D closed but \u201Ccaption\u201D was still open.");
+    }
+
+    private void errNoTableRowToClose() throws SAXException {
+        err("No table row to close.");
+    }
+
+    private void errNonSpaceInTable() throws SAXException {
+        err("Misplaced non-space characters insided a table.");
+    }
+
+    private void errUnclosedChildrenInRuby() throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("Unclosed children in \u201Cruby\u201D.");
+    }
+
+    private void errStartTagSeenWithoutRuby(@Local String name) throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("Start tag \u201C"
+                + name
+                + "\u201D seen without a \u201Cruby\u201D element being open.");
+    }
+
+    private void errSelfClosing() throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("Self-closing syntax (\u201C/>\u201D) used on a non-void HTML element. Ignoring the slash and treating as a start tag.");
+    }
+
+    private void errNoCheckUnclosedElementsOnStack() throws SAXException {
+        errNoCheck("Unclosed elements on stack.");
+    }
+
+    private void errEndTagDidNotMatchCurrentOpenElement(@Local String name,
+            @Local String currOpenName) throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("End tag \u201C"
+                + name
+                + "\u201D did not match the name of the current open element (\u201C"
+                + currOpenName + "\u201D).");
+    }
+
+    private void errEndTagViolatesNestingRules(@Local String name) throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("End tag \u201C" + name + "\u201D violates nesting rules.");
+    }
+
+    private void errEofWithUnclosedElements() throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("End of file seen and there were open elements.");
+        // just report all remaining unclosed elements
+        errListUnclosedStartTags(0);
+    }
+
+    /**
+     * Reports arriving at/near end of document with unclosed elements remaining.
+     * 
+     * @param message
+     *            the message
+     * @throws SAXException
+     */
+    private void errEndWithUnclosedElements(@Local String name) throws SAXException {
+        if (errorHandler == null) {
+            return;
+        }
+        errNoCheck("End tag for  \u201C"
+                + name
+                + "\u201D seen, but there were unclosed elements.");
+        // just report all remaining unclosed elements
+        errListUnclosedStartTags(0);
+    }
 }
--- a/parser/html/nsHtml5AtomList.h
+++ b/parser/html/nsHtml5AtomList.h
@@ -26,28 +26,29 @@ HTML5_ATOM(textarea, "textarea")
 HTML5_ATOM(style, "style")
 HTML5_ATOM(xmp, "xmp")
 HTML5_ATOM(iframe, "iframe")
 HTML5_ATOM(noembed, "noembed")
 HTML5_ATOM(noframes, "noframes")
 HTML5_ATOM(noscript, "noscript")
 HTML5_ATOM(plaintext, "plaintext")
 HTML5_ATOM(script, "script")
+HTML5_ATOM(svg, "svg")
+HTML5_ATOM(table, "table")
 HTML5_ATOM(caption, "caption")
 HTML5_ATOM(p, "p")
 HTML5_ATOM(address, "address")
 HTML5_ATOM(div, "div")
 HTML5_ATOM(a, "a")
 HTML5_ATOM(nobr, "nobr")
 HTML5_ATOM(input, "input")
 HTML5_ATOM(option, "option")
 HTML5_ATOM(ruby, "ruby")
 HTML5_ATOM(select, "select")
 HTML5_ATOM(optgroup, "optgroup")
-HTML5_ATOM(table, "table")
 HTML5_ATOM(frameset, "frameset")
 HTML5_ATOM(button, "button")
 HTML5_ATOM(ul, "ul")
 HTML5_ATOM(ol, "ol")
 HTML5_ATOM(html, "html")
 HTML5_ATOM(td, "td")
 HTML5_ATOM(th, "th")
 HTML5_ATOM(tr, "tr")
@@ -766,17 +767,16 @@ HTML5_ATOM(map, "map")
 HTML5_ATOM(mtr, "mtr")
 HTML5_ATOM(neq, "neq")
 HTML5_ATOM(not_, "not")
 HTML5_ATOM(nav, "nav")
 HTML5_ATOM(pre, "pre")
 HTML5_ATOM(rem, "rem")
 HTML5_ATOM(sub, "sub")
 HTML5_ATOM(sec, "sec")
-HTML5_ATOM(svg, "svg")
 HTML5_ATOM(sum, "sum")
 HTML5_ATOM(sin, "sin")
 HTML5_ATOM(sep, "sep")
 HTML5_ATOM(sup, "sup")
 HTML5_ATOM(set, "set")
 HTML5_ATOM(tan, "tan")
 HTML5_ATOM(use, "use")
 HTML5_ATOM(var, "var")
--- a/parser/html/nsHtml5AttributeName.cpp
+++ b/parser/html/nsHtml5AttributeName.cpp
@@ -28,27 +28,23 @@
 #define nsHtml5AttributeName_cpp__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
-#include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
-#include "nsHtml5NamedCharacters.h"
-#include "nsHtml5NamedCharactersAccel.h"
+#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
-#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
 
 #include "nsHtml5Tokenizer.h"
 #include "nsHtml5TreeBuilder.h"
 #include "nsHtml5MetaScanner.h"
 #include "nsHtml5ElementName.h"
 #include "nsHtml5HtmlAttributes.h"
 #include "nsHtml5StackNode.h"
--- a/parser/html/nsHtml5AttributeName.h
+++ b/parser/html/nsHtml5AttributeName.h
@@ -29,27 +29,23 @@
 #define nsHtml5AttributeName_h__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
-#include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
-#include "nsHtml5NamedCharacters.h"
-#include "nsHtml5NamedCharactersAccel.h"
+#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
-#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
 
 class nsHtml5StreamParser;
 
 class nsHtml5Tokenizer;
 class nsHtml5TreeBuilder;
 class nsHtml5MetaScanner;
 class nsHtml5ElementName;
--- a/parser/html/nsHtml5ElementName.cpp
+++ b/parser/html/nsHtml5ElementName.cpp
@@ -28,27 +28,23 @@
 #define nsHtml5ElementName_cpp__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
-#include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
-#include "nsHtml5NamedCharacters.h"
-#include "nsHtml5NamedCharactersAccel.h"
+#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
-#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
 
 #include "nsHtml5Tokenizer.h"
 #include "nsHtml5TreeBuilder.h"
 #include "nsHtml5MetaScanner.h"
 #include "nsHtml5AttributeName.h"
 #include "nsHtml5HtmlAttributes.h"
 #include "nsHtml5StackNode.h"
--- a/parser/html/nsHtml5ElementName.h
+++ b/parser/html/nsHtml5ElementName.h
@@ -29,27 +29,23 @@
 #define nsHtml5ElementName_h__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
-#include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
-#include "nsHtml5NamedCharacters.h"
-#include "nsHtml5NamedCharactersAccel.h"
+#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
-#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
 
 class nsHtml5StreamParser;
 
 class nsHtml5Tokenizer;
 class nsHtml5TreeBuilder;
 class nsHtml5MetaScanner;
 class nsHtml5AttributeName;
new file mode 100644
--- /dev/null
+++ b/parser/html/nsHtml5Highlighter.cpp
@@ -0,0 +1,849 @@
+/* ***** 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 HTML5 View Source code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Henri Sivonen <hsivonen@iki.fi>
+ *
+ * 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 "nsHtml5Highlighter.h"
+#include "nsDebug.h"
+#include "nsHtml5Tokenizer.h"
+#include "nsHtml5AttributeName.h"
+#include "nsString.h"
+#include "nsThreadUtils.h"
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
+
+// The old code had a limit of 16 tokens. 1300 is a number picked my measuring
+// the size of 16 tokens on cnn.com.
+#define NS_HTML5_HIGHLIGHTER_PRE_BREAK_THRESHOLD 1300
+
+PRUnichar nsHtml5Highlighter::sComment[] =
+  { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
+
+PRUnichar nsHtml5Highlighter::sCdata[] =
+  { 'c', 'd', 'a', 't', 'a', 0 };
+
+PRUnichar nsHtml5Highlighter::sEntity[] =
+  { 'e', 'n', 't', 'i', 't', 'y', 0 };
+
+PRUnichar nsHtml5Highlighter::sEndTag[] =
+  { 'e', 'n', 'd', '-', 't', 'a', 'g', 0 };
+
+PRUnichar nsHtml5Highlighter::sStartTag[] =
+  { 's', 't', 'a', 'r', 't', '-', 't', 'a', 'g', 0 };
+
+PRUnichar nsHtml5Highlighter::sAttributeName[] =
+  { 'a', 't', 't', 'r', 'i', 'b', 'u', 't', 'e', '-', 'n', 'a', 'm', 'e', 0 };
+
+PRUnichar nsHtml5Highlighter::sAttributeValue[] =
+  { 'a', 't', 't', 'r', 'i', 'b', 'u', 't', 'e', '-',
+    'v', 'a', 'l', 'u', 'e', 0 };
+
+PRUnichar nsHtml5Highlighter::sDoctype[] =
+  { 'd', 'o', 'c', 't', 'y', 'p', 'e', 0 };
+
+PRUnichar nsHtml5Highlighter::sPi[] =
+  { 'p', 'i', 0 };
+
+nsHtml5Highlighter::nsHtml5Highlighter(nsAHtml5TreeOpSink* aOpSink)
+ : mState(NS_HTML5TOKENIZER_DATA)
+ , mCStart(PR_INT32_MAX)
+ , mPos(0)
+ , mLineNumber(1)
+ , mUnicharsInThisPre(0)
+ , mInlinesOpen(0)
+ , mInCharacters(false)
+ , mBuffer(nsnull)
+ , mSyntaxHighlight(Preferences::GetBool("view_source.syntax_highlight",
+                                         true))
+ , mWrapLongLines(Preferences::GetBool("view_source.wrap_long_lines", true))
+ , mTabSize(Preferences::GetInt("view_source.tab_size", 4))
+ , mOpSink(aOpSink)
+ , mCurrentRun(nsnull)
+ , mAmpersand(nsnull)
+ , mSlash(nsnull)
+ , mHandles(new nsIContent*[NS_HTML5_HIGHLIGHTER_HANDLE_ARRAY_LENGTH])
+ , mHandlesUsed(0)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+}
+
+nsHtml5Highlighter::~nsHtml5Highlighter()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+}
+
+void
+nsHtml5Highlighter::Start()
+{
+  // Doctype
+  mOpQueue.AppendElement()->Init(nsGkAtoms::html, EmptyString(), EmptyString());
+
+  mOpQueue.AppendElement()->Init(STANDARDS_MODE);
+
+  nsIContent** root = CreateElement(nsHtml5Atoms::html, nsnull);
+  mOpQueue.AppendElement()->Init(eTreeOpAppendToDocument, root);
+  mStack.AppendElement(root);
+
+  Push(nsGkAtoms::head, nsnull);
+
+  Push(nsGkAtoms::title, nsnull);
+  // XUL will add the "Source of: " prefix.
+  AppendCharacters(mURL.get(), 0, mURL.Length());
+  Pop(); // title
+
+  nsHtml5HtmlAttributes* linkAttrs = new nsHtml5HtmlAttributes(0);
+  nsString* rel = new nsString(NS_LITERAL_STRING("stylesheet"));
+  linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_REL, rel);
+  nsString* type = new nsString(NS_LITERAL_STRING("text/css"));
+  linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_TYPE, type);
+  nsString* href = new nsString(
+      NS_LITERAL_STRING("resource://gre-resources/viewsource.css"));
+  linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_HREF, href);
+  Push(nsGkAtoms::link, linkAttrs);
+
+  mOpQueue.AppendElement()->Init(eTreeOpUpdateStyleSheet, CurrentNode());
+
+  Pop(); // link
+
+  Pop(); // head
+
+  nsHtml5HtmlAttributes* bodyAttrs = new nsHtml5HtmlAttributes(0);
+  nsString* id = new nsString(NS_LITERAL_STRING("viewsource"));
+  bodyAttrs->addAttribute(nsHtml5AttributeName::ATTR_ID, id);
+
+  if (mWrapLongLines) {
+    nsString* klass = new nsString(NS_LITERAL_STRING("wrap"));
+    bodyAttrs->addAttribute(nsHtml5AttributeName::ATTR_CLASS, klass);
+  }
+
+  if (mTabSize > 0) {
+    nsString* style = new nsString(NS_LITERAL_STRING("-moz-tab-size: "));
+    style->AppendInt(mTabSize);
+    bodyAttrs->addAttribute(nsHtml5AttributeName::ATTR_CLASS, style);
+  }
+
+  Push(nsGkAtoms::body, bodyAttrs);
+
+  nsHtml5HtmlAttributes* preAttrs = new nsHtml5HtmlAttributes(0);
+  nsString* preId = new nsString(NS_LITERAL_STRING("line1"));
+  preAttrs->addAttribute(nsHtml5AttributeName::ATTR_ID, preId);
+  Push(nsGkAtoms::pre, preAttrs);
+
+  StartCharacters();
+
+  mOpQueue.AppendElement()->Init(eTreeOpStartLayout);
+}
+
+PRInt32
+nsHtml5Highlighter::Transition(PRInt32 aState, bool aReconsume, PRInt32 aPos)
+{
+  mPos = aPos;
+  switch (mState) {
+    case NS_HTML5TOKENIZER_SCRIPT_DATA:
+    case NS_HTML5TOKENIZER_RAWTEXT:
+    case NS_HTML5TOKENIZER_RCDATA:
+    case NS_HTML5TOKENIZER_DATA:
+      // We can transition on < and on &. Either way, we don't yet know the
+      // role of the token, so open a span without class.
+      if (aState == NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE) {
+        StartSpan();
+        // Start another span for highlighting the ampersand
+        StartSpan();
+        mAmpersand = CurrentNode();
+      } else {
+        EndCharacters();
+        StartSpan();
+        mCurrentRun = CurrentNode();
+      }
+      break;
+    case NS_HTML5TOKENIZER_TAG_OPEN:
+      switch (aState) {
+        case NS_HTML5TOKENIZER_TAG_NAME:
+          StartSpan(sStartTag);
+          break;
+        case NS_HTML5TOKENIZER_DATA:
+          FinishTag(); // DATA
+          break;
+        case NS_HTML5TOKENIZER_PROCESSING_INSTRUCTION:
+          AddClass(sPi);
+          break;
+      }
+      break;
+    case NS_HTML5TOKENIZER_TAG_NAME:
+      switch (aState) {
+        case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME:
+          EndSpanOrA(); // NS_HTML5TOKENIZER_TAG_NAME
+          break;
+        case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG:
+          EndSpanOrA(); // NS_HTML5TOKENIZER_TAG_NAME
+          StartSpan(); // for highlighting the slash
+          mSlash = CurrentNode();
+          break;
+        default:
+          FinishTag();
+          break;
+      }
+      break;
+    case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME:
+      switch (aState) {
+        case NS_HTML5TOKENIZER_ATTRIBUTE_NAME:
+          StartSpan(sAttributeName);
+          break;
+        case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG:
+          StartSpan(); // for highlighting the slash
+          mSlash = CurrentNode();
+          break;
+        default:
+          FinishTag();
+          break;
+      }
+      break;
+    case NS_HTML5TOKENIZER_ATTRIBUTE_NAME:
+      switch (aState) {
+        case NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_NAME:
+        case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_VALUE:
+          EndSpanOrA(); // NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME
+          break;
+        case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG:
+          EndSpanOrA(); // NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME
+          StartSpan(); // for highlighting the slash
+          mSlash = CurrentNode();
+          break;
+        default:
+          FinishTag();
+          break;
+      }
+      break;
+    case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_VALUE:
+      switch (aState) {
+        case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_DOUBLE_QUOTED:
+        case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_SINGLE_QUOTED:
+          FlushCurrent();
+          StartA();
+          break;
+        case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_UNQUOTED:
+          StartA();
+          break;
+        default:
+          FinishTag();
+          break;
+      }
+      break;
+    case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_DOUBLE_QUOTED:
+    case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_SINGLE_QUOTED:
+      switch (aState) {
+        case NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_VALUE_QUOTED:
+          EndSpanOrA();
+          break;
+        case NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE:
+          StartSpan();
+          StartSpan(); // for ampersand itself
+          mAmpersand = CurrentNode();
+          break;
+        default:
+          NS_NOTREACHED("Impossible transition.");
+          break;
+      }
+      break;
+    case NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_VALUE_QUOTED:
+      switch (aState) {
+        case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME:
+          break;
+        case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG:
+          StartSpan(); // for highlighting the slash
+          mSlash = CurrentNode();
+          break;
+        default:
+          FinishTag();
+          break;
+      }
+      break;
+    case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG:
+      EndSpanOrA(); // end the slash highlight
+      switch (aState) {
+        case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME:
+          break;
+        default:
+          FinishTag();
+          break;
+      }
+      break;
+    case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_UNQUOTED:
+      switch (aState) {
+        case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME:
+          EndSpanOrA();
+          break;
+        case NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE:
+          StartSpan();
+          StartSpan(); // for ampersand itself
+          mAmpersand = CurrentNode();
+          break;
+        default:
+          FinishTag();
+          break;
+      }
+      break;
+    case NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_NAME:
+      switch (aState) {
+        case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG:
+          StartSpan(); // for highlighting the slash
+          mSlash = CurrentNode();
+          break;
+        case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_VALUE:
+          break;
+        case NS_HTML5TOKENIZER_ATTRIBUTE_NAME:
+          StartSpan(sAttributeName);
+          break;
+        default:
+          FinishTag();
+          break;
+      }
+      break;
+      // most comment states are omitted, because they don't matter to
+      // highlighting
+    case NS_HTML5TOKENIZER_COMMENT_END:
+    case NS_HTML5TOKENIZER_COMMENT_END_BANG:
+    case NS_HTML5TOKENIZER_COMMENT_START_DASH:
+    case NS_HTML5TOKENIZER_BOGUS_COMMENT:
+    case NS_HTML5TOKENIZER_BOGUS_COMMENT_HYPHEN:
+      if (aState == NS_HTML5TOKENIZER_DATA) {
+        AddClass(sComment);
+        FinishTag();
+      }
+      break;
+      // most cdata states are omitted, because they don't matter to
+      // highlighting
+    case NS_HTML5TOKENIZER_CDATA_RSQB_RSQB:
+      if (aState == NS_HTML5TOKENIZER_DATA) {
+        AddClass(sCdata);
+        FinishTag();
+      }
+      break;
+    case NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE:
+      EndSpanOrA(); // the span for the ampersand
+      switch (aState) {
+        case NS_HTML5TOKENIZER_CONSUME_NCR:
+        case NS_HTML5TOKENIZER_CHARACTER_REFERENCE_HILO_LOOKUP:
+          break;
+        default:
+          // not actually a character reference
+          EndSpanOrA();
+          break;
+      }
+      break;
+    case NS_HTML5TOKENIZER_CHARACTER_REFERENCE_HILO_LOOKUP:
+      if (aState == NS_HTML5TOKENIZER_CHARACTER_REFERENCE_TAIL) {
+        break;
+      }
+      // not actually a character reference
+      EndSpanOrA();
+      break;
+    case NS_HTML5TOKENIZER_CHARACTER_REFERENCE_TAIL:
+      if (!aReconsume) {
+        FlushCurrent();
+      }
+      EndSpanOrA();
+      break;
+    case NS_HTML5TOKENIZER_DECIMAL_NRC_LOOP:
+    case NS_HTML5TOKENIZER_HEX_NCR_LOOP:
+      switch (aState) {
+        case NS_HTML5TOKENIZER_HANDLE_NCR_VALUE:
+          AddClass(sEntity);
+          FlushCurrent();
+          break;
+        case NS_HTML5TOKENIZER_HANDLE_NCR_VALUE_RECONSUME:
+          AddClass(sEntity);
+          break;
+      }
+      EndSpanOrA();
+      break;
+    case NS_HTML5TOKENIZER_CLOSE_TAG_OPEN:
+      switch (aState) {
+        case NS_HTML5TOKENIZER_DATA:
+          FinishTag();
+          break;
+        case NS_HTML5TOKENIZER_TAG_NAME:
+          StartSpan(sEndTag);
+          break;
+      }
+      break;
+    case NS_HTML5TOKENIZER_RAWTEXT_RCDATA_LESS_THAN_SIGN:
+      if (aState == NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME) {
+        FlushCurrent();
+        StartSpan(); // don't know if it is "end-tag" yet :-(
+        break;
+      }
+      EndSpanOrA();
+      StartCharacters();
+      break;
+    case NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME:
+      switch (aState) {
+        case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME:
+          AddClass(sEndTag);
+          EndSpanOrA();
+          break;
+        case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG:
+          AddClass(sEndTag);
+          EndSpanOrA();
+          StartSpan(); // for highlighting the slash
+          mSlash = CurrentNode();
+          break;
+        case NS_HTML5TOKENIZER_DATA: // yes, as a result of emitting the token
+          AddClass(sEndTag);
+          FinishTag();
+          break;
+        default:
+          FinishTag();
+          break;
+      }
+      break;
+    case NS_HTML5TOKENIZER_SCRIPT_DATA_LESS_THAN_SIGN:
+    case NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN:
+      if (aState == NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME) {
+        break;
+      }
+      FinishTag();
+      break;
+    case NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED_DASH_DASH:
+    case NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED:
+    case NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED_DASH:
+      if (aState == NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN) {
+        EndCharacters();
+        StartSpan();
+      }
+      break;
+      // Lots of double escape states omitted, because they don't highlight.
+      // Likewise, only doctype states that can emit the doctype are of
+      // interest. Otherwise, the transition out of bogus comment deals.
+    case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_NAME:
+    case NS_HTML5TOKENIZER_DOCTYPE_NAME:
+    case NS_HTML5TOKENIZER_AFTER_DOCTYPE_NAME:
+    case NS_HTML5TOKENIZER_AFTER_DOCTYPE_PUBLIC_KEYWORD:
+    case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_PUBLIC_IDENTIFIER:
+    case NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED:
+    case NS_HTML5TOKENIZER_AFTER_DOCTYPE_PUBLIC_IDENTIFIER:
+    case NS_HTML5TOKENIZER_BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS:
+    case NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED:
+    case NS_HTML5TOKENIZER_AFTER_DOCTYPE_SYSTEM_IDENTIFIER:
+    case NS_HTML5TOKENIZER_BOGUS_DOCTYPE:
+    case NS_HTML5TOKENIZER_AFTER_DOCTYPE_SYSTEM_KEYWORD:
+    case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_SYSTEM_IDENTIFIER:
+    case NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED:
+    case NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED:
+      if (aState == NS_HTML5TOKENIZER_DATA) {
+        AddClass(sDoctype);
+        FinishTag();
+      }
+      break;
+    case NS_HTML5TOKENIZER_PROCESSING_INSTRUCTION_QUESTION_MARK:
+      if (aState == NS_HTML5TOKENIZER_DATA) {
+        FinishTag();
+      }
+      break;
+    default:
+      break;
+  }
+  mState = aState;
+  return aState;
+}
+
+void
+nsHtml5Highlighter::End()
+{
+  switch (mState) {
+    case NS_HTML5TOKENIZER_COMMENT_END:
+    case NS_HTML5TOKENIZER_COMMENT_END_BANG:
+    case NS_HTML5TOKENIZER_COMMENT_START_DASH:
+    case NS_HTML5TOKENIZER_BOGUS_COMMENT:
+    case NS_HTML5TOKENIZER_BOGUS_COMMENT_HYPHEN:
+      AddClass(sComment);
+      break;
+    case NS_HTML5TOKENIZER_CDATA_RSQB_RSQB:
+      AddClass(sCdata);
+      break;
+    case NS_HTML5TOKENIZER_DECIMAL_NRC_LOOP:
+    case NS_HTML5TOKENIZER_HEX_NCR_LOOP:
+      // XXX need tokenizer help here
+      break;
+    case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_NAME:
+    case NS_HTML5TOKENIZER_DOCTYPE_NAME:
+    case NS_HTML5TOKENIZER_AFTER_DOCTYPE_NAME:
+    case NS_HTML5TOKENIZER_AFTER_DOCTYPE_PUBLIC_KEYWORD:
+    case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_PUBLIC_IDENTIFIER:
+    case NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED:
+    case NS_HTML5TOKENIZER_AFTER_DOCTYPE_PUBLIC_IDENTIFIER:
+    case NS_HTML5TOKENIZER_BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS:
+    case NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED:
+    case NS_HTML5TOKENIZER_AFTER_DOCTYPE_SYSTEM_IDENTIFIER:
+    case NS_HTML5TOKENIZER_BOGUS_DOCTYPE:
+    case NS_HTML5TOKENIZER_AFTER_DOCTYPE_SYSTEM_KEYWORD:
+    case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_SYSTEM_IDENTIFIER:
+    case NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED:
+    case NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED:
+      AddClass(sDoctype);
+      break;
+    default:
+      break;
+  }
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  treeOp->Init(eTreeOpStreamEnded);
+  FlushOps();
+}
+
+void
+nsHtml5Highlighter::SetBuffer(nsHtml5UTF16Buffer* aBuffer)
+{
+  NS_PRECONDITION(!mBuffer, "Old buffer still here!");
+  mBuffer = aBuffer;
+  mCStart = aBuffer->getStart();
+}
+
+void
+nsHtml5Highlighter::DropBuffer(PRInt32 aPos)
+{
+  NS_PRECONDITION(mBuffer, "No buffer to drop!");
+  mPos = aPos;
+  FlushChars();
+  mBuffer = nsnull;
+}
+
+void
+nsHtml5Highlighter::StartSpan()
+{
+  FlushChars();
+  Push(nsGkAtoms::span, nsnull);
+  ++mInlinesOpen;
+}
+
+void
+nsHtml5Highlighter::StartSpan(const PRUnichar* aClass)
+{
+  StartSpan();
+  AddClass(aClass);
+}
+
+void
+nsHtml5Highlighter::EndSpanOrA()
+{
+  FlushChars();
+  Pop();
+  --mInlinesOpen;
+}
+
+void
+nsHtml5Highlighter::StartCharacters()
+{
+  NS_PRECONDITION(!mInCharacters, "Already in characters!");
+  FlushChars();
+  Push(nsGkAtoms::span, nsnull);
+  mCurrentRun = CurrentNode();
+  mInCharacters = true;
+}
+
+void
+nsHtml5Highlighter::EndCharacters()
+{
+  NS_PRECONDITION(mInCharacters, "Not in characters!");
+  FlushChars();
+  Pop();
+  mInCharacters = false;
+}
+
+void
+nsHtml5Highlighter::StartA()
+{
+  FlushChars();
+  Push(nsGkAtoms::a, nsnull);
+  AddClass(sAttributeValue);
+  ++mInlinesOpen;
+}
+
+void
+nsHtml5Highlighter::FinishTag()
+{
+  while (mInlinesOpen > 1) {
+    EndSpanOrA();
+  }
+  FlushCurrent(); // >
+  EndSpanOrA(); // DATA
+  NS_ASSERTION(!mInlinesOpen, "mInlinesOpen got out of sync!");
+  StartCharacters();
+}
+
+void
+nsHtml5Highlighter::FlushChars()
+{
+  if (mCStart < mPos) {
+    PRUnichar* buf = mBuffer->getBuffer();
+    PRInt32 i = mCStart;
+    while (i < mPos) {
+      PRUnichar c = buf[i];
+      switch (c) {
+        case '\r':
+          // The input this code sees has been normalized so that there are
+          // CR breaks and LF breaks but no CRLF breaks. Overwrite CR with LF
+          // to show consistent LF line breaks to layout. It is OK to mutate
+          // the input data, because there are no reparses in the View Source
+          // case, so we won't need the original data in the buffer anymore.
+          buf[i] = '\n';
+          // fall through
+        case '\n': {
+          ++i;
+          if (mCStart < i) {
+            PRInt32 len = i - mCStart;
+            AppendCharacters(buf, mCStart, len);
+            mCStart = i;
+            mUnicharsInThisPre += len;
+          }
+          ++mLineNumber;
+          if (mUnicharsInThisPre > NS_HTML5_HIGHLIGHTER_PRE_BREAK_THRESHOLD &&
+              !mInlinesOpen && mInCharacters) {
+            mUnicharsInThisPre = 0;
+            // Split the pre. See bug 86355.
+            Pop(); // span
+            Pop(); // pre
+            Push(nsGkAtoms::pre, nsnull);
+            nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
+            NS_ASSERTION(treeOp, "Tree op allocation failed.");
+            treeOp->InitAddLineNumberId(CurrentNode(), mLineNumber);
+            Push(nsGkAtoms::span, nsnull);
+            break;
+          }
+          Push(nsGkAtoms::span, nsnull);
+          nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
+          NS_ASSERTION(treeOp, "Tree op allocation failed.");
+          treeOp->InitAddLineNumberId(CurrentNode(), mLineNumber);
+          Pop();
+          break;
+        }
+        default:
+          ++i;
+          break;
+      }
+    }
+    if (mCStart < mPos) {
+      PRInt32 len = mPos - mCStart;
+      AppendCharacters(buf, mCStart, len);
+      mCStart = mPos;
+      mUnicharsInThisPre += len;
+    }
+  }
+}
+
+void
+nsHtml5Highlighter::FlushCurrent()
+{
+  mPos++;
+  FlushChars();
+}
+
+bool
+nsHtml5Highlighter::FlushOps()
+{
+  bool hasOps = !mOpQueue.IsEmpty();
+  if (hasOps) {
+    mOpSink->MoveOpsFrom(mOpQueue);
+  }
+  return hasOps;
+}
+
+void
+nsHtml5Highlighter::MaybeLinkifyAttributeValue(nsHtml5AttributeName* aName,
+                                               nsString* aValue)
+{
+  if (!(nsHtml5AttributeName::ATTR_HREF == aName ||
+        nsHtml5AttributeName::ATTR_SRC == aName ||
+        nsHtml5AttributeName::ATTR_ACTION == aName ||
+        nsHtml5AttributeName::ATTR_CITE == aName ||
+        nsHtml5AttributeName::ATTR_BACKGROUND == aName ||
+        nsHtml5AttributeName::ATTR_LONGDESC == aName ||
+        nsHtml5AttributeName::ATTR_XLINK_HREF == aName ||
+        nsHtml5AttributeName::ATTR_DEFINITIONURL == aName)) {
+    return;
+  }
+  AddViewSourceHref(*aValue);
+}
+
+void
+nsHtml5Highlighter::CompletedNamedCharacterReference()
+{
+  AddClass(sEntity);
+}
+
+nsIContent**
+nsHtml5Highlighter::AllocateContentHandle()
+{
+  if (mHandlesUsed == NS_HTML5_HIGHLIGHTER_HANDLE_ARRAY_LENGTH) {
+    mOldHandles.AppendElement(mHandles.forget());
+    mHandles = new nsIContent*[NS_HTML5_HIGHLIGHTER_HANDLE_ARRAY_LENGTH];
+    mHandlesUsed = 0;
+  }
+#ifdef DEBUG
+  mHandles[mHandlesUsed] = (nsIContent*)0xC0DEDBAD;
+#endif
+  return &mHandles[mHandlesUsed++];
+}
+
+nsIContent**
+nsHtml5Highlighter::CreateElement(nsIAtom* aName,
+                                  nsHtml5HtmlAttributes* aAttributes)
+{
+  NS_PRECONDITION(aName, "Got null name.");
+  nsIContent** content = AllocateContentHandle();
+  mOpQueue.AppendElement()->Init(kNameSpaceID_XHTML,
+                                 aName,
+                                 aAttributes,
+                                 content,
+                                 true);
+  return content;
+}
+
+nsIContent**
+nsHtml5Highlighter::CurrentNode()
+{
+  NS_PRECONDITION(mStack.Length() >= 1, "Must have something on stack.");
+  return mStack[mStack.Length() - 1];
+}
+
+void
+nsHtml5Highlighter::Push(nsIAtom* aName,
+                         nsHtml5HtmlAttributes* aAttributes)
+{
+  NS_PRECONDITION(mStack.Length() >= 1, "Pushing without root.");
+  nsIContent** elt = CreateElement(aName, aAttributes); // Don't inline below!
+  mOpQueue.AppendElement()->Init(eTreeOpAppend, elt, CurrentNode());
+  mStack.AppendElement(elt);
+}
+
+void
+nsHtml5Highlighter::Pop()
+{
+  NS_PRECONDITION(mStack.Length() >= 2, "Popping when stack too short.");
+  mStack.RemoveElementAt(mStack.Length() - 1);
+}
+
+void
+nsHtml5Highlighter::AppendCharacters(const PRUnichar* aBuffer,
+                                     PRInt32 aStart,
+                                     PRInt32 aLength)
+{
+  NS_PRECONDITION(aBuffer, "Null buffer");
+
+  PRUnichar* bufferCopy = new PRUnichar[aLength];
+  memcpy(bufferCopy, aBuffer + aStart, aLength * sizeof(PRUnichar));
+
+  mOpQueue.AppendElement()->Init(eTreeOpAppendText,
+                                 bufferCopy,
+                                 aLength,
+                                 CurrentNode());
+}
+
+
+void
+nsHtml5Highlighter::AddClass(const PRUnichar* aClass)
+{
+  mOpQueue.AppendElement()->InitAddClass(CurrentNode(), aClass);
+}
+
+void
+nsHtml5Highlighter::AddViewSourceHref(const nsString& aValue)
+{
+  PRUnichar* bufferCopy = new PRUnichar[aValue.Length() + 1];
+  memcpy(bufferCopy, aValue.get(), aValue.Length() * sizeof(PRUnichar));
+  bufferCopy[aValue.Length()] = 0;
+
+  mOpQueue.AppendElement()->Init(eTreeOpAddViewSourceHref,
+                                 bufferCopy,
+                                 aValue.Length(),
+                                 CurrentNode());
+}
+
+void
+nsHtml5Highlighter::AddErrorToCurrentNode(const char* aMsgId)
+{
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  treeOp->Init(CurrentNode(), aMsgId);
+}
+
+void
+nsHtml5Highlighter::AddErrorToCurrentRun(const char* aMsgId)
+{
+  NS_PRECONDITION(mCurrentRun, "Adding error to run without one!");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  treeOp->Init(mCurrentRun, aMsgId);
+}
+
+void
+nsHtml5Highlighter::AddErrorToCurrentRun(const char* aMsgId,
+                                         nsIAtom* aName)
+{
+  NS_PRECONDITION(mCurrentRun, "Adding error to run without one!");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  treeOp->Init(mCurrentRun, aMsgId, aName);
+}
+
+void
+nsHtml5Highlighter::AddErrorToCurrentRun(const char* aMsgId,
+                                         nsIAtom* aName,
+                                         nsIAtom* aOther)
+{
+  NS_PRECONDITION(mCurrentRun, "Adding error to run without one!");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  treeOp->Init(mCurrentRun, aMsgId, aName, aOther);
+}
+
+void
+nsHtml5Highlighter::AddErrorToCurrentAmpersand(const char* aMsgId)
+{
+  NS_PRECONDITION(mAmpersand, "Adding error to ampersand without one!");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  treeOp->Init(mAmpersand, aMsgId);
+}
+
+void
+nsHtml5Highlighter::AddErrorToCurrentSlash(const char* aMsgId)
+{
+  NS_PRECONDITION(mSlash, "Adding error to slash without one!");
+  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
+  NS_ASSERTION(treeOp, "Tree op allocation failed.");
+  treeOp->Init(mSlash, aMsgId);
+}
new file mode 100644
--- /dev/null
+++ b/parser/html/nsHtml5Highlighter.h
@@ -0,0 +1,459 @@
+/* ***** 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 HTML5 View Source code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Henri Sivonen <hsivonen@iki.fi>
+ *
+ * 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 ***** */
+#ifndef nsHtml5Highlighter_h_
+#define nsHtml5Highlighter_h_
+
+#include "prtypes.h"
+#include "nsCOMPtr.h"
+#include "nsHtml5TreeOperation.h"
+#include "nsHtml5UTF16Buffer.h"
+#include "nsHtml5TreeOperation.h"
+#include "nsAHtml5TreeOpSink.h"
+
+#define NS_HTML5_HIGHLIGHTER_HANDLE_ARRAY_LENGTH 512
+
+/**
+ * A state machine for generating HTML for display in View Source based on
+ * the transitions the tokenizer makes on the source being viewed.
+ */
+class nsHtml5Highlighter
+{
+  public:
+    /**
+     * The constructor.
+     *
+     * @param aOpSink the sink for the tree ops generated by this highlighter
+     */
+    nsHtml5Highlighter(nsAHtml5TreeOpSink* aOpSink);
+
+    /**
+     * The destructor.
+     */
+    ~nsHtml5Highlighter();
+
+    /**
+     * Starts the generated document.
+     */
+    void Start();
+
+    /**
+     * Report a tokenizer state transition.
+     *
+     * @param aState the state being transitioned to
+     * @param aReconsume whether this is a reconsuming transition
+     * @param aPos the tokenizer's current position into the buffer
+     */
+    PRInt32 Transition(PRInt32 aState, bool aReconsume, PRInt32 aPos);
+
+    /**
+     * Report end of file.
+     */
+    void End();
+
+    /**
+     * Set the current buffer being tokenized
+     */
+    void SetBuffer(nsHtml5UTF16Buffer* aBuffer);
+
+    /**
+     * Let go of the buffer being tokenized but first, flush text from it.
+     *
+     * @param aPos the first UTF-16 code unit not to flush
+     */
+    void DropBuffer(PRInt32 aPos);
+
+    /**
+     * Flush the tree ops into the sink.
+     *
+     * @return true if there were ops to flush
+     */
+    bool FlushOps();
+
+    /**
+     * Linkify the current attribute value if the attribute name is one of
+     * known URL attributes. (When executing tree ops, javascript: URLs will
+     * not be linkified, though.)
+     *
+     * @param aName the name of the attribute
+     * @param aValue the value of the attribute
+     */
+    void MaybeLinkifyAttributeValue(nsHtml5AttributeName* aName,
+                                    nsString* aValue);
+
+    /**
+     * Inform the highlighter that the tokenizer successfully completed a
+     * named character reference.
+     */
+    void CompletedNamedCharacterReference();
+
+    /**
+     * Adds an error annotation to the node that's currently on top of
+     * mStack.
+     *
+     * @param aMsgId the id of the message in the property file
+     */
+    void AddErrorToCurrentNode(const char* aMsgId);
+
+    /**
+     * Adds an error annotation to the node that corresponds to the most
+     * recently opened markup declaration/tag span, character reference or
+     * run of text.
+     *
+     * @param aMsgId the id of the message in the property file
+     */
+    void AddErrorToCurrentRun(const char* aMsgId);
+
+    /**
+     * Adds an error annotation to the node that corresponds to the most
+     * recently opened markup declaration/tag span, character reference or
+     * run of text with one atom to use when formatting the message.
+     *
+     * @param aMsgId the id of the message in the property file
+     * @param aName the atom
+     */
+    void AddErrorToCurrentRun(const char* aMsgId, nsIAtom* aName);
+
+    /**
+     * Adds an error annotation to the node that corresponds to the most
+     * recently opened markup declaration/tag span, character reference or
+     * run of text with two atoms to use when formatting the message.
+     *
+     * @param aMsgId the id of the message in the property file
+     * @param aName the first atom
+     * @param aOther the second atom
+     */
+    void AddErrorToCurrentRun(const char* aMsgId,
+                              nsIAtom* aName,
+                              nsIAtom* aOther);
+
+    /**
+     * Adds an error annotation to the node that corresponds to the most
+     * recent potentially character reference-starting ampersand.
+     *
+     * @param aMsgId the id of the message in the property file
+     */
+    void AddErrorToCurrentAmpersand(const char* aMsgId);
+
+    /**
+     * Adds an error annotation to the node that corresponds to the most
+     * recent potentially self-closing slash.
+     *
+     * @param aMsgId the id of the message in the property file
+     */
+    void AddErrorToCurrentSlash(const char* aMsgId);
+
+  private:
+
+    /**
+     * Starts a span with no class.
+     */
+    void StartSpan();
+
+    /**
+     * Starts a <span> and sets the class attribute on it.
+     *
+     * @param aClass the class to set (MUST be a static string that does not
+     *        need to be released!)
+     */
+    void StartSpan(const PRUnichar* aClass);
+
+    /**
+     * End the current <span> or <a> in the highlighter output.
+     */
+    void EndSpanOrA();
+
+    /**
+     * Starts a wrapper around a run of characters.
+     */
+    void StartCharacters();
+
+    /**
+     * Ends a wrapper around a run of characters.
+     */
+    void EndCharacters();
+
+    /**
+     * Starts an <a>.
+     */
+    void StartA();
+
+    /**
+     * Flushes characters up to but not including the current one.
+     */
+    void FlushChars();
+
+    /**
+     * Flushes characters up to and including the current one.
+     */
+    void FlushCurrent();
+
+    /**
+     * Finishes highlighting a tag in the input data by closing the open
+     * <span> and <a> elements in the highlighter output and then starts
+     * another <span> for potentially highlighting characters potentially
+     * appearing next.
+     */
+    void FinishTag();
+
+    /**
+     * Adds a class attribute to the current node.
+     *
+     * @param aClass the class to set (MUST be a static string that does not
+     *        need to be released!)
+     */
+    void AddClass(const PRUnichar* aClass);
+
+    /**
+     * Allocates a handle for an element.
+     *
+     * See the documentation for nsHtml5TreeBuilder::AllocateContentHandle()
+     * in nsHtml5TreeBuilderHSupplement.h.
+     *
+     * @return the handle
+     */
+    nsIContent** AllocateContentHandle();
+
+    /**
+     * Enqueues an element creation tree operation.
+     *
+     * @param aName the name of the element
+     * @param aAttributes the attribute holder (ownership will be taken) or
+     *        nsnull for no attributes
+     * @return the handle for the element that will be created
+     */
+    nsIContent** CreateElement(nsIAtom* aName,
+                               nsHtml5HtmlAttributes* aAttributes);
+
+    /**
+     * Gets the handle for the current node. May be called only after the
+     * root element has been set.
+     *
+     * @return the handle for the current node
+     */
+    nsIContent** CurrentNode();
+
+    /**
+     * Create an element and push it (its handle) on the stack.
+     *
+     * @param aName the name of the element
+     * @param aAttributes the attribute holder (ownership will be taken) or
+     *        nsnull for no attributes
+     */
+    void Push(nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes);
+
+    /**
+     * Pops the current node off the stack.
+     */
+    void Pop();
+
+    /**
+     * Appends text content to the current node.
+     *
+     * @param aBuffer the buffer to copy from
+     * @param aStart the index of the first code unit to copy
+     * @param aLength the number of code units to copy
+     */
+    void AppendCharacters(const PRUnichar* aBuffer,
+                          PRInt32 aStart,
+                          PRInt32 aLength);
+
+    /**
+     * Enqueues a tree op for adding an href attribute with the view-source:
+     * URL scheme to the current node.
+     *
+     * @param aValue the (potentially relative) URL to link to
+     */
+    void AddViewSourceHref(const nsString& aValue);
+
+    /**
+     * The state we are transitioning away from.
+     */
+    PRInt32 mState;
+
+    /**
+     * The index of the first UTF-16 code unit in mBuffer that hasn't been
+     * flushed yet.
+     */
+    PRInt32 mCStart;
+
+    /**
+     * The position of the code unit in mBuffer that caused the current
+     * transition.
+     */
+    PRInt32 mPos;
+
+    /**
+     * The current line number.
+     */
+    PRInt32 mLineNumber;
+
+    /**
+     * The number of PRUnichars flushed since the start of the current pre
+     * block.
+     */
+    PRInt32 mUnicharsInThisPre;
+
+    /**
+     * The number of inline elements open inside the <pre> excluding the
+     * span potentially wrapping a run of characters.
+     */
+    PRInt32 mInlinesOpen;
+
+    /**
+     * Whether there's a span wrapping a run of characters (excluding CDATA
+     * section) open.
+     */
+    bool mInCharacters;
+
+    /**
+     * The current buffer being tokenized.
+     */
+    nsHtml5UTF16Buffer* mBuffer;
+
+    /**
+     * The URL of the document to be shown in the page title.
+     */
+    nsString mURL;
+
+    /**
+     * Whether to highlight syntax visibly initially.
+     */
+    bool mSyntaxHighlight;
+
+    /**
+     * Whether to wrap long lines.
+     */
+    bool mWrapLongLines;
+
+    /**
+     * The tab size pref.
+     */
+    PRInt32 mTabSize;
+
+    /**
+     * The outgoing tree op queue.
+     */
+    nsTArray<nsHtml5TreeOperation> mOpQueue;
+
+    /**
+     * The tree op stage for the tree op executor.
+     */
+    nsAHtml5TreeOpSink* mOpSink;
+
+    /**
+     * The most recently opened markup declaration/tag or run of characters.
+     */
+    nsIContent** mCurrentRun;
+
+    /**
+     * The most recent ampersand in a place where character references were
+     * allowed.
+     */
+    nsIContent** mAmpersand;
+
+    /**
+     * The most recent slash that might become a self-closing slash.
+     */
+    nsIContent** mSlash;
+
+    /**
+     * Memory for element handles.
+     */
+    nsAutoArrayPtr<nsIContent*> mHandles;
+
+    /**
+     * Number of handles used in mHandles
+     */
+    PRInt32 mHandlesUsed;
+
+    /**
+     * A holder for old contents of mHandles
+     */
+    nsTArray<nsAutoArrayPtr<nsIContent*> > mOldHandles;
+
+    /**
+     * The element stack.
+     */
+    nsTArray<nsIContent**> mStack;
+
+    /**
+     * The string "comment"
+     */
+    static PRUnichar sComment[];
+
+    /**
+     * The string "cdata"
+     */
+    static PRUnichar sCdata[];
+
+    /**
+     * The string "start-tag"
+     */
+    static PRUnichar sStartTag[];
+
+    /**
+     * The string "attribute-name"
+     */
+    static PRUnichar sAttributeName[];
+
+    /**
+     * The string "attribute-value"
+     */
+    static PRUnichar sAttributeValue[];
+
+    /**
+     * The string "end-tag"
+     */
+    static PRUnichar sEndTag[];
+
+    /**
+     * The string "doctype"
+     */
+    static PRUnichar sDoctype[];
+
+    /**
+     * The string "entity"
+     */
+    static PRUnichar sEntity[];
+
+    /**
+     * The string "pi"
+     */
+    static PRUnichar sPi[];
+};
+
+#endif // nsHtml5Highlighter_h_
--- a/parser/html/nsHtml5HtmlAttributes.cpp
+++ b/parser/html/nsHtml5HtmlAttributes.cpp
@@ -29,27 +29,23 @@
 #define nsHtml5HtmlAttributes_cpp__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
-#include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
-#include "nsHtml5NamedCharacters.h"
-#include "nsHtml5NamedCharactersAccel.h"
+#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
-#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
 
 #include "nsHtml5Tokenizer.h"
 #include "nsHtml5TreeBuilder.h"
 #include "nsHtml5MetaScanner.h"
 #include "nsHtml5AttributeName.h"
 #include "nsHtml5ElementName.h"
 #include "nsHtml5StackNode.h"
--- a/parser/html/nsHtml5HtmlAttributes.h
+++ b/parser/html/nsHtml5HtmlAttributes.h
@@ -30,27 +30,23 @@
 #define nsHtml5HtmlAttributes_h__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
-#include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
-#include "nsHtml5NamedCharacters.h"
-#include "nsHtml5NamedCharactersAccel.h"
+#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
-#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
 
 class nsHtml5StreamParser;
 
 class nsHtml5Tokenizer;
 class nsHtml5TreeBuilder;
 class nsHtml5MetaScanner;
 class nsHtml5AttributeName;
--- a/parser/html/nsHtml5MetaScanner.cpp
+++ b/parser/html/nsHtml5MetaScanner.cpp
@@ -29,27 +29,23 @@
 #define nsHtml5MetaScanner_cpp__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
-#include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
-#include "nsHtml5NamedCharacters.h"
-#include "nsHtml5NamedCharactersAccel.h"
+#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
-#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
 
 #include "nsHtml5Tokenizer.h"
 #include "nsHtml5TreeBuilder.h"
 #include "nsHtml5AttributeName.h"
 #include "nsHtml5ElementName.h"
 #include "nsHtml5HtmlAttributes.h"
 #include "nsHtml5StackNode.h"
--- a/parser/html/nsHtml5MetaScanner.h
+++ b/parser/html/nsHtml5MetaScanner.h
@@ -30,27 +30,23 @@
 #define nsHtml5MetaScanner_h__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
-#include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
-#include "nsHtml5NamedCharacters.h"
-#include "nsHtml5NamedCharactersAccel.h"
+#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
-#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
 
 class nsHtml5StreamParser;
 
 class nsHtml5Tokenizer;
 class nsHtml5TreeBuilder;
 class nsHtml5AttributeName;
 class nsHtml5ElementName;
--- a/parser/html/nsHtml5Parser.cpp
+++ b/parser/html/nsHtml5Parser.cpp
@@ -85,17 +85,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   tmp->DropStreamParser();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 nsHtml5Parser::nsHtml5Parser()
   : mFirstBuffer(new nsHtml5OwningUTF16Buffer((void*)nsnull))
   , mLastBuffer(mFirstBuffer)
   , mExecutor(new nsHtml5TreeOpExecutor())
   , mTreeBuilder(new nsHtml5TreeBuilder(mExecutor, nsnull))
-  , mTokenizer(new nsHtml5Tokenizer(mTreeBuilder))
+  , mTokenizer(new nsHtml5Tokenizer(mTreeBuilder, false))
   , mRootContextLineNumber(1)
 {
   mAtomTable.Init(); // we aren't checking for OOM anyway...
   mTokenizer->setInterner(&mAtomTable);
   // There's a zeroing operator new for everything else
 }
 
 nsHtml5Parser::~nsHtml5Parser()
@@ -123,17 +123,18 @@ NS_IMETHODIMP_(void)
 nsHtml5Parser::GetCommand(nsCString& aCommand)
 {
   aCommand.Assign("view");
 }
 
 NS_IMETHODIMP_(void)
 nsHtml5Parser::SetCommand(const char* aCommand)
 {
-  NS_ASSERTION(!strcmp(aCommand, "view"), "Parser command was not view");
+  NS_ASSERTION(!strcmp(aCommand, "view") || !strcmp(aCommand, "view-source"),
+      "Parser command was not view");
 }
 
 NS_IMETHODIMP_(void)
 nsHtml5Parser::SetCommand(eParserCommands aParserCommand)
 {
   NS_ASSERTION(aParserCommand == eViewNormal, 
                "Parser command was not eViewNormal.");
 }
@@ -488,17 +489,17 @@ nsHtml5Parser::Parse(const nsAString& aS
       mDocWriteSpeculatorActive = true;
       if (!mDocWriteSpeculativeTreeBuilder) {
         // Lazily initialize if uninitialized
         mDocWriteSpeculativeTreeBuilder =
             new nsHtml5TreeBuilder(nsnull, mExecutor->GetStage());
         mDocWriteSpeculativeTreeBuilder->setScriptingEnabled(
             mTreeBuilder->isScriptingEnabled());
         mDocWriteSpeculativeTokenizer =
-            new nsHtml5Tokenizer(mDocWriteSpeculativeTreeBuilder);
+            new nsHtml5Tokenizer(mDocWriteSpeculativeTreeBuilder, false);
         mDocWriteSpeculativeTokenizer->setInterner(&mAtomTable);
         mDocWriteSpeculativeTokenizer->start();
       }
       mDocWriteSpeculativeTokenizer->resetToDataState();
       mDocWriteSpeculativeTreeBuilder->loadState(mTreeBuilder, &mAtomTable);
       mDocWriteSpeculativeLastWasCR = false;
     }
 
@@ -693,20 +694,32 @@ nsHtml5Parser::BeginEvaluatingParserInse
 
 void
 nsHtml5Parser::EndEvaluatingParserInsertedScript()
 {
   --mParserInsertedScriptsBeingEvaluated;
 }
 
 void
-nsHtml5Parser::MarkAsNotScriptCreated()
+nsHtml5Parser::MarkAsNotScriptCreated(const char* aCommand)
 {
   NS_PRECONDITION(!mStreamParser, "Must not call this twice.");
-  mStreamParser = new nsHtml5StreamParser(mExecutor, this);
+  eParserMode mode = NORMAL;
+  if (!nsCRT::strcmp(aCommand, "view-source")) {
+    mode = VIEW_SOURCE_HTML;
+  } else if (!nsCRT::strcmp(aCommand, "view-source-xml")) {
+    mode = VIEW_SOURCE_XML;
+  }
+#ifdef DEBUG
+  else {
+    NS_ASSERTION(!nsCRT::strcmp(aCommand, "view"),
+        "Unsupported parser command!");
+  }
+#endif
+  mStreamParser = new nsHtml5StreamParser(mExecutor, this, mode);
 }
 
 bool
 nsHtml5Parser::IsScriptCreated()
 {
   return !mStreamParser;
 }
 
--- a/parser/html/nsHtml5Parser.h
+++ b/parser/html/nsHtml5Parser.h
@@ -241,18 +241,21 @@ class nsHtml5Parser : public nsIParser,
     /**
      * Call immediately after having evaluated a parser-inserted script.
      */
     virtual void EndEvaluatingParserInsertedScript();
 
     /**
      * Marks the HTML5 parser as not a script-created parser: Prepares the 
      * parser to be able to read a stream.
+     *
+     * @param aCommand the parser command (Yeah, this is bad API design. Let's
+     * make this better when retiring nsIParser)
      */
-    virtual void MarkAsNotScriptCreated();
+    virtual void MarkAsNotScriptCreated(const char* aCommand);
 
     /**
      * True if this is a script-created HTML5 parser.
      */
     virtual bool IsScriptCreated();
 
     /* End nsIParser  */
 
--- a/parser/html/nsHtml5Portability.h
+++ b/parser/html/nsHtml5Portability.h
@@ -29,27 +29,23 @@
 #define nsHtml5Portability_h__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
-#include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
-#include "nsHtml5NamedCharacters.h"
-#include "nsHtml5NamedCharactersAccel.h"
+#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
-#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
 
 class nsHtml5StreamParser;
 
 class nsHtml5Tokenizer;
 class nsHtml5TreeBuilder;
 class nsHtml5MetaScanner;
 class nsHtml5AttributeName;
--- a/parser/html/nsHtml5StackNode.cpp
+++ b/parser/html/nsHtml5StackNode.cpp
@@ -29,27 +29,23 @@
 #define nsHtml5StackNode_cpp__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
-#include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
-#include "nsHtml5NamedCharacters.h"
-#include "nsHtml5NamedCharactersAccel.h"
+#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
-#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
 
 #include "nsHtml5Tokenizer.h"
 #include "nsHtml5TreeBuilder.h"
 #include "nsHtml5MetaScanner.h"
 #include "nsHtml5AttributeName.h"
 #include "nsHtml5ElementName.h"
 #include "nsHtml5HtmlAttributes.h"
--- a/parser/html/nsHtml5StackNode.h
+++ b/parser/html/nsHtml5StackNode.h
@@ -30,27 +30,23 @@
 #define nsHtml5StackNode_h__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
-#include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
-#include "nsHtml5NamedCharacters.h"
-#include "nsHtml5NamedCharactersAccel.h"
+#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
-#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
 
 class nsHtml5StreamParser;
 
 class nsHtml5Tokenizer;
 class nsHtml5TreeBuilder;
 class nsHtml5MetaScanner;
 class nsHtml5AttributeName;
--- a/parser/html/nsHtml5StateSnapshot.cpp
+++ b/parser/html/nsHtml5StateSnapshot.cpp
@@ -28,27 +28,23 @@
 #define nsHtml5StateSnapshot_cpp__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
-#include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
-#include "nsHtml5NamedCharacters.h"
-#include "nsHtml5NamedCharactersAccel.h"
+#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
-#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
 
 #include "nsHtml5Tokenizer.h"
 #include "nsHtml5TreeBuilder.h"
 #include "nsHtml5MetaScanner.h"
 #include "nsHtml5AttributeName.h"
 #include "nsHtml5ElementName.h"
 #include "nsHtml5HtmlAttributes.h"
--- a/parser/html/nsHtml5StateSnapshot.h
+++ b/parser/html/nsHtml5StateSnapshot.h
@@ -29,27 +29,23 @@
 #define nsHtml5StateSnapshot_h__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
-#include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
-#include "nsHtml5NamedCharacters.h"
-#include "nsHtml5NamedCharactersAccel.h"
+#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
-#include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
 
 class nsHtml5StreamParser;
 
 class nsHtml5Tokenizer;
 class nsHtml5TreeBuilder;
 class nsHtml5MetaScanner;
 class nsHtml5AttributeName;
--- a/parser/html/nsHtml5StreamParser.cpp
+++ b/parser/html/nsHtml5StreamParser.cpp
@@ -48,16 +48,19 @@
 #include "nsIHttpChannel.h"
 #include "nsHtml5Parser.h"
 #include "nsHtml5TreeBuilder.h"
 #include "nsHtml5AtomTable.h"
 #include "nsHtml5Module.h"
 #include "nsHtml5RefPtr.h"
 #include "nsIScriptError.h"
 #include "mozilla/Preferences.h"
+#include "nsHtml5Highlighter.h"
+#include "expat_config.h"
+#include "expat.h"
 
 using namespace mozilla;
 
 static NS_DEFINE_CID(kCharsetAliasCID, NS_CHARSETALIAS_CID);
 
 PRInt32 nsHtml5StreamParser::sTimerInitialDelay = 120;
 PRInt32 nsHtml5StreamParser::sTimerSubsequentDelay = 120;
 
@@ -169,41 +172,53 @@ class nsHtml5LoadFlusher : public nsRunn
     NS_IMETHODIMP Run()
     {
       mExecutor->FlushSpeculativeLoads();
       return NS_OK;
     }
 };
 
 nsHtml5StreamParser::nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor,
-                                         nsHtml5Parser* aOwner)
+                                         nsHtml5Parser* aOwner,
+                                         eParserMode aMode)
   : mFirstBuffer(nsnull) // Will be filled when starting
   , mLastBuffer(nsnull) // Will be filled when starting
   , mExecutor(aExecutor)
-  , mTreeBuilder(new nsHtml5TreeBuilder(mExecutor->GetStage(),
-                                        mExecutor->GetStage()))
-  , mTokenizer(new nsHtml5Tokenizer(mTreeBuilder))
+  , mTreeBuilder(new nsHtml5TreeBuilder((aMode == VIEW_SOURCE_HTML ||
+                                         aMode == VIEW_SOURCE_XML) ?
+                                             nsnull : mExecutor->GetStage(),
+                                         aMode == NORMAL ?
+                                             mExecutor->GetStage() : nsnull))
+  , mTokenizer(new nsHtml5Tokenizer(mTreeBuilder, aMode == VIEW_SOURCE_XML))
   , mTokenizerMutex("nsHtml5StreamParser mTokenizerMutex")
   , mOwner(aOwner)
   , mSpeculationMutex("nsHtml5StreamParser mSpeculationMutex")
   , mTerminatedMutex("nsHtml5StreamParser mTerminatedMutex")
   , mThread(nsHtml5Module::GetStreamParserThread())
   , mExecutorFlusher(new nsHtml5ExecutorFlusher(aExecutor))
   , mLoadFlusher(new nsHtml5LoadFlusher(aExecutor))
   , mFlushTimer(do_CreateInstance("@mozilla.org/timer;1"))
+  , mMode(aMode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   mFlushTimer->SetTarget(mThread);
   mAtomTable.Init(); // we aren't checking for OOM anyway...
 #ifdef DEBUG
   mAtomTable.SetPermittedLookupThread(mThread);
 #endif
   mTokenizer->setInterner(&mAtomTable);
   mTokenizer->setEncodingDeclarationHandler(this);
 
+  if (aMode == VIEW_SOURCE_HTML || aMode == VIEW_SOURCE_XML) {
+    nsHtml5Highlighter* highlighter =
+      new nsHtml5Highlighter(mExecutor->GetStage());
+    mTokenizer->EnableViewSource(highlighter); // takes ownership
+    mTreeBuilder->EnableViewSource(highlighter); // doesn't own
+  }
+
   // Chardet instantiation adapted from nsDOMFile.
   // Chardet is initialized here even if it turns out to be useless
   // to make the chardet refcount its observer (nsHtml5StreamParser)
   // on the main thread.
   const nsAdoptingCString& detectorName =
     Preferences::GetLocalizedCString("intl.charset.detector");
   if (!detectorName.IsEmpty()) {
     nsCAutoString detectorContractID;
@@ -385,23 +400,165 @@ nsHtml5StreamParser::SniffBOMlessUTF16Ba
   } else {
     mCharset.Assign("UTF-16BE");
   }
   mCharsetSource = kCharsetFromIrreversibleAutoDetection;
   mTreeBuilder->SetDocumentCharset(mCharset, mCharsetSource);
   mFeedChardet = false;
 }
 
+void
+nsHtml5StreamParser::MaybeSetEncodingFromExpat(const PRUnichar* aEncoding)
+{
+  nsDependentString utf16(aEncoding);
+  nsCAutoString utf8;
+  CopyUTF16toUTF8(utf16, utf8);
+  if (PreferredForInternalEncodingDecl(utf8)) {
+    mCharset.Assign(utf8);
+    mCharsetSource = kCharsetFromMetaTag; // closest for XML
+  }
+}
+
+// A separate user data struct is used instead of passing the
+// nsHtml5StreamParser instance as user data in order to avoid including
+// expat.h in nsHtml5StreamParser.h. Doing that would cause naming conflicts.
+// Using a separate user data struct also avoids bloating nsHtml5StreamParser
+// by one pointer.
+struct UserData {
+  XML_Parser mExpat;
+  nsHtml5StreamParser* mStreamParser;
+};
+
+// Using no-namespace handler callbacks to avoid including expat.h in
+// nsHtml5StreamParser.h, since doing so would cause naming conclicts.
+static void
+HandleXMLDeclaration(void* aUserData,
+                     const XML_Char* aVersion,
+                     const XML_Char* aEncoding,
+                     int aStandalone)
+{
+  UserData* ud = static_cast<UserData*>(aUserData);
+  ud->mStreamParser->MaybeSetEncodingFromExpat(
+      reinterpret_cast<const PRUnichar*>(aEncoding));
+  XML_StopParser(ud->mExpat, false);
+}
+
+static void
+HandleStartElement(void* aUserData,
+                   const XML_Char* aName,
+                   const XML_Char **aAtts)
+{
+  UserData* ud = static_cast<UserData*>(aUserData);
+  XML_StopParser(ud->mExpat, false);
+}
+
+static void
+HandleEndElement(void* aUserData,
+                 const XML_Char* aName)
+{
+  UserData* ud = static_cast<UserData*>(aUserData);
+  XML_StopParser(ud->mExpat, false);
+}
+
+static void
+HandleComment(void* aUserData,
+              const XML_Char* aName)
+{
+  UserData* ud = static_cast<UserData*>(aUserData);
+  XML_StopParser(ud->mExpat, false);
+}
+
+static void
+HandleProcessingInstruction(void* aUserData,
+                            const XML_Char* aTarget,
+                            const XML_Char* aData)
+{
+  UserData* ud = static_cast<UserData*>(aUserData);
+  XML_StopParser(ud->mExpat, false);
+}
+
 nsresult
 nsHtml5StreamParser::FinalizeSniffing(const PRUint8* aFromSegment, // can be null
                                       PRUint32 aCount,
                                       PRUint32* aWriteCount,
                                       PRUint32 aCountToSniffingLimit)
 {
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
+  NS_ASSERTION(mCharsetSource < kCharsetFromMetaTag,
+      "Should not finalize sniffing when already confident.");
+  if (mMode == VIEW_SOURCE_XML) {
+    static const XML_Memory_Handling_Suite memsuite =
+      {
+        (void *(*)(size_t))moz_xmalloc,
+        (void *(*)(void *, size_t))moz_xrealloc,
+        moz_free
+      };
+
+    static const PRUnichar kExpatSeparator[] = { 0xFFFF, '\0' };
+
+    static const PRUnichar kISO88591[] =
+        { 'I', 'S', 'O', '-', '8', '8', '5', '9', '-', '1', '\0' };
+
+    UserData ud;
+    ud.mStreamParser = this;
+
+    // If we got this far, the stream didn't have a BOM. UTF-16-encoded XML
+    // documents MUST begin with a BOM. We don't support EBCDIC and such.
+    // Thus, at this point, what we have is garbage or something encoded using
+    // a rough ASCII superset. ISO-8859-1 allows us to decode ASCII bytes
+    // without throwing errors when bytes have the most significant bit set
+    // and without triggering expat's unknown encoding code paths. This is
+    // enough to be able to use expat to parse the XML declaration in order
+    // to extract the encoding name from it.
+    ud.mExpat = XML_ParserCreate_MM(kISO88591, &memsuite, kExpatSeparator);
+    XML_SetXmlDeclHandler(ud.mExpat, HandleXMLDeclaration);
+    XML_SetElementHandler(ud.mExpat, HandleStartElement, HandleEndElement);
+    XML_SetCommentHandler(ud.mExpat, HandleComment);
+    XML_SetProcessingInstructionHandler(ud.mExpat, HandleProcessingInstruction);
+    XML_SetUserData(ud.mExpat, static_cast<void*>(&ud));
+
+    XML_Status status = XML_STATUS_OK;
+
+    // aFromSegment points to the data obtained from the current network
+    // event. mSniffingBuffer (if it exists) contains the data obtained before
+    // the current event. Thus, mSniffingLenth bytes of mSniffingBuffer
+    // followed by aCountToSniffingLimit bytes from aFromSegment are the
+    // first 1024 bytes of the file (or the file as a whole if the file is
+    // 1024 bytes long or shorter). Thus, we parse both buffers, but if the
+    // first call succeeds already, we skip parsing the second buffer.
+    if (mSniffingBuffer) {
+      status = XML_Parse(ud.mExpat,
+                         reinterpret_cast<const char*>(mSniffingBuffer.get()),
+                         mSniffingLength,
+                         false);
+    }
+    if (status == XML_STATUS_OK &&
+        mCharsetSource < kCharsetFromMetaTag &&
+        aFromSegment) {
+      status = XML_Parse(ud.mExpat,
+                         reinterpret_cast<const char*>(aFromSegment),
+                         aCountToSniffingLimit,
+                         false);
+    }
+    XML_ParserFree(ud.mExpat);
+
+    if (mCharsetSource < kCharsetFromMetaTag) {
+      // Failed to get an encoding from the XML declaration. XML defaults
+      // confidently to UTF-8 in this case.
+      // It is also possible that the document has an XML declaration that is
+      // longer than 1024 bytes, but that case is not worth worrying about.
+      mCharset.AssignLiteral("UTF-8");
+      mCharsetSource = kCharsetFromMetaTag; // means confident
+    }
+
+    return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment,
+                                                                aCount,
+                                                                aWriteCount);
+  }
+
   // meta scan failed.
   if (mCharsetSource >= kCharsetFromHintPrevDoc) {
     mFeedChardet = false;
     return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment, aCount, aWriteCount);
   }
   // Check for BOMless UTF-16 with Basic
   // Latin content for compat with IE. See bug 631751.
   SniffBOMlessUTF16BasicLatin(aFromSegment, aCountToSniffingLimit);
@@ -519,49 +676,62 @@ nsHtml5StreamParser::SniffStreamBytes(co
         break;
       default:
         mBomState = BOM_SNIFFING_OVER;
         break;
     }
   }
   // if we get here, there either was no BOM or the BOM sniffing isn't complete yet
   
-  if (!mMetaScanner) {
+  if (!mMetaScanner && (mMode == NORMAL || mMode == VIEW_SOURCE_HTML)) {
     mMetaScanner = new nsHtml5MetaScanner();
   }
   
   if (mSniffingLength + aCount >= NS_HTML5_STREAM_PARSER_SNIFFING_BUFFER_SIZE) {
     // this is the last buffer
-    PRUint32 countToSniffingLimit = NS_HTML5_STREAM_PARSER_SNIFFING_BUFFER_SIZE - mSniffingLength;
-    nsHtml5ByteReadable readable(aFromSegment, aFromSegment + countToSniffingLimit);
+    PRUint32 countToSniffingLimit =
+        NS_HTML5_STREAM_PARSER_SNIFFING_BUFFER_SIZE - mSniffingLength;
+    if (mMode == NORMAL || mMode == VIEW_SOURCE_HTML) {
+      nsHtml5ByteReadable readable(aFromSegment, aFromSegment +
+          countToSniffingLimit);
+      mMetaScanner->sniff(&readable, getter_AddRefs(mUnicodeDecoder), mCharset);
+      if (mUnicodeDecoder) {
+        mUnicodeDecoder->SetInputErrorBehavior(
+            nsIUnicodeDecoder::kOnError_Recover);
+        // meta scan successful
+        mCharsetSource = kCharsetFromMetaPrescan;
+        mFeedChardet = false;
+        mTreeBuilder->SetDocumentCharset(mCharset, mCharsetSource);
+        mMetaScanner = nsnull;
+        return WriteSniffingBufferAndCurrentSegment(aFromSegment, aCount,
+            aWriteCount);
+      }
+    }
+    return FinalizeSniffing(aFromSegment, aCount, aWriteCount,
+        countToSniffingLimit);
+  }
+
+  // not the last buffer
+  if (mMode == NORMAL || mMode == VIEW_SOURCE_HTML) {
+    nsHtml5ByteReadable readable(aFromSegment, aFromSegment + aCount);
     mMetaScanner->sniff(&readable, getter_AddRefs(mUnicodeDecoder), mCharset);
     if (mUnicodeDecoder) {
-      mUnicodeDecoder->SetInputErrorBehavior(nsIUnicodeDecoder::kOnError_Recover);
       // meta scan successful
+      mUnicodeDecoder->SetInputErrorBehavior(
+          nsIUnicodeDecoder::kOnError_Recover);
       mCharsetSource = kCharsetFromMetaPrescan;
       mFeedChardet = false;
       mTreeBuilder->SetDocumentCharset(mCharset, mCharsetSource);
       mMetaScanner = nsnull;
-      return WriteSniffingBufferAndCurrentSegment(aFromSegment, aCount, aWriteCount);
+      return WriteSniffingBufferAndCurrentSegment(aFromSegment, 
+                                                  aCount,
+                                                  aWriteCount);
     }
-    return FinalizeSniffing(aFromSegment, aCount, aWriteCount, countToSniffingLimit);
   }
 
-  // not the last buffer
-  nsHtml5ByteReadable readable(aFromSegment, aFromSegment + aCount);
-  mMetaScanner->sniff(&readable, getter_AddRefs(mUnicodeDecoder), mCharset);
-  if (mUnicodeDecoder) {
-    // meta scan successful
-    mUnicodeDecoder->SetInputErrorBehavior(nsIUnicodeDecoder::kOnError_Recover);
-    mCharsetSource = kCharsetFromMetaPrescan;
-    mFeedChardet = false;
-    mTreeBuilder->SetDocumentCharset(mCharset, mCharsetSource);
-    mMetaScanner = nsnull;
-    return WriteSniffingBufferAndCurrentSegment(aFromSegment, aCount, aWriteCount);
-  }
   if (!mSniffingBuffer) {
     const mozilla::fallible_t fallible = mozilla::fallible_t();
     mSniffingBuffer = new (fallible)
       PRUint8[NS_HTML5_STREAM_PARSER_SNIFFING_BUFFER_SIZE];
     if (!mSniffingBuffer) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
@@ -680,16 +850,21 @@ nsHtml5StreamParser::OnStartRequest(nsIR
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   if (mObserver) {
     mObserver->OnStartRequest(aRequest, aContext);
   }
   mRequest = aRequest;
 
   mStreamState = STREAM_BEING_READ;
 
+  if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) {
+    mTokenizer->StartViewSource();
+  }
+  // For View Source, the parser should run with scripts "enabled" if a normal
+  // load would have scripts enabled.
   bool scriptingEnabled = mExecutor->IsScriptEnabled();
   mOwner->StartTokenizer(scriptingEnabled);
   mTreeBuilder->setScriptingEnabled(scriptingEnabled);
   mTokenizer->start();
   mExecutor->Start();
   mExecutor->StartReadingFromStage();
   /*
    * If you move the following line, be very careful not to cause 
@@ -708,17 +883,21 @@ nsHtml5StreamParser::OnStartRequest(nsIR
     return NS_ERROR_OUT_OF_MEMORY;
   }
   NS_ASSERTION(!mFirstBuffer, "How come we have the first buffer set?");
   NS_ASSERTION(!mLastBuffer, "How come we have the last buffer set?");
   mFirstBuffer = mLastBuffer = newBuf;
 
   nsresult rv = NS_OK;
 
-  mReparseForbidden = false;
+  // The line below means that the encoding can end up being wrong if
+  // a view-source URL is loaded without having the encoding hint from a
+  // previous normal load in the history.
+  mReparseForbidden = !(mMode == NORMAL);
+
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mRequest, &rv));
   if (NS_SUCCEEDED(rv)) {
     nsCAutoString method;
     httpChannel->GetRequestMethod(method);
     // XXX does Necko have a way to renavigate POST, etc. without hitting
     // the network?
     if (!method.EqualsLiteral("GET")) {
       // This is the old Gecko behavior but the HTML5 spec disagrees.
@@ -915,32 +1094,19 @@ nsHtml5StreamParser::OnDataAvailable(nsI
                                                                 totalRead);
   if (NS_FAILED(mThread->Dispatch(dataAvailable, nsIThread::DISPATCH_NORMAL))) {
     NS_WARNING("Dispatching DataAvailable event failed.");
   }
   return rv;
 }
 
 bool
-nsHtml5StreamParser::internalEncodingDeclaration(nsString* aEncoding)
+nsHtml5StreamParser::PreferredForInternalEncodingDecl(nsACString& aEncoding)
 {
-  // This code needs to stay in sync with
-  // nsHtml5MetaScanner::tryCharset. Unfortunately, the
-  // trickery with member fields there leads to some copy-paste reuse. :-(
-  NS_ASSERTION(IsParserThread(), "Wrong thread!");
-  if (mCharsetSource >= kCharsetFromMetaTag) { // this threshold corresponds to "confident" in the HTML5 spec
-    return false;
-  }
-
-  if (mReparseForbidden) {
-    return false; // not reparsing even if we wanted to
-  }
-
-  nsCAutoString newEncoding;
-  CopyUTF16toUTF8(*aEncoding, newEncoding);
+  nsCAutoString newEncoding(aEncoding);
   newEncoding.Trim(" \t\r\n\f");
   if (newEncoding.LowerCaseEqualsLiteral("utf-16") ||
       newEncoding.LowerCaseEqualsLiteral("utf-16be") ||
       newEncoding.LowerCaseEqualsLiteral("utf-16le")) {
     newEncoding.Assign("UTF-8");
   }
 
   nsresult rv = NS_OK;
@@ -977,21 +1143,46 @@ nsHtml5StreamParser::internalEncodingDec
       preferred.LowerCaseEqualsLiteral("utf-7") ||
       preferred.LowerCaseEqualsLiteral("jis_x0212-1990") ||
       preferred.LowerCaseEqualsLiteral("x-jis0208") ||
       preferred.LowerCaseEqualsLiteral("x-imap4-modified-utf7") ||
       preferred.LowerCaseEqualsLiteral("x-user-defined")) {
     // Not a rough ASCII superset
     return false;
   }
+  aEncoding.Assign(preferred);
+  return true;
+}
+
+bool
+nsHtml5StreamParser::internalEncodingDeclaration(nsString* aEncoding)
+{
+  // This code needs to stay in sync with
+  // nsHtml5MetaScanner::tryCharset. Unfortunately, the
+  // trickery with member fields there leads to some copy-paste reuse. :-(
+  NS_ASSERTION(IsParserThread(), "Wrong thread!");
+  if (mCharsetSource >= kCharsetFromMetaTag) { // this threshold corresponds to "confident" in the HTML5 spec
+    return false;
+  }
+
+  if (mReparseForbidden) {
+    return false; // not reparsing even if we wanted to
+  }
+
+  nsCAutoString newEncoding;
+  CopyUTF16toUTF8(*aEncoding, newEncoding);
+
+  if (!PreferredForInternalEncodingDecl(newEncoding)) {
+    return false;
+  }
 
   // Avoid having the chardet ask for another restart after this restart
   // request.
   mFeedChardet = false;
-  mTreeBuilder->NeedsCharsetSwitchTo(preferred, kCharsetFromMetaTag);
+  mTreeBuilder->NeedsCharsetSwitchTo(newEncoding, kCharsetFromMetaTag);
   FlushTreeOpsAndDisarmTimer();
   Interrupt();
   // the tree op executor will cause the stream parser to terminate
   // if the charset switch request is accepted or it'll uninterrupt 
   // if the request failed. Note that if the restart request fails,
   // we don't bother trying to make chardet resume. Might as well
   // assume that chardet-requested restarts would fail, too.
   return true;
@@ -1002,16 +1193,19 @@ nsHtml5StreamParser::FlushTreeOpsAndDisa
 {
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
   if (mFlushTimerArmed) {
     // avoid calling Cancel if the flush timer isn't armed to avoid acquiring
     // a mutex
     mFlushTimer->Cancel();
     mFlushTimerArmed = false;
   }
+  if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) {
+    mTokenizer->FlushViewSource();
+  }
   mTreeBuilder->Flush();
   if (NS_FAILED(NS_DispatchToMainThread(mExecutorFlusher))) {
     NS_WARNING("failed to dispatch executor flush event");
   }
 }
 
 void
 nsHtml5StreamParser::ParseAvailableData()
@@ -1044,16 +1238,19 @@ nsHtml5StreamParser::ParseAvailableData(
             return; // no more data for now but expecting more
           case STREAM_ENDED:
             if (mAtEOF) {
               return;
             }
             mAtEOF = true;
             mTokenizer->eof();
             mTreeBuilder->StreamEnded();
+            if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) {
+              mTokenizer->EndViewSource();
+            }
             FlushTreeOpsAndDisarmTimer();
             return; // no more data and not expecting more
           default:
             NS_NOTREACHED("It should be impossible to reach this.");
             return;
         }
       }
       mFirstBuffer = mFirstBuffer->next;
@@ -1064,17 +1261,17 @@ nsHtml5StreamParser::ParseAvailableData(
     mFirstBuffer->adjust(mLastWasCR);
     mLastWasCR = false;
     if (mFirstBuffer->hasMore()) {
       mLastWasCR = mTokenizer->tokenizeBuffer(mFirstBuffer);
       // At this point, internalEncodingDeclaration() may have called 
       // Terminate, but that never happens together with script.
       // Can't assert that here, though, because it's possible that the main
       // thread has called Terminate() while this thread was parsing.
-      if (mTreeBuilder->HasScript()) {
+      if (mMode == NORMAL && mTreeBuilder->HasScript()) {
         mozilla::MutexAutoLock speculationAutoLock(mSpeculationMutex);
         nsHtml5Speculation* speculation = 
           new nsHtml5Speculation(mFirstBuffer,
                                  mFirstBuffer->getStart(),
                                  mTokenizer->getLineNumber(),
                                  mTreeBuilder->newSnapshot());
         mTreeBuilder->AddSnapshotToScript(speculation->GetSnapshot(), 
                                           speculation->GetStartLineNumber());
@@ -1109,16 +1306,18 @@ public:
 };
 
 void
 nsHtml5StreamParser::ContinueAfterScripts(nsHtml5Tokenizer* aTokenizer, 
                                           nsHtml5TreeBuilder* aTreeBuilder,
                                           bool aLastWasCR)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!(mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML),
+      "ContinueAfterScripts called in view source mode!");
   if (mExecutor->IsBroken()) {
     return;
   }
   #ifdef DEBUG
     mExecutor->AssertStageEmpty();
   #endif
   bool speculationFailed = false;
   {
@@ -1324,21 +1523,30 @@ nsHtml5StreamParser::TimerFlush()
   mFlushTimerArmed = false;
 
   mFlushTimerEverFired = true;
 
   if (IsTerminatedOrInterrupted()) {
     return;
   }
 
-  // we aren't speculating and we don't know when new data is
-  // going to arrive. Send data to the main thread.
-  if (mTreeBuilder->Flush(true)) {
-    if (NS_FAILED(NS_DispatchToMainThread(mExecutorFlusher))) {
-      NS_WARNING("failed to dispatch executor flush event");
+  if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) {
+    mTreeBuilder->Flush(); // delete useless ops
+    if (mTokenizer->FlushViewSource()) {
+       if (NS_FAILED(NS_DispatchToMainThread(mExecutorFlusher))) {
+         NS_WARNING("failed to dispatch executor flush event");
+       }
+     }
+  } else {
+    // we aren't speculating and we don't know when new data is
+    // going to arrive. Send data to the main thread.
+    if (mTreeBuilder->Flush(true)) {
+      if (NS_FAILED(NS_DispatchToMainThread(mExecutorFlusher))) {
+        NS_WARNING("failed to dispatch executor flush event");
+      }
     }
   }
 }
 
 void
 nsHtml5StreamParser::MarkAsBroken()
 {
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
--- a/parser/html/nsHtml5StreamParser.h
+++ b/parser/html/nsHtml5StreamParser.h
@@ -55,16 +55,38 @@
 #include "nsITimer.h"
 #include "nsICharsetDetector.h"
 
 class nsHtml5Parser;
 
 #define NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE 1024
 #define NS_HTML5_STREAM_PARSER_SNIFFING_BUFFER_SIZE 1024
 
+enum eParserMode {
+  /**
+   * Parse a document normally as HTML.
+   */
+  NORMAL,
+
+  /**
+   * View document as HTML source.
+   */
+  VIEW_SOURCE_HTML,
+
+  /**
+   * View document as XML source
+   */
+  VIEW_SOURCE_XML,
+
+  /**
+   * View document as plain text
+   */
+  PLAIN_TEXT
+};
+
 enum eBomState {
   /**
    * BOM sniffing hasn't started.
    */
   BOM_SNIFFING_NOT_STARTED = 0,
 
   /**
    * BOM sniffing is ongoing, and the first byte of an UTF-16LE BOM has been
@@ -113,17 +135,18 @@ class nsHtml5StreamParser : public nsISt
   public:
     NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsHtml5StreamParser, nsIStreamListener)
 
     static void InitializeStatics();
 
     nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor,
-                        nsHtml5Parser* aOwner);
+                        nsHtml5Parser* aOwner,
+                        eParserMode aMode);
                         
     virtual ~nsHtml5StreamParser();
 
     // nsIRequestObserver methods:
     NS_DECL_NSIREQUESTOBSERVER
     // nsIStreamListener methods:
     NS_DECL_NSISTREAMLISTENER
     
@@ -180,16 +203,22 @@ class nsHtml5StreamParser : public nsISt
 
     void Terminate() {
       mozilla::MutexAutoLock autoLock(mTerminatedMutex);
       mTerminated = true;
     }
     
     void DropTimer();
 
+    /**
+     * Sets mCharset and mCharsetSource appropriately for the XML View Source
+     * case if aEncoding names a supported rough ASCII superset.
+     */
+    void MaybeSetEncodingFromExpat(const PRUnichar* aEncoding);
+
   private:
 
 #ifdef DEBUG
     bool IsParserThread() {
       bool ret;
       mThread->IsOnCurrentThread(&ret);
       return ret;
     }
@@ -322,16 +351,26 @@ class nsHtml5StreamParser : public nsISt
      * @param aDecoderCharsetName The actual name for the decoder's charset
      *                            (UTF-16BE, UTF-16LE or UTF-8; the BOM has
      *                            been swallowed)
      */
     nsresult SetupDecodingFromBom(const char* aCharsetName,
                                   const char* aDecoderCharsetName);
 
     /**
+     * Become confident or resolve and encoding name to its preferred form.
+     * @param aEncoding the value of an internal encoding decl. Acts as an
+     *                  out param, too, when the method returns true.
+     * @return true if the parser needs to start using the new value of
+     *         aEncoding and false if the parser became confident or if
+     *         the encoding name did not specify a usable encoding
+     */
+    bool PreferredForInternalEncodingDecl(nsACString& aEncoding);
+
+    /**
      * Callback for mFlushTimer.
      */
     static void TimerCallback(nsITimer* aTimer, void* aClosure);
 
     /**
      * Parser thread entry point for (maybe) flushing the ops and posting
      * a flush runnable back on the main thread.
      */
@@ -491,16 +530,21 @@ class nsHtml5StreamParser : public nsISt
     bool                          mFlushTimerArmed;
 
     /**
      * False initially and true after the timer has fired at least once.
      */
     bool                          mFlushTimerEverFired;
 
     /**
+     * Whether the parser is doing a normal parse, view source or plain text.
+     */
+    eParserMode                   mMode;
+
+    /**
      * The pref html5.flushtimer.initialdelay: Time in milliseconds between
      * the time a network buffer is seen and the timer firing when the
      * timer hasn't fired previously in this parse.
      */
     static PRInt32                sTimerInitialDelay;
 
     /**
      * The pref html5.flushtimer.subsequentdelay: Time in milliseconds between
--- a/parser/html/nsHtml5Tokenizer.cpp
+++ b/parser/html/nsHtml5Tokenizer.cpp
@@ -29,30 +29,28 @@
  */
 
 #define nsHtml5Tokenizer_cpp__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
-#include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsHtml5NamedCharacters.h"
 #include "nsHtml5NamedCharactersAccel.h"
 #include "nsHtml5Atoms.h"
-#include "nsHtml5ByteReadable.h"
-#include "nsIUnicodeDecoder.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
+#include "nsHtml5Highlighter.h"
+#include "nsHtml5TokenizerLoopPolicies.h"
 
 #include "nsHtml5TreeBuilder.h"
 #include "nsHtml5MetaScanner.h"
 #include "nsHtml5AttributeName.h"
 #include "nsHtml5ElementName.h"
 #include "nsHtml5HtmlAttributes.h"
 #include "nsHtml5StackNode.h"
 #include "nsHtml5UTF16Buffer.h"
@@ -86,27 +84,28 @@ static PRUnichar const IFRAME_ARR_DATA[]
 staticJArray<PRUnichar,PRInt32> nsHtml5Tokenizer::IFRAME_ARR = { IFRAME_ARR_DATA, NS_ARRAY_LENGTH(IFRAME_ARR_DATA) };
 static PRUnichar const NOEMBED_ARR_DATA[] = { 'n', 'o', 'e', 'm', 'b', 'e', 'd' };
 staticJArray<PRUnichar,PRInt32> nsHtml5Tokenizer::NOEMBED_ARR = { NOEMBED_ARR_DATA, NS_ARRAY_LENGTH(NOEMBED_ARR_DATA) };
 static PRUnichar const NOSCRIPT_ARR_DATA[] = { 'n', 'o', 's', 'c', 'r', 'i', 'p', 't' };
 staticJArray<PRUnichar,PRInt32> nsHtml5Tokenizer::NOSCRIPT_ARR = { NOSCRIPT_ARR_DATA, NS_ARRAY_LENGTH(NOSCRIPT_ARR_DATA) };
 static PRUnichar const NOFRAMES_ARR_DATA[] = { 'n', 'o', 'f', 'r', 'a', 'm', 'e', 's' };
 staticJArray<PRUnichar,PRInt32> nsHtml5Tokenizer::NOFRAMES_ARR = { NOFRAMES_ARR_DATA, NS_ARRAY_LENGTH(NOFRAMES_ARR_DATA) };
 
-nsHtml5Tokenizer::nsHtml5Tokenizer(nsHtml5TreeBuilder* tokenHandler)
+nsHtml5Tokenizer::nsHtml5Tokenizer(nsHtml5TreeBuilder* tokenHandler, bool viewingXmlSource)
   : tokenHandler(tokenHandler),
     encodingDeclarationHandler(nsnull),
     bmpChar(jArray<PRUnichar,PRInt32>::newJArray(1)),
     astralChar(jArray<PRUnichar,PRInt32>::newJArray(2)),
     tagName(nsnull),
     attributeName(nsnull),
     doctypeName(nsnull),
     publicIdentifier(nsnull),
     systemIdentifier(nsnull),
-    attributes(nsnull)
+    attributes(nsnull),
+    viewingXmlSource(viewingXmlSource)
 {
   MOZ_COUNT_CTOR(nsHtml5Tokenizer);
 }
 
 void 
 nsHtml5Tokenizer::setInterner(nsHtml5AtomTable* interner)
 {
   this->interner = interner;
@@ -114,16 +113,22 @@ nsHtml5Tokenizer::setInterner(nsHtml5Ato
 
 void 
 nsHtml5Tokenizer::initLocation(nsString* newPublicId, nsString* newSystemId)
 {
   this->systemId = newSystemId;
   this->publicId = newPublicId;
 }
 
+bool 
+nsHtml5Tokenizer::isViewingXmlSource()
+{
+  return viewingXmlSource;
+}
+
 void 
 nsHtml5Tokenizer::setStateAndEndTagExpectation(PRInt32 specialTokenizerState, nsIAtom* endTagExpectation)
 {
   this->stateSave = specialTokenizerState;
   if (specialTokenizerState == NS_HTML5TOKENIZER_DATA) {
     return;
   }
   autoJArray<PRUnichar,PRInt32> asArray = nsHtml5Portability::newCharArrayFromLocal(endTagExpectation);
@@ -290,41 +295,47 @@ nsHtml5Tokenizer::strBufToElementNameStr
 {
   tagName = nsHtml5ElementName::elementNameByBuffer(strBuf, 0, strBufLen, interner);
 }
 
 PRInt32 
 nsHtml5Tokenizer::emitCurrentTagToken(bool selfClosing, PRInt32 pos)
 {
   cstart = pos + 1;
-
+  maybeErrSlashInEndTag(selfClosing);
   stateSave = NS_HTML5TOKENIZER_DATA;
   nsHtml5HtmlAttributes* attrs = (!attributes ? nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES : attributes);
   if (endTag) {
-
-    tokenHandler->endTag(tagName);
+    maybeErrAttributesOnEndTag(attrs);
+    if (!viewingXmlSource) {
+      tokenHandler->endTag(tagName);
+    }
     delete attributes;
   } else {
-    tokenHandler->startTag(tagName, attrs, selfClosing);
+    if (viewingXmlSource) {
+      delete attributes;
+    } else {
+      tokenHandler->startTag(tagName, attrs, selfClosing);
+    }
   }
   tagName->release();
   tagName = nsnull;
   resetAttributes();
   return stateSave;
 }
 
 void 
 nsHtml5Tokenizer::attributeNameComplete()
 {
   attributeName = nsHtml5AttributeName::nameByBuffer(strBuf, 0, strBufLen, interner);
   if (!attributes) {
     attributes = new nsHtml5HtmlAttributes(0);
   }
   if (attributes->contains(attributeName)) {
-
+    errDuplicateAttribute();
     attributeName->release();
     attributeName = nsnull;
   }
 }
 
 void 
 nsHtml5Tokenizer::addAttributeWithoutValue()
 {
@@ -335,16 +346,19 @@ nsHtml5Tokenizer::addAttributeWithoutVal
   }
 }
 
 void 
 nsHtml5Tokenizer::addAttributeWithValue()
 {
   if (attributeName) {
     nsString* val = longStrBufToString();
+    if (mViewSource) {
+      mViewSource->MaybeLinkifyAttributeValue(attributeName, val);
+    }
     attributes->addAttribute(attributeName, val);
     attributeName = nsnull;
   }
 }
 
 void 
 nsHtml5Tokenizer::start()
 {
@@ -383,25 +397,32 @@ nsHtml5Tokenizer::tokenizeBuffer(nsHtml5
       cstart = start;
       break;
     }
     default: {
       cstart = PR_INT32_MAX;
       break;
     }
   }
-  pos = stateLoop(state, c, pos, buffer->getBuffer(), false, returnState, buffer->getEnd());
+  if (mViewSource) {
+    mViewSource->SetBuffer(buffer);
+    pos = stateLoop<nsHtml5ViewSourcePolicy>(state, c, pos, buffer->getBuffer(), false, returnState, buffer->getEnd());
+    mViewSource->DropBuffer((pos == buffer->getEnd()) ? pos : pos + 1);
+  } else {
+    pos = stateLoop<nsHtml5SilentPolicy>(state, c, pos, buffer->getBuffer(), false, returnState, buffer->getEnd());
+  }
   if (pos == buffer->getEnd()) {
     buffer->setStart(pos);
   } else {
     buffer->setStart(pos + 1);
   }
   return lastCR;
 }
 
+template<class P>
 PRInt32 
 nsHtml5Tokenizer::stateLoop(PRInt32 state, PRUnichar c, PRInt32 pos, PRUnichar* buf, bool reconsume, PRInt32 returnState, PRInt32 endPos)
 {
   stateloop: for (; ; ) {
     switch(state) {
       case NS_HTML5TOKENIZER_DATA: {
         for (; ; ) {
           if (reconsume) {
@@ -413,22 +434,22 @@ nsHtml5Tokenizer::stateLoop(PRInt32 stat
             c = checkChar(buf, pos);
           }
           switch(c) {
             case '&': {
               flushChars(buf, pos);
               clearStrBufAndAppend(c);
               setAdditionalAndRememberAmpersandLocation('\0');
               returnState = state;
-              state = NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '<': {
               flushChars(buf, pos);
-              state = NS_HTML5TOKENIZER_TAG_OPEN;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_TAG_OPEN, reconsume, pos);
               NS_HTML5_BREAK(dataloop);
             }
             case '\0': {
               emitReplacementCharacter(buf, pos);
               continue;
             }
             case '\r': {
               emitCarriageReturn(buf, pos);
@@ -448,51 +469,61 @@ nsHtml5Tokenizer::stateLoop(PRInt32 stat
         for (; ; ) {
           if (++pos == endPos) {
             NS_HTML5_BREAK(stateloop);
           }
           c = checkChar(buf, pos);
           if (c >= 'A' && c <= 'Z') {
             endTag = false;
             clearStrBufAndAppend((PRUnichar) (c + 0x20));
-            state = NS_HTML5TOKENIZER_TAG_NAME;
+            state = P::transition(mViewSource, NS_HTML5TOKENIZER_TAG_NAME, reconsume, pos);
             NS_HTML5_BREAK(tagopenloop);
           } else if (c >= 'a' && c <= 'z') {
             endTag = false;
             clearStrBufAndAppend(c);
-            state = NS_HTML5TOKENIZER_TAG_NAME;
+            state = P::transition(mViewSource, NS_HTML5TOKENIZER_TAG_NAME, reconsume, pos);
             NS_HTML5_BREAK(tagopenloop);
           }
           switch(c) {
             case '!': {
-              state = NS_HTML5TOKENIZER_MARKUP_DECLARATION_OPEN;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_MARKUP_DECLARATION_OPEN, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '/': {
-              state = NS_HTML5TOKENIZER_CLOSE_TAG_OPEN;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_CLOSE_TAG_OPEN, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '\?': {
-
+              if (viewingXmlSource) {
+                state = P::transition(mViewSource, NS_HTML5TOKENIZER_PROCESSING_INSTRUCTION, reconsume, pos);
+                NS_HTML5_CONTINUE(stateloop);
+              }
+              if (P::reportErrors) {
+                errProcessingInstruction();
+              }
               clearLongStrBufAndAppend(c);
-              state = NS_HTML5TOKENIZER_BOGUS_COMMENT;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_BOGUS_COMMENT, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '>': {
-
+              if (P::reportErrors) {
+                errLtGt();
+              }
               tokenHandler->characters(nsHtml5Tokenizer::LT_GT, 0, 2);
               cstart = pos + 1;
-              state = NS_HTML5TOKENIZER_DATA;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_DATA, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             default: {
-
+              if (P::reportErrors) {
+                errBadCharAfterLt(c);
+              }
               tokenHandler->characters(nsHtml5Tokenizer::LT_GT, 0, 1);
               cstart = pos;
-              state = NS_HTML5TOKENIZER_DATA;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_DATA, reconsume, pos);
               reconsume = true;
               NS_HTML5_CONTINUE(stateloop);
             }
           }
         }
         tagopenloop_end: ;
       }
       case NS_HTML5TOKENIZER_TAG_NAME: {
@@ -500,37 +531,37 @@ nsHtml5Tokenizer::stateLoop(PRInt32 stat
           if (++pos == endPos) {
             NS_HTML5_BREAK(stateloop);
           }
           c = checkChar(buf, pos);
           switch(c) {
             case '\r': {
               silentCarriageReturn();
               strBufToElementNameString();
-              state = NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME, reconsume, pos);
               NS_HTML5_BREAK(stateloop);
             }
             case '\n': {
               silentLineFeed();
             }
             case ' ':
             case '\t':
             case '\f': {
               strBufToElementNameString();
-              state = NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME, reconsume, pos);
               NS_HTML5_BREAK(tagnameloop);
             }
             case '/': {
               strBufToElementNameString();
-              state = NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '>': {
               strBufToElementNameString();
-              state = emitCurrentTagToken(false, pos);
+              state = P::transition(mViewSource, emitCurrentTagToken(false, pos), reconsume, pos);
               if (shouldSuspend) {
                 NS_HTML5_BREAK(stateloop);
               }
               NS_HTML5_CONTINUE(stateloop);
             }
             case '\0': {
               c = 0xfffd;
             }
@@ -564,94 +595,102 @@ nsHtml5Tokenizer::stateLoop(PRInt32 stat
               silentLineFeed();
             }
             case ' ':
             case '\t':
             case '\f': {
               continue;
             }
             case '/': {
-              state = NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '>': {
-              state = emitCurrentTagToken(false, pos);
+              state = P::transition(mViewSource, emitCurrentTagToken(false, pos), reconsume, pos);
               if (shouldSuspend) {
                 NS_HTML5_BREAK(stateloop);
               }
               NS_HTML5_CONTINUE(stateloop);
             }
             case '\0': {
               c = 0xfffd;
             }
             case '\"':
             case '\'':
             case '<':
-            case '=':
+            case '=': {
+              if (P::reportErrors) {
+                errBadCharBeforeAttributeNameOrNull(c);
+              }
+            }
             default: {
               if (c >= 'A' && c <= 'Z') {
                 c += 0x20;
               }
               clearStrBufAndAppend(c);
-              state = NS_HTML5TOKENIZER_ATTRIBUTE_NAME;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_NAME, reconsume, pos);
               NS_HTML5_BREAK(beforeattributenameloop);
             }
           }
         }
         beforeattributenameloop_end: ;
       }
       case NS_HTML5TOKENIZER_ATTRIBUTE_NAME: {
         for (; ; ) {
           if (++pos == endPos) {
             NS_HTML5_BREAK(stateloop);
           }
           c = checkChar(buf, pos);
           switch(c) {
             case '\r': {
               silentCarriageReturn();
               attributeNameComplete();
-              state = NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_NAME;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_NAME, reconsume, pos);
               NS_HTML5_BREAK(stateloop);
             }
             case '\n': {
               silentLineFeed();
             }
             case ' ':
             case '\t':
             case '\f': {
               attributeNameComplete();
-              state = NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_NAME;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_NAME, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '/': {
               attributeNameComplete();
               addAttributeWithoutValue();
-              state = NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '=': {
               attributeNameComplete();
-              state = NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_VALUE;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_VALUE, reconsume, pos);
               NS_HTML5_BREAK(attributenameloop);
             }
             case '>': {
               attributeNameComplete();
               addAttributeWithoutValue();
-              state = emitCurrentTagToken(false, pos);
+              state = P::transition(mViewSource, emitCurrentTagToken(false, pos), reconsume, pos);
               if (shouldSuspend) {
                 NS_HTML5_BREAK(stateloop);
               }
               NS_HTML5_CONTINUE(stateloop);
             }
             case '\0': {
               c = 0xfffd;
             }
             case '\"':
             case '\'':
-            case '<':
+            case '<': {
+              if (P::reportErrors) {
+                errQuoteOrLtInAttributeNameOrNull(c);
+              }
+            }
             default: {
               if (c >= 'A' && c <= 'Z') {
                 c += 0x20;
               }
               appendStrBuf(c);
               continue;
             }
           }
@@ -674,49 +713,55 @@ nsHtml5Tokenizer::stateLoop(PRInt32 stat
             }
             case ' ':
             case '\t':
             case '\f': {
               continue;
             }
             case '\"': {
               clearLongStrBuf();
-              state = NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_DOUBLE_QUOTED;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_DOUBLE_QUOTED, reconsume, pos);
               NS_HTML5_BREAK(beforeattributevalueloop);
             }
             case '&': {
               clearLongStrBuf();
-              state = NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_UNQUOTED;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_UNQUOTED, reconsume, pos);
 
               reconsume = true;
               NS_HTML5_CONTINUE(stateloop);
             }
             case '\'': {
               clearLongStrBuf();
-              state = NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_SINGLE_QUOTED;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_SINGLE_QUOTED, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '>': {
-
+              if (P::reportErrors) {
+                errAttributeValueMissing();
+              }
               addAttributeWithoutValue();
-              state = emitCurrentTagToken(false, pos);
+              state = P::transition(mViewSource, emitCurrentTagToken(false, pos), reconsume, pos);
               if (shouldSuspend) {
                 NS_HTML5_BREAK(stateloop);
               }
               NS_HTML5_CONTINUE(stateloop);
             }
             case '\0': {
               c = 0xfffd;
             }
             case '<':
             case '=':
-            case '`':
+            case '`': {
+              if (P::reportErrors) {
+                errLtOrEqualsOrGraveInUnquotedAttributeOrNull(c);
+              }
+            }
             default: {
               clearLongStrBufAndAppend(c);
-              state = NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_UNQUOTED;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_UNQUOTED, reconsume, pos);
 
               NS_HTML5_CONTINUE(stateloop);
             }
           }
         }
         beforeattributevalueloop_end: ;
       }
       case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_DOUBLE_QUOTED: {
@@ -727,24 +772,24 @@ nsHtml5Tokenizer::stateLoop(PRInt32 stat
             if (++pos == endPos) {
               NS_HTML5_BREAK(stateloop);
             }
             c = checkChar(buf, pos);
           }
           switch(c) {
             case '\"': {
               addAttributeWithValue();
-              state = NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_VALUE_QUOTED;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_VALUE_QUOTED, reconsume, pos);
               NS_HTML5_BREAK(attributevaluedoublequotedloop);
             }
             case '&': {
               clearStrBufAndAppend(c);
               setAdditionalAndRememberAmpersandLocation('\"');
               returnState = state;
-              state = NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '\r': {
               appendLongStrBufCarriageReturn();
               NS_HTML5_BREAK(stateloop);
             }
             case '\n': {
               appendLongStrBufLineFeed();
@@ -765,65 +810,69 @@ nsHtml5Tokenizer::stateLoop(PRInt32 stat
         for (; ; ) {
           if (++pos == endPos) {
             NS_HTML5_BREAK(stateloop);
           }
           c = checkChar(buf, pos);
           switch(c) {
             case '\r': {
               silentCarriageReturn();
-              state = NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME, reconsume, pos);
               NS_HTML5_BREAK(stateloop);
             }
             case '\n': {
               silentLineFeed();
             }
             case ' ':
             case '\t':
             case '\f': {
-              state = NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '/': {
-              state = NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG, reconsume, pos);
               NS_HTML5_BREAK(afterattributevaluequotedloop);
             }
             case '>': {
-              state = emitCurrentTagToken(false, pos);
+              state = P::transition(mViewSource, emitCurrentTagToken(false, pos), reconsume, pos);
               if (shouldSuspend) {
                 NS_HTML5_BREAK(stateloop);
               }
               NS_HTML5_CONTINUE(stateloop);
             }
             default: {
-
-              state = NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME;
+              if (P::reportErrors) {
+                errNoSpaceBetweenAttributes();
+              }
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME, reconsume, pos);
               reconsume = true;
               NS_HTML5_CONTINUE(stateloop);
             }
           }
         }
         afterattributevaluequotedloop_end: ;
       }
       case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG: {
         if (++pos == endPos) {
           NS_HTML5_BREAK(stateloop);
         }
         c = checkChar(buf, pos);
         switch(c) {
           case '>': {
-            state = emitCurrentTagToken(true, pos);
+            state = P::transition(mViewSource, emitCurrentTagToken(true, pos), reconsume, pos);
             if (shouldSuspend) {
               NS_HTML5_BREAK(stateloop);
             }
             NS_HTML5_CONTINUE(stateloop);
           }
           default: {
-
-            state = NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME;
+            if (P::reportErrors) {
+              errSlashNotFollowedByGt();
+            }
+            state = P::transition(mViewSource, NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME, reconsume, pos);
             reconsume = true;
             NS_HTML5_CONTINUE(stateloop);
           }
         }
       }
       case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_UNQUOTED: {
         for (; ; ) {
           if (reconsume) {
@@ -833,52 +882,56 @@ nsHtml5Tokenizer::stateLoop(PRInt32 stat
               NS_HTML5_BREAK(stateloop);
             }
             c = checkChar(buf, pos);
           }
           switch(c) {
             case '\r': {
               silentCarriageReturn();
               addAttributeWithValue();
-              state = NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME, reconsume, pos);
               NS_HTML5_BREAK(stateloop);
             }
             case '\n': {
               silentLineFeed();
             }
             case ' ':
             case '\t':
             case '\f': {
               addAttributeWithValue();
-              state = NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '&': {
               clearStrBufAndAppend(c);
               setAdditionalAndRememberAmpersandLocation('>');
               returnState = state;
-              state = NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '>': {
               addAttributeWithValue();
-              state = emitCurrentTagToken(false, pos);
+              state = P::transition(mViewSource, emitCurrentTagToken(false, pos), reconsume, pos);
               if (shouldSuspend) {
                 NS_HTML5_BREAK(stateloop);
               }
               NS_HTML5_CONTINUE(stateloop);
             }
             case '\0': {
               c = 0xfffd;
             }
             case '<':
             case '\"':
             case '\'':
             case '=':
-            case '`':
+            case '`': {
+              if (P::reportErrors) {
+                errUnquotedAttributeValOrNull(c);
+              }
+            }
             default: {
 
               appendLongStrBuf(c);
               continue;
             }
           }
         }
       }
@@ -898,80 +951,86 @@ nsHtml5Tokenizer::stateLoop(PRInt32 stat
             }
             case ' ':
             case '\t':
             case '\f': {
               continue;
             }
             case '/': {
               addAttributeWithoutValue();
-              state = NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '=': {
-              state = NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_VALUE;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_VALUE, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '>': {
               addAttributeWithoutValue();
-              state = emitCurrentTagToken(false, pos);
+              state = P::transition(mViewSource, emitCurrentTagToken(false, pos), reconsume, pos);
               if (shouldSuspend) {
                 NS_HTML5_BREAK(stateloop);
               }
               NS_HTML5_CONTINUE(stateloop);
             }
             case '\0': {
               c = 0xfffd;
             }
             case '\"':
             case '\'':
-            case '<':
+            case '<': {
+              if (P::reportErrors) {
+                errQuoteOrLtInAttributeNameOrNull(c);
+              }
+            }
             default: {
               addAttributeWithoutValue();
               if (c >= 'A' && c <= 'Z') {
                 c += 0x20;
               }
               clearStrBufAndAppend(c);
-              state = NS_HTML5TOKENIZER_ATTRIBUTE_NAME;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_NAME, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
           }
         }
       }
       case NS_HTML5TOKENIZER_MARKUP_DECLARATION_OPEN: {
         for (; ; ) {
           if (++pos == endPos) {
             NS_HTML5_BREAK(stateloop);
           }
           c = checkChar(buf, pos);
           switch(c) {
             case '-': {
               clearLongStrBufAndAppend(c);
-              state = NS_HTML5TOKENIZER_MARKUP_DECLARATION_HYPHEN;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_MARKUP_DECLARATION_HYPHEN, reconsume, pos);
               NS_HTML5_BREAK(markupdeclarationopenloop);
             }
             case 'd':
             case 'D': {
               clearLongStrBufAndAppend(c);
               index = 0;
-              state = NS_HTML5TOKENIZER_MARKUP_DECLARATION_OCTYPE;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_MARKUP_DECLARATION_OCTYPE, reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '[': {
               if (tokenHandler->cdataSectionAllowed()) {
                 clearLongStrBufAndAppend(c);
                 index = 0;
-                state = NS_HTML5TOKENIZER_CDATA_START;
+                state = P::transition(mViewSource, NS_HTML5TOKENIZER_CDATA_START, reconsume, pos);
                 NS_HTML5_CONTINUE(stateloop);
               }
             }
             default: {
-
+              if (P::reportErrors) {
+                errBogusComment();
+              }
               clearLongStrBuf();
-              state = NS_HTML5TOKENIZER_BOGUS_COMMENT;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_BOGUS_COMMENT, reconsume, pos);
               reconsume = true;
               NS_HTML5_CONTINUE(stateloop);
             }
           }
         }
         markupdeclarationopenloop_end: ;
       }
       case NS_HTML5TOKENIZER_MARKUP_DECLARATION_HYPHEN: {
@@ -981,79 +1040,83 @@ nsHtml5Tokenizer::stateLoop(PRInt32 stat
           }
           c = checkChar(buf, pos);
           switch(c) {
             case '\0': {
               NS_HTML5_BREAK(stateloop);
             }
             case '-': {
               clearLongStrBuf();
-              state = NS_HTML5TOKENIZER_COMMENT_START;
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_COMMENT_START, reconsume, pos);
               NS_HTML5_BREAK(markupdeclarationhyphenloop);
             }
             default: {
-
-              state = NS_HTML5TOKENIZER_BOGUS_COMMENT;
+              if (P::reportErrors) {
+                errBogusComment();
+              }
+              state = P::transition(mViewSource, NS_HTML5TOKENIZER_BOGUS_COMMENT, reconsume, pos);
               reconsume = true;
               NS_HTML5_CONTINUE(stateloop);
             }
           }
         }
         markupdeclarationhyphenloop_end: ;
       }
       case NS_HTML5TOKENIZER_COMMENT_START: {
         for (; ; ) {